From 09c4175dffe2b20e8e418824a6b94663551a45d8 Mon Sep 17 00:00:00 2001 From: "tsmith/tim@siva.hindu.god" <> Date: Fri, 10 Nov 2006 12:13:52 -0700 Subject: [PATCH 001/336] Backport patch of bugfix for: - Bug #15815: Very poor performance with multiple queries running concurrently - Bug #22868: 'Thread thrashing' with > 50 concurrent conns under an upd-intensive workloadw This is a patch from an e-mail; it is not included (yet) in an InnoDB snapshot. --- innobase/buf/buf0buf.c | 173 +++++++++++++++++++++++------------ innobase/buf/buf0flu.c | 92 +++++++++++++------ innobase/buf/buf0lru.c | 25 ++++- innobase/include/buf0buf.h | 40 +++++--- innobase/include/buf0buf.ic | 19 ++-- innobase/include/sync0arr.h | 13 +-- innobase/include/sync0rw.h | 1 + innobase/include/sync0rw.ic | 6 +- innobase/include/sync0sync.h | 1 + innobase/os/os0sync.c | 55 ++++++++++- innobase/sync/sync0arr.c | 119 +++++++++--------------- innobase/sync/sync0rw.c | 2 + innobase/sync/sync0sync.c | 8 +- 13 files changed, 356 insertions(+), 198 deletions(-) diff --git a/innobase/buf/buf0buf.c b/innobase/buf/buf0buf.c index 31a581d2ba8..90da3205a82 100644 --- a/innobase/buf/buf0buf.c +++ b/innobase/buf/buf0buf.c @@ -221,6 +221,9 @@ in the free list to the frames. 5) When we have AWE enabled, we disable adaptive hash indexes. */ +/* Value in microseconds */ +static const int WAIT_FOR_READ = 20000; + buf_pool_t* buf_pool = NULL; /* The buffer buf_pool of the database */ ulint buf_dbg_counter = 0; /* This is used to insert validation @@ -466,6 +469,9 @@ buf_block_init( block->n_pointers = 0; + mutex_create(&block->mutex); + mutex_set_level(&block->mutex, SYNC_BUF_BLOCK); + rw_lock_create(&(block->lock)); ut_ad(rw_lock_validate(&(block->lock))); @@ -734,8 +740,15 @@ buf_awe_map_page_to_frame( bck = UT_LIST_GET_LAST(buf_pool->awe_LRU_free_mapped); while (bck) { - if (bck->state == BUF_BLOCK_FILE_PAGE - && (bck->buf_fix_count != 0 || bck->io_fix != 0)) { + ibool skip; + + mutex_enter(&bck->mutex); + + skip = (bck->state == BUF_BLOCK_FILE_PAGE + && (bck->buf_fix_count != 0 || bck->io_fix != 0)); + + if (skip) { + mutex_exit(&bck->mutex); /* We have to skip this */ bck = UT_LIST_GET_PREV(awe_LRU_free_mapped, bck); @@ -768,6 +781,8 @@ buf_awe_map_page_to_frame( buf_pool->n_pages_awe_remapped++; + mutex_exit(&bck->mutex); + return; } } @@ -806,13 +821,22 @@ buf_block_make_young( /*=================*/ buf_block_t* block) /* in: block to make younger */ { - if (buf_pool->freed_page_clock >= block->freed_page_clock - + 1 + (buf_pool->curr_size / 1024)) { +#ifdef UNIV_SYNC_DEBUG + ut_ad(!mutex_own(&(buf_pool->mutex))); +#endif /* UNIV_SYNC_DEBUG */ + /* Note that we read freed_page_clock's without holding any mutex: + this is allowed since the result is used only in heuristics */ + + if (buf_pool->freed_page_clock >= block->freed_page_clock + + 1 + (buf_pool->curr_size / 4)) { + + mutex_enter(&buf_pool->mutex); /* There has been freeing activity in the LRU list: best to move to the head of the LRU list */ buf_LRU_make_block_young(block); + mutex_exit(&buf_pool->mutex); } } @@ -847,12 +871,16 @@ buf_block_free( /*===========*/ buf_block_t* block) /* in, own: block to be freed */ { - ut_a(block->state != BUF_BLOCK_FILE_PAGE); - mutex_enter(&(buf_pool->mutex)); + mutex_enter(&block->mutex); + + ut_a(block->state != BUF_BLOCK_FILE_PAGE); + buf_LRU_block_free_non_file_page(block); + mutex_exit(&block->mutex); + mutex_exit(&(buf_pool->mutex)); } @@ -1071,9 +1099,8 @@ buf_page_get_gen( #endif buf_pool->n_page_gets++; loop: - mutex_enter_fast(&(buf_pool->mutex)); - block = NULL; + mutex_enter_fast(&(buf_pool->mutex)); if (guess) { block = buf_block_align(guess); @@ -1111,6 +1138,8 @@ loop: goto loop; } + mutex_enter(&block->mutex); + ut_a(block->state == BUF_BLOCK_FILE_PAGE); must_read = FALSE; @@ -1120,9 +1149,9 @@ loop: must_read = TRUE; if (mode == BUF_GET_IF_IN_POOL) { - /* The page is only being read to buffer */ - mutex_exit(&(buf_pool->mutex)); + mutex_exit(&buf_pool->mutex); + mutex_exit(&block->mutex); return(NULL); } @@ -1146,7 +1175,7 @@ loop: #else buf_block_buf_fix_inc(block); #endif - buf_block_make_young(block); + mutex_exit(&buf_pool->mutex); /* Check if this is the first access to the page */ @@ -1154,10 +1183,13 @@ loop: block->accessed = TRUE; + mutex_exit(&block->mutex); + + buf_block_make_young(block); + #ifdef UNIV_DEBUG_FILE_ACCESSES ut_a(block->file_page_was_freed == FALSE); #endif - mutex_exit(&(buf_pool->mutex)); #ifdef UNIV_DEBUG buf_dbg_counter++; @@ -1182,13 +1214,14 @@ loop: } if (!success) { - mutex_enter(&(buf_pool->mutex)); + mutex_enter(&block->mutex); block->buf_fix_count--; + + mutex_exit(&block->mutex); #ifdef UNIV_SYNC_DEBUG rw_lock_s_unlock(&(block->debug_latch)); #endif - mutex_exit(&(buf_pool->mutex)); return(NULL); } @@ -1199,18 +1232,16 @@ loop: completes */ for (;;) { - mutex_enter(&(buf_pool->mutex)); + mutex_enter(&block->mutex); if (block->io_fix == BUF_IO_READ) { - mutex_exit(&(buf_pool->mutex)); + mutex_exit(&block->mutex); - /* Sleep 20 milliseconds */ - - os_thread_sleep(20000); + os_thread_sleep(WAIT_FOR_READ); } else { - mutex_exit(&(buf_pool->mutex)); + mutex_exit(&block->mutex); break; } @@ -1268,14 +1299,14 @@ buf_page_optimistic_get_func( ut_ad(mtr && block); ut_ad((rw_latch == RW_S_LATCH) || (rw_latch == RW_X_LATCH)); - - mutex_enter(&(buf_pool->mutex)); /* If AWE is used, block may have a different frame now, e.g., NULL */ - + + mutex_enter(&block->mutex); + if (block->state != BUF_BLOCK_FILE_PAGE || block->frame != guess) { - mutex_exit(&(buf_pool->mutex)); + mutex_exit(&block->mutex); return(FALSE); } @@ -1285,16 +1316,15 @@ buf_page_optimistic_get_func( #else buf_block_buf_fix_inc(block); #endif + accessed = block->accessed; + block->accessed = TRUE; + + mutex_exit(&block->mutex); + buf_block_make_young(block); /* Check if this is the first access to the page */ - accessed = block->accessed; - - block->accessed = TRUE; - - mutex_exit(&(buf_pool->mutex)); - ut_ad(!ibuf_inside() || ibuf_page(block->space, block->offset)); if (rw_latch == RW_S_LATCH) { @@ -1308,14 +1338,15 @@ buf_page_optimistic_get_func( } if (!success) { - mutex_enter(&(buf_pool->mutex)); - + mutex_enter(&block->mutex); + block->buf_fix_count--; + + mutex_exit(&block->mutex); + #ifdef UNIV_SYNC_DEBUG rw_lock_s_unlock(&(block->debug_latch)); -#endif - mutex_exit(&(buf_pool->mutex)); - +#endif return(FALSE); } @@ -1329,14 +1360,15 @@ buf_page_optimistic_get_func( rw_lock_x_unlock(&(block->lock)); } - mutex_enter(&(buf_pool->mutex)); - + mutex_enter(&block->mutex); + block->buf_fix_count--; + + mutex_exit(&block->mutex); + #ifdef UNIV_SYNC_DEBUG rw_lock_s_unlock(&(block->debug_latch)); -#endif - mutex_exit(&(buf_pool->mutex)); - +#endif return(FALSE); } @@ -1394,10 +1426,10 @@ buf_page_get_known_nowait( ut_ad(mtr); ut_ad((rw_latch == RW_S_LATCH) || (rw_latch == RW_X_LATCH)); - mutex_enter(&(buf_pool->mutex)); - block = buf_block_align(guess); + mutex_enter(&block->mutex); + if (block->state == BUF_BLOCK_REMOVE_HASH) { /* Another thread is just freeing the block from the LRU list of the buffer pool: do not try to access this page; this @@ -1406,7 +1438,7 @@ buf_page_get_known_nowait( we have already removed it from the page address hash table of the buffer pool. */ - mutex_exit(&(buf_pool->mutex)); + mutex_exit(&block->mutex); return(FALSE); } @@ -1418,12 +1450,12 @@ buf_page_get_known_nowait( #else buf_block_buf_fix_inc(block); #endif + mutex_exit(&block->mutex); + if (mode == BUF_MAKE_YOUNG) { buf_block_make_young(block); } - mutex_exit(&(buf_pool->mutex)); - ut_ad(!ibuf_inside() || (mode == BUF_KEEP_OLD)); if (rw_latch == RW_S_LATCH) { @@ -1437,13 +1469,15 @@ buf_page_get_known_nowait( } if (!success) { - mutex_enter(&(buf_pool->mutex)); + mutex_enter(&block->mutex); block->buf_fix_count--; + + mutex_exit(&block->mutex); + #ifdef UNIV_SYNC_DEBUG rw_lock_s_unlock(&(block->debug_latch)); #endif - mutex_exit(&(buf_pool->mutex)); return(FALSE); } @@ -1491,8 +1525,7 @@ buf_page_init_for_backup_restore( block->offset = offset; block->lock_hash_val = 0; - block->lock_mutex = NULL; - + block->freed_page_clock = 0; block->newest_modification = ut_dulint_zero; @@ -1524,6 +1557,7 @@ buf_page_init( { #ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(buf_pool->mutex))); + ut_ad(mutex_own(&(block->mutex))); #endif /* UNIV_SYNC_DEBUG */ ut_a(block->state != BUF_BLOCK_FILE_PAGE); @@ -1537,8 +1571,7 @@ buf_page_init( block->check_index_page_at_flush = FALSE; block->lock_hash_val = lock_rec_hash(space, offset); - block->lock_mutex = NULL; - + /* Insert into the hash table of file pages */ if (buf_page_hash_get(space, offset)) { @@ -1630,6 +1663,7 @@ buf_page_init_for_read( ut_a(block); mutex_enter(&(buf_pool->mutex)); + mutex_enter(&block->mutex); if (fil_tablespace_deleted_or_being_deleted_in_mem(space, tablespace_version)) { @@ -1642,7 +1676,9 @@ buf_page_init_for_read( /* The page belongs to a space which has been deleted or is being deleted, or the page is already in buf_pool, return */ + mutex_exit(&block->mutex); mutex_exit(&(buf_pool->mutex)); + buf_block_free(block); if (mode == BUF_READ_IBUF_PAGES_ONLY) { @@ -1662,6 +1698,7 @@ buf_page_init_for_read( buf_LRU_add_block(block, TRUE); /* TRUE == to old blocks */ block->io_fix = BUF_IO_READ; + buf_pool->n_pend_reads++; /* We set a pass-type x-lock on the frame because then the same @@ -1673,6 +1710,7 @@ buf_page_init_for_read( rw_lock_x_lock_gen(&(block->lock), BUF_IO_READ); + mutex_exit(&block->mutex); mutex_exit(&(buf_pool->mutex)); if (mode == BUF_READ_IBUF_PAGES_ONLY) { @@ -1735,6 +1773,8 @@ buf_page_create( block = free_block; + mutex_enter(&block->mutex); + buf_page_init(space, offset, block); /* The block must be put to the LRU list */ @@ -1745,13 +1785,15 @@ buf_page_create( #else buf_block_buf_fix_inc(block); #endif + buf_pool->n_pages_created++; + + mutex_exit(&(buf_pool->mutex)); + mtr_memo_push(mtr, block, MTR_MEMO_BUF_FIX); block->accessed = TRUE; - buf_pool->n_pages_created++; - - mutex_exit(&(buf_pool->mutex)); + mutex_exit(&block->mutex); /* Delete possible entries for the page from the insert buffer: such can exist if the page belonged to an index which was dropped */ @@ -1800,6 +1842,12 @@ buf_page_io_complete( ut_a(block->state == BUF_BLOCK_FILE_PAGE); + /* We do not need protect block->io_fix here by block->mutex to read + it because this is the only function where we can change the value + from BUF_IO_READ or BUF_IO_WRITE to some other value, and our code + ensures that this is the only thread that handles the i/o for this + block. */ + io_type = block->io_fix; if (io_type == BUF_IO_READ) { @@ -1868,11 +1916,12 @@ buf_page_io_complete( } } + mutex_enter(&(buf_pool->mutex)); + mutex_enter(&block->mutex); + #ifdef UNIV_IBUF_DEBUG ut_a(ibuf_count_get(block->space, block->offset) == 0); #endif - mutex_enter(&(buf_pool->mutex)); - /* Because this thread which does the unlocking is not the same that did the locking, we use a pass value != 0 in unlock, which simply removes the newest lock debug record, without checking the thread @@ -1911,6 +1960,7 @@ buf_page_io_complete( } } + mutex_exit(&block->mutex); mutex_exit(&(buf_pool->mutex)); if (buf_debug_prints) { @@ -1970,6 +2020,8 @@ buf_validate(void) block = buf_pool_get_nth_block(buf_pool, i); + mutex_enter(&block->mutex); + if (block->state == BUF_BLOCK_FILE_PAGE) { ut_a(buf_page_hash_get(block->space, @@ -2013,6 +2065,8 @@ buf_validate(void) } else if (block->state == BUF_BLOCK_NOT_USED) { n_free++; } + + mutex_exit(&block->mutex); } if (n_lru + n_free > buf_pool->curr_size) { @@ -2303,16 +2357,21 @@ buf_all_freed(void) block = buf_pool_get_nth_block(buf_pool, i); + mutex_enter(&block->mutex); + if (block->state == BUF_BLOCK_FILE_PAGE) { if (!buf_flush_ready_for_replace(block)) { fprintf(stderr, "Page %lu %lu still fixed or dirty\n", - (ulong) block->space, (ulong) block->offset); + (ulong) block->space, + (ulong) block->offset); ut_error; } } + + mutex_exit(&block->mutex); } mutex_exit(&(buf_pool->mutex)); diff --git a/innobase/buf/buf0flu.c b/innobase/buf/buf0flu.c index 4df0e9962fb..a8252781f61 100644 --- a/innobase/buf/buf0flu.c +++ b/innobase/buf/buf0flu.c @@ -114,6 +114,7 @@ buf_flush_ready_for_replace( { #ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(buf_pool->mutex))); + ut_ad(mutex_own(&block->mutex)); #endif /* UNIV_SYNC_DEBUG */ if (block->state != BUF_BLOCK_FILE_PAGE) { ut_print_timestamp(stderr); @@ -148,6 +149,7 @@ buf_flush_ready_for_flush( { #ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(buf_pool->mutex))); + ut_ad(mutex_own(&(block->mutex))); #endif /* UNIV_SYNC_DEBUG */ ut_a(block->state == BUF_BLOCK_FILE_PAGE); @@ -533,8 +535,15 @@ buf_flush_try_page( ut_a(!block || block->state == BUF_BLOCK_FILE_PAGE); + if (!block) { + mutex_exit(&(buf_pool->mutex)); + return(0); + } + + mutex_enter(&block->mutex); + if (flush_type == BUF_FLUSH_LIST - && block && buf_flush_ready_for_flush(block, flush_type)) { + && buf_flush_ready_for_flush(block, flush_type)) { block->io_fix = BUF_IO_WRITE; @@ -572,6 +581,7 @@ buf_flush_try_page( locked = TRUE; } + mutex_exit(&block->mutex); mutex_exit(&(buf_pool->mutex)); if (!locked) { @@ -590,8 +600,8 @@ buf_flush_try_page( return(1); - } else if (flush_type == BUF_FLUSH_LRU && block - && buf_flush_ready_for_flush(block, flush_type)) { + } else if (flush_type == BUF_FLUSH_LRU + && buf_flush_ready_for_flush(block, flush_type)) { /* VERY IMPORTANT: Because any thread may call the LRU flush, even when owning @@ -631,14 +641,15 @@ buf_flush_try_page( buf_pool mutex: this ensures that the latch is acquired immediately. */ + mutex_exit(&block->mutex); mutex_exit(&(buf_pool->mutex)); buf_flush_write_block_low(block); return(1); - } else if (flush_type == BUF_FLUSH_SINGLE_PAGE && block - && buf_flush_ready_for_flush(block, flush_type)) { + } else if (flush_type == BUF_FLUSH_SINGLE_PAGE + && buf_flush_ready_for_flush(block, flush_type)) { block->io_fix = BUF_IO_WRITE; @@ -664,6 +675,7 @@ buf_flush_try_page( (buf_pool->n_flush[flush_type])++; + mutex_exit(&block->mutex); mutex_exit(&(buf_pool->mutex)); rw_lock_s_lock_gen(&(block->lock), BUF_IO_WRITE); @@ -678,11 +690,12 @@ buf_flush_try_page( buf_flush_write_block_low(block); return(1); - } else { - mutex_exit(&(buf_pool->mutex)); + } - return(0); - } + mutex_exit(&block->mutex); + mutex_exit(&(buf_pool->mutex)); + + return(0); } /*************************************************************** @@ -727,34 +740,48 @@ buf_flush_try_neighbors( block = buf_page_hash_get(space, i); ut_a(!block || block->state == BUF_BLOCK_FILE_PAGE); - if (block && flush_type == BUF_FLUSH_LRU && i != offset - && !block->old) { + if (!block) { + + continue; + + } else if (flush_type == BUF_FLUSH_LRU && i != offset + && !block->old) { /* We avoid flushing 'non-old' blocks in an LRU flush, because the flushed blocks are soon freed */ continue; - } + } else { - if (block && buf_flush_ready_for_flush(block, flush_type) - && (i == offset || block->buf_fix_count == 0)) { - /* We only try to flush those neighbors != offset - where the buf fix count is zero, as we then know that - we probably can latch the page without a semaphore - wait. Semaphore waits are expensive because we must - flush the doublewrite buffer before we start - waiting. */ + mutex_enter(&block->mutex); - mutex_exit(&(buf_pool->mutex)); + if (buf_flush_ready_for_flush(block, flush_type) + && (i == offset || block->buf_fix_count == 0)) { + /* We only try to flush those + neighbors != offset where the buf fix count is + zero, as we then know that we probably can + latch the page without a semaphore wait. + Semaphore waits are expensive because we must + flush the doublewrite buffer before we start + waiting. */ - /* Note: as we release the buf_pool mutex above, in - buf_flush_try_page we cannot be sure the page is still - in a flushable state: therefore we check it again - inside that function. */ + mutex_exit(&block->mutex); - count += buf_flush_try_page(space, i, flush_type); + mutex_exit(&(buf_pool->mutex)); - mutex_enter(&(buf_pool->mutex)); + /* Note: as we release the buf_pool mutex + above, in buf_flush_try_page we cannot be sure + the page is still in a flushable state: + therefore we check it again inside that + function. */ + + count += buf_flush_try_page(space, i, + flush_type); + + mutex_enter(&(buf_pool->mutex)); + } else { + mutex_exit(&block->mutex); + } } } @@ -848,12 +875,15 @@ buf_flush_batch( while ((block != NULL) && !found) { ut_a(block->state == BUF_BLOCK_FILE_PAGE); + mutex_enter(&block->mutex); + if (buf_flush_ready_for_flush(block, flush_type)) { found = TRUE; space = block->space; offset = block->offset; + mutex_exit(&block->mutex); mutex_exit(&(buf_pool->mutex)); old_page_count = page_count; @@ -871,10 +901,14 @@ buf_flush_batch( } else if (flush_type == BUF_FLUSH_LRU) { + mutex_exit(&block->mutex); + block = UT_LIST_GET_PREV(LRU, block); } else { ut_ad(flush_type == BUF_FLUSH_LIST); + mutex_exit(&block->mutex); + block = UT_LIST_GET_PREV(flush_list, block); } } @@ -951,10 +985,14 @@ buf_flush_LRU_recommendation(void) + BUF_FLUSH_EXTRA_MARGIN) && (distance < BUF_LRU_FREE_SEARCH_LEN)) { + mutex_enter(&block->mutex); + if (buf_flush_ready_for_replace(block)) { n_replaceable++; } + mutex_exit(&block->mutex); + distance++; block = UT_LIST_GET_PREV(LRU, block); diff --git a/innobase/buf/buf0lru.c b/innobase/buf/buf0lru.c index 05e92933edf..681b4d81462 100644 --- a/innobase/buf/buf0lru.c +++ b/innobase/buf/buf0lru.c @@ -86,6 +86,9 @@ scan_again: block = UT_LIST_GET_LAST(buf_pool->LRU); while (block != NULL) { + + mutex_enter(&block->mutex); + ut_a(block->state == BUF_BLOCK_FILE_PAGE); if (block->space == id @@ -112,6 +115,8 @@ scan_again: if (block->is_hashed) { page_no = block->offset; + mutex_exit(&block->mutex); + mutex_exit(&(buf_pool->mutex)); /* Note that the following call will acquire @@ -138,6 +143,7 @@ scan_again: buf_LRU_block_free_hashed_page(block); } next_page: + mutex_exit(&block->mutex); block = UT_LIST_GET_PREV(LRU, block); } @@ -211,6 +217,9 @@ buf_LRU_search_and_free_block( while (block != NULL) { ut_a(block->in_LRU_list); + + mutex_enter(&block->mutex); + if (buf_flush_ready_for_replace(block)) { if (buf_debug_prints) { @@ -223,6 +232,7 @@ buf_LRU_search_and_free_block( buf_LRU_block_remove_hashed_page(block); mutex_exit(&(buf_pool->mutex)); + mutex_exit(&block->mutex); /* Remove possible adaptive hash index built on the page; in the case of AWE the block may not have a @@ -231,15 +241,21 @@ buf_LRU_search_and_free_block( if (block->frame) { btr_search_drop_page_hash_index(block->frame); } - mutex_enter(&(buf_pool->mutex)); ut_a(block->buf_fix_count == 0); + mutex_enter(&(buf_pool->mutex)); + mutex_enter(&block->mutex); + buf_LRU_block_free_hashed_page(block); freed = TRUE; + mutex_exit(&block->mutex); break; } + + mutex_exit(&block->mutex); + block = UT_LIST_GET_PREV(LRU, block); distance++; @@ -413,8 +429,12 @@ loop: } } + mutex_enter(&block->mutex); + block->state = BUF_BLOCK_READY_FOR_USE; + mutex_exit(&block->mutex); + mutex_exit(&(buf_pool->mutex)); if (started_monitor) { @@ -815,6 +835,7 @@ buf_LRU_block_free_non_file_page( { #ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(buf_pool->mutex))); + ut_ad(mutex_own(&block->mutex)); #endif /* UNIV_SYNC_DEBUG */ ut_ad(block); @@ -854,6 +875,7 @@ buf_LRU_block_remove_hashed_page( { #ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(buf_pool->mutex))); + ut_ad(mutex_own(&block->mutex)); #endif /* UNIV_SYNC_DEBUG */ ut_ad(block); @@ -911,6 +933,7 @@ buf_LRU_block_free_hashed_page( { #ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(buf_pool->mutex))); + ut_ad(mutex_own(&block->mutex)); #endif /* UNIV_SYNC_DEBUG */ ut_a(block->state == BUF_BLOCK_REMOVE_HASH); diff --git a/innobase/include/buf0buf.h b/innobase/include/buf0buf.h index 53599d03c73..f9c69581476 100644 --- a/innobase/include/buf0buf.h +++ b/innobase/include/buf0buf.h @@ -455,8 +455,8 @@ Gets the mutex number protecting the page record lock hash chain in the lock table. */ UNIV_INLINE mutex_t* -buf_frame_get_lock_mutex( -/*=====================*/ +buf_frame_get_mutex( +/*================*/ /* out: mutex */ byte* ptr); /* in: pointer to within a buffer frame */ /*********************************************************************** @@ -699,7 +699,10 @@ struct buf_block_struct{ ulint magic_n; /* magic number to check */ ulint state; /* state of the control block: - BUF_BLOCK_NOT_USED, ... */ + BUF_BLOCK_NOT_USED, ...; changing + this is only allowed when a thread + has BOTH the buffer pool mutex AND + block->mutex locked */ byte* frame; /* pointer to buffer frame which is of size UNIV_PAGE_SIZE, and aligned to an address divisible by @@ -717,8 +720,12 @@ struct buf_block_struct{ ulint offset; /* page number within the space */ ulint lock_hash_val; /* hashed value of the page address in the record lock hash table */ - mutex_t* lock_mutex; /* mutex protecting the chain in the - record lock hash table */ + mutex_t mutex; /* mutex protecting this block: + state (also protected by the buffer + pool mutex), io_fix, buf_fix_count, + and accessed; we introduce this new + mutex in InnoDB-5.1 to relieve + contention on the buffer pool mutex */ rw_lock_t lock; /* read-write lock of the buffer frame */ buf_block_t* hash; /* node used in chaining to the page @@ -774,20 +781,27 @@ struct buf_block_struct{ in heuristic algorithms, because of the possibility of a wrap-around! */ ulint freed_page_clock;/* the value of freed_page_clock - buffer pool when this block was - last time put to the head of the - LRU list */ + of the buffer pool when this block was + the last time put to the head of the + LRU list; a thread is allowed to + read this for heuristic purposes + without holding any mutex or latch */ ibool old; /* TRUE if the block is in the old blocks in the LRU list */ ibool accessed; /* TRUE if the page has been accessed while in the buffer pool: read-ahead may read in pages which have not been - accessed yet */ + accessed yet; this is protected by + block->mutex; a thread is allowed to + read this for heuristic purposes + without holding any mutex or latch */ ulint buf_fix_count; /* count of how manyfold this block - is currently bufferfixed */ + is currently bufferfixed; this is + protected by block->mutex */ ulint io_fix; /* if a read is pending to the frame, io_fix is BUF_IO_READ, in the case - of a write BUF_IO_WRITE, otherwise 0 */ + of a write BUF_IO_WRITE, otherwise 0; + this is protected by block->mutex */ /* 4. Optimistic search field */ dulint modify_clock; /* this clock is incremented every @@ -940,7 +954,9 @@ struct buf_pool_struct{ number of buffer blocks removed from the end of the LRU list; NOTE that this counter may wrap around at 4 - billion! */ + billion! A thread is allowed to + read this for heuristic purposes + without holding any mutex or latch */ ulint LRU_flush_ended;/* when an LRU flush ends for a page, this is incremented by one; this is set to zero when a buffer block is diff --git a/innobase/include/buf0buf.ic b/innobase/include/buf0buf.ic index 681a0ef000a..8a18b2fb0fa 100644 --- a/innobase/include/buf0buf.ic +++ b/innobase/include/buf0buf.ic @@ -333,8 +333,8 @@ Gets the mutex number protecting the page record lock hash chain in the lock table. */ UNIV_INLINE mutex_t* -buf_frame_get_lock_mutex( -/*=====================*/ +buf_frame_get_mutex( +/*================*/ /* out: mutex */ byte* ptr) /* in: pointer to within a buffer frame */ { @@ -342,7 +342,7 @@ buf_frame_get_lock_mutex( block = buf_block_align(ptr); - return(block->lock_mutex); + return(&block->mutex); } /************************************************************************* @@ -521,6 +521,7 @@ buf_block_buf_fix_inc_debug( ret = rw_lock_s_lock_func_nowait(&(block->debug_latch), file, line); ut_ad(ret == TRUE); + ut_ad(mutex_own(&block->mutex)); #endif block->buf_fix_count++; } @@ -533,6 +534,9 @@ buf_block_buf_fix_inc( /*==================*/ buf_block_t* block) /* in: block to bufferfix */ { +#ifdef UNIV_SYNC_DEBUG + ut_ad(mutex_own(&block->mutex)); +#endif block->buf_fix_count++; } #endif /* UNIV_SYNC_DEBUG */ @@ -627,23 +631,24 @@ buf_page_release( ut_ad(block); - mutex_enter_fast(&(buf_pool->mutex)); - ut_a(block->state == BUF_BLOCK_FILE_PAGE); ut_a(block->buf_fix_count > 0); if (rw_latch == RW_X_LATCH && mtr->modifications) { - + mutex_enter(&buf_pool->mutex); buf_flush_note_modification(block, mtr); + mutex_exit(&buf_pool->mutex); } + mutex_enter(&block->mutex); + #ifdef UNIV_SYNC_DEBUG rw_lock_s_unlock(&(block->debug_latch)); #endif buf_fix_count = block->buf_fix_count; block->buf_fix_count = buf_fix_count - 1; - mutex_exit(&(buf_pool->mutex)); + mutex_exit(&block->mutex); if (rw_latch == RW_S_LATCH) { rw_lock_s_unlock(&(block->lock)); diff --git a/innobase/include/sync0arr.h b/innobase/include/sync0arr.h index fecd910683e..ba712d14aad 100644 --- a/innobase/include/sync0arr.h +++ b/innobase/include/sync0arr.h @@ -75,17 +75,12 @@ sync_array_free_cell( sync_array_t* arr, /* in: wait array */ ulint index); /* in: index of the cell in array */ /************************************************************************** -Looks for the cells in the wait array which refer -to the wait object specified, -and sets their corresponding events to the signaled state. In this -way releases the threads waiting for the object to contend for the object. -It is possible that no such cell is found, in which case does nothing. */ +Note that one of the wait objects was signalled. */ void -sync_array_signal_object( -/*=====================*/ - sync_array_t* arr, /* in: wait array */ - void* object);/* in: wait object */ +sync_array_object_signalled( +/*========================*/ + sync_array_t* arr); /* in: wait array */ /************************************************************************** If the wakeup algorithm does not work perfectly at semaphore relases, this function will do the waking (see the comment in mutex_exit). This diff --git a/innobase/include/sync0rw.h b/innobase/include/sync0rw.h index 9a988a03e92..c59608e0916 100644 --- a/innobase/include/sync0rw.h +++ b/innobase/include/sync0rw.h @@ -410,6 +410,7 @@ blocked by readers, a writer may queue for the lock by setting the writer field. Then no new readers are allowed in. */ struct rw_lock_struct { + os_event_t event; /* Used by sync0arr.c for thread queueing */ ulint reader_count; /* Number of readers who have locked this lock in the shared mode */ ulint writer; /* This field is set to RW_LOCK_EX if there diff --git a/innobase/include/sync0rw.ic b/innobase/include/sync0rw.ic index 3a92100ba01..92a75059ee3 100644 --- a/innobase/include/sync0rw.ic +++ b/innobase/include/sync0rw.ic @@ -380,7 +380,8 @@ rw_lock_s_unlock_func( mutex_exit(mutex); if (sg == TRUE) { - sync_array_signal_object(sync_primary_wait_array, lock); + os_event_set(lock->event); + sync_array_object_signalled(sync_primary_wait_array); } ut_ad(rw_lock_validate(lock)); @@ -459,7 +460,8 @@ rw_lock_x_unlock_func( mutex_exit(&(lock->mutex)); if (sg == TRUE) { - sync_array_signal_object(sync_primary_wait_array, lock); + os_event_set(lock->event); + sync_array_object_signalled(sync_primary_wait_array); } ut_ad(rw_lock_validate(lock)); diff --git a/innobase/include/sync0sync.h b/innobase/include/sync0sync.h index 8e0ec715b12..1b008c69d3c 100644 --- a/innobase/include/sync0sync.h +++ b/innobase/include/sync0sync.h @@ -447,6 +447,7 @@ Do not use its fields directly! The structure used in the spin lock implementation of a mutual exclusion semaphore. */ struct mutex_struct { + os_event_t event; /* Used by sync0arr.c for the wait queue */ ulint lock_word; /* This ulint is the target of the atomic test-and-set instruction in Win32 */ #if !defined(_WIN32) || !defined(UNIV_CAN_USE_X86_ASSEMBLER) diff --git a/innobase/os/os0sync.c b/innobase/os/os0sync.c index 4ad9473fe66..bf82f69023d 100644 --- a/innobase/os/os0sync.c +++ b/innobase/os/os0sync.c @@ -21,6 +21,7 @@ Created 9/6/1995 Heikki Tuuri /* Type definition for an operating system mutex struct */ struct os_mutex_struct{ + os_event_t event; /* Used by sync0arr.c for queing threads */ void* handle; /* OS handle to mutex */ ulint count; /* we use this counter to check that the same thread does not @@ -35,6 +36,7 @@ struct os_mutex_struct{ /* Mutex protecting counts and the lists of OS mutexes and events */ os_mutex_t os_sync_mutex; ibool os_sync_mutex_inited = FALSE; +ibool os_sync_free_called = FALSE; /* This is incremented by 1 in os_thread_create and decremented by 1 in os_thread_exit */ @@ -50,6 +52,10 @@ ulint os_event_count = 0; ulint os_mutex_count = 0; ulint os_fast_mutex_count = 0; +/* Because a mutex is embedded inside an event and there is an +event embedded inside a mutex, on free, this generates a recursive call. +This version of the free event function doesn't acquire the global lock */ +static void os_event_free_internal(os_event_t event); /************************************************************* Initializes global event and OS 'slow' mutex lists. */ @@ -76,6 +82,7 @@ os_sync_free(void) os_event_t event; os_mutex_t mutex; + os_sync_free_called = TRUE; event = UT_LIST_GET_FIRST(os_event_list); while (event) { @@ -99,6 +106,7 @@ os_sync_free(void) mutex = UT_LIST_GET_FIRST(os_mutex_list); } + os_sync_free_called = FALSE; } /************************************************************* @@ -146,14 +154,21 @@ os_event_create( event->signal_count = 0; #endif /* __WIN__ */ - /* Put to the list of events */ - os_mutex_enter(os_sync_mutex); + /* The os_sync_mutex can be NULL because during startup an event + can be created [ because it's embedded in the mutex/rwlock ] before + this module has been initialized */ + if (os_sync_mutex != NULL) { + os_mutex_enter(os_sync_mutex); + } + /* Put to the list of events */ UT_LIST_ADD_FIRST(os_event_list, os_event_list, event); os_event_count++; - os_mutex_exit(os_sync_mutex); + if (os_sync_mutex != NULL) { + os_mutex_exit(os_sync_mutex); + } return(event); } @@ -255,6 +270,35 @@ os_event_reset( #endif } +/************************************************************** +Frees an event object, without acquiring the global lock. */ +static +void +os_event_free_internal( +/*===================*/ + os_event_t event) /* in: event to free */ +{ +#ifdef __WIN__ + ut_a(event); + + ut_a(CloseHandle(event->handle)); +#else + ut_a(event); + + /* This is to avoid freeing the mutex twice */ + os_fast_mutex_free(&(event->os_mutex)); + + ut_a(0 == pthread_cond_destroy(&(event->cond_var))); +#endif + /* Remove from the list of events */ + + UT_LIST_REMOVE(os_event_list, os_event_list, event); + + os_event_count--; + + ut_free(event); +} + /************************************************************** Frees an event object. */ @@ -456,6 +500,7 @@ os_mutex_create( mutex_str->handle = mutex; mutex_str->count = 0; + mutex_str->event = os_event_create(NULL); if (os_sync_mutex_inited) { /* When creating os_sync_mutex itself we cannot reserve it */ @@ -532,6 +577,10 @@ os_mutex_free( { ut_a(mutex); + if (!os_sync_free_called) { + os_event_free_internal(mutex->event); + } + if (os_sync_mutex_inited) { os_mutex_enter(os_sync_mutex); } diff --git a/innobase/sync/sync0arr.c b/innobase/sync/sync0arr.c index 198ef49ca9f..64f9310bad3 100644 --- a/innobase/sync/sync0arr.c +++ b/innobase/sync/sync0arr.c @@ -62,9 +62,6 @@ struct sync_cell_struct { ibool waiting; /* TRUE if the thread has already called sync_array_event_wait on this cell */ - ibool event_set; /* TRUE if the event is set */ - os_event_t event; /* operating system event - semaphore handle */ time_t reservation_time;/* time when the thread reserved the wait cell */ }; @@ -218,10 +215,7 @@ sync_array_create( for (i = 0; i < n_cells; i++) { cell = sync_array_get_nth_cell(arr, i); cell->wait_object = NULL; - - /* Create an operating system event semaphore with no name */ - cell->event = os_event_create(NULL); - cell->event_set = FALSE; /* it is created in reset state */ + cell->waiting = FALSE; } return(arr); @@ -235,19 +229,12 @@ sync_array_free( /*============*/ sync_array_t* arr) /* in, own: sync wait array */ { - ulint i; - sync_cell_t* cell; ulint protection; ut_a(arr->n_reserved == 0); sync_array_validate(arr); - for (i = 0; i < arr->n_cells; i++) { - cell = sync_array_get_nth_cell(arr, i); - os_event_free(cell->event); - } - protection = arr->protection; /* Release the mutex protecting the wait array complex */ @@ -292,28 +279,20 @@ sync_array_validate( sync_array_exit(arr); } -/*********************************************************************** -Puts the cell event in set state. */ -static -void -sync_cell_event_set( -/*================*/ - sync_cell_t* cell) /* in: array cell */ -{ - os_event_set(cell->event); - cell->event_set = TRUE; -} - /*********************************************************************** Puts the cell event in reset state. */ static void sync_cell_event_reset( /*==================*/ - sync_cell_t* cell) /* in: array cell */ + ulint type, /* in: lock type mutex/rw_lock */ + void* object) /* in: the rw_lock/mutex object */ { - os_event_reset(cell->event); - cell->event_set = FALSE; + if (type == SYNC_MUTEX) { + os_event_reset(((mutex_t *) object)->event); + } else { + os_event_reset(((rw_lock_t *) object)->event); + } } /********************************************************************** @@ -346,14 +325,7 @@ sync_array_reserve_cell( if (cell->wait_object == NULL) { - /* Make sure the event is reset */ - if (cell->event_set) { - sync_cell_event_reset(cell); - } - - cell->reservation_time = time(NULL); - cell->thread = os_thread_get_curr_id(); - + cell->waiting = FALSE; cell->wait_object = object; if (type == SYNC_MUTEX) { @@ -363,7 +335,6 @@ sync_array_reserve_cell( } cell->request_type = type; - cell->waiting = FALSE; cell->file = file; cell->line = line; @@ -373,6 +344,13 @@ sync_array_reserve_cell( *index = i; sync_array_exit(arr); + + /* Make sure the event is reset */ + sync_cell_event_reset(type, object); + + cell->reservation_time = time(NULL); + + cell->thread = os_thread_get_curr_id(); return; } @@ -408,7 +386,12 @@ sync_array_wait_event( ut_a(!cell->waiting); ut_ad(os_thread_get_curr_id() == cell->thread); - event = cell->event; + if (cell->request_type == SYNC_MUTEX) { + event = ((mutex_t*) cell->wait_object)->event; + } else { + event = ((rw_lock_t*) cell->wait_object)->event; + } + cell->waiting = TRUE; #ifdef UNIV_SYNC_DEBUG @@ -510,10 +493,6 @@ sync_array_cell_print( if (!cell->waiting) { fputs("wait has ended\n", file); } - - if (cell->event_set) { - fputs("wait is ending\n", file); - } } #ifdef UNIV_SYNC_DEBUG @@ -623,7 +602,7 @@ sync_array_detect_deadlock( depth++; - if (cell->event_set || !cell->waiting) { + if (!cell->waiting) { return(FALSE); /* No deadlock here */ } @@ -802,6 +781,7 @@ sync_array_free_cell( ut_a(cell->wait_object != NULL); + cell->waiting = FALSE; cell->wait_object = NULL; ut_a(arr->n_reserved > 0); @@ -811,44 +791,17 @@ sync_array_free_cell( } /************************************************************************** -Looks for the cells in the wait array which refer to the wait object -specified, and sets their corresponding events to the signaled state. In this -way releases the threads waiting for the object to contend for the object. -It is possible that no such cell is found, in which case does nothing. */ +Increments the signalled count. */ void -sync_array_signal_object( -/*=====================*/ - sync_array_t* arr, /* in: wait array */ - void* object) /* in: wait object */ +sync_array_object_signalled( +/*========================*/ + sync_array_t* arr) /* in: wait array */ { - sync_cell_t* cell; - ulint count; - ulint i; - sync_array_enter(arr); arr->sg_count++; - i = 0; - count = 0; - - while (count < arr->n_reserved) { - - cell = sync_array_get_nth_cell(arr, i); - - if (cell->wait_object != NULL) { - - count++; - if (cell->wait_object == object) { - - sync_cell_event_set(cell); - } - } - - i++; - } - sync_array_exit(arr); } @@ -881,7 +834,17 @@ sync_arr_wake_threads_if_sema_free(void) if (sync_arr_cell_can_wake_up(cell)) { - sync_cell_event_set(cell); + if (cell->request_type == SYNC_MUTEX) { + mutex_t* mutex; + + mutex = cell->wait_object; + os_event_set(mutex->event); + } else { + rw_lock_t* lock; + + lock = cell->wait_object; + os_event_set(lock->event); + } } } @@ -911,7 +874,7 @@ sync_array_print_long_waits(void) cell = sync_array_get_nth_cell(sync_primary_wait_array, i); - if (cell->wait_object != NULL + if (cell->wait_object != NULL && cell->waiting && difftime(time(NULL), cell->reservation_time) > 240) { fputs("InnoDB: Warning: a long semaphore wait:\n", stderr); @@ -919,7 +882,7 @@ sync_array_print_long_waits(void) noticed = TRUE; } - if (cell->wait_object != NULL + if (cell->wait_object != NULL && cell->waiting && difftime(time(NULL), cell->reservation_time) > fatal_timeout) { fatal = TRUE; diff --git a/innobase/sync/sync0rw.c b/innobase/sync/sync0rw.c index 77757685208..384c2e6dfad 100644 --- a/innobase/sync/sync0rw.c +++ b/innobase/sync/sync0rw.c @@ -123,6 +123,7 @@ rw_lock_create_func( lock->last_x_file_name = "not yet reserved"; lock->last_s_line = 0; lock->last_x_line = 0; + lock->event = os_event_create(NULL); mutex_enter(&rw_lock_list_mutex); @@ -158,6 +159,7 @@ rw_lock_free( mutex_free(rw_lock_get_mutex(lock)); mutex_enter(&rw_lock_list_mutex); + os_event_free(lock->event); if (UT_LIST_GET_PREV(list, lock)) { ut_a(UT_LIST_GET_PREV(list, lock)->magic_n == RW_LOCK_MAGIC_N); diff --git a/innobase/sync/sync0sync.c b/innobase/sync/sync0sync.c index 86306e49cac..468789c120d 100644 --- a/innobase/sync/sync0sync.c +++ b/innobase/sync/sync0sync.c @@ -210,6 +210,7 @@ mutex_create_func( os_fast_mutex_init(&(mutex->os_fast_mutex)); mutex->lock_word = 0; #endif + mutex->event = os_event_create(NULL); mutex_set_waiters(mutex, 0); mutex->magic_n = MUTEX_MAGIC_N; #ifdef UNIV_SYNC_DEBUG @@ -275,6 +276,8 @@ mutex_free( mutex_exit(&mutex_list_mutex); } + os_event_free(mutex->event); + #if !defined(_WIN32) || !defined(UNIV_CAN_USE_X86_ASSEMBLER) os_fast_mutex_free(&(mutex->os_fast_mutex)); #endif @@ -498,8 +501,8 @@ mutex_signal_object( /* The memory order of resetting the waiters field and signaling the object is important. See LEMMA 1 above. */ - - sync_array_signal_object(sync_primary_wait_array, mutex); + os_event_set(mutex->event); + sync_array_object_signalled(sync_primary_wait_array); } #ifdef UNIV_SYNC_DEBUG @@ -1047,6 +1050,7 @@ sync_thread_add_level( ut_a(sync_thread_levels_g(array, SYNC_PURGE_SYS)); } else if (level == SYNC_TREE_NODE) { ut_a(sync_thread_levels_contain(array, SYNC_INDEX_TREE) + || sync_thread_levels_contain(array, SYNC_DICT_OPERATION) || sync_thread_levels_g(array, SYNC_TREE_NODE - 1)); } else if (level == SYNC_TREE_NODE_FROM_HASH) { ut_a(1); From c336960463f5eb771cac3103d00d5ccd3d4568f8 Mon Sep 17 00:00:00 2001 From: "rafal@quant.(none)" <> Date: Fri, 15 Dec 2006 11:32:41 +0100 Subject: [PATCH 002/336] BUG#21132 (Slave fails to reconnect on update_slave_list): The update_slave_list() call is a remainder from attempts to implement failsafe replication. This code is now obsolete and not maintained (see comments in rpl_failsafe.cc). Inspecting the code one can see that this function do not interferre with normal slave operation and thus can be safely removed. This will solve the issue reported in the bug (errors on slave reconnection). A related issue is to remove unneccessary reconnections done by slave. This is handled in the patch for BUG#20435. --- sql/slave.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/slave.cc b/sql/slave.cc index d0396444ace..a5d2e01b9ec 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -3526,7 +3526,7 @@ connected: on with life. */ thd->proc_info = "Registering slave on master"; - if (register_slave_on_master(mysql) || update_slave_list(mysql, mi)) + if (register_slave_on_master(mysql)) goto err; } From 1807f3a15642bbebbe141cf0a211d33a44635795 Mon Sep 17 00:00:00 2001 From: "mats@capulet.net" <> Date: Thu, 12 Apr 2007 09:47:45 +0200 Subject: [PATCH 003/336] Adding build file for Solaris on AMD64 --- BUILD/compile-solaris-amd64 | 55 +++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100755 BUILD/compile-solaris-amd64 diff --git a/BUILD/compile-solaris-amd64 b/BUILD/compile-solaris-amd64 new file mode 100755 index 00000000000..f128fb12973 --- /dev/null +++ b/BUILD/compile-solaris-amd64 @@ -0,0 +1,55 @@ +#!/usr/bin/bash + +function _find_mysql_root () ( + while [ "x$PWD" != "x/" ]; do + # Check if some directories are present + if [ -d BUILD -a -d sql -a -d mysys ]; then + echo "$PWD" + return 0 + fi + cd .. + done + return 1 +) + +make -k clean || true +/bin/rm -f */.deps/*.P config.cache + +path=`dirname $0` +. "$path/autorun.sh" + +warning_flags="-Wimplicit -Wreturn-type -Wswitch -Wtrigraphs -Wcomment -W -Wchar-subscripts -Wformat -Wparentheses -Wsign-compare -Wwrite-strings -Wunused" +compiler_flags="-g -O3 -fno-omit-frame-pointer" + +export CC CXX CFLAGS CXXFLAGS LDFLAGS LIBS +CC="gcc" +CXX="gcc" +CFLAGS="$warning_flags $compiler_flags" +CXXFLAGS="" +LDFLAGS="-O3 -g -static-libgcc" +LIBS=-lmtmalloc +root=$(_find_mysql_root) + +$root/configure \ + --prefix=/usr/local/mysql \ + --localstatedir=/usr/local/mysql/data \ + --libexecdir=/usr/local/mysql/bin \ + --with-extra-charsets=complex \ + --enable-thread-safe-client \ + --enable-local-infile \ + --with-zlib-dir=bundled \ + --with-big-tables \ + --with-readline \ + --with-archive-storage-engine \ + --with-named-curses=-lcurses \ + --with-big-tables \ + --with-innodb \ + --with-berkeley-db \ + --with-example-storage-engine \ + --with-blackhole-storage-engine \ + --with-ndbcluster \ + --with-federated-storage-engine \ + --with-csv-storage-engine \ + --with-ssl \ + --with-embedded-server \ + --disable-shared From 5270db37b28bcfa5cd94cfcaafb46599b3e3eb68 Mon Sep 17 00:00:00 2001 From: "jmiller/root@mysql.com/ndbqa01.mysql.com" <> Date: Tue, 17 Jul 2007 15:49:07 -0500 Subject: [PATCH 004/336] Many files: Added new test case for dropping column on the end of master table --- .../extra/rpl_tests/rpl_extraSlave_Col.test | 66 ++++++++++++++++++- mysql-test/r/rpl_extraCol_innodb.result | 60 +++++++++++++++++ mysql-test/r/rpl_extraCol_myisam.result | 60 +++++++++++++++++ mysql-test/r/rpl_ndb_extraCol.result | 60 +++++++++++++++++ 4 files changed, 244 insertions(+), 2 deletions(-) diff --git a/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test b/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test index abeef5f2903..36884c79973 100644 --- a/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test +++ b/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test @@ -10,7 +10,7 @@ ########### Clean up ################ --disable_warnings --disable_query_log -DROP TABLE IF EXISTS t1, t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16,t17; +DROP TABLE IF EXISTS t1, t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t14a,t15,t16,t17; --enable_query_log --enable_warnings @@ -653,6 +653,68 @@ sync_slave_with_master; --replace_column 7 CURRENT_TIMESTAMP SELECT * FROM t14 ORDER BY c1; +#################################################### +# - Alter Master drop column at end of table # +# Expect: column dropped # +#################################################### + +--echo *** Create t14a on slave *** +STOP SLAVE; +RESET SLAVE; +eval CREATE TABLE t14a (c1 INT KEY, c4 BLOB, c5 CHAR(5), + c6 INT DEFAULT '1', + c7 TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP + )ENGINE=$engine_type; + +--echo *** Create t14a on Master *** +connection master; +eval CREATE TABLE t14a (c1 INT PRIMARY KEY, c4 BLOB, c5 CHAR(5) + ) ENGINE=$engine_type; +RESET MASTER; + +--echo *** Start Slave *** +connection slave; +START SLAVE; + +--echo *** Master Data Insert *** +connection master; +set @b1 = 'b1b1b1b1'; +set @b1 = concat(@b1,@b1); +INSERT INTO t14a () VALUES(1,@b1,'Kyle'), + (2,@b1,'JOE'), + (3,@b1,'QA'); + +SELECT * FROM t14a ORDER BY c1; +--echo *** Select on Slave **** +sync_slave_with_master; +--replace_column 5 CURRENT_TIMESTAMP +SELECT * FROM t14a ORDER BY c1; +STOP SLAVE; +RESET SLAVE; + +--echo *** Master Drop c5 *** +connection master; +ALTER TABLE t14a DROP COLUMN c5; +RESET MASTER; + +--echo *** Start Slave *** +connection slave; +START SLAVE; + +--echo *** Master Data Insert *** +connection master; +set @b1 = 'b1b1b1b1'; +set @b1 = concat(@b1,@b1); + +INSERT INTO t14a () VALUES(4,@b1), + (5,@b1), + (6,@b1); +SELECT * FROM t14a ORDER BY c1; + +--echo *** Select on Slave **** +sync_slave_with_master; +--replace_column 5 CURRENT_TIMESTAMP +SELECT * FROM t14a ORDER BY c1; #################################################### # - Alter Master Dropping columns from the middle. # @@ -847,7 +909,7 @@ sync_slave_with_master; #### Clean Up #### --disable_warnings --disable_query_log -DROP TABLE IF EXISTS t1, t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16,t17; +DROP TABLE IF EXISTS t1, t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t14a,t15,t16,t17; --enable_query_log --enable_warnings diff --git a/mysql-test/r/rpl_extraCol_innodb.result b/mysql-test/r/rpl_extraCol_innodb.result index cfce12b594e..9f38a7116b8 100644 --- a/mysql-test/r/rpl_extraCol_innodb.result +++ b/mysql-test/r/rpl_extraCol_innodb.result @@ -548,6 +548,66 @@ c1 c2 c3 c4 c5 c6 c7 1 1.00 Replication Testing Extra Col b1b1b1b1b1b1b1b1 Kyle 1 CURRENT_TIMESTAMP 2 2.00 This Test Should work b1b1b1b1b1b1b1b1 JOE 1 CURRENT_TIMESTAMP 3 3.00 If is does not, I will open a bug b1b1b1b1b1b1b1b1 QA 1 CURRENT_TIMESTAMP +*** Create t14a on slave *** +STOP SLAVE; +RESET SLAVE; +CREATE TABLE t14a (c1 INT KEY, c4 BLOB, c5 CHAR(5), +c6 INT DEFAULT '1', +c7 TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP +)ENGINE='InnoDB'; +*** Create t14a on Master *** +CREATE TABLE t14a (c1 INT PRIMARY KEY, c4 BLOB, c5 CHAR(5) +) ENGINE='InnoDB'; +RESET MASTER; +*** Start Slave *** +START SLAVE; +*** Master Data Insert *** +set @b1 = 'b1b1b1b1'; +set @b1 = concat(@b1,@b1); +INSERT INTO t14a () VALUES(1,@b1,'Kyle'), +(2,@b1,'JOE'), +(3,@b1,'QA'); +SELECT * FROM t14a ORDER BY c1; +c1 c4 c5 +1 b1b1b1b1b1b1b1b1 Kyle +2 b1b1b1b1b1b1b1b1 JOE +3 b1b1b1b1b1b1b1b1 QA +*** Select on Slave **** +SELECT * FROM t14a ORDER BY c1; +c1 c4 c5 c6 c7 +1 b1b1b1b1b1b1b1b1 Kyle 1 CURRENT_TIMESTAMP +2 b1b1b1b1b1b1b1b1 JOE 1 CURRENT_TIMESTAMP +3 b1b1b1b1b1b1b1b1 QA 1 CURRENT_TIMESTAMP +STOP SLAVE; +RESET SLAVE; +*** Master Drop c5 *** +ALTER TABLE t14a DROP COLUMN c5; +RESET MASTER; +*** Start Slave *** +START SLAVE; +*** Master Data Insert *** +set @b1 = 'b1b1b1b1'; +set @b1 = concat(@b1,@b1); +INSERT INTO t14a () VALUES(4,@b1), +(5,@b1), +(6,@b1); +SELECT * FROM t14a ORDER BY c1; +c1 c4 +1 b1b1b1b1b1b1b1b1 +2 b1b1b1b1b1b1b1b1 +3 b1b1b1b1b1b1b1b1 +4 b1b1b1b1b1b1b1b1 +5 b1b1b1b1b1b1b1b1 +6 b1b1b1b1b1b1b1b1 +*** Select on Slave **** +SELECT * FROM t14a ORDER BY c1; +c1 c4 c5 c6 c7 +1 b1b1b1b1b1b1b1b1 Kyle 1 CURRENT_TIMESTAMP +2 b1b1b1b1b1b1b1b1 JOE 1 CURRENT_TIMESTAMP +3 b1b1b1b1b1b1b1b1 QA 1 CURRENT_TIMESTAMP +4 b1b1b1b1b1b1b1b1 NULL 1 CURRENT_TIMESTAMP +5 b1b1b1b1b1b1b1b1 NULL 1 CURRENT_TIMESTAMP +6 b1b1b1b1b1b1b1b1 NULL 1 CURRENT_TIMESTAMP *** connect to master and drop columns *** ALTER TABLE t14 DROP COLUMN c2; ALTER TABLE t14 DROP COLUMN c4; diff --git a/mysql-test/r/rpl_extraCol_myisam.result b/mysql-test/r/rpl_extraCol_myisam.result index b250911368c..f7b56c910e5 100644 --- a/mysql-test/r/rpl_extraCol_myisam.result +++ b/mysql-test/r/rpl_extraCol_myisam.result @@ -548,6 +548,66 @@ c1 c2 c3 c4 c5 c6 c7 1 1.00 Replication Testing Extra Col b1b1b1b1b1b1b1b1 Kyle 1 CURRENT_TIMESTAMP 2 2.00 This Test Should work b1b1b1b1b1b1b1b1 JOE 1 CURRENT_TIMESTAMP 3 3.00 If is does not, I will open a bug b1b1b1b1b1b1b1b1 QA 1 CURRENT_TIMESTAMP +*** Create t14a on slave *** +STOP SLAVE; +RESET SLAVE; +CREATE TABLE t14a (c1 INT KEY, c4 BLOB, c5 CHAR(5), +c6 INT DEFAULT '1', +c7 TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP +)ENGINE='MyISAM'; +*** Create t14a on Master *** +CREATE TABLE t14a (c1 INT PRIMARY KEY, c4 BLOB, c5 CHAR(5) +) ENGINE='MyISAM'; +RESET MASTER; +*** Start Slave *** +START SLAVE; +*** Master Data Insert *** +set @b1 = 'b1b1b1b1'; +set @b1 = concat(@b1,@b1); +INSERT INTO t14a () VALUES(1,@b1,'Kyle'), +(2,@b1,'JOE'), +(3,@b1,'QA'); +SELECT * FROM t14a ORDER BY c1; +c1 c4 c5 +1 b1b1b1b1b1b1b1b1 Kyle +2 b1b1b1b1b1b1b1b1 JOE +3 b1b1b1b1b1b1b1b1 QA +*** Select on Slave **** +SELECT * FROM t14a ORDER BY c1; +c1 c4 c5 c6 c7 +1 b1b1b1b1b1b1b1b1 Kyle 1 CURRENT_TIMESTAMP +2 b1b1b1b1b1b1b1b1 JOE 1 CURRENT_TIMESTAMP +3 b1b1b1b1b1b1b1b1 QA 1 CURRENT_TIMESTAMP +STOP SLAVE; +RESET SLAVE; +*** Master Drop c5 *** +ALTER TABLE t14a DROP COLUMN c5; +RESET MASTER; +*** Start Slave *** +START SLAVE; +*** Master Data Insert *** +set @b1 = 'b1b1b1b1'; +set @b1 = concat(@b1,@b1); +INSERT INTO t14a () VALUES(4,@b1), +(5,@b1), +(6,@b1); +SELECT * FROM t14a ORDER BY c1; +c1 c4 +1 b1b1b1b1b1b1b1b1 +2 b1b1b1b1b1b1b1b1 +3 b1b1b1b1b1b1b1b1 +4 b1b1b1b1b1b1b1b1 +5 b1b1b1b1b1b1b1b1 +6 b1b1b1b1b1b1b1b1 +*** Select on Slave **** +SELECT * FROM t14a ORDER BY c1; +c1 c4 c5 c6 c7 +1 b1b1b1b1b1b1b1b1 Kyle 1 CURRENT_TIMESTAMP +2 b1b1b1b1b1b1b1b1 JOE 1 CURRENT_TIMESTAMP +3 b1b1b1b1b1b1b1b1 QA 1 CURRENT_TIMESTAMP +4 b1b1b1b1b1b1b1b1 NULL 1 CURRENT_TIMESTAMP +5 b1b1b1b1b1b1b1b1 NULL 1 CURRENT_TIMESTAMP +6 b1b1b1b1b1b1b1b1 NULL 1 CURRENT_TIMESTAMP *** connect to master and drop columns *** ALTER TABLE t14 DROP COLUMN c2; ALTER TABLE t14 DROP COLUMN c4; diff --git a/mysql-test/r/rpl_ndb_extraCol.result b/mysql-test/r/rpl_ndb_extraCol.result index 5afc9c1db77..a4cb236a6b8 100644 --- a/mysql-test/r/rpl_ndb_extraCol.result +++ b/mysql-test/r/rpl_ndb_extraCol.result @@ -548,6 +548,66 @@ c1 c2 c3 c4 c5 c6 c7 1 1.00 Replication Testing Extra Col b1b1b1b1b1b1b1b1 Kyle NULL CURRENT_TIMESTAMP 2 2.00 This Test Should work b1b1b1b1b1b1b1b1 JOE NULL CURRENT_TIMESTAMP 3 3.00 If is does not, I will open a bug b1b1b1b1b1b1b1b1 QA NULL CURRENT_TIMESTAMP +*** Create t14a on slave *** +STOP SLAVE; +RESET SLAVE; +CREATE TABLE t14a (c1 INT KEY, c4 BLOB, c5 CHAR(5), +c6 INT DEFAULT '1', +c7 TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP +)ENGINE='NDB'; +*** Create t14a on Master *** +CREATE TABLE t14a (c1 INT PRIMARY KEY, c4 BLOB, c5 CHAR(5) +) ENGINE='NDB'; +RESET MASTER; +*** Start Slave *** +START SLAVE; +*** Master Data Insert *** +set @b1 = 'b1b1b1b1'; +set @b1 = concat(@b1,@b1); +INSERT INTO t14a () VALUES(1,@b1,'Kyle'), +(2,@b1,'JOE'), +(3,@b1,'QA'); +SELECT * FROM t14a ORDER BY c1; +c1 c4 c5 +1 b1b1b1b1b1b1b1b1 Kyle +2 b1b1b1b1b1b1b1b1 JOE +3 b1b1b1b1b1b1b1b1 QA +*** Select on Slave **** +SELECT * FROM t14a ORDER BY c1; +c1 c4 c5 c6 c7 +1 b1b1b1b1b1b1b1b1 Kyle NULL CURRENT_TIMESTAMP +2 b1b1b1b1b1b1b1b1 JOE NULL CURRENT_TIMESTAMP +3 b1b1b1b1b1b1b1b1 QA NULL CURRENT_TIMESTAMP +STOP SLAVE; +RESET SLAVE; +*** Master Drop c5 *** +ALTER TABLE t14a DROP COLUMN c5; +RESET MASTER; +*** Start Slave *** +START SLAVE; +*** Master Data Insert *** +set @b1 = 'b1b1b1b1'; +set @b1 = concat(@b1,@b1); +INSERT INTO t14a () VALUES(4,@b1), +(5,@b1), +(6,@b1); +SELECT * FROM t14a ORDER BY c1; +c1 c4 +1 b1b1b1b1b1b1b1b1 +2 b1b1b1b1b1b1b1b1 +3 b1b1b1b1b1b1b1b1 +4 b1b1b1b1b1b1b1b1 +5 b1b1b1b1b1b1b1b1 +6 b1b1b1b1b1b1b1b1 +*** Select on Slave **** +SELECT * FROM t14a ORDER BY c1; +c1 c4 c5 c6 c7 +1 b1b1b1b1b1b1b1b1 Kyle NULL CURRENT_TIMESTAMP +2 b1b1b1b1b1b1b1b1 JOE NULL CURRENT_TIMESTAMP +3 b1b1b1b1b1b1b1b1 QA NULL CURRENT_TIMESTAMP +4 b1b1b1b1b1b1b1b1 NULL NULL CURRENT_TIMESTAMP +5 b1b1b1b1b1b1b1b1 NULL NULL CURRENT_TIMESTAMP +6 b1b1b1b1b1b1b1b1 NULL NULL CURRENT_TIMESTAMP *** connect to master and drop columns *** ALTER TABLE t14 DROP COLUMN c2; ALTER TABLE t14 DROP COLUMN c4; From 76d61416ef9035a7eb0ef1d84df515b4cf4bccb1 Mon Sep 17 00:00:00 2001 From: "jmiller/ndbdev@mysql.com/ndb08.mysql.com" <> Date: Fri, 17 Aug 2007 19:51:25 +0200 Subject: [PATCH 005/336] rpl_packet.test: Removed sleep from test per lars request --- mysql-test/suite/rpl/t/rpl_packet.test | 1 - 1 file changed, 1 deletion(-) diff --git a/mysql-test/suite/rpl/t/rpl_packet.test b/mysql-test/suite/rpl/t/rpl_packet.test index 316278cb75d..c3987f7ee15 100644 --- a/mysql-test/suite/rpl/t/rpl_packet.test +++ b/mysql-test/suite/rpl/t/rpl_packet.test @@ -67,7 +67,6 @@ INSERT INTO `t1`(`f1`) VALUES ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa # The slave I/O thread must stop after trying to read the above event connection slave; -sleep 2; --source include/wait_for_slave_io_to_stop.inc SHOW STATUS LIKE 'Slave_running'; From 8a81bd47494e4e259e6ed386d7aac55107595caa Mon Sep 17 00:00:00 2001 From: "skozlov/ksm@mysql.com/virtop.localdomain" <> Date: Mon, 20 Aug 2007 12:31:21 +0400 Subject: [PATCH 006/336] rpl.rpl_innodb_mixed_dml enabled --- mysql-test/suite/rpl/t/disabled.def | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/suite/rpl/t/disabled.def b/mysql-test/suite/rpl/t/disabled.def index d1b636ad9a2..34a8d6988a9 100644 --- a/mysql-test/suite/rpl/t/disabled.def +++ b/mysql-test/suite/rpl/t/disabled.def @@ -12,7 +12,7 @@ rpl_ddl : BUG#26418 2007-03-01 mleich Slave out of sync after CREATE/DROP TEMPORARY TABLE + ROLLBACK on master #rpl_innodb_mixed_ddl : Bug #29363 rpl.rpl_innodb_mixed_* test failures -rpl_innodb_mixed_dml : Bug #29363 rpl.rpl_innodb_mixed_* test failures +#rpl_innodb_mixed_dml : Bug #29363 rpl.rpl_innodb_mixed_* test failures rpl_invoked_features : BUG#29020 2007-06-21 Lars Non-deterministic test case rpl_auto_increment_11932 : Bug#29809 2007-07-16 ingo Slave SQL errors in warnings file rpl_stm_extraColmaster_ndb : WL#3915 : Statement-based replication not supported in ndb. Enable test when supported. From cb6375eda1981521c49feda6dca0fc2b4871f514 Mon Sep 17 00:00:00 2001 From: "skozlov/ksm@mysql.com/virtop.localdomain" <> Date: Mon, 20 Aug 2007 13:24:37 +0400 Subject: [PATCH 007/336] Bug#29363 --- mysql-test/suite/rpl/include/rpl_mixed_dml.inc | 4 ++-- mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mysql-test/suite/rpl/include/rpl_mixed_dml.inc b/mysql-test/suite/rpl/include/rpl_mixed_dml.inc index 1accf40160a..96dfdbed541 100644 --- a/mysql-test/suite/rpl/include/rpl_mixed_dml.inc +++ b/mysql-test/suite/rpl/include/rpl_mixed_dml.inc @@ -328,7 +328,7 @@ DROP VIEW v2; --echo --echo ******************** SHOW BINLOG EVENTS ******************** --replace_column 2 # 5 # ---replace_regex /Server ver: .+/Server ver: #/ /table_id: [0-9]+/table_id: #/ /COMMIT.+xid=[0-9]+.+/#/ +--replace_regex /Server ver: .+/Server ver: #/ /table_id: [0-9]+/table_id: #/ /COMMIT.+xid=[0-9]+.+/#/ /file_id=[0-9]+/file_id=#/ /block_len=[0-9]+/block_len=#/ show binlog events from 1; sync_slave_with_master; # as we're using UUID we don't SELECT but use "diff" like in rpl_row_UUID @@ -344,4 +344,4 @@ sync_slave_with_master; # will be created. You will need to go to the mysql-test dir and diff # the files your self to see what is not matching ---exec diff $MYSQLTEST_VARDIR/tmp/rpl_switch_stm_row_mixed_master.sql $MYSQLTEST_VARDIR/tmp/rpl_switch_stm_row_mixed_slave.sql; +--exec diff $MYSQLTEST_VARDIR/tmp/rpl_switch_stm_row_mixed_master.sql $MYSQLTEST_VARDIR/tmp/rpl_switch_stm_row_mixed_slave.sql diff --git a/mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result b/mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result index 462400e12bb..19c5299df25 100644 --- a/mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result +++ b/mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result @@ -867,8 +867,8 @@ master-bin.000001 # Query 1 # use `test_rpl`; DELETE FROM t1 master-bin.000001 # Xid 1 # # master-bin.000001 # Query 1 # use `test_rpl`; DELETE FROM t2 master-bin.000001 # Xid 1 # # -master-bin.000001 # Begin_load_query 1 # ;file_id=1;block_len=30 -master-bin.000001 # Execute_load_query 1 # use `test_rpl`; LOAD DATA INFILE '../tmp/rpl_mixed.dat' INTO TABLE t1 FIELDS TERMINATED BY '|' ;file_id=1 +master-bin.000001 # Begin_load_query 1 # ;file_id=#;block_len=# +master-bin.000001 # Execute_load_query 1 # use `test_rpl`; LOAD DATA INFILE '../tmp/rpl_mixed.dat' INTO TABLE t1 FIELDS TERMINATED BY '|' ;file_id=# master-bin.000001 # Xid 1 # # master-bin.000001 # Query 1 # use `test_rpl`; DELETE FROM t1 master-bin.000001 # Xid 1 # # From 77998c30c2c697440ed3a9eb93abe7a4ed26f55d Mon Sep 17 00:00:00 2001 From: "aelkin/elkin@dsl-hkibras-fe38f900-157.dhcp.inet.fi" <> Date: Tue, 21 Aug 2007 15:16:55 +0300 Subject: [PATCH 008/336] Bug #23333 stored function + non-transac table + transac table = breaks stmt-based binlog Binlogging of the statement with a side effect like a modified non-trans table did not happen. The artifact involved all binloggable dml queries. Fixed with changing the binlogging conditions all over the code to exploit thd->transaction.stmt.modified_non_trans_table introduced by the patch for bug@27417. Multi-delete case has own specific addressed by another bug@29136. Multi-update case has been addressed by bug#27716 and patch and will need merging. --- mysql-test/r/mix_innodb_myisam_binlog.result | 73 ++++++++++- mysql-test/r/sp_trans_log.result | 5 +- mysql-test/t/mix_innodb_myisam_binlog.test | 120 ++++++++++++++++++- mysql-test/t/sp_trans_log.test | 3 +- sql/sql_delete.cc | 6 +- sql/sql_insert.cc | 78 ++++++------ sql/sql_load.cc | 2 +- sql/sql_update.cc | 2 +- 8 files changed, 238 insertions(+), 51 deletions(-) diff --git a/mysql-test/r/mix_innodb_myisam_binlog.result b/mysql-test/r/mix_innodb_myisam_binlog.result index 5777bd890b2..181f4c67254 100644 --- a/mysql-test/r/mix_innodb_myisam_binlog.result +++ b/mysql-test/r/mix_innodb_myisam_binlog.result @@ -365,7 +365,7 @@ insert into t2 values (bug27417(2)); ERROR 23000: Duplicate entry '2' for key 1 show master status; File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 98 +master-bin.000001 196 /* only (!) with fixes for #23333 will show there is the query */; select count(*) from t1 /* must be 3 */; count(*) @@ -390,6 +390,75 @@ affected rows: 0 select count(*) from t1 /* must be 7 */; count(*) 7 -drop function bug27417; drop table t1,t2; +CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; +CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; +CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); +insert into t2 values (1); +reset master; +insert into t2 values (bug27417(1)); +ERROR 23000: Duplicate entry '1' for key 1 +show master status /* the offset must denote there is the query */; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 267 +select count(*) from t1 /* must be 1 */; +count(*) +1 +delete from t1; +delete from t2; +insert into t2 values (2); +reset master; +insert into t2 select bug27417(1) union select bug27417(2); +ERROR 23000: Duplicate entry '2' for key 1 +show master status /* the offset must denote there is the query */; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 290 +select count(*) from t1 /* must be 2 */; +count(*) +2 +delete from t1; +insert into t3 values (1,1),(2,3),(3,4); +reset master; +update t3 set b=b+bug27417(1); +ERROR 23000: Duplicate entry '4' for key 2 +show master status /* the offset must denote there is the query */; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 190 +select count(*) from t1 /* must be 2 */; +count(*) +2 +delete from t1; +delete from t2; +delete from t3; +insert into t2 values (1); +insert into t3 values (1,1); +create trigger trg_del before delete on t2 for each row +insert into t3 values (bug27417(1), 2); +reset master; +delete from t2; +ERROR 23000: Duplicate entry '1' for key 1 +show master status /* the offset must denote there is the query */; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 246 +select count(*) from t1 /* must be 1 */; +count(*) +1 +delete from t1; +create table t4 (a int default 0, b int primary key) engine=innodb; +insert into t4 values (0, 17); +reset master; +load data infile '../std_data_ln/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2); +ERROR 23000: Duplicate entry '17' for key 1 +select * from t4; +a b +0 17 +select count(*) from t1 /* must be 2 */; +count(*) +2 +show master status /* the offset must denote there is the query */; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 376 +drop trigger trg_del; +drop table t1,t2,t3; +drop function bug27417; end of tests diff --git a/mysql-test/r/sp_trans_log.result b/mysql-test/r/sp_trans_log.result index 96e6f76b23c..14a8ecf6a37 100644 --- a/mysql-test/r/sp_trans_log.result +++ b/mysql-test/r/sp_trans_log.result @@ -12,8 +12,9 @@ end| reset master| insert into t2 values (bug23333(),1)| ERROR 23000: Duplicate entry '1' for key 1 -show binlog events from 98 /* with fixes for #23333 will show there is the query */| -Log_name Pos Event_type Server_id End_log_pos Info +show master status /* the offset must denote there is the query */| +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 284 select count(*),@a from t1 /* must be 1,1 */| count(*) @a 1 1 diff --git a/mysql-test/t/mix_innodb_myisam_binlog.test b/mysql-test/t/mix_innodb_myisam_binlog.test index f9d7235ff84..e5fec37cc23 100644 --- a/mysql-test/t/mix_innodb_myisam_binlog.test +++ b/mysql-test/t/mix_innodb_myisam_binlog.test @@ -380,8 +380,126 @@ delete t2 from t2 where t2.a=bug27417(100) /* must not affect t2 */; --disable_info select count(*) from t1 /* must be 7 */; -drop function bug27417; +# function bug27417 remains for the following testing of bug#23333 drop table t1,t2; +# +# Bug#23333 using the patch (and the test) for bug#27471 +# throughout the bug tests +# t1 - non-trans side effects gatherer; +# t2 - transactional table; +# +CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; +CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; +CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); + + +# +# INSERT +# + +# prepare + + insert into t2 values (1); + reset master; + +# execute + + --error ER_DUP_ENTRY + insert into t2 values (bug27417(1)); + +# check + + show master status /* the offset must denote there is the query */; + select count(*) from t1 /* must be 1 */; + +# +# INSERT SELECT +# + +# prepare + delete from t1; + delete from t2; + insert into t2 values (2); + reset master; + +# execute + + --error ER_DUP_ENTRY + insert into t2 select bug27417(1) union select bug27417(2); + +# check + + show master status /* the offset must denote there is the query */; + select count(*) from t1 /* must be 2 */; + +# +# UPDATE (multi-update see bug#27716) +# + +# prepare + delete from t1; + insert into t3 values (1,1),(2,3),(3,4); + reset master; + +# execute + --error ER_DUP_ENTRY + update t3 set b=b+bug27417(1); + +# check + show master status /* the offset must denote there is the query */; + select count(*) from t1 /* must be 2 */; + + +# +# DELETE (for multi-delete see Bug #29136) +# + +# prepare + delete from t1; + delete from t2; + delete from t3; + insert into t2 values (1); + insert into t3 values (1,1); + create trigger trg_del before delete on t2 for each row + insert into t3 values (bug27417(1), 2); + reset master; + +# execute + --error ER_DUP_ENTRY + delete from t2; +# check + show master status /* the offset must denote there is the query */; + select count(*) from t1 /* must be 1 */; + + +# +# LOAD DATA +# + +# prepare + delete from t1; + create table t4 (a int default 0, b int primary key) engine=innodb; + insert into t4 values (0, 17); + reset master; + +# execute + --error ER_DUP_ENTRY + load data infile '../std_data_ln/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2); +# check + select * from t4; + select count(*) from t1 /* must be 2 */; + show master status /* the offset must denote there is the query */; + +# +# bug#23333 cleanup +# + + +drop trigger trg_del; +drop table t1,t2,t3; +drop function bug27417; + + --echo end of tests diff --git a/mysql-test/t/sp_trans_log.test b/mysql-test/t/sp_trans_log.test index 3e440b3ccc1..508c730a1cf 100644 --- a/mysql-test/t/sp_trans_log.test +++ b/mysql-test/t/sp_trans_log.test @@ -26,8 +26,7 @@ end| reset master| --error ER_DUP_ENTRY insert into t2 values (bug23333(),1)| ---replace_column 2 # 5 # 6 # -show binlog events from 98 /* with fixes for #23333 will show there is the query */| +show master status /* the offset must denote there is the query */| select count(*),@a from t1 /* must be 1,1 */| drop table t1, t2| diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 56edfa6c5b2..7555219f5d8 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -319,7 +319,7 @@ cleanup: thd->transaction.stmt.modified_non_trans_table= TRUE; /* See similar binlogging code in sql_update.cc, for comments */ - if ((error < 0) || (deleted && !transactional_table)) + if ((error < 0) || thd->transaction.stmt.modified_non_trans_table) { if (mysql_bin_log.is_open()) { @@ -817,7 +817,8 @@ bool multi_delete::send_eof() { query_cache_invalidate3(thd, delete_tables, 1); } - if ((local_error == 0) || (deleted && normal_tables)) + DBUG_ASSERT(!normal_tables || !deleted || thd->transaction.stmt.modified_non_trans_table); + if ((local_error == 0) || thd->transaction.stmt.modified_non_trans_table) { if (mysql_bin_log.is_open()) { @@ -831,7 +832,6 @@ bool multi_delete::send_eof() if (thd->transaction.stmt.modified_non_trans_table) thd->transaction.all.modified_non_trans_table= TRUE; } - DBUG_ASSERT(!normal_tables || !deleted || thd->transaction.stmt.modified_non_trans_table); /* Commit or rollback the current SQL statement */ if (transactional_tables) diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index bd21d929291..a2fd71ba240 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -866,8 +866,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, transactional_table= table->file->has_transactions(); - if ((changed= (info.copied || info.deleted || info.updated)) || - was_insert_delayed) + if ((changed= (info.copied || info.deleted || info.updated))) { /* Invalidate the table in the query cache if something changed. @@ -876,46 +875,47 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, */ if (changed) query_cache_invalidate3(thd, table_list, 1); - if (error <= 0 || !transactional_table) + } + if (changed && error <= 0 || thd->transaction.stmt.modified_non_trans_table + || was_insert_delayed) + { + if (mysql_bin_log.is_open()) { - if (mysql_bin_log.is_open()) + if (error <= 0) { - if (error <= 0) - { - /* - [Guilhem wrote] Temporary errors may have filled - thd->net.last_error/errno. For example if there has - been a disk full error when writing the row, and it was - MyISAM, then thd->net.last_error/errno will be set to - "disk full"... and the my_pwrite() will wait until free - space appears, and so when it finishes then the - write_row() was entirely successful - */ - /* todo: consider removing */ - thd->clear_error(); - } - /* bug#22725: - - A query which per-row-loop can not be interrupted with - KILLED, like INSERT, and that does not invoke stored - routines can be binlogged with neglecting the KILLED error. - - If there was no error (error == zero) until after the end of - inserting loop the KILLED flag that appeared later can be - disregarded since previously possible invocation of stored - routines did not result in any error due to the KILLED. In - such case the flag is ignored for constructing binlog event. + /* + [Guilhem wrote] Temporary errors may have filled + thd->net.last_error/errno. For example if there has + been a disk full error when writing the row, and it was + MyISAM, then thd->net.last_error/errno will be set to + "disk full"... and the my_pwrite() will wait until free + space appears, and so when it finishes then the + write_row() was entirely successful */ - Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_table, FALSE, - (error>0) ? thd->killed : THD::NOT_KILLED); - DBUG_ASSERT(thd->killed != THD::KILL_BAD_DATA || error > 0); - if (mysql_bin_log.write(&qinfo) && transactional_table) - error=1; + /* todo: consider removing */ + thd->clear_error(); } - if (thd->transaction.stmt.modified_non_trans_table) - thd->transaction.all.modified_non_trans_table= TRUE; + /* bug#22725: + + A query which per-row-loop can not be interrupted with + KILLED, like INSERT, and that does not invoke stored + routines can be binlogged with neglecting the KILLED error. + + If there was no error (error == zero) until after the end of + inserting loop the KILLED flag that appeared later can be + disregarded since previously possible invocation of stored + routines did not result in any error due to the KILLED. In + such case the flag is ignored for constructing binlog event. + */ + Query_log_event qinfo(thd, thd->query, thd->query_length, + transactional_table, FALSE, + (error>0) ? thd->killed : THD::NOT_KILLED); + DBUG_ASSERT(thd->killed != THD::KILL_BAD_DATA || error > 0); + if (mysql_bin_log.write(&qinfo) && transactional_table) + error=1; } + if (thd->transaction.stmt.modified_non_trans_table) + thd->transaction.all.modified_non_trans_table= TRUE; } DBUG_ASSERT(transactional_table || !changed || thd->transaction.stmt.modified_non_trans_table); @@ -3001,6 +3001,7 @@ void select_insert::abort() */ DBUG_VOID_RETURN; } + changed= (info.copied || info.deleted || info.updated); transactional_table= table->file->has_transactions(); if (!thd->prelocked_mode) table->file->end_bulk_insert(); @@ -3010,8 +3011,7 @@ void select_insert::abort() error while inserting into a MyISAM table) we must write to the binlog (and the error code will make the slave stop). */ - if ((changed= info.copied || info.deleted || info.updated) && - !transactional_table) + if (thd->transaction.stmt.modified_non_trans_table) { if (last_insert_id) thd->insert_id(last_insert_id); // For binary log diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 55cbbf1c540..0dc02ac4a68 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -444,7 +444,7 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, /* If the file was not empty, wrote_create_file is true */ if (lf_info.wrote_create_file) { - if ((info.copied || info.deleted) && !transactional_table) + if (thd->transaction.stmt.modified_non_trans_table) write_execute_load_query_log_event(thd, handle_duplicates, ignore, transactional_table); else diff --git a/sql/sql_update.cc b/sql/sql_update.cc index c78e246f518..3f38ad8b33c 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -580,7 +580,7 @@ int mysql_update(THD *thd, Sometimes we want to binlog even if we updated no rows, in case user used it to be sure master and slave are in same state. */ - if ((error < 0) || (updated && !transactional_table)) + if ((error < 0) || thd->transaction.stmt.modified_non_trans_table) { if (mysql_bin_log.is_open()) { From 81be50576fe6e224327a60aa5047904576d77778 Mon Sep 17 00:00:00 2001 From: "aelkin/elkin@dsl-hkibras-fe38f900-157.dhcp.inet.fi" <> Date: Wed, 22 Aug 2007 10:40:38 +0300 Subject: [PATCH 009/336] bug#27417 refining of cleanup of the tests. --- mysql-test/r/mix_innodb_myisam_binlog.result | 2 +- mysql-test/t/mix_innodb_myisam_binlog.test | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/mix_innodb_myisam_binlog.result b/mysql-test/r/mix_innodb_myisam_binlog.result index 181f4c67254..5d5726c9689 100644 --- a/mysql-test/r/mix_innodb_myisam_binlog.result +++ b/mysql-test/r/mix_innodb_myisam_binlog.result @@ -459,6 +459,6 @@ show master status /* the offset must denote there is the query */; File Position Binlog_Do_DB Binlog_Ignore_DB master-bin.000001 376 drop trigger trg_del; -drop table t1,t2,t3; +drop table t1,t2,t3,t4; drop function bug27417; end of tests diff --git a/mysql-test/t/mix_innodb_myisam_binlog.test b/mysql-test/t/mix_innodb_myisam_binlog.test index e5fec37cc23..e1740bda03e 100644 --- a/mysql-test/t/mix_innodb_myisam_binlog.test +++ b/mysql-test/t/mix_innodb_myisam_binlog.test @@ -497,7 +497,7 @@ CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); drop trigger trg_del; -drop table t1,t2,t3; +drop table t1,t2,t3,t4; drop function bug27417; From d4192c14ad38cec97cd548f3056ed7bb78b92e31 Mon Sep 17 00:00:00 2001 From: "aelkin/elkin@dsl-hkibras-fe38f900-157.dhcp.inet.fi" <> Date: Wed, 22 Aug 2007 15:43:16 +0300 Subject: [PATCH 010/336] bug#23333 fixing the test due a to different offsets in binlog with ps-protocol (a possible bug to be reported) --- mysql-test/r/sp_trans_log.result | 7 ++++--- mysql-test/t/sp_trans_log.test | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/sp_trans_log.result b/mysql-test/r/sp_trans_log.result index 14a8ecf6a37..9b644798079 100644 --- a/mysql-test/r/sp_trans_log.result +++ b/mysql-test/r/sp_trans_log.result @@ -12,9 +12,10 @@ end| reset master| insert into t2 values (bug23333(),1)| ERROR 23000: Duplicate entry '1' for key 1 -show master status /* the offset must denote there is the query */| -File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 284 +show binlog events from 98 /* with fixes for #23333 will show there are 2 queries */| +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query 1 # # +master-bin.000001 # Query 1 # # select count(*),@a from t1 /* must be 1,1 */| count(*) @a 1 1 diff --git a/mysql-test/t/sp_trans_log.test b/mysql-test/t/sp_trans_log.test index 508c730a1cf..93605722f6b 100644 --- a/mysql-test/t/sp_trans_log.test +++ b/mysql-test/t/sp_trans_log.test @@ -26,7 +26,8 @@ end| reset master| --error ER_DUP_ENTRY insert into t2 values (bug23333(),1)| -show master status /* the offset must denote there is the query */| +--replace_column 2 # 5 # 6 # +show binlog events from 98 /* with fixes for #23333 will show there are 2 queries */| select count(*),@a from t1 /* must be 1,1 */| drop table t1, t2| From 4581efe9314b602e510f25d19788e31924d46788 Mon Sep 17 00:00:00 2001 From: "rafal@quant.(none)" <> Date: Mon, 27 Aug 2007 16:17:17 +0200 Subject: [PATCH 011/336] Post merge fixes. --- sql/log_event.cc | 41 +++++++++++++++++++++++------------------ sql/log_event.h | 24 ++++++++++++------------ sql/log_event_old.cc | 24 ++++++++++++------------ sql/log_event_old.h | 16 ++++++++-------- sql/sql_yacc.yy | 13 +------------ 5 files changed, 56 insertions(+), 62 deletions(-) diff --git a/sql/log_event.cc b/sql/log_event.cc index 2142aa0b54e..b77452d1af4 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -5653,9 +5653,10 @@ Rows_log_event::Rows_log_event(THD *thd_arg, TABLE *tbl_arg, ulong tid, m_table(tbl_arg), m_table_id(tid), m_width(tbl_arg ? tbl_arg->s->fields : 1), - m_rows_buf(0), m_rows_cur(0), m_rows_end(0), - m_curr_row(NULL), m_curr_row_end(NULL), - m_flags(0), m_key(NULL) + m_rows_buf(0), m_rows_cur(0), m_rows_end(0), m_flags(0) +#ifdef HAVE_REPLICATION + ,m_key(NULL), m_curr_row(NULL), m_curr_row_end(NULL) +#endif { /* We allow a special form of dummy event when the table, and cols @@ -5697,10 +5698,13 @@ Rows_log_event::Rows_log_event(const char *buf, uint event_len, *description_event) : Log_event(buf, description_event), m_row_count(0), +#ifndef MYSQL_CLIENT m_table(NULL), - m_rows_buf(0), m_rows_cur(0), m_rows_end(0), - m_curr_row(NULL), m_curr_row_end(NULL), - m_key(NULL) +#endif + m_rows_buf(0), m_rows_cur(0), m_rows_end(0) +#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) + ,m_key(NULL), m_curr_row(NULL), m_curr_row_end(NULL) +#endif { DBUG_ENTER("Rows_log_event::Rows_log_event(const char*,...)"); uint8 const common_header_len= description_event->common_header_len; @@ -5789,7 +5793,9 @@ Rows_log_event::Rows_log_event(const char *buf, uint event_len, m_rows_buf= (uchar*) my_malloc(data_size, MYF(MY_WME)); if (likely((bool)m_rows_buf)) { +#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) m_curr_row= m_rows_buf; +#endif m_rows_end= m_rows_buf + data_size; m_rows_cur= m_rows_end; memcpy(m_rows_buf, ptr_rows_data, data_size); @@ -6055,7 +6061,7 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) TABLE* table= - m_table= const_cast(rli)->m_table_map.get_table(m_table_id); + m_table= const_cast(rli)->m_table_map.get_table(m_table_id); if (table) { @@ -6100,7 +6106,7 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) inside a statement and halting abruptly might cause problems when restarting. */ - const_cast(rli)->set_flag(RELAY_LOG_INFO::IN_STMT); + const_cast(rli)->set_flag(Relay_log_info::IN_STMT); if ( m_width == table->s->fields && bitmap_is_set_all(&m_cols)) set_flags(COMPLETE_ROWS_F); @@ -6187,8 +6193,8 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) } // if (table) /* - We need to delay this clear until the table def stored in m_table_def is no - longer needed. It is used in unpack_current_row(). + We need to delay this clear until here bacause unpack_current_row() uses + master-side table definitions stored in rli. */ if (rli->tables_to_lock && get_flags(STMT_END_F)) const_cast(rli)->clear_tables_to_lock(); @@ -7136,7 +7142,7 @@ is_duplicate_key_error(int errcode) */ int -Rows_log_event::write_row(const RELAY_LOG_INFO *const rli, +Rows_log_event::write_row(const Relay_log_info *const rli, const bool overwrite) { DBUG_ENTER("write_row"); @@ -7323,7 +7329,7 @@ Rows_log_event::write_row(const RELAY_LOG_INFO *const rli, #endif int -Write_rows_log_event::do_exec_row(const RELAY_LOG_INFO *const rli) +Write_rows_log_event::do_exec_row(const Relay_log_info *const rli) { DBUG_ASSERT(m_table != NULL); int error= write_row(rli, TRUE /* overwrite */); @@ -7453,7 +7459,7 @@ record_compare_exit: @c position() and @c rnd_pos() will be used. */ -int Rows_log_event::find_row(const RELAY_LOG_INFO *rli) +int Rows_log_event::find_row(const Relay_log_info *rli) { DBUG_ENTER("find_row"); @@ -7505,7 +7511,7 @@ int Rows_log_event::find_row(const RELAY_LOG_INFO *rli) DBUG_RETURN(error); } - // We can't use pisition() - try other methods. + // We can't use position() - try other methods. /* We need to retrieve all fields @@ -7721,8 +7727,7 @@ Delete_rows_log_event::do_before_row_operations(const Slave_reporting_capability m_table->s->primary_key < MAX_KEY) { /* - We don't need to allocate any memory for m_after_image and - m_key since they are not used. + We don't need to allocate any memory for m_key since it is not used. */ return 0; } @@ -7749,7 +7754,7 @@ Delete_rows_log_event::do_after_row_operations(const Slave_reporting_capability return error; } -int Delete_rows_log_event::do_exec_row(const RELAY_LOG_INFO *const rli) +int Delete_rows_log_event::do_exec_row(const Relay_log_info *const rli) { int error; DBUG_ASSERT(m_table != NULL); @@ -7873,7 +7878,7 @@ Update_rows_log_event::do_after_row_operations(const Slave_reporting_capability } int -Update_rows_log_event::do_exec_row(const RELAY_LOG_INFO *const rli) +Update_rows_log_event::do_exec_row(const Relay_log_info *const rli) { DBUG_ASSERT(m_table != NULL); diff --git a/sql/log_event.h b/sql/log_event.h index 0ec98561ae0..5c6a52fd9db 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -829,7 +829,7 @@ public: @see do_apply_event */ - int apply_event(RELAY_LOG_INFO const *rli) + int apply_event(Relay_log_info const *rli) { return do_apply_event(rli); } @@ -2291,20 +2291,20 @@ protected: uchar *m_rows_cur; /* One-after the end of the data */ uchar *m_rows_end; /* One-after the end of the allocated space */ - const uchar *m_curr_row; /* Start of the row being processed */ - const uchar *m_curr_row_end; /* One-after the end of the current row */ - flag_set m_flags; /* Flags for row-level events */ - uchar *m_key; /* Buffer to keep key value during searches */ /* helper functions */ #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) - int find_row(const RELAY_LOG_INFO *const); - int write_row(const RELAY_LOG_INFO *const, const bool); + const uchar *m_curr_row; /* Start of the row being processed */ + const uchar *m_curr_row_end; /* One-after the end of the current row */ + uchar *m_key; /* Buffer to keep key value during searches */ + + int find_row(const Relay_log_info *const); + int write_row(const Relay_log_info *const, const bool); // Unpack the current row into m_table->record[0] - int unpack_current_row(const RELAY_LOG_INFO *const rli) + int unpack_current_row(const Relay_log_info *const rli) { DBUG_ASSERT(m_table); return ::unpack_row(rli, m_table, m_width, m_curr_row, &m_cols, @@ -2368,7 +2368,7 @@ private: 0 if execution succeeded, 1 if execution failed. */ - virtual int do_exec_row(const RELAY_LOG_INFO *const rli) = 0; + virtual int do_exec_row(const Relay_log_info *const rli) = 0; #endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */ friend class Old_rows_log_event; @@ -2424,7 +2424,7 @@ private: #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) virtual int do_before_row_operations(const Slave_reporting_capability *const); virtual int do_after_row_operations(const Slave_reporting_capability *const,int); - virtual int do_exec_row(const RELAY_LOG_INFO *const); + virtual int do_exec_row(const Relay_log_info *const); #endif }; @@ -2498,7 +2498,7 @@ protected: #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) virtual int do_before_row_operations(const Slave_reporting_capability *const); virtual int do_after_row_operations(const Slave_reporting_capability *const,int); - virtual int do_exec_row(const RELAY_LOG_INFO *const); + virtual int do_exec_row(const Relay_log_info *const); #endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */ }; @@ -2563,7 +2563,7 @@ protected: #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) virtual int do_before_row_operations(const Slave_reporting_capability *const); virtual int do_after_row_operations(const Slave_reporting_capability *const,int); - virtual int do_exec_row(const RELAY_LOG_INFO *const); + virtual int do_exec_row(const Relay_log_info *const); #endif }; diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc index 420df67dc54..949179386ea 100644 --- a/sql/log_event_old.cc +++ b/sql/log_event_old.cc @@ -11,7 +11,7 @@ // Old implementation of do_apply_event() int -Old_rows_log_event::do_apply_event(Rows_log_event *ev, const RELAY_LOG_INFO *rli) +Old_rows_log_event::do_apply_event(Rows_log_event *ev, const Relay_log_info *rli) { DBUG_ENTER("Rows_log_event::do_apply_event(st_relay_log_info*)"); int error= 0; @@ -32,7 +32,7 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const RELAY_LOG_INFO *rli */ DBUG_ASSERT(ev->get_flags(Rows_log_event::STMT_END_F)); - const_cast(rli)->clear_tables_to_lock(); + const_cast(rli)->clear_tables_to_lock(); close_thread_tables(thd); thd->clear_error(); DBUG_RETURN(0); @@ -88,7 +88,7 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const RELAY_LOG_INFO *rli "Error in %s event: when locking tables", ev->get_type_str()); } - const_cast(rli)->clear_tables_to_lock(); + const_cast(rli)->clear_tables_to_lock(); DBUG_RETURN(error); } @@ -125,7 +125,7 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const RELAY_LOG_INFO *rli "unexpected success or fatal error")); thd->query_error= 1; } - const_cast(rli)->clear_tables_to_lock(); + const_cast(rli)->clear_tables_to_lock(); DBUG_RETURN(error); } } @@ -147,7 +147,7 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const RELAY_LOG_INFO *rli mysql_unlock_tables(thd, thd->lock); thd->lock= 0; thd->query_error= 1; - const_cast(rli)->clear_tables_to_lock(); + const_cast(rli)->clear_tables_to_lock(); DBUG_RETURN(Rows_log_event::ERR_BAD_TABLE_DEF); } } @@ -169,14 +169,14 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const RELAY_LOG_INFO *rli */ for (TABLE_LIST *ptr= rli->tables_to_lock ; ptr ; ptr= ptr->next_global) { - const_cast(rli)->m_table_map.set_table(ptr->table_id, ptr->table); + const_cast(rli)->m_table_map.set_table(ptr->table_id, ptr->table); } #ifdef HAVE_QUERY_CACHE query_cache.invalidate_locked_for_write(rli->tables_to_lock); #endif } - TABLE* table= const_cast(rli)->m_table_map.get_table(ev->m_table_id); + TABLE* table= const_cast(rli)->m_table_map.get_table(ev->m_table_id); if (table) { @@ -221,7 +221,7 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const RELAY_LOG_INFO *rli inside a statement and halting abruptly might cause problems when restarting. */ - const_cast(rli)->set_flag(RELAY_LOG_INFO::IN_STMT); + const_cast(rli)->set_flag(Relay_log_info::IN_STMT); error= do_before_row_operations(table); while (error == 0 && row_start < ev->m_rows_end) @@ -262,7 +262,7 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const RELAY_LOG_INFO *rli row_start= row_end; } DBUG_EXECUTE_IF("STOP_SLAVE_after_first_Rows_event", - const_cast(rli)->abort_slave= 1;); + const_cast(rli)->abort_slave= 1;); error= do_after_row_operations(table, error); if (!ev->cache_stmt) { @@ -276,7 +276,7 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const RELAY_LOG_INFO *rli The table def is needed in unpack_row(). */ if (rli->tables_to_lock && ev->get_flags(Rows_log_event::STMT_END_F)) - const_cast(rli)->clear_tables_to_lock(); + const_cast(rli)->clear_tables_to_lock(); if (error) { /* error has occured during the transaction */ @@ -299,7 +299,7 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const RELAY_LOG_INFO *rli rollback at the caller along with sbr. */ thd->reset_current_stmt_binlog_row_based(); - const_cast(rli)->cleanup_context(thd, error); + const_cast(rli)->cleanup_context(thd, error); thd->query_error= 1; DBUG_RETURN(error); } @@ -329,7 +329,7 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const RELAY_LOG_INFO *rli problem. When WL#2975 is implemented, just remove the member st_relay_log_info::last_event_start_time and all its occurences. */ - const_cast(rli)->last_event_start_time= my_time(0); + const_cast(rli)->last_event_start_time= my_time(0); } DBUG_RETURN(0); diff --git a/sql/log_event_old.h b/sql/log_event_old.h index ffe87a045cc..81e55097905 100644 --- a/sql/log_event_old.h +++ b/sql/log_event_old.h @@ -31,7 +31,7 @@ class Old_rows_log_event #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) - int do_apply_event(Rows_log_event*,const RELAY_LOG_INFO*); + int do_apply_event(Rows_log_event*,const Relay_log_info*); /* Primitive to prepare for a sequence of row executions. @@ -80,7 +80,7 @@ class Old_rows_log_event RETURN VALUE Error code, if something went wrong, 0 otherwise. */ - virtual int do_prepare_row(THD*, RELAY_LOG_INFO const*, TABLE*, + virtual int do_prepare_row(THD*, Relay_log_info const*, TABLE*, uchar const *row_start, uchar const **row_end) = 0; @@ -131,13 +131,13 @@ private: #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) // use old definition of do_apply_event() - virtual int do_apply_event(const RELAY_LOG_INFO *rli) + virtual int do_apply_event(const Relay_log_info *rli) { return Old_rows_log_event::do_apply_event(this,rli); } // primitives for old version of do_apply_event() virtual int do_before_row_operations(TABLE *table); virtual int do_after_row_operations(TABLE *table, int error); - virtual int do_prepare_row(THD*, RELAY_LOG_INFO const*, TABLE*, + virtual int do_prepare_row(THD*, Relay_log_info const*, TABLE*, uchar const *row_start, uchar const **row_end); virtual int do_exec_row(TABLE *table); @@ -179,13 +179,13 @@ private: #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) // use old definition of do_apply_event() - virtual int do_apply_event(const RELAY_LOG_INFO *rli) + virtual int do_apply_event(const Relay_log_info *rli) { return Old_rows_log_event::do_apply_event(this,rli); } // primitives for old version of do_apply_event() virtual int do_before_row_operations(TABLE *table); virtual int do_after_row_operations(TABLE *table, int error); - virtual int do_prepare_row(THD*, RELAY_LOG_INFO const*, TABLE*, + virtual int do_prepare_row(THD*, Relay_log_info const*, TABLE*, uchar const *row_start, uchar const **row_end); virtual int do_exec_row(TABLE *table); #endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */ @@ -226,13 +226,13 @@ private: #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) // use old definition of do_apply_event() - virtual int do_apply_event(const RELAY_LOG_INFO *rli) + virtual int do_apply_event(const Relay_log_info *rli) { return Old_rows_log_event::do_apply_event(this,rli); } // primitives for old version of do_apply_event() virtual int do_before_row_operations(TABLE *table); virtual int do_after_row_operations(TABLE *table, int error); - virtual int do_prepare_row(THD*, RELAY_LOG_INFO const*, TABLE*, + virtual int do_prepare_row(THD*, Relay_log_info const*, TABLE*, uchar const *row_start, uchar const **row_end); virtual int do_exec_row(TABLE *table); #endif diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index af6dd590679..ddd63da9adb 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -857,7 +857,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token OUT_SYM /* SQL-2003-R */ %token OWNER_SYM %token PACK_KEYS_SYM -%token PAGE_SYM %token PARAM_MARKER %token PARSER_SYM %token PARTIAL /* SQL-2003-N */ @@ -1010,7 +1009,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token TO_SYM /* SQL-2003-R */ %token TRAILING /* SQL-2003-R */ %token TRANSACTION_SYM -%token TRANSACTIONAL_SYM %token TRIGGERS_SYM %token TRIGGER_SYM /* SQL-2003-R */ %token TRIM /* SQL-2003-N */ @@ -4366,12 +4364,6 @@ create_table_option: Lex->create_info.used_fields|= HA_CREATE_USED_KEY_BLOCK_SIZE; Lex->create_info.key_block_size= $3; } - | TRANSACTIONAL_SYM opt_equal ulong_num - { - Lex->create_info.used_fields|= HA_CREATE_USED_TRANSACTIONAL; - Lex->create_info.transactional= ($3 != 0 ? HA_CHOICE_YES : - HA_CHOICE_NO); - } ; default_charset: @@ -4450,8 +4442,7 @@ row_types: | DYNAMIC_SYM { $$= ROW_TYPE_DYNAMIC; } | COMPRESSED_SYM { $$= ROW_TYPE_COMPRESSED; } | REDUNDANT_SYM { $$= ROW_TYPE_REDUNDANT; } - | COMPACT_SYM { $$= ROW_TYPE_COMPACT; } - | PAGE_SYM { $$= ROW_TYPE_PAGE; }; + | COMPACT_SYM { $$= ROW_TYPE_COMPACT; }; merge_insert_types: NO_SYM { $$= MERGE_INSERT_DISABLED; } @@ -10082,7 +10073,6 @@ keyword_sp: | ONE_SHOT_SYM {} | ONE_SYM {} | PACK_KEYS_SYM {} - | PAGE_SYM {} | PARTIAL {} | PARTITIONING_SYM {} | PARTITIONS_SYM {} @@ -10152,7 +10142,6 @@ keyword_sp: | TEXT_SYM {} | THAN_SYM {} | TRANSACTION_SYM {} - | TRANSACTIONAL_SYM {} | TRIGGERS_SYM {} | TIMESTAMP {} | TIMESTAMP_ADD {} From e212c6a64a8e42c93718fc3f9ec5a89394569c1a Mon Sep 17 00:00:00 2001 From: "skozlov/ksm@mysql.com/virtop.localdomain" <> Date: Mon, 27 Aug 2007 18:44:13 +0400 Subject: [PATCH 012/336] WL#3694 Replication of Invocation and Invoked Features Testing. Bug#29020 Event results not correctly replicated to slave in RBR: partially. --- .../suite/rpl/r/rpl_invoked_features.result | 30 +++--- mysql-test/suite/rpl/t/disabled.def | 3 - .../suite/rpl/t/rpl_invoked_features.test | 92 +++++++++++-------- 3 files changed, 69 insertions(+), 56 deletions(-) diff --git a/mysql-test/suite/rpl/r/rpl_invoked_features.result b/mysql-test/suite/rpl/r/rpl_invoked_features.result index 3bcef762497..502bb040218 100644 --- a/mysql-test/suite/rpl/r/rpl_invoked_features.result +++ b/mysql-test/suite/rpl/r/rpl_invoked_features.result @@ -17,13 +17,13 @@ DROP EVENT IF EXISTS e11; CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY, b INT, c VARCHAR(64)) ENGINE=myisam; INSERT INTO t1 VALUES (1,1,'1'); INSERT INTO t1 VALUES (2,2,UUID()); -CREATE TABLE t2 (a INT, b INT, c VARCHAR(64)) ENGINE=myisam; +CREATE TABLE t2 (a INT UNIQUE, b INT, c VARCHAR(64)) ENGINE=myisam; INSERT INTO t2 VALUES (1,1,'1'); INSERT INTO t2 VALUES (2,2,UUID()); CREATE TABLE t11 (a INT NOT NULL PRIMARY KEY, b INT, c VARCHAR(64)) ENGINE=innodb; INSERT INTO t11 VALUES (1,1,'1'); INSERT INTO t11 VALUES (2,2,UUID()); -CREATE TABLE t12 (a INT, b INT, c VARCHAR(64)) ENGINE=innodb; +CREATE TABLE t12 (a INT UNIQUE, b INT, c VARCHAR(64)) ENGINE=innodb; INSERT INTO t12 VALUES (1,1,'1'); INSERT INTO t12 VALUES (2,2,UUID()); @@ -49,21 +49,15 @@ BEGIN UPDATE t12 SET c = ''; UPDATE t13 SET c = ''; END| -CREATE EVENT e1 ON SCHEDULE EVERY 1 SECOND ENABLE DO +CREATE EVENT e1 ON SCHEDULE EVERY 1 SECOND DISABLE DO BEGIN -DECLARE c INT; -SELECT a INTO c FROM t1 WHERE a < 11 ORDER BY a DESC LIMIT 1; -IF c = 7 THEN +ALTER EVENT e1 DISABLE; CALL p1(10, ''); -END IF; END| -CREATE EVENT e11 ON SCHEDULE EVERY 1 SECOND ENABLE DO +CREATE EVENT e11 ON SCHEDULE EVERY 1 SECOND DISABLE DO BEGIN -DECLARE c INT; -SELECT a INTO c FROM t11 WHERE a < 11 ORDER BY a DESC LIMIT 1; -IF c = 7 THEN +ALTER EVENT e11 DISABLE; CALL p11(10, ''); -END IF; END| CREATE FUNCTION f1 (x INT) RETURNS VARCHAR(64) BEGIN @@ -78,11 +72,11 @@ RETURN f1(x); END| CREATE PROCEDURE p1 (IN x INT, IN y VARCHAR(64)) BEGIN -INSERT INTO t1 VALUES (x,x,y); +INSERT IGNORE INTO t1 VALUES (x,x,y); END| CREATE PROCEDURE p11 (IN x INT, IN y VARCHAR(64)) BEGIN -INSERT INTO t11 VALUES (x,x,y); +INSERT IGNORE INTO t11 VALUES (x,x,y); END| CREATE TABLE t3 SELECT * FROM v1; @@ -110,6 +104,8 @@ INSERT INTO t11 VALUES(7,7,f2(7)); INSERT INTO t11 VALUES (103,103,''); SET GLOBAL EVENT_SCHEDULER = on; +ALTER EVENT e1 ENABLE; +ALTER EVENT e11 ENABLE; SET GLOBAL EVENT_SCHEDULER = off; SHOW TABLES LIKE 't%'; @@ -138,8 +134,8 @@ PROCEDURE p1 PROCEDURE p11 SELECT event_name, status FROM information_schema.events WHERE event_schema='test'; event_name status -e1 ENABLED -e11 ENABLED +e1 DISABLED +e11 DISABLED SELECT COUNT(*) FROM t1; COUNT(*) @@ -438,6 +434,8 @@ UPDATE t3 SET c=''; UPDATE t11 SET c=''; UPDATE t12 SET c=''; UPDATE t13 SET c=''; +ALTER TABLE t3 ORDER BY a; +ALTER TABLE t13 ORDER BY a; diff --git a/mysql-test/suite/rpl/t/disabled.def b/mysql-test/suite/rpl/t/disabled.def index 34a8d6988a9..72b68fa59db 100644 --- a/mysql-test/suite/rpl/t/disabled.def +++ b/mysql-test/suite/rpl/t/disabled.def @@ -11,9 +11,6 @@ ############################################################################## rpl_ddl : BUG#26418 2007-03-01 mleich Slave out of sync after CREATE/DROP TEMPORARY TABLE + ROLLBACK on master -#rpl_innodb_mixed_ddl : Bug #29363 rpl.rpl_innodb_mixed_* test failures -#rpl_innodb_mixed_dml : Bug #29363 rpl.rpl_innodb_mixed_* test failures -rpl_invoked_features : BUG#29020 2007-06-21 Lars Non-deterministic test case rpl_auto_increment_11932 : Bug#29809 2007-07-16 ingo Slave SQL errors in warnings file rpl_stm_extraColmaster_ndb : WL#3915 : Statement-based replication not supported in ndb. Enable test when supported. rpl_row_extraColmaster_ndb : BUG#29549 : Replication of BLOBs fail for NDB diff --git a/mysql-test/suite/rpl/t/rpl_invoked_features.test b/mysql-test/suite/rpl/t/rpl_invoked_features.test index e797e0552ef..0fc5d917566 100644 --- a/mysql-test/suite/rpl/t/rpl_invoked_features.test +++ b/mysql-test/suite/rpl/t/rpl_invoked_features.test @@ -8,10 +8,9 @@ --source include/master-slave.inc --source include/have_innodb.inc - -# -# Define variables used by test case -# +# --disable_warnings/--enable_warnings added before/after query +# if one uses UUID() function because we need to avoid warnings +# for STATEMENT binlog format # Non-transactional engine --let $engine_type= myisam @@ -45,20 +44,24 @@ DROP EVENT IF EXISTS e11; --echo eval CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY, b INT, c VARCHAR(64)) ENGINE=$engine_type; ---disable_warnings INSERT INTO t1 VALUES (1,1,'1'); +--disable_warnings INSERT INTO t1 VALUES (2,2,UUID()); -eval CREATE TABLE t2 (a INT, b INT, c VARCHAR(64)) ENGINE=$engine_type; +--enable_warnings +eval CREATE TABLE t2 (a INT UNIQUE, b INT, c VARCHAR(64)) ENGINE=$engine_type; INSERT INTO t2 VALUES (1,1,'1'); +--disable_warnings INSERT INTO t2 VALUES (2,2,UUID()); --enable_warnings eval CREATE TABLE t11 (a INT NOT NULL PRIMARY KEY, b INT, c VARCHAR(64)) ENGINE=$engine_type2; ---disable_warnings INSERT INTO t11 VALUES (1,1,'1'); +--disable_warnings INSERT INTO t11 VALUES (2,2,UUID()); -eval CREATE TABLE t12 (a INT, b INT, c VARCHAR(64)) ENGINE=$engine_type2; +--enable_warnings +eval CREATE TABLE t12 (a INT UNIQUE, b INT, c VARCHAR(64)) ENGINE=$engine_type2; INSERT INTO t12 VALUES (1,1,'1'); +--disable_warnings INSERT INTO t12 VALUES (2,2,UUID()); --enable_warnings @@ -96,22 +99,16 @@ BEGIN END| # Create events which will run every 1 sec -CREATE EVENT e1 ON SCHEDULE EVERY 1 SECOND ENABLE DO +CREATE EVENT e1 ON SCHEDULE EVERY 1 SECOND DISABLE DO BEGIN - DECLARE c INT; - SELECT a INTO c FROM t1 WHERE a < 11 ORDER BY a DESC LIMIT 1; - IF c = 7 THEN - CALL p1(10, ''); - END IF; + ALTER EVENT e1 DISABLE; + CALL p1(10, ''); END| -CREATE EVENT e11 ON SCHEDULE EVERY 1 SECOND ENABLE DO +CREATE EVENT e11 ON SCHEDULE EVERY 1 SECOND DISABLE DO BEGIN - DECLARE c INT; - SELECT a INTO c FROM t11 WHERE a < 11 ORDER BY a DESC LIMIT 1; - IF c = 7 THEN - CALL p11(10, ''); - END IF; + ALTER EVENT e11 DISABLE; + CALL p11(10, ''); END| # Create functions and procedures used for events @@ -130,12 +127,12 @@ END| CREATE PROCEDURE p1 (IN x INT, IN y VARCHAR(64)) BEGIN - INSERT INTO t1 VALUES (x,x,y); + INSERT IGNORE INTO t1 VALUES (x,x,y); END| CREATE PROCEDURE p11 (IN x INT, IN y VARCHAR(64)) BEGIN - INSERT INTO t11 VALUES (x,x,y); + INSERT IGNORE INTO t11 VALUES (x,x,y); END| DELIMITER ;| @@ -147,17 +144,24 @@ DELIMITER ;| # Do some actions for non-transactional tables --echo ---disable_warnings CREATE TABLE t3 SELECT * FROM v1; INSERT INTO t1 VALUES (3,3,''); UPDATE t1 SET c='2' WHERE a = 1; +--disable_warnings INSERT INTO t1 VALUES(4,4,f1(4)); +--enable_warnings INSERT INTO t1 VALUES (100,100,''); +--disable_warnings CALL p1(5, UUID()); +--enable_warnings INSERT INTO t1 VALUES (101,101,''); +--disable_warnings INSERT INTO t1 VALUES(6,6,f1(6)); +--enable_warnings INSERT INTO t1 VALUES (102,102,''); +--disable_warnings INSERT INTO t1 VALUES(7,7,f2(7)); +--enable_warnings INSERT INTO t1 VALUES (103,103,''); # Do some actions for transactional tables @@ -165,21 +169,34 @@ INSERT INTO t1 VALUES (103,103,''); CREATE TABLE t13 SELECT * FROM v11; INSERT INTO t11 VALUES (3,3,''); UPDATE t11 SET c='2' WHERE a = 1; +--disable_warnings INSERT INTO t11 VALUES(4,4,f1(4)); -INSERT INTO t11 VALUES (100,100,''); -CALL p11(5, UUID()); -INSERT INTO t11 VALUES (101,101,''); -INSERT INTO t11 VALUES(6,6,f1(6)); -INSERT INTO t11 VALUES (102,102,''); -INSERT INTO t11 VALUES(7,7,f2(7)); -INSERT INTO t11 VALUES (103,103,''); --enable_warnings +INSERT INTO t11 VALUES (100,100,''); +--disable_warnings +CALL p11(5, UUID()); +--enable_warnings +INSERT INTO t11 VALUES (101,101,''); +--disable_warnings +INSERT INTO t11 VALUES(6,6,f1(6)); +--enable_warnings +INSERT INTO t11 VALUES (102,102,''); +--disable_warnings +INSERT INTO t11 VALUES(7,7,f2(7)); +--enable_warnings +INSERT INTO t11 VALUES (103,103,''); # Scheduler is on --echo +# Temporally events fire sequentally due Bug#29020. SET GLOBAL EVENT_SCHEDULER = on; -# Wait 2 sec while events will executed ---sleep 2 +# Wait while events will executed +ALTER EVENT e1 ENABLE; +let $wait_condition= SELECT COUNT(*) = 1 FROM t1 WHERE t1.a = 10; +--source include/wait_condition.inc +ALTER EVENT e11 ENABLE; +let $wait_condition= SELECT COUNT(*) = 1 FROM t11 WHERE t11.a = 10; +--source include/wait_condition.inc SET GLOBAL EVENT_SCHEDULER = off; # Check original objects @@ -234,7 +251,7 @@ SELECT COUNT(*) FROM t13; SELECT a,b FROM t13 ORDER BY a; SELECT a,b FROM v11 ORDER BY a; -# Remove UUID() before comparing +# Remove UUID() before comparing and sort tables --connection master --echo @@ -245,6 +262,9 @@ UPDATE t11 SET c=''; UPDATE t12 SET c=''; UPDATE t13 SET c=''; +ALTER TABLE t3 ORDER BY a; +ALTER TABLE t13 ORDER BY a; + --sync_slave_with_master slave # Compare a data from master and slave @@ -260,13 +280,12 @@ UPDATE t13 SET c=''; # Remove dumps --echo ---exec rm $MYSQLTEST_VARDIR/tmp/rpl_invoked_features_master.sql ---exec rm $MYSQLTEST_VARDIR/tmp/rpl_invoked_features_slave.sql +#--exec rm $MYSQLTEST_VARDIR/tmp/rpl_invoked_features_master.sql +#--exec rm $MYSQLTEST_VARDIR/tmp/rpl_invoked_features_slave.sql # Remove tables,views,procedures,functions --connection master --echo ---disable_warnings DROP VIEW IF EXISTS v1,v11; DROP TABLE IF EXISTS t1,t2,t3,t11,t12,t13; DROP PROCEDURE IF EXISTS p1; @@ -275,7 +294,6 @@ DROP FUNCTION IF EXISTS f1; DROP FUNCTION IF EXISTS f2; DROP EVENT IF EXISTS e1; DROP EVENT IF EXISTS e11; ---enable_warnings --sync_slave_with_master slave From 9ea7b6a7fcc8178f15d8927694bc004351027589 Mon Sep 17 00:00:00 2001 From: "aelkin/elkin@koti.dsl.inet.fi" <> Date: Wed, 29 Aug 2007 19:57:10 +0300 Subject: [PATCH 013/336] Bug #30209 rpl_packet.test: Slave_running mismatch (timing bug?) explicit --sleep is removed in favor of wait_for_slave_io_to_stop.inc. The status reporting uses `SHOW SLAVE STATUS' *not* possibly buggy "SHOW STATUS LIKE 'Slave_running'". --- mysql-test/r/rpl_packet.result | 37 +++++++++++++++++++++++++++++++--- mysql-test/t/rpl_packet.test | 10 +++++---- 2 files changed, 40 insertions(+), 7 deletions(-) diff --git a/mysql-test/r/rpl_packet.result b/mysql-test/r/rpl_packet.result index 894bc81b08d..9425724b434 100644 --- a/mysql-test/r/rpl_packet.result +++ b/mysql-test/r/rpl_packet.result @@ -21,6 +21,37 @@ STOP SLAVE; START SLAVE; CREATE TABLe `t1` (`f1` LONGTEXT) ENGINE=MyISAM; INSERT INTO `t1`(`f1`) VALUES ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa2048'); -SHOW STATUS LIKE 'Slave_running'; -Variable_name Value -Slave_running OFF +show slave status; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port MASTER_MYPORT +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos 2138 +Relay_Log_File # +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running No +Slave_SQL_Running # +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 0 +Last_Error +Skip_Counter 0 +Exec_Master_Log_Pos 2138 +Relay_Log_Space # +Until_Condition None +Until_Log_File +Until_Log_Pos 0 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master # diff --git a/mysql-test/t/rpl_packet.test b/mysql-test/t/rpl_packet.test index f410b561663..84bc5d908bf 100644 --- a/mysql-test/t/rpl_packet.test +++ b/mysql-test/t/rpl_packet.test @@ -64,9 +64,11 @@ CREATE TABLe `t1` (`f1` LONGTEXT) ENGINE=MyISAM; INSERT INTO `t1`(`f1`) VALUES ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa2048'); # The slave I/O thread must stop after trying to read the above event -connection slave; -sleep 2; -SHOW STATUS LIKE 'Slave_running'; - +connection slave; +--source include/wait_for_slave_io_to_stop.inc +--replace_result $MASTER_MYPORT MASTER_MYPORT +# import is only the 11th column Slave_IO_Running +--replace_column 1 # 8 # 9 # 12 # 23 # 33 # +query_vertical show slave status; # End of tests From 1835b16255a0fb9a2da63b3c12cf2a0dff8e6b00 Mon Sep 17 00:00:00 2001 From: "rafal@quant.(none)" <> Date: Tue, 4 Sep 2007 15:24:04 +0200 Subject: [PATCH 014/336] Disabling rpl_ndb_2other test. --- mysql-test/suite/rpl_ndb/t/disabled.def | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/suite/rpl_ndb/t/disabled.def b/mysql-test/suite/rpl_ndb/t/disabled.def index 90286ecc421..5b102a915ef 100644 --- a/mysql-test/suite/rpl_ndb/t/disabled.def +++ b/mysql-test/suite/rpl_ndb/t/disabled.def @@ -13,6 +13,7 @@ rpl_ndb_2innodb : BUG#19227 2006-04-20 pekka pk delete apparently not replicated rpl_ndb_2myisam : BUG#19227 Seems to pass currently +rpl_ndb_2other : BUG#29549 2007-09-04 rafal test fails on big-endian architectures rpl_ndb_dd_partitions : BUG#19259 2006-04-21 rpl_ndb_dd_partitions fails on s/AMD rpl_ndb_innodb2ndb : Bug#29549 rpl_ndb_myisam2ndb,rpl_ndb_innodb2ndb failed on Solaris for pack_length issue rpl_ndb_myisam2ndb : Bug#29549 rpl_ndb_myisam2ndb,rpl_ndb_innodb2ndb failed on Solaris for pack_length issue From 4bfad3e923fd54c7bfe49b3874002e520663afe6 Mon Sep 17 00:00:00 2001 From: "skozlov/ksm@mysql.com/virtop.localdomain" <> Date: Fri, 7 Sep 2007 12:04:57 +0400 Subject: [PATCH 015/336] replaced '--exec rm' to '--remove_file' --- mysql-test/suite/rpl/t/rpl_invoked_features.test | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/rpl/t/rpl_invoked_features.test b/mysql-test/suite/rpl/t/rpl_invoked_features.test index 0fc5d917566..2e69c0fabd9 100644 --- a/mysql-test/suite/rpl/t/rpl_invoked_features.test +++ b/mysql-test/suite/rpl/t/rpl_invoked_features.test @@ -280,8 +280,8 @@ ALTER TABLE t13 ORDER BY a; # Remove dumps --echo -#--exec rm $MYSQLTEST_VARDIR/tmp/rpl_invoked_features_master.sql -#--exec rm $MYSQLTEST_VARDIR/tmp/rpl_invoked_features_slave.sql +--remove_file $MYSQLTEST_VARDIR/tmp/rpl_invoked_features_master.sql +--remove_file $MYSQLTEST_VARDIR/tmp/rpl_invoked_features_slave.sql # Remove tables,views,procedures,functions --connection master From 6f96967f0af1665ff71c1dc16630223001fbda0e Mon Sep 17 00:00:00 2001 From: "cbell/Chuck@mysql_cab_desk." <> Date: Fri, 14 Sep 2007 11:22:41 -0400 Subject: [PATCH 016/336] BUG#30790 : Suspicious code in rpl_utility.cc This patch clarifies some of the coding choices with documentationa and removes a limitation in the code for future expansion of the CHAR and BINARY fields to length > 255. --- sql/field.cc | 1 + sql/log_event.cc | 10 ++++++++++ sql/rpl_utility.cc | 36 +++++++++++++++++++++++------------- sql/rpl_utility.h | 14 +++++++------- 4 files changed, 41 insertions(+), 20 deletions(-) diff --git a/sql/field.cc b/sql/field.cc index 1b01d626512..9e86e405512 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -6732,6 +6732,7 @@ const uint Field_varstring::MAX_SIZE= UINT_MAX16; int Field_varstring::do_save_field_metadata(uchar *metadata_ptr) { char *ptr= (char *)metadata_ptr; + DBUG_ASSERT(field_length <= 65535); int2store(ptr, field_length); return 2; } diff --git a/sql/log_event.cc b/sql/log_event.cc index 33442baaf90..0dee50c8179 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -6469,6 +6469,16 @@ void Rows_log_event::print_helper(FILE *file, data) in the table map are initialized as zero (0). The array size is the same as the columns for the table on the slave. + Additionally, values saved for field metadata on the master are saved as a + string of bytes (uchar) in the binlog. A field may require 1 or more bytes + to store the information. In cases where values require multiple bytes + (e.g. values > 255), the endian-safe methods are used to properly encode + the values on the master and decode them on the slave. When the field + metadata values are captured on the slave, they are stored in an array of + type uint16. This allows the least number of casts to prevent casting bugs + when the field metadata is used in comparisons of field attributes. When + the field metadata is used for calculating addresses in pointer math, the + type used is uint32. */ /** diff --git a/sql/rpl_utility.cc b/sql/rpl_utility.cc index d1ce5bf3b7b..b3ca26d4c2c 100644 --- a/sql/rpl_utility.cc +++ b/sql/rpl_utility.cc @@ -31,31 +31,34 @@ uint32 table_def::calc_field_size(uint col, uchar *master_data) const switch (type(col)) { case MYSQL_TYPE_NEWDECIMAL: length= my_decimal_get_binary_size(m_field_metadata[col] >> 8, - m_field_metadata[col] - ((m_field_metadata[col] >> 8) << 8)); + m_field_metadata[col] & 0xff); break; case MYSQL_TYPE_DECIMAL: case MYSQL_TYPE_FLOAT: case MYSQL_TYPE_DOUBLE: length= m_field_metadata[col]; break; + /* + The cases for SET and ENUM are include for completeness, however + both are mapped to type MYSQL_TYPE_STRING and their real types + are encoded in the field metadata. + */ case MYSQL_TYPE_SET: case MYSQL_TYPE_ENUM: case MYSQL_TYPE_STRING: { - if (((m_field_metadata[col] & 0xff00) == (MYSQL_TYPE_SET << 8)) || - ((m_field_metadata[col] & 0xff00) == (MYSQL_TYPE_ENUM << 8))) + uchar type= m_field_metadata[col] >> 8U; + if ((type == MYSQL_TYPE_SET) || (type == MYSQL_TYPE_ENUM)) length= m_field_metadata[col] & 0x00ff; else { - length= m_field_metadata[col] & 0x00ff; - DBUG_ASSERT(length > 0); - if (length > 255) - { - DBUG_ASSERT(uint2korr(master_data) > 0); - length= uint2korr(master_data) + 2; - } - else - length= (uint) *master_data + 1; + /* + We are reading the actual size from the master_data record + because this field has the actual lengh stored in the first + byte. + */ + length= (uint) *master_data + 1; + DBUG_ASSERT(length != 0); } break; } @@ -95,6 +98,13 @@ uint32 table_def::calc_field_size(uint col, uchar *master_data) const break; case MYSQL_TYPE_BIT: { + /* + Decode the size of the bit field from the master. + from_len is the length in bytes from the master + from_bit_len is the number of extra bits stored in the master record + If from_bit_len is not 0, add 1 to the length to account for accurate + number of bytes needed. + */ uint from_len= (m_field_metadata[col] >> 8U) & 0x00ff; uint from_bit_len= m_field_metadata[col] & 0x00ff; DBUG_ASSERT(from_bit_len <= 7); @@ -136,7 +146,7 @@ uint32 table_def::calc_field_size(uint col, uchar *master_data) const length= *master_data; break; case 2: - length= sint2korr(master_data); + length= uint2korr(master_data); break; case 3: length= uint3korr(master_data); diff --git a/sql/rpl_utility.h b/sql/rpl_utility.h index 4fd38022da0..f2ab34fe947 100644 --- a/sql/rpl_utility.h +++ b/sql/rpl_utility.h @@ -99,7 +99,7 @@ public: /* These types store a single byte. */ - m_field_metadata[i]= (uchar)field_metadata[index]; + m_field_metadata[i]= field_metadata[index]; index++; break; } @@ -107,14 +107,14 @@ public: case MYSQL_TYPE_ENUM: case MYSQL_TYPE_STRING: { - short int x= field_metadata[index++] << 8U; // real_type - x = x + field_metadata[index++]; // pack or field length + uint16 x= field_metadata[index++] << 8U; // real_type + x+= field_metadata[index++]; // pack or field length m_field_metadata[i]= x; break; } case MYSQL_TYPE_BIT: { - short int x= field_metadata[index++]; + uint16 x= field_metadata[index++]; x = x + (field_metadata[index++] << 8U); m_field_metadata[i]= x; break; @@ -125,14 +125,14 @@ public: These types store two bytes. */ char *ptr= (char *)&field_metadata[index]; - m_field_metadata[i]= sint2korr(ptr); + m_field_metadata[i]= uint2korr(ptr); index= index + 2; break; } case MYSQL_TYPE_NEWDECIMAL: { - short int x= field_metadata[index++] << 8U; // precision - x = x + field_metadata[index++]; // decimals + uint16 x= field_metadata[index++] << 8U; // precision + x+= field_metadata[index++]; // decimals m_field_metadata[i]= x; break; } From e9b287f27e8a44dc906fbc9373f14331c67b6929 Mon Sep 17 00:00:00 2001 From: "aelkin@dl145j.mysql.com" <> Date: Sun, 16 Sep 2007 12:07:00 +0200 Subject: [PATCH 017/336] Manual merge fixes/tests for bugs_28960,27417,23333. --- .../mix_innodb_myisam_binlog.test | 250 ------------------ .../r/binlog_stm_mix_innodb_myisam.result | 108 ++++++-- .../t/binlog_stm_mix_innodb_myisam.test | 138 +++++++++- mysql-test/suite/rpl/r/rpl_packet.result | 9 +- mysql-test/suite/rpl/t/rpl_packet.test | 2 +- 5 files changed, 223 insertions(+), 284 deletions(-) diff --git a/mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test b/mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test index 8d530261662..7141bd1abb9 100644 --- a/mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test +++ b/mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test @@ -316,253 +316,3 @@ disconnect con3; connection con4; select get_lock("a",10); # wait for rollback to finish -# we check that the error code of the "ROLLBACK" event is 0 and not -# ER_SERVER_SHUTDOWN (i.e. disconnection just rolls back transaction -# and does not make slave to stop) ---exec $MYSQL_BINLOG --start-position=547 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/mix_innodb_myisam_binlog.output ---replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR -eval select -(@a:=load_file("$MYSQLTEST_VARDIR/tmp/mix_innodb_myisam_binlog.output")) -is not null; ---replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR -eval select -@a like "%#%error_code=0%ROLLBACK/*!*/;%ROLLBACK /* added by mysqlbinlog */;%", -@a not like "%#%error_code=%error_code=%"; -drop table t1, t2; - -# -# Bug #27417 thd->no_trans_update.stmt lost value inside of SF-exec-stack -# bug #28960 non-trans temp table changes with insert .. select -# not binlogged after rollback -# -# testing appearence of insert into temp_table in binlog. -# There are two branches of execution that require different setup. - -## send_eof() branch - -# prepare - -create temporary table tt (a int unique); -create table ti (a int) engine=innodb; -reset master; -show master status; - -# action - -begin; -insert into ti values (1); -insert into ti values (2) ; -insert into tt select * from ti; -rollback; - -# check - -select count(*) from tt /* 2 */; -show master status; ---replace_column 2 # 5 # -show binlog events from 98; -select count(*) from ti /* zero */; -insert into ti select * from tt; -select * from ti /* that is what slave would miss - a bug */; - - -## send_error() branch -delete from ti; -delete from tt where a=1; -reset master; -show master status; - -# action - -begin; -insert into ti values (1); -insert into ti values (2) /* to make the dup error in the following */; ---error ER_DUP_ENTRY -insert into tt select * from ti /* one affected and error */; -rollback; - -# check - -show master status; ---replace_column 2 # 5 # -show binlog events from 98; -select count(*) from ti /* zero */; -insert into ti select * from tt; -select * from tt /* that is what otherwise slave missed - the bug */; - -drop table ti; - - -# -# Bug #27417 thd->no_trans_update.stmt lost value inside of SF-exec-stack -# -# Testing asserts: if there is a side effect of modifying non-transactional -# table thd->no_trans_update.stmt must be TRUE; -# the assert is active with debug build -# - ---disable_warnings -drop function if exists bug27417; -drop table if exists t1,t2; ---enable_warnings -# side effect table -CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; -# target tables -CREATE TABLE t2 (a int NOT NULL auto_increment, PRIMARY KEY (a)); - -delimiter |; -create function bug27417(n int) -RETURNS int(11) -begin - insert into t1 values (null); - return n; -end| -delimiter ;| - -reset master; - -# execute - -insert into t2 values (bug27417(1)); -insert into t2 select bug27417(2); -reset master; - ---error ER_DUP_ENTRY -insert into t2 values (bug27417(2)); -show master status; /* only (!) with fixes for #23333 will show there is the query */; -select count(*) from t1 /* must be 3 */; - -reset master; -select count(*) from t2; -delete from t2 where a=bug27417(3); -select count(*) from t2 /* nothing got deleted */; -show master status; /* the query must be in regardless of #23333 */; -select count(*) from t1 /* must be 5 */; - ---enable_info -delete t2 from t2 where t2.a=bug27417(100) /* must not affect t2 */; ---disable_info -select count(*) from t1 /* must be 7 */; - -# function bug27417 remains for the following testing of bug#23333 -drop table t1,t2; - -# -# Bug#23333 using the patch (and the test) for bug#27471 -# throughout the bug tests -# t1 - non-trans side effects gatherer; -# t2 - transactional table; -# -CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; -CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; -CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); - - -# -# INSERT -# - -# prepare - - insert into t2 values (1); - reset master; - -# execute - - --error ER_DUP_ENTRY - insert into t2 values (bug27417(1)); - -# check - - show master status /* the offset must denote there is the query */; - select count(*) from t1 /* must be 1 */; - -# -# INSERT SELECT -# - -# prepare - delete from t1; - delete from t2; - insert into t2 values (2); - reset master; - -# execute - - --error ER_DUP_ENTRY - insert into t2 select bug27417(1) union select bug27417(2); - -# check - - show master status /* the offset must denote there is the query */; - select count(*) from t1 /* must be 2 */; - -# -# UPDATE (multi-update see bug#27716) -# - -# prepare - delete from t1; - insert into t3 values (1,1),(2,3),(3,4); - reset master; - -# execute - --error ER_DUP_ENTRY - update t3 set b=b+bug27417(1); - -# check - show master status /* the offset must denote there is the query */; - select count(*) from t1 /* must be 2 */; - - -# -# DELETE (for multi-delete see Bug #29136) -# - -# prepare - delete from t1; - delete from t2; - delete from t3; - insert into t2 values (1); - insert into t3 values (1,1); - create trigger trg_del before delete on t2 for each row - insert into t3 values (bug27417(1), 2); - reset master; - -# execute - --error ER_DUP_ENTRY - delete from t2; -# check - show master status /* the offset must denote there is the query */; - select count(*) from t1 /* must be 1 */; - - -# -# LOAD DATA -# - -# prepare - delete from t1; - create table t4 (a int default 0, b int primary key) engine=innodb; - insert into t4 values (0, 17); - reset master; - -# execute - --error ER_DUP_ENTRY - load data infile '../std_data_ln/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2); -# check - select * from t4; - select count(*) from t1 /* must be 2 */; - show master status /* the offset must denote there is the query */; - -# -# bug#23333 cleanup -# - - -drop trigger trg_del; -drop table t1,t2,t3,t4; -drop function bug27417; - - ---echo end of tests diff --git a/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result b/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result index 5ef36861c30..62c111af19a 100644 --- a/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result +++ b/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result @@ -380,7 +380,7 @@ select @a like "%#%error_code=0%ROLLBACK/*!*/;%ROLLBACK /* added by mysqlbinlog */;%" @a not like "%#%error_code=%error_code=%" 1 1 drop table t1, t2; -create table tt (a int unique); +create temporary table tt (a int unique); create table ti (a int) engine=innodb; reset master; show master status; @@ -399,18 +399,18 @@ count(*) show master status; File Position Binlog_Do_DB Binlog_Ignore_DB master-bin.000001 515 -show binlog events from 106; +show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Query 1 # use `test`; BEGIN -master-bin.000001 # Query 1 # use `test`; insert into ti values (1) -master-bin.000001 # Query 1 # use `test`; insert into ti values (2) -master-bin.000001 # Query 1 # use `test`; insert into tt select * from ti -master-bin.000001 # Query 1 # use `test`; ROLLBACK +master-bin.000001 # Query # # use `test`; BEGIN +master-bin.000001 # Query # # use `test`; insert into ti values (1) +master-bin.000001 # Query # # use `test`; insert into ti values (2) +master-bin.000001 # Query # # use `test`; insert into tt select * from ti +master-bin.000001 # Query # # use `test`; ROLLBACK select count(*) from ti /* zero */; count(*) 0 insert into ti select * from tt; -select * from ti /* that is what slave would miss - a bug */; +select * from ti /* that is what slave would miss - bug#28960 */; a 1 2 @@ -426,18 +426,11 @@ insert into ti values (2) /* to make the dup error in the following */; insert into tt select * from ti /* one affected and error */; ERROR 23000: Duplicate entry '2' for key 'a' rollback; -Warnings: -Warning 1196 Some non-transactional changed tables couldn't be rolled back show master status; File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 589 -show binlog events from 106; +master-bin.000001 106 +show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Query 1 # use `test`; BEGIN -master-bin.000001 # Query 1 # use `test`; insert into ti values (1) -master-bin.000001 # Query 1 # use `test`; insert into ti values (2) /* to make the dup error in the following */ -master-bin.000001 # Query 1 # use `test`; insert into tt select * from ti /* one affected and error */ -master-bin.000001 # Query 1 # use `test`; ROLLBACK select count(*) from ti /* zero */; count(*) 0 @@ -446,7 +439,7 @@ select * from tt /* that is what otherwise slave missed - the bug */; a 1 2 -drop table ti,tt; +drop table ti; drop function if exists bug27417; drop table if exists t1,t2; CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; @@ -463,6 +456,10 @@ insert into t2 select bug27417(2); reset master; insert into t2 values (bug27417(2)); ERROR 23000: Duplicate entry '2' for key 'PRIMARY' +show master status; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 222 +/* only (!) with fixes for #23333 will show there is the query */; select count(*) from t1 /* must be 3 */; count(*) 3 @@ -474,6 +471,10 @@ delete from t2 where a=bug27417(3); select count(*) from t2 /* nothing got deleted */; count(*) 2 +show master status; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 227 +/* the query must be in regardless of #23333 */; select count(*) from t1 /* must be 5 */; count(*) 5 @@ -482,6 +483,75 @@ affected rows: 0 select count(*) from t1 /* must be 7 */; count(*) 7 -drop function bug27417; drop table t1,t2; +CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; +CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; +CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); +insert into t2 values (1); +reset master; +insert into t2 values (bug27417(1)); +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +show master status /* the offset must denote there is the query */; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 293 +select count(*) from t1 /* must be 1 */; +count(*) +1 +delete from t1; +delete from t2; +insert into t2 values (2); +reset master; +insert into t2 select bug27417(1) union select bug27417(2); +ERROR 23000: Duplicate entry '2' for key 'PRIMARY' +show master status /* the offset must denote there is the query */; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 332 +select count(*) from t1 /* must be 2 */; +count(*) +2 +delete from t1; +insert into t3 values (1,1),(2,3),(3,4); +reset master; +update t3 set b=b+bug27417(1); +ERROR 23000: Duplicate entry '4' for key 'b' +show master status /* the offset must denote there is the query */; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 305 +select count(*) from t1 /* must be 2 */; +count(*) +2 +delete from t1; +delete from t2; +delete from t3; +insert into t2 values (1); +insert into t3 values (1,1); +create trigger trg_del before delete on t2 for each row +insert into t3 values (bug27417(1), 2); +reset master; +delete from t2; +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +show master status /* the offset must denote there is the query */; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 335 +select count(*) from t1 /* must be 1 */; +count(*) +1 +delete from t1; +create table t4 (a int default 0, b int primary key) engine=innodb; +insert into t4 values (0, 17); +reset master; +load data infile '../std_data_ln/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2); +ERROR 23000: Duplicate entry '17' for key 'PRIMARY' +select * from t4; +a b +0 17 +select count(*) from t1 /* must be 2 */; +count(*) +2 +show master status /* the offset must denote there is the query */; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 362 +drop trigger trg_del; +drop table t1,t2,t3,t4; +drop function bug27417; end of tests diff --git a/mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test b/mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test index 1815f3deb34..826206a1425 100644 --- a/mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test +++ b/mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test @@ -36,7 +36,7 @@ drop table t1, t2; # prepare -create table tt (a int unique); +create temporary table tt (a int unique); create table ti (a int) engine=innodb; reset master; show master status; @@ -53,11 +53,10 @@ rollback; select count(*) from tt /* 2 */; show master status; ---replace_column 2 # 5 # -show binlog events from 106; +source include/show_binlog_events.inc; select count(*) from ti /* zero */; insert into ti select * from tt; -select * from ti /* that is what slave would miss - a bug */; +select * from ti /* that is what slave would miss - bug#28960 */; ## send_error() branch @@ -78,13 +77,12 @@ rollback; # check show master status; ---replace_column 2 # 5 # -show binlog events from 106; +source include/show_binlog_events.inc; select count(*) from ti /* zero */; insert into ti select * from tt; select * from tt /* that is what otherwise slave missed - the bug */; -drop table ti,tt; +drop table ti; # @@ -123,16 +121,14 @@ reset master; --error ER_DUP_ENTRY insert into t2 values (bug27417(2)); -#TODO: Andrei: enable this test after 23333 is pushed -#show master status; /* only (!) with fixes for #23333 will show there is the query */; +show master status; /* only (!) with fixes for #23333 will show there is the query */; select count(*) from t1 /* must be 3 */; reset master; select count(*) from t2; delete from t2 where a=bug27417(3); select count(*) from t2 /* nothing got deleted */; -#TODO: Andrei: enable this test after 23333 is pushed -#show master status; /* the query must be in regardless of #23333 */; +show master status; /* the query must be in regardless of #23333 */; select count(*) from t1 /* must be 5 */; --enable_info @@ -140,7 +136,125 @@ delete t2 from t2 where t2.a=bug27417(100) /* must not affect t2 */; --disable_info select count(*) from t1 /* must be 7 */; -drop function bug27417; +# function bug27417 remains for the following testing of bug#23333 drop table t1,t2; +# +# Bug#23333 using the patch (and the test) for bug#27471 +# throughout the bug tests +# t1 - non-trans side effects gatherer; +# t2 - transactional table; +# +CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; +CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; +CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); + + +# +# INSERT +# + +# prepare + + insert into t2 values (1); + reset master; + +# execute + + --error ER_DUP_ENTRY + insert into t2 values (bug27417(1)); + +# check + + show master status /* the offset must denote there is the query */; + select count(*) from t1 /* must be 1 */; + +# +# INSERT SELECT +# + +# prepare + delete from t1; + delete from t2; + insert into t2 values (2); + reset master; + +# execute + + --error ER_DUP_ENTRY + insert into t2 select bug27417(1) union select bug27417(2); + +# check + + show master status /* the offset must denote there is the query */; + select count(*) from t1 /* must be 2 */; + +# +# UPDATE (multi-update see bug#27716) +# + +# prepare + delete from t1; + insert into t3 values (1,1),(2,3),(3,4); + reset master; + +# execute + --error ER_DUP_ENTRY + update t3 set b=b+bug27417(1); + +# check + show master status /* the offset must denote there is the query */; + select count(*) from t1 /* must be 2 */; + + +# +# DELETE (for multi-delete see Bug #29136) +# + +# prepare + delete from t1; + delete from t2; + delete from t3; + insert into t2 values (1); + insert into t3 values (1,1); + create trigger trg_del before delete on t2 for each row + insert into t3 values (bug27417(1), 2); + reset master; + +# execute + --error ER_DUP_ENTRY + delete from t2; +# check + show master status /* the offset must denote there is the query */; + select count(*) from t1 /* must be 1 */; + + +# +# LOAD DATA +# + +# prepare + delete from t1; + create table t4 (a int default 0, b int primary key) engine=innodb; + insert into t4 values (0, 17); + reset master; + +# execute + --error ER_DUP_ENTRY + load data infile '../std_data_ln/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2); +# check + select * from t4; + select count(*) from t1 /* must be 2 */; + show master status /* the offset must denote there is the query */; + +# +# bug#23333 cleanup +# + + +drop trigger trg_del; +drop table t1,t2,t3,t4; +drop function bug27417; + + --echo end of tests diff --git a/mysql-test/suite/rpl/r/rpl_packet.result b/mysql-test/suite/rpl/r/rpl_packet.result index c23b990acd4..dd56eb0471c 100644 --- a/mysql-test/suite/rpl/r/rpl_packet.result +++ b/mysql-test/suite/rpl/r/rpl_packet.result @@ -34,7 +34,7 @@ Master_User root Master_Port MASTER_MYPORT Connect_Retry 1 Master_Log_File master-bin.000001 -Read_Master_Log_Pos 2138 +Read_Master_Log_Pos # Relay_Log_File # Relay_Log_Pos # Relay_Master_Log_File master-bin.000001 @@ -49,7 +49,7 @@ Replicate_Wild_Ignore_Table Last_Errno 0 Last_Error Skip_Counter 0 -Exec_Master_Log_Pos 2138 +Exec_Master_Log_Pos # Relay_Log_Space # Until_Condition None Until_Log_File @@ -61,3 +61,8 @@ Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master # +Master_SSL_Verify_Server_Cert No +Last_IO_Errno 0 +Last_IO_Error +Last_SQL_Errno 0 +Last_SQL_Error diff --git a/mysql-test/suite/rpl/t/rpl_packet.test b/mysql-test/suite/rpl/t/rpl_packet.test index a4b290f89a3..0e17ae3144c 100644 --- a/mysql-test/suite/rpl/t/rpl_packet.test +++ b/mysql-test/suite/rpl/t/rpl_packet.test @@ -70,7 +70,7 @@ connection slave; --source include/wait_for_slave_io_to_stop.inc --replace_result $MASTER_MYPORT MASTER_MYPORT # import is only the 11th column Slave_IO_Running ---replace_column 1 # 8 # 9 # 12 # 23 # 33 # +--replace_column 1 # 7 # 8 # 9 # 12 # 22 # 23 # 33 # query_vertical show slave status; # End of tests From 11c9a13a2401135ffaba1ee34626e762121d484e Mon Sep 17 00:00:00 2001 From: "aelkin@dl145j.mysql.com" <> Date: Sun, 16 Sep 2007 18:16:40 +0200 Subject: [PATCH 018/336] Merge: bug#27417,23333 manual work for fixing tests and a source code. --- .../r/binlog_stm_mix_innodb_myisam.result | 77 +++++++++++++------ .../t/binlog_stm_mix_innodb_myisam.test | 16 ++-- sql/sql_insert.cc | 19 ++--- 3 files changed, 71 insertions(+), 41 deletions(-) diff --git a/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result b/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result index 62c111af19a..564fa8d86bd 100644 --- a/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result +++ b/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result @@ -426,11 +426,18 @@ insert into ti values (2) /* to make the dup error in the following */; insert into tt select * from ti /* one affected and error */; ERROR 23000: Duplicate entry '2' for key 'a' rollback; +Warnings: +Warning 1196 Some non-transactional changed tables couldn't be rolled back show master status; File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 106 +master-bin.000001 589 show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; BEGIN +master-bin.000001 # Query # # use `test`; insert into ti values (1) +master-bin.000001 # Query # # use `test`; insert into ti values (2) /* to make the dup error in the following */ +master-bin.000001 # Query # # use `test`; insert into tt select * from ti /* one affected and error */ +master-bin.000001 # Query # # use `test`; ROLLBACK select count(*) from ti /* zero */; count(*) 0 @@ -456,10 +463,11 @@ insert into t2 select bug27417(2); reset master; insert into t2 values (bug27417(2)); ERROR 23000: Duplicate entry '2' for key 'PRIMARY' -show master status; -File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 222 -/* only (!) with fixes for #23333 will show there is the query */; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F select count(*) from t1 /* must be 3 */; count(*) 3 @@ -471,10 +479,11 @@ delete from t2 where a=bug27417(3); select count(*) from t2 /* nothing got deleted */; count(*) 2 -show master status; -File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 227 -/* the query must be in regardless of #23333 */; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F select count(*) from t1 /* must be 5 */; count(*) 5 @@ -491,9 +500,12 @@ insert into t2 values (1); reset master; insert into t2 values (bug27417(1)); ERROR 23000: Duplicate entry '1' for key 'PRIMARY' -show master status /* the offset must denote there is the query */; -File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 293 +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # use `test`; ROLLBACK select count(*) from t1 /* must be 1 */; count(*) 1 @@ -503,9 +515,13 @@ insert into t2 values (2); reset master; insert into t2 select bug27417(1) union select bug27417(2); ERROR 23000: Duplicate entry '2' for key 'PRIMARY' -show master status /* the offset must denote there is the query */; -File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 332 +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # use `test`; ROLLBACK select count(*) from t1 /* must be 2 */; count(*) 2 @@ -514,9 +530,13 @@ insert into t3 values (1,1),(2,3),(3,4); reset master; update t3 set b=b+bug27417(1); ERROR 23000: Duplicate entry '4' for key 'b' -show master status /* the offset must denote there is the query */; -File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 305 +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Table_map # # table_id: # (test.t3) +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Update_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F select count(*) from t1 /* must be 2 */; count(*) 2 @@ -530,9 +550,13 @@ insert into t3 values (bug27417(1), 2); reset master; delete from t2; ERROR 23000: Duplicate entry '1' for key 'PRIMARY' -show master status /* the offset must denote there is the query */; -File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 335 +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Table_map # # table_id: # (test.t3) +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # use `test`; ROLLBACK select count(*) from t1 /* must be 1 */; count(*) 1 @@ -548,9 +572,14 @@ a b select count(*) from t1 /* must be 2 */; count(*) 2 -show master status /* the offset must denote there is the query */; -File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 362 +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Table_map # # table_id: # (test.t4) +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # use `test`; ROLLBACK drop trigger trg_del; drop table t1,t2,t3,t4; drop function bug27417; diff --git a/mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test b/mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test index 826206a1425..14397f85c38 100644 --- a/mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test +++ b/mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test @@ -120,15 +120,15 @@ insert into t2 select bug27417(2); reset master; --error ER_DUP_ENTRY -insert into t2 values (bug27417(2)); -show master status; /* only (!) with fixes for #23333 will show there is the query */; +insert into t2 values (bug27417(2)); +source include/show_binlog_events.inc; #only (!) with fixes for #23333 will show there is the query select count(*) from t1 /* must be 3 */; reset master; select count(*) from t2; delete from t2 where a=bug27417(3); select count(*) from t2 /* nothing got deleted */; -show master status; /* the query must be in regardless of #23333 */; +source include/show_binlog_events.inc; # the query must be in regardless of #23333 select count(*) from t1 /* must be 5 */; --enable_info @@ -166,7 +166,7 @@ CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); # check - show master status /* the offset must denote there is the query */; + source include/show_binlog_events.inc; # must be event of the query select count(*) from t1 /* must be 1 */; # @@ -186,7 +186,7 @@ CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); # check - show master status /* the offset must denote there is the query */; + source include/show_binlog_events.inc; # must be events of the query select count(*) from t1 /* must be 2 */; # @@ -203,7 +203,7 @@ CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); update t3 set b=b+bug27417(1); # check - show master status /* the offset must denote there is the query */; + source include/show_binlog_events.inc; # must be events of the query select count(*) from t1 /* must be 2 */; @@ -225,7 +225,7 @@ CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); --error ER_DUP_ENTRY delete from t2; # check - show master status /* the offset must denote there is the query */; + source include/show_binlog_events.inc; # must be events of the query select count(*) from t1 /* must be 1 */; @@ -245,7 +245,7 @@ CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); # check select * from t4; select count(*) from t1 /* must be 2 */; - show master status /* the offset must denote there is the query */; + source include/show_binlog_events.inc; # must be events of the query # # bug#23333 cleanup diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 16ad280c690..2f899a35179 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -3163,6 +3163,7 @@ void select_insert::abort() { */ if (table) { + bool changed, transactional_table; /* If we are not in prelocked mode, we end the bulk insert started before. @@ -3184,20 +3185,20 @@ void select_insert::abort() { If table creation failed, the number of rows modified will also be zero, so no check for that is made. */ - if (info.copied || info.deleted || info.updated) + changed= (info.copied || info.deleted || info.updated); + transactional_table= table->file->has_transactions(); + if (thd->transaction.stmt.modified_non_trans_table) { - DBUG_ASSERT(table != NULL); - if (!table->file->has_transactions()) - { if (mysql_bin_log.is_open()) thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query, thd->query_length, - table->file->has_transactions(), FALSE); - if (!thd->current_stmt_binlog_row_based && !table->s->tmp_table && - !can_rollback_data()) + transactional_table, FALSE); + if (!thd->current_stmt_binlog_row_based && !can_rollback_data()) thd->transaction.all.modified_non_trans_table= TRUE; - query_cache_invalidate3(thd, table, 1); - } + if (changed) + query_cache_invalidate3(thd, table, 1); } + DBUG_ASSERT(transactional_table || !changed || + thd->transaction.stmt.modified_non_trans_table); table->file->ha_release_auto_increment(); } From 0c153419ce54f2ca63ad13b2f71e63b8ccf11839 Mon Sep 17 00:00:00 2001 From: "aelkin@dl145j.mysql.com" <> Date: Mon, 17 Sep 2007 12:31:10 +0200 Subject: [PATCH 019/336] Merge: bug@27417,23333 and bug#28960 tests with 5.1 --- .../mix_innodb_myisam_side_effects.test | 234 ++++++++++++++++++ .../r/binlog_row_mix_innodb_myisam.result | 186 ++++++++++++++ .../r/binlog_stm_mix_innodb_myisam.result | 45 ++-- .../t/binlog_row_mix_innodb_myisam.test | 2 + .../t/binlog_stm_mix_innodb_myisam.test | 234 +----------------- 5 files changed, 443 insertions(+), 258 deletions(-) create mode 100644 mysql-test/extra/binlog_tests/mix_innodb_myisam_side_effects.test diff --git a/mysql-test/extra/binlog_tests/mix_innodb_myisam_side_effects.test b/mysql-test/extra/binlog_tests/mix_innodb_myisam_side_effects.test new file mode 100644 index 00000000000..6c961c4694d --- /dev/null +++ b/mysql-test/extra/binlog_tests/mix_innodb_myisam_side_effects.test @@ -0,0 +1,234 @@ +# the file to be sourced from binlog.binlog_mix_innodb_myisam + +# +# Bug #27417 thd->no_trans_update.stmt lost value inside of SF-exec-stack +# bug #28960 non-trans temp table changes with insert .. select +# not binlogged after rollback +# +# testing appearence of insert into temp_table in binlog. +# There are two branches of execution that require different setup. + +# checking binlog content filled with row-based events due to +# a used stored function modifies non-transactional table + +## send_eof() branch + +# prepare + +create temporary table tt (a int unique); +create table ti (a int) engine=innodb; +reset master; +show master status; + +# action + +begin; +insert into ti values (1); +insert into ti values (2) ; +insert into tt select * from ti; +rollback; + +# check + +select count(*) from tt /* 2 */; +show master status; +source include/show_binlog_events.inc; +select count(*) from ti /* zero */; +insert into ti select * from tt; +select * from ti /* that is what slave would miss - bug#28960 */; + + +## send_error() branch +delete from ti; +delete from tt where a=1; +reset master; +show master status; + +# action + +begin; +insert into ti values (1); +insert into ti values (2) /* to make the dup error in the following */; +--error ER_DUP_ENTRY +insert into tt select * from ti /* one affected and error */; +rollback; + +# check + +show master status; +source include/show_binlog_events.inc; # nothing in binlog with row bilog format +select count(*) from ti /* zero */; +insert into ti select * from tt; +select * from tt /* that is what otherwise slave missed - the bug */; + +drop table ti; + + +# +# Bug #27417 thd->no_trans_update.stmt lost value inside of SF-exec-stack +# +# Testing asserts: if there is a side effect of modifying non-transactional +# table thd->no_trans_update.stmt must be TRUE; +# the assert is active with debug build +# + +--disable_warnings +drop function if exists bug27417; +drop table if exists t1,t2; +--enable_warnings +# side effect table +CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; +# target tables +CREATE TABLE t2 (a int NOT NULL auto_increment, PRIMARY KEY (a)); + +delimiter |; +create function bug27417(n int) +RETURNS int(11) +begin + insert into t1 values (null); + return n; +end| +delimiter ;| + +reset master; + +# execute + +insert into t2 values (bug27417(1)); +insert into t2 select bug27417(2); +reset master; + +--error ER_DUP_ENTRY +insert into t2 values (bug27417(2)); +source include/show_binlog_events.inc; #only (!) with fixes for #23333 will show there is the query +select count(*) from t1 /* must be 3 */; + +reset master; +select count(*) from t2; +delete from t2 where a=bug27417(3); +select count(*) from t2 /* nothing got deleted */; +source include/show_binlog_events.inc; # the query must be in regardless of #23333 +select count(*) from t1 /* must be 5 */; + +--enable_info +delete t2 from t2 where t2.a=bug27417(100) /* must not affect t2 */; +--disable_info +select count(*) from t1 /* must be 7 */; + +# function bug27417 remains for the following testing of bug#23333 +drop table t1,t2; + +# +# Bug#23333 using the patch (and the test) for bug#27471 +# throughout the bug tests +# t1 - non-trans side effects gatherer; +# t2 - transactional table; +# +CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; +CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; +CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); + + +# +# INSERT +# + +# prepare + + insert into t2 values (1); + reset master; + +# execute + + --error ER_DUP_ENTRY + insert into t2 values (bug27417(1)); + +# check + + source include/show_binlog_events.inc; # must be event of the query + select count(*) from t1 /* must be 1 */; + +# +# INSERT SELECT +# + +# prepare + delete from t1; + delete from t2; + insert into t2 values (2); + reset master; + +# execute + + --error ER_DUP_ENTRY + insert into t2 select bug27417(1) union select bug27417(2); + +# check + + source include/show_binlog_events.inc; # must be events of the query + select count(*) from t1 /* must be 2 */; + +# +# UPDATE (multi-update see bug#27716) +# + +# prepare + delete from t1; + insert into t3 values (1,1),(2,3),(3,4); + reset master; + +# execute + --error ER_DUP_ENTRY + update t3 set b=b+bug27417(1); + +# check + source include/show_binlog_events.inc; # must be events of the query + select count(*) from t1 /* must be 2 */; + + +# +# DELETE (for multi-delete see Bug #29136) +# + +# prepare + delete from t1; + delete from t2; + delete from t3; + insert into t2 values (1); + insert into t3 values (1,1); + create trigger trg_del before delete on t2 for each row + insert into t3 values (bug27417(1), 2); + reset master; + +# execute + --error ER_DUP_ENTRY + delete from t2; +# check + source include/show_binlog_events.inc; # must be events of the query + select count(*) from t1 /* must be 1 */; + + +# +# LOAD DATA +# + +# prepare + delete from t1; + create table t4 (a int default 0, b int primary key) engine=innodb; + insert into t4 values (0, 17); + reset master; + +# execute + --error ER_DUP_ENTRY + load data infile '../std_data_ln/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2); +# check + select * from t4; + select count(*) from t1 /* must be 2 */; + source include/show_binlog_events.inc; # must be events of the query + +# +# bug#23333 cleanup +# +drop trigger trg_del; +drop table t1,t2,t3,t4; +drop function bug27417; diff --git a/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result b/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result index 6ac942176c7..8022f2b1e10 100644 --- a/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result +++ b/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result @@ -413,3 +413,189 @@ select @a like "%#%error_code=0%ROLLBACK/*!*/;%ROLLBACK /* added by mysqlbinlog */;%" @a not like "%#%error_code=%error_code=%" 1 1 drop table t1, t2; +create temporary table tt (a int unique); +create table ti (a int) engine=innodb; +reset master; +show master status; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 106 +begin; +insert into ti values (1); +insert into ti values (2) ; +insert into tt select * from ti; +rollback; +Warnings: +Warning 1196 Some non-transactional changed tables couldn't be rolled back +select count(*) from tt /* 2 */; +count(*) +2 +show master status; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 395 +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; BEGIN +master-bin.000001 # Table_map # # table_id: # (test.ti) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (test.ti) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # use `test`; ROLLBACK +select count(*) from ti /* zero */; +count(*) +0 +insert into ti select * from tt; +select * from ti /* that is what slave would miss - bug#28960 */; +a +1 +2 +delete from ti; +delete from tt where a=1; +reset master; +show master status; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 106 +begin; +insert into ti values (1); +insert into ti values (2) /* to make the dup error in the following */; +insert into tt select * from ti /* one affected and error */; +ERROR 23000: Duplicate entry '2' for key 'a' +rollback; +show master status; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 106 +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +select count(*) from ti /* zero */; +count(*) +0 +insert into ti select * from tt; +select * from tt /* that is what otherwise slave missed - the bug */; +a +1 +2 +drop table ti; +drop function if exists bug27417; +drop table if exists t1,t2; +CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; +CREATE TABLE t2 (a int NOT NULL auto_increment, PRIMARY KEY (a)); +create function bug27417(n int) +RETURNS int(11) +begin +insert into t1 values (null); +return n; +end| +reset master; +insert into t2 values (bug27417(1)); +insert into t2 select bug27417(2); +reset master; +insert into t2 values (bug27417(2)); +ERROR 23000: Duplicate entry '2' for key 'PRIMARY' +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Intvar # # INSERT_ID=3 +master-bin.000001 # Query # # use `test`; insert into t2 values (bug27417(2)) +select count(*) from t1 /* must be 3 */; +count(*) +3 +reset master; +select count(*) from t2; +count(*) +2 +delete from t2 where a=bug27417(3); +select count(*) from t2 /* nothing got deleted */; +count(*) +2 +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Intvar # # INSERT_ID=4 +master-bin.000001 # Query # # use `test`; delete from t2 where a=bug27417(3) +select count(*) from t1 /* must be 5 */; +count(*) +5 +delete t2 from t2 where t2.a=bug27417(100) /* must not affect t2 */; +affected rows: 0 +select count(*) from t1 /* must be 7 */; +count(*) +7 +drop table t1,t2; +CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; +CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; +CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); +insert into t2 values (1); +reset master; +insert into t2 values (bug27417(1)); +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Intvar # # INSERT_ID=1 +master-bin.000001 # Query # # use `test`; insert into t2 values (bug27417(1)) +master-bin.000001 # Query # # use `test`; ROLLBACK +select count(*) from t1 /* must be 1 */; +count(*) +1 +delete from t1; +delete from t2; +insert into t2 values (2); +reset master; +insert into t2 select bug27417(1) union select bug27417(2); +ERROR 23000: Duplicate entry '2' for key 'PRIMARY' +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Intvar # # INSERT_ID=2 +master-bin.000001 # Query # # use `test`; insert into t2 select bug27417(1) union select bug27417(2) +master-bin.000001 # Query # # use `test`; ROLLBACK +select count(*) from t1 /* must be 2 */; +count(*) +2 +delete from t1; +insert into t3 values (1,1),(2,3),(3,4); +reset master; +update t3 set b=b+bug27417(1); +ERROR 23000: Duplicate entry '4' for key 'b' +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Intvar # # INSERT_ID=4 +master-bin.000001 # Query # # use `test`; update t3 set b=b+bug27417(1) +select count(*) from t1 /* must be 2 */; +count(*) +2 +delete from t1; +delete from t2; +delete from t3; +insert into t2 values (1); +insert into t3 values (1,1); +create trigger trg_del before delete on t2 for each row +insert into t3 values (bug27417(1), 2); +reset master; +delete from t2; +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Intvar # # INSERT_ID=6 +master-bin.000001 # Query # # use `test`; delete from t2 +master-bin.000001 # Query # # use `test`; ROLLBACK +select count(*) from t1 /* must be 1 */; +count(*) +1 +delete from t1; +create table t4 (a int default 0, b int primary key) engine=innodb; +insert into t4 values (0, 17); +reset master; +load data infile '../std_data_ln/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2); +ERROR 23000: Duplicate entry '17' for key 'PRIMARY' +select * from t4; +a b +0 17 +select count(*) from t1 /* must be 2 */; +count(*) +2 +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Intvar # # INSERT_ID=7 +master-bin.000001 # Begin_load_query # # ;file_id=1;block_len=12 +master-bin.000001 # Intvar # # INSERT_ID=7 +master-bin.000001 # Execute_load_query # # use `test`; load data infile '../std_data_ln/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2) ;file_id=1 +master-bin.000001 # Query # # use `test`; ROLLBACK +drop trigger trg_del; +drop table t1,t2,t3,t4; +drop function bug27417; diff --git a/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result b/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result index 564fa8d86bd..9c580b2312e 100644 --- a/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result +++ b/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result @@ -380,6 +380,7 @@ select @a like "%#%error_code=0%ROLLBACK/*!*/;%ROLLBACK /* added by mysqlbinlog */;%" @a not like "%#%error_code=%error_code=%" 1 1 drop table t1, t2; +set @@session.binlog_format=statement; create temporary table tt (a int unique); create table ti (a int) engine=innodb; reset master; @@ -465,9 +466,8 @@ insert into t2 values (bug27417(2)); ERROR 23000: Duplicate entry '2' for key 'PRIMARY' show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Table_map # # table_id: # (test.t2) -master-bin.000001 # Table_map # # table_id: # (test.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Intvar # # INSERT_ID=3 +master-bin.000001 # Query # # use `test`; insert into t2 values (bug27417(2)) select count(*) from t1 /* must be 3 */; count(*) 3 @@ -481,9 +481,8 @@ count(*) 2 show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Table_map # # table_id: # (test.t2) -master-bin.000001 # Table_map # # table_id: # (test.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Intvar # # INSERT_ID=4 +master-bin.000001 # Query # # use `test`; delete from t2 where a=bug27417(3) select count(*) from t1 /* must be 5 */; count(*) 5 @@ -502,9 +501,8 @@ insert into t2 values (bug27417(1)); ERROR 23000: Duplicate entry '1' for key 'PRIMARY' show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Table_map # # table_id: # (test.t2) -master-bin.000001 # Table_map # # table_id: # (test.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Intvar # # INSERT_ID=1 +master-bin.000001 # Query # # use `test`; insert into t2 values (bug27417(1)) master-bin.000001 # Query # # use `test`; ROLLBACK select count(*) from t1 /* must be 1 */; count(*) @@ -517,10 +515,8 @@ insert into t2 select bug27417(1) union select bug27417(2); ERROR 23000: Duplicate entry '2' for key 'PRIMARY' show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Table_map # # table_id: # (test.t2) -master-bin.000001 # Table_map # # table_id: # (test.t1) -master-bin.000001 # Write_rows # # table_id: # -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Intvar # # INSERT_ID=2 +master-bin.000001 # Query # # use `test`; insert into t2 select bug27417(1) union select bug27417(2) master-bin.000001 # Query # # use `test`; ROLLBACK select count(*) from t1 /* must be 2 */; count(*) @@ -532,11 +528,8 @@ update t3 set b=b+bug27417(1); ERROR 23000: Duplicate entry '4' for key 'b' show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Table_map # # table_id: # (test.t3) -master-bin.000001 # Table_map # # table_id: # (test.t1) -master-bin.000001 # Write_rows # # table_id: # -master-bin.000001 # Update_rows # # table_id: # -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Intvar # # INSERT_ID=4 +master-bin.000001 # Query # # use `test`; update t3 set b=b+bug27417(1) select count(*) from t1 /* must be 2 */; count(*) 2 @@ -552,10 +545,8 @@ delete from t2; ERROR 23000: Duplicate entry '1' for key 'PRIMARY' show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Table_map # # table_id: # (test.t2) -master-bin.000001 # Table_map # # table_id: # (test.t3) -master-bin.000001 # Table_map # # table_id: # (test.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Intvar # # INSERT_ID=6 +master-bin.000001 # Query # # use `test`; delete from t2 master-bin.000001 # Query # # use `test`; ROLLBACK select count(*) from t1 /* must be 1 */; count(*) @@ -574,13 +565,13 @@ count(*) 2 show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Table_map # # table_id: # (test.t4) -master-bin.000001 # Table_map # # table_id: # (test.t1) -master-bin.000001 # Write_rows # # table_id: # -master-bin.000001 # Write_rows # # table_id: # -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Intvar # # INSERT_ID=7 +master-bin.000001 # Begin_load_query # # ;file_id=1;block_len=12 +master-bin.000001 # Intvar # # INSERT_ID=7 +master-bin.000001 # Execute_load_query # # use `test`; load data infile '../std_data_ln/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2) ;file_id=1 master-bin.000001 # Query # # use `test`; ROLLBACK drop trigger trg_del; drop table t1,t2,t3,t4; drop function bug27417; +set @@session.binlog_format=@@global.binlog_format; end of tests diff --git a/mysql-test/suite/binlog/t/binlog_row_mix_innodb_myisam.test b/mysql-test/suite/binlog/t/binlog_row_mix_innodb_myisam.test index 7b7753a487e..3148cc50fd0 100644 --- a/mysql-test/suite/binlog/t/binlog_row_mix_innodb_myisam.test +++ b/mysql-test/suite/binlog/t/binlog_row_mix_innodb_myisam.test @@ -31,3 +31,5 @@ eval select @a like "%#%error_code=0%ROLLBACK/*!*/;%ROLLBACK /* added by mysqlbinlog */;%", @a not like "%#%error_code=%error_code=%"; drop table t1, t2; + +-- source extra/binlog_tests/mix_innodb_myisam_side_effects.test diff --git a/mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test b/mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test index 14397f85c38..e7149e03b87 100644 --- a/mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test +++ b/mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test @@ -24,237 +24,9 @@ eval select drop table t1, t2; -# -# Bug #27417 thd->no_trans_update.stmt lost value inside of SF-exec-stack -# bug #28960 non-trans temp table changes with insert .. select -# not binlogged after rollback -# -# testing appearence of insert into temp_table in binlog. -# There are two branches of execution that require different setup. - -## send_eof() branch - -# prepare - -create temporary table tt (a int unique); -create table ti (a int) engine=innodb; -reset master; -show master status; - -# action - -begin; -insert into ti values (1); -insert into ti values (2) ; -insert into tt select * from ti; -rollback; - -# check - -select count(*) from tt /* 2 */; -show master status; -source include/show_binlog_events.inc; -select count(*) from ti /* zero */; -insert into ti select * from tt; -select * from ti /* that is what slave would miss - bug#28960 */; - - -## send_error() branch -delete from ti; -delete from tt where a=1; -reset master; -show master status; - -# action - -begin; -insert into ti values (1); -insert into ti values (2) /* to make the dup error in the following */; ---error ER_DUP_ENTRY -insert into tt select * from ti /* one affected and error */; -rollback; - -# check - -show master status; -source include/show_binlog_events.inc; -select count(*) from ti /* zero */; -insert into ti select * from tt; -select * from tt /* that is what otherwise slave missed - the bug */; - -drop table ti; - - -# -# Bug #27417 thd->no_trans_update.stmt lost value inside of SF-exec-stack -# -# Testing asserts: if there is a side effect of modifying non-transactional -# table thd->no_trans_update.stmt must be TRUE; -# the assert is active with debug build -# - ---disable_warnings -drop function if exists bug27417; -drop table if exists t1,t2; ---enable_warnings -# side effect table -CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; -# target tables -CREATE TABLE t2 (a int NOT NULL auto_increment, PRIMARY KEY (a)); - -delimiter |; -create function bug27417(n int) -RETURNS int(11) -begin - insert into t1 values (null); - return n; -end| -delimiter ;| - -reset master; - -# execute - -insert into t2 values (bug27417(1)); -insert into t2 select bug27417(2); -reset master; - ---error ER_DUP_ENTRY -insert into t2 values (bug27417(2)); -source include/show_binlog_events.inc; #only (!) with fixes for #23333 will show there is the query -select count(*) from t1 /* must be 3 */; - -reset master; -select count(*) from t2; -delete from t2 where a=bug27417(3); -select count(*) from t2 /* nothing got deleted */; -source include/show_binlog_events.inc; # the query must be in regardless of #23333 -select count(*) from t1 /* must be 5 */; - ---enable_info -delete t2 from t2 where t2.a=bug27417(100) /* must not affect t2 */; ---disable_info -select count(*) from t1 /* must be 7 */; - -# function bug27417 remains for the following testing of bug#23333 -drop table t1,t2; - -# -# Bug#23333 using the patch (and the test) for bug#27471 -# throughout the bug tests -# t1 - non-trans side effects gatherer; -# t2 - transactional table; -# -CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; -CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; -CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); - - -# -# INSERT -# - -# prepare - - insert into t2 values (1); - reset master; - -# execute - - --error ER_DUP_ENTRY - insert into t2 values (bug27417(1)); - -# check - - source include/show_binlog_events.inc; # must be event of the query - select count(*) from t1 /* must be 1 */; - -# -# INSERT SELECT -# - -# prepare - delete from t1; - delete from t2; - insert into t2 values (2); - reset master; - -# execute - - --error ER_DUP_ENTRY - insert into t2 select bug27417(1) union select bug27417(2); - -# check - - source include/show_binlog_events.inc; # must be events of the query - select count(*) from t1 /* must be 2 */; - -# -# UPDATE (multi-update see bug#27716) -# - -# prepare - delete from t1; - insert into t3 values (1,1),(2,3),(3,4); - reset master; - -# execute - --error ER_DUP_ENTRY - update t3 set b=b+bug27417(1); - -# check - source include/show_binlog_events.inc; # must be events of the query - select count(*) from t1 /* must be 2 */; - - -# -# DELETE (for multi-delete see Bug #29136) -# - -# prepare - delete from t1; - delete from t2; - delete from t3; - insert into t2 values (1); - insert into t3 values (1,1); - create trigger trg_del before delete on t2 for each row - insert into t3 values (bug27417(1), 2); - reset master; - -# execute - --error ER_DUP_ENTRY - delete from t2; -# check - source include/show_binlog_events.inc; # must be events of the query - select count(*) from t1 /* must be 1 */; - - -# -# LOAD DATA -# - -# prepare - delete from t1; - create table t4 (a int default 0, b int primary key) engine=innodb; - insert into t4 values (0, 17); - reset master; - -# execute - --error ER_DUP_ENTRY - load data infile '../std_data_ln/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2); -# check - select * from t4; - select count(*) from t1 /* must be 2 */; - source include/show_binlog_events.inc; # must be events of the query - -# -# bug#23333 cleanup -# - - -drop trigger trg_del; -drop table t1,t2,t3,t4; -drop function bug27417; +set @@session.binlog_format=statement; +-- source extra/binlog_tests/mix_innodb_myisam_side_effects.test +set @@session.binlog_format=@@global.binlog_format; --echo end of tests From cd88c4dc8aae41aa810743a3b6ed6568cb778edd Mon Sep 17 00:00:00 2001 From: "mats@kindahl-laptop.dnsalias.net" <> Date: Fri, 21 Sep 2007 08:13:52 +0200 Subject: [PATCH 020/336] Fixing bug in test in that a database was not dropped and was visible in following tests. --- mysql-test/suite/rpl/r/rpl_bug31076.result | 1 + mysql-test/suite/rpl/t/rpl_bug31076.test | 3 +++ 2 files changed, 4 insertions(+) diff --git a/mysql-test/suite/rpl/r/rpl_bug31076.result b/mysql-test/suite/rpl/r/rpl_bug31076.result index c991b2f1946..2d6bed37901 100644 --- a/mysql-test/suite/rpl/r/rpl_bug31076.result +++ b/mysql-test/suite/rpl/r/rpl_bug31076.result @@ -61,3 +61,4 @@ visits_id myid src ip cc org ref time host entry visit_exit user_id visit_start SELECT * FROM visits_events; event_id visit_id timestamp src data visits_events_id 20000 21231038 2007-09-18 03:59:02 Downloads/MySQL-4.1/mysql-4.1.12a-win32.zip 33712207 +DROP DATABASE track; diff --git a/mysql-test/suite/rpl/t/rpl_bug31076.test b/mysql-test/suite/rpl/t/rpl_bug31076.test index 6cb8cc0d902..95fb1e5fb96 100644 --- a/mysql-test/suite/rpl/t/rpl_bug31076.test +++ b/mysql-test/suite/rpl/t/rpl_bug31076.test @@ -111,3 +111,6 @@ VALUES ('3m3l4rhs6do0sf5p1i9lr94g928a272v', '', '', INET_ATON('71.118.124.98'), SELECT * FROM visits; SELECT * FROM visits_events; + +DROP DATABASE track; +sync_slave_with_master; From 5dc3fbf187520ff34b1b0c16c2dc27908271bcc7 Mon Sep 17 00:00:00 2001 From: "aelkin/elkin@koti.dsl.inet.fi" <> Date: Wed, 26 Sep 2007 21:59:17 +0200 Subject: [PATCH 021/336] Bug #26000 SHOW SLAVE STATUS can crash mysqld during shutdown process active_mi has been reset (shutdown) at the time of quering with SHOW SLAVE STATUS so that at handling of SHOW an attempt to read its members segfaults. Fixed with checking the value of active_mi before to call show_master_info() Merely send_ok() is invoked when active_mi does not exist. A test can not be easiely written. Notice, there are more analogical cases in the code which require a similar treatment (to be reported as a bug separately). --- sql/sql_parse.cc | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 58f5ffc5235..075ce2c9e8c 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2844,7 +2844,16 @@ mysql_execute_command(THD *thd) if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL)) goto error; pthread_mutex_lock(&LOCK_active_mi); - res = show_master_info(thd,active_mi); + if (active_mi != NULL) + { + res = show_master_info(thd, active_mi); + } + else + { + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0, + "the master info structure does not exist"); + send_ok(thd); + } pthread_mutex_unlock(&LOCK_active_mi); break; } From 33ad13280c22e0d5b1ba6bd6ceb920f49a678d95 Mon Sep 17 00:00:00 2001 From: "kent@mysql.com/kent-amd64.(none)" <> Date: Fri, 28 Sep 2007 22:35:48 +0200 Subject: [PATCH 022/336] ctype-simple.c: Avoid undefined value when negating (bug#30069) --- strings/ctype-simple.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/strings/ctype-simple.c b/strings/ctype-simple.c index ccdfb5936b7..0355803daa8 100644 --- a/strings/ctype-simple.c +++ b/strings/ctype-simple.c @@ -802,7 +802,7 @@ int my_long10_to_str_8bit(CHARSET_INFO *cs __attribute__((unused)), { if (val < 0) { - val= -val; + val= -(unsigned long int)val; *dst++= '-'; len--; sign= 1; @@ -838,7 +838,7 @@ int my_longlong10_to_str_8bit(CHARSET_INFO *cs __attribute__((unused)), { if (val < 0) { - val = -val; + val = -(ulonglong)val; *dst++= '-'; len--; sign= 1; From aacebc7ce8b1ab071f35c0cc9f21bfd66e888ae1 Mon Sep 17 00:00:00 2001 From: "bar@mysql.com/bar.myoffice.izhnet.ru" <> Date: Mon, 1 Oct 2007 15:35:42 +0500 Subject: [PATCH 023/336] Bug#30315 Character sets: insertion of euckr code value 0xa141 fails Problem: some valid euc-kr characters were rejected because condition checking multi-byte tail didn't allow multi-byte characters having the second byte in the ranges [0x41..0x5A] and [0x61..0x7A]. Fix: allow these byte ranges for mb tails --- mysql-test/r/ctype_euckr.result | 41 +++++++++++++++++++++++++++++++++ mysql-test/t/ctype_euckr.test | 23 ++++++++++++++++++ strings/ctype-euc_kr.c | 27 ++++++++++++++++++---- 3 files changed, 87 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/ctype_euckr.result b/mysql-test/r/ctype_euckr.result index 6017bc07763..57e3e2ed8f8 100644 --- a/mysql-test/r/ctype_euckr.result +++ b/mysql-test/r/ctype_euckr.result @@ -165,3 +165,44 @@ hex(a) A2E6 FEF7 DROP TABLE t1; +create table t1 (s1 varchar(5) character set euckr); +insert into t1 values (0xA141); +insert into t1 values (0xA15A); +insert into t1 values (0xA161); +insert into t1 values (0xA17A); +insert into t1 values (0xA181); +insert into t1 values (0xA1FE); +insert into t1 values (0xA140); +Warnings: +Warning 1366 Incorrect string value: '\xA1@' for column 's1' at row 1 +insert into t1 values (0xA15B); +Warnings: +Warning 1366 Incorrect string value: '\xA1[' for column 's1' at row 1 +insert into t1 values (0xA160); +Warnings: +Warning 1366 Incorrect string value: '\xA1`' for column 's1' at row 1 +insert into t1 values (0xA17B); +Warnings: +Warning 1366 Incorrect string value: '\xA1{' for column 's1' at row 1 +insert into t1 values (0xA180); +Warnings: +Warning 1366 Incorrect string value: '\xA1\x80' for column 's1' at row 1 +insert into t1 values (0xA1FF); +Warnings: +Warning 1366 Incorrect string value: '\xA1\xFF' for column 's1' at row 1 +select hex(s1), hex(convert(s1 using utf8)) from t1 order by binary s1; +hex(s1) hex(convert(s1 using utf8)) + + + + + + +A141 ECA2A5 +A15A ECA381 +A161 ECA382 +A17A ECA3A5 +A181 ECA3A6 +A1FE EFBFA2 +drop table t1; +End of 5.0 tests diff --git a/mysql-test/t/ctype_euckr.test b/mysql-test/t/ctype_euckr.test index 56939817b2f..05e4b04eded 100644 --- a/mysql-test/t/ctype_euckr.test +++ b/mysql-test/t/ctype_euckr.test @@ -31,3 +31,26 @@ SELECT hex(a) FROM t1 ORDER BY a; DROP TABLE t1; # End of 4.1 tests + +# +#Bug #30315 Character sets: insertion of euckr code value 0xa141 fails +# +create table t1 (s1 varchar(5) character set euckr); +# Insert some valid characters +insert into t1 values (0xA141); +insert into t1 values (0xA15A); +insert into t1 values (0xA161); +insert into t1 values (0xA17A); +insert into t1 values (0xA181); +insert into t1 values (0xA1FE); +# Insert some invalid characters +insert into t1 values (0xA140); +insert into t1 values (0xA15B); +insert into t1 values (0xA160); +insert into t1 values (0xA17B); +insert into t1 values (0xA180); +insert into t1 values (0xA1FF); +select hex(s1), hex(convert(s1 using utf8)) from t1 order by binary s1; +drop table t1; + +--echo End of 5.0 tests diff --git a/strings/ctype-euc_kr.c b/strings/ctype-euc_kr.c index abaa8f1a516..1aaf65c98b3 100644 --- a/strings/ctype-euc_kr.c +++ b/strings/ctype-euc_kr.c @@ -179,20 +179,39 @@ static uchar NEAR sort_order_euc_kr[]= /* Support for Korean(EUC_KR) characters, by powerm90@tinc.co.kr and mrpark@tinc.co.kr */ -#define iseuc_kr(c) ((0xa1<=(uchar)(c) && (uchar)(c)<=0xfe)) +/* + Unicode mapping is done according to: + ftp://ftp.unicode.org/Public/MAPPINGS/OBSOLETE/EASTASIA/KSC/KSC5601.TXT + + Valid multi-byte characters: + + [A1..FE][41..5A,61..7A,81..FE] + + Note, 0x5C is not a valid MB tail, + so escape_with_backslash_is_dangerous is not set. +*/ +#define iseuc_kr_head(c) ((0xa1<=(uchar)(c) && (uchar)(c)<=0xfe)) + +#define iseuc_kr_tail1(c) ((uchar) (c) >= 0x41 && (uchar) (c) <= 0x5A) +#define iseuc_kr_tail2(c) ((uchar) (c) >= 0x61 && (uchar) (c) <= 0x7A) +#define iseuc_kr_tail3(c) ((uchar) (c) >= 0x81 && (uchar) (c) <= 0xFE) + +#define iseuc_kr_tail(c) (iseuc_kr_tail1(c) || \ + iseuc_kr_tail2(c) || \ + iseuc_kr_tail3(c)) static int ismbchar_euc_kr(CHARSET_INFO *cs __attribute__((unused)), const char* p, const char *e) { return ((*(uchar*)(p)<0x80)? 0:\ - iseuc_kr(*(p)) && (e)-(p)>1 && iseuc_kr(*((p)+1))? 2:\ + iseuc_kr_head(*(p)) && (e)-(p)>1 && iseuc_kr_tail(*((p)+1))? 2:\ 0); } static int mbcharlen_euc_kr(CHARSET_INFO *cs __attribute__((unused)),uint c) { - return (iseuc_kr(c) ? 2 : 1); + return (iseuc_kr_head(c) ? 2 : 1); } @@ -8653,7 +8672,7 @@ my_well_formed_len_euckr(CHARSET_INFO *cs __attribute__((unused)), /* Single byte ascii character */ b++; } - else if (b < emb && iseuc_kr(*b) && iseuc_kr(b[1])) + else if (b < emb && iseuc_kr_head(*b) && iseuc_kr_tail(b[1])) { /* Double byte character */ b+= 2; From 065bcba38eca86e56d5636055fe5b18a6b44b923 Mon Sep 17 00:00:00 2001 From: "bar@mysql.com/bar.myoffice.izhnet.ru" <> Date: Tue, 2 Oct 2007 13:28:58 +0500 Subject: [PATCH 024/336] Fixing comments to use "#" instead of "--" --- mysql-test/t/ctype_uca.test | 2 +- mysql-test/t/subselect.test | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/t/ctype_uca.test b/mysql-test/t/ctype_uca.test index 17632e7c8fc..695a21adbf5 100644 --- a/mysql-test/t/ctype_uca.test +++ b/mysql-test/t/ctype_uca.test @@ -530,7 +530,7 @@ create table t1 ( a varchar(255), key a(a) ) character set utf8 collate utf8_czech_ci; --- In Czech 'ch' is a single letter between 'h' and 'i' +# In Czech 'ch' is a single letter between 'h' and 'i' insert into t1 values ('b'),('c'),('d'),('e'),('f'),('g'),('h'),('ch'),('i'),('j'); select * from t1 where a like 'c%'; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index d076ca6bd33..86d2aec870c 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -2970,7 +2970,7 @@ DROP TABLE t1,t2; CREATE TABLE t1 (a INT, b INT); INSERT INTO t1 VALUES (1, 2), (1,3), (1,4), (2,1), (2,2); --- returns no rows, when it should +# returns no rows, when it should SELECT a1.a, COUNT(*) FROM t1 a1 WHERE a1.a = 1 AND EXISTS( SELECT a2.a FROM t1 a2 WHERE a2.a = a1.a) GROUP BY a1.a; From 5e14f4f038773440ac168a723932683fa91ccb4d Mon Sep 17 00:00:00 2001 From: "bar@mysql.com/bar.myoffice.izhnet.ru" <> Date: Tue, 2 Oct 2007 15:20:45 +0500 Subject: [PATCH 025/336] Bug#29675 collation_connection is defined twice for the same value Removing redundant initialization. --- sql/mysqld.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 08c2b60fa79..9b339a59946 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2849,7 +2849,6 @@ static int init_common_variables(const char *conf_file_name, int argc, global_system_variables.collation_connection= default_charset_info; global_system_variables.character_set_results= default_charset_info; global_system_variables.character_set_client= default_charset_info; - global_system_variables.collation_connection= default_charset_info; if (!(character_set_filesystem= get_charset_by_csname(character_set_filesystem_name, From 5daff6547edcec209393940e384a49d1c7782668 Mon Sep 17 00:00:00 2001 From: "sven@murkla.(none)" <> Date: Wed, 3 Oct 2007 11:57:14 +0200 Subject: [PATCH 026/336] BUG#30752 rpl_dual_pos_advance valgrind (jump depends on uninitialized LOG_INFO) Problem: one thread could read uninitialized memory from (the stack of) another thread. Fix: swapped order of initializing the memory and making it available to the other thread. Fix: put lock around the statement that makes the memory available to the other thread. Fix: all fields of the struct are now initialized in the constructor, to avoid future problems. --- sql/sql_class.h | 8 +++++++- sql/sql_repl.cc | 10 ++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/sql/sql_class.h b/sql/sql_class.h index 4fac86dc405..a96000a0598 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -159,7 +159,13 @@ typedef struct st_log_info my_off_t pos; bool fatal; // if the purge happens to give us a negative offset pthread_mutex_t lock; - st_log_info():fatal(0) { pthread_mutex_init(&lock, MY_MUTEX_INIT_FAST);} + st_log_info() + : index_file_offset(0), index_file_start_offset(0), + pos(0), fatal(0) + { + log_file_name[0] = '\0'; + pthread_mutex_init(&lock, MY_MUTEX_INIT_FAST); + } ~st_log_info() { pthread_mutex_destroy(&lock);} } LOG_INFO; diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 9cc0ba7c29a..903d254db8f 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -364,7 +364,6 @@ void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos, name=0; // Find first log linfo.index_file_offset = 0; - thd->current_linfo = &linfo; if (mysql_bin_log.find_log_pos(&linfo, name, 1)) { @@ -373,6 +372,10 @@ void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos, goto err; } + pthread_mutex_lock(&LOCK_thread_count); + thd->current_linfo = &linfo; + pthread_mutex_unlock(&LOCK_thread_count); + if ((file=open_binlog(&log, log_file_name, &errmsg)) < 0) { my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG; @@ -1338,7 +1341,6 @@ bool mysql_show_binlog_events(THD* thd) name=0; // Find first log linfo.index_file_offset = 0; - thd->current_linfo = &linfo; if (mysql_bin_log.find_log_pos(&linfo, name, 1)) { @@ -1346,6 +1348,10 @@ bool mysql_show_binlog_events(THD* thd) goto err; } + pthread_mutex_lock(&LOCK_thread_count); + thd->current_linfo = &linfo; + pthread_mutex_unlock(&LOCK_thread_count); + if ((file=open_binlog(&log, linfo.log_file_name, &errmsg)) < 0) goto err; From 2b42750a513acf4c3b424e1de2f96282d6ad5f87 Mon Sep 17 00:00:00 2001 From: "bar@mysql.com/bar.myoffice.izhnet.ru" <> Date: Thu, 4 Oct 2007 13:06:01 +0500 Subject: [PATCH 027/336] Bug#29323 mysql client only accetps ANSI encoded files Fix: ignore BOM marker in the first line. --- client/mysql.cc | 11 +++++++++++ mysql-test/r/mysql.result | 2 ++ mysql-test/t/mysql.test | 9 +++++++++ 3 files changed, 22 insertions(+) diff --git a/client/mysql.cc b/client/mysql.cc index 8e1b6c2a9b4..3cc7f2ad090 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -1042,6 +1042,17 @@ static int read_and_execute(bool interactive) if (!interactive) { line=batch_readline(status.line_buff); + /* + Skip UTF8 Byte Order Marker (BOM) 0xEFBBBF. + Editors like "notepad" put this marker in + the very beginning of a text file when + you save the file using "Unicode UTF-8" format. + */ + if (!line_number && + (uchar) line[0] == 0xEF && + (uchar) line[1] == 0xBB && + (uchar) line[2] == 0xBF) + line+= 3; line_number++; if (!glob_buffer.length()) status.query_start_line=line_number; diff --git a/mysql-test/r/mysql.result b/mysql-test/r/mysql.result index c6e589a5fb7..eded1a3fc3b 100644 --- a/mysql-test/r/mysql.result +++ b/mysql-test/r/mysql.result @@ -178,4 +178,6 @@ ERROR at line 1: DELIMITER cannot contain a backslash character 1 1 1 +This is a file starting with UTF8 BOM 0xEFBBBF +This is a file starting with UTF8 BOM 0xEFBBBF End of 5.0 tests diff --git a/mysql-test/t/mysql.test b/mysql-test/t/mysql.test index 6e97d0faede..182b292c817 100644 --- a/mysql-test/t/mysql.test +++ b/mysql-test/t/mysql.test @@ -281,4 +281,13 @@ remove_file $MYSQLTEST_VARDIR/tmp/bug21412.sql; # --exec $MYSQL test -e "/*! \C latin1 */ select 1;" +# +# Bug#29323 mysql client only accetps ANSI encoded files +# +--write_file $MYSQLTEST_VARDIR/tmp/bug29323.sql +select "This is a file starting with UTF8 BOM 0xEFBBBF"; +EOF +--exec $MYSQL < $MYSQLTEST_VARDIR/tmp/bug29323.sql 2>&1 +remove_file $MYSQLTEST_VARDIR/tmp/bug29323.sql; + --echo End of 5.0 tests From 2c12ddc1d4cd9b0a665150041b7296b220d968fe Mon Sep 17 00:00:00 2001 From: "aelkin/elkin@koti.dsl.inet.fi" <> Date: Thu, 4 Oct 2007 13:13:04 +0300 Subject: [PATCH 028/336] manual merge --- sql/log.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sql/log.h b/sql/log.h index e597c986794..afcb1d1adf4 100644 --- a/sql/log.h +++ b/sql/log.h @@ -130,7 +130,13 @@ typedef struct st_log_info my_off_t pos; bool fatal; // if the purge happens to give us a negative offset pthread_mutex_t lock; - st_log_info():fatal(0) { pthread_mutex_init(&lock, MY_MUTEX_INIT_FAST);} + st_log_info() + : index_file_offset(0), index_file_start_offset(0), + pos(0), fatal(0) + { + log_file_name[0] = '\0'; + pthread_mutex_init(&lock, MY_MUTEX_INIT_FAST); + } ~st_log_info() { pthread_mutex_destroy(&lock);} } LOG_INFO; From 501cce2b33729650236ad4b60ef59e93b7eddc9a Mon Sep 17 00:00:00 2001 From: "aelkin/elkin@koti.dsl.inet.fi" <> Date: Thu, 4 Oct 2007 18:46:31 +0300 Subject: [PATCH 029/336] Bug #29309 Incorrect "Seconds_Behind_Master" value in SHOW SLAVE STATUS after FLUSH LOGS Report claims that Seconds_behind_master behaves unexpectedly. Code analysis shows that there is an evident flaw in that treating of FormatDescription event is wrong so that after FLUSH LOGS on slave the Seconds_behind_master's calculation slips and incorrect value can be reported to SHOW SLAVE STATUS. Even worse is that the gap between the correct and incorrect deltas grows with time. Fixed with prohibiting changes to rpl->last_master_timestamp by artifical events (any kind of). suggestion as comments is added how to fight with lack of info on the slave side by means of new heartbeat feature coming. The test can not be done ealily fully determistic. --- .../manual/r/rpl_replication_delay.result | 121 ++++++++++++++++++ .../manual/t/rpl_replication_delay-slave.opt | 1 + .../suite/manual/t/rpl_replication_delay.test | 71 ++++++++++ sql/log_event.cc | 32 ++++- sql/slave.cc | 11 +- 5 files changed, 234 insertions(+), 2 deletions(-) create mode 100644 mysql-test/suite/manual/r/rpl_replication_delay.result create mode 100644 mysql-test/suite/manual/t/rpl_replication_delay-slave.opt create mode 100644 mysql-test/suite/manual/t/rpl_replication_delay.test diff --git a/mysql-test/suite/manual/r/rpl_replication_delay.result b/mysql-test/suite/manual/r/rpl_replication_delay.result new file mode 100644 index 00000000000..22447a30cba --- /dev/null +++ b/mysql-test/suite/manual/r/rpl_replication_delay.result @@ -0,0 +1,121 @@ +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; +show slave status /* Second_behind reports 0 */;; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port 9306 +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos 98 +Relay_Log_File # +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running Yes +Slave_SQL_Running Yes +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 0 +Last_Error +Skip_Counter 0 +Exec_Master_Log_Pos 98 +Relay_Log_Space # +Until_Condition None +Until_Log_File +Until_Log_Pos 0 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master 0 +drop table if exists t1; +Warnings: +Note 1051 Unknown table 't1' +create table t1 (f1 int); +flush logs /* contaminate rli->last_master_timestamp */; +lock table t1 write; +insert into t1 values (1); +show slave status /* bug emulated: reports slave threads starting time about 3*3 not 3 secs */;; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port 9306 +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos 359 +Relay_Log_File # +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running Yes +Slave_SQL_Running Yes +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 0 +Last_Error +Skip_Counter 0 +Exec_Master_Log_Pos 271 +Relay_Log_Space # +Until_Condition None +Until_Log_File +Until_Log_Pos 0 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master 10 +unlock tables; +flush logs /* this time rli->last_master_timestamp is not affected */; +lock table t1 write; +insert into t1 values (2); +show slave status /* reports the correct diff with master query time about 3+3 secs */;; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port 9306 +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos 447 +Relay_Log_File # +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running Yes +Slave_SQL_Running Yes +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 0 +Last_Error +Skip_Counter 0 +Exec_Master_Log_Pos 359 +Relay_Log_Space # +Until_Condition None +Until_Log_File +Until_Log_Pos 0 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master 6 +unlock tables; +drop table t1; diff --git a/mysql-test/suite/manual/t/rpl_replication_delay-slave.opt b/mysql-test/suite/manual/t/rpl_replication_delay-slave.opt new file mode 100644 index 00000000000..24a4c5952fe --- /dev/null +++ b/mysql-test/suite/manual/t/rpl_replication_delay-slave.opt @@ -0,0 +1 @@ +--loose-debug=d,let_first_flush_log_change_timestamp diff --git a/mysql-test/suite/manual/t/rpl_replication_delay.test b/mysql-test/suite/manual/t/rpl_replication_delay.test new file mode 100644 index 00000000000..8230698c8f9 --- /dev/null +++ b/mysql-test/suite/manual/t/rpl_replication_delay.test @@ -0,0 +1,71 @@ +# +# Testing replication delay reporting (bug#29309) +# there is an unavoidable non-determinism in the test +# please compare the results with the comments +# + + +source include/master-slave.inc; + +connection master; +#connection slave; +sync_slave_with_master; +--replace_result $DEFAULT_MASTER_PORT DEFAULT_MASTER_PORT +--replace_column 1 # 8 # 9 # 23 # +--query_vertical show slave status /* Second_behind reports 0 */; +sleep 3; + +### bug emulation + +connection master; +drop table if exists t1; +create table t1 (f1 int); +sleep 3; + +#connection slave; +sync_slave_with_master; +flush logs /* contaminate rli->last_master_timestamp */; + +connection slave; +lock table t1 write; + +connection master; +insert into t1 values (1); + +sleep 3; + +connection slave; +--replace_result $DEFAULT_MASTER_PORT DEFAULT_MASTER_PORT +--replace_column 1 # 8 # 9 # 23 # +--query_vertical show slave status /* bug emulated: reports slave threads starting time about 3*3 not 3 secs */; +unlock tables; + +connection master; +sync_slave_with_master; + +### bugfix + + +connection slave; +flush logs /* this time rli->last_master_timestamp is not affected */; +lock table t1 write; + +connection master; +insert into t1 values (2); +sleep 3; + +connection slave; +--replace_result $DEFAULT_MASTER_PORT DEFAULT_MASTER_PORT +--replace_column 1 # 8 # 9 # 23 # +--query_vertical show slave status /* reports the correct diff with master query time about 3+3 secs */; +unlock tables; + +connection master; +drop table t1; + +#connection slave; +sync_slave_with_master; + + +# End of tests + diff --git a/sql/log_event.cc b/sql/log_event.cc index 1ef765f607f..3899e772bf8 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -27,6 +27,10 @@ #define log_cs &my_charset_latin1 +#ifndef DBUG_OFF +uint debug_not_change_ts_if_art_event= 1; // bug#29309 simulation +#endif + /* pretty_print_str() */ @@ -481,6 +485,18 @@ int Log_event::exec_event(struct st_relay_log_info* rli) rli->inc_event_relay_log_pos(); else { + /* + bug#29309 simulation: resetting the flag to force + wrong behaviour of artificial event to update + rli->last_master_timestamp for only one time - + the first FLUSH LOGS in the test. + */ + DBUG_EXECUTE_IF("let_first_flush_log_change_timestamp", + if (debug_not_change_ts_if_art_event == 1 + && is_artificial_event()) + { + debug_not_change_ts_if_art_event= 0; + }); rli->inc_group_relay_log_pos(log_pos); flush_relay_log_info(rli); /* @@ -491,7 +507,21 @@ int Log_event::exec_event(struct st_relay_log_info* rli) rare cases, only consequence is that value may take some time to display in Seconds_Behind_Master - not critical). */ - rli->last_master_timestamp= when; +#ifndef DBUG_OFF + if (!(is_artificial_event() && debug_not_change_ts_if_art_event > 0)) +#else + if (!is_artificial_event()) +#endif + rli->last_master_timestamp= when; + /* + The flag is set back to be positive so that + any further FLUSH LOGS will be handled as prescribed. + */ + DBUG_EXECUTE_IF("let_first_flush_log_change_timestamp", + if (debug_not_change_ts_if_art_event == 0) + { + debug_not_change_ts_if_art_event= 2; + }); } } DBUG_RETURN(0); diff --git a/sql/slave.cc b/sql/slave.cc index 57f6e64ce03..0bc4bf7b32f 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -4931,7 +4931,16 @@ Log_event* next_event(RELAY_LOG_INFO* rli) a new event and is queuing it; the false "0" will exist until SQL finishes executing the new event; it will be look abnormal only if the events have old timestamps (then you get "many", 0, "many"). - Transient phases like this can't really be fixed. + + Transient phases like this can be fixed with implemeting + Heartbeat event which provides the slave the status of the + master at time the master does not have any new update to send. + Seconds_Behind_Master would be zero only when master has no + more updates in binlog for slave. The heartbeat can be sent + in a (small) fraction of slave_net_timeout. Until it's done + rli->last_master_timestamp is temporarely (for time of + waiting for the following event) reset whenever EOF is + reached. */ time_t save_timestamp= rli->last_master_timestamp; rli->last_master_timestamp= 0; From 40f68cd4b3debe0c5841e21970f7ff601cd82025 Mon Sep 17 00:00:00 2001 From: "bar@mysql.com/bar.myoffice.izhnet.ru" <> Date: Fri, 5 Oct 2007 12:15:11 +0500 Subject: [PATCH 030/336] Bug#31081 server crash in regexp function Problem: The "regex" library written by Henry Spencer does not support tricky character sets like UCS2. Fix: convert tricky character sets to UTF8 before calling regex functions. --- mysql-test/include/ctype_regex.inc | 42 ++++++++++ mysql-test/r/ctype_uca.result | 45 +++++++++++ mysql-test/r/ctype_ucs.result | 45 +++++++++++ mysql-test/r/ctype_utf8.result | 45 +++++++++++ mysql-test/r/func_regexp.result | 14 +++- mysql-test/t/ctype_uca.test | 4 + mysql-test/t/ctype_ucs.test | 4 + mysql-test/t/ctype_utf8.test | 7 ++ mysql-test/t/func_regexp.test | 23 +----- sql/item_cmpfunc.cc | 122 +++++++++++++++++------------ sql/item_cmpfunc.h | 4 + 11 files changed, 283 insertions(+), 72 deletions(-) create mode 100644 mysql-test/include/ctype_regex.inc diff --git a/mysql-test/include/ctype_regex.inc b/mysql-test/include/ctype_regex.inc new file mode 100644 index 00000000000..0e6b4c41607 --- /dev/null +++ b/mysql-test/include/ctype_regex.inc @@ -0,0 +1,42 @@ +# +# To test a desired collation, set session.collation_connection to +# this collation before including this file +# + +--disable_warnings +drop table if exists t1; +--enable_warnings + +# +# Create a table with two varchar(64) null-able column, +# using current values of +# @@character_set_connection and @@collation_connection. +# + +create table t1 as +select repeat(' ', 64) as s1, repeat(' ',64) as s2 +union +select null, null; +show create table t1; +delete from t1; + +insert into t1 values('aaa','aaa'); +insert into t1 values('aaa|qqq','qqq'); +insert into t1 values('gheis','^[^a-dXYZ]+$'); +insert into t1 values('aab','^aa?b'); +insert into t1 values('Baaan','^Ba*n'); +insert into t1 values('aaa','qqq|aaa'); +insert into t1 values('qqq','qqq|aaa'); + +insert into t1 values('bbb','qqq|aaa'); +insert into t1 values('bbb','qqq'); +insert into t1 values('aaa','aba'); + +insert into t1 values(null,'abc'); +insert into t1 values('def',null); +insert into t1 values(null,null); +insert into t1 values('ghi','ghi['); + +select HIGH_PRIORITY s1 regexp s2 from t1; + +drop table t1; diff --git a/mysql-test/r/ctype_uca.result b/mysql-test/r/ctype_uca.result index 889702e380c..ada7ace9696 100644 --- a/mysql-test/r/ctype_uca.result +++ b/mysql-test/r/ctype_uca.result @@ -2754,4 +2754,49 @@ a c ch drop table t1; +set collation_connection=ucs2_unicode_ci; +drop table if exists t1; +create table t1 as +select repeat(' ', 64) as s1, repeat(' ',64) as s2 +union +select null, null; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `s1` varchar(64) character set ucs2 collate ucs2_unicode_ci default NULL, + `s2` varchar(64) character set ucs2 collate ucs2_unicode_ci default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +delete from t1; +insert into t1 values('aaa','aaa'); +insert into t1 values('aaa|qqq','qqq'); +insert into t1 values('gheis','^[^a-dXYZ]+$'); +insert into t1 values('aab','^aa?b'); +insert into t1 values('Baaan','^Ba*n'); +insert into t1 values('aaa','qqq|aaa'); +insert into t1 values('qqq','qqq|aaa'); +insert into t1 values('bbb','qqq|aaa'); +insert into t1 values('bbb','qqq'); +insert into t1 values('aaa','aba'); +insert into t1 values(null,'abc'); +insert into t1 values('def',null); +insert into t1 values(null,null); +insert into t1 values('ghi','ghi['); +select HIGH_PRIORITY s1 regexp s2 from t1; +s1 regexp s2 +1 +1 +1 +1 +1 +1 +1 +0 +0 +0 +NULL +NULL +NULL +NULL +drop table t1; +set names utf8; End for 5.0 tests diff --git a/mysql-test/r/ctype_ucs.result b/mysql-test/r/ctype_ucs.result index 023267c227c..954fdab7699 100644 --- a/mysql-test/r/ctype_ucs.result +++ b/mysql-test/r/ctype_ucs.result @@ -922,4 +922,49 @@ ERROR HY000: Illegal mix of collations (ascii_general_ci,IMPLICIT) and (ucs2_gen select * from t1 where a=if(b<10,_ucs2 0x0062,_ucs2 0x00C0); ERROR HY000: Illegal mix of collations (ascii_general_ci,IMPLICIT) and (ucs2_general_ci,COERCIBLE) for operation '=' drop table t1; +set collation_connection=ucs2_general_ci; +drop table if exists t1; +create table t1 as +select repeat(' ', 64) as s1, repeat(' ',64) as s2 +union +select null, null; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `s1` varchar(64) character set ucs2 default NULL, + `s2` varchar(64) character set ucs2 default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +delete from t1; +insert into t1 values('aaa','aaa'); +insert into t1 values('aaa|qqq','qqq'); +insert into t1 values('gheis','^[^a-dXYZ]+$'); +insert into t1 values('aab','^aa?b'); +insert into t1 values('Baaan','^Ba*n'); +insert into t1 values('aaa','qqq|aaa'); +insert into t1 values('qqq','qqq|aaa'); +insert into t1 values('bbb','qqq|aaa'); +insert into t1 values('bbb','qqq'); +insert into t1 values('aaa','aba'); +insert into t1 values(null,'abc'); +insert into t1 values('def',null); +insert into t1 values(null,null); +insert into t1 values('ghi','ghi['); +select HIGH_PRIORITY s1 regexp s2 from t1; +s1 regexp s2 +1 +1 +1 +1 +1 +1 +1 +0 +0 +0 +NULL +NULL +NULL +NULL +drop table t1; +set names latin1; End of 5.0 tests diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index 710cac388a5..7cdc5c265d7 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -267,6 +267,51 @@ b select * from t1 where a = 'b' and a != 'b'; a drop table t1; +set collation_connection=utf8_general_ci; +drop table if exists t1; +create table t1 as +select repeat(' ', 64) as s1, repeat(' ',64) as s2 +union +select null, null; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `s1` varchar(64) character set utf8 default NULL, + `s2` varchar(64) character set utf8 default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +delete from t1; +insert into t1 values('aaa','aaa'); +insert into t1 values('aaa|qqq','qqq'); +insert into t1 values('gheis','^[^a-dXYZ]+$'); +insert into t1 values('aab','^aa?b'); +insert into t1 values('Baaan','^Ba*n'); +insert into t1 values('aaa','qqq|aaa'); +insert into t1 values('qqq','qqq|aaa'); +insert into t1 values('bbb','qqq|aaa'); +insert into t1 values('bbb','qqq'); +insert into t1 values('aaa','aba'); +insert into t1 values(null,'abc'); +insert into t1 values('def',null); +insert into t1 values(null,null); +insert into t1 values('ghi','ghi['); +select HIGH_PRIORITY s1 regexp s2 from t1; +s1 regexp s2 +1 +1 +1 +1 +1 +1 +1 +0 +0 +0 +NULL +NULL +NULL +NULL +drop table t1; +set names utf8; set names utf8; select 'вася' rlike '[[:<:]]вася[[:>:]]'; 'вася' rlike '[[:<:]]вася[[:>:]]' diff --git a/mysql-test/r/func_regexp.result b/mysql-test/r/func_regexp.result index 584c8a9b820..752ec3a5810 100644 --- a/mysql-test/r/func_regexp.result +++ b/mysql-test/r/func_regexp.result @@ -1,5 +1,17 @@ drop table if exists t1; -create table t1 (s1 char(64),s2 char(64)); +set names latin1; +drop table if exists t1; +create table t1 as +select repeat(' ', 64) as s1, repeat(' ',64) as s2 +union +select null, null; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `s1` varchar(64) default NULL, + `s2` varchar(64) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +delete from t1; insert into t1 values('aaa','aaa'); insert into t1 values('aaa|qqq','qqq'); insert into t1 values('gheis','^[^a-dXYZ]+$'); diff --git a/mysql-test/t/ctype_uca.test b/mysql-test/t/ctype_uca.test index 17632e7c8fc..bac3ef7d63c 100644 --- a/mysql-test/t/ctype_uca.test +++ b/mysql-test/t/ctype_uca.test @@ -538,4 +538,8 @@ alter table t1 convert to character set ucs2 collate ucs2_czech_ci; select * from t1 where a like 'c%'; drop table t1; +set collation_connection=ucs2_unicode_ci; +--source include/ctype_regex.inc +set names utf8; + -- echo End for 5.0 tests diff --git a/mysql-test/t/ctype_ucs.test b/mysql-test/t/ctype_ucs.test index bca3a9c3a96..3779dd50260 100644 --- a/mysql-test/t/ctype_ucs.test +++ b/mysql-test/t/ctype_ucs.test @@ -651,4 +651,8 @@ select * from t1 where a=if(b<10,_ucs2 0x00C0,_ucs2 0x0062); select * from t1 where a=if(b<10,_ucs2 0x0062,_ucs2 0x00C0); drop table t1; +set collation_connection=ucs2_general_ci; +--source include/ctype_regex.inc +set names latin1; + --echo End of 5.0 tests diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test index f8eed0bae9a..927794f2d5a 100644 --- a/mysql-test/t/ctype_utf8.test +++ b/mysql-test/t/ctype_utf8.test @@ -185,6 +185,13 @@ select * from t1 where a = 'b' and a = 'b'; select * from t1 where a = 'b' and a != 'b'; drop table t1; +# +# Testing regexp +# +set collation_connection=utf8_general_ci; +--source include/ctype_regex.inc +set names utf8; + # # Bug #3928 regexp [[:>:]] and UTF-8 # diff --git a/mysql-test/t/func_regexp.test b/mysql-test/t/func_regexp.test index 23070c71fe9..f34830f6100 100644 --- a/mysql-test/t/func_regexp.test +++ b/mysql-test/t/func_regexp.test @@ -6,28 +6,9 @@ drop table if exists t1; --enable_warnings -create table t1 (s1 char(64),s2 char(64)); +set names latin1; +--source include/ctype_regex.inc -insert into t1 values('aaa','aaa'); -insert into t1 values('aaa|qqq','qqq'); -insert into t1 values('gheis','^[^a-dXYZ]+$'); -insert into t1 values('aab','^aa?b'); -insert into t1 values('Baaan','^Ba*n'); -insert into t1 values('aaa','qqq|aaa'); -insert into t1 values('qqq','qqq|aaa'); - -insert into t1 values('bbb','qqq|aaa'); -insert into t1 values('bbb','qqq'); -insert into t1 values('aaa','aba'); - -insert into t1 values(null,'abc'); -insert into t1 values('def',null); -insert into t1 values(null,null); -insert into t1 values('ghi','ghi['); - -select HIGH_PRIORITY s1 regexp s2 from t1; - -drop table t1; # # This test a bug in regexp on Alpha diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 86eb10d50b0..51b3e8cda6b 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -4225,6 +4225,51 @@ void Item_func_like::cleanup() #ifdef USE_REGEX +bool +Item_func_regex::regcomp(bool send_error) +{ + char buff[MAX_FIELD_WIDTH]; + String tmp(buff,sizeof(buff),&my_charset_bin); + String *res= args[1]->val_str(&tmp); + int error; + + if (args[1]->null_value) + return TRUE; + + if (regex_compiled) + { + if (!stringcmp(res, &prev_regexp)) + return FALSE; + prev_regexp.copy(*res); + my_regfree(&preg); + regex_compiled= 0; + } + + if (cmp_collation.collation != regex_lib_charset) + { + /* Convert UCS2 strings to UTF8 */ + uint dummy_errors; + if (conv.copy(res->ptr(), res->length(), res->charset(), + regex_lib_charset, &dummy_errors)) + return TRUE; + res= &conv; + } + + if ((error= my_regcomp(&preg, res->c_ptr(), + regex_lib_flags, regex_lib_charset))) + { + if (send_error) + { + (void) my_regerror(error, &preg, buff, sizeof(buff)); + my_error(ER_REGEXP_ERROR, MYF(0), buff); + } + return TRUE; + } + regex_compiled= 1; + return FALSE; +} + + bool Item_func_regex::fix_fields(THD *thd, Item **ref) { @@ -4241,34 +4286,33 @@ Item_func_regex::fix_fields(THD *thd, Item **ref) if (agg_arg_charsets(cmp_collation, args, 2, MY_COLL_CMP_CONV, 1)) return TRUE; + regex_lib_flags= (cmp_collation.collation->state & + (MY_CS_BINSORT | MY_CS_CSSORT)) ? + REG_EXTENDED | REG_NOSUB : + REG_EXTENDED | REG_NOSUB | REG_ICASE; + /* + If the case of UCS2 and other non-ASCII character sets, + we will convert patterns and strings to UTF8. + */ + regex_lib_charset= (cmp_collation.collation->mbminlen > 1) ? + &my_charset_utf8_general_ci : + cmp_collation.collation; + used_tables_cache=args[0]->used_tables() | args[1]->used_tables(); not_null_tables_cache= (args[0]->not_null_tables() | args[1]->not_null_tables()); const_item_cache=args[0]->const_item() && args[1]->const_item(); if (!regex_compiled && args[1]->const_item()) { - char buff[MAX_FIELD_WIDTH]; - String tmp(buff,sizeof(buff),&my_charset_bin); - String *res=args[1]->val_str(&tmp); if (args[1]->null_value) { // Will always return NULL maybe_null=1; return FALSE; } - int error; - if ((error= my_regcomp(&preg,res->c_ptr(), - ((cmp_collation.collation->state & - (MY_CS_BINSORT | MY_CS_CSSORT)) ? - REG_EXTENDED | REG_NOSUB : - REG_EXTENDED | REG_NOSUB | REG_ICASE), - cmp_collation.collation))) - { - (void) my_regerror(error,&preg,buff,sizeof(buff)); - my_error(ER_REGEXP_ERROR, MYF(0), buff); + if (regcomp(TRUE)) return TRUE; - } - regex_compiled=regex_is_const=1; - maybe_null=args[0]->maybe_null; + regex_is_const= 1; + maybe_null= args[0]->maybe_null; } else maybe_null=1; @@ -4281,47 +4325,25 @@ longlong Item_func_regex::val_int() { DBUG_ASSERT(fixed == 1); char buff[MAX_FIELD_WIDTH]; - String *res, tmp(buff,sizeof(buff),&my_charset_bin); + String tmp(buff,sizeof(buff),&my_charset_bin); + String *res= args[0]->val_str(&tmp); - res=args[0]->val_str(&tmp); - if (args[0]->null_value) - { - null_value=1; + if ((null_value= (args[0]->null_value || + (!regex_is_const && regcomp(FALSE))))) return 0; - } - if (!regex_is_const) - { - char buff2[MAX_FIELD_WIDTH]; - String *res2, tmp2(buff2,sizeof(buff2),&my_charset_bin); - res2= args[1]->val_str(&tmp2); - if (args[1]->null_value) + if (cmp_collation.collation != regex_lib_charset) + { + /* Convert UCS2 strings to UTF8 */ + uint dummy_errors; + if (conv.copy(res->ptr(), res->length(), res->charset(), + regex_lib_charset, &dummy_errors)) { - null_value=1; + null_value= 1; return 0; } - if (!regex_compiled || stringcmp(res2,&prev_regexp)) - { - prev_regexp.copy(*res2); - if (regex_compiled) - { - my_regfree(&preg); - regex_compiled=0; - } - if (my_regcomp(&preg,res2->c_ptr_safe(), - ((cmp_collation.collation->state & - (MY_CS_BINSORT | MY_CS_CSSORT)) ? - REG_EXTENDED | REG_NOSUB : - REG_EXTENDED | REG_NOSUB | REG_ICASE), - cmp_collation.collation)) - { - null_value=1; - return 0; - } - regex_compiled=1; - } + res= &conv; } - null_value=0; return my_regexec(&preg,res->c_ptr_safe(),0,(my_regmatch_t*) 0,0) ? 0 : 1; } diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 8410c66b034..11851e9a4e4 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -1313,6 +1313,10 @@ class Item_func_regex :public Item_bool_func bool regex_is_const; String prev_regexp; DTCollation cmp_collation; + CHARSET_INFO *regex_lib_charset; + int regex_lib_flags; + String conv; + bool regcomp(bool send_error); public: Item_func_regex(Item *a,Item *b) :Item_bool_func(a,b), regex_compiled(0),regex_is_const(0) {} From 015c00ccb801044c3091fcf1821e87e8cf94e11c Mon Sep 17 00:00:00 2001 From: "bar@mysql.com/bar.myoffice.izhnet.ru" <> Date: Tue, 9 Oct 2007 13:53:39 +0500 Subject: [PATCH 031/336] Bug#27287 extractvalue() (and updatexml()) extremely slow for large XML Performance improvements made. ExtractValue for large XML values is now much faster (about 2000 times faster of 1Mb-long XML values). --- sql/item_xmlfunc.cc | 60 ++++++++++++++++++--------------------------- 1 file changed, 24 insertions(+), 36 deletions(-) diff --git a/sql/item_xmlfunc.cc b/sql/item_xmlfunc.cc index 15be9c97b6e..d0dbab16b1c 100644 --- a/sql/item_xmlfunc.cc +++ b/sql/item_xmlfunc.cc @@ -2611,35 +2611,27 @@ typedef struct uint level; String *pxml; // parsed XML uint pos[MAX_LEVEL]; // Tag position stack + uint parent; // Offset of the parent of the current node } MY_XML_USER_DATA; -/* - Find the parent node - - SYNOPSYS - Find the parent node, i.e. a tag or attrubute node on the given level. - - RETURN - 1 - success - 0 - failure -*/ -static uint xml_parent_tag(MY_XML_NODE *items, uint nitems, uint level) +static bool +append_node(String *str, MY_XML_NODE *node) { - if (!nitems) - return 0; - - MY_XML_NODE *p, *last= &items[nitems-1]; - for (p= last; p >= items; p--) - { - if (p->level == level && - (p->type == MY_XML_NODE_TAG || - p->type == MY_XML_NODE_ATTR)) - { - return p - items; - } - } - return 0; + /* + If "str" doesn't have space for a new node, + it will allocate two times more space that it has had so far. + (2*len+512) is a heuristic value, + which gave the best performance during tests. + The ideas behind this formula are: + - It allows to have a very small number of reallocs: + about 10 reallocs on a 1Mb-long XML value. + - At the same time, it avoids excessive memory use. + */ + if (str->reserve(sizeof(MY_XML_NODE), 2 * str->length() + 512)) + return TRUE; + str->q_append((const char*) node, sizeof(MY_XML_NODE)); + return FALSE; } @@ -2661,19 +2653,17 @@ extern "C" int xml_enter(MY_XML_PARSER *st,const char *attr, size_t len); int xml_enter(MY_XML_PARSER *st,const char *attr, size_t len) { MY_XML_USER_DATA *data= (MY_XML_USER_DATA*)st->user_data; - MY_XML_NODE *nodes= (MY_XML_NODE*) data->pxml->ptr(); uint numnodes= data->pxml->length() / sizeof(MY_XML_NODE); - uint parent= xml_parent_tag(nodes, numnodes, data->level - 1); MY_XML_NODE node; + node.parent= data->parent; // Set parent for the new node to old parent + data->parent= numnodes; // Remember current node as new parent data->pos[data->level]= numnodes; node.level= data->level++; node.type= st->current_node_type; // TAG or ATTR node.beg= attr; node.end= attr + len; - node.parent= parent; - data->pxml->append((const char*) &node, sizeof(MY_XML_NODE)); - return MY_XML_OK; + return append_node(data->pxml, &node) ? MY_XML_ERROR : MY_XML_OK; } @@ -2694,18 +2684,14 @@ extern "C" int xml_value(MY_XML_PARSER *st,const char *attr, size_t len); int xml_value(MY_XML_PARSER *st,const char *attr, size_t len) { MY_XML_USER_DATA *data= (MY_XML_USER_DATA*)st->user_data; - MY_XML_NODE *nodes= (MY_XML_NODE*) data->pxml->ptr(); - uint numnodes= data->pxml->length() / sizeof(MY_XML_NODE); - uint parent= xml_parent_tag(nodes, numnodes, data->level - 1); MY_XML_NODE node; + node.parent= data->parent; // Set parent for the new text node to old parent node.level= data->level; node.type= MY_XML_NODE_TEXT; node.beg= attr; node.end= attr + len; - node.parent= parent; - data->pxml->append((const char*) &node, sizeof(MY_XML_NODE)); - return MY_XML_OK; + return append_node(data->pxml, &node) ? MY_XML_ERROR : MY_XML_OK; } @@ -2730,6 +2716,7 @@ int xml_leave(MY_XML_PARSER *st,const char *attr, size_t len) data->level--; MY_XML_NODE *nodes= (MY_XML_NODE*) data->pxml->ptr(); + data->parent= nodes[data->parent].parent; nodes+= data->pos[data->level]; nodes->tagend= st->cur; @@ -2760,6 +2747,7 @@ String *Item_xml_str_func::parse_xml(String *raw_xml, String *parsed_xml_buf) p.flags= MY_XML_FLAG_RELATIVE_NAMES | MY_XML_FLAG_SKIP_TEXT_NORMALIZATION; user_data.level= 0; user_data.pxml= parsed_xml_buf; + user_data.parent= 0; my_xml_set_enter_handler(&p, xml_enter); my_xml_set_value_handler(&p, xml_value); my_xml_set_leave_handler(&p, xml_leave); From 56c88d4a52fad96c95a43f0483c17456bf7aa99b Mon Sep 17 00:00:00 2001 From: "cmiller@zippy.cornsilk.net" <> Date: Tue, 9 Oct 2007 17:56:32 -0400 Subject: [PATCH 032/336] Doxygenize comments, a*.cc - field.cc . --- sql/derror.cc | 37 ++-- sql/des_key_file.cc | 17 +- sql/discover.cc | 54 ++--- sql/field.cc | 513 +++++++++++++++++++++----------------------- 4 files changed, 309 insertions(+), 312 deletions(-) diff --git a/sql/derror.cc b/sql/derror.cc index 3b67e0f5bf0..a8cfa00ad1d 100644 --- a/sql/derror.cc +++ b/sql/derror.cc @@ -14,7 +14,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* Read language depeneded messagefile */ +/** + @file + + @brief + Read language depeneded messagefile +*/ #include "mysql_priv.h" #include "mysys_err.h" @@ -23,20 +28,17 @@ static bool read_texts(const char *file_name,const char ***point, uint error_messages); static void init_myfunc_errs(void); -/* +/** Read messages from errorfile. - SYNOPSIS - init_errmessage() + This function can be called multiple times to reload the messages. + If it fails to load the messages, it will fail softly by initializing + the errmesg pointer to an array of empty strings or by keeping the + old array if it exists. - DESCRIPTION - This function can be called multiple times to reload the messages. - If it fails to load the messages, it will fail softly by initializing - the errmesg pointer to an array of empty strings or by keeping the - old array if it exists. - - RETURN + @retval FALSE OK + @retval TRUE Error */ @@ -75,7 +77,14 @@ bool init_errmessage(void) } - /* Read text from packed textfile in language-directory */ +/** + Read text from packed textfile in language-directory. + + If we can't read messagefile then it's panic- we can't continue. + + @todo + Convert the character set to server system character set +*/ static bool read_texts(const char *file_name,const char ***point, uint error_messages) @@ -178,7 +187,9 @@ err1: } /* read_texts */ - /* Initiates error-messages used by my_func-library */ +/** + Initiates error-messages used by my_func-library. +*/ static void init_myfunc_errs() { diff --git a/sql/des_key_file.cc b/sql/des_key_file.cc index d99d712b45a..317cb237360 100644 --- a/sql/des_key_file.cc +++ b/sql/des_key_file.cc @@ -21,17 +21,18 @@ struct st_des_keyschedule des_keyschedule[10]; uint des_default_key; -/* - Function which loads DES keys from plaintext file into memory on MySQL - server startup and on command FLUSH DES_KEY_FILE. - Blame tonu@spam.ee on bugs ;) +#define des_cs &my_charset_latin1 - RETURN - 0 ok - 1 Error +/** + Load DES keys from plaintext file into + memory on MySQL server startup and on command FLUSH DES_KEY_FILE. + + @retval + 0 ok + @retval + 1 Error */ -#define des_cs &my_charset_latin1 bool load_des_key_file(const char *file_name) diff --git a/sql/discover.cc b/sql/discover.cc index a7af90c440f..56dc00cc5c4 100644 --- a/sql/discover.cc +++ b/sql/discover.cc @@ -14,29 +14,33 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* Functions for discover of frm file from handler */ +/** + @file + + @brief + Functions for discover of frm file from handler +*/ #include "mysql_priv.h" #include -/* - Read the contents of a .frm file +/** + Read the contents of a .frm file. - SYNOPSIS - readfrm() + frmdata and len are set to 0 on error. - name path to table-file "db/name" - frmdata frm data - len length of the read frmdata + @param name path to table-file "db/name" + @param frmdata frm data + @param len length of the read frmdata - RETURN VALUES - 0 ok - 1 Could not open file - 2 Could not stat file - 3 Could not allocate data for read - Could not read file - - frmdata and len are set to 0 on error + @retval + 0 ok + @retval + 1 Could not open file + @retval + 2 Could not stat file + @retval + 3 Could not allocate data for read. Could not read file */ int readfrm(const char *name, uchar **frmdata, size_t *len) @@ -87,18 +91,16 @@ int readfrm(const char *name, uchar **frmdata, size_t *len) /* Write the content of a frm data pointer - to a frm file + to a frm file. - SYNOPSIS - writefrm() + @param name path to table-file "db/name" + @param frmdata frm data + @param len length of the frmdata - name path to table-file "db/name" - frmdata frm data - len length of the frmdata - - RETURN VALUES - 0 ok - 2 Could not write file + @retval + 0 ok + @retval + 2 Could not write file */ int writefrm(const char *name, const uchar *frmdata, size_t len) diff --git a/sql/field.cc b/sql/field.cc index fa93454c757..61ae105b639 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -14,9 +14,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/***************************************************************************** -** This file implements classes defined in field.h -*****************************************************************************/ +/** + @file + + @brief + This file implements classes defined in field.h +*/ #ifdef USE_PRAGMA_IMPLEMENTATION #pragma implementation // gcc: Class implementation @@ -913,14 +916,13 @@ static enum_field_types field_types_merge_rules [FIELDTYPE_NUM][FIELDTYPE_NUM]= } }; -/* - Return type of which can carry value of both given types in UNION result +/** + Return type of which can carry value of both given types in UNION result. - SYNOPSIS - Field::field_type_merge() - a, b types for merging + @param a type for merging + @param b type for merging - RETURN + @return type of field */ @@ -992,14 +994,12 @@ test_if_important_data(CHARSET_INFO *cs, const char *str, const char *strend) } -/* - Detect Item_result by given field type of UNION merge result +/** + Detect Item_result by given field type of UNION merge result. - SYNOPSIS - Field::result_merge_type() - field_type given field type + @param field_type given field type - RETURN + @return Item_result (type of internal MySQL expression result) */ @@ -1015,18 +1015,17 @@ Item_result Field::result_merge_type(enum_field_types field_type) *****************************************************************************/ -/* - Check whether a field type can be partially indexed by a key +/** + Check whether a field type can be partially indexed by a key. This is a static method, rather than a virtual function, because we need to check the type of a non-Field in mysql_alter_table(). - SYNOPSIS - type_can_have_key_part() - type field type + @param type field type - RETURN + @retval TRUE Type can have a prefixed key + @retval FALSE Type can not have a prefixed key */ @@ -1048,8 +1047,8 @@ bool Field::type_can_have_key_part(enum enum_field_types type) } -/* - Numeric fields base class constructor +/** + Numeric fields base class constructor. */ Field_num::Field_num(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, utype unireg_check_arg, @@ -1080,23 +1079,25 @@ void Field_num::prepend_zeros(String *value) } } -/* +/** Test if given number is a int. - SYNOPSIS - Field_num::check_int - cs Character set - str String to test - end Pointer to char after last used digit - length String length - error Error returned by strntoull10rnd() + @todo + Make this multi-byte-character safe - NOTE + @param str String to test + @param length Length of 'str' + @param int_end Pointer to char after last used digit + @param cs Character set + + @note This is called after one has called strntoull10rnd() function. - RETURN - 0 ok + @retval + 0 OK + @retval 1 error: empty string or wrong integer. + @retval 2 error: garbage at the end of string. */ @@ -1191,16 +1192,15 @@ out_of_range: return 1; } -/* +/** Process decimal library return codes and issue warnings for overflow and truncation. - SYNOPSIS - Field::warn_if_overflow() - op_result decimal library return code (E_DEC_* see include/decimal.h) + @param op_result decimal library return code (E_DEC_* see include/decimal.h) - RETURN + @retval 1 there was overflow + @retval 0 no error or some other errors except overflow */ @@ -1275,10 +1275,10 @@ static bool test_if_real(const char *str,int length, CHARSET_INFO *cs) #endif -/* +/** Interpret field value as an integer but return the result as a string. - This is used for printing bit_fields as numbers while debugging + This is used for printing bit_fields as numbers while debugging. */ String *Field::val_int_as_str(String *val_buffer, my_bool unsigned_val) @@ -1299,6 +1299,7 @@ String *Field::val_int_as_str(String *val_buffer, my_bool unsigned_val) } +/// This is used as a table name when the table structure is not set up Field::Field(uchar *ptr_arg,uint32 length_arg,uchar *null_ptr_arg, uchar null_bit_arg, utype unireg_check_arg, const char *field_name_arg) @@ -1474,17 +1475,15 @@ void Field::make_field(Send_field *field) } -/* +/** Conversion from decimal to longlong with checking overflow and - setting correct value (min/max) in case of overflow + setting correct value (min/max) in case of overflow. - SYNOPSIS - Field::convert_decimal2longlong() - val value which have to be converted - unsigned_flag type of integer in which we convert val - err variable to pass error code + @param val value which have to be converted + @param unsigned_flag type of integer in which we convert val + @param err variable to pass error code - RETURN + @return value converted from val */ longlong Field::convert_decimal2longlong(const my_decimal *val, @@ -1518,19 +1517,18 @@ longlong Field::convert_decimal2longlong(const my_decimal *val, } -/* +/** Storing decimal in integer fields. - SYNOPSIS - Field_num::store_decimal() - val value for storing + @param val value for storing - NOTE + @note This method is used by all integer fields, real/decimal redefine it - RETURN + @retval 0 OK - != 0 error + @retval + !=0 error */ int Field_num::store_decimal(const my_decimal *val) @@ -1542,19 +1540,17 @@ int Field_num::store_decimal(const my_decimal *val) } -/* - Return decimal value of integer field +/** + Return decimal value of integer field. - SYNOPSIS - Field_num::val_decimal() - decimal_value buffer for storing decimal value + @param decimal_value buffer for storing decimal value - NOTE - This method is used by all integer fields, real/decimal redefine it + @note + This method is used by all integer fields, real/decimal redefine it. All longlong values fit in our decimal buffer which cal store 8*9=72 digits of integer number - RETURN + @return pointer to decimal buffer with value of field */ @@ -1587,22 +1583,24 @@ void Field_num::make_field(Send_field *field) field->decimals= dec; } -/* - Decimal representation of Field_str +/** + Decimal representation of Field_str. - SYNOPSIS - Field_str::store_decimal() - d value for storing + @param d value for storing - NOTE - Field_str is the base class for fields like Field_enum, Field_date and some - similar. Some dates use fraction and also string value should be - converted to floating point value according our rules, so we use double - to store value of decimal in string + @note + Field_str is the base class for fields like Field_enum, + Field_date and some similar. Some dates use fraction and also + string value should be converted to floating point value according + our rules, so we use double to store value of decimal in string. - RETURN + @todo + use decimal2string? + + @retval 0 OK - != 0 error + @retval + !=0 error */ int Field_str::store_decimal(const my_decimal *d) @@ -1675,11 +1673,11 @@ bool Field::get_time(MYSQL_TIME *ltime) return 0; } -/* - This is called when storing a date in a string +/** + This is called when storing a date in a string. - NOTES - Needs to be changed if/when we want to support different time formats + @note + Needs to be changed if/when we want to support different time formats. */ int Field::store_time(MYSQL_TIME *ltime, timestamp_type type_arg) @@ -2301,9 +2299,9 @@ String *Field_decimal::val_str(String *val_buffer __attribute__((unused)), return val_ptr; } -/* -** Should be able to handle at least the following fixed decimal formats: -** 5.00 , -1.0, 05, -05, +5 with optional pre/end space +/** + Should be able to handle at least the following fixed decimal formats: + 5.00 , -1.0, 05, -05, +5 with optional pre/end space */ int Field_decimal::cmp(const uchar *a_ptr,const uchar *b_ptr) @@ -2425,13 +2423,11 @@ int Field_new_decimal::reset(void) } -/* +/** Generate max/min decimal value in case of overflow. - SYNOPSIS - Field_new_decimal::set_value_on_overflow(); - decimal_value buffer for value - sign sign of value which caused overflow + @param decimal_value buffer for value + @param sign sign of value which caused overflow */ void Field_new_decimal::set_value_on_overflow(my_decimal *decimal_value, @@ -2450,21 +2446,19 @@ void Field_new_decimal::set_value_on_overflow(my_decimal *decimal_value, } -/* - Store decimal value in the binary buffer +/** + Store decimal value in the binary buffer. - SYNOPSIS - store_value(const my_decimal *decimal_value) - decimal_value my_decimal + Checks if decimal_value fits into field size. + If it does, stores the decimal in the buffer using binary format. + Otherwise sets maximal number that can be stored in the field. - DESCRIPTION - checks if decimal_value fits into field size. - if it does, stores the decimal in the buffer using binary format. - Otherwise sets maximal number that can be stored in the field. + @param decimal_value my_decimal - RETURN - 0 ok - 1 error + @retval + 0 ok + @retval + 1 error */ bool Field_new_decimal::store_value(const my_decimal *decimal_value) @@ -2573,6 +2567,12 @@ int Field_new_decimal::store(const char *from, uint length, } +/** + @todo + Fix following when double2my_decimal when double2decimal + will return E_DEC_TRUNCATED always correctly +*/ + int Field_new_decimal::store(double nr) { ASSERT_COLUMN_MARKED_FOR_WRITE; @@ -4546,9 +4546,8 @@ void Field_double::sql_type(String &res) const } -/* - TIMESTAMP type. - Holds datetime values in range from 1970-01-01 00:00:01 UTC to +/** + TIMESTAMP type holds datetime values in range from 1970-01-01 00:00:01 UTC to 2038-01-01 00:00:00 UTC stored as number of seconds since Unix Epoch in UTC. @@ -4581,7 +4580,7 @@ void Field_double::sql_type(String &res) const NONE - field which is not auto-set on update with some other than NOW() default value (TIMESTAMP DEFAULT 0). - Note that TIMESTAMP_OLD_FIELD's are never created explicitly now, they are + Note that TIMESTAMP_OLD_FIELDs are never created explicitly now, they are left only for preserving ability to read old tables. Such fields replaced with their newer analogs in CREATE TABLE and in SHOW CREATE TABLE. This is because we want to prefer NONE unireg_check before TIMESTAMP_OLD_FIELD for @@ -4623,15 +4622,11 @@ Field_timestamp::Field_timestamp(bool maybe_null_arg, } -/* +/** Get auto-set type for TIMESTAMP field. - SYNOPSIS - get_auto_set_type() - - DESCRIPTION - Returns value indicating during which operations this TIMESTAMP field - should be auto-set to current timestamp. + Returns value indicating during which operations this TIMESTAMP field + should be auto-set to current timestamp. */ timestamp_auto_set_type Field_timestamp::get_auto_set_type() const { @@ -5114,7 +5109,8 @@ longlong Field_time::val_int(void) } -/* +/** + @note This function is multi-byte safe as the result string is always of type my_charset_bin */ @@ -5141,7 +5137,8 @@ String *Field_time::val_str(String *val_buffer, } -/* +/** + @note Normally we would not consider 'time' as a valid date, but we allow get_date() here to be able to do things like DATE_FORMAT(time, "%l.%i %p") @@ -6243,15 +6240,12 @@ int Field_string::store(const char *from,uint length,CHARSET_INFO *cs) } -/* +/** Store double value in Field_string or Field_varstring. - SYNOPSIS - store(double nr) - nr number + Pretty prints double number into field_length characters buffer. - DESCRIPTION - Pretty prints double number into field_length characters buffer. + @param nr number */ int Field_str::store(double nr) @@ -6605,18 +6599,18 @@ int Field_string::pack_cmp(const uchar *a, const uchar *b, uint length, } -/* - Compare a packed key against row +/** + Compare a packed key against row. - SYNOPSIS - pack_cmp() - key Original key - length Key length. (May be less than field length) - insert_or_update 1 if this is an insert or update + @param key Original key + @param length Key length. (May be less than field length) + @param insert_or_update 1 if this is an insert or update - RETURN + @return < 0 row < key + @return 0 row = key + @return > 0 row > key */ @@ -6859,8 +6853,9 @@ int Field_varstring::cmp_max(const uchar *a_ptr, const uchar *b_ptr, } -/* - NOTE: varstring and blob keys are ALWAYS stored with a 2 byte length prefix +/** + @note + varstring and blob keys are ALWAYS stored with a 2 byte length prefix */ int Field_varstring::key_cmp(const uchar *key_ptr, uint max_key_length) @@ -6880,10 +6875,10 @@ int Field_varstring::key_cmp(const uchar *key_ptr, uint max_key_length) } -/* - Compare to key segments (always 2 byte length prefix) +/** + Compare to key segments (always 2 byte length prefix). - NOTE + @note This is used only to compare key segments created for index_read(). (keys are created and compared in key.cc) */ @@ -6995,21 +6990,18 @@ uchar *Field_varstring::pack_key(uchar *to, const uchar *key, uint max_length) } -/* +/** Unpack a key into a record buffer. - SYNOPSIS - unpack_key() - to Pointer into the record buffer. - key Pointer to the packed key. - max_length Key length limit from key description. + A VARCHAR key has a maximum size of 64K-1. + In its packed form, the length field is one or two bytes long, + depending on 'max_length'. - DESCRIPTION - A VARCHAR key has a maximum size of 64K-1. - In its packed form, the length field is one or two bytes long, - depending on 'max_length'. + @param to Pointer into the record buffer. + @param key Pointer to the packed key. + @param max_length Key length limit from key description. - RETURN + @return Pointer to end of 'key' (To the next key part if multi-segment key) */ @@ -7030,16 +7022,14 @@ const uchar *Field_varstring::unpack_key(uchar *to, const uchar *key, return key + length; } -/* - Create a packed key that will be used for storage in the index tree +/** + Create a packed key that will be used for storage in the index tree. - SYNOPSIS - pack_key_from_key_image() - to Store packed key segment here - from Key segment (as given to index_read()) - max_length Max length of key + @param to Store packed key segment here + @param from Key segment (as given to index_read()) + @param max_length Max length of key - RETURN + @return end of key storage */ @@ -7389,21 +7379,15 @@ uint32 Field_blob::get_length(const uchar *pos, bool low_byte_first) } -/* +/** Put a blob length field into a record buffer. - SYNOPSIS - Field_blob::put_length() - pos Pointer into the record buffer. - length The length value to put. + Depending on the maximum length of a blob, its length field is + put into 1 to 4 bytes. This is a property of the blob object, + described by 'packlength'. - DESCRIPTION - Depending on the maximum length of a blob, its length field is - put into 1 to 4 bytes. This is a property of the blob object, - described by 'packlength'. - - RETURN - nothing + @param pos Pointer into the record buffer. + @param length The length value to put. */ void Field_blob::put_length(uchar *pos, uint32 length) @@ -7891,7 +7875,7 @@ int Field_blob::pack_cmp(const uchar *b, uint key_length_arg, insert_or_update); } -/* Create a packed key that will be used for storage from a MySQL row */ +/** Create a packed key that will be used for storage from a MySQL row. */ uchar *Field_blob::pack_key(uchar *to, const uchar *from, uint max_length) { @@ -7915,26 +7899,24 @@ uchar *Field_blob::pack_key(uchar *to, const uchar *from, uint max_length) } -/* +/** Unpack a blob key into a record buffer. - SYNOPSIS - Field_blob::unpack_key() - to Pointer into the record buffer. - from Pointer to the packed key. - max_length Key length limit from key description. + A blob key has a maximum size of 64K-1. + In its packed form, the length field is one or two bytes long, + depending on 'max_length'. + Depending on the maximum length of a blob, its length field is + put into 1 to 4 bytes. This is a property of the blob object, + described by 'packlength'. + Blobs are internally stored apart from the record buffer, which + contains a pointer to the blob buffer. - DESCRIPTION - A blob key has a maximum size of 64K-1. - In its packed form, the length field is one or two bytes long, - depending on 'max_length'. - Depending on the maximum length of a blob, its length field is - put into 1 to 4 bytes. This is a property of the blob object, - described by 'packlength'. - Blobs are internally stored apart from the record buffer, which - contains a pointer to the blob buffer. - RETURN + @param to Pointer into the record buffer. + @param from Pointer to the packed key. + @param max_length Key length limit from key description. + + @return Pointer into 'from' past the last byte copied from packed key. */ @@ -7960,7 +7942,7 @@ const uchar *Field_blob::unpack_key(uchar *to, const uchar *from, } -/* Create a packed key that will be used for storage from a MySQL key */ +/** Create a packed key that will be used for storage from a MySQL key. */ uchar *Field_blob::pack_key_from_key_image(uchar *to, const uchar *from, uint max_length) @@ -8181,9 +8163,10 @@ void Field_enum::store_type(ulonglong value) } -/* -** Note. Storing a empty string in a enum field gives a warning -** (if there isn't a empty value in the enum) +/** + @note + Storing a empty string in a enum field gives a warning + (if there isn't a empty value in the enum) */ int Field_enum::store(const char *from,uint length,CHARSET_INFO *cs) @@ -8509,7 +8492,12 @@ void Field_set::sql_type(String &res) const res.append(')'); } -/* returns 1 if the fields are equally defined */ +/** + @retval + 1 if the fields are equally defined + @retval + 0 if the fields are unequally defined +*/ bool Field::eq_def(Field *field) { @@ -8519,6 +8507,10 @@ bool Field::eq_def(Field *field) return 1; } +/** + @return + returns 1 if the fields are equally defined +*/ bool Field_enum::eq_def(Field *field) { if (!Field::eq_def(field)) @@ -8537,6 +8529,10 @@ bool Field_enum::eq_def(Field *field) return 1; } +/** + @return + returns 1 if the fields are equally defined +*/ bool Field_num::eq_def(Field *field) { if (!Field::eq_def(field)) @@ -9113,14 +9109,8 @@ void Field_bit_as_char::sql_type(String &res) const Handling of field and Create_field *****************************************************************************/ -/* - Convert Create_field::length from number of characters to number of bytes - - SYNOPSIS - Create_field::create_length_to_internal_length() - - DESCRIPTION - Convert Create_field::length from number of characters to number of bytes. +/** + Convert create_field::length from number of characters to number of bytes. */ void Create_field::create_length_to_internal_length(void) @@ -9170,6 +9160,9 @@ void Create_field::create_length_to_internal_length(void) } +/** + Init for a tmp table field. To be extended if need be. +*/ void Create_field::init_for_tmp_table(enum_field_types sql_type_arg, uint32 length_arg, uint32 decimals_arg, bool maybe_null, bool is_unsigned) @@ -9188,26 +9181,26 @@ void Create_field::init_for_tmp_table(enum_field_types sql_type_arg, } -/* - Initialize field definition for create +/** + Initialize field definition for create. - SYNOPSIS - thd Thread handle - fld_name Field name - fld_type Field type - fld_length Field length - fld_decimals Decimal (if any) - fld_type_modifier Additional type information - fld_default_value Field default value (if any) - fld_on_update_value The value of ON UPDATE clause - fld_comment Field comment - fld_change Field change - fld_interval_list Interval list (if any) - fld_charset Field charset - fld_geom_type Field geometry type (if any) + @param thd Thread handle + @param fld_name Field name + @param fld_type Field type + @param fld_length Field length + @param fld_decimals Decimal (if any) + @param fld_type_modifier Additional type information + @param fld_default_value Field default value (if any) + @param fld_on_update_value The value of ON UPDATE clause + @param fld_comment Field comment + @param fld_change Field change + @param fld_interval_list Interval list (if any) + @param fld_charset Field charset + @param fld_geom_type Field geometry type (if any) - RETURN + @retval FALSE on success + @retval TRUE on error */ @@ -9795,7 +9788,7 @@ Field *make_field(TABLE_SHARE *share, uchar *ptr, uint32 field_length, } -/* Create a field suitable for create of table */ +/** Create a field suitable for create of table. */ Create_field::Create_field(Field *old_field,Field *orig_field) { @@ -9883,13 +9876,10 @@ Create_field::Create_field(Field *old_field,Field *orig_field) } -/* - maximum possible display length for blob +/** + maximum possible display length for blob. - SYNOPSIS - Field_blob::max_display_length() - - RETURN + @return length */ @@ -9916,24 +9906,23 @@ uint32 Field_blob::max_display_length() Warning handling *****************************************************************************/ -/* - Produce warning or note about data saved into field +/** + Produce warning or note about data saved into field. - SYNOPSIS - set_warning() - level - level of message (Note/Warning/Error) - code - error code of message to be produced - cuted_increment - whenever we should increase cut fields count or not + @param level - level of message (Note/Warning/Error) + @param code - error code of message to be produced + @param cuted_increment - whenever we should increase cut fields count or not - NOTE + @note This function won't produce warning and increase cut fields counter if count_cuted_fields == CHECK_FIELD_IGNORE for current thread. if count_cuted_fields == CHECK_FIELD_IGNORE then we ignore notes. This allows us to avoid notes in optimisation, like convert_constant_item(). - RETURN VALUE + @retval 1 if count_cuted_fields == CHECK_FIELD_IGNORE and error level is not NOTE + @retval 0 otherwise */ @@ -9957,21 +9946,19 @@ Field::set_warning(MYSQL_ERROR::enum_warning_level level, uint code, } -/* - Produce warning or note about datetime string data saved into field +/** + Produce warning or note about datetime string data saved into field. - SYNOPSIS - set_datime_warning() - level - level of message (Note/Warning/Error) - code - error code of message to be produced - str - string value which we tried to save - str_len - length of string which we tried to save - ts_type - type of datetime value (datetime/date/time) - cuted_increment - whenever we should increase cut fields count or not - - NOTE - This function will always produce some warning but won't increase cut - fields counter if count_cuted_fields == FIELD_CHECK_IGNORE for current + @param level level of message (Note/Warning/Error) + @param code error code of message to be produced + @param str string value which we tried to save + @param str_length length of string which we tried to save + @param ts_type type of datetime value (datetime/date/time) + @param cuted_increment whenever we should increase cut fields count or not + + @note + This function will always produce some warning but won't increase cut + fields counter if count_cuted_fields ==FIELD_CHECK_IGNORE for current thread. */ @@ -9989,20 +9976,18 @@ Field::set_datetime_warning(MYSQL_ERROR::enum_warning_level level, uint code, } -/* - Produce warning or note about integer datetime value saved into field +/** + Produce warning or note about integer datetime value saved into field. - SYNOPSIS - set_warning() - level - level of message (Note/Warning/Error) - code - error code of message to be produced - nr - numeric value which we tried to save - ts_type - type of datetime value (datetime/date/time) - cuted_increment - whenever we should increase cut fields count or not - - NOTE - This function will always produce some warning but won't increase cut - fields counter if count_cuted_fields == FIELD_CHECK_IGNORE for current + @param level level of message (Note/Warning/Error) + @param code error code of message to be produced + @param nr numeric value which we tried to save + @param ts_type type of datetime value (datetime/date/time) + @param cuted_increment whenever we should increase cut fields count or not + + @note + This function will always produce some warning but won't increase cut + fields counter if count_cuted_fields == FIELD_CHECK_IGNORE for current thread. */ @@ -10023,19 +10008,17 @@ Field::set_datetime_warning(MYSQL_ERROR::enum_warning_level level, uint code, } -/* - Produce warning or note about double datetime data saved into field +/** + Produce warning or note about double datetime data saved into field. - SYNOPSIS - set_warning() - level - level of message (Note/Warning/Error) - code - error code of message to be produced - nr - double value which we tried to save - ts_type - type of datetime value (datetime/date/time) - - NOTE - This function will always produce some warning but won't increase cut - fields counter if count_cuted_fields == FIELD_CHECK_IGNORE for current + @param level level of message (Note/Warning/Error) + @param code error code of message to be produced + @param nr double value which we tried to save + @param ts_type type of datetime value (datetime/date/time) + + @note + This function will always produce some warning but won't increase cut + fields counter if count_cuted_fields == FIELD_CHECK_IGNORE for current thread. */ From c302f74da65ae0dab64905a07e02773d3319bcce Mon Sep 17 00:00:00 2001 From: "sven@murkla.(none)" <> Date: Wed, 10 Oct 2007 18:10:54 +0200 Subject: [PATCH 033/336] BUG#29046: rpl_stm_mystery22 unstable Problem: rpl_stm_mystery22 is unstable. Reason: At one place, the test case *should* wait until the SQL thread on the slave receives an error, but instead it waits until the SQL thread stops. The SQL thread may stop before the error flag is set, so that when the test case continues to execute, the error flag is not set. Fix: Introduce the subroutine mysql-test/include/wait_for_slave_sql_error.inc, which waits until there is an error in the sql thread of the slave. Re-commit: fixed one logical error and two smaller things noted by Mats. --- .../include/wait_for_slave_sql_error.inc | 33 +++++++++++++++++++ mysql-test/suite/rpl/t/rpl_stm_mystery22.test | 2 +- 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 mysql-test/include/wait_for_slave_sql_error.inc diff --git a/mysql-test/include/wait_for_slave_sql_error.inc b/mysql-test/include/wait_for_slave_sql_error.inc new file mode 100644 index 00000000000..6780edbe2f0 --- /dev/null +++ b/mysql-test/include/wait_for_slave_sql_error.inc @@ -0,0 +1,33 @@ +################################################### +#Author: Sven +#Date: 2007-10-09 +#Purpose: Wait until the slave has an error in the +# sql thread, as indicated by +# "SHOW SLAVE STATUS", or at most 30 +# seconds. +#Details: +# 1) Fill in and setup variables +# 2) loop, looking for sql error on slave +# 3) If it loops too long, die. +#################################################### +connection slave; +let $row_number= 1; +let $run= 1; +let $counter= 300; + +while ($run) +{ + let $sql_result= query_get_value("SHOW SLAVE STATUS", Last_SQL_Errno, $row_number); + let $run= `SELECT '$sql_result' = '0'`; + if ($run) { + real_sleep 0.1; + if (!$counter){ + --echo "Failed while waiting for slave to produce an error in its sql thread" + --replace_result $MASTER_MYPORT MASTER_PORT + --replace_column 1 # 7 # 8 # 9 # 22 # 23 # 33 # + query_vertical SHOW SLAVE STATUS; + exit; + } + dec $counter; + } +} diff --git a/mysql-test/suite/rpl/t/rpl_stm_mystery22.test b/mysql-test/suite/rpl/t/rpl_stm_mystery22.test index 017593fdfba..b43a734fffc 100644 --- a/mysql-test/suite/rpl/t/rpl_stm_mystery22.test +++ b/mysql-test/suite/rpl/t/rpl_stm_mystery22.test @@ -28,7 +28,7 @@ insert into t1 values(NULL,'new'); save_master_pos; connection slave; # wait until the slave tries to run the query, fails and aborts slave thread -wait_for_slave_to_stop; +source include/wait_for_slave_sql_error.inc; select * from t1 order by n; delete from t1 where n = 2; --disable_warnings From c4298a3fb9fef9dc8de380064cd087f1d8cb74f3 Mon Sep 17 00:00:00 2001 From: "mats@kindahl-laptop.dnsalias.net" <> Date: Thu, 11 Oct 2007 18:18:05 +0200 Subject: [PATCH 034/336] BUG#29549 (Endians: test failures on Solaris): Refactoring code to add parameter to pack() and unpack() functions with purpose of indicating if data should be packed in little-endian or native order. Using new functions to always pack data for binary log in little-endian order. The purpose of this refactoring is to allow proper implementation of endian-agnostic pack() and unpack() functions. Eliminating several versions of virtual pack() and unpack() functions in favor for one single virtual function which is overridden in subclasses. Implementing pack() and unpack() functions for some field types that packed data in native format regardless of the value of the st_table_share::db_low_byte_first flag. The field types that were packed in native format regardless are: Field_real, Field_decimal, Field_tiny, Field_short, Field_medium, Field_long, Field_longlong, and Field_blob. Before the patch, row-based logging wrote the rows incorrectly on big-endian machines where the storage engine defined its own low_byte_first() to be FALSE on big-endian machines (the default is TRUE), while little-endian machines wrote the fields in correct order. The only known storage engine that does this is NDB. In effect, this means that row-based replication from or to a big-endian machine where the table was using NDB as storage engine failed if the other engine was either non-NDB or on a little-endian machine. With this patch, row-based logging is now always done in little-endian order, while ORDER BY uses the native order if the storage engine defines low_byte_first() to return FALSE for big-endian machines. In addition, the max_data_length() function available in Field_blob was generalized to the entire Field hierarchy to give the maximum number of bytes that Field::pack() will write. --- .../extra/rpl_tests/rpl_extraMaster_Col.test | 2 +- .../rpl/r/rpl_extraColmaster_innodb.result | Bin 38226 -> 38226 bytes .../rpl/r/rpl_extraColmaster_myisam.result | Bin 38226 -> 38226 bytes .../rpl/r/rpl_row_extraColmaster_ndb.result | Bin 19129 -> 19129 bytes mysql-test/suite/rpl/t/disabled.def | 1 - .../suite/rpl/t/rpl_row_mysqlbinlog.test | 1 + .../suite/rpl_ndb/r/rpl_ndb_innodb2ndb.result | 855 ++++++++++++++++++ .../suite/rpl_ndb/r/rpl_ndb_myisam2ndb.result | 855 ++++++++++++++++++ mysql-test/suite/rpl_ndb/t/disabled.def | 2 - .../rpl_ndb/t/rpl_ndb_innodb2ndb-slave.opt | 2 +- .../suite/rpl_ndb/t/rpl_ndb_innodb2ndb.test | 10 +- .../rpl_ndb/t/rpl_ndb_myisam2ndb-slave.opt | 2 +- .../suite/rpl_ndb/t/rpl_ndb_myisam2ndb.test | 7 +- mysql-test/t/partition.test | 3 +- sql/field.cc | 407 ++++++--- sql/field.h | 271 +++++- sql/log.cc | 3 - sql/log_event.cc | 4 + sql/rpl_record.cc | 54 +- sql/sql_show.cc | 6 +- 20 files changed, 2251 insertions(+), 234 deletions(-) create mode 100644 mysql-test/suite/rpl_ndb/r/rpl_ndb_innodb2ndb.result create mode 100644 mysql-test/suite/rpl_ndb/r/rpl_ndb_myisam2ndb.result diff --git a/mysql-test/extra/rpl_tests/rpl_extraMaster_Col.test b/mysql-test/extra/rpl_tests/rpl_extraMaster_Col.test index 26b1e6d5ba0..a03aa337c2b 100644 --- a/mysql-test/extra/rpl_tests/rpl_extraMaster_Col.test +++ b/mysql-test/extra/rpl_tests/rpl_extraMaster_Col.test @@ -466,7 +466,7 @@ binary data'; select * from t2 order by f1; select * from t3 order by f1; select * from t4 order by f1; - select * from t31 order by f1; + select * from t31 order by f3; connection master; diff --git a/mysql-test/suite/rpl/r/rpl_extraColmaster_innodb.result b/mysql-test/suite/rpl/r/rpl_extraColmaster_innodb.result index 189066179255c33b7d56e0fdfd8a3893dda3535c..ef6e2a6de25a11ce8c9b48e9bd4a0ab8e0380089 100644 GIT binary patch delta 27 dcmcb#is{lSrVXZUlVyXYHwU=6c|jQqSpb}X3M&8r delta 27 ecmcb#is{lSrVXZUlW+A)Zw_#C^MW!KvH$?ISqvQj diff --git a/mysql-test/suite/rpl/r/rpl_extraColmaster_myisam.result b/mysql-test/suite/rpl/r/rpl_extraColmaster_myisam.result index 5bc1a13b1078a054d99dfef348ad74e85295e302..475ea4cdcbaab56b53f74844b68bcae4aaa0d753 100644 GIT binary patch delta 27 dcmcb#is{lSrVXZUlVyXYHwU=6c|jQqSpb}X3M&8r delta 27 ecmcb#is{lSrVXZUlW+A)Zw_#C^MW!KvH$?ISqvQj diff --git a/mysql-test/suite/rpl/r/rpl_row_extraColmaster_ndb.result b/mysql-test/suite/rpl/r/rpl_row_extraColmaster_ndb.result index 0b1f2e6c8bf9514ef53ef326dde109d3a78bdea8..fb83c5088e502338e8db678565120f65b47dcba1 100644 GIT binary patch delta 82 zcmdlvm2u}(#tna6C;ySTNkkg2>I5jyxFNF)lG3G4E$Si`eO*qr?ON&Y} Xz!IjMX_;wIwi#z}X2s@Uw=@<2Nf{Ui delta 86 zcmdlvm2u}(#tna6Cm(Yab~fcq%Slow_byte_first is dependent on how the + packed data is going to be used: for local use, e.g., temporary + store on disk or in memory, use the native format since that is + faster. For data that is going to be transfered to other machines + (e.g., when writing data to the binary log), data should always be + stored in little-endian format. + + @note The default method for packing fields just copy the raw bytes + of the record into the destination, but never more than + max_length characters. + + @param to + Pointer to memory area where representation of field should be put. + + @param from + Pointer to memory area where record representation of field is + stored. + + @param max_length + Maximum length of the field, as given in the column definition. For + example, for CHAR(1000), the max_length + is 1000. This information is sometimes needed to decide how to pack + the data. + + @param low_byte_first + @c TRUE if integers should be stored little-endian, @c FALSE if + native format should be used. Note that for little-endian machines, + the value of this flag is a moot point since the native format is + little-endian. +*/ +uchar * +Field::pack(uchar *to, const uchar *from, uint max_length, + bool low_byte_first __attribute__((unused))) +{ + uint32 length= pack_length(); + set_if_smaller(length, max_length); + memcpy(to, from, length); + return to+length; +} + /** Unpack a field from row data. - This method is used to unpack a field from a master whose size - of the field is less than that of the slave. - + This method is used to unpack a field from a master whose size of + the field is less than that of the slave. + + The param_data parameter is a two-byte integer (stored + in the least significant 16 bits of the unsigned integer) usually + consisting of two parts: the real type in the most significant byte + and a original pack length in the least significant byte. + + The exact layout of the param_data field is given by + the Table_map_log_event::save_field_metadata(). + + This is the default method for unpacking a field. It just copies + the memory block in byte order (of original pack length bytes or + length of field, whichever is smaller). + @param to Destination of the data @param from Source of the data - @param param_data Pack length of the field data + @param param_data Real type and original pack length of the field + data + + @param low_byte_first + If this flag is @c true, all composite entities (e.g., lengths) + should be unpacked in little-endian format; otherwise, the entities + are unpacked in native order. @return New pointer into memory based on from + length of the data */ -const uchar *Field::unpack(uchar* to, - const uchar *from, - uint param_data) +const uchar * +Field::unpack(uchar* to, const uchar *from, uint param_data, + bool low_byte_first __attribute__((unused))) { uint length=pack_length(); int from_type= 0; @@ -1399,19 +1464,18 @@ const uchar *Field::unpack(uchar* to, from_type= (param_data & 0xff00) >> 8U; // real_type. param_data= param_data & 0x00ff; // length. } + + if ((param_data == 0) || + (length == param_data) || + (from_type != real_type())) + { + memcpy(to, from, length); + return from+length; + } + uint len= (param_data && (param_data < length)) ? param_data : length; - /* - If the length is the same, use old unpack method. - If the param_data is 0, use the old unpack method. - This is possible if the table map was generated from a down-level - master or if the data was not available on the master. - If the real_types are not the same, use the old unpack method. - */ - if ((length == param_data) || - (param_data == 0) || - (from_type != real_type())) - return(unpack(to, from)); + memcpy(to, from, param_data > length ? length : len); return from+len; } @@ -2714,10 +2778,15 @@ uint Field_new_decimal::is_equal(Create_field *new_field) @return New pointer into memory based on from + length of the data */ -const uchar *Field_new_decimal::unpack(uchar* to, - const uchar *from, - uint param_data) +const uchar * +Field_new_decimal::unpack(uchar* to, + const uchar *from, + uint param_data, + bool low_byte_first) { + if (param_data == 0) + return Field::unpack(to, from, param_data, low_byte_first); + uint from_precision= (param_data & 0xff00) >> 8U; uint from_decimal= param_data & 0x00ff; uint length=pack_length(); @@ -3857,6 +3926,49 @@ void Field_longlong::sql_type(String &res) const } +/* + Floating-point numbers + */ + +uchar * +Field_real::pack(uchar *to, const uchar *from, + uint max_length, bool low_byte_first) +{ + DBUG_ENTER("Field_real::pack"); + DBUG_ASSERT(max_length >= pack_length()); + DBUG_PRINT("debug", ("pack_length(): %u", pack_length())); +#ifdef WORDS_BIGENDIAN + if (low_byte_first != table->s->db_low_byte_first) + { + const uchar *dptr= from + pack_length(); + while (dptr-- > from) + *to++ = *dptr; + DBUG_RETURN(to); + } + else +#endif + DBUG_RETURN(Field::pack(to, from, max_length, low_byte_first)); +} + +const uchar * +Field_real::unpack(uchar *to, const uchar *from, + uint param_data, bool low_byte_first) +{ + DBUG_ENTER("Field_real::unpack"); + DBUG_PRINT("debug", ("pack_length(): %u", pack_length())); +#ifdef WORDS_BIGENDIAN + if (low_byte_first != table->s->db_low_byte_first) + { + const uchar *dptr= from + pack_length(); + while (dptr-- > from) + *to++ = *dptr; + DBUG_RETURN(from + pack_length()); + } + else +#endif + DBUG_RETURN(Field::unpack(to, from, param_data, low_byte_first)); +} + /**************************************************************************** single precision float ****************************************************************************/ @@ -6211,6 +6323,11 @@ int Field_longstr::store_decimal(const my_decimal *d) return store(str.ptr(), str.length(), str.charset()); } +uint32 Field_longstr::max_data_length() const +{ + return field_length + (field_length > 255 ? 2 : 1); +} + double Field_string::val_real(void) { @@ -6355,7 +6472,9 @@ void Field_string::sql_type(String &res) const } -uchar *Field_string::pack(uchar *to, const uchar *from, uint max_length) +uchar *Field_string::pack(uchar *to, const uchar *from, + uint max_length, + bool low_byte_first __attribute__((unused))) { uint length= min(field_length,max_length); uint local_char_length= max_length/field_charset->mbmaxlen; @@ -6363,11 +6482,15 @@ uchar *Field_string::pack(uchar *to, const uchar *from, uint max_length) local_char_length= my_charpos(field_charset, from, from+length, local_char_length); set_if_smaller(length, local_char_length); - while (length && from[length-1] == ' ') + while (length && from[length-1] == field_charset->pad_char) length--; + + // Length always stored little-endian *to++= (uchar) length; if (field_length > 255) *to++= (uchar) (length >> 8); + + // Store the actual bytes of the string memcpy(to, from, length); return to+length; } @@ -6389,34 +6512,27 @@ uchar *Field_string::pack(uchar *to, const uchar *from, uint max_length) @return New pointer into memory based on from + length of the data */ -const uchar *Field_string::unpack(uchar *to, - const uchar *from, - uint param_data) -{ - uint from_len= param_data & 0x00ff; // length. - uint length= 0; - uint f_length; - f_length= (from_len < field_length) ? from_len : field_length; - DBUG_ASSERT(f_length <= 255); - length= (uint) *from++; - bitmap_set_bit(table->write_set,field_index); - store((const char *)from, length, system_charset_info); - return from+length; -} - - -const uchar *Field_string::unpack(uchar *to, const uchar *from) +const uchar * +Field_string::unpack(uchar *to, + const uchar *from, + uint param_data, + bool low_byte_first __attribute__((unused))) { + uint from_length= + param_data ? min(param_data & 0x00ff, field_length) : field_length; uint length; - if (field_length > 255) + + if (from_length > 255) { length= uint2korr(from); from+= 2; } else length= (uint) *from++; - memcpy(to, from, (int) length); - bfill(to+length, field_length - length, ' '); + + memcpy(to, from, length); + // Pad the string with the pad character of the fields charset + bfill(to + length, field_length - length, field_charset->pad_char); return from+length; } @@ -6796,22 +6912,30 @@ uint32 Field_varstring::data_length() Here the number of length bytes are depending on the given max_length */ -uchar *Field_varstring::pack(uchar *to, const uchar *from, uint max_length) +uchar *Field_varstring::pack(uchar *to, const uchar *from, + uint max_length, + bool low_byte_first __attribute__((unused))) { uint length= length_bytes == 1 ? (uint) *from : uint2korr(from); set_if_smaller(max_length, field_length); if (length > max_length) length=max_length; - *to++= (char) (length & 255); + + /* Length always stored little-endian */ + *to++= length & 0xFF; if (max_length > 255) - *to++= (char) (length >> 8); - if (length) + *to++= (length >> 8) & 0xFF; + + /* Store bytes of string */ + if (length > 0) memcpy(to, from+length_bytes, length); return to+length; } -uchar *Field_varstring::pack_key(uchar *to, const uchar *key, uint max_length) +uchar * +Field_varstring::pack_key(uchar *to, const uchar *key, uint max_length, + bool low_byte_first __attribute__((unused))) { uint length= length_bytes == 1 ? (uint) *key : uint2korr(key); uint local_char_length= ((field_charset->mbmaxlen > 1) ? @@ -6850,8 +6974,9 @@ uchar *Field_varstring::pack_key(uchar *to, const uchar *key, uint max_length) Pointer to end of 'key' (To the next key part if multi-segment key) */ -const uchar *Field_varstring::unpack_key(uchar *to, const uchar *key, - uint max_length) +const uchar * +Field_varstring::unpack_key(uchar *to, const uchar *key, uint max_length, + bool low_byte_first __attribute__((unused))) { /* get length of the blob key */ uint32 length= *key++; @@ -6880,8 +7005,9 @@ const uchar *Field_varstring::unpack_key(uchar *to, const uchar *key, end of key storage */ -uchar *Field_varstring::pack_key_from_key_image(uchar *to, const uchar *from, - uint max_length) +uchar * +Field_varstring::pack_key_from_key_image(uchar *to, const uchar *from, uint max_length, + bool low_byte_first __attribute__((unused))) { /* Key length is always stored as 2 bytes */ uint length= uint2korr(from); @@ -6901,6 +7027,9 @@ uchar *Field_varstring::pack_key_from_key_image(uchar *to, const uchar *from, This method is used to unpack a varstring field from a master whose size of the field is less than that of the slave. + + @note + The string length is always packed little-endian. @param to Destination of the data @param from Source of the data @@ -6908,9 +7037,10 @@ uchar *Field_varstring::pack_key_from_key_image(uchar *to, const uchar *from, @return New pointer into memory based on from + length of the data */ -const uchar *Field_varstring::unpack(uchar *to, - const uchar *from, - uint param_data) +const uchar * +Field_varstring::unpack(uchar *to, const uchar *from, + uint param_data, + bool low_byte_first __attribute__((unused))) { uint length; uint l_bytes= (param_data && (param_data < field_length)) ? @@ -6922,28 +7052,7 @@ const uchar *Field_varstring::unpack(uchar *to, if (length_bytes == 2) to[1]= 0; } - else - { - length= uint2korr(from); - to[0]= *from++; - to[1]= *from++; - } - if (length) - memcpy(to+ length_bytes, from, length); - return from+length; -} - - -/* - unpack field packed with Field_varstring::pack() -*/ - -const uchar *Field_varstring::unpack(uchar *to, const uchar *from) -{ - uint length; - if (length_bytes == 1) - length= (uint) (*to= *from++); - else + else /* l_bytes == 2 */ { length= uint2korr(from); to[0]= *from++; @@ -7192,9 +7301,9 @@ void Field_blob::store_length(uchar *i_ptr, } -uint32 Field_blob::get_length(const uchar *pos, bool low_byte_first) +uint32 Field_blob::get_length(const uchar *pos, uint packlength_arg, bool low_byte_first) { - switch (packlength) { + switch (packlength_arg) { case 1: return (uint32) pos[0]; case 2: @@ -7608,28 +7717,37 @@ void Field_blob::sql_type(String &res) const } } - -uchar *Field_blob::pack(uchar *to, const uchar *from, uint max_length) +uchar *Field_blob::pack(uchar *to, const uchar *from, + uint max_length, bool low_byte_first) { + DBUG_ENTER("Field_blob::pack"); + DBUG_PRINT("enter", ("to: 0x%lx; from: 0x%lx;" + " max_length: %u; low_byte_first: %d", + (ulong) to, (ulong) from, + max_length, low_byte_first)); + DBUG_DUMP("record", from, table->s->reclength); uchar *save= ptr; ptr= (uchar*) from; uint32 length=get_length(); // Length of from string - if (length > max_length) - { - ptr=to; - length=max_length; - store_length(length); // Store max length - ptr= (uchar*) from; - } - else - memcpy(to,from,packlength); // Copy length - if (length) + + /* + Store max length, which will occupy packlength bytes. If the max + length given is smaller than the actual length of the blob, we + just store the initial bytes of the blob. + */ + store_length(to, packlength, min(length, max_length), low_byte_first); + + /* + Store the actual blob data, which will occupy 'length' bytes. + */ + if (length > 0) { get_ptr((uchar**) &from); memcpy(to+packlength, from,length); } ptr=save; // Restore org row pointer - return to+packlength+length; + DBUG_DUMP("packed", to, packlength + length); + DBUG_RETURN(to+packlength+length); } @@ -7644,28 +7762,26 @@ uchar *Field_blob::pack(uchar *to, const uchar *from, uint max_length) @param to Destination of the data @param from Source of the data - @param param_data @return New pointer into memory based on from + length of the data */ const uchar *Field_blob::unpack(uchar *to, const uchar *from, - uint param_data) + uint param_data, + bool low_byte_first) { - return unpack(to, from); -} - - -const uchar *Field_blob::unpack(uchar *to, const uchar *from) -{ - memcpy(to,from,packlength); - uint32 length=get_length(from); - from+=packlength; - if (length) - memcpy_fixed(to+packlength, &from, sizeof(from)); - else - bzero(to+packlength,sizeof(from)); - return from+length; + DBUG_ENTER("Field_blob::unpack"); + DBUG_PRINT("enter", ("to: 0x%lx; from: 0x%lx;" + " param_data: %u; low_byte_first: %d", + (ulong) to, (ulong) from, param_data, low_byte_first)); + uint const master_packlength= + param_data > 0 ? param_data & 0xFF : packlength; + uint32 const length= get_length(from, master_packlength, low_byte_first); + DBUG_DUMP("packed", from, length + master_packlength); + store(reinterpret_cast(from) + master_packlength, + length, field_charset); + DBUG_DUMP("record", to, table->s->reclength); + DBUG_RETURN(from + master_packlength + length); } /* Keys for blobs are like keys on varchars */ @@ -7715,7 +7831,9 @@ int Field_blob::pack_cmp(const uchar *b, uint key_length_arg, /* Create a packed key that will be used for storage from a MySQL row */ -uchar *Field_blob::pack_key(uchar *to, const uchar *from, uint max_length) +uchar * +Field_blob::pack_key(uchar *to, const uchar *from, uint max_length, + bool low_byte_first __attribute__((unused))) { uchar *save= ptr; ptr= (uchar*) from; @@ -7760,8 +7878,9 @@ uchar *Field_blob::pack_key(uchar *to, const uchar *from, uint max_length) Pointer into 'from' past the last byte copied from packed key. */ -const uchar *Field_blob::unpack_key(uchar *to, const uchar *from, - uint max_length) +const uchar * +Field_blob::unpack_key(uchar *to, const uchar *from, uint max_length, + bool low_byte_first __attribute__((unused))) { /* get length of the blob key */ uint32 length= *from++; @@ -7784,8 +7903,9 @@ const uchar *Field_blob::unpack_key(uchar *to, const uchar *from, /* Create a packed key that will be used for storage from a MySQL key */ -uchar *Field_blob::pack_key_from_key_image(uchar *to, const uchar *from, - uint max_length) +uchar * +Field_blob::pack_key_from_key_image(uchar *to, const uchar *from, uint max_length, + bool low_byte_first __attribute__((unused))) { uint length=uint2korr(from); if (length > max_length) @@ -8672,9 +8792,11 @@ void Field_bit::sql_type(String &res) const } -uchar *Field_bit::pack(uchar *to, const uchar *from, uint max_length) +uchar * +Field_bit::pack(uchar *to, const uchar *from, uint max_length, + bool low_byte_first __attribute__((unused))) { - DBUG_ASSERT(max_length); + DBUG_ASSERT(max_length > 0); uint length; if (bit_len > 0) { @@ -8709,28 +8831,44 @@ uchar *Field_bit::pack(uchar *to, const uchar *from, uint max_length) /** Unpack a bit field from row data. - This method is used to unpack a bit field from a master whose size + This method is used to unpack a bit field from a master whose size of the field is less than that of the slave. - + @param to Destination of the data @param from Source of the data @param param_data Bit length (upper) and length (lower) values @return New pointer into memory based on from + length of the data */ -const uchar *Field_bit::unpack(uchar *to, - const uchar *from, - uint param_data) +const uchar * +Field_bit::unpack(uchar *to, const uchar *from, uint param_data, + bool low_byte_first __attribute__((unused))) { uint const from_len= (param_data >> 8U) & 0x00ff; uint const from_bit_len= param_data & 0x00ff; /* - If the master and slave have the same sizes, then use the old - unpack() method. + If the parameter data is zero (i.e., undefined), or if the master + and slave have the same sizes, then use the old unpack() method. */ - if ((from_bit_len == bit_len) && - (from_len == bytes_in_rec)) - return(unpack(to, from)); + if (param_data == 0 || + (from_bit_len == bit_len) && (from_len == bytes_in_rec)) + { + if (bit_len > 0) + { + /* + set_rec_bits is a macro, don't put the post-increment in the + argument since that might cause strange side-effects. + + For the choice of the second argument, see the explanation for + Field_bit::pack(). + */ + set_rec_bits(*from, bit_ptr + (to - ptr), bit_ofs, bit_len); + from++; + } + memcpy(to, from, bytes_in_rec); + return from + bytes_in_rec; + } + /* We are converting a smaller bit field to a larger one here. To do that, we first need to construct a raw value for the original @@ -8758,25 +8896,6 @@ const uchar *Field_bit::unpack(uchar *to, } -const uchar *Field_bit::unpack(uchar *to, const uchar *from) -{ - if (bit_len > 0) - { - /* - set_rec_bits is a macro, don't put the post-increment in the - argument since that might cause strange side-effects. - - For the choice of the second argument, see the explanation for - Field_bit::pack(). - */ - set_rec_bits(*from, bit_ptr + (to - ptr), bit_ofs, bit_len); - from++; - } - memcpy(to, from, bytes_in_rec); - return from + bytes_in_rec; -} - - void Field_bit::set_default() { if (bit_len > 0) diff --git a/sql/field.h b/sql/field.h index 60f6fc19d76..37a0cdae070 100644 --- a/sql/field.h +++ b/sql/field.h @@ -157,6 +157,17 @@ public: */ virtual uint32 data_length() { return pack_length(); } virtual uint32 sort_length() const { return pack_length(); } + + /** + Get the maximum size of the data in packed format. + + @return Maximum data length of the field when packed using the + Field::pack() function. + */ + virtual uint32 max_data_length() const { + return pack_length(); + }; + virtual int reset(void) { bzero(ptr,pack_length()); return 0; } virtual void reset_fields() {} virtual void set_default() @@ -339,32 +350,45 @@ public: return str; } virtual bool send_binary(Protocol *protocol); - virtual uchar *pack(uchar *to, const uchar *from, uint max_length=~(uint) 0) + + virtual uchar *pack(uchar *to, const uchar *from, + uint max_length, bool low_byte_first); + /** + @overload Field::pack(uchar*, const uchar*, uint, bool) + */ + uchar *pack(uchar *to, const uchar *from) { - uint32 length=pack_length(); - memcpy(to,from,length); - return to+length; + DBUG_ENTER("Field::pack"); + uchar *result= this->pack(to, from, UINT_MAX, table->s->db_low_byte_first); + DBUG_RETURN(result); } - virtual const uchar *unpack(uchar* to, const uchar *from, uint param_data); - virtual const uchar *unpack(uchar* to, const uchar *from) + + virtual const uchar *unpack(uchar* to, const uchar *from, + uint param_data, bool low_byte_first); + /** + @overload Field::unpack(uchar*, const uchar*, uint, bool) + */ + const uchar *unpack(uchar* to, const uchar *from) { - uint length=pack_length(); - memcpy(to,from,length); - return from+length; + DBUG_ENTER("Field::unpack"); + const uchar *result= unpack(to, from, 0U, table->s->db_low_byte_first); + DBUG_RETURN(result); } - virtual uchar *pack_key(uchar* to, const uchar *from, uint max_length) + + virtual uchar *pack_key(uchar* to, const uchar *from, + uint max_length, bool low_byte_first) { - return pack(to,from,max_length); + return pack(to, from, max_length, low_byte_first); } virtual uchar *pack_key_from_key_image(uchar* to, const uchar *from, - uint max_length) + uint max_length, bool low_byte_first) { - return pack(to,from,max_length); + return pack(to, from, max_length, low_byte_first); } virtual const uchar *unpack_key(uchar* to, const uchar *from, - uint max_length) + uint max_length, bool low_byte_first) { - return unpack(to,from); + return unpack(to, from, max_length, low_byte_first); } virtual uint packed_col_length(const uchar *to, uint length) { return length;} @@ -536,6 +560,7 @@ public: {} int store_decimal(const my_decimal *d); + uint32 max_data_length() const; }; /* base class for float and double and decimal (old one) */ @@ -556,6 +581,10 @@ public: int truncate(double *nr, double max_length); uint32 max_display_length() { return field_length; } uint size_of() const { return sizeof(*this); } + virtual const uchar *unpack(uchar* to, const uchar *from, + uint param_data, bool low_byte_first); + virtual uchar *pack(uchar* to, const uchar *from, + uint max_length, bool low_byte_first); }; @@ -584,6 +613,16 @@ public: void overflow(bool negative); bool zero_pack() const { return 0; } void sql_type(String &str) const; + virtual const uchar *unpack(uchar* to, const uchar *from, + uint param_data, bool low_byte_first) + { + return Field::unpack(to, from, param_data, low_byte_first); + } + virtual uchar *pack(uchar* to, const uchar *from, + uint max_length, bool low_byte_first) + { + return Field::pack(to, from, max_length, low_byte_first); + } }; @@ -629,7 +668,8 @@ public: uint size_of() const { return sizeof(*this); } uint32 pack_length() const { return (uint32) bin_size; } uint is_equal(Create_field *new_field); - virtual const uchar *unpack(uchar* to, const uchar *from, uint param_data); + virtual const uchar *unpack(uchar* to, const uchar *from, + uint param_data, bool low_byte_first); }; @@ -660,6 +700,20 @@ public: uint32 pack_length() const { return 1; } void sql_type(String &str) const; uint32 max_display_length() { return 4; } + + virtual uchar *pack(uchar* to, const uchar *from, + uint max_length, bool low_byte_first) + { + *to= *from; + return to + 1; + } + + virtual const uchar *unpack(uchar* to, const uchar *from, + uint param_data, bool low_byte_first) + { + *to= *from; + return from + 1; + } }; @@ -695,8 +749,47 @@ public: uint32 pack_length() const { return 2; } void sql_type(String &str) const; uint32 max_display_length() { return 6; } -}; + virtual uchar *pack(uchar* to, const uchar *from, + uint max_length, bool low_byte_first) + { + int16 val; +#ifdef WORDS_BIGENDIAN + if (table->s->db_low_byte_first) + val = sint2korr(from); + else +#endif + shortget(val, from); + +#ifdef WORDS_BIGENDIAN + if (low_byte_first) + int2store(to, val); + else +#endif + shortstore(to, val); + return to + sizeof(val); + } + + virtual const uchar *unpack(uchar* to, const uchar *from, + uint param_data, bool low_byte_first) + { + int16 val; +#ifdef WORDS_BIGENDIAN + if (low_byte_first) + val = sint2korr(from); + else +#endif + shortget(val, from); + +#ifdef WORDS_BIGENDIAN + if (table->s->db_low_byte_first) + int2store(to, val); + else +#endif + shortstore(to, val); + return from + sizeof(val); + } +}; class Field_medium :public Field_num { public: @@ -725,6 +818,18 @@ public: uint32 pack_length() const { return 3; } void sql_type(String &str) const; uint32 max_display_length() { return 8; } + + virtual uchar *pack(uchar* to, const uchar *from, + uint max_length, bool low_byte_first) + { + return Field::pack(to, from, max_length, low_byte_first); + } + + virtual const uchar *unpack(uchar* to, const uchar *from, + uint param_data, bool low_byte_first) + { + return Field::unpack(to, from, param_data, low_byte_first); + } }; @@ -760,6 +865,45 @@ public: uint32 pack_length() const { return 4; } void sql_type(String &str) const; uint32 max_display_length() { return MY_INT32_NUM_DECIMAL_DIGITS; } + virtual uchar *pack(uchar* to, const uchar *from, + uint max_length, bool low_byte_first) + { + int32 val; +#ifdef WORDS_BIGENDIAN + if (table->s->db_low_byte_first) + val = sint4korr(from); + else +#endif + longget(val, from); + +#ifdef WORDS_BIGENDIAN + if (low_byte_first) + int4store(to, val); + else +#endif + longstore(to, val); + return to + sizeof(val); + } + + virtual const uchar *unpack(uchar* to, const uchar *from, + uint param_data, bool low_byte_first) + { + int32 val; +#ifdef WORDS_BIGENDIAN + if (low_byte_first) + val = sint4korr(from); + else +#endif + longget(val, from); + +#ifdef WORDS_BIGENDIAN + if (table->s->db_low_byte_first) + int4store(to, val); + else +#endif + longstore(to, val); + return from + sizeof(val); + } }; @@ -802,6 +946,45 @@ public: void sql_type(String &str) const; bool can_be_compared_as_longlong() const { return TRUE; } uint32 max_display_length() { return 20; } + virtual uchar *pack(uchar* to, const uchar *from, + uint max_length, bool low_byte_first) + { + int64 val; +#ifdef WORDS_BIGENDIAN + if (table->s->db_low_byte_first) + val = sint8korr(from); + else +#endif + longlongget(val, from); + +#ifdef WORDS_BIGENDIAN + if (low_byte_first) + int8store(to, val); + else +#endif + longlongstore(to, val); + return to + sizeof(val); + } + + virtual const uchar *unpack(uchar* to, const uchar *from, + uint param_data, bool low_byte_first) + { + int64 val; +#ifdef WORDS_BIGENDIAN + if (low_byte_first) + val = sint8korr(from); + else +#endif + longlongget(val, from); + +#ifdef WORDS_BIGENDIAN + if (table->s->db_low_byte_first) + int8store(to, val); + else +#endif + longlongstore(to, val); + return from + sizeof(val); + } }; #endif @@ -1176,9 +1359,10 @@ public: int cmp(const uchar *,const uchar *); void sort_string(uchar *buff,uint length); void sql_type(String &str) const; - uchar *pack(uchar *to, const uchar *from, uint max_length=~(uint) 0); - virtual const uchar *unpack(uchar* to, const uchar *from, uint param_data); - const uchar *unpack(uchar* to, const uchar *from); + virtual uchar *pack(uchar *to, const uchar *from, + uint max_length, bool low_byte_first); + virtual const uchar *unpack(uchar* to, const uchar *from, + uint param_data, bool low_byte_first); int pack_cmp(const uchar *a,const uchar *b,uint key_length, my_bool insert_or_update); int pack_cmp(const uchar *b,uint key_length,my_bool insert_or_update); @@ -1250,13 +1434,15 @@ public: uint get_key_image(uchar *buff,uint length, imagetype type); void set_key_image(const uchar *buff,uint length); void sql_type(String &str) const; - uchar *pack(uchar *to, const uchar *from, uint max_length=~(uint) 0); - uchar *pack_key(uchar *to, const uchar *from, uint max_length); + virtual uchar *pack(uchar *to, const uchar *from, + uint max_length, bool low_byte_first); + uchar *pack_key(uchar *to, const uchar *from, uint max_length, bool low_byte_first); uchar *pack_key_from_key_image(uchar* to, const uchar *from, - uint max_length); - virtual const uchar *unpack(uchar* to, const uchar *from, uint param_data); - const uchar *unpack(uchar* to, const uchar *from); - const uchar *unpack_key(uchar* to, const uchar *from, uint max_length); + uint max_length, bool low_byte_first); + virtual const uchar *unpack(uchar* to, const uchar *from, + uint param_data, bool low_byte_first); + const uchar *unpack_key(uchar* to, const uchar *from, + uint max_length, bool low_byte_first); int pack_cmp(const uchar *a, const uchar *b, uint key_length, my_bool insert_or_update); int pack_cmp(const uchar *b, uint key_length,my_bool insert_or_update); @@ -1346,7 +1532,7 @@ public: uint32 pack_length_no_ptr() const { return (uint32) (packlength); } uint32 sort_length() const; - inline uint32 max_data_length() const + virtual uint32 max_data_length() const { return (uint32) (((ulonglong) 1 << (packlength*8)) -1); } @@ -1374,13 +1560,13 @@ public: @retval The length in the row plus the size of the data. */ uint32 get_packed_size(const uchar *ptr_arg, bool low_byte_first) - {return packlength + get_length(ptr_arg, low_byte_first);} + {return packlength + get_length(ptr_arg, packlength, low_byte_first);} inline uint32 get_length(uint row_offset= 0) - { return get_length(ptr+row_offset, table->s->db_low_byte_first); } - uint32 get_length(const uchar *ptr, bool low_byte_first); + { return get_length(ptr+row_offset, this->packlength, table->s->db_low_byte_first); } + uint32 get_length(const uchar *ptr, uint packlength, bool low_byte_first); uint32 get_length(const uchar *ptr_arg) - { return get_length(ptr_arg, table->s->db_low_byte_first); } + { return get_length(ptr_arg, this->packlength, table->s->db_low_byte_first); } void put_length(uchar *pos, uint32 length); inline void get_ptr(uchar **str) { @@ -1421,13 +1607,16 @@ public: memcpy_fixed(ptr+packlength,&tmp,sizeof(char*)); return 0; } - uchar *pack(uchar *to, const uchar *from, uint max_length= ~(uint) 0); - uchar *pack_key(uchar *to, const uchar *from, uint max_length); + virtual uchar *pack(uchar *to, const uchar *from, + uint max_length, bool low_byte_first); + uchar *pack_key(uchar *to, const uchar *from, + uint max_length, bool low_byte_first); uchar *pack_key_from_key_image(uchar* to, const uchar *from, - uint max_length); - virtual const uchar *unpack(uchar *to, const uchar *from, uint param_data); - const uchar *unpack(uchar *to, const uchar *from); - const uchar *unpack_key(uchar* to, const uchar *from, uint max_length); + uint max_length, bool low_byte_first); + virtual const uchar *unpack(uchar *to, const uchar *from, + uint param_data, bool low_byte_first); + const uchar *unpack_key(uchar* to, const uchar *from, + uint max_length, bool low_byte_first); int pack_cmp(const uchar *a, const uchar *b, uint key_length, my_bool insert_or_update); int pack_cmp(const uchar *b, uint key_length,my_bool insert_or_update); @@ -1572,6 +1761,7 @@ public: enum_field_types type() const { return MYSQL_TYPE_BIT; } enum ha_base_keytype key_type() const { return HA_KEYTYPE_BIT; } uint32 key_length() const { return (uint32) (field_length + 7) / 8; } + uint32 max_data_length() const { return (field_length + 7) / 8; } uint32 max_display_length() { return field_length; } uint size_of() const { return sizeof(*this); } Item_result result_type () const { return INT_RESULT; } @@ -1602,9 +1792,10 @@ public: uint32 pack_length() const { return (uint32) (field_length + 7) / 8; } uint32 pack_length_in_rec() const { return bytes_in_rec; } void sql_type(String &str) const; - uchar *pack(uchar *to, const uchar *from, uint max_length=~(uint) 0); - virtual const uchar *unpack(uchar *to, const uchar *from, uint param_data); - const uchar *unpack(uchar* to, const uchar *from); + virtual uchar *pack(uchar *to, const uchar *from, + uint max_length, bool low_byte_first); + virtual const uchar *unpack(uchar *to, const uchar *from, + uint param_data, bool low_byte_first); virtual void set_default(); Field *new_key_field(MEM_ROOT *root, struct st_table *new_table, diff --git a/sql/log.cc b/sql/log.cc index dcf27161f1a..4d1ef9eed9f 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -3571,9 +3571,6 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info) (!binlog_filter->db_ok(local_db))) { VOID(pthread_mutex_unlock(&LOCK_log)); - DBUG_PRINT("info",("OPTION_BIN_LOG is %s, db_ok('%s') == %d", - (thd->options & OPTION_BIN_LOG) ? "set" : "clear", - local_db, binlog_filter->db_ok(local_db))); DBUG_RETURN(0); } #endif /* HAVE_REPLICATION */ diff --git a/sql/log_event.cc b/sql/log_event.cc index cfac7df21a8..cf4bb229b2f 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -5697,7 +5697,9 @@ Rows_log_event::Rows_log_event(const char *buf, uint event_len, *description_event) : Log_event(buf, description_event), m_row_count(0), +#ifndef MYSQL_CLIENT m_table(NULL), +#endif m_rows_buf(0), m_rows_cur(0), m_rows_end(0), m_curr_row(NULL), m_curr_row_end(NULL), m_key(NULL) @@ -6168,6 +6170,8 @@ int Rows_log_event::do_apply_event(RELAY_LOG_INFO const *rli) unpack_current_row(rli); // at this moment m_curr_row_end should be set + DBUG_PRINT("debug", ("m_curr_row_end: 0x%lx; m_curr_row: 0x%lx; m_rows_end: 0x%lx", + m_curr_row_end, m_curr_row, m_rows_end)); DBUG_ASSERT(error || m_curr_row_end != NULL); DBUG_ASSERT(error || m_curr_row < m_curr_row_end); DBUG_ASSERT(error || m_curr_row_end <= m_rows_end); diff --git a/sql/rpl_record.cc b/sql/rpl_record.cc index de4f6e0c337..dbfe7902ee9 100644 --- a/sql/rpl_record.cc +++ b/sql/rpl_record.cc @@ -65,6 +65,8 @@ pack_row(TABLE *table, MY_BITMAP const* cols, my_ptrdiff_t const rec_offset= record - table->record[0]; my_ptrdiff_t const def_offset= table->s->default_values - table->record[0]; + DBUG_ENTER("pack_row"); + /* We write the null bits and the packed records using one pass through all the fields. The null bytes are written little-endian, @@ -96,26 +98,14 @@ pack_row(TABLE *table, MY_BITMAP const* cols, For big-endian machines, we have to make sure that the length is stored in little-endian format, since this is the format used for the binlog. - - We do this by setting the db_low_byte_first, which is used - inside some store_length() to decide what order to write the - bytes in. - - In reality, db_log_byte_first is only set for legacy table - type Isam, but in the event of a bug, we need to guarantee - the endianess when writing to the binlog. - - This is currently broken for NDB due to BUG#29549, so we - will fix it when NDB has fixed their way of handling BLOBs. */ -#if 0 - bool save= table->s->db_low_byte_first; - table->s->db_low_byte_first= TRUE; -#endif - pack_ptr= field->pack(pack_ptr, field->ptr + offset); -#if 0 - table->s->db_low_byte_first= save; -#endif + const uchar *old_pack_ptr= pack_ptr; + pack_ptr= field->pack(pack_ptr, field->ptr + offset, + field->max_data_length(), TRUE); + DBUG_PRINT("debug", ("field: %s; pack_ptr: 0x%lx;" + " pack_ptr':0x%lx; bytes: %d", + field->field_name, (ulong) old_pack_ptr, + (ulong) pack_ptr, pack_ptr - old_pack_ptr)); } null_mask <<= 1; @@ -143,8 +133,8 @@ pack_row(TABLE *table, MY_BITMAP const* cols, packed data. If it doesn't, something is very wrong. */ DBUG_ASSERT(null_ptr == row_data + null_byte_count); - - return static_cast(pack_ptr - row_data); + DBUG_DUMP("row_data", row_data, pack_ptr - row_data); + DBUG_RETURN(static_cast(pack_ptr - row_data)); } #endif @@ -242,18 +232,14 @@ unpack_row(RELAY_LOG_INFO const *rli, Use the master's size information if available else call normal unpack operation. */ -#if 0 - bool save= table->s->db_low_byte_first; - table->s->db_low_byte_first= TRUE; -#endif uint16 const metadata= tabledef->field_metadata(i); - if (tabledef && metadata) - pack_ptr= f->unpack(f->ptr, pack_ptr, metadata); - else - pack_ptr= f->unpack(f->ptr, pack_ptr); -#if 0 - table->s->db_low_byte_first= save; -#endif + uchar const *const old_pack_ptr= pack_ptr; + pack_ptr= f->unpack(f->ptr, pack_ptr, metadata, TRUE); + DBUG_PRINT("debug", ("field: %s; metadata: 0x%x;" + " pack_ptr: 0x%lx; pack_ptr': 0x%lx; bytes: %d", + f->field_name, metadata, + (ulong) old_pack_ptr, (ulong) pack_ptr, + pack_ptr - old_pack_ptr)); } null_mask <<= 1; @@ -265,6 +251,7 @@ unpack_row(RELAY_LOG_INFO const *rli, throw away master's extra fields */ uint max_cols= min(tabledef->size(), cols->n_bits); + DBUG_PRINT("debug", ("Master has %u fields, slave %u", tabledef->size(), cols->n_bits)); for (; i < max_cols; i++) { if (bitmap_is_set(cols, i)) @@ -279,6 +266,7 @@ unpack_row(RELAY_LOG_INFO const *rli, if (!((null_bits & null_mask) && tabledef->maybe_null(i))) pack_ptr+= tabledef->calc_field_size(i, (uchar *) pack_ptr); + DBUG_PRINT("debug", ("pack_ptr: 0x%lx", (ulong) pack_ptr)); null_mask <<= 1; } } @@ -289,6 +277,8 @@ unpack_row(RELAY_LOG_INFO const *rli, */ DBUG_ASSERT(null_ptr == row_data + master_null_byte_count); + DBUG_DUMP("row_data", row_data, pack_ptr - row_data); + *row_end = pack_ptr; if (master_reclength) { diff --git a/sql/sql_show.cc b/sql/sql_show.cc index bb4f5107df8..49910e75286 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -29,6 +29,8 @@ #include "event_data_objects.h" #include +#define STR_OR_NIL(S) ((S) ? (S) : "") + #ifdef WITH_PARTITION_STORAGE_ENGINE #include "ha_partition.h" #endif @@ -3096,8 +3098,8 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) schema_table_idx= get_schema_table_idx(schema_table); get_lookup_field_values(thd, cond, tables, &lookup_field_vals); DBUG_PRINT("INDEX VALUES",("db_name='%s', table_name='%s'", - lookup_field_vals.db_value.str, - lookup_field_vals.table_value.str)); + STR_OR_NIL(lookup_field_vals.db_value.str), + STR_OR_NIL(lookup_field_vals.table_value.str))); if (!lookup_field_vals.wild_db_value && !lookup_field_vals.wild_table_value) { From 91b5c11922643dd3b62d0ddcd0184388faf83ead Mon Sep 17 00:00:00 2001 From: "cmiller@zippy.cornsilk.net" <> Date: Thu, 11 Oct 2007 13:29:09 -0400 Subject: [PATCH 035/336] Doxygenization of comments. --- sql/field_conv.cc | 55 +-- sql/filesort.cc | 296 +++++++------ sql/gen_lex_hash.cc | 17 +- sql/ha_ndbcluster.cc | 469 ++++++++++---------- sql/handler.cc | 465 ++++++++++---------- sql/hostname.cc | 11 +- sql/init.cc | 7 +- sql/item.cc | 998 +++++++++++++++++++++--------------------- sql/item_buff.cc | 19 +- sql/item_cmpfunc.cc | 466 ++++++++++---------- sql/item_create.cc | 7 +- sql/item_func.cc | 297 ++++++------- sql/item_geofunc.cc | 13 +- sql/item_row.cc | 7 +- sql/item_strfunc.cc | 99 +++-- sql/item_subselect.cc | 112 ++--- sql/item_sum.cc | 153 ++++--- sql/item_timefunc.cc | 166 +++---- sql/key.cc | 86 ++-- sql/lock.cc | 217 +++++---- sql/log.cc | 446 ++++++++++--------- sql/log_event.cc | 295 +++++++------ sql/mf_iocache.cc | 21 +- sql/my_decimal.cc | 12 +- sql/mysqld.cc | 248 +++++------ 25 files changed, 2510 insertions(+), 2472 deletions(-) diff --git a/sql/field_conv.cc b/sql/field_conv.cc index 16e27bb6cab..11d0bb9cc82 100644 --- a/sql/field_conv.cc +++ b/sql/field_conv.cc @@ -14,11 +14,15 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* - Functions to copy data to or from fields - This could be done with a single short function but opencoding this - gives much more speed. - */ +/** + @file + + @brief + Functions to copy data to or from fields + + This could be done with a single short function but opencoding this + gives much more speed. +*/ #include "mysql_priv.h" #include @@ -129,22 +133,21 @@ set_field_to_null(Field *field) } -/* - Set field to NULL or TIMESTAMP or to next auto_increment number +/** + Set field to NULL or TIMESTAMP or to next auto_increment number. - SYNOPSIS - set_field_to_null_with_conversions() - field Field to update - no_conversion Set to 1 if we should return 1 if field can't - take null values. - If set to 0 we will do store the 'default value' - if the field is a special field. If not we will - give an error. + @param field Field to update + @param no_conversions Set to 1 if we should return 1 if field can't + take null values. + If set to 0 we will do store the 'default value' + if the field is a special field. If not we will + give an error. - RETURN VALUES - 0 Field could take 0 or an automatic conversion was used - -1 Field could not take NULL and no conversion was used. - If no_conversion was not set, an error message is printed + @retval + 0 Field could take 0 or an automatic conversion was used + @retval + -1 Field could not take NULL and no conversion was used. + If no_conversion was not set, an error message is printed */ int @@ -283,7 +286,7 @@ static void do_conv_blob(Copy_field *copy) copy->tmp.charset()); } -/* Save blob in copy->tmp for GROUP BY */ +/** Save blob in copy->tmp for GROUP BY. */ static void do_save_blob(Copy_field *copy) { @@ -352,9 +355,9 @@ static void do_field_decimal(Copy_field *copy) } -/* +/** string copy for single byte characters set when to string is shorter than - from string + from string. */ static void do_cut_string(Copy_field *copy) @@ -374,9 +377,9 @@ static void do_cut_string(Copy_field *copy) } -/* +/** string copy for multi byte characters set when to string is shorter than - from string + from string. */ static void do_cut_string_complex(Copy_field *copy) @@ -507,7 +510,7 @@ static void do_varstring2_mb(Copy_field *copy) ** The different functions that fills in a Copy_field class ***************************************************************************/ -/* +/** copy of field to maybe null string. If field is null then the all bytes are set to 0. if field is not null then the first byte is set to 1 and the rest of the @@ -748,7 +751,7 @@ Copy_field::get_copy_func(Field *to,Field *from) } -/* Simple quick field convert that is called on insert */ +/** Simple quick field convert that is called on insert. */ int field_conv(Field *to,Field *from) { diff --git a/sql/filesort.cc b/sql/filesort.cc index b6a5d844eac..71d3c29b188 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -14,7 +14,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* Sorts a database */ +/** + @file + + @brief + Sorts a database +*/ #include "mysql_priv.h" #ifdef HAVE_STDDEF_H @@ -27,8 +32,7 @@ #define SKIP_DBUG_IN_FILESORT #endif - /* How to write record_ref. */ - +/// How to write record_ref. #define WRITE_REF(file,from) \ if (my_b_write((file),(uchar*) (from),param->ref_length)) \ DBUG_RETURN(1); @@ -58,42 +62,40 @@ static SORT_ADDON_FIELD *get_addon_fields(THD *thd, Field **ptabfield, uint sortlength, uint *plength); static void unpack_addon_fields(struct st_sort_addon_field *addon_field, uchar *buff); +/** + Sort a table. + Creates a set of pointers that can be used to read the rows + in sorted order. This should be done with the functions + in records.cc. -/* - Sort a table + Before calling filesort, one must have done + table->file->info(HA_STATUS_VARIABLE) - SYNOPSIS - filesort() - table Table to sort - sortorder How to sort the table - s_length Number of elements in sortorder - select Condition to apply to the rows - ha_maxrows Return only this many rows - sort_positions Set to 1 if we want to force sorting by position + The result set is stored in table->io_cache or + table->record_pointers. + + @param thd Current thread + @param table Table to sort + @param sortorder How to sort the table + @param s_length Number of elements in sortorder + @param select condition to apply to the rows + @param max_rows Return only this many rows + @param sort_positions Set to 1 if we want to force sorting by position (Needed by UPDATE/INSERT or ALTER TABLE) - examined_rows Store number of examined rows here + @param examined_rows Store number of examined rows here - IMPLEMENTATION - Creates a set of pointers that can be used to read the rows - in sorted order. This should be done with the functions - in records.cc - - REQUIREMENTS - Before calling filesort, one must have done - table->file->info(HA_STATUS_VARIABLE) - - NOTES + @todo + check why we do this (param.keys--) + @note If we sort by position (like if sort_positions is 1) filesort() will call table->prepare_for_position(). - RETURN + @retval HA_POS_ERROR Error - # Number of rows - + @retval + \# Number of rows + @retval examined_rows will be set to number of examined rows - - The result set is stored in table->io_cache or - table->record_pointers */ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length, @@ -351,7 +353,7 @@ void filesort_free_buffers(TABLE *table, bool full) } } - /* Make a array of string pointers */ +/** Make a array of string pointers. */ static char **make_char_array(char **old_pos, register uint fields, uint length, myf my_flag) @@ -372,7 +374,7 @@ static char **make_char_array(char **old_pos, register uint fields, } /* make_char_array */ -/* Read 'count' number of buffer pointers into memory */ +/** Read 'count' number of buffer pointers into memory. */ static BUFFPEK *read_buffpek_from_file(IO_CACHE *buffpek_pointers, uint count) { @@ -395,38 +397,40 @@ static BUFFPEK *read_buffpek_from_file(IO_CACHE *buffpek_pointers, uint count) } -/* +/** Search after sort_keys and write them into tempfile. - SYNOPSIS - find_all_keys() - param Sorting parameter - select Use this to get source data - sort_keys Array of pointers to sort key + addon buffers. - buffpek_pointers File to write BUFFPEKs describing sorted segments - in tempfile. - tempfile File to write sorted sequences of sortkeys to. - indexfile If !NULL, use it for source data (contains rowids) - - NOTE + All produced sequences are guaranteed to be non-empty. + + @param param Sorting parameter + @param select Use this to get source data + @param sort_keys Array of pointers to sort key + addon buffers. + @param buffpek_pointers File to write BUFFPEKs describing sorted segments + in tempfile. + @param tempfile File to write sorted sequences of sortkeys to. + @param indexfile If !NULL, use it for source data (contains rowids) + + @note Basic idea: - while (get_next_sortkey()) - { - if (no free space in sort_keys buffers) - { - sort sort_keys buffer; - dump sorted sequence to 'tempfile'; - dump BUFFPEK describing sequence location into 'buffpek_pointers'; - } - put sort key into 'sort_keys'; - } - if (sort_keys has some elements && dumped at least once) - sort-dump-dump as above; - else - don't sort, leave sort_keys array to be sorted by caller. - - All produced sequences are guaranteed to be non-empty. - RETURN + @verbatim + while (get_next_sortkey()) + { + if (no free space in sort_keys buffers) + { + sort sort_keys buffer; + dump sorted sequence to 'tempfile'; + dump BUFFPEK describing sequence location into 'buffpek_pointers'; + } + put sort key into 'sort_keys'; + } + if (sort_keys has some elements && dumped at least once) + sort-dump-dump as above; + else + don't sort, leave sort_keys array to be sorted by caller. + @endverbatim + + @retval Number of records written on success. + @retval HA_POS_ERROR on error. */ @@ -591,23 +595,25 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select, } /* find_all_keys */ -/* +/** + @details Sort the buffer and write: - 1) the sorted sequence to tempfile - 2) a BUFFPEK describing the sorted sequence position to buffpek_pointers - (was: Skriver en buffert med nycklar till filen) - SYNOPSIS - write_keys() - param Sort parameters - sort_keys Array of pointers to keys to sort - count Number of elements in sort_keys array - buffpek_pointers One 'BUFFPEK' struct will be written into this file. - The BUFFPEK::{file_pos, count} will indicate where - the sorted data was stored. - tempfile The sorted sequence will be written into this file. - - RETURN + -# the sorted sequence to tempfile + -# a BUFFPEK describing the sorted sequence position to buffpek_pointers + + (was: Skriver en buffert med nycklar till filen) + + @param param Sort parameters + @param sort_keys Array of pointers to keys to sort + @param count Number of elements in sort_keys array + @param buffpek_pointers One 'BUFFPEK' struct will be written into this file. + The BUFFPEK::{file_pos, count} will indicate where + the sorted data was stored. + @param tempfile The sorted sequence will be written into this file. + + @retval 0 OK + @retval 1 Error */ @@ -650,8 +656,8 @@ err: } /* write_keys */ -/* - Store length as suffix in high-byte-first order +/** + Store length as suffix in high-byte-first order. */ static inline void store_length(uchar *to, uint length, uint pack_length) @@ -673,7 +679,7 @@ static inline void store_length(uchar *to, uint length, uint pack_length) } - /* makes a sort-key from record */ +/** Make a sort-key from record. */ static void make_sortkey(register SORTPARAM *param, register uchar *to, uchar *ref_pos) @@ -987,7 +993,7 @@ static bool save_index(SORTPARAM *param, uchar **sort_keys, uint count, } - /* Merge buffers to make < MERGEBUFF2 buffers */ +/** Merge buffers to make < MERGEBUFF2 buffers. */ int merge_many_buff(SORTPARAM *param, uchar *sort_buffer, BUFFPEK *buffpek, uint *maxbuffer, IO_CACHE *t_file) @@ -1040,8 +1046,12 @@ cleanup: } /* merge_many_buff */ - /* Read data to buffer */ - /* This returns (uint) -1 if something goes wrong */ +/** + Read data to buffer. + + @retval + (uint)-1 if something goes wrong +*/ uint read_to_buffer(IO_CACHE *fromfile, BUFFPEK *buffpek, uint rec_length) @@ -1063,15 +1073,15 @@ uint read_to_buffer(IO_CACHE *fromfile, BUFFPEK *buffpek, } /* read_to_buffer */ -/* - Put all room used by freed buffer to use in adjacent buffer. Note, that - we can't simply distribute memory evenly between all buffers, because - new areas must not overlap with old ones. - SYNOPSIS - reuse_freed_buff() - queue IN list of non-empty buffers, without freed buffer - reuse IN empty buffer - key_length IN key length +/** + Put all room used by freed buffer to use in adjacent buffer. + + Note, that we can't simply distribute memory evenly between all buffers, + because new areas must not overlap with old ones. + + @param[in] queue list of non-empty buffers, without freed buffer + @param[in] reuse empty buffer + @param[in] key_length key length */ void reuse_freed_buff(QUEUE *queue, BUFFPEK *reuse, uint key_length) @@ -1096,22 +1106,22 @@ void reuse_freed_buff(QUEUE *queue, BUFFPEK *reuse, uint key_length) } -/* - Merge buffers to one buffer - SYNOPSIS - merge_buffers() - param Sort parameter - from_file File with source data (BUFFPEKs point to this file) - to_file File to write the sorted result data. - sort_buffer Buffer for data to store up to MERGEBUFF2 sort keys. - lastbuff OUT Store here BUFFPEK describing data written to to_file - Fb First element in source BUFFPEKs array - Tb Last element in source BUFFPEKs array - flag +/** + Merge buffers to one buffer. - RETURN - 0 - OK - other - error + @param param Sort parameter + @param from_file File with source data (BUFFPEKs point to this file) + @param to_file File to write the sorted result data. + @param sort_buffer Buffer for data to store up to MERGEBUFF2 sort keys. + @param lastbuff OUT Store here BUFFPEK describing data written to to_file + @param Fb First element in source BUFFPEKs array + @param Tb Last element in source BUFFPEKs array + @param flag + + @retval + 0 OK + @retval + other error */ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file, @@ -1347,23 +1357,21 @@ static uint suffix_length(ulong string_length) -/* - Calculate length of sort key +/** + Calculate length of sort key. - SYNOPSIS - sortlength() - thd Thread handler - sortorder Order of items to sort - uint s_length Number of items to sort - multi_byte_charset (out) - Set to 1 if we are using multi-byte charset - (In which case we have to use strxnfrm()) + @param thd Thread handler + @param sortorder Order of items to sort + @param s_length Number of items to sort + @param[out] multi_byte_charset Set to 1 if we are using multi-byte charset + (In which case we have to use strxnfrm()) - NOTES - sortorder->length is updated for each sort item + @note + sortorder->length is updated for each sort item. + @n sortorder->need_strxnfrm is set 1 if we have to use strxnfrm - RETURN + @return Total length of sort buffer in bytes */ @@ -1450,33 +1458,31 @@ sortlength(THD *thd, SORT_FIELD *sortorder, uint s_length, } -/* +/** Get descriptors of fields appended to sorted fields and - calculate its total length + calculate its total length. - SYNOPSIS - get_addon_fields() - thd Current thread - ptabfields Array of references to the table fields - sortlength Total length of sorted fields - plength out: Total length of appended fields + The function first finds out what fields are used in the result set. + Then it calculates the length of the buffer to store the values of + these fields together with the value of sort values. + If the calculated length is not greater than max_length_for_sort_data + the function allocates memory for an array of descriptors containing + layouts for the values of the non-sorted fields in the buffer and + fills them. - DESCRIPTION - The function first finds out what fields are used in the result set. - Then it calculates the length of the buffer to store the values of - these fields together with the value of sort values. - If the calculated length is not greater than max_length_for_sort_data - the function allocates memory for an array of descriptors containing - layouts for the values of the non-sorted fields in the buffer and - fills them. + @param thd Current thread + @param ptabfield Array of references to the table fields + @param sortlength Total length of sorted fields + @param[out] plength Total length of appended fields - NOTES + @note The null bits for the appended values are supposed to be put together and stored the buffer just ahead of the value of the first field. - RETURN + @return Pointer to the layout descriptors for the appended fields, if any - NULL - if we do not store field values with sort data. + @retval + NULL if we do not store field values with sort data. */ static SORT_ADDON_FIELD * @@ -1552,20 +1558,18 @@ get_addon_fields(THD *thd, Field **ptabfield, uint sortlength, uint *plength) } -/* - Copy (unpack) values appended to sorted fields from a buffer back to +/** + Copy (unpack) values appended to sorted fields from a buffer back to their regular positions specified by the Field::ptr pointers. - SYNOPSIS - unpack_addon_fields() - addon_field Array of descriptors for appended fields - buff Buffer which to unpack the value from + @param addon_field Array of descriptors for appended fields + @param buff Buffer which to unpack the value from - NOTES + @note The function is supposed to be used only as a callback function when getting field values for the sorted result set. - RETURN + @return void. */ diff --git a/sql/gen_lex_hash.cc b/sql/gen_lex_hash.cc index 36b7f30dc64..c9c1813a429 100644 --- a/sql/gen_lex_hash.cc +++ b/sql/gen_lex_hash.cc @@ -13,8 +13,11 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* +/** + @file + @details +@verbatim The idea of presented algorithm see in "The Art of Computer Programming" by Donald E. Knuth Volume 3 "Sorting and searching" @@ -63,12 +66,14 @@ for optimization, link is the 16-bit index in 'symbols' or 'sql_functions' or search-array.. So, we can read full search-structure as 32-bit word +@endverbatim + +@todo + use instead to_upper_lex, special array + (substitute chars) without skip codes.. +@todo + try use reverse order of comparing.. -TODO: -1. use instead to_upper_lex, special array - (substitute chars) without skip codes.. -2. try use reverse order of comparing.. - */ #define NO_YACC_SYMBOLS diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index b2152fbb906..3153925155f 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -14,9 +14,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* - This file defines the NDB Cluster handler: the interface between MySQL and - NDB Cluster +/** + @file + + @brief + This file defines the NDB Cluster handler: the interface between + MySQL and NDB Cluster */ #ifdef USE_PRAGMA_IMPLEMENTATION @@ -140,10 +143,10 @@ static Ndb* g_ndb= NULL; Ndb_cluster_connection* g_ndb_cluster_connection= NULL; uchar g_node_id_map[max_ndb_nodes]; -// Handler synchronization +/// Handler synchronization pthread_mutex_t ndbcluster_mutex; -// Table lock handling +/// Table lock handling HASH ndbcluster_open_tables; static uchar *ndbcluster_get_key(NDB_SHARE *share, size_t *length, @@ -164,14 +167,14 @@ pthread_cond_t COND_ndb_util_ready; pthread_handler_t ndb_util_thread_func(void *arg); ulong ndb_cache_check_time; -/* +/** Dummy buffer to read zero pack_length fields - which are mapped to 1 char + which are mapped to 1 char. */ static uint32 dummy_buf; -/* - Stats that can be retrieved from ndb +/** + Stats that can be retrieved from ndb. */ struct Ndb_statistics { @@ -602,10 +605,10 @@ int ha_ndbcluster::ndb_err(NdbTransaction *trans) } -/* +/** Override the default get_error_message in order to add the - error message of NDB - */ + error message of NDB . +*/ bool ha_ndbcluster::get_error_message(int error, String *buf) @@ -626,7 +629,7 @@ bool ha_ndbcluster::get_error_message(int error, #ifndef DBUG_OFF -/* +/** Check if type is supported by NDB. */ @@ -668,8 +671,8 @@ static bool ndb_supported_type(enum_field_types type) #endif /* !DBUG_OFF */ -/* - Check if MySQL field type forces var part in ndb storage +/** + Check if MySQL field type forces var part in ndb storage. */ static bool field_type_forces_var_part(enum_field_types type) { @@ -688,8 +691,8 @@ static bool field_type_forces_var_part(enum_field_types type) } } -/* - Instruct NDB to set the value of the hidden primary key +/** + Instruct NDB to set the value of the hidden primary key. */ bool ha_ndbcluster::set_hidden_key(NdbOperation *ndb_op, @@ -700,8 +703,8 @@ bool ha_ndbcluster::set_hidden_key(NdbOperation *ndb_op, } -/* - Instruct NDB to set the value of one primary key attribute +/** + Instruct NDB to set the value of one primary key attribute. */ int ha_ndbcluster::set_ndb_key(NdbOperation *ndb_op, Field *field, @@ -721,8 +724,8 @@ int ha_ndbcluster::set_ndb_key(NdbOperation *ndb_op, Field *field, } -/* - Instruct NDB to set the value of one attribute +/** + Instruct NDB to set the value of one attribute. */ int ha_ndbcluster::set_ndb_value(NdbOperation *ndb_op, Field *field, @@ -817,20 +820,22 @@ int ha_ndbcluster::set_ndb_value(NdbOperation *ndb_op, Field *field, } -/* - Callback to read all blob values. - - not done in unpack_record because unpack_record is valid - after execute(Commit) but reading blobs is not - - may only generate read operations; they have to be executed - somewhere before the data is available - - due to single buffer for all blobs, we let the last blob - process all blobs (last so that all are active) - - null bit is still set in unpack_record - - TODO allocate blob part aligned buffers -*/ - NdbBlob::ActiveHook g_get_ndb_blobs_value; +/** + Callback to read all blob values. + - not done in unpack_record because unpack_record is valid + after execute(Commit) but reading blobs is not + - may only generate read operations; they have to be executed + somewhere before the data is available + - due to single buffer for all blobs, we let the last blob + process all blobs (last so that all are active) + - null bit is still set in unpack_record. + + @todo + allocate blob part aligned buffers +*/ + int g_get_ndb_blobs_value(NdbBlob *ndb_blob, void *arg) { DBUG_ENTER("g_get_ndb_blobs_value"); @@ -925,10 +930,11 @@ int get_ndb_blobs_value(TABLE* table, NdbValue* value_array, } -/* - Instruct NDB to fetch one field - - data is read directly into buffer provided by field - if field is NULL, data is read into memory provided by NDBAPI +/** + Instruct NDB to fetch one field. + + Data is read directly into buffer provided by field + if field is NULL, data is read into memory provided by NDBAPI. */ int ha_ndbcluster::get_ndb_value(NdbOperation *ndb_op, Field *field, @@ -990,7 +996,7 @@ int ha_ndbcluster::get_ndb_partition_id(NdbOperation *ndb_op) (char *)&m_part_id) == NULL); } -/* +/** Check if any set or get of blob value in current query. */ @@ -1013,15 +1019,15 @@ bool ha_ndbcluster::uses_blob_value() } -/* - Get metadata for this table from NDB +/** + Get metadata for this table from NDB. - IMPLEMENTATION - - check that frm-file on disk is equal to frm-file - of table accessed in NDB + Check that frm-file on disk is equal to frm-file + of table accessed in NDB. - RETURN + @retval 0 ok + @retval -2 Meta data has changed; Re-read data and try again */ @@ -1419,9 +1425,9 @@ int ha_ndbcluster::drop_indexes(Ndb *ndb, TABLE *tab) DBUG_RETURN(error); } -/* +/** Decode the type of an index from information - provided in table object + provided in table object. */ NDB_INDEX_TYPE ha_ndbcluster::get_index_type_from_table(uint inx) const { @@ -1563,10 +1569,10 @@ inline bool ha_ndbcluster::has_null_in_unique_index(uint idx_no) const } -/* - Get the flags for an index +/** + Get the flags for an index. - RETURN + @return flags depending on the type of the index. */ @@ -1719,8 +1725,8 @@ int ha_ndbcluster::define_read_attrs(uchar* buf, NdbOperation* op) } -/* - Read one record from NDB using primary key +/** + Read one record from NDB using primary key. */ int ha_ndbcluster::pk_read(const uchar *key, uint key_len, uchar *buf, @@ -1787,9 +1793,9 @@ int ha_ndbcluster::pk_read(const uchar *key, uint key_len, uchar *buf, DBUG_RETURN(0); } -/* +/** Read one complementing record from NDB using primary key from old_data - or hidden key + or hidden key. */ int ha_ndbcluster::complemented_read(const uchar *old_data, uchar *new_data, @@ -1850,7 +1856,7 @@ int ha_ndbcluster::complemented_read(const uchar *old_data, uchar *new_data, unpack_record(new_data); table->status= 0; - /** + /* * restore m_value */ for (i= 0; i < no_fields; i++) @@ -1866,12 +1872,12 @@ int ha_ndbcluster::complemented_read(const uchar *old_data, uchar *new_data, DBUG_RETURN(0); } -/* - * Check that all operations between first and last all - * have gotten the errcode - * If checking for HA_ERR_KEY_NOT_FOUND then update m_dupkey - * for all succeeding operations - */ +/** + Check that all operations between first and last all + have gotten the errcode + If checking for HA_ERR_KEY_NOT_FOUND then update m_dupkey + for all succeeding operations +*/ bool ha_ndbcluster::check_all_operations_for_error(NdbTransaction *trans, const NdbOperation *first, const NdbOperation *last, @@ -1951,9 +1957,9 @@ check_null_in_record(const KEY* key_info, const uchar *record) */ } -/* - * Peek to check if any rows already exist with conflicting - * primary key or unique index values +/** + Peek to check if any rows already exist with conflicting + primary key or unique index values */ int ha_ndbcluster::peek_indexed_rows(const uchar *record, @@ -2056,8 +2062,8 @@ int ha_ndbcluster::peek_indexed_rows(const uchar *record, } -/* - Read one record from NDB using unique secondary index +/** + Read one record from NDB using unique secondary index. */ int ha_ndbcluster::unique_index_read(const uchar *key, @@ -2199,15 +2205,14 @@ inline int ha_ndbcluster::fetch_next(NdbScanOperation* cursor) DBUG_RETURN(1); } -/* +/** Get the next record of a started scan. Try to fetch it locally from NdbApi cached records if possible, otherwise ask NDB for more. - NOTE - If this is a update/delete make sure to not contact - NDB before any pending ops have been sent to NDB. - + @note + If this is a update/delete make sure to not contact + NDB before any pending ops have been sent to NDB. */ inline int ha_ndbcluster::next_result(uchar *buf) @@ -2240,7 +2245,7 @@ inline int ha_ndbcluster::next_result(uchar *buf) } } -/* +/** Set bounds for ordered index scan. */ @@ -2421,8 +2426,8 @@ int ha_ndbcluster::set_bounds(NdbIndexScanOperation *op, DBUG_RETURN(op->end_of_bound(range_no)); } -/* - Start ordered index scan in NDB +/** + Start ordered index scan in NDB. */ int ha_ndbcluster::ordered_index_scan(const key_range *start_key, @@ -2606,10 +2611,9 @@ int ha_ndbcluster::unique_index_scan(const KEY* key_info, } -/* - Start full table scan in NDB - */ - +/** + Start full table scan in NDB. +*/ int ha_ndbcluster::full_table_scan(uchar *buf) { int res; @@ -2674,8 +2678,8 @@ int ha_ndbcluster::full_table_scan(uchar *buf) DBUG_RETURN(next_result(buf)); } -/* - Insert one record into NDB +/** + Insert one record into NDB. */ int ha_ndbcluster::write_row(uchar *record) { @@ -2900,7 +2904,9 @@ int ha_ndbcluster::write_row(uchar *record) } -/* Compare if a key in a row has changed */ +/** + Compare if a key in a row has changed. +*/ int ha_ndbcluster::key_cmp(uint keynr, const uchar * old_row, const uchar * new_row) @@ -2934,8 +2940,8 @@ int ha_ndbcluster::key_cmp(uint keynr, const uchar * old_row, return 0; } -/* - Update one record in NDB using primary key +/** + Update one record in NDB using primary key. */ int ha_ndbcluster::update_row(const uchar *old_data, uchar *new_data) @@ -3142,8 +3148,8 @@ int ha_ndbcluster::update_row(const uchar *old_data, uchar *new_data) } -/* - Delete one record from NDB, using primary key +/** + Delete one record from NDB, using primary key . */ int ha_ndbcluster::delete_row(const uchar *record) @@ -3257,14 +3263,12 @@ int ha_ndbcluster::delete_row(const uchar *record) DBUG_RETURN(0); } -/* - Unpack a record read from NDB +/** + Unpack a record read from NDB. - SYNOPSIS - unpack_record() - buf Buffer to store read row + @param buf Buffer to store read row - NOTE + @note The data for each row is read directly into the destination buffer. This function is primarily called in order to check if any fields should be @@ -3425,12 +3429,12 @@ void ha_ndbcluster::unpack_record(uchar *buf) #endif } -/* - Utility function to print/dump the fetched field - to avoid unnecessary work, wrap in DBUG_EXECUTE as in: +/** + Utility function to print/dump the fetched field. + To avoid unnecessary work, wrap in DBUG_EXECUTE as in: DBUG_EXECUTE("value", print_results();); - */ +*/ void ha_ndbcluster::print_results() { @@ -3512,8 +3516,8 @@ int ha_ndbcluster::index_end() } /** - * Check if key contains null - */ + Check if key contains null. +*/ static int check_null_in_key(const KEY* key_info, const uchar *key, uint key_len) @@ -3786,11 +3790,10 @@ int ha_ndbcluster::rnd_next(uchar *buf) } -/* +/** An "interesting" record has been found and it's pk - retrieved by calling position - Now it's time to read the record from db once - again + retrieved by calling position. Now it's time to read + the record from db once again. */ int ha_ndbcluster::rnd_pos(uchar *buf, uchar *pos) @@ -3833,10 +3836,10 @@ int ha_ndbcluster::rnd_pos(uchar *buf, uchar *pos) } -/* +/** Store the primary key of this record in ref variable, so that the row can be retrieved again later - using "reference" in rnd_pos + using "reference" in rnd_pos. */ void ha_ndbcluster::position(const uchar *record) @@ -4110,14 +4113,13 @@ int ha_ndbcluster::reset() } -/* - Start of an insert, remember number of rows to be inserted, it will - be used in write_row and get_autoincrement to send an optimal number - of rows in each roundtrip to the server +/** + Start of an insert, remember number of rows to be inserted, it will + be used in write_row and get_autoincrement to send an optimal number + of rows in each roundtrip to the server. - SYNOPSIS + @param rows number of rows to insert, 0 if unknown - */ void ha_ndbcluster::start_bulk_insert(ha_rows rows) @@ -4167,9 +4169,9 @@ void ha_ndbcluster::start_bulk_insert(ha_rows rows) DBUG_VOID_RETURN; } -/* - End of an insert - */ +/** + End of an insert. +*/ int ha_ndbcluster::end_bulk_insert() { int error= 0; @@ -4230,8 +4232,9 @@ const char** ha_ndbcluster::bas_ext() const return ha_ndbcluster_exts; } -/* - How many seeks it will take to read through the table +/** + How many seeks it will take to read through the table. + This is to be comparable to the number returned by records_in_range so that we can decide if we should scan the table or use keys. */ @@ -4582,7 +4585,7 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type) DBUG_RETURN(error); } -/* +/** Unlock the last row read in an open scan. Rows are unlocked by default in ndb, but for SELECT FOR UPDATE and SELECT LOCK WIT SHARE MODE @@ -4598,12 +4601,12 @@ void ha_ndbcluster::unlock_row() DBUG_VOID_RETURN; } -/* +/** Start a transaction for running a statement if one is not already running in a transaction. This will be the case in a BEGIN; COMMIT; block When using LOCK TABLE's external_lock will start a transaction - since ndb does not currently does not support table locking + since ndb does not currently does not support table locking. */ int ha_ndbcluster::start_stmt(THD *thd, thr_lock_type lock_type) @@ -4633,9 +4636,9 @@ int ha_ndbcluster::start_stmt(THD *thd, thr_lock_type lock_type) } -/* - Commit a transaction started in NDB - */ +/** + Commit a transaction started in NDB. +*/ static int ndbcluster_commit(handlerton *hton, THD *thd, bool all) { @@ -4695,9 +4698,9 @@ static int ndbcluster_commit(handlerton *hton, THD *thd, bool all) } -/* - Rollback a transaction started in NDB - */ +/** + Rollback a transaction started in NDB. +*/ static int ndbcluster_rollback(handlerton *hton, THD *thd, bool all) { @@ -4735,14 +4738,17 @@ static int ndbcluster_rollback(handlerton *hton, THD *thd, bool all) } -/* +/** Define NDB column based on Field. - Returns 0 or mysql error code. + Not member of ha_ndbcluster because NDBCOL cannot be declared. MySQL text types with character set "binary" are mapped to true NDB binary types without a character set. This may change. - */ + + @return + Returns 0 or mysql error code. +*/ static int create_ndb_column(NDBCOL &col, Field *field, @@ -5029,7 +5035,7 @@ static int create_ndb_column(NDBCOL &col, return 0; } -/* +/** Create a table in NDB Cluster */ @@ -5577,9 +5583,12 @@ int ha_ndbcluster::create_unique_index(const char *name, } -/* - Create an index in NDB Cluster - */ +/** + Create an index in NDB Cluster. + + @todo + Only temporary ordered indexes supported +*/ int ha_ndbcluster::create_ndb_index(const char *name, KEY *key_info, @@ -5722,8 +5731,8 @@ int ha_ndbcluster::final_drop_index(TABLE *table_arg) DBUG_RETURN(error); } -/* - Rename a table in NDB Cluster +/** + Rename a table in NDB Cluster. */ int ha_ndbcluster::rename_table(const char *from, const char *to) @@ -5903,10 +5912,9 @@ int ha_ndbcluster::rename_table(const char *from, const char *to) } -/* - Delete table from NDB Cluster - - */ +/** + Delete table from NDB Cluster. +*/ /* static version which does not need a handler */ @@ -6175,9 +6183,9 @@ void ha_ndbcluster::get_auto_increment(ulonglong offset, ulonglong increment, } -/* - Constructor for the NDB Cluster table handler - */ +/** + Constructor for the NDB Cluster table handler . +*/ /* Normal flags for binlogging is that ndb has HA_HAS_OWN_BINLOGGING @@ -6263,9 +6271,9 @@ int ha_ndbcluster::ha_initialise() DBUG_RETURN(TRUE); } -/* - Destructor for NDB Cluster table handler - */ +/** + Destructor for NDB Cluster table handler. +*/ ha_ndbcluster::~ha_ndbcluster() { @@ -6305,13 +6313,15 @@ ha_ndbcluster::~ha_ndbcluster() -/* - Open a table for further use +/** + Open a table for further use. + - fetch metadata for this table from NDB - check that table exists - RETURN + @retval 0 ok + @retval < 0 Table has changed */ @@ -6419,10 +6429,9 @@ void ha_ndbcluster::set_part_info(partition_info *part_info) m_use_partition_function= TRUE; } -/* - Close the table - - release resources setup by open() - */ +/** + Close the table; release resources setup by open(). +*/ int ha_ndbcluster::close(void) { @@ -6439,6 +6448,12 @@ int ha_ndbcluster::close(void) } +/** + @todo + - Alt.1 If init fails because to many allocated Ndb + wait on condition for a Ndb object to be released. + - Alt.2 Seize/release from pool, wait until next release +*/ Thd_ndb* ha_ndbcluster::seize_thd_ndb() { Thd_ndb *thd_ndb; @@ -6474,7 +6489,7 @@ void ha_ndbcluster::release_thd_ndb(Thd_ndb* thd_ndb) } -/* +/** If this thread already has a Thd_ndb object allocated in current THD, reuse it. Otherwise seize a Thd_ndb object, assign it to current THD and use it. @@ -6523,9 +6538,9 @@ static int ndbcluster_close_connection(handlerton *hton, THD *thd) } -/* - Try to discover one table from NDB - */ +/** + Try to discover one table from NDB. +*/ int ndbcluster_discover(handlerton *hton, THD* thd, const char *db, const char *name, @@ -6632,10 +6647,9 @@ err: DBUG_RETURN(error); } -/* - Check if a table exists in NDB - - */ +/** + Check if a table exists in NDB. +*/ int ndbcluster_table_exists_in_engine(handlerton *hton, THD* thd, const char *db, @@ -6674,11 +6688,12 @@ extern "C" uchar* tables_get_key(const char *entry, size_t *length, } -/* +/** Drop a database in NDB Cluster - NOTE add a dummy void function, since stupid handlerton is returning void instead of int... -*/ + @note + add a dummy void function, since stupid handlerton is returning void instead of int... +*/ int ndbcluster_drop_database_impl(const char *path) { DBUG_ENTER("ndbcluster_drop_database"); @@ -7434,10 +7449,9 @@ void ha_ndbcluster::print_error(int error, myf errflag) } -/* - Static error print function called from - static handler method ndbcluster_commit - and ndbcluster_rollback +/** + Static error print function called from static handler method + ndbcluster_commit and ndbcluster_rollback. */ void ndbcluster_print_error(int error, const NdbOperation *error_op) @@ -7455,9 +7469,9 @@ void ndbcluster_print_error(int error, const NdbOperation *error_op) } /** - * Set a given location from full pathname to database name - * - */ + Set a given location from full pathname to database name. +*/ + void ha_ndbcluster::set_dbname(const char *path_name, char *dbname) { char *end, *ptr, *tmp_name; @@ -7490,9 +7504,9 @@ void ha_ndbcluster::set_dbname(const char *path_name, char *dbname) filename_to_tablename(tmp_name, dbname, FN_REFLEN); } -/* - Set m_dbname from full pathname to table file - */ +/** + Set m_dbname from full pathname to table file. +*/ void ha_ndbcluster::set_dbname(const char *path_name) { @@ -7500,9 +7514,9 @@ void ha_ndbcluster::set_dbname(const char *path_name) } /** - * Set a given location from full pathname to table file - * - */ + Set a given location from full pathname to table file. +*/ + void ha_ndbcluster::set_tabname(const char *path_name, char * tabname) { @@ -7531,9 +7545,9 @@ ha_ndbcluster::set_tabname(const char *path_name, char * tabname) filename_to_tablename(tmp_name, tabname, FN_REFLEN); } -/* - Set m_tabname from full pathname to table file - */ +/** + Set m_tabname from full pathname to table file. +*/ void ha_ndbcluster::set_tabname(const char *path_name) { @@ -7804,31 +7818,30 @@ uint ndb_get_commitcount(THD *thd, char *dbname, char *tabname, } -/* +/** Check if a cached query can be used. + This is done by comparing the supplied engine_data to commit_count of the table. + The commit_count is either retrieved from the share for the table, where it has been cached by the util thread. If the util thread is not started, NDB has to be contacetd to retrieve the commit_count, this will introduce a small delay while waiting for NDB to answer. - SYNOPSIS - ndbcluster_cache_retrieval_allowed - thd thread handle - full_name concatenation of database name, - the null character '\0', and the table - name - full_name_len length of the full name, - i.e. len(dbname) + len(tablename) + 1 + @param thd thread handle + @param full_name concatenation of database name, + the null character '\\0', and the table name + @param full_name_len length of the full name, + i.e. len(dbname) + len(tablename) + 1 + @param engine_data parameter retrieved when query was first inserted into + the cache. If the value of engine_data is changed, + all queries for this table should be invalidated. - engine_data parameter retrieved when query was first inserted into - the cache. If the value of engine_data is changed, - all queries for this table should be invalidated. - - RETURN VALUE + @retval TRUE Yes, use the query from cache + @retval FALSE No, don't use the cached query, and if engine_data has changed, all queries for this table should be invalidated @@ -7884,25 +7897,25 @@ ndbcluster_cache_retrieval_allowed(THD *thd, /** - Register a table for use in the query cache. Fetch the commit_count - for the table and return it in engine_data, this will later be used - to check if the table has changed, before the cached query is reused. + Register a table for use in the query cache. - SYNOPSIS - ha_ndbcluster::can_query_cache_table - thd thread handle - full_name concatenation of database name, - the null character '\0', and the table - name - full_name_len length of the full name, - i.e. len(dbname) + len(tablename) + 1 - qc_engine_callback function to be called before using cache on this table - engine_data out, commit_count for this table + Fetch the commit_count for the table and return it in engine_data, + this will later be used to check if the table has changed, before + the cached query is reused. - RETURN VALUE + @param thd thread handle + @param full_name concatenation of database name, + the null character '\\0', and the table name + @param full_name_len length of the full name, + i.e. len(dbname) + len(tablename) + 1 + @param engine_callback function to be called before using cache on + this table + @param[out] engine_data commit_count for this table + + @retval TRUE Yes, it's ok to cahce this query + @retval FALSE No, don't cach the query - */ my_bool @@ -7939,13 +7952,14 @@ ha_ndbcluster::register_query_cache_table(THD *thd, } -/* +/** Handling the shared NDB_SHARE structure that is needed to provide table locking. + It's also used for sharing data with other NDB handlers in the same MySQL Server. There is currently not much data we want to or can share. - */ +*/ static uchar *ndbcluster_get_key(NDB_SHARE *share, size_t *length, my_bool not_used __attribute__((unused))) @@ -8498,9 +8512,9 @@ retry: DBUG_RETURN(reterr); } -/* +/** Create a .ndb file to serve as a placeholder indicating - that the table with this name is a ndb table + that the table with this name is a ndb table. */ int ha_ndbcluster::write_ndb_file(const char *name) @@ -8607,7 +8621,7 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p, thd_ndb->query_state|= NDB_QUERY_MULTI_READ_RANGE; m_disable_multi_read= FALSE; - /** + /* * Copy arguments into member variables */ m_multi_ranges= ranges; @@ -8616,7 +8630,7 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p, multi_range_sorted= sorted; multi_range_buffer= buffer; - /** + /* * read multi range will read ranges as follows (if not ordered) * * input read order @@ -8629,7 +8643,7 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p, * pk-op 6 pk-ok 6 */ - /** + /* * Variables for loop */ uchar *curr= (uchar*)buffer->buffer; @@ -8756,7 +8770,7 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p, if (multi_range_curr != multi_range_end) { - /** + /* * Mark that we're using entire buffer (even if might not) as * we haven't read all ranges for some reason * This as we don't want mysqld to reuse the buffer when we read @@ -8769,7 +8783,7 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p, buffer->end_of_used_area= curr; } - /** + /* * Set first operation in multi range */ m_current_multi_operation= @@ -8873,10 +8887,10 @@ ha_ndbcluster::read_multi_range_next(KEY_MULTI_RANGE ** multi_range_found_p) continue; } } - else /** m_multi_cursor == 0 */ + else /* m_multi_cursor == 0 */ { DBUG_MULTI_RANGE(7); - /** + /* * Corresponds to range 5 in example in read_multi_range_first */ (void)1; @@ -8907,7 +8921,7 @@ close_scan: DBUG_RETURN(HA_ERR_END_OF_FILE); } - /** + /* * Read remaining ranges */ DBUG_RETURN(read_multi_range_first(multi_range_found_p, @@ -8917,7 +8931,7 @@ close_scan: multi_range_buffer)); found: - /** + /* * Found a record belonging to a scan */ m_active_cursor= m_multi_cursor; @@ -8929,7 +8943,7 @@ found: DBUG_RETURN(0); found_next: - /** + /* * Found a record belonging to a pk/index op, * copy result and move to next to prepare for next call */ @@ -8970,6 +8984,12 @@ ha_ndbcluster::setup_recattr(const NdbRecAttr* curr) DBUG_RETURN(0); } +/** + @param[in] comment table comment defined by user + + @return + table comment + additional +*/ char* ha_ndbcluster::update_table_comment( /* out: table comment + additional */ @@ -9011,7 +9031,9 @@ ha_ndbcluster::update_table_comment( } -// Utility thread main loop +/** + Utility thread main loop. +*/ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused))) { THD *thd; /* needs to be first for thread_stack */ @@ -9298,7 +9320,7 @@ ndb_util_thread_fail: /* Condition pushdown */ -/* +/** Push a condition to ndbcluster storage engine for evaluation during table and index scans. The conditions will be stored on a stack for possibly storing several conditions. The stack can be popped @@ -9309,9 +9331,10 @@ ndb_util_thread_fail: expressions and function calls) and the following comparison operators: =, !=, >, >=, <, <=, "is null", and "is not null". - RETURN + @retval NULL The condition was supported and will be evaluated for each - row found during the scan + row found during the scan + @retval cond The condition was not supported and all rows will be returned from the scan for evaluation (and thus not saved on stack) */ @@ -9331,7 +9354,7 @@ ha_ndbcluster::cond_push(const COND *cond) DBUG_RETURN(m_cond->cond_push(cond, table, (NDBTAB *)m_table)); } -/* +/** Pop the top condition from the condition stack of the handler instance. */ void diff --git a/sql/handler.cc b/sql/handler.cc index 75c3a64bc27..e012aae8200 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -199,8 +199,8 @@ handlerton *ha_resolve_by_legacy_type(THD *thd, enum legacy_db_type db_type) } -/** @brief - Use other database handler if databasehandler is not compiled in +/** + Use other database handler if databasehandler is not compiled in. */ handlerton *ha_checktype(THD *thd, enum legacy_db_type database_type, bool no_substitute, bool report_error) @@ -280,15 +280,13 @@ handler *get_ha_partition(partition_info *part_info) #endif -/** @brief +/** Register handler error messages for use with my_error(). - SYNOPSIS - ha_init_errors() - - RETURN + @retval 0 OK - != 0 Error + @retval + !=0 Error */ static int ha_init_errors(void) { @@ -349,15 +347,13 @@ static int ha_init_errors(void) } -/** @brief +/** Unregister handler error messages. - SYNOPSIS - ha_finish_errors() - - RETURN + @retval 0 OK - != 0 Error + @retval + !=0 Error */ static int ha_finish_errors(void) { @@ -567,8 +563,9 @@ static my_bool closecon_handlerton(THD *thd, plugin_ref plugin, } -/** @brief - don't bother to rollback here, it's done already +/** + @note + don't bother to rollback here, it's done already */ void ha_close_connection(THD* thd) { @@ -578,17 +575,16 @@ void ha_close_connection(THD* thd) /* ======================================================================== ======================= TRANSACTIONS ===================================*/ -/** @brief - Register a storage engine for a transaction +/** + Register a storage engine for a transaction. - DESCRIPTION - Every storage engine MUST call this function when it starts - a transaction or a statement (that is it must be called both for the - "beginning of transaction" and "beginning of statement"). - Only storage engines registered for the transaction/statement - will know when to commit/rollback it. + Every storage engine MUST call this function when it starts + a transaction or a statement (that is it must be called both for the + "beginning of transaction" and "beginning of statement"). + Only storage engines registered for the transaction/statement + will know when to commit/rollback it. - NOTE + @note trans_register_ha is idempotent - storage engine may register many times per transaction. @@ -620,10 +616,11 @@ void trans_register_ha(THD *thd, bool all, handlerton *ht_arg) DBUG_VOID_RETURN; } -/** @brief - RETURN - 0 - ok - 1 - error, transaction was rolled back +/** + @retval + 0 ok + @retval + 1 error, transaction was rolled back */ int ha_prepare(THD *thd) { @@ -660,11 +657,19 @@ int ha_prepare(THD *thd) DBUG_RETURN(error); } -/** @brief - RETURN - 0 - ok - 1 - transaction was rolled back - 2 - error during commit, data may be inconsistent +/** + @retval + 0 ok + @retval + 1 transaction was rolled back + @retval + 2 error during commit, data may be inconsistent + + @todo + Since we don't support nested statement transactions in 5.0, + we can't commit or rollback stmt transactions while we are inside + stored functions or triggers. So we simply do nothing now. + TODO: This should be fixed in later ( >= 5.1) releases. */ int ha_commit_trans(THD *thd, bool all) { @@ -757,9 +762,9 @@ end: DBUG_RETURN(error); } -/** @brief - NOTE - this function does not care about global read lock. - A caller should. +/** + @note + This function does not care about global read lock. A caller should. */ int ha_commit_one_phase(THD *thd, bool all) { @@ -869,13 +874,16 @@ int ha_rollback_trans(THD *thd, bool all) DBUG_RETURN(error); } -/** @brief - This is used to commit or rollback a single statement depending on the value - of error. Note that if the autocommit is on, then the following call inside - InnoDB will commit or rollback the whole transaction (= the statement). The - autocommit mechanism built into InnoDB is based on counting locks, but if - the user has used LOCK TABLES then that mechanism does not know to do the - commit. +/** + This is used to commit or rollback a single statement depending on + the value of error. + + @note + Note that if the autocommit is on, then the following call inside + InnoDB will commit or rollback the whole transaction (= the statement). The + autocommit mechanism built into InnoDB is based on counting locks, but if + the user has used LOCK TABLES then that mechanism does not know to do the + commit. */ int ha_autocommit_or_rollback(THD *thd, int error) { @@ -944,7 +952,10 @@ int ha_commit_or_rollback_by_xid(XID *xid, bool commit) #ifndef DBUG_OFF -/* this does not need to be multi-byte safe or anything */ +/** + @note + This does not need to be multi-byte safe or anything +*/ static char* xid_to_str(char *buf, XID *xid) { int i; @@ -996,24 +1007,21 @@ static char* xid_to_str(char *buf, XID *xid) } #endif -/** @brief - recover() step of xa +/** + recover() step of xa. - NOTE - there are three modes of operation: - - - automatic recover after a crash - in this case commit_list != 0, tc_heuristic_recover==0 - all xids from commit_list are committed, others are rolled back - - - manual (heuristic) recover - in this case commit_list==0, tc_heuristic_recover != 0 - DBA has explicitly specified that all prepared transactions should - be committed (or rolled back). - - - no recovery (MySQL did not detect a crash) - in this case commit_list==0, tc_heuristic_recover == 0 - there should be no prepared transactions in this case. + @note + there are three modes of operation: + - automatic recover after a crash + in this case commit_list != 0, tc_heuristic_recover==0 + all xids from commit_list are committed, others are rolled back + - manual (heuristic) recover + in this case commit_list==0, tc_heuristic_recover != 0 + DBA has explicitly specified that all prepared transactions should + be committed (or rolled back). + - no recovery (MySQL did not detect a crash) + in this case commit_list==0, tc_heuristic_recover == 0 + there should be no prepared transactions in this case. */ struct xarecover_st { @@ -1146,10 +1154,10 @@ int ha_recover(HASH *commit_list) DBUG_RETURN(0); } -/** @brief - return the list of XID's to a client, the same way SHOW commands do +/** + return the list of XID's to a client, the same way SHOW commands do. - NOTE + @note I didn't find in XA specs that an RM cannot return the same XID twice, so mysql_xa_recover does not filter XID's to ensure uniqueness. It can be easily fixed later, if necessary. @@ -1195,7 +1203,8 @@ bool mysql_xa_recover(THD *thd) DBUG_RETURN(0); } -/** @brief +/** + @details This function should be called when MySQL sends rows of a SELECT result set or the EOF mark to the client. It releases a possible adaptive hash index S-latch held by thd in InnoDB and also releases a possible InnoDB query @@ -1207,9 +1216,10 @@ bool mysql_xa_recover(THD *thd) performs another SQL query. In MySQL-4.1 this is even more important because there a connection can have several SELECT queries open at the same time. - arguments: - thd: the thread handle of the current connection - return value: always 0 + @param thd the thread handle of the current connection + + @return + always 0 */ static my_bool release_temporary_latches(THD *thd, plugin_ref plugin, void *unused) @@ -1276,8 +1286,9 @@ int ha_rollback_to_savepoint(THD *thd, SAVEPOINT *sv) DBUG_RETURN(error); } -/** @brief - note, that according to the sql standard (ISO/IEC 9075-2:2003) +/** + @note + according to the sql standard (ISO/IEC 9075-2:2003) section "4.33.4 SQL-statements and transaction states", SAVEPOINT is *not* transaction-initiating SQL-statement */ @@ -1573,8 +1584,9 @@ int handler::ha_open(TABLE *table_arg, const char *name, int mode, } -/** @brief - Read first row (only) from a table +/** + Read first row (only) from a table. + This is never called for InnoDB tables, as these table types has the HA_STATS_RECORDS_IS_EXACT set. */ @@ -1607,16 +1619,16 @@ int handler::read_first_row(uchar * buf, uint primary_key) DBUG_RETURN(error); } -/** @brief - Generate the next auto-increment number based on increment and offset: +/** + Generate the next auto-increment number based on increment and offset. computes the lowest number - strictly greater than "nr" - of the form: auto_increment_offset + N * auto_increment_increment In most cases increment= offset= 1, in which case we get: - 1,2,3,4,5,... - If increment=10 and offset=5 and previous number is 1, we get: - 1,5,15,25,35,... + @verbatim 1,2,3,4,5,... @endverbatim + If increment=10 and offset=5 and previous number is 1, we get: + @verbatim 1,5,15,25,35,... @endverbatim */ inline ulonglong compute_next_insert_id(ulonglong nr,struct system_variables *variables) @@ -1682,23 +1694,10 @@ prev_insert_id(ulonglong nr, struct system_variables *variables) } -/* - Update the auto_increment field if necessary +/** + Update the auto_increment field if necessary. - SYNOPSIS - update_auto_increment() - - RETURN - 0 ok - HA_ERR_AUTOINC_READ_FAILED - get_auto_increment() was called and returned ~(ulonglong) 0 - HA_ERR_AUTOINC_ERANGE - storing value in field caused strict mode failure. - - - IMPLEMENTATION - - Updates the record's Field of type NEXT_NUMBER if: + Updates columns with type NEXT_NUMBER if: - If column value is set to NULL (in which case auto_increment_field_not_null is 0) @@ -1749,13 +1748,20 @@ prev_insert_id(ulonglong nr, struct system_variables *variables) present in thd->auto_inc_intervals_in_cur_stmt_for_binlog it is added to this list. - TODO - + @todo Replace all references to "next number" or NEXT_NUMBER to "auto_increment", everywhere (see below: there is table->auto_increment_field_not_null, and there also exists table->next_number_field, it's not consistent). + @retval + 0 ok + @retval + HA_ERR_AUTOINC_READ_FAILED get_auto_increment() was called and + returned ~(ulonglong) 0 + @retval + HA_ERR_AUTOINC_ERANGE storing value in field caused strict mode + failure. */ #define AUTO_INC_DEFAULT_NB_ROWS 1 // Some prefer 1024 here @@ -2059,14 +2065,14 @@ void handler::print_keydup_error(uint key_nr, const char *msg) } -/** @brief - Print error that we got from handler function +/** + Print error that we got from handler function. - NOTE - In case of delete table it's only safe to use the following parts of - the 'table' structure: - table->s->path - table->alias + @note + In case of delete table it's only safe to use the following parts of + the 'table' structure: + - table->s->path + - table->alias */ void handler::print_error(int error, myf errflag) { @@ -2253,14 +2259,14 @@ void handler::print_error(int error, myf errflag) } -/** @brief - Return an error message specific to this handler +/** + Return an error message specific to this handler. - SYNOPSIS - error error code previously returned by handler - buf Pointer to String where to add error message + @param error error code previously returned by handler + @param buf pointer to String where to add error message - Returns true if this is a temporary error + @return + Returns true if this is a temporary error */ bool handler::get_error_message(int error, String* buf) { @@ -2367,8 +2373,10 @@ err: -/** @brief - Return key if error because of duplicated keys */ +/** + @return + key if error because of duplicated keys +*/ uint handler::get_dup_key(int error) { DBUG_ENTER("handler::get_dup_key"); @@ -2381,21 +2389,20 @@ uint handler::get_dup_key(int error) } -/** @brief - Delete all files with extension from bas_ext() +/** + Delete all files with extension from bas_ext(). - SYNOPSIS - delete_table() - name Base name of table + @param name Base name of table - NOTES + @note We assume that the handler may return more extensions than was actually used for the file. - RETURN + @retval 0 If we successfully deleted at least one file from base_ext and - didn't get any other errors than ENOENT - # Error + didn't get any other errors than ENOENT + @retval + !0 Error */ int handler::delete_table(const char *name) { @@ -2442,21 +2449,20 @@ void handler::drop_table(const char *name) } -/** @brief - Performs checks upon the table. +/** + Performs checks upon the table. - SYNOPSIS - check() - thd thread doing CHECK TABLE operation - check_opt options from the parser + @param thd thread doing CHECK TABLE operation + @param check_opt options from the parser - NOTES - - RETURN - HA_ADMIN_OK Successful upgrade - HA_ADMIN_NEEDS_UPGRADE Table has structures requiring upgrade - HA_ADMIN_NEEDS_ALTER Table has structures requiring ALTER TABLE - HA_ADMIN_NOT_IMPLEMENTED + @retval + HA_ADMIN_OK Successful upgrade + @retval + HA_ADMIN_NEEDS_UPGRADE Table has structures requiring upgrade + @retval + HA_ADMIN_NEEDS_ALTER Table has structures requiring ALTER TABLE + @retval + HA_ADMIN_NOT_IMPLEMENTED */ int handler::ha_check(THD *thd, HA_CHECK_OPT *check_opt) { @@ -2491,7 +2497,7 @@ int handler::ha_repair(THD* thd, HA_CHECK_OPT* check_opt) } -/** @brief +/** Tell the storage engine that it is allowed to "disable transaction" in the handler. It is a hint that ACID is not required - it is used in NDB for ALTER TABLE, for example, when data are copied to temporary table. @@ -2559,15 +2565,12 @@ void handler::get_dynamic_partition_info(PARTITION_INFO *stat_info, ** Some general functions that isn't in the handler class ****************************************************************************/ -/** @brief - Initiates table-file and calls appropriate database-creator +/** + Initiates table-file and calls appropriate database-creator. - NOTES - We must have a write lock on LOCK_open to be sure no other thread - interferes with table - - RETURN + @retval 0 ok + @retval 1 error */ int ha_create_table(THD *thd, const char *path, @@ -2605,17 +2608,18 @@ err: DBUG_RETURN(error != 0); } -/** @brief - Try to discover table from engine +/** + Try to discover table from engine. - NOTES + @note If found, write the frm file to disk. - RETURN VALUES: + @retval -1 Table did not exists + @retval 0 Table created ok + @retval > 0 Error, table existed but could not be created - */ int ha_create_table_from_engine(THD* thd, const char *db, const char *name) { @@ -2687,8 +2691,8 @@ void st_ha_check_opt::init() call to ha_init_key_cache() (probably out of memory) *****************************************************************************/ -/** @brief - Init a key cache if it has not been initied before +/** + Init a key cache if it has not been initied before. */ int ha_init_key_cache(const char *name, KEY_CACHE *key_cache) { @@ -2711,8 +2715,8 @@ int ha_init_key_cache(const char *name, KEY_CACHE *key_cache) } -/** @brief - Resize key cache +/** + Resize key cache. */ int ha_resize_key_cache(KEY_CACHE *key_cache) { @@ -2734,7 +2738,7 @@ int ha_resize_key_cache(KEY_CACHE *key_cache) } -/** @brief +/** Change parameters for key cache (like size) */ int ha_change_key_cache_param(KEY_CACHE *key_cache) @@ -2750,8 +2754,8 @@ int ha_change_key_cache_param(KEY_CACHE *key_cache) return 0; } -/** @brief - Free memory allocated by a key cache +/** + Free memory allocated by a key cache. */ int ha_end_key_cache(KEY_CACHE *key_cache) { @@ -2759,8 +2763,8 @@ int ha_end_key_cache(KEY_CACHE *key_cache) return 0; } -/** @brief - Move all tables from one key cache to another one +/** + Move all tables from one key cache to another one. */ int ha_change_key_cache(KEY_CACHE *old_key_cache, KEY_CACHE *new_key_cache) @@ -2770,13 +2774,15 @@ int ha_change_key_cache(KEY_CACHE *old_key_cache, } -/** @brief - Try to discover one table from handler(s) +/** + Try to discover one table from handler(s). - RETURN - -1 : Table did not exists - 0 : OK. In this case *frmblob and *frmlen are set - >0 : error. frmblob and frmlen may not be set + @retval + -1 Table did not exists + @retval + 0 OK. In this case *frmblob and *frmlen are set + @retval + >0 error. frmblob and frmlen may not be set */ struct st_discover_args { @@ -2821,9 +2827,9 @@ int ha_discover(THD *thd, const char *db, const char *name, } -/** @brief - Call this function in order to give the handler the possibility - to ask engine if there are any new tables that should be written to disk +/** + Call this function in order to give the handler the possiblity + to ask engine if there are any new tables that should be written to disk or any dropped tables that need to be removed from disk */ struct st_find_files_args @@ -2866,16 +2872,15 @@ ha_find_files(THD *thd,const char *db,const char *path, DBUG_RETURN(error); } -/* - Ask handler if the table exists in engine - - RETURN +/** + Ask handler if the table exists in engine. + @retval HA_ERR_NO_SUCH_TABLE Table does not exist + @retval HA_ERR_TABLE_EXIST Table exists - # Error code - - */ - + @retval + \# Error code +*/ struct st_table_exists_in_engine_args { const char *db; @@ -3050,29 +3055,29 @@ void ha_binlog_log_query(THD *thd, handlerton *hton, } #endif -/** @brief +/** Read the first row of a multi-range set. - SYNOPSIS - read_multi_range_first() - found_range_p Returns a pointer to the element in 'ranges' that - corresponds to the returned row. - ranges An array of KEY_MULTI_RANGE range descriptions. - range_count Number of ranges in 'ranges'. - sorted If result should be sorted per key. - buffer A HANDLER_BUFFER for internal handler usage. + @param found_range_p Returns a pointer to the element in 'ranges' that + corresponds to the returned row. + @param ranges An array of KEY_MULTI_RANGE range descriptions. + @param range_count Number of ranges in 'ranges'. + @param sorted If result should be sorted per key. + @param buffer A HANDLER_BUFFER for internal handler usage. - NOTES - Record is read into table->record[0]. - *found_range_p returns a valid value only if read_multi_range_first() + @note + - Record is read into table->record[0]. + - *found_range_p returns a valid value only if read_multi_range_first() returns 0. - Sorting is done within each range. If you want an overall sort, enter + - Sorting is done within each range. If you want an overall sort, enter 'ranges' with sorted ranges. - RETURN + @retval 0 OK, found a row + @retval HA_ERR_END_OF_FILE No rows in range - # Error code + @retval + \# Error code */ int handler::read_multi_range_first(KEY_MULTI_RANGE **found_range_p, KEY_MULTI_RANGE *ranges, uint range_count, @@ -3106,23 +3111,23 @@ int handler::read_multi_range_first(KEY_MULTI_RANGE **found_range_p, } -/** @brief +/** Read the next row of a multi-range set. - SYNOPSIS - read_multi_range_next() - found_range_p Returns a pointer to the element in 'ranges' that - corresponds to the returned row. + @param found_range_p Returns a pointer to the element in 'ranges' that + corresponds to the returned row. - NOTES - Record is read into table->record[0]. - *found_range_p returns a valid value only if read_multi_range_next() + @note + - Record is read into table->record[0]. + - *found_range_p returns a valid value only if read_multi_range_next() returns 0. - RETURN + @retval 0 OK, found a row + @retval HA_ERR_END_OF_FILE No (more) rows in range - # Error code + @retval + \# Error code */ int handler::read_multi_range_next(KEY_MULTI_RANGE **found_range_p) { @@ -3176,25 +3181,24 @@ int handler::read_multi_range_next(KEY_MULTI_RANGE **found_range_p) } -/** @brief +/** Read first row between two ranges. - Store ranges for future calls to read_range_next + Store ranges for future calls to read_range_next. - SYNOPSIS - read_range_first() - start_key Start key. Is 0 if no min range - end_key End key. Is 0 if no max range - eq_range_arg Set to 1 if start_key == end_key and the range endpoints - will not change during query execution. - sorted Set to 1 if result should be sorted per key + @param start_key Start key. Is 0 if no min range + @param end_key End key. Is 0 if no max range + @param eq_range_arg Set to 1 if start_key == end_key + @param sorted Set to 1 if result should be sorted per key - NOTES + @note Record is read into table->record[0] - RETURN + @retval 0 Found row + @retval HA_ERR_END_OF_FILE No rows in range - # Error code + @retval + \# Error code */ int handler::read_range_first(const key_range *start_key, const key_range *end_key, @@ -3230,19 +3234,18 @@ int handler::read_range_first(const key_range *start_key, } -/** @brief +/** Read next row between two ranges. - SYNOPSIS - read_range_next() - - NOTES + @note Record is read into table->record[0] - RETURN + @retval 0 Found row + @retval HA_ERR_END_OF_FILE No rows in range - # Error code + @retval + \# Error code */ int handler::read_range_next() { @@ -3263,22 +3266,20 @@ int handler::read_range_next() } -/** @brief - Compare if found key (in row) is over max-value +/** + Compare if found key (in row) is over max-value. - SYNOPSIS - compare_key - range range to compare to row. May be 0 for no range - - NOTES - See key.cc::key_cmp() for details + @param range range to compare to row. May be 0 for no range - RETURN + @seealso + key.cc::key_cmp() + + @return The return value is SIGN(key_in_row - range_key): - 0 Key is equal to range or 'range' == 0 (no range) - -1 Key is less than range - 1 Key is larger than range + - 0 : Key is equal to range or 'range' == 0 (no range) + - -1 : Key is less than range + - 1 : Key is larger than range */ int handler::compare_key(key_range *range) { @@ -3307,18 +3308,14 @@ int handler::index_read_idx_map(uchar * buf, uint index, const uchar * key, } -/** @brief +/** Returns a list of all known extensions. - SYNOPSIS - ha_known_exts() - - NOTES No mutexes, worst case race is a minor surplus memory allocation We have to recreate the extension map if mysqld is restarted (for example within libmysqld) - RETURN VALUE + @retval pointer pointer to TYPELIB structure */ static my_bool exts_handlerton(THD *unused, plugin_ref plugin, diff --git a/sql/hostname.cc b/sql/hostname.cc index 34384a9c8c0..c8cf46383a9 100644 --- a/sql/hostname.cc +++ b/sql/hostname.cc @@ -14,9 +14,14 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* - Get hostname for an IP. Hostnames are checked with reverse name lookup and - checked that they doesn't resemble an ip. +/** + @file + + @brief + Get hostname for an IP. + + Hostnames are checked with reverse name lookup and + checked that they doesn't resemble an ip. */ #include "mysql_priv.h" diff --git a/sql/init.cc b/sql/init.cc index 73feaa797c3..aee0eb7179c 100644 --- a/sql/init.cc +++ b/sql/init.cc @@ -14,7 +14,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* Init and dummy functions for interface with unireg */ +/** + @file + + @brief + Init and dummy functions for interface with unireg +*/ #include "mysql_priv.h" #include diff --git a/sql/item.cc b/sql/item.cc index dc94615c6e6..6cf4ffd4de2 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -95,6 +95,10 @@ void Hybrid_type_traits_decimal::add(Hybrid_type *val, Field *f) const } +/** + @todo + what is '4' for scale? +*/ void Hybrid_type_traits_decimal::div(Hybrid_type *val, ulonglong u) const { int2my_decimal(E_DEC_FATAL_ERROR, u, TRUE, &val->dec_buf[2]); @@ -156,7 +160,9 @@ Hybrid_type_traits_integer::fix_length_and_dec(Item *item, Item *arg) const ** Item functions *****************************************************************************/ -/* Init all special items */ +/** + Init all special items. +*/ void item_init(void) { @@ -165,8 +171,9 @@ void item_init(void) } -/* -TODO: make this functions class dependent +/** + @todo + Make this functions class dependent */ bool Item::val_bool() @@ -396,10 +403,12 @@ Item::Item(): } } -/* - Constructor used by Item_field, Item_*_ref & aggregate (sum) functions. +/** + Constructor used by Item_field, Item_ref & aggregate (sum) + functions. + Used for duplicating lists in processing queries with temporary - tables + tables. */ Item::Item(THD *thd, Item *item): rsize(0), @@ -456,12 +465,10 @@ void Item::cleanup() } -/* - cleanup() item if it is 'fixed' +/** + cleanup() item if it is 'fixed'. - SYNOPSIS - cleanup_processor() - arg - a dummy parameter, is not used here + @param arg a dummy parameter, is not used here */ bool Item::cleanup_processor(uchar *arg) @@ -472,12 +479,10 @@ bool Item::cleanup_processor(uchar *arg) } -/* - rename item (used for views, cleanup() return original name) +/** + rename item (used for views, cleanup() return original name). - SYNOPSIS - Item::rename() - new_name new name of item; + @param new_name new name of item; */ void Item::rename(char *new_name) @@ -492,36 +497,30 @@ void Item::rename(char *new_name) } -/* +/** Traverse item tree possibly transforming it (replacing items). - SYNOPSIS - Item::transform() - transformer functor that performs transformation of a subtree - arg opaque argument passed to the functor + This function is designed to ease transformation of Item trees. + Re-execution note: every such transformation is registered for + rollback by THD::change_item_tree() and is rolled back at the end + of execution by THD::rollback_item_tree_changes(). - DESCRIPTION - This function is designed to ease transformation of Item trees. + Therefore: + - this function can not be used at prepared statement prepare + (in particular, in fix_fields!), as only permanent + transformation of Item trees are allowed at prepare. + - the transformer function shall allocate new Items in execution + memory root (thd->mem_root) and not anywhere else: allocated + items will be gone in the end of execution. - Re-execution note: every such transformation is registered for - rollback by THD::change_item_tree() and is rolled back at the end - of execution by THD::rollback_item_tree_changes(). - - Therefore: - - - this function can not be used at prepared statement prepare - (in particular, in fix_fields!), as only permanent - transformation of Item trees are allowed at prepare. - - - the transformer function shall allocate new Items in execution - memory root (thd->mem_root) and not anywhere else: allocated - items will be gone in the end of execution. - - If you don't need to transform an item tree, but only traverse - it, please use Item::walk() instead. + If you don't need to transform an item tree, but only traverse + it, please use Item::walk() instead. - RETURN VALUE + @param transformer functor that performs transformation of a subtree + @param arg opaque argument passed to the functor + + @return Returns pointer to the new subtree root. THD::change_item_tree() should be called for it if transformation took place, i.e. if a pointer to newly allocated item is returned. @@ -549,7 +548,9 @@ Item_ident::Item_ident(Name_resolution_context *context_arg, } -/* Constructor used by Item_field & Item_*_ref (see Item comment) */ +/** + Constructor used by Item_field & Item_*_ref (see Item comment) +*/ Item_ident::Item_ident(THD *thd, Item_ident *item) :Item(thd, item), @@ -594,26 +595,22 @@ bool Item_ident::remove_dependence_processor(uchar * arg) } -/* +/** Store the pointer to this item field into a list if not already there. - SYNOPSIS - Item_field::collect_item_field_processor() - arg pointer to a List + The method is used by Item::walk to collect all unique Item_field objects + from a tree of Items into a set of items represented as a list. - DESCRIPTION - The method is used by Item::walk to collect all unique Item_field objects - from a tree of Items into a set of items represented as a list. + Item_cond::walk() and Item_func::walk() stop the evaluation of the + processor function for its arguments once the processor returns + true.Therefore in order to force this method being called for all item + arguments in a condition the method must return false. - IMPLEMENTATION - Item_cond::walk() and Item_func::walk() stop the evaluation of the - processor function for its arguments once the processor returns - true.Therefore in order to force this method being called for all item - arguments in a condition the method must return false. + @param arg pointer to a List - RETURN + @return FALSE to force the evaluation of collect_item_field_processor - for the subsequent items. + for the subsequent items. */ bool Item_field::collect_item_field_processor(uchar *arg) @@ -633,21 +630,19 @@ bool Item_field::collect_item_field_processor(uchar *arg) } -/* +/** Check if an Item_field references some field from a list of fields. - SYNOPSIS - Item_field::find_item_in_field_list_processor - arg Field being compared, arg must be of type Field + Check whether the Item_field represented by 'this' references any + of the fields in the keyparts passed via 'arg'. Used with the + method Item::walk() to test whether any keypart in a sequence of + keyparts is referenced in an expression. - DESCRIPTION - Check whether the Item_field represented by 'this' references any - of the fields in the keyparts passed via 'arg'. Used with the - method Item::walk() to test whether any keypart in a sequence of - keyparts is referenced in an expression. + @param arg Field being compared, arg must be of type Field - RETURN + @retval TRUE if 'this' references the field 'arg' + @retval FALSE otherwise */ @@ -739,7 +734,8 @@ void Item::set_name(const char *str, uint length, CHARSET_INFO *cs) } -/* +/** + @details This function is called when: - Comparing items in the WHERE clause (when doing where optimization) - When trying to find an ORDER BY/GROUP BY item in the SELECT part @@ -764,7 +760,8 @@ Item *Item::safe_charset_converter(CHARSET_INFO *tocs) } -/* +/** + @details Created mostly for mysql_prepare_table(). Important when a string ENUM/SET column is described with a numeric default value: @@ -891,10 +888,10 @@ bool Item_string::eq(const Item *item, bool binary_cmp) const } -/* +/** Get the value of the function as a MYSQL_TIME structure. As a extra convenience the time structure is reset on error! - */ +*/ bool Item::get_date(MYSQL_TIME *ltime,uint fuzzydate) { @@ -928,10 +925,11 @@ err: return 1; } -/* - Get time of first argument. +/** + Get time of first argument.\ + As a extra convenience the time structure is reset on error! - */ +*/ bool Item::get_time(MYSQL_TIME *ltime) { @@ -1297,27 +1295,25 @@ public: }; -/* - Move SUM items out from item tree and replace with reference +/** + Move SUM items out from item tree and replace with reference. - SYNOPSIS - split_sum_func2() - thd Thread handler - ref_pointer_array Pointer to array of reference fields - fields All fields in select - ref Pointer to item - skip_registered <=> function be must skipped for registered SUM items + @param thd Thread handler + @param ref_pointer_array Pointer to array of reference fields + @param fields All fields in select + @param ref Pointer to item + @param skip_registered <=> function be must skipped for registered + SUM items - NOTES - This is from split_sum_func2() for items that should be split + @note + This is from split_sum_func2() for items that should be split - All found SUM items are added FIRST in the fields list and - we replace the item with a reference. + All found SUM items are added FIRST in the fields list and + we replace the item with a reference. - thd->fatal_error() may be called if we are out of memory + thd->fatal_error() may be called if we are out of memory */ - void Item::split_sum_func2(THD *thd, Item **ref_pointer_array, List &fields, Item **ref, bool skip_registered) @@ -1384,41 +1380,42 @@ left_is_superset(DTCollation *left, DTCollation *right) return FALSE; } -/* - Aggregate two collations together taking - into account their coercibility (aka derivation): +/** + Aggregate two collations together taking + into account their coercibility (aka derivation):. - 0 == DERIVATION_EXPLICIT - an explicitly written COLLATE clause - 1 == DERIVATION_NONE - a mix of two different collations - 2 == DERIVATION_IMPLICIT - a column - 3 == DERIVATION_COERCIBLE - a string constant + 0 == DERIVATION_EXPLICIT - an explicitly written COLLATE clause @n + 1 == DERIVATION_NONE - a mix of two different collations @n + 2 == DERIVATION_IMPLICIT - a column @n + 3 == DERIVATION_COERCIBLE - a string constant. - The most important rules are: - - 1. If collations are the same: - chose this collation, and the strongest derivation. - - 2. If collations are different: - - Character sets may differ, but only if conversion without - data loss is possible. The caller provides flags whether - character set conversion attempts should be done. If no - flags are substituted, then the character sets must be the same. - Currently processed flags are: - MY_COLL_ALLOW_SUPERSET_CONV - allow conversion to a superset - MY_COLL_ALLOW_COERCIBLE_CONV - allow conversion of a coercible value - - two EXPLICIT collations produce an error, e.g. this is wrong: - CONCAT(expr1 collate latin1_swedish_ci, expr2 collate latin1_german_ci) - - the side with smaller derivation value wins, - i.e. a column is stronger than a string constant, - an explicit COLLATE clause is stronger than a column. - - if derivations are the same, we have DERIVATION_NONE, - we'll wait for an explicit COLLATE clause which possibly can - come from another argument later: for example, this is valid, - but we don't know yet when collecting the first two arguments: - CONCAT(latin1_swedish_ci_column, - latin1_german1_ci_column, - expr COLLATE latin1_german2_ci) + The most important rules are: + -# If collations are the same: + chose this collation, and the strongest derivation. + -# If collations are different: + - Character sets may differ, but only if conversion without + data loss is possible. The caller provides flags whether + character set conversion attempts should be done. If no + flags are substituted, then the character sets must be the same. + Currently processed flags are: + MY_COLL_ALLOW_SUPERSET_CONV - allow conversion to a superset + MY_COLL_ALLOW_COERCIBLE_CONV - allow conversion of a coercible value + - two EXPLICIT collations produce an error, e.g. this is wrong: + CONCAT(expr1 collate latin1_swedish_ci, expr2 collate latin1_german_ci) + - the side with smaller derivation value wins, + i.e. a column is stronger than a string constant, + an explicit COLLATE clause is stronger than a column. + - if derivations are the same, we have DERIVATION_NONE, + we'll wait for an explicit COLLATE clause which possibly can + come from another argument later: for example, this is valid, + but we don't know yet when collecting the first two arguments: + @code + CONCAT(latin1_swedish_ci_column, + latin1_german1_ci_column, + expr COLLATE latin1_german2_ci) + @endcode */ + bool DTCollation::aggregate(DTCollation &dt, uint flags) { if (!my_charset_same(collation, dt.collation)) @@ -1582,8 +1579,9 @@ bool agg_item_collations_for_comparison(DTCollation &c, const char *fname, } -/* +/** Collect arguments' character sets together. + We allow to apply automatic character set conversion in some cases. The conditions when conversion is possible are: - arguments A and B have different charsets @@ -1599,17 +1597,17 @@ bool agg_item_collations_for_comparison(DTCollation &c, const char *fname, to the collation of A. For functions with more than two arguments: - + @code collect(A,B,C) ::= collect(collect(A,B),C) - + @endcode Since this function calls THD::change_item_tree() on the passed Item ** pointers, it is necessary to pass the original Item **'s, not copies. Otherwise their values will not be properly restored (see BUG#20769). If the items are not consecutive (eg. args[2] and args[5]), use the item_sep argument, ie. - + @code agg_item_charsets(coll, fname, &args[2], 2, flags, 3) - + @endcode */ bool agg_item_charsets(DTCollation &coll, const char *fname, @@ -1731,6 +1729,13 @@ Item_field::Item_field(Field *f) } +/** + Constructor used inside setup_wild(). + + Ensures that field, table, and database names will live as long as + Item_field (this is important in prepared statements). +*/ + Item_field::Item_field(THD *thd, Name_resolution_context *context_arg, Field *f) :Item_ident(context_arg, f->table->s->db.str, *f->table_name, f->field_name), @@ -1782,7 +1787,10 @@ Item_field::Item_field(Name_resolution_context *context_arg, select->select_n_where_fields++; } -// Constructor need to process subselect with temporary tables (see Item) +/** + Constructor need to process subselect with temporary tables (see Item) +*/ + Item_field::Item_field(THD *thd, Item_field *item) :Item_ident(thd, item), field(item->field), @@ -1813,7 +1821,7 @@ void Item_field::set_field(Field *field_par) } -/* +/** Reset this item to point to a field from the new temporary table. This is used when we create a new temporary table for each execution of prepared statement. @@ -2082,9 +2090,9 @@ longlong Item_field::val_int_endpoint(bool left_endp, bool *incl_endp) return null_value? LONGLONG_MIN : res; } -/* +/** Create an item from a string we KNOW points to a valid longlong - end \0 terminated number string. + end \\0 terminated number string. This is always 'signed'. Unsigned values are created with Item_uint() */ @@ -2325,6 +2333,10 @@ double Item_string::val_real() } +/** + @todo + Give error if we wanted a signed integer and we got an unsigned one +*/ longlong Item_string::val_int() { DBUG_ASSERT(fixed == 1); @@ -2398,9 +2410,9 @@ Item *Item_null::safe_charset_converter(CHARSET_INFO *tocs) /*********************** Item_param related ******************************/ -/* +/** Default function of Item_param::set_param_func, so in case - of malformed packet the server won't SIGSEGV + of malformed packet the server won't SIGSEGV. */ static void @@ -2474,16 +2486,14 @@ void Item_param::set_double(double d) } -/* +/** Set decimal parameter value from string. - SYNOPSIS - set_decimal() - str - character string - length - string length + @param str character string + @param length string length - NOTE - as we use character strings to send decimal values in + @note + As we use character strings to send decimal values in binary protocol, we use str2my_decimal to convert it to internal decimal value. */ @@ -2504,16 +2514,14 @@ void Item_param::set_decimal(const char *str, ulong length) } -/* +/** Set parameter value from MYSQL_TIME value. - SYNOPSIS - set_time() - tm - datetime value to set (time_type is ignored) - type - type of datetime value - max_length_arg - max length of datetime value as string + @param tm datetime value to set (time_type is ignored) + @param type type of datetime value + @param max_length_arg max length of datetime value as string - NOTE + @note If we value to be stored is not normalized, zero value will be stored instead and proper warning will be produced. This function relies on the fact that even wrong value sent over binary protocol fits into @@ -2589,16 +2597,15 @@ bool Item_param::set_longdata(const char *str, ulong length) } -/* +/** Set parameter value from user variable value. - SYNOPSIS - set_from_user_var - thd Current thread - entry User variable structure (NULL means use NULL value) + @param thd Current thread + @param entry User variable structure (NULL means use NULL value) - RETURN + @retval 0 OK + @retval 1 Out of memory */ @@ -2667,14 +2674,11 @@ bool Item_param::set_from_user_var(THD *thd, const user_var_entry *entry) DBUG_RETURN(0); } -/* - Resets parameter after execution. - - SYNOPSIS - Item_param::reset() - - NOTES - We clear null_value here instead of setting it in set_* methods, +/** + Resets parameter after execution. + + @note + We clear null_value here instead of setting it in set_* methods, because we want more easily handle case for long data. */ @@ -2893,11 +2897,15 @@ String *Item_param::val_str(String* str) return str; } -/* +/** Return Param item values in string format, for generating the dynamic - query used in update/binary logs - TODO: change interface and implementation to fill log data in place - and avoid one more memcpy/alloc between str and log string. + query used in update/binary logs. + + @todo + - Change interface and implementation to fill log data in place + and avoid one more memcpy/alloc between str and log string. + - In case of error we need to notify replication + that binary log contains wrong statement */ const String *Item_param::query_val_str(String* str) const @@ -2950,7 +2958,7 @@ const String *Item_param::query_val_str(String* str) const } -/* +/** Convert string from client character set to the character set of connection. */ @@ -3174,17 +3182,16 @@ bool Item_ref_null_helper::get_date(MYSQL_TIME *ltime, uint fuzzydate) } -/* - Mark item and SELECT_LEXs as dependent if item was resolved in outer SELECT +/** + Mark item and SELECT_LEXs as dependent if item was resolved in + outer SELECT. - SYNOPSIS - mark_as_dependent() - thd - thread handler - last - select from which current item depend - current - current select - resolved_item - item which was resolved in outer SELECT(for warning) - mark_item - item which should be marked (can be differ in case of - substitution) + @param thd thread handler + @param last select from which current item depend + @param current current select + @param resolved_item item which was resolved in outer SELECT(for warning) + @param mark_item item which should be marked (can be differ in case of + substitution) */ static void mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current, @@ -3213,21 +3220,19 @@ static void mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current, } -/* - Mark range of selects and resolved identifier (field/reference) item as - dependent +/** + Mark range of selects and resolved identifier (field/reference) + item as dependent. - SYNOPSIS - mark_select_range_as_dependent() - thd - thread handler - last_select - select where resolved_item was resolved - current_sel - current select (select where resolved_item was placed) - found_field - field which was found during resolving - found_item - Item which was found during resolving (if resolved - identifier belongs to VIEW) - resolved_item - Identifier which was resolved + @param thd thread handler + @param last_select select where resolved_item was resolved + @param current_sel current select (select where resolved_item was placed) + @param found_field field which was found during resolving + @param found_item Item which was found during resolving (if resolved + identifier belongs to VIEW) + @param resolved_item Identifier which was resolved - NOTE: + @note We have to mark all items between current_sel (including) and last_select (excluding) as dependend (select before last_select should be marked with actual table mask used by resolved item, all other with @@ -3279,20 +3284,17 @@ void mark_select_range_as_dependent(THD *thd, } -/* +/** Search a GROUP BY clause for a field with a certain name. - SYNOPSIS - find_field_in_group_list() - find_item the item being searched for - group_list GROUP BY clause + Search the GROUP BY list for a column named as find_item. When searching + preference is given to columns that are qualified with the same table (and + database) name as the one being searched for. - DESCRIPTION - Search the GROUP BY list for a column named as find_item. When searching - preference is given to columns that are qualified with the same table (and - database) name as the one being searched for. + @param find_item the item being searched for + @param group_list GROUP BY clause - RETURN + @return - the found item on success - NULL if find_item is not in group_list */ @@ -3388,43 +3390,40 @@ static Item** find_field_in_group_list(Item *find_item, ORDER *group_list) } -/* +/** Resolve a column reference in a sub-select. - SYNOPSIS - resolve_ref_in_select_and_group() - thd current thread - ref column reference being resolved - select the sub-select that ref is resolved against + Resolve a column reference (usually inside a HAVING clause) against the + SELECT and GROUP BY clauses of the query described by 'select'. The name + resolution algorithm searches both the SELECT and GROUP BY clauses, and in + case of a name conflict prefers GROUP BY column names over SELECT names. If + both clauses contain different fields with the same names, a warning is + issued that name of 'ref' is ambiguous. We extend ANSI SQL in that when no + GROUP BY column is found, then a HAVING name is resolved as a possibly + derived SELECT column. This extension is allowed only if the + MODE_ONLY_FULL_GROUP_BY sql mode isn't enabled. - DESCRIPTION - Resolve a column reference (usually inside a HAVING clause) against the - SELECT and GROUP BY clauses of the query described by 'select'. The name - resolution algorithm searches both the SELECT and GROUP BY clauses, and in - case of a name conflict prefers GROUP BY column names over SELECT names. If - both clauses contain different fields with the same names, a warning is - issued that name of 'ref' is ambiguous. We extend ANSI SQL in that when no - GROUP BY column is found, then a HAVING name is resolved as a possibly - derived SELECT column. This extension is allowed only if the - MODE_ONLY_FULL_GROUP_BY sql mode isn't enabled. + @param thd current thread + @param ref column reference being resolved + @param select the sub-select that ref is resolved against - NOTES + @note The resolution procedure is: - Search for a column or derived column named col_ref_i [in table T_j] - in the SELECT clause of Q. + in the SELECT clause of Q. - Search for a column named col_ref_i [in table T_j] - in the GROUP BY clause of Q. + in the GROUP BY clause of Q. - If found different columns with the same name in GROUP BY and SELECT - - issue a warning and return the GROUP BY column, - - otherwise - - if the MODE_ONLY_FULL_GROUP_BY mode is enabled return error - - else return the found SELECT column. + - issue a warning and return the GROUP BY column, + - otherwise + - if the MODE_ONLY_FULL_GROUP_BY mode is enabled return error + - else return the found SELECT column. - RETURN - NULL - there was an error, and the error was already reported - not_found_item - the item was not resolved, no error was reported - resolved item - if the item was resolved + @return + - NULL - there was an error, and the error was already reported + - not_found_item - the item was not resolved, no error was reported + - resolved item - if the item was resolved */ static Item** @@ -3500,44 +3499,45 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select) } -/* +/** Resolve the name of an outer select column reference. - SYNOPSIS - Item_field::fix_outer_field() - thd [in] current thread - from_field [in/out] found field reference or (Field*)not_found_field - reference [in/out] view column if this item was resolved to a view column + The method resolves the column reference represented by 'this' as a column + present in outer selects that contain current select. - DESCRIPTION - The method resolves the column reference represented by 'this' as a column - present in outer selects that contain current select. + In prepared statements, because of cache, find_field_in_tables() + can resolve fields even if they don't belong to current context. + In this case this method only finds appropriate context and marks + current select as dependent. The found reference of field should be + provided in 'from_field'. - NOTES + @param[in] thd current thread + @param[in,out] from_field found field reference or (Field*)not_found_field + @param[in,out] reference view column if this item was resolved to a + view column + + @note This is the inner loop of Item_field::fix_fields: + @code + for each outer query Q_k beginning from the inner-most one + { + search for a column or derived column named col_ref_i + [in table T_j] in the FROM clause of Q_k; - for each outer query Q_k beginning from the inner-most one - { - search for a column or derived column named col_ref_i - [in table T_j] in the FROM clause of Q_k; + if such a column is not found + Search for a column or derived column named col_ref_i + [in table T_j] in the SELECT and GROUP clauses of Q_k. + } + @endcode - if such a column is not found - Search for a column or derived column named col_ref_i - [in table T_j] in the SELECT and GROUP clauses of Q_k. - } - - IMPLEMENTATION - In prepared statements, because of cache, find_field_in_tables() - can resolve fields even if they don't belong to current context. - In this case this method only finds appropriate context and marks - current select as dependent. The found reference of field should be - provided in 'from_field'. - - RETURN - 1 - column succefully resolved and fix_fields() should continue. - 0 - column fully fixed and fix_fields() should return FALSE - -1 - error occured + @retval + 1 column succefully resolved and fix_fields() should continue. + @retval + 0 column fully fixed and fix_fields() should return FALSE + @retval + -1 error occured */ + int Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference) { @@ -3798,48 +3798,48 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference) } -/* +/** Resolve the name of a column reference. - SYNOPSIS - Item_field::fix_fields() - thd [in] current thread - reference [in/out] view column if this item was resolved to a view column + The method resolves the column reference represented by 'this' as a column + present in one of: FROM clause, SELECT clause, GROUP BY clause of a query + Q, or in outer queries that contain Q. - DESCRIPTION - The method resolves the column reference represented by 'this' as a column - present in one of: FROM clause, SELECT clause, GROUP BY clause of a query - Q, or in outer queries that contain Q. + The name resolution algorithm used is (where [T_j] is an optional table + name that qualifies the column name): - NOTES - The name resolution algorithm used is (where [T_j] is an optional table - name that qualifies the column name): + @code + resolve_column_reference([T_j].col_ref_i) + { + search for a column or derived column named col_ref_i + [in table T_j] in the FROM clause of Q; - resolve_column_reference([T_j].col_ref_i) + if such a column is NOT found AND // Lookup in outer queries. + there are outer queries { - search for a column or derived column named col_ref_i - [in table T_j] in the FROM clause of Q; - - if such a column is NOT found AND // Lookup in outer queries. - there are outer queries + for each outer query Q_k beginning from the inner-most one { - for each outer query Q_k beginning from the inner-most one - { - search for a column or derived column named col_ref_i - [in table T_j] in the FROM clause of Q_k; + search for a column or derived column named col_ref_i + [in table T_j] in the FROM clause of Q_k; - if such a column is not found - Search for a column or derived column named col_ref_i - [in table T_j] in the SELECT and GROUP clauses of Q_k. - } + if such a column is not found + Search for a column or derived column named col_ref_i + [in table T_j] in the SELECT and GROUP clauses of Q_k. } } + } + @endcode Notice that compared to Item_ref::fix_fields, here we first search the FROM clause, and then we search the SELECT and GROUP BY clauses. - RETURN + @param[in] thd current thread + @param[in,out] reference view column if this item was resolved to a + view column + + @retval TRUE if error + @retval FALSE on success */ @@ -4053,26 +4053,24 @@ void Item_field::cleanup() DBUG_VOID_RETURN; } -/* - Find a field among specified multiple equalities +/** + Find a field among specified multiple equalities. - SYNOPSIS - find_item_equal() - cond_equal reference to list of multiple equalities where - the field (this object) is to be looked for - - DESCRIPTION - The function first searches the field among multiple equalities - of the current level (in the cond_equal->current_level list). - If it fails, it continues searching in upper levels accessed - through a pointer cond_equal->upper_levels. - The search terminates as soon as a multiple equality containing - the field is found. + The function first searches the field among multiple equalities + of the current level (in the cond_equal->current_level list). + If it fails, it continues searching in upper levels accessed + through a pointer cond_equal->upper_levels. + The search terminates as soon as a multiple equality containing + the field is found. - RETURN VALUES - First Item_equal containing the field, if success - 0, otherwise + @param cond_equal reference to list of multiple equalities where + the field (this object) is to be looked for + + @return + - First Item_equal containing the field, if success + - 0, otherwise */ + Item_equal *Item_field::find_item_equal(COND_EQUAL *cond_equal) { Item_equal *item= 0; @@ -4094,32 +4092,33 @@ Item_equal *Item_field::find_item_equal(COND_EQUAL *cond_equal) } -/* - Check whether a field can be substituted by an equal item +/** + Check whether a field can be substituted by an equal item. - SYNOPSIS - equal_fields_propagator() - arg - *arg != NULL <-> the field is in the context where - substitution for an equal item is valid - - DESCRIPTION - The function checks whether a substitution of the field - occurrence for an equal item is valid. + The function checks whether a substitution of the field + occurrence for an equal item is valid. - NOTES + @param arg *arg != NULL <-> the field is in the context where + substitution for an equal item is valid + + @note The following statement is not always true: + @n x=y => F(x)=F(x/y). + @n This means substitution of an item for an equal item not always - yields an equavalent condition. - Here's an example: - 'a'='a ' - (LENGTH('a')=1) != (LENGTH('a ')=2) + yields an equavalent condition. Here's an example: + @code + 'a'='a ' + (LENGTH('a')=1) != (LENGTH('a ')=2) + @endcode Such a substitution is surely valid if either the substituted field is not of a STRING type or if it is an argument of - a comparison predicate. + a comparison predicate. - RETURN + @retval TRUE substitution is valid + @retval FALSE otherwise */ @@ -4129,30 +4128,28 @@ bool Item_field::subst_argument_checker(uchar **arg) } -/* +/** Set a pointer to the multiple equality the field reference belongs to - (if any) - - SYNOPSIS - equal_fields_propagator() - arg - reference to list of multiple equalities where - the field (this object) is to be looked for - - DESCRIPTION - The function looks for a multiple equality containing the field item - among those referenced by arg. - In the case such equality exists the function does the following. - If the found multiple equality contains a constant, then the field - reference is substituted for this constant, otherwise it sets a pointer - to the multiple equality in the field item. + (if any). - NOTES + The function looks for a multiple equality containing the field item + among those referenced by arg. + In the case such equality exists the function does the following. + If the found multiple equality contains a constant, then the field + reference is substituted for this constant, otherwise it sets a pointer + to the multiple equality in the field item. + + + @param arg reference to list of multiple equalities where + the field (this object) is to be looked for + + @note This function is supposed to be called as a callback parameter in calls - of the compile method. + of the compile method. - RETURN VALUES - pointer to the replacing constant item, if the field item was substituted - pointer to the field item, otherwise. + @return + - pointer to the replacing constant item, if the field item was substituted + - pointer to the field item, otherwise. */ Item *Item_field::equal_fields_propagator(uchar *arg) @@ -4181,9 +4178,10 @@ Item *Item_field::equal_fields_propagator(uchar *arg) } -/* - Mark the item to not be part of substitution if it's not a binary item - See comments in Arg_comparator::set_compare_func() for details +/** + Mark the item to not be part of substitution if it's not a binary item. + + See comments in Arg_comparator::set_compare_func() for details. */ bool Item_field::set_no_const_sub(uchar *arg) @@ -4194,31 +4192,29 @@ bool Item_field::set_no_const_sub(uchar *arg) } -/* +/** Replace an Item_field for an equal Item_field that evaluated earlier - (if any) - - SYNOPSIS - replace_equal_field_() - arg - a dummy parameter, is not used here - - DESCRIPTION - The function returns a pointer to an item that is taken from - the very beginning of the item_equal list which the Item_field - object refers to (belongs to) unless item_equal contains a constant - item. In this case the function returns this constant item, - (if the substitution does not require conversion). - If the Item_field object does not refer any Item_equal object - 'this' is returned + (if any). - NOTES + The function returns a pointer to an item that is taken from + the very beginning of the item_equal list which the Item_field + object refers to (belongs to) unless item_equal contains a constant + item. In this case the function returns this constant item, + (if the substitution does not require conversion). + If the Item_field object does not refer any Item_equal object + 'this' is returned . + + @param arg a dummy parameter, is not used here + + + @note This function is supposed to be called as a callback parameter in calls - of the thransformer method. + of the thransformer method. - RETURN VALUES - pointer to a replacement Item_field if there is a better equal item or - a pointer to a constant equal item; - this - otherwise. + @return + - pointer to a replacement Item_field if there is a better equal item or + a pointer to a constant equal item; + - this - otherwise. */ Item *Item_field::replace_equal_field(uchar *arg) @@ -4314,20 +4310,16 @@ bool Item::is_datetime() } -/* - Create a field to hold a string value from an item +/** + Create a field to hold a string value from an item. - SYNOPSIS - make_string_field() - table Table for which the field is created + If max_length > CONVERT_IF_BIGGER_TO_BLOB create a blob @n + If max_length > 0 create a varchar @n + If max_length == 0 create a CHAR(0) - IMPLEMENTATION - If max_length > CONVERT_IF_BIGGER_TO_BLOB create a blob - If max_length > 0 create a varchar - If max_length == 0 create a CHAR(0) + @param table Table for which the field is created */ - Field *Item::make_string_field(TABLE *table) { Field *field; @@ -4349,15 +4341,16 @@ Field *Item::make_string_field(TABLE *table) } -/* - Create a field based on field_type of argument +/** + Create a field based on field_type of argument. For now, this is only used to create a field for IFNULL(x,something) and time functions - RETURN - 0 error - # Created field + @retval + NULL error + @retval + \# Created field */ Field *Item::tmp_table_field_from_field_type(TABLE *table, bool fixed_length) @@ -4484,8 +4477,8 @@ void Item_field::make_field(Send_field *tmp_field) } -/* - Set a field:s value from a item +/** + Set a field's value from a item. */ void Item_field::save_org_in_field(Field *to) @@ -4521,21 +4514,19 @@ int Item_field::save_in_field(Field *to, bool no_conversions) } -/* - Store null in field +/** + Store null in field. - SYNOPSIS - save_in_field() - field Field where we want to store NULL + This is used on INSERT. + Allow NULL to be inserted in timestamp and auto_increment values. - DESCRIPTION - This is used on INSERT. - Allow NULL to be inserted in timestamp and auto_increment values + @param field Field where we want to store NULL - RETURN VALUES - 0 ok - 1 Field doesn't support NULL values and can't handle 'field = NULL' -*/ + @retval + 0 ok + @retval + 1 Field doesn't support NULL values and can't handle 'field = NULL' +*/ int Item_null::save_in_field(Field *field, bool no_conversions) { @@ -4543,17 +4534,16 @@ int Item_null::save_in_field(Field *field, bool no_conversions) } -/* - Store null in field +/** + Store null in field. - SYNOPSIS - save_safe_in_field() - field Field where we want to store NULL + @param field Field where we want to store NULL - RETURN VALUES + @retval 0 OK + @retval 1 Field doesn't support NULL values -*/ +*/ int Item_null::save_safe_in_field(Field *field) { @@ -4711,7 +4701,7 @@ static uint nr_of_decimals(const char *str, const char *end) } -/* +/** This function is only called during parsing. We will signal an error if value is not a true double value (overflow) */ @@ -4928,8 +4918,8 @@ Item_bin_string::Item_bin_string(const char *str, uint str_length) } -/* - Pack data in buffer for sending +/** + Pack data in buffer for sending. */ bool Item_null::send(Protocol *protocol, String *packet) @@ -4937,8 +4927,8 @@ bool Item_null::send(Protocol *protocol, String *packet) return protocol->store_null(); } -/* - This is only called from items that is not of type item_field +/** + This is only called from items that is not of type item_field. */ bool Item::send(Protocol *protocol, String *buffer) @@ -5147,60 +5137,67 @@ Item_ref::Item_ref(Name_resolution_context *context_arg, } -/* +/** Resolve the name of a reference to a column reference. - SYNOPSIS - Item_ref::fix_fields() - thd [in] current thread - reference [in/out] view column if this item was resolved to a view column + The method resolves the column reference represented by 'this' as a column + present in one of: GROUP BY clause, SELECT clause, outer queries. It is + used typically for columns in the HAVING clause which are not under + aggregate functions. - DESCRIPTION - The method resolves the column reference represented by 'this' as a column - present in one of: GROUP BY clause, SELECT clause, outer queries. It is - used typically for columns in the HAVING clause which are not under - aggregate functions. + POSTCONDITION @n + Item_ref::ref is 0 or points to a valid item. - NOTES + @note The name resolution algorithm used is (where [T_j] is an optional table name that qualifies the column name): - resolve_extended([T_j].col_ref_i) - { - Search for a column or derived column named col_ref_i [in table T_j] - in the SELECT and GROUP clauses of Q. - - if such a column is NOT found AND // Lookup in outer queries. - there are outer queries + @code + resolve_extended([T_j].col_ref_i) { - for each outer query Q_k beginning from the inner-most one - { - Search for a column or derived column named col_ref_i - [in table T_j] in the SELECT and GROUP clauses of Q_k. + Search for a column or derived column named col_ref_i [in table T_j] + in the SELECT and GROUP clauses of Q. - if such a column is not found AND - - Q_k is not a group query AND - - Q_k is not inside an aggregate function - OR - - Q_(k-1) is not in a HAVING or SELECT clause of Q_k - { - search for a column or derived column named col_ref_i - [in table T_j] in the FROM clause of Q_k; + if such a column is NOT found AND // Lookup in outer queries. + there are outer queries + { + for each outer query Q_k beginning from the inner-most one + { + Search for a column or derived column named col_ref_i + [in table T_j] in the SELECT and GROUP clauses of Q_k. + + if such a column is not found AND + - Q_k is not a group query AND + - Q_k is not inside an aggregate function + OR + - Q_(k-1) is not in a HAVING or SELECT clause of Q_k + { + search for a column or derived column named col_ref_i + [in table T_j] in the FROM clause of Q_k; + } } } } - } - + @endcode + @n This procedure treats GROUP BY and SELECT clauses as one namespace for column references in HAVING. Notice that compared to Item_field::fix_fields, here we first search the SELECT and GROUP BY clauses, and then we search the FROM clause. - POSTCONDITION - Item_ref::ref is 0 or points to a valid item + @param[in] thd current thread + @param[in,out] reference view column if this item was resolved to a + view column - RETURN + @todo + Here we could first find the field anyway, and then test this + condition, so that we can give a better error message - + ER_WRONG_FIELD_WITH_GROUP, instead of the less informative + ER_BAD_FIELD_ERROR which we produce now. + + @retval TRUE if error + @retval FALSE on success */ @@ -5727,16 +5724,15 @@ bool Item_direct_ref::get_date(MYSQL_TIME *ltime,uint fuzzydate) } -/* - Prepare referenced field then call usual Item_direct_ref::fix_fields +/** + Prepare referenced field then call usual Item_direct_ref::fix_fields . - SYNOPSIS - Item_direct_view_ref::fix_fields() - thd thread handler - reference reference on reference where this item stored + @param thd thread handler + @param reference reference on reference where this item stored - RETURN + @retval FALSE OK + @retval TRUE Error */ @@ -5779,25 +5775,23 @@ bool Item_outer_ref::fix_fields(THD *thd, Item **reference) } -/* +/** Compare two view column references for equality. - SYNOPSIS - Item_direct_view_ref::eq() - item item to compare with - binary_cmp make binary comparison + A view column reference is considered equal to another column + reference if the second one is a view column and if both column + references resolve to the same item. It is assumed that both + items are of the same type. - DESCRIPTION - A view column reference is considered equal to another column - reference if the second one is a view column and if both column - references resolve to the same item. + @param item item to compare with + @param binary_cmp make binary comparison - RETURN + @retval TRUE Referenced item is equal to given item + @retval FALSE otherwise */ - bool Item_direct_view_ref::eq(const Item *item, bool binary_cmp) const { if (item->type() == REF_ITEM) @@ -5916,9 +5910,9 @@ int Item_default_value::save_in_field(Field *field_arg, bool no_conversions) } -/* +/** This method like the walk method traverses the item tree, but at the - same time it can replace some nodes in the tree + same time it can replace some nodes in the tree. */ Item *Item_default_value::transform(Item_transformer transformer, uchar *args) @@ -6015,17 +6009,15 @@ void Item_insert_value::print(String *str) } -/* +/** Find index of Field object which will be appropriate for item representing field of row being changed in trigger. - SYNOPSIS - setup_field() - thd - current thread context - table - table of trigger (and where we looking for fields) - table_grant_info - GRANT_INFO of the subject table + @param thd current thread context + @param table table of trigger (and where we looking for fields) + @param table_grant_info GRANT_INFO of the subject table - NOTE + @note This function does almost the same as fix_fields() for Item_field but is invoked right after trigger definition parsing. Since at this stage we can't say exactly what Field object (corresponding @@ -6259,8 +6251,10 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item) thd->change_item_tree(ref, new_item); } -/* - Return true if the value stored in the field is equal to the const item +/** + Return true if the value stored in the field is equal to the const + item. + We need to use this on the range optimizer because in some cases we can't store the value in the field without some precision/character loss. */ @@ -6593,14 +6587,11 @@ Item_type_holder::Item_type_holder(THD *thd, Item *item) } -/* - Return expression type of Item_type_holder +/** + Return expression type of Item_type_holder. - SYNOPSIS - Item_type_holder::result_type() - - RETURN - Item_result (type of internal MySQL expression result) + @return + Item_result (type of internal MySQL expression result) */ Item_result Item_type_holder::result_type() const @@ -6609,13 +6600,10 @@ Item_result Item_type_holder::result_type() const } -/* - Find real field type of item +/** + Find real field type of item. - SYNOPSIS - Item_type_holder::get_real_type() - - RETURN + @return type of field which should be created to store item value */ @@ -6678,17 +6666,16 @@ enum_field_types Item_type_holder::get_real_type(Item *item) return item->field_type(); } -/* +/** Find field type which can carry current Item_type_holder type and type of given Item. - SYNOPSIS - Item_type_holder::join_types() - thd thread handler - item given item to join its parameters with this item ones + @param thd thread handler + @param item given item to join its parameters with this item ones - RETURN + @retval TRUE error - types are incompatible + @retval FALSE OK */ @@ -6789,14 +6776,12 @@ bool Item_type_holder::join_types(THD *thd, Item *item) DBUG_RETURN(FALSE); } -/* - Calculate lenth for merging result for given Item type +/** + Calculate lenth for merging result for given Item type. - SYNOPSIS - Item_type_holder::real_length() - item Item for lrngth detection + @param item Item for length detection - RETURN + @return length */ @@ -6850,15 +6835,13 @@ uint32 Item_type_holder::display_length(Item *item) } -/* +/** Make temporary table field according collected information about type - of UNION result + of UNION result. - SYNOPSIS - Item_type_holder::make_field_by_type() - table temporary table for which we create fields + @param table temporary table for which we create fields - RETURN + @return created field */ @@ -6896,13 +6879,11 @@ Field *Item_type_holder::make_field_by_type(TABLE *table) } -/* +/** Get full information from Item about enum/set fields to be able to create - them later + them later. - SYNOPSIS - Item_type_holder::get_full_info - item Item for information collection + @param item Item for information collection */ void Item_type_holder::get_full_info(Item *item) { @@ -6965,26 +6946,21 @@ void Item_result_field::cleanup() DBUG_VOID_RETURN; } -/* - Dummy error processor used by default by Name_resolution_context +/** + Dummy error processor used by default by Name_resolution_context. - SYNOPSIS - dummy_error_processor() - - NOTE + @note do nothing */ void dummy_error_processor(THD *thd, void *data) {} -/* - Wrapper of hide_view_error call for Name_resolution_context error processor +/** + Wrapper of hide_view_error call for Name_resolution_context error + processor. - SYNOPSIS - view_error_processor() - - NOTE + @note hide view underlying tables details in error messages */ diff --git a/sql/item_buff.cc b/sql/item_buff.cc index c162b84f457..2f45d0a17c2 100644 --- a/sql/item_buff.cc +++ b/sql/item_buff.cc @@ -14,12 +14,17 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* Buffers to save and compare item values */ +/** + @file + + @brief + Buffers to save and compare item values +*/ #include "mysql_priv.h" -/* -** Create right type of Cached_item for an item +/** + Create right type of Cached_item for an item. */ Cached_item *new_Cached_item(THD *thd, Item *item) @@ -45,9 +50,11 @@ Cached_item *new_Cached_item(THD *thd, Item *item) Cached_item::~Cached_item() {} -/* -** Compare with old value and replace value with new value -** Return true if values have changed +/** + Compare with old value and replace value with new value. + + @return + Return true if values have changed */ Cached_item_str::Cached_item_str(THD *thd, Item *arg) diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 8f5ff050dd6..f315da53393 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -14,7 +14,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* This file defines all compare functions */ +/** + @file + + @brief + This file defines all compare functions +*/ #ifdef USE_PRAGMA_IMPLEMENTATION #pragma implementation // gcc: Class implementation @@ -104,7 +109,7 @@ static int cmp_row_type(Item* item1, Item* item2) } -/* +/** Aggregates result types from the array of items. SYNOPSIS: @@ -117,11 +122,13 @@ static int cmp_row_type(Item* item1, Item* item2) This function aggregates result types from the array of items. Found type supposed to be used later for comparison of values of these items. Aggregation itself is performed by the item_cmp_type() function. - The function also checks compatibility of row signatures for the - submitted items (see the spec for the cmp_row_type function). + @param[out] type the aggregated type + @param items array of items to aggregate the type from + @param nitems number of items in the array - RETURN VALUES + @retval 1 type incompatibility has been detected + @retval 0 otherwise */ @@ -257,10 +264,11 @@ void Item_func_not::print(String *str) str->append(')'); } -/* - special NOT for ALL subquery +/** + special NOT for ALL subquery. */ + longlong Item_func_not_all::val_int() { DBUG_ASSERT(fixed == 1); @@ -293,10 +301,13 @@ void Item_func_not_all::print(String *str) } -/* - Special NOP (No OPeration) for ALL subquery it is like Item_func_not_all - (return TRUE if underlying subquery do not return rows) but if subquery - returns some rows it return same value as argument (TRUE/FALSE). +/** + Special NOP (No OPeration) for ALL subquery. It is like + Item_func_not_all. + + @return + (return TRUE if underlying subquery do not return rows) but if subquery + returns some rows it return same value as argument (TRUE/FALSE). */ longlong Item_func_nop_all::val_int() @@ -316,16 +327,9 @@ longlong Item_func_nop_all::val_int() } -/* - Convert a constant item to an int and replace the original item +/** + Convert a constant item to an int and replace the original item. - SYNOPSIS - convert_constant_item() - thd thread handle - field item will be converted using the type of this field - item [in/out] reference to the item to convert - - DESCRIPTION The function converts a constant expression or string to an integer. On successful conversion the original item is substituted for the result of the item evaluation. @@ -333,16 +337,21 @@ longlong Item_func_nop_all::val_int() also when comparing bigint to strings (in which case strings are converted to bigints). - NOTES + @param thd thread handle + @param field item will be converted using the type of this field + @param[in,out] item reference to the item to convert + + @note This function is called only at prepare stage. As all derived tables are filled only after all derived tables are prepared we do not evaluate items with subselects here because they can contain derived tables and thus we may attempt to use a table that has not been populated yet. - RESULT VALUES - 0 Can't convert item - 1 Item was replaced with an integer version of the item + @retval + 0 Can't convert item + @retval + 1 Item was replaced with an integer version of the item */ static bool convert_constant_item(THD *thd, Field *field, Item **item) @@ -1013,13 +1022,15 @@ int Arg_comparator::compare_string() } -/* +/** Compare strings byte by byte. End spaces are also compared. - RETURN - < 0 *a < *b - 0 *b == *b - > 0 *a > *b + @retval + <0 *a < *b + @retval + 0 *b == *b + @retval + >0 *a > *b */ int Arg_comparator::compare_binary_string() @@ -1041,10 +1052,11 @@ int Arg_comparator::compare_binary_string() } -/* - Compare strings, but take into account that NULL == NULL +/** + Compare strings, but take into account that NULL == NULL. */ + int Arg_comparator::compare_e_string() { String *res1,*res2; @@ -1185,7 +1197,7 @@ int Arg_comparator::compare_int_signed() } -/* +/** Compare values as BIGINT UNSIGNED. */ @@ -1208,7 +1220,7 @@ int Arg_comparator::compare_int_unsigned() } -/* +/** Compare signed (*a) with unsigned (*B) */ @@ -1233,7 +1245,7 @@ int Arg_comparator::compare_int_signed_unsigned() } -/* +/** Compare unsigned (*a) with signed (*B) */ @@ -1269,7 +1281,7 @@ int Arg_comparator::compare_e_int() return test(val1 == val2); } -/* +/** Compare unsigned *a with signed *b or signed *a with unsigned *b. */ int Arg_comparator::compare_e_int_diff_signedness() @@ -1558,7 +1570,7 @@ longlong Item_func_eq::val_int() } -/* Same as Item_func_eq, but NULL = NULL */ +/** Same as Item_func_eq, but NULL = NULL. */ void Item_func_equal::fix_length_and_dec() { @@ -1709,21 +1721,18 @@ void Item_func_interval::fix_length_and_dec() } -/* - Execute Item_func_interval() +/** + Execute Item_func_interval(). - SYNOPSIS - Item_func_interval::val_int() + @note + If we are doing a decimal comparison, we are evaluating the first + item twice. - NOTES - If we are doing a decimal comparison, we are - evaluating the first item twice. - - RETURN - -1 if null value, - 0 if lower than lowest - 1 - arg_count-1 if between args[n] and args[n+1] - arg_count if higher than biggest argument + @return + - -1 if null value, + - 0 if lower than lowest + - 1 - arg_count-1 if between args[n] and args[n+1] + - arg_count if higher than biggest argument */ longlong Item_func_interval::val_int() @@ -1795,32 +1804,31 @@ longlong Item_func_interval::val_int() } -/* - Perform context analysis of a BETWEEN item tree +/** + Perform context analysis of a BETWEEN item tree. - SYNOPSIS: - fix_fields() - thd reference to the global context of the query thread - tables list of all open tables involved in the query - ref pointer to Item* variable where pointer to resulting "fixed" - item is to be assigned - - DESCRIPTION This function performs context analysis (name resolution) and calculates various attributes of the item tree with Item_func_between as its root. The function saves in ref the pointer to the item or to a newly created item that is considered as a replacement for the original one. - NOTES + @param thd reference to the global context of the query thread + @param ref pointer to Item* variable where pointer to resulting "fixed" + item is to be assigned + + @note Let T0(e)/T1(e) be the value of not_null_tables(e) when e is used on a predicate/function level. Then it's easy to show that: + @verbatim T0(e BETWEEN e1 AND e2) = union(T1(e),T1(e1),T1(e2)) T1(e BETWEEN e1 AND e2) = union(T1(e),intersection(T1(e1),T1(e2))) T0(e NOT BETWEEN e1 AND e2) = union(T1(e),intersection(T1(e1),T1(e2))) T1(e NOT BETWEEN e1 AND e2) = union(T1(e),intersection(T1(e1),T1(e2))) + @endverbatim - RETURN + @retval 0 ok + @retval 1 got error */ @@ -2156,30 +2164,29 @@ Item_func_ifnull::str_op(String *str) } -/* - Perform context analysis of an IF item tree +/** + Perform context analysis of an IF item tree. - SYNOPSIS: - fix_fields() - thd reference to the global context of the query thread - tables list of all open tables involved in the query - ref pointer to Item* variable where pointer to resulting "fixed" - item is to be assigned - - DESCRIPTION This function performs context analysis (name resolution) and calculates various attributes of the item tree with Item_func_if as its root. The function saves in ref the pointer to the item or to a newly created item that is considered as a replacement for the original one. - NOTES + @param thd reference to the global context of the query thread + @param ref pointer to Item* variable where pointer to resulting "fixed" + item is to be assigned + + @note Let T0(e)/T1(e) be the value of not_null_tables(e) when e is used on a predicate/function level. Then it's easy to show that: + @verbatim T0(IF(e,e1,e2) = T1(IF(e,e1,e2)) T1(IF(e,e1,e2)) = intersection(T1(e1),T1(e2)) + @endverbatim - RETURN + @retval 0 ok + @retval 1 got error */ @@ -2321,11 +2328,14 @@ Item_func_nullif::fix_length_and_dec() } -/* - nullif () returns NULL if arguments are equal, else it returns the - first argument. +/** + @note Note that we have to evaluate the first argument twice as the compare may have been done with a different type than return value + @return + NULL if arguments are equal + @return + the first argument if not equal */ double @@ -2397,14 +2407,7 @@ Item_func_nullif::is_null() } -/* - Return the matching ITEM or NULL if all compares (including else) failed - - SYNOPSIS - find_item() - str Buffer string - - DESCRIPTION +/** Find and return matching items for CASE or ELSE item if all compares are failed or NULL if ELSE item isn't defined. @@ -2418,9 +2421,10 @@ Item_func_nullif::is_null() to it according to their int values i.e. STRING_RESULT is mapped to bit 0, REAL_RESULT to bit 1, so on. - RETURN - NULL - Nothing found and there is no ELSE expression defined - item - Found item or ELSE item if defined and all comparisons are + @retval + NULL Nothing found and there is no ELSE expression defined + @retval + item Found item or ELSE item if defined and all comparisons are failed */ @@ -2645,7 +2649,10 @@ uint Item_func_case::decimal_precision() const } -/* TODO: Fix this so that it prints the whole CASE expression */ +/** + @todo + Fix this so that it prints the whole CASE expression +*/ void Item_func_case::print(String *str) { @@ -2687,7 +2694,7 @@ void Item_func_case::cleanup() } -/* +/** Coalesce - return first not NULL argument. */ @@ -3305,32 +3312,31 @@ bool Item_func_in::nulls_in_row() } -/* - Perform context analysis of an IN item tree +/** + Perform context analysis of an IN item tree. - SYNOPSIS: - fix_fields() - thd reference to the global context of the query thread - tables list of all open tables involved in the query - ref pointer to Item* variable where pointer to resulting "fixed" - item is to be assigned - - DESCRIPTION This function performs context analysis (name resolution) and calculates various attributes of the item tree with Item_func_in as its root. The function saves in ref the pointer to the item or to a newly created item that is considered as a replacement for the original one. - NOTES + @param thd reference to the global context of the query thread + @param ref pointer to Item* variable where pointer to resulting "fixed" + item is to be assigned + + @note Let T0(e)/T1(e) be the value of not_null_tables(e) when e is used on a predicate/function level. Then it's easy to show that: + @verbatim T0(e IN(e1,...,en)) = union(T1(e),intersection(T1(ei))) T1(e IN(e1,...,en)) = union(T1(e),intersection(T1(ei))) T0(e NOT IN(e1,...,en)) = union(T1(e),union(T1(ei))) T1(e NOT IN(e1,...,en)) = union(T1(e),intersection(T1(ei))) + @endverbatim - RETURN + @retval 0 ok + @retval 1 got error */ @@ -3805,25 +3811,22 @@ bool Item_cond::walk(Item_processor processor, bool walk_subquery, uchar *arg) } -/* - Transform an Item_cond object with a transformer callback function - - SYNOPSIS - transform() - transformer the transformer callback function to be applied to the nodes - of the tree of the object - arg parameter to be passed to the transformer - - DESCRIPTION +/** + Transform an Item_cond object with a transformer callback function. + The function recursively applies the transform method to each - member item of the condition list. + member item of the condition list. If the call of the method for a member item returns a new item the old item is substituted for a new one. After this the transformer is applied to the root node - of the Item_cond object. - - RETURN VALUES - Item returned as the result of transformation of the root node + of the Item_cond object. + + @param transformer the transformer callback function to be applied to + the nodes of the tree of the object + @param arg parameter to be passed to the transformer + + @return + Item returned as the result of transformation of the root node */ Item *Item_cond::transform(Item_transformer transformer, uchar *arg) @@ -3851,19 +3854,10 @@ Item *Item_cond::transform(Item_transformer transformer, uchar *arg) } -/* - Compile Item_cond object with a processor and a transformer callback functions - - SYNOPSIS - compile() - analyzer the analyzer callback function to be applied to the nodes - of the tree of the object - arg_p in/out parameter to be passed to the analyzer - transformer the transformer callback function to be applied to the nodes - of the tree of the object - arg_t parameter to be passed to the transformer - - DESCRIPTION +/** + Compile Item_cond object with a processor and a transformer + callback functions. + First the function applies the analyzer to the root node of the Item_func object. Then if the analyzer succeeeds (returns TRUE) the function recursively applies the compile method to member @@ -3872,9 +3866,16 @@ Item *Item_cond::transform(Item_transformer transformer, uchar *arg) the old item is substituted for a new one. After this the transformer is applied to the root node of the Item_cond object. - - RETURN VALUES - Item returned as the result of transformation of the root node + + @param analyzer the analyzer callback function to be applied to the + nodes of the tree of the object + @param[in,out] arg_p parameter to be passed to the analyzer + @param transformer the transformer callback function to be applied to the + nodes of the tree of the object + @param arg_t parameter to be passed to the transformer + + @return + Item returned as the result of transformation of the root node */ Item *Item_cond::compile(Item_analyzer analyzer, uchar **arg_p, @@ -3923,23 +3924,21 @@ void Item_cond::traverse_cond(Cond_traverser traverser, } } -/* - Move SUM items out from item tree and replace with reference +/** + Move SUM items out from item tree and replace with reference. - SYNOPSIS - split_sum_func() - thd Thread handler - ref_pointer_array Pointer to array of reference fields - fields All fields in select + The split is done to get an unique item for each SUM function + so that we can easily find and calculate them. + (Calculation done by update_sum_func() and copy_sum_funcs() in + sql_select.cc) - NOTES - This function is run on all expression (SELECT list, WHERE, HAVING etc) - that have or refer (HAVING) to a SUM expression. + @param thd Thread handler + @param ref_pointer_array Pointer to array of reference fields + @param fields All fields in select - The split is done to get an unique item for each SUM function - so that we can easily find and calculate them. - (Calculation done by update_sum_func() and copy_sum_funcs() in - sql_select.cc) + @note + This function is run on all expression (SELECT list, WHERE, HAVING etc) + that have or refer (HAVING) to a SUM expression. */ void Item_cond::split_sum_func(THD *thd, Item **ref_pointer_array, @@ -4010,20 +4009,22 @@ void Item_cond::neg_arguments(THD *thd) } -/* - Evaluation of AND(expr, expr, expr ...) +/** + Evaluation of AND(expr, expr, expr ...). - NOTES: + @note abort_if_null is set for AND expressions for which we don't care if the result is NULL or 0. This is set for: - WHERE clause - HAVING clause - IF(expression) - RETURN VALUES + @retval 1 If all expressions are true + @retval 0 If all expressions are false or if we find a NULL expression and - 'abort_on_null' is set. + 'abort_on_null' is set. + @retval NULL if all expression are either 1 or NULL */ @@ -4065,24 +4066,23 @@ longlong Item_cond_or::val_int() return 0; } -/* - Create an AND expression from two expressions +/** + Create an AND expression from two expressions. - SYNOPSIS - and_expressions() - a expression or NULL - b expression. - org_item Don't modify a if a == *org_item - If a == NULL, org_item is set to point at b, - to ensure that future calls will not modify b. + @param a expression or NULL + @param b expression. + @param org_item Don't modify a if a == *org_item. + If a == NULL, org_item is set to point at b, + to ensure that future calls will not modify b. - NOTES + @note This will not modify item pointed to by org_item or b The idea is that one can call this in a loop and create and 'and' over all items without modifying any of the original items. - RETURN + @retval NULL Error + @retval Item */ @@ -4140,7 +4140,9 @@ longlong Item_is_not_null_test::val_int() DBUG_RETURN(1); } -/* Optimize case of not_null_column IS NULL */ +/** + Optimize case of not_null_column IS NULL. +*/ void Item_is_not_null_test::update_used_tables() { if (!args[0]->maybe_null) @@ -4200,7 +4202,9 @@ longlong Item_func_like::val_int() } -/* We can optimize a where if first character isn't a wildcard */ +/** + We can optimize a where if first character isn't a wildcard +*/ Item_func::optimize_type Item_func_like::select_optimize() const { @@ -4463,10 +4467,9 @@ void Item_func_regex::cleanup() #endif -/********************************************************************** - turboBM_compute_suffixes() +/** Precomputation dependent only on pattern_len. -**********************************************************************/ +*/ void Item_func_like::turboBM_compute_suffixes(int *suff) { @@ -4520,10 +4523,9 @@ void Item_func_like::turboBM_compute_suffixes(int *suff) } -/********************************************************************** - turboBM_compute_good_suffix_shifts() - Precomputation dependent only on pattern_len. -**********************************************************************/ +/** + Precomputation dependent only on pattern_len. +*/ void Item_func_like::turboBM_compute_good_suffix_shifts(int *suff) { @@ -4565,10 +4567,9 @@ void Item_func_like::turboBM_compute_good_suffix_shifts(int *suff) } -/********************************************************************** - turboBM_compute_bad_character_shifts() - Precomputation dependent on pattern_len. -**********************************************************************/ +/** + Precomputation dependent on pattern_len. +*/ void Item_func_like::turboBM_compute_bad_character_shifts() { @@ -4594,10 +4595,12 @@ void Item_func_like::turboBM_compute_bad_character_shifts() } -/********************************************************************** - turboBM_matches() - Search for pattern in text, returns true/false for match/no match -**********************************************************************/ +/** + Search for pattern in text. + + @return + returns true/false for match/no match +*/ bool Item_func_like::turboBM_matches(const char* text, int text_len) const { @@ -4677,24 +4680,20 @@ bool Item_func_like::turboBM_matches(const char* text, int text_len) const } -/* +/** Make a logical XOR of the arguments. - SYNOPSIS - val_int() - - DESCRIPTION If either operator is NULL, return NULL. - NOTE - As we don't do any index optimization on XOR this is not going to be - very fast to use. - - TODO (low priority) - Change this to be optimized as: - A XOR B -> (A) == 1 AND (B) <> 1) OR (A <> 1 AND (B) == 1) + @todo + (low priority) Change this to be optimized as: @n + A XOR B -> (A) == 1 AND (B) <> 1) OR (A <> 1 AND (B) == 1) @n To be able to do this, we would however first have to extend the MySQL range optimizer to handle OR better. + + @note + As we don't do any index optimization on XOR this is not going to be + very fast to use. */ longlong Item_cond_xor::val_int() @@ -4716,15 +4715,12 @@ longlong Item_cond_xor::val_int() return (longlong) result; } -/* +/** Apply NOT transformation to the item and return a new one. - SYNOPSIS - neg_transformer() - thd thread handler - DESCRIPTION Transform the item using next rules: + @verbatim a AND b AND ... -> NOT(a) OR NOT(b) OR ... a OR b OR ... -> NOT(a) AND NOT(b) AND ... NOT(a) -> a @@ -4736,8 +4732,11 @@ longlong Item_cond_xor::val_int() a <= b -> a > b IS NULL(a) -> IS NOT NULL(a) IS NOT NULL(a) -> IS NULL(a) + @endverbatim - RETURN + @param thd thread handler + + @return New item or NULL if we cannot apply NOT transformation (see Item::neg_transformer()). */ @@ -4755,7 +4754,9 @@ Item *Item_bool_rowready_func2::neg_transformer(THD *thd) } -/* a IS NULL -> a IS NOT NULL */ +/** + a IS NULL -> a IS NOT NULL. +*/ Item *Item_func_isnull::neg_transformer(THD *thd) { Item *item= new Item_func_isnotnull(args[0]); @@ -4763,7 +4764,9 @@ Item *Item_func_isnull::neg_transformer(THD *thd) } -/* a IS NOT NULL -> a IS NULL */ +/** + a IS NOT NULL -> a IS NULL. +*/ Item *Item_func_isnotnull::neg_transformer(THD *thd) { Item *item= new Item_func_isnull(args[0]); @@ -4846,7 +4849,9 @@ Item *Item_func_le::negated_item() /* a <= b -> a > b */ return new Item_func_gt(args[0], args[1]); } -// just fake method, should never be called +/** + just fake method, should never be called. +*/ Item *Item_bool_rowready_func2::negated_item() { DBUG_ASSERT(0); @@ -4911,19 +4916,17 @@ uint Item_equal::members() } -/* - Check whether a field is referred in the multiple equality +/** + Check whether a field is referred in the multiple equality. - SYNOPSIS - contains() - field field whose occurrence is to be checked - - DESCRIPTION - The function checks whether field is occurred in the Item_equal object - - RETURN VALUES + The function checks whether field is occurred in the Item_equal object . + + @param field field whose occurrence is to be checked + + @retval 1 if nultiple equality contains a reference to field - 0 otherwise + @retval + 0 otherwise */ bool Item_equal::contains(Field *field) @@ -4939,22 +4942,15 @@ bool Item_equal::contains(Field *field) } -/* - Join members of another Item_equal object +/** + Join members of another Item_equal object. - SYNOPSIS - merge() - item multiple equality whose members are to be joined - - DESCRIPTION The function actually merges two multiple equalities. After this operation the Item_equal object additionally contains the field items of another item of the type Item_equal. If the optional constant items are not equal the cond_false flag is set to 1. - - RETURN VALUES - none + @param item multiple equality whose members are to be joined */ void Item_equal::merge(Item_equal *item) @@ -4974,28 +4970,21 @@ void Item_equal::merge(Item_equal *item) } -/* - Order field items in multiple equality according to a sorting criteria +/** + Order field items in multiple equality according to a sorting criteria. - SYNOPSIS - sort() - cmp function to compare field item - arg context extra parameter for the cmp function - - DESCRIPTION The function perform ordering of the field items in the Item_equal object according to the criteria determined by the cmp callback parameter. If cmp(item_field1,item_field2,arg)<0 than item_field1 must be placed after item_fiel2. - IMPLEMENTATION The function sorts field items by the exchange sort algorithm. The list of field items is looked through and whenever two neighboring members follow in a wrong order they are swapped. This is performed again and again until we get all members in a right order. - - RETURN VALUES - None + + @param cmp function to compare field item + @param arg context extra parameter for the cmp function */ void Item_equal::sort(Item_field_cmpfunc cmp, void *arg) @@ -5030,21 +5019,14 @@ void Item_equal::sort(Item_field_cmpfunc cmp, void *arg) } -/* - Check appearance of new constant items in the multiple equality object +/** + Check appearance of new constant items in the multiple equality object. - SYNOPSIS - update_const() - - DESCRIPTION The function checks appearance of new constant items among the members of multiple equalities. Each new constant item is compared with the designated constant item if there is any in the multiple equality. If there is none the first new constant item becomes designated. - - RETURN VALUES - none */ void Item_equal::update_const() diff --git a/sql/item_create.cc b/sql/item_create.cc index 12b795e79a1..f03b592bcb3 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -13,7 +13,12 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* Functions to create an item. Used by sql_yacc.yy */ +/** + @file + + @brief + Functions to create an item. Used by sql_yac.yy +*/ #include "mysql_priv.h" #include "item_create.h" diff --git a/sql/item_func.cc b/sql/item_func.cc index efc42c1b73f..8ea7d027f58 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -14,7 +14,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* This file defines all numerical functions */ +/** + @file + + @brief + This file defines all numerical functions +*/ #ifdef USE_PRAGMA_IMPLEMENTATION #pragma implementation // gcc: Class implementation @@ -46,7 +51,10 @@ bool check_reserved_words(LEX_STRING *name) } -/* return TRUE if item is a constant */ +/** + @return + TRUE if item is a constant +*/ bool eval_const_cond(COND *cond) @@ -237,25 +245,21 @@ void Item_func::traverse_cond(Cond_traverser traverser, } -/* - Transform an Item_func object with a transformer callback function - - SYNOPSIS - transform() - transformer the transformer callback function to be applied to the nodes - of the tree of the object - argument parameter to be passed to the transformer - - DESCRIPTION +/** + Transform an Item_func object with a transformer callback function. + The function recursively applies the transform method to each argument of the Item_func node. If the call of the method for an argument item returns a new item the old item is substituted for a new one. After this the transformer is applied to the root node of the Item_func object. - - RETURN VALUES - Item returned as the result of transformation of the root node + @param transformer the transformer callback function to be applied to + the nodes of the tree of the object + @param argument parameter to be passed to the transformer + + @return + Item returned as the result of transformation of the root node */ Item *Item_func::transform(Item_transformer transformer, uchar *argument) @@ -285,19 +289,10 @@ Item *Item_func::transform(Item_transformer transformer, uchar *argument) } -/* - Compile Item_func object with a processor and a transformer callback functions - - SYNOPSIS - compile() - analyzer the analyzer callback function to be applied to the nodes - of the tree of the object - arg_p in/out parameter to be passed to the processor - transformer the transformer callback function to be applied to the nodes - of the tree of the object - arg_t parameter to be passed to the transformer - - DESCRIPTION +/** + Compile Item_func object with a processor and a transformer + callback functions. + First the function applies the analyzer to the root node of the Item_func object. Then if the analizer succeeeds (returns TRUE) the function recursively applies the compile method to each argument @@ -306,9 +301,16 @@ Item *Item_func::transform(Item_transformer transformer, uchar *argument) the old item is substituted for a new one. After this the transformer is applied to the root node of the Item_func object. - - RETURN VALUES - Item returned as the result of transformation of the root node + + @param analyzer the analyzer callback function to be applied to the + nodes of the tree of the object + @param[in,out] arg_p parameter to be passed to the processor + @param transformer the transformer callback function to be applied to the + nodes of the tree of the object + @param arg_t parameter to be passed to the transformer + + @return + Item returned as the result of transformation of the root node */ Item *Item_func::compile(Item_analyzer analyzer, uchar **arg_p, @@ -334,7 +336,9 @@ Item *Item_func::compile(Item_analyzer analyzer, uchar **arg_p, return (this->*transformer)(arg_t); } -/* See comments in Item_cmp_func::split_sum_func() */ +/** + See comments in Item_cmp_func::split_sum_func() +*/ void Item_func::split_sum_func(THD *thd, Item **ref_pointer_array, List &fields) @@ -523,12 +527,9 @@ void Item_func_numhybrid::fix_num_length_and_dec() {} -/* +/** Set max_length/decimals of function if function is fixed point and - result length/precision depends on argument ones - - SYNOPSIS - Item_func::count_decimal_length() + result length/precision depends on argument ones. */ void Item_func::count_decimal_length() @@ -548,11 +549,8 @@ void Item_func::count_decimal_length() } -/* - Set max_length of if it is maximum length of its arguments - - SYNOPSIS - Item_func::count_only_length() +/** + Set max_length of if it is maximum length of its arguments. */ void Item_func::count_only_length() @@ -567,12 +565,9 @@ void Item_func::count_only_length() } -/* +/** Set max_length/decimals of function if function is floating point and - result length/precision depends on argument ones - - SYNOPSIS - Item_func::count_real_length() + result length/precision depends on argument ones. */ void Item_func::count_real_length() @@ -655,12 +650,9 @@ bool Item_func_connection_id::fix_fields(THD *thd, Item **ref) } -/* +/** Check arguments here to determine result's type for a numeric function of two arguments. - - SYNOPSIS - Item_num_op::find_num_type() */ void Item_num_op::find_num_type(void) @@ -699,13 +691,10 @@ void Item_num_op::find_num_type(void) } -/* +/** Set result type for a numeric function of one argument (can be also used by a numeric function of many arguments, if the result type depends only on the first argument) - - SYNOPSIS - Item_func_num1::find_num_type() */ void Item_func_num1::find_num_type() @@ -1117,16 +1106,15 @@ longlong Item_func_plus::int_op() } -/* - Calculate plus of two decimail's +/** + Calculate plus of two decimals. - SYNOPSIS - decimal_op() - decimal_value Buffer that can be used to store result + @param decimal_value Buffer that can be used to store result - RETURN - 0 Value was NULL; In this case null_value is set - # Value of operation as a decimal + @retval + 0 Value was NULL; In this case null_value is set + @retval + \# Value of operation as a decimal */ my_decimal *Item_func_plus::decimal_op(my_decimal *decimal_value) @@ -1144,11 +1132,8 @@ my_decimal *Item_func_plus::decimal_op(my_decimal *decimal_value) return 0; } -/* +/** Set precision of results for additive operations (+ and -) - - SYNOPSIS - Item_func_additive_op::result_precision() */ void Item_func_additive_op::result_precision() { @@ -1167,7 +1152,7 @@ void Item_func_additive_op::result_precision() } -/* +/** The following function is here to allow the user to force subtraction of UNSIGNED BIGINT to return negative values. */ @@ -1199,7 +1184,9 @@ longlong Item_func_minus::int_op() } -/* See Item_func_plus::decimal_op for comments */ +/** + See Item_func_plus::decimal_op for comments. +*/ my_decimal *Item_func_minus::decimal_op(my_decimal *decimal_value) { @@ -1238,7 +1225,7 @@ longlong Item_func_mul::int_op() } -/* See Item_func_plus::decimal_op for comments */ +/** See Item_func_plus::decimal_op for comments. */ my_decimal *Item_func_mul::decimal_op(my_decimal *decimal_value) { @@ -1570,7 +1557,7 @@ void Item_func_abs::fix_length_and_dec() } -/* Gateway to natural LOG function */ +/** Gateway to natural LOG function. */ double Item_func_ln::val_real() { DBUG_ASSERT(fixed == 1); @@ -1585,10 +1572,11 @@ double Item_func_ln::val_real() return log(value); } -/* - Extended but so slower LOG function - We have to check if all values are > zero and first one is not one - as these are the cases then result is not a number. +/** + Extended but so slower LOG function. + + We have to check if all values are > zero and first one is not one + as these are the cases then result is not a number. */ double Item_func_log::val_real() { @@ -3014,8 +3002,10 @@ bool udf_handler::get_arguments() return 0; } -/* This returns (String*) 0 in case of NULL values */ - +/** + @return + (String*)NULL in case of NULL values +*/ String *udf_handler::val_str(String *str,String *save_str) { uchar is_null_tmp=0; @@ -3219,10 +3209,11 @@ String *Item_func_udf_str::val_str(String *str) } -/* - This has to come last in the udf_handler methods, or C for AIX - version 6.0.0.0 fails to compile with debugging enabled. (Yes, really.) - */ +/** + @note + This has to come last in the udf_handler methods, or C for AIX + version 6.0.0.0 fails to compile with debugging enabled. (Yes, really.) +*/ udf_handler::~udf_handler() { @@ -3320,10 +3311,10 @@ void item_user_lock_release(User_level_lock *ull) delete ull; } -/* - Wait until we are at or past the given position in the master binlog - on the slave - */ +/** + Wait until we are at or past the given position in the master binlog + on the slave. +*/ longlong Item_master_pos_wait::val_int() { @@ -3425,11 +3416,15 @@ void debug_sync_point(const char* lock_name, uint lock_timeout) #endif -/* - Get a user level lock. If the thread has an old lock this is first released. - Returns 1: Got lock - Returns 0: Timeout - Returns NULL: Error +/** + Get a user level lock. If the thread has an old lock this is first released. + + @retval + 1 : Got lock + @retval + 0 : Timeout + @retval + NULL : Error */ longlong Item_func_get_lock::val_int() @@ -3549,12 +3544,12 @@ longlong Item_func_get_lock::val_int() } -/* +/** Release a user level lock. - Return: - 1 if lock released - 0 if lock wasn't held - (SQL) NULL if no such lock + @return + - 1 if lock released + - 0 if lock wasn't held + - (SQL) NULL if no such lock */ longlong Item_func_release_lock::val_int() @@ -3679,7 +3674,7 @@ void Item_func_benchmark::print(String *str) } -/* This function is just used to create tests with time gaps */ +/** This function is just used to create tests with time gaps. */ longlong Item_func_sleep::val_int() { @@ -3835,22 +3830,22 @@ bool Item_func_set_user_var::register_field_in_read_map(uchar *arg) } -/* +/** Set value to user variable. - SYNOPSYS - update_hash() - entry - pointer to structure representing variable - set_null - should we set NULL value ? - ptr - pointer to buffer with new value - length - length of new value - type - type of new value - cs - charset info for new value - dv - derivation for new value - unsigned_arg - indiates if a value of type INT_RESULT is unsigned + @param entry pointer to structure representing variable + @param set_null should we set NULL value ? + @param ptr pointer to buffer with new value + @param length length of new value + @param type type of new value + @param cs charset info for new value + @param dv derivation for new value + @param unsigned_arg indiates if a value of type INT_RESULT is unsigned - RETURN VALUE - False - success, True - failure + @retval + false success + @retval + true failure */ static bool @@ -3935,7 +3930,7 @@ Item_func_set_user_var::update_hash(void *ptr, uint length, } -/* Get the value of a variable as a double */ +/** Get the value of a variable as a double. */ double user_var_entry::val_real(my_bool *null_value) { @@ -3963,7 +3958,7 @@ double user_var_entry::val_real(my_bool *null_value) } -/* Get the value of a variable as an integer */ +/** Get the value of a variable as an integer. */ longlong user_var_entry::val_int(my_bool *null_value) { @@ -3994,7 +3989,7 @@ longlong user_var_entry::val_int(my_bool *null_value) } -/* Get the value of a variable as a string */ +/** Get the value of a variable as a string. */ String *user_var_entry::val_str(my_bool *null_value, String *str, uint decimals) @@ -4025,7 +4020,7 @@ String *user_var_entry::val_str(my_bool *null_value, String *str, return(str); } -/* Get the value of a variable as a decimal */ +/** Get the value of a variable as a decimal. */ my_decimal *user_var_entry::val_decimal(my_bool *null_value, my_decimal *val) { @@ -4052,18 +4047,17 @@ my_decimal *user_var_entry::val_decimal(my_bool *null_value, my_decimal *val) return(val); } -/* - This functions is invoked on SET @variable or @variable:= expression. +/** + This functions is invoked on SET \@variable or + \@variable:= expression. + Evaluate (and check expression), store results. - SYNOPSYS - Item_func_set_user_var::check() - - NOTES + @note For now it always return OK. All problem with value evaluating will be caught by thd->net.report_error check in sql_set_variables(). - RETURN + @retval FALSE OK. */ @@ -4112,18 +4106,17 @@ Item_func_set_user_var::check(bool use_result_field) } -/* - This functions is invoked on SET @variable or @variable:= expression. +/** + This functions is invoked on + SET \@variable or \@variable:= expression. - SYNOPSIS - Item_func_set_user_var::update() - - NOTES + @note We have to store the expression as such in the variable, independent of the value method used by the user - RETURN + @retval 0 OK + @retval 1 EOM Error */ @@ -4432,24 +4425,23 @@ longlong Item_func_get_user_var::val_int() } -/* +/** Get variable by name and, if necessary, put the record of variable use into the binary log. - - SYNOPSIS - get_var_with_binlog() - thd Current thread - name Variable name - out_entry [out] variable structure or NULL. The pointer is set - regardless of whether function succeeded or not. When a user variable is invoked from an update query (INSERT, UPDATE etc), stores this variable and its value in thd->user_var_events, so that it can be written to the binlog (will be written just before the query is written, see log.cc). - RETURN + @param thd Current thread + @param name Variable name + @param[out] out_entry variable structure or NULL. The pointer is set + regardless of whether function succeeded or not. + + @retval 0 OK + @retval 1 Failed to put appropriate record into binary log */ @@ -5104,22 +5096,20 @@ longlong Item_func_bit_xor::val_int() System variables ****************************************************************************/ -/* - Return value of an system variable base[.name] as a constant item +/** + Return value of an system variable base[.name] as a constant item. - SYNOPSIS - get_system_var() - thd Thread handler - var_type global / session - name Name of base or system variable - component Component + @param thd Thread handler + @param var_type global / session + @param name Name of base or system variable + @param component Component. - NOTES + @note If component.str = 0 then the variable name is in 'name' - RETURN - 0 error - # constant item + @return + - 0 : error + - # : constant item */ @@ -5159,16 +5149,15 @@ Item *get_system_var(THD *thd, enum_var_type var_type, LEX_STRING name, } -/* +/** Check a user level lock. - SYNOPSIS: - val_int() + Sets null_value=TRUE on error. - RETURN VALUES + @retval 1 Available - 0 Already taken - NULL Error + @retval + 0 Already taken, or error */ longlong Item_func_is_free_lock::val_int() diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index 78741483c0b..c4e36da80a3 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -14,7 +14,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* This file defines all spatial functions */ +/** + @file + + @brief + This file defines all spatial functions +*/ #ifdef USE_PRAGMA_IMPLEMENTATION #pragma implementation // gcc: Class implementation @@ -360,7 +365,7 @@ String *Item_func_point::val_str(String *str) } -/* +/** Concatenates various items into various collections with checkings for valid wkb type of items. For example, MultiPoint can be a collection of Points only. @@ -542,6 +547,10 @@ longlong Item_func_isempty::val_int() } +/** + @todo + Ramil or Holyfoot, add real IsSimple calculation +*/ longlong Item_func_issimple::val_int() { DBUG_ASSERT(fixed == 1); diff --git a/sql/item_row.cc b/sql/item_row.cc index d1d1011ab2b..369aa04930e 100644 --- a/sql/item_row.cc +++ b/sql/item_row.cc @@ -15,13 +15,18 @@ #include "mysql_priv.h" -/* +/** Row items used for comparing rows and IN operations on rows: + @verbatim (a, b, c) > (10, 10, 30) (a, b, c) = (select c, d, e, from t1 where x=12) (a, b, c) IN ((1,2,2), (3,4,5), (6,7,8) (a, b, c) IN (select c, d, e, from t1) + @endverbatim + + @todo + think placing 2-3 component items in item (as it done for function */ Item_row::Item_row(List &arg): diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index d1c8e7a37e8..fc50f6280d6 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -14,9 +14,15 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* This file defines all string functions -** Warning: Some string functions doesn't always put and end-null on a String -** (This shouldn't be needed) +/** + @file + + @brief + This file defines all string functions + + @warning + Some string functions don't always put and end-null on a String. + (This shouldn't be needed) */ #ifdef USE_PRAGMA_IMPLEMENTATION @@ -297,9 +303,9 @@ void Item_func_aes_decrypt::fix_length_and_dec() } -/* +/** Concatenate args with the following premises: - If only one arg (which is ok), return value of arg + If only one arg (which is ok), return value of arg; Don't reallocate val_str() if not absolute necessary. */ @@ -430,13 +436,15 @@ void Item_func_concat::fix_length_and_dec() max_length= (ulong) max_result_length; } -/* +/** + @details Function des_encrypt() by tonu@spam.ee & monty Works only if compiled with OpenSSL library support. - This returns a binary string where first character is CHAR(128 | key-number). - If one uses a string key key_number is 127. - Encryption result is longer than original by formula: - new_length= org_length + (8-(org_length % 8))+1 + @return + A binary string where first character is CHAR(128 | key-number). + If one uses a string key key_number is 127. + Encryption result is longer than original by formula: + @code new_length= org_length + (8-(org_length % 8))+1 @endcode */ String *Item_func_des_encrypt::val_str(String *str) @@ -609,7 +617,7 @@ wrong_key: } -/* +/** concat with separator. First arg is the separator concat_ws takes at least two arguments. */ @@ -806,12 +814,14 @@ void Item_func_reverse::fix_length_and_dec() max_length = args[0]->max_length; } -/* -** Replace all occurences of string2 in string1 with string3. -** Don't reallocate val_str() if not needed -*/ +/** + Replace all occurences of string2 in string1 with string3. -/* TODO: Fix that this works with binary strings when using USE_MB */ + Don't reallocate val_str() if not needed. + + @todo + Fix that this works with binary strings when using USE_MB +*/ String *Item_func_replace::val_str(String *str) { @@ -1776,8 +1786,9 @@ String *Item_func_database::val_str(String *str) } -/* - TODO: make USER() replicate properly (currently it is replicated to "") +/** + @todo + make USER() replicate properly (currently it is replicated to "") */ bool Item_func_user::init(const char *user, const char *host) { @@ -1837,7 +1848,7 @@ void Item_func_soundex::fix_length_and_dec() } -/* +/** If alpha, map input letter to soundex code. If not alpha and remove_garbage is set then skip to next char else return 0 @@ -1981,9 +1992,10 @@ String *Item_func_soundex::val_str(String *str) } -/* -** Change a number to format '3,333,333,333.000' -** This should be 'internationalized' sometimes. +/** + Change a number to format '3,333,333,333.000'. + + This should be 'internationalized' sometimes. */ const int FORMAT_MAX_DECIMALS= 30; @@ -2002,8 +2014,9 @@ void Item_func_format::fix_length_and_dec() } -/* - TODO: This needs to be fixed for multi-byte character set where numbers +/** + @todo + This needs to be fixed for multi-byte character set where numbers are stored in more than one byte */ @@ -2349,9 +2362,9 @@ void Item_func_repeat::fix_length_and_dec() } } -/* -** Item_func_repeat::str is carefully written to avoid reallocs -** as much as possible at the cost of a local buffer +/** + Item_func_repeat::str is carefully written to avoid reallocs + as much as possible at the cost of a local buffer */ String *Item_func_repeat::val_str(String *str) @@ -2827,7 +2840,7 @@ String *Item_func_hex::val_str(String *str) return &tmp_value; } - /* Convert given hex string to a binary string */ + /** Convert given hex string to a binary string. */ String *Item_func_unhex::val_str(String *str) { @@ -3060,27 +3073,27 @@ String* Item_func_inet_ntoa::val_str(String* str) } -/* +#define get_esc_bit(mask, num) (1 & (*((mask) + ((num) >> 3))) >> ((num) & 7)) + +/** QUOTE() function returns argument string in single quotes suitable for using in a SQL statement. - DESCRIPTION - Adds a \ before all characters that needs to be escaped in a SQL string. - We also escape '^Z' (END-OF-FILE in windows) to avoid probelms when - running commands from a file in windows. + Adds a \\ before all characters that needs to be escaped in a SQL string. + We also escape '^Z' (END-OF-FILE in windows) to avoid probelms when + running commands from a file in windows. - This function is very useful when you want to generate SQL statements + This function is very useful when you want to generate SQL statements. - NOTE + @note QUOTE(NULL) returns the string 'NULL' (4 letters, without quotes). - RETURN VALUES - str Quoted string - NULL Out of memory. + @retval + str Quoted string + @retval + NULL Out of memory. */ -#define get_esc_bit(mask, num) (1 & (*((mask) + ((num) >> 3))) >> ((num) & 7)) - String *Item_func_quote::val_str(String *str) { DBUG_ASSERT(fixed == 1); @@ -3326,8 +3339,10 @@ static uint nanoseq; static ulonglong uuid_time=0; static char clock_seq_and_node_str[]="-0000-000000000000"; -/* number of 100-nanosecond intervals between - 1582-10-15 00:00:00.00 and 1970-01-01 00:00:00.00 */ +/** + number of 100-nanosecond intervals between + 1582-10-15 00:00:00.00 and 1970-01-01 00:00:00.00. +*/ #define UUID_TIME_OFFSET ((ulonglong) 141427 * 24 * 60 * 60 * 1000 * 10 ) #define UUID_VERSION 0x1000 diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 843c6ced263..760c991198a 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -13,12 +13,15 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* - subselect Item +/** + @file -SUBSELECT TODO: - - add function from mysql_select that use JOIN* as parameter to JOIN methods - (sql_select.h/sql_select.cc) + @brief + subselect Item + + @todo + - add function from mysql_select that use JOIN* as parameter to JOIN + methods (sql_select.h/sql_select.cc) */ #ifdef USE_PRAGMA_IMPLEMENTATION @@ -403,6 +406,16 @@ void Item_singlerow_subselect::reset() } +/** + @todo + - We cant change name of Item_field or Item_ref, because it will + prevent it's correct resolving, but we should save name of + removed item => we do not make optimization if top item of + list is field or reference. + - switch off this optimization for prepare statement, + because we do not rollback this changes. + Make rollback for it, or special name resolving mode in 5.0. +*/ Item_subselect::trans_res Item_singlerow_subselect::select_transformer(JOIN *join) { @@ -1445,24 +1458,24 @@ Item_in_subselect::select_transformer(JOIN *join) } -/* +/** Prepare IN/ALL/ANY/SOME subquery transformation and call appropriate - transformation function + transformation function. - SYNOPSIS - Item_in_subselect::select_in_like_transformer() - join JOIN object of transforming subquery - func creator of condition function of subquery - - DESCRIPTION To decide which transformation procedure (scalar or row) applicable here we have to call fix_fields() for left expression to be able to call cols() method on it. Also this method make arena management for underlying transformation methods. - RETURN + @param join JOIN object of transforming subquery + @param func creator of condition function of subquery + + @retval RES_OK OK - RES_REDUCE OK, and current subquery was reduced during transformation + @retval + RES_REDUCE OK, and current subquery was reduced during + transformation + @retval RES_ERROR Error */ @@ -2412,16 +2425,15 @@ void subselect_indexsubquery_engine::print(String *str) str->append(')'); } -/* - change select_result object of engine +/** + change select_result object of engine. - SYNOPSIS - subselect_single_select_engine::change_result() - si new subselect Item - res new select_result object + @param si new subselect Item + @param res new select_result object - RETURN + @retval FALSE OK + @retval TRUE error */ @@ -2434,16 +2446,15 @@ bool subselect_single_select_engine::change_result(Item_subselect *si, } -/* - change select_result object of engine +/** + change select_result object of engine. - SYNOPSIS - subselect_single_select_engine::change_result() - si new subselect Item - res new select_result object + @param si new subselect Item + @param res new select_result object - RETURN + @retval FALSE OK + @retval TRUE error */ @@ -2457,16 +2468,15 @@ bool subselect_union_engine::change_result(Item_subselect *si, } -/* - change select_result emulation, never should be called +/** + change select_result emulation, never should be called. - SYNOPSIS - subselect_single_select_engine::change_result() - si new subselect Item - res new select_result object + @param si new subselect Item + @param res new select_result object - RETURN + @retval FALSE OK + @retval TRUE error */ @@ -2478,14 +2488,12 @@ bool subselect_uniquesubquery_engine::change_result(Item_subselect *si, } -/* - Report about presence of tables in subquery +/** + Report about presence of tables in subquery. - SYNOPSIS - subselect_single_select_engine::no_tables() - - RETURN + @retval TRUE there are not tables used in subquery + @retval FALSE there are some tables in subquery */ bool subselect_single_select_engine::no_tables() @@ -2510,14 +2518,12 @@ bool subselect_single_select_engine::may_be_null() } -/* - Report about presence of tables in subquery +/** + Report about presence of tables in subquery. - SYNOPSIS - subselect_union_engine::no_tables() - - RETURN + @retval TRUE there are not tables used in subquery + @retval FALSE there are some tables in subquery */ bool subselect_union_engine::no_tables() @@ -2531,14 +2537,12 @@ bool subselect_union_engine::no_tables() } -/* - Report about presence of tables in subquery +/** + Report about presence of tables in subquery. - SYNOPSIS - subselect_uniquesubquery_engine::no_tables() - - RETURN + @retval TRUE there are not tables used in subquery + @retval FALSE there are some tables in subquery */ diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 2684cce16ac..b3be4d6f22a 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -14,7 +14,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* Sum functions (COUNT, MIN...) */ +/** + @file + + @brief + Sum functions (COUNT, MIN...) +*/ #ifdef USE_PRAGMA_IMPLEMENTATION #pragma implementation // gcc: Class implementation @@ -23,28 +28,25 @@ #include "mysql_priv.h" #include "sql_select.h" -/* - Prepare an aggregate function item for checking context conditions +/** + Prepare an aggregate function item for checking context conditions. - SYNOPSIS - init_sum_func_check() - thd reference to the thread context info - - DESCRIPTION The function initializes the members of the Item_sum object created for a set function that are used to check validity of the set function occurrence. If the set function is not allowed in any subquery where it occurs an error is reported immediately. - NOTES + @param thd reference to the thread context info + + @note This function is to be called for any item created for a set function object when the traversal of trees built for expressions used in the query is performed at the phase of context analysis. This function is to be invoked at the descent of this traversal. - - RETURN - TRUE if an error is reported + @retval + TRUE if an error is reported + @retval FALSE otherwise */ @@ -69,15 +71,9 @@ bool Item_sum::init_sum_func_check(THD *thd) return FALSE; } -/* - Check constraints imposed on a usage of a set function +/** + Check constraints imposed on a usage of a set function. - SYNOPSIS - check_sum_func() - thd reference to the thread context info - ref location of the pointer to this item in the embedding expression - - DESCRIPTION The method verifies whether context conditions imposed on a usage of any set function are met for this occurrence. It checks whether the set function occurs in the position where it @@ -89,13 +85,6 @@ bool Item_sum::init_sum_func_check(THD *thd) adds it to the chain of items for such set functions that is attached to the the st_select_lex structure for this subquery. - NOTES - This function is to be called for any item created for a set function - object when the traversal of trees built for expressions used in the query - is performed at the phase of context analysis. This function is to - be invoked at the ascent of this traversal. - - IMPLEMENTATION A number of designated members of the object are used to check the conditions. They are specified in the comment before the Item_sum class declaration. @@ -106,16 +95,28 @@ bool Item_sum::init_sum_func_check(THD *thd) of set functions are allowed (i.e either in the SELECT list or in the HAVING clause of the corresponding subquery) Consider the query: - SELECT SUM(t1.b) FROM t1 GROUP BY t1.a - HAVING t1.a IN (SELECT t2.c FROM t2 WHERE AVG(t1.b) > 20) AND - t1.a > (SELECT MIN(t2.d) FROM t2); + @code + SELECT SUM(t1.b) FROM t1 GROUP BY t1.a + HAVING t1.a IN (SELECT t2.c FROM t2 WHERE AVG(t1.b) > 20) AND + t1.a > (SELECT MIN(t2.d) FROM t2); + @endcode allow_sum_func will contain: - for SUM(t1.b) - 1 at the first position - for AVG(t1.b) - 1 at the first position, 0 at the second position - for MIN(t2.d) - 1 at the first position, 1 at the second position. + - for SUM(t1.b) - 1 at the first position + - for AVG(t1.b) - 1 at the first position, 0 at the second position + - for MIN(t2.d) - 1 at the first position, 1 at the second position. - RETURN - TRUE if an error is reported + @param thd reference to the thread context info + @param ref location of the pointer to this item in the embedding expression + + @note + This function is to be called for any item created for a set function + object when the traversal of trees built for expressions used in the query + is performed at the phase of context analysis. This function is to + be invoked at the ascent of this traversal. + + @retval + TRUE if an error is reported + @retval FALSE otherwise */ @@ -200,15 +201,9 @@ bool Item_sum::check_sum_func(THD *thd, Item **ref) return FALSE; } -/* - Attach a set function to the subquery where it must be aggregated +/** + Attach a set function to the subquery where it must be aggregated. - SYNOPSIS - register_sum_func() - thd reference to the thread context info - ref location of the pointer to this item in the embedding expression - - DESCRIPTION The function looks for an outer subquery where the set function must be aggregated. If it finds such a subquery then aggr_level is set to the nest level of this subquery and the item for the set function @@ -216,14 +211,18 @@ bool Item_sum::check_sum_func(THD *thd, Item **ref) inner_sum_func_list defined for each subquery. When the item is placed there the field 'ref_by' is set to ref. - NOTES. + @note Now we 'register' only set functions that are aggregated in outer subqueries. Actually it makes sense to link all set function for a subquery in one chain. It would simplify the process of 'splitting' for set functions. - RETURN + @param thd reference to the thread context info + @param ref location of the pointer to this item in the embedding expression + + @retval FALSE if the executes without failures (currently always) + @retval TRUE otherwise */ @@ -311,8 +310,8 @@ Item_sum::Item_sum(List &list) :arg_count(list.elements), } -/* - Constructor used in processing select with temporary tebles +/** + Constructor used in processing select with temporary tebles. */ Item_sum::Item_sum(THD *thd, Item_sum *item): @@ -655,6 +654,10 @@ Field *Item_sum_hybrid::create_tmp_field(bool group, TABLE *table, ** reset and add of sum_func ***********************************************************************/ +/** + @todo + check if the following assignments are really needed +*/ Item_sum_sum::Item_sum_sum(THD *thd, Item_sum_sum *item) :Item_sum_num(thd, item), hybrid_type(item->hybrid_type), curr_dec_buff(item->curr_dec_buff) @@ -833,7 +836,7 @@ Item_sum_distinct::Item_sum_distinct(THD *thd, Item_sum_distinct *original) } -/* +/** Behaves like an Integer except to fix_length_and_dec(). Additionally div() converts val with this traits to a val with true decimal traits along with conversion of integer value to decimal value. @@ -910,6 +913,10 @@ void Item_sum_distinct::fix_length_and_dec() } +/** + @todo + check that the case of CHAR(0) works OK +*/ bool Item_sum_distinct::setup(THD *thd) { List field_list; @@ -2002,8 +2009,8 @@ void Item_sum_bit::update_field() } -/* -** calc next value and merge it with field_value +/** + calc next value and merge it with field_value. */ void Item_sum_sum::update_field() @@ -2179,6 +2186,10 @@ Item_sum_hybrid::min_max_update_int_field() } +/** + @todo + optimize: do not get result_field in case of args[0] is NULL +*/ void Item_sum_hybrid::min_max_update_decimal_field() { @@ -2367,7 +2378,7 @@ int simple_str_key_cmp(void* arg, uchar* key1, uchar* key2) return f->cmp(key1, key2); } -/* +/** Did not make this one static - at least gcc gets confused when I try to declare a static function as a friend. If you can figure out the syntax to make a static function a friend, make this one @@ -2434,7 +2445,10 @@ void Item_sum_count_distinct::cleanup() } -/* This is used by rollup to create a separate usable copy of the function */ +/** + This is used by rollup to create a separate usable copy of + the function. +*/ void Item_sum_count_distinct::make_unique() { @@ -2801,7 +2815,7 @@ my_decimal *Item_sum_udf_int::val_decimal(my_decimal *dec) } -/* Default max_length is max argument length */ +/** Default max_length is max argument length. */ void Item_sum_udf_str::fix_length_and_dec() { @@ -2851,9 +2865,8 @@ String *Item_sum_udf_str::val_str(String *str) Blobs doesn't work with DISTINCT or ORDER BY *****************************************************************************/ -/* - function of sort for syntax: - GROUP_CONCAT(DISTINCT expr,...) +/** + function of sort for syntax: GROUP_CONCAT(DISTINCT expr,...) */ int group_concat_key_cmp_with_distinct(void* arg, uchar* key1, @@ -2890,9 +2903,8 @@ int group_concat_key_cmp_with_distinct(void* arg, uchar* key1, } -/* - function of sort for syntax: - GROUP_CONCAT(expr,... ORDER BY col,... ) +/** + function of sort for syntax: GROUP_CONCAT(expr,... ORDER BY col,... ) */ int group_concat_key_cmp_with_order(void* arg, uchar* key1, uchar* key2) @@ -2934,11 +2946,11 @@ int group_concat_key_cmp_with_order(void* arg, uchar* key1, uchar* key2) } -/* +/** function of sort for syntax: - GROUP_CONCAT(DISTINCT expr,... ORDER BY col,... ) + GROUP_CONCAT(DISTINCT expr,... ORDER BY col,... ). - BUG: + @bug This doesn't work in the case when the order by contains data that is not part of the field list because tree-insert will not notice the duplicated values when inserting things sorted by ORDER BY @@ -2953,8 +2965,8 @@ int group_concat_key_cmp_with_distinct_and_order(void* arg,uchar* key1, } -/* - Append data from current leaf to item->result +/** + Append data from current leaf to item->result. */ int dump_leaf_key(uchar* key, element_count count __attribute__((unused)), @@ -3025,12 +3037,13 @@ int dump_leaf_key(uchar* key, element_count count __attribute__((unused)), } -/* - Constructor of Item_func_group_concat - distinct_arg - distinct - select_list - list of expression for show values - order_list - list of sort columns - separator_arg - string value of separator +/** + Constructor of Item_func_group_concat. + + @param distinct_arg distinct + @param select_list list of expression for show values + @param order_list list of sort columns + @param separator_arg string value of separator. */ Item_func_group_concat:: diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 300d0788f55..79e23191efa 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -14,7 +14,15 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* This file defines all time functions */ +/** + @file + + @brief + This file defines all time functions + + @todo + Move month and days to language files +*/ #ifdef USE_PRAGMA_IMPLEMENTATION #pragma implementation // gcc: Class implementation @@ -24,17 +32,16 @@ #include #include -/* TODO: Move month and days to language files */ - -/* Day number for Dec 31st, 9999 */ +/** Day number for Dec 31st, 9999. */ #define MAX_DAY_NUMBER 3652424L -/* - OPTIMIZATION TODO: - - Replace the switch with a function that should be called for each - date type. - - Remove sprintf and opencode the conversion, like we do in - Field_datetime. +/** + @todo + OPTIMIZATION + - Replace the switch with a function that should be called for each + date type. + - Remove sprintf and opencode the conversion, like we do in + Field_datetime. The reason for this functions existence is that as we don't have a way to know if a datetime/time value has microseconds in them @@ -226,37 +233,37 @@ static DATE_TIME_FORMAT time_ampm_format= {{0}, '\0', 0, static DATE_TIME_FORMAT time_24hrs_format= {{0}, '\0', 0, {(char *)"%H:%i:%S", 8}}; -/* +/** Extract datetime value to MYSQL_TIME struct from string value - according to format string. + according to format string. - SYNOPSIS - extract_date_time() - format date/time format specification - val String to decode - length Length of string - l_time Store result here - cached_timestamp_type - It uses to get an appropriate warning - in the case when the value is truncated. - sub_pattern_end if non-zero then we are parsing string which - should correspond compound specifier (like %T or - %r) and this parameter is pointer to place where - pointer to end of string matching this specifier - should be stored. - NOTE - Possibility to parse strings matching to patterns equivalent to compound - specifiers is mainly intended for use from inside of this function in - order to understand %T and %r conversion specifiers, so number of - conversion specifiers that can be used in such sub-patterns is limited. - Also most of checks are skipped in this case. + @param format date/time format specification + @param val String to decode + @param length Length of string + @param l_time Store result here + @param cached_timestamp_type It uses to get an appropriate warning + in the case when the value is truncated. + @param sub_pattern_end if non-zero then we are parsing string which + should correspond compound specifier (like %T or + %r) and this parameter is pointer to place where + pointer to end of string matching this specifier + should be stored. - If one adds new format specifiers to this function he should also - consider adding them to get_date_time_result_type() function. + @note + Possibility to parse strings matching to patterns equivalent to compound + specifiers is mainly intended for use from inside of this function in + order to understand %T and %r conversion specifiers, so number of + conversion specifiers that can be used in such sub-patterns is limited. + Also most of checks are skipped in this case. - RETURN - 0 ok - 1 error + @note + If one adds new format specifiers to this function he should also + consider adding them to get_date_time_result_type() function. + + @retval + 0 ok + @retval + 1 error */ static bool extract_date_time(DATE_TIME_FORMAT *format, @@ -603,8 +610,8 @@ err: } -/* - Create a formated date/time value in a string +/** + Create a formated date/time value in a string. */ bool make_date_time(DATE_TIME_FORMAT *format, MYSQL_TIME *l_time, @@ -838,7 +845,8 @@ bool make_date_time(DATE_TIME_FORMAT *format, MYSQL_TIME *l_time, } -/* +/** + @details Get a array of positive numbers from a string object. Each number is separated by 1 non digit character Return error if there is too many numbers. @@ -846,16 +854,14 @@ bool make_date_time(DATE_TIME_FORMAT *format, MYSQL_TIME *l_time, from the high end. This allows one to give: DAY_TO_SECOND as "D MM:HH:SS", "MM:HH:SS" "HH:SS" or as seconds. - SYNOPSIS - str: string value - length: length of str - cs: charset of str - values: array of results - count: count of elements in result array - transform_msec: if value is true we suppose - that the last part of string value is microseconds - and we should transform value to six digit value. - For example, '1.1' -> '1.100000' + @param length: length of str + @param cs: charset of str + @param values: array of results + @param count: count of elements in result array + @param transform_msec: if value is true we suppose + that the last part of string value is microseconds + and we should transform value to six digit value. + For example, '1.1' -> '1.100000' */ static bool get_interval_info(const char *str,uint length,CHARSET_INFO *cs, @@ -1046,7 +1052,9 @@ String* Item_func_monthname::val_str(String* str) } -// Returns the quarter of the year +/** + Returns the quarter of the year. +*/ longlong Item_func_quarter::val_int() { @@ -1072,8 +1080,10 @@ longlong Item_func_minute::val_int() (void) get_arg0_time(<ime); return ltime.minute; } -// Returns the second in time_exp in the range of 0 - 59 +/** + Returns the second in time_exp in the range of 0 - 59. +*/ longlong Item_func_second::val_int() { DBUG_ASSERT(fixed == 1); @@ -1091,7 +1101,8 @@ uint week_mode(uint mode) return week_format; } -/* +/** + @verbatim The bits in week_format(for calc_week() function) has the following meaning: WEEK_MONDAY_FIRST (0) If not set Sunday is first day of week If set Monday is first day of week @@ -1118,6 +1129,7 @@ uint week_mode(uint mode) four or more days in the new year, then it is week 1; Otherwise it is the last week of the previous year, and the next week is week 1. + @endverbatim */ longlong Item_func_week::val_int() @@ -1281,8 +1293,9 @@ longlong Item_func_time_to_sec::val_int() } -/* - Convert a string to a interval value +/** + Convert a string to a interval value. + To make code easy, allow interval objects without separators. */ @@ -1506,7 +1519,7 @@ String *Item_func_curdate::val_str(String *str) return str; } -/* +/** Converts current time in my_time_t to MYSQL_TIME represenatation for local time zone. Defines time zone (local) used for whole CURDATE function. */ @@ -1519,7 +1532,7 @@ void Item_func_curdate_local::store_now_in_TIME(MYSQL_TIME *now_time) } -/* +/** Converts current time in my_time_t to MYSQL_TIME represenatation for UTC time zone. Defines time zone (UTC) used for whole UTC_DATE function. */ @@ -1563,7 +1576,7 @@ void Item_func_curtime::fix_length_and_dec() } -/* +/** Converts current time in my_time_t to MYSQL_TIME represenatation for local time zone. Defines time zone (local) used for whole CURTIME function. */ @@ -1576,7 +1589,7 @@ void Item_func_curtime_local::store_now_in_TIME(MYSQL_TIME *now_time) } -/* +/** Converts current time in my_time_t to MYSQL_TIME represenatation for UTC time zone. Defines time zone (UTC) used for whole UTC_TIME function. */ @@ -1612,7 +1625,7 @@ void Item_func_now::fix_length_and_dec() } -/* +/** Converts current time in my_time_t to MYSQL_TIME represenatation for local time zone. Defines time zone (local) used for whole NOW function. */ @@ -1625,7 +1638,7 @@ void Item_func_now_local::store_now_in_TIME(MYSQL_TIME *now_time) } -/* +/** Converts current time in my_time_t to MYSQL_TIME represenatation for UTC time zone. Defines time zone (UTC) used for whole UTC_TIMESTAMP function. */ @@ -1656,7 +1669,7 @@ int Item_func_now::save_in_field(Field *to, bool no_conversions) } -/* +/** Converts current time in my_time_t to MYSQL_TIME represenatation for local time zone. Defines time zone (local) used for whole SYSDATE function. */ @@ -2612,7 +2625,7 @@ longlong Item_date_typecast::val_int() return (longlong) (ltime.year * 10000L + ltime.month * 100 + ltime.day); } -/* +/** MAKEDATE(a,b) is a date function that creates a date value from a year and day value. @@ -2722,7 +2735,7 @@ void Item_func_add_time::fix_length_and_dec() cached_field_type= MYSQL_TYPE_TIME; } -/* +/** ADDTIME(t,a) and SUBTIME(t,a) are time functions that calculate a time/datetime value @@ -2824,7 +2837,7 @@ void Item_func_add_time::print(String *str) } -/* +/** TIMEDIFF(t,s) is a time function that calculates the time value between a start and end time. @@ -2874,7 +2887,7 @@ null_date: return 0; } -/* +/** MAKETIME(h,m,s) is a time function that calculates a time value from the total number of hours, minutes, and seconds. Result: Time value @@ -2941,7 +2954,7 @@ String *Item_func_maketime::val_str(String *str) } -/* +/** MICROSECOND(a) is a function ( extraction) that extracts the microseconds from a. @@ -3167,25 +3180,28 @@ void Item_func_get_format::print(String *str) } -/* +/** Get type of datetime value (DATE/TIME/...) which will be produced according to format string. - SYNOPSIS - get_date_time_result_type() - format - format string - length - length of format string + @param format format string + @param length length of format string - NOTE + @note We don't process day format's characters('D', 'd', 'e') because day may be a member of all date/time types. + @note Format specifiers supported by this function should be in sync with specifiers supported by extract_date_time() function. - RETURN VALUE + @return One of date_time_format_types values: - DATE_TIME_MICROSECOND, DATE_TIME, DATE_ONLY, TIME_MICROSECOND, TIME_ONLY + - DATE_TIME_MICROSECOND + - DATE_TIME + - DATE_ONLY + - TIME_MICROSECOND + - TIME_ONLY */ static date_time_format_types diff --git a/sql/key.cc b/sql/key.cc index e8354ed2635..95402d213cd 100644 --- a/sql/key.cc +++ b/sql/key.cc @@ -90,25 +90,19 @@ int find_ref_key(KEY *key, uint key_count, uchar *record, Field *field, } -/* +/** Copy part of a record that forms a key or key prefix to a buffer. - SYNOPSIS - key_copy() - to_key buffer that will be used as a key - from_record full record to be copied from - key_info descriptor of the index - key_length specifies length of all keyparts that will be copied - - DESCRIPTION The function takes a complete table record (as e.g. retrieved by handler::index_read()), and a description of an index on the same table, and extracts the first key_length bytes of the record which are part of a key into to_key. If length == 0 then copy all bytes from the record that form a key. - RETURN - None + @param to_key buffer that will be used as a key + @param from_record full record to be copied from + @param key_info descriptor of the index + @param key_length specifies length of all keyparts that will be copied */ void key_copy(uchar *to_key, uchar *from_record, KEY *key_info, @@ -163,22 +157,16 @@ void key_copy(uchar *to_key, uchar *from_record, KEY *key_info, } -/* +/** Restore a key from some buffer to record. - SYNOPSIS - key_restore() - to_record record buffer where the key will be restored to - from_key buffer that contains a key - key_info descriptor of the index - key_length specifies length of all keyparts that will be restored - - DESCRIPTION This function converts a key into record format. It can be used in cases when we want to return a key as a result row. - RETURN - None + @param to_record record buffer where the key will be restored to + @param from_key buffer that contains a key + @param key_info descriptor of the index + @param key_length specifies length of all keyparts that will be restored */ void key_restore(uchar *to_record, uchar *from_key, KEY *key_info, @@ -255,24 +243,23 @@ void key_restore(uchar *to_record, uchar *from_key, KEY *key_info, } -/* - Compare if a key has changed +/** + Compare if a key has changed. - SYNOPSIS - key_cmp_if_same() - table TABLE - key key to compare to row - idx Index used - key_length Length of key + @param table TABLE + @param key key to compare to row + @param idx Index used + @param key_length Length of key - NOTES + @note In theory we could just call field->cmp() for all field types, but as we are only interested if a key has changed (not if the key is larger or smaller than the previous value) we can do things a bit faster by using memcmp() instead. - RETURN + @retval 0 If key is equal + @retval 1 Key has changed */ @@ -331,17 +318,17 @@ bool key_cmp_if_same(TABLE *table,const uchar *key,uint idx,uint key_length) } /* - unpack key-fields from record to some buffer + unpack key-fields from record to some buffer. - SYNOPSIS - key_unpack() + This is used mainly to get a good error message. We temporary + change the column bitmap so that all columns are readable. + + @param to Store value here in an easy to read form + @param table Table to use + @param idx Key number - - NOTES - This is used mainly to get a good error message - We temporary change the column bitmap so that all columns are readable. */ void key_unpack(String *to,TABLE *table,uint idx) @@ -419,21 +406,18 @@ bool is_key_used(TABLE *table, uint idx, const MY_BITMAP *fields) } -/* - Compare key in row to a given key +/** + Compare key in row to a given key. - SYNOPSIS - key_cmp() - key_part Key part handler - key Key to compare to value in table->record[0] - key_length length of 'key' + @param key_part Key part handler + @param key Key to compare to value in table->record[0] + @param key_length length of 'key' - RETURN + @return The return value is SIGN(key_in_row - range_key): - - 0 Key is equal to range or 'range' == 0 (no range) - -1 Key is less than range - 1 Key is larger than range + - 0 Key is equal to range or 'range' == 0 (no range) + - -1 Key is less than range + - 1 Key is larger than range */ int key_cmp(KEY_PART_INFO *key_part, const uchar *key, uint key_length) diff --git a/sql/lock.cc b/sql/lock.cc index 29a07858bc1..3c6406cd154 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -14,8 +14,11 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* locking functions for mysql */ -/* +/** + @file + + Locking functions for mysql. + Because of the new concurrent inserts, we must first get external locks before getting internal locks. If we do it in the other order, the status information is not up to date when called from the lock handler. @@ -65,7 +68,7 @@ excluding one that caused failure. That means handler must cleanup itself in case external_lock() fails. -TODO: + @todo Change to use my_malloc() ONLY when using LOCK TABLES command or when we are forced to use mysql_lock_merge. */ @@ -390,10 +393,11 @@ void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock) DBUG_VOID_RETURN; } -/* - Unlock some of the tables locked by mysql_lock_tables +/** + Unlock some of the tables locked by mysql_lock_tables. + This will work even if get_lock_data fails (next unlock will free all) - */ +*/ void mysql_unlock_some_tables(THD *thd, TABLE **table,uint count) { @@ -405,8 +409,8 @@ void mysql_unlock_some_tables(THD *thd, TABLE **table,uint count) } -/* -** unlock all tables locked for read. +/** + unlock all tables locked for read. */ void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock) @@ -567,7 +571,7 @@ void mysql_lock_downgrade_write(THD *thd, TABLE *table, } -/* abort all other threads waiting to get lock in table */ +/** Abort all other threads waiting to get lock in table. */ void mysql_lock_abort(THD *thd, TABLE *table, bool upgrade_lock) { @@ -586,16 +590,15 @@ void mysql_lock_abort(THD *thd, TABLE *table, bool upgrade_lock) } -/* - Abort one thread / table combination +/** + Abort one thread / table combination. - SYNOPSIS - mysql_lock_abort_for_thread() - thd Thread handler - table Table that should be removed from lock queue + @param thd Thread handler + @param table Table that should be removed from lock queue - RETURN + @retval 0 Table was not locked by another thread + @retval 1 Table was locked by at least one other thread */ @@ -663,28 +666,27 @@ MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b) } -/* +/** Find duplicate lock in tables. - SYNOPSIS - mysql_lock_have_duplicate() - thd The current thread. - needle The table to check for duplicate lock. - haystack The list of tables to search for the dup lock. + Temporary tables are ignored here like they are ignored in + get_lock_data(). If we allow two opens on temporary tables later, + both functions should be checked. - NOTE + @param thd The current thread. + @param needle The table to check for duplicate lock. + @param haystack The list of tables to search for the dup lock. + + @note This is mainly meant for MERGE tables in INSERT ... SELECT situations. The 'real', underlying tables can be found only after the MERGE tables are opened. This function assumes that the tables are already locked. - Temporary tables are ignored here like they are ignored in - get_lock_data(). If we allow two opens on temporary tables later, - both functions should be checked. - - RETURN - NULL No duplicate lock found. - ! NULL First table from 'haystack' that matches a lock on 'needle'. + @retval + NULL No duplicate lock found. + @retval + !NULL First table from 'haystack' that matches a lock on 'needle'. */ TABLE_LIST *mysql_lock_have_duplicate(THD *thd, TABLE_LIST *needle, @@ -768,7 +770,7 @@ TABLE_LIST *mysql_lock_have_duplicate(THD *thd, TABLE_LIST *needle, } - /* unlock a set of external */ +/** Unlock a set of external. */ static int unlock_external(THD *thd, TABLE **table,uint count) { @@ -793,21 +795,17 @@ static int unlock_external(THD *thd, TABLE **table,uint count) } -/* - Get lock structures from table structs and initialize locks +/** + Get lock structures from table structs and initialize locks. - SYNOPSIS - get_lock_data() - thd Thread handler - table_ptr Pointer to tables that should be locks - flags One of: - GET_LOCK_UNLOCK: If we should send TL_IGNORE to - store lock - GET_LOCK_STORE_LOCKS: Store lock info in TABLE - write_lock_used Store pointer to last table with WRITE_ALLOW_WRITE + @param thd Thread handler + @param table_ptr Pointer to tables that should be locks + @param flags One of: + - GET_LOCK_UNLOCK : If we should send TL_IGNORE to store lock + - GET_LOCK_STORE_LOCKS : Store lock info in TABLE + @param write_lock_used Store pointer to last table with WRITE_ALLOW_WRITE */ - static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, uint flags, TABLE **write_lock_used) { @@ -893,31 +891,25 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, } -/* +/** Reset lock type in lock data. - SYNOPSIS - reset_lock_data() - sql_lock The MySQL lock. + After a locking error we want to quit the locking of the table(s). + The test case in the bug report for Bug #18544 has the following + cases: + -# Locking error in lock_external() due to InnoDB timeout. + -# Locking error in get_lock_data() due to missing write permission. + -# Locking error in wait_if_global_read_lock() due to lock conflict. - DESCRIPTION + In all these cases we have already set the lock type into the lock + data of the open table(s). If the table(s) are in the open table + cache, they could be reused with the non-zero lock type set. This + could lead to ignoring a different lock type with the next lock. - After a locking error we want to quit the locking of the table(s). - The test case in the bug report for Bug #18544 has the following - cases: 1. Locking error in lock_external() due to InnoDB timeout. - 2. Locking error in get_lock_data() due to missing write permission. - 3. Locking error in wait_if_global_read_lock() due to lock conflict. + Clear the lock type of all lock data. This ensures that the next + lock request will set its lock type properly. - In all these cases we have already set the lock type into the lock - data of the open table(s). If the table(s) are in the open table - cache, they could be reused with the non-zero lock type set. This - could lead to ignoring a different lock type with the next lock. - - Clear the lock type of all lock data. This ensures that the next - lock request will set its lock type properly. - - RETURN - void + @param sql_lock The MySQL lock. */ static void reset_lock_data(MYSQL_LOCK *sql_lock) @@ -940,20 +932,19 @@ static void reset_lock_data(MYSQL_LOCK *sql_lock) This is used when we need total access to a closed, not open table *****************************************************************************/ -/* +/** Lock and wait for the named lock. - SYNOPSIS - lock_and_wait_for_table_name() - thd Thread handler - table_list Lock first table in this list + @param thd Thread handler + @param table_list Lock first table in this list - NOTES + @note Works together with global read lock. - RETURN + @retval 0 ok + @retval 1 error */ @@ -982,30 +973,30 @@ end: } -/* +/** Put a not open table with an old refresh version in the table cache. - SYNPOSIS - lock_table_name() - thd Thread handler - table_list Lock first table in this list - check_in_use Do we need to check if table already in use by us + @param thd Thread handler + @param table_list Lock first table in this list + @param check_in_use Do we need to check if table already in use by us - WARNING + @note + One must have a lock on LOCK_open! + + @warning If you are going to update the table, you should use lock_and_wait_for_table_name instead of this function as this works together with 'FLUSH TABLES WITH READ LOCK' - NOTES + @note This will force any other threads that uses the table to release it as soon as possible. - REQUIREMENTS - One must have a lock on LOCK_open ! - - RETURN: + @return < 0 error + @return == 0 table locked + @return > 0 table locked, but someone is using it */ @@ -1102,23 +1093,22 @@ bool wait_for_locked_table_names(THD *thd, TABLE_LIST *table_list) } -/* - Lock all tables in list with a name lock +/** + Lock all tables in list with a name lock. - SYNOPSIS - lock_table_names() - thd Thread handle - table_list Names of tables to lock + REQUIREMENTS + - One must have a lock on LOCK_open when calling this - NOTES + @param thd Thread handle + @param table_list Names of tables to lock + + @note If you are just locking one table, you should use lock_and_wait_for_table_name(). - REQUIREMENTS - One must have a lock on LOCK_open when calling this - - RETURN + @retval 0 ok + @retval 1 Fatal error (end of memory ?) */ @@ -1148,12 +1138,13 @@ end: /** - @brief Lock all tables in list with an exclusive table name lock. + Unlock all tables in list with a name lock. - @param thd Thread handle. + @param thd Thread handle. @param table_list Names of tables to lock. - @note This function needs to be protected by LOCK_open. If we're + @note + This function needs to be protected by LOCK_open. If we're under LOCK TABLES, this function does not work as advertised. Namely, it does not exclude other threads from using this table and does not put an exclusive name lock on this table into the table cache. @@ -1183,7 +1174,7 @@ bool lock_table_names_exclusively(THD *thd, TABLE_LIST *table_list) /** - @brief Test is 'table' is protected by an exclusive name lock. + Test is 'table' is protected by an exclusive name lock. @param[in] thd The current thread handler @param[in] table_list Table container containing the single table to be @@ -1211,7 +1202,7 @@ is_table_name_exclusively_locked_by_this_thread(THD *thd, /** - @brief Test is 'table key' is protected by an exclusive name lock. + Test is 'table key' is protected by an exclusive name lock. @param[in] thd The current thread handler. @param[in] key @@ -1245,23 +1236,27 @@ is_table_name_exclusively_locked_by_this_thread(THD *thd, uchar *key, return FALSE; } -/* - Unlock all tables in list with a name lock +/** + Unlock all tables in list with a name lock. - SYNOPSIS - unlock_table_names() + @param thd Thread handle + @param table_list Names of tables to unlock + @param last_table Don't unlock any tables after this one. - (default 0, which will unlock all tables) + (default 0, which will unlock all tables) - NOTES + @note One must have a lock on LOCK_open when calling this. + + @note This function will broadcast refresh signals to inform other threads that the name locks are removed. - RETURN + @retval 0 ok + @retval 1 Fatal error (end of memory ?) */ @@ -1565,14 +1560,9 @@ bool make_global_read_lock_block_commit(THD *thd) } -/* +/** Broadcast COND_refresh and COND_global_read_lock. - SYNOPSIS - broadcast_refresh() - void No parameters. - - DESCRIPTION Due to a bug in a threading library it could happen that a signal did not reach its target. A condition for this was that the same condition variable was used with different mutexes in @@ -1584,12 +1574,9 @@ bool make_global_read_lock_block_commit(THD *thd) in global read lock handling. But now it is necessary to signal both conditions at the same time. - NOTE + @note When signalling COND_global_read_lock within the global read lock handling, it is not necessary to also signal COND_refresh. - - RETURN - void */ void broadcast_refresh(void) diff --git a/sql/log.cc b/sql/log.cc index 95204e89d0e..98a20fdeb3b 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -14,8 +14,15 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* logging of commands */ -/* TODO: Abort logging when we get an error in reading or writing log files */ +/** + @file + + @brief + logging of commands + + @todo + Abort logging when we get an error in reading or writing log files +*/ #include "mysql_priv.h" #include "sql_repl.h" @@ -689,7 +696,7 @@ void Log_to_file_event_handler::init_pthread_objects() } -/* Wrapper around MYSQL_LOG::write() for slow log */ +/** Wrapper around MYSQL_LOG::write() for slow log. */ bool Log_to_file_event_handler:: log_slow(THD *thd, time_t current_time, time_t query_start_arg, @@ -704,7 +711,7 @@ bool Log_to_file_event_handler:: } -/* +/** Wrapper around MYSQL_LOG::write() for general log. We need it since we want all log event handlers to have the same signature. */ @@ -806,7 +813,7 @@ void LOGGER::cleanup_end() } -/* +/** Perform basic log initialization: create file-based log handler and init error log. */ @@ -1466,9 +1473,12 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all) DBUG_RETURN(error); } -/* - NOTE: how do we handle this (unlikely but legal) case: - [transaction] + [update to non-trans table] + [rollback to savepoint] ? +/** + @note + How do we handle this (unlikely but legal) case: + @verbatim + [transaction] + [update to non-trans table] + [rollback to savepoint] ? + @endverbatim The problem occurs when a savepoint is before the update to the non-transactional table. Then when there's a rollback to the savepoint, if we simply truncate the binlog cache, we lose the part of the binlog cache where @@ -1615,11 +1625,14 @@ static void setup_windows_event_source() #endif /* __NT__ */ -/**************************************************************************** -** Find a uniq filename for 'filename.#'. -** Set # to a number as low as possible -** returns != 0 if not possible to get uniq filename -****************************************************************************/ +/** + Find a unique filename for 'filename.#'. + + Set '#' to a number as low as possible. + + @return + nonzero if not possible to get unique filename +*/ static int find_uniq_filename(char *name) { @@ -1833,7 +1846,7 @@ void MYSQL_LOG::close(uint exiting) DBUG_VOID_RETURN; } -/* this is called only once */ +/** This is called only once. */ void MYSQL_LOG::cleanup() { @@ -2160,6 +2173,11 @@ bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time, } +/** + @todo + The following should be using fn_format(); We just need to + first change fn_format() to cut the file name if it's too long. +*/ const char *MYSQL_LOG::generate_name(const char *log_name, const char *suffix, bool strip_ext, char *buff) @@ -2278,17 +2296,17 @@ bool MYSQL_BIN_LOG::open_index_file(const char *index_file_name_arg, } -/* +/** Open a (new) binlog file. - DESCRIPTION - Open the log file and the index file. Register the new - file name in it + file name in it - When calling this when the file is in use, you must have a locks - on LOCK_log and LOCK_index. + on LOCK_log and LOCK_index. - RETURN VALUES + @retval 0 ok + @retval 1 error */ @@ -2440,24 +2458,20 @@ int MYSQL_BIN_LOG::raw_get_current_log(LOG_INFO* linfo) return 0; } -/* - Move all data up in a file in an filename index file +/** + Move all data up in a file in an filename index file. - SYNOPSIS - copy_up_file_and_fill() - index_file File to move - offset Move everything from here to beginning - - NOTE - File will be truncated to be 'offset' shorter or filled up with - newlines - - IMPLEMENTATION We do the copy outside of the IO_CACHE as the cache buffers would just make things slower and more complicated. In most cases the copy loop should only do one read. - RETURN VALUES + @param index_file File to move + @param offset Move everything from here to beginning + + @note + File will be truncated to be 'offset' shorter or filled up with newlines + + @retval 0 ok */ @@ -2498,25 +2512,25 @@ err: #endif /* HAVE_REPLICATION */ -/* - Find the position in the log-index-file for the given log name +/** + Find the position in the log-index-file for the given log name. - SYNOPSIS - find_log_pos() - linfo Store here the found log file name and position to - the NEXT log file name in the index file. - log_name Filename to find in the index file. - Is a null pointer if we want to read the first entry - need_lock Set this to 1 if the parent doesn't already have a - lock on LOCK_index + @param linfo Store here the found log file name and position to + the NEXT log file name in the index file. + @param log_name Filename to find in the index file. + Is a null pointer if we want to read the first entry + @param need_lock Set this to 1 if the parent doesn't already have a + lock on LOCK_index - NOTE + @note On systems without the truncate function the file will end with one or more empty lines. These will be ignored when reading the file. - RETURN VALUES + @retval 0 ok - LOG_INFO_EOF End of log-index-file found + @retval + LOG_INFO_EOF End of log-index-file found + @retval LOG_INFO_IO Got IO error while reading file */ @@ -2572,25 +2586,27 @@ int MYSQL_BIN_LOG::find_log_pos(LOG_INFO *linfo, const char *log_name, } -/* - Find the position in the log-index-file for the given log name +/** + Find the position in the log-index-file for the given log name. - SYNOPSIS - find_next_log() + @param linfo Store here the next log file name and position to the file name after that. + @param need_lock Set this to 1 if the parent doesn't already have a lock on LOCK_index - NOTE + @note - Before calling this function, one has to call find_log_pos() - to set up 'linfo' + to set up 'linfo' - Mutex needed because we need to make sure the file pointer does not move - from under our feet + from under our feet - RETURN VALUES + @retval 0 ok - LOG_INFO_EOF End of log-index-file found + @retval + LOG_INFO_EOF End of log-index-file found + @retval LOG_INFO_IO Got IO error while reading file */ @@ -2624,21 +2640,20 @@ err: } -/* - Delete all logs refered to in the index file - Start writing to a new log file. The new index file will only contain - this file. +/** + Delete all logs refered to in the index file. + Start writing to a new log file. - SYNOPSIS - reset_logs() - thd Thread + The new index file will only contain this file. - NOTE + @param thd Thread + + @note If not called from slave thread, write start event to new log - - RETURN VALUES + @retval 0 ok + @retval 1 error */ @@ -2702,38 +2717,40 @@ err: } -/* +/** Delete relay log files prior to rli->group_relay_log_name (i.e. all logs which are not involved in a non-finished group - (transaction)), remove them from the index file and start on next relay log. - - SYNOPSIS - purge_first_log() - rli Relay log information - included If false, all relay logs that are strictly before - rli->group_relay_log_name are deleted ; if true, the latter is - deleted too (i.e. all relay logs - read by the SQL slave thread are deleted). - - NOTE - - This is only called from the slave-execute thread when it has read - all commands from a relay log and want to switch to a new relay log. - - When this happens, we can be in an active transaction as - a transaction can span over two relay logs - (although it is always written as a single block to the master's binary - log, hence cannot span over two master's binary logs). + (transaction)), remove them from the index file and start on next + relay log. IMPLEMENTATION - - Protects index file with LOCK_index - - Delete relevant relay log files - - Copy all file names after these ones to the front of the index file - - If the OS has truncate, truncate the file, else fill it with \n' - - Read the next file name from the index file and store in rli->linfo + - Protects index file with LOCK_index + - Delete relevant relay log files + - Copy all file names after these ones to the front of the index file + - If the OS has truncate, truncate the file, else fill it with \n' + - Read the next file name from the index file and store in rli->linfo - RETURN VALUES + @param rli Relay log information + @param included If false, all relay logs that are strictly before + rli->group_relay_log_name are deleted ; if true, the + latter is deleted too (i.e. all relay logs + read by the SQL slave thread are deleted). + + @note + - This is only called from the slave-execute thread when it has read + all commands from a relay log and want to switch to a new relay log. + - When this happens, we can be in an active transaction as + a transaction can span over two relay logs + (although it is always written as a single block to the master's binary + log, hence cannot span over two master's binary logs). + + @retval 0 ok - LOG_INFO_EOF End of log-index-file found + @retval + LOG_INFO_EOF End of log-index-file found + @retval LOG_INFO_SEEK Could not allocate IO cache + @retval LOG_INFO_IO Got IO error while reading file */ @@ -2811,8 +2828,8 @@ err: DBUG_RETURN(error); } -/* - Update log index_file +/** + Update log index_file. */ int MYSQL_BIN_LOG::update_log_index(LOG_INFO* log_info, bool need_update_threads) @@ -2826,25 +2843,24 @@ int MYSQL_BIN_LOG::update_log_index(LOG_INFO* log_info, bool need_update_threads return 0; } -/* +/** Remove all logs before the given log from disk and from the index file. - SYNOPSIS - purge_logs() - to_log Delete all log file name before this file. - included If true, to_log is deleted too. - need_mutex - need_update_threads If we want to update the log coordinates of - all threads. False for relay logs, true otherwise. - freed_log_space If not null, decrement this variable of - the amount of log space freed + @param to_log Delete all log file name before this file. + @param included If true, to_log is deleted too. + @param need_mutex + @param need_update_threads If we want to update the log coordinates of + all threads. False for relay logs, true otherwise. + @param freed_log_space If not null, decrement this variable of + the amount of log space freed - NOTES + @note If any of the logs before the deleted one is in use, only purge logs up to this one. - RETURN VALUES - 0 ok + @retval + 0 ok + @retval LOG_INFO_EOF to_log not found */ @@ -2928,21 +2944,20 @@ err: DBUG_RETURN(error); } -/* +/** Remove all logs before the given file date from disk and from the index file. - SYNOPSIS - purge_logs_before_date() - thd Thread pointer - before_date Delete all log files before given date. + @param thd Thread pointer + @param before_date Delete all log files before given date. - NOTES + @note If any of the logs before the deleted one is in use, only purge logs up to this one. - RETURN VALUES + @retval 0 ok + @retval LOG_INFO_PURGE_NO_ROTATE Binary file that can't be rotated */ @@ -2992,14 +3007,12 @@ err: #endif /* HAVE_REPLICATION */ -/* - Create a new log file name +/** + Create a new log file name. - SYNOPSIS - make_log_name() - buf buf of at least FN_REFLEN where new name is stored + @param buf buf of at least FN_REFLEN where new name is stored - NOTE + @note If file name will be longer then FN_REFLEN it will be truncated */ @@ -3013,8 +3026,8 @@ void MYSQL_BIN_LOG::make_log_name(char* buf, const char* log_ident) } -/* - Check if we are writing/reading to the given log file +/** + Check if we are writing/reading to the given log file. */ bool MYSQL_BIN_LOG::is_active(const char *log_file_name_arg) @@ -3043,14 +3056,12 @@ void MYSQL_BIN_LOG::new_file_without_locking() } -/* - Start writing to a new log file or reopen the old file +/** + Start writing to a new log file or reopen the old file. - SYNOPSIS - new_file_impl() - need_lock Set to 1 if caller has not locked LOCK_log + @param need_lock Set to 1 if caller has not locked LOCK_log - NOTE + @note The new file name is stored last in the index file */ @@ -3521,8 +3532,8 @@ MYSQL_BIN_LOG::flush_and_set_pending_rows_event(THD *thd, DBUG_RETURN(error); } -/* - Write an event to the binary log +/** + Write an event to the binary log. */ bool MYSQL_BIN_LOG::write(Log_event *event_info) @@ -3922,27 +3933,25 @@ int MYSQL_BIN_LOG::write_cache(IO_CACHE *cache, bool lock_log, bool sync_log) return 0; // All OK } -/* - Write a cached log entry to the binary log +/** + Write a cached log entry to the binary log. + - To support transaction over replication, we wrap the transaction + with BEGIN/COMMIT or BEGIN/ROLLBACK in the binary log. + We want to write a BEGIN/ROLLBACK block when a non-transactional table + was updated in a transaction which was rolled back. This is to ensure + that the same updates are run on the slave. - SYNOPSIS - write() - thd - cache The cache to copy to the binlog - commit_event The commit event to print after writing the + @param thd + @param cache The cache to copy to the binlog + @param commit_event The commit event to print after writing the contents of the cache. - NOTE - - We only come here if there is something in the cache. - - The thing in the cache is always a complete transaction - - 'cache' needs to be reinitialized after this functions returns. - - IMPLEMENTATION - - To support transaction over replication, we wrap the transaction - with BEGIN/COMMIT or BEGIN/ROLLBACK in the binary log. - We want to write a BEGIN/ROLLBACK block when a non-transactional table - was updated in a transaction which was rolled back. This is to ensure - that the same updates are run on the slave. + @note + We only come here if there is something in the cache. + @note + The thing in the cache is always a complete transaction. + @note + 'cache' needs to be reinitialized after this functions returns. */ bool MYSQL_BIN_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event) @@ -4039,17 +4048,15 @@ err: } -/* - Wait until we get a signal that the binary log has been updated +/** + Wait until we get a signal that the binary log has been updated. - SYNOPSIS - wait_for_update() - thd Thread variable - is_slave If 0, the caller is the Binlog_dump thread from master; - if 1, the caller is the SQL thread from the slave. This - influences only thd->proc_info. + @param thd Thread variable + @param is_slave If 0, the caller is the Binlog_dump thread from master; + if 1, the caller is the SQL thread from the slave. This + influences only thd->proc_info. - NOTES + @note One must have a lock on LOCK_log before calling this function. This lock will be released before return! That's required by THD::enter_cond() (see NOTES in sql_class.h). @@ -4072,18 +4079,16 @@ void MYSQL_BIN_LOG::wait_for_update(THD* thd, bool is_slave) } -/* - Close the log file +/** + Close the log file. - SYNOPSIS - close() - exiting Bitmask for one or more of the following bits: - LOG_CLOSE_INDEX if we should close the index file - LOG_CLOSE_TO_BE_OPENED if we intend to call open - at once after close. - LOG_CLOSE_STOP_EVENT write a 'stop' event to the log + @param exiting Bitmask for one or more of the following bits: + - LOG_CLOSE_INDEX : if we should close the index file + - LOG_CLOSE_TO_BE_OPENED : if we intend to call open + at once after close. + - LOG_CLOSE_STOP_EVENT : write a 'stop' event to the log - NOTES + @note One can do an open on the object at once after doing a close. The internal structures are not freed until cleanup() is called */ @@ -4163,21 +4168,20 @@ void MYSQL_BIN_LOG::set_max_size(ulong max_size_arg) } -/* - Check if a string is a valid number +/** + Check if a string is a valid number. - SYNOPSIS - test_if_number() - str String to test - res Store value here - allow_wildcards Set to 1 if we should ignore '%' and '_' + @param str String to test + @param res Store value here + @param allow_wildcards Set to 1 if we should ignore '%' and '_' - NOTE + @note For the moment the allow_wildcards argument is not used Should be move to some other file. - RETURN VALUES + @retval 1 String is a number + @retval 0 Error */ @@ -4318,23 +4322,18 @@ static void print_buffer_to_nt_eventlog(enum loglevel level, char *buff, #endif /* __NT__ */ -/* +/** Prints a printf style message to the error log and, under NT, to the Windows event log. - SYNOPSIS - vprint_msg_to_log() - event_type Type of event to write (Error, Warning, or Info) - format Printf style format of message - args va_list list of arguments for the message + This function prints the message into a buffer and then sends that buffer + to other functions to write that message to other logging sources. - NOTE + @param event_type Type of event to write (Error, Warning, or Info) + @param format Printf style format of message + @param args va_list list of arguments for the message - IMPLEMENTATION - This function prints the message into a buffer and then sends that buffer - to other functions to write that message to other logging sources. - - RETURN VALUES + @returns The function always returns 0. The return value is present in the signature to be compatible with other logging routines, which could return an error (e.g. logging to the log tables) @@ -4588,16 +4587,18 @@ err: return 1; } -/* - there is no active page, let's got one from the pool +/** + there is no active page, let's got one from the pool. - two strategies here: - 1. take the first from the pool - 2. if there're waiters - take the one with the most free space + Two strategies here: + -# take the first from the pool + -# if there're waiters - take the one with the most free space. - TODO page merging. try to allocate adjacent page first, - so that they can be flushed both in one sync + @todo + TODO page merging. try to allocate adjacent page first, + so that they can be flushed both in one sync */ + void TC_LOG_MMAP::get_active_from_pool() { PAGE **p, **best_p=0; @@ -4640,6 +4641,10 @@ void TC_LOG_MMAP::get_active_from_pool() pthread_mutex_unlock(&LOCK_pool); } +/** + @todo + perhaps, increase log size ? +*/ int TC_LOG_MMAP::overflow() { /* @@ -4652,10 +4657,9 @@ int TC_LOG_MMAP::overflow() return 1; // always return 1 } -/* - Record that transaction XID is committed on the persistent storage +/** + Record that transaction XID is committed on the persistent storage. - NOTES This function is called in the middle of two-phase commit: First all resources prepare the transaction, then tc_log->log() is called, then all resources commit the transaction, then tc_log->unlog() is called. @@ -4666,18 +4670,18 @@ int TC_LOG_MMAP::overflow() threads waiting for a page, but then all these threads will be waiting for a fsync() anyway - IMPLEMENTATION If tc_log == MYSQL_LOG then tc_log writes transaction to binlog and records XID in a special Xid_log_event. If tc_log = TC_LOG_MMAP then xid is written in a special memory-mapped log. - RETURN - 0 Error - # "cookie", a number that will be passed as an argument - to unlog() call. tc_log can define it any way it wants, - and use for whatever purposes. TC_LOG_MMAP sets it - to the position in memory where xid was logged to. + @retval + 0 - error + @retval + \# - otherwise, "cookie", a number that will be passed as an argument + to unlog() call. tc_log can define it any way it wants, + and use for whatever purposes. TC_LOG_MMAP sets it + to the position in memory where xid was logged to. */ int TC_LOG_MMAP::log_xid(THD *thd, my_xid xid) @@ -4785,9 +4789,9 @@ int TC_LOG_MMAP::sync() return err; } -/* +/** erase xid from the page, update page free space counters/pointers. - cookie points directly to the memory where xid was logged + cookie points directly to the memory where xid was logged. */ void TC_LOG_MMAP::unlog(ulong cookie, my_xid xid) @@ -4898,16 +4902,17 @@ TC_LOG *tc_log; TC_LOG_DUMMY tc_log_dummy; TC_LOG_MMAP tc_log_mmap; -/* - Perform heuristic recovery, if --tc-heuristic-recover was used +/** + Perform heuristic recovery, if --tc-heuristic-recover was used. - RETURN VALUE - 0 no heuristic recovery was requested - 1 heuristic recovery was performed - - NOTE + @note no matter whether heuristic recovery was successful or not mysqld must exit. So, return value is the same in both cases. + + @retval + 0 no heuristic recovery was requested + @retval + 1 heuristic recovery was performed */ int TC_LOG::using_heuristic_recover() @@ -4925,8 +4930,9 @@ int TC_LOG::using_heuristic_recover() /****** transaction coordinator log for 2pc - binlog() based solution ******/ #define TC_LOG_BINLOG MYSQL_BIN_LOG -/* - TODO keep in-memory list of prepared transactions +/** + @todo + keep in-memory list of prepared transactions (add to list in log(), remove on unlog()) and copy it to the new binlog if rotated but let's check the behaviour of tc_log_page_waits first! @@ -5017,7 +5023,7 @@ err: return error; } -/* this is called on shutdown, after ha_panic */ +/** This is called on shutdown, after ha_panic. */ void TC_LOG_BINLOG::close() { DBUG_ASSERT(prepared_xids==0); @@ -5025,12 +5031,14 @@ void TC_LOG_BINLOG::close() pthread_cond_destroy (&COND_prep_xids); } -/* - TODO group commit +/** + @todo + group commit - RETURN - 0 - error - 1 - success + @retval + 0 error + @retval + 1 success */ int TC_LOG_BINLOG::log_xid(THD *thd, my_xid xid) { diff --git a/sql/log_event.cc b/sql/log_event.cc index 9094a7c38b2..6a4be9318a2 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -154,8 +154,8 @@ static void clear_all_errors(THD *thd, Relay_log_info *rli) } -/* - Ignore error code specified on command line +/** + Ignore error code specified on command line. */ inline int ignored_error_code(int err_code) @@ -212,21 +212,20 @@ static char *pretty_print_str(char *packet, char *str, int len) #endif /* !MYSQL_CLIENT */ -/* - Creates a temporary name for load data infile: +#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) - SYNOPSIS - slave_load_file_stem() - buf Store new filename here - file_id File_id (part of file name) - event_server_id Event_id (part of file name) - ext Extension for file name +/** + Creates a temporary name for load data infile:. - RETURN + @param buf Store new filename here + @param file_id File_id (part of file name) + @param event_server_id Event_id (part of file name) + @param ext Extension for file name + + @return Pointer to start of extension */ -#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) static char *slave_load_file_stem(char *buf, uint file_id, int event_server_id, const char *ext) { @@ -246,14 +245,12 @@ static char *slave_load_file_stem(char *buf, uint file_id, #endif -/* - Delete all temporary files used for SQL_LOAD. +#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) - SYNOPSIS - cleanup_load_tmpdir() +/** + Delete all temporary files used for SQL_LOAD. */ -#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) static void cleanup_load_tmpdir() { MY_DIR *dirp; @@ -321,7 +318,7 @@ static inline int read_str(const char **buf, const char *buf_end, } -/* +/** Transforms a string into "" or its expression in 0x... form. */ @@ -338,12 +335,14 @@ char *str_to_hex(char *to, const char *from, uint len) return to; // pointer to end 0 of 'to' } -/* +#ifndef MYSQL_CLIENT + +/** Append a version of the 'from' string suitable for use in a query to the 'to' string. To generate a correct escaping, the character set information in 'csinfo' is used. - */ -#ifndef MYSQL_CLIENT +*/ + int append_query_string(CHARSET_INFO *csinfo, String const *from, String *to) @@ -370,7 +369,7 @@ append_query_string(CHARSET_INFO *csinfo, #endif -/* +/** Prints a "session_var=value" string. Used by mysqlbinlog to print some SET commands just before it prints a query. */ @@ -395,8 +394,9 @@ static void print_set_option(IO_CACHE* file, uint32 bits_changed, Log_event methods (= the parent class of all events) **************************************************************************/ -/* - Log_event::get_type_str() +/** + @return + returns the human readable name of the event's type */ const char* Log_event::get_type_str() @@ -444,7 +444,7 @@ Log_event::Log_event(THD* thd_arg, uint16 flags_arg, bool using_trans) } -/* +/** This minimal constructor is for when you are not even sure that there is a valid THD. For example in the server when we are shutting down or flushing logs after receiving a SIGHUP (then we must write a Rotate to @@ -589,12 +589,9 @@ void Log_event::pack_info(Protocol *protocol) } -/* - Log_event::net_send() - +/** Only called by SHOW BINLOG EVENTS */ - int Log_event::net_send(Protocol *protocol, const char* log_name, my_off_t pos) { const char *p= strrchr(log_name, FN_LIBCHAR); @@ -615,8 +612,10 @@ int Log_event::net_send(Protocol *protocol, const char* log_name, my_off_t pos) #endif /* HAVE_REPLICATION */ -/* - Log_event::init_show_field_list() +/** + init_show_field_list() prepares the column names and types for the + output of SHOW BINLOG EVENTS; it is used only by SHOW BINLOG + EVENTS. */ void Log_event::init_show_field_list(List* field_list) @@ -712,12 +711,9 @@ bool Log_event::write_header(IO_CACHE* file, ulong event_data_length) } -/* - Log_event::read_log_event() - +/** This needn't be format-tolerant, because we only read LOG_EVENT_MINIMAL_HEADER_LEN (we just want to read the event's length). - */ int Log_event::read_log_event(IO_CACHE* file, String* packet, @@ -800,14 +796,11 @@ end: #define LOCK_MUTEX #endif -/* - Log_event::read_log_event() - - NOTE: +#ifndef MYSQL_CLIENT +/** + @note Allocates memory; The caller is responsible for clean-up. */ - -#ifndef MYSQL_CLIENT Log_event* Log_event::read_log_event(IO_CACHE* file, pthread_mutex_t* log_lock, const Format_description_log_event @@ -905,8 +898,7 @@ err: } -/* - Log_event::read_log_event() +/** Binlog format tolerance is in (buf, event_len, description_event) constructors. */ @@ -1233,12 +1225,13 @@ void Log_event::print_timestamp(IO_CACHE* file, time_t* ts) #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) -/* - Query_log_event::pack_info() +/** This (which is used only for SHOW BINLOG EVENTS) could be updated to print SET @@session_var=. But this is not urgent, as SHOW BINLOG EVENTS is only an information, it does not produce suitable queries to replay (for example it does not print LOAD DATA INFILE). + @todo + show the catalog ?? */ void Query_log_event::pack_info(Protocol *protocol) @@ -1267,7 +1260,9 @@ void Query_log_event::pack_info(Protocol *protocol) #ifndef MYSQL_CLIENT -/* Utility function for the next method */ +/** + Utility function for the next method (Query_log_event::write()) . +*/ static void write_str_with_code_and_len(char **dst, const char *src, int len, uint code) { @@ -1279,10 +1274,10 @@ static void write_str_with_code_and_len(char **dst, const char *src, } -/* - Query_log_event::write() +/** + Query_log_event::write(). - NOTES: + @note In this event we have to modify the header to have the correct EVENT_LEN_OFFSET as we don't yet know how many status variables we will print! @@ -1454,9 +1449,7 @@ bool Query_log_event::write(IO_CACHE* file) my_b_safe_write(file, (uchar*) query, q_len)) ? 1 : 0; } -/* - Query_log_event::Query_log_event() - +/** The simplest constructor that could possibly work. This is used for creating static objects that have a special meaning and are invisible to the log. @@ -1580,8 +1573,7 @@ static void copy_str_and_move(const char **src, *(*dst)++= 0; } -/* - Query_log_event::Query_log_event() +/** This is used by the SQL slave thread to prepare the event before execution. */ @@ -1748,11 +1740,13 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, } -/* - Query_log_event::print() -*/ - #ifdef MYSQL_CLIENT +/** + Query_log_event::print(). + + @todo + print the catalog ?? +*/ void Query_log_event::print_query_header(IO_CACHE* file, PRINT_EVENT_INFO* print_event_info) { @@ -1937,6 +1931,23 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli) } +/** + @todo + Compare the values of "affected rows" around here. Something + like: + @code + if ((uint32) affected_in_event != (uint32) affected_on_slave) + { + sql_print_error("Slave: did not get the expected number of affected \ + rows running query from master - expected %d, got %d (this numbers \ + should have matched modulo 4294967296).", 0, ...); + thd->query_error = 1; + } + @endcode + We may also want an option to tell the slave to ignore "affected" + mismatch. This mismatch could be implemented with a new ER_ code, and + to ignore it you would use --slave-skip-errors... +*/ int Query_log_event::do_apply_event(Relay_log_info const *rli, const char *query_arg, uint32 q_len_arg) { @@ -2367,30 +2378,31 @@ bool Start_log_event_v3::write(IO_CACHE* file) #endif -/* - Start_log_event_v3::do_apply_event() +#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) +/** + Start_log_event_v3::do_apply_event() . The master started - IMPLEMENTATION + IMPLEMENTATION - To handle the case where the master died without having time to write - DROP TEMPORARY TABLE, DO RELEASE_LOCK (prepared statements' deletion is - TODO), we clean up all temporary tables that we got, if we are sure we - can (see below). + DROP TEMPORARY TABLE, DO RELEASE_LOCK (prepared statements' deletion is + TODO), we clean up all temporary tables that we got, if we are sure we + can (see below). - TODO + @todo - Remove all active user locks. - Guilhem 2003-06: this is true but not urgent: the worst it can cause is - the use of a bit of memory for a user lock which will not be used - anymore. If the user lock is later used, the old one will be released. In - other words, no deadlock problem. + Guilhem 2003-06: this is true but not urgent: the worst it can cause is + the use of a bit of memory for a user lock which will not be used + anymore. If the user lock is later used, the old one will be released. In + other words, no deadlock problem. */ -#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) int Start_log_event_v3::do_apply_event(Relay_log_info const *rli) { DBUG_ENTER("Start_log_event_v3::do_apply_event"); - switch (binlog_version) { + switch (binlog_version) + { case 3: case 4: /* @@ -2438,23 +2450,20 @@ int Start_log_event_v3::do_apply_event(Relay_log_info const *rli) Format_description_log_event methods ****************************************************************************/ -/* +/** Format_description_log_event 1st ctor. - SYNOPSIS - Format_description_log_event::Format_description_log_event - binlog_version the binlog version for which we want to build - an event. Can be 1 (=MySQL 3.23), 3 (=4.0.x - x>=2 and 4.1) or 4 (MySQL 5.0). Note that the - old 4.0 (binlog version 2) is not supported; - it should not be used for replication with - 5.0. - - DESCRIPTION Ctor. Can be used to create the event to write to the binary log (when the server starts or when FLUSH LOGS), or to create artificial events to parse binlogs from MySQL 3.23 or 4.x. When in a client, only the 2nd use is possible. + + @param binlog_version the binlog version for which we want to build + an event. Can be 1 (=MySQL 3.23), 3 (=4.0.x + x>=2 and 4.1) or 4 (MySQL 5.0). Note that the + old 4.0 (binlog version 2) is not supported; + it should not be used for replication with + 5.0. */ Format_description_log_event:: @@ -2562,18 +2571,20 @@ Format_description_log_event(uint8 binlog_ver, const char* server_ver) } -/* +/** The problem with this constructor is that the fixed header may have a length different from this version, but we don't know this length as we have not read the Format_description_log_event which says it, yet. This length is in the post-header of the event, but we don't know where the post-header starts. + So this type of event HAS to: - either have the header's length at the beginning (in the header, at a fixed position which will never be changed), not in the post-header. That would make the header be "shifted" compared to other events. - or have a header of size LOG_EVENT_MINIMAL_HEADER_LEN (19), in all future versions, so that we know for sure. + I (Guilhem) chose the 2nd solution. Rotate has the same constraint (because it is sent before Format_description_log_event). */ @@ -3008,14 +3019,11 @@ Load_log_event::Load_log_event(THD *thd_arg, sql_exchange *ex, #endif /* !MYSQL_CLIENT */ -/* - Load_log_event::Load_log_event() - - NOTE +/** + @note The caller must do buf[event_len] = 0 before he starts using the constructed event. */ - Load_log_event::Load_log_event(const char *buf, uint event_len, const Format_description_log_event *description_event) :Log_event(buf, description_event), num_fields(0), fields(0), @@ -3190,17 +3198,18 @@ void Load_log_event::print(FILE* file_arg, PRINT_EVENT_INFO* print_event_info, } #endif /* MYSQL_CLIENT */ +#ifndef MYSQL_CLIENT -/* +/** Load_log_event::set_fields() - Note that this function can not use the member variable - for the database, since LOAD DATA INFILE on the slave - can be for a different database than the current one. - This is the reason for the affected_db argument to this method. + @note + This function can not use the member variable + for the database, since LOAD DATA INFILE on the slave + can be for a different database than the current one. + This is the reason for the affected_db argument to this method. */ -#ifndef MYSQL_CLIENT void Load_log_event::set_fields(const char* affected_db, List &field_list, Name_resolution_context *context) @@ -3218,32 +3227,33 @@ void Load_log_event::set_fields(const char* affected_db, #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) -/* - Does the data loading job when executing a LOAD DATA on the slave +/** + Does the data loading job when executing a LOAD DATA on the slave. - SYNOPSIS - Load_log_event::do_apply_event - net - rli - use_rli_only_for_errors - if set to 1, rli is provided to - Load_log_event::do_apply_event - only for this function to have - RPL_LOG_NAME and - rli->last_slave_error, both being - used by error reports. rli's - position advancing is skipped (done - by the caller which is - Execute_load_log_event::do_apply_event). - - if set to 0, rli is provided for - full use, i.e. for error reports and - position advancing. + @param net + @param rli + @param use_rli_only_for_errors If set to 1, rli is provided to + Load_log_event::exec_event only for this + function to have RPL_LOG_NAME and + rli->last_slave_error, both being used by + error reports. rli's position advancing + is skipped (done by the caller which is + Execute_load_log_event::exec_event). + If set to 0, rli is provided for full use, + i.e. for error reports and position + advancing. - DESCRIPTION - Does the data loading job when executing a LOAD DATA on the slave + @todo + fix this; this can be done by testing rules in + Create_file_log_event::exec_event() and then discarding Append_block and + al. + @todo + this is a bug - this needs to be moved to the I/O thread - RETURN VALUE + @retval 0 Success - 1 Failure + @retval + 1 Failure */ int Load_log_event::do_apply_event(NET* net, Relay_log_info const *rli, @@ -3619,24 +3629,21 @@ bool Rotate_log_event::write(IO_CACHE* file) #endif +#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) + /* - Rotate_log_event::do_apply_event() + Got a rotate log event from the master. - Got a rotate log event from the master + This is mainly used so that we can later figure out the logname and + position for the master. - IMPLEMENTATION - This is mainly used so that we can later figure out the logname and - position for the master. + We can't rotate the slave's BINlog as this will cause infinitive rotations + in a A -> B -> A setup. + The NOTES below is a wrong comment which will disappear when 4.1 is merged. - We can't rotate the slave's BINlog as this will cause infinitive rotations - in a A -> B -> A setup. - The NOTES below is a wrong comment which will disappear when 4.1 is merged. - - RETURN VALUES + @retval 0 ok */ - -#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) int Rotate_log_event::do_update_pos(Relay_log_info *rli) { DBUG_ENTER("Rotate_log_event::do_update_pos"); @@ -3994,12 +4001,12 @@ void Xid_log_event::pack_info(Protocol *protocol) } #endif -/* - NOTE it's ok not to use int8store here, +/** + @note + It's ok not to use int8store here, as long as xid_t::set(ulonglong) and - xid_t::get_my_xid doesn't do it either - - we don't care about actual values of xids as long as + xid_t::get_my_xid doesn't do it either. + We don't care about actual values of xids as long as identical numbers compare identically */ @@ -4470,6 +4477,10 @@ void Slave_log_event::pack_info(Protocol *protocol) #ifndef MYSQL_CLIENT +/** + @todo + re-write this better without holding both locks at the same time +*/ Slave_log_event::Slave_log_event(THD* thd_arg, Relay_log_info* rli) :Log_event(thd_arg, 0, 0) , mem_pool(0), master_host(0) @@ -4565,7 +4576,7 @@ void Slave_log_event::init_from_mem_pool(int data_size) } -/* This code is not used, so has not been updated to be format-tolerant */ +/** This code is not used, so has not been updated to be format-tolerant. */ Slave_log_event::Slave_log_event(const char* buf, uint event_len) :Log_event(buf,0) /*unused event*/ ,mem_pool(0),master_host(0) { @@ -4613,9 +4624,8 @@ void Stop_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info) #endif /* MYSQL_CLIENT */ +#ifndef MYSQL_CLIENT /* - Stop_log_event::do_apply_event() - The master stopped. We used to clean up all temporary tables but this is useless as, as the master has shut down properly, it has written all DROP TEMPORARY TABLE (prepared statements' deletion is @@ -4626,8 +4636,6 @@ void Stop_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info) Start_log_event_v3::do_apply_event(), not here. Because if we come here, the master was sane. */ - -#ifndef MYSQL_CLIENT int Stop_log_event::do_update_pos(Relay_log_info *rli) { /* @@ -5437,7 +5445,9 @@ void Execute_load_query_log_event::print(FILE* file, print(file, print_event_info, 0); } - +/** + Prints the query as LOAD DATA LOCAL and with rewritten filename. +*/ void Execute_load_query_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info, const char *local_fname) @@ -6471,15 +6481,17 @@ void Rows_log_event::print_helper(FILE *file, */ +#if !defined(MYSQL_CLIENT) /** Save the field metadata based on the real_type of the field. The metadata saved depends on the type of the field. Some fields store a single byte for pack_length() while others store two bytes for field_length (max length). - @retval 0 Ok. + @retval 0 Ok. - TODO: We may want to consider changing the encoding of the information. + @todo + We may want to consider changing the encoding of the information. Currently, the code attempts to minimize the number of bytes written to the tablemap. There are at least two other alternatives; 1) using net_store_length() to store the data allowing it to choose the number of @@ -6494,7 +6506,6 @@ void Rows_log_event::print_helper(FILE *file, is less wasteful for space but does waste 1 byte for every field that does not encode 2 parts. */ -#if !defined(MYSQL_CLIENT) int Table_map_log_event::save_field_metadata() { DBUG_ENTER("Table_map_log_event::save_field_metadata"); diff --git a/sql/mf_iocache.cc b/sql/mf_iocache.cc index 5d9d6d834b4..8c2d16c40b0 100644 --- a/sql/mf_iocache.cc +++ b/sql/mf_iocache.cc @@ -13,8 +13,11 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* - Cashing of files with only does (sequential) read or writes of fixed- +/** + @file + + @details + Caching of files with only does (sequential) read or writes of fixed- length records. A read isn't allowed to go over file-length. A read is ok if it ends at file-length and next read can try to read after file-length (and get a EOF-error). @@ -34,11 +37,15 @@ extern "C" { - /* - ** Read buffered from the net. - ** Returns 1 if can't read requested characters - ** Returns 0 if record read - */ +/** + Read buffered from the net. + + @retval + 1 if can't read requested characters + @retval + 0 if record read +*/ + int _my_b_net_read(register IO_CACHE *info, uchar *Buffer, size_t Count __attribute__((unused))) diff --git a/sql/my_decimal.cc b/sql/my_decimal.cc index 54cef6abdb5..651ff22d198 100644 --- a/sql/my_decimal.cc +++ b/sql/my_decimal.cc @@ -18,17 +18,15 @@ #ifndef MYSQL_CLIENT -/* - report result of decimal operation +/** + report result of decimal operation. - SYNOPSIS - decimal_operation_results() - result decimal library return code (E_DEC_* see include/decimal.h) + @param result decimal library return code (E_DEC_* see include/decimal.h) - TODO + @todo Fix error messages - RETURN + @return result */ diff --git a/sql/mysqld.cc b/sql/mysqld.cc index a355c560996..2b843af6238 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -170,10 +170,10 @@ int initgroups(const char *,unsigned int); typedef fp_except fp_except_t; #endif - /* We can't handle floating point exceptions with threads, so disable - this on freebsd - */ - +/** + We can't handle floating point exceptions with threads, so disable + this on freebsd. +*/ inline void reset_floating_point_exceptions() { /* Don't fall for overflow, underflow,divide-by-zero or loss of precision */ @@ -325,7 +325,7 @@ static my_bool opt_short_log_format= 0; static uint kill_cached_threads, wake_thread; static ulong killed_threads, thread_created; static ulong max_used_connections; -static ulong my_bind_addr; /* the address we bind to */ +static ulong my_bind_addr; /**< the address we bind to */ static volatile ulong cached_thread_count= 0; static const char *sql_mode_str= "OFF"; static char *mysqld_user, *mysqld_chroot, *log_error_file_ptr; @@ -366,7 +366,7 @@ bool volatile shutdown_in_progress; */ bool volatile grant_option; -my_bool opt_skip_slave_start = 0; // If set, slave is not autostarted +my_bool opt_skip_slave_start = 0; ///< If set, slave is not autostarted my_bool opt_reckless_slave = 0; my_bool opt_enable_named_pipe= 0; my_bool opt_local_infile, opt_slave_compressed_protocol; @@ -430,7 +430,7 @@ TYPELIB binlog_format_typelib= ulong opt_binlog_format_id= (ulong) BINLOG_FORMAT_UNSPEC; const char *opt_binlog_format= binlog_format_names[opt_binlog_format_id]; #ifdef HAVE_INITGROUPS -static bool calling_initgroups= FALSE; /* Used in SIGSEGV handler. */ +static bool calling_initgroups= FALSE; /**< Used in SIGSEGV handler. */ #endif uint mysqld_port, test_flags, select_errors, dropping_tables, ha_open_options; uint mysqld_port_timeout; @@ -458,12 +458,12 @@ ulong specialflag=0; ulong binlog_cache_use= 0, binlog_cache_disk_use= 0; ulong max_connections, max_connect_errors; uint max_user_connections= 0; -/* +/** Limit of the total number of prepared statements in the server. Is necessary to protect the server against out-of-memory attacks. */ ulong max_prepared_stmt_count; -/* +/** Current total number of prepared statements in the server. This number is exact, and therefore may not be equal to the difference between `com_stmt_prepare' and `com_stmt_close' (global status variables), as @@ -499,13 +499,13 @@ uint mysql_data_home_len; char mysql_data_home_buff[2], *mysql_data_home=mysql_real_data_home; char server_version[SERVER_VERSION_LENGTH]; char *mysqld_unix_port, *opt_mysql_tmpdir; -const char **errmesg; /* Error messages */ +const char **errmesg; /**< Error messages */ const char *myisam_recover_options_str="OFF"; const char *myisam_stats_method_str="nulls_unequal"; -/* name of reference on left espression in rewritten IN subquery */ +/** name of reference on left espression in rewritten IN subquery */ const char *in_left_expr_name= ""; -/* name of additional condition */ +/** name of additional condition */ const char *in_additional_cond= ""; const char *in_having_cond= ""; @@ -555,7 +555,7 @@ pthread_mutex_t LOCK_mysql_create_db, LOCK_Acl, LOCK_open, LOCK_thread_count, LOCK_crypt, LOCK_bytes_sent, LOCK_bytes_received, LOCK_global_system_variables, LOCK_user_conn, LOCK_slave_list, LOCK_active_mi; -/* +/** The below lock protects access to two global server variables: max_prepared_stmt_count and prepared_stmt_count. These variables set the limit and hold the current total number of prepared statements @@ -604,7 +604,7 @@ static char **defaults_argv; static char *opt_bin_logname; static my_socket unix_sock,ip_sock; -struct rand_struct sql_rand; // used by sql_class.cc:THD::THD() +struct rand_struct sql_rand; ///< used by sql_class.cc:THD::THD() #ifndef EMBEDDED_LIBRARY struct passwd *user_info; @@ -628,7 +628,7 @@ static char **opt_argv; static HANDLE hEventShutdown; static char shutdown_event_name[40]; #include "nt_servc.h" -static NTService Service; // Service object for WinNT +static NTService Service; ///< Service object for WinNT #endif /* EMBEDDED_LIBRARY */ #endif /* __WIN__ */ @@ -1009,19 +1009,15 @@ void kill_mysql(void) DBUG_VOID_RETURN; } -/* - Force server down. Kill all connections and threads and exit +/** + Force server down. Kill all connections and threads and exit. - SYNOPSIS - kill_server + @param sig_ptr Signal number that caused kill_server to be called. - sig_ptr Signal number that caused kill_server to be called. - - NOTE! + @note A signal number of 0 mean that the function was not called from a signal handler and there is thus no signal to block or stop, we just want to kill the server. - */ #if defined(__NETWARE__) @@ -1114,21 +1110,18 @@ extern "C" sig_handler print_signal_warning(int sig) #endif } -/* - cleanup all memory and end program nicely +#ifndef EMBEDDED_LIBRARY - SYNOPSIS - unireg_end() - - NOTES - This function never returns. +/** + cleanup all memory and end program nicely. If SIGNALS_DONT_BREAK_READ is defined, this function is called by the main thread. To get MySQL to shut down nicely in this case (Mac OS X) we have to call exit() instead if pthread_exit(). -*/ -#ifndef EMBEDDED_LIBRARY + @note + This function never returns. +*/ void unireg_end(void) { clean_up(1); @@ -1275,11 +1268,10 @@ void clean_up(bool print_message) #ifndef EMBEDDED_LIBRARY -/* +/** This is mainly needed when running with purify, but it's still nice to - know that all child threads have died when mysqld exits + know that all child threads have died when mysqld exits. */ - static void wait_for_signal_thread_to_end() { #ifndef __NETWARE__ @@ -1506,8 +1498,7 @@ static void set_effective_user(struct passwd *user_info_arg) } -/* Change root user if started with --chroot */ - +/** Change root user if started with @c --chroot . */ static void set_root(const char *path) { #if !defined(__WIN__) && !defined(__NETWARE__) @@ -1696,19 +1687,16 @@ static void network_init(void) #ifndef EMBEDDED_LIBRARY -/* - Close a connection +/** + Close a connection. - SYNOPSIS - close_connection() - thd Thread handle - errcode Error code to print to console - lock 1 if we have have to lock LOCK_thread_count + @param thd Thread handle + @param errcode Error code to print to console + @param lock 1 if we have have to lock LOCK_thread_count - NOTES + @note For the connection that is doing shutdown, this is called twice */ - void close_connection(THD *thd, uint errcode, bool lock) { st_vio *vio; @@ -1733,9 +1721,8 @@ void close_connection(THD *thd, uint errcode, bool lock) #endif /* EMBEDDED_LIBRARY */ - /* Called when a thread is aborted */ - /* ARGSUSED */ - +/** Called when a thread is aborted. */ +/* ARGSUSED */ extern "C" sig_handler end_thread_signal(int sig __attribute__((unused))) { THD *thd=current_thd; @@ -1877,13 +1864,13 @@ void flush_thread_cache() } -/* - Aborts a thread nicely. Commes here on SIGPIPE - TODO: One should have to fix that thr_alarm know about this - thread too. -*/ - #ifdef THREAD_SPECIFIC_SIGPIPE +/** + Aborts a thread nicely. Comes here on SIGPIPE. + + @todo + One should have to fix that thr_alarm know about this thread too. +*/ extern "C" sig_handler abort_thread(int sig __attribute__((unused))) { THD *thd=current_thd; @@ -1931,7 +1918,7 @@ static void check_data_home(const char *path) #elif defined(__NETWARE__) -// down server event callback +/// down server event callback. void mysql_down_server_cb(void *, void *) { event_flag= TRUE; @@ -1939,7 +1926,7 @@ void mysql_down_server_cb(void *, void *) } -// destroy callback resources +/// destroy callback resources. void mysql_cb_destroy(void *) { UnRegisterEventNotification(eh); // cleanup down event notification @@ -1951,7 +1938,7 @@ void mysql_cb_destroy(void *) } -// initialize callbacks +/// initialize callbacks. void mysql_cb_init() { // register for down server event @@ -1974,8 +1961,7 @@ void mysql_cb_init() } -/* To get the name of the NetWare volume having MySQL data folder */ - +/** To get the name of the NetWare volume having MySQL data folder. */ static void getvolumename() { char *p; @@ -1989,8 +1975,8 @@ static void getvolumename() } -/* - Registering with NEB for NSS Volume Deactivation event +/** + Registering with NEB for NSS Volume Deactivation event. */ static void registerwithneb() @@ -2042,8 +2028,8 @@ static void registerwithneb() } -/* - Callback for NSS Volume Deactivation event +/** + Callback for NSS Volume Deactivation event. */ ulong neb_event_callback(struct EventBlock *eblock) @@ -2075,12 +2061,11 @@ ulong neb_event_callback(struct EventBlock *eblock) } -/* - Function to get NSS volume ID of the MySQL data -*/ - #define ADMIN_VOL_PATH "_ADMIN:/Volumes/" +/** + Function to get NSS volume ID of the MySQL data. +*/ static void getvolumeID(BYTE *volumeName) { char path[zMAX_FULL_NAME]; @@ -2155,10 +2140,10 @@ static void start_signal_handler(void) } -/* - Warn if the data is on a Traditional volume +/** + Warn if the data is on a Traditional volume. - NOTE + @note Already done by mysqld_safe */ @@ -2419,8 +2404,7 @@ static void start_signal_handler(void) } -/* This threads handles all signals and alarms */ - +/** This threads handles all signals and alarms. */ /* ARGSUSED */ pthread_handler_t signal_hand(void *arg __attribute__((unused))) { @@ -2558,12 +2542,10 @@ static void check_data_home(const char *path) #endif /* __WIN__*/ -/* +/** All global error messages are sent here where the first one is stored - for the client + for the client. */ - - /* ARGSUSED */ extern "C" int my_message_sql(uint error, const char *str, myf MyFlags); @@ -2689,20 +2671,19 @@ sizeof(load_default_groups)/sizeof(load_default_groups[0]); #endif /*!EMBEDDED_LIBRARY*/ -/* - Initialize one of the global date/time format variables +/** + Initialize one of the global date/time format variables. - SYNOPSIS - init_global_datetime_format() - format_type What kind of format should be supported - var_ptr Pointer to variable that should be updated + @param format_type What kind of format should be supported + @param var_ptr Pointer to variable that should be updated - NOTES + @note The default value is taken from either opt_date_time_formats[] or the ISO format (ANSI SQL) - RETURN + @retval 0 ok + @retval 1 error */ @@ -4046,21 +4027,20 @@ static char *add_quoted_string(char *to, const char *from, char *to_end) } -/* - Handle basic handling of services, like installation and removal +/** + Handle basic handling of services, like installation and removal. - SYNOPSIS - default_service_handling() - argv Pointer to argument list - servicename Internal name of service - displayname Display name of service (in taskbar ?) - file_path Path to this program - startup_option Startup option to mysqld + @param argv Pointer to argument list + @param servicename Internal name of service + @param displayname Display name of service (in taskbar ?) + @param file_path Path to this program + @param startup_option Startup option to mysqld - RETURN VALUES + @retval 0 option handled + @retval 1 Could not handle option - */ +*/ static bool default_service_handling(char **argv, @@ -4209,7 +4189,7 @@ int main(int argc, char **argv) #endif -/* +/** Execute all commands from a file. Used by the mysql_install_db script to create MySQL privilege tables without having to start a full MySQL server. */ @@ -4334,23 +4314,17 @@ void create_thread_to_handle_connection(THD *thd) } -/* +/** Create new thread to handle incoming connection. - SYNOPSIS - create_new_thread() - thd in/out Thread handle of future thread. - - DESCRIPTION This function will create new thread to handle the incoming connection. If there are idle cached threads one will be used. 'thd' will be pushed into 'threads'. - In single-threaded mode (#define ONE_THREAD) connection will be + In single-threaded mode (\#define ONE_THREAD) connection will be handled inside this function. - RETURN VALUE - none + @param[in,out] thd Thread handle of future thread. */ static void create_new_thread(THD *thd) @@ -4699,15 +4673,13 @@ pthread_handler_t handle_connections_namedpipes(void *arg) #endif /* __NT__ */ -/* - Thread of shared memory's service - - SYNOPSIS - handle_connections_shared_memory() - arg Arguments of thread -*/ - #ifdef HAVE_SMEM + +/** + Thread of shared memory's service. + + @param arg Arguments of thread +*/ pthread_handler_t handle_connections_shared_memory(void *arg) { /* file-mapping object, use for create shared memory */ @@ -7039,13 +7011,13 @@ To see what values a running MySQL server is using, type\n\ #endif /*!EMBEDDED_LIBRARY*/ -/* - Initialize all MySQL global variables to default values +/** + Initialize all MySQL global variables to default values. - SYNOPSIS - mysql_init_variables() + We don't need to set numeric variables refered to in my_long_options + as these are initialized by my_getopt. - NOTES + @note The reason to set a lot of global variables to zero is to allow one to restart the embedded server with a clean environment It's also needed on some exotic platforms where global variables are @@ -7771,7 +7743,7 @@ mysqld_get_one_option(int optid, } -/* Handle arguments for multiple key caches */ +/** Handle arguments for multiple key caches. */ extern "C" uchar **mysql_getopt_value(const char *keyname, uint key_length, const struct my_option *option); @@ -7822,6 +7794,10 @@ void option_error_reporter(enum loglevel level, const char *format, ...) } +/** + @todo + - FIXME add EXIT_TOO_MANY_ARGUMENTS to "mysys_err.h" and return that code? +*/ static void get_options(int *argc,char **argv) { int ho_error; @@ -7953,10 +7929,11 @@ static char *get_relative_path(const char *path) } -/* +/** Fix filename and replace extension where 'dir' is relative to mysql_real_data_home. - Return 1 if len(path) > FN_REFLEN + @return + 1 if len(path) > FN_REFLEN */ bool @@ -8061,9 +8038,11 @@ static ulong find_bit_type_or_exit(const char *x, TYPELIB *bit_lib, } -/* - Return a bitfield from a string of substrings separated by ',' - returns ~(ulong) 0 on error. +/** + @return + a bitfield from a string of substrings separated by ',' + or + ~(ulong) 0 on error. */ static ulong find_bit_type(const char *x, TYPELIB *bit_lib) @@ -8122,16 +8101,16 @@ skip: ; } /* find_bit_type */ -/* - Check if file system used for databases is case insensitive +/** + Check if file system used for databases is case insensitive. - SYNOPSIS - test_if_case_sensitive() - dir_name Directory to test + @param dir_name Directory to test - RETURN + @retval -1 Don't know (Test failed) + @retval 0 File system is case sensitive + @retval 1 File system is case insensitive */ @@ -8162,10 +8141,11 @@ static int test_if_case_insensitive(const char *dir_name) } -/* Create file to store pid number */ - #ifndef EMBEDDED_LIBRARY +/** + Create file to store pid number. +*/ static void create_pid_file() { File file; @@ -8187,7 +8167,7 @@ static void create_pid_file() } #endif /* EMBEDDED_LIBRARY */ -/* Clear most status variables */ +/** Clear most status variables. */ void refresh_status(THD *thd) { pthread_mutex_lock(&LOCK_status); From 2d615a6169c26442fbfc2c54c0be792ac2f43cfb Mon Sep 17 00:00:00 2001 From: "cmiller@zippy.cornsilk.net" <> Date: Thu, 11 Oct 2007 14:37:45 -0400 Subject: [PATCH 036/336] Doxygenized comments. --- sql/net_serv.cc | 137 ++++++++------- sql/nt_servc.cc | 78 +++++---- sql/opt_sum.cc | 165 +++++++++--------- sql/parse_file.cc | 288 ++++++++++++++++--------------- sql/procedure.cc | 11 +- sql/protocol.cc | 212 ++++++++++++----------- sql/records.cc | 127 +++++++------- sql/repl_failsafe.cc | 63 ++++--- sql/set_var.cc | 196 +++++++++++---------- sql/sp.cc | 351 +++++++++++++++++++------------------- sql/sp_head.cc | 395 ++++++++++++++++++++++--------------------- 11 files changed, 1029 insertions(+), 994 deletions(-) diff --git a/sql/net_serv.cc b/sql/net_serv.cc index 1f75d7ab1d7..0fc503383ab 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -13,15 +13,16 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* +/** + @file + This file is the net layer API for the MySQL client/server protocol, which is a tightly coupled, proprietary protocol owned by MySQL AB. + @note Any re-implementations of this protocol must also be under GPL unless one has got an license from MySQL AB stating otherwise. -*/ -/* - Write and read of logical packets to/from socket + Write and read of logical packets to/from socket. Writes are cached into net_buffer_length big packets. Read packets are reallocated dynamicly when reading big packets. @@ -111,7 +112,7 @@ extern void query_cache_insert(NET *net, const char *packet, ulong length); static my_bool net_write_buff(NET *net,const uchar *packet,ulong len); - /* Init with packet info */ +/** Init with packet info. */ my_bool my_net_init(NET *net, Vio* vio) { @@ -163,7 +164,7 @@ void net_end(NET *net) } -/* Realloc the packet buffer */ +/** Realloc the packet buffer. */ my_bool net_realloc(NET *net, size_t length) { @@ -201,20 +202,17 @@ my_bool net_realloc(NET *net, size_t length) } -/* - Check if there is any data to be read from the socket +/** + Check if there is any data to be read from the socket. - SYNOPSIS - net_data_is_ready() - sd socket descriptor + @param sd socket descriptor - DESCRIPTION - Check if there is any data to be read from the socket. - - RETURN VALUES - 0 No data to read - 1 Data or EOF to read - -1 Don't know if data is ready or not + @retval + 0 No data to read + @retval + 1 Data or EOF to read + @retval + -1 Don't know if data is ready or not */ #if !defined(EMBEDDED_LIBRARY) @@ -258,16 +256,10 @@ static int net_data_is_ready(my_socket sd) #endif /* EMBEDDED_LIBRARY */ -/* +/** Remove unwanted characters from connection - and check if disconnected + and check if disconnected. - SYNOPSIS - net_clear() - net NET handler - clear_buffer If <> 0, then clear all data from communication buffer - - DESCRIPTION Read from socket until there is nothing more to read. Discard what is read. @@ -278,6 +270,8 @@ static int net_data_is_ready(my_socket sd) a FIN packet), then select() considers a socket "ready to read", in the sense that there's EOF to read, but read() returns 0. + @param net NET handler + @param clear_buffer if <> 0, then clear all data from comm buff */ void net_clear(NET *net, my_bool clear_buffer) @@ -335,7 +329,7 @@ void net_clear(NET *net, my_bool clear_buffer) } - /* Flush write_buffer if not empty. */ +/** Flush write_buffer if not empty. */ my_bool net_flush(NET *net) { @@ -358,12 +352,13 @@ my_bool net_flush(NET *net) ** Write something to server/client buffer *****************************************************************************/ -/* - Write a logical packet with packet header +/** + Write a logical packet with packet header. + Format: Packet length (3 bytes), packet number(1 byte) When compression is used a 3 byte compression length is added - NOTE + @note If compression is used the original package is modified! */ @@ -400,19 +395,9 @@ my_net_write(NET *net,const uchar *packet,size_t len) return test(net_write_buff(net,packet,len)); } -/* +/** Send a command to the server. - SYNOPSIS - net_write_command() - net NET handler - command Command in MySQL server (enum enum_server_command) - header Header to write after command - head_len Length of header - packet Query or parameter to query - len Length of packet - - DESCRIPTION The reason for having both header and packet is so that libmysql can easy add a header to a special command (like prepared statements) without having to re-alloc the string. @@ -420,11 +405,20 @@ my_net_write(NET *net,const uchar *packet,size_t len) As the command is part of the first data packet, we have to do some data juggling to put the command in there, without having to create a new packet. + This function will split big packets into sub-packets if needed. (Each sub packet can only be 2^24 bytes) - RETURN VALUES + @param net NET handler + @param command Command in MySQL server (enum enum_server_command) + @param header Header to write after command + @param head_len Length of header + @param packet Query or parameter to query + @param len Length of packet + + @retval 0 ok + @retval 1 error */ @@ -468,33 +462,30 @@ net_write_command(NET *net,uchar command, net_write_buff(net, packet, len) || net_flush(net))); } -/* +/** Caching the data in a local buffer before sending it. - SYNOPSIS - net_write_buff() - net Network handler - packet Packet to send - len Length of packet - - DESCRIPTION - Fill up net->buffer and send it to the client when full. + Fill up net->buffer and send it to the client when full. If the rest of the to-be-sent-packet is bigger than buffer, send it in one big block (to avoid copying to internal buffer). If not, copy the rest of the data to the buffer and return without sending data. - NOTES - The cached buffer can be sent as it is with 'net_flush()'. + @param net Network handler + @param packet Packet to send + @param len Length of packet + @note + The cached buffer can be sent as it is with 'net_flush()'. In this code we have to be careful to not send a packet longer than MAX_PACKET_LENGTH to net_real_write() if we are using the compressed protocol as we store the length of the compressed packet in 3 bytes. - RETURN - 0 ok - 1 + @retval + 0 ok + @retval + 1 */ static my_bool @@ -547,9 +538,12 @@ net_write_buff(NET *net, const uchar *packet, ulong len) } -/* +/** Read and write one packet using timeouts. If needed, the packet is compressed before sending. + + @todo + - TODO is it needed to set this variable if we have no socket */ int @@ -726,18 +720,17 @@ static my_bool net_safe_read(NET *net, uchar *buff, size_t length, return 0; } -/* +/** Help function to clear the commuication buffer when we get a too big packet. - SYNOPSIS - my_net_skip_rest() - net Communication handle - remain Bytes to read - alarmed Parameter for thr_alarm() - alarm_buff Parameter for thr_alarm() + @param net Communication handle + @param remain Bytes to read + @param alarmed Parameter for thr_alarm() + @param alarm_buff Parameter for thr_alarm() - RETURN VALUES + @retval 0 Was able to read the whole packet + @retval 1 Got mailformed packet from client */ @@ -780,10 +773,13 @@ static my_bool my_net_skip_rest(NET *net, uint32 remain, thr_alarm_t *alarmed, #endif /* NO_ALARM */ -/* - Reads one packet to net->buff + net->where_b - Returns length of packet. Long packets are handled by my_net_read(). +/** + Reads one packet to net->buff + net->where_b. + Long packets are handled by my_net_read(). This function reallocates the net->buff buffer if necessary. + + @return + Returns length of packet. */ static ulong @@ -972,15 +968,18 @@ end: } -/* +/** Read a packet from the client/server and return it without the internal package header. + If the packet is the first packet of a multi-packet packet (which is indicated by the length of the packet = 0xffffff) then all sub packets are read and concatenated. + If the packet was compressed, its uncompressed and the length of the uncompressed packet is returned. + @return The function returns the length of the found packet or packet_error. net->read_pos points to the read data. */ diff --git a/sql/nt_servc.cc b/sql/nt_servc.cc index a04f284a3de..7ff06d5bdf5 100644 --- a/sql/nt_servc.cc +++ b/sql/nt_servc.cc @@ -1,8 +1,12 @@ -/* ------------------------------------------------------------------------ - Windows NT Service class library - Copyright Abandoned 1998 Irena Pancirov - Irnet Snc - This file is public domain and comes with NO WARRANTY of any kind - -------------------------------------------------------------------------- */ +/** + @file + + @brief + Windows NT Service class library. + + Copyright Abandoned 1998 Irena Pancirov - Irnet Snc + This file is public domain and comes with NO WARRANTY of any kind +*/ #include #include #include @@ -73,12 +77,13 @@ BOOL NTService::GetOS() } -/* ------------------------------------------------------------------------ - Init() Registers the main service thread with the service manager +/** + Registers the main service thread with the service manager. + + @param ServiceThread pointer to the main programs entry function + when the service is started +*/ - ServiceThread - pointer to the main programs entry function - when the service is started - -------------------------------------------------------------------------- */ long NTService::Init(LPCSTR szInternName,void *ServiceThread) { @@ -99,13 +104,15 @@ long NTService::Init(LPCSTR szInternName,void *ServiceThread) } -/* ------------------------------------------------------------------------ - Install() - Installs the service with Service manager +/** + Installs the service with Service manager. + nError values: - 0 success - 1 Can't open the Service manager - 2 Failed to create service - -------------------------------------------------------------------------- */ + - 0 success + - 1 Can't open the Service manager + - 2 Failed to create service. +*/ + BOOL NTService::Install(int startType, LPCSTR szInternName, LPCSTR szDisplayName, @@ -155,14 +162,16 @@ BOOL NTService::Install(int startType, LPCSTR szInternName, } -/* ------------------------------------------------------------------------ - Remove() - Removes the service +/** + Removes the service. + nError values: - 0 success - 1 Can't open the Service manager - 2 Failed to locate service - 3 Failed to delete service - -------------------------------------------------------------------------- */ + - 0 success + - 1 Can't open the Service manager + - 2 Failed to locate service + - 3 Failed to delete service. +*/ + BOOL NTService::Remove(LPCSTR szInternName) { @@ -199,10 +208,10 @@ BOOL NTService::Remove(LPCSTR szInternName) return ret_value; } -/* ------------------------------------------------------------------------ - Stop() - this function should be called before the app. exits to stop - the service - -------------------------------------------------------------------------- */ +/** + this function should be called before the app. exits to stop + the service +*/ void NTService::Stop(void) { SetStatus(SERVICE_STOP_PENDING,NO_ERROR, 0, 1, 60000); @@ -210,10 +219,11 @@ void NTService::Stop(void) SetStatus(SERVICE_STOPPED, NO_ERROR, 0, 1, 1000); } -/* ------------------------------------------------------------------------ - ServiceMain() - This is the function that is called from the - service manager to start the service - -------------------------------------------------------------------------- */ +/** + This is the function that is called from the + service manager to start the service. +*/ + void NTService::ServiceMain(DWORD argc, LPTSTR *argv) { @@ -264,9 +274,9 @@ error: return; } -/* ------------------------------------------------------------------------ - StartService() - starts the appliaction thread - -------------------------------------------------------------------------- */ +/** + starts the appliaction thread. +*/ BOOL NTService::StartService() { diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc index 6836c53db4e..45b1fc83394 100644 --- a/sql/opt_sum.cc +++ b/sql/opt_sum.cc @@ -14,7 +14,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* +/** + @file + Optimising of MIN(), MAX() and COUNT(*) queries without 'group by' clause by replacing the aggregate expression with a constant. @@ -22,6 +24,7 @@ types of queries are optimised (assuming the table handler supports the required methods) + @verbatim SELECT COUNT(*) FROM t1[,t2,t3,...] SELECT MIN(b) FROM t1 WHERE a=const SELECT MAX(c) FROM t1 WHERE a=const AND b=const @@ -29,6 +32,7 @@ SELECT MIN(b) FROM t1 WHERE a=const AND b>const SELECT MIN(b) FROM t1 WHERE a=const AND b BETWEEN const AND const SELECT MAX(b) FROM t1 WHERE a=const AND b BETWEEN const AND const + @endverbatim Instead of '<' one can use '<=', '>', '>=' and '=' as well. Instead of 'a=const' the condition 'a IS NULL' can be used. @@ -36,10 +40,11 @@ If all selected fields are replaced then we will also remove all involved tables and return the answer without any join. Thus, the following query will be replaced with a row of two constants: + @verbatim SELECT MAX(b), MIN(d) FROM t1,t2 WHERE a=const AND bconst + @endverbatim (assuming a index for column d of table t2 is defined) - */ #include "mysql_priv.h" @@ -83,25 +88,25 @@ static ulonglong get_exact_record_count(TABLE_LIST *tables) } -/* +/** Substitutes constants for some COUNT(), MIN() and MAX() functions. - SYNOPSIS - opt_sum_query() - tables list of leaves of join table tree - all_fields All fields to be returned - conds WHERE clause + @param tables list of leaves of join table tree + @param all_fields All fields to be returned + @param conds WHERE clause - NOTE: + @note This function is only called for queries with sum functions and no GROUP BY part. - RETURN VALUES + @retval 0 no errors + @retval 1 if all items were resolved + @retval HA_ERR_KEY_NOT_FOUND on impossible conditions - OR an error number from my_base.h HA_ERR_... if a deadlock or a lock - wait timeout happens, for example + @retval + HA_ERR_... if a deadlock or a lock wait timeout happens, for example */ int opt_sum_query(TABLE_LIST *tables, List &all_fields,COND *conds) @@ -472,19 +477,18 @@ int opt_sum_query(TABLE_LIST *tables, List &all_fields,COND *conds) } -/* - Test if the predicate compares a field with constants +/** + Test if the predicate compares a field with constants. - SYNOPSIS - simple_pred() - func_item Predicate item - args out: Here we store the field followed by constants - inv_order out: Is set to 1 if the predicate is of the form - 'const op field' + @param func_item Predicate item + @param[out] args Here we store the field followed by constants + @param[out] inv_order Is set to 1 if the predicate is of the form + 'const op field' - RETURN + @retval 0 func_item is a simple predicate: a field is compared with - constants + constants + @retval 1 Otherwise */ @@ -556,34 +560,33 @@ bool simple_pred(Item_func *func_item, Item **args, bool *inv_order) } -/* - Check whether a condition matches a key to get {MAX|MIN}(field): +/** + Check whether a condition matches a key to get {MAX|MIN}(field):. - SYNOPSIS - matching_cond() - max_fl in: Set to 1 if we are optimising MAX() - ref in/out: Reference to the structure we store the key value - keyinfo in Reference to the key info - field_part in: Pointer to the key part for the field - cond in WHERE condition - key_part_used in/out: Map of matchings parts - range_fl in/out: Says whether including key will be used - prefix_len out: Length of common key part for the range - where MAX/MIN is searched for - - DESCRIPTION For the index specified by the keyinfo parameter, index that contains field as its component (field_part), the function checks whether the condition cond is a conjunction and all its conjuncts referring to the columns of the same table as column field are one of the following forms: - f_i= const_i or const_i= f_i or f_i is null, - where f_i is part of the index + where f_i is part of the index - field {<|<=|>=|>|=} const or const {<|<=|>=|>|=} field - field between const1 and const2 - RETURN + @param[in] max_fl Set to 1 if we are optimising MAX() + @param[in,out] ref Reference to the structure we store the key + value + @param[in] keyinfo Reference to the key info + @param[in] field_part Pointer to the key part for the field + @param[in] cond WHERE condition + @param[in,out] key_part_used Map of matchings parts + @param[in,out] range_fl Says whether including key will be used + @param[out] prefix_len Length of common key part for the range + where MAX/MIN is searched for + + @retval 0 Index can't be used. + @retval 1 We can use index to get MIN/MAX value */ @@ -748,31 +751,21 @@ static bool matching_cond(bool max_fl, TABLE_REF *ref, KEY *keyinfo, } -/* +/** Check whether we can get value for {max|min}(field) by using a key. - SYNOPSIS - find_key_for_maxmin() - max_fl in: 0 for MIN(field) / 1 for MAX(field) - ref in/out Reference to the structure we store the key value - field in: Field used inside MIN() / MAX() - cond in: WHERE condition - range_fl out: Bit flags for how to search if key is ok - prefix_len out: Length of prefix for the search range + If where-condition is not a conjunction of 0 or more conjuct the + function returns false, otherwise it checks whether there is an + index including field as its k-th component/part such that: - DESCRIPTION - If where condition is not a conjunction of 0 or more conjuct the - function returns false, otherwise it checks whether there is an - index including field as its k-th component/part such that: - - 1. for each previous component f_i there is one and only one conjunct + -# for each previous component f_i there is one and only one conjunct of the form: f_i= const_i or const_i= f_i or f_i is null - 2. references to field occur only in conjucts of the form: + -# references to field occur only in conjucts of the form: field {<|<=|>=|>|=} const or const {<|<=|>=|>|=} field or field BETWEEN const1 AND const2 - 3. all references to the columns from the same table as column field + -# all references to the columns from the same table as column field occur only in conjucts mentioned above. - 4. each of k first components the index is not partial, i.e. is not + -# each of k first components the index is not partial, i.e. is not defined on a fixed length proper prefix of the field. If such an index exists the function through the ref parameter @@ -780,17 +773,26 @@ static bool matching_cond(bool max_fl, TABLE_REF *ref, KEY *keyinfo, the length of first (k-1) components of the key and flags saying how to apply the key for the search max/min value. (if we have a condition field = const, prefix_len contains the length - of the whole search key) + of the whole search key) - NOTE + @param[in] max_fl 0 for MIN(field) / 1 for MAX(field) + @param[in,out] ref Reference to the structure we store the key value + @param[in] field Field used inside MIN() / MAX() + @param[in] cond WHERE condition + @param[out] range_fl Bit flags for how to search if key is ok + @param[out] prefix_len Length of prefix for the search range + + @note This function may set table->key_read to 1, which must be reset after index is used! (This can only happen when function returns 1) - RETURN + @retval 0 Index can not be used to optimize MIN(field)/MAX(field) - 1 Can use key to optimize MIN()/MAX() - In this case ref, range_fl and prefix_len are updated -*/ + @retval + 1 Can use key to optimize MIN()/MAX(). + In this case ref, range_fl and prefix_len are updated +*/ + static bool find_key_for_maxmin(bool max_fl, TABLE_REF *ref, Field* field, COND *cond, @@ -883,20 +885,19 @@ static bool find_key_for_maxmin(bool max_fl, TABLE_REF *ref, } -/* - Check whether found key is in range specified by conditions +/** + Check whether found key is in range specified by conditions. - SYNOPSIS - reckey_in_range() - max_fl in: 0 for MIN(field) / 1 for MAX(field) - ref in: Reference to the key value and info - field in: Field used the MIN/MAX expression - cond in: WHERE condition - range_fl in: Says whether there is a condition to to be checked - prefix_len in: Length of the constant part of the key + @param[in] max_fl 0 for MIN(field) / 1 for MAX(field) + @param[in] ref Reference to the key value and info + @param[in] field Field used the MIN/MAX expression + @param[in] cond WHERE condition + @param[in] range_fl Says whether there is a condition to to be checked + @param[in] prefix_len Length of the constant part of the key - RETURN + @retval 0 ok + @retval 1 WHERE was not true for the found row */ @@ -911,16 +912,16 @@ static int reckey_in_range(bool max_fl, TABLE_REF *ref, Field* field, } -/* - Check whether {MAX|MIN}(field) is in range specified by conditions - SYNOPSIS - maxmin_in_range() - max_fl in: 0 for MIN(field) / 1 for MAX(field) - field in: Field used the MIN/MAX expression - cond in: WHERE condition +/** + Check whether {MAX|MIN}(field) is in range specified by conditions. - RETURN + @param[in] max_fl 0 for MIN(field) / 1 for MAX(field) + @param[in] field Field used the MIN/MAX expression + @param[in] cond WHERE condition + + @retval 0 ok + @retval 1 WHERE was not true for the found row */ diff --git a/sql/parse_file.cc b/sql/parse_file.cc index 19fb11ac0cc..1f0a45edd5e 100644 --- a/sql/parse_file.cc +++ b/sql/parse_file.cc @@ -13,7 +13,12 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -// Text .frm files management routines +/** + @file + + @brief + Text .frm files management routines +*/ #include "mysql_priv.h" #include @@ -22,17 +27,16 @@ #include -/* - write string with escaping +/** + Write string with escaping. - SYNOPSIS - write_escaped_string() - file - IO_CACHE for record - val_s - string for writing + @param file IO_CACHE for record + @param val_s string for writing - RETURN - FALSE - OK - TRUE - error + @retval + FALSE OK + @retval + TRUE error */ static my_bool @@ -77,21 +81,21 @@ write_escaped_string(IO_CACHE *file, LEX_STRING *val_s) } -/* - write parameter value to IO_CACHE +/** + Write parameter value to IO_CACHE. - SYNOPSIS - write_parameter() - file pointer to IO_CACHE structure for writing - base pointer to data structure - parameter pointer to parameter descriptor - old_version for returning back old version number value + @param file pointer to IO_CACHE structure for writing + @param base pointer to data structure + @param parameter pointer to parameter descriptor + @param old_version for returning back old version number value - RETURN - FALSE - OK - TRUE - error + @retval + FALSE OK + @retval + TRUE error */ + static my_bool write_parameter(IO_CACHE *file, uchar* base, File_option *parameter, ulonglong *old_version) @@ -191,24 +195,24 @@ write_parameter(IO_CACHE *file, uchar* base, File_option *parameter, } -/* - write new .frm +/** + Write new .frm. - SYNOPSIS - sql_create_definition_file() - dir directory where put .frm - file .frm file name - type .frm type string (VIEW, TABLE) - base base address for parameter reading (structure like - TABLE) - parameters parameters description - max_versions number of versions to save + @param dir directory where put .frm + @param file_name .frm file name + @param type .frm type string (VIEW, TABLE) + @param base base address for parameter reading (structure like + TABLE) + @param parameters parameters description + @param max_versions number of versions to save - RETURN - FALSE - OK - TRUE - error + @retval + FALSE OK + @retval + TRUE error */ + my_bool sql_create_definition_file(const LEX_STRING *dir, const LEX_STRING *file_name, const LEX_STRING *type, @@ -345,21 +349,19 @@ err_w_file: DBUG_RETURN(TRUE); } -/* - Renames a frm file (including backups) in same schema +/** + Renames a frm file (including backups) in same schema. - SYNOPSIS - rename_in_schema_file - schema name of given schema - old_name original file name - new_name new file name - revision revision number - num_view_backups number of backups - - RETURN - 0 - OK - 1 - Error (only if renaming of frm failed) + @param schema name of given schema + @param old_name original file name + @param new_name new file name + @param revision revision number + @param num_view_backups number of backups + @retval + 0 OK + @retval + 1 Error (only if renaming of frm failed) */ my_bool rename_in_schema_file(const char *schema, const char *old_name, const char *new_name, ulonglong revision, @@ -401,21 +403,20 @@ my_bool rename_in_schema_file(const char *schema, const char *old_name, return 0; } -/* - Prepare frm to parse (read to memory) +/** + Prepare frm to parse (read to memory). - SYNOPSIS - sql_parse_prepare() - file_name - path & filename to .frm file - mem_root - MEM_ROOT for buffer allocation - bad_format_errors - send errors on bad content + @param file_name path & filename to .frm file + @param mem_root MEM_ROOT for buffer allocation + @param bad_format_errors send errors on bad content - RETURN - 0 - error - parser object - - NOTE + @note returned pointer + 1 will be type of .frm + + @return + 0 - error + @return + parser object */ File_parser * @@ -506,22 +507,22 @@ frm_error: } -/* - parse LEX_STRING +/** + parse LEX_STRING. - SYNOPSIS - parse_string() - ptr - pointer on string beginning - end - pointer on symbol after parsed string end (still owned - by buffer and can be accessed - mem_root - MEM_ROOT for parameter allocation - str - pointer on string, where results should be stored + @param ptr pointer on string beginning + @param end pointer on symbol after parsed string end (still owned + by buffer and can be accessed + @param mem_root MEM_ROOT for parameter allocation + @param str pointer on string, where results should be stored - RETURN - 0 - error - # - pointer on symbol after string + @retval + 0 error + @retval + \# pointer on symbol after string */ + static char * parse_string(char *ptr, char *end, MEM_ROOT *mem_root, LEX_STRING *str) { @@ -539,18 +540,17 @@ parse_string(char *ptr, char *end, MEM_ROOT *mem_root, LEX_STRING *str) } -/* - read escaped string from ptr to eol in already allocated str +/** + read escaped string from ptr to eol in already allocated str. - SYNOPSIS - read_escaped_string() - ptr - pointer on string beginning - eol - pointer on character after end of string - str - target string + @param ptr pointer on string beginning + @param eol pointer on character after end of string + @param str target string - RETURN - FALSE - OK - TRUE - error + @retval + FALSE OK + @retval + TRUE error */ my_bool @@ -598,22 +598,22 @@ read_escaped_string(char *ptr, char *eol, LEX_STRING *str) } -/* - parse \n delimited escaped string +/** + parse \\n delimited escaped string. - SYNOPSIS - parse_escaped_string() - ptr - pointer on string beginning - end - pointer on symbol after parsed string end (still owned - by buffer and can be accessed - mem_root - MEM_ROOT for parameter allocation - str - pointer on string, where results should be stored + @param ptr pointer on string beginning + @param end pointer on symbol after parsed string end (still owned + by buffer and can be accessed + @param mem_root MEM_ROOT for parameter allocation + @param str pointer on string, where results should be stored - RETURN - 0 - error - # - pointer on symbol after string + @retval + 0 error + @retval + \# pointer on symbol after string */ + char * parse_escaped_string(char *ptr, char *end, MEM_ROOT *mem_root, LEX_STRING *str) { @@ -628,20 +628,19 @@ parse_escaped_string(char *ptr, char *end, MEM_ROOT *mem_root, LEX_STRING *str) } -/* - parse '' delimited escaped string +/** + parse '' delimited escaped string. - SYNOPSIS - parse_quoted_escaped_string() - ptr - pointer on string beginning - end - pointer on symbol after parsed string end (still owned - by buffer and can be accessed - mem_root - MEM_ROOT for parameter allocation - str - pointer on string, where results should be stored + @param ptr pointer on string beginning + @param end pointer on symbol after parsed string end (still owned + by buffer and can be accessed + @param mem_root MEM_ROOT for parameter allocation + @param str pointer on string, where results should be stored - RETURN - 0 - error - # - pointer on symbol after string + @retval + 0 error + @retval + \# pointer on symbol after string */ static char * @@ -673,18 +672,16 @@ parse_quoted_escaped_string(char *ptr, char *end, } -/* +/** Parser for FILE_OPTIONS_ULLLIST type value. - SYNOPSIS - get_file_options_ulllist() - ptr [in/out] pointer to parameter - end [in] end of the configuration - line [in] pointer to the line begining - base [in] base address for parameter writing (structure - like TABLE) - parameter [in] description - mem_root [in] MEM_ROOT for parameters allocation + @param[in,out] ptr pointer to parameter + @param[in] end end of the configuration + @param[in] line pointer to the line begining + @param[in] base base address for parameter writing (structure + like TABLE) + @param[in] parameter description + @param[in] mem_root MEM_ROOT for parameters allocation */ bool get_file_options_ulllist(char *&ptr, char *end, char *line, @@ -728,28 +725,28 @@ nlist_err: } -/* - parse parameters +/** + parse parameters. - SYNOPSIS - File_parser::parse() - base base address for parameter writing (structure like - TABLE) - mem_root MEM_ROOT for parameters allocation - parameters parameters description - required number of parameters in the above list. If the file - contains more parameters than "required", they will - be ignored. If the file contains less parameters - then "required", non-existing parameters will - remain their values. - hook hook called for unknown keys - hook_data some data specific for the hook + @param base base address for parameter writing (structure like + TABLE) + @param mem_root MEM_ROOT for parameters allocation + @param parameters parameters description + @param required number of required parameters in above list. If the file + contains more parameters than "required", they will + be ignored. If the file contains less parameters + then "required", non-existing parameters will + remain their values. + @param hook hook called for unknown keys + @param hook_data some data specific for the hook - RETURN - FALSE - OK - TRUE - error + @retval + FALSE OK + @retval + TRUE error */ + my_bool File_parser::parse(uchar* base, MEM_ROOT *mem_root, struct File_option *parameters, uint required, @@ -935,26 +932,25 @@ list_err: } -/* - Dummy unknown key hook +/** + Dummy unknown key hook. - SYNOPSIS - File_parser_dummy_hook::process_unknown_string() - unknown_key [in/out] reference on the line with unknown - parameter and the parsing point - base [in] base address for parameter writing (structure like - TABLE) - mem_root [in] MEM_ROOT for parameters allocation - end [in] the end of the configuration + @param[in,out] unknown_key reference on the line with unknown + parameter and the parsing point + @param[in] base base address for parameter writing + (structure like TABLE) + @param[in] mem_root MEM_ROOT for parameters allocation + @param[in] end the end of the configuration - NOTE + @note This hook used to catch no longer supported keys and process them for backward compatibility, but it will not slow down processing of modern format files. This hook does nothing except debug output. - RETURN + @retval FALSE OK + @retval TRUE Error */ diff --git a/sql/procedure.cc b/sql/procedure.cc index bbfabc46608..c993ba976ac 100644 --- a/sql/procedure.cc +++ b/sql/procedure.cc @@ -68,10 +68,13 @@ my_decimal *Item_proc_real::val_decimal(my_decimal *decimal_value) } -/***************************************************************************** -** Setup handling of procedure -** Return 0 if everything is ok -*****************************************************************************/ +/** + Setup handling of procedure. + + @return + Return 0 if everything is ok +*/ + Procedure * setup_procedure(THD *thd,ORDER *param,select_result *result, diff --git a/sql/protocol.cc b/sql/protocol.cc index 2ed241c4c98..66313d74b80 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -13,8 +13,10 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* - Low level functions for storing data to be send to the MySQL client +/** + @file + + Low level functions for storing data to be send to the MySQL client. The actual communction is handled by the net_xxx functions in net_serv.cc */ @@ -53,17 +55,18 @@ bool Protocol_binary::net_store_data(const uchar *from, size_t length) } -/* - Send a error string to client +/** + Send a error string to client. - Design note: + Design note: - net_printf_error and net_send_error are low-level functions - that shall be used only when a new connection is being - established or at server startup. - For SIGNAL/RESIGNAL and GET DIAGNOSTICS functionality it's - critical that every error that can be intercepted is issued in one - place only, my_message_sql. + net_printf_error and net_send_error are low-level functions + that shall be used only when a new connection is being + established or at server startup. + + For SIGNAL/RESIGNAL and GET DIAGNOSTICS functionality it's + critical that every error that can be intercepted is issued in one + place only, my_message_sql. */ void net_send_error(THD *thd, uint sql_errno, const char *err) { @@ -120,19 +123,22 @@ void net_send_error(THD *thd, uint sql_errno, const char *err) DBUG_VOID_RETURN; } -/* - Write error package and flush to client - It's a little too low level, but I don't want to use another buffer for - this +/** + Write error package and flush to client. - Design note: + @note + It's a little too low level, but I don't want to use another buffer for + this. - net_printf_error and net_send_error are low-level functions - that shall be used only when a new connection is being - established or at server startup. - For SIGNAL/RESIGNAL and GET DIAGNOSTICS functionality it's - critical that every error that can be intercepted is issued in one - place only, my_message_sql. + Design note: + + net_printf_error and net_send_error are low-level functions + that shall be used only when a new connection is being + established or at server startup. + + For SIGNAL/RESIGNAL and GET DIAGNOSTICS functionality it's + critical that every error that can be intercepted is issued in one + place only, my_message_sql. */ void @@ -239,31 +245,28 @@ net_printf_error(THD *thd, uint errcode, ...) DBUG_VOID_RETURN; } -/* +/** Return ok to the client. - SYNOPSIS - send_ok() - thd Thread handler - affected_rows Number of rows changed by statement - id Auto_increment id for first row (if used) - message Message to send to the client (Used by mysql_status) + The ok packet has the following structure: - DESCRIPTION - The ok packet has the following structure + - 0 : Marker (1 byte) + - affected_rows : Stored in 1-9 bytes + - id : Stored in 1-9 bytes + - server_status : Copy of thd->server_status; Can be used by client + to check if we are inside an transaction. + New in 4.0 protocol + - warning_count : Stored in 2 bytes; New in 4.1 protocol + - message : Stored as packed length (1-9 bytes) + message. + Is not stored if no message. - 0 Marker (1 byte) - affected_rows Stored in 1-9 bytes - id Stored in 1-9 bytes - server_status Copy of thd->server_status; Can be used by client - to check if we are inside an transaction - New in 4.0 protocol - warning_count Stored in 2 bytes; New in 4.1 protocol - message Stored as packed length (1-9 bytes) + message - Is not stored if no message + If net->no_send_ok return without sending packet. - If net->no_send_ok return without sending packet -*/ + @param thd Thread handler + @param affected_rows Number of rows changed by statement + @param id Auto_increment id for first row (if used) + @param message Message to send to the client (Used by mysql_status) +*/ #ifndef EMBEDDED_LIBRARY void @@ -319,27 +322,24 @@ send_ok(THD *thd, ha_rows affected_rows, ulonglong id, const char *message) static uchar eof_buff[1]= { (uchar) 254 }; /* Marker for end of fields */ -/* - Send eof (= end of result set) to the client +/** + Send eof (= end of result set) to the client. - SYNOPSIS - send_eof() - thd Thread handler - no_flush Set to 1 if there will be more data to the client, - like in send_fields(). + The eof packet has the following structure: - DESCRIPTION - The eof packet has the following structure + - 254 : Marker (1 byte) + - warning_count : Stored in 2 bytes; New in 4.1 protocol + - status_flag : Stored in 2 bytes; + For flags like SERVER_MORE_RESULTS_EXISTS. - 254 Marker (1 byte) - warning_count Stored in 2 bytes; New in 4.1 protocol - status_flag Stored in 2 bytes; - For flags like SERVER_MORE_RESULTS_EXISTS + Note that the warning count will not be sent if 'no_flush' is set as + we don't want to report the warning count until all data is sent to the + client. - Note that the warning count will not be sent if 'no_flush' is set as - we don't want to report the warning count until all data is sent to the - client. -*/ + @param thd Thread handler + @param no_flush Set to 1 if there will be more data to the client, + like in send_fields(). +*/ void send_eof(THD *thd) @@ -357,7 +357,7 @@ send_eof(THD *thd) } -/* +/** Format EOF packet according to the current protocol and write it to the network output buffer. */ @@ -388,15 +388,15 @@ static void write_eof_packet(THD *thd, NET *net) VOID(my_net_write(net, eof_buff, 1)); } -/* - Please client to send scrambled_password in old format. - SYNOPSYS - send_old_password_request() - thd thread handle - - RETURN VALUE - 0 ok - !0 error +/** + Please client to send scrambled_password in old format. + + @param thd thread handle + + @retval + 0 ok + @retval + !0 error */ bool send_old_password_request(THD *thd) @@ -450,14 +450,15 @@ void net_send_error_packet(THD *thd, uint sql_errno, const char *err) #endif /* EMBEDDED_LIBRARY */ -/* +/** Faster net_store_length when we know that length is less than 65536. We keep a separate version for that range because it's widely used in libmysql. + uint is used as agrument type because of MySQL type conventions: - uint for 0..65536 - ulong for 0..4294967296 - ulonglong for bigger numbers. + - uint for 0..65536 + - ulong for 0..4294967296 + - ulonglong for bigger numbers. */ static uchar *net_store_length_fast(uchar *packet, uint length) @@ -530,27 +531,26 @@ bool Protocol::flush() #endif } -/* +#ifndef EMBEDDED_LIBRARY + +/** Send name and type of result to client. - SYNOPSIS - send_fields() - THD Thread data object - list List of items to send to client - flag Bit mask with the following functions: - 1 send number of rows - 2 send default values - 4 don't write eof packet + Sum fields has table name empty and field_name. - DESCRIPTION - Sum fields has table name empty and field_name. + @param THD Thread data object + @param list List of items to send to client + @param flag Bit mask with the following functions: + - 1 send number of rows + - 2 send default values + - 4 don't write eof packet - RETURN VALUES + @retval 0 ok - 1 Error (Note that in this case the error is not sent to the client) + @retval + 1 Error (Note that in this case the error is not sent to the + client) */ - -#ifndef EMBEDDED_LIBRARY bool Protocol::send_fields(List *list, uint flags) { List_iterator_fast it(*list); @@ -704,18 +704,17 @@ bool Protocol::write() #endif /* EMBEDDED_LIBRARY */ -/* - Send \0 end terminated string +/** + Send \\0 end terminated string. - SYNOPSIS - store() - from NullS or \0 terminated string + @param from NullS or \\0 terminated string - NOTES + @note In most cases one should use store(from, length) instead of this function - RETURN VALUES + @retval 0 ok + @retval 1 error */ @@ -728,8 +727,8 @@ bool Protocol::store(const char *from, CHARSET_INFO *cs) } -/* - Send a set of strings as one long string with ',' in between +/** + Send a set of strings as one long string with ',' in between. */ bool Protocol::store(I_List* str_list) @@ -781,7 +780,7 @@ bool Protocol_text::store_null() #endif -/* +/** Auxilary function to convert string to the given character set and store in network buffer. */ @@ -957,13 +956,12 @@ bool Protocol_text::store(Field *field) } -/* - TODO: - Second_part format ("%06") needs to change when - we support 0-6 decimals for time. +/** + @todo + Second_part format ("%06") needs to change when + we support 0-6 decimals for time. */ - bool Protocol_text::store(MYSQL_TIME *tm) { #ifndef DBUG_OFF @@ -1001,10 +999,10 @@ bool Protocol_text::store_date(MYSQL_TIME *tm) } -/* - TODO: - Second_part format ("%06") needs to change when - we support 0-6 decimals for time. +/** + @todo + Second_part format ("%06") needs to change when + we support 0-6 decimals for time. */ bool Protocol_text::store_time(MYSQL_TIME *tm) diff --git a/sql/records.cc b/sql/records.cc index 81c26da4b4d..f095a2ebef9 100644 --- a/sql/records.cc +++ b/sql/records.cc @@ -14,7 +14,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* Functions for easy reading of records, possible through a cache */ +/** + @file + + @brief + Functions for easy reading of records, possible through a cache +*/ #include "mysql_priv.h" @@ -31,25 +36,20 @@ static int rr_index_first(READ_RECORD *info); static int rr_index(READ_RECORD *info); -/* - Initialize READ_RECORD structure to perform full index scan +/** + Initialize READ_RECORD structure to perform full index scan (in forward + direction) using read_record.read_record() interface. - SYNOPSIS - init_read_record_idx() - info READ_RECORD structure to initialize. - thd Thread handle - table Table to be accessed - print_error If true, call table->file->print_error() if an error - occurs (except for end-of-records error) - idx index to scan - - DESCRIPTION - Initialize READ_RECORD structure to perform full index scan (in forward - direction) using read_record.read_record() interface. - This function has been added at late stage and is used only by UPDATE/DELETE. Other statements perform index scans using join_read_first/next functions. + + @param info READ_RECORD structure to initialize. + @param thd Thread handle + @param table Table to be accessed + @param print_error If true, call table->file->print_error() if an error + occurs (except for end-of-records error) + @param idx index to scan */ void init_read_record_idx(READ_RECORD *info, THD *thd, TABLE *table, @@ -284,7 +284,7 @@ static int rr_handle_error(READ_RECORD *info, int error) } - /* Read a record from head-database */ +/** Read a record from head-database. */ static int rr_quick(READ_RECORD *info) { @@ -306,20 +306,19 @@ static int rr_quick(READ_RECORD *info) } -/* - Reads first row in an index scan +/** + Reads first row in an index scan. - SYNOPSIS - rr_index_first() - info Scan info - - RETURN + @param info Scan info + + @retval 0 Ok - -1 End of records - 1 Error + @retval + -1 End of records + @retval + 1 Error */ - static int rr_index_first(READ_RECORD *info) { int tmp= info->file->index_first(info->record); @@ -330,24 +329,22 @@ static int rr_index_first(READ_RECORD *info) } -/* - Reads index sequentially after first row +/** + Reads index sequentially after first row. - SYNOPSIS - rr_index() - info Scan info - - DESCRIPTION - Read the next index record (in forward direction) and translate return - value. - - RETURN + Read the next index record (in forward direction) and translate return + value. + + @param info Scan info + + @retval 0 Ok - -1 End of records - 1 Error + @retval + -1 End of records + @retval + 1 Error */ - static int rr_index(READ_RECORD *info) { int tmp= info->file->index_next(info->record); @@ -401,22 +398,20 @@ static int rr_from_tempfile(READ_RECORD *info) } /* rr_from_tempfile */ -/* - Read a result set record from a temporary file after sorting +/** + Read a result set record from a temporary file after sorting. - SYNOPSIS - rr_unpack_from_tempfile() - info Reference to the context including record descriptors + The function first reads the next sorted record from the temporary file. + into a buffer. If a success it calls a callback function that unpacks + the fields values use in the result set from this buffer into their + positions in the regular record buffer. - DESCRIPTION - The function first reads the next sorted record from the temporary file. - into a buffer. If a success it calls a callback function that unpacks - the fields values use in the result set from this buffer into their - positions in the regular record buffer. + @param info Reference to the context including record descriptors - RETURN - 0 - Record successfully read. - -1 - There is no record to be read anymore. + @retval + 0 Record successfully read. + @retval + -1 There is no record to be read anymore. */ static int rr_unpack_from_tempfile(READ_RECORD *info) @@ -454,22 +449,20 @@ static int rr_from_pointers(READ_RECORD *info) return tmp; } -/* - Read a result set record from a buffer after sorting +/** + Read a result set record from a buffer after sorting. - SYNOPSIS - rr_unpack_from_buffer() - info Reference to the context including record descriptors + The function first reads the next sorted record from the sort buffer. + If a success it calls a callback function that unpacks + the fields values use in the result set from this buffer into their + positions in the regular record buffer. - DESCRIPTION - The function first reads the next sorted record from the sort buffer. - If a success it calls a callback function that unpacks - the fields values use in the result set from this buffer into their - positions in the regular record buffer. + @param info Reference to the context including record descriptors - RETURN - 0 - Record successfully read. - -1 - There is no record to be read anymore. + @retval + 0 Record successfully read. + @retval + -1 There is no record to be read anymore. */ static int rr_unpack_from_buffer(READ_RECORD *info) diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index 834d87532af..619cf3a4e73 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -13,6 +13,16 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/** + @file + + All of the functions defined in this file which are not used (the ones to + handle failsafe) are not used; their code has not been updated for more + than one year now so should be considered as BADLY BROKEN. Do not enable + it. The used functions (to handle LOAD DATA FROM MASTER, plus some small + functions like register_slave()) are working. +*/ + #include "mysql_priv.h" #ifdef HAVE_REPLICATION @@ -144,12 +154,13 @@ void unregister_slave(THD* thd, bool only_mine, bool need_mutex) } -/* - Register slave in 'slave_list' hash table +/** + Register slave in 'slave_list' hash table. - RETURN VALUES - 0 ok - 1 Error. Error message sent to client + @return + 0 ok + @return + 1 Error. Error message sent to client */ int register_slave(THD* thd, uchar* packet, uint packet_length) @@ -252,7 +263,8 @@ static int find_target_pos(LEX_MASTER_INFO *mi, IO_CACHE *log, char *errmsg) /* Impossible */ } -/* +/** + @details Before 4.0.15 we had a member of THD called log_pos, it was meant for failsafe replication code in repl_failsafe.cc which is disabled until it is reworked. Event's log_pos used to be preserved through @@ -388,8 +400,8 @@ err: } -/* - Caller must delete result when done +/** + Caller must delete result when done. */ static Slave_log_event* find_slave_event(IO_CACHE* log, @@ -428,9 +440,11 @@ static Slave_log_event* find_slave_event(IO_CACHE* log, return (Slave_log_event*)ev; } -/* - This function is broken now. See comment for translate_master(). - */ +/** + This function is broken now. + + @seealso translate_master() +*/ bool show_new_master(THD* thd) { @@ -466,20 +480,19 @@ bool show_new_master(THD* thd) } } -/* +/** Asks the master for the list of its other connected slaves. - This is for failsafe replication: + + This is for failsafe replication: in order for failsafe replication to work, the servers involved in replication must know of each other. We accomplish this by having each slave report to the master how to reach it, and on connection, each slave receives information about where the other slaves are. - SYNOPSIS - update_slave_list() - mysql pre-existing connection to the master - mi master info + @param mysql pre-existing connection to the master + @param mi master info - NOTES + @note mi is used only to give detailed error messages which include the hostname/port of the master, the username used by the slave to connect to the master. @@ -487,10 +500,11 @@ bool show_new_master(THD* thd) REPLICATION SLAVE privilege, it will pop in this function because SHOW SLAVE HOSTS will fail on the master. - RETURN VALUES + @retval 1 error + @retval 0 success - */ +*/ int update_slave_list(MYSQL* mysql, Master_info* mi) { @@ -754,11 +768,16 @@ static int fetch_db_tables(THD *thd, MYSQL *mysql, const char *db, return 0; } -/* +/** Load all MyISAM tables from master to this slave. REQUIREMENTS - - No active transaction (flush_relay_log_info would not work in this case) + - No active transaction (flush_relay_log_info would not work in this case). + + @todo + - add special option, not enabled + by default, to allow inclusion of mysql database into load + data from master */ bool load_master_data(THD* thd) diff --git a/sql/set_var.cc b/sql/set_var.cc index ec82b56d793..759ceb40729 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -13,9 +13,13 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* +/** + @file + + @brief Handling of MySQL SQL variables + @details To add a new variable, one has to do the following: - Use one of the 'sys_var... classes from set_var.h or write a specific @@ -28,18 +32,19 @@ - Don't forget to initialize new fields in global_system_variables and max_system_variables! - NOTES: - - Be careful with var->save_result: sys_var::check() only updates + @todo + Add full support for the variable character_set (for 4.1) + + @todo + When updating myisam_delay_key_write, we should do a 'flush tables' + of all MyISAM tables to ensure that they are reopen with the + new attribute. + + @note + Be careful with var->save_result: sys_var::check() only updates ulonglong_value; so other members of the union are garbage then; to use them you must first assign a value to them (in specific ::check() for example). - - TODO: - - Add full support for the variable character_set (for 4.1) - - - When updating myisam_delay_key_write, we should do a 'flush tables' - of all MyISAM tables to ensure that they are reopen with the - new attribute. */ #ifdef USE_PRAGMA_IMPLEMENTATION @@ -819,9 +824,9 @@ static void sys_default_ftb_syntax(THD *thd, enum_var_type type) } -/* +/** If one sets the LOW_PRIORIY UPDATES flag, we also must change the - used lock type + used lock type. */ static void fix_low_priority_updates(THD *thd, enum_var_type type) @@ -843,8 +848,8 @@ fix_myisam_max_sort_file_size(THD *thd, enum_var_type type) (my_off_t) global_system_variables.myisam_max_sort_file_size; } -/* - Set the OPTION_BIG_SELECTS flag if max_join_size == HA_POS_ERROR +/** + Set the OPTION_BIG_SELECTS flag if max_join_size == HA_POS_ERROR. */ static void fix_max_join_size(THD *thd, enum_var_type type) @@ -859,7 +864,7 @@ static void fix_max_join_size(THD *thd, enum_var_type type) } -/* +/** Can't change the 'next' tx_isolation while we are already in a transaction */ @@ -875,7 +880,7 @@ static int check_tx_isolation(THD *thd, set_var *var) /* If one doesn't use the SESSION modifier, the isolation level - is only active for the next command + is only active for the next command. */ static void fix_tx_isolation(THD *thd, enum_var_type type) { @@ -1447,9 +1452,12 @@ err: } -/* - Return an Item for a variable. Used with @@[global.]variable_name - If type is not given, return local value if exists, else global +/** + Return an Item for a variable. + + Used with @@[global.]variable_name. + + If type is not given, return local value if exists, else global. */ Item *sys_var::item(THD *thd, enum_var_type var_type, LEX_STRING *base) @@ -1611,7 +1619,7 @@ uchar *sys_var_thd_bit::value_ptr(THD *thd, enum_var_type type, } -/* Update a date_time format variable based on given value */ +/** Update a date_time format variable based on given value. */ void sys_var_thd_date_time_format::update2(THD *thd, enum_var_type type, DATE_TIME_FORMAT *new_value) @@ -2028,6 +2036,12 @@ end: } +/** + @todo + Abort if some other thread is changing the key cache. + This should be changed so that we wait until the previous + assignment is done and then do the new assign +*/ bool sys_var_key_cache_long::update(THD *thd, set_var *var) { ulong tmp= (ulong) var->value->val_int(); @@ -2720,23 +2734,20 @@ static uchar *get_error_count(THD *thd) } -/* - Get the tmpdir that was specified or chosen by default +/** + Get the tmpdir that was specified or chosen by default. - SYNOPSIS - get_tmpdir() - thd thread handle + This is necessary because if the user does not specify a temporary + directory via the command line, one is chosen based on the environment + or system defaults. But we can't just always use mysql_tmpdir, because + that is actually a call to my_tmpdir() which cycles among possible + temporary directories. - DESCRIPTION - This is necessary because if the user does not specify a temporary - directory via the command line, one is chosen based on the environment - or system defaults. But we can't just always use mysql_tmpdir, because - that is actually a call to my_tmpdir() which cycles among possible - temporary directories. + @param thd thread handle - RETURN VALUES + @retval ptr pointer to NUL-terminated string - */ +*/ static uchar *get_tmpdir(THD *thd) { if (opt_mysql_tmpdir) @@ -2751,16 +2762,16 @@ static uchar *get_tmpdir(THD *thd) - Update loop ****************************************************************************/ -/* - Find variable name in option my_getopt structure used for command line args +/** + Find variable name in option my_getopt structure used for + command line args. - SYNOPSIS - find_option() - opt option structure array to search in - name variable name + @param opt option structure array to search in + @param name variable name - RETURN VALUES + @retval 0 Error + @retval ptr pointer to option structure */ @@ -2783,8 +2794,8 @@ static struct my_option *find_option(struct my_option *opt, const char *name) } -/* - Return variable name and length for hashing of variables +/** + Return variable name and length for hashing of variables. */ static uchar *get_sys_var_length(const sys_var *var, size_t *length, @@ -2986,17 +2997,17 @@ int mysql_append_static_vars(const SHOW_VAR *show_vars, uint count) } -/* - Find a user set-table variable +/** + Find a user set-table variable. - SYNOPSIS - intern_find_sys_var() - str Name of system variable to find - length Length of variable. zero means that we should use strlen() - on the variable + @param str Name of system variable to find + @param length Length of variable. zero means that we should use strlen() + on the variable + @param no_error Refuse to emit an error, even if one occurred. - RETURN VALUES + @retval pointer pointer to variable definitions + @retval 0 Unknown variable (error message is given) */ @@ -3017,25 +3028,23 @@ sys_var *intern_find_sys_var(const char *str, uint length, bool no_error) } -/* - Execute update of all variables +/** + Execute update of all variables. - SYNOPSIS + First run a check of all variables that all updates will go ok. + If yes, then execute all updates, returning an error if any one failed. - sql_set - THD Thread id - set_var List of variables to update + This should ensure that in all normal cases none all or variables are + updated. - DESCRIPTION - First run a check of all variables that all updates will go ok. - If yes, then execute all updates, returning an error if any one failed. + @param THD Thread id + @param var_list List of variables to update - This should ensure that in all normal cases none all or variables are - updated - - RETURN VALUE + @retval 0 ok + @retval 1 ERROR, message sent (normally no variables was updated) + @retval -1 ERROR, message not sent */ @@ -3064,20 +3073,19 @@ err: } -/* - Say if all variables set by a SET support the ONE_SHOT keyword (currently, - only character set and collation do; later timezones will). +/** + Say if all variables set by a SET support the ONE_SHOT keyword + (currently, only character set and collation do; later timezones + will). - SYNOPSIS + @param var_list List of variables to update - not_all_support_one_shot - set_var List of variables to update - - NOTES + @note It has a "not_" because it makes faster tests (no need to "!") - RETURN VALUE + @retval 0 all variables of the list support ONE_SHOT + @retval 1 at least one does not support ONE_SHOT */ @@ -3136,17 +3144,17 @@ int set_var::check(THD *thd) } -/* - Check variable, but without assigning value (used by PS) +/** + Check variable, but without assigning value (used by PS). - SYNOPSIS - set_var::light_check() - thd thread handler + @param thd thread handler - RETURN VALUE + @retval 0 ok + @retval 1 ERROR, message sent (normally no variables was updated) - -1 ERROR, message not sent + @retval + -1 ERROR, message not sent */ int set_var::light_check(THD *thd) { @@ -3193,17 +3201,17 @@ int set_var_user::check(THD *thd) } -/* - Check variable, but without assigning value (used by PS) +/** + Check variable, but without assigning value (used by PS). - SYNOPSIS - set_var_user::light_check() - thd thread handler + @param thd thread handler - RETURN VALUE + @retval 0 ok + @retval 1 ERROR, message sent (normally no variables was updated) - -1 ERROR, message not sent + @retval + -1 ERROR, message not sent */ int set_var_user::light_check(THD *thd) { @@ -3377,13 +3385,15 @@ bool sys_var_thd_table_type::update(THD *thd, set_var *var) Functions to handle sql_mode ****************************************************************************/ -/* - Make string representation of mode +/** + Make string representation of mode. - SYNOPSIS - thd in thread handler - val in sql_mode value - rep out pointer pointer to string with sql_mode representation + @param[in] thd thread handler + @param[in] val sql_mode value + @param[out] len pointer on length of string + + @return + pointer to string with sql_mode representation */ bool @@ -3454,7 +3464,7 @@ void fix_sql_mode_var(THD *thd, enum_var_type type) } } -/* Map database specific bits to function bits */ +/** Map database specific bits to function bits. */ ulong fix_sql_mode(ulong sql_mode) { diff --git a/sql/sp.cc b/sql/sp.cc index 6032688f7f1..ec37a64abd0 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -249,19 +249,18 @@ Stored_routine_creation_ctx::load_from_db(THD *thd, /*************************************************************************/ -/* +/** Open the mysql.proc table for read. - SYNOPSIS - open_proc_table_for_read() - thd Thread context - backup Pointer to Open_tables_state instance where information about - currently open tables will be saved, and from which will be - restored when we will end work with mysql.proc. + @param thd Thread context + @param backup Pointer to Open_tables_state instance where information about + currently open tables will be saved, and from which will be + restored when we will end work with mysql.proc. - RETURN + @retval 0 Error - # Pointer to TABLE object of mysql.proc + @retval + \# Pointer to TABLE object of mysql.proc */ TABLE *open_proc_table_for_read(THD *thd, Open_tables_state *backup) @@ -281,19 +280,18 @@ TABLE *open_proc_table_for_read(THD *thd, Open_tables_state *backup) } -/* +/** Open the mysql.proc table for update. - SYNOPSIS - open_proc_table_for_update() - thd Thread context + @param thd Thread context - NOTES + @note Table opened with this call should closed using close_thread_tables(). - RETURN + @retval 0 Error - # Pointer to TABLE object of mysql.proc + @retval + \# Pointer to TABLE object of mysql.proc */ static TABLE *open_proc_table_for_update(THD *thd) @@ -310,19 +308,18 @@ static TABLE *open_proc_table_for_update(THD *thd) } -/* +/** Find row in open mysql.proc table representing stored routine. - SYNOPSIS - db_find_routine_aux() - thd Thread context - type Type of routine to find (function or procedure) - name Name of routine - table TABLE object for open mysql.proc table. + @param thd Thread context + @param type Type of routine to find (function or procedure) + @param name Name of routine + @param table TABLE object for open mysql.proc table. - RETURN VALUE - SP_OK - Routine found - SP_KEY_NOT_FOUND- No routine with given name + @retval + SP_OK Routine found + @retval + SP_KEY_NOT_FOUND No routine with given name */ static int @@ -357,25 +354,24 @@ db_find_routine_aux(THD *thd, int type, sp_name *name, TABLE *table) } -/* +/** Find routine definition in mysql.proc table and create corresponding sp_head object for it. - SYNOPSIS - db_find_routine() - thd Thread context - type Type of routine (TYPE_ENUM_PROCEDURE/...) - name Name of routine - sphp Out parameter in which pointer to created sp_head - object is returned (0 in case of error). + @param thd Thread context + @param type Type of routine (TYPE_ENUM_PROCEDURE/...) + @param name Name of routine + @param sphp Out parameter in which pointer to created sp_head + object is returned (0 in case of error). - NOTE + @note This function may damage current LEX during execution, so it is good idea to create temporary LEX and make it active before calling it. - RETURN VALUE - 0 - Success - non-0 - Error (may be one of special codes like SP_KEY_NOT_FOUND) + @retval + 0 Success + @retval + non-0 Error (may be one of special codes like SP_KEY_NOT_FOUND) */ static int @@ -1284,22 +1280,21 @@ sp_show_create_routine(THD *thd, int type, sp_name *name) } -/* +/** Obtain object representing stored procedure/function by its name from stored procedures cache and looking into mysql.proc if needed. - SYNOPSIS - sp_find_routine() - thd - thread context - type - type of object (TYPE_ENUM_FUNCTION or TYPE_ENUM_PROCEDURE) - name - name of procedure - cp - hash to look routine in - cache_only - if true perform cache-only lookup - (Don't look in mysql.proc). + @param thd thread context + @param type type of object (TYPE_ENUM_FUNCTION or TYPE_ENUM_PROCEDURE) + @param name name of procedure + @param cp hash to look routine in + @param cache_only if true perform cache-only lookup + (Don't look in mysql.proc). - RETURN VALUE - Non-0 pointer to sp_head object for the procedure, or - 0 - in case of error. + @retval + NonNULL pointer to sp_head object for the procedure + @retval + NULL in case of error. */ sp_head * @@ -1395,7 +1390,7 @@ sp_find_routine(THD *thd, int type, sp_name *name, sp_cache **cp, } -/* +/** This is used by sql_acl.cc:mysql_routine_grant() and is used to find the routines in 'routines'. */ @@ -1444,18 +1439,17 @@ sp_exist_routines(THD *thd, TABLE_LIST *routines, bool any, bool no_error) } -/* +/** Check if a routine exists in the mysql.proc table, without actually - parsing the definition. (Used for dropping) + parsing the definition. (Used for dropping). - SYNOPSIS - sp_routine_exists_in_table() - thd - thread context - name - name of procedure + @param thd thread context + @param name name of procedure - RETURN VALUE - 0 - Success - non-0 - Error; SP_OPEN_TABLE_FAILED or SP_KEY_NOT_FOUND + @retval + 0 Success + @retval + non-0 Error; SP_OPEN_TABLE_FAILED or SP_KEY_NOT_FOUND */ int @@ -1477,7 +1471,7 @@ sp_routine_exists_in_table(THD *thd, int type, sp_name *name) } -/* +/** Structure that represents element in the set of stored routines used by statement or routine. */ @@ -1485,14 +1479,16 @@ struct Sroutine_hash_entry; struct Sroutine_hash_entry { - /* Set key consisting of one-byte routine type and quoted routine name. */ + /** + Set key consisting of one-byte routine type and quoted routine name. + */ LEX_STRING key; - /* + /** Next element in list linking all routines in set. See also comments for LEX::sroutine/sroutine_list and sp_head::m_sroutines. */ Sroutine_hash_entry *next; - /* + /** Uppermost view which directly or indirectly uses this routine. 0 if routine is not used in view. Note that it also can be 0 if statement uses routine both via view and directly. @@ -1510,24 +1506,22 @@ extern "C" uchar* sp_sroutine_key(const uchar *ptr, size_t *plen, } -/* +/** Check if - current statement (the one in thd->lex) needs table prelocking - first routine in thd->lex->sroutines_list needs to execute its body in prelocked mode. - SYNOPSIS - sp_get_prelocking_info() - thd Current thread, thd->lex is the statement to be - checked. - need_prelocking OUT TRUE - prelocked mode should be activated - before executing the statement - FALSE - Don't activate prelocking - first_no_prelocking OUT TRUE - Tables used by first routine in - thd->lex->sroutines_list should be - prelocked. - FALSE - Otherwise. - NOTES + @param thd Current thread, thd->lex is the statement to be + checked. + @param[out] need_prelocking TRUE - prelocked mode should be activated + before executing the statement; + FALSE - Don't activate prelocking + @param[out] first_no_prelocking TRUE - Tables used by first routine in + thd->lex->sroutines_list should be + prelocked. FALSE - Otherwise. + + @note This function assumes that for any "CALL proc(...)" statement routines_list will have 'proc' as first element (it may have several, consider e.g. "proc(sp_func(...)))". This property is currently guaranted by the parser. @@ -1547,36 +1541,37 @@ void sp_get_prelocking_info(THD *thd, bool *need_prelocking, } -/* +/** Auxilary function that adds new element to the set of stored routines used by statement. - SYNOPSIS - add_used_routine() - lex LEX representing statement - arena Arena in which memory for new element will be allocated - key Key for the hash representing set - belong_to_view Uppermost view which uses this routine - (0 if routine is not used by view) + In case when statement uses stored routines but does not need + prelocking (i.e. it does not use any tables) we will access the + elements of LEX::sroutines set on prepared statement re-execution. + Because of this we have to allocate memory for both hash element + and copy of its key in persistent arena. - NOTES + @param lex LEX representing statement + @param arena Arena in which memory for new element will be + allocated + @param key Key for the hash representing set + @param belong_to_view Uppermost view which uses this routine + (0 if routine is not used by view) + + @note Will also add element to end of 'LEX::sroutines_list' list. - In case when statement uses stored routines but does not need - prelocking (i.e. it does not use any tables) we will access the - elements of LEX::sroutines set on prepared statement re-execution. - Because of this we have to allocate memory for both hash element - and copy of its key in persistent arena. - - TODO + @todo When we will got rid of these accesses on re-executions we will be able to allocate memory for hash elements in non-persitent arena and directly use key values from sp_head::m_sroutines sets instead of making their copies. - RETURN VALUE - TRUE - new element was added. - FALSE - element was not added (because it is already present in the set). + @retval + TRUE new element was added. + @retval + FALSE element was not added (because it is already present in + the set). */ static bool add_used_routine(LEX *lex, Query_arena *arena, @@ -1606,24 +1601,22 @@ static bool add_used_routine(LEX *lex, Query_arena *arena, } -/* +/** Add routine which is explicitly used by statement to the set of stored routines used by this statement. - SYNOPSIS - sp_add_used_routine() - lex - LEX representing statement - arena - arena in which memory for new element of the set - will be allocated - rt - routine name - rt_type - routine type (one of TYPE_ENUM_PROCEDURE/...) + To be friendly towards prepared statements one should pass + persistent arena as second argument. - NOTES + @param lex LEX representing statement + @param arena arena in which memory for new element of the set + will be allocated + @param rt routine name + @param rt_type routine type (one of TYPE_ENUM_PROCEDURE/...) + + @note Will also add element to end of 'LEX::sroutines_list' list (and will take into account that this is explicitly used routine). - - To be friendly towards prepared statements one should pass - persistent arena as second argument. */ void sp_add_used_routine(LEX *lex, Query_arena *arena, @@ -1636,13 +1629,11 @@ void sp_add_used_routine(LEX *lex, Query_arena *arena, } -/* +/** Remove routines which are only indirectly used by statement from the set of routines used by this statement. - SYNOPSIS - sp_remove_not_own_routines() - lex LEX representing statement + @param lex LEX representing statement */ void sp_remove_not_own_routines(LEX *lex) @@ -1665,16 +1656,14 @@ void sp_remove_not_own_routines(LEX *lex) } -/* +/** Merge contents of two hashes representing sets of routines used by statements or by other routines. - SYNOPSIS - sp_update_sp_used_routines() - dst - hash to which elements should be added - src - hash from which elements merged + @param dst hash to which elements should be added + @param src hash from which elements merged - NOTE + @note This procedure won't create new Sroutine_hash_entry objects, instead it will simply add elements from source to destination hash. Thus time of life of elements in destination hash becomes @@ -1694,18 +1683,17 @@ void sp_update_sp_used_routines(HASH *dst, HASH *src) } -/* +/** Add contents of hash representing set of routines to the set of routines used by statement. - SYNOPSIS - sp_update_stmt_used_routines() - thd Thread context - lex LEX representing statement - src Hash representing set from which routines will be added - belong_to_view Uppermost view which uses these routines, 0 if none + @param thd Thread context + @param lex LEX representing statement + @param src Hash representing set from which routines will + be added + @param belong_to_view Uppermost view which uses these routines, 0 if none - NOTE + @note It will also add elements to end of 'LEX::sroutines_list' list. */ @@ -1721,18 +1709,17 @@ sp_update_stmt_used_routines(THD *thd, LEX *lex, HASH *src, } -/* +/** Add contents of list representing set of routines to the set of routines used by statement. - SYNOPSIS - sp_update_stmt_used_routines() - thd Thread context - lex LEX representing statement - src List representing set from which routines will be added - belong_to_view Uppermost view which uses these routines, 0 if none + @param thd Thread context + @param lex LEX representing statement + @param src List representing set from which routines will + be added + @param belong_to_view Uppermost view which uses these routines, 0 if none - NOTE + @note It will also add elements to end of 'LEX::sroutines_list' list. */ @@ -1745,27 +1732,28 @@ static void sp_update_stmt_used_routines(THD *thd, LEX *lex, SQL_LIST *src, } -/* +/** Cache sub-set of routines used by statement, add tables used by these routines to statement table list. Do the same for all routines used by these routines. - SYNOPSIS - sp_cache_routines_and_add_tables_aux() - thd - thread context - lex - LEX representing statement - start - first routine from the list of routines to be cached - (this list defines mentioned sub-set). - first_no_prelock - If true, don't add tables or cache routines used by - the body of the first routine (i.e. *start) - will be executed in non-prelocked mode. - NOTE + @param thd thread context + @param lex LEX representing statement + @param start first routine from the list of routines to be cached + (this list defines mentioned sub-set). + @param first_no_prelock If true, don't add tables or cache routines used by + the body of the first routine (i.e. *start) + will be executed in non-prelocked mode. + @param tabs_changed Set to TRUE some tables were added, FALSE otherwise + + @note If some function is missing this won't be reported here. Instead this fact will be discovered during query execution. - RETURN VALUE - 0 - success - non-0 - failure + @retval + 0 success + @retval + non-0 failure */ static int @@ -1857,21 +1845,20 @@ sp_cache_routines_and_add_tables_aux(THD *thd, LEX *lex, } -/* +/** Cache all routines from the set of used by statement, add tables used by those routines to statement table list. Do the same for all routines used by those routines. - SYNOPSIS - sp_cache_routines_and_add_tables() - thd - thread context - lex - LEX representing statement - first_no_prelock - If true, don't add tables or cache routines used by - the body of the first routine (i.e. *start) + @param thd thread context + @param lex LEX representing statement + @param first_no_prelock If true, don't add tables or cache routines used by + the body of the first routine (i.e. *start) - RETURN VALUE - 0 - success - non-0 - failure + @retval + 0 success + @retval + non-0 failure */ int @@ -1883,20 +1870,21 @@ sp_cache_routines_and_add_tables(THD *thd, LEX *lex, bool first_no_prelock) } -/* - Add all routines used by view to the set of routines used by statement. +/** + Add all routines used by view to the set of routines used by + statement. + Add tables used by those routines to statement table list. Do the same for all routines used by these routines. - SYNOPSIS - sp_cache_routines_and_add_tables_for_view() - thd Thread context - lex LEX representing statement - view Table list element representing view + @param thd Thread context + @param lex LEX representing statement + @param view Table list element representing view - RETURN VALUE - 0 - success - non-0 - failure + @retval + 0 success + @retval + non-0 failure */ int @@ -1911,20 +1899,19 @@ sp_cache_routines_and_add_tables_for_view(THD *thd, LEX *lex, TABLE_LIST *view) } -/* +/** Add triggers for table to the set of routines used by statement. Add tables used by them to statement table list. Do the same for all implicitly used routines. - SYNOPSIS - sp_cache_routines_and_add_tables_for_triggers() - thd thread context - lex LEX respresenting statement - table Table list element for table with trigger + @param thd thread context + @param lex LEX respresenting statement + @param table Table list element for table with trigger - RETURN VALUE - 0 - success - non-0 - failure + @retval + 0 success + @retval + non-0 failure */ int @@ -1970,10 +1957,12 @@ sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex, } -/* - * Generates the CREATE... string from the table information. - * Returns TRUE on success, FALSE on (alloc) failure. - */ +/** + Generates the CREATE... string from the table information. + + @return + Returns TRUE on success, FALSE on (alloc) failure. +*/ static bool create_string(THD *thd, String *buf, int type, diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 828517011d5..a84b54b3cf8 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -80,19 +80,20 @@ sp_map_item_type(enum enum_field_types type) } -/* +/** Return a string representation of the Item value. - NOTE: If the item has a string result type, the string is escaped - according to its character set. + @param thd thread handle + @param str string buffer for representation of the value - SYNOPSIS - item a pointer to the Item - str string buffer for representation of the value + @note + If the item has a string result type, the string is escaped + according to its character set. - RETURN - NULL on error - a pointer to valid a valid string on success + @retval + NULL on error + @retval + non-NULL a pointer to valid a valid string on success */ static String * @@ -137,16 +138,12 @@ sp_get_item_value(THD *thd, Item *item, String *str) } -/* - SYNOPSIS - sp_get_flags_for_command() - - DESCRIPTION - Returns a combination of: - * sp_head::MULTI_RESULTS: added if the 'cmd' is a command that might - result in multiple result sets being sent back. - * sp_head::CONTAINS_DYNAMIC_SQL: added if 'cmd' is one of PREPARE, - EXECUTE, DEALLOCATE. +/** + Returns a combination of: + - sp_head::MULTI_RESULTS: added if the 'cmd' is a command that might + result in multiple result sets being sent back. + - sp_head::CONTAINS_DYNAMIC_SQL: added if 'cmd' is one of PREPARE, + EXECUTE, DEALLOCATE. */ uint @@ -286,17 +283,16 @@ sp_get_flags_for_command(LEX *lex) return flags; } -/* +/** Prepare an Item for evaluation (call of fix_fields). - SYNOPSIS - sp_prepare_func_item() - thd thread handler - it_addr pointer on item refernce + @param thd thread handler + @param it_addr pointer on item refernce - RETURN - NULL error - prepared item + @retval + NULL error + @retval + non-NULL prepared item */ Item * @@ -316,17 +312,16 @@ sp_prepare_func_item(THD* thd, Item **it_addr) } -/* +/** Evaluate an expression and store the result in the field. - SYNOPSIS - sp_eval_expr() - thd - current thread object - expr_item - the root item of the expression - result_field - the field to store the result + @param thd current thread object + @param result_field the field to store the result + @param expr_item_ptr the root item of the expression - RETURN VALUES + @retval FALSE on success + @retval TRUE on error */ @@ -386,6 +381,9 @@ sp_eval_expr(THD *thd, Field *result_field, Item **expr_item_ptr) * */ +/** + Init the qualified name from the db and name. +*/ void sp_name::init_qname(THD *thd) { @@ -400,16 +398,17 @@ sp_name::init_qname(THD *thd) } -/* - Check that the name 'ident' is ok. It's assumed to be an 'ident' +/** + Check that the name 'ident' is ok. It's assumed to be an 'ident' from the parser, so we only have to check length and trailing spaces. The former is a standard requirement (and 'show status' assumes a non-empty name), the latter is a mysql:ism as trailing spaces are removed by get_field(). - - RETURN - TRUE - bad name - FALSE - name is ok + + @retval + TRUE bad name + @retval + FALSE name is ok */ bool @@ -417,7 +416,7 @@ check_routine_name(LEX_STRING *ident) { if (!ident || !ident->str || !ident->str[0] || ident->str[ident->length-1] == ' ') - { + { my_error(ER_SP_WRONG_NAME, MYF(0), ident->str); return TRUE; } @@ -742,7 +741,7 @@ sp_head::destroy() } -/* +/** This is only used for result fields from functions (both during fix_length_and_dec() and evaluation). */ @@ -861,29 +860,23 @@ int cmp_splocal_locations(Item_splocal * const *a, Item_splocal * const *b) */ -/* - Replace thd->query{_length} with a string that one can write to the binlog - or the query cache. - - SYNOPSIS - subst_spvars() - thd Current thread. - instr Instruction (we look for Item_splocal instances in - instr->free_list) - query_str Original query string - - DESCRIPTION +/** + Replace thd->query{_length} with a string that one can write to + the binlog. The binlog-suitable string is produced by replacing references to SP local - variables with NAME_CONST('sp_var_name', value) calls. To make this string - suitable for the query cache this function allocates some additional space - for the query cache flags. - - RETURN - FALSE on success - thd->query{_length} either has been appropriately replaced or there - is no need for replacements. - TRUE out of memory error. + variables with NAME_CONST('sp_var_name', value) calls. + + @param thd Current thread. + @param instr Instruction (we look for Item_splocal instances in + instr->free_list) + @param query_str Original query string + + @return + - FALSE on success. + thd->query{_length} either has been appropriately replaced or there + is no need for replacements. + - TRUE out of memory error. */ static bool @@ -1002,14 +995,17 @@ void sp_head::recursion_level_error(THD *thd) } -/* - Execute the routine. The main instruction jump loop is there +/** + Execute the routine. The main instruction jump loop is there. Assume the parameters already set. - - RETURN - FALSE on success - TRUE on error + @todo + - Will write this SP statement into binlog separately + (TODO: consider changing the condition to "not inside event union") + @retval + FALSE on success + @retval + TRUE on error */ bool @@ -1299,22 +1295,26 @@ sp_head::execute(THD *thd) #ifndef NO_EMBEDDED_ACCESS_CHECKS -/* +/** set_routine_security_ctx() changes routine security context, and checks if there is an EXECUTE privilege in new context. If there is no EXECUTE privilege, it changes the context back and returns a error. - SYNOPSIS - set_routine_security_ctx() - thd thread handle - sp stored routine to change the context for - is_proc TRUE is procedure, FALSE if function - save_ctx pointer to an old security context - - RETURN - TRUE if there was a error, and the context wasn't changed. - FALSE if the context was changed. + @param thd thread handle + @param sp stored routine to change the context for + @param is_proc TRUE is procedure, FALSE if function + @param save_ctx pointer to an old security context + + @todo + - Cache if the definer has the right to use the object on the + first usage and only reset the cache if someone does a GRANT + statement that 'may' affect this. + + @retval + TRUE if there was a error, and the context wasn't changed. + @retval + FALSE if the context was changed. */ bool @@ -1356,22 +1356,27 @@ set_routine_security_ctx(THD *thd, sp_head *sp, bool is_proc, /** Execute trigger stored program. - Execute a trigger: - - changes security context for triggers; - - switch to new memroot; - - call sp_head::execute; - - restore old memroot; - - restores security context. + - changes security context for triggers + - switch to new memroot + - call sp_head::execute + - restore old memroot + - restores security context - @param thd Thread context. - @param db_name Database name. - @param table_name Table name. - @param grant_info GRANT_INFO structure to be filled with information - about definer's privileges on subject table. + @param thd Thread handle + @param db database name + @param table table name + @param grant_info GRANT_INFO structure to be filled with + information about definer's privileges + on subject table - @return Error status. - @retval FALSE on success. - @retval TRUE on error. + @todo + - TODO: we should create sp_rcontext once per command and reuse it + on subsequent executions of a trigger. + + @retval + FALSE on success + @retval + TRUE on error */ bool @@ -1479,8 +1484,9 @@ err_with_cleanup: } -/* - Execute a function: +/** + Execute a function. + - evaluate parameters - changes security context for SUID routines - switch to new memroot @@ -1489,17 +1495,25 @@ err_with_cleanup: - evaluate the return value - restores security context - SYNOPSIS - sp_head::execute_function() - thd Thread handle - argp Passed arguments (these are items from containing - statement?) - argcount Number of passed arguments. We need to check if this is - correct. - return_value_fld Save result here. - - RETURN + @param thd Thread handle + @param argp Passed arguments (these are items from containing + statement?) + @param argcount Number of passed arguments. We need to check if + this is correct. + @param return_value_fld Save result here. + + @todo + We should create sp_rcontext once per command and reuse + it on subsequent executions of a function/trigger. + + @todo + In future we should associate call arena/mem_root with + sp_rcontext and allocate all these objects (and sp_rcontext + itself) on it directly rather than juggle with arenas. + + @retval FALSE on success + @retval TRUE on error */ @@ -1716,14 +1730,8 @@ err_with_cleanup: } -/* +/** Execute a procedure. - SYNOPSIS - sp_head::execute_procedure() - thd Thread handle - args List of values passed as arguments. - - DESCRIPTION The function does the following steps: - Set all parameters @@ -1732,8 +1740,12 @@ err_with_cleanup: - copy back values of INOUT and OUT parameters - restores security context - RETURN + @param thd Thread handle + @param args List of values passed as arguments. + + @retval FALSE on success + @retval TRUE on error */ @@ -1935,7 +1947,7 @@ sp_head::execute_procedure(THD *thd, List *args) } -// Reset lex during parsing, before we parse a sub statement. +/// Reset lex during parsing, before we parse a sub statement. void sp_head::reset_lex(THD *thd) { @@ -1968,7 +1980,7 @@ sp_head::reset_lex(THD *thd) DBUG_VOID_RETURN; } -// Restore lex during parsing, after we have parsed a sub statement. +/// Restore lex during parsing, after we have parsed a sub statement. void sp_head::restore_lex(THD *thd) { @@ -2011,6 +2023,9 @@ sp_head::restore_lex(THD *thd) DBUG_VOID_RETURN; } +/** + Put the instruction on the backpatch list, associated with the label. +*/ void sp_head::push_backpatch(sp_instr *i, sp_label_t *lab) { @@ -2024,6 +2039,10 @@ sp_head::push_backpatch(sp_instr *i, sp_label_t *lab) } } +/** + Update all instruction with this label in the backpatch list to + the current position. +*/ void sp_head::backpatch(sp_label_t *lab) { @@ -2038,19 +2057,18 @@ sp_head::backpatch(sp_label_t *lab) } } -/* +/** Prepare an instance of Create_field for field creation (fill all necessary attributes). - SYNOPSIS - sp_head::fill_field_definition() - thd [IN] Thread handle - lex [IN] Yacc parsing context - field_type [IN] Field type - field_def [OUT] An instance of Create_field to be filled + @param[in] thd Thread handle + @param[in] lex Yacc parsing context + @param[in] field_type Field type + @param[out] field_def An instance of create_field to be filled - RETURN + @retval FALSE on success + @retval TRUE on error */ @@ -2196,18 +2214,17 @@ sp_head::restore_thd_mem_root(THD *thd) } -/* - Check if a user has access right to a routine +/** + Check if a user has access right to a routine. - SYNOPSIS - check_show_routine_access() - thd Thread handler - sp SP - full_access Set to 1 if the user has SELECT right to the - 'mysql.proc' able or is the owner of the routine - RETURN - 0 ok - 1 error + @param thd Thread handler + @param sp SP + @param full_access Set to 1 if the user has SELECT right to the + 'mysql.proc' able or is the owner of the routine + @retval + false ok + @retval + true error */ bool check_show_routine_access(THD *thd, sp_head *sp, bool *full_access) @@ -2334,12 +2351,10 @@ sp_head::show_create_routine(THD *thd, int type) -/* - Add instruction to SP +/** + Add instruction to SP. - SYNOPSIS - sp_head::add_instr() - instr Instruction + @param instr Instruction */ void sp_head::add_instr(sp_instr *instr) @@ -2357,20 +2372,20 @@ void sp_head::add_instr(sp_instr *instr) } -/* +/** Do some minimal optimization of the code: - 1) Mark used instructions - 1.1) While doing this, shortcut jumps to jump instructions - 2) Compact the code, removing unused instructions + -# Mark used instructions + -# While doing this, shortcut jumps to jump instructions + -# Compact the code, removing unused instructions. This is the main mark and move loop; it relies on the following methods in sp_instr and its subclasses: - opt_mark() Mark instruction as reachable - opt_shortcut_jump() Shortcut jumps to the final destination; - used by opt_mark(). - opt_move() Update moved instruction - set_destination() Set the new destination (jump instructions only) + - opt_mark() : Mark instruction as reachable + - opt_shortcut_jump(): Shortcut jumps to the final destination; + used by opt_mark(). + - opt_move() : Update moved instruction + - set_destination() : Set the new destination (jump instructions only) */ void sp_head::optimize() @@ -2461,9 +2476,10 @@ sp_head::opt_mark() #ifndef DBUG_OFF -/* +/** Return the routine instructions as a result set. - Returns 0 if ok, !=0 on error. + @return + 0 if ok, !=0 on error. */ int sp_head::show_routine_code(THD *thd) @@ -2526,27 +2542,25 @@ sp_head::show_routine_code(THD *thd) #endif // ifndef DBUG_OFF -/* +/** Prepare LEX and thread for execution of instruction, if requested open and lock LEX's tables, execute instruction's core function, perform cleanup afterwards. - SYNOPSIS - reset_lex_and_exec_core() - thd - thread context - nextp - out - next instruction - open_tables - if TRUE then check read access to tables in LEX's table - list and open and lock them (used in instructions which - need to calculate some expression and don't execute - complete statement). - sp_instr - instruction for which we prepare context, and which core - function execute by calling its exec_core() method. + @param thd thread context + @param nextp out - next instruction + @param open_tables if TRUE then check read access to tables in LEX's table + list and open and lock them (used in instructions which + need to calculate some expression and don't execute + complete statement). + @param sp_instr instruction for which we prepare context, and which core + function execute by calling its exec_core() method. - NOTE + @note We are not saving/restoring some parts of THD which may need this because we do this once for whole routine execution in sp_head::execute(). - RETURN VALUE + @return 0/non-0 - Success/Failure */ @@ -3300,6 +3314,11 @@ sp_instr_cpop::print(String *str) sp_instr_copen class functions */ +/** + @todo + Assert that we either have an error or a cursor +*/ + int sp_instr_copen::execute(THD *thd, uint *nextp) { @@ -3621,24 +3640,23 @@ uchar *sp_table_key(const uchar *ptr, size_t *plen, my_bool first) } -/* +/** Merge the list of tables used by some query into the multi-set of tables used by routine. - SYNOPSIS - merge_table_list() - thd - thread context - table - table list - lex_for_tmp_check - LEX of the query for which we are merging - table list. + @param thd thread context + @param table table list + @param lex_for_tmp_check LEX of the query for which we are merging + table list. - NOTE + @note This method will use LEX provided to check whenever we are creating temporary table and mark it as such in target multi-set. - RETURN VALUE - TRUE - Success - FALSE - Error + @retval + TRUE Success + @retval + FALSE Error */ bool @@ -3726,27 +3744,26 @@ sp_head::merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check) } -/* +/** Add tables used by routine to the table list. - SYNOPSIS - add_used_tables_to_table_list() - thd [in] Thread context - query_tables_last_ptr [in/out] Pointer to the next_global member of - last element of the list where tables - will be added (or to its root). - belong_to_view [in] Uppermost view which uses this routine, - 0 if none. - - DESCRIPTION Converts multi-set of tables used by this routine to table list and adds this list to the end of table list specified by 'query_tables_last_ptr'. Elements of list will be allocated in PS memroot, so this list will be persistent between PS executions. - RETURN VALUE - TRUE - if some elements were added, FALSE - otherwise. + @param[in] thd Thread context + @param[in,out] query_tables_last_ptr Pointer to the next_global member of + last element of the list where tables + will be added (or to its root). + @param[in] belong_to_view Uppermost view which uses this routine, + 0 if none. + + @retval + TRUE if some elements were added + @retval + FALSE otherwise. */ bool @@ -3816,7 +3833,7 @@ sp_head::add_used_tables_to_table_list(THD *thd, } -/* +/** Simple function for adding an explicetly named (systems) table to the global table list, e.g. "mysql", "proc". */ From bcef0be8a6c8b67b2691ac5b3b2a84989ff8e0ff Mon Sep 17 00:00:00 2001 From: "mats@kindahl-laptop.dnsalias.net" <> Date: Fri, 12 Oct 2007 18:22:31 +0200 Subject: [PATCH 037/336] BUG#29549 (Endians: rpl_ndb_myisam2ndb,rpl_ndb_innodb2ndb and rpl_ndb_mix_innodb failed on): Post-merge fixes. Setting write bit before calling Field::store() since the function asserts that the write bit has been set. --- sql/field.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/sql/field.cc b/sql/field.cc index a872beab726..29a4fcc1947 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -7962,6 +7962,7 @@ const uchar *Field_blob::unpack(uchar *to, param_data > 0 ? param_data & 0xFF : packlength; uint32 const length= get_length(from, master_packlength, low_byte_first); DBUG_DUMP("packed", from, length + master_packlength); + bitmap_set_bit(table->write_set, field_index); store(reinterpret_cast(from) + master_packlength, length, field_charset); DBUG_DUMP("record", to, table->s->reclength); From ed0ab76e28d7a90c94732b689c18dabb1becd920 Mon Sep 17 00:00:00 2001 From: "aelkin/elkin@koti.dsl.inet.fi" <> Date: Sat, 13 Oct 2007 15:49:42 +0300 Subject: [PATCH 038/336] Bug #29136 erred multi-delete on trans table does not rollback the statement similar to bug_27716, but it was stressed on in the synopsis on that there is another side of the artifact affecting behaviour in transaction. Fixed with deploying multi_delete::send_error() - otherwise never called - and refining its logic to perform binlogging job if needed. The changeset includes the following side effects: - added tests to check bug_23333's scenarios on the mixture of tables for multi_update; - fixes bug@30763 with two-liner patch and a test coinciding to one added for bug_23333. --- mysql-test/r/innodb.result | 17 ++++- mysql-test/r/mix_innodb_myisam_binlog.result | 52 ++++++++++++-- mysql-test/r/multi_update.result | 24 ++++++- mysql-test/t/innodb.test | 32 +++++++++ mysql-test/t/mix_innodb_myisam_binlog.test | 76 ++++++++++++++++++-- mysql-test/t/multi_update.test | 34 +++++++++ sql/sql_class.h | 10 +++ sql/sql_delete.cc | 29 ++++++-- sql/sql_parse.cc | 7 ++ sql/sql_update.cc | 22 +++--- 10 files changed, 274 insertions(+), 29 deletions(-) diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index 6082a30bce3..38b26425ec8 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -1119,6 +1119,19 @@ show master status /* there must be no UPDATE query event */; File Position Binlog_Do_DB Binlog_Ignore_DB master-bin.000001 98 drop table t1, t2; +drop table if exists t1, t2; +CREATE TABLE t1 (a int, PRIMARY KEY (a)); +CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; +create trigger trg_del_t2 after delete on t2 for each row +insert into t1 values (1); +insert into t1 values (1); +insert into t2 values (1),(2); +delete t2 from t2; +ERROR 23000: Duplicate entry '1' for key 1 +select count(*) from t2 /* must be 2 as restored after rollback caused by the error */; +count(*) +2 +drop table t1, t2; create table t1 (a int, b int) engine=innodb; insert into t1 values(20,null); select t2.b, ifnull(t2.b,"this is null") from t1 as t2 left join t1 as t3 on @@ -1792,10 +1805,10 @@ Variable_name Value Innodb_page_size 16384 show status like "Innodb_rows_deleted"; Variable_name Value -Innodb_rows_deleted 72 +Innodb_rows_deleted 73 show status like "Innodb_rows_inserted"; Variable_name Value -Innodb_rows_inserted 29732 +Innodb_rows_inserted 29734 show status like "Innodb_rows_updated"; Variable_name Value Innodb_rows_updated 29532 diff --git a/mysql-test/r/mix_innodb_myisam_binlog.result b/mysql-test/r/mix_innodb_myisam_binlog.result index 5d5726c9689..89ee82e9655 100644 --- a/mysql-test/r/mix_innodb_myisam_binlog.result +++ b/mysql-test/r/mix_innodb_myisam_binlog.result @@ -351,7 +351,7 @@ drop function if exists bug27417; drop table if exists t1,t2; CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; CREATE TABLE t2 (a int NOT NULL auto_increment, PRIMARY KEY (a)); -create function bug27417(n int) +create function bug27417(n int) RETURNS int(11) begin insert into t1 values (null); @@ -393,7 +393,9 @@ count(*) drop table t1,t2; CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; -CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); +CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique) ENGINE=MyISAM; +CREATE TABLE t4 (a int, PRIMARY KEY (a), b int unique) ENGINE=Innodb; +CREATE TABLE t5 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; insert into t2 values (1); reset master; insert into t2 values (bug27417(1)); @@ -427,6 +429,31 @@ master-bin.000001 190 select count(*) from t1 /* must be 2 */; count(*) 2 +delete from t3; +delete from t4; +insert into t3 values (1,1); +insert into t4 values (1,1),(2,2); +reset master; +UPDATE t4,t3 SET t4.a=t3.a + bug27417(1) /* top level non-ta table */; +ERROR 23000: Duplicate entry '2' for key 1 +show master status /* the offset must denote there is the query */; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 301 +select count(*) from t1 /* must be 4 */; +count(*) +4 +delete from t1; +delete from t3; +delete from t4; +insert into t3 values (1,1),(2,2); +insert into t4 values (1,1),(2,2); +reset master; +UPDATE t3,t4 SET t3.a=t4.a + bug27417(1); +ERROR 23000: Duplicate entry '2' for key 1 +select count(*) from t1 /* must be 1 */; +count(*) +1 +drop table t4; delete from t1; delete from t2; delete from t3; @@ -443,6 +470,23 @@ master-bin.000001 246 select count(*) from t1 /* must be 1 */; count(*) 1 +drop trigger trg_del; +delete from t1; +delete from t2; +delete from t5; +create trigger trg_del_t2 after delete on t2 for each row +insert into t1 values (1); +insert into t2 values (2),(3); +insert into t5 values (1),(2); +reset master; +delete t2.* from t2,t5 where t2.a=t5.a + 1; +ERROR 23000: Duplicate entry '1' for key 1 +show master status /* the offset must denote there is the query */; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 274 +select count(*) from t1 /* must be 1 */; +count(*) +1 delete from t1; create table t4 (a int default 0, b int primary key) engine=innodb; insert into t4 values (0, 17); @@ -458,7 +502,7 @@ count(*) show master status /* the offset must denote there is the query */; File Position Binlog_Do_DB Binlog_Ignore_DB master-bin.000001 376 -drop trigger trg_del; -drop table t1,t2,t3,t4; +drop trigger trg_del_t2; +drop table t1,t2,t3,t4,t5; drop function bug27417; end of tests diff --git a/mysql-test/r/multi_update.result b/mysql-test/r/multi_update.result index 0f624e3ee8d..d95036090a5 100644 --- a/mysql-test/r/multi_update.result +++ b/mysql-test/r/multi_update.result @@ -545,7 +545,7 @@ a b 4 4 show master status /* there must be the UPDATE query event */; File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 189 +master-bin.000001 260 delete from t1; delete from t2; insert into t1 values (1,2),(3,4),(4,4); @@ -555,6 +555,26 @@ UPDATE t2,t1 SET t2.a=t2.b where t2.a=t1.a; ERROR 23000: Duplicate entry '4' for key 1 show master status /* there must be the UPDATE query event */; File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 204 +master-bin.000001 275 drop table t1, t2; +drop table if exists t1, t2, t3; +CREATE TABLE t1 (a int, PRIMARY KEY (a)); +CREATE TABLE t2 (a int, PRIMARY KEY (a)); +CREATE TABLE t3 (a int, PRIMARY KEY (a)) ENGINE=MyISAM; +create trigger trg_del_t3 before delete on t3 for each row insert into t1 values (1); +insert into t2 values (1),(2); +insert into t3 values (1),(2); +reset master; +delete t3.* from t2,t3 where t2.a=t3.a; +ERROR 23000: Duplicate entry '1' for key 1 +select count(*) from t1 /* must be 1 */; +count(*) +1 +select count(*) from t3 /* must be 1 */; +count(*) +1 +show binlog events from 98; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 98 Query 1 # use `test`; delete t3.* from t2,t3 where t2.a=t3.a +drop table t1, t2, t3; end of tests diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index 04dfa1d0836..d045bad39f7 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -792,6 +792,38 @@ show master status /* there must be no UPDATE query event */; # cleanup bug#27716 drop table t1, t2; +# +# Bug #29136 erred multi-delete on trans table does not rollback +# + +# prepare +--disable_warnings +drop table if exists t1, t2; +--enable_warnings +CREATE TABLE t1 (a int, PRIMARY KEY (a)); +CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; +create trigger trg_del_t2 after delete on t2 for each row + insert into t1 values (1); +insert into t1 values (1); +insert into t2 values (1),(2); + + +# exec cases A, B - see multi_update.test + +# A. send_error() w/o send_eof() branch + +--error ER_DUP_ENTRY +delete t2 from t2; + +# check + +select count(*) from t2 /* must be 2 as restored after rollback caused by the error */; + +# cleanup bug#29136 + +drop table t1, t2; + + # # Testing of IFNULL # diff --git a/mysql-test/t/mix_innodb_myisam_binlog.test b/mysql-test/t/mix_innodb_myisam_binlog.test index e1740bda03e..e0ce802254a 100644 --- a/mysql-test/t/mix_innodb_myisam_binlog.test +++ b/mysql-test/t/mix_innodb_myisam_binlog.test @@ -347,7 +347,7 @@ CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; CREATE TABLE t2 (a int NOT NULL auto_increment, PRIMARY KEY (a)); delimiter |; -create function bug27417(n int) +create function bug27417(n int) RETURNS int(11) begin insert into t1 values (null); @@ -385,13 +385,17 @@ drop table t1,t2; # # Bug#23333 using the patch (and the test) for bug#27471 +# # throughout the bug tests # t1 - non-trans side effects gatherer; # t2 - transactional table; # + CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; -CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); +CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique) ENGINE=MyISAM; +CREATE TABLE t4 (a int, PRIMARY KEY (a), b int unique) ENGINE=Innodb; +CREATE TABLE t5 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; # @@ -434,7 +438,7 @@ CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); select count(*) from t1 /* must be 2 */; # -# UPDATE (multi-update see bug#27716) +# UPDATE inc multi-update # # prepare @@ -450,9 +454,48 @@ CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); show master status /* the offset must denote there is the query */; select count(*) from t1 /* must be 2 */; +## multi_update::send_eof() branch + +# prepare + delete from t3; + delete from t4; + insert into t3 values (1,1); + insert into t4 values (1,1),(2,2); + + reset master; + +# execute + --error ER_DUP_ENTRY + UPDATE t4,t3 SET t4.a=t3.a + bug27417(1) /* top level non-ta table */; + +# check + show master status /* the offset must denote there is the query */; + select count(*) from t1 /* must be 4 */; + +## send_error() branch of multi_update + +# prepare + delete from t1; + delete from t3; + delete from t4; + insert into t3 values (1,1),(2,2); + insert into t4 values (1,1),(2,2); + + reset master; + +# execute + --error ER_DUP_ENTRY + UPDATE t3,t4 SET t3.a=t4.a + bug27417(1); + +# check + select count(*) from t1 /* must be 1 */; + +# cleanup + drop table t4; + # -# DELETE (for multi-delete see Bug #29136) +# DELETE incl multi-delete # # prepare @@ -472,6 +515,27 @@ CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); show master status /* the offset must denote there is the query */; select count(*) from t1 /* must be 1 */; +# cleanup + drop trigger trg_del; + +# prepare + delete from t1; + delete from t2; + delete from t5; + create trigger trg_del_t2 after delete on t2 for each row + insert into t1 values (1); + insert into t2 values (2),(3); + insert into t5 values (1),(2); + reset master; + +# execute + --error ER_DUP_ENTRY + delete t2.* from t2,t5 where t2.a=t5.a + 1; + +# check + show master status /* the offset must denote there is the query */; + select count(*) from t1 /* must be 1 */; + # # LOAD DATA @@ -496,8 +560,8 @@ CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); # -drop trigger trg_del; -drop table t1,t2,t3,t4; +drop trigger trg_del_t2; +drop table t1,t2,t3,t4,t5; drop function bug27417; diff --git a/mysql-test/t/multi_update.test b/mysql-test/t/multi_update.test index 84e6a444d47..37cdfcf5f26 100644 --- a/mysql-test/t/multi_update.test +++ b/mysql-test/t/multi_update.test @@ -574,4 +574,38 @@ show master status /* there must be the UPDATE query event */; # cleanup bug#27716 drop table t1, t2; +# +# Bug #29136 erred multi-delete on trans table does not rollback +# + +# prepare +--disable_warnings +drop table if exists t1, t2, t3; +--enable_warnings +CREATE TABLE t1 (a int, PRIMARY KEY (a)); +CREATE TABLE t2 (a int, PRIMARY KEY (a)); +CREATE TABLE t3 (a int, PRIMARY KEY (a)) ENGINE=MyISAM; +create trigger trg_del_t3 before delete on t3 for each row insert into t1 values (1); + +insert into t2 values (1),(2); +insert into t3 values (1),(2); +reset master; + +# exec cases B, A - see innodb.test + +# B. send_eof() and send_error() afterward + +--error ER_DUP_ENTRY +delete t3.* from t2,t3 where t2.a=t3.a; + +# check +select count(*) from t1 /* must be 1 */; +select count(*) from t3 /* must be 1 */; +# the query must be in binlog (no surprise though) +source include/show_binlog_events.inc; + +# cleanup bug#29136 +drop table t1, t2, t3; + + --echo end of tests diff --git a/sql/sql_class.h b/sql/sql_class.h index a96000a0598..457c8c87fc8 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -2356,6 +2356,11 @@ class multi_delete :public select_result_interceptor /* True if at least one table we delete from is not transactional */ bool normal_tables; bool delete_while_scanning; + /* + error handling (rollback and binlogging) can happen in send_eof() + so that afterward send_error() needs to find out that. + */ + bool error_handled; public: multi_delete(TABLE_LIST *dt, uint num_of_tables); @@ -2391,6 +2396,11 @@ class multi_update :public select_result_interceptor /* True if the update operation has made a change in a transactional table */ bool transactional_tables; bool ignore; + /* + error handling (rollback and binlogging) can happen in send_eof() + so that afterward send_error() needs to find out that. + */ + bool error_handled; public: multi_update(TABLE_LIST *ut, TABLE_LIST *leaves_list, diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 7555219f5d8..add37c8c552 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -504,7 +504,7 @@ bool mysql_multi_delete_prepare(THD *thd) multi_delete::multi_delete(TABLE_LIST *dt, uint num_of_tables_arg) : delete_tables(dt), deleted(0), found(0), num_of_tables(num_of_tables_arg), error(0), - do_delete(0), transactional_tables(0), normal_tables(0) + do_delete(0), transactional_tables(0), normal_tables(0), error_handled(0) { tempfiles= (Unique **) sql_calloc(sizeof(Unique *) * num_of_tables); } @@ -685,12 +685,14 @@ void multi_delete::send_error(uint errcode,const char *err) /* First send error what ever it is ... */ my_message(errcode, err, MYF(0)); - /* If nothing deleted return */ - if (!deleted) + /* the error was handled or nothing deleted and no side effects return */ + if (error_handled || + !thd->transaction.stmt.modified_non_trans_table && !deleted) DBUG_VOID_RETURN; /* Something already deleted so we have to invalidate cache */ - query_cache_invalidate3(thd, delete_tables, 1); + if (deleted) + query_cache_invalidate3(thd, delete_tables, 1); /* If rows from the first table only has been deleted and it is @@ -710,12 +712,29 @@ void multi_delete::send_error(uint errcode,const char *err) */ error= 1; send_eof(); + DBUG_ASSERT(error_handled); + DBUG_VOID_RETURN; + } + + if (thd->transaction.stmt.modified_non_trans_table) + { + /* + there is only side effects; to binlog with the error + */ + if (mysql_bin_log.is_open()) + { + Query_log_event qinfo(thd, thd->query, thd->query_length, + transactional_tables, FALSE); + mysql_bin_log.write(&qinfo); + } + thd->transaction.all.modified_non_trans_table= true; } DBUG_ASSERT(!normal_tables || !deleted || thd->transaction.stmt.modified_non_trans_table); DBUG_VOID_RETURN; } + /* Do delete from other tables. Returns values: @@ -832,6 +851,8 @@ bool multi_delete::send_eof() if (thd->transaction.stmt.modified_non_trans_table) thd->transaction.all.modified_non_trans_table= TRUE; } + if (local_error != 0) + error_handled= TRUE; // to force early leave from ::send_error() /* Commit or rollback the current SQL statement */ if (transactional_tables) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index f4ee2ffc0f7..77695f47b1f 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3701,6 +3701,13 @@ end_with_restore_list: SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK | OPTION_SETUP_TABLES_DONE, del_result, unit, select_lex); + res|= thd->net.report_error; + if (unlikely(res)) + { + /* If we had a another error reported earlier then this will be ignored */ + del_result->send_error(ER_UNKNOWN_ERROR, "Execution of the query failed"); + del_result->abort(); + } delete del_result; } else diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 3f38ad8b33c..f3695976508 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -994,8 +994,8 @@ multi_update::multi_update(TABLE_LIST *table_list, :all_tables(table_list), leaves(leaves_list), update_tables(0), tmp_tables(0), updated(0), found(0), fields(field_list), values(value_list), table_count(0), copy_field(0), - handle_duplicates(handle_duplicates_arg), do_update(1), trans_safe(0), - transactional_tables(1), ignore(ignore_arg) + handle_duplicates(handle_duplicates_arg), do_update(1), trans_safe(1), + transactional_tables(1), ignore(ignore_arg), error_handled(0) {} @@ -1202,7 +1202,6 @@ multi_update::initialize_tables(JOIN *join) if ((thd->options & OPTION_SAFE_UPDATES) && error_if_full_join(join)) DBUG_RETURN(1); main_table=join->join_tab->table; - trans_safe= transactional_tables= main_table->file->has_transactions(); table_to_update= 0; /* Any update has at least one pair (field, value) */ @@ -1484,12 +1483,14 @@ void multi_update::send_error(uint errcode,const char *err) /* First send error what ever it is ... */ my_error(errcode, MYF(0), err); - /* If nothing updated return */ - if (updated == 0) /* the counter might be reset in send_eof */ - return; /* and then the query has been binlogged */ + /* the error was handled or nothing deleted and no side effects return */ + if (error_handled || + !thd->transaction.stmt.modified_non_trans_table && !updated) + return; /* Something already updated so we have to invalidate cache */ - query_cache_invalidate3(thd, update_tables, 1); + if (updated) + query_cache_invalidate3(thd, update_tables, 1); /* If all tables that has been updated are trans safe then just do rollback. If not attempt to do remaining updates. @@ -1525,8 +1526,7 @@ void multi_update::send_error(uint errcode,const char *err) transactional_tables, FALSE); mysql_bin_log.write(&qinfo); } - if (!trans_safe) - thd->transaction.all.modified_non_trans_table= TRUE; + thd->transaction.all.modified_non_trans_table= TRUE; } DBUG_ASSERT(trans_safe || !updated || thd->transaction.stmt.modified_non_trans_table); @@ -1739,8 +1739,6 @@ bool multi_update::send_eof() { if (local_error == 0) thd->clear_error(); - else - updated= 0; /* if there's an error binlog it here not in ::send_error */ Query_log_event qinfo(thd, thd->query, thd->query_length, transactional_tables, FALSE); if (mysql_bin_log.write(&qinfo) && trans_safe) @@ -1749,6 +1747,8 @@ bool multi_update::send_eof() if (thd->transaction.stmt.modified_non_trans_table) thd->transaction.all.modified_non_trans_table= TRUE; } + if (local_error != 0) + error_handled= TRUE; // to force early leave from ::send_error() if (transactional_tables) { From 8f7550ecad8e6dee0f7fb36592ba1d3a330e8f39 Mon Sep 17 00:00:00 2001 From: "aelkin/elkin@koti.dsl.inet.fi" <> Date: Sat, 13 Oct 2007 23:12:50 +0300 Subject: [PATCH 039/336] manual merge for bug_29136, bug#29309. --- .../mix_innodb_myisam_side_effects.test | 74 +++++++++++++++++-- mysql-test/r/innodb.result | 17 ++++- mysql-test/r/multi_update.result | 23 +++++- .../r/binlog_row_mix_innodb_myisam.result | 59 +++++++++++++-- .../r/binlog_stm_mix_innodb_myisam.result | 59 +++++++++++++-- .../manual/r/rpl_replication_delay.result | 31 ++++++-- mysql-test/t/innodb.test | 39 ---------- mysql-test/t/multi_update.test | 8 +- sql/log_event.cc | 28 ++++++- sql/rpl_rli.cc | 10 ++- sql/sql_delete.cc | 6 +- 11 files changed, 278 insertions(+), 76 deletions(-) diff --git a/mysql-test/extra/binlog_tests/mix_innodb_myisam_side_effects.test b/mysql-test/extra/binlog_tests/mix_innodb_myisam_side_effects.test index 6c961c4694d..03514bfdb55 100644 --- a/mysql-test/extra/binlog_tests/mix_innodb_myisam_side_effects.test +++ b/mysql-test/extra/binlog_tests/mix_innodb_myisam_side_effects.test @@ -126,7 +126,9 @@ drop table t1,t2; # CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; -CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); +CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique) ENGINE=MyISAM; +CREATE TABLE t4 (a int, PRIMARY KEY (a), b int unique) ENGINE=Innodb; +CREATE TABLE t5 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; # @@ -169,7 +171,7 @@ CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); select count(*) from t1 /* must be 2 */; # -# UPDATE (multi-update see bug#27716) +# UPDATE inc multi-update # # prepare @@ -185,9 +187,48 @@ CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); source include/show_binlog_events.inc; # must be events of the query select count(*) from t1 /* must be 2 */; +## multi_update::send_eof() branch + +# prepare + delete from t3; + delete from t4; + insert into t3 values (1,1); + insert into t4 values (1,1),(2,2); + + reset master; + +# execute + --error ER_DUP_ENTRY + UPDATE t4,t3 SET t4.a=t3.a + bug27417(1) /* top level non-ta table */; + +# check + source include/show_binlog_events.inc; # the offset must denote there is the query + select count(*) from t1 /* must be 4 */; + +## send_error() branch of multi_update + +# prepare + delete from t1; + delete from t3; + delete from t4; + insert into t3 values (1,1),(2,2); + insert into t4 values (1,1),(2,2); + + reset master; + +# execute + --error ER_DUP_ENTRY + UPDATE t3,t4 SET t3.a=t4.a + bug27417(1); + +# check + select count(*) from t1 /* must be 1 */; + +# cleanup + drop table t4; + # -# DELETE (for multi-delete see Bug #29136) +# DELETE incl multi-delete # # prepare @@ -203,6 +244,27 @@ CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); # execute --error ER_DUP_ENTRY delete from t2; +# check + source include/show_binlog_events.inc; # the offset must denote there is the query + select count(*) from t1 /* must be 1 */; + +# cleanup + drop trigger trg_del; + +# prepare + delete from t1; + delete from t2; + delete from t5; + create trigger trg_del_t2 after delete on t2 for each row + insert into t1 values (1); + insert into t2 values (2),(3); + insert into t5 values (1),(2); + reset master; + +# execute + --error ER_DUP_ENTRY + delete t2.* from t2,t5 where t2.a=t5.a + 1; + # check source include/show_binlog_events.inc; # must be events of the query select count(*) from t1 /* must be 1 */; @@ -229,6 +291,8 @@ CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); # # bug#23333 cleanup # -drop trigger trg_del; -drop table t1,t2,t3,t4; + + +drop trigger trg_del_t2; +drop table t1,t2,t3,t4,t5; drop function bug27417; diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index d0b67e90afb..e1cc365f5c3 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -1086,6 +1086,19 @@ n d 1 30 2 20 drop table t1,t2; +drop table if exists t1, t2; +CREATE TABLE t1 (a int, PRIMARY KEY (a)); +CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; +create trigger trg_del_t2 after delete on t2 for each row +insert into t1 values (1); +insert into t1 values (1); +insert into t2 values (1),(2); +delete t2 from t2; +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +select count(*) from t2 /* must be 2 as restored after rollback caused by the error */; +count(*) +2 +drop table t1, t2; create table t1 (a int, b int) engine=innodb; insert into t1 values(20,null); select t2.b, ifnull(t2.b,"this is null") from t1 as t2 left join t1 as t3 on @@ -1751,10 +1764,10 @@ Variable_name Value Innodb_page_size 16384 show status like "Innodb_rows_deleted"; Variable_name Value -Innodb_rows_deleted 70 +Innodb_rows_deleted 71 show status like "Innodb_rows_inserted"; Variable_name Value -Innodb_rows_inserted 1083 +Innodb_rows_inserted 1085 show status like "Innodb_rows_updated"; Variable_name Value Innodb_rows_updated 886 diff --git a/mysql-test/r/multi_update.result b/mysql-test/r/multi_update.result index 55e47756312..0bc01e95d2d 100644 --- a/mysql-test/r/multi_update.result +++ b/mysql-test/r/multi_update.result @@ -614,6 +614,7 @@ CREATE TABLE `t2` ( `b` int(11) default NULL, PRIMARY KEY (`a`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 ; +set @sav_binlog_format= @@session.binlog_format; set @@session.binlog_format= mixed; insert into t1 values (1,1),(2,2); insert into t2 values (1,1),(4,4); @@ -626,7 +627,7 @@ a b 4 4 show master status /* there must be the UPDATE query event */; File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 197 +master-bin.000001 268 delete from t1; delete from t2; insert into t1 values (1,2),(3,4),(4,4); @@ -636,6 +637,24 @@ UPDATE t2,t1 SET t2.a=t2.b where t2.a=t1.a; ERROR 23000: Duplicate entry '4' for key 'PRIMARY' show master status /* there must be the UPDATE query event */; File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 212 +master-bin.000001 283 drop table t1, t2; +set @@session.binlog_format= @sav_binlog_format; +drop table if exists t1, t2, t3; +CREATE TABLE t1 (a int, PRIMARY KEY (a)); +CREATE TABLE t2 (a int, PRIMARY KEY (a)); +CREATE TABLE t3 (a int, PRIMARY KEY (a)) ENGINE=MyISAM; +create trigger trg_del_t3 before delete on t3 for each row insert into t1 values (1); +insert into t2 values (1),(2); +insert into t3 values (1),(2); +reset master; +delete t3.* from t2,t3 where t2.a=t3.a; +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +select count(*) from t1 /* must be 1 */; +count(*) +1 +select count(*) from t3 /* must be 1 */; +count(*) +1 +drop table t1, t2, t3; end of tests diff --git a/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result b/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result index 8022f2b1e10..f69d5717a1f 100644 --- a/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result +++ b/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result @@ -520,7 +520,9 @@ count(*) drop table t1,t2; CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; -CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); +CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique) ENGINE=MyISAM; +CREATE TABLE t4 (a int, PRIMARY KEY (a), b int unique) ENGINE=Innodb; +CREATE TABLE t5 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; insert into t2 values (1); reset master; insert into t2 values (bug27417(1)); @@ -559,6 +561,33 @@ master-bin.000001 # Query # # use `test`; update t3 set b=b+bug27417(1) select count(*) from t1 /* must be 2 */; count(*) 2 +delete from t3; +delete from t4; +insert into t3 values (1,1); +insert into t4 values (1,1),(2,2); +reset master; +UPDATE t4,t3 SET t4.a=t3.a + bug27417(1) /* top level non-ta table */; +ERROR 23000: Duplicate entry '2' for key 'PRIMARY' +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Intvar # # INSERT_ID=6 +master-bin.000001 # Query # # use `test`; UPDATE t4,t3 SET t4.a=t3.a + bug27417(1) /* top level non-ta table */ +master-bin.000001 # Query # # use `test`; ROLLBACK +select count(*) from t1 /* must be 4 */; +count(*) +4 +delete from t1; +delete from t3; +delete from t4; +insert into t3 values (1,1),(2,2); +insert into t4 values (1,1),(2,2); +reset master; +UPDATE t3,t4 SET t3.a=t4.a + bug27417(1); +ERROR 23000: Duplicate entry '2' for key 'PRIMARY' +select count(*) from t1 /* must be 1 */; +count(*) +1 +drop table t4; delete from t1; delete from t2; delete from t3; @@ -571,12 +600,30 @@ delete from t2; ERROR 23000: Duplicate entry '1' for key 'PRIMARY' show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Intvar # # INSERT_ID=6 +master-bin.000001 # Intvar # # INSERT_ID=9 master-bin.000001 # Query # # use `test`; delete from t2 master-bin.000001 # Query # # use `test`; ROLLBACK select count(*) from t1 /* must be 1 */; count(*) 1 +drop trigger trg_del; +delete from t1; +delete from t2; +delete from t5; +create trigger trg_del_t2 after delete on t2 for each row +insert into t1 values (1); +insert into t2 values (2),(3); +insert into t5 values (1),(2); +reset master; +delete t2.* from t2,t5 where t2.a=t5.a + 1; +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; delete t2.* from t2,t5 where t2.a=t5.a + 1 +master-bin.000001 # Query # # use `test`; ROLLBACK +select count(*) from t1 /* must be 1 */; +count(*) +1 delete from t1; create table t4 (a int default 0, b int primary key) engine=innodb; insert into t4 values (0, 17); @@ -591,11 +638,11 @@ count(*) 2 show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Intvar # # INSERT_ID=7 +master-bin.000001 # Intvar # # INSERT_ID=10 master-bin.000001 # Begin_load_query # # ;file_id=1;block_len=12 -master-bin.000001 # Intvar # # INSERT_ID=7 +master-bin.000001 # Intvar # # INSERT_ID=10 master-bin.000001 # Execute_load_query # # use `test`; load data infile '../std_data_ln/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2) ;file_id=1 master-bin.000001 # Query # # use `test`; ROLLBACK -drop trigger trg_del; -drop table t1,t2,t3,t4; +drop trigger trg_del_t2; +drop table t1,t2,t3,t4,t5; drop function bug27417; diff --git a/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result b/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result index 9c580b2312e..c15478bc826 100644 --- a/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result +++ b/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result @@ -494,7 +494,9 @@ count(*) drop table t1,t2; CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; -CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); +CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique) ENGINE=MyISAM; +CREATE TABLE t4 (a int, PRIMARY KEY (a), b int unique) ENGINE=Innodb; +CREATE TABLE t5 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; insert into t2 values (1); reset master; insert into t2 values (bug27417(1)); @@ -533,6 +535,33 @@ master-bin.000001 # Query # # use `test`; update t3 set b=b+bug27417(1) select count(*) from t1 /* must be 2 */; count(*) 2 +delete from t3; +delete from t4; +insert into t3 values (1,1); +insert into t4 values (1,1),(2,2); +reset master; +UPDATE t4,t3 SET t4.a=t3.a + bug27417(1) /* top level non-ta table */; +ERROR 23000: Duplicate entry '2' for key 'PRIMARY' +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Intvar # # INSERT_ID=6 +master-bin.000001 # Query # # use `test`; UPDATE t4,t3 SET t4.a=t3.a + bug27417(1) /* top level non-ta table */ +master-bin.000001 # Query # # use `test`; ROLLBACK +select count(*) from t1 /* must be 4 */; +count(*) +4 +delete from t1; +delete from t3; +delete from t4; +insert into t3 values (1,1),(2,2); +insert into t4 values (1,1),(2,2); +reset master; +UPDATE t3,t4 SET t3.a=t4.a + bug27417(1); +ERROR 23000: Duplicate entry '2' for key 'PRIMARY' +select count(*) from t1 /* must be 1 */; +count(*) +1 +drop table t4; delete from t1; delete from t2; delete from t3; @@ -545,12 +574,30 @@ delete from t2; ERROR 23000: Duplicate entry '1' for key 'PRIMARY' show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Intvar # # INSERT_ID=6 +master-bin.000001 # Intvar # # INSERT_ID=9 master-bin.000001 # Query # # use `test`; delete from t2 master-bin.000001 # Query # # use `test`; ROLLBACK select count(*) from t1 /* must be 1 */; count(*) 1 +drop trigger trg_del; +delete from t1; +delete from t2; +delete from t5; +create trigger trg_del_t2 after delete on t2 for each row +insert into t1 values (1); +insert into t2 values (2),(3); +insert into t5 values (1),(2); +reset master; +delete t2.* from t2,t5 where t2.a=t5.a + 1; +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; delete t2.* from t2,t5 where t2.a=t5.a + 1 +master-bin.000001 # Query # # use `test`; ROLLBACK +select count(*) from t1 /* must be 1 */; +count(*) +1 delete from t1; create table t4 (a int default 0, b int primary key) engine=innodb; insert into t4 values (0, 17); @@ -565,13 +612,13 @@ count(*) 2 show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Intvar # # INSERT_ID=7 +master-bin.000001 # Intvar # # INSERT_ID=10 master-bin.000001 # Begin_load_query # # ;file_id=1;block_len=12 -master-bin.000001 # Intvar # # INSERT_ID=7 +master-bin.000001 # Intvar # # INSERT_ID=10 master-bin.000001 # Execute_load_query # # use `test`; load data infile '../std_data_ln/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2) ;file_id=1 master-bin.000001 # Query # # use `test`; ROLLBACK -drop trigger trg_del; -drop table t1,t2,t3,t4; +drop trigger trg_del_t2; +drop table t1,t2,t3,t4,t5; drop function bug27417; set @@session.binlog_format=@@global.binlog_format; end of tests diff --git a/mysql-test/suite/manual/r/rpl_replication_delay.result b/mysql-test/suite/manual/r/rpl_replication_delay.result index 22447a30cba..a8fa6ce8265 100644 --- a/mysql-test/suite/manual/r/rpl_replication_delay.result +++ b/mysql-test/suite/manual/r/rpl_replication_delay.result @@ -11,7 +11,7 @@ Master_User root Master_Port 9306 Connect_Retry 1 Master_Log_File master-bin.000001 -Read_Master_Log_Pos 98 +Read_Master_Log_Pos 106 Relay_Log_File # Relay_Log_Pos # Relay_Master_Log_File master-bin.000001 @@ -26,7 +26,7 @@ Replicate_Wild_Ignore_Table Last_Errno 0 Last_Error Skip_Counter 0 -Exec_Master_Log_Pos 98 +Exec_Master_Log_Pos 106 Relay_Log_Space # Until_Condition None Until_Log_File @@ -38,6 +38,11 @@ Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master 0 +Master_SSL_Verify_Server_Cert No +Last_IO_Errno 0 +Last_IO_Error +Last_SQL_Errno 0 +Last_SQL_Error drop table if exists t1; Warnings: Note 1051 Unknown table 't1' @@ -52,7 +57,7 @@ Master_User root Master_Port 9306 Connect_Retry 1 Master_Log_File master-bin.000001 -Read_Master_Log_Pos 359 +Read_Master_Log_Pos 367 Relay_Log_File # Relay_Log_Pos # Relay_Master_Log_File master-bin.000001 @@ -67,7 +72,7 @@ Replicate_Wild_Ignore_Table Last_Errno 0 Last_Error Skip_Counter 0 -Exec_Master_Log_Pos 271 +Exec_Master_Log_Pos 279 Relay_Log_Space # Until_Condition None Until_Log_File @@ -78,7 +83,12 @@ Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key -Seconds_Behind_Master 10 +Seconds_Behind_Master 9 +Master_SSL_Verify_Server_Cert No +Last_IO_Errno 0 +Last_IO_Error +Last_SQL_Errno 0 +Last_SQL_Error unlock tables; flush logs /* this time rli->last_master_timestamp is not affected */; lock table t1 write; @@ -90,7 +100,7 @@ Master_User root Master_Port 9306 Connect_Retry 1 Master_Log_File master-bin.000001 -Read_Master_Log_Pos 447 +Read_Master_Log_Pos 455 Relay_Log_File # Relay_Log_Pos # Relay_Master_Log_File master-bin.000001 @@ -105,7 +115,7 @@ Replicate_Wild_Ignore_Table Last_Errno 0 Last_Error Skip_Counter 0 -Exec_Master_Log_Pos 359 +Exec_Master_Log_Pos 367 Relay_Log_Space # Until_Condition None Until_Log_File @@ -116,6 +126,11 @@ Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key -Seconds_Behind_Master 6 +Seconds_Behind_Master 7 +Master_SSL_Verify_Server_Cert No +Last_IO_Errno 0 +Last_IO_Error +Last_SQL_Errno 0 +Last_SQL_Error unlock tables; drop table t1; diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index 63682ab96eb..c7fe033fd36 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -753,45 +753,6 @@ select * from t1; select * from t2; drop table t1,t2; -# -# Bug#27716 multi-update did partially and has not binlogged -# - -CREATE TABLE `t1` ( - `a` int(11) NOT NULL auto_increment, - `b` int(11) default NULL, - PRIMARY KEY (`a`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1 ; - -CREATE TABLE `t2` ( - `a` int(11) NOT NULL auto_increment, - `b` int(11) default NULL, - PRIMARY KEY (`a`) -) ENGINE=INNODB DEFAULT CHARSET=latin1 ; - -# A. testing multi_update::send_eof() execution branch -insert into t1 values (1,1),(2,2); -insert into t2 values (1,1),(4,4); -reset master; ---error ER_DUP_ENTRY -UPDATE t2,t1 SET t2.a=t1.a+2; -# check -select * from t2 /* must be (3,1), (4,4) */; -show master status /* there must no UPDATE in binlog */; - -# B. testing multi_update::send_error() execution branch -delete from t1; -delete from t2; -insert into t1 values (1,2),(3,4),(4,4); -insert into t2 values (1,2),(3,4),(4,4); -reset master; ---error ER_DUP_ENTRY -UPDATE t2,t1 SET t2.a=t2.b where t2.a=t1.a; -show master status /* there must be no UPDATE query event */; - -# cleanup bug#27716 -drop table t1, t2; - # # Bug #29136 erred multi-delete on trans table does not rollback # diff --git a/mysql-test/t/multi_update.test b/mysql-test/t/multi_update.test index 8b8132df84a..331663dceb5 100644 --- a/mysql-test/t/multi_update.test +++ b/mysql-test/t/multi_update.test @@ -588,6 +588,7 @@ CREATE TABLE `t2` ( ) ENGINE=MyISAM DEFAULT CHARSET=latin1 ; # as the test is about to see erroed queries in binlog +set @sav_binlog_format= @@session.binlog_format; set @@session.binlog_format= mixed; @@ -614,6 +615,7 @@ show master status /* there must be the UPDATE query event */; # cleanup bug#27716 drop table t1, t2; +set @@session.binlog_format= @sav_binlog_format; # # Bug #29136 erred multi-delete on trans table does not rollback @@ -642,11 +644,13 @@ delete t3.* from t2,t3 where t2.a=t3.a; # check select count(*) from t1 /* must be 1 */; select count(*) from t3 /* must be 1 */; -# the query must be in binlog (no surprise though) -source include/show_binlog_events.inc; # cleanup bug#29136 drop table t1, t2, t3; +# +# Add further tests from here +# + --echo end of tests diff --git a/sql/log_event.cc b/sql/log_event.cc index 31309694c1a..ec4d6820cca 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -558,8 +558,32 @@ int Log_event::do_update_pos(Relay_log_info *rli) Matz: I don't think we will need this check with this refactoring. */ if (rli) - rli->stmt_done(log_pos, when); - + { + /* + bug#29309 simulation: resetting the flag to force + wrong behaviour of artificial event to update + rli->last_master_timestamp for only one time - + the first FLUSH LOGS in the test. + */ + DBUG_EXECUTE_IF("let_first_flush_log_change_timestamp", + if (debug_not_change_ts_if_art_event == 1 + && is_artificial_event()) + { + debug_not_change_ts_if_art_event= 0; + }); +#ifndef DBUG_OFF + rli->stmt_done(log_pos, + is_artificial_event() && + debug_not_change_ts_if_art_event > 0 ? 0 : when); +#else + rli->stmt_done(log_pos, is_artificial_event()? 0 : when); +#endif + DBUG_EXECUTE_IF("let_first_flush_log_change_timestamp", + if (debug_not_change_ts_if_art_event == 0) + { + debug_not_change_ts_if_art_event= 2; + }); + } return 0; // Cannot fail currently } diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index 867d55a60a3..15d7d97affd 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -1082,6 +1082,9 @@ bool Relay_log_info::cached_charset_compare(char *charset) const void Relay_log_info::stmt_done(my_off_t event_master_log_pos, time_t event_creation_time) { +#ifndef DBUG_OFF + extern uint debug_not_change_ts_if_art_event; +#endif clear_flag(IN_STMT); /* @@ -1121,7 +1124,12 @@ void Relay_log_info::stmt_done(my_off_t event_master_log_pos, is that value may take some time to display in Seconds_Behind_Master - not critical). */ - last_master_timestamp= event_creation_time; +#ifndef DBUG_OFF + if (!(event_creation_time == 0 && debug_not_change_ts_if_art_event > 0)) +#else + if (event_creation_time != 0) +#endif + last_master_timestamp= event_creation_time; } } diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index aad0514b10b..b4b877b9a37 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -758,9 +758,9 @@ void multi_delete::send_error(uint errcode,const char *err) */ if (mysql_bin_log.is_open()) { - Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_tables, FALSE); - mysql_bin_log.write(&qinfo); + thd->binlog_query(THD::ROW_QUERY_TYPE, + thd->query, thd->query_length, + transactional_tables, FALSE); } thd->transaction.all.modified_non_trans_table= true; } From e0691da0c199ab2c65f4c9fb9681e4292c224a14 Mon Sep 17 00:00:00 2001 From: "kaa@polly.(none)" <> Date: Mon, 15 Oct 2007 10:34:34 +0400 Subject: [PATCH 040/336] Fix for bug #30453: String not cast to int correctly. Problem: my_strntoull10rnd_8bit() handled incorrectly cases when the input string contains a decimal point and is long enough to overrun the 'unsigned long long' type. The position of the decimal point was not taken into account which resulted in miscalculated numbers and truncation to appropriate SQL data type limits. Solution: Fix my_strntoull10rnd_8bit() to take the position of a decimal point into account in such cases. --- mysql-test/r/insert.result | 14 ++++++++++++++ mysql-test/t/insert.test | 15 +++++++++++++++ strings/ctype-simple.c | 14 +++++++++----- 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/insert.result b/mysql-test/r/insert.result index 8a0a3ba848c..e1cad814226 100644 --- a/mysql-test/r/insert.result +++ b/mysql-test/r/insert.result @@ -461,4 +461,18 @@ i 2 2 DROP TABLE t1, t2; +CREATE TABLE t1 (c1 INT NOT NULL); +INSERT INTO t1 VALUES(4188.32999999999992724042385816574096679687500), +('4188.32999999999992724042385816574096679687500'), (4188); +SELECT * FROM t1; +c1 +4188 +4188 +4188 +CREATE TABLE t2 (c1 BIGINT); +INSERT INTO t2 VALUES('15449237462.0000000000'); +SELECT * FROM t2; +c1 +15449237462 +DROP TABLE t1, t2; End of 5.0 tests. diff --git a/mysql-test/t/insert.test b/mysql-test/t/insert.test index 76177403bd0..c36408a52fe 100644 --- a/mysql-test/t/insert.test +++ b/mysql-test/t/insert.test @@ -353,5 +353,20 @@ SELECT * FROM t2; DROP TABLE t1, t2; +# +# Bug #30453: String not cast to int correctly +# + +CREATE TABLE t1 (c1 INT NOT NULL); +INSERT INTO t1 VALUES(4188.32999999999992724042385816574096679687500), +('4188.32999999999992724042385816574096679687500'), (4188); +SELECT * FROM t1; + +CREATE TABLE t2 (c1 BIGINT); +INSERT INTO t2 VALUES('15449237462.0000000000'); +SELECT * FROM t2; + +DROP TABLE t1, t2; + --echo End of 5.0 tests. diff --git a/strings/ctype-simple.c b/strings/ctype-simple.c index 8b1b0d6790d..e073262cd4c 100644 --- a/strings/ctype-simple.c +++ b/strings/ctype-simple.c @@ -1538,14 +1538,18 @@ my_strntoull10rnd_8bit(CHARSET_INFO *cs __attribute__((unused)), } else addon= (*str >= '5'); - for ( ; str < end && (ch= (unsigned char) (*str - '0')) < 10; str++) + if (!dot) { - if (!dot) - shift++; + for ( ; str < end && (ch= (unsigned char) (*str - '0')) < 10; shift++, str++); + if (str < end && *str == '.') + { + str++; + for ( ; str < end && (ch= (unsigned char) (*str - '0')) < 10; str++); + } } - if (str < end && *str == '.' && !dot) + else { - str++; + shift= dot - str; for ( ; str < end && (ch= (unsigned char) (*str - '0')) < 10; str++); } goto exp; From 0dfe3a8dfbcba14d4ccdf09cfe88d59f98fee741 Mon Sep 17 00:00:00 2001 From: "ramil/ram@mysql.com/ramil.myoffice.izhnet.ru" <> Date: Tue, 16 Oct 2007 13:43:16 +0500 Subject: [PATCH 041/336] Fix for bug #31285: main.status test fails with different Table_locks_waited Problem: Table_locks_waited value may depend on general logging. Fix: switch general logging off. --- mysql-test/r/status.result | 3 +++ mysql-test/t/status.test | 3 +++ 2 files changed, 6 insertions(+) diff --git a/mysql-test/r/status.result b/mysql-test/r/status.result index db75044ee5d..c95b09597fc 100644 --- a/mysql-test/r/status.result +++ b/mysql-test/r/status.result @@ -8,6 +8,8 @@ VARIABLE_NAME VARIABLE_VALUE TABLE_LOCKS_IMMEDIATE 2 TABLE_LOCKS_WAITED 0 SET SQL_LOG_BIN=0; +set @old_general_log = @@global.general_log; +set global general_log = 'OFF'; drop table if exists t1; create table t1(n int) engine=myisam; insert into t1 values(1); @@ -20,6 +22,7 @@ show status like 'Table_locks_waited'; Variable_name Value Table_locks_waited 1 drop table t1; +set global general_log = @old_general_log; select 1; 1 1 diff --git a/mysql-test/t/status.test b/mysql-test/t/status.test index 1cd5aa1726a..6a11791924a 100644 --- a/mysql-test/t/status.test +++ b/mysql-test/t/status.test @@ -21,6 +21,8 @@ select * from information_schema.session_status where variable_name like 'Table_ connection con1; # ++Immediate = 3 SET SQL_LOG_BIN=0; +set @old_general_log = @@global.general_log; +set global general_log = 'OFF'; --disable_warnings # ++Immediate = 4 drop table if exists t1; @@ -60,6 +62,7 @@ reap; # ++Immediate = 16 + $wait_condition_reps show status like 'Table_locks_waited'; drop table t1; +set global general_log = @old_general_log; disconnect con2; disconnect con1; From 73834a4a86455df93d81d5a72f411d56a745c6ad Mon Sep 17 00:00:00 2001 From: "bar@mysql.com/bar.myoffice.izhnet.ru" <> Date: Tue, 16 Oct 2007 15:22:44 +0500 Subject: [PATCH 042/336] After merge fix: Adjusting SHOW CREATE TABLE output from 5.0 to 5.1 format --- mysql-test/r/ctype_uca.result | 4 ++-- mysql-test/r/ctype_ucs.result | 4 ++-- mysql-test/r/ctype_utf8.result | 4 ++-- mysql-test/r/func_regexp.result | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/mysql-test/r/ctype_uca.result b/mysql-test/r/ctype_uca.result index ada7ace9696..4980b179c4b 100644 --- a/mysql-test/r/ctype_uca.result +++ b/mysql-test/r/ctype_uca.result @@ -2763,8 +2763,8 @@ select null, null; show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `s1` varchar(64) character set ucs2 collate ucs2_unicode_ci default NULL, - `s2` varchar(64) character set ucs2 collate ucs2_unicode_ci default NULL + `s1` varchar(64) CHARACTER SET ucs2 COLLATE ucs2_unicode_ci DEFAULT NULL, + `s2` varchar(64) CHARACTER SET ucs2 COLLATE ucs2_unicode_ci DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 delete from t1; insert into t1 values('aaa','aaa'); diff --git a/mysql-test/r/ctype_ucs.result b/mysql-test/r/ctype_ucs.result index 709a097d823..dab49cdd8bb 100644 --- a/mysql-test/r/ctype_ucs.result +++ b/mysql-test/r/ctype_ucs.result @@ -931,8 +931,8 @@ select null, null; show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `s1` varchar(64) character set ucs2 default NULL, - `s2` varchar(64) character set ucs2 default NULL + `s1` varchar(64) CHARACTER SET ucs2 DEFAULT NULL, + `s2` varchar(64) CHARACTER SET ucs2 DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 delete from t1; insert into t1 values('aaa','aaa'); diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index 0981f72b0c1..3575a07d83c 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -276,8 +276,8 @@ select null, null; show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `s1` varchar(64) character set utf8 default NULL, - `s2` varchar(64) character set utf8 default NULL + `s1` varchar(64) CHARACTER SET utf8 DEFAULT NULL, + `s2` varchar(64) CHARACTER SET utf8 DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 delete from t1; insert into t1 values('aaa','aaa'); diff --git a/mysql-test/r/func_regexp.result b/mysql-test/r/func_regexp.result index c3851e51207..dca73244780 100644 --- a/mysql-test/r/func_regexp.result +++ b/mysql-test/r/func_regexp.result @@ -8,8 +8,8 @@ select null, null; show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `s1` varchar(64) default NULL, - `s2` varchar(64) default NULL + `s1` varchar(64) DEFAULT NULL, + `s2` varchar(64) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 delete from t1; insert into t1 values('aaa','aaa'); From 3d2f493fb42001aac3706b838d8c8bc9f651538e Mon Sep 17 00:00:00 2001 From: "ramil/ram@mysql.com/ramil.myoffice.izhnet.ru" <> Date: Tue, 16 Oct 2007 17:19:07 +0500 Subject: [PATCH 043/336] Fix bug #31604: server crash when setting slow_query_log_file/global general_log_file variable Problem: we don't evaluate given expression checking values of the slow_query_log_file/general_log_file, don't check it for NULL. Fix: evaluate the expression, check result returned. --- mysql-test/r/log_state.result | 13 +++++++++++++ mysql-test/t/log_state.test | 20 ++++++++++++++++++++ sql/set_var.cc | 23 +++++++++++++++++------ 3 files changed, 50 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/log_state.result b/mysql-test/r/log_state.result index 3a3ef584ce3..407d93cf321 100644 --- a/mysql-test/r/log_state.result +++ b/mysql-test/r/log_state.result @@ -175,3 +175,16 @@ SET GLOBAL slow_query_log = ON; SET GLOBAL READ_ONLY = OFF; SET GLOBAL general_log = @old_general_log_state; SET GLOBAL slow_query_log = @old_slow_log_state; +set @old_general_log_file= @@global.general_log_file; +set @old_slow_query_log_file= @@global.slow_query_log_file; +set global general_log_file= concat('/not exiting path/log.maste', 'r'); +ERROR 42000: Variable 'general_log_file' can't be set to the value of '/not exiting path/log.master' +set global general_log_file= NULL; +ERROR 42000: Variable 'general_log_file' can't be set to the value of 'NULL' +set global slow_query_log_file= concat('/not exiting path/log.maste', 'r'); +ERROR 42000: Variable 'slow_query_log_file' can't be set to the value of '/not exiting path/log.master' +set global slow_query_log_file= NULL; +ERROR 42000: Variable 'slow_query_log_file' can't be set to the value of 'NULL' +set global general_log_file= @old_general_log_file; +set global slow_query_log_file= @old_slow_query_log_file; +End of 5.1 tests diff --git a/mysql-test/t/log_state.test b/mysql-test/t/log_state.test index c67da261ef1..ec3644cbff1 100644 --- a/mysql-test/t/log_state.test +++ b/mysql-test/t/log_state.test @@ -189,3 +189,23 @@ disconnect con1; # Remove the log files that was created in the "default location" # i.e var/run --remove_file $MYSQLTEST_VARDIR/run/master.log + +# +# Bug #31604: server crash when setting slow_query_log_file/general_log_file +# +set @old_general_log_file= @@global.general_log_file; +set @old_slow_query_log_file= @@global.slow_query_log_file; + +--error 1231 +set global general_log_file= concat('/not exiting path/log.maste', 'r'); +--error 1231 +set global general_log_file= NULL; +--error 1231 +set global slow_query_log_file= concat('/not exiting path/log.maste', 'r'); +--error 1231 +set global slow_query_log_file= NULL; + +set global general_log_file= @old_general_log_file; +set global slow_query_log_file= @old_slow_query_log_file; + +--echo End of 5.1 tests diff --git a/sql/set_var.cc b/sql/set_var.cc index ec82b56d793..c26e9a8d6e2 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -2102,18 +2102,24 @@ void sys_var_log_state::set_default(THD *thd, enum_var_type type) static int sys_check_log_path(THD *thd, set_var *var) { - char path[FN_REFLEN]; + char path[FN_REFLEN], buff[FN_REFLEN]; MY_STAT f_stat; - const char *var_path= var->value->str_value.ptr(); + String str(buff, sizeof(buff), system_charset_info), *res; + const char *log_file_str; + + if (!(res= var->value->val_str(&str))) + goto err; + + log_file_str= res->c_ptr(); bzero(&f_stat, sizeof(MY_STAT)); - (void) unpack_filename(path, var_path); + (void) unpack_filename(path, log_file_str); if (my_stat(path, &f_stat, MYF(0))) { /* Check if argument is a file and we have 'write' permission */ if (!MY_S_ISREG(f_stat.st_mode) || !(f_stat.st_mode & MY_S_IWRITE)) - return -1; + goto err; } else { @@ -2122,11 +2128,16 @@ static int sys_check_log_path(THD *thd, set_var *var) Check if directory exists and we have permission to create file & write to file */ - (void) dirname_part(path, var_path, &path_length); + (void) dirname_part(path, log_file_str, &path_length); if (my_access(path, (F_OK|W_OK))) - return -1; + goto err; } return 0; + +err: + my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name, + res ? log_file_str : "NULL"); + return 1; } From 253bb96e7949db3410567bdca070f82c7cfac5a7 Mon Sep 17 00:00:00 2001 From: "skozlov/ksm@mysql.com/virtop.localdomain" <> Date: Tue, 16 Oct 2007 23:19:39 +0400 Subject: [PATCH 044/336] Fix for non-deterministic behavior of SELECTs and VIEWs --- .../rpl/include/rpl_mixed_check_select.inc | 8 +- .../rpl/include/rpl_mixed_check_view.inc | 4 +- .../suite/rpl/include/rpl_mixed_dml.inc | 8 +- .../suite/rpl/r/rpl_innodb_mixed_dml.result | 152 +++++++++--------- 4 files changed, 86 insertions(+), 86 deletions(-) diff --git a/mysql-test/suite/rpl/include/rpl_mixed_check_select.inc b/mysql-test/suite/rpl/include/rpl_mixed_check_select.inc index 5d3b80e077b..b3e0cefbbd7 100644 --- a/mysql-test/suite/rpl/include/rpl_mixed_check_select.inc +++ b/mysql-test/suite/rpl/include/rpl_mixed_check_select.inc @@ -7,15 +7,15 @@ --echo ==========MASTER========== SELECT COUNT(*) FROM t1; -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; SELECT COUNT(*) FROM t2; -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; sync_slave_with_master; --echo ==========SLAVE=========== USE test_rpl; SELECT COUNT(*) FROM t1; -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; SELECT COUNT(*) FROM t2; -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; connection master; diff --git a/mysql-test/suite/rpl/include/rpl_mixed_check_view.inc b/mysql-test/suite/rpl/include/rpl_mixed_check_view.inc index 43feedfe64a..a9f7ad8cd68 100644 --- a/mysql-test/suite/rpl/include/rpl_mixed_check_view.inc +++ b/mysql-test/suite/rpl/include/rpl_mixed_check_view.inc @@ -7,11 +7,11 @@ --echo ==========MASTER========== SHOW CREATE VIEW v1; -SELECT * FROM v1; +SELECT * FROM v1 ORDER BY a; sync_slave_with_master; --echo ==========SLAVE=========== USE test_rpl; SHOW CREATE VIEW v1; -SELECT * FROM v1; +SELECT * FROM v1 ORDER BY a; connection master; diff --git a/mysql-test/suite/rpl/include/rpl_mixed_dml.inc b/mysql-test/suite/rpl/include/rpl_mixed_dml.inc index 96dfdbed541..d596df31b99 100644 --- a/mysql-test/suite/rpl/include/rpl_mixed_dml.inc +++ b/mysql-test/suite/rpl/include/rpl_mixed_dml.inc @@ -54,7 +54,7 @@ DELETE FROM t2 WHERE a = 2; --exec cp ./suite/rpl/data/rpl_mixed.dat $MYSQLTEST_VARDIR/tmp/ LOAD DATA INFILE '../tmp/rpl_mixed.dat' INTO TABLE t1 FIELDS TERMINATED BY '|' ; --exec rm $MYSQLTEST_VARDIR/tmp/rpl_mixed.dat -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; --source suite/rpl/include/rpl_mixed_check_select.inc --source suite/rpl/include/rpl_mixed_clear_tables.inc @@ -75,7 +75,7 @@ DELETE FROM t1 WHERE a = 2; --echo --echo ******************** SELECT ******************** INSERT INTO t1 VALUES(1, 't1, text 1'); -SELECT * FROM t1 WHERE b <> UUID(); +SELECT * FROM t1 WHERE b <> UUID() ORDER BY a; --source suite/rpl/include/rpl_mixed_clear_tables.inc # JOIN @@ -85,8 +85,8 @@ INSERT INTO t1 VALUES(1, 'CCC'); INSERT INTO t1 VALUES(2, 'DDD'); INSERT INTO t2 VALUES(1, 'DDD'); INSERT INTO t2 VALUES(2, 'CCC'); -SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a; -SELECT * FROM t1 INNER JOIN t2 ON t1.b = t2.b; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a ORDER BY t1.a,t2.a; +SELECT * FROM t1 INNER JOIN t2 ON t1.b = t2.b ORDER BY t1.a,t2.a; --source suite/rpl/include/rpl_mixed_clear_tables.inc # UNION diff --git a/mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result b/mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result index 19c5299df25..0e11d132cc4 100644 --- a/mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result +++ b/mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result @@ -41,26 +41,26 @@ DELETE FROM t2 WHERE b <> UUID(); SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 2 t1, text 2 SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b ==========SLAVE=========== USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 2 t1, text 2 SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b DELETE FROM t1; DELETE FROM t2; @@ -76,13 +76,13 @@ DELETE FROM t2 WHERE a = 2; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 t1, text 1 SELECT COUNT(*) FROM t2; COUNT(*) 1 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b 1 t2, text 1 ==========SLAVE=========== @@ -90,13 +90,13 @@ USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 t1, text 1 SELECT COUNT(*) FROM t2; COUNT(*) 1 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b 1 t2, text 1 DELETE FROM t1; @@ -104,7 +104,7 @@ DELETE FROM t2; ******************** LOAD DATA INFILE ******************** LOAD DATA INFILE '../tmp/rpl_mixed.dat' INTO TABLE t1 FIELDS TERMINATED BY '|' ; -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 10 line A 20 line B @@ -113,7 +113,7 @@ a b SELECT COUNT(*) FROM t1; COUNT(*) 3 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 10 line A 20 line B @@ -121,14 +121,14 @@ a b SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b ==========SLAVE=========== USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 3 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 10 line A 20 line B @@ -136,7 +136,7 @@ a b SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b DELETE FROM t1; DELETE FROM t2; @@ -153,35 +153,35 @@ DELETE FROM t1 WHERE a = 2; SELECT COUNT(*) FROM t1; COUNT(*) 2 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 t1, text 11 3 t1, text 33 SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b ==========SLAVE=========== USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 2 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 t1, text 11 3 t1, text 33 SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b DELETE FROM t1; DELETE FROM t2; ******************** SELECT ******************** INSERT INTO t1 VALUES(1, 't1, text 1'); -SELECT * FROM t1 WHERE b <> UUID(); +SELECT * FROM t1 WHERE b <> UUID() ORDER BY a; a b 1 t1, text 1 DELETE FROM t1; @@ -192,11 +192,11 @@ INSERT INTO t1 VALUES(1, 'CCC'); INSERT INTO t1 VALUES(2, 'DDD'); INSERT INTO t2 VALUES(1, 'DDD'); INSERT INTO t2 VALUES(2, 'CCC'); -SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a ORDER BY t1.a,t2.a; a b a b 1 CCC 1 DDD 2 DDD 2 CCC -SELECT * FROM t1 INNER JOIN t2 ON t1.b = t2.b; +SELECT * FROM t1 INNER JOIN t2 ON t1.b = t2.b ORDER BY t1.a,t2.a; a b a b 1 CCC 2 CCC 2 DDD 1 DDD @@ -219,50 +219,50 @@ INSERT INTO t1 VALUES(1, 't1, text 1'); SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 t1, text 1 SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b ==========SLAVE=========== USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 t1, text 1 SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b TRUNCATE t1; ==========MASTER========== SELECT COUNT(*) FROM t1; COUNT(*) 0 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b ==========SLAVE=========== USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 0 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b DELETE FROM t1; DELETE FROM t2; @@ -275,13 +275,13 @@ UPDATE t1 SET b = 't1, text 1 updated' WHERE a = 1; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 t1, text 1 updated SELECT COUNT(*) FROM t2; COUNT(*) 1 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b 1 t2, text 1 ==========SLAVE=========== @@ -289,13 +289,13 @@ USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 t1, text 1 updated SELECT COUNT(*) FROM t2; COUNT(*) 1 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b 1 t2, text 1 UPDATE t1, t2 SET t1.b = 'test', t2.b = 'test'; @@ -303,13 +303,13 @@ UPDATE t1, t2 SET t1.b = 'test', t2.b = 'test'; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 test SELECT COUNT(*) FROM t2; COUNT(*) 1 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b 1 test ==========SLAVE=========== @@ -317,13 +317,13 @@ USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 test SELECT COUNT(*) FROM t2; COUNT(*) 1 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b 1 test DELETE FROM t1; @@ -349,26 +349,26 @@ COMMIT; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 start SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b ==========SLAVE=========== USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 start SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b START TRANSACTION; INSERT INTO t1 VALUES (2, 'rollback'); @@ -377,26 +377,26 @@ ROLLBACK; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 start SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b ==========SLAVE=========== USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 start SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b START TRANSACTION; INSERT INTO t1 VALUES (3, 'before savepoint s1'); @@ -407,27 +407,27 @@ ROLLBACK TO SAVEPOINT s1; SELECT COUNT(*) FROM t1; COUNT(*) 2 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 start 3 before savepoint s1 SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b ==========SLAVE=========== USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 start SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b START TRANSACTION; INSERT INTO t1 VALUES (5, 'before savepoint s2'); @@ -441,7 +441,7 @@ DELETE FROM t1 WHERE a = 7; SELECT COUNT(*) FROM t1; COUNT(*) 4 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 start 3 before savepoint s1 @@ -450,14 +450,14 @@ a b SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b ==========SLAVE=========== USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 4 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 start 3 before savepoint s1 @@ -466,7 +466,7 @@ a b SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b DELETE FROM t1; DELETE FROM t2; @@ -610,28 +610,28 @@ DELETE FROM t1 WHERE a = 202; SELECT COUNT(*) FROM t1; COUNT(*) 2 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 100 test 201 test SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b ==========SLAVE=========== USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 2 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 100 test 201 test SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b ALTER PROCEDURE p1 COMMENT 'p1'; DROP PROCEDURE p1; @@ -649,13 +649,13 @@ INSERT INTO t1 VALUES (1, 'test'); SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 test SELECT COUNT(*) FROM t2; COUNT(*) 1 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b 1 test ==========SLAVE=========== @@ -663,13 +663,13 @@ USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 test SELECT COUNT(*) FROM t2; COUNT(*) 1 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b 1 test DELETE FROM t1; @@ -694,51 +694,51 @@ test_rpl e1 @ SYSTEM RECURRING NULL 1 # # NULL SLAVESIDE_DISABLED 1 latin1 latin SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 test1 SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b ==========SLAVE=========== USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 test1 SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b ==========MASTER========== SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 test1 SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b ==========SLAVE=========== USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 test1 SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b ALTER EVENT e1 RENAME TO e2; ==========MASTER========== @@ -754,26 +754,26 @@ test_rpl e2 @ SYSTEM RECURRING NULL 1 # # NULL SLAVESIDE_DISABLED 1 latin1 latin SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 test1 SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b ==========SLAVE=========== USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 test1 SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b DROP EVENT e2; ==========MASTER========== @@ -795,7 +795,7 @@ CREATE VIEW v2 AS SELECT * FROM t1 WHERE b <> UUID(); SHOW CREATE VIEW v1; View Create View character_set_client collation_connection v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `a`,`t1`.`b` AS `b` from `t1` where (`t1`.`a` = 1) latin1 latin1_swedish_ci -SELECT * FROM v1; +SELECT * FROM v1 ORDER BY a; a b 1 test1 ==========SLAVE=========== @@ -803,7 +803,7 @@ USE test_rpl; SHOW CREATE VIEW v1; View Create View character_set_client collation_connection v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `a`,`t1`.`b` AS `b` from `t1` where (`t1`.`a` = 1) latin1 latin1_swedish_ci -SELECT * FROM v1; +SELECT * FROM v1 ORDER BY a; a b 1 test1 ALTER VIEW v1 AS SELECT * FROM t1 WHERE a = 2; @@ -811,7 +811,7 @@ ALTER VIEW v1 AS SELECT * FROM t1 WHERE a = 2; SHOW CREATE VIEW v1; View Create View character_set_client collation_connection v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `a`,`t1`.`b` AS `b` from `t1` where (`t1`.`a` = 2) latin1 latin1_swedish_ci -SELECT * FROM v1; +SELECT * FROM v1 ORDER BY a; a b 2 test2 ==========SLAVE=========== @@ -819,7 +819,7 @@ USE test_rpl; SHOW CREATE VIEW v1; View Create View character_set_client collation_connection v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `a`,`t1`.`b` AS `b` from `t1` where (`t1`.`a` = 2) latin1 latin1_swedish_ci -SELECT * FROM v1; +SELECT * FROM v1 ORDER BY a; a b 2 test2 DROP VIEW v1; From dee842e093e8cc07cf785b9f06d509face46ed09 Mon Sep 17 00:00:00 2001 From: "cmiller@zippy.cornsilk.net" <> Date: Tue, 16 Oct 2007 15:37:31 -0400 Subject: [PATCH 045/336] Doxygenized comments. --- sql/sql_base.cc | 30 +- sql/sql_cache.cc | 22 +- sql/sql_class.cc | 2 +- sql/sql_cursor.cc | 76 +- sql/sql_parse.cc | 800 +++++++-------- sql/sql_prepare.cc | 596 ++++++----- sql/sql_select.cc | 2340 +++++++++++++++++++++++--------------------- sql/sql_trigger.cc | 341 +++---- sql/sql_update.cc | 2 +- sql/sql_view.cc | 2 +- 10 files changed, 2103 insertions(+), 2108 deletions(-) diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 337fde53dac..bf6c7ebaf92 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1817,8 +1817,8 @@ static void relink_unused(TABLE *table) /** - @brief Remove all instances of table from thread's open list and - table cache. + Remove all instances of table from thread's open list and + table cache. @param thd Thread context @param find Table to remove @@ -1867,7 +1867,7 @@ void unlink_open_table(THD *thd, TABLE *find, bool unlock) /** - @brief Auxiliary routine which closes and drops open table. + Auxiliary routine which closes and drops open table. @param thd Thread handle @param table TABLE object for table to be dropped @@ -2039,9 +2039,9 @@ bool reopen_name_locked_table(THD* thd, TABLE_LIST* table_list, bool link_in) /** - @brief Create and insert into table cache placeholder for table - which will prevent its opening (or creation) (a.k.a lock - table name). + Create and insert into table cache placeholder for table + which will prevent its opening (or creation) (a.k.a lock + table name). @param thd Thread context @param key Table cache key for name to be locked @@ -2090,8 +2090,8 @@ TABLE *table_cache_insert_placeholder(THD *thd, const char *key, /** - @brief Obtain an exclusive name lock on the table if it is not cached - in the table cache. + Obtain an exclusive name lock on the table if it is not cached + in the table cache. @param thd Thread context @param db Name of database @@ -2142,8 +2142,8 @@ bool lock_table_name_if_not_cached(THD *thd, const char *db, /** - @brief Check that table exists in table definition cache, on disk - or in some storage engine. + Check that table exists in table definition cache, on disk + or in some storage engine. @param thd Thread context @param table Table list element @@ -2815,8 +2815,8 @@ bool reopen_table(TABLE *table) /** - @brief Close all instances of a table open by this thread and replace - them with exclusive name-locks. + Close all instances of a table open by this thread and replace + them with exclusive name-locks. @param thd Thread context @param db Database name for the table to be closed @@ -2867,7 +2867,7 @@ void close_data_files_and_morph_locks(THD *thd, const char *db, /** - @brief Reopen all tables with closed data files. + Reopen all tables with closed data files. @param thd Thread context @param get_locks Should we get locks after reopening tables ? @@ -2957,8 +2957,8 @@ bool reopen_tables(THD *thd,bool get_locks,bool in_refresh) /** - @brief Close handlers for tables in list, but leave the TABLE structure - intact so that we can re-open these quickly. + Close handlers for tables in list, but leave the TABLE structure + intact so that we can re-open these quickly. @param thd Thread context @param table Head of the list of TABLE objects diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index ada927fa467..ed28ca35628 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -1524,7 +1524,7 @@ void Query_cache::invalidate(THD *thd, const char *key, uint32 key_length, /** - @brief Synchronize the thread with any flushing operations. + Synchronize the thread with any flushing operations. This helper function is called whenever a thread needs to operate on the query cache structure (example: during invalidation). If a table flush is in @@ -1565,7 +1565,7 @@ void Query_cache::wait_while_table_flush_is_in_progress(bool *interrupt) /** - @brief Remove all cached queries that uses the given database + Remove all cached queries that uses the given database. */ void Query_cache::invalidate(char *db) @@ -1675,8 +1675,8 @@ void Query_cache::flush() /** - @brief Rearrange the memory blocks and join result in cache in 1 block (if - result length > join_limit) + Rearrange the memory blocks and join result in cache in 1 block (if + result length > join_limit) @param[in] join_limit If the minimum length of a result block to be joined. @param[in] iteration_limit The maximum number of packing and joining @@ -1946,7 +1946,7 @@ void Query_cache::make_disabled() /** @class Query_cache - @brief Free all resources allocated by the cache. + Free all resources allocated by the cache. This function frees all resources allocated by the cache. You have to call init_cache() before using the cache again. This function @@ -1970,7 +1970,7 @@ void Query_cache::free_cache() /** - @brief Flush the cache. + Flush the cache. This function will flush cache contents. It assumes we have 'structure_guard_mutex' locked. The function sets the m_cache_status flag and @@ -2516,7 +2516,7 @@ Query_cache::invalidate_table_internal(THD *thd, uchar *key, uint32 key_length) } /** - @brief Invalidate a linked list of query cache blocks. + Invalidate a linked list of query cache blocks. Each block tries to aquire a block level lock before free_query is a called. This function will in turn affect @@ -2684,7 +2684,7 @@ my_bool Query_cache::register_all_tables(Query_cache_block *block, /** - @brief Insert used table name into the cache. + Insert used table name into the cache. @return Error status @retval FALSE On error @@ -3413,8 +3413,8 @@ my_bool Query_cache::ask_handler_allowance(THD *thd, /** - @brief Rearrange all memory blocks so that free memory joins at the - 'bottom' of the allocated memory block containing all cache data. + Rearrange all memory blocks so that free memory joins at the + 'bottom' of the allocated memory block containing all cache data. @see Query_cache::pack(ulong join_limit, uint iteration_limit) */ @@ -4028,7 +4028,7 @@ void Query_cache::tables_dump() /** - @brief Checks integrity of the various linked lists + Checks integrity of the various linked lists @return Error status code @retval FALSE Query cache is operational. diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 66a51d5bb00..df14e94850c 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -934,7 +934,7 @@ void THD::cleanup_after_query() /** - Create a LEX_STRING in this connection + Create a LEX_STRING in this connection. @param lex_str pointer to LEX_STRING object to be initialized @param str initializer to be copied into lex_str diff --git a/sql/sql_cursor.cc b/sql/sql_cursor.cc index d31c0af1163..2301b561797 100644 --- a/sql/sql_cursor.cc +++ b/sql/sql_cursor.cc @@ -24,9 +24,9 @@ Declarations. ****************************************************************************/ -/* +/** Sensitive_cursor -- a sensitive non-materialized server side - cursor An instance of this class cursor has its own runtime + cursor. An instance of this class cursor has its own runtime state -- list of used items and memory root for runtime memory, open and locked tables, change list for the changes of the parsed tree. This state is freed when the cursor is closed. @@ -69,7 +69,7 @@ public: }; -/* +/** Materialized_cursor -- an insensitive materialized server-side cursor. The result set of this cursor is saved in a temporary table at open. The cursor itself is simply an interface for the @@ -96,7 +96,7 @@ public: }; -/* +/** Select_materialize -- a mediator between a cursor query and the protocol. In case we were not able to open a non-materialzed cursor, it creates an internal temporary HEAP table, and insert @@ -107,7 +107,7 @@ public: class Select_materialize: public select_union { - select_result *result; /* the result object of the caller (PS or SP) */ + select_result *result; /**< the result object of the caller (PS or SP) */ public: Select_materialize(select_result *result_arg) :result(result_arg) {} virtual bool send_fields(List &list, uint flags); @@ -116,22 +116,21 @@ public: /**************************************************************************/ -/* +/** Attempt to open a materialized or non-materialized cursor. - SYNOPSIS - mysql_open_cursor() - thd thread handle - flags [in] create a materialized cursor or not - result [in] result class of the caller used as a destination - for the rows fetched from the cursor - pcursor [out] a pointer to store a pointer to cursor in + @param thd thread handle + @param[in] flags create a materialized cursor or not + @param[in] result result class of the caller used as a destination + for the rows fetched from the cursor + @param[out] pcursor a pointer to store a pointer to cursor in - RETURN VALUE - 0 the query has been successfully executed; in this - case pcursor may or may not contain - a pointer to an open cursor. - non-zero an error, 'pcursor' has been left intact. + @retval + 0 the query has been successfully executed; in this + case pcursor may or may not contain + a pointer to an open cursor. + @retval + non-zero an error, 'pcursor' has been left intact. */ int mysql_open_cursor(THD *thd, uint flags, select_result *result, @@ -279,6 +278,14 @@ Sensitive_cursor::Sensitive_cursor(THD *thd, select_result *result_arg) } +/** + Save THD state into cursor. + + @todo + - XXX: thd->locked_tables is not changed. + - What problems can we have with it if cursor is open? + - TODO: must be fixed because of the prelocked mode. +*/ void Sensitive_cursor::post_open(THD *thd) { @@ -334,6 +341,10 @@ Sensitive_cursor::post_open(THD *thd) } +/** + bzero cursor state in THD. +*/ + void Sensitive_cursor::reset_thd(THD *thd) { @@ -393,20 +404,13 @@ Sensitive_cursor::open(JOIN *join_arg) } -/* - SYNOPSIS - Sensitive_cursor::fetch() - num_rows fetch up to this number of rows (maybe less) +/** + Fetch next num_rows rows from the cursor and send them to the client. - DESCRIPTION - Fetch next num_rows rows from the cursor and send them to the client + Precondition: + - Sensitive_cursor is open - Precondition: - Sensitive_cursor is open - - RETURN VALUES: - none, this function will send OK to the clinet or set an error - message in THD + @param num_rows fetch up to this number of rows (maybe less) */ void @@ -478,6 +482,11 @@ Sensitive_cursor::fetch(ulong num_rows) } +/** + @todo + Another hack: we need to set THD state as if in a fetch to be + able to call stmt close. +*/ void Sensitive_cursor::close() { @@ -579,10 +588,9 @@ int Materialized_cursor::open(JOIN *join __attribute__((unused))) } -/* +/** Fetch up to the given number of rows from a materialized cursor. - DESCRIPTION Precondition: the cursor is open. If the cursor points after the last row, the fetch will automatically @@ -590,10 +598,6 @@ int Materialized_cursor::open(JOIN *join __attribute__((unused))) with SERVER_STATUS_LAST_ROW_SENT). This is an extra round trip and probably should be improved to return SERVER_STATUS_LAST_ROW_SENT along with the last row. - - RETURN VALUE - none, in case of success the row is sent to the client, otherwise - an error message is set in THD */ void Materialized_cursor::fetch(ulong num_rows) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index ae347bebb47..26055731547 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -158,8 +158,8 @@ bool begin_trans(THD *thd) } #ifdef HAVE_REPLICATION -/* - Returns true if all tables should be ignored +/** + Returns true if all tables should be ignored. */ inline bool all_tables_not_ok(THD *thd, TABLE_LIST *tables) { @@ -182,9 +182,10 @@ static bool some_non_temp_table_to_be_updated(THD *thd, TABLE_LIST *tables) } -/* - Mark all commands that somehow changes a table - This is used to check number of updates / hour +/** + Mark all commands that somehow changes a table. + + This is used to check number of updates / hour. sql_command is actually set to SQLCOM_END sometimes so we need the +1 to include it in the array. @@ -339,9 +340,10 @@ void execute_init_command(THD *thd, sys_var_str *init_command_var, } -/* +/** Execute commands from bootstrap_file. - Used when creating the initial grant tables + + Used when creating the initial grant tables. */ pthread_handler_t handle_bootstrap(void *arg) @@ -495,21 +497,20 @@ void cleanup_items(Item *item) DBUG_VOID_RETURN; } -/* - Handle COM_TABLE_DUMP command +/** + Handle COM_TABLE_DUMP command. - SYNOPSIS - mysql_table_dump - thd thread handle - db database name or an empty string. If empty, - the current database of the connection is used - tbl_name name of the table to dump + @param thd thread handle + @param db database name or an empty string. If empty, + the current database of the connection is used + @param tbl_name name of the table to dump - NOTES + @note This function is written to handle one specific command only. - RETURN VALUE + @retval 0 success + @retval 1 error, the error message is set in THD */ @@ -563,16 +564,14 @@ err: DBUG_RETURN(error); } -/* - Ends the current transaction and (maybe) begin the next +/** + Ends the current transaction and (maybe) begin the next. - SYNOPSIS - end_trans() - thd Current thread - completion Completion type + @param thd Current thread + @param completion Completion type - RETURN - 0 - OK + @retval + 0 OK */ int end_trans(THD *thd, enum enum_mysql_completiontype completion) @@ -641,13 +640,12 @@ int end_trans(THD *thd, enum enum_mysql_completiontype completion) #ifndef EMBEDDED_LIBRARY -/* +/** Read one command from connection and execute it (query or simple command). This function is called in loop from thread function. - SYNOPSIS - do_command() - RETURN VALUE + @retval 0 success + @retval 1 request of thread shutdown (see dispatch_command() description) */ @@ -719,21 +717,25 @@ bool do_command(THD *thd) #endif /* EMBEDDED_LIBRARY */ -/* - Perform one connection-level (COM_XXXX) command. +/** + Perform one connection-level (COM_XXXX) command. - SYNOPSIS - dispatch_command() - thd connection handle - command type of command to perform - packet data for the command, packet is always null-terminated - packet_length length of packet + 1 (to show that data is - null-terminated) except for COM_SLEEP, where it - can be zero. - RETURN VALUE + @param command type of command to perform + @param thd connection handle + @param packet data for the command, packet is always null-terminated + @param packet_length length of packet + 1 (to show that data is + null-terminated) except for COM_SLEEP, where it + can be zero. + + @todo + - TODO: set thd->lex->sql_command to SQLCOM_END here + - TODO: The following has to be changed to an 8 byte integer + + @retval 0 ok + @retval 1 request of thread shutdown, i. e. if command is - COM_QUIT/COM_SHUTDOWN + COM_QUIT/COM_SHUTDOWN */ bool dispatch_command(enum enum_server_command command, THD *thd, @@ -1380,32 +1382,30 @@ void log_slow_statement(THD *thd) } -/* +/** Create a TABLE_LIST object for an INFORMATION_SCHEMA table. - SYNOPSIS - prepare_schema_table() - thd thread handle - lex current lex - table_ident table alias if it's used - schema_table_idx the type of the INFORMATION_SCHEMA table to be - created - - DESCRIPTION This function is used in the parser to convert a SHOW or DESCRIBE table_name command to a SELECT from INFORMATION_SCHEMA. It prepares a SELECT_LEX and a TABLE_LIST object to represent the given command as a SELECT parse tree. - NOTES + @param thd thread handle + @param lex current lex + @param table_ident table alias if it's used + @param schema_table_idx the type of the INFORMATION_SCHEMA table to be + created + + @note Due to the way this function works with memory and LEX it cannot be used outside the parser (parse tree transformations outside the parser break PS and SP). - RETURN VALUE + @retval 0 success + @retval 1 out of memory or SHOW commands are not allowed - in this version of the server. + in this version of the server. */ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident, @@ -1505,17 +1505,17 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident, } -/* - Read query from packet and store in thd->query - Used in COM_QUERY and COM_STMT_PREPARE +/** + Read query from packet and store in thd->query. + Used in COM_QUERY and COM_STMT_PREPARE. - DESCRIPTION - Sets the following THD variables: - query - query_length + Sets the following THD variables: + - query + - query_length - RETURN VALUES + @retval FALSE ok + @retval TRUE error; In this case thd->fatal_error is set */ @@ -1655,14 +1655,8 @@ bool sp_process_definer(THD *thd) } -/* - Execute command saved in thd and lex->sql_command - - SYNOPSIS - mysql_execute_command() - thd Thread handle - - IMPLEMENTATION +/** + Execute command saved in thd and lex->sql_command. Before every operation that can request a write lock for a table wait if a global read lock exists. However do not wait if this @@ -1674,8 +1668,20 @@ bool sp_process_definer(THD *thd) global read lock when it succeeds. This needs to be released by start_waiting_global_read_lock() after the operation. - RETURN + @param thd Thread handle + + @todo + - Invalidate the table in the query cache if something changed + after unlocking when changes become visible. + TODO: this is workaround. right way will be move invalidating in + the unlock procedure. + - TODO: use check_change_password() + - JOIN is not supported yet. TODO + - SUSPEND and FOR MIGRATE are not supported yet. TODO + + @retval FALSE OK + @retval TRUE Error */ @@ -4555,20 +4561,19 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables) } -/* +/** Check grants for commands which work only with one table. - SYNOPSIS - check_single_table_access() - thd Thread handler - privilege requested privilege - all_tables global table list of query - no_errors FALSE/TRUE - report/don't report error to - the client (using my_error() call). + @param thd Thread handler + @param privilege requested privilege + @param all_tables global table list of query + @param no_errors FALSE/TRUE - report/don't report error to + the client (using my_error() call). - RETURN - 0 - OK - 1 - access denied, error is sent to client + @retval + 0 OK + @retval + 1 access denied, error is sent to client */ bool check_single_table_access(THD *thd, ulong privilege, @@ -4606,19 +4611,18 @@ deny: return 1; } -/* +/** Check grants for commands which work only with one table and all other tables belonging to subselects or implicitly opened tables. - SYNOPSIS - check_one_table_access() - thd Thread handler - privilege requested privilege - all_tables global table list of query + @param thd Thread handler + @param privilege requested privilege + @param all_tables global table list of query - RETURN - 0 - OK - 1 - access denied, error is sent to client + @retval + 0 OK + @retval + 1 access denied, error is sent to client */ bool check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *all_tables) @@ -4648,25 +4652,26 @@ bool check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *all_tables) } -/**************************************************************************** - Get the user (global) and database privileges for all used tables +/** + Get the user (global) and database privileges for all used tables. - NOTES + @param save_priv In this we store global and db level grants for the + table. Note that we don't store db level grants if the + global grants is enough to satisfy the request and the + global grants contains a SELECT grant. + + @note The idea of EXTRA_ACL is that one will be granted access to the table if one has the asked privilege on any column combination of the table; For example to be able to check a table one needs to have SELECT privilege on any column of the table. - RETURN + @retval 0 ok - 1 If we can't get the privileges and we don't use table/column grants. - - save_priv In this we store global and db level grants for the table - Note that we don't store db level grants if the global grants - is enough to satisfy the request and the global grants contains - a SELECT grant. -****************************************************************************/ - + @retval + 1 If we can't get the privileges and we don't use table/column + grants. +*/ bool check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, bool dont_check_global_grants, bool no_errors, bool schema_db) @@ -4788,22 +4793,21 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, } -/* - check for global access and give descriptive error message if it fails +/** + check for global access and give descriptive error message if it fails. - SYNOPSIS - check_global_access() - thd Thread handler - want_access Use should have any of these global rights + @param thd Thread handler + @param want_access Use should have any of these global rights - WARNING - One gets access right if one has ANY of the rights in want_access + @warning + One gets access right if one has ANY of the rights in want_access. This is useful as one in most cases only need one global right, but in some case we want to check if the user has SUPER or REPL_CLIENT_ACL rights. - RETURN + @retval 0 ok + @retval 1 Access denied. In this case an error is sent to the client */ @@ -4881,27 +4885,26 @@ static bool check_show_access(THD *thd, TABLE_LIST *table) } -/* +/** Check the privilege for all used tables. - SYNOPSYS - check_table_access() - thd Thread context - want_access Privileges requested - tables List of tables to be checked - no_errors FALSE/TRUE - report/don't report error to - the client (using my_error() call). + @param thd Thread context + @param want_access Privileges requested + @param tables List of tables to be checked + @param no_errors FALSE/TRUE - report/don't report error to + the client (using my_error() call). - NOTES + @note Table privileges are cached in the table list for GRANT checking. This functions assumes that table list used and thd->lex->query_tables_own_last value correspond to each other (the latter should be either 0 or point to next_global member of one of elements of this table list). - RETURN VALUE - FALSE - OK - TRUE - Access denied + @retval + FALSE OK + @retval + TRUE Access denied */ bool @@ -5005,17 +5008,16 @@ check_routine_access(THD *thd, ulong want_access,char *db, char *name, } -/* - Check if the routine has any of the routine privileges +/** + Check if the routine has any of the routine privileges. - SYNOPSIS - check_some_routine_access() - thd Thread handler - db Database name - name Routine name + @param thd Thread handler + @param db Database name + @param name Routine name - RETURN + @retval 0 ok + @retval 1 error */ @@ -5039,17 +5041,15 @@ bool check_some_routine_access(THD *thd, const char *db, const char *name, /* Check if the given table has any of the asked privileges - SYNOPSIS - check_some_access() - thd Thread handler - want_access Bitmap of possible privileges to check for + @param thd Thread handler + @param want_access Bitmap of possible privileges to check for - RETURN + @retval 0 ok + @retval 1 error */ - bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table) { ulong access; @@ -5108,12 +5108,13 @@ bool check_merge_table_access(THD *thd, char *db, long max_stack_used; #endif -/* +/** + @note Note: The 'buf' parameter is necessary, even if it is unused here. - fix_fields functions has a "dummy" buffer large enough for the corresponding exec. (Thus we only have to check in fix_fields.) - Passing to check_stack_overrun() prevents the compiler from removing it. - */ +*/ bool check_stack_overrun(THD *thd, long margin, uchar *buf __attribute__((unused))) { @@ -5167,17 +5168,17 @@ bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, ulong *yystacksize) } -/* - Reset THD part responsible for command processing state. +/** + Reset THD part responsible for command processing state. - DESCRIPTION - This needs to be called before execution of every statement - (prepared or conventional). - It is not called by substatements of routines. + This needs to be called before execution of every statement + (prepared or conventional). + It is not called by substatements of routines. - TODO + @todo Make it a method of THD and align its name with the rest of reset/end/start/init methods. + @todo Call it after we use THD for queries, not before. */ @@ -5322,17 +5323,14 @@ mysql_new_select(LEX *lex, bool move_down) DBUG_RETURN(0); } -/* +/** Create a select to return the same output as 'SELECT @@var_name'. - SYNOPSIS - create_select_for_variable() - var_name Variable name + Used for SHOW COUNT(*) [ WARNINGS | ERROR]. - DESCRIPTION - Used for SHOW COUNT(*) [ WARNINGS | ERROR] + This will crash with a core dump if the variable doesn't exists. - This will crash with a core dump if the variable doesn't exists + @param var_name Variable name */ void create_select_for_variable(const char *var_name) @@ -5498,8 +5496,9 @@ void mysql_parse(THD *thd, const char *inBuf, uint length, Usable by the replication SQL thread only: just parse a query to know if it can be ignored because of replicate-*-table rules. - RETURN VALUES + @retval 0 cannot be ignored + @retval 1 can be ignored */ @@ -5524,10 +5523,12 @@ bool mysql_test_parse_for_slave(THD *thd, char *inBuf, uint length) -/***************************************************************************** -** Store field definition for create -** Return 0 if ok -******************************************************************************/ +/** + Store field definition for create. + + @return + Return 0 if ok +*/ bool add_field_to_list(THD *thd, LEX_STRING *field_name, enum_field_types type, char *length, char *decimals, @@ -5631,7 +5632,7 @@ bool add_field_to_list(THD *thd, LEX_STRING *field_name, enum_field_types type, } -/* Store position for column in ALTER TABLE .. ADD column */ +/** Store position for column in ALTER TABLE .. ADD column. */ void store_position_for_column(const char *name) { @@ -5655,10 +5656,9 @@ add_proc_to_list(THD* thd, Item *item) } -/**************************************************************************** -** save order by and tables in own lists -****************************************************************************/ - +/** + save order by and tables in own lists. +*/ bool add_to_list(THD *thd, SQL_LIST &list,Item *item,bool asc) { @@ -5677,24 +5677,23 @@ bool add_to_list(THD *thd, SQL_LIST &list,Item *item,bool asc) } -/* - Add a table to list of used tables +/** + Add a table to list of used tables. - SYNOPSIS - add_table_to_list() - table Table to add - alias alias for table (or null if no alias) - table_options A set of the following bits: - TL_OPTION_UPDATING Table will be updated - TL_OPTION_FORCE_INDEX Force usage of index - TL_OPTION_ALIAS an alias in multi table DELETE - lock_type How table should be locked - use_index List of indexed used in USE INDEX - ignore_index List of indexed used in IGNORE INDEX + @param table Table to add + @param alias alias for table (or null if no alias) + @param table_options A set of the following bits: + - TL_OPTION_UPDATING : Table will be updated + - TL_OPTION_FORCE_INDEX : Force usage of index + - TL_OPTION_ALIAS : an alias in multi table DELETE + @param lock_type How table should be locked + @param use_index List of indexed used in USE INDEX + @param ignore_index List of indexed used in IGNORE INDEX - RETURN - 0 Error - # Pointer to TABLE_LIST element added to the total table list + @retval + 0 Error + @retval + \# Pointer to TABLE_LIST element added to the total table list */ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, @@ -5832,14 +5831,9 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, } -/* - Initialize a new table list for a nested join +/** + Initialize a new table list for a nested join. - SYNOPSIS - init_nested_join() - thd current thread - - DESCRIPTION The function initializes a structure of the TABLE_LIST type for a nested join. It sets up its nested join list as empty. The created structure is added to the front of the current @@ -5848,9 +5842,12 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, created empty list after having saved the info on the old level in the initialized structure. - RETURN VALUE - 0, if success - 1, otherwise + @param thd current thread + + @retval + 0 if success + @retval + 1 otherwise */ bool st_select_lex::init_nested_join(THD *thd) @@ -5876,21 +5873,18 @@ bool st_select_lex::init_nested_join(THD *thd) } -/* - End a nested join table list +/** + End a nested join table list. - SYNOPSIS - end_nested_join() - thd current thread - - DESCRIPTION The function returns to the previous join nest level. If the current level contains only one member, the function moves it one level up, eliminating the nest. - RETURN VALUE - Pointer to TABLE_LIST element added to the total table list, if success - 0, otherwise + @param thd current thread + + @return + - Pointer to TABLE_LIST element added to the total table list, if success + - 0, otherwise */ TABLE_LIST *st_select_lex::end_nested_join(THD *thd) @@ -5922,20 +5916,17 @@ TABLE_LIST *st_select_lex::end_nested_join(THD *thd) } -/* - Nest last join operation +/** + Nest last join operation. - SYNOPSIS - nest_last_join() - thd current thread + The function nest last join operation as if it was enclosed in braces. - DESCRIPTION - The function nest last join operation as if it was enclosed in braces. + @param thd current thread - RETURN VALUE + @retval 0 Error - # Pointer to TABLE_LIST element created for the new nested join - + @retval + \# Pointer to TABLE_LIST element created for the new nested join */ TABLE_LIST *st_select_lex::nest_last_join(THD *thd) @@ -5980,20 +5971,17 @@ TABLE_LIST *st_select_lex::nest_last_join(THD *thd) } -/* - Add a table to the current join list +/** + Add a table to the current join list. - SYNOPSIS - add_joined_table() - table the table to add - - DESCRIPTION The function puts a table in front of the current join list of st_select_lex object. Thus, joined tables are put into this list in the reverse order (the most outer join operation follows first). - RETURN VALUE + @param table the table to add + + @return None */ @@ -6007,14 +5995,9 @@ void st_select_lex::add_joined_table(TABLE_LIST *table) } -/* - Convert a right join into equivalent left join +/** + Convert a right join into equivalent left join. - SYNOPSIS - convert_right_join() - thd current thread - - DESCRIPTION The function takes the current join list t[0],t[1] ... and effectively converts it into the list t[1],t[0] ... Although the outer_join flag for the new nested table contains @@ -6022,21 +6005,25 @@ void st_select_lex::add_joined_table(TABLE_LIST *table) operation. EXAMPLES - SELECT * FROM t1 RIGHT JOIN t2 ON on_expr => - SELECT * FROM t2 LEFT JOIN t1 ON on_expr + @verbatim + SELECT * FROM t1 RIGHT JOIN t2 ON on_expr => + SELECT * FROM t2 LEFT JOIN t1 ON on_expr - SELECT * FROM t1,t2 RIGHT JOIN t3 ON on_expr => - SELECT * FROM t1,t3 LEFT JOIN t2 ON on_expr + SELECT * FROM t1,t2 RIGHT JOIN t3 ON on_expr => + SELECT * FROM t1,t3 LEFT JOIN t2 ON on_expr - SELECT * FROM t1,t2 RIGHT JOIN (t3,t4) ON on_expr => - SELECT * FROM t1,(t3,t4) LEFT JOIN t2 ON on_expr + SELECT * FROM t1,t2 RIGHT JOIN (t3,t4) ON on_expr => + SELECT * FROM t1,(t3,t4) LEFT JOIN t2 ON on_expr - SELECT * FROM t1 LEFT JOIN t2 ON on_expr1 RIGHT JOIN t3 ON on_expr2 => - SELECT * FROM t3 LEFT JOIN (t1 LEFT JOIN t2 ON on_expr2) ON on_expr1 + SELECT * FROM t1 LEFT JOIN t2 ON on_expr1 RIGHT JOIN t3 ON on_expr2 => + SELECT * FROM t3 LEFT JOIN (t1 LEFT JOIN t2 ON on_expr2) ON on_expr1 + @endverbatim - RETURN - Pointer to the table representing the inner table, if success - 0, otherwise + @param thd current thread + + @return + - Pointer to the table representing the inner table, if success + - 0, otherwise */ TABLE_LIST *st_select_lex::convert_right_join() @@ -6052,14 +6039,12 @@ TABLE_LIST *st_select_lex::convert_right_join() DBUG_RETURN(tab1); } -/* - Set lock for all tables in current select level +/** + Set lock for all tables in current select level. - SYNOPSIS: - set_lock_for_tables() - lock_type Lock to set for tables + @param lock_type Lock to set for tables - NOTE: + @note If lock is a write lock, then tables->updating is set 1 This is to get tables_ok to know that the table is updated by the query @@ -6083,27 +6068,29 @@ void st_select_lex::set_lock_for_tables(thr_lock_type lock_type) } -/* - Create a fake SELECT_LEX for a unit +/** + Create a fake SELECT_LEX for a unit. - SYNOPSIS: - add_fake_select_lex() - thd thread handle - - DESCRIPTION The method create a fake SELECT_LEX object for a unit. This object is created for any union construct containing a union operation and also for any single select union construct of the form + @verbatim (SELECT ... ORDER BY order_list [LIMIT n]) ORDER BY ... + @endvarbatim or of the form + @varbatim (SELECT ... ORDER BY LIMIT n) ORDER BY ... - - NOTES + @endvarbatim + + @param thd_arg thread handle + + @note The object is used to retrieve rows from the temporary table where the result on the union is obtained. - RETURN VALUES + @retval 1 on failure to create the object + @retval 0 on success */ @@ -6145,24 +6132,22 @@ bool st_select_lex_unit::add_fake_select_lex(THD *thd_arg) } -/* +/** Push a new name resolution context for a JOIN ... ON clause to the context stack of a query block. - SYNOPSIS - push_new_name_resolution_context() - thd pointer to current thread - left_op left operand of the JOIN - right_op rigth operand of the JOIN - - DESCRIPTION Create a new name resolution context for a JOIN ... ON clause, set the first and last leaves of the list of table references to be used for name resolution, and push the newly created context to the stack of contexts of the query. - RETURN + @param thd pointer to current thread + @param left_op left operand of the JOIN + @param right_op rigth operand of the JOIN + + @retval FALSE if all is OK + @retval TRUE if a memory allocation error occured */ @@ -6182,19 +6167,17 @@ push_new_name_resolution_context(THD *thd, } -/* +/** Add an ON condition to the second operand of a JOIN ... ON. - SYNOPSIS - add_join_on - b the second operand of a JOIN ... ON - expr the condition to be added to the ON clause + Add an ON condition to the right operand of a JOIN ... ON clause. - DESCRIPTION - Add an ON condition to the right operand of a JOIN ... ON clause. + @param b the second operand of a JOIN ... ON + @param expr the condition to be added to the ON clause - RETURN + @retval FALSE if there was some error + @retval TRUE if all is OK */ @@ -6218,18 +6201,10 @@ void add_join_on(TABLE_LIST *b, Item *expr) } -/* +/** Mark that there is a NATURAL JOIN or JOIN ... USING between two tables. - SYNOPSIS - add_join_natural() - a Left join argument - b Right join argument - using_fields Field names from USING clause - lex The current st_select_lex - - IMPLEMENTATION This function marks that table b should be joined with a either via a NATURAL JOIN or via JOIN ... USING. Both join types are special cases of each other, so we treat them together. The function @@ -6240,20 +6215,23 @@ void add_join_on(TABLE_LIST *b, Item *expr) was an outer join. EXAMPLE - SELECT * FROM t1 NATURAL LEFT JOIN t2 - <=> - SELECT * FROM t1 LEFT JOIN t2 ON (t1.i=t2.i and t1.j=t2.j ... ) + @verbatim + SELECT * FROM t1 NATURAL LEFT JOIN t2 + <=> + SELECT * FROM t1 LEFT JOIN t2 ON (t1.i=t2.i and t1.j=t2.j ... ) - SELECT * FROM t1 NATURAL JOIN t2 WHERE - <=> - SELECT * FROM t1, t2 WHERE (t1.i=t2.i and t1.j=t2.j and ) + SELECT * FROM t1 NATURAL JOIN t2 WHERE + <=> + SELECT * FROM t1, t2 WHERE (t1.i=t2.i and t1.j=t2.j and ) - SELECT * FROM t1 JOIN t2 USING(j) WHERE - <=> - SELECT * FROM t1, t2 WHERE (t1.j=t2.j and ) + SELECT * FROM t1 JOIN t2 USING(j) WHERE + <=> + SELECT * FROM t1, t2 WHERE (t1.j=t2.j and ) + @endverbatim - RETURN - None + @param a Left join argument + @param b Right join argument + @param using_fields Field names from USING clause */ void add_join_natural(TABLE_LIST *a, TABLE_LIST *b, List *using_fields, @@ -6264,24 +6242,24 @@ void add_join_natural(TABLE_LIST *a, TABLE_LIST *b, List *using_fields, } -/* +/** Reload/resets privileges and the different caches. - SYNOPSIS - reload_acl_and_cache() - thd Thread handler (can be NULL!) - options What should be reset/reloaded (tables, privileges, - slave...) - tables Tables to flush (if any) - write_to_binlog Depending on 'options', it may be very bad to write the - query to the binlog (e.g. FLUSH SLAVE); this is a - pointer where reload_acl_and_cache() will put 0 if - it thinks we really should not write to the binlog. - Otherwise it will put 1. + @param thd Thread handler (can be NULL!) + @param options What should be reset/reloaded (tables, privileges, + slave...) + @param tables Tables to flush (if any) + @param write_to_binlog Depending on 'options', it may be very bad to + write the query to the binlog (e.g. FLUSH SLAVE); + this is a pointer where reload_acl_and_cache() + will put 0 if it thinks we really should not write + to the binlog. + Otherwise it will put 1. - RETURN + @retval 0 ok - !=0 error. thd->killed or thd->net.report_error is set + @retval + !=0 error. thd->killed or thd->net.report_error is set */ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, @@ -6454,16 +6432,14 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, } -/* - kills a thread +/** + kill on thread. - SYNOPSIS - kill_one_thread() - thd Thread class - id Thread id - only_kill_query Should it kill the query or the connection + @param thd Thread class + @param id Thread id + @param only_kill_query Should it kill the query or the connection - NOTES + @note This is written such that we have a short lock on LOCK_thread_count */ @@ -6523,7 +6499,7 @@ void sql_kill(THD *thd, ulong id, bool only_kill_query) } - /* If pointer is not a null pointer, append filename to it */ +/** If pointer is not a null pointer, append filename to it. */ bool append_file_to_dir(THD *thd, const char **filename_ptr, const char *table_name) @@ -6550,14 +6526,12 @@ bool append_file_to_dir(THD *thd, const char **filename_ptr, } -/* - Check if the select is a simple select (not an union) +/** + Check if the select is a simple select (not an union). - SYNOPSIS - check_simple_select() - - RETURN VALUES + @retval 0 ok + @retval 1 error ; In this case the error messege is sent to the client */ @@ -6614,17 +6588,15 @@ Comp_creator *comp_ne_creator(bool invert) } -/* - Construct ALL/ANY/SOME subquery Item +/** + Construct ALL/ANY/SOME subquery Item. - SYNOPSIS - all_any_subquery_creator() - left_expr - pointer to left expression - cmp - compare function creator - all - true if we create ALL subquery - select_lex - pointer on parsed subquery structure + @param left_expr pointer to left expression + @param cmp compare function creator + @param all true if we create ALL subquery + @param select_lex pointer on parsed subquery structure - RETURN VALUE + @return constructed Item (or 0 if out of memory) */ Item * all_any_subquery_creator(Item *left_expr, @@ -6647,16 +6619,15 @@ Item * all_any_subquery_creator(Item *left_expr, } -/* - Multi update query pre-check +/** + Multi update query pre-check. - SYNOPSIS - multi_update_precheck() - thd Thread handler - tables Global/local table list (have to be the same) + @param thd Thread handler + @param tables Global/local table list (have to be the same) - RETURN VALUE + @retval FALSE OK + @retval TRUE Error */ @@ -6724,16 +6695,15 @@ bool multi_update_precheck(THD *thd, TABLE_LIST *tables) DBUG_RETURN(FALSE); } -/* - Multi delete query pre-check +/** + Multi delete query pre-check. - SYNOPSIS - multi_delete_precheck() - thd Thread handler - tables Global/local table list + @param thd Thread handler + @param tables Global/local table list - RETURN VALUE + @retval FALSE OK + @retval TRUE error */ @@ -6773,17 +6743,16 @@ bool multi_delete_precheck(THD *thd, TABLE_LIST *tables) } -/* +/** Link tables in auxilary table list of multi-delete with corresponding elements in main table list, and set proper locks for them. - SYNOPSIS - multi_delete_set_locks_and_link_aux_tables() - lex - pointer to LEX representing multi-delete + @param lex pointer to LEX representing multi-delete - RETURN VALUE - FALSE - success - TRUE - error + @retval + FALSE success + @retval + TRUE error */ bool multi_delete_set_locks_and_link_aux_tables(LEX *lex) @@ -6826,16 +6795,15 @@ bool multi_delete_set_locks_and_link_aux_tables(LEX *lex) } -/* - simple UPDATE query pre-check +/** + simple UPDATE query pre-check. - SYNOPSIS - update_precheck() - thd Thread handler - tables Global table list + @param thd Thread handler + @param tables Global table list - RETURN VALUE + @retval FALSE OK + @retval TRUE Error */ @@ -6851,16 +6819,15 @@ bool update_precheck(THD *thd, TABLE_LIST *tables) } -/* - simple DELETE query pre-check +/** + simple DELETE query pre-check. - SYNOPSIS - delete_precheck() - thd Thread handler - tables Global table list + @param thd Thread handler + @param tables Global table list - RETURN VALUE + @retval FALSE OK + @retval TRUE error */ @@ -6875,16 +6842,15 @@ bool delete_precheck(THD *thd, TABLE_LIST *tables) } -/* - simple INSERT query pre-check +/** + simple INSERT query pre-check. - SYNOPSIS - insert_precheck() - thd Thread handler - tables Global table list + @param thd Thread handler + @param tables Global table list - RETURN VALUE + @retval FALSE OK + @retval TRUE error */ @@ -6932,17 +6898,16 @@ static bool check_show_create_table_access(THD *thd, TABLE_LIST *table) } -/* - CREATE TABLE query pre-check +/** + CREATE TABLE query pre-check. - SYNOPSIS - create_table_precheck() - thd Thread handler - tables Global table list - create_table Table which will be created + @param thd Thread handler + @param tables Global table list + @param create_table Table which will be created - RETURN VALUE + @retval FALSE OK + @retval TRUE Error */ @@ -7008,15 +6973,13 @@ err: } -/* - negate given expression +/** + negate given expression. - SYNOPSIS - negate_expression() - thd thread handler - expr expression for negation + @param thd thread handler + @param expr expression for negation - RETURN + @return negated expression */ @@ -7043,14 +7006,12 @@ Item *negate_expression(THD *thd, Item *expr) return new Item_func_not(expr); } -/* - Set the specified definer to the default value, which is the current user in - the thread. - - SYNOPSIS - get_default_definer() - thd [in] thread handler - definer [out] definer +/** + Set the specified definer to the default value, which is the + current user in the thread. + + @param[in] thd thread handler + @param[out] definer definer */ void get_default_definer(THD *thd, LEX_USER *definer) @@ -7065,17 +7026,15 @@ void get_default_definer(THD *thd, LEX_USER *definer) } -/* +/** Create default definer for the specified THD. - SYNOPSIS - create_default_definer() - thd [in] thread handler + @param[in] thd thread handler - RETURN - On success, return a valid pointer to the created and initialized + @return + - On success, return a valid pointer to the created and initialized LEX_USER, which contains definer information. - On error, return 0. + - On error, return 0. */ LEX_USER *create_default_definer(THD *thd) @@ -7091,19 +7050,17 @@ LEX_USER *create_default_definer(THD *thd) } -/* +/** Create definer with the given user and host names. - SYNOPSIS - create_definer() - thd [in] thread handler - user_name [in] user name - host_name [in] host name + @param[in] thd thread handler + @param[in] user_name user name + @param[in] host_name host name - RETURN - On success, return a valid pointer to the created and initialized + @return + - On success, return a valid pointer to the created and initialized LEX_USER, which contains definer information. - On error, return 0. + - On error, return 0. */ LEX_USER *create_definer(THD *thd, LEX_STRING *user_name, LEX_STRING *host_name) @@ -7122,18 +7079,16 @@ LEX_USER *create_definer(THD *thd, LEX_STRING *user_name, LEX_STRING *host_name) } -/* +/** Retuns information about user or current user. - SYNOPSIS - get_current_user() - thd [in] thread handler - user [in] user + @param[in] thd thread handler + @param[in] user user - RETURN - On success, return a valid pointer to initialized + @return + - On success, return a valid pointer to initialized LEX_USER, which contains user information. - On error, return 0. + - On error, return 0. */ LEX_USER *get_current_user(THD *thd, LEX_USER *user) @@ -7145,17 +7100,16 @@ LEX_USER *get_current_user(THD *thd, LEX_USER *user) } -/* +/** Check that byte length of a string does not exceed some limit. - SYNOPSIS - check_string_byte_length() - str string to be checked - err_msg error message to be displayed if the string is too long - max_byte_length max length in bytes + @param str string to be checked + @param err_msg error message to be displayed if the string is too long + @param max_length max length - RETURN + @retval FALSE the passed string is not longer than max_length + @retval TRUE the passed string is longer than max_length NOTE diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 9337a2aa329..fb657df54cd 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -13,7 +13,9 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/********************************************************************** +/** + @file + This file contains the implementation of prepared statements. When one prepares a statement: @@ -28,11 +30,13 @@ When one prepares a statement: - Without executing the query, return back to client the total number of parameters along with result-set metadata information (if any) in the following format: + @verbatim [STMT_ID:4] [Column_count:2] [Param_count:2] [Params meta info (stubs only for now)] (if Param_count > 0) [Columns meta info] (if Column_count > 0) + @endverbatim During prepare the tables used in a statement are opened, but no locks are acquired. Table opening will block any DDL during the @@ -45,12 +49,14 @@ When one executes a statement: - Server gets the command 'COM_STMT_EXECUTE' to execute the previously prepared query. If there are any parameter markers, then the client will send the data in the following format: + @verbatim [COM_STMT_EXECUTE:1] [STMT_ID:4] [NULL_BITS:(param_count+7)/8)] [TYPES_SUPPLIED_BY_CLIENT(0/1):1] [[length]data] [[length]data] .. [[length]data]. + @endverbatim (Note: Except for string/binary types; all other types will not be supplied with length field) - If it is a first execute or types of parameters were altered by client, @@ -75,8 +81,7 @@ When one supplies long data for a placeholder: server doesn't care; also, the server doesn't notify the client whether it got the data or not; if there is any error, then it will be returned at statement execute. - -***********************************************************************/ +*/ #include "mysql_priv.h" #include "sql_select.h" // for JOIN @@ -91,7 +96,9 @@ When one supplies long data for a placeholder: #include #endif -/* A result class used to send cursor rows using the binary protocol. */ +/** + A result class used to send cursor rows using the binary protocol. +*/ class Select_fetch_protocol_binary: public select_send { @@ -112,7 +119,7 @@ public: /****************************************************************************/ /** - @brief Prepared_statement: a statement that can contain placeholders + Prepared_statement: a statement that can contain placeholders. */ class Prepared_statement: public Statement @@ -176,20 +183,17 @@ inline bool is_param_null(const uchar *pos, ulong param_no) return pos[param_no/8] & (1 << (param_no & 7)); } -/* +/** Find a prepared statement in the statement map by id. - SYNOPSIS - find_prepared_statement() - thd thread handle - id statement id - where the place from which this function is called (for - error reporting). - - DESCRIPTION Try to find a prepared statement and set THD error if it's not found. - RETURN VALUE + @param thd thread handle + @param id statement id + @param where the place from which this function is called (for + error reporting). + + @return 0 if the statement was not found, a pointer otherwise. */ @@ -214,13 +218,13 @@ find_prepared_statement(THD *thd, ulong id, const char *where) } -/* +/** Send prepared statement id and metadata to the client after prepare. - SYNOPSIS - send_prep_stmt() + @todo + Fix this nasty upcast from List to List - RETURN VALUE + @return 0 in case of success, 1 otherwise */ @@ -265,24 +269,22 @@ static bool send_prep_stmt(Prepared_statement *stmt, #endif /*!EMBEDDED_LIBRARY*/ -/* +#ifndef EMBEDDED_LIBRARY + +/** Read the length of the parameter data and return it back to the caller. - SYNOPSIS - get_param_length() - packet a pointer to the data - len remaining packet length - - DESCRIPTION Read data length, position the packet to the first byte after it, and return the length to the caller. - RETURN VALUE + @param packet a pointer to the data + @param len remaining packet length + + @return Length of data piece. */ -#ifndef EMBEDDED_LIBRARY static ulong get_param_length(uchar **packet, ulong len) { reg1 uchar *pos= *packet; @@ -323,16 +325,9 @@ static ulong get_param_length(uchar **packet, ulong len) #define get_param_length(packet, len) len #endif /*!EMBEDDED_LIBRARY*/ - /* - Data conversion routines. +/** + Data conversion routines. - SYNOPSIS - set_param_xx() - param parameter item - pos input data buffer - len length of data in the buffer - - DESCRIPTION All these functions read the data from pos, convert it to requested type and assign to param; pos is advanced to predefined length. @@ -340,8 +335,9 @@ static ulong get_param_length(uchar **packet, ulong len) (i.e. when input types altered) and for all subsequent executions we don't read any values for this. - RETURN VALUE - none + @param param parameter item + @param pos input data buffer + @param len length of data in the buffer */ static void set_param_tiny(Item_param *param, uchar **pos, ulong len) @@ -443,6 +439,10 @@ static void set_param_decimal(Item_param *param, uchar **pos, ulong len) libmysql.c (store_param_{time,date,datetime}). */ +/** + @todo + Add warning 'Data truncated' here +*/ static void set_param_time(Item_param *param, uchar **pos, ulong len) { MYSQL_TIME tm; @@ -532,6 +532,10 @@ static void set_param_date(Item_param *param, uchar **pos, ulong len) } #else/*!EMBEDDED_LIBRARY*/ +/** + @todo + Add warning 'Data truncated' here +*/ void set_param_time(Item_param *param, uchar **pos, ulong len) { MYSQL_TIME tm= *((MYSQL_TIME*)*pos); @@ -684,14 +688,13 @@ static void setup_one_conversion_function(THD *thd, Item_param *param, } #ifndef EMBEDDED_LIBRARY -/* +/** Routines to assign parameters from data supplied by the client. - DESCRIPTION Update the parameter markers by reading data from the packet and and generate a valid query for logging. - NOTES + @note This function, along with other _with_log functions is called when one of binary, slow or general logs is open. Logging of prepared statements in all cases is performed by means of conventional queries: if parameter @@ -699,21 +702,28 @@ static void setup_one_conversion_function(THD *thd, Item_param *param, replaced with its actual value; if we're logging a [Dynamic] SQL prepared statement, parameter markers are replaced with variable names. Example: + @verbatim mysql_stmt_prepare("UPDATE t1 SET a=a*1.25 WHERE a=?") --> general logs gets [Prepare] UPDATE t1 SET a*1.25 WHERE a=?" mysql_stmt_execute(stmt); --> general and binary logs get [Execute] UPDATE t1 SET a*1.25 WHERE a=1" - If a statement has been prepared using SQL syntax: + @endverbatim + + If a statement has been prepared using SQL syntax: + @verbatim PREPARE stmt FROM "UPDATE t1 SET a=a*1.25 WHERE a=?" --> general log gets [Query] PREPARE stmt FROM "UPDATE ..." EXECUTE stmt USING @a --> general log gets - [Query] EXECUTE stmt USING @a; + [Query] EXECUTE stmt USING @a; + @endverbatim - RETURN VALUE - 0 if success, 1 otherwise + @retval + 0 if success + @retval + 1 otherwise */ static bool insert_params_with_log(Prepared_statement *stmt, uchar *null_array, @@ -829,12 +839,12 @@ static bool setup_conversion_functions(Prepared_statement *stmt, #else -/* +/** Embedded counterparts of parameter assignment routines. - DESCRIPTION The main difference between the embedded library and the server is that in embedded case we don't serialize/deserialize parameters data. + Additionally, for unknown reason, the client-side flag raised for changed types of placeholders is ignored and we simply setup conversion functions at each execute (TODO: fix). @@ -928,15 +938,14 @@ static bool emb_insert_params_with_log(Prepared_statement *stmt, #endif /*!EMBEDDED_LIBRARY*/ -/* +/** Assign prepared statement parameters from user variables. - SYNOPSIS - insert_params_from_vars() - stmt Statement - varnames List of variables. Caller must ensure that number of variables - in the list is equal to number of statement parameters - query Ignored + @param stmt Statement + @param varnames List of variables. Caller must ensure that number + of variables in the list is equal to number of statement + parameters + @param query Ignored */ static bool insert_params_from_vars(Prepared_statement *stmt, @@ -965,17 +974,16 @@ static bool insert_params_from_vars(Prepared_statement *stmt, } -/* +/** Do the same as insert_params_from_vars but also construct query text for binary log. - SYNOPSIS - insert_params_from_vars() - stmt Prepared statement - varnames List of variables. Caller must ensure that number of variables - in the list is equal to number of statement parameters - query The query with parameter markers replaced with corresponding - user variables that were used to execute the query. + @param stmt Prepared statement + @param varnames List of variables. Caller must ensure that number of + variables in the list is equal to number of statement + parameters + @param query The query with parameter markers replaced with corresponding + user variables that were used to execute the query. */ static bool insert_params_from_vars_with_log(Prepared_statement *stmt, @@ -1024,17 +1032,16 @@ static bool insert_params_from_vars_with_log(Prepared_statement *stmt, DBUG_RETURN(0); } -/* +/** Validate INSERT statement. - SYNOPSIS - mysql_test_insert() - stmt prepared statement - tables global/local table list + @param stmt prepared statement + @param tables global/local table list - RETURN VALUE - FALSE success - TRUE error, error message is set in THD + @retval + FALSE success + @retval + TRUE error, error message is set in THD */ static bool mysql_test_insert(Prepared_statement *stmt, @@ -1112,18 +1119,21 @@ error: } -/* - Validate UPDATE statement +/** + Validate UPDATE statement. - SYNOPSIS - mysql_test_update() - stmt prepared statement - tables list of tables used in this query + @param stmt prepared statement + @param tables list of tables used in this query - RETURN VALUE - 0 success - 1 error, error message is set in THD - 2 convert to multi_update + @todo + - here we should send types of placeholders to the client. + + @retval + 0 success + @retval + 1 error, error message is set in THD + @retval + 2 convert to multi_update */ static int mysql_test_update(Prepared_statement *stmt, @@ -1196,17 +1206,16 @@ error: } -/* +/** Validate DELETE statement. - SYNOPSIS - mysql_test_delete() - stmt prepared statement - tables list of tables used in this query + @param stmt prepared statement + @param tables list of tables used in this query - RETURN VALUE - FALSE success - TRUE error, error message is set in THD + @retval + FALSE success + @retval + TRUE error, error message is set in THD */ static bool mysql_test_delete(Prepared_statement *stmt, @@ -1233,22 +1242,21 @@ error: } -/* +/** Validate SELECT statement. - SYNOPSIS - mysql_test_select() - stmt prepared statement - tables list of tables used in the query - - DESCRIPTION In case of success, if this query is not EXPLAIN, send column list info back to the client. - RETURN VALUE - 0 success - 1 error, error message is set in THD - 2 success, and statement metadata has been sent + @param stmt prepared statement + @param tables list of tables used in the query + + @retval + 0 success + @retval + 1 error, error message is set in THD + @retval + 2 success, and statement metadata has been sent */ static int mysql_test_select(Prepared_statement *stmt, @@ -1313,18 +1321,17 @@ error: } -/* +/** Validate and prepare for execution DO statement expressions. - SYNOPSIS - mysql_test_do_fields() - stmt prepared statement - tables list of tables used in this query - values list of expressions + @param stmt prepared statement + @param tables list of tables used in this query + @param values list of expressions - RETURN VALUE - FALSE success - TRUE error, error message is set in THD + @retval + FALSE success + @retval + TRUE error, error message is set in THD */ static bool mysql_test_do_fields(Prepared_statement *stmt, @@ -1343,18 +1350,17 @@ static bool mysql_test_do_fields(Prepared_statement *stmt, } -/* - Validate and prepare for execution SET statement expressions +/** + Validate and prepare for execution SET statement expressions. - SYNOPSIS - mysql_test_set_fields() - stmt prepared statement - tables list of tables used in this query - values list of expressions + @param stmt prepared statement + @param tables list of tables used in this query + @param values list of expressions - RETURN VALUE - FALSE success - TRUE error, error message is set in THD + @retval + FALSE success + @retval + TRUE error, error message is set in THD */ static bool mysql_test_set_fields(Prepared_statement *stmt, @@ -1381,23 +1387,22 @@ error: } -/* - Check internal SELECT of the prepared command +/** + Check internal SELECT of the prepared command. - SYNOPSIS - select_like_stmt_test() - stmt prepared statement - specific_prepare function of command specific prepare - setup_tables_done_option options to be passed to LEX::unit.prepare() + @param stmt prepared statement + @param specific_prepare function of command specific prepare + @param setup_tables_done_option options to be passed to LEX::unit.prepare() - NOTE + @note This function won't directly open tables used in select. They should be opened either by calling function (and in this case you probably should use select_like_stmt_test_with_open()) or by "specific_prepare" call (like this happens in case of multi-update). - RETURN VALUE + @retval FALSE success + @retval TRUE error, error message is set in THD */ @@ -1420,20 +1425,19 @@ static bool select_like_stmt_test(Prepared_statement *stmt, DBUG_RETURN(lex->unit.prepare(thd, 0, setup_tables_done_option)); } -/* +/** Check internal SELECT of the prepared command (with opening of used tables). - SYNOPSIS - select_like_stmt_test_with_open() - stmt prepared statement - tables list of tables to be opened before calling - specific_prepare function - specific_prepare function of command specific prepare - setup_tables_done_option options to be passed to LEX::unit.prepare() + @param stmt prepared statement + @param tables list of tables to be opened + before calling specific_prepare function + @param specific_prepare function of command specific prepare + @param setup_tables_done_option options to be passed to LEX::unit.prepare() - RETURN VALUE + @retval FALSE success + @retval TRUE error */ @@ -1459,17 +1463,16 @@ select_like_stmt_test_with_open(Prepared_statement *stmt, } -/* - Validate and prepare for execution CREATE TABLE statement +/** + Validate and prepare for execution CREATE TABLE statement. - SYNOPSIS - mysql_test_create_table() - stmt prepared statement - tables list of tables used in this query + @param stmt prepared statement + @param tables list of tables used in this query - RETURN VALUE - FALSE success - TRUE error, error message is set in THD + @retval + FALSE success + @retval + TRUE error, error message is set in THD */ static bool mysql_test_create_table(Prepared_statement *stmt) @@ -1512,18 +1515,17 @@ static bool mysql_test_create_table(Prepared_statement *stmt) } -/* +/** Validate and prepare for execution a multi update statement. - SYNOPSIS - mysql_test_multiupdate() - stmt prepared statement - tables list of tables used in this query - converted converted to multi-update from usual update + @param stmt prepared statement + @param tables list of tables used in this query + @param converted converted to multi-update from usual update - RETURN VALUE - FALSE success - TRUE error, error message is set in THD + @retval + FALSE success + @retval + TRUE error, error message is set in THD */ static bool mysql_test_multiupdate(Prepared_statement *stmt, @@ -1539,17 +1541,16 @@ static bool mysql_test_multiupdate(Prepared_statement *stmt, } -/* +/** Validate and prepare for execution a multi delete statement. - SYNOPSIS - mysql_test_multidelete() - stmt prepared statement - tables list of tables used in this query + @param stmt prepared statement + @param tables list of tables used in this query - RETURN VALUE - FALSE success - TRUE error, error message in THD is set. + @retval + FALSE success + @retval + TRUE error, error message in THD is set. */ static bool mysql_test_multidelete(Prepared_statement *stmt, @@ -1579,15 +1580,13 @@ error: } -/* +/** Wrapper for mysql_insert_select_prepare, to make change of local tables after open_normal_and_derived_tables() call. - SYNOPSIS - mysql_insert_select_prepare_tester() - thd thread handle + @param thd thread handle - NOTE + @note We need to remove the first local table after open_normal_and_derived_tables(), because mysql_handle_derived uses local tables lists. @@ -1608,17 +1607,16 @@ static bool mysql_insert_select_prepare_tester(THD *thd) } -/* +/** Validate and prepare for execution INSERT ... SELECT statement. - SYNOPSIS - mysql_test_insert_select() - stmt prepared statement - tables list of tables used in this query + @param stmt prepared statement + @param tables list of tables used in this query - RETURN VALUE - FALSE success - TRUE error, error message is set in THD + @retval + FALSE success + @retval + TRUE error, error message is set in THD */ static bool mysql_test_insert_select(Prepared_statement *stmt, @@ -1651,23 +1649,21 @@ static bool mysql_test_insert_select(Prepared_statement *stmt, } -/* +/** Perform semantic analysis of the parsed tree and send a response packet to the client. - SYNOPSIS - check_prepared_statement() - stmt prepared statement - - DESCRIPTION This function - opens all tables and checks access rights - validates semantics of statement columns and SQL functions by calling fix_fields. - RETURN VALUE - FALSE success, statement metadata is sent to client - TRUE error, error message is set in THD (but not sent) + @param stmt prepared statement + + @retval + FALSE success, statement metadata is sent to client + @retval + TRUE error, error message is set in THD (but not sent) */ static bool check_prepared_statement(Prepared_statement *stmt, @@ -1834,7 +1830,7 @@ error: DBUG_RETURN(TRUE); } -/* +/** Initialize array of parameters in statement from LEX. (We need to have quick access to items by number in mysql_stmt_get_longdata). This is to avoid using malloc/realloc in the parser. @@ -1870,31 +1866,28 @@ static bool init_param_array(Prepared_statement *stmt) } -/* +/** COM_STMT_PREPARE handler. - SYNOPSIS - mysql_stmt_prepare() - packet query to be prepared - packet_length query string length, including ignored - trailing NULL or quote char. - - DESCRIPTION Given a query string with parameter markers, create a prepared statement from it and send PS info back to the client. - NOTES - This function parses the query and sends the total number of parameters - and resultset metadata information back to client (if any), without - executing the query i.e. without any log/disk writes. This allows the - queries to be re-executed without re-parsing during execute. - If parameter markers are found in the query, then store the information using Item_param along with maintaining a list in lex->param_array, so that a fast and direct retrieval can be made without going through all field items. - RETURN VALUE + @param packet query to be prepared + @param packet_length query string length, including ignored + trailing NULL or quote char. + + @note + This function parses the query and sends the total number of parameters + and resultset metadata information back to client (if any), without + executing the query i.e. without any log/disk writes. This allows the + queries to be re-executed without re-parsing during execute. + + @return none: in case of success a new statement id and metadata is sent to the client, otherwise an error message is set in THD. */ @@ -1944,22 +1937,22 @@ void mysql_stmt_prepare(THD *thd, const char *packet, uint packet_length) DBUG_VOID_RETURN; } -/* - SYNOPSIS - get_dynamic_sql_string() - lex in main lex - query_len out length of the SQL statement (is set only - in case of success) +/** + Get an SQL statement text from a user variable or from plain text. - DESCRIPTION - Get an SQL statement text from a user variable or from plain - text. If the statement is plain text, just assign the - pointers, otherwise allocate memory in thd->mem_root and copy - the contents of the variable, possibly with character - set conversion. + If the statement is plain text, just assign the + pointers, otherwise allocate memory in thd->mem_root and copy + the contents of the variable, possibly with character + set conversion. - RETURN VALUE - non-zero success, 0 in case of error (out of memory) + @param[in] lex main lex + @param[out] query_len length of the SQL statement (is set only + in case of success) + + @retval + non-zero success + @retval + 0 in case of error (out of memory) */ static const char *get_dynamic_sql_string(LEX *lex, uint *query_len) @@ -2037,7 +2030,7 @@ end: } -/* Init PS/SP specific parse tree members. */ +/** Init PS/SP specific parse tree members. */ static void init_stmt_after_parse(LEX *lex) { @@ -2050,19 +2043,16 @@ static void init_stmt_after_parse(LEX *lex) sl->uncacheable&= ~UNCACHEABLE_PREPARE; } -/* +/** SQLCOM_PREPARE implementation. - SYNOPSIS - mysql_sql_stmt_prepare() - thd thread handle - - DESCRIPTION Prepare an SQL prepared statement. This is called from mysql_execute_command and should therefore behave like an ordinary query (e.g. should not reset any global THD data). - RETURN VALUE + @param thd thread handle + + @return none: in case of success, OK packet is sent to the client, otherwise an error message is set in THD */ @@ -2118,7 +2108,14 @@ void mysql_sql_stmt_prepare(THD *thd) DBUG_VOID_RETURN; } -/* Reinit prepared statement/stored procedure before execution */ +/** + Reinit prepared statement/stored procedure before execution. + + @todo + When the new table structure is ready, then have a status bit + to indicate the table is altered, and re-do the setup_* + and open the tables back. +*/ void reinit_stmt_before_use(THD *thd, LEX *lex) { @@ -2224,13 +2221,11 @@ void reinit_stmt_before_use(THD *thd, LEX *lex) } -/* - Clears parameters from data left from previous execution or long data +/** + Clears parameters from data left from previous execution or long data. - SYNOPSIS - reset_stmt_params() - stmt prepared statement for which parameters should - be reset + @param stmt prepared statement for which parameters should + be reset */ static void reset_stmt_params(Prepared_statement *stmt) @@ -2242,22 +2237,19 @@ static void reset_stmt_params(Prepared_statement *stmt) } -/* +/** COM_STMT_EXECUTE handler: execute a previously prepared statement. - SYNOPSIS - mysql_stmt_execute() - thd current thread - packet parameter types and data, if any - packet_length packet length, including the terminator character. - - DESCRIPTION If there are any parameters, then replace parameter markers with the data supplied from the client, and then execute the statement. This function uses binary protocol to send a possible result set to the client. - RETURN VALUE + @param thd current thread + @param packet_arg parameter types and data, if any + @param packet_length packet length, including the terminator character. + + @return none: in case of success OK packet or a result set is sent to the client, otherwise an error message is set in THD. */ @@ -2331,14 +2323,9 @@ set_params_data_err: } -/* +/** SQLCOM_EXECUTE implementation. - SYNOPSIS - mysql_sql_stmt_execute() - thd thread handle - - DESCRIPTION Execute prepared statement using parameter values from lex->prepared_stmt_params and send result to the client using text protocol. This is called from mysql_execute_command and @@ -2346,7 +2333,9 @@ set_params_data_err: global THD data, such as warning count, server status, etc). This function uses text protocol to send a possible result set. - RETURN + @param thd thread handle + + @return none: in case of success, OK (or result set) packet is sent to the client, otherwise an error is set in THD */ @@ -2398,14 +2387,12 @@ set_params_data_err: } -/* - COM_STMT_FETCH handler: fetches requested amount of rows from cursor +/** + COM_STMT_FETCH handler: fetches requested amount of rows from cursor. - SYNOPSIS - mysql_stmt_fetch() - thd Thread handle - packet Packet from client (with stmt_id & num_rows) - packet_length Length of packet + @param thd Thread handle + @param packet Packet from client (with stmt_id & num_rows) + @param packet_length Length of packet */ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length) @@ -2456,22 +2443,20 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length) } -/* +/** Reset a prepared statement in case there was a recoverable error. - SYNOPSIS - mysql_stmt_reset() - thd Thread handle - packet Packet with stmt id - DESCRIPTION This function resets statement to the state it was right after prepare. It can be used to: - - clear an error happened during mysql_stmt_send_long_data - - cancel long data stream for all placeholders without - having to call mysql_stmt_execute. - - close an open cursor + - clear an error happened during mysql_stmt_send_long_data + - cancel long data stream for all placeholders without + having to call mysql_stmt_execute. + - close an open cursor Sends 'OK' packet in case of success (statement was reset) or 'ERROR' packet (unrecoverable error/statement not found/etc). + + @param thd Thread handle + @param packet Packet with stmt id */ void mysql_stmt_reset(THD *thd, char *packet) @@ -2504,9 +2489,11 @@ void mysql_stmt_reset(THD *thd, char *packet) } -/* +/** Delete a prepared statement from memory. - Note: we don't send any reply to this command. + + @note + we don't send any reply to this command. */ void mysql_stmt_close(THD *thd, char *packet) @@ -2530,15 +2517,14 @@ void mysql_stmt_close(THD *thd, char *packet) } -/* +/** SQLCOM_DEALLOCATE implementation. - DESCRIPTION Close an SQL prepared statement. As this can be called from Dynamic SQL, we should be careful to not close a statement that is currently being executed. - RETURN VALUE + @return none: OK packet is sent in case of success, otherwise an error message is set in THD */ @@ -2561,21 +2547,18 @@ void mysql_sql_stmt_close(THD *thd) send_ok(thd); } -/* +/** Handle long data in pieces from client. - SYNOPSIS - mysql_stmt_get_longdata() - thd Thread handle - packet String to append - packet_length Length of string (including end \0) - - DESCRIPTION Get a part of a long data. To make the protocol efficient, we are not sending any return packets here. If something goes wrong, then we will send the error on 'execute' We assume that the client takes care of checking that all parts are sent to the server. (No checking that we get a 'end of column' in the server is performed). + + @param thd Thread handle + @param packet String to append + @param packet_length Length of string (including end \\0) */ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length) @@ -2742,12 +2725,12 @@ void Prepared_statement::setup_set_params() } -/* - DESCRIPTION - Destroy this prepared statement, cleaning up all used memory - and resources. This is called from ::deallocate() to - handle COM_STMT_CLOSE and DEALLOCATE PREPARE or when - THD ends and all prepared statements are freed. +/** + Destroy this prepared statement, cleaning up all used memory + and resources. + + This is called from ::deallocate() to handle COM_STMT_CLOSE and + DEALLOCATE PREPARE or when THD ends and all prepared statements are freed. */ Prepared_statement::~Prepared_statement() @@ -2804,28 +2787,24 @@ bool Prepared_statement::set_name(LEX_STRING *name_arg) global THD state management to the caller. ***************************************************************************/ -/* +/** Parse statement text, validate the statement, and prepare it for execution. - SYNOPSIS - Prepared_statement::prepare() - packet statement text - packet_len - - DESCRIPTION You should not change global THD state in this function, if at all possible: it may be called from any context, e.g. when executing a COM_* command, and SQLCOM_* command, or a stored procedure. - NOTES - Precondition. - ------------- + @param packet statement text + @param packet_len + + @note + Precondition: The caller must ensure that thd->change_list and thd->free_list is empty: this function will not back them up but will free in the end of its execution. - Postcondition. - -------------- + @note + Postcondition: thd->mem_root contains unused memory allocated during validation. */ @@ -2956,28 +2935,25 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) DBUG_RETURN(error); } -/* +/** Execute a prepared statement. - SYNOPSIS - Prepared_statement::execute() - expanded_query A query for binlogging which has all parameter - markers ('?') replaced with their actual values. - open_cursor True if an attempt to open a cursor should be made. - Currenlty used only in the binary protocol. - - DESCRIPTION You should not change global THD state in this function, if at all possible: it may be called from any context, e.g. when executing a COM_* command, and SQLCOM_* command, or a stored procedure. - NOTES - Preconditions, postconditions. - ------------------------------ - See the comment for Prepared_statement::prepare(). + @param expanded_query A query for binlogging which has all parameter + markers ('?') replaced with their actual values. + @param open_cursor True if an attempt to open a cursor should be made. + Currenlty used only in the binary protocol. - RETURN - FALSE ok + @note + Preconditions, postconditions. + - See the comment for Prepared_statement::prepare(). + + @retval + FALSE ok + @retval TRUE Error */ @@ -3161,7 +3137,7 @@ error: } -/* Common part of DEALLOCATE PREPARE and mysql_stmt_close */ +/** Common part of DEALLOCATE PREPARE and mysql_stmt_close. */ bool Prepared_statement::deallocate() { diff --git a/sql/sql_select.cc b/sql/sql_select.cc index b77bb719e1e..7c751fa7393 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -14,12 +14,16 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /** + @file + + @brief + mysql_select and join optimization + + @defgroup Query_Optimizer Query Optimizer @{ */ -/* mysql_select and join optimization */ - #ifdef USE_PRAGMA_IMPLEMENTATION #pragma implementation // gcc: Class implementation #endif @@ -225,8 +229,8 @@ static Item *remove_additional_cond(Item* conds); static void add_group_and_distinct_keys(JOIN *join, JOIN_TAB *join_tab); -/* - This handles SELECT with and without UNION +/** + This handles SELECT with and without UNION. */ bool handle_select(THD *thd, LEX *lex, select_result *result, @@ -382,8 +386,8 @@ fix_inner_refs(THD *thd, List &all_fields, SELECT_LEX *select, return res; } -/* - Function to setup clauses without sum functions +/** + Function to setup clauses without sum functions. */ inline int setup_without_group(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, @@ -416,10 +420,17 @@ inline int setup_without_group(THD *thd, Item **ref_pointer_array, mysql_select assumes that all tables are already opened *****************************************************************************/ -/* +/** Prepare of whole select (including sub queries in future). - return -1 on error - 0 on success + + @todo + Add check of calculation of GROUP functions and fields: + SELECT COUNT(*)+table.col1 from table1; + + @retval + -1 on error + @retval + 0 on success */ int JOIN::prepare(Item ***rref_pointer_array, @@ -742,11 +753,16 @@ static void save_index_subquery_explain_info(JOIN_TAB *join_tab, Item* where) } -/* +/** global select optimisation. - return 0 - success - 1 - error - error code saved in field 'error' + + @note + error code saved in field 'error' + + @retval + 0 success + @retval + 1 error */ int @@ -1495,8 +1511,8 @@ JOIN::optimize() } -/* - Restore values in temporary join +/** + Restore values in temporary join. */ void JOIN::restore_tmp() { @@ -1584,8 +1600,16 @@ JOIN::save_join_tab() } -/* - Exec select +/** + Exec select. + + @todo + Note, that create_sort_index calls test_if_skip_sort_order and may + finally replace sorting with index scan if there is a LIMIT clause in + the query. It's never shown in EXPLAIN! + + @todo + When can we have here thd->net.report_error not zero? */ void JOIN::exec() @@ -2157,8 +2181,11 @@ JOIN::exec() } -/* - Clean up join. Return error that hold JOIN. +/** + Clean up join. + + @return + Return error that hold JOIN. */ int @@ -2192,49 +2219,48 @@ JOIN::destroy() DBUG_RETURN(error); } -/* +/** An entry point to single-unit select (a select without UNION). - SYNOPSIS - mysql_select() + @param thd thread handler + @param rref_pointer_array a reference to ref_pointer_array of + the top-level select_lex for this query + @param tables list of all tables used in this query. + The tables have been pre-opened. + @param wild_num number of wildcards used in the top level + select of this query. + For example statement + SELECT *, t1.*, catalog.t2.* FROM t0, t1, t2; + has 3 wildcards. + @param fields list of items in SELECT list of the top-level + select + e.g. SELECT a, b, c FROM t1 will have Item_field + for a, b and c in this list. + @param conds top level item of an expression representing + WHERE clause of the top level select + @param og_num total number of ORDER BY and GROUP BY clauses + arguments + @param order linked list of ORDER BY agruments + @param group linked list of GROUP BY arguments + @param having top level item of HAVING expression + @param proc_param list of PROCEDUREs + @param select_options select options (BIG_RESULT, etc) + @param result an instance of result set handling class. + This object is responsible for send result + set rows to the client or inserting them + into a table. + @param select_lex the only SELECT_LEX of this query + @param unit top-level UNIT of this query + UNIT is an artificial object created by the + parser for every SELECT clause. + e.g. + SELECT * FROM t1 WHERE a1 IN (SELECT * FROM t2) + has 2 unions. - thd thread handler - rref_pointer_array a reference to ref_pointer_array of - the top-level select_lex for this query - tables list of all tables used in this query. - The tables have been pre-opened. - wild_num number of wildcards used in the top level - select of this query. - For example statement - SELECT *, t1.*, catalog.t2.* FROM t0, t1, t2; - has 3 wildcards. - fields list of items in SELECT list of the top-level - select - e.g. SELECT a, b, c FROM t1 will have Item_field - for a, b and c in this list. - conds top level item of an expression representing - WHERE clause of the top level select - og_num total number of ORDER BY and GROUP BY clauses - arguments - order linked list of ORDER BY agruments - group linked list of GROUP BY arguments - having top level item of HAVING expression - proc_param list of PROCEDUREs - select_options select options (BIG_RESULT, etc) - result an instance of result set handling class. - This object is responsible for send result - set rows to the client or inserting them - into a table. - select_lex the only SELECT_LEX of this query - unit top-level UNIT of this query - UNIT is an artificial object created by the parser - for every SELECT clause. - e.g. SELECT * FROM t1 WHERE a1 IN (SELECT * FROM t2) - has 2 unions. - - RETURN VALUE - FALSE success - TRUE an error + @retval + FALSE success + @retval + TRUE an error */ bool @@ -2380,12 +2406,13 @@ typedef struct st_sargable_param uint num_values; /* number of values in the above array */ } SARGABLE_PARAM; -/* - Calculate the best possible join and initialize the join structure +/** + Calculate the best possible join and initialize the join structure. - RETURN VALUES - 0 ok - 1 Fatal error + @retval + 0 ok + @retval + 1 Fatal error */ static bool @@ -2826,13 +2853,14 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds, keyuse Pointer to possible keys *****************************************************************************/ -typedef struct key_field_t { // Used when finding key fields +/// Used when finding key fields +typedef struct key_field_t { Field *field; - Item *val; // May be empty if diff constant + Item *val; ///< May be empty if diff constant uint level; uint optimize; bool eq_func; - /* + /** If true, the condition this struct represents will not be satisfied when val IS NULL. */ @@ -2844,22 +2872,28 @@ typedef struct key_field_t { // Used when finding key fields #define KEY_OPTIMIZE_EXISTS 1 #define KEY_OPTIMIZE_REF_OR_NULL 2 -/* - Merge new key definitions to old ones, remove those not used in both +/** + Merge new key definitions to old ones, remove those not used in both. - This is called for OR between different levels + This is called for OR between different levels. To be able to do 'ref_or_null' we merge a comparison of a column and 'column IS NULL' to one test. This is useful for sub select queries - that are internally transformed to something like: + that are internally transformed to something like:. + @code SELECT * FROM t1 WHERE t1.key=outer_ref_field or t1.key IS NULL + @endcode - KEY_FIELD::null_rejecting is processed as follows: + KEY_FIELD::null_rejecting is processed as follows: @n result has null_rejecting=true if it is set for both ORed references. for example: - (t2.key = t1.field OR t2.key = t1.field) -> null_rejecting=true - (t2.key = t1.field OR t2.key <=> t1.field) -> null_rejecting=false + - (t2.key = t1.field OR t2.key = t1.field) -> null_rejecting=true + - (t2.key = t1.field OR t2.key <=> t1.field) -> null_rejecting=false + + @todo + The result of this is that we're missing some 'ref' accesses. + OptimizerTeam: Fix this */ static KEY_FIELD * @@ -2968,25 +3002,23 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end, } -/* +/** Add a possible key to array of possible keys if it's usable as a key - SYNPOSIS - add_key_field() - key_fields Pointer to add key, if usable - and_level And level, to be stored in KEY_FIELD - cond Condition predicate - field Field used in comparision - eq_func True if we used =, <=> or IS NULL - value Value used for comparison with field - usable_tables Tables which can be used for key optimization - sargables IN/OUT Array of found sargable candidates + @param key_fields Pointer to add key, if usable + @param and_level And level, to be stored in KEY_FIELD + @param cond Condition predicate + @param field Field used in comparision + @param eq_func True if we used =, <=> or IS NULL + @param value Value used for comparison with field + @param usable_tables Tables which can be used for key optimization + @param sargables IN/OUT Array of found sargable candidates - NOTES + @note If we are doing a NOT NULL comparison on a NOT NULL field in a outer join table, we store this to be able to do not exists optimization later. - RETURN + @returns *key_fields is incremented if we stored a key in the array */ @@ -3137,26 +3169,25 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, Item_func *cond, (*key_fields)++; } -/* - Add possible keys to array of possible keys originated from a simple predicate +/** + Add possible keys to array of possible keys originated from a simple + predicate. - SYNPOSIS - add_key_equal_fields() - key_fields Pointer to add key, if usable - and_level And level, to be stored in KEY_FIELD - cond Condition predicate - field Field used in comparision - eq_func True if we used =, <=> or IS NULL - value Value used for comparison with field - Is NULL for BETWEEN and IN - usable_tables Tables which can be used for key optimization - sargables IN/OUT Array of found sargable candidates + @param key_fields Pointer to add key, if usable + @param and_level And level, to be stored in KEY_FIELD + @param cond Condition predicate + @param field Field used in comparision + @param eq_func True if we used =, <=> or IS NULL + @param value Value used for comparison with field + Is NULL for BETWEEN and IN + @param usable_tables Tables which can be used for key optimization + @param sargables IN/OUT Array of found sargable candidates - NOTES + @note If field items f1 and f2 belong to the same multiple equality and a key is added for f1, the the same key is added for f2. - RETURN + @returns *key_fields is incremented if we stored a key in the array */ @@ -3387,9 +3418,13 @@ add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level, } } -/* - Add all keys with uses 'field' for some keypart - If field->and_level != and_level then only mark key_part as const_part +/** + Add all keys with uses 'field' for some keypart. + + If field->and_level != and_level then only mark key_part as const_part. + + @todo + ft-keys in non-ft queries. SerG */ static uint @@ -3522,33 +3557,37 @@ sort_keyuse(KEYUSE *a,KEYUSE *b) /* - Add to KEY_FIELD array all 'ref' access candidates within nested join + Add to KEY_FIELD array all 'ref' access candidates within nested join. - SYNPOSIS - add_key_fields_for_nj() - nested_join_table IN Nested join pseudo-table to process - end INOUT End of the key field array - and_level INOUT And-level - sargables IN/OUT Array of found sargable candidates - - DESCRIPTION This function populates KEY_FIELD array with entries generated from the ON condition of the given nested join, and does the same for nested joins contained within this nested join. - NOTES + @param[in] nested_join_table Nested join pseudo-table to process + @param[in,out] end End of the key field array + @param[in,out] and_level And-level + @param[in,out] sargables Array of found sargable candidates + + + @note We can add accesses to the tables that are direct children of this nested join (1), and are not inner tables w.r.t their neighbours (2). Example for #1 (outer brackets pair denotes nested join this function is invoked for): + @code ... LEFT JOIN (t1 LEFT JOIN (t2 ... ) ) ON cond + @endcode Example for #2: + @code ... LEFT JOIN (t1 LEFT JOIN t2 ) ON cond + @endcode In examples 1-2 for condition cond, we can add 'ref' access candidates to t1 only. Example #3: + @code ... LEFT JOIN (t1, t2 LEFT JOIN t3 ON inner_cond) ON cond + @endcode Here we can add 'ref' access candidates for t1 and t2, but not for t3. */ @@ -3574,25 +3613,25 @@ static void add_key_fields_for_nj(JOIN *join, TABLE_LIST *nested_join_table, } -/* - Update keyuse array with all possible keys we can use to fetch rows +/** + Update keyuse array with all possible keys we can use to fetch rows. - SYNOPSIS - update_ref_and_keys() - thd - keyuse OUT Put here ordered array of KEYUSE structures - join_tab Array in tablenr_order - tables Number of tables in join - cond WHERE condition (note that the function analyzes - join_tab[i]->on_expr too) - normal_tables Tables not inner w.r.t some outer join (ones for which - we can make ref access based the WHERE clause) - select_lex current SELECT - sargables OUT Array of found sargable candidates + @param thd + @param[out] keyuse Put here ordered array of KEYUSE structures + @param join_tab Array in tablenr_order + @param tables Number of tables in join + @param cond WHERE condition (note that the function analyzes + join_tab[i]->on_expr too) + @param normal_tables Tables not inner w.r.t some outer join (ones + for which we can make ref access based the WHERE + clause) + @param select_lex current SELECT + @param[out] sargables Array of found sargable candidates - RETURN - 0 - OK - 1 - Out of memory. + @retval + 0 OK + @retval + 1 Out of memory. */ static bool @@ -3751,8 +3790,8 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab, return FALSE; } -/* - Update some values in keyuse for faster choose_plan() loop +/** + Update some values in keyuse for faster choose_plan() loop. */ static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array) @@ -3793,23 +3832,21 @@ static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array) } -/* +/** Discover the indexes that can be used for GROUP BY or DISTINCT queries. - SYNOPSIS - add_group_and_distinct_keys() - join - join_tab + If the query has a GROUP BY clause, find all indexes that contain all + GROUP BY fields, and add those indexes to join->const_keys. - DESCRIPTION - If the query has a GROUP BY clause, find all indexes that contain all - GROUP BY fields, and add those indexes to join->const_keys. - If the query has a DISTINCT clause, find all indexes that contain all - SELECT fields, and add those indexes to join->const_keys. - This allows later on such queries to be processed by a - QUICK_GROUP_MIN_MAX_SELECT. + If the query has a DISTINCT clause, find all indexes that contain all + SELECT fields, and add those indexes to join->const_keys. + This allows later on such queries to be processed by a + QUICK_GROUP_MIN_MAX_SELECT. - RETURN + @param join + @param join_tab + + @return None */ @@ -3861,7 +3898,7 @@ add_group_and_distinct_keys(JOIN *join, JOIN_TAB *join_tab) which uses least records *****************************************************************************/ -/* Save const tables first as used tables */ +/** Save const tables first as used tables. */ static void set_position(JOIN *join,uint idx,JOIN_TAB *table,KEYUSE *key) @@ -3884,31 +3921,28 @@ set_position(JOIN *join,uint idx,JOIN_TAB *table,KEYUSE *key) } -/* - Find the best access path for an extension of a partial execution plan and - add this path to the plan. +/** + Find the best access path for an extension of a partial execution + plan and add this path to the plan. - SYNOPSIS - best_access_path() - join pointer to the structure providing all context info - for the query - s the table to be joined by the function - thd thread for the connection that submitted the query - remaining_tables set of tables not included into the partial plan yet - idx the length of the partial plan - record_count estimate for the number of records returned by the partial - plan - read_time the cost of the partial plan + The function finds the best access path to table 's' from the passed + partial plan where an access path is the general term for any means to + access the data in 's'. An access path may use either an index or a scan, + whichever is cheaper. The input partial plan is passed via the array + 'join->positions' of length 'idx'. The chosen access method for 's' and its + cost are stored in 'join->positions[idx]'. - DESCRIPTION - The function finds the best access path to table 's' from the passed - partial plan where an access path is the general term for any means to - access the data in 's'. An access path may use either an index or a scan, - whichever is cheaper. The input partial plan is passed via the array - 'join->positions' of length 'idx'. The chosen access method for 's' and its - cost are stored in 'join->positions[idx]'. + @param join pointer to the structure providing all context info + for the query + @param s the table to be joined by the function + @param thd thread for the connection that submitted the query + @param remaining_tables set of tables not included into the partial plan yet + @param idx the length of the partial plan + @param record_count estimate for the number of records returned by the + partial plan + @param read_time the cost of the partial plan - RETURN + @return None */ @@ -4436,24 +4470,26 @@ best_access_path(JOIN *join, } -/* +/** Selects and invokes a search strategy for an optimal query plan. - SYNOPSIS - choose_plan() - join pointer to the structure providing all context info for - the query - join_tables set of the tables in the query + The function checks user-configurable parameters that control the search + strategy for an optimal plan, selects the search method and then invokes + it. Each specific optimization procedure stores the final optimal plan in + the array 'join->best_positions', and the cost of the plan in + 'join->best_read'. - DESCRIPTION - The function checks user-configurable parameters that control the search - strategy for an optimal plan, selects the search method and then invokes - it. Each specific optimization procedure stores the final optimal plan in - the array 'join->best_positions', and the cost of the plan in - 'join->best_read'. + @param join pointer to the structure providing all context info for + the query + @param join_tables set of the tables in the query - RETURN VALUES + @todo + 'MAX_TABLES+2' denotes the old implementation of find_best before + the greedy version. Will be removed when greedy_search is approved. + + @retval FALSE ok + @retval TRUE Fatal error */ @@ -4515,17 +4551,17 @@ choose_plan(JOIN *join, table_map join_tables) } -/* +/** Compare two JOIN_TAB objects based on the number of accessed records. - SYNOPSIS - join_tab_cmp() - ptr1 pointer to first JOIN_TAB object - ptr2 pointer to second JOIN_TAB object + @param ptr1 pointer to first JOIN_TAB object + @param ptr2 pointer to second JOIN_TAB object - RETURN + @retval 1 if first is bigger - -1 if second is bigger + @retval + -1 if second is bigger + @retval 0 if equal */ @@ -4547,7 +4583,7 @@ join_tab_cmp(const void* ptr1, const void* ptr2) } -/* +/** Same as join_tab_cmp, but for use with SELECT_STRAIGHT_JOIN. */ @@ -4564,27 +4600,33 @@ join_tab_cmp_straight(const void* ptr1, const void* ptr2) return jt1 > jt2 ? 1 : (jt1 < jt2 ? -1 : 0); } -/* +/** Heuristic procedure to automatically guess a reasonable degree of exhaustiveness for the greedy search procedure. - SYNOPSIS - determine_search_depth() - join pointer to the structure providing all context info for the query + The procedure estimates the optimization time and selects a search depth + big enough to result in a near-optimal QEP, that doesn't take too long to + find. If the number of tables in the query exceeds some constant, then + search_depth is set to this constant. - DESCRIPTION - The procedure estimates the optimization time and selects a search depth - big enough to result in a near-optimal QEP, that doesn't take too long to - find. If the number of tables in the query exceeds some constant, then - search_depth is set to this constant. + @param join pointer to the structure providing all context info for + the query - NOTES + @note This is an extremely simplistic implementation that serves as a stub for a more advanced analysis of the join. Ideally the search depth should be determined by learning from previous query optimizations, because it will depend on the CPU power (and other factors). - RETURN + @todo + this value should be determined dynamically, based on statistics: + uint max_tables_for_exhaustive_opt= 7; + + @todo + this value could be determined by some mapping of the form: + depth : table_count -> [max_tables_for_exhaustive_opt..MAX_EXHAUSTIVE] + + @return A positive integer that specifies the search depth (and thus the exhaustiveness) of the depth-first search algorithm used by 'greedy_search'. @@ -4611,16 +4653,9 @@ determine_search_depth(JOIN *join) } -/* +/** Select the best ways to access the tables in a query without reordering them. - SYNOPSIS - optimize_straight_join() - join pointer to the structure providing all context info for - the query - join_tables set of the tables in the query - - DESCRIPTION Find the best access paths for each query table and compute their costs according to their order in the array 'join->best_ref' (thus without reordering the join tables). The function calls sequentially @@ -4628,15 +4663,17 @@ determine_search_depth(JOIN *join) access method. The final optimal plan is stored in the array 'join->best_positions', and the corresponding cost in 'join->best_read'. - NOTES + @param join pointer to the structure providing all context info for + the query + @param join_tables set of the tables in the query + + @note This function can be applied to: - queries with STRAIGHT_JOIN - internally to compute the cost of an arbitrary QEP + @par Thus 'optimize_straight_join' can be used at any stage of the query optimization process to finalize a QEP as it is. - - RETURN - None */ static void @@ -4669,31 +4706,24 @@ optimize_straight_join(JOIN *join, table_map join_tables) } -/* +/** Find a good, possibly optimal, query execution plan (QEP) by a greedy search. - SYNOPSIS - join pointer to the structure providing all context info - for the query - remaining_tables set of tables not included into the partial plan yet - search_depth controlls the exhaustiveness of the search - prune_level the pruning heuristics that should be applied during - search - - DESCRIPTION The search procedure uses a hybrid greedy/exhaustive search with controlled exhaustiveness. The search is performed in N = card(remaining_tables) steps. Each step evaluates how promising is each of the unoptimized tables, selects the most promising table, and extends the current partial QEP with that table. Currenly the most 'promising' table is the one with least - expensive extension. + expensive extension.\ + There are two extreme cases: - 1. When (card(remaining_tables) < search_depth), the estimate finds the best - complete continuation of the partial QEP. This continuation can be - used directly as a result of the search. - 2. When (search_depth == 1) the 'best_extension_by_limited_search' - consideres the extension of the current QEP with each of the remaining - unoptimized tables. + -# When (card(remaining_tables) < search_depth), the estimate finds the + best complete continuation of the partial QEP. This continuation can be + used directly as a result of the search. + -# When (search_depth == 1) the 'best_extension_by_limited_search' + consideres the extension of the current QEP with each of the remaining + unoptimized tables. + All other cases are in-between these two extremes. Thus the parameter 'search_depth' controlls the exhaustiveness of the search. The higher the value, the longer the optimizaton time and possibly the better the @@ -4701,16 +4731,18 @@ optimize_straight_join(JOIN *join, table_map join_tables) estimated, but the more likely to get a bad QEP. All intermediate and final results of the procedure are stored in 'join': - join->positions modified for every partial QEP that is explored - join->best_positions modified for the current best complete QEP - join->best_read modified for the current best complete QEP - join->best_ref might be partially reordered + - join->positions : modified for every partial QEP that is explored + - join->best_positions: modified for the current best complete QEP + - join->best_read : modified for the current best complete QEP + - join->best_ref : might be partially reordered + The final optimal plan is stored in 'join->best_positions', and its corresponding cost in 'join->best_read'. - NOTES + @note The following pseudocode describes the algorithm of 'greedy_search': + @code procedure greedy_search input: remaining_tables output: pplan; @@ -4724,6 +4756,7 @@ optimize_straight_join(JOIN *join, table_map join_tables) return pplan; } + @endcode where 'best_extension' is a placeholder for a procedure that selects the most "promising" of all tables in 'remaining_tables'. Currently this estimate is performed by calling @@ -4731,16 +4764,26 @@ optimize_straight_join(JOIN *join, table_map join_tables) current QEP of size 'search_depth', thus the complexity of 'greedy_search' mainly depends on that of 'best_extension_by_limited_search'. + @par If 'best_extension()' == 'best_extension_by_limited_search()', then the worst-case complexity of this algorithm is <= O(N*N^search_depth/search_depth). When serch_depth >= N, then the complexity of greedy_search is O(N!). + @par In the future, 'greedy_search' might be extended to support other implementations of 'best_extension', e.g. some simpler quadratic procedure. - RETURN VALUES + @param join pointer to the structure providing all context info + for the query + @param remaining_tables set of tables not included into the partial plan yet + @param search_depth controlls the exhaustiveness of the search + @param prune_level the pruning heuristics that should be applied during + search + + @retval FALSE ok + @retval TRUE Fatal error */ @@ -4816,29 +4859,10 @@ greedy_search(JOIN *join, } -/* +/** Find a good, possibly optimal, query execution plan (QEP) by a possibly exhaustive search. - SYNOPSIS - best_extension_by_limited_search() - join pointer to the structure providing all context info for - the query - remaining_tables set of tables not included into the partial plan yet - idx length of the partial QEP in 'join->positions'; - since a depth-first search is used, also corresponds to - the current depth of the search tree; - also an index in the array 'join->best_ref'; - record_count estimate for the number of records returned by the best - partial plan - read_time the cost of the best partial plan - search_depth maximum depth of the recursion and thus size of the found - optimal plan (0 < search_depth <= join->tables+1). - prune_level pruning heuristics that should be applied during - optimization - (values: 0 = EXHAUSTIVE, 1 = PRUNE_BY_TIME_OR_ROWS) - - DESCRIPTION The procedure searches for the optimal ordering of the query tables in set 'remaining_tables' of size N, and the corresponding optimal access paths to each table. The choice of a table order and an access path for each table @@ -4865,16 +4889,18 @@ greedy_search(JOIN *join, The final optimal plan is stored in 'join->best_positions'. The corresponding cost of the optimal plan is in 'join->best_read'. - NOTES + @note The procedure uses a recursive depth-first search where the depth of the recursion (and thus the exhaustiveness of the search) is controlled by the parameter 'search_depth'. + @note The pseudocode below describes the algorithm of 'best_extension_by_limited_search'. The worst-case complexity of this algorithm is O(N*N^search_depth/search_depth). When serch_depth >= N, then the complexity of greedy_search is O(N!). + @code procedure best_extension_by_limited_search( pplan in, // in, partial plan of tables-joined-so-far pplan_cost, // in, cost of pplan @@ -4914,18 +4940,39 @@ greedy_search(JOIN *join, } } } + @endcode - IMPLEMENTATION + @note When 'best_extension_by_limited_search' is called for the first time, 'join->best_read' must be set to the largest possible value (e.g. DBL_MAX). The actual implementation provides a way to optionally use pruning heuristic (controlled by the parameter 'prune_level') to reduce the search space by skipping some partial plans. + + @note The parameter 'search_depth' provides control over the recursion depth, and thus the size of the resulting optimal plan. - RETURN VALUES + @param join pointer to the structure providing all context info + for the query + @param remaining_tables set of tables not included into the partial plan yet + @param idx length of the partial QEP in 'join->positions'; + since a depth-first search is used, also corresponds + to the current depth of the search tree; + also an index in the array 'join->best_ref'; + @param record_count estimate for the number of records returned by the + best partial plan + @param read_time the cost of the best partial plan + @param search_depth maximum depth of the recursion and thus size of the + found optimal plan + (0 < search_depth <= join->tables+1). + @param prune_level pruning heuristics that should be applied during + optimization + (values: 0 = EXHAUSTIVE, 1 = PRUNE_BY_TIME_OR_ROWS) + + @retval FALSE ok + @retval TRUE Fatal error */ @@ -5065,8 +5112,9 @@ best_extension_by_limited_search(JOIN *join, } -/* - TODO: this function is here only temporarily until 'greedy_search' is +/** + @todo + - TODO: this function is here only temporarily until 'greedy_search' is tested and accepted. RETURN VALUES @@ -5147,8 +5195,8 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, } -/* - Find how much space the prevous read not const tables takes in cache +/** + Find how much space the prevous read not const tables takes in cache. */ static void calc_used_field_length(THD *thd, JOIN_TAB *join_tab) @@ -5292,9 +5340,9 @@ prev_record_reads(JOIN *join, uint idx, table_map found_ref) } -/***************************************************************************** +/** Set up join struct according to best position. -*****************************************************************************/ +*/ static bool get_best_combination(JOIN *join) @@ -5535,9 +5583,11 @@ get_store_key(THD *thd, KEYUSE *keyuse, table_map used_tables, keyuse->val); } -/* - This function is only called for const items on fields which are keys - returns 1 if there was some conversion made when the field was stored. +/** + This function is only called for const items on fields which are keys. + + @return + returns 1 if there was some conversion made when the field was stored. */ bool @@ -5647,22 +5697,18 @@ inline void add_cond_and_fix(Item **e1, Item *e2) } -/* - Add to join_tab->select_cond[i] "table.field IS NOT NULL" conditions we've - inferred from ref/eq_ref access performed. +/** + Add to join_tab->select_cond[i] "table.field IS NOT NULL" conditions + we've inferred from ref/eq_ref access performed. - SYNOPSIS - add_not_null_conds() - join Join to process - - NOTES This function is a part of "Early NULL-values filtering for ref access" optimization. Example of this optimization: - For query SELECT * FROM t1,t2 WHERE t2.key=t1.field - and plan " any-access(t1), ref(t2.key=t1.field) " - add "t1.field IS NOT NULL" to t1's table condition. + For query SELECT * FROM t1,t2 WHERE t2.key=t1.field @n + and plan " any-access(t1), ref(t2.key=t1.field) " @n + add "t1.field IS NOT NULL" to t1's table condition. @n + Description of the optimization: We look through equalities choosen to perform ref/eq_ref access, @@ -5674,8 +5720,10 @@ inline void add_cond_and_fix(Item **e1, Item *e2) Exception from that is the case when referred_tab->join != join. I.e. don't add NOT NULL constraints from any embedded subquery. Consider this query: + @code SELECT A.f2 FROM t1 LEFT JOIN t2 A ON A.f2 = f1 WHERE A.f3=(SELECT MIN(f3) FROM t2 C WHERE A.f4 = C.f4) OR A.f3 IS NULL; + @endocde Here condition A.f3 IS NOT NULL is going to be added to the WHERE condition of the embedding query. Another example: @@ -5746,25 +5794,21 @@ static void add_not_null_conds(JOIN *join) DBUG_VOID_RETURN; } -/* - Build a predicate guarded by match variables for embedding outer joins +/** + Build a predicate guarded by match variables for embedding outer joins. + The function recursively adds guards for predicate cond + assending from tab to the first inner table next embedding + nested outer join and so on until it reaches root_tab + (root_tab can be 0). - SYNOPSIS - add_found_match_trig_cond() - tab the first inner table for most nested outer join - cond the predicate to be guarded (must be set) - root_tab the first inner table to stop + @param tab the first inner table for most nested outer join + @param cond the predicate to be guarded (must be set) + @param root_tab the first inner table to stop - DESCRIPTION - The function recursively adds guards for predicate cond - assending from tab to the first inner table next embedding - nested outer join and so on until it reaches root_tab - (root_tab can be 0). - - RETURN VALUE - pointer to the guarded predicate, if success - 0, otherwise -*/ + @return + - pointer to the guarded predicate, if success + - 0, otherwise +*/ static COND* add_found_match_trig_cond(JOIN_TAB *tab, COND *cond, JOIN_TAB *root_tab) @@ -5784,14 +5828,9 @@ add_found_match_trig_cond(JOIN_TAB *tab, COND *cond, JOIN_TAB *root_tab) } -/* - Fill in outer join related info for the execution plan structure +/** + Fill in outer join related info for the execution plan structure. - SYNOPSIS - make_outerjoin_info() - join - reference to the info fully describing the query - - DESCRIPTION For each outer join operation left after simplification of the original query the function set up the following pointers in the linear structure join->join_tab representing the selected execution plan. @@ -5806,21 +5845,25 @@ add_found_match_trig_cond(JOIN_TAB *tab, COND *cond, JOIN_TAB *root_tab) corresponding first inner table through the field t0->on_expr_ref. Here ti are structures of the JOIN_TAB type. - EXAMPLE - For the query: - SELECT * FROM t1 - LEFT JOIN - (t2, t3 LEFT JOIN t4 ON t3.a=t4.a) - ON (t1.a=t2.a AND t1.b=t3.b) - WHERE t1.c > 5, + EXAMPLE. For the query: + @code + SELECT * FROM t1 + LEFT JOIN + (t2, t3 LEFT JOIN t4 ON t3.a=t4.a) + ON (t1.a=t2.a AND t1.b=t3.b) + WHERE t1.c > 5, + @endcode + given the execution plan with the table order t1,t2,t3,t4 is selected, the following references will be set; t4->last_inner=[t4], t4->first_inner=[t4], t4->first_upper=[t2] t2->last_inner=[t4], t2->first_inner=t3->first_inner=[t2], on expression (t1.a=t2.a AND t1.b=t3.b) will be attached to *t2->on_expr_ref, while t3.a=t4.a will be attached to *t4->on_expr_ref. - - NOTES + + @param join reference to the info fully describing the query + + @note The function assumes that the simplification procedure has been already applied to the join query (see simplify_joins). This function can be called only after the execution plan @@ -6444,20 +6487,18 @@ make_join_readinfo(JOIN *join, ulonglong options) } -/* - Give error if we some tables are done with a full join +/** + Give error if we some tables are done with a full join. - SYNOPSIS - error_if_full_join() - join Join condition + This is used by multi_table_update and multi_table_delete when running + in safe mode. - USAGE - This is used by multi_table_update and multi_table_delete when running - in safe mode + @param join Join condition - RETURN VALUES - 0 ok - 1 Error (full join used) + @retval + 0 ok + @retval + 1 Error (full join used) */ bool error_if_full_join(JOIN *join) @@ -6477,11 +6518,8 @@ bool error_if_full_join(JOIN *join) } -/* - cleanup JOIN_TAB - - SYNOPSIS - JOIN_TAB::cleanup() +/** + cleanup JOIN_TAB. */ void JOIN_TAB::cleanup() @@ -6511,11 +6549,10 @@ void JOIN_TAB::cleanup() } -/* +/** Partially cleanup JOIN after it has executed: close index or rnd read (table cursors), free quick selects. - DESCRIPTION This function is called in the end of execution of a JOIN, before the used tables are unlocked and closed. @@ -6535,23 +6572,24 @@ void JOIN_TAB::cleanup() If a JOIN is executed for a subquery or if it has a subquery, we can't do the full cleanup and need to do a partial cleanup only. - o If a JOIN is not the top level join, we must not unlock the tables - because the outer select may not have been evaluated yet, and we - can't unlock only selected tables of a query. + - If a JOIN is not the top level join, we must not unlock the tables + because the outer select may not have been evaluated yet, and we + can't unlock only selected tables of a query. + - Additionally, if this JOIN corresponds to a correlated subquery, we + should not free quick selects and join buffers because they will be + needed for the next execution of the correlated subquery. + - However, if this is a JOIN for a [sub]select, which is not + a correlated subquery itself, but has subqueries, we can free it + fully and also free JOINs of all its subqueries. The exception + is a subquery in SELECT list, e.g: @n + SELECT a, (select max(b) from t1) group by c @n + This subquery will not be evaluated at first sweep and its value will + not be inserted into the temporary table. Instead, it's evaluated + when selecting from the temporary table. Therefore, it can't be freed + here even though it's not correlated. - o Additionally, if this JOIN corresponds to a correlated subquery, we - should not free quick selects and join buffers because they will be - needed for the next execution of the correlated subquery. - - o However, if this is a JOIN for a [sub]select, which is not - a correlated subquery itself, but has subqueries, we can free it - fully and also free JOINs of all its subqueries. The exception - is a subquery in SELECT list, e.g: - SELECT a, (select max(b) from t1) group by c - This subquery will not be evaluated at first sweep and its value will - not be inserted into the temporary table. Instead, it's evaluated - when selecting from the temporary table. Therefore, it can't be freed - here even though it's not correlated. + @todo + Unlock tables even if the join isn't top level select in the tree */ void JOIN::join_free() @@ -6611,15 +6649,15 @@ void JOIN::join_free() } -/* - Free resources of given join +/** + Free resources of given join. - SYNOPSIS - JOIN::cleanup() - fill - true if we should free all resources, call with full==1 should be - last, before it this function can be called with full==0 + @param fill true if we should free all resources, call with full==1 + should be last, before it this function can be called with + full==0 - NOTE: with subquery this function definitely will be called several times, + @note + With subquery this function definitely will be called several times, but even for simple query it can be called several times. */ @@ -6689,21 +6727,25 @@ void JOIN::cleanup(bool full) } -/***************************************************************************** +/** Remove the following expressions from ORDER BY and GROUP BY: - Constant expressions + Constant expressions @n Expression that only uses tables that are of type EQ_REF and the reference is in the ORDER list or if all refereed tables are of the above type. In the following, the X field can be removed: + @code SELECT * FROM t1,t2 WHERE t1.a=t2.a ORDER BY t1.a,t2.X SELECT * FROM t1,t2,t3 WHERE t1.a=t2.a AND t2.b=t3.b ORDER BY t1.a,t3.X + @endcode These can't be optimized: + @code SELECT * FROM t1,t2 WHERE t1.a=t2.a ORDER BY t2.X,t1.a SELECT * FROM t1,t2 WHERE t1.a=t2.a AND t1.b=t2.b ORDER BY t1.a,t2.c SELECT * FROM t1,t2 WHERE t1.a=t2.a ORDER BY t2.b,t1.a -*****************************************************************************/ + @endcode +*/ static bool eq_ref_table(JOIN *join, ORDER *start_order, JOIN_TAB *tab) @@ -6771,7 +6813,7 @@ only_eq_ref_tables(JOIN *join,ORDER *order,table_map tables) } -/* Update the dependency map for the tables */ +/** Update the dependency map for the tables. */ static void update_depend_map(JOIN *join) { @@ -6798,7 +6840,7 @@ static void update_depend_map(JOIN *join) } -/* Update the dependency map for the sort order */ +/** Update the dependency map for the sort order. */ static void update_depend_map(JOIN *join, ORDER *order) { @@ -6823,25 +6865,23 @@ static void update_depend_map(JOIN *join, ORDER *order) } -/* - Remove all constants and check if ORDER only contains simple expressions +/** + Remove all constants and check if ORDER only contains simple + expressions. - SYNOPSIS - remove_const() - join Join handler - first_order List of SORT or GROUP order - cond WHERE statement - change_list Set to 1 if we should remove things from list - If this is not set, then only simple_order is - calculated - simple_order Set to 1 if we are only using simple expressions + simple_order is set to 1 if sort_order only uses fields from head table + and the head table is not a LEFT JOIN table. - RETURN + @param join Join handler + @param first_order List of SORT or GROUP order + @param cond WHERE statement + @param change_list Set to 1 if we should remove things from list. + If this is not set, then only simple_order is + calculated. + @param simple_order Set to 1 if we are only using simple expressions + + @return Returns new sort order - - simple_order is set to 1 if sort_order only uses fields from head table - and the head table is not a LEFT JOIN table - */ static ORDER * @@ -6997,25 +7037,23 @@ template class List_iterator; #endif -/* - Find the multiple equality predicate containing a field - - SYNOPSIS - find_item_equal() - cond_equal multiple equalities to search in - field field to look for - inherited_fl :out set up to TRUE if multiple equality is found - on upper levels (not on current level of cond_equal) +/** + Find the multiple equality predicate containing a field. - DESCRIPTION - The function retrieves the multiple equalities accessed through - the con_equal structure from current level and up looking for - an equality containing field. It stops retrieval as soon as the equality - is found and set up inherited_fl to TRUE if it's found on upper levels. + The function retrieves the multiple equalities accessed through + the con_equal structure from current level and up looking for + an equality containing field. It stops retrieval as soon as the equality + is found and set up inherited_fl to TRUE if it's found on upper levels. - RETURN - Item_equal for the found multiple equality predicate if a success; - NULL - otherwise. + @param cond_equal multiple equalities to search in + @param field field to look for + @param[out] inherited_fl set up to TRUE if multiple equality is found + on upper levels (not on current level of + cond_equal) + + @return + - Item_equal for the found multiple equality predicate if a success; + - NULL otherwise. */ Item_equal *find_item_equal(COND_EQUAL *cond_equal, Field *field, @@ -7041,18 +7079,9 @@ finish: } -/* - Check whether an equality can be used to build multiple equalities +/** + Check whether an equality can be used to build multiple equalities. - SYNOPSIS - check_simple_equality() - left_item left term of the quality to be checked - right_item right term of the equality to be checked - item equality item if the equality originates from a condition - predicate, 0 if the equality is the result of row elimination - cond_equal multiple equalities that must hold together with the equality - - DESCRIPTION This function first checks whether the equality (left_item=right_item) is a simple equality i.e. the one that equates a field with another field or a constant (field=field_item or field=const_item). @@ -7067,22 +7096,24 @@ finish: This guarantees that the set of multiple equalities covering equality predicates will be minimal. - EXAMPLE + EXAMPLE: For the where condition - WHERE a=b AND b=c AND - (b=2 OR f=e) + @code + WHERE a=b AND b=c AND + (b=2 OR f=e) + @endcode the check_equality will be called for the following equality predicates a=b, b=c, b=2 and f=e. - For a=b it will be called with *cond_equal=(0,[]) and will transform - *cond_equal into (0,[Item_equal(a,b)]). - For b=c it will be called with *cond_equal=(0,[Item_equal(a,b)]) - and will transform *cond_equal into CE=(0,[Item_equal(a,b,c)]). - For b=2 it will be called with *cond_equal=(ptr(CE),[]) - and will transform *cond_equal into (ptr(CE),[Item_equal(2,a,b,c)]). - For f=e it will be called with *cond_equal=(ptr(CE), []) - and will transform *cond_equal into (ptr(CE),[Item_equal(f,e)]). + - For a=b it will be called with *cond_equal=(0,[]) and will transform + *cond_equal into (0,[Item_equal(a,b)]). + - For b=c it will be called with *cond_equal=(0,[Item_equal(a,b)]) + and will transform *cond_equal into CE=(0,[Item_equal(a,b,c)]). + - For b=2 it will be called with *cond_equal=(ptr(CE),[]) + and will transform *cond_equal into (ptr(CE),[Item_equal(2,a,b,c)]). + - For f=e it will be called with *cond_equal=(ptr(CE), []) + and will transform *cond_equal into (ptr(CE),[Item_equal(f,e)]). - NOTES + @note Now only fields that have the same type definitions (verified by the Field::eq_def method) are placed to the same multiple equalities. Because of this some equality predicates are not eliminated and @@ -7094,8 +7125,8 @@ finish: equality. But at the same time it would allow us to get rid of constant propagation completely: it would be done by the call to build_equal_items_for_cond. - - IMPLEMENTATION + + The implementation does not follow exactly the above rules to build a new multiple equality for the equality predicate. If it processes the equality of the form field1=field2, it @@ -7115,9 +7146,18 @@ finish: acceptable, as this happens rarely. The implementation without copying would be much more complicated. - RETURN + @param left_item left term of the quality to be checked + @param right_item right term of the equality to be checked + @param item equality item if the equality originates from a condition + predicate, 0 if the equality is the result of row + elimination + @param cond_equal multiple equalities that must hold together with the + equality + + @retval TRUE if the predicate is a simple equality predicate to be used - for building multiple equalities + for building multiple equalities + @retval FALSE otherwise */ @@ -7286,30 +7326,30 @@ static bool check_simple_equality(Item *left_item, Item *right_item, } -/* - Convert row equalities into a conjunction of regular equalities +/** + Convert row equalities into a conjunction of regular equalities. - SYNOPSIS - check_row_equality() - thd thread handle - left_row left term of the row equality to be processed - right_row right term of the row equality to be processed - cond_equal multiple equalities that must hold together with the predicate - eq_list results of conversions of row equalities that are not simple - enough to form multiple equalities - - DESCRIPTION The function converts a row equality of the form (E1,...,En)=(E'1,...,E'n) into a list of equalities E1=E'1,...,En=E'n. For each of these equalities - Ei=E'i the function checks whether it is a simple equality or a row equality. - If it is a simple equality it is used to expand multiple equalities of - cond_equal. If it is a row equality it converted to a sequence of equalities - between row elements. If Ei=E'i is neither a simple equality nor a row - equality the item for this predicate is added to eq_list. + Ei=E'i the function checks whether it is a simple equality or a row + equality. If it is a simple equality it is used to expand multiple + equalities of cond_equal. If it is a row equality it converted to a + sequence of equalities between row elements. If Ei=E'i is neither a + simple equality nor a row equality the item for this predicate is added + to eq_list. - RETURN - TRUE if conversion has succeeded (no fatal error) - FALSE otherwise + @param thd thread handle + @param left_row left term of the row equality to be processed + @param right_row right term of the row equality to be processed + @param cond_equal multiple equalities that must hold together with the + predicate + @param eq_list results of conversions of row equalities that are not + simple enough to form multiple equalities + + @retval + TRUE if conversion has succeeded (no fatal error) + @retval + FALSE otherwise */ static bool check_row_equality(THD *thd, Item *left_row, Item_row *right_row, @@ -7351,18 +7391,9 @@ static bool check_row_equality(THD *thd, Item *left_row, Item_row *right_row, } -/* - Eliminate row equalities and form multiple equalities predicates +/** + Eliminate row equalities and form multiple equalities predicates. - SYNOPSIS - check_equality() - thd thread handle - item predicate to process - cond_equal multiple equalities that must hold together with the predicate - eq_list results of conversions of row equalities that are not simple - enough to form multiple equalities - - DESCRIPTION This function checks whether the item is a simple equality i.e. the one that equates a field with another field or a constant (field=field_item or field=constant_item), or, a row equality. @@ -7370,11 +7401,20 @@ static bool check_row_equality(THD *thd, Item *left_row, Item_row *right_row, in the lists referenced directly or indirectly by cond_equal inferring the given simple equality. If it doesn't find any, it builds/expands multiple equality that covers the predicate. - Row equalities are eliminated substituted for conjunctive regular equalities - which are treated in the same way as original equality predicates. + Row equalities are eliminated substituted for conjunctive regular + equalities which are treated in the same way as original equality + predicates. - RETURN + @param thd thread handle + @param item predicate to process + @param cond_equal multiple equalities that must hold together with the + predicate + @param eq_list results of conversions of row equalities that are not + simple enough to form multiple equalities + + @retval TRUE if re-writing rules have been applied + @retval FALSE otherwise, i.e. if the predicate is not an equality, or, if the equality is neither a simple one nor a row equality, @@ -7406,16 +7446,9 @@ static bool check_equality(THD *thd, Item *item, COND_EQUAL *cond_equal, } -/* - Replace all equality predicates in a condition by multiple equality items +/** + Replace all equality predicates in a condition by multiple equality items. - SYNOPSIS - build_equal_items_for_cond() - thd thread handle - cond condition(expression) where to make replacement - inherited path to all inherited multiple equality items - - DESCRIPTION At each 'and' level the function detects items for equality predicates and replaced them by a set of multiple equality items of class Item_equal, taking into account inherited equalities from upper levels. @@ -7434,7 +7467,7 @@ static bool check_equality(THD *thd, Item *item, COND_EQUAL *cond_equal, equality lists of each Item_cond_and object assigning it to thd->lex->current_select->max_equal_elems. - NOTES + @note Multiple equality predicate =(f1,..fn) is equivalent to the conjuction of f1=f2, .., fn-1=fn. It substitutes any inference from these equality predicates that is equivalent to the conjunction. @@ -7452,7 +7485,6 @@ static bool check_equality(THD *thd, Item *item, COND_EQUAL *cond_equal, but if additionally =(t4.d,t2.b) is inherited, it will be replaced by (=(t1.a,t2.b,t3.c,t4.d) AND t2.b>5) - IMPLEMENTATION The function performs the substitution in a recursive descent by the condtion tree, passing to the next AND level a chain of multiple equality predicates which have been built at the upper levels. @@ -7466,10 +7498,15 @@ static bool check_equality(THD *thd, Item *item, COND_EQUAL *cond_equal, - join them into disjoint Item_equal() groups - process the included OR conditions recursively to do the same for lower AND levels. + We need to do things in this order as lower AND levels need to know about all possible Item_equal objects in upper levels. - RETURN + @param thd thread handle + @param cond condition(expression) where to make replacement + @param inherited path to all inherited multiple equality items + + @return pointer to the transformed condition */ @@ -7617,19 +7654,10 @@ static COND *build_equal_items_for_cond(THD *thd, COND *cond, } -/* +/** Build multiple equalities for a condition and all on expressions that - inherit these multiple equalities + inherit these multiple equalities. - SYNOPSIS - build_equal_items() - thd thread handle - cond condition to build the multiple equalities for - inherited path to all inherited multiple equality items - join_list list of join tables to which the condition refers to - cond_equal_ref :out pointer to the structure to place built equalities in - - DESCRIPTION The function first applies the build_equal_items_for_cond function to build all multiple equalities for condition cond utilizing equalities referred through the parameter inherited. The extended set of @@ -7638,14 +7666,16 @@ static COND *build_equal_items_for_cond(THD *thd, COND *cond, all on expressions whose direct references can be found in join_list and who inherit directly the multiple equalities just having built. - NOTES + @note The on expression used in an outer join operation inherits all equalities - from the on expression of the embedding join, if there is any, or + from the on expression of the embedding join, if there is any, or otherwise - from the where condition. This fact is not obvious, but presumably can be proved. Consider the following query: + @code SELECT * FROM (t1,t2) LEFT JOIN (t3,t4) ON t1.a=t3.a AND t2.a=t4.a WHERE t1.a=t2.a; + @endcode If the on expression in the query inherits =(t1.a,t2.a), then we can build the multiple equality =(t1.a,t2.a,t3.a,t4.a) that infers the equality t3.a=t4.a. Although the on expression @@ -7655,23 +7685,38 @@ static COND *build_equal_items_for_cond(THD *thd, COND *cond, Interesting that multiple equality =(t1.a,t2.a,t3.a,t4.a) allows us to use t1.a=t3.a AND t3.a=t4.a under the on condition: + @code SELECT * FROM (t1,t2) LEFT JOIN (t3,t4) ON t1.a=t3.a AND t3.a=t4.a WHERE t1.a=t2.a + @endcode This query equivalent to: + @code SELECT * FROM (t1 LEFT JOIN (t3,t4) ON t1.a=t3.a AND t3.a=t4.a),t2 WHERE t1.a=t2.a + @endcode Similarly the original query can be rewritten to the query: + @code SELECT * FROM (t1,t2) LEFT JOIN (t3,t4) ON t2.a=t4.a AND t3.a=t4.a WHERE t1.a=t2.a + @endcode that is equivalent to: + @code SELECT * FROM (t2 LEFT JOIN (t3,t4)ON t2.a=t4.a AND t3.a=t4.a), t1 WHERE t1.a=t2.a + @endcode Thus, applying equalities from the where condition we basically can get more freedom in performing join operations. Althogh we don't use this property now, it probably makes sense to use it in the future. - - RETURN + @param thd Thread handler + @param cond condition to build the multiple equalities for + @param inherited path to all inherited multiple equality items + @param join_list list of join tables to which the condition + refers to + @param[out] cond_equal_ref pointer to the structure to place built + equalities in + + @return pointer to the transformed condition containing multiple equalities */ @@ -7729,25 +7774,24 @@ static COND *build_equal_items(THD *thd, COND *cond, } -/* - Compare field items by table order in the execution plan - - SYNOPSIS - compare_fields_by_table_order() - field1 first field item to compare - field2 second field item to compare - table_join_idx index to tables determining table order +/** + Compare field items by table order in the execution plan. - DESCRIPTION field1 considered as better than field2 if the table containing field1 is accessed earlier than the table containing field2. The function finds out what of two fields is better according this criteria. - RETURN - 1, if field1 is better than field2 - -1, if field2 is better than field1 - 0, otherwise + @param field1 first field item to compare + @param field2 second field item to compare + @param table_join_idx index to tables determining table order + + @retval + 1 if field1 is better than field2 + @retval + -1 if field2 is better than field1 + @retval + 0 otherwise */ static int compare_fields_by_table_order(Item_field *field1, @@ -7774,16 +7818,9 @@ static int compare_fields_by_table_order(Item_field *field1, } -/* - Generate minimal set of simple equalities equivalent to a multiple equality - - SYNOPSIS - eliminate_item_equal() - cond condition to add the generated equality to - upper_levels structure to access multiple equality of upper levels - item_equal multiple equality to generate simple equality from +/** + Generate minimal set of simple equalities equivalent to a multiple equality. - DESCRIPTION The function retrieves the fields of the multiple equality item item_equal and for each field f: - if item_equal contains const it generates the equality f=const_item; @@ -7791,7 +7828,11 @@ static int compare_fields_by_table_order(Item_field *field1, f=item_equal->get_first(). All generated equality are added to the cond conjunction. - NOTES + @param cond condition to add the generated equality to + @param upper_levels structure to access multiple equality of upper levels + @param item_equal multiple equality to generate simple equality from + + @note Before generating an equality function checks that it has not been generated for multiple equalities of the upper levels. E.g. for the following where condition @@ -7811,10 +7852,10 @@ static int compare_fields_by_table_order(Item_field *field1, If cond is equal to 0, then not more then one equality is generated and a pointer to it is returned as the result of the function. - RETURN - The condition with generated simple equalities or + @return + - The condition with generated simple equalities or a pointer to the simple generated equality, if success. - 0, otherwise. + - 0, otherwise. */ static Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels, @@ -7889,17 +7930,10 @@ static Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels, } -/* - Substitute every field reference in a condition by the best equal field - and eliminate all multiple equality predicates - - SYNOPSIS - substitute_for_best_equal_field() - cond condition to process - cond_equal multiple equalities to take into consideration - table_join_idx index to tables determining field preference +/** + Substitute every field reference in a condition by the best equal field + and eliminate all multiple equality predicates. - DESCRIPTION The function retrieves the cond condition and for each encountered multiple equality predicate it sorts the field references in it according to the order of tables specified by the table_join_idx @@ -7910,14 +7944,17 @@ static Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels, After this the function retrieves all other conjuncted predicates substitute every field reference by the field reference to the first equal field or equal constant if there are any. - - NOTES + @param cond condition to process + @param cond_equal multiple equalities to take into consideration + @param table_join_idx index to tables determining field preference + + @note At the first glance full sort of fields in multiple equality seems to be an overkill. Yet it's not the case due to possible new fields in multiple equality item of lower levels. We want the order in them to comply with the order of upper levels. - RETURN + @return The transformed condition */ @@ -7992,20 +8029,17 @@ static COND* substitute_for_best_equal_field(COND *cond, } -/* +/** Check appearance of new constant items in multiple equalities - of a condition after reading a constant table - - SYNOPSIS - update_const_equal_items() - cond condition whose multiple equalities are to be checked - table constant table that has been read + of a condition after reading a constant table. - DESCRIPTION The function retrieves the cond condition and for each encountered multiple equality checks whether new constants have appeared after reading the constant (single row) table tab. If so it adjusts the multiple equality appropriately. + + @param cond condition whose multiple equalities are to be checked + @param table constant table that has been read */ static void update_const_equal_items(COND *cond, JOIN_TAB *tab) @@ -8144,14 +8178,12 @@ change_cond_ref_to_const(THD *thd, I_List *save_list, } } -/* - Remove additional condition inserted by IN/ALL/ANY transformation +/** + Remove additional condition inserted by IN/ALL/ANY transformation. - SYNOPSIS - remove_additional_cond() - conds Condition for processing + @param conds condition for processing - RETURN VALUES + @return new conditions */ @@ -8239,17 +8271,10 @@ propagate_cond_constants(THD *thd, I_List *save_list, } -/* - Simplify joins replacing outer joins by inner joins whenever it's possible +/** + Simplify joins replacing outer joins by inner joins whenever it's + possible. - SYNOPSIS - simplify_joins() - join reference to the query info - join_list list representation of the join to be converted - conds conditions to add on expressions for converted joins - top true <=> conds is the where condition - - DESCRIPTION The function, during a retrieval of join_list, eliminates those outer joins that can be converted into inner join, possibly nested. It also moves the on expressions for the converted outer joins @@ -8273,26 +8298,39 @@ propagate_cond_constants(THD *thd, I_List *save_list, The function also removes all braces that can be removed from the join expression without changing its meaning. - NOTES + @note An outer join can be replaced by an inner join if the where condition or the on expression for an embedding nested join contains a conjunctive predicate rejecting null values for some attribute of the inner tables. E.g. in the query: + @code SELECT * FROM t1 LEFT JOIN t2 ON t2.a=t1.a WHERE t2.b < 5 + @endcode the predicate t2.b < 5 rejects nulls. The query is converted first to: + @code SELECT * FROM t1 INNER JOIN t2 ON t2.a=t1.a WHERE t2.b < 5 + @endcode then to the equivalent form: - SELECT * FROM t1, t2 ON t2.a=t1.a WHERE t2.b < 5 AND t2.a=t1.a. + @code + SELECT * FROM t1, t2 ON t2.a=t1.a WHERE t2.b < 5 AND t2.a=t1.a + @endcode + Similarly the following query: + @code SELECT * from t1 LEFT JOIN (t2, t3) ON t2.a=t1.a t3.b=t1.b WHERE t2.c < 5 + @endcode is converted to: + @code SELECT * FROM t1, (t2, t3) WHERE t2.c < 5 AND t2.a=t1.a t3.b=t1.b + @endcode + One conversion might trigger another: + @code SELECT * FROM t1 LEFT JOIN t2 ON t2.a=t1.a LEFT JOIN t3 ON t3.b=t2.b WHERE t3 IS NOT NULL => @@ -8300,16 +8338,26 @@ propagate_cond_constants(THD *thd, I_List *save_list, WHERE t3 IS NOT NULL AND t3.b=t2.b => SELECT * FROM t1, t2, t3 WHERE t3 IS NOT NULL AND t3.b=t2.b AND t2.a=t1.a - + @endcode + The function removes all unnecessary braces from the expression produced by the conversions. - E.g. SELECT * FROM t1, (t2, t3) WHERE t2.c < 5 AND t2.a=t1.a AND t3.b=t1.b + E.g. + @code + SELECT * FROM t1, (t2, t3) WHERE t2.c < 5 AND t2.a=t1.a AND t3.b=t1.b + @endcode finally is converted to: + @code SELECT * FROM t1, t2, t3 WHERE t2.c < 5 AND t2.a=t1.a AND t3.b=t1.b + @endcode + + It also will remove braces from the following queries: + @code SELECT * from (t1 LEFT JOIN t2 ON t2.a=t1.a) LEFT JOIN t3 ON t3.b=t2.b SELECT * from (t1, (t2,t3)) WHERE t1.a=t2.a AND t2.b=t3.b. + @endcode The benefit of this simplification procedure is that it might return a query for which the optimizer can evaluate execution plan with more @@ -8317,20 +8365,26 @@ propagate_cond_constants(THD *thd, I_List *save_list, consider any plan where one of the inner tables is before some of outer tables. - IMPLEMENTATION. + The function is implemented by a recursive procedure. On the recursive ascent all attributes are calculated, all outer joins that can be converted are replaced and then all unnecessary braces are removed. As join list contains join tables in the reverse order sequential elimination of outer joins does not require extra recursive calls. - EXAMPLES Here is an example of a join query with invalid cross references: + @code SELECT * FROM t1 LEFT JOIN t2 ON t2.a=t3.a LEFT JOIN t3 ON t3.b=t1.b - - RETURN VALUE - The new condition, if success - 0, otherwise + @endcode + + @param join reference to the query info + @param join_list list representation of the join to be converted + @param conds conditions to add on expressions for converted joins + @param top true <=> conds is the where condition + + @return + - The new condition, if success + - 0, otherwise */ static COND * @@ -8492,26 +8546,23 @@ simplify_joins(JOIN *join, List *join_list, COND *conds, bool top) } -/* - Assign each nested join structure a bit in nested_join_map +/** + Assign each nested join structure a bit in nested_join_map. - SYNOPSIS - build_bitmap_for_nested_joins() - join Join being processed - join_list List of tables - first_unused Number of first unused bit in nested_join_map before the - call - - DESCRIPTION Assign each nested join structure (except "confluent" ones - those that embed only one element) a bit in nested_join_map. - NOTE + @param join Join being processed + @param join_list List of tables + @param first_unused Number of first unused bit in nested_join_map before the + call + + @note This function is called after simplify_joins(), when there are no redundant nested joins, #non_confluent_nested_joins <= #tables_in_join so we will not run out of bits in nested_join_map. - RETURN + @return First unused bit in nested_join_map after the call. */ @@ -8547,17 +8598,14 @@ static uint build_bitmap_for_nested_joins(List *join_list, } -/* - Set NESTED_JOIN::counter=0 in all nested joins in passed list +/** + Set NESTED_JOIN::counter=0 in all nested joins in passed list. - SYNOPSIS - reset_nj_counters() - join_list List of nested joins to process. It may also contain base - tables which will be ignored. - - DESCRIPTION Recursively set NESTED_JOIN::counter=0 for all nested joins contained in the passed join_list. + + @param join_list List of nested joins to process. It may also contain base + tables which will be ignored. */ static void reset_nj_counters(List *join_list) @@ -8578,95 +8626,96 @@ static void reset_nj_counters(List *join_list) } -/* - Check interleaving with an inner tables of an outer join for extension table +/** + Check interleaving with an inner tables of an outer join for + extension table. - SYNOPSIS - check_interleaving_with_nj() - join Join being processed - last_tab Last table in current partial join order (this function is - not called for empty partial join orders) - next_tab Table we're going to extend the current partial join with - - DESCRIPTION Check if table next_tab can be added to current partial join order, and if yes, record that it has been added. The function assumes that both current partial join order and its extension with next_tab are valid wrt table dependencies. - IMPLEMENTATION - LIMITATIONS ON JOIN ORDER - The nested [outer] joins executioner algorithm imposes these limitations - on join order: - 1. "Outer tables first" - any "outer" table must be before any - corresponding "inner" table. - 2. "No interleaving" - tables inside a nested join must form a continuous - sequence in join order (i.e. the sequence must not be interrupted by - tables that are outside of this nested join). + @verbatim + IMPLEMENTATION + LIMITATIONS ON JOIN ORDER + The nested [outer] joins executioner algorithm imposes these limitations + on join order: + 1. "Outer tables first" - any "outer" table must be before any + corresponding "inner" table. + 2. "No interleaving" - tables inside a nested join must form a continuous + sequence in join order (i.e. the sequence must not be interrupted by + tables that are outside of this nested join). - #1 is checked elsewhere, this function checks #2 provided that #1 has - been already checked. + #1 is checked elsewhere, this function checks #2 provided that #1 has + been already checked. - WHY NEED NON-INTERLEAVING - Consider an example: - - select * from t0 join t1 left join (t2 join t3) on cond1 - - The join order "t1 t2 t0 t3" is invalid: + WHY NEED NON-INTERLEAVING + Consider an example: - table t0 is outside of the nested join, so WHERE condition for t0 is - attached directly to t0 (without triggers, and it may be used to access - t0). Applying WHERE(t0) to (t2,t0,t3) record is invalid as we may miss - combinations of (t1, t2, t3) that satisfy condition cond1, and produce a - null-complemented (t1, t2.NULLs, t3.NULLs) row, which should not have - been produced. - - If table t0 is not between t2 and t3, the problem doesn't exist: - * If t0 is located after (t2,t3), WHERE(t0) is applied after nested join - processing has finished. - * If t0 is located before (t2,t3), predicates like WHERE_cond(t0, t2) are - wrapped into condition triggers, which takes care of correct nested - join processing. - - HOW IT IS IMPLEMENTED - The limitations on join order can be rephrased as follows: for valid - join order one must be able to: - 1. write down the used tables in the join order on one line. - 2. for each nested join, put one '(' and one ')' on the said line - 3. write "LEFT JOIN" and "ON (...)" where appropriate - 4. get a query equivalent to the query we're trying to execute. - - Calls to check_interleaving_with_nj() are equivalent to writing the - above described line from left to right. - A single check_interleaving_with_nj(A,B) call is equivalent to writing - table B and appropriate brackets on condition that table A and - appropriate brackets is the last what was written. Graphically the - transition is as follows: + select * from t0 join t1 left join (t2 join t3) on cond1 - +---- current position - | - ... last_tab ))) | ( next_tab ) )..) | ... - X Y Z | - +- need to move to this - position. + The join order "t1 t2 t0 t3" is invalid: - Notes about the position: - The caller guarantees that there is no more then one X-bracket by - checking "!(remaining_tables & s->dependent)" before calling this - function. X-bracket may have a pair in Y-bracket. - - When "writing" we store/update this auxilary info about the current - position: - 1. join->cur_embedding_map - bitmap of pairs of brackets (aka nested - joins) we've opened but didn't close. - 2. {each NESTED_JOIN structure not simplified away}->counter - number - of this nested join's children that have already been added to to - the partial join order. - - RETURN - FALSE Join order extended, nested joins info about current join order - (see NOTE section) updated. + table t0 is outside of the nested join, so WHERE condition for t0 is + attached directly to t0 (without triggers, and it may be used to access + t0). Applying WHERE(t0) to (t2,t0,t3) record is invalid as we may miss + combinations of (t1, t2, t3) that satisfy condition cond1, and produce a + null-complemented (t1, t2.NULLs, t3.NULLs) row, which should not have + been produced. + + If table t0 is not between t2 and t3, the problem doesn't exist: + If t0 is located after (t2,t3), WHERE(t0) is applied after nested join + processing has finished. + If t0 is located before (t2,t3), predicates like WHERE_cond(t0, t2) are + wrapped into condition triggers, which takes care of correct nested + join processing. + + HOW IT IS IMPLEMENTED + The limitations on join order can be rephrased as follows: for valid + join order one must be able to: + 1. write down the used tables in the join order on one line. + 2. for each nested join, put one '(' and one ')' on the said line + 3. write "LEFT JOIN" and "ON (...)" where appropriate + 4. get a query equivalent to the query we're trying to execute. + + Calls to check_interleaving_with_nj() are equivalent to writing the + above described line from left to right. + A single check_interleaving_with_nj(A,B) call is equivalent to writing + table B and appropriate brackets on condition that table A and + appropriate brackets is the last what was written. Graphically the + transition is as follows: + + +---- current position + | + ... last_tab ))) | ( next_tab ) )..) | ... + X Y Z | + +- need to move to this + position. + + Notes about the position: + The caller guarantees that there is no more then one X-bracket by + checking "!(remaining_tables & s->dependent)" before calling this + function. X-bracket may have a pair in Y-bracket. + + When "writing" we store/update this auxilary info about the current + position: + 1. join->cur_embedding_map - bitmap of pairs of brackets (aka nested + joins) we've opened but didn't close. + 2. {each NESTED_JOIN structure not simplified away}->counter - number + of this nested join's children that have already been added to to + the partial join order. + @endverbatim + + @param join Join being processed + @param last_tab Last table in current partial join order (this function is + not called for empty partial join orders) + @param next_tab Table we're going to extend the current partial join with + + @retval + FALSE Join order extended, nested joins info about current join + order (see NOTE section) updated. + @retval TRUE Requested join order extension not allowed. */ @@ -8715,19 +8764,16 @@ static bool check_interleaving_with_nj(JOIN_TAB *last_tab, JOIN_TAB *next_tab) } -/* - Nested joins perspective: Remove the last table from the join order +/** + Nested joins perspective: Remove the last table from the join order. - SYNOPSIS - restore_prev_nj_state() - last join table to remove, it is assumed to be the last in current - partial join order. - - DESCRIPTION Remove the last table from the partial join order and update the nested joins counters and join->cur_embedding_map. It is ok to call this function for the first table in join order (for which check_interleaving_with_nj has not been called) + + @param last join table to remove, it is assumed to be the last in current + partial join order. */ static void restore_prev_nj_state(JOIN_TAB *last) @@ -8786,12 +8832,15 @@ optimize_cond(JOIN *join, COND *conds, List *join_list, } -/* - Remove const and eq items. Return new item, or NULL if no condition - cond_value is set to according: - COND_OK query is possible (field = constant) - COND_TRUE always true ( 1 = 1 ) - COND_FALSE always false ( 1 = 2 ) +/** + Remove const and eq items. + + @return + Return new item, or NULL if no condition @n + cond_value is set to according: + - COND_OK : query is possible (field = constant) + - COND_TRUE : always true ( 1 = 1 ) + - COND_FALSE : always false ( 1 = 2 ) */ COND * @@ -8982,8 +9031,8 @@ test_if_equality_guarantees_uniqueness(Item *l, Item *r) l->collation.collation == r->collation.collation))); } -/* - Return 1 if the item is a const value in all the WHERE clause +/** + Return TRUE if the item is a const value in all the WHERE clause. */ static bool @@ -9044,26 +9093,25 @@ const_expression_in_where(COND *cond, Item *comp_item, Item **const_item) Create internal temporary table ****************************************************************************/ -/* - Create field for temporary table from given field - - SYNOPSIS - create_tmp_field_from_field() - thd Thread handler - org_field field from which new field will be created - name New field name - table Temporary table - item !=NULL if item->result_field should point to new field. - This is relevant for how fill_record() is going to work: - If item != NULL then fill_record() will update - the record in the original table. - If item == NULL then fill_record() will update - the temporary table - convert_blob_length If >0 create a varstring(convert_blob_length) field - instead of blob. +/** + Create field for temporary table from given field. - RETURN - 0 on error + @param thd Thread handler + @param org_field field from which new field will be created + @param name New field name + @param table Temporary table + @param item !=NULL if item->result_field should point to new field. + This is relevant for how fill_record() is going to work: + If item != NULL then fill_record() will update + the record in the original table. + If item == NULL then fill_record() will update + the temporary table + @param convert_blob_length If >0 create a varstring(convert_blob_length) + field instead of blob. + + @retval + NULL on error + @retval new_created field */ @@ -9106,28 +9154,27 @@ Field *create_tmp_field_from_field(THD *thd, Field *org_field, return new_field; } -/* - Create field for temporary table using type of given item - - SYNOPSIS - create_tmp_field_from_item() - thd Thread handler - item Item to create a field for - table Temporary table - copy_func If set and item is a function, store copy of item - in this array - modify_item 1 if item->result_field should point to new item. - This is relevent for how fill_record() is going to - work: - If modify_item is 1 then fill_record() will update - the record in the original table. - If modify_item is 0 then fill_record() will update - the temporary table - convert_blob_length If >0 create a varstring(convert_blob_length) field - instead of blob. +/** + Create field for temporary table using type of given item. - RETURN - 0 on error + @param thd Thread handler + @param item Item to create a field for + @param table Temporary table + @param copy_func If set and item is a function, store copy of + item in this array + @param modify_item 1 if item->result_field should point to new + item. This is relevent for how fill_record() + is going to work: + If modify_item is 1 then fill_record() will + update the record in the original table. + If modify_item is 0 then fill_record() will + update the temporary table + @param convert_blob_length If >0 create a varstring(convert_blob_length) + field instead of blob. + + @retval + 0 on error + @retval new_created field */ @@ -9206,17 +9253,16 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table, } -/* - Create field for information schema table +/** + Create field for information schema table. - SYNOPSIS - create_tmp_field_for_schema() - thd Thread handler - table Temporary table - item Item to create a field for + @param thd Thread handler + @param table Temporary table + @param item Item to create a field for - RETURN + @retval 0 on error + @retval new_created field */ @@ -9240,33 +9286,32 @@ Field *create_tmp_field_for_schema(THD *thd, Item *item, TABLE *table) } -/* - Create field for temporary table +/** + Create field for temporary table. - SYNOPSIS - create_tmp_field() - thd Thread handler - table Temporary table - item Item to create a field for - type Type of item (normally item->type) - copy_func If set and item is a function, store copy of item - in this array - from_field if field will be created using other field as example, - pointer example field will be written here - default_field If field has a default value field, store it here - group 1 if we are going to do a relative group by on result - modify_item 1 if item->result_field should point to new item. - This is relevent for how fill_record() is going to - work: - If modify_item is 1 then fill_record() will update - the record in the original table. - If modify_item is 0 then fill_record() will update - the temporary table - convert_blob_length If >0 create a varstring(convert_blob_length) field - instead of blob. + @param thd Thread handler + @param table Temporary table + @param item Item to create a field for + @param type Type of item (normally item->type) + @param copy_func If set and item is a function, store copy of item + in this array + @param from_field if field will be created using other field as example, + pointer example field will be written here + @param default_field If field has a default value field, store it here + @param group 1 if we are going to do a relative group by on result + @param modify_item 1 if item->result_field should point to new item. + This is relevent for how fill_record() is going to + work: + If modify_item is 1 then fill_record() will update + the record in the original table. + If modify_item is 0 then fill_record() will update + the temporary table + @param convert_blob_length If >0 create a varstring(convert_blob_length) + field instead of blob. - RETURN + @retval 0 on error + @retval new_created field */ @@ -9397,33 +9442,30 @@ void setup_tmp_table_column_bitmaps(TABLE *table, uchar *bitmaps) } -/* +/** Create a temp table according to a field list. - SYNOPSIS - create_tmp_table() - thd thread handle - param a description used as input to create the table - fields list of items that will be used to define - column types of the table (also see NOTES) - group TODO document - distinct should table rows be distinct - save_sum_fields see NOTES - select_options - rows_limit - table_alias possible name of the temporary table that can be used - for name resolving; can be "". + Given field pointers are changed to point at tmp_table for + send_fields. The table object is self contained: it's + allocated in its own memory root, as well as Field objects + created for table columns. + This function will replace Item_sum items in 'fields' list with + corresponding Item_field items, pointing at the fields in the + temporary table, unless this was prohibited by TRUE + value of argument save_sum_fields. The Item_field objects + are created in THD memory root. - DESCRIPTION - Given field pointers are changed to point at tmp_table for - send_fields. The table object is self contained: it's - allocated in its own memory root, as well as Field objects - created for table columns. - This function will replace Item_sum items in 'fields' list with - corresponding Item_field items, pointing at the fields in the - temporary table, unless this was prohibited by TRUE - value of argument save_sum_fields. The Item_field objects - are created in THD memory root. + @param thd thread handle + @param param a description used as input to create the table + @param fields list of items that will be used to define + column types of the table (also see NOTES) + @param group TODO document + @param distinct should table rows be distinct + @param save_sum_fields see NOTES + @param select_options + @param rows_limit + @param table_alias possible name of the temporary table that can + be used for name resolving; can be "". */ #define STRING_TOTAL_LENGTH_TO_PACK_ROWS 128 @@ -10094,16 +10136,10 @@ err: /****************************************************************************/ -/* +/** Create a reduced TABLE object with properly set up Field list from a list of field definitions. - SYNOPSIS - create_virtual_tmp_table() - thd connection handle - field_list list of column definitions - - DESCRIPTION The created table doesn't have a table handler associated with it, has no keys, no group/distinct, no copy_funcs array. The sole purpose of this TABLE object is to use the power of Field @@ -10112,7 +10148,10 @@ err: The table is created in THD mem_root, so are the table's fields. Consequently, if you don't BLOB fields, you don't need to free it. - RETURN + @param thd connection handle + @param field_list list of column definitions + + @return 0 if out of memory, TABLE object in case of success */ @@ -10385,8 +10424,9 @@ free_tmp_table(THD *thd, TABLE *entry) DBUG_VOID_RETURN; } -/* -* If a HEAP table gets full, create a MyISAM table and copy all rows to this +/** + If a HEAP table gets full, create a MyISAM table and copy all rows + to this. */ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param, @@ -10496,17 +10536,15 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param, } -/* - SYNOPSIS - setup_end_select_func() - join join to setup the function for. +/** + @details + Rows produced by a join sweep may end up in a temporary table or be sent + to a client. Setup the function of the nested loop join algorithm which + handles final fully constructed and matched records. - DESCRIPTION - Rows produced by a join sweep may end up in a temporary table or be sent - to a client. Setup the function of the nested loop join algorithm which - handles final fully constructed and matched records. + @param join join to setup the function for. - RETURN + @return end_select function to use. This function can't fail. */ @@ -10570,12 +10608,16 @@ Next_select_func setup_end_select_func(JOIN *join) } -/**************************************************************************** - Make a join of all tables and write it on socket or to table - Return: 0 if ok - 1 if error is sent - -1 if error should be sent -****************************************************************************/ +/** + Make a join of all tables and write it on socket or to table. + + @retval + 0 if ok + @retval + 1 if error is sent + @retval + -1 if error should be sent +*/ static int do_select(JOIN *join,List *fields,TABLE *table,Procedure *procedure) @@ -10713,30 +10755,25 @@ sub_select_cache(JOIN *join,JOIN_TAB *join_tab,bool end_of_records) return rc; } -/* - Retrieve records ends with a given beginning from the result of a join +/** + Retrieve records ends with a given beginning from the result of a join. - SYNPOSIS - sub_select() - join pointer to the structure providing all context info for the query - join_tab the first next table of the execution plan to be retrieved - end_records true when we need to perform final steps of retrival - - DESCRIPTION For a given partial join record consisting of records from the tables preceding the table join_tab in the execution plan, the function retrieves all matching full records from the result set and send them to the result set stream. - NOTES + @note The function effectively implements the final (n-k) nested loops of nested loops join algorithm, where k is the ordinal number of the join_tab table and n is the total number of tables in the join query. It performs nested loops joins with all conjunctive predicates from the where condition pushed as low to the tables as possible. E.g. for the query - SELECT * FROM t1,t2,t3 - WHERE t1.a=t2.a AND t2.b=t3.b AND t1.a BETWEEN 5 AND 9 + @code + SELECT * FROM t1,t2,t3 + WHERE t1.a=t2.a AND t2.b=t3.b AND t1.a BETWEEN 5 AND 9 + @endcode the predicate (t1.a BETWEEN 5 AND 9) will be pushed to table t1, given the selected plan prescribes to nest retrievals of the joined tables in the following order: t1,t2,t3. @@ -10752,9 +10789,11 @@ sub_select_cache(JOIN *join,JOIN_TAB *join_tab,bool end_of_records) the execution plan. In this case the pushed down predicates can be checked only at certain conditions. Suppose for the query - SELECT * FROM t1 LEFT JOIN (t2,t3) ON t3.a=t1.a - WHERE t1>2 AND (t2.b>5 OR t2.b IS NULL) - the optimizer has chosen a plan with the table order t1,t2,t3. + @code + SELECT * FROM t1 LEFT JOIN (t2,t3) ON t3.a=t1.a + WHERE t1>2 AND (t2.b>5 OR t2.b IS NULL) + @endcode + the optimizer has chosen a plan with the table order t1,t2,t3. The predicate P1=t1>2 will be pushed down to the table t1, while the predicate P2=(t2.b>5 OR t2.b IS NULL) will be attached to the table t2. But the second predicate can not be unconditionally tested right @@ -10782,7 +10821,9 @@ sub_select_cache(JOIN *join,JOIN_TAB *join_tab,bool end_of_records) been done for the first row with a match. The only difference is the predicates from on expressions are not checked. - IMPLEMENTATION + @par + @b IMPLEMENTATION + @par The function forms output rows for a current partial join of k tables tables recursively. For each partial join record ending with a certain row from @@ -10798,11 +10839,13 @@ sub_select_cache(JOIN *join,JOIN_TAB *join_tab,bool end_of_records) To carry out a return to a nested loop level of join table t the pointer to t is remembered in the field 'return_tab' of the join structure. Consider the following query: - SELECT * FROM t1, - LEFT JOIN - (t2, t3 LEFT JOIN (t4,t5) ON t5.a=t3.a) - ON t4.a=t2.a - WHERE (t2.b=5 OR t2.b IS NULL) AND (t4.b=2 OR t4.b IS NULL) + @code + SELECT * FROM t1, + LEFT JOIN + (t2, t3 LEFT JOIN (t4,t5) ON t5.a=t3.a) + ON t4.a=t2.a + WHERE (t2.b=5 OR t2.b IS NULL) AND (t4.b=2 OR t4.b IS NULL) + @endcode Suppose the chosen execution plan dictates the order t1,t2,t3,t4,t5 and suppose for a given joined rows from tables t1,t2,t3 there are no rows in the result set yet. @@ -10817,11 +10860,18 @@ sub_select_cache(JOIN *join,JOIN_TAB *join_tab,bool end_of_records) Thus, when the first row from t5 with t5.a=t3.a is found this pointer for t5 is changed from t4 to t2. - STRUCTURE NOTES + @par + @b STRUCTURE @b NOTES + @par join_tab->first_unmatched points always backwards to the first inner table of the embedding nested join, if any. - RETURN + @param join pointer to the structure providing all context info for + the query + @param join_tab the first next table of the execution plan to be retrieved + @param end_records true when we need to perform final steps of retrival + + @return return one of enum_nested_loop_state, except NESTED_LOOP_NO_MORE_ROWS. */ @@ -10885,10 +10935,9 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records) } -/* +/** Process one record of the nested loop join. - DESCRIPTION This function will evaluate parts of WHERE/ON clauses that are applicable to the partial record on hand and in case of success submit this record to the next level of the nested loop. @@ -11012,8 +11061,9 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, } -/* - DESCRIPTION +/** + + @details Construct a NULL complimented partial join record and feed it to the next level of the nested loop. This function is used in case we have an OUTER join and no matching record was found. @@ -11157,7 +11207,7 @@ flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skip_last) Returns -1 if row was not found, 0 if row was found and 1 on errors *****************************************************************************/ -/* Help function when we get some an error from the table handler */ +/** Help function when we get some an error from the table handler. */ int report_error(TABLE *table, int error) { @@ -11296,17 +11346,17 @@ join_read_system(JOIN_TAB *tab) } -/* - Read a table when there is at most one matching row +/** + Read a table when there is at most one matching row. - SYNOPSIS - join_read_const() - tab Table to read + @param tab Table to read - RETURN + @retval 0 Row was found - -1 Row was not found - 1 Got an error (other than row not found) during read + @retval + -1 Row was not found + @retval + 1 Got an error (other than row not found) during read */ static int @@ -11407,9 +11457,9 @@ join_read_always_key(JOIN_TAB *tab) } -/* +/** This function is used when optimizing away ORDER BY in - SELECT * FROM t1 WHERE a=1 ORDER BY a DESC,b DESC + SELECT * FROM t1 WHERE a=1 ORDER BY a DESC,b DESC. */ static int @@ -11624,8 +11674,8 @@ join_ft_read_next(READ_RECORD *info) } -/* - Reading of key with key reference and one part that may be NULL +/** + Reading of key with key reference and one part that may be NULL. */ int @@ -11934,8 +11984,8 @@ end: DBUG_RETURN(NESTED_LOOP_OK); } -/* Group by searching after group record and updating it if possible */ /* ARGSUSED */ +/** Group by searching after group record and updating it if possible. */ static enum_nested_loop_state end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), @@ -12010,7 +12060,7 @@ end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), } -/* Like end_update, but this is done with unique constraints instead of keys */ +/** Like end_update, but this is done with unique constraints instead of keys. */ static enum_nested_loop_state end_unique_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), @@ -12141,7 +12191,10 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), in sorted order. *****************************************************************************/ -/* Return 1 if right_item is used removable reference key on left_item */ +/** + @return + 1 if right_item is used removable reference key on left_item +*/ static bool test_if_ref(Item_field *left_item,Item *right_item) { @@ -12291,26 +12344,26 @@ part_of_refkey(TABLE *table,Field *field) } -/***************************************************************************** - Test if one can use the key to resolve ORDER BY +/** + Test if one can use the key to resolve ORDER BY. - SYNOPSIS - test_if_order_by_key() - order Sort order - table Table to sort - idx Index to check - used_key_parts Return value for used key parts. + @param order Sort order + @param table Table to sort + @param idx Index to check + @param used_key_parts Return value for used key parts. - NOTES + @note used_key_parts is set to correct key parts used if return value != 0 (On other cases, used_key_part may be changed) - RETURN + @retval 1 key is ok. + @retval 0 Key can't be used - -1 Reverse key can be used -*****************************************************************************/ + @retval + -1 Reverse key can be used +*/ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx, uint *used_key_parts) @@ -12405,20 +12458,19 @@ uint find_shortest_key(TABLE *table, const key_map *usable_keys) return best; } -/* +/** Test if a second key is the subkey of the first one. - SYNOPSIS - is_subkey() - key_part First key parts - ref_key_part Second key parts - ref_key_part_end Last+1 part of the second key + @param key_part First key parts + @param ref_key_part Second key parts + @param ref_key_part_end Last+1 part of the second key - NOTE + @note Second key MUST be shorter than the first one. - RETURN + @retval 1 is a subkey + @retval 0 no sub key */ @@ -12432,17 +12484,16 @@ is_subkey(KEY_PART_INFO *key_part, KEY_PART_INFO *ref_key_part, return 1; } -/* - Test if we can use one of the 'usable_keys' instead of 'ref' key for sorting +/** + Test if we can use one of the 'usable_keys' instead of 'ref' key + for sorting. - SYNOPSIS - test_if_subkey() - ref Number of key, used for WHERE clause - usable_keys Keys for testing + @param ref Number of key, used for WHERE clause + @param usable_keys Keys for testing - RETURN - MAX_KEY If we can't use other key - the number of found key Otherwise + @return + - MAX_KEY If we can't use other key + - the number of found key Otherwise */ static uint @@ -12473,24 +12524,19 @@ test_if_subkey(ORDER *order, TABLE *table, uint ref, uint ref_key_parts, } -/* +/** Check if GROUP BY/DISTINCT can be optimized away because the set is already known to be distinct. - - SYNOPSIS - list_contains_unique_index () - table The table to operate on. - find_func function to iterate over the list and search - for a field - DESCRIPTION - Used in removing the GROUP BY/DISTINCT of the following types of - statements: - SELECT [DISTINCT] ... FROM - [GROUP BY ,...] + Used in removing the GROUP BY/DISTINCT of the following types of + statements: + @code + SELECT [DISTINCT] ... FROM + [GROUP BY ,...] + @endcode If (a,b,c is distinct) - then ,{whatever} is also distinct + then ,{whatever} is also distinct This function checks if all the key parts of any of the unique keys of the table are referenced by a list : either the select list @@ -12499,9 +12545,14 @@ test_if_subkey(ORDER *order, TABLE *table, uint ref, uint ref_key_parts, If the above holds and the key parts cannot contain NULLs then we can safely remove the GROUP BY/DISTINCT, as no result set can be more distinct than an unique key. - - RETURN VALUE + + @param table The table to operate on. + @param find_func function to iterate over the list and search + for a field + + @retval 1 found + @retval 0 not found. */ @@ -12534,20 +12585,17 @@ list_contains_unique_index(TABLE *table, } -/* +/** Helper function for list_contains_unique_index. Find a field reference in a list of ORDER structures. - - SYNOPSIS - find_field_in_order_list () - field The field to search for. - data ORDER *.The list to search in - - DESCRIPTION - Finds a direct reference of the Field in the list. - - RETURN VALUE + Finds a direct reference of the Field in the list. + + @param field The field to search for. + @param data ORDER *.The list to search in + + @retval 1 found + @retval 0 not found. */ @@ -12570,20 +12618,17 @@ find_field_in_order_list (Field *field, void *data) } -/* +/** Helper function for list_contains_unique_index. Find a field reference in a dynamic list of Items. - - SYNOPSIS - find_field_in_item_list () - field in The field to search for. - data in List *.The list to search in - - DESCRIPTION - Finds a direct reference of the Field in the list. - - RETURN VALUE + Finds a direct reference of the Field in the list. + + @param[in] field The field to search for. + @param[in] data List *.The list to search in + + @retval 1 found + @retval 0 not found. */ @@ -12608,15 +12653,20 @@ find_field_in_item_list (Field *field, void *data) } -/* +/** Test if we can skip the ORDER BY by using an index. If we can use an index, the JOIN_TAB / tab->select struct is changed to use the index. - Return: - 0 We have to use filesort to do the sorting - 1 We can use an index. + @todo + - sergeyp: Results of all index merge selects actually are ordered + by clustered PK values. + + @retval + 0 We have to use filesort to do the sorting + @retval + 1 We can use an index. */ static bool @@ -13155,11 +13205,11 @@ err: DBUG_RETURN(-1); } -/* - Add the HAVING criteria to table->select +#ifdef NOT_YET +/** + Add the HAVING criteria to table->select. */ -#ifdef NOT_YET static bool fix_having(JOIN *join, Item **having) { (*having)->update_used_tables(); // Some tables may have been const @@ -13366,9 +13416,11 @@ err: } -/* - Generate a hash index for each row to quickly find duplicate rows - Note that this will not work on tables with blobs! +/** + Generate a hash index for each row to quickly find duplicate rows. + + @note + Note that this will not work on tables with blobs! */ static int remove_dup_with_hash_index(THD *thd, TABLE *table, @@ -13805,37 +13857,37 @@ cp_buffer_from_ref(THD *thd, TABLE *table, TABLE_REF *ref) Group and order functions *****************************************************************************/ -/* +/** Resolve an ORDER BY or GROUP BY column reference. - SYNOPSIS - find_order_in_list() - thd [in] Pointer to current thread structure - ref_pointer_array [in/out] All select, group and order by fields - tables [in] List of tables to search in (usually FROM clause) - order [in] Column reference to be resolved - fields [in] List of fields to search in (usually SELECT list) - all_fields [in/out] All select, group and order by fields - is_group_field [in] True if order is a GROUP field, false if - ORDER by field + Given a column reference (represented by 'order') from a GROUP BY or ORDER + BY clause, find the actual column it represents. If the column being + resolved is from the GROUP BY clause, the procedure searches the SELECT + list 'fields' and the columns in the FROM list 'tables'. If 'order' is from + the ORDER BY clause, only the SELECT list is being searched. - DESCRIPTION - Given a column reference (represented by 'order') from a GROUP BY or ORDER - BY clause, find the actual column it represents. If the column being - resolved is from the GROUP BY clause, the procedure searches the SELECT - list 'fields' and the columns in the FROM list 'tables'. If 'order' is from - the ORDER BY clause, only the SELECT list is being searched. + If 'order' is resolved to an Item, then order->item is set to the found + Item. If there is no item for the found column (that is, it was resolved + into a table field), order->item is 'fixed' and is added to all_fields and + ref_pointer_array. - If 'order' is resolved to an Item, then order->item is set to the found - Item. If there is no item for the found column (that is, it was resolved - into a table field), order->item is 'fixed' and is added to all_fields and - ref_pointer_array. + ref_pointer_array and all_fields are updated. - RETURN + @param[in] thd Pointer to current thread structure + @param[in,out] ref_pointer_array All select, group and order by fields + @param[in] tables List of tables to search in (usually + FROM clause) + @param[in] order Column reference to be resolved + @param[in] fields List of fields to search in (usually + SELECT list) + @param[in,out] all_fields All select, group and order by fields + @param[in] is_group_field True if order is a GROUP field, false if + ORDER by field + + @retval FALSE if OK + @retval TRUE if error occurred - - ref_pointer_array and all_fields are updated */ static bool @@ -13969,9 +14021,11 @@ find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, } -/* - Change order to point at item in select list. If item isn't a number - and doesn't exits in the select list, add it the the field list. +/** + Change order to point at item in select list. + + If item isn't a number and doesn't exits in the select list, add it the + the field list. */ int setup_order(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, @@ -13988,27 +14042,30 @@ int setup_order(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, } -/* +/** Intitialize the GROUP BY list. - SYNOPSIS - setup_group() - thd Thread handler - ref_pointer_array We store references to all fields that was not in - 'fields' here. - fields All fields in the select part. Any item in 'order' - that is part of these list is replaced by a pointer - to this fields. - all_fields Total list of all unique fields used by the select. - All items in 'order' that was not part of fields will - be added first to this list. - order The fields we should do GROUP BY on. - hidden_group_fields Pointer to flag that is set to 1 if we added any fields - to all_fields. + @param thd Thread handler + @param ref_pointer_array We store references to all fields that was + not in 'fields' here. + @param fields All fields in the select part. Any item in + 'order' that is part of these list is replaced + by a pointer to this fields. + @param all_fields Total list of all unique fields used by the + select. All items in 'order' that was not part + of fields will be added first to this list. + @param order The fields we should do GROUP BY on. + @param hidden_group_fields Pointer to flag that is set to 1 if we added + any fields to all_fields. - RETURN - 0 ok - 1 error (probably out of memory) + @todo + change ER_WRONG_FIELD_WITH_GROUP to more detailed + ER_NON_GROUPING_FIELD_USED + + @retval + 0 ok + @retval + 1 error (probably out of memory) */ int @@ -14101,8 +14158,11 @@ next_field: return 0; } -/* - Add fields with aren't used at start of field list. Return FALSE if ok +/** + Add fields with aren't used at start of field list. + + @return + FALSE if ok */ static bool @@ -14132,10 +14192,11 @@ setup_new_fields(THD *thd, List &fields, DBUG_RETURN(0); } -/* - Create a group by that consist of all non const fields. Try to use - the fields in the order given by 'order' to allow one to optimize - away 'order by'. +/** + Create a group by that consist of all non const fields. + + Try to use the fields in the order given by 'order' to allow one to + optimize away 'order by'. */ static ORDER * @@ -14222,9 +14283,9 @@ next_item: } -/***************************************************************************** - Update join with count of the different type of fields -*****************************************************************************/ +/** + Update join with count of the different type of fields. +*/ void count_field_types(SELECT_LEX *select_lex, TMP_TABLE_PARAM *param, @@ -14274,8 +14335,9 @@ count_field_types(SELECT_LEX *select_lex, TMP_TABLE_PARAM *param, } -/* - Return 1 if second is a subpart of first argument +/** + Return 1 if second is a subpart of first argument. + If first parts has different direction, change it to second part (group is sorted like order) */ @@ -14293,10 +14355,9 @@ test_if_subpart(ORDER *a,ORDER *b) return test(!b); } -/* +/** Return table number if there is only one table in sort order - and group and order is compatible - else return 0; + and group and order is compatible, else return 0. */ static TABLE * @@ -14327,7 +14388,9 @@ get_sort_by_table(ORDER *a,ORDER *b,TABLE_LIST *tables) } - /* calc how big buffer we need for comparing group entries */ +/** + calc how big buffer we need for comparing group entries. +*/ static void calc_group_buffer(JOIN *join,ORDER *group) @@ -14393,17 +14456,17 @@ calc_group_buffer(JOIN *join,ORDER *group) } -/* - allocate group fields or take prepared (cached) +/** + allocate group fields or take prepared (cached). - SYNOPSIS - make_group_fields() - main_join - join of current select - curr_join - current join (join of current select or temporary copy of it) + @param main_join join of current select + @param curr_join current join (join of current select or temporary copy + of it) - RETURN - 0 - ok - 1 - failed + @retval + 0 ok + @retval + 1 failed */ static bool @@ -14424,9 +14487,10 @@ make_group_fields(JOIN *main_join, JOIN *curr_join) } -/* - Get a list of buffers for saveing last group - Groups are saved in reverse order for easyer check loop +/** + Get a list of buffers for saveing last group. + + Groups are saved in reverse order for easyer check loop. */ static bool @@ -14464,27 +14528,33 @@ test_if_group_changed(List &list) } -/* +/** + Setup copy_fields to save fields at start of new group. + Setup copy_fields to save fields at start of new group - setup_copy_fields() - thd - THD pointer - param - temporary table parameters - ref_pointer_array - array of pointers to top elements of filed list - res_selected_fields - new list of items of select item list - res_all_fields - new list of all items - elements - number of elements in select item list - all_fields - all fields list + Only FIELD_ITEM:s and FUNC_ITEM:s needs to be saved between groups. + Change old item_field to use a new field with points at saved fieldvalue + This function is only called before use of send_fields. - DESCRIPTION - Setup copy_fields to save fields at start of new group - Only FIELD_ITEM:s and FUNC_ITEM:s needs to be saved between groups. - Change old item_field to use a new field with points at saved fieldvalue - This function is only called before use of send_fields - - RETURN - 0 - ok - !=0 - error + @param thd THD pointer + @param param temporary table parameters + @param ref_pointer_array array of pointers to top elements of filed list + @param res_selected_fields new list of items of select item list + @param res_all_fields new list of all items + @param elements number of elements in select item list + @param all_fields all fields list + + @todo + In most cases this result will be sent to the user. + This should be changed to use copy_int or copy_real depending + on how the value is to be used: In some cases this may be an + argument in a group function, like: IF(ISNULL(col),0,COUNT(*)) + + @retval + 0 ok + @retval + !=0 error */ bool @@ -14618,8 +14688,8 @@ err2: } -/* - Make a copy of all simple SELECT'ed items +/** + Make a copy of all simple SELECT'ed items. This is done at the start of a new group so that we can retrieve these later when the group changes. @@ -14641,14 +14711,13 @@ copy_fields(TMP_TABLE_PARAM *param) } -/* - Make an array of pointers to sum_functions to speed up sum_func calculation +/** + Make an array of pointers to sum_functions to speed up + sum_func calculation. - SYNOPSIS - alloc_func_list() - - RETURN + @retval 0 ok + @retval 1 Error */ @@ -14693,18 +14762,17 @@ bool JOIN::alloc_func_list() } -/* - Initialize 'sum_funcs' array with all Item_sum objects +/** + Initialize 'sum_funcs' array with all Item_sum objects. - SYNOPSIS - make_sum_func_list() - field_list All items - send_fields Items in select list - before_group_by Set to 1 if this is called before GROUP BY handling - recompute Set to TRUE if sum_funcs must be recomputed + @param field_list All items + @param send_fields Items in select list + @param before_group_by Set to 1 if this is called before GROUP BY handling + @param recompute Set to TRUE if sum_funcs must be recomputed - RETURN + @retval 0 ok + @retval 1 error */ @@ -14745,21 +14813,21 @@ bool JOIN::make_sum_func_list(List &field_list, List &send_fields, } -/* +/** Change all funcs and sum_funcs to fields in tmp table, and create new list of all items. - change_to_use_tmp_fields() - thd - THD pointer - ref_pointer_array - array of pointers to top elements of filed list - res_selected_fields - new list of items of select item list - res_all_fields - new list of all items - elements - number of elements in select item list - all_fields - all fields list + @param thd THD pointer + @param ref_pointer_array array of pointers to top elements of filed list + @param res_selected_fields new list of items of select item list + @param res_all_fields new list of all items + @param elements number of elements in select item list + @param all_fields all fields list - RETURN - 0 - ok - !=0 - error + @retval + 0 ok + @retval + !=0 error */ static bool @@ -14833,20 +14901,20 @@ change_to_use_tmp_fields(THD *thd, Item **ref_pointer_array, } -/* - Change all sum_func refs to fields to point at fields in tmp table - Change all funcs to be fields in tmp table +/** + Change all sum_func refs to fields to point at fields in tmp table. + Change all funcs to be fields in tmp table. - change_refs_to_tmp_fields() - thd - THD pointer - ref_pointer_array - array of pointers to top elements of filed list - res_selected_fields - new list of items of select item list - res_all_fields - new list of all items - elements - number of elements in select item list - all_fields - all fields list + @param thd THD pointer + @param ref_pointer_array array of pointers to top elements of filed list + @param res_selected_fields new list of items of select item list + @param res_all_fields new list of all items + @param elements number of elements in select item list + @param all_fields all fields list - RETURN + @retval 0 ok + @retval 1 error */ @@ -14884,16 +14952,15 @@ change_refs_to_tmp_fields(THD *thd, Item **ref_pointer_array, ******************************************************************************/ -/* - Call ::setup for all sum functions +/** + Call ::setup for all sum functions. - SYNOPSIS - setup_sum_funcs() - thd thread handler - func_ptr sum function list + @param thd thread handler + @param func_ptr sum function list - RETURN + @retval FALSE ok + @retval TRUE error */ @@ -14919,7 +14986,7 @@ init_tmptable_sum_functions(Item_sum **func_ptr) } - /* Update record 0 in tmp_table from record 1 */ +/** Update record 0 in tmp_table from record 1. */ static void update_tmptable_sum_func(Item_sum **func_ptr, @@ -14931,7 +14998,7 @@ update_tmptable_sum_func(Item_sum **func_ptr, } - /* Copy result of sum functions to record in tmp_table */ +/** Copy result of sum functions to record in tmp_table. */ static void copy_sum_funcs(Item_sum **func_ptr, Item_sum **end_ptr) @@ -14970,7 +15037,7 @@ update_sum_func(Item_sum **func_ptr) return 0; } - /* Copy result of functions to record in tmp_table */ +/** Copy result of functions to record in tmp_table. */ void copy_funcs(Item **func_ptr) @@ -14981,9 +15048,9 @@ copy_funcs(Item **func_ptr) } -/* +/** Create a condition for a const reference and add this to the - currenct select for the table + currenct select for the table. */ static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab) @@ -15023,12 +15090,11 @@ static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab) } -/* +/** Free joins of subselect of this select. - free_underlaid_joins() - thd - THD pointer - select - pointer to st_select_lex which subselects joins we will free + @param thd THD pointer + @param select pointer to st_select_lex which subselects joins we will free */ void free_underlaid_joins(THD *thd, SELECT_LEX *select) @@ -15043,41 +15109,43 @@ void free_underlaid_joins(THD *thd, SELECT_LEX *select) ROLLUP handling ****************************************************************************/ -/* - Replace occurences of group by fields in an expression by ref items +/** + Replace occurences of group by fields in an expression by ref items. - SYNOPSIS - change_group_ref() - thd reference to the context - expr expression to make replacement - group_list list of references to group by items - changed out: returns 1 if item contains a replaced field item + The function replaces occurrences of group by fields in expr + by ref objects for these fields unless they are under aggregate + functions. + The function also corrects value of the the maybe_null attribute + for the items of all subexpressions containing group by fields. - DESCRIPTION - The function replaces occurrences of group by fields in expr - by ref objects for these fields unless they are under aggregate - functions. - The function also corrects value of the the maybe_null attribute - for the items of all subexpressions containing group by fields. + @b EXAMPLES + @code + SELECT a+1 FROM t1 GROUP BY a WITH ROLLUP + SELECT SUM(a)+a FROM t1 GROUP BY a WITH ROLLUP + @endcode + + @b IMPLEMENTATION - IMPLEMENTATION The function recursively traverses the tree of the expr expression, looks for occurrences of the group by fields that are not under aggregate functions and replaces them for the corresponding ref items. - NOTES + @note This substitution is needed GROUP BY queries with ROLLUP if SELECT list contains expressions over group by attributes. - TODO: Some functions are not null-preserving. For those functions + @param thd reference to the context + @param expr expression to make replacement + @param group_list list of references to group by items + @param changed out: returns 1 if item contains a replaced field item + + @todo + - TODO: Some functions are not null-preserving. For those functions updating of the maybe_null attribute is an overkill. - EXAMPLES - SELECT a+1 FROM t1 GROUP BY a WITH ROLLUP - SELECT SUM(a)+a FROM t1 GROUP BY a WITH ROLLUP - - RETURN + @retval 0 if ok + @retval 1 on error */ @@ -15126,7 +15194,7 @@ static bool change_group_ref(THD *thd, Item_func *expr, ORDER *group_list, } -/* Allocate memory needed for other rollup functions */ +/** Allocate memory needed for other rollup functions. */ bool JOIN::rollup_init() { @@ -15229,22 +15297,20 @@ bool JOIN::rollup_init() } -/* - Fill up rollup structures with pointers to fields to use +/** + Fill up rollup structures with pointers to fields to use. - SYNOPSIS - rollup_make_fields() - fields_arg List of all fields (hidden and real ones) - sel_fields Pointer to selected fields - func Store here a pointer to all fields + Creates copies of item_sum items for each sum level. - IMPLEMENTATION: - Creates copies of item_sum items for each sum level + @param fields_arg List of all fields (hidden and real ones) + @param sel_fields Pointer to selected fields + @param func Store here a pointer to all fields - RETURN - 0 if ok - In this case func is pointing to next not used element. - 1 on error + @retval + 0 if ok; + In this case func is pointing to next not used element. + @retval + 1 on error */ bool JOIN::rollup_make_fields(List &fields_arg, List &sel_fields, @@ -15362,21 +15428,22 @@ bool JOIN::rollup_make_fields(List &fields_arg, List &sel_fields, return 0; } -/* - Send all rollup levels higher than the current one to the client +/** + Send all rollup levels higher than the current one to the client. - SYNOPSIS: - rollup_send_data() - idx Level we are on: - 0 = Total sum level - 1 = First group changed (a) - 2 = Second group changed (a,b) + @b SAMPLE + @code + SELECT a, b, c SUM(b) FROM t1 GROUP BY a,b WITH ROLLUP + @endcode - SAMPLE - SELECT a, b, c SUM(b) FROM t1 GROUP BY a,b WITH ROLLUP + @param idx Level we are on: + - 0 = Total sum level + - 1 = First group changed (a) + - 2 = Second group changed (a,b) - RETURN - 0 ok + @retval + 0 ok + @retval 1 If send_data_failed() */ @@ -15402,22 +15469,23 @@ int JOIN::rollup_send_data(uint idx) return 0; } -/* - Write all rollup levels higher than the current one to a temp table +/** + Write all rollup levels higher than the current one to a temp table. - SYNOPSIS: - rollup_write_data() - idx Level we are on: - 0 = Total sum level - 1 = First group changed (a) - 2 = Second group changed (a,b) - table reference to temp table + @b SAMPLE + @code + SELECT a, b, SUM(c) FROM t1 GROUP BY a,b WITH ROLLUP + @endcode - SAMPLE - SELECT a, b, SUM(c) FROM t1 GROUP BY a,b WITH ROLLUP + @param idx Level we are on: + - 0 = Total sum level + - 1 = First group changed (a) + - 2 = Second group changed (a,b) + @param table reference to temp table - RETURN - 0 ok + @retval + 0 ok + @retval 1 if write_data_failed() */ @@ -15454,12 +15522,9 @@ int JOIN::rollup_write_data(uint idx, TABLE *table_arg) return 0; } -/* +/** clear results if there are not rows found for group (end_send_group/end_write_group) - - SYNOPSYS - JOIN::clear() */ void JOIN::clear() @@ -15475,11 +15540,11 @@ void JOIN::clear() } } -/**************************************************************************** - EXPLAIN handling +/** + EXPLAIN handling. - Send a description about what how the select will be done to stdout -****************************************************************************/ + Send a description about what how the select will be done to stdout. +*/ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, bool distinct,const char *message) @@ -15994,14 +16059,12 @@ bool mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result) } -/* - Print joins from the FROM clause +/** + Print joins from the FROM clause. - SYNOPSIS - print_join() - thd thread handler - str string where table should be printed - tables list of tables in join + @param thd thread handler + @param str string where table should be printed + @param tables list of tables in join */ static void print_join(THD *thd, String *str, List *tables) @@ -16043,12 +16106,10 @@ static void print_join(THD *thd, String *str, List *tables) } -/* - Print table as it should be in join list +/** + Print table as it should be in join list. - SYNOPSIS - TABLE_LIST::print(); - str string where table should bbe printed + @param str string where table should bbe printed */ void TABLE_LIST::print(THD *thd, String *str) @@ -16234,16 +16295,15 @@ void st_select_lex::print(THD *thd, String *str) } -/* - change select_result object of JOIN +/** + change select_result object of JOIN. - SYNOPSIS - JOIN::change_result() - res new select_result object + @param res new select_result object - RETURN - FALSE - OK - TRUE - error + @retval + FALSE OK + @retval + TRUE error */ bool JOIN::change_result(select_result *res) diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index ce26b025430..7b255a8ce59 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -168,7 +168,7 @@ static const LEX_STRING triggers_file_type= const char * const TRG_EXT= ".TRG"; -/* +/** Table of .TRG file field descriptors. We have here only one field now because in nearest future .TRG files will be merged into .FRM files (so we don't need something @@ -216,7 +216,7 @@ File_option sql_modes_parameters= FILE_OPTIONS_ULLLIST }; -/* +/** This must be kept up to date whenever a new option is added to the list above, as it specifies the number of required parameters of the trigger in .trg file. @@ -292,23 +292,27 @@ private: }; -/* +/** Create or drop trigger for table. - SYNOPSIS - mysql_create_or_drop_trigger() - thd - current thread context (including trigger definition in LEX) - tables - table list containing one table for which trigger is created. - create - whenever we create (TRUE) or drop (FALSE) trigger + @param thd current thread context (including trigger definition in LEX) + @param tables table list containing one table for which trigger is created. + @param create whenever we create (TRUE) or drop (FALSE) trigger - NOTE + @note This function is mainly responsible for opening and locking of table and invalidation of all its instances in table cache after trigger creation. Real work on trigger creation/dropping is done inside Table_triggers_list methods. - RETURN VALUE + @todo + TODO: We should check if user has TRIGGER privilege for table here. + Now we just require SUPER privilege for creating/dropping because + we don't have proper privilege checking for triggers in place yet. + + @retval FALSE Success + @retval TRUE error */ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) @@ -479,29 +483,28 @@ end: } -/* +/** Create trigger for table. - SYNOPSIS - create_trigger() - thd - current thread context (including trigger definition in - LEX) - tables - table list containing one open table for which the - trigger is created. - stmt_query - [OUT] after successful return, this string contains - well-formed statement for creating this trigger. + @param thd current thread context (including trigger definition in + LEX) + @param tables table list containing one open table for which the + trigger is created. + @param[out] stmt_query after successful return, this string contains + well-formed statement for creation this trigger. - NOTE + @note - Assumes that trigger name is fully qualified. - NULL-string means the following LEX_STRING instance: - { str = 0; length = 0 }. + { str = 0; length = 0 }. - In other words, definer_user and definer_host should contain - simultaneously NULL-strings (non-SUID/old trigger) or valid strings - (SUID/new trigger). + simultaneously NULL-strings (non-SUID/old trigger) or valid strings + (SUID/new trigger). - RETURN VALUE - False - success - True - error + @retval + False success + @retval + True error */ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables, String *stmt_query) @@ -767,19 +770,18 @@ err_with_cleanup: } -/* - Deletes the .TRG file for a table +/** + Deletes the .TRG file for a table. - SYNOPSIS - rm_trigger_file() - path - char buffer of size FN_REFLEN to be used - for constructing path to .TRG file. - db - table's database name - table_name - table's name + @param path char buffer of size FN_REFLEN to be used + for constructing path to .TRG file. + @param db table's database name + @param table_name table's name - RETURN VALUE - False - success - True - error + @retval + False success + @retval + True error */ static bool rm_trigger_file(char *path, const char *db, @@ -790,19 +792,18 @@ static bool rm_trigger_file(char *path, const char *db, } -/* - Deletes the .TRN file for a trigger +/** + Deletes the .TRN file for a trigger. - SYNOPSIS - rm_trigname_file() - path - char buffer of size FN_REFLEN to be used - for constructing path to .TRN file. - db - trigger's database name - table_name - trigger's name + @param path char buffer of size FN_REFLEN to be used + for constructing path to .TRN file. + @param db trigger's database name + @param table_name trigger's name - RETURN VALUE - False - success - True - error + @retval + False success + @retval + True error */ static bool rm_trigname_file(char *path, const char *db, @@ -813,17 +814,16 @@ static bool rm_trigname_file(char *path, const char *db, } -/* +/** Helper function that saves .TRG file for Table_triggers_list object. - SYNOPSIS - save_trigger_file() - triggers Table_triggers_list object for which file should be saved - db Name of database for subject table - table_name Name of subject table + @param triggers Table_triggers_list object for which file should be saved + @param db Name of database for subject table + @param table_name Name of subject table - RETURN VALUE + @retval FALSE Success + @retval TRUE Error */ @@ -842,21 +842,26 @@ static bool save_trigger_file(Table_triggers_list *triggers, const char *db, } -/* +/** Drop trigger for table. - SYNOPSIS - drop_trigger() - thd - current thread context - (including trigger definition in LEX) - tables - table list containing one open table for which trigger - is dropped. - stmt_query - [OUT] after successful return, this string contains - well-formed statement for deleting this trigger. + @param thd current thread context + (including trigger definition in LEX) + @param tables table list containing one open table for which trigger + is dropped. + @param[out] stmt_query after successful return, this string contains + well-formed statement for creation this trigger. - RETURN VALUE - False - success - True - error + @todo + Probably instead of removing .TRG file we should move + to archive directory but this should be done as part of + parse_file.cc functionality (because we will need it + elsewhere). + + @retval + False success + @retval + True error */ bool Table_triggers_list::drop_trigger(THD *thd, TABLE_LIST *tables, String *stmt_query) @@ -939,18 +944,17 @@ Table_triggers_list::~Table_triggers_list() } -/* +/** Prepare array of Field objects referencing to TABLE::record[1] instead of record[0] (they will represent OLD.* row values in ON UPDATE trigger and in ON DELETE trigger which will be called during REPLACE execution). - SYNOPSIS - prepare_record1_accessors() - table - pointer to TABLE object for which we are creating fields. + @param table pointer to TABLE object for which we are creating fields. - RETURN VALUE - False - success - True - error + @retval + False success + @retval + True error */ bool Table_triggers_list::prepare_record1_accessors(TABLE *table) { @@ -979,12 +983,10 @@ bool Table_triggers_list::prepare_record1_accessors(TABLE *table) } -/* +/** Adjust Table_triggers_list with new TABLE pointer. - SYNOPSIS - set_table() - new_table - new pointer to TABLE instance + @param new_table new pointer to TABLE instance */ void Table_triggers_list::set_table(TABLE *new_table) @@ -998,20 +1000,26 @@ void Table_triggers_list::set_table(TABLE *new_table) } -/* +/** Check whenever .TRG file for table exist and load all triggers it contains. - SYNOPSIS - check_n_load() - thd - current thread context - db - table's database name - table_name - table's name - table - pointer to table object - names_only - stop after loading trigger names + @param thd current thread context + @param db table's database name + @param table_name table's name + @param table pointer to table object + @param names_only stop after loading trigger names - RETURN VALUE - False - success - True - error + @todo + A lot of things to do here e.g. how about other funcs and being + more paranoical ? + + @todo + This could be avoided if there is no triggers for UPDATE and DELETE. + + @retval + False success + @retval + True error */ bool Table_triggers_list::check_n_load(THD *thd, const char *db, @@ -1394,24 +1402,23 @@ err_with_lex_cleanup: } -/* - Obtains and returns trigger metadata +/** + Obtains and returns trigger metadata. - SYNOPSIS - get_trigger_info() - thd - current thread context - event - trigger event type - time_type - trigger action time - name - returns name of trigger - stmt - returns statement of trigger - sql_mode - returns sql_mode of trigger - definer_user - returns definer/creator of trigger. The caller is - responsible to allocate enough space for storing definer - information. + @param thd current thread context + @param event trigger event type + @param time_type trigger action time + @param trigger_name returns name of trigger + @param trigger_stmt returns statement of trigger + @param sql_mode returns sql_mode of trigger + @param definer returns definer/creator of trigger. The caller is + responsible to allocate enough space for storing + definer information. - RETURN VALUE - False - success - True - error + @retval + False success + @retval + True error */ bool Table_triggers_list::get_trigger_info(THD *thd, trg_event_type event, @@ -1577,21 +1584,20 @@ bool add_table_for_trigger(THD *thd, } -/* +/** Drop all triggers for table. - SYNOPSIS - drop_all_triggers() - thd - current thread context - db - schema for table - name - name for table + @param thd current thread context + @param db schema for table + @param name name for table - NOTE + @note The calling thread should hold the LOCK_open mutex; - RETURN VALUE - False - success - True - error + @retval + False success + @retval + True error */ bool Table_triggers_list::drop_all_triggers(THD *thd, char *db, char *name) @@ -1641,19 +1647,18 @@ end: } -/* +/** Update .TRG file after renaming triggers' subject table (change name of table in triggers' definitions). - SYNOPSIS - change_table_name_in_triggers() - thd Thread context - db_name Database of subject table - old_table_name Old subject table's name - new_table_name New subject table's name + @param thd Thread context + @param db_name Database of subject table + @param old_table_name Old subject table's name + @param new_table_name New subject table's name - RETURN VALUE + @retval FALSE Success + @retval TRUE Failure */ @@ -1723,21 +1728,20 @@ Table_triggers_list::change_table_name_in_triggers(THD *thd, } -/* - Iterate though Table_triggers_list::names_list list and update .TRN files - after renaming triggers' subject table. +/** + Iterate though Table_triggers_list::names_list list and update + .TRN files after renaming triggers' subject table. - SYNOPSIS - change_table_name_in_trignames() - db_name Database of subject table - new_table_name New subject table's name - stopper Pointer to Table_triggers_list::names_list at - which we should stop updating. + @param db_name Database of subject table + @param new_table_name New subject table's name + @param stopper Pointer to Table_triggers_list::names_list at + which we should stop updating. - RETURN VALUE + @retval 0 Success + @retval non-0 Failure, pointer to Table_triggers_list::names_list element - for which update failed. + for which update failed. */ LEX_STRING* @@ -1771,7 +1775,7 @@ Table_triggers_list::change_table_name_in_trignames(const char *db_name, /** - @brief Update .TRG and .TRN files after renaming triggers' subject table. + Update .TRG and .TRN files after renaming triggers' subject table. @param[in,out] thd Thread context @param[in] db Old database of subject table @@ -1933,19 +1937,17 @@ bool Table_triggers_list::process_triggers(THD *thd, } -/* - Mark fields of subject table which we read/set in its triggers as such. +/** + Mark fields of subject table which we read/set in its triggers + as such. - SYNOPSIS - mark_fields_used() - thd Current thread context - event Type of event triggers for which we are going to ins + This method marks fields of subject table which are read/set in its + triggers as such (by properly updating TABLE::read_set/write_set) + and thus informs handler that values for these fields should be + retrieved/stored during execution of statement. - DESCRIPTION - This method marks fields of subject table which are read/set in its - triggers as such (by properly updating TABLE::read_set/write_set) - and thus informs handler that values for these fields should be - retrieved/stored during execution of statement. + @param thd Current thread context + @param event Type of event triggers for which we are going to inspect */ void Table_triggers_list::mark_fields_used(trg_event_type event) @@ -1971,23 +1973,23 @@ void Table_triggers_list::mark_fields_used(trg_event_type event) } -/* - Trigger BUG#14090 compatibility hook +/** + Trigger BUG#14090 compatibility hook. - SYNOPSIS - Handle_old_incorrect_sql_modes_hook::process_unknown_string() - unknown_key [in/out] reference on the line with unknown - parameter and the parsing point - base [in] base address for parameter writing (structure - like TABLE) - mem_root [in] MEM_ROOT for parameters allocation - end [in] the end of the configuration + @param[in,out] unknown_key reference on the line with unknown + parameter and the parsing point + @param[in] base base address for parameter writing + (structure like TABLE) + @param[in] mem_root MEM_ROOT for parameters allocation + @param[in] end the end of the configuration - NOTE: this hook process back compatibility for incorrectly written - sql_modes parameter (see BUG#14090). + @note + NOTE: this hook process back compatibility for incorrectly written + sql_modes parameter (see BUG#14090). - RETURN + @retval FALSE OK + @retval TRUE Error */ @@ -2029,13 +2031,12 @@ Handle_old_incorrect_sql_modes_hook::process_unknown_string(char *&unknown_key, DBUG_RETURN(FALSE); } -/* +#define INVALID_TRIGGER_TABLE_LENGTH 15 + +/** Trigger BUG#15921 compatibility hook. For details see Handle_old_incorrect_sql_modes_hook::process_unknown_string(). */ - -#define INVALID_TRIGGER_TABLE_LENGTH 15 - bool Handle_old_incorrect_trigger_table_hook:: process_unknown_string(char *&unknown_key, uchar* base, MEM_ROOT *mem_root, @@ -2074,9 +2075,9 @@ process_unknown_string(char *&unknown_key, uchar* base, MEM_ROOT *mem_root, /** Contruct path to TRN-file. - @param[in] thd Thread context. - @param[in] trg_name Trigger name. - @param[out] trn_path Variable to store constructed path + @param thd[in] Thread context. + @param trg_name[in] Trigger name. + @param trn_path[out] Variable to store constructed path */ void build_trn_path(THD *thd, const sp_name *trg_name, LEX_STRING *trn_path) @@ -2109,10 +2110,10 @@ bool check_trn_exists(const LEX_STRING *trn_path) /** Retrieve table name for given trigger. - @param[in] thd Thread context. - @param[in] trg_name Trigger name. - @param[in] trn_path Path to the corresponding TRN-file. - @param[out] tbl_name Variable to store retrieved table name. + @param thd[in] Thread context. + @param trg_name[in] Trigger name. + @param trn_path[in] Path to the corresponding TRN-file. + @param tbl_name[out] Variable to store retrieved table name. @return Error status. @retval FALSE on success. diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 4071bb86c90..127e2b94214 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -84,7 +84,7 @@ static bool check_fields(THD *thd, List &items) /** - @brief Re-read record if more columns are needed for error message. + Re-read record if more columns are needed for error message. If we got a duplicate key error, we want to write an error message containing the value of the duplicate key. If we do not have diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 56d50761d95..d0e03ec3237 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -206,7 +206,7 @@ fill_defined_view_parts (THD *thd, TABLE_LIST *view) /** - @brief Creating/altering VIEW procedure + Creating/altering VIEW procedure @param thd thread handler @param views views to create From 5a19f077b372d96b301a9a926326fb780d88c5e8 Mon Sep 17 00:00:00 2001 From: "cmiller@zippy.cornsilk.net" <> Date: Tue, 16 Oct 2007 16:11:50 -0400 Subject: [PATCH 046/336] Doxygenize comments. --- sql/my_decimal.h | 27 ++++-- sql/mysql_priv.h | 90 +++++++++--------- sql/mysqld_suffix.h | 7 +- sql/nt_servc.h | 16 ++-- sql/parse_file.h | 24 ++--- sql/procedure.h | 4 +- sql/protocol.h | 2 +- sql/sp_head.h | 217 +++++++++++++++++++++++--------------------- sql/sql_cache.h | 4 +- sql/sql_class.h | 15 +-- sql/sql_cursor.h | 11 ++- sql/sql_select.h | 133 ++++++++++++++------------- sql/sql_trigger.h | 20 ++-- sql/structs.h | 2 +- sql/tztime.h | 12 +-- sql/unireg.h | 10 +- 16 files changed, 313 insertions(+), 281 deletions(-) diff --git a/sql/my_decimal.h b/sql/my_decimal.h index 800ae23425b..1885036f42b 100644 --- a/sql/my_decimal.h +++ b/sql/my_decimal.h @@ -13,7 +13,9 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* +/** + @file + It is interface module to fixed precision decimals library. Most functions use 'uint mask' as parameter, if during operation error @@ -34,14 +36,14 @@ C_MODE_END #define DECIMAL_LONG_DIGITS 10 #define DECIMAL_LONG3_DIGITS 8 -/* maximum length of buffer in our big digits (uint32) */ +/** maximum length of buffer in our big digits (uint32). */ #define DECIMAL_BUFF_LENGTH 9 /* the number of digits that my_decimal can possibly contain */ #define DECIMAL_MAX_POSSIBLE_PRECISION (DECIMAL_BUFF_LENGTH * 9) -/* +/** maximum guaranteed precision of number in decimal digits (number of our digits * number of decimal digits in one our big digit - number of decimal digits in one our big digit decreased by 1 (because we always put decimal @@ -51,13 +53,14 @@ C_MODE_END #define DECIMAL_MAX_SCALE 30 #define DECIMAL_NOT_SPECIFIED 31 -/* +/** maximum length of string representation (number of maximum decimal digits + 1 position for sign + 1 position for decimal point) */ #define DECIMAL_MAX_STR_LENGTH (DECIMAL_MAX_POSSIBLE_PRECISION + 2) -/* - maximum size of packet length + +/** + maximum size of packet length. */ #define DECIMAL_MAX_FIELD_SIZE DECIMAL_MAX_PRECISION @@ -78,11 +81,12 @@ inline int my_decimal_int_part(uint precision, uint decimals) } -/* - my_decimal class limits 'decimal_t' type to what we need in MySQL +/** + my_decimal class limits 'decimal_t' type to what we need in MySQL. + It contains internally all necessary space needed by the instance so no extra memory is needed. One should call fix_buffer_pointer() function - when he moves my_decimal objects in memory + when he moves my_decimal objects in memory. */ class my_decimal :public decimal_t @@ -384,7 +388,10 @@ int my_decimal_mod(uint mask, my_decimal *res, const my_decimal *a, } -/* Returns -1 if ab and 0 if a==b */ +/** + @return + -1 if ab and 0 if a==b +*/ inline int my_decimal_cmp(const my_decimal *a, const my_decimal *b) { diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index dfea3060cee..034e548cfbd 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -13,10 +13,13 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* +/** + @file + + @details Mostly this file is used in the server. But a little part of it is used in mysqlbinlog too (definition of SELECT_DISTINCT and others). - The consequence is that 90% of the file is wrapped in #ifndef MYSQL_CLIENT, + The consequence is that 90% of the file is wrapped in \#ifndef MYSQL_CLIENT, except the part which must be in the server and in the client. */ @@ -253,12 +256,12 @@ protected: Feel free to raise this by the smallest amount you can to get the "execution_constants" test to pass. */ -#define STACK_MIN_SIZE 12000 // Abort if less stack during eval. +#define STACK_MIN_SIZE 12000 ///< Abort if less stack during eval. #define STACK_MIN_SIZE_FOR_OPEN 1024*80 -#define STACK_BUFF_ALLOC 352 // For stack overrun checks +#define STACK_BUFF_ALLOC 352 ///< For stack overrun checks #ifndef MYSQLD_NET_RETRY_COUNT -#define MYSQLD_NET_RETRY_COUNT 10 // Abort read after this many int. +#define MYSQLD_NET_RETRY_COUNT 10 ///< Abort read after this many int. #endif #define TEMP_POOL_SIZE 128 @@ -282,14 +285,14 @@ protected: #define MIN_ROWS_TO_USE_TABLE_CACHE 100 #define MIN_ROWS_TO_USE_BULK_INSERT 100 -/* +/** The following is used to decide if MySQL should use table scanning instead of reading with keys. The number says how many evaluation of the WHERE clause is comparable to reading one extra row from a table. */ #define TIME_FOR_COMPARE 5 // 5 compares == one read -/* +/** Number of comparisons of table rowids equivalent to reading one row from a table. */ @@ -309,17 +312,17 @@ protected: #define DISK_SEEK_PROP_COST ((double)0.5/BLOCKS_IN_AVG_SEEK) -/* +/** Number of rows in a reference table when refereed through a not unique key. This value is only used when we don't know anything about the key distribution. */ #define MATCHING_ROWS_IN_OTHER_TABLE 10 -/* Don't pack string keys shorter than this (if PACK_KEYS=1 isn't used) */ +/** Don't pack string keys shorter than this (if PACK_KEYS=1 isn't used). */ #define KEY_DEFAULT_PACK_LENGTH 8 -/* Characters shown for the command in 'show processlist' */ +/** Characters shown for the command in 'show processlist'. */ #define PROCESS_LIST_WIDTH 100 /* Characters shown for the command in 'information_schema.processlist' */ #define PROCESS_LIST_INFO_WIDTH 65535 @@ -335,11 +338,11 @@ protected: /* The following can also be changed from the command line */ #define DEFAULT_CONCURRENCY 10 -#define DELAYED_LIMIT 100 /* pause after xxx inserts */ +#define DELAYED_LIMIT 100 /**< pause after xxx inserts */ #define DELAYED_QUEUE_SIZE 1000 -#define DELAYED_WAIT_TIMEOUT 5*60 /* Wait for delayed insert */ -#define FLUSH_TIME 0 /* Don't flush tables */ -#define MAX_CONNECT_ERRORS 10 // errors before disabling host +#define DELAYED_WAIT_TIMEOUT 5*60 /**< Wait for delayed insert */ +#define FLUSH_TIME 0 /**< Don't flush tables */ +#define MAX_CONNECT_ERRORS 10 ///< errors before disabling host #ifdef __NETWARE__ #define IF_NETWARE(A,B) A @@ -349,7 +352,7 @@ protected: #if defined(__WIN__) #undef FLUSH_TIME -#define FLUSH_TIME 1800 /* Flush every half hour */ +#define FLUSH_TIME 1800 /**< Flush every half hour */ #define INTERRUPT_PRIOR -2 #define CONNECT_PRIOR -1 @@ -368,12 +371,12 @@ protected: #define TEST_MIT_THREAD 4 #define TEST_BLOCKING 8 #define TEST_KEEP_TMP_TABLES 16 -#define TEST_READCHECK 64 /* Force use of readcheck */ +#define TEST_READCHECK 64 /**< Force use of readcheck */ #define TEST_NO_EXTRA 128 -#define TEST_CORE_ON_SIGNAL 256 /* Give core if signal */ +#define TEST_CORE_ON_SIGNAL 256 /**< Give core if signal */ #define TEST_NO_STACKTRACE 512 -#define TEST_SIGINT 1024 /* Allow sigint on threads */ -#define TEST_SYNCHRONIZATION 2048 /* get server to do sleep in +#define TEST_SIGINT 1024 /**< Allow sigint on threads */ +#define TEST_SYNCHRONIZATION 2048 /**< get server to do sleep in some places */ #endif @@ -423,26 +426,26 @@ protected: /* The following is used to detect a conflict with DISTINCT */ #define SELECT_ALL (ULL(1) << 24) // SELECT, user, parser -/* The following can be set when importing tables in a 'wrong order' +/** The following can be set when importing tables in a 'wrong order' to suppress foreign key checks */ #define OPTION_NO_FOREIGN_KEY_CHECKS (ULL(1) << 26) // THD, user, binlog -/* The following speeds up inserts to InnoDB tables by suppressing unique +/** The following speeds up inserts to InnoDB tables by suppressing unique key checks in some cases */ #define OPTION_RELAXED_UNIQUE_CHECKS (ULL(1) << 27) // THD, user, binlog #define SELECT_NO_UNLOCK (ULL(1) << 28) // SELECT, intern #define OPTION_SCHEMA_TABLE (ULL(1) << 29) // SELECT, intern -/* Flag set if setup_tables already done */ +/** Flag set if setup_tables already done */ #define OPTION_SETUP_TABLES_DONE (ULL(1) << 30) // intern -/* If not set then the thread will ignore all warnings with level notes. */ +/** If not set then the thread will ignore all warnings with level notes. */ #define OPTION_SQL_NOTES (ULL(1) << 31) // THD, user -/* +/** Force the used temporary table to be a MyISAM table (because we will use fulltext functions when reading from it. */ #define TMP_TABLE_FORCE_MYISAM (ULL(1) << 32) -/* +/** Maximum length of time zone name that we support (Time zone name is char(64) in db). mysqlbinlog needs it. */ @@ -505,9 +508,9 @@ protected: #define UNCACHEABLE_DEPENDENT 1 #define UNCACHEABLE_RAND 2 #define UNCACHEABLE_SIDEEFFECT 4 -// forcing to save JOIN for explain +/// forcing to save JOIN for explain #define UNCACHEABLE_EXPLAIN 8 -/* Don't evaluate subqueries in prepare even if they're not correlated */ +/** Don't evaluate subqueries in prepare even if they're not correlated */ #define UNCACHEABLE_PREPARE 16 /* For uncorrelated SELECT in an UNION with some correlated SELECTs */ #define UNCACHEABLE_UNITED 32 @@ -515,7 +518,7 @@ protected: /* Used to check GROUP BY list in the MODE_ONLY_FULL_GROUP_BY mode */ #define UNDEF_POS (-1) #ifdef EXTRA_DEBUG -/* +/** Sync points allow us to force the server to reach a certain line of code and block there until the client tells the server it is ok to go on. The client tells the server to block with SELECT GET_LOCK() @@ -551,7 +554,7 @@ void view_store_options(THD *thd, TABLE_LIST *table, String *buff); #define portable_sizeof_char_ptr 8 -#define tmp_file_prefix "#sql" /* Prefix for tmp tables */ +#define tmp_file_prefix "#sql" /**< Prefix for tmp tables */ #define tmp_file_prefix_length 4 /* Flags for calc_week() function. */ @@ -586,9 +589,9 @@ enum enum_check_fields CHECK_FIELD_WARN, CHECK_FIELD_ERROR_FOR_NULL }; - -/* Struct to handle simple linked lists */ + +/** Struct to handle simple linked lists. */ typedef struct st_sql_list { uint elements; uchar *first; @@ -2192,16 +2195,15 @@ Item * all_any_subquery_creator(Item *left_expr, bool all, SELECT_LEX *select_lex); -/* - clean/setup table fields and map +/** + clean/setup table fields and map. - SYNOPSYS - setup_table_map() - table - TABLE structure pointer (which should be setup) - table_list TABLE_LIST structure pointer (owner of TABLE) - tablenr - table number + @param table TABLE structure pointer (which should be setup) + @param table_list TABLE_LIST structure pointer (owner of TABLE) + @param tablenr table number */ + inline void setup_table_map(TABLE *table, TABLE_LIST *table_list, uint tablenr) { table->used_fields= 0; @@ -2223,10 +2225,8 @@ inline void setup_table_map(TABLE *table, TABLE_LIST *table_list, uint tablenr) } -/* - SYNOPSYS - hexchar_to_int() - convert a hex digit into number +/** + convert a hex digit into number. */ inline int hexchar_to_int(char c) @@ -2239,11 +2239,9 @@ inline int hexchar_to_int(char c) return -1; } -/* - is_user_table() - return true if the table was created explicitly +/** + return true if the table was created explicitly. */ - inline bool is_user_table(TABLE * table) { const char *name= table->s->table_name.str; diff --git a/sql/mysqld_suffix.h b/sql/mysqld_suffix.h index b348f272db1..654d7cf88c1 100644 --- a/sql/mysqld_suffix.h +++ b/sql/mysqld_suffix.h @@ -13,8 +13,11 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* - Set MYSQL_SERVER_SUFFIX_STR +/** + @file + + Set MYSQL_SERVER_SUFFIX_STR. + The following code is quite ugly as there is no portable way to easily set a string to the value of a macro */ diff --git a/sql/nt_servc.h b/sql/nt_servc.h index a3c12569114..525f709388b 100644 --- a/sql/nt_servc.h +++ b/sql/nt_servc.h @@ -1,8 +1,12 @@ -/* ------------------------------------------------------------------------ - Windows NT Service class library - Copyright Abandoned 1998 Irena Pancirov - Irnet Snc - This file is public domain and comes with NO WARRANTY of any kind - -------------------------------------------------------------------------- */ +/** + @file + + @brief + Windows NT Service class library + + Copyright Abandoned 1998 Irena Pancirov - Irnet Snc + This file is public domain and comes with NO WARRANTY of any kind +*/ // main application thread typedef void (*THREAD_FC)(void *); @@ -13,7 +17,7 @@ class NTService NTService(); ~NTService(); - BOOL bOsNT; // true if OS is NT, false for Win95 + BOOL bOsNT; ///< true if OS is NT, false for Win95 //install optinos DWORD dwDesiredAccess; DWORD dwServiceType; diff --git a/sql/parse_file.h b/sql/parse_file.h index 91700959681..30c902478b8 100644 --- a/sql/parse_file.h +++ b/sql/parse_file.h @@ -20,27 +20,27 @@ #define PARSE_FILE_TIMESTAMPLENGTH 19 enum file_opt_type { - FILE_OPTIONS_STRING, /* String (LEX_STRING) */ - FILE_OPTIONS_ESTRING, /* Escaped string (LEX_STRING) */ - FILE_OPTIONS_ULONGLONG, /* ulonglong parameter (ulonglong) */ - FILE_OPTIONS_REV, /* Revision version number (ulonglong) */ - FILE_OPTIONS_TIMESTAMP, /* timestamp (LEX_STRING have to be + FILE_OPTIONS_STRING, /**< String (LEX_STRING) */ + FILE_OPTIONS_ESTRING, /**< Escaped string (LEX_STRING) */ + FILE_OPTIONS_ULONGLONG, /**< ulonglong parameter (ulonglong) */ + FILE_OPTIONS_REV, /**< Revision version number (ulonglong) */ + FILE_OPTIONS_TIMESTAMP, /**< timestamp (LEX_STRING have to be allocated with length 20 (19+1) */ - FILE_OPTIONS_STRLIST, /* list of escaped strings + FILE_OPTIONS_STRLIST, /**< list of escaped strings (List) */ - FILE_OPTIONS_ULLLIST /* list of ulonglong values + FILE_OPTIONS_ULLLIST /**< list of ulonglong values (List) */ }; struct File_option { - LEX_STRING name; /* Name of the option */ - int offset; /* offset to base address of value */ - file_opt_type type; /* Option type */ + LEX_STRING name; /**< Name of the option */ + int offset; /**< offset to base address of value */ + file_opt_type type; /**< Option type */ }; -/* +/** This hook used to catch no longer supported keys and process them for backward compatibility. */ @@ -55,7 +55,7 @@ public: }; -/* Dummy hook for parsers which do not need hook for unknown keys */ +/** Dummy hook for parsers which do not need hook for unknown keys. */ class File_parser_dummy_hook: public Unknown_key_hook { diff --git a/sql/procedure.h b/sql/procedure.h index 6a731766046..4578fcb87f1 100644 --- a/sql/procedure.h +++ b/sql/procedure.h @@ -20,8 +20,8 @@ #pragma interface /* gcc class implementation */ #endif -#define PROC_NO_SORT 1 /* Bits in flags */ -#define PROC_GROUP 2 /* proc must have group */ +#define PROC_NO_SORT 1 /**< Bits in flags */ +#define PROC_GROUP 2 /**< proc must have group */ /* Procedure items used by procedures to store values for send_fields */ diff --git a/sql/protocol.h b/sql/protocol.h index 46a2b6d36b6..853cca0f769 100644 --- a/sql/protocol.h +++ b/sql/protocol.h @@ -110,7 +110,7 @@ public: }; -/* Class used for the old (MySQL 4.0 protocol) */ +/** Class used for the old (MySQL 4.0 protocol). */ class Protocol_text :public Protocol { diff --git a/sql/sp_head.h b/sql/sp_head.h index 3a8b41acd4c..d0d4f92ae67 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -109,7 +109,7 @@ public: LEX_STRING m_db; LEX_STRING m_name; LEX_STRING m_qname; - /* + /** Key representing routine in the set of stored routines used by statement. Consists of 1-byte routine type and m_qname (which usually refences to same buffer). Note that one must complete initialization of the key by @@ -125,7 +125,7 @@ public: m_qname.length= m_sroutines_key.length= 0; } - /* + /** Creates temporary sp_name object from key, used mainly for SP-cache lookups. */ @@ -158,12 +158,12 @@ check_routine_name(LEX_STRING *ident); class sp_head :private Query_arena { - sp_head(const sp_head &); /* Prevent use of these */ + sp_head(const sp_head &); /**< Prevent use of these */ void operator=(sp_head &); MEM_ROOT main_mem_root; public: - /* Possible values of m_flags */ + /** Possible values of m_flags */ enum { HAS_RETURN= 1, // For FUNCTIONs only: is set if has RETURN MULTI_RESULTS= 8, // Is set if a procedure with SELECT(s) @@ -179,16 +179,16 @@ public: HAS_SQLCOM_FLUSH= 4096 }; - /* TYPE_ENUM_FUNCTION, TYPE_ENUM_PROCEDURE or TYPE_ENUM_TRIGGER */ + /** TYPE_ENUM_FUNCTION, TYPE_ENUM_PROCEDURE or TYPE_ENUM_TRIGGER */ int m_type; uint m_flags; // Boolean attributes of a stored routine - Create_field m_return_field_def; /* This is used for FUNCTIONs only. */ + Create_field m_return_field_def; /**< This is used for FUNCTIONs only. */ - const char *m_tmp_query; // Temporary pointer to sub query string + const char *m_tmp_query; ///< Temporary pointer to sub query string st_sp_chistics *m_chistics; - ulong m_sql_mode; // For SHOW CREATE and execution - LEX_STRING m_qname; // db.name + ulong m_sql_mode; ///< For SHOW CREATE and execution + LEX_STRING m_qname; ///< db.name /** Key representing routine in the set of stored routines used by statement. [routine_type]db.name @@ -220,20 +220,20 @@ public: longlong m_created; longlong m_modified; - /* Recursion level of the current SP instance. The levels are numbered from 0 */ + /** Recursion level of the current SP instance. The levels are numbered from 0 */ ulong m_recursion_level; - /* + /** A list of diferent recursion level instances for the same procedure. For every recursion level we have a sp_head instance. This instances connected in the list. The list ordered by increasing recursion level (m_recursion_level). */ sp_head *m_next_cached_sp; - /* + /** Pointer to the first element of the above list */ sp_head *m_first_instance; - /* + /** Pointer to the first free (non-INVOKED) routine in the list of cached instances for this SP. This pointer is set only for the first SP in the list of instences (see above m_first_cached_sp pointer). @@ -241,12 +241,12 @@ public: For non-first instance value of this pointer meanless (point to itself); */ sp_head *m_first_free_instance; - /* + /** Pointer to the last element in the list of instances of the SP. For non-first instance value of this pointer meanless (point to itself); */ sp_head *m_last_cached_sp; - /* + /** Set containing names of stored routines used by this routine. Note that unlike elements of similar set for statement elements of this set are not linked in one list. Because of this we are able save memory @@ -276,11 +276,11 @@ public: sp_head(); - // Initialize after we have reset mem_root + /// Initialize after we have reset mem_root void init(LEX *lex); - /* Copy sp name from parser. */ + /** Copy sp name from parser. */ void init_sp_name(THD *thd, sp_name *spname); @@ -297,7 +297,7 @@ public: virtual ~sp_head(); - // Free memory + /// Free memory void destroy(); @@ -334,33 +334,41 @@ public: return i; } - // Resets lex in 'thd' and keeps a copy of the old one. + /* + Resets lex in 'thd' and keeps a copy of the old one. + + @todo Conflicting comment in sp_head.cc + */ void reset_lex(THD *thd); - // Restores lex in 'thd' from our copy, but keeps some status from the - // one in 'thd', like ptr, tables, fields, etc. + /** + Restores lex in 'thd' from our copy, but keeps some status from the + one in 'thd', like ptr, tables, fields, etc. + + @todo Conflicting comment in sp_head.cc + */ void restore_lex(THD *thd); - // Put the instruction on the backpatch list, associated with the label. + /// Put the instruction on the backpatch list, associated with the label. void push_backpatch(sp_instr *, struct sp_label *); - // Update all instruction with this label in the backpatch list to - // the current position. + /// Update all instruction with this label in the backpatch list to + /// the current position. void backpatch(struct sp_label *); - // Start a new cont. backpatch level. If 'i' is NULL, the level is just incr. + /// Start a new cont. backpatch level. If 'i' is NULL, the level is just incr. void new_cont_backpatch(sp_instr_opt_meta *i); - // Add an instruction to the current level + /// Add an instruction to the current level void add_cont_backpatch(sp_instr_opt_meta *i); - // Backpatch (and pop) the current level to the current position. + /// Backpatch (and pop) the current level to the current position. void do_cont_backpatch(); @@ -423,7 +431,7 @@ public: TABLE_LIST ***query_tables_last_ptr, TABLE_LIST *belong_to_view); - /* + /** Check if this stored routine contains statements disallowed in a stored function or trigger, and set an appropriate error message if this is the case. @@ -472,19 +480,19 @@ public: private: - MEM_ROOT *m_thd_root; // Temp. store for thd's mem_root - THD *m_thd; // Set if we have reset mem_root + MEM_ROOT *m_thd_root; ///< Temp. store for thd's mem_root + THD *m_thd; ///< Set if we have reset mem_root - sp_pcontext *m_pcont; // Parse context - List m_lex; // Temp. store for the other lex - DYNAMIC_ARRAY m_instr; // The "instructions" + sp_pcontext *m_pcont; ///< Parse context + List m_lex; ///< Temp. store for the other lex + DYNAMIC_ARRAY m_instr; ///< The "instructions" typedef struct { struct sp_label *lab; sp_instr *instr; } bp_t; - List m_backpatch; // Instructions needing backpatching - /* + List m_backpatch; ///< Instructions needing backpatching + /** We need a special list for backpatching of instructions with a continue destination (in the case of a continue handler catching an error in the test), since it would otherwise interfere with the normal backpatch @@ -492,15 +500,16 @@ private: which are to be patched differently. Since these occur in a more restricted way (always the same "level" in the code), we don't need the label. - */ + */ List m_cont_backpatch; uint m_cont_level; // The current cont. backpatch level - /* + /** Multi-set representing optimized list of tables to be locked by this routine. Does not include tables which are used by invoked routines. - Note: for prelocking-free SPs this multiset is constructed too. + @note + For prelocking-free SPs this multiset is constructed too. We do so because the same instance of sp_head may be called both in prelocked mode and in non-prelocked mode. */ @@ -515,7 +524,7 @@ private: */ void opt_mark(); - /* + /** Merge the list of tables used by query into the multi-set of tables used by routine. */ @@ -529,16 +538,16 @@ private: class sp_instr :public Query_arena, public Sql_alloc { - sp_instr(const sp_instr &); /* Prevent use of these */ + sp_instr(const sp_instr &); /**< Prevent use of these */ void operator=(sp_instr &); public: uint marked; - uint m_ip; // My index - sp_pcontext *m_ctx; // My parse context + uint m_ip; ///< My index + sp_pcontext *m_ctx; ///< My parse context - // Should give each a name or type code for debugging purposes? + /// Should give each a name or type code for debugging purposes? sp_instr(uint ip, sp_pcontext *ctx) :Query_arena(0, INITIALIZED_FOR_SP), marked(0), m_ip(ip), m_ctx(ctx) {} @@ -547,21 +556,19 @@ public: { free_items(); } - /* + /** Execute this instruction - SYNOPSIS - execute() - thd Thread handle - nextp OUT index of the next instruction to execute. (For most - instructions this will be the instruction following this - one). Note that this parameter is undefined in case of - errors, use get_cont_dest() to find the continuation - instruction for CONTINUE error handlers. - - RETURN - 0 on success, - other if some error occurred + + @param thd Thread handle + @param[out] nextp index of the next instruction to execute. (For most + instructions this will be the instruction following this + one). Note that this parameter is undefined in case of + errors, use get_cont_dest() to find the continuation + instruction for CONTINUE error handlers. + + @retval 0 on success, + @retval other if some error occured */ virtual int execute(THD *thd, uint *nextp) = 0; @@ -599,7 +606,7 @@ public: virtual void backpatch(uint dest, sp_pcontext *dst_ctx) {} - /* + /** Mark this instruction as reachable during optimization and return the index to the next instruction. Jump instruction will add their destination to the leads list. @@ -610,7 +617,7 @@ public: return m_ip+1; } - /* + /** Short-cut jumps to jumps during optimization. This is used by the jump instructions' opt_mark() methods. 'start' is the starting point, used to prevent the mark sweep from looping for ever. Return the @@ -621,7 +628,7 @@ public: return m_ip; } - /* + /** Inform the instruction that it has been moved during optimization. Most instructions will simply update its index, but jump instructions must also take care of their destination pointers. Forward jumps get @@ -635,7 +642,7 @@ public: }; // class sp_instr : public Sql_alloc -/* +/** Auxilary class to which instructions delegate responsibility for handling LEX and preparations before executing statement or calculating complex expression. @@ -643,13 +650,14 @@ public: Exist mainly to avoid having double hierarchy between instruction classes. - TODO: Add ability to not store LEX and do any preparations if - expression used is simple. + @todo + Add ability to not store LEX and do any preparations if + expression used is simple. */ class sp_lex_keeper { - /* Prevent use of these */ + /** Prevent use of these */ sp_lex_keeper(const sp_lex_keeper &); void operator=(sp_lex_keeper &); public: @@ -669,10 +677,12 @@ public: } } - /* + /** Prepare execution of instruction using LEX, if requested check whenever we have read access to tables used and open/lock them, call instruction's exec_core() method, perform cleanup afterwards. + + @todo Conflicting comment in sp_head.cc */ int reset_lex_and_exec_core(THD *thd, uint *nextp, bool open_tables, sp_instr* instr); @@ -689,7 +699,7 @@ public: private: LEX *m_lex; - /* + /** Indicates whenever this sp_lex_keeper instance responsible for LEX deletion. */ @@ -702,13 +712,13 @@ private: prelocked mode itself. */ - /* + /** List of additional tables this statement needs to lock when it enters/leaves prelocked mode on its own. */ TABLE_LIST *prelocking_tables; - /* + /** The value m_lex->query_tables_own_last should be set to this when the statement enters/leaves prelocked mode on its own. */ @@ -716,17 +726,17 @@ private: }; -// -// Call out to some prepared SQL statement. -// +/** + Call out to some prepared SQL statement. +*/ class sp_instr_stmt : public sp_instr { - sp_instr_stmt(const sp_instr_stmt &); /* Prevent use of these */ + sp_instr_stmt(const sp_instr_stmt &); /**< Prevent use of these */ void operator=(sp_instr_stmt &); public: - LEX_STRING m_query; // For thd->query + LEX_STRING m_query; ///< For thd->query sp_instr_stmt(uint ip, sp_pcontext *ctx, LEX *lex) : sp_instr(ip, ctx), m_lex_keeper(lex, TRUE) @@ -753,7 +763,7 @@ private: class sp_instr_set : public sp_instr { - sp_instr_set(const sp_instr_set &); /* Prevent use of these */ + sp_instr_set(const sp_instr_set &); /**< Prevent use of these */ void operator=(sp_instr_set &); public: @@ -776,15 +786,15 @@ public: private: - uint m_offset; // Frame offset + uint m_offset; ///< Frame offset Item *m_value; - enum enum_field_types m_type; // The declared type + enum enum_field_types m_type; ///< The declared type sp_lex_keeper m_lex_keeper; }; // class sp_instr_set : public sp_instr -/* +/** Set NEW/OLD row field value instruction. Used in triggers. */ class sp_instr_set_trigger_field : public sp_instr @@ -818,18 +828,19 @@ private: }; // class sp_instr_trigger_field : public sp_instr -/* +/** An abstract class for all instructions with destinations that needs to be updated by the optimizer. + Even if not all subclasses will use both the normal destination and the continuation destination, we put them both here for simplicity. - */ +*/ class sp_instr_opt_meta : public sp_instr { public: - uint m_dest; // Where we will go - uint m_cont_dest; // Where continue handlers will go + uint m_dest; ///< Where we will go + uint m_cont_dest; ///< Where continue handlers will go sp_instr_opt_meta(uint ip, sp_pcontext *ctx) : sp_instr(ip, ctx), @@ -851,14 +862,14 @@ public: protected: - sp_instr *m_optdest; // Used during optimization - sp_instr *m_cont_optdest; // Used during optimization + sp_instr *m_optdest; ///< Used during optimization + sp_instr *m_cont_optdest; ///< Used during optimization }; // class sp_instr_opt_meta : public sp_instr class sp_instr_jump : public sp_instr_opt_meta { - sp_instr_jump(const sp_instr_jump &); /* Prevent use of these */ + sp_instr_jump(const sp_instr_jump &); /**< Prevent use of these */ void operator=(sp_instr_jump &); public: @@ -890,7 +901,7 @@ public: m_dest= dest; } - /* + /** Update the destination; used by the optimizer. */ virtual void set_destination(uint old_dest, uint new_dest) @@ -904,7 +915,7 @@ public: class sp_instr_jump_if_not : public sp_instr_jump { - sp_instr_jump_if_not(const sp_instr_jump_if_not &); /* Prevent use of these */ + sp_instr_jump_if_not(const sp_instr_jump_if_not &); /**< Prevent use of these */ void operator=(sp_instr_jump_if_not &); public: @@ -930,7 +941,7 @@ public: virtual uint opt_mark(sp_head *sp, List *leads); - /* Override sp_instr_jump's shortcut; we stop here */ + /** Override sp_instr_jump's shortcut; we stop here */ virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start) { return m_ip; @@ -947,7 +958,7 @@ public: private: - Item *m_expr; // The condition + Item *m_expr; ///< The condition sp_lex_keeper m_lex_keeper; }; // class sp_instr_jump_if_not : public sp_instr_jump @@ -955,7 +966,7 @@ private: class sp_instr_freturn : public sp_instr { - sp_instr_freturn(const sp_instr_freturn &); /* Prevent use of these */ + sp_instr_freturn(const sp_instr_freturn &); /**< Prevent use of these */ void operator=(sp_instr_freturn &); public: @@ -992,7 +1003,7 @@ protected: class sp_instr_hpush_jump : public sp_instr_jump { - sp_instr_hpush_jump(const sp_instr_hpush_jump &); /* Prevent use of these */ + sp_instr_hpush_jump(const sp_instr_hpush_jump &); /**< Prevent use of these */ void operator=(sp_instr_hpush_jump &); public: @@ -1014,7 +1025,7 @@ public: virtual uint opt_mark(sp_head *sp, List *leads); - /* Override sp_instr_jump's shortcut; we stop here. */ + /** Override sp_instr_jump's shortcut; we stop here. */ virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start) { return m_ip; @@ -1027,7 +1038,7 @@ public: private: - int m_type; // Handler type + int m_type; ///< Handler type uint m_frame; List m_cond; @@ -1036,7 +1047,7 @@ private: class sp_instr_hpop : public sp_instr { - sp_instr_hpop(const sp_instr_hpop &); /* Prevent use of these */ + sp_instr_hpop(const sp_instr_hpop &); /**< Prevent use of these */ void operator=(sp_instr_hpop &); public: @@ -1061,7 +1072,7 @@ private: class sp_instr_hreturn : public sp_instr_jump { - sp_instr_hreturn(const sp_instr_hreturn &); /* Prevent use of these */ + sp_instr_hreturn(const sp_instr_hreturn &); /**< Prevent use of these */ void operator=(sp_instr_hreturn &); public: @@ -1092,10 +1103,10 @@ private: }; // class sp_instr_hreturn : public sp_instr_jump -/* This is DECLARE CURSOR */ +/** This is DECLARE CURSOR */ class sp_instr_cpush : public sp_instr { - sp_instr_cpush(const sp_instr_cpush &); /* Prevent use of these */ + sp_instr_cpush(const sp_instr_cpush &); /**< Prevent use of these */ void operator=(sp_instr_cpush &); public: @@ -1111,7 +1122,7 @@ public: virtual void print(String *str); - /* + /** This call is used to cleanup the instruction when a sensitive cursor is closed. For now stored procedures always use materialized cursors and the call is not used. @@ -1120,14 +1131,14 @@ public: private: sp_lex_keeper m_lex_keeper; - uint m_cursor; /* Frame offset (for debugging) */ + uint m_cursor; /**< Frame offset (for debugging) */ }; // class sp_instr_cpush : public sp_instr class sp_instr_cpop : public sp_instr { - sp_instr_cpop(const sp_instr_cpop &); /* Prevent use of these */ + sp_instr_cpop(const sp_instr_cpop &); /**< Prevent use of these */ void operator=(sp_instr_cpop &); public: @@ -1152,7 +1163,7 @@ private: class sp_instr_copen : public sp_instr { - sp_instr_copen(const sp_instr_copen &); /* Prevent use of these */ + sp_instr_copen(const sp_instr_copen &); /**< Prevent use of these */ void operator=(sp_instr_copen &); public: @@ -1172,14 +1183,14 @@ public: private: - uint m_cursor; // Stack index + uint m_cursor; ///< Stack index }; // class sp_instr_copen : public sp_instr_stmt class sp_instr_cclose : public sp_instr { - sp_instr_cclose(const sp_instr_cclose &); /* Prevent use of these */ + sp_instr_cclose(const sp_instr_cclose &); /**< Prevent use of these */ void operator=(sp_instr_cclose &); public: @@ -1204,7 +1215,7 @@ private: class sp_instr_cfetch : public sp_instr { - sp_instr_cfetch(const sp_instr_cfetch &); /* Prevent use of these */ + sp_instr_cfetch(const sp_instr_cfetch &); /**< Prevent use of these */ void operator=(sp_instr_cfetch &); public: @@ -1237,7 +1248,7 @@ private: class sp_instr_error : public sp_instr { - sp_instr_error(const sp_instr_error &); /* Prevent use of these */ + sp_instr_error(const sp_instr_error &); /**< Prevent use of these */ void operator=(sp_instr_error &); public: diff --git a/sql/sql_cache.h b/sql/sql_cache.h index b47e2e9a43b..f2c33eff614 100644 --- a/sql/sql_cache.h +++ b/sql/sql_cache.h @@ -66,8 +66,8 @@ struct Query_cache_result; class Query_cache; /** - @brief This class represents a node in the linked chain of queries - belonging to one table. + This class represents a node in the linked chain of queries + belonging to one table. @note The root of this linked list is not a query-type block, but the table- type block which all queries has in common. diff --git a/sql/sql_class.h b/sql/sql_class.h index 7875870bd1a..e8bfab370a9 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -77,10 +77,10 @@ typedef struct st_user_var_events was actually changed or not. */ typedef struct st_copy_info { - ha_rows records; /* Number of processed records */ - ha_rows deleted; /* Number of deleted records */ - ha_rows updated; /* Number of updated records */ - ha_rows copied; /* Number of copied records */ + ha_rows records; /**< Number of processed records */ + ha_rows deleted; /**< Number of deleted records */ + ha_rows updated; /**< Number of updated records */ + ha_rows copied; /**< Number of copied records */ ha_rows error_count; ha_rows touched; /* Number of touched records */ enum enum_duplicates handle_duplicates; @@ -1045,14 +1045,17 @@ public: */ char *catalog; - /* - WARNING: some members of THD (currently 'Statement::db', + /** + @note + Some members of THD (currently 'Statement::db', 'catalog' and 'query') are set and alloced by the slave SQL thread (for the THD of that thread); that thread is (and must remain, for now) the only responsible for freeing these 3 members. If you add members here, and you add code to set them in replication, don't forget to free_them_and_set_them_to_0 in replication properly. For details see the 'err:' label of the handle_slave_sql() in sql/slave.cc. + + @see handle_slave_sql */ Security_context main_security_ctx; diff --git a/sql/sql_cursor.h b/sql/sql_cursor.h index 6edd6b24b36..1f19cbfdbcf 100644 --- a/sql/sql_cursor.h +++ b/sql/sql_cursor.h @@ -20,12 +20,14 @@ #pragma interface /* gcc class interface */ #endif -/* +/** + @file + Declarations for implementation of server side cursors. Only read-only non-scrollable cursors are currently implemented. */ -/* +/** Server_side_cursor -- an interface for materialized and sensitive (non-materialized) implementation of cursors. All cursors are self-contained (created in their own memory root). @@ -36,7 +38,7 @@ class Server_side_cursor: protected Query_arena, public Sql_alloc { protected: - /* Row destination used for fetch */ + /** Row destination used for fetch */ select_result *result; public: Server_side_cursor(MEM_ROOT *mem_root_arg, select_result *result_arg) @@ -58,8 +60,7 @@ int mysql_open_cursor(THD *thd, uint flags, select_result *result, Server_side_cursor **res); -/* Possible values for flags */ - +/** Possible values for flags */ enum { ANY_CURSOR= 1, ALWAYS_MATERIALIZED_CURSOR= 2 }; #endif /* _sql_cusor_h_ */ diff --git a/sql/sql_select.h b/sql/sql_select.h index efa92432e2b..f91a965d4ac 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -14,7 +14,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* classes to use when handling where clause */ +/** + @file + + @brief + classes to use when handling where clause +*/ #ifdef USE_PRAGMA_INTERFACE #pragma interface /* gcc class implementation */ @@ -25,12 +30,12 @@ typedef struct keyuse_t { TABLE *table; - Item *val; /* or value if no field */ + Item *val; /**< or value if no field */ table_map used_tables; uint key, keypart, optimize; key_part_map keypart_map; ha_rows ref_table_rows; - /* + /** If true, the comparison this value was created from will not be satisfied if val has NULL 'value'. */ @@ -53,13 +58,13 @@ class store_key; typedef struct st_table_ref { bool key_err; - uint key_parts; // num of ... - uint key_length; // length of key_buff - int key; // key no - uchar *key_buff; // value to look for with key - uchar *key_buff2; // key_buff+key_length + uint key_parts; ///< num of ... + uint key_length; ///< length of key_buff + int key; ///< key no + uchar *key_buff; ///< value to look for with key + uchar *key_buff2; ///< key_buff+key_length store_key **key_copy; // - Item **items; // val()'s for each keypart + Item **items; ///< val()'s for each keypart /* Array of pointers to trigger variables. Some/all of the pointers may be NULL. The ref access can be used iff @@ -72,18 +77,18 @@ typedef struct st_table_ref underlying conditions is switched off (see subquery code for more details) */ bool **cond_guards; - /* + /** (null_rejecting & (1< *fields; List group_fields, group_fields_cache; TABLE *tmp_table; - // used to store 2 possible tmp table of SELECT + /// used to store 2 possible tmp table of SELECT TABLE *exec_tmp_table1, *exec_tmp_table2; THD *thd; Item_sum **sum_funcs, ***sum_funcs_end; - /* second copy of sumfuncs (for queries with 2 temporary tables */ + /** second copy of sumfuncs (for queries with 2 temporary tables */ Item_sum **sum_funcs2, ***sum_funcs_end2; Procedure *procedure; Item *having; - Item *tmp_having; // To store having when processed temporary table - Item *having_history; // Store having for explain + Item *tmp_having; ///< To store having when processed temporary table + Item *having_history; ///< Store having for explain ulonglong select_options; select_result *result; TMP_TABLE_PARAM tmp_table_param; MYSQL_LOCK *lock; - // unit structure (with global parameters) for this select + /// unit structure (with global parameters) for this select SELECT_LEX_UNIT *unit; - // select that processed + /// select that processed SELECT_LEX *select_lex; - /* + /** TRUE <=> optimizer must not mark any table as a constant table. This is needed for subqueries in form "a IN (SELECT .. UNION SELECT ..): when we optimize the select that reads the results of the union from a @@ -331,11 +336,11 @@ public: */ bool no_const_tables; - JOIN *tmp_join; // copy of this JOIN to be used with temporary tables - ROLLUP rollup; // Used with rollup + JOIN *tmp_join; ///< copy of this JOIN to be used with temporary tables + ROLLUP rollup; ///< Used with rollup - bool select_distinct; // Set if SELECT DISTINCT - /* + bool select_distinct; ///< Set if SELECT DISTINCT + /** If we have the GROUP BY statement in the query, but the group_list was emptied by optimizer, this flag is TRUE. @@ -350,42 +355,42 @@ public: It's also set if ORDER/GROUP BY is empty. */ bool simple_order, simple_group; - /* + /** Is set only in case if we have a GROUP BY clause and no ORDER BY after constant elimination of 'order'. */ bool no_order; - /* Is set if we have a GROUP BY and we have ORDER BY on a constant. */ + /** Is set if we have a GROUP BY and we have ORDER BY on a constant. */ bool skip_sort_order; bool need_tmp, hidden_group_fields; DYNAMIC_ARRAY keyuse; Item::cond_result cond_value, having_value; - List all_fields; // to store all fields that used in query - //Above list changed to use temporary table + List all_fields; ///< to store all fields that used in query + ///Above list changed to use temporary table List tmp_all_fields1, tmp_all_fields2, tmp_all_fields3; - //Part, shared with list above, emulate following list + ///Part, shared with list above, emulate following list List tmp_fields_list1, tmp_fields_list2, tmp_fields_list3; - List &fields_list; // hold field list passed to mysql_select + List &fields_list; ///< hold field list passed to mysql_select List procedure_fields_list; int error; ORDER *order, *group_list, *proc_param; //hold parameters of mysql_select COND *conds; // ---"--- Item *conds_history; // store WHERE for explain - TABLE_LIST *tables_list; //hold 'tables' parameter of mysql_select - List *join_list; // list of joined tables in reverse order + TABLE_LIST *tables_list; /// *join_list; ///< list of joined tables in reverse order COND_EQUAL *cond_equal; - SQL_SELECT *select; //created in optimisation phase - JOIN_TAB *return_tab; //used only for outer joins - Item **ref_pointer_array; //used pointer reference for this select + SQL_SELECT *select; /// &all_fields,COND *conds); /* from sql_delete.cc, used by opt_range.cc */ extern "C" int refpos_order_cmp(void* arg, const void *a,const void *b); -/* class to copying an field/item to a key struct */ +/** class to copying an field/item to a key struct */ class store_key :public Sql_alloc { @@ -578,7 +583,7 @@ public: to_field=field_arg->new_key_field(thd->mem_root, field_arg->table, ptr, null, 1); } - virtual ~store_key() {} /* Not actually needed */ + virtual ~store_key() {} /** Not actually needed */ virtual const char *name() const=0; /** diff --git a/sql/sql_trigger.h b/sql/sql_trigger.h index 8f6b08c927f..1b0edf6bea8 100644 --- a/sql/sql_trigger.h +++ b/sql/sql_trigger.h @@ -14,7 +14,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* +/** This class holds all information about triggers of table. QQ: Will it be merged into TABLE in the future ? @@ -22,20 +22,20 @@ class Table_triggers_list: public Sql_alloc { - /* Triggers as SPs grouped by event, action_time */ + /** Triggers as SPs grouped by event, action_time */ sp_head *bodies[TRG_EVENT_MAX][TRG_ACTION_MAX]; - /* + /** Heads of the lists linking items for all fields used in triggers grouped by event and action_time. */ Item_trigger_field *trigger_fields[TRG_EVENT_MAX][TRG_ACTION_MAX]; - /* + /** Copy of TABLE::Field array with field pointers set to TABLE::record[1] buffer instead of TABLE::record[0] (used for OLD values in on UPDATE trigger and DELETE trigger when it is called for REPLACE). */ Field **record1_field; - /* + /** During execution of trigger new_field and old_field should point to the array of fields representing new or old version of row correspondingly (so it can point to TABLE::field or to Tale_triggers_list::record1_field) @@ -45,30 +45,30 @@ class Table_triggers_list: public Sql_alloc /* TABLE instance for which this triggers list object was created */ TABLE *trigger_table; - /* + /** Names of triggers. Should correspond to order of triggers on definitions_list, used in CREATE/DROP TRIGGER for looking up trigger by name. */ List names_list; - /* + /** List of "ON table_name" parts in trigger definitions, used for updating trigger definitions during RENAME TABLE. */ List on_table_names_list; - /* + /** Grant information for each trigger (pair: subject table, trigger definer). */ GRANT_INFO subject_table_grants[TRG_EVENT_MAX][TRG_ACTION_MAX]; public: - /* + /** Field responsible for storing triggers definitions in file. It have to be public because we are using it directly from parser. */ List definitions_list; - /* + /** List of sql modes for triggers */ List definition_modes_list; diff --git a/sql/structs.h b/sql/structs.h index 09a3c4d7285..aeaa3a31005 100644 --- a/sql/structs.h +++ b/sql/structs.h @@ -209,7 +209,7 @@ typedef struct user_conn { char *user; /* Pointer to host part of the key. */ char *host; - /* + /** The moment of time when per hour counters were reset last time (i.e. start of "hour" for conn_per_hour, updates, questions counters). */ diff --git a/sql/tztime.h b/sql/tztime.h index ddd80b88bf2..3d77a3eefa3 100644 --- a/sql/tztime.h +++ b/sql/tztime.h @@ -20,7 +20,7 @@ #if !defined(TESTTIME) && !defined(TZINFO2SQL) -/* +/** This class represents abstract time zone and provides basic interface for MYSQL_TIME <-> my_time_t conversion. Actual time zones which are specified by DB, or via offset @@ -30,7 +30,7 @@ class Time_zone: public Sql_alloc { public: Time_zone() {} /* Remove gcc warning */ - /* + /** Converts local time in broken down MYSQL_TIME representation to my_time_t (UTC seconds since Epoch) represenation. Returns 0 in case of error. Sets in_dst_time_gap to true if date provided @@ -38,19 +38,19 @@ public: */ virtual my_time_t TIME_to_gmt_sec(const MYSQL_TIME *t, my_bool *in_dst_time_gap) const = 0; - /* + /** Converts time in my_time_t representation to local time in broken down MYSQL_TIME representation. */ virtual void gmt_sec_to_TIME(MYSQL_TIME *tmp, my_time_t t) const = 0; - /* + /** Because of constness of String returned by get_name() time zone name have to be already zeroended to be able to use String::ptr() instead of c_ptr(). */ virtual const String * get_name() const = 0; - /* + /** We need this only for surpressing warnings, objects of this type are allocated on MEM_ROOT and should not require destruction. */ @@ -65,7 +65,7 @@ extern my_bool my_tz_init(THD *org_thd, const char *default_tzname, my_bool extern void my_tz_free(); extern my_time_t sec_since_epoch_TIME(MYSQL_TIME *t); -/* +/** Number of elements in table list produced by my_tz_get_table_list() (this table list contains tables which are needed for dynamical loading of time zone descriptions). Actually it is imlementation detail that diff --git a/sql/unireg.h b/sql/unireg.h index f0b4a88c7f8..2e0172ce31d 100644 --- a/sql/unireg.h +++ b/sql/unireg.h @@ -155,34 +155,34 @@ #define OPEN_VIEW 8192 /* Allow open on view */ #define OPEN_VIEW_NO_PARSE 16384 /* Open frm only if it's a view, but do not parse view itself */ -/* +/** This flag is used in function get_all_tables() which fills I_S tables with data which are retrieved from frm files and storage engine The flag means that we need to open FRM file only to get necessary data. */ #define OPEN_FRM_FILE_ONLY 32768 -/* +/** This flag is used in function get_all_tables() which fills I_S tables with data which are retrieved from frm files and storage engine The flag means that we need to process tables only to get necessary data. Views are not processed. */ #define OPEN_TABLE_ONLY OPEN_FRM_FILE_ONLY*2 -/* +/** This flag is used in function get_all_tables() which fills I_S tables with data which are retrieved from frm files and storage engine The flag means that we need to process views only to get necessary data. Tables are not processed. */ #define OPEN_VIEW_ONLY OPEN_TABLE_ONLY*2 -/* +/** This flag is used in function get_all_tables() which fills I_S tables with data which are retrieved from frm files and storage engine. The flag means that we need to open a view using open_normal_and_derived_tables() function. */ #define OPEN_VIEW_FULL OPEN_VIEW_ONLY*2 -/* +/** This flag is used in function get_all_tables() which fills I_S tables with data which are retrieved from frm files and storage engine. The flag means that I_S table uses optimization algorithm. From 56ae0be77d381b1e78cc220d4f4d6163156b3eb5 Mon Sep 17 00:00:00 2001 From: "mats@kindahl-laptop.dnsalias.net" <> Date: Wed, 17 Oct 2007 06:50:03 +0200 Subject: [PATCH 047/336] Eliminating some valgrind warnings resulting from that some storage engines do not set the unused null bits (i.e., the filler bits and the X bit) correctly. Also adding some casts to debug printouts to eliminate compiler warnings. --- sql/ha_ndbcluster.cc | 110 +++++++++++++++++++++---------------------- sql/records.cc | 2 + sql/rpl_record.cc | 5 +- 3 files changed, 60 insertions(+), 57 deletions(-) diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index b2152fbb906..21267f4901a 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -411,7 +411,7 @@ Ndb *ha_ndbcluster::get_ndb() void ha_ndbcluster::set_rec_per_key() { - DBUG_ENTER("ha_ndbcluster::get_status_const"); + DBUG_ENTER("ha_ndbcluster::set_rec_per_key"); for (uint i=0 ; i < table_share->keys ; i++) { table->key_info[i].rec_per_key[table->key_info[i].key_parts-1]= 1; @@ -558,7 +558,7 @@ int ha_ndbcluster::ndb_err(NdbTransaction *trans) THD *thd= current_thd; int res; NdbError err= trans->getNdbError(); - DBUG_ENTER("ndb_err"); + DBUG_ENTER("ha_ndbcluster::ndb_err"); set_ndb_err(thd, err); @@ -695,7 +695,7 @@ static bool field_type_forces_var_part(enum_field_types type) bool ha_ndbcluster::set_hidden_key(NdbOperation *ndb_op, uint fieldnr, const uchar *field_ptr) { - DBUG_ENTER("set_hidden_key"); + DBUG_ENTER("ha_ndbcluster::set_hidden_key"); DBUG_RETURN(ndb_op->equal(fieldnr, (char*)field_ptr) != 0); } @@ -708,7 +708,7 @@ int ha_ndbcluster::set_ndb_key(NdbOperation *ndb_op, Field *field, uint fieldnr, const uchar *field_ptr) { uint32 pack_len= field->pack_length(); - DBUG_ENTER("set_ndb_key"); + DBUG_ENTER("ha_ndbcluster::set_ndb_key"); DBUG_PRINT("enter", ("%d: %s, ndb_type: %u, len=%d", fieldnr, field->field_name, field->type(), pack_len)); @@ -731,7 +731,7 @@ int ha_ndbcluster::set_ndb_value(NdbOperation *ndb_op, Field *field, { const uchar* field_ptr= field->ptr + row_offset; uint32 pack_len= field->pack_length(); - DBUG_ENTER("set_ndb_value"); + DBUG_ENTER("ha_ndbcluster::set_ndb_value"); DBUG_PRINT("enter", ("%d: %s type: %u len=%d is_null=%s", fieldnr, field->field_name, field->type(), pack_len, field->is_null(row_offset) ? "Y" : "N")); @@ -934,7 +934,7 @@ int get_ndb_blobs_value(TABLE* table, NdbValue* value_array, int ha_ndbcluster::get_ndb_value(NdbOperation *ndb_op, Field *field, uint fieldnr, uchar* buf) { - DBUG_ENTER("get_ndb_value"); + DBUG_ENTER("ha_ndbcluster::get_ndb_value"); DBUG_PRINT("enter", ("fieldnr: %d flags: %o", fieldnr, (int)(field != NULL ? field->flags : 0))); @@ -985,7 +985,7 @@ int ha_ndbcluster::get_ndb_value(NdbOperation *ndb_op, Field *field, */ int ha_ndbcluster::get_ndb_partition_id(NdbOperation *ndb_op) { - DBUG_ENTER("get_ndb_partition_id"); + DBUG_ENTER("ha_ndbcluster::get_ndb_partition_id"); DBUG_RETURN(ndb_op->getValue(NdbDictionary::Column::FRAGMENT, (char *)&m_part_id) == NULL); } @@ -1044,7 +1044,7 @@ int ha_ndbcluster::get_metadata(const char *path) NDBDICT *dict= ndb->getDictionary(); const NDBTAB *tab; int error; - DBUG_ENTER("get_metadata"); + DBUG_ENTER("ha_ndbcluster::get_metadata"); DBUG_PRINT("enter", ("m_tabname: %s, path: %s", m_tabname, path)); DBUG_ASSERT(m_table == NULL); @@ -1463,7 +1463,7 @@ void ha_ndbcluster::release_metadata(THD *thd, Ndb *ndb) { uint i; - DBUG_ENTER("release_metadata"); + DBUG_ENTER("ha_ndbcluster::release_metadata"); DBUG_PRINT("enter", ("m_tabname: %s", m_tabname)); NDBDICT *dict= ndb->getDictionary(); @@ -1604,7 +1604,7 @@ int ha_ndbcluster::set_primary_key(NdbOperation *op, const uchar *key) KEY* key_info= table->key_info + table_share->primary_key; KEY_PART_INFO* key_part= key_info->key_part; KEY_PART_INFO* end= key_part+key_info->key_parts; - DBUG_ENTER("set_primary_key"); + DBUG_ENTER("ha_ndbcluster::set_primary_key"); for (; key_part != end; key_part++) { @@ -1626,7 +1626,7 @@ int ha_ndbcluster::set_primary_key_from_record(NdbOperation *op, const uchar *re KEY* key_info= table->key_info + table_share->primary_key; KEY_PART_INFO* key_part= key_info->key_part; KEY_PART_INFO* end= key_part+key_info->key_parts; - DBUG_ENTER("set_primary_key_from_record"); + DBUG_ENTER("ha_ndbcluster::set_primary_key_from_record"); for (; key_part != end; key_part++) { @@ -1645,7 +1645,7 @@ int ha_ndbcluster::set_index_key_from_record(NdbOperation *op, KEY_PART_INFO* key_part= key_info->key_part; KEY_PART_INFO* end= key_part+key_info->key_parts; uint i; - DBUG_ENTER("set_index_key_from_record"); + DBUG_ENTER("ha_ndbcluster::set_index_key_from_record"); for (i= 0; key_part != end; key_part++, i++) { @@ -1684,7 +1684,7 @@ inline int ha_ndbcluster::define_read_attrs(uchar* buf, NdbOperation* op) { uint i; - DBUG_ENTER("define_read_attrs"); + DBUG_ENTER("ha_ndbcluster::define_read_attrs"); // Define attributes to read for (i= 0; i < table_share->fields; i++) @@ -1731,7 +1731,7 @@ int ha_ndbcluster::pk_read(const uchar *key, uint key_len, uchar *buf, NdbOperation *op; int res; - DBUG_ENTER("pk_read"); + DBUG_ENTER("ha_ndbcluster::pk_read"); DBUG_PRINT("enter", ("key_len: %u", key_len)); DBUG_DUMP("key", key, key_len); m_write_op= FALSE; @@ -1798,7 +1798,7 @@ int ha_ndbcluster::complemented_read(const uchar *old_data, uchar *new_data, uint no_fields= table_share->fields, i; NdbTransaction *trans= m_active_trans; NdbOperation *op; - DBUG_ENTER("complemented_read"); + DBUG_ENTER("ha_ndbcluster::complemented_read"); m_write_op= FALSE; if (bitmap_is_set_all(table->read_set)) @@ -1964,7 +1964,7 @@ int ha_ndbcluster::peek_indexed_rows(const uchar *record, const NdbOperation *first, *last; uint i; int res; - DBUG_ENTER("peek_indexed_rows"); + DBUG_ENTER("ha_ndbcluster::peek_indexed_rows"); NdbOperation::LockMode lm= (NdbOperation::LockMode)get_ndb_lock_type(m_lock.type); @@ -2104,7 +2104,7 @@ int ha_ndbcluster::unique_index_read(const uchar *key, inline int ha_ndbcluster::fetch_next(NdbScanOperation* cursor) { - DBUG_ENTER("fetch_next"); + DBUG_ENTER("ha_ndbcluster::fetch_next"); int local_check; NdbTransaction *trans= m_active_trans; @@ -2213,7 +2213,7 @@ inline int ha_ndbcluster::fetch_next(NdbScanOperation* cursor) inline int ha_ndbcluster::next_result(uchar *buf) { int res; - DBUG_ENTER("next_result"); + DBUG_ENTER("ha_ndbcluster::next_result"); if (!m_active_cursor) DBUG_RETURN(HA_ERR_END_OF_FILE); @@ -2256,7 +2256,7 @@ int ha_ndbcluster::set_bounds(NdbIndexScanOperation *op, uint tot_len; uint i, j; - DBUG_ENTER("set_bounds"); + DBUG_ENTER("ha_ndbcluster::set_bounds"); DBUG_PRINT("info", ("key_parts=%d", key_parts)); for (j= 0; j <= 1; j++) @@ -2543,7 +2543,7 @@ int ha_ndbcluster::unique_index_scan(const KEY* key_info, NdbTransaction *trans= m_active_trans; part_id_range part_spec; - DBUG_ENTER("unique_index_scan"); + DBUG_ENTER("ha_ndbcluster::unique_index_scan"); DBUG_PRINT("enter", ("Starting new scan on %s", m_tabname)); NdbOperation::LockMode lm= @@ -2617,7 +2617,7 @@ int ha_ndbcluster::full_table_scan(uchar *buf) NdbTransaction *trans= m_active_trans; part_id_range part_spec; - DBUG_ENTER("full_table_scan"); + DBUG_ENTER("ha_ndbcluster::full_table_scan"); DBUG_PRINT("enter", ("Starting new scan on %s", m_tabname)); m_write_op= FALSE; @@ -2950,7 +2950,7 @@ int ha_ndbcluster::update_row(const uchar *old_data, uchar *new_data) longlong func_value; bool pk_update= (table_share->primary_key != MAX_KEY && key_cmp(table_share->primary_key, old_data, new_data)); - DBUG_ENTER("update_row"); + DBUG_ENTER("ha_ndbcluster::update_row"); m_write_op= TRUE; /* @@ -3154,7 +3154,7 @@ int ha_ndbcluster::delete_row(const uchar *record) NdbOperation *op; uint32 part_id; int error; - DBUG_ENTER("delete_row"); + DBUG_ENTER("ha_ndbcluster::delete_row"); m_write_op= TRUE; ha_statistic_increment(&SSV::ha_delete_count); @@ -3434,7 +3434,7 @@ void ha_ndbcluster::unpack_record(uchar *buf) void ha_ndbcluster::print_results() { - DBUG_ENTER("print_results"); + DBUG_ENTER("ha_ndbcluster::print_results"); #ifndef DBUG_OFF @@ -3701,7 +3701,7 @@ int ha_ndbcluster::read_range_next() int ha_ndbcluster::rnd_init(bool scan) { NdbScanOperation *cursor= m_active_cursor; - DBUG_ENTER("rnd_init"); + DBUG_ENTER("ha_ndbcluster::rnd_init"); DBUG_PRINT("enter", ("scan: %d", scan)); // Check if scan is to be restarted if (cursor) @@ -3721,7 +3721,7 @@ int ha_ndbcluster::rnd_init(bool scan) int ha_ndbcluster::close_scan() { NdbTransaction *trans= m_active_trans; - DBUG_ENTER("close_scan"); + DBUG_ENTER("ha_ndbcluster::close_scan"); m_multi_cursor= 0; if (!m_active_cursor && !m_multi_cursor) @@ -3770,14 +3770,14 @@ int ha_ndbcluster::close_scan() int ha_ndbcluster::rnd_end() { - DBUG_ENTER("rnd_end"); + DBUG_ENTER("ha_ndbcluster::rnd_end"); DBUG_RETURN(close_scan()); } int ha_ndbcluster::rnd_next(uchar *buf) { - DBUG_ENTER("rnd_next"); + DBUG_ENTER("ha_ndbcluster::rnd_next"); ha_statistic_increment(&SSV::ha_read_rnd_next_count); if (!m_active_cursor) @@ -3795,7 +3795,7 @@ int ha_ndbcluster::rnd_next(uchar *buf) int ha_ndbcluster::rnd_pos(uchar *buf, uchar *pos) { - DBUG_ENTER("rnd_pos"); + DBUG_ENTER("ha_ndbcluster::rnd_pos"); ha_statistic_increment(&SSV::ha_read_rnd_count); // The primary key for the record is stored in pos // Perform a pk_read using primary key "index" @@ -3847,7 +3847,7 @@ void ha_ndbcluster::position(const uchar *record) uchar *buff; uint key_length; - DBUG_ENTER("position"); + DBUG_ENTER("ha_ndbcluster::position"); if (table_share->primary_key != MAX_KEY) { @@ -3931,7 +3931,7 @@ void ha_ndbcluster::position(const uchar *record) int ha_ndbcluster::info(uint flag) { int result= 0; - DBUG_ENTER("info"); + DBUG_ENTER("ha_ndbcluster::info"); DBUG_PRINT("enter", ("flag: %d", flag)); if (flag & HA_STATUS_POS) @@ -4032,7 +4032,7 @@ void ha_ndbcluster::get_dynamic_partition_info(PARTITION_INFO *stat_info, int ha_ndbcluster::extra(enum ha_extra_function operation) { - DBUG_ENTER("extra"); + DBUG_ENTER("ha_ndbcluster::extra"); switch (operation) { case HA_EXTRA_IGNORE_DUP_KEY: /* Dup keys don't rollback everything*/ DBUG_PRINT("info", ("HA_EXTRA_IGNORE_DUP_KEY")); @@ -4125,7 +4125,7 @@ void ha_ndbcluster::start_bulk_insert(ha_rows rows) int bytes, batch; const NDBTAB *tab= m_table; - DBUG_ENTER("start_bulk_insert"); + DBUG_ENTER("ha_ndbcluster::start_bulk_insert"); DBUG_PRINT("enter", ("rows: %d", (int)rows)); m_rows_inserted= (ha_rows) 0; @@ -4174,7 +4174,7 @@ int ha_ndbcluster::end_bulk_insert() { int error= 0; - DBUG_ENTER("end_bulk_insert"); + DBUG_ENTER("ha_ndbcluster::end_bulk_insert"); // Check if last inserts need to be flushed if (m_bulk_insert_not_flushed) { @@ -4215,7 +4215,7 @@ int ha_ndbcluster::end_bulk_insert() int ha_ndbcluster::extra_opt(enum ha_extra_function operation, ulong cache_size) { - DBUG_ENTER("extra_opt"); + DBUG_ENTER("ha_ndbcluster::extra_opt"); DBUG_PRINT("enter", ("cache_size: %lu", cache_size)); DBUG_RETURN(extra(operation)); } @@ -4257,7 +4257,7 @@ THR_LOCK_DATA **ha_ndbcluster::store_lock(THD *thd, THR_LOCK_DATA **to, enum thr_lock_type lock_type) { - DBUG_ENTER("store_lock"); + DBUG_ENTER("ha_ndbcluster::store_lock"); if (lock_type != TL_IGNORE && m_lock.type == TL_UNLOCK) { @@ -4375,7 +4375,7 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type) { int error=0; NdbTransaction* trans= NULL; - DBUG_ENTER("external_lock"); + DBUG_ENTER("ha_ndbcluster::external_lock"); /* Check that this handler instance has a connection @@ -4591,7 +4591,7 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type) void ha_ndbcluster::unlock_row() { - DBUG_ENTER("unlock_row"); + DBUG_ENTER("ha_ndbcluster::unlock_row"); DBUG_PRINT("info", ("Unlocking row")); m_lock_tuple= FALSE; @@ -4609,7 +4609,7 @@ void ha_ndbcluster::unlock_row() int ha_ndbcluster::start_stmt(THD *thd, thr_lock_type lock_type) { int error=0; - DBUG_ENTER("start_stmt"); + DBUG_ENTER("ha_ndbcluster::start_stmt"); PRINT_OPTION_FLAGS(thd); Thd_ndb *thd_ndb= get_thd_ndb(thd); @@ -5446,7 +5446,7 @@ int ha_ndbcluster::create_handler_files(const char *file, size_t length, pack_length; int error= 0; - DBUG_ENTER("create_handler_files"); + DBUG_ENTER("ha_ndbcluster::create_handler_files"); if (action_flag != CHF_INDEX_FLAG) { @@ -6131,7 +6131,7 @@ void ha_ndbcluster::get_auto_increment(ulonglong offset, ulonglong increment, { int cache_size; Uint64 auto_value; - DBUG_ENTER("get_auto_increment"); + DBUG_ENTER("ha_ndbcluster::get_auto_increment"); DBUG_PRINT("enter", ("m_tabname: %s", m_tabname)); Ndb *ndb= get_ndb(); @@ -6238,7 +6238,7 @@ ha_ndbcluster::ha_ndbcluster(handlerton *hton, TABLE_SHARE *table_arg): { int i; - DBUG_ENTER("ha_ndbcluster"); + DBUG_ENTER("ha_ndbcluster::ha_ndbcluster"); m_tabname[0]= '\0'; m_dbname[0]= '\0'; @@ -6271,7 +6271,7 @@ ha_ndbcluster::~ha_ndbcluster() { THD *thd= current_thd; Ndb *ndb= thd ? check_ndb_in_thd(thd) : g_ndb; - DBUG_ENTER("~ha_ndbcluster"); + DBUG_ENTER("ha_ndbcluster::~ha_ndbcluster"); if (m_share) { @@ -6426,7 +6426,7 @@ void ha_ndbcluster::set_part_info(partition_info *part_info) int ha_ndbcluster::close(void) { - DBUG_ENTER("close"); + DBUG_ENTER("ha_ndbcluster::close"); THD *thd= table->in_use; Ndb *ndb= thd ? check_ndb_in_thd(thd) : g_ndb; /* ndb_share reference handler free */ @@ -6442,7 +6442,7 @@ int ha_ndbcluster::close(void) Thd_ndb* ha_ndbcluster::seize_thd_ndb() { Thd_ndb *thd_ndb; - DBUG_ENTER("seize_thd_ndb"); + DBUG_ENTER("ha_ndbcluster::seize_thd_ndb"); thd_ndb= new Thd_ndb(); if (thd_ndb == NULL) @@ -6468,7 +6468,7 @@ Thd_ndb* ha_ndbcluster::seize_thd_ndb() void ha_ndbcluster::release_thd_ndb(Thd_ndb* thd_ndb) { - DBUG_ENTER("release_thd_ndb"); + DBUG_ENTER("ha_ndbcluster::release_thd_ndb"); delete thd_ndb; DBUG_VOID_RETURN; } @@ -6498,7 +6498,7 @@ Ndb* check_ndb_in_thd(THD* thd) int ha_ndbcluster::check_ndb_connection(THD* thd) { Ndb *ndb; - DBUG_ENTER("check_ndb_connection"); + DBUG_ENTER("ha_ndbcluster::check_ndb_connection"); if (!(ndb= check_ndb_in_thd(thd))) DBUG_RETURN(HA_ERR_NO_CONNECTION); @@ -7549,7 +7549,7 @@ ha_ndbcluster::records_in_range(uint inx, key_range *min_key, uint key_length= key_info->key_length; NDB_INDEX_TYPE idx_type= get_index_type(inx); - DBUG_ENTER("records_in_range"); + DBUG_ENTER("ha_ndbcluster::records_in_range"); // Prevent partial read of hash indexes by returning HA_POS_ERROR if ((idx_type == UNIQUE_INDEX || idx_type == PRIMARY_KEY_INDEX) && ((min_key && min_key->length < key_length) || @@ -8509,7 +8509,7 @@ int ha_ndbcluster::write_ndb_file(const char *name) bool error=1; char path[FN_REFLEN]; - DBUG_ENTER("write_ndb_file"); + DBUG_ENTER("ha_ndbcluster::write_ndb_file"); DBUG_PRINT("enter", ("name: %s", name)); (void)strxnmov(path, FN_REFLEN-1, @@ -8553,7 +8553,7 @@ ha_ndbcluster::null_value_index_search(KEY_MULTI_RANGE *ranges, KEY_MULTI_RANGE *end_range, HANDLER_BUFFER *buffer) { - DBUG_ENTER("null_value_index_search"); + DBUG_ENTER("ha_ndbcluster::null_value_index_search"); KEY* key_info= table->key_info + active_index; KEY_MULTI_RANGE *range= ranges; ulong reclength= table->s->reclength; @@ -8948,7 +8948,7 @@ found_next: int ha_ndbcluster::setup_recattr(const NdbRecAttr* curr) { - DBUG_ENTER("setup_recattr"); + DBUG_ENTER("ha_ndbcluster::setup_recattr"); Field **field, **end; NdbValue *value= m_value; @@ -9319,7 +9319,7 @@ const COND* ha_ndbcluster::cond_push(const COND *cond) { - DBUG_ENTER("cond_push"); + DBUG_ENTER("ha_ndbcluster::cond_push"); if (!m_cond) m_cond= new ha_ndbcluster_cond; if (!m_cond) @@ -9554,7 +9554,7 @@ int ha_ndbcluster::set_range_data(void *tab_ref, partition_info *part_info) uint i; int error= 0; bool unsigned_flag= part_info->part_expr->unsigned_flag; - DBUG_ENTER("set_range_data"); + DBUG_ENTER("ha_ndbcluster::set_range_data"); if (!range_data) { @@ -9593,7 +9593,7 @@ int ha_ndbcluster::set_list_data(void *tab_ref, partition_info *part_info) uint32 *part_id, i; int error= 0; bool unsigned_flag= part_info->part_expr->unsigned_flag; - DBUG_ENTER("set_list_data"); + DBUG_ENTER("ha_ndbcluster::set_list_data"); if (!list_data) { @@ -9924,7 +9924,7 @@ int ndbcluster_alter_tablespace(handlerton *hton, int error; const char *errmsg; Ndb *ndb; - DBUG_ENTER("ha_ndbcluster::alter_tablespace"); + DBUG_ENTER("alter_tablespace"); LINT_INIT(errmsg); ndb= check_ndb_in_thd(thd); diff --git a/sql/records.cc b/sql/records.cc index 81c26da4b4d..0bf815e4073 100644 --- a/sql/records.cc +++ b/sql/records.cc @@ -55,6 +55,7 @@ static int rr_index(READ_RECORD *info); void init_read_record_idx(READ_RECORD *info, THD *thd, TABLE *table, bool print_error, uint idx) { + empty_record(table); bzero((char*) info,sizeof(*info)); info->table= table; info->file= table->file; @@ -161,6 +162,7 @@ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table, } else { + empty_record(table); info->record= table->record[0]; info->ref_length= table->file->ref_length; } diff --git a/sql/rpl_record.cc b/sql/rpl_record.cc index 71cc431890b..061f931436f 100644 --- a/sql/rpl_record.cc +++ b/sql/rpl_record.cc @@ -105,7 +105,8 @@ pack_row(TABLE *table, MY_BITMAP const* cols, DBUG_PRINT("debug", ("field: %s; pack_ptr: 0x%lx;" " pack_ptr':0x%lx; bytes: %d", field->field_name, (ulong) old_pack_ptr, - (ulong) pack_ptr, pack_ptr - old_pack_ptr)); + (ulong) pack_ptr, + (int) (pack_ptr - old_pack_ptr))); } null_mask <<= 1; @@ -239,7 +240,7 @@ unpack_row(Relay_log_info const *rli, " pack_ptr: 0x%lx; pack_ptr': 0x%lx; bytes: %d", f->field_name, metadata, (ulong) old_pack_ptr, (ulong) pack_ptr, - pack_ptr - old_pack_ptr)); + (int) (pack_ptr - old_pack_ptr))); } null_mask <<= 1; From 7ef34c3a707a739a2433df241f9d2dc295c4869d Mon Sep 17 00:00:00 2001 From: "mats@kindahl-laptop.dnsalias.net" <> Date: Wed, 17 Oct 2007 09:29:11 +0200 Subject: [PATCH 048/336] Removing debug variables from non-debug builds. --- sql/rpl_record.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sql/rpl_record.cc b/sql/rpl_record.cc index 061f931436f..ed0dc82cf01 100644 --- a/sql/rpl_record.cc +++ b/sql/rpl_record.cc @@ -99,7 +99,9 @@ pack_row(TABLE *table, MY_BITMAP const* cols, length is stored in little-endian format, since this is the format used for the binlog. */ +#ifndef DBUG_OFF const uchar *old_pack_ptr= pack_ptr; +#endif pack_ptr= field->pack(pack_ptr, field->ptr + offset, field->max_data_length(), TRUE); DBUG_PRINT("debug", ("field: %s; pack_ptr: 0x%lx;" @@ -234,7 +236,9 @@ unpack_row(Relay_log_info const *rli, normal unpack operation. */ uint16 const metadata= tabledef->field_metadata(i); +#ifndef DBUG_OFF uchar const *const old_pack_ptr= pack_ptr; +#endif pack_ptr= f->unpack(f->ptr, pack_ptr, metadata, TRUE); DBUG_PRINT("debug", ("field: %s; metadata: 0x%x;" " pack_ptr: 0x%lx; pack_ptr': 0x%lx; bytes: %d", From ffde32d219d7824257efc98476c310bf3ffac06b Mon Sep 17 00:00:00 2001 From: "ramil/ram@mysql.com/ramil.myoffice.izhnet.ru" <> Date: Wed, 17 Oct 2007 14:28:00 +0500 Subject: [PATCH 049/336] Fix for bug#31615: crash after set names ucs2 collate xxx Problem: currently, UCS-2 cannot be used as a client character set. Fix: raise an error if one attempts to set it to USC-2. --- mysql-test/r/ctype_ucs.result | 8 ++++++++ mysql-test/t/ctype_ucs.test | 12 ++++++++++++ sql/set_var.cc | 22 ++++++++++++++++++++++ sql/set_var.h | 1 + 4 files changed, 43 insertions(+) diff --git a/mysql-test/r/ctype_ucs.result b/mysql-test/r/ctype_ucs.result index bf827209795..befbd04f63d 100644 --- a/mysql-test/r/ctype_ucs.result +++ b/mysql-test/r/ctype_ucs.result @@ -803,4 +803,12 @@ quote(name) ???????? ???????????????? drop table bug20536; +set names ucs2; +ERROR 42000: Variable 'character_set_client' can't be set to the value of 'ucs2' +set names ucs2 collate ucs2_bin; +ERROR 42000: Variable 'character_set_client' can't be set to the value of 'ucs2' +set character_set_client= ucs2; +ERROR 42000: Variable 'character_set_client' can't be set to the value of 'ucs2' +set character_set_client= concat('ucs', substr('2', 1)); +ERROR 42000: Variable 'character_set_client' can't be set to the value of 'ucs2' End of 4.1 tests diff --git a/mysql-test/t/ctype_ucs.test b/mysql-test/t/ctype_ucs.test index 10559d33eb3..9e6bd0e95e6 100644 --- a/mysql-test/t/ctype_ucs.test +++ b/mysql-test/t/ctype_ucs.test @@ -535,4 +535,16 @@ select quote(name) from bug20536; drop table bug20536; +# +# Bug #31615: crash after set names ucs2 collate xxx +# +--error 1231 +set names ucs2; +--error 1231 +set names ucs2 collate ucs2_bin; +--error 1231 +set character_set_client= ucs2; +--error 1231 +set character_set_client= concat('ucs', substr('2', 1)); + --echo End of 4.1 tests diff --git a/sql/set_var.cc b/sql/set_var.cc index 520ee5c9f70..275252c4960 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -1992,6 +1992,21 @@ void sys_var_character_set_client::set_default(THD *thd, enum_var_type type) } +bool sys_var_character_set_client::check(THD *thd, set_var *var) +{ + if (sys_var_character_set::check(thd, var)) + return 1; + /* Currently, UCS-2 cannot be used as a client character set */ + if (var->save_result.charset->mbminlen > 1) + { + my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name, + var->save_result.charset->csname); + return 1; + } + return 0; +} + + CHARSET_INFO ** sys_var_character_set_results::ci_ptr(THD *thd, enum_var_type type) { @@ -2355,6 +2370,13 @@ end: int set_var_collation_client::check(THD *thd) { + /* Currently, UCS-2 cannot be used as a client character set */ + if (character_set_client->mbminlen > 1) + { + my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), "character_set_client", + character_set_client->csname); + return 1; + } return 0; } diff --git a/sql/set_var.h b/sql/set_var.h index 78b34963e9d..f6fd0a082b5 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -578,6 +578,7 @@ public: sys_var_character_set(name_arg) {} void set_default(THD *thd, enum_var_type type); CHARSET_INFO **ci_ptr(THD *thd, enum_var_type type); + bool check(THD *thd, set_var *var); }; class sys_var_character_set_results :public sys_var_character_set From 6d1f3e8de56e3cc861272265fc1f6119a41036a9 Mon Sep 17 00:00:00 2001 From: "kaa@polly.(none)" <> Date: Wed, 17 Oct 2007 20:08:58 +0400 Subject: [PATCH 050/336] Fix for bug #31207: Test "join_nested" shows different strategy on IA64 CPUs / Intel's ICC compile The bug is a combination of two problems: 1. IA64/ICC MySQL binaries use glibc's qsort(), not the one in mysys. 2. The order relation implemented by join_tab_cmp() is not transitive, i.e. it is possible to choose such a, b and c that (a < b) && (b < c) but (c < a). This implies that result of a sort using the relation implemented by join_tab_cmp() depends on the order in which elements are compared, i.e. the result is implementation-specific. Since choose_plan() uses qsort() to pre-sort the join tables using join_tab_cmp() as a compare function, the results of the sorting may vary depending on qsort() implementation. It is neither possible nor important to implement a better ordering algorithm in join_tab_cmp(). Therefore the only way to fix it is to force our own qsort() to be used by renaming it to my_qsort(), so we don't depend on linker to decide that. This patch also "fixes" bug #20530: qsort redefinition violates the standard. --- include/my_sys.h | 6 ++++-- libmysql/Makefile.shared | 2 +- myisam/ft_boolean_search.c | 4 ++-- myisam/ft_nlq_search.c | 3 ++- myisam/myisampack.c | 2 +- myisam/sort.c | 12 ++++++------ mysys/mf_keycache.c | 2 +- mysys/mf_qsort.c | 4 ++-- mysys/mf_sort.c | 2 +- mysys/my_lib.c | 6 +++--- mysys/queues.c | 4 ++-- sql/examples/ha_tina.cc | 2 +- sql/item_cmpfunc.cc | 2 +- sql/item_cmpfunc.h | 2 +- sql/opt_range.cc | 8 ++++---- sql/records.cc | 3 ++- sql/sql_acl.cc | 20 ++++++++++---------- sql/sql_array.h | 2 +- sql/sql_help.cc | 2 +- sql/sql_select.cc | 18 +++++++++++++++--- sql/sql_table.cc | 2 +- 21 files changed, 62 insertions(+), 46 deletions(-) diff --git a/include/my_sys.h b/include/my_sys.h index 4f7e75a836e..d401cfca082 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -709,8 +709,10 @@ extern sig_handler my_set_alarm_variable(int signo); extern void my_string_ptr_sort(void *base,uint items,size_s size); extern void radixsort_for_str_ptr(uchar* base[], uint number_of_elements, size_s size_of_element,uchar *buffer[]); -extern qsort_t qsort2(void *base_ptr, size_t total_elems, size_t size, - qsort2_cmp cmp, void *cmp_argument); +extern qsort_t my_qsort(void *base_ptr, size_t total_elems, size_t size, + qsort_cmp cmp); +extern qsort_t my_qsort2(void *base_ptr, size_t total_elems, size_t size, + qsort2_cmp cmp, void *cmp_argument); extern qsort2_cmp get_ptr_compare(uint); void my_store_ptr(byte *buff, uint pack_length, my_off_t pos); my_off_t my_get_ptr(byte *ptr, uint pack_length); diff --git a/libmysql/Makefile.shared b/libmysql/Makefile.shared index dc6d658fcdf..5947ae26486 100644 --- a/libmysql/Makefile.shared +++ b/libmysql/Makefile.shared @@ -73,7 +73,7 @@ sqlobjects = net.lo sql_cmn_objects = pack.lo client.lo my_time.lo # Not needed in the minimum library -mysysobjects2 = my_lib.lo +mysysobjects2 = my_lib.lo mf_qsort.lo mysysobjects = $(mysysobjects1) $(mysysobjects2) target_libadd = $(mysysobjects) $(mystringsobjects) $(dbugobjects) \ $(sql_cmn_objects) $(vio_objects) $(sqlobjects) diff --git a/myisam/ft_boolean_search.c b/myisam/ft_boolean_search.c index 9f442148069..57de75ee4be 100644 --- a/myisam/ft_boolean_search.c +++ b/myisam/ft_boolean_search.c @@ -430,8 +430,8 @@ FT_INFO * ft_init_boolean_search(MI_INFO *info, uint keynr, byte *query, ftb->list=(FTB_WORD **)alloc_root(&ftb->mem_root, sizeof(FTB_WORD *)*ftb->queue.elements); memcpy(ftb->list, ftb->queue.root+1, sizeof(FTB_WORD *)*ftb->queue.elements); - qsort2(ftb->list, ftb->queue.elements, sizeof(FTB_WORD *), - (qsort2_cmp)FTB_WORD_cmp_list, ftb->charset); + my_qsort2(ftb->list, ftb->queue.elements, sizeof(FTB_WORD *), + (qsort2_cmp)FTB_WORD_cmp_list, ftb->charset); if (ftb->queue.elements<2) ftb->with_scan &= ~FTB_FLAG_TRUNC; ftb->state=READY; return ftb; diff --git a/myisam/ft_nlq_search.c b/myisam/ft_nlq_search.c index f63735b7e68..41d145c070f 100644 --- a/myisam/ft_nlq_search.c +++ b/myisam/ft_nlq_search.c @@ -281,7 +281,8 @@ FT_INFO *ft_init_nlq_search(MI_INFO *info, uint keynr, byte *query, &dptr, left_root_right); if (flags & FT_SORTED) - qsort2(dlist->doc, dlist->ndocs, sizeof(FT_DOC), (qsort2_cmp)&FT_DOC_cmp, 0); + my_qsort2(dlist->doc, dlist->ndocs, sizeof(FT_DOC), (qsort2_cmp)&FT_DOC_cmp, + 0); err: delete_tree(&aio.dtree); diff --git a/myisam/myisampack.c b/myisam/myisampack.c index 4ead51639f3..fa58211ea88 100644 --- a/myisam/myisampack.c +++ b/myisam/myisampack.c @@ -3148,7 +3148,7 @@ static void fakebigcodes(HUFF_COUNTS *huff_counts, HUFF_COUNTS *end_count) cur_sort_p= sort_counts; while (cur_count_p < end_count_p) *(cur_sort_p++)= cur_count_p++; - (void) qsort(sort_counts, 256, sizeof(my_off_t*), (qsort_cmp) fakecmp); + (void) my_qsort(sort_counts, 256, sizeof(my_off_t*), (qsort_cmp) fakecmp); /* Assign faked counts. diff --git a/myisam/sort.c b/myisam/sort.c index f48161b7c8e..c44b05313b0 100644 --- a/myisam/sort.c +++ b/myisam/sort.c @@ -649,8 +649,8 @@ static int NEAR_F write_keys(MI_SORT_PARAM *info, register uchar **sort_keys, uint sort_length=info->key_length; DBUG_ENTER("write_keys"); - qsort2((byte*) sort_keys,count,sizeof(byte*),(qsort2_cmp) info->key_cmp, - info); + my_qsort2((byte*) sort_keys,count,sizeof(byte*),(qsort2_cmp) info->key_cmp, + info); if (!my_b_inited(tempfile) && open_cached_file(tempfile, my_tmpdir(info->tmpdir), "ST", DISK_BUFFER_SIZE, info->sort_info->param->myf_rw)) @@ -692,8 +692,8 @@ static int NEAR_F write_keys_varlen(MI_SORT_PARAM *info, int err; DBUG_ENTER("write_keys_varlen"); - qsort2((byte*) sort_keys,count,sizeof(byte*),(qsort2_cmp) info->key_cmp, - info); + my_qsort2((byte*) sort_keys,count,sizeof(byte*),(qsort2_cmp) info->key_cmp, + info); if (!my_b_inited(tempfile) && open_cached_file(tempfile, my_tmpdir(info->tmpdir), "ST", DISK_BUFFER_SIZE, info->sort_info->param->myf_rw)) @@ -735,8 +735,8 @@ static int NEAR_F write_index(MI_SORT_PARAM *info, register uchar **sort_keys, { DBUG_ENTER("write_index"); - qsort2((gptr) sort_keys,(size_t) count,sizeof(byte*), - (qsort2_cmp) info->key_cmp,info); + my_qsort2((gptr) sort_keys,(size_t) count,sizeof(byte*), + (qsort2_cmp) info->key_cmp,info); while (count--) { if ((*info->key_write)(info,*sort_keys++)) diff --git a/mysys/mf_keycache.c b/mysys/mf_keycache.c index 83363e6960d..baf3bffccb8 100644 --- a/mysys/mf_keycache.c +++ b/mysys/mf_keycache.c @@ -2268,7 +2268,7 @@ static int flush_cached_blocks(KEY_CACHE *keycache, As all blocks referred in 'cache' are marked by BLOCK_IN_FLUSH we are guarunteed no thread will change them */ - qsort((byte*) cache, count, sizeof(*cache), (qsort_cmp) cmp_sec_link); + my_qsort((byte*) cache, count, sizeof(*cache), (qsort_cmp) cmp_sec_link); keycache_pthread_mutex_lock(&keycache->cache_lock); for ( ; cache != end ; cache++) diff --git a/mysys/mf_qsort.c b/mysys/mf_qsort.c index 3d52d56c952..4b3ecb603a6 100644 --- a/mysys/mf_qsort.c +++ b/mysys/mf_qsort.c @@ -91,10 +91,10 @@ typedef struct st_stack *****************************************************************************/ #ifdef QSORT_EXTRA_CMP_ARGUMENT -qsort_t qsort2(void *base_ptr, size_t count, size_t size, qsort2_cmp cmp, +qsort_t my_qsort2(void *base_ptr, size_t count, size_t size, qsort2_cmp cmp, void *cmp_argument) #else -qsort_t qsort(void *base_ptr, size_t count, size_t size, qsort_cmp cmp) +qsort_t my_qsort(void *base_ptr, size_t count, size_t size, qsort_cmp cmp) #endif { char *low, *high, *pivot; diff --git a/mysys/mf_sort.c b/mysys/mf_sort.c index e7fd6873eee..a0c74642cb0 100644 --- a/mysys/mf_sort.c +++ b/mysys/mf_sort.c @@ -35,7 +35,7 @@ void my_string_ptr_sort(void *base, uint items, size_s size) if (size && items) { uint size_arg=size; - qsort2(base,items,sizeof(byte*),get_ptr_compare(size),(void*) &size_arg); + my_qsort2(base,items,sizeof(byte*),get_ptr_compare(size),(void*) &size_arg); } } } diff --git a/mysys/my_lib.c b/mysys/my_lib.c index 61de4ff9065..a076a0c971d 100644 --- a/mysys/my_lib.c +++ b/mysys/my_lib.c @@ -187,7 +187,7 @@ MY_DIR *my_dir(const char *path, myf MyFlags) result->number_off_files= dir_entries_storage->elements; if (!(MyFlags & MY_DONT_SORT)) - qsort((void *) result->dir_entry, result->number_off_files, + my_qsort((void *) result->dir_entry, result->number_off_files, sizeof(FILEINFO), (qsort_cmp) comp_names); DBUG_RETURN(result); @@ -498,7 +498,7 @@ MY_DIR *my_dir(const char *path, myf MyFlags) result->number_off_files= dir_entries_storage->elements; if (!(MyFlags & MY_DONT_SORT)) - qsort((void *) result->dir_entry, result->number_off_files, + my_qsort((void *) result->dir_entry, result->number_off_files, sizeof(FILEINFO), (qsort_cmp) comp_names); DBUG_PRINT("exit", ("found %d files", result->number_off_files)); DBUG_RETURN(result); @@ -605,7 +605,7 @@ MY_DIR *my_dir(const char* path, myf MyFlags) result->number_off_files= dir_entries_storage->elements; if (!(MyFlags & MY_DONT_SORT)) - qsort((void *) result->dir_entry, result->number_off_files, + my_qsort((void *) result->dir_entry, result->number_off_files, sizeof(FILEINFO), (qsort_cmp) comp_names); DBUG_RETURN(result); diff --git a/mysys/queues.c b/mysys/queues.c index 7809c97131c..6b88420a1cd 100644 --- a/mysys/queues.c +++ b/mysys/queues.c @@ -250,6 +250,6 @@ static int queue_fix_cmp(QUEUE *queue, void **a, void **b) void queue_fix(QUEUE *queue) { - qsort2(queue->root+1,queue->elements, sizeof(void *), - (qsort2_cmp)queue_fix_cmp, queue); + my_qsort2(queue->root+1,queue->elements, sizeof(void *), + (qsort2_cmp)queue_fix_cmp, queue); } diff --git a/sql/examples/ha_tina.cc b/sql/examples/ha_tina.cc index 2c5226222e2..0d1d821cf17 100644 --- a/sql/examples/ha_tina.cc +++ b/sql/examples/ha_tina.cc @@ -852,7 +852,7 @@ int ha_tina::rnd_end() It also sorts so that we move the final blocks to the beginning so that we move the smallest amount of data possible. */ - qsort(chain, (size_t)(chain_ptr - chain), sizeof(tina_set), (qsort_cmp)sort_set); + my_qsort(chain, (size_t)(chain_ptr - chain), sizeof(tina_set), (qsort_cmp)sort_set); for (ptr= chain; ptr < chain_ptr; ptr++) { memmove(share->mapped_file + ptr->begin, share->mapped_file + ptr->end, diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 86eb10d50b0..45ed61a2ab7 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -2775,7 +2775,7 @@ static inline int cmp_ulongs (ulonglong a_val, ulonglong b_val) SYNOPSIS cmp_longlong() - cmp_arg an argument passed to the calling function (qsort2) + cmp_arg an argument passed to the calling function (my_qsort2) a left argument b right argument diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 8410c66b034..2ea155b3fac 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -781,7 +781,7 @@ public: virtual byte *get_value(Item *item)=0; void sort() { - qsort2(base,used_count,size,compare,collation); + my_qsort2(base,used_count,size,compare,collation); } int find(Item *item); diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 04e2816d553..c3e9b6638bd 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -3159,8 +3159,8 @@ TRP_ROR_INTERSECT *get_best_ror_intersect(const PARAM *param, SEL_TREE *tree, ROR_SCAN_INFO's. Step 2: Get best ROR-intersection using an approximate algorithm. */ - qsort(tree->ror_scans, tree->n_ror_scans, sizeof(ROR_SCAN_INFO*), - (qsort_cmp)cmp_ror_scan_info); + my_qsort(tree->ror_scans, tree->n_ror_scans, sizeof(ROR_SCAN_INFO*), + (qsort_cmp)cmp_ror_scan_info); DBUG_EXECUTE("info",print_ror_scans_arr(param->table, "ordered", tree->ror_scans, tree->ror_scans_end);); @@ -3349,8 +3349,8 @@ TRP_ROR_INTERSECT *get_best_covering_ror_intersect(PARAM *param, bitmap_get_first(&(*scan)->covered_fields); } - qsort(ror_scan_mark, ror_scans_end-ror_scan_mark, sizeof(ROR_SCAN_INFO*), - (qsort_cmp)cmp_ror_scan_info_covering); + my_qsort(ror_scan_mark, ror_scans_end-ror_scan_mark, sizeof(ROR_SCAN_INFO*), + (qsort_cmp)cmp_ror_scan_info_covering); DBUG_EXECUTE("info", print_ror_scans_arr(param->table, "remaining scans", diff --git a/sql/records.cc b/sql/records.cc index 3a833c87b7b..f61efc13034 100644 --- a/sql/records.cc +++ b/sql/records.cc @@ -497,7 +497,8 @@ static int rr_from_cache(READ_RECORD *info) int3store(ref_position,(long) i); ref_position+=3; } - qsort(info->read_positions,length,info->struct_length,(qsort_cmp) rr_cmp); + my_qsort(info->read_positions, length, info->struct_length, + (qsort_cmp) rr_cmp); position=info->read_positions; for (i=0 ; i < length ; i++) diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index f9bd2c6ba0d..d5257b1076a 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -248,8 +248,8 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables) #endif VOID(push_dynamic(&acl_hosts,(gptr) &host)); } - qsort((gptr) dynamic_element(&acl_hosts,0,ACL_HOST*),acl_hosts.elements, - sizeof(ACL_HOST),(qsort_cmp) acl_compare); + my_qsort((gptr) dynamic_element(&acl_hosts,0,ACL_HOST*),acl_hosts.elements, + sizeof(ACL_HOST),(qsort_cmp) acl_compare); end_read_record(&read_record_info); freeze_size(&acl_hosts); @@ -421,8 +421,8 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables) allow_all_hosts=1; // Anyone can connect } } - qsort((gptr) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements, - sizeof(ACL_USER),(qsort_cmp) acl_compare); + my_qsort((gptr) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements, + sizeof(ACL_USER),(qsort_cmp) acl_compare); end_read_record(&read_record_info); freeze_size(&acl_users); @@ -479,8 +479,8 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables) #endif VOID(push_dynamic(&acl_dbs,(gptr) &db)); } - qsort((gptr) dynamic_element(&acl_dbs,0,ACL_DB*),acl_dbs.elements, - sizeof(ACL_DB),(qsort_cmp) acl_compare); + my_qsort((gptr) dynamic_element(&acl_dbs,0,ACL_DB*),acl_dbs.elements, + sizeof(ACL_DB),(qsort_cmp) acl_compare); end_read_record(&read_record_info); freeze_size(&acl_dbs); init_check_host(); @@ -1110,8 +1110,8 @@ static void acl_insert_user(const char *user, const char *host, if (!acl_user.host.hostname || (acl_user.host.hostname[0] == wild_many && !acl_user.host.hostname[1])) allow_all_hosts=1; // Anyone can connect /* purecov: tested */ - qsort((gptr) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements, - sizeof(ACL_USER),(qsort_cmp) acl_compare); + my_qsort((gptr) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements, + sizeof(ACL_USER),(qsort_cmp) acl_compare); /* Rebuild 'acl_check_hosts' since 'acl_users' has been modified */ rebuild_check_host(); @@ -1173,8 +1173,8 @@ static void acl_insert_db(const char *user, const char *host, const char *db, acl_db.access=privileges; acl_db.sort=get_sort(3,acl_db.host.hostname,acl_db.db,acl_db.user); VOID(push_dynamic(&acl_dbs,(gptr) &acl_db)); - qsort((gptr) dynamic_element(&acl_dbs,0,ACL_DB*),acl_dbs.elements, - sizeof(ACL_DB),(qsort_cmp) acl_compare); + my_qsort((gptr) dynamic_element(&acl_dbs,0,ACL_DB*),acl_dbs.elements, + sizeof(ACL_DB),(qsort_cmp) acl_compare); } diff --git a/sql/sql_array.h b/sql/sql_array.h index e2e12bee241..dcef457dce7 100644 --- a/sql/sql_array.h +++ b/sql/sql_array.h @@ -62,7 +62,7 @@ public: void sort(CMP_FUNC cmp_func) { - qsort(array.buffer, array.elements, sizeof(Elem), (qsort_cmp)cmp_func); + my_qsort(array.buffer, array.elements, sizeof(Elem), (qsort_cmp)cmp_func); } }; diff --git a/sql/sql_help.cc b/sql/sql_help.cc index ba7f1a534ea..69a257a9d37 100644 --- a/sql/sql_help.cc +++ b/sql/sql_help.cc @@ -524,7 +524,7 @@ int send_variant_2_list(MEM_ROOT *mem_root, Protocol *protocol, List_iterator it(*names); for (pos= pointers; pos!=end; (*pos++= it++)); - qsort(pointers,names->elements,sizeof(String*),string_ptr_cmp); + my_qsort(pointers,names->elements,sizeof(String*),string_ptr_cmp); for (pos= pointers; pos!=end; pos++) { diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 1d11f23d854..b519c06420f 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -3658,7 +3658,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab, { KEYUSE key_end,*prev,*save_pos,*use; - qsort(keyuse->buffer,keyuse->elements,sizeof(KEYUSE), + my_qsort(keyuse->buffer,keyuse->elements,sizeof(KEYUSE), (qsort_cmp) sort_keyuse); bzero((char*) &key_end,sizeof(key_end)); /* Add for easy testing */ @@ -4371,8 +4371,9 @@ choose_plan(JOIN *join, table_map join_tables) Apply heuristic: pre-sort all access plans with respect to the number of records accessed. */ - qsort(join->best_ref + join->const_tables, join->tables - join->const_tables, - sizeof(JOIN_TAB*), straight_join?join_tab_cmp_straight:join_tab_cmp); + my_qsort(join->best_ref + join->const_tables, + join->tables - join->const_tables, sizeof(JOIN_TAB*), + straight_join ? join_tab_cmp_straight : join_tab_cmp); if (straight_join) { @@ -4421,6 +4422,17 @@ choose_plan(JOIN *join, table_map join_tables) ptr1 pointer to first JOIN_TAB object ptr2 pointer to second JOIN_TAB object + NOTES + The order relation implemented by join_tab_cmp() is not transitive, + i.e. it is possible to choose such a, b and c that (a < b) && (b < c) + but (c < a). This implies that result of a sort using the relation + implemented by join_tab_cmp() depends on the order in which + elements are compared, i.e. the result is implementation-specific. + Example: + a: dependent = 0x0 table->map = 0x1 found_records = 3 ptr = 0x907e6b0 + b: dependent = 0x0 table->map = 0x2 found_records = 3 ptr = 0x907e838 + c: dependent = 0x6 table->map = 0x10 found_records = 2 ptr = 0x907ecd0 + RETURN 1 if first is bigger -1 if second is bigger diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 6cbe98fe862..b6e41788ef0 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1476,7 +1476,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, DBUG_RETURN(-1); } /* Sort keys in optimized order */ - qsort((gptr) *key_info_buffer, *key_count, sizeof(KEY), + my_qsort((gptr) *key_info_buffer, *key_count, sizeof(KEY), (qsort_cmp) sort_keys); create_info->null_bits= null_fields; From 7c16fd2c0f9eb167b841b94241d8083ec1d6c984 Mon Sep 17 00:00:00 2001 From: "mattiasj@mattiasj-laptop.(none)" <> Date: Wed, 17 Oct 2007 20:40:23 +0200 Subject: [PATCH 051/336] Bug #30878: Crashing when alter an auto_increment non partitioned table to partitioned Problem: Crashed because usage of an uninitialised mutex when auto_incrementing a partitioned temporary table Fix: Only locking (using the mutex) if not temporary table. --- mysql-test/r/partition.result | 12 ++++++++++++ mysql-test/t/partition.test | 18 ++++++++++++++++++ sql/ha_partition.cc | 20 +++++++++++++++----- 3 files changed, 45 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/partition.result b/mysql-test/r/partition.result index f90f3b07d70..753a2e31632 100644 --- a/mysql-test/r/partition.result +++ b/mysql-test/r/partition.result @@ -1,4 +1,16 @@ drop table if exists t1; +create table t1 (id int auto_increment, s1 int, primary key (id)); +insert into t1 values (null,1); +insert into t1 values (null,6); +select * from t1; +id s1 +1 1 +2 6 +alter table t1 partition by range (id) ( +partition p0 values less than (3), +partition p1 values less than maxvalue +); +drop table t1; create table t1 (a int) partition by key(a) partitions 0.2+e1; diff --git a/mysql-test/t/partition.test b/mysql-test/t/partition.test index f391237a4db..929d3ecce9e 100644 --- a/mysql-test/t/partition.test +++ b/mysql-test/t/partition.test @@ -9,6 +9,24 @@ drop table if exists t1; --enable_warnings +# +# Bug 30878: crashing when alter an auto_increment non partitioned +# table to partitioned + +create table t1 (id int auto_increment, s1 int, primary key (id)); + +insert into t1 values (null,1); +insert into t1 values (null,6); + +select * from t1; + +alter table t1 partition by range (id) ( + partition p0 values less than (3), + partition p1 values less than maxvalue +); + +drop table t1; + # # Bug 15890: Strange number of partitions accepted # diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 1150cf41417..81d75c58d05 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -2678,7 +2678,8 @@ int ha_partition::write_row(uchar * buf) uint32 part_id; int error; longlong func_value; - bool autoincrement_lock= false; + bool autoincrement_lock= FALSE; + my_bitmap_map *old_map; #ifdef NOT_NEEDED uchar *rec0= m_rec0; #endif @@ -2705,8 +2706,17 @@ int ha_partition::write_row(uchar * buf) use autoincrement_lock variable to avoid unnecessary locks. Probably not an ideal solution. */ - autoincrement_lock= true; - pthread_mutex_lock(&table_share->mutex); + if (table_share->tmp_table == NO_TMP_TABLE) + { + /* + Bug#30878 crash when alter table from non partitioned table + to partitioned. + Checking if tmp table then there is no need to lock, + and the table_share->mutex may not be initialised. + */ + autoincrement_lock= TRUE; + pthread_mutex_lock(&table_share->mutex); + } error= update_auto_increment(); /* @@ -2715,10 +2725,10 @@ int ha_partition::write_row(uchar * buf) the correct partition. We must check and fail if neccessary. */ if (error) - DBUG_RETURN(error); + goto exit; } - my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set); + old_map= dbug_tmp_use_all_columns(table, table->read_set); #ifdef NOT_NEEDED if (likely(buf == rec0)) #endif From 04b1c9ca40edcce1dc0dfcc00b65a0971efb18f8 Mon Sep 17 00:00:00 2001 From: "kaa@polly.(none)" <> Date: Thu, 18 Oct 2007 15:17:21 +0400 Subject: [PATCH 052/336] Post-merge changes for bug #31207: Test "join_nested" shows different strategy on IA64 CPUs / Intel's ICC compiler. --- include/my_sys.h | 2 +- sql/partition_info.cc | 4 ++-- sql/set_var.cc | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/include/my_sys.h b/include/my_sys.h index e919ed75541..638b1f4a2d4 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -784,7 +784,7 @@ extern int get_index_dynamic(DYNAMIC_ARRAY *array, uchar * element); #define dynamic_element(array,array_index,type) ((type)((array)->buffer) +(array_index)) #define push_dynamic(A,B) insert_dynamic((A),(B)) #define reset_dynamic(array) ((array)->elements= 0) -#define sort_dynamic(A,cmp) qsort((A)->buffer, (A)->elements, (A)->size_of_element, (cmp)) +#define sort_dynamic(A,cmp) my_qsort((A)->buffer, (A)->elements, (A)->size_of_element, (cmp)) extern my_bool init_dynamic_string(DYNAMIC_STRING *str, const char *init_str, size_t init_alloc,size_t alloc_increment); diff --git a/sql/partition_info.cc b/sql/partition_info.cc index ab887d5dda0..86d50cdf524 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -666,8 +666,8 @@ bool partition_info::check_list_constants() if (fixed && no_list_values) { bool first= TRUE; - qsort((void*)list_array, no_list_values, sizeof(LIST_PART_ENTRY), - &list_part_cmp); + my_qsort((void*)list_array, no_list_values, sizeof(LIST_PART_ENTRY), + &list_part_cmp); i= 0; LINT_INIT(prev_value); diff --git a/sql/set_var.cc b/sql/set_var.cc index ec82b56d793..9a6ad9ce662 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -2900,7 +2900,8 @@ SHOW_VAR* enumerate_sys_vars(THD *thd, bool sorted) /* sort into order */ if (sorted) - qsort(result, count + fixed_count, sizeof(SHOW_VAR), (qsort_cmp)show_cmp); + my_qsort(result, count + fixed_count, sizeof(SHOW_VAR), + (qsort_cmp) show_cmp); /* make last element empty */ bzero(show, sizeof(SHOW_VAR)); From 525fe23acd6772f92ed1bd7840eff2fbbc862e6d Mon Sep 17 00:00:00 2001 From: "msvensson@pilot.mysql.com" <> Date: Thu, 18 Oct 2007 21:48:16 +0200 Subject: [PATCH 053/336] Remove unportable use of "system rm" --- mysql-test/t/binlog_killed.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/t/binlog_killed.test b/mysql-test/t/binlog_killed.test index 034895f17cb..e0b2f0a3db6 100644 --- a/mysql-test/t/binlog_killed.test +++ b/mysql-test/t/binlog_killed.test @@ -242,7 +242,7 @@ drop function bug27563; drop function bug27565; } -system rm $MYSQLTEST_VARDIR/tmp/kill_query_calling_sp.binlog ; +remove_file $MYSQLTEST_VARDIR/tmp/kill_query_calling_sp.binlog ; drop table t1,t2,t3; From b4f558419ff3b603fbd29adfa085f2d2c8f4b379 Mon Sep 17 00:00:00 2001 From: "ramil/ram@mysql.com/ramil.myoffice.izhnet.ru" <> Date: Fri, 19 Oct 2007 14:54:05 +0500 Subject: [PATCH 054/336] Fix for bug #31349: ERROR 1062 (23000): Duplicate entry '' for key 'group_key' Problem: lying to the optimizer that a function (Item_func_inet_ntoa) cannot return NULL values leads to unexpected results (in the case group keys creation/comparison is broken). Fix: Item_func_inet_ntoa::maybe_null should be set properly. --- mysql-test/r/func_misc.result | 6 ++++++ mysql-test/t/func_misc.test | 8 ++++++++ sql/item_strfunc.h | 7 ++++++- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/func_misc.result b/mysql-test/r/func_misc.result index 35101e26ff6..db2490bd261 100644 --- a/mysql-test/r/func_misc.result +++ b/mysql-test/r/func_misc.result @@ -185,4 +185,10 @@ ERROR 21000: Operand should contain 1 column(s) drop table table_26093; drop function func_26093_a; drop function func_26093_b; +create table t1 (a int not null); +insert into t1 values (-1), (-2); +select min(a) from t1 group by inet_ntoa(a); +min(a) +-2 +drop table t1; End of 5.0 tests diff --git a/mysql-test/t/func_misc.test b/mysql-test/t/func_misc.test index 8ff62f68e45..5a70daa50e8 100644 --- a/mysql-test/t/func_misc.test +++ b/mysql-test/t/func_misc.test @@ -189,4 +189,12 @@ drop table table_26093; drop function func_26093_a; drop function func_26093_b; +# +# Bug #31349: ERROR 1062 (23000): Duplicate entry '' for key 'group_key' +# +create table t1 (a int not null); +insert into t1 values (-1), (-2); +select min(a) from t1 group by inet_ntoa(a); +drop table t1; + --echo End of 5.0 tests diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 6ca0b89a22b..4ffd8125422 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -683,7 +683,12 @@ public: } String* val_str(String* str); const char *func_name() const { return "inet_ntoa"; } - void fix_length_and_dec() { decimals = 0; max_length=3*8+7; } + void fix_length_and_dec() + { + decimals= 0; + max_length= 3 * 8 + 7; + maybe_null= 1; + } }; class Item_func_quote :public Item_str_func From f2ba11c327c99c3e1c56a58967ea9f3da1deef3c Mon Sep 17 00:00:00 2001 From: "mats@kindahl-laptop.dnsalias.net" <> Date: Fri, 19 Oct 2007 14:18:41 +0200 Subject: [PATCH 055/336] BUG#28618 (Skipping into the middle of a group with SQL_SLAVE_SKIP_COUNTER is possible): When skipping the beginning of a transaction starting with BEGIN, the OPTION_BEGIN flag was not set correctly, which caused the slave to not recognize that it was inside a group. This patch sets the OPTION_BEGIN flag for BEGIN, COMMIT, ROLLBACK, and XID events. It also adds checks if inside a group before decreasing the slave skip counter to zero. Begin_query_log_event was not marked that it could not end a group, which is now corrected. --- .../extra/rpl_tests/rpl_extraSlave_Col.test | 4 +- mysql-test/suite/rpl/data/rpl_bug28618.dat | 3 + mysql-test/suite/rpl/r/rpl_slave_skip.result | 208 +++++++++++++++ .../suite/rpl/t/rpl_slave_skip-slave.opt | 1 + mysql-test/suite/rpl/t/rpl_slave_skip.test | 239 ++++++++++++++++++ .../suite/rpl_ndb/r/rpl_ndb_extraCol.result | 2 +- sql/log_event.cc | 81 ++++-- sql/log_event.h | 25 ++ sql/rpl_rli.h | 12 + sql/slave.cc | 5 +- 10 files changed, 560 insertions(+), 20 deletions(-) create mode 100644 mysql-test/suite/rpl/data/rpl_bug28618.dat create mode 100644 mysql-test/suite/rpl/t/rpl_slave_skip-slave.opt diff --git a/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test b/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test index a4ac55cc2e8..72013fe7ce8 100644 --- a/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test +++ b/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test @@ -736,7 +736,7 @@ connection slave; --replace_result $MASTER_MYPORT MASTER_PORT --replace_column 1 # 4 # 7 # 8 # 9 # 16 # 22 # 23 # 33 # 35 # 36 # --query_vertical SHOW SLAVE STATUS -SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; START SLAVE; --echo *** Try to insert in master **** @@ -744,6 +744,8 @@ connection master; INSERT INTO t15 () VALUES(5,2.00,'Replication Testing',@b1,'Buda',2); SELECT * FROM t15 ORDER BY c1; +#SHOW BINLOG EVENTS; + --echo *** Try to select from slave **** sync_slave_with_master; --replace_column 7 CURRENT_TIMESTAMP diff --git a/mysql-test/suite/rpl/data/rpl_bug28618.dat b/mysql-test/suite/rpl/data/rpl_bug28618.dat new file mode 100644 index 00000000000..b800c4dd39d --- /dev/null +++ b/mysql-test/suite/rpl/data/rpl_bug28618.dat @@ -0,0 +1,3 @@ +1|master only +2|master only +3|master only diff --git a/mysql-test/suite/rpl/r/rpl_slave_skip.result b/mysql-test/suite/rpl/r/rpl_slave_skip.result index 8e492fe4732..f89fa34e319 100644 --- a/mysql-test/suite/rpl/r/rpl_slave_skip.result +++ b/mysql-test/suite/rpl/r/rpl_slave_skip.result @@ -142,3 +142,211 @@ Last_SQL_Errno 0 Last_SQL_Error **** On Master **** DROP TABLE t1, t2; +SET SESSION BINLOG_FORMAT=ROW; +SET AUTOCOMMIT=0; +CREATE TABLE t1 (a INT, b VARCHAR(20)) ENGINE=myisam; +CREATE TABLE t2 (a INT, b VARCHAR(20)) ENGINE=myisam; +CREATE TABLE t3 (a INT, b VARCHAR(20)) ENGINE=myisam; +INSERT INTO t1 VALUES (1,'master/slave'); +INSERT INTO t2 VALUES (1,'master/slave'); +INSERT INTO t3 VALUES (1,'master/slave'); +CREATE TRIGGER tr1 AFTER UPDATE on t1 FOR EACH ROW +BEGIN +INSERT INTO t2 VALUES (NEW.a,NEW.b); +DELETE FROM t2 WHERE a < NEW.a; +END| +CREATE TRIGGER tr2 AFTER INSERT on t2 FOR EACH ROW +BEGIN +UPDATE t3 SET a =2, b = 'master only'; +END| +**** On Slave **** +STOP SLAVE; +**** On Master **** +UPDATE t1 SET a = 2, b = 'master only' WHERE a = 1; +DROP TRIGGER tr1; +DROP TRIGGER tr2; +INSERT INTO t1 VALUES (3,'master/slave'); +INSERT INTO t2 VALUES (3,'master/slave'); +INSERT INTO t3 VALUES (3,'master/slave'); +SELECT * FROM t1 ORDER BY a; +a b +2 master only +3 master/slave +SELECT * FROM t2 ORDER BY a; +a b +2 master only +3 master/slave +SELECT * FROM t3 ORDER BY a; +a b +2 master only +3 master/slave +*** On Slave *** +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; +START SLAVE; +SELECT * FROM t1 ORDER BY a; +a b +1 master/slave +3 master/slave +SELECT * FROM t2 ORDER BY a; +a b +1 master/slave +3 master/slave +SELECT * FROM t3 ORDER BY a; +a b +1 master/slave +3 master/slave +DROP TABLE t1, t2, t3; +**** Case 2: Row binlog format and transactional tables **** +*** On Master *** +CREATE TABLE t4 (a INT, b VARCHAR(20)) ENGINE=innodb; +CREATE TABLE t5 (a INT, b VARCHAR(20)) ENGINE=innodb; +CREATE TABLE t6 (a INT, b VARCHAR(20)) ENGINE=innodb; +**** On Slave **** +STOP SLAVE; +*** On Master *** +BEGIN; +INSERT INTO t4 VALUES (2, 'master only'); +INSERT INTO t5 VALUES (2, 'master only'); +INSERT INTO t6 VALUES (2, 'master only'); +COMMIT; +BEGIN; +INSERT INTO t4 VALUES (3, 'master/slave'); +INSERT INTO t5 VALUES (3, 'master/slave'); +INSERT INTO t6 VALUES (3, 'master/slave'); +COMMIT; +SELECT * FROM t4 ORDER BY a; +a b +2 master only +3 master/slave +SELECT * FROM t5 ORDER BY a; +a b +2 master only +3 master/slave +SELECT * FROM t6 ORDER BY a; +a b +2 master only +3 master/slave +*** On Slave *** +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; +START SLAVE; +SELECT * FROM t4 ORDER BY a; +a b +3 master/slave +SELECT * FROM t5 ORDER BY a; +a b +3 master/slave +SELECT * FROM t6 ORDER BY a; +a b +3 master/slave +**** On Slave **** +STOP SLAVE; +*** On Master *** +BEGIN; +INSERT INTO t4 VALUES (6, 'master only'); +INSERT INTO t5 VALUES (6, 'master only'); +INSERT INTO t6 VALUES (6, 'master only'); +COMMIT; +BEGIN; +INSERT INTO t4 VALUES (7, 'master only'); +INSERT INTO t5 VALUES (7, 'master only'); +INSERT INTO t6 VALUES (7, 'master only'); +COMMIT; +SELECT * FROM t4 ORDER BY a; +a b +2 master only +3 master/slave +6 master only +7 master only +SELECT * FROM t5 ORDER BY a; +a b +2 master only +3 master/slave +6 master only +7 master only +SELECT * FROM t6 ORDER BY a; +a b +2 master only +3 master/slave +6 master only +7 master only +*** On Slave *** +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=10; +START SLAVE; +SELECT * FROM t4 ORDER BY a; +a b +3 master/slave +SELECT * FROM t5 ORDER BY a; +a b +3 master/slave +SELECT * FROM t6 ORDER BY a; +a b +3 master/slave +STOP SLAVE; +SET AUTOCOMMIT=0; +INSERT INTO t4 VALUES (4, 'master only'); +INSERT INTO t5 VALUES (4, 'master only'); +INSERT INTO t6 VALUES (4, 'master only'); +COMMIT; +INSERT INTO t4 VALUES (5, 'master/slave'); +INSERT INTO t5 VALUES (5, 'master/slave'); +INSERT INTO t6 VALUES (5, 'master/slave'); +COMMIT; +SELECT * FROM t4 ORDER BY a; +a b +2 master only +3 master/slave +4 master only +5 master/slave +6 master only +7 master only +SELECT * FROM t5 ORDER BY a; +a b +2 master only +3 master/slave +4 master only +5 master/slave +6 master only +7 master only +SELECT * FROM t6 ORDER BY a; +a b +2 master only +3 master/slave +4 master only +5 master/slave +6 master only +7 master only +*** On Slave *** +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; +START SLAVE; +SELECT * FROM t4 ORDER BY a; +a b +3 master/slave +5 master/slave +SELECT * FROM t5 ORDER BY a; +a b +3 master/slave +5 master/slave +SELECT * FROM t6 ORDER BY a; +a b +3 master/slave +5 master/slave +DROP TABLE t4, t5, t6; +**** Case 3: Statement logging format and LOAD DATA with non-transactional table **** +*** On Master *** +CREATE TABLE t10 (a INT, b VARCHAR(20)) ENGINE=myisam; +*** On Slave *** +STOP SLAVE; +*** On Master *** +SET SESSION BINLOG_FORMAT=STATEMENT; +LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/rpl_bug28618.dat' INTO TABLE t10 FIELDS TERMINATED BY '|'; +SELECT * FROM t10 ORDER BY a; +a b +1 master only +2 master only +3 master only +*** On Slave *** +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; +START SLAVE; +SELECT * FROM t10 ORDER BY a; +a b +DROP TABLE t10; diff --git a/mysql-test/suite/rpl/t/rpl_slave_skip-slave.opt b/mysql-test/suite/rpl/t/rpl_slave_skip-slave.opt new file mode 100644 index 00000000000..627becdbfb5 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_slave_skip-slave.opt @@ -0,0 +1 @@ +--innodb diff --git a/mysql-test/suite/rpl/t/rpl_slave_skip.test b/mysql-test/suite/rpl/t/rpl_slave_skip.test index b19d6a2730b..6783098fd7c 100644 --- a/mysql-test/suite/rpl/t/rpl_slave_skip.test +++ b/mysql-test/suite/rpl/t/rpl_slave_skip.test @@ -1,7 +1,9 @@ source include/master-slave.inc; +source include/have_innodb.inc; --echo **** On Slave **** connection slave; +source include/have_innodb.inc; STOP SLAVE; --echo **** On Master **** @@ -69,3 +71,240 @@ query_vertical SHOW SLAVE STATUS; connection master; DROP TABLE t1, t2; sync_slave_with_master; + +# +# More tests for BUG#28618 +# +# Case 1. +# ROW binlog format and non-transactional tables. +# Create the group of events via triggers and try to skip +# some items of that group. +# + +connection master; +SET SESSION BINLOG_FORMAT=ROW; +SET AUTOCOMMIT=0; + +CREATE TABLE t1 (a INT, b VARCHAR(20)) ENGINE=myisam; +CREATE TABLE t2 (a INT, b VARCHAR(20)) ENGINE=myisam; +CREATE TABLE t3 (a INT, b VARCHAR(20)) ENGINE=myisam; + +INSERT INTO t1 VALUES (1,'master/slave'); +INSERT INTO t2 VALUES (1,'master/slave'); +INSERT INTO t3 VALUES (1,'master/slave'); + +DELIMITER |; + +CREATE TRIGGER tr1 AFTER UPDATE on t1 FOR EACH ROW +BEGIN + INSERT INTO t2 VALUES (NEW.a,NEW.b); + DELETE FROM t2 WHERE a < NEW.a; +END| + +CREATE TRIGGER tr2 AFTER INSERT on t2 FOR EACH ROW +BEGIN + UPDATE t3 SET a =2, b = 'master only'; +END| + +DELIMITER ;| + +--echo **** On Slave **** +sync_slave_with_master; +STOP SLAVE; +source include/wait_for_slave_to_stop.inc; + +--echo **** On Master **** +connection master; +UPDATE t1 SET a = 2, b = 'master only' WHERE a = 1; +DROP TRIGGER tr1; +DROP TRIGGER tr2; +INSERT INTO t1 VALUES (3,'master/slave'); +INSERT INTO t2 VALUES (3,'master/slave'); +INSERT INTO t3 VALUES (3,'master/slave'); + +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +SELECT * FROM t3 ORDER BY a; + +save_master_pos; + +--echo *** On Slave *** +connection slave; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; +START SLAVE; +source include/wait_for_slave_to_start.inc; +sync_with_master; + +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +SELECT * FROM t3 ORDER BY a; + +connection master; +DROP TABLE t1, t2, t3; +sync_slave_with_master; + +--echo **** Case 2: Row binlog format and transactional tables **** + +# Create the transaction and try to skip some +# queries from one. + +--echo *** On Master *** +connection master; +CREATE TABLE t4 (a INT, b VARCHAR(20)) ENGINE=innodb; +CREATE TABLE t5 (a INT, b VARCHAR(20)) ENGINE=innodb; +CREATE TABLE t6 (a INT, b VARCHAR(20)) ENGINE=innodb; + +--echo **** On Slave **** +sync_slave_with_master; +STOP SLAVE; +source include/wait_for_slave_to_stop.inc; + +--echo *** On Master *** +connection master; +BEGIN; +INSERT INTO t4 VALUES (2, 'master only'); +INSERT INTO t5 VALUES (2, 'master only'); +INSERT INTO t6 VALUES (2, 'master only'); +COMMIT; + +BEGIN; +INSERT INTO t4 VALUES (3, 'master/slave'); +INSERT INTO t5 VALUES (3, 'master/slave'); +INSERT INTO t6 VALUES (3, 'master/slave'); +COMMIT; + +SELECT * FROM t4 ORDER BY a; +SELECT * FROM t5 ORDER BY a; +SELECT * FROM t6 ORDER BY a; + +save_master_pos; + +--echo *** On Slave *** +connection slave; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; +START SLAVE; +source include/wait_for_slave_to_start.inc; +sync_with_master; + +SELECT * FROM t4 ORDER BY a; +SELECT * FROM t5 ORDER BY a; +SELECT * FROM t6 ORDER BY a; + +# Test skipping two groups + +--echo **** On Slave **** +connection slave; +STOP SLAVE; +source include/wait_for_slave_to_stop.inc; + +--echo *** On Master *** +connection master; +BEGIN; +INSERT INTO t4 VALUES (6, 'master only'); +INSERT INTO t5 VALUES (6, 'master only'); +INSERT INTO t6 VALUES (6, 'master only'); +COMMIT; + +BEGIN; +INSERT INTO t4 VALUES (7, 'master only'); +INSERT INTO t5 VALUES (7, 'master only'); +INSERT INTO t6 VALUES (7, 'master only'); +COMMIT; + +SELECT * FROM t4 ORDER BY a; +SELECT * FROM t5 ORDER BY a; +SELECT * FROM t6 ORDER BY a; + +save_master_pos; + +--echo *** On Slave *** +connection slave; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=10; +START SLAVE; +source include/wait_for_slave_to_start.inc; +sync_with_master; + +SELECT * FROM t4 ORDER BY a; +SELECT * FROM t5 ORDER BY a; +SELECT * FROM t6 ORDER BY a; + +# +# And the same, but with autocommit = 0 +# +connection slave; +STOP SLAVE; +source include/wait_for_slave_to_stop.inc; + +connection master; +SET AUTOCOMMIT=0; + +INSERT INTO t4 VALUES (4, 'master only'); +INSERT INTO t5 VALUES (4, 'master only'); +INSERT INTO t6 VALUES (4, 'master only'); +COMMIT; + +INSERT INTO t4 VALUES (5, 'master/slave'); +INSERT INTO t5 VALUES (5, 'master/slave'); +INSERT INTO t6 VALUES (5, 'master/slave'); +COMMIT; + +SELECT * FROM t4 ORDER BY a; +SELECT * FROM t5 ORDER BY a; +SELECT * FROM t6 ORDER BY a; + +save_master_pos; + +--echo *** On Slave *** +connection slave; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; +START SLAVE; +source include/wait_for_slave_to_start.inc; +sync_with_master; + +SELECT * FROM t4 ORDER BY a; +SELECT * FROM t5 ORDER BY a; +SELECT * FROM t6 ORDER BY a; + +connection master; +DROP TABLE t4, t5, t6; +sync_slave_with_master; + +--echo **** Case 3: Statement logging format and LOAD DATA with non-transactional table **** + +# LOAD DATA creates two events in binary log for statement binlog format. +# Try to skip the first. + +--echo *** On Master *** +connection master; +CREATE TABLE t10 (a INT, b VARCHAR(20)) ENGINE=myisam; + +--echo *** On Slave *** +sync_slave_with_master; +STOP SLAVE; +source include/wait_for_slave_to_stop.inc; + +--echo *** On Master *** +connection master; +SET SESSION BINLOG_FORMAT=STATEMENT; +exec cp ./suite/rpl/data/rpl_bug28618.dat $MYSQLTEST_VARDIR/tmp/; +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +eval LOAD DATA INFILE '$MYSQLTEST_VARDIR/tmp/rpl_bug28618.dat' INTO TABLE t10 FIELDS TERMINATED BY '|'; +remove_file $MYSQLTEST_VARDIR/tmp/rpl_bug28618.dat; + +SELECT * FROM t10 ORDER BY a; + +save_master_pos; + +--echo *** On Slave *** +connection slave; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; +START SLAVE; +source include/wait_for_slave_to_start.inc; +sync_with_master; + +SELECT * FROM t10 ORDER BY a; + +connection master; +DROP TABLE t10; +sync_slave_with_master; + diff --git a/mysql-test/suite/rpl_ndb/r/rpl_ndb_extraCol.result b/mysql-test/suite/rpl_ndb/r/rpl_ndb_extraCol.result index 2327dc7ee81..6f040d2e6ad 100644 --- a/mysql-test/suite/rpl_ndb/r/rpl_ndb_extraCol.result +++ b/mysql-test/suite/rpl_ndb/r/rpl_ndb_extraCol.result @@ -707,7 +707,7 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1060 Last_SQL_Error Error 'Duplicate column name 'c6'' on query. Default database: 'test'. Query: 'ALTER TABLE t15 ADD COLUMN c6 INT AFTER c5' -SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; START SLAVE; *** Try to insert in master **** INSERT INTO t15 () VALUES(5,2.00,'Replication Testing',@b1,'Buda',2); diff --git a/sql/log_event.cc b/sql/log_event.cc index 7e5cfd6a7a4..0e877252ce8 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -570,7 +570,8 @@ Log_event::do_shall_skip(Relay_log_info *rli) (ulong) server_id, (ulong) ::server_id, rli->replicate_same_server_id, rli->slave_skip_counter)); - if (server_id == ::server_id && !rli->replicate_same_server_id) + if (server_id == ::server_id && !rli->replicate_same_server_id || + rli->slave_skip_counter == 1 && rli->is_in_group()) return EVENT_SKIP_IGNORE; else if (rli->slave_skip_counter > 0) return EVENT_SKIP_COUNT; @@ -1227,6 +1228,16 @@ void Log_event::print_timestamp(IO_CACHE* file, time_t* ts) #endif /* MYSQL_CLIENT */ +#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) +inline Log_event::enum_skip_reason +Log_event::continue_group(Relay_log_info *rli) +{ + if (rli->slave_skip_counter == 1) + return Log_event::EVENT_SKIP_IGNORE; + return Log_event::do_shall_skip(rli); +} +#endif + /************************************************************************** Query_log_event methods **************************************************************************/ @@ -2235,6 +2246,30 @@ int Query_log_event::do_update_pos(Relay_log_info *rli) } +Log_event::enum_skip_reason +Query_log_event::do_shall_skip(Relay_log_info *rli) +{ + DBUG_ENTER("Query_log_event::do_shall_skip"); + DBUG_PRINT("debug", ("query: %s; q_len: %d", query, q_len)); + DBUG_ASSERT(query && q_len > 0); + + if (rli->slave_skip_counter > 0) + { + if (strcmp("BEGIN", query) == 0) + { + thd->options|= OPTION_BEGIN; + DBUG_RETURN(Log_event::continue_group(rli)); + } + + if (strcmp("COMMIT", query) == 0 || strcmp("ROLLBACK", query) == 0) + { + thd->options&= ~OPTION_BEGIN; + DBUG_RETURN(Log_event::EVENT_SKIP_COUNT); + } + } + DBUG_RETURN(Log_event::do_shall_skip(rli)); +} + #endif @@ -3871,10 +3906,7 @@ Intvar_log_event::do_shall_skip(Relay_log_info *rli) that we do not change the value of the slave skip counter since it will be decreased by the following insert event. */ - if (rli->slave_skip_counter == 1) - return Log_event::EVENT_SKIP_IGNORE; - else - return Log_event::do_shall_skip(rli); + return continue_group(rli); } #endif @@ -3970,10 +4002,7 @@ Rand_log_event::do_shall_skip(Relay_log_info *rli) that we do not change the value of the slave skip counter since it will be decreased by the following insert event. */ - if (rli->slave_skip_counter == 1) - return Log_event::EVENT_SKIP_IGNORE; - else - return Log_event::do_shall_skip(rli); + return continue_group(rli); } #endif /* !MYSQL_CLIENT */ @@ -4049,6 +4078,17 @@ int Xid_log_event::do_apply_event(Relay_log_info const *rli) "COMMIT /* implicit, from Xid_log_event */"); return end_trans(thd, COMMIT); } + +Log_event::enum_skip_reason +Xid_log_event::do_shall_skip(Relay_log_info *rli) +{ + DBUG_ENTER("Xid_log_event::do_shall_skip"); + if (rli->slave_skip_counter > 0) { + thd->options&= ~OPTION_BEGIN; + DBUG_RETURN(Log_event::EVENT_SKIP_COUNT); + } + DBUG_RETURN(Log_event::do_shall_skip(rli)); +} #endif /* !MYSQL_CLIENT */ @@ -4427,10 +4467,7 @@ User_var_log_event::do_shall_skip(Relay_log_info *rli) that we do not change the value of the slave skip counter since it will be decreased by the following insert event. */ - if (rli->slave_skip_counter == 1) - return Log_event::EVENT_SKIP_IGNORE; - else - return Log_event::do_shall_skip(rli); + return continue_group(rli); } #endif /* !MYSQL_CLIENT */ @@ -5366,6 +5403,19 @@ int Begin_load_query_log_event::get_create_or_append() const #endif /* defined( HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */ +#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) +Log_event::enum_skip_reason +Begin_load_query_log_event::do_shall_skip(Relay_log_info *rli) +{ + /* + If the slave skip counter is 1, then we should not start executing + on the next event. + */ + return continue_group(rli); +} +#endif + + /************************************************************************** Execute_load_query_log_event methods **************************************************************************/ @@ -6870,10 +6920,7 @@ Table_map_log_event::do_shall_skip(Relay_log_info *rli) If the slave skip counter is 1, then we should not start executing on the next event. */ - if (rli->slave_skip_counter == 1) - return Log_event::EVENT_SKIP_IGNORE; - else - return Log_event::do_shall_skip(rli); + return continue_group(rli); } int Table_map_log_event::do_update_pos(Relay_log_info *rli) diff --git a/sql/log_event.h b/sql/log_event.h index 05d4c70042f..9321860a062 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -870,6 +870,25 @@ public: protected: + /** + Helper function to ignore an event w.r.t. the slave skip counter. + + This function can be used inside do_shall_skip() for functions + that cannot end a group. If the slave skip counter is 1 when + seeing such an event, the event shall be ignored, the counter + left intact, and processing continue with the next event. + + A typical usage is: + @code + enum_skip_reason do_shall_skip(Relay_log_info *rli) { + return continue_group(rli); + } + @endcode + + @return Skip reason + */ + enum_skip_reason continue_group(Relay_log_info *rli); + /** Primitive to apply an event to the database. @@ -1086,6 +1105,7 @@ public: public: /* !!! Public in this patch to allow old usage */ #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) + virtual enum_skip_reason do_shall_skip(Relay_log_info *rli); virtual int do_apply_event(Relay_log_info const *rli); virtual int do_update_pos(Relay_log_info *rli); @@ -1559,6 +1579,7 @@ class Xid_log_event: public Log_event private: #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) virtual int do_apply_event(Relay_log_info const *rli); + enum_skip_reason do_shall_skip(Relay_log_info *rli); #endif }; @@ -1937,6 +1958,10 @@ public: *description_event); ~Begin_load_query_log_event() {} Log_event_type get_type_code() { return BEGIN_LOAD_QUERY_EVENT; } +private: +#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) + virtual enum_skip_reason do_shall_skip(Relay_log_info *rli); +#endif }; diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h index 10ecf1a43d4..a3a57ad4ce9 100644 --- a/sql/rpl_rli.h +++ b/sql/rpl_rli.h @@ -365,6 +365,18 @@ public: m_flags |= (1UL << flag); } + /** + Get the value of a replication state flag. + + @param flag Flag to get value of + + @return @c true if the flag was set, @c false otherwise. + */ + bool get_flag(enum_state_flag flag) + { + return m_flags & (1UL << flag); + } + /** Clear the value of a replication state flag. diff --git a/sql/slave.cc b/sql/slave.cc index fcbd4eb841b..570bf57d212 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1853,10 +1853,13 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli) // EVENT_SKIP_NOT, "not skipped", // EVENT_SKIP_IGNORE, - "skipped because event originated from this server", + "skipped because event should be ignored", // EVENT_SKIP_COUNT "skipped because event skip counter was non-zero" }; + DBUG_PRINT("info", ("OPTION_BEGIN: %d; IN_STMT: %d", + thd->options & OPTION_BEGIN ? 1 : 0, + rli->get_flag(Relay_log_info::IN_STMT))); DBUG_PRINT("skip_event", ("%s event was %s", ev->get_type_str(), explain[reason])); #endif From 24ea15a24d22718f0deff20e52454d3fc0113a6f Mon Sep 17 00:00:00 2001 From: "mats@kindahl-laptop.dnsalias.net" <> Date: Sat, 20 Oct 2007 18:19:55 +0200 Subject: [PATCH 056/336] Bug#31702 (Missing row on slave causes assertion failure under row-based replication): When replicating an update pair (before image, after image) under row-based replication, and the before image is not found on the slave, the after image was not discared, and was hence read as a before image for the next row. Eventually, this lead to an after image being read outside the block of rows in the event, causing an assertion to fire. This patch fixes this by reading the after image in the event that the row was not found on the slave, adds some extra debug assertion to catch future errors earlier, and also adds a few non-debug checks to prevent reading outside the block of the event. --- include/my_base.h | 8 ++-- .../suite/rpl/r/rpl_row_basic_11bugs.result | 31 ++++++++++++++++ .../suite/rpl/t/rpl_row_basic_11bugs.test | 37 +++++++++++++++++++ sql/log_event.cc | 27 +++++++++++--- sql/log_event.h | 24 +++++++++++- 5 files changed, 117 insertions(+), 10 deletions(-) diff --git a/include/my_base.h b/include/my_base.h index 339554979a8..e65a04bb16d 100644 --- a/include/my_base.h +++ b/include/my_base.h @@ -407,9 +407,11 @@ enum ha_base_keytype { #define HA_ERR_RECORD_IS_THE_SAME 169 /* row not actually updated : new values same as the old values */ -#define HA_ERR_LOGGING_IMPOSSIBLE 170 /* It is not possible to log this - statement */ -#define HA_ERR_LAST 170 /*Copy last error nr.*/ +#define HA_ERR_LOGGING_IMPOSSIBLE 170 /* It is not possible to log this + statement */ +#define HA_ERR_CORRUPT_EVENT 171 /* The event was corrupt, leading to + illegal data being read */ +#define HA_ERR_LAST 171 /*Copy last error nr.*/ /* Add error numbers before HA_ERR_LAST and change it accordingly. */ #define HA_ERR_ERRORS (HA_ERR_LAST - HA_ERR_FIRST + 1) diff --git a/mysql-test/suite/rpl/r/rpl_row_basic_11bugs.result b/mysql-test/suite/rpl/r/rpl_row_basic_11bugs.result index 7dc9926522b..5ad9ba7ced0 100644 --- a/mysql-test/suite/rpl/r/rpl_row_basic_11bugs.result +++ b/mysql-test/suite/rpl/r/rpl_row_basic_11bugs.result @@ -242,3 +242,34 @@ a b 3 1 4 4 drop table t1,t2; +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; +**** On Master **** +SET SESSION BINLOG_FORMAT=ROW; +CREATE TABLE t1 (a INT PRIMARY KEY, b SET('master','slave')); +INSERT INTO t1 VALUES (1,'master,slave'), (2,'master,slave'); +**** On Slave **** +UPDATE t1 SET a = 5, b = 'slave' WHERE a = 1; +SELECT * FROM t1 ORDER BY a; +a b +2 master,slave +5 slave +**** On Master **** +UPDATE t1 SET a = 5, b = 'master' WHERE a = 1; +SELECT * FROM t1 ORDER BY a; +a b +2 master,slave +5 master +**** On Slave **** +Last_SQL_Error +Error in Update_rows event: error during transaction execution on table test.t1. Can't find record in 't1' +SELECT * FROM t1 ORDER BY a; +a b +2 master,slave +5 slave +DROP TABLE t1; +**** On Master **** +DROP TABLE t1; diff --git a/mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test b/mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test index fb43664f121..f6180de52a4 100644 --- a/mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test +++ b/mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test @@ -223,3 +223,40 @@ connection master; drop table t1,t2; sync_slave_with_master; + +# +# BUG#31702: Missing row on slave causes assertion failure under +# row-based replication +# + +disable_query_log; +source include/master-slave-reset.inc; +enable_query_log; + +--echo **** On Master **** +connection master; +SET SESSION BINLOG_FORMAT=ROW; +CREATE TABLE t1 (a INT PRIMARY KEY, b SET('master','slave')); +INSERT INTO t1 VALUES (1,'master,slave'), (2,'master,slave'); +--echo **** On Slave **** +sync_slave_with_master; +UPDATE t1 SET a = 5, b = 'slave' WHERE a = 1; +SELECT * FROM t1 ORDER BY a; +--echo **** On Master **** +connection master; +UPDATE t1 SET a = 5, b = 'master' WHERE a = 1; +save_master_pos; +SELECT * FROM t1 ORDER BY a; +--echo **** On Slave **** +connection slave; +source include/wait_for_slave_sql_error.inc; +let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Error, 1); +disable_query_log; +eval SELECT "$last_error" AS Last_SQL_Error; +enable_query_log; +SELECT * FROM t1 ORDER BY a; +DROP TABLE t1; + +--echo **** On Master **** +connection master; +DROP TABLE t1; diff --git a/sql/log_event.cc b/sql/log_event.cc index ec4d6820cca..fd7e3e5db6b 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -6173,14 +6173,19 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) table->in_use = old_thd; switch (error) { - /* Some recoverable errors */ - case HA_ERR_RECORD_CHANGED: - case HA_ERR_KEY_NOT_FOUND: /* Idempotency support: OK if - tuple does not exist */ - error= 0; case 0: break; + /* Some recoverable errors */ + case HA_ERR_RECORD_CHANGED: + case HA_ERR_KEY_NOT_FOUND: /* Idempotency support: OK if + tuple does not exist */ + if (get_type_code() != UPDATE_ROWS_EVENT) + { + error= 0; + break; + } + /* Fall through in the event that we have an update event */ default: rli->report(ERROR_LEVEL, thd->net.last_errno, "Error in %s event: row application failed. %s", @@ -6197,6 +6202,10 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) m_curr_row_end. */ + DBUG_PRINT("info", ("error: %d", error)); + DBUG_PRINT("info", ("curr_row: 0x%lu; curr_row_end: 0x%lu; rows_end: 0x%lu", + (ulong) m_curr_row, (ulong) m_curr_row_end, (ulong) m_rows_end)); + if (!m_curr_row_end && !error) unpack_current_row(rli); @@ -7931,7 +7940,15 @@ Update_rows_log_event::do_exec_row(const Relay_log_info *const rli) int error= find_row(rli); if (error) + { + /* + We need to read the second image in the event of error to be + able to skip to the next pair of updates + */ + m_curr_row= m_curr_row_end; + unpack_current_row(rli); return error; + } /* This is the situation after locating BI: diff --git a/sql/log_event.h b/sql/log_event.h index 05d4c70042f..226ebc02712 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -37,6 +37,23 @@ #include "rpl_reporting.h" #endif +/** + Either assert or return an error. + + In debug build, the condition will be checked, but in non-debug + builds, the error code given will be returned instead. + + @param COND Condition to check + @param ERRNO Error number to return in non-debug builds +*/ +#ifdef DBUG_OFF +#define ASSERT_OR_RETURN_ERROR(COND, ERRNO) \ + do { if (!(COND)) return ERRNO; } while (0) +#else +#define ASSERT_OR_RETURN_ERROR(COND, ERRNO) \ + DBUG_ASSERT(COND) +#endif + #define LOG_READ_EOF -1 #define LOG_READ_BOGUS -2 #define LOG_READ_IO -3 @@ -2316,8 +2333,11 @@ protected: int unpack_current_row(const Relay_log_info *const rli) { DBUG_ASSERT(m_table); - return ::unpack_row(rli, m_table, m_width, m_curr_row, &m_cols, - &m_curr_row_end, &m_master_reclength); + ASSERT_OR_RETURN_ERROR(m_curr_row < m_rows_end, HA_ERR_CORRUPT_EVENT); + int const result= ::unpack_row(rli, m_table, m_width, m_curr_row, &m_cols, + &m_curr_row_end, &m_master_reclength); + ASSERT_OR_RETURN_ERROR(m_curr_row_end <= m_rows_end, HA_ERR_CORRUPT_EVENT); + return result; } #endif From 012bccc09f10825713e352784fc4abeb14a99d48 Mon Sep 17 00:00:00 2001 From: "mats@kindahl-laptop.dnsalias.net" <> Date: Sat, 20 Oct 2007 20:16:12 +0200 Subject: [PATCH 057/336] BUG#24860 (Incorrect SLAVE_TRANSACTION_RETRIES code can result in slave stuck): If a temporary error occured inside a group on an event that was not the first event of the group, the slave could get stuck because the retry counter is reset whenever an event was executed successfully. This patch only reset the retry counter when an entire group has been successfully executed, or failed with a non-transient error. --- .../suite/rpl/r/rpl_temporary_errors.result | 81 +++++++++++++++++++ .../rpl/t/rpl_temporary_errors-slave.opt | 3 + .../suite/rpl/t/rpl_temporary_errors.test | 29 +++++++ sql/slave.cc | 26 ++++-- 4 files changed, 134 insertions(+), 5 deletions(-) create mode 100644 mysql-test/suite/rpl/r/rpl_temporary_errors.result create mode 100644 mysql-test/suite/rpl/t/rpl_temporary_errors-slave.opt create mode 100644 mysql-test/suite/rpl/t/rpl_temporary_errors.test diff --git a/mysql-test/suite/rpl/r/rpl_temporary_errors.result b/mysql-test/suite/rpl/r/rpl_temporary_errors.result new file mode 100644 index 00000000000..31c8930ec4f --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_temporary_errors.result @@ -0,0 +1,81 @@ +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; +**** On Master **** +SET SESSION BINLOG_FORMAT=ROW; +CREATE TABLE t1 (a INT PRIMARY KEY, b INT); +INSERT INTO t1 VALUES (1,1), (2,2), (3,3), (4,4); +**** On Slave **** +SHOW STATUS LIKE 'Slave_retried_transactions'; +Variable_name Value +Slave_retried_transactions 0 +UPDATE t1 SET a = 5, b = 47 WHERE a = 1; +SELECT * FROM t1; +a b +5 47 +2 2 +3 3 +4 4 +**** On Master **** +UPDATE t1 SET a = 5, b = 5 WHERE a = 1; +SELECT * FROM t1; +a b +5 5 +2 2 +3 3 +4 4 +**** On Slave **** +SHOW STATUS LIKE 'Slave_retried_transactions'; +Variable_name Value +Slave_retried_transactions 2 +SELECT * FROM t1; +a b +5 47 +2 2 +3 3 +4 4 +SHOW SLAVE STATUS; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port MASTER_PORT +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos 408 +Relay_Log_File # +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running Yes +Slave_SQL_Running No +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table # +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 1032 +Last_Error Error in Update_rows event: error during transaction execution on table test.t1. Can't find record in 't1' +Skip_Counter 0 +Exec_Master_Log_Pos 318 +Relay_Log_Space # +Until_Condition None +Until_Log_File +Until_Log_Pos 0 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master # +Master_SSL_Verify_Server_Cert No +Last_IO_Errno # +Last_IO_Error # +Last_SQL_Errno 1032 +Last_SQL_Error Error in Update_rows event: error during transaction execution on table test.t1. Can't find record in 't1' +DROP TABLE t1; +**** On Master **** +DROP TABLE t1; diff --git a/mysql-test/suite/rpl/t/rpl_temporary_errors-slave.opt b/mysql-test/suite/rpl/t/rpl_temporary_errors-slave.opt new file mode 100644 index 00000000000..80c171170f6 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_temporary_errors-slave.opt @@ -0,0 +1,3 @@ +--loose-debug="+d,all_errors_are_temporary_errors" --slave-transaction-retries=2 + + diff --git a/mysql-test/suite/rpl/t/rpl_temporary_errors.test b/mysql-test/suite/rpl/t/rpl_temporary_errors.test new file mode 100644 index 00000000000..0ca515fff40 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_temporary_errors.test @@ -0,0 +1,29 @@ +source include/master-slave.inc; + +--echo **** On Master **** +connection master; +SET SESSION BINLOG_FORMAT=ROW; +CREATE TABLE t1 (a INT PRIMARY KEY, b INT); +INSERT INTO t1 VALUES (1,1), (2,2), (3,3), (4,4); +--echo **** On Slave **** +sync_slave_with_master; +SHOW STATUS LIKE 'Slave_retried_transactions'; +UPDATE t1 SET a = 5, b = 47 WHERE a = 1; +SELECT * FROM t1; +--echo **** On Master **** +connection master; +UPDATE t1 SET a = 5, b = 5 WHERE a = 1; +save_master_pos; +SELECT * FROM t1; +#SHOW BINLOG EVENTS; +--echo **** On Slave **** +connection slave; +source include/wait_for_slave_sql_to_stop.inc; +SHOW STATUS LIKE 'Slave_retried_transactions'; +SELECT * FROM t1; +source include/show_slave_status.inc; +DROP TABLE t1; + +--echo **** On Master **** +connection master; +DROP TABLE t1; diff --git a/sql/slave.cc b/sql/slave.cc index 9780ae70c5b..169cf897e6a 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1714,7 +1714,14 @@ static int has_temporary_error(THD *thd) DBUG_ENTER("has_temporary_error"); if (thd->is_fatal_error) + { + DBUG_PRINT("info", ("thd->net.last_errno: %s", ER(thd->net.last_errno))); DBUG_RETURN(0); + } + + DBUG_EXECUTE_IF("all_errors_are_temporary_errors", + if (thd->net.last_errno) + thd->net.last_errno= ER_LOCK_DEADLOCK;); /* Temporary error codes: @@ -1723,7 +1730,10 @@ static int has_temporary_error(THD *thd) */ if (thd->net.last_errno == ER_LOCK_DEADLOCK || thd->net.last_errno == ER_LOCK_WAIT_TIMEOUT) + { + DBUG_PRINT("info", ("thd->net.last_errno: %s", ER(thd->net.last_errno))); DBUG_RETURN(1); + } #ifdef HAVE_NDB_BINLOG /* @@ -1905,7 +1915,8 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli) } if (slave_trans_retries) { - if (exec_res && has_temporary_error(thd)) + int temp_err; + if (exec_res && (temp_err= has_temporary_error(thd))) { const char *errmsg; /* @@ -1953,15 +1964,19 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli) "the slave_transaction_retries variable.", slave_trans_retries); } - else if (!((thd->options & OPTION_BEGIN) && opt_using_transactions)) + else if (exec_res && !temp_err || + (opt_using_transactions && + rli->group_relay_log_pos == rli->event_relay_log_pos)) { /* - Only reset the retry counter if the event succeeded or - failed with a non-transient error. On a successful event, - the execution will proceed as usual; in the case of a + Only reset the retry counter if the entire group succeeded + or failed with a non-transient error. On a successful + event, the execution will proceed as usual; in the case of a non-transient error, the slave will stop with an error. */ rli->trans_retries= 0; // restart from fresh + DBUG_PRINT("info", ("Resetting retry counter, rli->trans_retries: %d", + rli->trans_retries)); } } DBUG_RETURN(exec_res); @@ -2450,6 +2465,7 @@ pthread_handler_t handle_slave_sql(void *arg) rli->ignore_log_space_limit= 0; pthread_mutex_unlock(&rli->log_space_lock); rli->trans_retries= 0; // start from "no error" + DBUG_PRINT("info", ("rli->trans_retries: %d", rli->trans_retries)); if (init_relay_log_pos(rli, rli->group_relay_log_name, From 0f818ddf75a2cebc1813329027a3f43eb86ed1a4 Mon Sep 17 00:00:00 2001 From: "aelkin/elkin@dsl-hkibras1-ff5fc300-23.dhcp.inet.fi" <> Date: Sun, 21 Oct 2007 18:37:37 +0300 Subject: [PATCH 058/336] Bug #26199 Replication Failure on Slave when using stored procs with bit-type parameters. The value of the actual argument of BIT-type-arg stored procedure was binlogged as non-escaped sequence of bytes corresponding to internal representation of the bit value. The patch enforces binlogging of the bit-argument as a valid literal: prefixing the quoted bytes sequence with _binary. Note, that behaviour of Item_field::var_str for field_type() of MYSQL_TYPE_BIT is exceptional in that the returned string contains the binary representation even though result_type() of the item is INT_RESULT. --- mysql-test/r/rpl_sp_effects.result | 41 ++++++++++++++++++++++++ mysql-test/t/rpl_sp_effects.test | 51 ++++++++++++++++++++++++++++++ sql/sp_head.cc | 5 +-- 3 files changed, 95 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/rpl_sp_effects.result b/mysql-test/r/rpl_sp_effects.result index bf8128d9385..70b2338d187 100644 --- a/mysql-test/r/rpl_sp_effects.result +++ b/mysql-test/r/rpl_sp_effects.result @@ -213,3 +213,44 @@ drop table t1; drop function f1; drop function f2; drop procedure p1; +create table t2 (b BIT(7)); +create procedure sp_bug26199(bitvalue BIT(7)) +begin +insert into t2 set b = bitvalue; +end // +create function sf_bug26199(b BIT(7)) returns int +begin +insert into t2 values(b); +return 0; +end// +call sp_bug26199(b'1110'); +call sp_bug26199('\0'); +select sf_bug26199(b'1111111'); +sf_bug26199(b'1111111') +0 +select sf_bug26199(b'101111111'); +sf_bug26199(b'101111111') +0 +Warnings: +Warning 1264 Out of range value adjusted for column 'b' at row 1 +select sf_bug26199('\''); +sf_bug26199('\'') +0 +select hex(b) from t2; +hex(b) +E +0 +7F +7F +27 +select hex(b) from t2; +hex(b) +E +0 +7F +7F +27 +drop table t2; +drop procedure sp_bug26199; +drop function sf_bug26199; +end of the tests diff --git a/mysql-test/t/rpl_sp_effects.test b/mysql-test/t/rpl_sp_effects.test index 9da5723b993..f18710efa37 100644 --- a/mysql-test/t/rpl_sp_effects.test +++ b/mysql-test/t/rpl_sp_effects.test @@ -195,9 +195,60 @@ sync_slave_with_master; connection slave; select 'slave', a from t1; +# +# cleanup +# + connection master; drop table t1; drop function f1; drop function f2; drop procedure p1; sync_slave_with_master; + +# +# bug#26199 Replication Failure on Slave when using stored procs +# with bit-type parameters + +connection master; + +create table t2 (b BIT(7)); +delimiter //; +create procedure sp_bug26199(bitvalue BIT(7)) +begin + insert into t2 set b = bitvalue; +end // + +create function sf_bug26199(b BIT(7)) returns int +begin + insert into t2 values(b); + return 0; +end// + +DELIMITER ;// + + + +call sp_bug26199(b'1110'); +call sp_bug26199('\0'); +select sf_bug26199(b'1111111'); +select sf_bug26199(b'101111111'); +select sf_bug26199('\''); +select hex(b) from t2; + +sync_slave_with_master; +#connection slave; +select hex(b) from t2; + +# +# cleanup bug#26199 +# +connection master; +drop table t2; +drop procedure sp_bug26199; +drop function sf_bug26199; + +sync_slave_with_master; + + +--echo end of the tests diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 5ad6625efb8..1843406b862 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -100,8 +100,9 @@ sp_get_item_value(THD *thd, Item *item, String *str) case REAL_RESULT: case INT_RESULT: case DECIMAL_RESULT: - return item->val_str(str); - + if (item->field_type() != MYSQL_TYPE_BIT) + return item->val_str(str); + else {/* Bit type is handled as binary string */} case STRING_RESULT: { String *result= item->val_str(str); From b65a9888c08a8721149fa6ae4e99c0a311ad0ba6 Mon Sep 17 00:00:00 2001 From: "mats@kindahl-laptop.dnsalias.net" <> Date: Mon, 22 Oct 2007 10:32:35 +0200 Subject: [PATCH 059/336] Post-merge fixes. --- mysql-test/suite/rpl/r/rpl_extraCol_innodb.result | 3 ++- mysql-test/suite/rpl/r/rpl_extraCol_myisam.result | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/rpl/r/rpl_extraCol_innodb.result b/mysql-test/suite/rpl/r/rpl_extraCol_innodb.result index fe5a5b28682..38e76a3c877 100644 --- a/mysql-test/suite/rpl/r/rpl_extraCol_innodb.result +++ b/mysql-test/suite/rpl/r/rpl_extraCol_innodb.result @@ -707,7 +707,7 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1060 Last_SQL_Error Error 'Duplicate column name 'c6'' on query. Default database: 'test'. Query: 'ALTER TABLE t15 ADD COLUMN c6 INT AFTER c5' -SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; START SLAVE; *** Try to insert in master **** INSERT INTO t15 () VALUES(5,2.00,'Replication Testing',@b1,'Buda',2); @@ -723,6 +723,7 @@ c1 c2 c3 c4 c5 c6 c7 1 1.00 Replication Testing Extra Col b1b1b1b1b1b1b1b1 Kyle 1 CURRENT_TIMESTAMP 2 2.00 This Test Should work b1b1b1b1b1b1b1b1 JOE 1 CURRENT_TIMESTAMP 3 3.00 If is does not, I will open a bug b1b1b1b1b1b1b1b1 QA 1 CURRENT_TIMESTAMP +5 2.00 Replication Testing b1b1b1b1b1b1b1b1 Buda 2 CURRENT_TIMESTAMP *** DROP TABLE t15 *** DROP TABLE t15; *** Create t16 on slave *** diff --git a/mysql-test/suite/rpl/r/rpl_extraCol_myisam.result b/mysql-test/suite/rpl/r/rpl_extraCol_myisam.result index e70a2efaf29..2228c68b271 100644 --- a/mysql-test/suite/rpl/r/rpl_extraCol_myisam.result +++ b/mysql-test/suite/rpl/r/rpl_extraCol_myisam.result @@ -707,7 +707,7 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1060 Last_SQL_Error Error 'Duplicate column name 'c6'' on query. Default database: 'test'. Query: 'ALTER TABLE t15 ADD COLUMN c6 INT AFTER c5' -SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; START SLAVE; *** Try to insert in master **** INSERT INTO t15 () VALUES(5,2.00,'Replication Testing',@b1,'Buda',2); @@ -723,6 +723,7 @@ c1 c2 c3 c4 c5 c6 c7 1 1.00 Replication Testing Extra Col b1b1b1b1b1b1b1b1 Kyle 1 CURRENT_TIMESTAMP 2 2.00 This Test Should work b1b1b1b1b1b1b1b1 JOE 1 CURRENT_TIMESTAMP 3 3.00 If is does not, I will open a bug b1b1b1b1b1b1b1b1 QA 1 CURRENT_TIMESTAMP +5 2.00 Replication Testing b1b1b1b1b1b1b1b1 Buda 2 CURRENT_TIMESTAMP *** DROP TABLE t15 *** DROP TABLE t15; *** Create t16 on slave *** From 697f796f34e574803074929243b1949dde43b9a7 Mon Sep 17 00:00:00 2001 From: "dkatz@damien-katzs-computer.local" <> Date: Mon, 22 Oct 2007 13:25:00 -0400 Subject: [PATCH 060/336] Merge bk-internal.mysql.com:/home/bk/mysql-5.1-runtime into damien-katzs-computer.local:/Users/dkatz/mysql-5.1-runtime From 0b0071743299aaaba6a14da099abc9be2afd6100 Mon Sep 17 00:00:00 2001 From: "kaa@polly.(none)" <> Date: Mon, 22 Oct 2007 22:35:08 +0400 Subject: [PATCH 061/336] Fixed the Windows build failures introduced by the patch for bug #31207: Test "join_nested" shows different strategy on IA64 CPUs / Intel's ICC compiler. --- libmysql/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libmysql/CMakeLists.txt b/libmysql/CMakeLists.txt index 59e70d68a6d..6f5d8a49363 100755 --- a/libmysql/CMakeLists.txt +++ b/libmysql/CMakeLists.txt @@ -96,7 +96,7 @@ SET(CLIENT_SOURCES ../mysys/array.c ../strings/bchange.c ../strings/bmove.c ../strings/strmov.c ../strings/strnlen.c ../strings/strnmov.c ../strings/strtod.c ../strings/strtoll.c ../strings/strtoull.c ../strings/strxmov.c ../strings/strxnmov.c ../mysys/thr_mutex.c ../mysys/typelib.c ../vio/vio.c ../vio/viosocket.c - ../vio/viossl.c ../vio/viosslfactories.c ../strings/xml.c + ../vio/viossl.c ../vio/viosslfactories.c ../strings/xml.c ../mysys/mf_qsort.c ${LIB_SOURCES}) # Need to set USE_TLS for building the DLL, since __declspec(thread) From 271c98d067c0c16ee2e8406a340724ef794391aa Mon Sep 17 00:00:00 2001 From: "aelkin/elkin@koti.dsl.inet.fi" <> Date: Mon, 22 Oct 2007 21:45:21 +0300 Subject: [PATCH 062/336] Bug #30594 rpl.rpl_skip_error is nondeterministic Non-determinism in the tests was due to results of SBR are different from those gained with row binlog format. Because tests effectively verify skipping only ER_DUP_ENTRY it is explicitly required to run the test on in mixed and stmt binlog format. ER_DUP_ENTRY is automatically ignored when happened in RBR because of implicit rule favoring reentrant reading from binlog rule which means that a Write_rows_log_event overwrites a slave's row if the one has the same primary key. If future we might have skipping error due to applying of row-based events. The comments added saying a new file would be needed for that: rpl_row_skip_error or smth. --- mysql-test/suite/rpl/r/rpl_skip_error.result | 3 +-- mysql-test/suite/rpl/t/rpl_skip_error-slave.opt | 2 +- mysql-test/suite/rpl/t/rpl_skip_error.test | 8 ++++++++ 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/mysql-test/suite/rpl/r/rpl_skip_error.result b/mysql-test/suite/rpl/r/rpl_skip_error.result index 525909387b3..ed4c4a6b3bb 100644 --- a/mysql-test/suite/rpl/r/rpl_skip_error.result +++ b/mysql-test/suite/rpl/r/rpl_skip_error.result @@ -29,8 +29,7 @@ select * from t1; a 1 2 -3 show slave status; Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error -# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 786 # # master-bin.000001 Yes Yes 0 0 786 # None 0 No # No 0 0 +# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 851 # # master-bin.000001 Yes Yes 0 0 851 # None 0 No # No 0 0 drop table t1; diff --git a/mysql-test/suite/rpl/t/rpl_skip_error-slave.opt b/mysql-test/suite/rpl/t/rpl_skip_error-slave.opt index c84171976a1..a8f5deaa30b 100644 --- a/mysql-test/suite/rpl/t/rpl_skip_error-slave.opt +++ b/mysql-test/suite/rpl/t/rpl_skip_error-slave.opt @@ -1 +1 @@ ---slave-skip-error=1062,1582 +--slave-skip-error=1062 diff --git a/mysql-test/suite/rpl/t/rpl_skip_error.test b/mysql-test/suite/rpl/t/rpl_skip_error.test index b68b637b3b0..72d434d9c9b 100644 --- a/mysql-test/suite/rpl/t/rpl_skip_error.test +++ b/mysql-test/suite/rpl/t/rpl_skip_error.test @@ -3,6 +3,14 @@ ######################################### # Note that errors are ignored by opt file. source include/master-slave.inc; +source include/have_binlog_format_mixed_or_statement.inc; + +# +# Bug #30594 +# Skipping error due to applying Row-based repliation events +# should be checked with another test file +# consider names like rpl_row_skip_error +# create table t1 (n int not null primary key); save_master_pos; From 5b01a77c9c92dff6020c58d8c24f22f7659d3f16 Mon Sep 17 00:00:00 2001 From: "dkatz@damien-katzs-computer.local" <> Date: Mon, 22 Oct 2007 15:16:43 -0400 Subject: [PATCH 063/336] Bug #31332 --event-scheduler option misbehaving Changed the behaviour of the --event-scheduler option when used without an arguments. It now turns the option on. --- mysql-test/r/events_bugs.result | 4 ++++ mysql-test/t/events_bugs-master.opt | 1 + mysql-test/t/events_bugs.test | 15 +++++++++++++++ sql/events.cc | 2 +- 4 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 mysql-test/t/events_bugs-master.opt diff --git a/mysql-test/r/events_bugs.result b/mysql-test/r/events_bugs.result index b6b77101874..b0de2358777 100644 --- a/mysql-test/r/events_bugs.result +++ b/mysql-test/r/events_bugs.result @@ -3,6 +3,10 @@ drop database if exists mysqltest_db1; drop database if exists mysqltest_db2; create database events_test; use events_test; +select * from information_schema.global_variables where variable_name like 'event_scheduler'; +VARIABLE_NAME VARIABLE_VALUE +EVENT_SCHEDULER ON +SET GLOBAL event_scheduler = 'OFF'; CREATE EVENT lower_case ON SCHEDULE EVERY 1 MINUTE DO SELECT 1; CREATE EVENT Lower_case ON SCHEDULE EVERY 2 MINUTE DO SELECT 2; ERROR HY000: Event 'Lower_case' already exists diff --git a/mysql-test/t/events_bugs-master.opt b/mysql-test/t/events_bugs-master.opt new file mode 100644 index 00000000000..f93413a61e5 --- /dev/null +++ b/mysql-test/t/events_bugs-master.opt @@ -0,0 +1 @@ +--event-scheduler diff --git a/mysql-test/t/events_bugs.test b/mysql-test/t/events_bugs.test index ebd86f3a3d2..efdb67349ec 100644 --- a/mysql-test/t/events_bugs.test +++ b/mysql-test/t/events_bugs.test @@ -9,6 +9,21 @@ drop database if exists mysqltest_db2; create database events_test; use events_test; +# +# START: Bug #31332 --event-scheduler option misbehaving +# + +# NOTE!! this test must come first! It's testing that the --event-scheduler +# option with no argument in events_bugs-master.opt turns the scheduler on. + +select * from information_schema.global_variables where variable_name like 'event_scheduler'; + +SET GLOBAL event_scheduler = 'OFF'; + +# +# END: Bug #31332 +# + # # START - 16415: Events: event names are case sensitive # diff --git a/sql/events.cc b/sql/events.cc index 1bfbc5d6645..67249b40c79 100644 --- a/sql/events.cc +++ b/sql/events.cc @@ -146,7 +146,7 @@ bool Events::set_opt_event_scheduler(char *argument) { if (argument == NULL) - opt_event_scheduler= Events::EVENTS_DISABLED; + opt_event_scheduler= Events::EVENTS_ON; else { int type; From c085e424f6e7289e906121051bec62433833b062 Mon Sep 17 00:00:00 2001 From: "tnurnberg@mysql.com/white.intern.koehntopp.de" <> Date: Tue, 23 Oct 2007 06:54:31 +0200 Subject: [PATCH 064/336] Bug #20901: CREATE privilege is enough to insert into a table CREATE TABLE IF NOT EXISTS ... SELECT let you insert into an existing table as long as you had the CREATE privilege. CREATE ... SELECT variants now always require INSERT privilege on target table. --- mysql-test/r/create.result | 38 +++++++++++++++++++ mysql-test/r/grant.result | 6 +-- mysql-test/t/create.test | 76 ++++++++++++++++++++++++++++++++++++++ mysql-test/t/grant.test | 2 +- sql/sql_parse.cc | 9 ++++- 5 files changed, 126 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index aa25c55f394..17894c65109 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -701,3 +701,41 @@ t2 CREATE TABLE `t2` ( drop table t1, t2; create table t1(a set("a,b","c,d") not null); ERROR HY000: Illegal set 'a,b' value found during parsing +create database mysqltest; +use mysqltest; +grant create on mysqltest.* to mysqltest@localhost; +create table t1 (i INT); +insert into t1 values (1); +ERROR 42000: Access denied for user 'mysqltest'@'localhost' to database 'mysqltest' +create table t2 (i INT); +create table t4 (i INT); +grant select, insert on mysqltest.t2 to mysqltest@localhost; +grant insert on mysqltest.t4 to mysqltest@localhost; +grant create, insert on mysqltest.t5 to mysqltest@localhost; +grant create, insert on mysqltest.t6 to mysqltest@localhost; +flush privileges; +insert into t2 values (1); +create table if not exists t1 select * from t2; +ERROR 42000: INSERT command denied to user 'mysqltest'@'localhost' for table 't1' +create table if not exists t3 select * from t2; +ERROR 42000: INSERT command denied to user 'mysqltest'@'localhost' for table 't3' +create table if not exists t4 select * from t2; +Warnings: +Note 1050 Table 't4' already exists +create table if not exists t5 select * from t2; +create table t6 select * from t2; +create table t7 select * from t2; +ERROR 42000: INSERT command denied to user 'mysqltest'@'localhost' for table 't7' +create table t4 select * from t2; +ERROR 42S01: Table 't4' already exists +create table t1 select * from t2; +ERROR 42000: INSERT command denied to user 'mysqltest'@'localhost' for table 't1' +drop table t1,t2,t4,t5,t6; +revoke create on mysqltest.* from mysqltest@localhost; +revoke select, insert on mysqltest.t2 from mysqltest@localhost; +revoke insert on mysqltest.t4 from mysqltest@localhost; +revoke create, insert on mysqltest.t5 from mysqltest@localhost; +revoke create, insert on mysqltest.t6 from mysqltest@localhost; +flush privileges; +drop database mysqltest; +use test; diff --git a/mysql-test/r/grant.result b/mysql-test/r/grant.result index 4e4e2ccff48..2f457a4acbc 100644 --- a/mysql-test/r/grant.result +++ b/mysql-test/r/grant.result @@ -349,12 +349,12 @@ show grants for grant_user@localhost; Grants for grant_user@localhost GRANT USAGE ON *.* TO 'grant_user'@'localhost' GRANT INSERT (a, d, c, b) ON `test`.`t1` TO 'grant_user'@'localhost' -select Host,Db,User,Table_name,Column_name,Column_priv from mysql.columns_priv; +select Host,Db,User,Table_name,Column_name,Column_priv from mysql.columns_priv order by Column_name; Host Db User Table_name Column_name Column_priv -localhost test grant_user t1 b Insert -localhost test grant_user t1 d Insert localhost test grant_user t1 a Insert +localhost test grant_user t1 b Insert localhost test grant_user t1 c Insert +localhost test grant_user t1 d Insert revoke ALL PRIVILEGES on t1 from grant_user@localhost; show grants for grant_user@localhost; Grants for grant_user@localhost diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test index 57b16a13c01..d54615ddb4d 100644 --- a/mysql-test/t/create.test +++ b/mysql-test/t/create.test @@ -609,4 +609,80 @@ drop table t1, t2; --error 1105 create table t1(a set("a,b","c,d") not null); +# +# Bug #20901 - CREATE privilege is enough to insert into a table +# + +create database mysqltest; +use mysqltest; + +grant create on mysqltest.* to mysqltest@localhost; +create table t1 (i INT); + +connect (user1,localhost,mysqltest,,mysqltest); +connection user1; +# show we don't have INSERT +--error 1044 +insert into t1 values (1); +# show we have CREATE +create table t2 (i INT); +create table t4 (i INT); + +connection default; +grant select, insert on mysqltest.t2 to mysqltest@localhost; +grant insert on mysqltest.t4 to mysqltest@localhost; +# to specify ACLs for non-existent objects, must explictly |CREATE +grant create, insert on mysqltest.t5 to mysqltest@localhost; +grant create, insert on mysqltest.t6 to mysqltest@localhost; +flush privileges; + +connection user1; +insert into t2 values (1); + + +# CREATE IF NOT EXISTS...SELECT, t1 exists, no INSERT, must fail +--error 1142 +create table if not exists t1 select * from t2; + +# CREATE IF NOT EXISTS...SELECT, no t3 yet, no INSERT, must fail +--error 1142 +create table if not exists t3 select * from t2; + +# CREATE IF NOT EXISTS...SELECT, t4 exists, have INSERT, must succeed +create table if not exists t4 select * from t2; + +# CREATE IF NOT EXISTS...SELECT, no t5 yet, have INSERT, must succeed +create table if not exists t5 select * from t2; + + +# CREATE...SELECT, no t6 yet, have INSERT, must succeed +create table t6 select * from t2; + +# CREATE...SELECT, no t7 yet, no INSERT, must fail +--error 1142 +create table t7 select * from t2; + +# CREATE...SELECT, t4 exists, have INSERT, must still fail (exists) +--error 1050 +create table t4 select * from t2; + +# CREATE...SELECT, t1 exists, no INSERT, must fail +--error 1142 +create table t1 select * from t2; + + +connection default; +drop table t1,t2,t4,t5,t6; + +revoke create on mysqltest.* from mysqltest@localhost; +revoke select, insert on mysqltest.t2 from mysqltest@localhost; +revoke insert on mysqltest.t4 from mysqltest@localhost; +revoke create, insert on mysqltest.t5 from mysqltest@localhost; +revoke create, insert on mysqltest.t6 from mysqltest@localhost; +flush privileges; + +disconnect user1; +drop database mysqltest; +use test; + # End of 4.1 tests diff --git a/mysql-test/t/grant.test b/mysql-test/t/grant.test index ea148c67262..dcdf3f6f4e0 100644 --- a/mysql-test/t/grant.test +++ b/mysql-test/t/grant.test @@ -296,7 +296,7 @@ DROP DATABASE testdb10; create table t1(a int, b int, c int, d int); grant insert(b), insert(c), insert(d), insert(a) on t1 to grant_user@localhost; show grants for grant_user@localhost; -select Host,Db,User,Table_name,Column_name,Column_priv from mysql.columns_priv; +select Host,Db,User,Table_name,Column_name,Column_priv from mysql.columns_priv order by Column_name; revoke ALL PRIVILEGES on t1 from grant_user@localhost; show grants for grant_user@localhost; select Host,Db,User,Table_name,Column_name,Column_priv from mysql.columns_priv; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 24f9ef30569..880a145903c 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -5832,8 +5832,15 @@ int create_table_precheck(THD *thd, TABLE_LIST *tables, int error= 1; // Error message is given DBUG_ENTER("create_table_precheck"); + /* + Require CREATE [TEMPORARY] privilege on new table; for + CREATE TABLE ... SELECT, also require INSERT. + */ + want_priv= ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ? - CREATE_TMP_ACL : CREATE_ACL); + CREATE_TMP_ACL : CREATE_ACL) | + (select_lex->item_list.elements ? INSERT_ACL : 0); + if (check_access(thd, want_priv, create_table->db, &create_table->grant.privilege, 0, 0) || check_merge_table_access(thd, create_table->db, From 90f391c01388d9c556351ac622a7ef5200c16bba Mon Sep 17 00:00:00 2001 From: "tnurnberg@mysql.com/white.intern.koehntopp.de" <> Date: Tue, 23 Oct 2007 07:09:16 +0200 Subject: [PATCH 065/336] Bug #20901: CREATE privilege is enough to insert into a table CREATE TABLE IF NOT EXISTS ... SELECT let you insert into an existing table as long as you had the CREATE privilege. CREATE ... SELECT variants now always require INSERT privilege on target table. --- mysql-test/r/create.result | 2 +- mysql-test/t/create.test | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index 006dc951297..daafaa1a45a 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -755,7 +755,7 @@ use mysqltest; grant create on mysqltest.* to mysqltest@localhost; create table t1 (i INT); insert into t1 values (1); -ERROR 42000: Access denied for user 'mysqltest'@'localhost' to database 'mysqltest' +ERROR 42000: INSERT command denied to user 'mysqltest'@'localhost' for table 't1' create table t2 (i INT); create table t4 (i INT); grant select, insert on mysqltest.t2 to mysqltest@localhost; diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test index 106ecbb2586..8d76787de5a 100644 --- a/mysql-test/t/create.test +++ b/mysql-test/t/create.test @@ -667,7 +667,7 @@ create table t1 (i INT); connect (user1,localhost,mysqltest,,mysqltest); connection user1; # show we don't have INSERT ---error 1044 +--error 1142 insert into t1 values (1); # show we have CREATE create table t2 (i INT); From acd497ad71bb85f6b2901ed50f45c7782f97d1a9 Mon Sep 17 00:00:00 2001 From: "msvensson@pilot.mysql.com" <> Date: Tue, 23 Oct 2007 11:52:55 +0200 Subject: [PATCH 066/336] Bug#30560 Valgrind option to mysql-test-run with spaces in cause strange error --- mysql-test/mysql-test-run.pl | 48 +++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 1ec91d200a5..b81d2eb0019 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -255,13 +255,13 @@ our $opt_timer= 1; our $opt_user; -our $opt_valgrind= 0; -our $opt_valgrind_mysqld= 0; -our $opt_valgrind_mysqltest= 0; -our $default_valgrind_options= "--show-reachable=yes"; -our $opt_valgrind_options; -our $opt_valgrind_path; -our $opt_callgrind; +my $opt_valgrind= 0; +my $opt_valgrind_mysqld= 0; +my $opt_valgrind_mysqltest= 0; +my @default_valgrind_args= ("--show-reachable=yes"); +my @valgrind_args; +my $opt_valgrind_path; +my $opt_callgrind; our $opt_stress= ""; our $opt_stress_suite= "main"; @@ -575,7 +575,18 @@ sub command_line_setup () { 'valgrind|valgrind-all' => \$opt_valgrind, 'valgrind-mysqltest' => \$opt_valgrind_mysqltest, 'valgrind-mysqld' => \$opt_valgrind_mysqld, - 'valgrind-options=s' => \$opt_valgrind_options, + 'valgrind-options=s' => sub { + my ($opt, $value)= @_; + # Deprecated option unless it's what we know pushbuild uses + if ($value eq "--gen-suppressions=all --show-reachable=yes") { + push(@valgrind_args, $_) for (split(' ', $value)); + return; + } + die("--valgrind-options=s is deprecated. Use ", + "--valgrind-option=s, to be specified several", + " times if necessary"); + }, + 'valgrind-option=s' => \@valgrind_args, 'valgrind-path=s' => \$opt_valgrind_path, 'callgrind' => \$opt_callgrind, @@ -992,7 +1003,7 @@ sub command_line_setup () { # -------------------------------------------------------------------------- # Check valgrind arguments # -------------------------------------------------------------------------- - if ( $opt_valgrind or $opt_valgrind_path or defined $opt_valgrind_options) + if ( $opt_valgrind or $opt_valgrind_path or @valgrind_args) { mtr_report("Turning on valgrind for all executables"); $opt_valgrind= 1; @@ -1017,17 +1028,18 @@ sub command_line_setup () { $opt_valgrind_mysqld= 1; # Set special valgrind options unless options passed on command line - $opt_valgrind_options="--trace-children=yes" - unless defined $opt_valgrind_options; + push(@valgrind_args, "--trace-children=yes") + unless @valgrind_args; } if ( $opt_valgrind ) { # Set valgrind_options to default unless already defined - $opt_valgrind_options=$default_valgrind_options - unless defined $opt_valgrind_options; + push(@valgrind_args, @default_valgrind_args) + unless @valgrind_args; - mtr_report("Running valgrind with options \"$opt_valgrind_options\""); + mtr_report("Running valgrind with options \"", + join(" ", @valgrind_args), "\""); } if ( ! $opt_testcase_timeout ) @@ -5008,7 +5020,7 @@ sub valgrind_arguments { } # Add valgrind options, can be overriden by user - mtr_add_arg($args, '%s', $opt_valgrind_options); + mtr_add_arg($args, '%s', $_) for (@valgrind_args); mtr_add_arg($args, $$exe); @@ -5148,12 +5160,14 @@ Options for coverage, profiling etc gcov FIXME gprof FIXME valgrind Run the "mysqltest" and "mysqld" executables using - valgrind with options($default_valgrind_options) + valgrind with default options valgrind-all Synonym for --valgrind valgrind-mysqltest Run the "mysqltest" and "mysql_client_test" executable with valgrind valgrind-mysqld Run the "mysqld" executable with valgrind - valgrind-options=ARGS Options to give valgrind, replaces default options + valgrind-options=ARGS Deprecated, use --valgrind-option + valgrind-option=ARGS Option to give valgrind, replaces default option(s), + can be specified more then once valgrind-path=[EXE] Path to the valgrind executable callgrind Instruct valgrind to use callgrind From 5adc332c632e1af62294820ed84e94409894c142 Mon Sep 17 00:00:00 2001 From: "gshchepa/uchum@gleb.loc" <> Date: Tue, 23 Oct 2007 16:16:59 +0500 Subject: [PATCH 067/336] Fixed bug #31663: if the FIELDS TERMINATED BY string in the SELECT INTO OUTFILE clause starts with a special character (one of n, t, r, b, 0, Z or N) and ENCLOSED BY is empty, every occurrence of this character within a field value is duplicated. Duplication has been avoided. New warning message has been added: "First character of the FIELDS TERMINATED string is ambiguous; please use non-optional and non-empty FIELDS ENCLOSED BY". --- mysql-test/r/outfile_loaddata.result | 85 ++++++++++++++++++++++++++ mysql-test/t/outfile_loaddata.test | 89 ++++++++++++++++++++++++++++ sql/share/errmsg.txt | 2 + sql/sql_class.cc | 44 +++++++++++--- sql/sql_class.h | 7 +++ 5 files changed, 218 insertions(+), 9 deletions(-) create mode 100644 mysql-test/r/outfile_loaddata.result create mode 100644 mysql-test/t/outfile_loaddata.test diff --git a/mysql-test/r/outfile_loaddata.result b/mysql-test/r/outfile_loaddata.result new file mode 100644 index 00000000000..1bcaf308b7c --- /dev/null +++ b/mysql-test/r/outfile_loaddata.result @@ -0,0 +1,85 @@ +DROP TABLE IF EXISTS t1, t2; +# +# Bug#31663 FIELDS TERMINATED BY special character +# +CREATE TABLE t1 (i1 int, i2 int, c1 VARCHAR(256), c2 VARCHAR(256)); +INSERT INTO t1 VALUES (101, 202, '-r-', '=raker='); +# FIELDS TERMINATED BY 'raker', warning: +SELECT * INTO OUTFILE 'MYSQLTEST_VARDIR/tmp/bug31663.txt' FIELDS TERMINATED BY 'raker' FROM t1; +Warnings: +Warning 1475 First character of the FIELDS TERMINATED string is ambiguous; please use non-optional and non-empty FIELDS ENCLOSED BY +SELECT LOAD_FILE('MYSQLTEST_VARDIR/tmp/bug31663.txt'); +LOAD_FILE('MYSQLTEST_VARDIR/tmp/bug31663.txt') +101raker202raker-r-raker=raker= + +CREATE TABLE t2 SELECT * FROM t1; +LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/bug31663.txt' INTO TABLE t2 FIELDS TERMINATED BY 'raker'; +Warnings: +Warning 1262 Row 1 was truncated; it contained more data than there were input columns +SELECT * FROM t2; +i1 i2 c1 c2 +101 202 -r- =raker= +101 202 -r- = +DROP TABLE t2; +# Only numeric fields, FIELDS TERMINATED BY 'r', no warnings: +SELECT i1, i2 INTO OUTFILE 'MYSQLTEST_VARDIR/tmp/bug31663.txt' FIELDS TERMINATED BY 'r' FROM t1; +SELECT LOAD_FILE('MYSQLTEST_VARDIR/tmp/bug31663.txt'); +LOAD_FILE('MYSQLTEST_VARDIR/tmp/bug31663.txt') +101r202 + +CREATE TABLE t2 SELECT i1, i2 FROM t1; +LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/bug31663.txt' INTO TABLE t2 FIELDS TERMINATED BY 'r'; +SELECT i1, i2 FROM t2; +i1 i2 +101 202 +101 202 +DROP TABLE t2; +# FIELDS TERMINATED BY '0', warning: +SELECT * INTO OUTFILE 'MYSQLTEST_VARDIR/tmp/bug31663.txt' FIELDS TERMINATED BY '0' FROM t1; +Warnings: +Warning 1475 First character of the FIELDS TERMINATED string is ambiguous; please use non-optional and non-empty FIELDS ENCLOSED BY +SELECT LOAD_FILE('MYSQLTEST_VARDIR/tmp/bug31663.txt'); +LOAD_FILE('MYSQLTEST_VARDIR/tmp/bug31663.txt') +10102020-r-0=raker= + +CREATE TABLE t2 SELECT * FROM t1; +LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/bug31663.txt' INTO TABLE t2 FIELDS TERMINATED BY '0'; +Warnings: +Warning 1262 Row 1 was truncated; it contained more data than there were input columns +SELECT * FROM t2; +i1 i2 c1 c2 +101 202 -r- =raker= +1 1 2 2 +DROP TABLE t2; +# FIELDS OPTIONALLY ENCLOSED BY '"' TERMINATED BY '0', warning: +SELECT * INTO OUTFILE 'MYSQLTEST_VARDIR/tmp/bug31663.txt' FIELDS OPTIONALLY ENCLOSED BY '"' TERMINATED BY '0' FROM t1; +Warnings: +Warning 1475 First character of the FIELDS TERMINATED string is ambiguous; please use non-optional and non-empty FIELDS ENCLOSED BY +SELECT LOAD_FILE('MYSQLTEST_VARDIR/tmp/bug31663.txt'); +LOAD_FILE('MYSQLTEST_VARDIR/tmp/bug31663.txt') +10102020"-r-"0"=raker=" + +CREATE TABLE t2 SELECT * FROM t1; +LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/bug31663.txt' INTO TABLE t2 FIELDS OPTIONALLY ENCLOSED BY '"' TERMINATED BY '0'; +Warnings: +Warning 1262 Row 1 was truncated; it contained more data than there were input columns +SELECT * FROM t2; +i1 i2 c1 c2 +101 202 -r- =raker= +1 1 2 2 +DROP TABLE t2; +# Only string fields, FIELDS OPTIONALLY ENCLOSED BY '"' TERMINATED BY '0', no warnings: +SELECT c1, c2 INTO OUTFILE 'MYSQLTEST_VARDIR/tmp/bug31663.txt' FIELDS OPTIONALLY ENCLOSED BY '"' TERMINATED BY '0' FROM t1; +SELECT LOAD_FILE('MYSQLTEST_VARDIR/tmp/bug31663.txt'); +LOAD_FILE('MYSQLTEST_VARDIR/tmp/bug31663.txt') +"-r-"0"=raker=" + +CREATE TABLE t2 SELECT c1, c2 FROM t1; +LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/bug31663.txt' INTO TABLE t2 FIELDS OPTIONALLY ENCLOSED BY '"' TERMINATED BY '0'; +SELECT c1, c2 FROM t2; +c1 c2 +-r- =raker= +-r- =raker= +DROP TABLE t2; +DROP TABLE t1; +# End of 5.0 tests. diff --git a/mysql-test/t/outfile_loaddata.test b/mysql-test/t/outfile_loaddata.test new file mode 100644 index 00000000000..2f6ac998b3d --- /dev/null +++ b/mysql-test/t/outfile_loaddata.test @@ -0,0 +1,89 @@ +--disable_warnings +DROP TABLE IF EXISTS t1, t2; +--enable_warnings + +--echo # +--echo # Bug#31663 FIELDS TERMINATED BY special character +--echo # + +CREATE TABLE t1 (i1 int, i2 int, c1 VARCHAR(256), c2 VARCHAR(256)); +INSERT INTO t1 VALUES (101, 202, '-r-', '=raker='); + +--let $fields=* +--let $clauses=FIELDS TERMINATED BY 'raker' +--echo # $clauses, warning: + +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--eval SELECT $fields INTO OUTFILE '$MYSQLTEST_VARDIR/tmp/bug31663.txt' $clauses FROM t1 +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--eval SELECT LOAD_FILE('$MYSQLTEST_VARDIR/tmp/bug31663.txt') +--eval CREATE TABLE t2 SELECT $fields FROM t1 +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--eval LOAD DATA INFILE '$MYSQLTEST_VARDIR/tmp/bug31663.txt' INTO TABLE t2 $clauses +--eval SELECT $fields FROM t2 +--remove_file $MYSQLTEST_VARDIR/tmp/bug31663.txt +DROP TABLE t2; + +--let $fields=i1, i2 +--let $clauses=FIELDS TERMINATED BY 'r' +--echo # Only numeric fields, $clauses, no warnings: + +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--eval SELECT $fields INTO OUTFILE '$MYSQLTEST_VARDIR/tmp/bug31663.txt' $clauses FROM t1 +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--eval SELECT LOAD_FILE('$MYSQLTEST_VARDIR/tmp/bug31663.txt') +--eval CREATE TABLE t2 SELECT $fields FROM t1 +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--eval LOAD DATA INFILE '$MYSQLTEST_VARDIR/tmp/bug31663.txt' INTO TABLE t2 $clauses +--eval SELECT $fields FROM t2 +--remove_file $MYSQLTEST_VARDIR/tmp/bug31663.txt +DROP TABLE t2; + +--let $fields=* +--let $clauses=FIELDS TERMINATED BY '0' +--echo # $clauses, warning: + +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--eval SELECT $fields INTO OUTFILE '$MYSQLTEST_VARDIR/tmp/bug31663.txt' $clauses FROM t1 +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--eval SELECT LOAD_FILE('$MYSQLTEST_VARDIR/tmp/bug31663.txt') +--eval CREATE TABLE t2 SELECT $fields FROM t1 +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--eval LOAD DATA INFILE '$MYSQLTEST_VARDIR/tmp/bug31663.txt' INTO TABLE t2 $clauses +--eval SELECT $fields FROM t2 +--remove_file $MYSQLTEST_VARDIR/tmp/bug31663.txt +DROP TABLE t2; + +--let $fields=* +--let $clauses=FIELDS OPTIONALLY ENCLOSED BY '"' TERMINATED BY '0' +--echo # $clauses, warning: + +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--eval SELECT $fields INTO OUTFILE '$MYSQLTEST_VARDIR/tmp/bug31663.txt' $clauses FROM t1 +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--eval SELECT LOAD_FILE('$MYSQLTEST_VARDIR/tmp/bug31663.txt') +--eval CREATE TABLE t2 SELECT $fields FROM t1 +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--eval LOAD DATA INFILE '$MYSQLTEST_VARDIR/tmp/bug31663.txt' INTO TABLE t2 $clauses +--eval SELECT $fields FROM t2 +--remove_file $MYSQLTEST_VARDIR/tmp/bug31663.txt +DROP TABLE t2; + +--let $fields=c1, c2 +--let $clauses=FIELDS OPTIONALLY ENCLOSED BY '"' TERMINATED BY '0' +--echo # Only string fields, $clauses, no warnings: + +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--eval SELECT $fields INTO OUTFILE '$MYSQLTEST_VARDIR/tmp/bug31663.txt' $clauses FROM t1 +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--eval SELECT LOAD_FILE('$MYSQLTEST_VARDIR/tmp/bug31663.txt') +--eval CREATE TABLE t2 SELECT $fields FROM t1 +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--eval LOAD DATA INFILE '$MYSQLTEST_VARDIR/tmp/bug31663.txt' INTO TABLE t2 $clauses +--eval SELECT $fields FROM t2 +--remove_file $MYSQLTEST_VARDIR/tmp/bug31663.txt +DROP TABLE t2; + +DROP TABLE t1; + +--echo # End of 5.0 tests. diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 709cd1fc0a9..9e6cf462113 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5639,3 +5639,5 @@ ER_TOO_HIGH_LEVEL_OF_NESTING_FOR_SELECT eng "Too high level of nesting for select" ER_NAME_BECOMES_EMPTY eng "Name '%-.64s' has become ''" +ER_AMBIGUOUS_FIELD_TERM + eng "First character of the FIELDS TERMINATED string is ambiguous; please use non-optional and non-empty FIELDS ENCLOSED BY" diff --git a/sql/sql_class.cc b/sql/sql_class.cc index b67f63778dc..1836989f2fa 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1194,6 +1194,7 @@ int select_export::prepare(List &list, SELECT_LEX_UNIT *u) { bool blob_flag=0; + bool string_results= FALSE, non_string_results= FALSE; unit= u; if ((uint) strlen(exchange->file_name) + NAME_LEN >= FN_REFLEN) strmake(path,exchange->file_name,FN_REFLEN-1); @@ -1211,13 +1212,18 @@ select_export::prepare(List &list, SELECT_LEX_UNIT *u) blob_flag=1; break; } + if (item->result_type() == STRING_RESULT) + string_results= TRUE; + else + non_string_results= TRUE; } } field_term_length=exchange->field_term->length(); + field_term_char= field_term_length ? (*exchange->field_term)[0] : INT_MAX; if (!exchange->line_term->length()) exchange->line_term=exchange->field_term; // Use this if it exists field_sep_char= (exchange->enclosed->length() ? (*exchange->enclosed)[0] : - field_term_length ? (*exchange->field_term)[0] : INT_MAX); + field_term_char); escape_char= (exchange->escaped->length() ? (*exchange->escaped)[0] : -1); is_ambiguous_field_sep= test(strchr(ESCAPE_CHARS, field_sep_char)); is_unsafe_field_sep= test(strchr(NUMERIC_CHARS, field_sep_char)); @@ -1229,12 +1235,25 @@ select_export::prepare(List &list, SELECT_LEX_UNIT *u) exchange->opt_enclosed=1; // A little quicker loop fixed_row_size= (!field_term_length && !exchange->enclosed->length() && !blob_flag); + if ((is_ambiguous_field_sep && exchange->enclosed->is_empty() && + (string_results || is_unsafe_field_sep)) || + (exchange->opt_enclosed && non_string_results && + field_term_length && strchr(NUMERIC_CHARS, field_term_char))) + { + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_AMBIGUOUS_FIELD_TERM, ER(ER_AMBIGUOUS_FIELD_TERM)); + is_ambiguous_field_term= TRUE; + } + else + is_ambiguous_field_term= FALSE; + return 0; } #define NEED_ESCAPING(x) ((int) (uchar) (x) == escape_char || \ - (int) (uchar) (x) == field_sep_char || \ + (enclosed ? (int) (uchar) (x) == field_sep_char \ + : (int) (uchar) (x) == field_term_char) || \ (int) (uchar) (x) == line_sep_char || \ !(x)) @@ -1263,8 +1282,10 @@ bool select_export::send_data(List &items) while ((item=li++)) { Item_result result_type=item->result_type(); + bool enclosed = (exchange->enclosed->length() && + (!exchange->opt_enclosed || result_type == STRING_RESULT)); res=item->str_result(&tmp); - if (res && (!exchange->opt_enclosed || result_type == STRING_RESULT)) + if (res && enclosed) { if (my_b_write(&cache,(byte*) exchange->enclosed->ptr(), exchange->enclosed->length())) @@ -1355,11 +1376,16 @@ bool select_export::send_data(List &items) DBUG_ASSERT before the loop makes that sure. */ - if (NEED_ESCAPING(*pos) || - (check_second_byte && - my_mbcharlen(character_set_client, (uchar) *pos) == 2 && - pos + 1 < end && - NEED_ESCAPING(pos[1]))) + if ((NEED_ESCAPING(*pos) || + (check_second_byte && + my_mbcharlen(character_set_client, (uchar) *pos) == 2 && + pos + 1 < end && + NEED_ESCAPING(pos[1]))) && + /* + Don't escape field_term_char by doubling - doubling is only + valid for ENCLOSED BY characters: + */ + (enclosed || !is_ambiguous_field_term || *pos != field_term_char)) { char tmp_buff[2]; tmp_buff[0]= ((int) *pos == field_sep_char && @@ -1398,7 +1424,7 @@ bool select_export::send_data(List &items) goto err; } } - if (res && (!exchange->opt_enclosed || result_type == STRING_RESULT)) + if (res && enclosed) { if (my_b_write(&cache, (byte*) exchange->enclosed->ptr(), exchange->enclosed->length())) diff --git a/sql/sql_class.h b/sql/sql_class.h index e6d65f3133a..62b1008e59c 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1992,12 +1992,19 @@ public: class select_export :public select_to_file { uint field_term_length; int field_sep_char,escape_char,line_sep_char; + int field_term_char; // first char of FIELDS TERMINATED BY or MAX_INT /* The is_ambiguous_field_sep field is true if a value of the field_sep_char field is one of the 'n', 't', 'r' etc characters (see the READ_INFO::unescape method and the ESCAPE_CHARS constant value). */ bool is_ambiguous_field_sep; + /* + The is_ambiguous_field_term is true if field_sep_char contains the first + char of the FIELDS TERMINATED BY (ENCLOSED BY is empty), and items can + contain this character. + */ + bool is_ambiguous_field_term; /* The is_unsafe_field_sep field is true if a value of the field_sep_char field is one of the '0'..'9', '+', '-', '.' and 'e' characters From 28e5063d933b130990f1c028b891870de4088ade Mon Sep 17 00:00:00 2001 From: "sergefp@mysql.com" <> Date: Tue, 23 Oct 2007 19:24:59 +0400 Subject: [PATCH 068/336] BUG#31450: Query causes error 1048 - Let Item::save_in_field() call set_field_to_null_with_conversions() for decimal type, like this is done for the other item result types. --- mysql-test/r/type_decimal.result | 11 +++++++++++ mysql-test/t/type_decimal.test | 19 +++++++++++++++++++ sql/item.cc | 2 +- 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/type_decimal.result b/mysql-test/r/type_decimal.result index 72f827f11ed..594da466644 100644 --- a/mysql-test/r/type_decimal.result +++ b/mysql-test/r/type_decimal.result @@ -805,3 +805,14 @@ SELECT 1 % .12345678912345678912345678912345678912345678912345678912345678912345 SELECT MOD(1, .123456789123456789123456789123456789123456789123456789123456789123456789123456789) AS 'MOD()'; MOD() 0.012345687012345687012345687012345687012345687012345687012345687012345687000000000 +create table t1 ( +ua_id decimal(22,0) not null, +ua_invited_by_id decimal(22,0) default NULL, +primary key(ua_id) +); +insert into t1 values (123, NULL), (456, NULL); +this must not produce error 1048: +select * from t1 where ua_invited_by_id not in (select ua_id from t1); +ua_id ua_invited_by_id +drop table t1; +End of 5.0 tests diff --git a/mysql-test/t/type_decimal.test b/mysql-test/t/type_decimal.test index c154b2685dd..38eb1ebb984 100644 --- a/mysql-test/t/type_decimal.test +++ b/mysql-test/t/type_decimal.test @@ -416,3 +416,22 @@ DROP TABLE t1; SELECT 1 % .123456789123456789123456789123456789123456789123456789123456789123456789123456789 AS '%'; SELECT MOD(1, .123456789123456789123456789123456789123456789123456789123456789123456789123456789) AS 'MOD()'; + + +# +# BUG#31450 "Query causes error 1048" +# +create table t1 ( + ua_id decimal(22,0) not null, + ua_invited_by_id decimal(22,0) default NULL, + primary key(ua_id) +); +insert into t1 values (123, NULL), (456, NULL); + +--echo this must not produce error 1048: +select * from t1 where ua_invited_by_id not in (select ua_id from t1); + +drop table t1; + +--echo End of 5.0 tests + diff --git a/sql/item.cc b/sql/item.cc index 83cbf261b8a..739fe7967e2 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -4548,7 +4548,7 @@ int Item::save_in_field(Field *field, bool no_conversions) my_decimal decimal_value; my_decimal *value= val_decimal(&decimal_value); if (null_value) - return set_field_to_null(field); + return set_field_to_null_with_conversions(field, no_conversions); field->set_notnull(); error=field->store_decimal(value); } From 7ca65155ad07834d136190a4d55a512e86df1fd5 Mon Sep 17 00:00:00 2001 From: "sergefp@mysql.com" <> Date: Tue, 23 Oct 2007 21:32:30 +0400 Subject: [PATCH 069/336] Post-merge fixes --- mysql-test/r/type_decimal.result | 1 + mysql-test/t/type_decimal.test | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/mysql-test/r/type_decimal.result b/mysql-test/r/type_decimal.result index 8dd4f6aaaf4..b550536d0db 100644 --- a/mysql-test/r/type_decimal.result +++ b/mysql-test/r/type_decimal.result @@ -811,6 +811,7 @@ insert into t1 values (-0.123456,0.123456); select group_concat(f1),group_concat(f2) from t1; group_concat(f1) group_concat(f2) -0.123456 0.123456 +drop table t1; create table t1 ( ua_id decimal(22,0) not null, ua_invited_by_id decimal(22,0) default NULL, diff --git a/mysql-test/t/type_decimal.test b/mysql-test/t/type_decimal.test index 4d61350a613..12d4398dd57 100644 --- a/mysql-test/t/type_decimal.test +++ b/mysql-test/t/type_decimal.test @@ -425,5 +425,20 @@ insert into t1 values (-0.123456,0.123456); select group_concat(f1),group_concat(f2) from t1; drop table t1; +# +# BUG#31450 "Query causes error 1048" +# +create table t1 ( + ua_id decimal(22,0) not null, + ua_invited_by_id decimal(22,0) default NULL, + primary key(ua_id) +); +insert into t1 values (123, NULL), (456, NULL); + +--echo this must not produce error 1048: +select * from t1 where ua_invited_by_id not in (select ua_id from t1); + +drop table t1; + --echo End of 5.0 tests From f733ea5a06862d32725a2153a01d137eed54ee77 Mon Sep 17 00:00:00 2001 From: "mattiasj@mattiasj-laptop.(none)" <> Date: Tue, 23 Oct 2007 22:04:09 +0200 Subject: [PATCH 070/336] Bug #30695: An apostrophe ' in the comment of the ADD PARTITION causes the Server to crash. Accessing partitioned table with an apostrophe in partition options like DATA DIRECTORY, INDEX DIRECTORY or COMMENT causes server crash. Partition options were saved in .frm file without escaping. When accessing such table it is not possible to properly restore partition information. Crashed because there was no check for partition info parser failure. Fixed by escaping quoted text in the partition info when writing it to the frm-file and added a check that it was able to parse the partition info before using it NOTE: If the comment is written by an earlier version of the server, the corrupted frm-file is not fixed, but left corrupted, you have to manually drop the table and recreate it. --- mysql-test/r/partition.result | 16 ++++++++++++++++ mysql-test/t/partition.test | 26 ++++++++++++++++++++++++++ sql/sql_partition.cc | 21 +++++++++++++++++---- sql/table.cc | 3 ++- 4 files changed, 61 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/partition.result b/mysql-test/r/partition.result index 5d985d053fc..2057b18de3d 100644 --- a/mysql-test/r/partition.result +++ b/mysql-test/r/partition.result @@ -1,4 +1,20 @@ drop table if exists t1; +CREATE TABLE t1 ( +d DATE NOT NULL +) +PARTITION BY RANGE( YEAR(d) ) ( +PARTITION p0 VALUES LESS THAN (1960), +PARTITION p1 VALUES LESS THAN (1970), +PARTITION p2 VALUES LESS THAN (1980), +PARTITION p3 VALUES LESS THAN (1990) +); +ALTER TABLE t1 ADD PARTITION ( +PARTITION `p5` VALUES LESS THAN (2010) +COMMENT 'APSTART \' APEND' +); +SELECT * FROM t1 LIMIT 1; +d +DROP TABLE t1; create table t1 (a int) partition by key(a) partitions 0.2+e1; diff --git a/mysql-test/t/partition.test b/mysql-test/t/partition.test index 42db23dadef..53454b132e9 100644 --- a/mysql-test/t/partition.test +++ b/mysql-test/t/partition.test @@ -9,6 +9,32 @@ drop table if exists t1; --enable_warnings +# +# Bug #30695: An apostrophe ' in the comment of the ADD PARTITION causes the Server to crash. +# +# To verify the fix for crashing (on unix-type OS) +# uncomment the exec and error rows! + +CREATE TABLE t1 ( + d DATE NOT NULL +) +PARTITION BY RANGE( YEAR(d) ) ( + PARTITION p0 VALUES LESS THAN (1960), + PARTITION p1 VALUES LESS THAN (1970), + PARTITION p2 VALUES LESS THAN (1980), + PARTITION p3 VALUES LESS THAN (1990) +); + +ALTER TABLE t1 ADD PARTITION ( +PARTITION `p5` VALUES LESS THAN (2010) +COMMENT 'APSTART \' APEND' +); +#--exec sed 's/APSTART \\/APSTART /' var/master-data/test/t1.frm > tmpt1.frm && mv tmpt1.frm var/master-data/test/t1.frm +#--error 1064 +SELECT * FROM t1 LIMIT 1; + +DROP TABLE t1; + # # Bug 15890: Strange number of partitions accepted # diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 8a8a03cb4e4..3ad2cbfb284 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -1849,6 +1849,20 @@ static int add_uint(File fptr, ulonglong number) return add_string(fptr, buff); } +/* + Must escape strings in partitioned tables frm-files, + parsing it later with mysql_unpack_partition will fail otherwise. +*/ +static int add_quoted_string(File fptr, const char *quotestr) +{ + String orgstr(quotestr, system_charset_info); + String escapedstr; + int err= add_string(fptr, "'"); + err+= append_escaped(&escapedstr, &orgstr); + err+= add_string(fptr, escapedstr.c_ptr()); + return err + add_string(fptr, "'"); +} + static int add_keyword_string(File fptr, const char *keyword, bool should_use_quotes, const char *keystr) @@ -1859,10 +1873,9 @@ static int add_keyword_string(File fptr, const char *keyword, err+= add_equal(fptr); err+= add_space(fptr); if (should_use_quotes) - err+= add_string(fptr, "'"); - err+= add_string(fptr, keystr); - if (should_use_quotes) - err+= add_string(fptr, "'"); + err+= add_quoted_string(fptr, keystr); + else + err+= add_string(fptr, keystr); return err + add_space(fptr); } diff --git a/sql/table.cc b/sql/table.cc index ccddbf8134b..7cf5eeaaad6 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -1782,7 +1782,8 @@ int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias, outparam, is_create_table, share->default_part_db_type, &work_part_info_used); - outparam->part_info->is_auto_partitioned= share->auto_partitioned; + if (!tmp) + outparam->part_info->is_auto_partitioned= share->auto_partitioned; DBUG_PRINT("info", ("autopartitioned: %u", share->auto_partitioned)); /* we should perform the fix_partition_func in either local or caller's arena depending on work_part_info_used value From 5cfd557fad08a36ad5fd55284c8b625d7754af33 Mon Sep 17 00:00:00 2001 From: "bar@mysql.com/bar.myoffice.izhnet.ru" <> Date: Wed, 24 Oct 2007 12:08:33 +0500 Subject: [PATCH 071/336] Bug#31081 server crash in regexp function Additional fix for valgrind warning --- sql/item_cmpfunc.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 51b3e8cda6b..59e11b81c17 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -4255,7 +4255,7 @@ Item_func_regex::regcomp(bool send_error) res= &conv; } - if ((error= my_regcomp(&preg, res->c_ptr(), + if ((error= my_regcomp(&preg, res->c_ptr_safe(), regex_lib_flags, regex_lib_charset))) { if (send_error) From 54cea40003b09f8c339b89d186a65f78e641f941 Mon Sep 17 00:00:00 2001 From: "gkodinov/kgeorge@magare.gmz" <> Date: Wed, 24 Oct 2007 11:15:08 +0300 Subject: [PATCH 072/336] Bug #30715: Assertion failed: item_field->field->real_maybe_null(), file .\opt_sum.cc, line The optimizer pre-calculates the MIN/MAX values for queries like SELECT MIN(kp_k) WHERE kp_1 = const AND ... AND kp_k-1 = const when there is a key over kp_1...kp_k In doing so it was not checking correctly nullability and there was a superfluous assert(). Fixed by making sure that the field can be null before checking and taking out the wrong assert(). . Introduced a correct check for nullability The MIN(field) can return NULL when all the row values in the group are NULL-able or if there were no rows. Fixed the assertion to reflect the case when there are no rows. --- mysql-test/r/func_group.result | 5 +++++ mysql-test/t/func_group.test | 9 +++++++++ sql/opt_sum.cc | 10 +++++----- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result index 3a2cb26910a..e7f27ebb07e 100644 --- a/mysql-test/r/func_group.result +++ b/mysql-test/r/func_group.result @@ -1387,4 +1387,9 @@ SELECT 1 FROM t1 GROUP BY (SELECT SLEEP(0) FROM t1 ORDER BY AVG(DISTINCT a) ); 1 1 DROP TABLE t1; +CREATE TABLE t1 (a int, b date NOT NULL, KEY k1 (a,b)); +SELECT MIN(b) FROM t1 WHERE a=1 AND b>'2007-08-01'; +MIN(b) +NULL +DROP TABLE t1; End of 5.0 tests diff --git a/mysql-test/t/func_group.test b/mysql-test/t/func_group.test index 8c020eb3dc8..7e115707625 100644 --- a/mysql-test/t/func_group.test +++ b/mysql-test/t/func_group.test @@ -873,5 +873,14 @@ SELECT 1 FROM t1 GROUP BY (SELECT SLEEP(0) FROM t1 ORDER BY AVG(DISTINCT a) ); DROP TABLE t1; +# +# Bug #30715: Assertion failed: item_field->field->real_maybe_null(), file +# .\opt_sum.cc, line +# + +CREATE TABLE t1 (a int, b date NOT NULL, KEY k1 (a,b)); +SELECT MIN(b) FROM t1 WHERE a=1 AND b>'2007-08-01'; +DROP TABLE t1; + ### --echo End of 5.0 tests diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc index b9de54dbf5c..3fc62d05ae5 100644 --- a/sql/opt_sum.cc +++ b/sql/opt_sum.cc @@ -249,20 +249,20 @@ int opt_sum_query(TABLE_LIST *tables, List &all_fields,COND *conds) Check if case 1 from above holds. If it does, we should read the skipped tuple. */ - if (ref.key_buff[prefix_len] == 1 && - /* + if (item_field->field->real_maybe_null() && + ref.key_buff[prefix_len] == 1 && + /* Last keypart (i.e. the argument to MIN) is set to NULL by find_key_for_maxmin only if all other keyparts are bound to constants in a conjunction of equalities. Hence, we can detect this by checking only if the last keypart is NULL. - */ + */ (error == HA_ERR_KEY_NOT_FOUND || key_cmp_if_same(table, ref.key_buff, ref.key, prefix_len))) { - DBUG_ASSERT(item_field->field->real_maybe_null()); error= table->file->index_read(table->record[0], ref.key_buff, - ref.key_length, + ref.key_length, HA_READ_KEY_EXACT); } } From c380020a7e70a8fdfefb72f9aafa3657577ff176 Mon Sep 17 00:00:00 2001 From: "ramil/ram@mysql.com/ramil.myoffice.izhnet.ru" <> Date: Wed, 24 Oct 2007 13:28:46 +0500 Subject: [PATCH 073/336] after-merge fix: new sys_var_character_set_client classs introduced to perform separate checking. --- sql/set_var.cc | 25 ++++++++++++++++++++++++- sql/set_var.h | 14 ++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/sql/set_var.cc b/sql/set_var.cc index b6b102aa4d0..8ab91caf1f3 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -164,7 +164,8 @@ static sys_var_character_set_sv sys_character_set_server(&vars, "character_set_s sys_var_const_str sys_charset_system(&vars, "character_set_system", (char *)my_charset_utf8_general_ci.name); static sys_var_character_set_database sys_character_set_database(&vars, "character_set_database"); -static sys_var_character_set_sv sys_character_set_client(&vars, "character_set_client", +static sys_var_character_set_client sys_character_set_client(&vars, + "character_set_client", &SV::character_set_client, &default_charset_info); static sys_var_character_set_sv sys_character_set_connection(&vars, "character_set_connection", @@ -1861,6 +1862,21 @@ CHARSET_INFO **sys_var_character_set_sv::ci_ptr(THD *thd, enum_var_type type) } +bool sys_var_character_set_client::check(THD *thd, set_var *var) +{ + if (sys_var_character_set_sv::check(thd, var)) + return 1; + /* Currently, UCS-2 cannot be used as a client character set */ + if (var->save_result.charset->mbminlen > 1) + { + my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name, + var->save_result.charset->csname); + return 1; + } + return 0; +} + + CHARSET_INFO ** sys_var_character_set_database::ci_ptr(THD *thd, enum_var_type type) { @@ -2290,6 +2306,13 @@ uchar *sys_var_log_output::value_ptr(THD *thd, enum_var_type type, int set_var_collation_client::check(THD *thd) { + /* Currently, UCS-2 cannot be used as a client character set */ + if (character_set_client->mbminlen > 1) + { + my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), "character_set_client", + character_set_client->csname); + return 1; + } return 0; } diff --git a/sql/set_var.h b/sql/set_var.h index eb2c893c89e..0e282212a3f 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -667,6 +667,20 @@ public: }; +class sys_var_character_set_client: public sys_var_character_set_sv +{ +public: + sys_var_character_set_client(sys_var_chain *chain, const char *name_arg, + CHARSET_INFO *SV::*offset_arg, + CHARSET_INFO **global_default_arg, + bool is_nullable= 0) + : sys_var_character_set_sv(chain, name_arg, offset_arg, global_default_arg, + is_nullable) + { } + bool check(THD *thd, set_var *var); +}; + + class sys_var_character_set_database :public sys_var_character_set { public: From 5d1ccce58ac10b2abff245734cd8e3f5ed2e9f67 Mon Sep 17 00:00:00 2001 From: "svoj@mysql.com/june.mysql.com" <> Date: Wed, 24 Oct 2007 16:09:30 +0500 Subject: [PATCH 074/336] BUG#31159 - fulltext search on ucs2 column crashes server ucs2 doesn't provide required by fulltext ctype array. Crash happens because fulltext attempts to use unitialized ctype array. Fixed by converting ucs2 fields to compatible utf8 analogue. --- include/my_sys.h | 2 ++ mysql-test/r/ctype_ucs.result | 6 ++++++ mysql-test/t/ctype_ucs.test | 8 +++++++ mysys/charset.c | 40 +++++++++++++++++++++++++++++++++++ sql/item_func.cc | 33 ++++++++++++++++++++++++++++- 5 files changed, 88 insertions(+), 1 deletion(-) diff --git a/include/my_sys.h b/include/my_sys.h index 759531fa649..4a0586b9f2d 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -784,6 +784,8 @@ extern CHARSET_INFO *get_charset(uint cs_number, myf flags); extern CHARSET_INFO *get_charset_by_name(const char *cs_name, myf flags); extern CHARSET_INFO *get_charset_by_csname(const char *cs_name, uint cs_flags, myf my_flags); +extern CHARSET_INFO *get_compatible_charset_with_ctype(CHARSET_INFO + *original_cs); extern void free_charsets(void); extern char *get_charsets_dir(char *buf); extern my_bool my_charset_same(CHARSET_INFO *cs1, CHARSET_INFO *cs2); diff --git a/mysql-test/r/ctype_ucs.result b/mysql-test/r/ctype_ucs.result index bf827209795..fef13b19ae8 100644 --- a/mysql-test/r/ctype_ucs.result +++ b/mysql-test/r/ctype_ucs.result @@ -803,4 +803,10 @@ quote(name) ???????? ???????????????? drop table bug20536; +CREATE TABLE t1(a TEXT CHARSET ucs2 COLLATE ucs2_unicode_ci); +INSERT INTO t1 VALUES('abcd'); +SELECT * FROM t1 WHERE MATCH(a) AGAINST ('+abcd' IN BOOLEAN MODE); +a +abcd +DROP TABLE t1; End of 4.1 tests diff --git a/mysql-test/t/ctype_ucs.test b/mysql-test/t/ctype_ucs.test index 10559d33eb3..57f741597e0 100644 --- a/mysql-test/t/ctype_ucs.test +++ b/mysql-test/t/ctype_ucs.test @@ -535,4 +535,12 @@ select quote(name) from bug20536; drop table bug20536; +# +# BUG#31159 - fulltext search on ucs2 column crashes server +# +CREATE TABLE t1(a TEXT CHARSET ucs2 COLLATE ucs2_unicode_ci); +INSERT INTO t1 VALUES('abcd'); +SELECT * FROM t1 WHERE MATCH(a) AGAINST ('+abcd' IN BOOLEAN MODE); +DROP TABLE t1; + --echo End of 4.1 tests diff --git a/mysys/charset.c b/mysys/charset.c index 6f2d4d3c347..f0ac61ceed5 100644 --- a/mysys/charset.c +++ b/mysys/charset.c @@ -673,3 +673,43 @@ CHARSET_INFO *fs_character_set() return fs_cset_cache; } #endif + + +/** + @brief Find compatible character set with ctype. + + @param[in] original_cs Original character set + + @note + 128 my_charset_ucs2_general_uca ->192 my_charset_utf8_general_uca_ci + 129 my_charset_ucs2_icelandic_uca_ci ->193 my_charset_utf8_icelandic_uca_ci + 130 my_charset_ucs2_latvian_uca_ci ->194 my_charset_utf8_latvian_uca_ci + 131 my_charset_ucs2_romanian_uca_ci ->195 my_charset_utf8_romanian_uca_ci + 132 my_charset_ucs2_slovenian_uca_ci ->196 my_charset_utf8_slovenian_uca_ci + 133 my_charset_ucs2_polish_uca_ci ->197 my_charset_utf8_polish_uca_ci + 134 my_charset_ucs2_estonian_uca_ci ->198 my_charset_utf8_estonian_uca_ci + 135 my_charset_ucs2_spanish_uca_ci ->199 my_charset_utf8_spanish_uca_ci + 136 my_charset_ucs2_swedish_uca_ci ->200 my_charset_utf8_swedish_uca_ci + 137 my_charset_ucs2_turkish_uca_ci ->201 my_charset_utf8_turkish_uca_ci + 138 my_charset_ucs2_czech_uca_ci ->202 my_charset_utf8_czech_uca_ci + 139 my_charset_ucs2_danish_uca_ci ->203 my_charset_utf8_danish_uca_ci + 140 my_charset_ucs2_lithuanian_uca_ci->204 my_charset_utf8_lithuanian_uca_ci + 141 my_charset_ucs2_slovak_uca_ci ->205 my_charset_utf8_slovak_uca_ci + 142 my_charset_ucs2_spanish2_uca_ci ->206 my_charset_utf8_spanish2_uca_ci + 143 my_charset_ucs2_roman_uca_ci ->207 my_charset_utf8_roman_uca_ci + 144 my_charset_ucs2_persian_uca_ci ->208 my_charset_utf8_persian_uca_ci + + @return Compatible character set or NULL. +*/ + +CHARSET_INFO *get_compatible_charset_with_ctype(CHARSET_INFO *original_cs) +{ + CHARSET_INFO *compatible_cs= 0; + DBUG_ENTER("get_compatible_charset_with_ctype"); + if (!strcmp(original_cs->csname, "ucs2") && + (compatible_cs= get_charset(original_cs->number + 64, MYF(0))) && + (!compatible_cs->ctype || + strcmp(original_cs->name + 4, compatible_cs->name + 4))) + compatible_cs= 0; + DBUG_RETURN(compatible_cs); +} diff --git a/sql/item_func.cc b/sql/item_func.cc index f71297515d6..6bfb920d7c8 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -3135,13 +3135,44 @@ bool Item_func_match::fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref) my_error(ER_WRONG_ARGUMENTS,MYF(0),"MATCH"); return 1; } - table=((Item_field *)item)->field->table; + /* + With prepared statements Item_func_match::fix_fields is called twice. + When it is called first time we have original item tree here and add + conversion layer for character sets that do not have ctype array a few + lines below. When it is called second time, we already have conversion + layer in item tree. + */ + table= (item->type() == Item::FIELD_ITEM) ? + ((Item_field *)item)->field->table : + ((Item_field *)((Item_func_conv *)item)->key_item())->field->table; if (!(table->file->table_flags() & HA_CAN_FULLTEXT)) { my_error(ER_TABLE_CANT_HANDLE_FT, MYF(0)); return 1; } table->fulltext_searched=1; + /* A workaround for ucs2 character set */ + if (!args[1]->collation.collation->ctype) + { + CHARSET_INFO *compatible_cs= + get_compatible_charset_with_ctype(args[1]->collation.collation); + bool rc= 1; + if (compatible_cs) + { + Item_string *conv_item= new Item_string("", 0, compatible_cs, + DERIVATION_EXPLICIT); + item= args[0]; + args[0]= conv_item; + rc= agg_item_charsets(cmp_collation, func_name(), args, arg_count, + MY_COLL_ALLOW_SUPERSET_CONV | + MY_COLL_ALLOW_COERCIBLE_CONV | + MY_COLL_DISALLOW_NONE); + args[0]= item; + } + else + my_error(ER_WRONG_ARGUMENTS, MYF(0), "MATCH"); + return rc; + } return agg_arg_collations_for_comparison(cmp_collation, args+1, arg_count-1); } From b9de3ce2a999af073eaca24408613c1eeaf2fd31 Mon Sep 17 00:00:00 2001 From: "mats@kindahl-laptop.dnsalias.net" <> Date: Wed, 24 Oct 2007 16:02:37 +0200 Subject: [PATCH 075/336] BUG#31702 (Missing row on slave causes assertion failure under row-based replication): Incremental patch to enable idempotency support for update events again. The final handling of errors will be done in BUG#31609, and until then the handling of errors should be consistent between the different types of changes. --- mysql-test/suite/rpl/r/rpl_row_basic_11bugs.result | 2 +- mysql-test/suite/rpl/r/rpl_temporary_errors.result | 14 +++++++------- mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test | 4 +--- mysql-test/suite/rpl/t/rpl_temporary_errors.test | 4 +--- sql/log_event.cc | 9 +++------ 5 files changed, 13 insertions(+), 20 deletions(-) diff --git a/mysql-test/suite/rpl/r/rpl_row_basic_11bugs.result b/mysql-test/suite/rpl/r/rpl_row_basic_11bugs.result index 5ad9ba7ced0..c3fd663fad8 100644 --- a/mysql-test/suite/rpl/r/rpl_row_basic_11bugs.result +++ b/mysql-test/suite/rpl/r/rpl_row_basic_11bugs.result @@ -265,7 +265,7 @@ a b 5 master **** On Slave **** Last_SQL_Error -Error in Update_rows event: error during transaction execution on table test.t1. Can't find record in 't1' + SELECT * FROM t1 ORDER BY a; a b 2 master,slave diff --git a/mysql-test/suite/rpl/r/rpl_temporary_errors.result b/mysql-test/suite/rpl/r/rpl_temporary_errors.result index 31c8930ec4f..5c681683b08 100644 --- a/mysql-test/suite/rpl/r/rpl_temporary_errors.result +++ b/mysql-test/suite/rpl/r/rpl_temporary_errors.result @@ -30,7 +30,7 @@ a b **** On Slave **** SHOW STATUS LIKE 'Slave_retried_transactions'; Variable_name Value -Slave_retried_transactions 2 +Slave_retried_transactions 0 SELECT * FROM t1; a b 5 47 @@ -49,17 +49,17 @@ Relay_Log_File # Relay_Log_Pos # Relay_Master_Log_File master-bin.000001 Slave_IO_Running Yes -Slave_SQL_Running No +Slave_SQL_Running Yes Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1032 -Last_Error Error in Update_rows event: error during transaction execution on table test.t1. Can't find record in 't1' +Last_Errno 0 +Last_Error Skip_Counter 0 -Exec_Master_Log_Pos 318 +Exec_Master_Log_Pos 408 Relay_Log_Space # Until_Condition None Until_Log_File @@ -74,8 +74,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1032 -Last_SQL_Error Error in Update_rows event: error during transaction execution on table test.t1. Can't find record in 't1' +Last_SQL_Errno 0 +Last_SQL_Error DROP TABLE t1; **** On Master **** DROP TABLE t1; diff --git a/mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test b/mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test index f6180de52a4..07fe763eb3c 100644 --- a/mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test +++ b/mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test @@ -245,11 +245,9 @@ SELECT * FROM t1 ORDER BY a; --echo **** On Master **** connection master; UPDATE t1 SET a = 5, b = 'master' WHERE a = 1; -save_master_pos; SELECT * FROM t1 ORDER BY a; --echo **** On Slave **** -connection slave; -source include/wait_for_slave_sql_error.inc; +sync_slave_with_master; let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Error, 1); disable_query_log; eval SELECT "$last_error" AS Last_SQL_Error; diff --git a/mysql-test/suite/rpl/t/rpl_temporary_errors.test b/mysql-test/suite/rpl/t/rpl_temporary_errors.test index 0ca515fff40..6a57f3cc167 100644 --- a/mysql-test/suite/rpl/t/rpl_temporary_errors.test +++ b/mysql-test/suite/rpl/t/rpl_temporary_errors.test @@ -13,12 +13,10 @@ SELECT * FROM t1; --echo **** On Master **** connection master; UPDATE t1 SET a = 5, b = 5 WHERE a = 1; -save_master_pos; SELECT * FROM t1; #SHOW BINLOG EVENTS; --echo **** On Slave **** -connection slave; -source include/wait_for_slave_sql_to_stop.inc; +sync_slave_with_master; SHOW STATUS LIKE 'Slave_retried_transactions'; SELECT * FROM t1; source include/show_slave_status.inc; diff --git a/sql/log_event.cc b/sql/log_event.cc index fd7e3e5db6b..5864433ec05 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -6180,12 +6180,9 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) case HA_ERR_RECORD_CHANGED: case HA_ERR_KEY_NOT_FOUND: /* Idempotency support: OK if tuple does not exist */ - if (get_type_code() != UPDATE_ROWS_EVENT) - { - error= 0; - break; - } - /* Fall through in the event that we have an update event */ + error= 0; + break; + default: rli->report(ERROR_LEVEL, thd->net.last_errno, "Error in %s event: row application failed. %s", From 78aa659979b02afeb26ec51742559e516a2ba41e Mon Sep 17 00:00:00 2001 From: "kaa@polly.(none)" <> Date: Wed, 24 Oct 2007 21:16:20 +0400 Subject: [PATCH 076/336] Fix for bug #31566: my_write(fd, 0x0, 0, flags) fails with EFAULT on some platforms Since the behavior of write(fd, buf, 0) is undefined, it may fail with EFAULT on some architectures when buf == NULL. The error was propagated up to a caller, since my_write() code did not handle it properly. Fixed by checking the 'number of bytes' argument in my_write() and returning before calling the write() system call when there is nothing to write. --- mysys/my_write.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mysys/my_write.c b/mysys/my_write.c index 4c3d187e4e8..08d70accd57 100644 --- a/mysys/my_write.c +++ b/mysys/my_write.c @@ -29,6 +29,10 @@ uint my_write(int Filedes, const byte *Buffer, uint Count, myf MyFlags) Filedes, (long) Buffer, Count, MyFlags)); errors=0; written=0L; + /* The behavior of write(fd, buf, 0) is not portable */ + if (unlikely(!Count)) + return 0; + for (;;) { if ((writenbytes = (uint) write(Filedes, Buffer, Count)) == Count) From bb79b4662f104c45edd3c61de8ff871a1d834ab1 Mon Sep 17 00:00:00 2001 From: "ramil/ram@mysql.com/ramil.myoffice.izhnet.ru" <> Date: Wed, 24 Oct 2007 22:36:57 +0500 Subject: [PATCH 077/336] Fix for bug #30679: 5.1 name encoding not performed for views during upgrade Problem: we skip views perfoming --fix-table-names. Fix: rename views as well. --- client/mysqlcheck.c | 7 +++++-- mysql-test/r/mysqlcheck.result | 18 ++++++++++++++++++ mysql-test/t/mysqlcheck.test | 13 +++++++++++++ 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/client/mysqlcheck.c b/client/mysqlcheck.c index fb2071ce10f..34f09f6ca92 100644 --- a/client/mysqlcheck.c +++ b/client/mysqlcheck.c @@ -533,8 +533,11 @@ static int process_all_tables_in_db(char *database) else { while ((row = mysql_fetch_row(res))) - /* Skip tables with an engine of NULL (probably a view). */ - if (row[1]) + /* + Skip tables with an engine of NULL (probably a view) + if we don't perform renaming. + */ + if (row[1] || what_to_do == DO_UPGRADE) { handle_request_for_tables(row[0], strlen(row[0])); } diff --git a/mysql-test/r/mysqlcheck.result b/mysql-test/r/mysqlcheck.result index b8ada0adff9..ac21e0aeb6a 100644 --- a/mysql-test/r/mysqlcheck.result +++ b/mysql-test/r/mysqlcheck.result @@ -58,3 +58,21 @@ test.t1 OK drop view v1; drop table t1; End of 5.0 tests +create table t1(a int); +create view v1 as select * from t1; +show tables; +Tables_in_test +t1 +v1 +show tables; +Tables_in_test +t1 +#mysql50#v-1 +v1 +show tables; +Tables_in_test +t1 +v1 +v-1 +drop view v1, `v-1`; +drop table t1; diff --git a/mysql-test/t/mysqlcheck.test b/mysql-test/t/mysqlcheck.test index d233546f9e3..b789e275ffe 100644 --- a/mysql-test/t/mysqlcheck.test +++ b/mysql-test/t/mysqlcheck.test @@ -38,3 +38,16 @@ drop view v1; drop table t1; --echo End of 5.0 tests + +# +# Bug #30679: 5.1 name encoding not performed for views during upgrade +# +create table t1(a int); +create view v1 as select * from t1; +show tables; +--copy_file $MYSQLTEST_VARDIR/master-data/test/v1.frm $MYSQLTEST_VARDIR/master-data/test/v-1.frm +show tables; +--exec $MYSQL_CHECK --check-upgrade --fix-table-names --databases test +show tables; +drop view v1, `v-1`; +drop table t1; From 3494f691c1da55fc37b2b64476ba1c03dde76100 Mon Sep 17 00:00:00 2001 From: "kaa@polly.(none)" <> Date: Thu, 25 Oct 2007 08:19:57 +0400 Subject: [PATCH 078/336] Replaced 'return' with DBUG_RETURN() in the fix for bug #31566. --- mysys/my_write.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysys/my_write.c b/mysys/my_write.c index 08d70accd57..9ff7babab31 100644 --- a/mysys/my_write.c +++ b/mysys/my_write.c @@ -31,7 +31,7 @@ uint my_write(int Filedes, const byte *Buffer, uint Count, myf MyFlags) /* The behavior of write(fd, buf, 0) is not portable */ if (unlikely(!Count)) - return 0; + DBUG_RETURN(0); for (;;) { From e36846deca5f07003a17fd12ba98284d19eb52d8 Mon Sep 17 00:00:00 2001 From: "gshchepa/uchum@gleb.loc" <> Date: Thu, 25 Oct 2007 10:32:52 +0500 Subject: [PATCH 079/336] Fixed bug #27695: View should not be allowed to have empty or all space column names. The parser has been modified to check VIEW column names with the check_column_name function and to report an error on empty and all space column names (same as for TABLE column names). --- mysql-test/r/select.result | 26 ++++++++++++-------------- mysql-test/t/select.test | 33 ++++++++++++++++++++------------- sql/sql_yacc.yy | 6 ++++++ 3 files changed, 38 insertions(+), 27 deletions(-) diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index ed120a1bbb8..52f2e84bf4e 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -4077,23 +4077,21 @@ x 1 Warnings: Warning 1466 Leading spaces are removed from name ' x' +CREATE VIEW v1 AS SELECT 1 AS ``; +ERROR 42000: Incorrect column name '' CREATE VIEW v1 AS SELECT 1 AS ` `; -Warnings: -Warning 1474 Name ' ' has become '' -SELECT `` FROM v1; - -1 -CREATE VIEW v2 AS SELECT 1 AS ` `; -Warnings: -Warning 1474 Name ' ' has become '' -SELECT `` FROM v2; - -1 -CREATE VIEW v3 AS SELECT 1 AS ` x`; +ERROR 42000: Incorrect column name ' ' +CREATE VIEW v1 AS SELECT 1 AS ` `; +ERROR 42000: Incorrect column name ' ' +CREATE VIEW v1 AS SELECT (SELECT 1 AS ` `); +ERROR 42000: Incorrect column name ' ' +CREATE VIEW v1 AS SELECT 1 AS ` x`; Warnings: Warning 1466 Leading spaces are removed from name ' x' -SELECT `x` FROM v3; +SELECT `x` FROM v1; x 1 -DROP VIEW v1, v2, v3; +ALTER VIEW v1 AS SELECT 1 AS ` `; +ERROR 42000: Incorrect column name ' ' +DROP VIEW v1; End of 5.0 tests diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index 5c30a17e08e..a6ed3c854b4 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -3466,22 +3466,29 @@ DROP TABLE t1; # --disable_ps_protocol - SELECT 1 AS ` `; SELECT 1 AS ` `; SELECT 1 AS ` x`; - -CREATE VIEW v1 AS SELECT 1 AS ` `; -SELECT `` FROM v1; - -CREATE VIEW v2 AS SELECT 1 AS ` `; -SELECT `` FROM v2; - -CREATE VIEW v3 AS SELECT 1 AS ` x`; -SELECT `x` FROM v3; - -DROP VIEW v1, v2, v3; - --enable_ps_protocol +--error 1166 +CREATE VIEW v1 AS SELECT 1 AS ``; + +--error 1166 +CREATE VIEW v1 AS SELECT 1 AS ` `; + +--error 1166 +CREATE VIEW v1 AS SELECT 1 AS ` `; + +--error 1166 +CREATE VIEW v1 AS SELECT (SELECT 1 AS ` `); + +CREATE VIEW v1 AS SELECT 1 AS ` x`; +SELECT `x` FROM v1; + +--error 1166 +ALTER VIEW v1 AS SELECT 1 AS ` `; + +DROP VIEW v1; + --echo End of 5.0 tests diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 368ce5673e2..3401bf739b3 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -4305,6 +4305,12 @@ select_item: MYSQL_YYABORT; if ($4.str) { + if (Lex->sql_command == SQLCOM_CREATE_VIEW && + check_column_name($4.str)) + { + my_error(ER_WRONG_COLUMN_NAME, MYF(0), $4.str); + MYSQL_YYABORT; + } $2->is_autogenerated_name= FALSE; $2->set_name($4.str, $4.length, system_charset_info); } From af7da8cd64fe360cf6b2fe2ed429151958aa68d3 Mon Sep 17 00:00:00 2001 From: "sven@murkla.(none)" <> Date: Thu, 25 Oct 2007 11:58:18 +0200 Subject: [PATCH 080/336] WL#4078: Document binary format of binlog entries Documented some binlog events using doxygen. More will be done later. Also fixed typos in other comments and added remarks about dubious code. Only comments are affected, there is no change to the actual code. --- sql/log_event.cc | 29 +- sql/log_event.h | 989 +++++++++++++++++++++++++++++++++++++++++------ sql/sql_class.h | 12 +- 3 files changed, 898 insertions(+), 132 deletions(-) diff --git a/sql/log_event.cc b/sql/log_event.cc index c0fbfb1000d..e5a26d48af9 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1328,6 +1328,11 @@ static void write_str_with_code_and_len(char **dst, const char *src, bool Query_log_event::write(IO_CACHE* file) { + /** + @todo if catalog can be of length FN_REFLEN==512, then we are not + replicating it correctly, since the length is stored in a byte + /sven + */ uchar buf[QUERY_HEADER_LEN+ 1+4+ // code of flags2 and flags2 1+8+ // code of sql_mode and sql_mode @@ -1554,6 +1559,10 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, time(&end_time); exec_time = (ulong) (end_time - thd_arg->start_time); + /** + @todo this means that if we have no catalog, then it is replicated + as an existing catalog of length zero. is that safe? /sven + */ catalog_len = (catalog) ? (uint32) strlen(catalog) : 0; /* status_vars_len is set just before writing the event */ db_len = (db) ? (uint32) strlen(db) : 0; @@ -1563,7 +1572,7 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, /* If we don't use flags2 for anything else than options contained in thd_arg->options, it would be more efficient to flags2=thd_arg->options - (OPTIONS_WRITTEN_TO_BINLOG would be used only at reading time). + (OPTIONS_WRITTEN_TO_BIN_LOG would be used only at reading time). But it's likely that we don't want to use 32 bits for 3 bits; in the future we will probably want to reclaim the 29 bits. So we need the &. */ @@ -1764,6 +1773,11 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, DBUG_VOID_RETURN; if (catalog_len) // If catalog is given { + /** + @todo we should clean up and do only copy_str_and_move; it + works for both cases. Then we can remove the catalog_nz + flag. /sven + */ if (likely(catalog_nz)) // true except if event comes from 5.0.0|1|2|3. copy_str_and_move(&catalog, &start, catalog_len); else @@ -1776,6 +1790,13 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, if (time_zone_len) copy_str_and_move(&time_zone_str, &start, time_zone_len); + /** + if time_zone_len or catalog_len are 0, then time_zone and catalog + are uninitialized at this point. shouldn't they point to the + zero-length null-terminated strings we allocated space for in the + my_alloc call above? /sven + */ + /* A 2nd variable part; this is common to all versions */ memcpy((char*) start, end, data_len); // Copy db and query start[data_len]= '\0'; // End query with \0 (For safetly) @@ -2836,7 +2857,7 @@ uint Load_log_event::get_query_buffer_length() 21 + sql_ex.field_term_len*4 + 2 + // " FIELDS TERMINATED BY 'str'" 23 + sql_ex.enclosed_len*4 + 2 + // " OPTIONALLY ENCLOSED BY 'str'" 12 + sql_ex.escaped_len*4 + 2 + // " ESCAPED BY 'str'" - 21 + sql_ex.line_term_len*4 + 2 + // " FIELDS TERMINATED BY 'str'" + 21 + sql_ex.line_term_len*4 + 2 + // " LINES TERMINATED BY 'str'" 19 + sql_ex.line_start_len*4 + 2 + // " LINES STARTING BY 'str'" 15 + 22 + // " IGNORE xxx LINES" 3 + (num_fields-1)*2 + field_block_len; // " (field1, field2, ...)" @@ -5654,6 +5675,10 @@ bool sql_ex_info::write_data(IO_CACHE* file) } else { + /** + @todo This is sensitive to field padding. We should write a + char[7], not an old_sql_ex. /sven + */ old_sql_ex old_ex; old_ex.field_term= *field_term; old_ex.enclosed= *enclosed; diff --git a/sql/log_event.h b/sql/log_event.h index f1f90aee69f..ab2424d8466 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -18,8 +18,10 @@ @{ @file - - Binary log event definitions. + + @brief Binary log event definitions. This includes generic code + common to all types of log events, as well as specific code for each + type of log event. */ @@ -411,15 +413,19 @@ struct sql_ex_info #define LOG_EVENT_BINLOG_IN_USE_F 0x1 -/* - If the query depends on the thread (for example: TEMPORARY TABLE). - Currently this is used by mysqlbinlog to know it must print - SET @@PSEUDO_THREAD_ID=xx; before the query (it would not hurt to print it - for every query but this would be slow). +/** + @def LOG_EVENT_THREAD_SPECIFIC_F + + If the query depends on the thread (for example: TEMPORARY TABLE). + Currently this is used by mysqlbinlog to know it must print + SET @@PSEUDO_THREAD_ID=xx; before the query (it would not hurt to print it + for every query but this would be slow). */ #define LOG_EVENT_THREAD_SPECIFIC_F 0x4 -/* +/** + @def LOG_EVENT_SUPPRESS_USE_F + Suppress the generation of 'USE' statements before the actual statement. This flag should be set for any events that does not need the current database set to function correctly. Most notable cases @@ -438,23 +444,26 @@ struct sql_ex_info */ #define LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F 0x10 -/* - OPTIONS_WRITTEN_TO_BIN_LOG are the bits of thd->options which must be - written to the binlog. OPTIONS_WRITTEN_TO_BINLOG could be written - into the Format_description_log_event, so that if later we don't want - to replicate a variable we did replicate, or the contrary, it's - doable. But it should not be too hard to decide once for all of what - we replicate and what we don't, among the fixed 32 bits of - thd->options. - I (Guilhem) have read through every option's usage, and it looks like - OPTION_AUTO_IS_NULL and OPTION_NO_FOREIGN_KEYS are the only ones - which alter how the query modifies the table. It's good to replicate - OPTION_RELAXED_UNIQUE_CHECKS too because otherwise, the slave may - insert data slower than the master, in InnoDB. - OPTION_BIG_SELECTS is not needed (the slave thread runs with - max_join_size=HA_POS_ERROR) and OPTION_BIG_TABLES is not needed - either, as the manual says (because a too big in-memory temp table is - automatically written to disk). +/** + @def OPTIONS_WRITTEN_TO_BIN_LOG + + OPTIONS_WRITTEN_TO_BIN_LOG are the bits of thd->options which must + be written to the binlog. OPTIONS_WRITTEN_TO_BIN_LOG could be + written into the Format_description_log_event, so that if later we + don't want to replicate a variable we did replicate, or the + contrary, it's doable. But it should not be too hard to decide once + for all of what we replicate and what we don't, among the fixed 32 + bits of thd->options. + + I (Guilhem) have read through every option's usage, and it looks + like OPTION_AUTO_IS_NULL and OPTION_NO_FOREIGN_KEYS are the only + ones which alter how the query modifies the table. It's good to + replicate OPTION_RELAXED_UNIQUE_CHECKS too because otherwise, the + slave may insert data slower than the master, in InnoDB. + OPTION_BIG_SELECTS is not needed (the slave thread runs with + max_join_size=HA_POS_ERROR) and OPTION_BIG_TABLES is not needed + either, as the manual says (because a too big in-memory temp table + is automatically written to disk). */ #define OPTIONS_WRITTEN_TO_BIN_LOG \ (OPTION_AUTO_IS_NULL | OPTION_NO_FOREIGN_KEY_CHECKS | \ @@ -469,6 +478,11 @@ struct sql_ex_info #endif #undef EXPECTED_OPTIONS /* You shouldn't use this one */ +/** + @enum Log_event_type + + Enumeration type for the different types of log events. +*/ enum Log_event_type { /* @@ -629,13 +643,90 @@ typedef struct st_print_event_info #endif -/***************************************************************************** - - Log_event class +/** + @class Log_event This is the abstract base class for binary log events. + + @section Log_event_binary_format Binary Format - ****************************************************************************/ + Any Log_event saved on disk consists of the following three + components. + + @li Common-Header + @li Post-Header + @li Body + + The Common-Header, documented below, always has the same form and + length within one version of MySQL. Each event type specifies a + form and length of the Post-Header common to all events of the type. + The Body may be of different form and length even for different + events of the same type. The binary formats of Post-Header and Body + are documented separately in each subclass. The binary format of + Common-Header is as follows. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Common-Header
NameFormat
Description
timestamp4 byte unsigned integerThe number of seconds since 1970. +
type1 byte enumerationSee enum #Log_event_type.
master_id4 byte integerServer ID of the server that created the event.
total_size4 byte integerThe total size of this event, in bytes. In other words, this + is the sum of the sizes of Common-Header, Post-Header, and Body. +
master_position4 byte integerThe position of the next event in the master binary log, in + bytes from the beginning of the file. +
flags2 byte bitfieldSee Log_event::flags.
+ + Summing up the numbers above, we see that the total size of the + common header is 19 bytes. + + @subsection Log_event_endianness_and_string_formats Endianness and String Formats + + All numbers, whether they are 16-, 32-, or 64-bit, are stored in + little endian, i.e., the least significant byte first. + + Strings are stored in various formats. The format of each string is + documented separately. +*/ class Log_event { public: @@ -709,8 +800,8 @@ public: */ uint32 server_id; - /* - Some 16 flags. Look above for LOG_EVENT_TIME_F, + /** + Some 16 flags. See the definitions above for LOG_EVENT_TIME_F, LOG_EVENT_FORCED_ROTATE_F, LOG_EVENT_THREAD_SPECIFIC_F, and LOG_EVENT_SUPPRESS_USE_F for notes. */ @@ -986,6 +1077,7 @@ protected: #endif }; + /* One class for each type of event. Two constructors for each class: @@ -999,13 +1091,332 @@ protected: mysqlbinlog. This constructor must be format-tolerant. */ -/***************************************************************************** +/** + @class Query_log_event + + Logs SQL queries. - Query Log Event class + @section Query_log_event_binary_format Binary format - Logs SQL queries + The Post-Header has five components: - ****************************************************************************/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Post-Header for Query_log_event
NameSize
Description
slave_proxy_id4 byte unsigned integerAn integer identifying the client thread, which is unique on + the server. (Note, however, that two threads on different servers + may have the same slave_proxy_id.) This is used when a client + thread creates a temporary table. Temporary tables are local to + the client, and the slave_proxy_id is used to distinguish + temporary tables belonging to different clients. +
exec_time4 byte integer???TODO
db_len1 byte integerThe length of the name of the currently selected + database. +
error_code2 byte integerError code generated by the master. If the master fails, the + slave will fail with the same error code, except for the error + codes ER_DB_CREATE_EXISTS==1007 and ER_DB_DROP_EXISTS==1008. +
status_vars_len2 byte integerThe length of the status_vars block of the Body, in bytes. See + below. +
Post-Header-For-Derived0 bytesThis field is only written by the subclass + Execute_load_query_log_event. In this base class, it takes 0 + bytes. See separate documentation for + Execute_load_query_log_event. +
+ + The Body has the following components: + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Body for Query_log_event
NameSize
Description
status_varsvariable lengthZero or more status variables. Each status variable consists + of one byte identifying the variable stored, followed by the value + of the variable. The possible variables are listed separately in + the table below. MySQL always writes events in the order defined + below; however, it is capable of reading them in any order. +
dbdb_len+1The currently selected database, as a null-terminated string. + + (The trailing zero is redundant since the length is already known; + it is db_len from Post-Header.) +
queryvariable length string without trailing zero, extending to the + end of the event (determined by the length field of the + Common-Header) + The SQL query.
+ + The following table lists the status variables that may appear in + the status_vars field. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Status variables for Query_log_event
Status variable1-byte identifierSize
Description
flags2Q_FLAGS2_CODE == 04 byte bitfieldThe flags in thd->options, binary AND-ed with + OPTIONS_WRITTEN_TO_BIN_LOG. The thd->options bitfield contains + options for SELECT. OPTIONS_WRITTEN identifies those options that + need to be written to the binlog (not all do). Specifically, + OPTIONS_WRITTEN_TO_BIN_LOG equals (OPTION_AUTO_IS_NULL | + OPTION_NO_FOREIGN_KEY_CHECKS | OPTION_RELAXED_UNIQUE_CHECKS | + OPTION_NOT_AUTOCOMMIT), or 0x0c084000 in hex. + + These flags correspond to the SQL variables SQL_AUTO_IS_NULL, + FOREIGN_KEY_CHECKS, UNIQUE_CHECKS, and AUTOCOMMIT, documented in + the "SET Syntax" section of the MySQL Manual. + + This field is always written to the binlog in version >= 5.0, and + never written in version < 5.0. +
sql_modeQ_SQL_MODE_CODE == 18 byte integerThe sql_mode variable. See the section "SQL Modes" in the + MySQL manual, and see mysql_priv.h for a list of the possible + flags. Currently (2007-10-04), the following flags are available: +
+    MODE_REAL_AS_FLOAT==0x1
+    MODE_PIPES_AS_CONCAT==0x2
+    MODE_ANSI_QUOTES==0x4
+    MODE_IGNORE_SPACE==0x8
+    MODE_NOT_USED==0x10
+    MODE_ONLY_FULL_GROUP_BY==0x20
+    MODE_NO_UNSIGNED_SUBTRACTION==0x40
+    MODE_NO_DIR_IN_CREATE==0x80
+    MODE_POSTGRESQL==0x100
+    MODE_ORACLE==0x200
+    MODE_MSSQL==0x400
+    MODE_DB2==0x800
+    MODE_MAXDB==0x1000
+    MODE_NO_KEY_OPTIONS==0x2000
+    MODE_NO_TABLE_OPTIONS==0x4000
+    MODE_NO_FIELD_OPTIONS==0x8000
+    MODE_MYSQL323==0x10000
+    MODE_MYSQL323==0x20000
+    MODE_MYSQL40==0x40000
+    MODE_ANSI==0x80000
+    MODE_NO_AUTO_VALUE_ON_ZERO==0x100000
+    MODE_NO_BACKSLASH_ESCAPES==0x200000
+    MODE_STRICT_TRANS_TABLES==0x400000
+    MODE_STRICT_ALL_TABLES==0x800000
+    MODE_NO_ZERO_IN_DATE==0x1000000
+    MODE_NO_ZERO_DATE==0x2000000
+    MODE_INVALID_DATES==0x4000000
+    MODE_ERROR_FOR_DIVISION_BY_ZERO==0x8000000
+    MODE_TRADITIONAL==0x10000000
+    MODE_NO_AUTO_CREATE_USER==0x20000000
+    MODE_HIGH_NOT_PRECEDENCE==0x40000000
+    MODE_PAD_CHAR_TO_FULL_LENGTH==0x80000000
+    
+ All these flags are replicated from the server. However, all + flags except MODE_NO_DIR_IN_CREATE are honored by the slave; the + slave always preserves its old value of MODE_NO_DIR_IN_CREATE. + For a rationale, see comment in Query_log_event::do_apply_event in + log_event.cc. + + This field is always written to the binlog. +
catalogQ_CATALOG_NZ_CODE == 6Variable-length string: the length in bytes (1 byte) followed + by the characters (at most 255 bytes) + Stores the client's current catalog. Every database belongs + to a catalog, the same way that every table belongs to a + database. Currently, there is only one catalog, 'std'. + + This field is written if the length of the catalog is > 0; + otherwise it is not written. +
auto_incrementQ_AUTO_INCREMENT == 3two 2 byte unsigned integers, totally 2+2=4 bytesThe two variables auto_increment_increment and + auto_increment_offset, in that order. For more information, see + "System variables" in the MySQL manual. + + This field is written if auto_increment>1; otherwise it is not + written. +
charsetQ_CHARSET_CODE == 4three 2-byte unsigned integers (i.e., 6 bytes)The three variables character_set_client, + collation_connection, and collation_server, in that order. + `character_set_client' is a code identifying the character set and + collation used by the client to encode the query. + `collation_connection' identifies the character set and collation + that the master converts the query to when it receives it; this is + useful when comparing literal strings. `collation_server' is the + default character set and collation used when a new database is + created. + + See also "Connection Character Sets and Collations" in the MySQL + 5.1 manual. + + All three variables are codes identifying a (character set, + collation) pair. To see which codes map to which pairs, run the + query "SELECT id, character_set_name, collation_name FROM + COLLATIONS". + + Cf. Q_CHARSET_DATABASE_NUMBER below. + + This field is always written. +
time_zoneQ_TIME_ZONE_CODE == 5Variable-length string: the length in bytes (1 byte) followed + by the characters (at most 255 bytes). + The time_zone of the master. + + See also "System Variables" and "MySQL Server Time Zone Support" + in the MySQL manual. + + This field is written if the length of the time zone string is > + 0; otherwise, it is not written. +
lc_time_names_numberQ_LC_TIME_NAMES_CODE == 72 byte integerA code identifying a table of month and day names. The + mapping from codes to languages is defined in sql_locale.cc. + + This field is written if it is != 0, i.e., if the locale is not + en_US. +
charset_database_numberQ_CHARSET_DATABASE_NUMBER == 82 byte integerThe value of the collation_database system variable (in the + source code stored in thd->variables.collation_database), which + holds the code for a (character set, collation) pair as described + above (see Q_CHARSET_CODE). + + `collation_database' was used in old versions (???WHEN). Its + value was loaded when issuing a "use db" command and could be + changed by issuing a "SET collation_database=xxx" command. It + used to affect the "LOAD DATA INFILE" and "CREATE TABLE" commands. + + In newer versions, "CREATE TABLE" has been changed to take the + character set from the database of the created table, rather than + the database of the current database. This makes a difference + when creating a table in another database than the current one. + "LOAD DATA INFILE" has not yet changed to do this, but there are + plans to eventually do it, and to make collation_database + read-only. + + This field is written if it is not 0. +
+ + @subsection Query_log_event_notes_on_previous_versions Notes on Previous Versions + + @li Status vars were introduced in version 5.0. To read earlier + versions correctly, check the length of the Post-Header. + + @li The status variable Q_CATALOG_CODE == 2 existed in MySQL 5.0.x, + where 0<=x<=3. It was identical to Q_CATALOG_CODE, except that the + string had a trailing '\0'. The '\0' was removed in 5.0.4 since it + was redundant (the string length is stored before the string). The + Q_CATALOG_CODE will never be written by a new master, but can still + be understood by a new slave. + + @li See Q_CHARSET_DATABASE_NUMBER in the table above. + +*/ class Query_log_event: public Log_event { protected: @@ -1063,7 +1474,7 @@ public: /* 'flags2' is a second set of flags (on top of those in Log_event), for session variables. These are thd->options which is & against a mask - (OPTIONS_WRITTEN_TO_BINLOG). + (OPTIONS_WRITTEN_TO_BIN_LOG). flags2_inited helps make a difference between flags2==0 (3.23 or 4.x master, we don't know flags2, so use the slave server's global options) and flags2==0 (5.0 master, we know this has a meaning of flags all down which @@ -1133,13 +1544,16 @@ public: /* !!! Public in this patch to allow old usage */ }; -/***************************************************************************** +/** + @class Muted_query_log_event - Muted Query Log Event class + Pretends to log SQL queries, but doesn't actually do so. - Pretends to Log SQL queries, but doesn't actually do so. + @section Muted_query_log_event_binary_format Binary Format - ****************************************************************************/ + This log event is not stored, and thus the binary format is 0 bytes + long. Note that not even the Common-Header is stored. +*/ class Muted_query_log_event: public Query_log_event { public: @@ -1156,14 +1570,54 @@ public: #ifdef HAVE_REPLICATION -/***************************************************************************** +/** + @class Slave_log_event - Slave Log Event class Note that this class is currently not used at all; no code writes a - Slave_log_event (though some code in repl_failsafe.cc reads Slave_log_event). - So it's not a problem if this code is not maintained. + Slave_log_event (though some code in repl_failsafe.cc reads + Slave_log_event). So it's not a problem if this code is not + maintained. - ****************************************************************************/ + @section Slave_log_event_binary_format Binary Format + + This event type has no Post-Header. The Body has the following + four components. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Body for Slave_log_event
NameSize
Description
master_pos8 byte integer???TODO +
master_port2 byte integer???TODO
master_hostnull-terminated string???TODO
master_lognull-terminated string???TODO
+*/ class Slave_log_event: public Log_event { protected: @@ -1202,11 +1656,202 @@ private: #endif /* HAVE_REPLICATION */ -/***************************************************************************** +/** + @class Load_log_event - Load Log Event class + This log event corresponds to a "LOAD DATA INFILE" SQL query on the + following form: - ****************************************************************************/ + @verbatim + (1) USE db; + (2) LOAD DATA [LOCAL] INFILE 'file_name' + (3) [REPLACE | IGNORE] + (4) INTO TABLE 'table_name' + (5) [FIELDS + (6) [TERMINATED BY 'field_term'] + (7) [[OPTIONALLY] ENCLOSED BY 'enclosed'] + (8) [ESCAPED BY 'escaped'] + (9) ] + (10) [LINES + (11) [TERMINATED BY 'line_term'] + (12) [LINES STARTING BY 'line_start'] + (13) ] + (14) [IGNORE skip_lines LINES] + (15) (field_1, field_2, ..., field_n)@endverbatim + + @section Load_log_event_binary_format Binary Format + + The Post-Header consists of the following six components. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Post-Header for Load_log_event
NameSize
Description
slave_proxy_id4 byte unsigned integerAn integer identifying the client thread, which is unique on + the server. (Note, however, that the same slave_proxy_id may + appear on different servers.) This is used when a client thread + creates a temporary table. Temporary tables are local to the + client, and the slave_proxy_id is used to distinguish temporary + tables belonging to different clients. +
exec_time4 byte unsigned integer???TODO
skip_lines4 byte unsigned integerThe number on line (14) above, if present, or 0 if line (14) + is left out. +
table_name_len1 byte unsigned integerThe length of 'table_name' on line (4) above.
db_len1 byte unsigned integerThe length of 'db' on line (1) above.
num_fields4 byte unsigned integerThe number n of fields on line (15) above.
+ + The Body contains the following components. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Body of Load_log_event
NameSize
Description
sql_exvariable lengthDescribes the part of the query on lines (3) and + (5)–(13) above. More precisely, it stores the five strings + (on lines) field_term (6), enclosed (7), escaped (8), line_term + (11), and line_start (12); as well as a bitfield indicating the + presence of the keywords REPLACE (3), IGNORE (3), and OPTIONALLY + (7). + + The data is stored in one of two formats, called "old" and "new". + The type field of Common-Header determines which of these two + formats is used: type LOAD_EVENT means that the old format is + used, and type NEW_LOAD_EVENT means that the new format is used. + When MySQL writes a Load_log_event, it uses the new format if at + least one of the five strings is two or more bytes long. + Otherwise (i.e., if all strings are 0 or 1 bytes long), the old + format is used. + + The new and old format differ in the way the five strings are + stored. + +
    +
  • In the new format, the strings are stored in the order + field_term, enclosed, escaped, line_term, line_start. Each string + consists of a length (1 byte), followed by a sequence of + characters (0-255 bytes). Finally, a boolean combination of the + following flags is stored in 1 byte: REPLACE_FLAG==0x4, + IGNORE_FLAG==0x8, and OPT_ENCLOSED_FLAG==0x2. If a flag is set, + it indicates the presence of the corresponding keyword in the SQL + query. + +
  • In the old format, we know that each string has length 0 or + 1. Therefore, only the first byte of each string is stored. The + order of the strings is the same as in the new format. These five + bytes are followed by the same 1-byte bitfield as in the new + format. Finally, a 1 byte bitfield called empty_flags is stored. + The low 5 bits of empty_flags indicate which of the five strings + have length 0. For each of the following flags that is set, the + corresponding string has length 0; for the flags that are not set, + the string has length 1: FIELD_TERM_EMPTY==0x1, + ENCLOSED_EMPTY==0x2, LINE_TERM_EMPTY==0x4, LINE_START_EMPTY==0x8, + ESCAPED_EMPTY==0x10. +
+ + Thus, the size of the new format is 6 bytes + the sum of the sizes + of the five strings. The size of the old format is always 7 + bytes. +
field_lensnum_fields 1-byte unsigned integersAn array of num_fields integers representing the length of + each field in the query. (num_fields is from the Post-Header). +
fieldsnum_fields null-terminated stringsAn array of num_fields null-terminated strings, each + representing a field in the query. (The trailing zero is + redundant, since the length are stored in the num_fields array.) + The total length of all strings equals to the sum of all + field_lens, plus num_fields bytes for all the trailing zeros. +
table_namenull-terminated string of length table_len+1 bytesThe 'table_name' from the query, as a null-terminated string. + (The trailing zero is actually redundant since the table_len is + known from Post-Header.) +
dbnull-terminated string of length db_len+1 bytesThe 'db' from the query, as a null-terminated string. + (The trailing zero is actually redundant since the db_len is known + from Post-Header.) +
file_namevariable length string without trailing zero, extending to the + end of the event (determined by the length field of the + Common-Header) + The 'file_name' from the query. +
+ + @subsection Load_log_event_notes_on_previous_versions Notes on Previous Versions + +*/ class Load_log_event: public Log_event { private: @@ -1313,9 +1958,8 @@ public: /* !!! Public in this patch to allow old usage */ extern char server_version[SERVER_VERSION_LENGTH]; -/***************************************************************************** - - Start Log Event_v3 class +/** + @class Start_log_event_v3 Start_log_event_v3 is the Start_log_event of binlog format 3 (MySQL 3.23 and 4.x). @@ -1325,8 +1969,8 @@ extern char server_version[SERVER_VERSION_LENGTH]; MySQL 5.0 whenever it starts sending a new binlog if the requested position is >4 (otherwise if ==4 the event will be sent naturally). - ****************************************************************************/ - + @section Start_log_event_v3_binary_format Binary Format +*/ class Start_log_event_v3: public Log_event { public: @@ -1409,10 +2053,14 @@ protected: }; -/* - For binlog version 4. - This event is saved by threads which read it, as they need it for future - use (to decode the ordinary events). +/** + @class Format_description_log_event + + For binlog version 4. + This event is saved by threads which read it, as they need it for future + use (to decode the ordinary events). + + @section Format_description_log_event_binary_format Binary Format */ class Format_description_log_event: public Start_log_event_v3 @@ -1466,13 +2114,41 @@ protected: }; -/***************************************************************************** +/** + @class Intvar_log_event - Intvar Log Event class + Logs special variables related to auto_increment values. - Logs special variables such as auto_increment values + @section Intvar_log_event_binary_format Binary Format - ****************************************************************************/ + The Post-Header has two components: + + + + + + + + + + + + + + + + + + + + + + +
Post-Header for Intvar_log_event
NameSize
Description
Type1 byte enumerationOne byte identifying the type of variable stored. Currently, + two identifiers are supported: LAST_INSERT_ID_EVENT==1 and + INSERT_ID_EVENT==2. +
value8 byte unsigned integerThe value of the variable.
+*/ class Intvar_log_event: public Log_event { @@ -1511,16 +2187,24 @@ private: }; -/***************************************************************************** - - Rand Log Event class +/** + @class Rand_log_event Logs random seed used by the next RAND(), and by PASSWORD() in 4.1.0. 4.1.1 does not need it (it's repeatable again) so this event needn't be written in 4.1.1 for PASSWORD() (but the fact that it is written is just a waste, it does not cause bugs). - ****************************************************************************/ + @section Rand_log_event_binary_format Binary Format + This event type has no Post-Header. The Body of this event type has + two components: + + @li seed1 (8 bytes): 64 bit random seed1. + @li seed2 (8 bytes): 64 bit random seed2. + + The state of the random number generation consists of 128 bits, + which are stored internally as two 64-bit numbers. +*/ class Rand_log_event: public Log_event { @@ -1557,14 +2241,14 @@ private: #endif }; -/***************************************************************************** - - Xid Log Event class +/** + @class Xid_log_event Logs xid of the transaction-to-be-committed in the 2pc protocol. Has no meaning in replication, slaves ignore it. - ****************************************************************************/ + @section Xid_log_event_binary_format Binary Format +*/ #ifdef MYSQL_CLIENT typedef ulonglong my_xid; // this line is the same as in handler.h #endif @@ -1600,14 +2284,14 @@ private: #endif }; -/***************************************************************************** - - User var Log Event class +/** + @class User_var_log_event Every time a query uses the value of a user variable, a User_var_log_event is written before the Query_log_event, to set the user variable. - ****************************************************************************/ + @section User_var_log_event_binary_format Binary Format +*/ class User_var_log_event: public Log_event { @@ -1649,11 +2333,14 @@ private: }; -/***************************************************************************** +/** + @class Stop_log_event - Stop Log Event class + @section Stop_log_event_binary_format Binary Format - ****************************************************************************/ + The Post-Header and Body for this event type are empty; it only has + the Common-Header. +*/ class Stop_log_event: public Log_event { public: @@ -1689,13 +2376,54 @@ private: #endif }; -/***************************************************************************** - - Rotate Log Event class +/** + @class Rotate_log_event This will be deprecated when we move to using sequence ids. - ****************************************************************************/ + @section Rotate_log_event_binary_format Binary Format + + The Post-Header has one component: + + + + + + + + + + + + + + + + +
Post-Header for Rotate_log_event
NameSize
Description
pos8 byte integer???TODO
+ + The Body has one component: + + + + + + + + + + + + + + + + +
Body for Rotate_log_event
NameSize
Description
new_log_identvariable length string without trailing zero, extending to the + end of the event (determined by the length field of the + Common-Header) + ???TODO
+*/ class Rotate_log_event: public Log_event { @@ -1742,9 +2470,11 @@ private: /* the classes below are for the new LOAD DATA INFILE logging */ -/***************************************************************************** - Create File Log Event class - ****************************************************************************/ +/** + @class Create_file_log_event + + @section Create_file_log_event_binary_format Binary Format +*/ class Create_file_log_event: public Load_log_event { @@ -1813,11 +2543,11 @@ private: }; -/***************************************************************************** +/** + @class Append_block_log_event - Append Block Log Event class - - ****************************************************************************/ + @section Append_block_log_event_binary_format Binary Format +*/ class Append_block_log_event: public Log_event { @@ -1868,11 +2598,11 @@ private: }; -/***************************************************************************** +/** + @class Delete_file_log_event - Delete File Log Event class - - ****************************************************************************/ + @section Delete_file_log_event_binary_format Binary Format +*/ class Delete_file_log_event: public Log_event { @@ -1909,11 +2639,11 @@ private: }; -/***************************************************************************** +/** + @class Execute_load_log_event - Execute Load Log Event class - - ****************************************************************************/ + @section Delete_file_log_event_binary_format Binary Format +*/ class Execute_load_log_event: public Log_event { @@ -1949,15 +2679,15 @@ private: }; -/*************************************************************************** - - Begin load query Log Event class +/** + @class Begin_load_query_log_event Event for the first block of file to be loaded, its only difference from Append_block event is that this event creates or truncates existing file before writing data. -****************************************************************************/ + @section Begin_load_query_log_event_binary_format Binary Format +*/ class Begin_load_query_log_event: public Append_block_log_event { public: @@ -1988,15 +2718,15 @@ private: enum enum_load_dup_handling { LOAD_DUP_ERROR= 0, LOAD_DUP_IGNORE, LOAD_DUP_REPLACE }; -/**************************************************************************** - - Execute load query Log Event class +/** + @class Execute_load_query_log_event Event responsible for LOAD DATA execution, it similar to Query_log_event but before executing the query it substitutes original filename in LOAD DATA query with name of temporary file. -****************************************************************************/ + @section Execute_load_query_log_event_binary_format Binary Format +*/ class Execute_load_query_log_event: public Query_log_event { public: @@ -2048,6 +2778,11 @@ private: #ifdef MYSQL_CLIENT +/** + @class Unknown_log_event + + @section Unknown_log_event_binary_format Binary Format +*/ class Unknown_log_event: public Log_event { public: @@ -2068,14 +2803,14 @@ public: #endif char *str_to_hex(char *to, const char *from, uint len); -/***************************************************************************** - - Table map log event class +/** + @class Table_map_log_event Create a mapping from a (database name, table name) couple to a table identifier (an integer number). - ****************************************************************************/ + @section Table_map_log_event_binary_format Binary Format +*/ class Table_map_log_event : public Log_event { public: @@ -2185,9 +2920,8 @@ private: }; -/***************************************************************************** - - Row level log event class. +/** + @class Rows_log_event Common base class for all row-containing log events. @@ -2197,7 +2931,8 @@ private: - Write data header and data body to an IO_CACHE. - Provide an interface for adding an individual row to the event. - ****************************************************************************/ + @section Rows_log_event_binary_format Binary Format +*/ class Rows_log_event : public Log_event @@ -2428,15 +3163,15 @@ private: friend class Old_rows_log_event; }; -/***************************************************************************** - - Write row log event class +/** + @class Write_rows_log_event Log row insertions and updates. The event contain several insert/update rows for a table. Note that each event contains only rows for one table. - ****************************************************************************/ + @section Write_rows_log_event_binary_format Binary Format +*/ class Write_rows_log_event : public Rows_log_event { public: @@ -2483,9 +3218,8 @@ private: }; -/***************************************************************************** - - Update rows log event class +/** + @class Update_rows_log_event Log row updates with a before image. The event contain several update rows for a table. Note that each event contains only rows for @@ -2494,7 +3228,8 @@ private: Also note that the row data consists of pairs of row data: one row for the old data and one row for the new data. - ****************************************************************************/ + @section Update_rows_log_event_binary_format Binary Format +*/ class Update_rows_log_event : public Rows_log_event { public: @@ -2556,9 +3291,8 @@ protected: #endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */ }; -/***************************************************************************** - - Delete rows log event class. +/** + @class Delete_rows_log_event Log row deletions. The event contain several delete rows for a table. Note that each event contains only rows for one table. @@ -2575,7 +3309,8 @@ protected: Row_reader Extract the rows from the event. - ****************************************************************************/ + @section Delete_rows_log_event_binary_format Binary Format +*/ class Delete_rows_log_event : public Rows_log_event { public: @@ -2625,6 +3360,8 @@ protected: #include "log_event_old.h" /** + @class Incident_log_event + Class representing an incident, an occurance out of the ordinary, that happened on the master. @@ -2636,7 +3373,7 @@ protected: Incident event format Symbol - Size
(bytes) + Size
(bytes) Description @@ -2655,7 +3392,9 @@ protected: The message, if present. Not null terminated. - */ + + @section Delete_rows_log_event_binary_format Binary Format +*/ class Incident_log_event : public Log_event { public: #ifndef MYSQL_CLIENT diff --git a/sql/sql_class.h b/sql/sql_class.h index 1b07ab08d32..2084fbcb7ed 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1263,14 +1263,16 @@ public: We follow this logic: - when stmt starts, first_successful_insert_id_in_prev_stmt contains the first insert id successfully inserted by the previous stmt. - - as stmt makes progress, handler::insert_id_for_cur_row changes; every - time get_auto_increment() is called, auto_inc_intervals_for_binlog is - augmented with the reserved interval (if statement-based binlogging). + - as stmt makes progress, handler::insert_id_for_cur_row changes; + every time get_auto_increment() is called, + auto_inc_intervals_in_cur_stmt_for_binlog is augmented with the + reserved interval (if statement-based binlogging). - at first successful insertion of an autogenerated value, first_successful_insert_id_in_cur_stmt is set to handler::insert_id_for_cur_row. - - when stmt goes to binlog, auto_inc_intervals_for_binlog is - binlogged if non-empty. + - when stmt goes to binlog, + auto_inc_intervals_in_cur_stmt_for_binlog is binlogged if + non-empty. - when stmt ends, first_successful_insert_id_in_prev_stmt is set to first_successful_insert_id_in_cur_stmt. */ From 99f4b74311c8e08446fb2db77e5ccc43d6d9af1d Mon Sep 17 00:00:00 2001 From: "kaa@polly.(none)" <> Date: Thu, 25 Oct 2007 14:02:27 +0400 Subject: [PATCH 081/336] Fix for bug #29131: SHOW VARIABLES reports variable 'log' but SET doesn't recognize it This is a 5.0 version of the patch, it will be null-merged to 5.1 Problem: 'log' and 'log_slow_queries' were "fixed" variables, i.e. they showed up in SHOW VARIABLES, but could not be used in expressions like "select @@log". Also, using them in the SET statement produced an incorrect "unknown system variable" error. Solution: Make 'log' and 'log_slow_queries' read-only dynamic variables to make them available for use in expressions, and produce a correct error about the variable being read-only when used in the SET statement. --- mysql-test/r/variables.result | 16 ++++++++++++++++ mysql-test/t/variables.test | 14 ++++++++++++++ sql/mysql_priv.h | 4 ++-- sql/mysqld.cc | 4 ++-- sql/set_var.cc | 8 ++++++-- sql/set_var.h | 22 ++++++++++++++++++++++ 6 files changed, 62 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/variables.result b/mysql-test/r/variables.result index 3d76f8e4a90..217be9400e6 100644 --- a/mysql-test/r/variables.result +++ b/mysql-test/r/variables.result @@ -791,6 +791,22 @@ ERROR HY000: Variable 'hostname' is a read only variable show variables like 'hostname'; Variable_name Value hostname # +SHOW VARIABLES LIKE 'log'; +Variable_name Value +log ON +SELECT @@log; +@@log +1 +SET GLOBAL log=0; +ERROR HY000: Variable 'log' is a read only variable +SHOW VARIABLES LIKE 'log_slow_queries'; +Variable_name Value +log_slow_queries ON +SELECT @@log_slow_queries; +@@log_slow_queries +1 +SET GLOBAL log_slow_queries=0; +ERROR HY000: Variable 'log_slow_queries' is a read only variable End of 5.0 tests set global binlog_cache_size =@my_binlog_cache_size; set global connect_timeout =@my_connect_timeout; diff --git a/mysql-test/t/variables.test b/mysql-test/t/variables.test index 0ad85a32568..13f897e7596 100644 --- a/mysql-test/t/variables.test +++ b/mysql-test/t/variables.test @@ -674,6 +674,20 @@ set @@hostname= "anothername"; --replace_column 2 # show variables like 'hostname'; +# +# Bug #29131: SHOW VARIABLES reports variable 'log' but SET doesn't recognize it +# + +SHOW VARIABLES LIKE 'log'; +SELECT @@log; +--error 1238 +SET GLOBAL log=0; + +SHOW VARIABLES LIKE 'log_slow_queries'; +SELECT @@log_slow_queries; +--error 1238 +SET GLOBAL log_slow_queries=0; + --echo End of 5.0 tests # This is at the very after the versioned tests, since it involves doing diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 5bec94857f7..8364456a9ee 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1306,8 +1306,8 @@ extern bool opt_endinfo, using_udf_functions; extern my_bool locked_in_memory; extern bool opt_using_transactions, mysqld_embedded; extern bool using_update_log, opt_large_files, server_id_supplied; -extern bool opt_log, opt_update_log, opt_bin_log, opt_slow_log, opt_error_log; -extern my_bool opt_log_queries_not_using_indexes; +extern bool opt_update_log, opt_bin_log, opt_error_log; +extern my_bool opt_log, opt_slow_log, opt_log_queries_not_using_indexes; extern bool opt_disable_networking, opt_skip_show_db; extern my_bool opt_character_set_client_handshake; extern bool volatile abort_loop, shutdown_in_progress, grant_option; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 08c2b60fa79..63cdf2b3640 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -339,8 +339,8 @@ static my_bool opt_sync_bdb_logs; /* Global variables */ -bool opt_log, opt_update_log, opt_bin_log, opt_slow_log; -my_bool opt_log_queries_not_using_indexes= 0; +bool opt_update_log, opt_bin_log; +my_bool opt_log, opt_slow_log, opt_log_queries_not_using_indexes= 0; bool opt_error_log= IF_WIN(1,0); bool opt_disable_networking=0, opt_skip_show_db=0; my_bool opt_character_set_client_handshake= 1; diff --git a/sql/set_var.cc b/sql/set_var.cc index fbfe174434d..80106b900fc 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -201,6 +201,7 @@ sys_var_key_cache_long sys_key_cache_age_threshold("key_cache_age_threshold", param_age_threshold)); sys_var_bool_ptr sys_local_infile("local_infile", &opt_local_infile); +sys_var_bool_const_ptr sys_log("log", &opt_log); sys_var_trust_routine_creators sys_trust_routine_creators("log_bin_trust_routine_creators", &trust_function_creators); @@ -213,6 +214,7 @@ sys_var_bool_ptr sys_var_thd_ulong sys_log_warnings("log_warnings", &SV::log_warnings); sys_var_thd_ulong sys_long_query_time("long_query_time", &SV::long_query_time); +sys_var_bool_const_ptr sys_log_slow("log_slow_queries", &opt_slow_log); sys_var_thd_bool sys_low_priority_updates("low_priority_updates", &SV::low_priority_updates, fix_low_priority_updates); @@ -665,9 +667,11 @@ sys_var *sys_variables[]= &sys_lc_time_names, &sys_license, &sys_local_infile, + &sys_log, &sys_log_binlog, &sys_log_off, &sys_log_queries_not_using_indexes, + &sys_log_slow, &sys_log_update, &sys_log_warnings, &sys_long_query_time, @@ -946,7 +950,7 @@ struct show_var_st init_vars[]= { #ifdef HAVE_MLOCKALL {"locked_in_memory", (char*) &locked_in_memory, SHOW_BOOL}, #endif - {"log", (char*) &opt_log, SHOW_BOOL}, + {sys_log.name, (char*) &sys_log, SHOW_SYS}, {"log_bin", (char*) &opt_bin_log, SHOW_BOOL}, {sys_trust_function_creators.name,(char*) &sys_trust_function_creators, SHOW_SYS}, {"log_error", (char*) log_error_file, SHOW_CHAR}, @@ -955,7 +959,7 @@ struct show_var_st init_vars[]= { #ifdef HAVE_REPLICATION {"log_slave_updates", (char*) &opt_log_slave_updates, SHOW_MY_BOOL}, #endif - {"log_slow_queries", (char*) &opt_slow_log, SHOW_BOOL}, + {sys_log_slow.name, (char*) &sys_log_slow, SHOW_SYS}, {sys_log_warnings.name, (char*) &sys_log_warnings, SHOW_SYS}, {sys_long_query_time.name, (char*) &sys_long_query_time, SHOW_SYS}, {sys_low_priority_updates.name, (char*) &sys_low_priority_updates, SHOW_SYS}, diff --git a/sql/set_var.h b/sql/set_var.h index 6000e155db9..7b3f864f44c 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -160,6 +160,28 @@ public: }; +class sys_var_bool_const_ptr : public sys_var +{ +public: + my_bool *value; + sys_var_bool_const_ptr(const char *name_arg, my_bool *value_arg) + :sys_var(name_arg),value(value_arg) + {} + bool check(THD *thd, set_var *var) + { + return 1; + } + bool update(THD *thd, set_var *var) + { + return 1; + } + SHOW_TYPE show_type() { return SHOW_MY_BOOL; } + byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base) + { return (byte*) value; } + bool check_update_type(Item_result type) { return 0; } + bool is_readonly() const { return 1; } +}; + class sys_var_str :public sys_var { public: From 1f268043f6c99d1ca10e9e513c2673b4f03b85f4 Mon Sep 17 00:00:00 2001 From: "kaa@polly.(none)" <> Date: Thu, 25 Oct 2007 14:03:24 +0400 Subject: [PATCH 082/336] Fix for bug #29131: SHOW VARIABLES reports variable 'log' but SET doesn't recognize it This is a 5.1 version of the patch. Problem: 'log' and 'log_slow_queries' were "fixed" variables, i.e. they showed up in SHOW VARIABLES, but could not be used in expressions like "select @@log". Also, using them in the SET statement produced an incorrect "unknown system variable" error. Solution: Since as of MySQL 5.1.12 one can enable or disable the general query log or the slow query log at runtime by changing values of general_log/slow_query_log, make 'log' and 'log_slow_queries" to be synonyms for 'general_log' and 'slow_query_log' respectively. This makes expressions using the '@@var' syntax backward compatible with 5.0 and SHOW VARIABLES output to be consistent with the SET statement. --- mysql-test/r/log_state.result | 63 +++++++++++++++++++++++++++++++++++ mysql-test/t/log_state.test | 36 ++++++++++++++++++++ sql/set_var.cc | 8 +++-- 3 files changed, 105 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/log_state.result b/mysql-test/r/log_state.result index 3a3ef584ce3..b0ec0d25935 100644 --- a/mysql-test/r/log_state.result +++ b/mysql-test/r/log_state.result @@ -175,3 +175,66 @@ SET GLOBAL slow_query_log = ON; SET GLOBAL READ_ONLY = OFF; SET GLOBAL general_log = @old_general_log_state; SET GLOBAL slow_query_log = @old_slow_log_state; +SET @old_general_log_state = @@global.general_log; +SET @old_slow_log_state = @@global.slow_query_log; +SHOW VARIABLES LIKE 'general_log'; +Variable_name Value +general_log ON +SHOW VARIABLES LIKE 'log'; +Variable_name Value +log ON +SELECT @@general_log, @@log; +@@general_log @@log +1 1 +SET GLOBAL log = 0; +SHOW VARIABLES LIKE 'general_log'; +Variable_name Value +general_log OFF +SHOW VARIABLES LIKE 'log'; +Variable_name Value +log OFF +SELECT @@general_log, @@log; +@@general_log @@log +0 0 +SET GLOBAL general_log = 1; +SHOW VARIABLES LIKE 'general_log'; +Variable_name Value +general_log ON +SHOW VARIABLES LIKE 'log'; +Variable_name Value +log ON +SELECT @@general_log, @@log; +@@general_log @@log +1 1 +SHOW VARIABLES LIKE 'slow_query_log'; +Variable_name Value +slow_query_log OFF +SHOW VARIABLES LIKE 'log_slow_queries'; +Variable_name Value +log_slow_queries OFF +SELECT @@slow_query_log, @@log_slow_queries; +@@slow_query_log @@log_slow_queries +0 0 +SET GLOBAL log_slow_queries = 0; +SHOW VARIABLES LIKE 'slow_query_log'; +Variable_name Value +slow_query_log OFF +SHOW VARIABLES LIKE 'log_slow_queries'; +Variable_name Value +log_slow_queries OFF +SELECT @@slow_query_log, @@log_slow_queries; +@@slow_query_log @@log_slow_queries +0 0 +SET GLOBAL slow_query_log = 1; +SHOW VARIABLES LIKE 'slow_query_log'; +Variable_name Value +slow_query_log ON +SHOW VARIABLES LIKE 'log_slow_queries'; +Variable_name Value +log_slow_queries ON +SELECT @@slow_query_log, @@log_slow_queries; +@@slow_query_log @@log_slow_queries +1 1 +SET GLOBAL general_log = @old_general_log_state; +SET GLOBAL slow_query_log = @old_slow_log_state; +End of 5.1 tests diff --git a/mysql-test/t/log_state.test b/mysql-test/t/log_state.test index c67da261ef1..f7795e49b37 100644 --- a/mysql-test/t/log_state.test +++ b/mysql-test/t/log_state.test @@ -179,6 +179,42 @@ SET GLOBAL READ_ONLY = OFF; SET GLOBAL general_log = @old_general_log_state; SET GLOBAL slow_query_log = @old_slow_log_state; +# +# Bug #29131: SHOW VARIABLES reports variable 'log' but SET doesn't recognize it +# + +SET @old_general_log_state = @@global.general_log; +SET @old_slow_log_state = @@global.slow_query_log; + +SHOW VARIABLES LIKE 'general_log'; +SHOW VARIABLES LIKE 'log'; +SELECT @@general_log, @@log; +SET GLOBAL log = 0; +SHOW VARIABLES LIKE 'general_log'; +SHOW VARIABLES LIKE 'log'; +SELECT @@general_log, @@log; +SET GLOBAL general_log = 1; +SHOW VARIABLES LIKE 'general_log'; +SHOW VARIABLES LIKE 'log'; +SELECT @@general_log, @@log; + +SHOW VARIABLES LIKE 'slow_query_log'; +SHOW VARIABLES LIKE 'log_slow_queries'; +SELECT @@slow_query_log, @@log_slow_queries; +SET GLOBAL log_slow_queries = 0; +SHOW VARIABLES LIKE 'slow_query_log'; +SHOW VARIABLES LIKE 'log_slow_queries'; +SELECT @@slow_query_log, @@log_slow_queries; +SET GLOBAL slow_query_log = 1; +SHOW VARIABLES LIKE 'slow_query_log'; +SHOW VARIABLES LIKE 'log_slow_queries'; +SELECT @@slow_query_log, @@log_slow_queries; + +SET GLOBAL general_log = @old_general_log_state; +SET GLOBAL slow_query_log = @old_slow_log_state; + +--echo End of 5.1 tests + --enable_ps_protocol # diff --git a/sql/set_var.cc b/sql/set_var.cc index 697de9cda97..f8e1e86e9f7 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -641,8 +641,14 @@ static sys_var_const_str sys_license(&vars, "license", STRINGIFY_ARG(LICENSE)); /* Global variables which enable|disable logging */ static sys_var_log_state sys_var_general_log(&vars, "general_log", &opt_log, QUERY_LOG_GENERAL); +/* Synonym of "general_log" for consistency with SHOW VARIABLES output */ +static sys_var_log_state sys_var_log(&vars, "log", &opt_log, + QUERY_LOG_GENERAL); static sys_var_log_state sys_var_slow_query_log(&vars, "slow_query_log", &opt_slow_log, QUERY_LOG_SLOW); +/* Synonym of "slow_query_log" for consistency with SHOW VARIABLES output */ +static sys_var_log_state sys_var_log_slow(&vars, "log_slow_queries", + &opt_slow_log, QUERY_LOG_SLOW); sys_var_str sys_var_general_log_path(&vars, "general_log_file", sys_check_log_path, sys_update_general_log_path, sys_default_general_log_path, @@ -678,10 +684,8 @@ static SHOW_VAR fixed_vars[]= { #ifdef HAVE_MLOCKALL {"locked_in_memory", (char*) &locked_in_memory, SHOW_MY_BOOL}, #endif - {"log", (char*) &opt_log, SHOW_MY_BOOL}, {"log_bin", (char*) &opt_bin_log, SHOW_BOOL}, {"log_error", (char*) log_error_file, SHOW_CHAR}, - {"log_slow_queries", (char*) &opt_slow_log, SHOW_MY_BOOL}, {"lower_case_file_system", (char*) &lower_case_file_system, SHOW_MY_BOOL}, {"lower_case_table_names", (char*) &lower_case_table_names, SHOW_INT}, {"myisam_recover_options", (char*) &myisam_recover_options_str, SHOW_CHAR_PTR}, From f9fc31f9675c518a265be9009226bbab6701700c Mon Sep 17 00:00:00 2001 From: "antony@pcg5ppc.xiphis.org" <> Date: Thu, 25 Oct 2007 17:23:12 -0700 Subject: [PATCH 083/336] protect bug31473 from regressing into 5.0 --- mysql-test/r/csv.result | 42 +++++++++++++++++++++++++++++++++++++++++ mysql-test/t/csv.test | 33 ++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/mysql-test/r/csv.result b/mysql-test/r/csv.result index 3900597d2a6..dca4e349c8a 100644 --- a/mysql-test/r/csv.result +++ b/mysql-test/r/csv.result @@ -5029,4 +5029,46 @@ F7 FE LATIN SMALL LETTER THORN FF LATIN SMALL LETTER Y WITH DIAERESIS drop table t1; +create table t1(a datetime) engine=csv; +insert into t1 values(); +select * from t1; +a +0000-00-00 00:00:00 +drop table t1; +create table t1(a set('foo','bar')) engine=csv; +insert into t1 values(); +select * from t1; +a + +drop table t1; +create table t1(a varchar(32)) engine=csv; +insert into t1 values(); +select * from t1; +a + +drop table t1; +create table t1(a int) engine=csv; +insert into t1 values(); +select * from t1; +a +0 +drop table t1; +create table t1(a blob) engine=csv; +insert into t1 values(); +select * from t1; +a + +drop table t1; +create table t1(a bit(1)) engine=csv; +insert into t1 values(); +select BIN(a) from t1; +BIN(a) +0 +drop table t1; +create table t1(a enum('foo','bar') default 'foo') engine=csv; +insert into t1 values(); +select * from t1; +a +foo +drop table t1; End of 5.0 tests diff --git a/mysql-test/t/csv.test b/mysql-test/t/csv.test index b724b4ce47c..db5cb92c3e6 100644 --- a/mysql-test/t/csv.test +++ b/mysql-test/t/csv.test @@ -1427,4 +1427,37 @@ insert into t1 values (0xFF,'LATIN SMALL LETTER Y WITH DIAERESIS'); select hex(c), c, name from t1 order by 1; drop table t1; +# +# Bug #31473: does not work with NULL value in datetime field +# This bug is a 5.1 but is here to prevent 5.0 regression. +# +create table t1(a datetime) engine=csv; +insert into t1 values(); +select * from t1; +drop table t1; +create table t1(a set('foo','bar')) engine=csv; +insert into t1 values(); +select * from t1; +drop table t1; +create table t1(a varchar(32)) engine=csv; +insert into t1 values(); +select * from t1; +drop table t1; +create table t1(a int) engine=csv; +insert into t1 values(); +select * from t1; +drop table t1; +create table t1(a blob) engine=csv; +insert into t1 values(); +select * from t1; +drop table t1; +create table t1(a bit(1)) engine=csv; +insert into t1 values(); +select BIN(a) from t1; +drop table t1; +create table t1(a enum('foo','bar') default 'foo') engine=csv; +insert into t1 values(); +select * from t1; +drop table t1; + --echo End of 5.0 tests From ada0b493285392baa63650294be59cbcf9748f00 Mon Sep 17 00:00:00 2001 From: "antony@pcg5ppc.xiphis.org" <> Date: Thu, 25 Oct 2007 21:19:28 -0700 Subject: [PATCH 084/336] Bug#30296 "Dynamic plugins fail to load on FreeBSD" ELF executables need to be linked using the -export-dynamic option to ld(1) for symbols defined in the executable to become visible to dlsym(). Also, do not build plugins on an all-static build. --- config/ac-macros/plugins.m4 | 11 +++++++++++ configure.in | 13 ++++++++++++- sql/sql_yacc.yy | 2 +- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/config/ac-macros/plugins.m4 b/config/ac-macros/plugins.m4 index 48754563992..8dfb698709f 100644 --- a/config/ac-macros/plugins.m4 +++ b/config/ac-macros/plugins.m4 @@ -360,6 +360,17 @@ AC_DEFUN([__MYSQL_EMIT_CHECK_PLUGIN],[ AC_MSG_ERROR([cannot disable mandatory plugin]) fi [mysql_plugin_]$2=yes + ],[ + case "$with_mysqld_ldflags " in + *"-all-static "*) + # No need to build shared plugins when mysqld is linked with + # -all-static as it won't be able to load them. + if test "X[$mysql_plugin_]$2" != Xyes -a \ + "X[$with_plugin_]$2" != Xyes; then + [with_plugin_]$2=no + fi + ;; + esac ]) if test "X[$with_plugin_]$2" = Xno; then AC_MSG_RESULT([no]) diff --git a/configure.in b/configure.in index 0fe2f1b5510..0c5fe692edf 100644 --- a/configure.in +++ b/configure.in @@ -1745,7 +1745,18 @@ then LDFLAGS="$LDFLAGS -rdynamic" AC_MSG_RESULT("-rdynamic") else - AC_MSG_RESULT("none") + case "$SYSTEM_TYPE$with_mysqld_ldflags " in + *freebsd*"-all-static "*|*dragonfly*"-all-static "*) + AC_MSG_RESULT("none") + ;; + *freebsd*|*dragonfly*) + MYSQLD_EXTRA_LDFLAGS="$MYSQLD_EXTRA_LDFLAGS -export-dynamic" + AC_MSG_RESULT("-export-dynamic") + ;; + *) + AC_MSG_RESULT("none") + ;; + esac fi dnl Checks for typedefs, structures, and compiler characteristics. diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 30e62c5d7b5..16fda2886f8 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -6492,7 +6492,7 @@ bool_pri: { $$= (*$2)(0)->create($1,$3); } | bool_pri comp_op all_or_any '(' subselect ')' %prec EQ { $$= all_any_subquery_creator($1, $2, $3, $5); } - | predicate ; + | predicate ; predicate: From 66047f1c163cc8e9caa08db5c79c3c8e24bf1274 Mon Sep 17 00:00:00 2001 From: "tnurnberg@mysql.com/white.intern.koehntopp.de" <> Date: Fri, 26 Oct 2007 09:01:29 +0200 Subject: [PATCH 085/336] Bug#31662: 'null' is shown as type of fields for view with bad definer, breaks mysqldump SHOW FIELDS FROM a view with no valid definer was possible (since fix for Bug#26817), but gave NULL as a field-type. This led to mysqldump-ing of such views being successful, but loading such a dump with the client failing. Patch allows SHOW FIELDS to give data-type of field in underlying table. --- mysql-test/r/information_schema_db.result | 6 +++--- sql/sql_base.cc | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/information_schema_db.result b/mysql-test/r/information_schema_db.result index dd1f0295277..ef63ef719a4 100644 --- a/mysql-test/r/information_schema_db.result +++ b/mysql-test/r/information_schema_db.result @@ -130,7 +130,7 @@ Warnings: Warning 1356 View 'testdb_1.v7' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them show fields from testdb_1.v7; Field Type Null Key Default Extra -f1 null YES NULL +f1 char(4) YES NULL Warnings: Note 1449 There is no 'no_such_user'@'no_such_host' registered create table t3 (f1 char(4), f2 char(4)); @@ -150,7 +150,7 @@ View Create View v6 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `testdb_1`.`v6` AS select `testdb_1`.`t1`.`f1` AS `f1` from `testdb_1`.`t1` show fields from testdb_1.v7; Field Type Null Key Default Extra -f1 null YES NULL +f1 char(4) YES NULL Warnings: Note 1449 There is no 'no_such_user'@'no_such_host' registered show create view testdb_1.v7; @@ -178,7 +178,7 @@ show create view v4; ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table show fields from v4; Field Type Null Key Default Extra -f1 null YES NULL +f1 char(4) YES NULL f2 char(4) YES NULL show fields from v2; Field Type Null Key Default Extra diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 2f8bb35683b..7679c9436e9 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -3958,7 +3958,9 @@ find_field_in_tables(THD *thd, Item_ident *item, { Field *cur_field= find_field_in_table_ref(thd, cur_table, name, length, item->name, db, table_name, ref, - check_privileges, + (thd->lex->sql_command == + SQLCOM_SHOW_FIELDS) + ? false : check_privileges, allow_rowid, &(item->cached_field_index), register_tree_change, From 8ec674dd0c42714214d9b9b1a10ae214fcc77103 Mon Sep 17 00:00:00 2001 From: "ramil/ram@mysql.com/ramil.myoffice.izhnet.ru" <> Date: Fri, 26 Oct 2007 15:37:38 +0500 Subject: [PATCH 086/336] Fix for bug #31137: Assertion failed: primary_key_no == -1 || primary_key_no == 0, file .\ha_innodb. Problem: if a partial unique key followed by a non-partial one we declare the second one as a primary key. Fix: sort non-partial unique keys before partial ones. --- include/my_base.h | 2 +- mysql-test/r/innodb_mysql.result | 15 +++++++++++ mysql-test/r/key.result | 44 ++++++++++++++++++++++++++++++++ mysql-test/t/innodb_mysql.test | 9 +++++++ mysql-test/t/key.test | 18 +++++++++++++ sql/sql_table.cc | 26 +++++++++++++------ sql/structs.h | 2 +- 7 files changed, 106 insertions(+), 10 deletions(-) diff --git a/include/my_base.h b/include/my_base.h index ef5ac364fed..9240b01a9f1 100644 --- a/include/my_base.h +++ b/include/my_base.h @@ -224,7 +224,7 @@ enum ha_base_keytype { #define HA_SPATIAL 1024 /* For spatial search */ #define HA_NULL_ARE_EQUAL 2048 /* NULL in key are cmp as equal */ #define HA_GENERATED_KEY 8192 /* Automaticly generated key */ - +#define HA_KEY_HAS_PART_KEY_SEG 65536 /* Key contains partial segments */ /* Automatic bits in key-flag */ #define HA_SPACE_PACK_USED 4 /* Test for if SPACE_PACK used */ diff --git a/mysql-test/r/innodb_mysql.result b/mysql-test/r/innodb_mysql.result index d5f014b6840..5a85df76347 100644 --- a/mysql-test/r/innodb_mysql.result +++ b/mysql-test/r/innodb_mysql.result @@ -1211,4 +1211,19 @@ a b 3 2 1 1 DROP TABLE t1; +create table t1(a char(10) not null, unique key aa(a(1)), +b char(4) not null, unique key bb(b(4))) engine=innodb; +desc t1; +Field Type Null Key Default Extra +a char(10) NO UNI NULL +b char(4) NO PRI NULL +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` char(10) NOT NULL, + `b` char(4) NOT NULL, + UNIQUE KEY `bb` (`b`), + UNIQUE KEY `aa` (`a`(1)) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +drop table t1; End of 5.0 tests diff --git a/mysql-test/r/key.result b/mysql-test/r/key.result index 2fc751c63bf..0f1ea46bd61 100644 --- a/mysql-test/r/key.result +++ b/mysql-test/r/key.result @@ -462,4 +462,48 @@ EXPLAIN SELECT MAX(a) FROM t1 FORCE INDEX(a); id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 system NULL NULL NULL NULL 1 DROP TABLE t1; +create table t1(a int not null, key aa(a), +b char(10) not null, unique key bb(b(1)), +c char(4) not null, unique key cc(c)); +desc t1; +Field Type Null Key Default Extra +a int(11) NO MUL NULL +b char(10) NO UNI NULL +c char(4) NO PRI NULL +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL, + `b` char(10) NOT NULL, + `c` char(4) NOT NULL, + UNIQUE KEY `cc` (`c`), + UNIQUE KEY `bb` (`b`(1)), + KEY `aa` (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create table t1(a int not null, key aa(a), +b char(10) not null, unique key bb(b(1)), +c char(4) not null); +desc t1; +Field Type Null Key Default Extra +a int(11) NO MUL NULL +b char(10) NO UNI NULL +c char(4) NO NULL +alter table t1 add unique key cc(c); +desc t1; +Field Type Null Key Default Extra +a int(11) NO MUL NULL +b char(10) NO UNI NULL +c char(4) NO PRI NULL +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL, + `b` char(10) NOT NULL, + `c` char(4) NOT NULL, + UNIQUE KEY `cc` (`c`), + UNIQUE KEY `bb` (`b`(1)), + KEY `aa` (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; End of 5.0 tests. diff --git a/mysql-test/t/innodb_mysql.test b/mysql-test/t/innodb_mysql.test index f64efd600c5..13aa6afd701 100644 --- a/mysql-test/t/innodb_mysql.test +++ b/mysql-test/t/innodb_mysql.test @@ -960,4 +960,13 @@ SELECT * FROM t1 ORDER BY b DESC, a ASC; DROP TABLE t1; +# +# Bug #31137: Assertion failed: primary_key_no == -1 || primary_key_no == 0 +# +create table t1(a char(10) not null, unique key aa(a(1)), + b char(4) not null, unique key bb(b(4))) engine=innodb; +desc t1; +show create table t1; +drop table t1; + --echo End of 5.0 tests diff --git a/mysql-test/t/key.test b/mysql-test/t/key.test index 3d0e68dc0f3..f63336a9864 100644 --- a/mysql-test/t/key.test +++ b/mysql-test/t/key.test @@ -443,4 +443,22 @@ ALTER TABLE t1 DISABLE KEYS; EXPLAIN SELECT MAX(a) FROM t1 FORCE INDEX(a); DROP TABLE t1; +# +# Bug #31137: Assertion failed: primary_key_no == -1 || primary_key_no == 0 +# +create table t1(a int not null, key aa(a), + b char(10) not null, unique key bb(b(1)), + c char(4) not null, unique key cc(c)); +desc t1; +show create table t1; +drop table t1; +create table t1(a int not null, key aa(a), + b char(10) not null, unique key bb(b(1)), + c char(4) not null); +desc t1; +alter table t1 add unique key cc(c); +desc t1; +show create table t1; +drop table t1; + --echo End of 5.0 tests. diff --git a/sql/sql_table.cc b/sql/sql_table.cc index b6e41788ef0..9d6f66aff53 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -361,7 +361,8 @@ int quick_rm_table(enum db_type base,const char *db, /* Sort keys in the following order: - PRIMARY KEY - - UNIQUE keyws where all column are NOT NULL + - UNIQUE keys where all column are NOT NULL + - UNIQUE keys that don't contain partial segments - Other UNIQUE keys - Normal keys - Fulltext keys @@ -372,26 +373,31 @@ int quick_rm_table(enum db_type base,const char *db, static int sort_keys(KEY *a, KEY *b) { - if (a->flags & HA_NOSAME) + ulong a_flags= a->flags, b_flags= b->flags; + + if (a_flags & HA_NOSAME) { - if (!(b->flags & HA_NOSAME)) + if (!(b_flags & HA_NOSAME)) return -1; - if ((a->flags ^ b->flags) & (HA_NULL_PART_KEY | HA_END_SPACE_KEY)) + if ((a_flags ^ b_flags) & (HA_NULL_PART_KEY | HA_END_SPACE_KEY)) { /* Sort NOT NULL keys before other keys */ - return (a->flags & (HA_NULL_PART_KEY | HA_END_SPACE_KEY)) ? 1 : -1; + return (a_flags & (HA_NULL_PART_KEY | HA_END_SPACE_KEY)) ? 1 : -1; } if (a->name == primary_key_name) return -1; if (b->name == primary_key_name) return 1; + /* Sort keys don't containing partial segments before others */ + if ((a_flags ^ b_flags) & HA_KEY_HAS_PART_KEY_SEG) + return (a_flags & HA_KEY_HAS_PART_KEY_SEG) ? 1 : -1; } - else if (b->flags & HA_NOSAME) + else if (b_flags & HA_NOSAME) return 1; // Prefer b - if ((a->flags ^ b->flags) & HA_FULLTEXT) + if ((a_flags ^ b_flags) & HA_FULLTEXT) { - return (a->flags & HA_FULLTEXT) ? 1 : -1; + return (a_flags & HA_FULLTEXT) ? 1 : -1; } /* Prefer original key order. usable_key_parts contains here @@ -1421,6 +1427,10 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, else key_info->flags|= HA_PACK_KEY; } + /* Check if the key segment is partial, set the key flag accordingly */ + if (length != sql_field->key_length) + key_info->flags|= HA_KEY_HAS_PART_KEY_SEG; + key_length+=length; key_part_info++; diff --git a/sql/structs.h b/sql/structs.h index 28bdd8c1519..bc373fe4b52 100644 --- a/sql/structs.h +++ b/sql/structs.h @@ -87,7 +87,7 @@ typedef struct st_key_part_info { /* Info about a key part */ typedef struct st_key { uint key_length; /* Tot length of key */ - uint flags; /* dupp key and pack flags */ + ulong flags; /* dupp key and pack flags */ uint key_parts; /* How many key_parts */ uint extra_length; uint usable_key_parts; /* Should normally be = key_parts */ From 8cc5fe116f85763a25634c67040d093b175aaca1 Mon Sep 17 00:00:00 2001 From: "istruewing@stella.local" <> Date: Fri, 26 Oct 2007 15:29:06 +0200 Subject: [PATCH 087/336] Bug#4692 - DISABLE/ENABLE KEYS waste a space Disabling and enabling indexes on a non-empty table grows the index file. Disabling indexes just sets a flag per non-unique index and does not free the index blocks of the affected indexes. Re-enabling indexes creates new indexes with new blocks. The old blocks remain unused in the index file. Fixed by dropping and re-creating all indexes if non-empty disabled indexes exist when enabling indexes. Dropping all indexes resets the internal end-of-file marker to the end of the index file header. It also clears the root block pointers of every index and clears the deleted blocks chains. This way all blocks are declared as free. --- myisam/mi_check.c | 222 +++++++++++++++++++++------- mysql-test/r/bdb_notembedded.result | 35 ----- mysql-test/r/myisam.result | 25 ++++ mysql-test/t/bdb_notembedded.test | 38 ----- mysql-test/t/myisam.test | 26 ++++ 5 files changed, 216 insertions(+), 130 deletions(-) delete mode 100644 mysql-test/r/bdb_notembedded.result delete mode 100644 mysql-test/t/bdb_notembedded.test diff --git a/myisam/mi_check.c b/myisam/mi_check.c index ed0a84e737d..c225e2bdb5c 100644 --- a/myisam/mi_check.c +++ b/myisam/mi_check.c @@ -1375,6 +1375,139 @@ int chk_data_link(MI_CHECK *param, MI_INFO *info,int extend) } /* chk_data_link */ +/** + @brief Drop all indexes + + @param[in] param check parameters + @param[in] info MI_INFO handle + @param[in] force if to force drop all indexes + + @return status + @retval 0 OK + @retval != 0 Error + + @note + Once allocated, index blocks remain part of the key file forever. + When indexes are disabled, no block is freed. When enabling indexes, + no block is freed either. The new indexes are create from new + blocks. (Bug #4692) + + Before recreating formerly disabled indexes, the unused blocks + must be freed. There are two options to do this: + - Follow the tree of disabled indexes, add all blocks to the + deleted blocks chain. Would require a lot of random I/O. + - Drop all blocks by clearing all index root pointers and all + delete chain pointers and resetting key_file_length to the end + of the index file header. This requires to recreate all indexes, + even those that may still be intact. + The second method is probably faster in most cases. + + When disabling indexes, MySQL disables either all indexes or all + non-unique indexes. When MySQL [re-]enables disabled indexes + (T_CREATE_MISSING_KEYS), then we either have "lost" blocks in the + index file, or there are no non-unique indexes. In the latter case, + mi_repair*() would not be called as there would be no disabled + indexes. + + If there would be more unique indexes than disabled (non-unique) + indexes, we could do the first method. But this is not implemented + yet. By now we drop and recreate all indexes when repair is called. + + However, there is an exception. Sometimes MySQL disables non-unique + indexes when the table is empty (e.g. when copying a table in + mysql_alter_table()). When enabling the non-unique indexes, they + are still empty. So there is no index block that can be lost. This + optimization is implemented in this function. + + Note that in normal repair (T_CREATE_MISSING_KEYS not set) we + recreate all enabled indexes unconditonally. We do not change the + key_map. Otherwise we invert the key map temporarily (outside of + this function) and recreate the then "seemingly" enabled indexes. + When we cannot use the optimization, and drop all indexes, we + pretend that all indexes were disabled. By the inversion, we will + then recrate all indexes. +*/ + +static int mi_drop_all_indexes(MI_CHECK *param, MI_INFO *info, my_bool force) +{ + MYISAM_SHARE *share= info->s; + MI_STATE_INFO *state= &share->state; + uint i; + int error; + DBUG_ENTER("mi_drop_all_indexes"); + + /* + If any of the disabled indexes has a key block assigned, we must + drop and recreate all indexes to avoid losing index blocks. + + If we want to recreate disabled indexes only _and_ all of these + indexes are empty, we don't need to recreate the existing indexes. + */ + if (!force && (param->testflag & T_CREATE_MISSING_KEYS)) + { + DBUG_PRINT("repair", ("creating missing indexes")); + for (i= 0; i < share->base.keys; i++) + { + DBUG_PRINT("repair", ("index #: %u key_root: 0x%lx active: %d", + i, (long) state->key_root[i], + mi_is_key_active(state->key_map, i))); + if ((state->key_root[i] != HA_OFFSET_ERROR) && + !mi_is_key_active(state->key_map, i)) + { + /* + This index has at least one key block and it is disabled. + We would lose its block(s) if would just recreate it. + So we need to drop and recreate all indexes. + */ + DBUG_PRINT("repair", ("nonempty and disabled: recreate all")); + break; + } + } + if (i >= share->base.keys) + { + /* + All of the disabled indexes are empty. We can just recreate them. + Flush dirty blocks of this index file from key cache and remove + all blocks of this index file from key cache. + */ + DBUG_PRINT("repair", ("all disabled are empty: create missing")); + error= flush_key_blocks(share->key_cache, share->kfile, + FLUSH_FORCE_WRITE); + goto end; + } + /* + We do now drop all indexes and declare them disabled. With the + T_CREATE_MISSING_KEYS flag, mi_repair*() will recreate all + disabled indexes and enable them. + */ + mi_clear_all_keys_active(state->key_map); + DBUG_PRINT("repair", ("declared all indexes disabled")); + } + + /* Remove all key blocks of this index file from key cache. */ + if ((error= flush_key_blocks(share->key_cache, share->kfile, + FLUSH_IGNORE_CHANGED))) + goto end; + + /* Clear index root block pointers. */ + for (i= 0; i < share->base.keys; i++) + state->key_root[i]= HA_OFFSET_ERROR; + + /* Clear the delete chains. */ + for (i= 0; i < state->header.max_block_size; i++) + state->key_del[i]= HA_OFFSET_ERROR; + + /* Reset index file length to end of index file header. */ + info->state->key_file_length= share->base.keystart; + + DBUG_PRINT("repair", ("dropped all indexes")); + /* error= 0; set by last (error= flush_key_bocks()). */ + + end: + DBUG_RETURN(error); +} + + /* Recover old table by reading each record and writing all keys */ /* Save new datafile-name in temp_filename */ @@ -1382,7 +1515,6 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info, my_string name, int rep_quick) { int error,got_error; - uint i; ha_rows start_records,new_header_length; my_off_t del; File new_file; @@ -1486,25 +1618,10 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info, info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED); - /* - Clear all keys. Note that all key blocks allocated until now remain - "dead" parts of the key file. (Bug #4692) - */ - for (i=0 ; i < info->s->base.keys ; i++) - share->state.key_root[i]= HA_OFFSET_ERROR; - - /* Drop the delete chain. */ - for (i=0 ; i < share->state.header.max_block_size ; i++) - share->state.key_del[i]= HA_OFFSET_ERROR; - - /* - If requested, activate (enable) all keys in key_map. In this case, - all indexes will be (re-)built. - */ + /* This function always recreates all enabled indexes. */ if (param->testflag & T_CREATE_MISSING_KEYS) mi_set_all_keys_active(share->state.key_map, share->base.keys); - - info->state->key_file_length=share->base.keystart; + mi_drop_all_indexes(param, info, TRUE); lock_memory(param); /* Everything is alloced */ @@ -2105,7 +2222,7 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info, ulong *rec_per_key_part; char llbuff[22]; SORT_INFO sort_info; - ulonglong key_map=share->state.key_map; + ulonglong key_map; DBUG_ENTER("mi_repair_by_sort"); start_records=info->state->records; @@ -2179,25 +2296,14 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info, } info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED); - if (!(param->testflag & T_CREATE_MISSING_KEYS)) + + /* Optionally drop indexes and optionally modify the key_map. */ + mi_drop_all_indexes(param, info, FALSE); + key_map= share->state.key_map; + if (param->testflag & T_CREATE_MISSING_KEYS) { - /* - Flush key cache for this file if we are calling this outside - myisamchk - */ - flush_key_blocks(share->key_cache,share->kfile, FLUSH_IGNORE_CHANGED); - /* Clear the pointers to the given rows */ - for (i=0 ; i < share->base.keys ; i++) - share->state.key_root[i]= HA_OFFSET_ERROR; - for (i=0 ; i < share->state.header.max_block_size ; i++) - share->state.key_del[i]= HA_OFFSET_ERROR; - info->state->key_file_length=share->base.keystart; - } - else - { - if (flush_key_blocks(share->key_cache,share->kfile, FLUSH_FORCE_WRITE)) - goto err; - key_map= ~key_map; /* Create the missing keys */ + /* Invert the copied key_map to recreate all disabled indexes. */ + key_map= ~key_map; } sort_info.info=info; @@ -2240,6 +2346,10 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info, sort_param.read_cache=param->read_cache; sort_param.keyinfo=share->keyinfo+sort_param.key; sort_param.seg=sort_param.keyinfo->seg; + /* + Skip this index if it is marked disabled in the copied + (and possibly inverted) key_map. + */ if (! mi_is_key_active(key_map, sort_param.key)) { /* Remember old statistics for key */ @@ -2247,6 +2357,8 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info, (char*) (share->state.rec_per_key_part + (uint) (rec_per_key_part - param->rec_per_key_part)), sort_param.keyinfo->keysegs*sizeof(*rec_per_key_part)); + DBUG_PRINT("repair", ("skipping seemingly disabled index #: %u", + sort_param.key)); continue; } @@ -2302,8 +2414,11 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info, if (param->testflag & T_STATISTICS) update_key_parts(sort_param.keyinfo, rec_per_key_part, sort_param.unique, param->stats_method == MI_STATS_METHOD_IGNORE_NULLS? - sort_param.notnull: NULL,(ulonglong) info->state->records); + sort_param.notnull: NULL, + (ulonglong) info->state->records); + /* Enable this index in the permanent (not the copied) key_map. */ mi_set_key_active(share->state.key_map, sort_param.key); + DBUG_PRINT("repair", ("set enabled index #: %u", sort_param.key)); if (sort_param.fix_datafile) { @@ -2504,7 +2619,7 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info, IO_CACHE new_data_cache; /* For non-quick repair. */ IO_CACHE_SHARE io_share; SORT_INFO sort_info; - ulonglong key_map=share->state.key_map; + ulonglong key_map; pthread_attr_t thr_attr; DBUG_ENTER("mi_repair_parallel"); @@ -2608,25 +2723,14 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info, } info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED); - if (!(param->testflag & T_CREATE_MISSING_KEYS)) + + /* Optionally drop indexes and optionally modify the key_map. */ + mi_drop_all_indexes(param, info, FALSE); + key_map= share->state.key_map; + if (param->testflag & T_CREATE_MISSING_KEYS) { - /* - Flush key cache for this file if we are calling this outside - myisamchk - */ - flush_key_blocks(share->key_cache,share->kfile, FLUSH_IGNORE_CHANGED); - /* Clear the pointers to the given rows */ - for (i=0 ; i < share->base.keys ; i++) - share->state.key_root[i]= HA_OFFSET_ERROR; - for (i=0 ; i < share->state.header.max_block_size ; i++) - share->state.key_del[i]= HA_OFFSET_ERROR; - info->state->key_file_length=share->base.keystart; - } - else - { - if (flush_key_blocks(share->key_cache,share->kfile, FLUSH_FORCE_WRITE)) - goto err; - key_map= ~key_map; /* Create the missing keys */ + /* Invert the copied key_map to recreate all disabled indexes. */ + key_map= ~key_map; } sort_info.info=info; @@ -2682,6 +2786,10 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info, sort_param[i].key=key; sort_param[i].keyinfo=share->keyinfo+key; sort_param[i].seg=sort_param[i].keyinfo->seg; + /* + Skip this index if it is marked disabled in the copied + (and possibly inverted) key_map. + */ if (! mi_is_key_active(key_map, key)) { /* Remember old statistics for key */ diff --git a/mysql-test/r/bdb_notembedded.result b/mysql-test/r/bdb_notembedded.result deleted file mode 100644 index 14cb5fad915..00000000000 --- a/mysql-test/r/bdb_notembedded.result +++ /dev/null @@ -1,35 +0,0 @@ -set autocommit=1; -reset master; -create table bug16206 (a int); -insert into bug16206 values(1); -start transaction; -insert into bug16206 values(2); -commit; -show binlog events; -Log_name Pos Event_type Server_id End_log_pos Info -f n Format_desc 1 n Server ver: VERSION, Binlog ver: 4 -f n Query 1 n use `test`; create table bug16206 (a int) -f n Query 1 n use `test`; insert into bug16206 values(1) -f n Query 1 n use `test`; insert into bug16206 values(2) -drop table bug16206; -reset master; -create table bug16206 (a int) engine= bdb; -insert into bug16206 values(0); -insert into bug16206 values(1); -start transaction; -insert into bug16206 values(2); -commit; -insert into bug16206 values(3); -show binlog events; -Log_name Pos Event_type Server_id End_log_pos Info -f n Format_desc 1 n Server ver: VERSION, Binlog ver: 4 -f n Query 1 n use `test`; create table bug16206 (a int) engine= bdb -f n Query 1 n use `test`; insert into bug16206 values(0) -f n Query 1 n use `test`; insert into bug16206 values(1) -f n Query 1 n use `test`; BEGIN -f n Query 1 n use `test`; insert into bug16206 values(2) -f n Query 1 n use `test`; COMMIT -f n Query 1 n use `test`; insert into bug16206 values(3) -drop table bug16206; -set autocommit=0; -End of 5.0 tests diff --git a/mysql-test/r/myisam.result b/mysql-test/r/myisam.result index 7fc29cd13ca..176d0e97012 100644 --- a/mysql-test/r/myisam.result +++ b/mysql-test/r/myisam.result @@ -1806,4 +1806,29 @@ SELECT a FROM t1 FORCE INDEX (inx) WHERE a=1; a 1 DROP TABLE t1; +CREATE TABLE t1 (c1 INT, c2 INT, UNIQUE INDEX (c1), INDEX (c2)) ENGINE=MYISAM; +SHOW TABLE STATUS LIKE 't1'; +Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment +t1 MyISAM 10 Fixed 0 # # # 1024 # # # # # # # +INSERT INTO t1 VALUES (1,1); +SHOW TABLE STATUS LIKE 't1'; +Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment +t1 MyISAM 10 Fixed 1 # # # 3072 # # # # # # # +ALTER TABLE t1 DISABLE KEYS; +SHOW TABLE STATUS LIKE 't1'; +Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment +t1 MyISAM 10 Fixed 1 # # # 3072 # # # # # # # +ALTER TABLE t1 ENABLE KEYS; +SHOW TABLE STATUS LIKE 't1'; +Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment +t1 MyISAM 10 Fixed 1 # # # 3072 # # # # # # # +ALTER TABLE t1 DISABLE KEYS; +SHOW TABLE STATUS LIKE 't1'; +Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment +t1 MyISAM 10 Fixed 1 # # # 3072 # # # # # # # +ALTER TABLE t1 ENABLE KEYS; +SHOW TABLE STATUS LIKE 't1'; +Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment +t1 MyISAM 10 Fixed 1 # # # 3072 # # # # # # # +DROP TABLE t1; End of 5.0 tests diff --git a/mysql-test/t/bdb_notembedded.test b/mysql-test/t/bdb_notembedded.test deleted file mode 100644 index 24e64ebbfb2..00000000000 --- a/mysql-test/t/bdb_notembedded.test +++ /dev/null @@ -1,38 +0,0 @@ --- source include/not_embedded.inc --- source include/have_bdb.inc - -# -# Bug #16206: Superfluous COMMIT event in binlog when updating BDB in autocommit mode -# -set autocommit=1; - -let $VERSION=`select version()`; - -reset master; -create table bug16206 (a int); -insert into bug16206 values(1); -start transaction; -insert into bug16206 values(2); -commit; ---replace_result $VERSION VERSION ---replace_column 1 f 2 n 5 n -show binlog events; -drop table bug16206; - -reset master; -create table bug16206 (a int) engine= bdb; -insert into bug16206 values(0); -insert into bug16206 values(1); -start transaction; -insert into bug16206 values(2); -commit; -insert into bug16206 values(3); ---replace_result $VERSION VERSION ---replace_column 1 f 2 n 5 n -show binlog events; -drop table bug16206; - -set autocommit=0; - - ---echo End of 5.0 tests diff --git a/mysql-test/t/myisam.test b/mysql-test/t/myisam.test index d5f403616c8..ad223dc2664 100644 --- a/mysql-test/t/myisam.test +++ b/mysql-test/t/myisam.test @@ -1161,4 +1161,30 @@ ALTER TABLE t1 ENABLE KEYS; SELECT a FROM t1 FORCE INDEX (inx) WHERE a=1; DROP TABLE t1; +# +# Bug#4692 - DISABLE/ENABLE KEYS waste a space +# +CREATE TABLE t1 (c1 INT, c2 INT, UNIQUE INDEX (c1), INDEX (c2)) ENGINE=MYISAM; +--replace_column 6 # 7 # 8 # 10 # 11 # 12 # 13 # 14 # 15 # 16 # +SHOW TABLE STATUS LIKE 't1'; +INSERT INTO t1 VALUES (1,1); +--replace_column 6 # 7 # 8 # 10 # 11 # 12 # 13 # 14 # 15 # 16 # +SHOW TABLE STATUS LIKE 't1'; +ALTER TABLE t1 DISABLE KEYS; +--replace_column 6 # 7 # 8 # 10 # 11 # 12 # 13 # 14 # 15 # 16 # +SHOW TABLE STATUS LIKE 't1'; +ALTER TABLE t1 ENABLE KEYS; +--replace_column 6 # 7 # 8 # 10 # 11 # 12 # 13 # 14 # 15 # 16 # +SHOW TABLE STATUS LIKE 't1'; +ALTER TABLE t1 DISABLE KEYS; +--replace_column 6 # 7 # 8 # 10 # 11 # 12 # 13 # 14 # 15 # 16 # +SHOW TABLE STATUS LIKE 't1'; +ALTER TABLE t1 ENABLE KEYS; +--replace_column 6 # 7 # 8 # 10 # 11 # 12 # 13 # 14 # 15 # 16 # +SHOW TABLE STATUS LIKE 't1'; +#--exec ls -log var/master-data/test/t1.MYI +#--exec myisamchk -dvv var/master-data/test/t1.MYI +#--exec myisamchk -iev var/master-data/test/t1.MYI +DROP TABLE t1; + --echo End of 5.0 tests From 6d1f99b7d67cd7c8e83539eade2db0d6502e7b0d Mon Sep 17 00:00:00 2001 From: "msvensson@pilot.mysql.com" <> Date: Fri, 26 Oct 2007 16:11:20 +0200 Subject: [PATCH 088/336] Bug#28772 rpl_row_until fails in pushbuild --- mysql-test/suite/rpl/t/rpl_row_until.test | 4 ++++ mysql-test/suite/rpl/t/rpl_stm_until.test | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/mysql-test/suite/rpl/t/rpl_row_until.test b/mysql-test/suite/rpl/t/rpl_row_until.test index 9464e5cfadd..610eec305df 100644 --- a/mysql-test/suite/rpl/t/rpl_row_until.test +++ b/mysql-test/suite/rpl/t/rpl_row_until.test @@ -13,6 +13,8 @@ save_master_pos; connection slave; sync_with_master; stop slave; +# Make sure the slave sql and io thread has stopped +--source include/wait_for_slave_to_stop.inc connection master; # create some events on master @@ -52,6 +54,8 @@ save_master_pos; connection slave; sync_with_master; stop slave; +# Make sure the slave sql and io thread has stopped +--source include/wait_for_slave_to_stop.inc # this should stop immediately as we are already there start slave until master_log_file='master-bin.000001', master_log_pos=740; diff --git a/mysql-test/suite/rpl/t/rpl_stm_until.test b/mysql-test/suite/rpl/t/rpl_stm_until.test index 98e7e0e5eac..c8d3cb1823d 100644 --- a/mysql-test/suite/rpl/t/rpl_stm_until.test +++ b/mysql-test/suite/rpl/t/rpl_stm_until.test @@ -12,6 +12,8 @@ save_master_pos; connection slave; sync_with_master; stop slave; +# Make sure the slave sql and io thread has stopped +--source include/wait_for_slave_to_stop.inc connection master; # create some events on master @@ -51,6 +53,8 @@ save_master_pos; connection slave; sync_with_master; stop slave; +# Make sure the slave sql and io thread has stopped +--source include/wait_for_slave_to_stop.inc # this should stop immediately as we are already there start slave until master_log_file='master-bin.000001', master_log_pos=776; From 5eb3b270d3dd38e2cc6894d622849eb3a12856db Mon Sep 17 00:00:00 2001 From: "gshchepa/uchum@gleb.loc" <> Date: Fri, 26 Oct 2007 21:26:06 +0500 Subject: [PATCH 089/336] Fixed bug #31036: Using order by with archive table crashes server. 1. Memory overrun have been fixed. 2. Server failure on assertion has been fixed. --- mysql-test/r/archive.result | 4 ++++ mysql-test/t/archive.test | 22 ++++++++++++++++++++++ storage/archive/azio.c | 10 +++++----- storage/archive/ha_archive.cc | 4 ++-- 4 files changed, 33 insertions(+), 7 deletions(-) diff --git a/mysql-test/r/archive.result b/mysql-test/r/archive.result index 36b013703d8..803c102f6cf 100644 --- a/mysql-test/r/archive.result +++ b/mysql-test/r/archive.result @@ -12682,3 +12682,7 @@ check table t1 extended; Table Op Msg_type Msg_text test.t1 check status OK drop table t1; +CREATE TABLE t1(a VARCHAR(510)) ENGINE = ARCHIVE; +INSERT INTO t1(a) VALUES (''); +SELECT * FROM t1 ORDER BY a; +DROP TABLE t1; diff --git a/mysql-test/t/archive.test b/mysql-test/t/archive.test index 23c591856a7..a8567ab9fd0 100644 --- a/mysql-test/t/archive.test +++ b/mysql-test/t/archive.test @@ -1559,3 +1559,25 @@ insert into t1 set a=''; insert into t1 set a='a'; check table t1 extended; drop table t1; + +# +# BUG#31036 - Using order by with archive table crashes server +# + +CREATE TABLE t1(a VARCHAR(510)) ENGINE = ARCHIVE; + +let $bug31036=41; +--disable_query_log +while($bug31036) +{ + INSERT INTO t1(a) VALUES (REPEAT('a', 510)); + dec $bug31036; +} +--enable_query_log +INSERT INTO t1(a) VALUES (''); + +--disable_result_log +SELECT * FROM t1 ORDER BY a; +--enable_result_log + +DROP TABLE t1; diff --git a/storage/archive/azio.c b/storage/archive/azio.c index f6b1a6e733f..b5c3dd465af 100644 --- a/storage/archive/azio.c +++ b/storage/archive/azio.c @@ -681,8 +681,8 @@ my_off_t azseek (s, offset, whence) /* There was a zmemzero here if inbuf was null -Brian */ while (offset > 0) { - uInt size = AZ_BUFSIZE_WRITE; - if (offset < AZ_BUFSIZE_WRITE) size = (uInt)offset; + uInt size = AZ_BUFSIZE_READ; + if (offset < AZ_BUFSIZE_READ) size = (uInt)offset; size = azwrite(s, s->inbuf, size); if (size == 0) return -1L; @@ -725,11 +725,11 @@ my_off_t azseek (s, offset, whence) } while (offset > 0) { int error; - unsigned int size = AZ_BUFSIZE_READ; - if (offset < AZ_BUFSIZE_READ) size = (int)offset; + unsigned int size = AZ_BUFSIZE_WRITE; + if (offset < AZ_BUFSIZE_WRITE) size = (int)offset; size = azread(s, s->outbuf, size, &error); - if (error <= 0) return -1L; + if (error < 0) return -1L; offset -= size; } return s->out; diff --git a/storage/archive/ha_archive.cc b/storage/archive/ha_archive.cc index 6696eac2fbb..3015ae78761 100644 --- a/storage/archive/ha_archive.cc +++ b/storage/archive/ha_archive.cc @@ -1241,8 +1241,8 @@ int ha_archive::rnd_pos(uchar * buf, uchar *pos) DBUG_ENTER("ha_archive::rnd_pos"); ha_statistic_increment(&SSV::ha_read_rnd_next_count); current_position= (my_off_t)my_get_ptr(pos, ref_length); - (void)azseek(&archive, current_position, SEEK_SET); - + if (azseek(&archive, current_position, SEEK_SET) < 0) + DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE); DBUG_RETURN(get_row(&archive, buf)); } From 83cfdff63883dbc70794945a0b6a97e6f568d8e4 Mon Sep 17 00:00:00 2001 From: "mats@kindahl-laptop.dnsalias.net" <> Date: Fri, 26 Oct 2007 18:52:58 +0200 Subject: [PATCH 090/336] BUG#12691 (Exec_master_log_pos corrupted with SQL_SLAVE_SKIP_COUNTER): Adding code to keep skipping events while inside a transaction. Execution will start just after the transaction has been skipped. --- mysql-test/r/rpl_slave_skip.result | 144 ++++++++++++++++++ mysql-test/t/rpl_slave_skip-slave.opt | 1 + mysql-test/t/rpl_slave_skip.test | 203 ++++++++++++++++++++++++++ sql/slave.cc | 56 ++++++- 4 files changed, 401 insertions(+), 3 deletions(-) create mode 100644 mysql-test/r/rpl_slave_skip.result create mode 100644 mysql-test/t/rpl_slave_skip-slave.opt create mode 100644 mysql-test/t/rpl_slave_skip.test diff --git a/mysql-test/r/rpl_slave_skip.result b/mysql-test/r/rpl_slave_skip.result new file mode 100644 index 00000000000..a59ac3eb884 --- /dev/null +++ b/mysql-test/r/rpl_slave_skip.result @@ -0,0 +1,144 @@ +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; +**** On Master **** +CREATE TABLE t1 (a INT, b SET('master','slave')) ENGINE=INNODB; +CREATE TABLE t2 (a INT, b SET('master','slave')) ENGINE=MYISAM; +==== Skipping normal transactions ==== +**** On Slave **** +STOP SLAVE; +**** On Master **** +BEGIN; +INSERT INTO t1 VALUES (1, 'master'); +INSERT INTO t1 VALUES (2, 'master'); +INSERT INTO t1 VALUES (3, 'master'); +COMMIT; +BEGIN; +INSERT INTO t1 VALUES (4, 'master,slave'); +INSERT INTO t1 VALUES (5, 'master,slave'); +INSERT INTO t1 VALUES (6, 'master,slave'); +COMMIT; +SELECT * FROM t1 ORDER BY a; +a b +1 master +2 master +3 master +4 master,slave +5 master,slave +6 master,slave +**** On Slave **** +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; +START SLAVE; +SELECT * FROM t1 ORDER BY a; +a b +4 master,slave +5 master,slave +6 master,slave +**** On Master **** +DELETE FROM t1; +==== Skipping two normal transactions ==== +**** On Slave **** +STOP SLAVE; +**** On Master **** +BEGIN; +INSERT INTO t1 VALUES (1, 'master'); +INSERT INTO t1 VALUES (2, 'master'); +INSERT INTO t1 VALUES (3, 'master'); +COMMIT; +BEGIN; +INSERT INTO t1 VALUES (4, 'master'); +INSERT INTO t1 VALUES (5, 'master'); +INSERT INTO t1 VALUES (6, 'master'); +COMMIT; +BEGIN; +INSERT INTO t1 VALUES (7, 'master,slave'); +INSERT INTO t1 VALUES (8, 'master,slave'); +INSERT INTO t1 VALUES (9, 'master,slave'); +COMMIT; +SELECT * FROM t1 ORDER BY a; +a b +1 master +2 master +3 master +4 master +5 master +6 master +7 master,slave +8 master,slave +9 master,slave +**** On Slave **** +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=8; +START SLAVE; +SELECT * FROM t1 ORDER BY a; +a b +7 master,slave +8 master,slave +9 master,slave +**** On Master **** +DELETE FROM t1; +==== Skipping without autocommit ==== +**** On Slave **** +STOP SLAVE; +**** On Master **** +SET AUTOCOMMIT=0; +INSERT INTO t1 VALUES (1, 'master'); +INSERT INTO t1 VALUES (2, 'master'); +INSERT INTO t1 VALUES (3, 'master'); +COMMIT; +INSERT INTO t1 VALUES (4, 'master,slave'); +INSERT INTO t1 VALUES (5, 'master,slave'); +INSERT INTO t1 VALUES (6, 'master,slave'); +COMMIT; +SELECT * FROM t1 ORDER BY a; +a b +1 master +2 master +3 master +4 master,slave +5 master,slave +6 master,slave +**** On Slave **** +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; +START SLAVE; +SELECT * FROM t1 ORDER BY a; +a b +4 master,slave +5 master,slave +6 master,slave +==== Rollback of transaction with non-transactional change ==== +**** On Master **** +DELETE FROM t1; +SET AUTOCOMMIT=1; +**** On Slave **** +STOP SLAVE; +**** On Master **** +BEGIN; +INSERT INTO t1 VALUES (1, ''); +INSERT INTO t2 VALUES (2, 'master'); +INSERT INTO t1 VALUES (3, ''); +ROLLBACK; +BEGIN; +INSERT INTO t1 VALUES (4, ''); +INSERT INTO t2 VALUES (5, 'master,slave'); +INSERT INTO t1 VALUES (6, ''); +ROLLBACK; +SELECT * FROM t1 ORDER BY a; +a b +SELECT * FROM t2 ORDER BY a; +a b +2 master +5 master,slave +**** On Slave **** +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; +START SLAVE; +SELECT * FROM t1 ORDER BY a; +a b +SELECT * FROM t2 ORDER BY a; +a b +5 master,slave +==== Cleanup ==== +**** On Master **** +DROP TABLE t1, t2; diff --git a/mysql-test/t/rpl_slave_skip-slave.opt b/mysql-test/t/rpl_slave_skip-slave.opt new file mode 100644 index 00000000000..627becdbfb5 --- /dev/null +++ b/mysql-test/t/rpl_slave_skip-slave.opt @@ -0,0 +1 @@ +--innodb diff --git a/mysql-test/t/rpl_slave_skip.test b/mysql-test/t/rpl_slave_skip.test new file mode 100644 index 00000000000..04aafc51129 --- /dev/null +++ b/mysql-test/t/rpl_slave_skip.test @@ -0,0 +1,203 @@ +source include/have_innodb.inc; +source include/master-slave.inc; + +# This test is for checking that the use of SQL_SLAVE_SKIP_COUNTER +# behaves as expected, i.e., that it is guaranteed to skip an entire +# group and not start executing in the middle of a transaction. + +# We are checking the correct behaviour when using both a +# transactional and non-transactional table. The non-transactional +# table comes into play when rolling back a transaction containing a +# write to this table. In that case, the transaction should still be +# written to the binary log, and the slave will apply it and then roll +# it back to get the non-transactional change into the table. + +--echo **** On Master **** +CREATE TABLE t1 (a INT, b SET('master','slave')) ENGINE=INNODB; +CREATE TABLE t2 (a INT, b SET('master','slave')) ENGINE=MYISAM; + +--echo ==== Skipping normal transactions ==== + +--echo **** On Slave **** +sync_slave_with_master; +STOP SLAVE; +source include/wait_for_slave_to_stop.inc; + +--echo **** On Master **** +connection master; + +BEGIN; +INSERT INTO t1 VALUES (1, 'master'); +INSERT INTO t1 VALUES (2, 'master'); +INSERT INTO t1 VALUES (3, 'master'); +COMMIT; + +BEGIN; +INSERT INTO t1 VALUES (4, 'master,slave'); +INSERT INTO t1 VALUES (5, 'master,slave'); +INSERT INTO t1 VALUES (6, 'master,slave'); +COMMIT; + +save_master_pos; + +SELECT * FROM t1 ORDER BY a; + +# This will skip a begin event and the first INSERT of the +# transaction, and it should keep skipping until it has reached the +# transaction terminator. + +--echo **** On Slave **** +connection slave; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; +START SLAVE; +source include/wait_for_slave_to_start.inc; +sync_with_master; +SELECT * FROM t1 ORDER BY a; + +--echo **** On Master **** +connection master; +DELETE FROM t1; +sync_slave_with_master; + +--echo ==== Skipping two normal transactions ==== + +--echo **** On Slave **** +connection slave; +STOP SLAVE; +source include/wait_for_slave_to_stop.inc; + +--echo **** On Master **** +connection master; + +BEGIN; +INSERT INTO t1 VALUES (1, 'master'); +INSERT INTO t1 VALUES (2, 'master'); +INSERT INTO t1 VALUES (3, 'master'); +COMMIT; + +BEGIN; +INSERT INTO t1 VALUES (4, 'master'); +INSERT INTO t1 VALUES (5, 'master'); +INSERT INTO t1 VALUES (6, 'master'); +COMMIT; + +BEGIN; +INSERT INTO t1 VALUES (7, 'master,slave'); +INSERT INTO t1 VALUES (8, 'master,slave'); +INSERT INTO t1 VALUES (9, 'master,slave'); +COMMIT; + +save_master_pos; + +SELECT * FROM t1 ORDER BY a; + +# This will skip a begin event and the first INSERT of the +# transaction, and it should keep skipping until it has reached the +# transaction terminator. + +--echo **** On Slave **** +connection slave; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=8; +START SLAVE; +source include/wait_for_slave_to_start.inc; +sync_with_master; +SELECT * FROM t1 ORDER BY a; + +--echo **** On Master **** +connection master; +DELETE FROM t1; +sync_slave_with_master; + +--echo ==== Skipping without autocommit ==== + +# Testing without using autocommit instead. It should still write a +# BEGIN event, so the behaviour should be the same + +--echo **** On Slave **** +connection slave; +STOP SLAVE; +source include/wait_for_slave_to_stop.inc; + +--echo **** On Master **** +connection master; +SET AUTOCOMMIT=0; + +INSERT INTO t1 VALUES (1, 'master'); +INSERT INTO t1 VALUES (2, 'master'); +INSERT INTO t1 VALUES (3, 'master'); +COMMIT; + +INSERT INTO t1 VALUES (4, 'master,slave'); +INSERT INTO t1 VALUES (5, 'master,slave'); +INSERT INTO t1 VALUES (6, 'master,slave'); +COMMIT; + +save_master_pos; + +SELECT * FROM t1 ORDER BY a; + +# This will skip a begin event and the first INSERT of the +# transaction, and it should keep skipping until it has reached the +# transaction terminator. + +--echo **** On Slave **** +connection slave; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; +START SLAVE; +source include/wait_for_slave_to_start.inc; +sync_with_master; +SELECT * FROM t1 ORDER BY a; + +# Testing with a non-transactional table in the transaction. This will +# log a ROLLBACK as a transaction terminator, which is a normal Query +# log event. + +--echo ==== Rollback of transaction with non-transactional change ==== + +--echo **** On Master **** +connection master; +DELETE FROM t1; +SET AUTOCOMMIT=1; + +--echo **** On Slave **** +sync_slave_with_master; +STOP SLAVE; +source include/wait_for_slave_to_stop.inc; + +--echo **** On Master **** +connection master; +disable_warnings; +BEGIN; +INSERT INTO t1 VALUES (1, ''); +INSERT INTO t2 VALUES (2, 'master'); +INSERT INTO t1 VALUES (3, ''); +ROLLBACK; + +BEGIN; +INSERT INTO t1 VALUES (4, ''); +INSERT INTO t2 VALUES (5, 'master,slave'); +INSERT INTO t1 VALUES (6, ''); +ROLLBACK; +enable_warnings; + +save_master_pos; + +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; + +--echo **** On Slave **** +connection slave; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; +START SLAVE; +source include/wait_for_slave_to_start.inc; +sync_with_master; + +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; + +--echo ==== Cleanup ==== + +--echo **** On Master **** +connection master; +DROP TABLE t1, t2; +sync_slave_with_master; diff --git a/sql/slave.cc b/sql/slave.cc index c1b0d655bea..1375b7279c2 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -3279,7 +3279,43 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli) now the relay log starts with its Format_desc, has a Rotate etc). */ - DBUG_PRINT("info",("type_code=%d, server_id=%d",type_code,ev->server_id)); + DBUG_PRINT("info",("type_code: %d; server_id: %d; slave_skip_counter: %d", + type_code, ev->server_id, rli->slave_skip_counter)); + + /* + If the slave skip counter is positive, we still need to set the + OPTION_BEGIN flag correctly and not skip the log events that + start or end a transaction. If we do this, the slave will not + notice that it is inside a transaction, and happily start + executing from inside the transaction. + + Note that the code block below is strictly 5.0. + */ +#if MYSQL_VERSION_ID < 50100 + if (unlikely(rli->slave_skip_counter > 0)) + { + switch (type_code) + { + case QUERY_EVENT: + { + Query_log_event* const qev= (Query_log_event*) ev; + DBUG_PRINT("info", ("QUERY_EVENT { query: '%s', q_len: %u }", + qev->query, qev->q_len)); + if (memcmp("BEGIN", qev->query, qev->q_len+1) == 0) + thd->options|= OPTION_BEGIN; + else if (memcmp("COMMIT", qev->query, qev->q_len+1) == 0 || + memcmp("ROLLBACK", qev->query, qev->q_len+1) == 0) + thd->options&= ~OPTION_BEGIN; + } + break; + + case XID_EVENT: + DBUG_PRINT("info", ("XID_EVENT")); + thd->options&= ~OPTION_BEGIN; + break; + } + } +#endif if ((ev->server_id == (uint32) ::server_id && !replicate_same_server_id && @@ -3301,6 +3337,9 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli) flush_relay_log_info(rli); } + DBUG_PRINT("info", ("thd->options: %s", + (thd->options & OPTION_BEGIN) ? "OPTION_BEGIN" : "")) + /* Protect against common user error of setting the counter to 1 instead of 2 while recovering from an insert which used auto_increment, @@ -3311,6 +3350,15 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli) type_code == RAND_EVENT || type_code == USER_VAR_EVENT) && rli->slave_skip_counter == 1) && +#if MYSQL_VERSION_ID < 50100 + /* + Decrease the slave skip counter only if we are not inside + a transaction or the slave skip counter is more than + 1. The slave skip counter will be decreased from 1 to 0 + when reaching the final ROLLBACK, COMMIT, or XID_EVENT. + */ + (!(thd->options & OPTION_BEGIN) || rli->slave_skip_counter > 1) && +#endif /* The events from ourselves which have something to do with the relay log itself must be skipped, true, but they mustn't decrement @@ -3321,8 +3369,10 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli) would not be skipped. */ !(ev->server_id == (uint32) ::server_id && - (type_code == ROTATE_EVENT || type_code == STOP_EVENT || - type_code == START_EVENT_V3 || type_code == FORMAT_DESCRIPTION_EVENT))) + (type_code == ROTATE_EVENT || + type_code == STOP_EVENT || + type_code == START_EVENT_V3 || + type_code == FORMAT_DESCRIPTION_EVENT))) --rli->slave_skip_counter; pthread_mutex_unlock(&rli->data_lock); delete ev; From 6fbac59c5c2d88d2b9ad1a2747a42a1631b80a90 Mon Sep 17 00:00:00 2001 From: "gshchepa/uchum@gleb.loc" <> Date: Sat, 27 Oct 2007 01:40:48 +0500 Subject: [PATCH 091/336] Many files: Error message numbers. --- mysql-test/r/binlog_unsafe.result | 4 +-- mysql-test/r/events_bugs.result | 16 +++++----- mysql-test/r/events_trans.result | 2 +- mysql-test/r/sp_gis.result | 4 +-- mysql-test/r/xml.result | 18 +++++------ mysql-test/suite/ndb/r/ndb_dd_basic.result | 6 ++-- mysql-test/suite/ndb/r/ndb_dd_ddl.result | 2 +- mysql-test/suite/ndb/r/ndb_gis.result | 4 +-- mysql-test/suite/ndb/r/ndb_row_format.result | 2 +- mysql-test/suite/ndb/r/ndb_single_user.result | 10 +++--- mysql-test/suite/rpl/r/rpl_incident.result | 4 +-- .../suite/rpl/r/rpl_loaddata_fatal.result | 4 +-- mysql-test/suite/rpl/r/rpl_udf.result | 8 ++--- .../suite/rpl_ndb/r/rpl_ndb_extraCol.result | 32 +++++++++---------- 14 files changed, 58 insertions(+), 58 deletions(-) diff --git a/mysql-test/r/binlog_unsafe.result b/mysql-test/r/binlog_unsafe.result index 281bb475944..47284ed8bc3 100644 --- a/mysql-test/r/binlog_unsafe.result +++ b/mysql-test/r/binlog_unsafe.result @@ -5,9 +5,9 @@ CREATE TABLE t3 (b INT AUTO_INCREMENT PRIMARY KEY); CREATE VIEW v1(a,b) AS SELECT a,b FROM t2,t3; INSERT INTO t1 SELECT UUID(); Warnings: -Warning 1591 Statement is not safe to log in statement format. +Warning 1592 Statement is not safe to log in statement format. SHOW WARNINGS; Level Warning -Code 1591 +Code 1592 Message Statement is not safe to log in statement format. DROP TABLE t1,t2,t3; diff --git a/mysql-test/r/events_bugs.result b/mysql-test/r/events_bugs.result index 3c9e6384c64..1cbc37cb5b5 100644 --- a/mysql-test/r/events_bugs.result +++ b/mysql-test/r/events_bugs.result @@ -31,7 +31,7 @@ create event e_55 on schedule at 10000101000000 do drop table t; ERROR HY000: Incorrect AT value: '10000101000000' create event e_55 on schedule at 20000101000000 do drop table t; Warnings: -Note 1587 Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. The event was dropped immediately after creation. +Note 1588 Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. The event was dropped immediately after creation. show events; Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status Originator character_set_client collation_connection Database Collation create event e_55 on schedule at 20200101000000 starts 10000101000000 do drop table t; @@ -457,22 +457,22 @@ CREATE EVENT e4 ON SCHEDULE EVERY 1 HOUR STARTS '1999-01-01 00:00:00' DO SELECT 1; Warnings: -Note 1587 Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. The event was dropped immediately after creation. +Note 1588 Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. The event was dropped immediately after creation. CREATE EVENT e4 ON SCHEDULE EVERY 1 HOUR STARTS '1999-01-01 00:00:00' ENDS '1999-01-02 00:00:00' DISABLE DO SELECT 1; Warnings: -Note 1587 Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. The event was dropped immediately after creation. +Note 1588 Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. The event was dropped immediately after creation. CREATE EVENT e4 ON SCHEDULE AT '1999-01-01 00:00:00' DO SELECT 1; Warnings: -Note 1587 Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. The event was dropped immediately after creation. +Note 1588 Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. The event was dropped immediately after creation. CREATE EVENT e4 ON SCHEDULE AT '1999-01-01 00:00:00' DISABLE DO SELECT 1; Warnings: -Note 1587 Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. The event was dropped immediately after creation. +Note 1588 Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. The event was dropped immediately after creation. SHOW EVENTS; Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status Originator character_set_client collation_connection Database Collation events_test e1 root@localhost +05:00 RECURRING NULL 1 DAY 2006-01-01 00:00:00 NULL ENABLED 1 latin1 latin1_swedish_ci latin1_swedish_ci @@ -482,19 +482,19 @@ The following should succeed giving a warning. ALTER EVENT e1 ON SCHEDULE EVERY 1 HOUR STARTS '1999-01-01 00:00:00' ENDS '1999-01-02 00:00:00' ON COMPLETION PRESERVE; Warnings: -Note 1543 Event execution time is in the past. Event has been disabled +Note 1544 Event execution time is in the past. Event has been disabled CREATE EVENT e4 ON SCHEDULE EVERY 1 HOUR STARTS '1999-01-01 00:00:00' ENDS '1999-01-02 00:00:00' ON COMPLETION PRESERVE DO SELECT 1; Warnings: -Note 1543 Event execution time is in the past. Event has been disabled +Note 1544 Event execution time is in the past. Event has been disabled CREATE EVENT e5 ON SCHEDULE AT '1999-01-01 00:00:00' ON COMPLETION PRESERVE DO SELECT 1; Warnings: -Note 1543 Event execution time is in the past. Event has been disabled +Note 1544 Event execution time is in the past. Event has been disabled The following should succeed without warnings. ALTER EVENT e2 ON SCHEDULE EVERY 1 HOUR STARTS '1999-01-01 00:00:00'; ALTER EVENT e3 ON SCHEDULE EVERY 1 HOUR STARTS '1999-01-01 00:00:00' diff --git a/mysql-test/r/events_trans.result b/mysql-test/r/events_trans.result index 984e22a2c1a..16ec64b4c50 100644 --- a/mysql-test/r/events_trans.result +++ b/mysql-test/r/events_trans.result @@ -63,7 +63,7 @@ begin work; insert into t1 (a) values ("OK: create event if not exists"); create event if not exists e1 on schedule every 2 day do select 2; Warnings: -Note 1536 Event 'e1' already exists +Note 1537 Event 'e1' already exists rollback work; select * from t1; a diff --git a/mysql-test/r/sp_gis.result b/mysql-test/r/sp_gis.result index b0960dec647..7a76507754f 100644 --- a/mysql-test/r/sp_gis.result +++ b/mysql-test/r/sp_gis.result @@ -7,11 +7,11 @@ return 1; create function x() returns int return 2; Warnings: -Note 1584 This function 'x' has the same name as a native function +Note 1585 This function 'x' has the same name as a native function create function y() returns int return 3; Warnings: -Note 1584 This function 'y' has the same name as a native function +Note 1585 This function 'y' has the same name as a native function select a(); a() 1 diff --git a/mysql-test/r/xml.result b/mysql-test/r/xml.result index 552f4896698..d98173dbe15 100644 --- a/mysql-test/r/xml.result +++ b/mysql-test/r/xml.result @@ -647,32 +647,32 @@ select extractValue('a','/a'); extractValue('a','/a') NULL Warnings: -Warning 1524 Incorrect XML value: 'parse error at line 1 pos 5: unexpected END-OF-INPUT' +Warning 1525 Incorrect XML value: 'parse error at line 1 pos 5: unexpected END-OF-INPUT' select extractValue('a<','/a'); extractValue('a<','/a') NULL Warnings: -Warning 1524 Incorrect XML value: 'parse error at line 1 pos 6: END-OF-INPUT unexpected (ident or '/' wanted)' +Warning 1525 Incorrect XML value: 'parse error at line 1 pos 6: END-OF-INPUT unexpected (ident or '/' wanted)' select extractValue('aaaa' wanted)' +Warning 1525 Incorrect XML value: 'parse error at line 1 pos 8: END-OF-INPUT unexpected ('>' wanted)' select extractValue('a','/a'); extractValue('a','/a') NULL Warnings: -Warning 1524 Incorrect XML value: 'parse error at line 1 pos 12: '' unexpected (END-OF-INPUT wanted)' +Warning 1525 Incorrect XML value: 'parse error at line 1 pos 12: '' unexpected (END-OF-INPUT wanted)' select extractValue('a','/a'); extractValue('a','/a') NULL Warnings: -Warning 1524 Incorrect XML value: 'parse error at line 1 pos 7: '>' unexpected (ident or string wanted)' +Warning 1525 Incorrect XML value: 'parse error at line 1 pos 7: '>' unexpected (ident or string wanted)' select extractValue('1','position()'); ERROR HY000: XPATH syntax error: '' select extractValue('1','last()'); @@ -723,17 +723,17 @@ select extractValue('<01>10:39:15<02>140','//* extractValue('<01>10:39:15<02>140','//*') NULL Warnings: -Warning 1524 Incorrect XML value: 'parse error at line 1 pos 13: unknown token unexpected (ident or '/' wanted)' +Warning 1525 Incorrect XML value: 'parse error at line 1 pos 13: unknown token unexpected (ident or '/' wanted)' select extractValue('<.>test','//*'); extractValue('<.>test','//*') NULL Warnings: -Warning 1524 Incorrect XML value: 'parse error at line 1 pos 2: unknown token unexpected (ident or '/' wanted)' +Warning 1525 Incorrect XML value: 'parse error at line 1 pos 2: unknown token unexpected (ident or '/' wanted)' select extractValue('<->test','//*'); extractValue('<->test','//*') NULL Warnings: -Warning 1524 Incorrect XML value: 'parse error at line 1 pos 2: unknown token unexpected (ident or '/' wanted)' +Warning 1525 Incorrect XML value: 'parse error at line 1 pos 2: unknown token unexpected (ident or '/' wanted)' select extractValue('<:>test','//*'); extractValue('<:>test','//*') test diff --git a/mysql-test/suite/ndb/r/ndb_dd_basic.result b/mysql-test/suite/ndb/r/ndb_dd_basic.result index 0ff28f889b7..f04905b8d13 100644 --- a/mysql-test/suite/ndb/r/ndb_dd_basic.result +++ b/mysql-test/suite/ndb/r/ndb_dd_basic.result @@ -8,20 +8,20 @@ INITIAL_SIZE 16M UNDO_BUFFER_SIZE = 1M ENGINE=MYISAM; Warnings: -Error 1477 Table storage engine 'MyISAM' does not support the create option 'TABLESPACE or LOGFILE GROUP' +Error 1478 Table storage engine 'MyISAM' does not support the create option 'TABLESPACE or LOGFILE GROUP' ALTER LOGFILE GROUP lg1 ADD UNDOFILE 'undofile02.dat' INITIAL_SIZE = 4M ENGINE=XYZ; Warnings: Warning 1286 Unknown table engine 'XYZ' -Error 1477 Table storage engine 'MyISAM' does not support the create option 'TABLESPACE or LOGFILE GROUP' +Error 1478 Table storage engine 'MyISAM' does not support the create option 'TABLESPACE or LOGFILE GROUP' CREATE TABLESPACE ts1 ADD DATAFILE 'datafile.dat' USE LOGFILE GROUP lg1 INITIAL_SIZE 12M; Warnings: -Error 1477 Table storage engine 'MyISAM' does not support the create option 'TABLESPACE or LOGFILE GROUP' +Error 1478 Table storage engine 'MyISAM' does not support the create option 'TABLESPACE or LOGFILE GROUP' set storage_engine=ndb; CREATE LOGFILE GROUP lg1 ADD UNDOFILE 'undofile.dat' diff --git a/mysql-test/suite/ndb/r/ndb_dd_ddl.result b/mysql-test/suite/ndb/r/ndb_dd_ddl.result index 569769cfaef..d8d9e8631d5 100644 --- a/mysql-test/suite/ndb/r/ndb_dd_ddl.result +++ b/mysql-test/suite/ndb/r/ndb_dd_ddl.result @@ -16,7 +16,7 @@ ERROR HY000: Failed to create LOGFILE GROUP SHOW WARNINGS; Level Code Message Error 1296 Got error 1514 'Currently there is a limit of one logfile group' from NDB -Error 1527 Failed to create LOGFILE GROUP +Error 1528 Failed to create LOGFILE GROUP CREATE LOGFILE GROUP lg1 ADD UNDOFILE 'undofile.dat' INITIAL_SIZE 1M diff --git a/mysql-test/suite/ndb/r/ndb_gis.result b/mysql-test/suite/ndb/r/ndb_gis.result index b401dee8054..6c44c6fb822 100644 --- a/mysql-test/suite/ndb/r/ndb_gis.result +++ b/mysql-test/suite/ndb/r/ndb_gis.result @@ -463,7 +463,7 @@ drop table t1; End of 4.1 tests CREATE TABLE t1 (name VARCHAR(100), square GEOMETRY); Warnings: -Error 1477 Table storage engine 'ndbcluster' does not support the create option 'Binlog of table with BLOB attribute and no PK' +Error 1478 Table storage engine 'ndbcluster' does not support the create option 'Binlog of table with BLOB attribute and no PK' INSERT INTO t1 VALUES("center", GeomFromText('POLYGON (( 0 0, 0 2, 2 2, 2 0, 0 0))')); INSERT INTO t1 VALUES("small", GeomFromText('POLYGON (( 0 0, 0 1, 1 1, 1 0, 0 0))')); INSERT INTO t1 VALUES("big", GeomFromText('POLYGON (( 0 0, 0 3, 3 3, 3 0, 0 0))')); @@ -1013,7 +1013,7 @@ drop table t1; End of 4.1 tests CREATE TABLE t1 (name VARCHAR(100), square GEOMETRY); Warnings: -Error 1477 Table storage engine 'ndbcluster' does not support the create option 'Binlog of table with BLOB attribute and no PK' +Error 1478 Table storage engine 'ndbcluster' does not support the create option 'Binlog of table with BLOB attribute and no PK' INSERT INTO t1 VALUES("center", GeomFromText('POLYGON (( 0 0, 0 2, 2 2, 2 0, 0 0))')); INSERT INTO t1 VALUES("small", GeomFromText('POLYGON (( 0 0, 0 1, 1 1, 1 0, 0 0))')); INSERT INTO t1 VALUES("big", GeomFromText('POLYGON (( 0 0, 0 3, 3 3, 3 0, 0 0))')); diff --git a/mysql-test/suite/ndb/r/ndb_row_format.result b/mysql-test/suite/ndb/r/ndb_row_format.result index ea495e7e9c5..eea0692dd92 100644 --- a/mysql-test/suite/ndb/r/ndb_row_format.result +++ b/mysql-test/suite/ndb/r/ndb_row_format.result @@ -8,7 +8,7 @@ ENGINE=NDB; ERROR HY000: Can't create table 'test.t1' (errno: 138) SHOW WARNINGS; Level Code Message -Error 1477 Table storage engine 'ndbcluster' does not support the create option 'Row format FIXED incompatible with variable sized attribute' +Error 1478 Table storage engine 'ndbcluster' does not support the create option 'Row format FIXED incompatible with variable sized attribute' Error 1005 Can't create table 'test.t1' (errno: 138) CREATE TABLE t1 ( a INT KEY, diff --git a/mysql-test/suite/ndb/r/ndb_single_user.result b/mysql-test/suite/ndb/r/ndb_single_user.result index 552629ae532..0a4f7cd0b5f 100644 --- a/mysql-test/suite/ndb/r/ndb_single_user.result +++ b/mysql-test/suite/ndb/r/ndb_single_user.result @@ -11,7 +11,7 @@ ERROR HY000: Failed to create LOGFILE GROUP show warnings; Level Code Message Error 1296 Got error 299 'Operation not allowed or aborted due to single user mode' from NDB -Error 1527 Failed to create LOGFILE GROUP +Error 1528 Failed to create LOGFILE GROUP create table t1 (a int key, b int unique, c int) engine ndb; CREATE LOGFILE GROUP lg1 ADD UNDOFILE 'undofile.dat' @@ -27,14 +27,14 @@ ERROR HY000: Failed to create TABLESPACE show warnings; Level Code Message Error 1296 Got error 299 'Operation not allowed or aborted due to single user mode' from NDB -Error 1527 Failed to create TABLESPACE +Error 1528 Failed to create TABLESPACE DROP LOGFILE GROUP lg1 ENGINE =NDB; ERROR HY000: Failed to drop LOGFILE GROUP show warnings; Level Code Message Error 1296 Got error 299 'Operation not allowed or aborted due to single user mode' from NDB -Error 1528 Failed to drop LOGFILE GROUP +Error 1529 Failed to drop LOGFILE GROUP CREATE TABLESPACE ts1 ADD DATAFILE 'datafile.dat' USE LOGFILE GROUP lg1 @@ -47,7 +47,7 @@ ERROR HY000: Failed to alter: DROP DATAFILE show warnings; Level Code Message Error 1296 Got error 299 'Operation not allowed or aborted due to single user mode' from NDB -Error 1532 Failed to alter: DROP DATAFILE +Error 1533 Failed to alter: DROP DATAFILE ALTER TABLESPACE ts1 DROP DATAFILE 'datafile.dat' ENGINE NDB; @@ -57,7 +57,7 @@ ERROR HY000: Failed to drop TABLESPACE show warnings; Level Code Message Error 1296 Got error 299 'Operation not allowed or aborted due to single user mode' from NDB -Error 1528 Failed to drop TABLESPACE +Error 1529 Failed to drop TABLESPACE DROP TABLESPACE ts1 ENGINE NDB; DROP LOGFILE GROUP lg1 diff --git a/mysql-test/suite/rpl/r/rpl_incident.result b/mysql-test/suite/rpl/r/rpl_incident.result index 568078cc276..c3baabbdbc3 100644 --- a/mysql-test/suite/rpl/r/rpl_incident.result +++ b/mysql-test/suite/rpl/r/rpl_incident.result @@ -44,7 +44,7 @@ Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1589 +Last_Errno 1590 Last_Error The incident LOST_EVENTS occured on the master. Message: Skip_Counter 0 Exec_Master_Log_Pos # @@ -62,7 +62,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno 0 Last_IO_Error -Last_SQL_Errno 1589 +Last_SQL_Errno 1590 Last_SQL_Error The incident LOST_EVENTS occured on the master. Message: SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; START SLAVE; diff --git a/mysql-test/suite/rpl/r/rpl_loaddata_fatal.result b/mysql-test/suite/rpl/r/rpl_loaddata_fatal.result index d30110f85e9..a4d67754bd6 100644 --- a/mysql-test/suite/rpl/r/rpl_loaddata_fatal.result +++ b/mysql-test/suite/rpl/r/rpl_loaddata_fatal.result @@ -65,7 +65,7 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1592 +Last_Errno 1593 Last_Error Fatal error: Not enough memory Skip_Counter 0 Exec_Master_Log_Pos 325 @@ -83,7 +83,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1592 +Last_SQL_Errno 1593 Last_SQL_Error Fatal error: Not enough memory SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; START SLAVE; diff --git a/mysql-test/suite/rpl/r/rpl_udf.result b/mysql-test/suite/rpl/r/rpl_udf.result index fcd2f4743ba..79a82b5fbc7 100644 --- a/mysql-test/suite/rpl/r/rpl_udf.result +++ b/mysql-test/suite/rpl/r/rpl_udf.result @@ -182,19 +182,19 @@ CREATE TABLE t1(sum INT, price FLOAT(24)) ENGINE=MyISAM; affected rows: 0 INSERT INTO t1 VALUES(myfunc_int(100), myfunc_double(50.00)); Warnings: -Warning 1591 Statement is not safe to log in statement format. +Warning 1592 Statement is not safe to log in statement format. affected rows: 1 INSERT INTO t1 VALUES(myfunc_int(10), myfunc_double(5.00)); Warnings: -Warning 1591 Statement is not safe to log in statement format. +Warning 1592 Statement is not safe to log in statement format. affected rows: 1 INSERT INTO t1 VALUES(myfunc_int(200), myfunc_double(25.00)); Warnings: -Warning 1591 Statement is not safe to log in statement format. +Warning 1592 Statement is not safe to log in statement format. affected rows: 1 INSERT INTO t1 VALUES(myfunc_int(1), myfunc_double(500.00)); Warnings: -Warning 1591 Statement is not safe to log in statement format. +Warning 1592 Statement is not safe to log in statement format. affected rows: 1 SELECT * FROM t1 ORDER BY sum; sum price diff --git a/mysql-test/suite/rpl_ndb/r/rpl_ndb_extraCol.result b/mysql-test/suite/rpl_ndb/r/rpl_ndb_extraCol.result index 41e888827b1..54056ac613b 100644 --- a/mysql-test/suite/rpl_ndb/r/rpl_ndb_extraCol.result +++ b/mysql-test/suite/rpl_ndb/r/rpl_ndb_extraCol.result @@ -72,7 +72,7 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 2 size mismatch - master has size 10, test.t2 on slave has size 6. Master's column size should be <= the slave's column size. Skip_Counter 0 Exec_Master_Log_Pos # @@ -90,7 +90,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 2 size mismatch - master has size 10, test.t2 on slave has size 6. Master's column size should be <= the slave's column size. STOP SLAVE; RESET SLAVE; @@ -139,7 +139,7 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 252, test.t3 has type 3 Skip_Counter 0 Exec_Master_Log_Pos # @@ -157,7 +157,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 252, test.t3 has type 3 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; @@ -201,7 +201,7 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 246, test.t4 has type 3 Skip_Counter 0 Exec_Master_Log_Pos # @@ -219,7 +219,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 246, test.t4 has type 3 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; @@ -263,7 +263,7 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 5 type mismatch - received type 4, test.t5 has type 246 Skip_Counter 0 Exec_Master_Log_Pos # @@ -281,7 +281,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 5 type mismatch - received type 4, test.t5 has type 246 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; @@ -324,7 +324,7 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 3 type mismatch - received type 16, test.t6 has type 3 Skip_Counter 0 Exec_Master_Log_Pos # @@ -342,7 +342,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 3 type mismatch - received type 16, test.t6 has type 3 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=3; *** Drop t6 *** @@ -436,7 +436,7 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 254, test.t10 has type 5 Skip_Counter 0 Exec_Master_Log_Pos # @@ -454,7 +454,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 254, test.t10 has type 5 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; @@ -497,7 +497,7 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 15, test.t11 has type 252 Skip_Counter 0 Exec_Master_Log_Pos # @@ -515,7 +515,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 15, test.t11 has type 252 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; @@ -823,7 +823,7 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 8, test.t17 has type 2 Skip_Counter 0 Exec_Master_Log_Pos # @@ -841,7 +841,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 8, test.t17 has type 2 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; From 3cc449465c8caf3dd91d9d2b7db8832f984e45cc Mon Sep 17 00:00:00 2001 From: "gshchepa/uchum@gleb.loc" <> Date: Sun, 28 Oct 2007 02:33:18 +0500 Subject: [PATCH 092/336] ha_archive.cc: Post-merge fix. --- storage/archive/ha_archive.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/archive/ha_archive.cc b/storage/archive/ha_archive.cc index 3015ae78761..84298e785d1 100644 --- a/storage/archive/ha_archive.cc +++ b/storage/archive/ha_archive.cc @@ -1241,7 +1241,7 @@ int ha_archive::rnd_pos(uchar * buf, uchar *pos) DBUG_ENTER("ha_archive::rnd_pos"); ha_statistic_increment(&SSV::ha_read_rnd_next_count); current_position= (my_off_t)my_get_ptr(pos, ref_length); - if (azseek(&archive, current_position, SEEK_SET) < 0) + if (azseek(&archive, current_position, SEEK_SET) == (my_off_t)(-1L)) DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE); DBUG_RETURN(get_row(&archive, buf)); } From 5ebb07a8c09384b772cc341df6d0c78e8957de64 Mon Sep 17 00:00:00 2001 From: "gshchepa/uchum@gleb.loc" <> Date: Sun, 28 Oct 2007 02:09:24 +0400 Subject: [PATCH 093/336] rpl_row_tabledefs_2myisam.result, sp.result, rpl_row_colSize.result: Error message numbers. --- mysql-test/r/sp.result | 8 +-- mysql-test/suite/rpl/r/rpl_row_colSize.result | 52 +++++++++---------- .../rpl/r/rpl_row_tabledefs_2myisam.result | 12 ++--- 3 files changed, 36 insertions(+), 36 deletions(-) diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 412f6b94fa2..68aa278585f 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -5670,7 +5670,7 @@ drop function if exists pi; create function pi() returns varchar(50) return "pie, my favorite desert."; Warnings: -Note 1584 This function 'pi' has the same name as a native function +Note 1585 This function 'pi' has the same name as a native function SET @save_sql_mode=@@sql_mode; SET SQL_MODE='IGNORE_SPACE'; select pi(), pi (); @@ -5719,15 +5719,15 @@ use test; create function `database`() returns varchar(50) return "Stored function database"; Warnings: -Note 1584 This function 'database' has the same name as a native function +Note 1585 This function 'database' has the same name as a native function create function `current_user`() returns varchar(50) return "Stored function current_user"; Warnings: -Note 1584 This function 'current_user' has the same name as a native function +Note 1585 This function 'current_user' has the same name as a native function create function md5(x varchar(50)) returns varchar(50) return "Stored function md5"; Warnings: -Note 1584 This function 'md5' has the same name as a native function +Note 1585 This function 'md5' has the same name as a native function SET SQL_MODE='IGNORE_SPACE'; select database(), database (); database() database () diff --git a/mysql-test/suite/rpl/r/rpl_row_colSize.result b/mysql-test/suite/rpl/r/rpl_row_colSize.result index 9358e36cac6..6d002a722f1 100644 --- a/mysql-test/suite/rpl/r/rpl_row_colSize.result +++ b/mysql-test/suite/rpl/r/rpl_row_colSize.result @@ -37,7 +37,7 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 10, test.t1 on slave has size 3. Master's column size should be <= the slave's column size. Skip_Counter 0 Exec_Master_Log_Pos # @@ -55,7 +55,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 10, test.t1 on slave has size 3. Master's column size should be <= the slave's column size. SELECT COUNT(*) FROM t1; COUNT(*) @@ -91,7 +91,7 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 12, test.t1 on slave has size 12. Master's column size should be <= the slave's column size. Skip_Counter 0 Exec_Master_Log_Pos # @@ -109,7 +109,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 12, test.t1 on slave has size 12. Master's column size should be <= the slave's column size. SELECT COUNT(*) FROM t1; COUNT(*) @@ -145,7 +145,7 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 10, test.t1 on slave has size 3. Master's column size should be <= the slave's column size. Skip_Counter 0 Exec_Master_Log_Pos # @@ -163,7 +163,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 10, test.t1 on slave has size 3. Master's column size should be <= the slave's column size. SELECT COUNT(*) FROM t1; COUNT(*) @@ -200,7 +200,7 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 5, test.t1 has type 4 Skip_Counter 0 Exec_Master_Log_Pos # @@ -218,7 +218,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 5, test.t1 has type 4 SELECT COUNT(*) FROM t1; COUNT(*) @@ -255,7 +255,7 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 8, test.t1 on slave has size 1. Master's column size should be <= the slave's column size. Skip_Counter 0 Exec_Master_Log_Pos # @@ -273,7 +273,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 8, test.t1 on slave has size 1. Master's column size should be <= the slave's column size. SELECT COUNT(*) FROM t1; COUNT(*) @@ -309,7 +309,7 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 2, test.t1 on slave has size 2. Master's column size should be <= the slave's column size. Skip_Counter 0 Exec_Master_Log_Pos # @@ -327,7 +327,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 2, test.t1 on slave has size 2. Master's column size should be <= the slave's column size. SELECT COUNT(*) FROM t1; COUNT(*) @@ -364,7 +364,7 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 2, test.t1 on slave has size 1. Master's column size should be <= the slave's column size. Skip_Counter 0 Exec_Master_Log_Pos # @@ -382,7 +382,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 2, test.t1 on slave has size 1. Master's column size should be <= the slave's column size. SELECT COUNT(*) FROM t1; COUNT(*) @@ -419,7 +419,7 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 20, test.t1 on slave has size 11. Master's column size should be <= the slave's column size. Skip_Counter 0 Exec_Master_Log_Pos # @@ -437,7 +437,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 20, test.t1 on slave has size 11. Master's column size should be <= the slave's column size. SELECT COUNT(*) FROM t1; COUNT(*) @@ -505,7 +505,7 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 2, test.t1 on slave has size 1. Master's column size should be <= the slave's column size. Skip_Counter 0 Exec_Master_Log_Pos # @@ -523,7 +523,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 2, test.t1 on slave has size 1. Master's column size should be <= the slave's column size. SELECT COUNT(*) FROM t1; COUNT(*) @@ -560,7 +560,7 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 2000, test.t1 on slave has size 100. Master's column size should be <= the slave's column size. Skip_Counter 0 Exec_Master_Log_Pos # @@ -578,7 +578,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 2000, test.t1 on slave has size 100. Master's column size should be <= the slave's column size. SELECT COUNT(*) FROM t1; COUNT(*) @@ -614,7 +614,7 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 200, test.t1 on slave has size 10. Master's column size should be <= the slave's column size. Skip_Counter 0 Exec_Master_Log_Pos # @@ -632,7 +632,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 200, test.t1 on slave has size 10. Master's column size should be <= the slave's column size. SELECT COUNT(*) FROM t1; COUNT(*) @@ -668,7 +668,7 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 2000, test.t1 on slave has size 1000. Master's column size should be <= the slave's column size. Skip_Counter 0 Exec_Master_Log_Pos # @@ -686,7 +686,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 2000, test.t1 on slave has size 1000. Master's column size should be <= the slave's column size. SELECT COUNT(*) FROM t1; COUNT(*) @@ -723,7 +723,7 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 4, test.t1 on slave has size 1. Master's column size should be <= the slave's column size. Skip_Counter 0 Exec_Master_Log_Pos # @@ -741,7 +741,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 4, test.t1 on slave has size 1. Master's column size should be <= the slave's column size. SELECT COUNT(*) FROM t1; COUNT(*) diff --git a/mysql-test/suite/rpl/r/rpl_row_tabledefs_2myisam.result b/mysql-test/suite/rpl/r/rpl_row_tabledefs_2myisam.result index 566537ab745..06dc90f18aa 100644 --- a/mysql-test/suite/rpl/r/rpl_row_tabledefs_2myisam.result +++ b/mysql-test/suite/rpl/r/rpl_row_tabledefs_2myisam.result @@ -214,7 +214,7 @@ Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 3, test.t4 has type 4 Skip_Counter 0 Exec_Master_Log_Pos # @@ -232,7 +232,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno 0 Last_IO_Error -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 3, test.t4 has type 4 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; @@ -257,7 +257,7 @@ Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 1 type mismatch - received type 3, test.t5 has type 4 Skip_Counter 0 Exec_Master_Log_Pos # @@ -275,7 +275,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno 0 Last_IO_Error -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 1 type mismatch - received type 3, test.t5 has type 4 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; @@ -300,7 +300,7 @@ Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 3, test.t6 has type 4 Skip_Counter 0 Exec_Master_Log_Pos # @@ -318,7 +318,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno 0 Last_IO_Error -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 3, test.t6 has type 4 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; From bf2bb354302fbabc2661c9d9efa14de5e51d0530 Mon Sep 17 00:00:00 2001 From: "gshchepa/uchum@gleb.loc" <> Date: Sun, 28 Oct 2007 11:30:36 +0400 Subject: [PATCH 094/336] Many files: Error message numbers. --- .../suite/rpl/r/rpl_extraCol_innodb.result | 32 +++++++++---------- .../suite/rpl/r/rpl_extraCol_myisam.result | 32 +++++++++---------- .../rpl/r/rpl_row_tabledefs_3innodb.result | 12 +++---- 3 files changed, 38 insertions(+), 38 deletions(-) diff --git a/mysql-test/suite/rpl/r/rpl_extraCol_innodb.result b/mysql-test/suite/rpl/r/rpl_extraCol_innodb.result index fe5a5b28682..007cd5a252c 100644 --- a/mysql-test/suite/rpl/r/rpl_extraCol_innodb.result +++ b/mysql-test/suite/rpl/r/rpl_extraCol_innodb.result @@ -72,7 +72,7 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 2 size mismatch - master has size 10, test.t2 on slave has size 6. Master's column size should be <= the slave's column size. Skip_Counter 0 Exec_Master_Log_Pos # @@ -90,7 +90,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 2 size mismatch - master has size 10, test.t2 on slave has size 6. Master's column size should be <= the slave's column size. STOP SLAVE; RESET SLAVE; @@ -139,7 +139,7 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 252, test.t3 has type 3 Skip_Counter 0 Exec_Master_Log_Pos # @@ -157,7 +157,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 252, test.t3 has type 3 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; @@ -201,7 +201,7 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 246, test.t4 has type 3 Skip_Counter 0 Exec_Master_Log_Pos # @@ -219,7 +219,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 246, test.t4 has type 3 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; @@ -263,7 +263,7 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 5 type mismatch - received type 4, test.t5 has type 246 Skip_Counter 0 Exec_Master_Log_Pos # @@ -281,7 +281,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 5 type mismatch - received type 4, test.t5 has type 246 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; @@ -324,7 +324,7 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 3 type mismatch - received type 16, test.t6 has type 3 Skip_Counter 0 Exec_Master_Log_Pos # @@ -342,7 +342,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 3 type mismatch - received type 16, test.t6 has type 3 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=3; *** Drop t6 *** @@ -436,7 +436,7 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 254, test.t10 has type 5 Skip_Counter 0 Exec_Master_Log_Pos # @@ -454,7 +454,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 254, test.t10 has type 5 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; @@ -497,7 +497,7 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 15, test.t11 has type 252 Skip_Counter 0 Exec_Master_Log_Pos # @@ -515,7 +515,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 15, test.t11 has type 252 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; @@ -822,7 +822,7 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 8, test.t17 has type 2 Skip_Counter 0 Exec_Master_Log_Pos # @@ -840,7 +840,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 8, test.t17 has type 2 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; diff --git a/mysql-test/suite/rpl/r/rpl_extraCol_myisam.result b/mysql-test/suite/rpl/r/rpl_extraCol_myisam.result index e70a2efaf29..873fc5cddbc 100644 --- a/mysql-test/suite/rpl/r/rpl_extraCol_myisam.result +++ b/mysql-test/suite/rpl/r/rpl_extraCol_myisam.result @@ -72,7 +72,7 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 2 size mismatch - master has size 10, test.t2 on slave has size 6. Master's column size should be <= the slave's column size. Skip_Counter 0 Exec_Master_Log_Pos # @@ -90,7 +90,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 2 size mismatch - master has size 10, test.t2 on slave has size 6. Master's column size should be <= the slave's column size. STOP SLAVE; RESET SLAVE; @@ -139,7 +139,7 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 252, test.t3 has type 3 Skip_Counter 0 Exec_Master_Log_Pos # @@ -157,7 +157,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 252, test.t3 has type 3 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; @@ -201,7 +201,7 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 246, test.t4 has type 3 Skip_Counter 0 Exec_Master_Log_Pos # @@ -219,7 +219,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 246, test.t4 has type 3 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; @@ -263,7 +263,7 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 5 type mismatch - received type 4, test.t5 has type 246 Skip_Counter 0 Exec_Master_Log_Pos # @@ -281,7 +281,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 5 type mismatch - received type 4, test.t5 has type 246 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; @@ -324,7 +324,7 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 3 type mismatch - received type 16, test.t6 has type 3 Skip_Counter 0 Exec_Master_Log_Pos # @@ -342,7 +342,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 3 type mismatch - received type 16, test.t6 has type 3 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=3; *** Drop t6 *** @@ -436,7 +436,7 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 254, test.t10 has type 5 Skip_Counter 0 Exec_Master_Log_Pos # @@ -454,7 +454,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 254, test.t10 has type 5 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; @@ -497,7 +497,7 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 15, test.t11 has type 252 Skip_Counter 0 Exec_Master_Log_Pos # @@ -515,7 +515,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 15, test.t11 has type 252 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; @@ -822,7 +822,7 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 8, test.t17 has type 2 Skip_Counter 0 Exec_Master_Log_Pos # @@ -840,7 +840,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 8, test.t17 has type 2 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; diff --git a/mysql-test/suite/rpl/r/rpl_row_tabledefs_3innodb.result b/mysql-test/suite/rpl/r/rpl_row_tabledefs_3innodb.result index 83df75b81e9..3911fe89b7f 100644 --- a/mysql-test/suite/rpl/r/rpl_row_tabledefs_3innodb.result +++ b/mysql-test/suite/rpl/r/rpl_row_tabledefs_3innodb.result @@ -214,7 +214,7 @@ Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 3, test.t4 has type 4 Skip_Counter 0 Exec_Master_Log_Pos # @@ -232,7 +232,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno 0 Last_IO_Error -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 3, test.t4 has type 4 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; @@ -257,7 +257,7 @@ Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 1 type mismatch - received type 3, test.t5 has type 4 Skip_Counter 0 Exec_Master_Log_Pos # @@ -275,7 +275,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno 0 Last_IO_Error -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 1 type mismatch - received type 3, test.t5 has type 4 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; @@ -300,7 +300,7 @@ Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 3, test.t6 has type 4 Skip_Counter 0 Exec_Master_Log_Pos # @@ -318,7 +318,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno 0 Last_IO_Error -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 3, test.t6 has type 4 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; From 98a4d99961eae8c3a224739099fc95544ff2b43d Mon Sep 17 00:00:00 2001 From: "ramil/ram@mysql.com/ramil.myoffice.izhnet.ru" <> Date: Mon, 29 Oct 2007 12:20:21 +0400 Subject: [PATCH 095/336] Fix for bug #30782: Truncated UNSIGNED BIGINT columns only in SELECT w/ CASE, JOIN, and ORDER BY Problem: improper maximum length calculation of the CASE function leads to decimal value truncation (storing/retrieving decimal field values). Fix: accurately calculate maximum length/unsigned flag/decimals parameters of the CASE function. --- mysql-test/r/case.result | 20 +++++++++++++++++++- mysql-test/t/case.test | 21 +++++++++++++++++++-- sql/item_cmpfunc.cc | 36 ++++++++++++++++++++++++++++++------ sql/item_cmpfunc.h | 2 ++ 4 files changed, 70 insertions(+), 9 deletions(-) diff --git a/mysql-test/r/case.result b/mysql-test/r/case.result index cf358e6a404..bc05edcfac1 100644 --- a/mysql-test/r/case.result +++ b/mysql-test/r/case.result @@ -1,4 +1,4 @@ -drop table if exists t1; +drop table if exists t1, t2; select CASE "b" when "a" then 1 when "b" then 2 END; CASE "b" when "a" then 1 when "b" then 2 END 2 @@ -200,3 +200,21 @@ CEMPNUM EMPMUM1 EMPNUM2 0.00 0 0.00 2.00 2 NULL DROP TABLE t1,t2; +End of 4.1 tests +create table t1 (a int, b bigint unsigned); +create table t2 (c int); +insert into t1 (a, b) values (1,4572794622775114594), (2,18196094287899841997), +(3,11120436154190595086); +insert into t2 (c) values (1), (2), (3); +select t1.a, (case t1.a when 0 then 0 else t1.b end) d from t1 +join t2 on t1.a=t2.c order by d; +a d +1 4572794622775114594 +3 11120436154190595086 +2 18196094287899841997 +select t1.a, (case t1.a when 0 then 0 else t1.b end) d from t1 +join t2 on t1.a=t2.c where b=11120436154190595086 order by d; +a d +3 11120436154190595086 +drop table t1, t2; +End of 5.0 tests diff --git a/mysql-test/t/case.test b/mysql-test/t/case.test index 0e9e141f6d8..b6654df4ecb 100644 --- a/mysql-test/t/case.test +++ b/mysql-test/t/case.test @@ -3,7 +3,7 @@ # --disable_warnings -drop table if exists t1; +drop table if exists t1, t2; --enable_warnings select CASE "b" when "a" then 1 when "b" then 2 END; @@ -152,4 +152,21 @@ SELECT IFNULL(t2.EMPNUM,t1.EMPNUM) AS CEMPNUM, FROM t1 LEFT JOIN t2 ON t1.EMPNUM=t2.EMPNUM; DROP TABLE t1,t2; -# End of 4.1 tests + +--echo End of 4.1 tests + +# +# #30782: Truncated UNSIGNED BIGINT columns +# +create table t1 (a int, b bigint unsigned); +create table t2 (c int); +insert into t1 (a, b) values (1,4572794622775114594), (2,18196094287899841997), + (3,11120436154190595086); +insert into t2 (c) values (1), (2), (3); +select t1.a, (case t1.a when 0 then 0 else t1.b end) d from t1 + join t2 on t1.a=t2.c order by d; +select t1.a, (case t1.a when 0 then 0 else t1.b end) d from t1 + join t2 on t1.a=t2.c where b=11120436154190595086 order by d; +drop table t1, t2; + +--echo End of 5.0 tests diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 86eb10d50b0..8cbbc115922 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -2530,6 +2530,23 @@ bool Item_func_case::fix_fields(THD *thd, Item **ref) } +void Item_func_case::agg_str_lengths(Item* arg) +{ + set_if_bigger(max_length, arg->max_length); + set_if_bigger(decimals, arg->decimals); + unsigned_flag= unsigned_flag && arg->unsigned_flag; +} + + +void Item_func_case::agg_num_lengths(Item *arg) +{ + uint len= my_decimal_length_to_precision(arg->max_length, arg->decimals, + arg->unsigned_flag) - arg->decimals; + set_if_bigger(max_length, len); + set_if_bigger(decimals, arg->decimals); + unsigned_flag= unsigned_flag && arg->unsigned_flag; +} + void Item_func_case::fix_length_and_dec() { @@ -2579,15 +2596,22 @@ void Item_func_case::fix_length_and_dec() max_length=0; decimals=0; - for (uint i=0 ; i < ncases ; i+=2) + unsigned_flag= TRUE; + if (cached_result_type == STRING_RESULT) { - set_if_bigger(max_length,args[i+1]->max_length); - set_if_bigger(decimals,args[i+1]->decimals); + for (uint i= 0; i < ncases; i+= 2) + agg_str_lengths(args[i + 1]); + if (else_expr_num != -1) + agg_str_lengths(args[else_expr_num]); } - if (else_expr_num != -1) + else { - set_if_bigger(max_length,args[else_expr_num]->max_length); - set_if_bigger(decimals,args[else_expr_num]->decimals); + for (uint i= 0; i < ncases; i+= 2) + agg_num_lengths(args[i + 1]); + if (else_expr_num != -1) + agg_num_lengths(args[else_expr_num]); + max_length= my_decimal_precision_to_length(max_length + decimals, decimals, + unsigned_flag); } } diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 8410c66b034..3e32b5d2c9c 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -753,6 +753,8 @@ public: void print(String *str); Item *find_item(String *str); CHARSET_INFO *compare_collation() { return cmp_collation.collation; } + void agg_str_lengths(Item *arg); + void agg_num_lengths(Item *arg); }; From 76bf63ba4ba05f79abbdb3ba74de068324088851 Mon Sep 17 00:00:00 2001 From: "kaa@polly.(none)" <> Date: Mon, 29 Oct 2007 11:52:44 +0300 Subject: [PATCH 096/336] Fixed compile warnings introduced by the patch for bug #29131. --- sql/mysqld.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 90bba4cd8ab..4c459d34a55 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -6544,7 +6544,8 @@ static void mysql_init_variables(void) /* Things reset to zero */ opt_skip_slave_start= opt_reckless_slave = 0; mysql_home[0]= pidfile_name[0]= log_error_file[0]= 0; - opt_log= opt_update_log= opt_slow_log= 0; + opt_log= opt_slow_log= 0; + opt_update_log= 0; opt_bin_log= 0; opt_disable_networking= opt_skip_show_db=0; opt_logname= opt_update_logname= opt_binlog_index_name= opt_slow_logname= 0; From 7f945b2ad1fc8f6dcdb64a46313a164362cf6475 Mon Sep 17 00:00:00 2001 From: "gluh@mysql.com/eagle.(none)" <> Date: Mon, 29 Oct 2007 14:45:35 +0400 Subject: [PATCH 097/336] backported test case from 5.1 --- mysql-test/r/information_schema.result | 32 ++++++++++++++++++++++++++ mysql-test/t/information_schema.test | 20 ++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index 0c6a1855072..80f85aee429 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -1385,6 +1385,38 @@ f6 bigint(20) NO 10 f7 datetime NO NULL f8 datetime YES 2006-01-01 00:00:00 drop table t1; +select * from information_schema.columns where table_schema = NULL; +TABLE_CATALOG TABLE_SCHEMA TABLE_NAME COLUMN_NAME ORDINAL_POSITION COLUMN_DEFAULT IS_NULLABLE DATA_TYPE CHARACTER_MAXIMUM_LENGTH CHARACTER_OCTET_LENGTH NUMERIC_PRECISION NUMERIC_SCALE CHARACTER_SET_NAME COLLATION_NAME COLUMN_TYPE COLUMN_KEY EXTRA PRIVILEGES COLUMN_COMMENT +select * from `information_schema`.`COLUMNS` where `TABLE_NAME` = NULL; +TABLE_CATALOG TABLE_SCHEMA TABLE_NAME COLUMN_NAME ORDINAL_POSITION COLUMN_DEFAULT IS_NULLABLE DATA_TYPE CHARACTER_MAXIMUM_LENGTH CHARACTER_OCTET_LENGTH NUMERIC_PRECISION NUMERIC_SCALE CHARACTER_SET_NAME COLLATION_NAME COLUMN_TYPE COLUMN_KEY EXTRA PRIVILEGES COLUMN_COMMENT +select * from `information_schema`.`KEY_COLUMN_USAGE` where `TABLE_SCHEMA` = NULL; +CONSTRAINT_CATALOG CONSTRAINT_SCHEMA CONSTRAINT_NAME TABLE_CATALOG TABLE_SCHEMA TABLE_NAME COLUMN_NAME ORDINAL_POSITION POSITION_IN_UNIQUE_CONSTRAINT REFERENCED_TABLE_SCHEMA REFERENCED_TABLE_NAME REFERENCED_COLUMN_NAME +select * from `information_schema`.`KEY_COLUMN_USAGE` where `TABLE_NAME` = NULL; +CONSTRAINT_CATALOG CONSTRAINT_SCHEMA CONSTRAINT_NAME TABLE_CATALOG TABLE_SCHEMA TABLE_NAME COLUMN_NAME ORDINAL_POSITION POSITION_IN_UNIQUE_CONSTRAINT REFERENCED_TABLE_SCHEMA REFERENCED_TABLE_NAME REFERENCED_COLUMN_NAME +select * from information_schema.schemata where schema_name = NULL; +CATALOG_NAME SCHEMA_NAME DEFAULT_CHARACTER_SET_NAME DEFAULT_COLLATION_NAME SQL_PATH +select * from `information_schema`.`STATISTICS` where `TABLE_SCHEMA` = NULL; +TABLE_CATALOG TABLE_SCHEMA TABLE_NAME NON_UNIQUE INDEX_SCHEMA INDEX_NAME SEQ_IN_INDEX COLUMN_NAME COLLATION CARDINALITY SUB_PART PACKED NULLABLE INDEX_TYPE COMMENT +select * from `information_schema`.`STATISTICS` where `TABLE_NAME` = NULL; +TABLE_CATALOG TABLE_SCHEMA TABLE_NAME NON_UNIQUE INDEX_SCHEMA INDEX_NAME SEQ_IN_INDEX COLUMN_NAME COLLATION CARDINALITY SUB_PART PACKED NULLABLE INDEX_TYPE COMMENT +select * from information_schema.tables where table_schema = NULL; +TABLE_CATALOG TABLE_SCHEMA TABLE_NAME TABLE_TYPE ENGINE VERSION ROW_FORMAT TABLE_ROWS AVG_ROW_LENGTH DATA_LENGTH MAX_DATA_LENGTH INDEX_LENGTH DATA_FREE AUTO_INCREMENT CREATE_TIME UPDATE_TIME CHECK_TIME TABLE_COLLATION CHECKSUM CREATE_OPTIONS TABLE_COMMENT +select * from information_schema.tables where table_catalog = NULL; +TABLE_CATALOG TABLE_SCHEMA TABLE_NAME TABLE_TYPE ENGINE VERSION ROW_FORMAT TABLE_ROWS AVG_ROW_LENGTH DATA_LENGTH MAX_DATA_LENGTH INDEX_LENGTH DATA_FREE AUTO_INCREMENT CREATE_TIME UPDATE_TIME CHECK_TIME TABLE_COLLATION CHECKSUM CREATE_OPTIONS TABLE_COMMENT +select * from information_schema.tables where table_name = NULL; +TABLE_CATALOG TABLE_SCHEMA TABLE_NAME TABLE_TYPE ENGINE VERSION ROW_FORMAT TABLE_ROWS AVG_ROW_LENGTH DATA_LENGTH MAX_DATA_LENGTH INDEX_LENGTH DATA_FREE AUTO_INCREMENT CREATE_TIME UPDATE_TIME CHECK_TIME TABLE_COLLATION CHECKSUM CREATE_OPTIONS TABLE_COMMENT +select * from `information_schema`.`TABLE_CONSTRAINTS` where `TABLE_SCHEMA` = NULL; +CONSTRAINT_CATALOG CONSTRAINT_SCHEMA CONSTRAINT_NAME TABLE_SCHEMA TABLE_NAME CONSTRAINT_TYPE +select * from `information_schema`.`TABLE_CONSTRAINTS` where `TABLE_NAME` = NULL; +CONSTRAINT_CATALOG CONSTRAINT_SCHEMA CONSTRAINT_NAME TABLE_SCHEMA TABLE_NAME CONSTRAINT_TYPE +select * from `information_schema`.`TRIGGERS` where `EVENT_OBJECT_SCHEMA` = NULL; +TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_MANIPULATION EVENT_OBJECT_CATALOG EVENT_OBJECT_SCHEMA EVENT_OBJECT_TABLE ACTION_ORDER ACTION_CONDITION ACTION_STATEMENT ACTION_ORIENTATION ACTION_TIMING ACTION_REFERENCE_OLD_TABLE ACTION_REFERENCE_NEW_TABLE ACTION_REFERENCE_OLD_ROW ACTION_REFERENCE_NEW_ROW CREATED SQL_MODE DEFINER +select * from `information_schema`.`TRIGGERS` where `EVENT_OBJECT_TABLE` = NULL; +TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_MANIPULATION EVENT_OBJECT_CATALOG EVENT_OBJECT_SCHEMA EVENT_OBJECT_TABLE ACTION_ORDER ACTION_CONDITION ACTION_STATEMENT ACTION_ORIENTATION ACTION_TIMING ACTION_REFERENCE_OLD_TABLE ACTION_REFERENCE_NEW_TABLE ACTION_REFERENCE_OLD_ROW ACTION_REFERENCE_NEW_ROW CREATED SQL_MODE DEFINER +select * from `information_schema`.`VIEWS` where `TABLE_SCHEMA` = NULL; +TABLE_CATALOG TABLE_SCHEMA TABLE_NAME VIEW_DEFINITION CHECK_OPTION IS_UPDATABLE DEFINER SECURITY_TYPE +select * from `information_schema`.`VIEWS` where `TABLE_NAME` = NULL; +TABLE_CATALOG TABLE_SCHEMA TABLE_NAME VIEW_DEFINITION CHECK_OPTION IS_UPDATABLE DEFINER SECURITY_TYPE End of 5.0 tests. show fields from information_schema.table_names; ERROR 42S02: Unknown table 'table_names' in information_schema diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test index 04ffd30ec62..3d3310e389e 100644 --- a/mysql-test/t/information_schema.test +++ b/mysql-test/t/information_schema.test @@ -1088,6 +1088,26 @@ select column_default from information_schema.columns where table_name= 't1'; show columns from t1; drop table t1; +# +# Bug#31633 Information schema = NULL queries crash the server +# +select * from information_schema.columns where table_schema = NULL; +select * from `information_schema`.`COLUMNS` where `TABLE_NAME` = NULL; +select * from `information_schema`.`KEY_COLUMN_USAGE` where `TABLE_SCHEMA` = NULL; +select * from `information_schema`.`KEY_COLUMN_USAGE` where `TABLE_NAME` = NULL; +select * from information_schema.schemata where schema_name = NULL; +select * from `information_schema`.`STATISTICS` where `TABLE_SCHEMA` = NULL; +select * from `information_schema`.`STATISTICS` where `TABLE_NAME` = NULL; +select * from information_schema.tables where table_schema = NULL; +select * from information_schema.tables where table_catalog = NULL; +select * from information_schema.tables where table_name = NULL; +select * from `information_schema`.`TABLE_CONSTRAINTS` where `TABLE_SCHEMA` = NULL; +select * from `information_schema`.`TABLE_CONSTRAINTS` where `TABLE_NAME` = NULL; +select * from `information_schema`.`TRIGGERS` where `EVENT_OBJECT_SCHEMA` = NULL; +select * from `information_schema`.`TRIGGERS` where `EVENT_OBJECT_TABLE` = NULL; +select * from `information_schema`.`VIEWS` where `TABLE_SCHEMA` = NULL; +select * from `information_schema`.`VIEWS` where `TABLE_NAME` = NULL; + --echo End of 5.0 tests. # From b943d8cf3c46f1246089a00b1878d8143eb400d5 Mon Sep 17 00:00:00 2001 From: "gluh@mysql.com/eagle.(none)" <> Date: Mon, 29 Oct 2007 14:53:10 +0400 Subject: [PATCH 098/336] Bug#30897 GROUP_CONCAT returns extra comma on empty fields The fix is a copy of Martin Friebe's suggestion. added testing for no_appended which will be false if anything, including the empty string is in result --- mysql-test/r/func_gconcat.result | 9 +++++++++ mysql-test/t/func_gconcat.test | 9 +++++++++ sql/item_sum.cc | 2 +- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/func_gconcat.result b/mysql-test/r/func_gconcat.result index 73f756bc1d2..df61954b22a 100644 --- a/mysql-test/r/func_gconcat.result +++ b/mysql-test/r/func_gconcat.result @@ -861,4 +861,13 @@ select group_concat(distinct a, c order by a desc, c desc) from t1; group_concat(distinct a, c order by a desc, c desc) 31,11,10,01,00 drop table t1; +create table t1 (f1 char(20)); +insert into t1 values (''),(''); +select group_concat(distinct f1) from t1; +group_concat(distinct f1) + +select group_concat(f1) from t1; +group_concat(f1) +, +drop table t1; End of 5.0 tests diff --git a/mysql-test/t/func_gconcat.test b/mysql-test/t/func_gconcat.test index c415ca6c6eb..df8199a5bc7 100644 --- a/mysql-test/t/func_gconcat.test +++ b/mysql-test/t/func_gconcat.test @@ -590,4 +590,13 @@ select group_concat(distinct a, c order by a desc, c desc) from t1; drop table t1; +# +# Bug#30897 GROUP_CONCAT returns extra comma on empty fields +# +create table t1 (f1 char(20)); +insert into t1 values (''),(''); +select group_concat(distinct f1) from t1; +select group_concat(f1) from t1; +drop table t1; + --echo End of 5.0 tests diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 30cbe872101..ad8ebd0791c 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -3406,7 +3406,7 @@ String* Item_func_group_concat::val_str(String* str) DBUG_ASSERT(fixed == 1); if (null_value) return 0; - if (!result.length() && tree) + if (no_appended && tree) /* Tree is used for sorting as in ORDER BY */ tree_walk(tree, (tree_walk_action)&dump_leaf_key, (void*)this, left_root_right); From 6b92ec4acbf78892bc4880913a762db0189ce20f Mon Sep 17 00:00:00 2001 From: "gluh@mysql.com/eagle.(none)" <> Date: Mon, 29 Oct 2007 15:39:56 +0400 Subject: [PATCH 099/336] Bug#30889: filesort and order by with float/numeric crashes server There are two problems with ROUND(X, D) on an exact numeric (DECIMAL, NUMERIC type) field of a table: 1) The implementation of the ROUND function would change the number of decimal places regardless of the value decided upon in fix_length_and_dec. When the number of decimal places is not constant, this would cause an inconsistent state where the number of digits was less than the number of decimal places, which crashes filesort. Fixed by not allowing the ROUND operation to add any more decimal places than was decided in fix_length_and_dec. 2) fix_length_and_dec would allow the number of decimals to be greater than the maximium configured value for constant values of D. This led to the same crash as in (1). Fixed by not allowing the above in fix_length_and_dec. --- mysql-test/r/type_decimal.result | 67 ++++++++++++++++++++++++++++++++ mysql-test/t/type_decimal.test | 39 ++++++++++++++++++- sql/item_func.cc | 3 +- sql/item_func.h | 31 +++++++++++++++ 4 files changed, 138 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/type_decimal.result b/mysql-test/r/type_decimal.result index b550536d0db..a438755ce6b 100644 --- a/mysql-test/r/type_decimal.result +++ b/mysql-test/r/type_decimal.result @@ -822,4 +822,71 @@ this must not produce error 1048: select * from t1 where ua_invited_by_id not in (select ua_id from t1); ua_id ua_invited_by_id drop table t1; +DROP TABLE IF EXISTS t3; +DROP TABLE IF EXISTS t4; +CREATE TABLE t1( a NUMERIC, b INT ); +INSERT INTO t1 VALUES (123456, 40), (123456, 40); +SELECT TRUNCATE( a, b ) AS c FROM t1 ORDER BY c; +c +123456 +123456 +SELECT ROUND( a, b ) AS c FROM t1 ORDER BY c; +c +123456 +123456 +SELECT ROUND( a, 100 ) AS c FROM t1 ORDER BY c; +c +123456.000000000000000000000000000000 +123456.000000000000000000000000000000 +CREATE TABLE t2( a NUMERIC, b INT ); +INSERT INTO t2 VALUES (123456, 100); +SELECT TRUNCATE( a, b ) AS c FROM t2 ORDER BY c; +c +123456 +SELECT ROUND( a, b ) AS c FROM t2 ORDER BY c; +c +123456 +CREATE TABLE t3( a DECIMAL, b INT ); +INSERT INTO t3 VALUES (123456, 40), (123456, 40); +SELECT TRUNCATE( a, b ) AS c FROM t3 ORDER BY c; +c +123456 +123456 +SELECT ROUND( a, b ) AS c FROM t3 ORDER BY c; +c +123456 +123456 +SELECT ROUND( a, 100 ) AS c FROM t3 ORDER BY c; +c +123456.000000000000000000000000000000 +123456.000000000000000000000000000000 +CREATE TABLE t4( a DECIMAL, b INT ); +INSERT INTO t4 VALUES (123456, 40), (123456, 40); +SELECT TRUNCATE( a, b ) AS c FROM t4 ORDER BY c; +c +123456 +123456 +SELECT ROUND( a, b ) AS c FROM t4 ORDER BY c; +c +123456 +123456 +SELECT ROUND( a, 100 ) AS c FROM t4 ORDER BY c; +c +123456.000000000000000000000000000000 +123456.000000000000000000000000000000 +delete from t1; +INSERT INTO t1 VALUES (1234567890, 20), (999.99, 5); +Warnings: +Note 1265 Data truncated for column 'a' at row 2 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` decimal(10,0) default NULL, + `b` int(11) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +select round(a,b) as c from t1 order by c; +c +1000 +1234567890 +DROP TABLE t1, t2, t3, t4; End of 5.0 tests diff --git a/mysql-test/t/type_decimal.test b/mysql-test/t/type_decimal.test index 12d4398dd57..807d1e6b01e 100644 --- a/mysql-test/t/type_decimal.test +++ b/mysql-test/t/type_decimal.test @@ -440,5 +440,42 @@ select * from t1 where ua_invited_by_id not in (select ua_id from t1); drop table t1; ---echo End of 5.0 tests +# +# Bug #30889: filesort and order by with float/numeric crashes server +# +--disable_warnings +DROP TABLE IF EXISTS t3; +DROP TABLE IF EXISTS t4; +--enable_warnings +CREATE TABLE t1( a NUMERIC, b INT ); +INSERT INTO t1 VALUES (123456, 40), (123456, 40); +SELECT TRUNCATE( a, b ) AS c FROM t1 ORDER BY c; +SELECT ROUND( a, b ) AS c FROM t1 ORDER BY c; +SELECT ROUND( a, 100 ) AS c FROM t1 ORDER BY c; +CREATE TABLE t2( a NUMERIC, b INT ); +INSERT INTO t2 VALUES (123456, 100); +SELECT TRUNCATE( a, b ) AS c FROM t2 ORDER BY c; +SELECT ROUND( a, b ) AS c FROM t2 ORDER BY c; + +CREATE TABLE t3( a DECIMAL, b INT ); +INSERT INTO t3 VALUES (123456, 40), (123456, 40); +SELECT TRUNCATE( a, b ) AS c FROM t3 ORDER BY c; +SELECT ROUND( a, b ) AS c FROM t3 ORDER BY c; +SELECT ROUND( a, 100 ) AS c FROM t3 ORDER BY c; + +CREATE TABLE t4( a DECIMAL, b INT ); +INSERT INTO t4 VALUES (123456, 40), (123456, 40); +SELECT TRUNCATE( a, b ) AS c FROM t4 ORDER BY c; +SELECT ROUND( a, b ) AS c FROM t4 ORDER BY c; +SELECT ROUND( a, 100 ) AS c FROM t4 ORDER BY c; + +delete from t1; +INSERT INTO t1 VALUES (1234567890, 20), (999.99, 5); +show create table t1; + +select round(a,b) as c from t1 order by c; + +DROP TABLE t1, t2, t3, t4; + +--echo End of 5.0 tests diff --git a/sql/item_func.cc b/sql/item_func.cc index 22b0044242c..2ee9973c785 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -2003,6 +2003,7 @@ void Item_func_round::fix_length_and_dec() case DECIMAL_RESULT: { hybrid_type= DECIMAL_RESULT; + decimals_to_set= min(DECIMAL_MAX_SCALE, decimals_to_set); int decimals_delta= args[0]->decimals - decimals_to_set; int precision= args[0]->decimal_precision(); int length_increase= ((decimals_delta <= 0) || truncate) ? 0:1; @@ -2109,7 +2110,7 @@ my_decimal *Item_func_round::decimal_op(my_decimal *decimal_value) longlong dec= args[1]->val_int(); if (dec > 0 || (dec < 0 && args[1]->unsigned_flag)) { - dec= min((ulonglong) dec, DECIMAL_MAX_SCALE); + dec= min((ulonglong) dec, decimals); decimals= (uint8) dec; // to get correct output } else if (dec < INT_MIN) diff --git a/sql/item_func.h b/sql/item_func.h index 43221a18a5b..a31294c0395 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -236,9 +236,40 @@ public: my_decimal *val_decimal(my_decimal *); String *val_str(String*str); + /** + @brief Performs the operation that this functions implements when the + result type is INT. + + @return The result of the operation. + */ virtual longlong int_op()= 0; + + /** + @brief Performs the operation that this functions implements when the + result type is REAL. + + @return The result of the operation. + */ virtual double real_op()= 0; + + /** + @brief Performs the operation that this functions implements when the + result type is DECIMAL. + + @param A pointer where the DECIMAL value will be allocated. + @return + - 0 If the result is NULL + - The same pointer it was given, with the area initialized to the + result of the operation. + */ virtual my_decimal *decimal_op(my_decimal *)= 0; + + /** + @brief Performs the operation that this functions implements when the + result type is a string type. + + @return The result of the operation. + */ virtual String *str_op(String *)= 0; bool is_null() { update_null_value(); return null_value; } }; From 69ed192e7277556f4e2ca487967322be7fe7edf7 Mon Sep 17 00:00:00 2001 From: "gluh@mysql.com/eagle.(none)" <> Date: Mon, 29 Oct 2007 15:49:56 +0400 Subject: [PATCH 100/336] after merge fix --- mysql-test/r/type_decimal.result | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/type_decimal.result b/mysql-test/r/type_decimal.result index 4e9dcf41256..e37a398d22e 100644 --- a/mysql-test/r/type_decimal.result +++ b/mysql-test/r/type_decimal.result @@ -881,8 +881,8 @@ Note 1265 Data truncated for column 'a' at row 2 show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `a` decimal(10,0) default NULL, - `b` int(11) default NULL + `a` decimal(10,0) DEFAULT NULL, + `b` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 select round(a,b) as c from t1 order by c; c From 27436f0ba38ff189d2baa1b713194538a84af935 Mon Sep 17 00:00:00 2001 From: "aelkin/elkin@koti.dsl.inet.fi" <> Date: Mon, 29 Oct 2007 15:20:59 +0200 Subject: [PATCH 101/336] Bug #27571 asynchronousity in setting mysql_`query`::error and Query_log_event::error_code A query can perform completely having the local var error of mysql_$query zero, where $query in insert, update, delete, load, and be binlogged with error_code e.g KILLED_QUERY while there is no reason do to so. That can happen because Query_log_event consults thd->killed flag to evaluate error_code. Fixed with implementing a scheme suggested and partly implemented at time of bug@22725 work-on. error_status is cached immediatly after the control leaves the main rows-loop and that instance always corresponds to `error' the local of mysql_$query functions. The cached value is passed to Query_log_event constructor, not the default thd->killed which can be changed in between of the caching and the constructing. --- mysql-test/r/binlog_killed.result | 106 ++++++ mysql-test/t/binlog_killed.test | 333 ++++++++++-------- .../t/binlog_killed_bug27571-master.opt | 1 + mysql-test/t/binlog_killed_bug27571.test | 68 ++++ .../t/binlog_killed_simulate-master.opt | 1 + mysql-test/t/binlog_killed_simulate.test | 65 ++++ sql/log_event.cc | 11 +- sql/log_event.h | 10 +- sql/sql_delete.cc | 18 +- sql/sql_insert.cc | 3 +- sql/sql_load.cc | 26 +- sql/sql_update.cc | 70 ++-- 12 files changed, 509 insertions(+), 203 deletions(-) create mode 100644 mysql-test/t/binlog_killed_bug27571-master.opt create mode 100644 mysql-test/t/binlog_killed_bug27571.test create mode 100644 mysql-test/t/binlog_killed_simulate-master.opt create mode 100644 mysql-test/t/binlog_killed_simulate.test diff --git a/mysql-test/r/binlog_killed.result b/mysql-test/r/binlog_killed.result index ba4f38fb4c1..ddd80283eca 100644 --- a/mysql-test/r/binlog_killed.result +++ b/mysql-test/r/binlog_killed.result @@ -9,4 +9,110 @@ insert into t2 values (null, null), (null, get_lock("a", 10)); select @result /* must be zero either way */; @result 0 +delete from t1; +delete from t2; +insert into t1 values (1,1),(2,2); +begin; +update t1 set b=11 where a=2; +update t1 set b=b+10; +kill query ID; +rollback; +ERROR 70100: Query execution was interrupted +select * from t1 /* must be the same as before (1,1),(2,2) */; +a b +1 1 +2 2 +begin; +delete from t1 where a=2; +delete from t1 where a=2; +kill query ID; +rollback; +ERROR 70100: Query execution was interrupted +select * from t1 /* must be the same as before (1,1),(2,2) */; +a b +1 1 +2 2 +drop table if exists t4; +create table t4 (a int, b int) engine=innodb; +insert into t4 values (3, 3); +begin; +insert into t1 values (3, 3); +begin; +insert into t1 select * from t4 for update; +kill query ID; +rollback; +ERROR 70100: Query execution was interrupted +rollback; +select * from t1 /* must be the same as before (1,1),(2,2) */; +a b +1 1 +2 2 +drop table t4; +create function bug27563(n int) +RETURNS int(11) +DETERMINISTIC +begin +if n > 1 then +select get_lock("a", 10) into @a; +end if; +return n; +end| +delete from t2; +insert into t2 values (1,1), (2,2); +reset master; +select get_lock("a", 20); +get_lock("a", 20) +1 +update t2 set b=b + bug27563(b) order by a; +kill query ID; +ERROR 70100: Query execution was interrupted +select * from t2 /* must be (1,2), (2,2) */; +a b +1 2 +2 2 +show master status /* must have the update event more to FD */; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 211 +select +(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) +is not null; +(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) +is not null +1 +select 0 /* must return 0 to mean the killed query is in */; +0 +0 +select RELEASE_LOCK("a"); +RELEASE_LOCK("a") +1 +delete from t2; +insert into t2 values (1,1), (2,2); +reset master; +select get_lock("a", 20); +get_lock("a", 20) +1 +delete from t2 where a=1 or a=bug27563(2) order by a; +kill query ID; +ERROR 70100: Query execution was interrupted +select * from t2 /* must be (1,2), (2,2) */; +a b +1 1 +2 2 +show master status /* must have the update event more to FD */; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 98 +select +(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) +is not null; +(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) +is not null +1 +select 0 /* must return 0 to mean the killed query is in */; +0 +0 +select RELEASE_LOCK("a"); +RELEASE_LOCK("a") +1 +drop function bug27563; drop table t1,t2,t3; +end of the tests diff --git a/mysql-test/t/binlog_killed.test b/mysql-test/t/binlog_killed.test index 034895f17cb..0e35e46c845 100644 --- a/mysql-test/t/binlog_killed.test +++ b/mysql-test/t/binlog_killed.test @@ -55,194 +55,239 @@ enable_result_log; select @result /* must be zero either way */; -# the functions are either *insensitive* to killing or killing can cause -# strange problmes with the error propagation out of SF's stack -# Bug#27563, Bug#27565, BUG#24971 + +--remove_file $MYSQLTEST_VARDIR/tmp/kill_query_calling_sp.binlog + # -# TODO: use if's block as regression test for the bugs or remove +# bug#27571 asynchronous setting mysql_`query`::error and Query_log_e::error_code # -if (0) -{ + +# checking that killing inside of select loops is safe as before +# killing after the loop can be only simulated - another test + +delete from t1; +delete from t2; +insert into t1 values (1,1),(2,2); +let $ID= `select connection_id()`; + +# +# simple update +# +connection con1; +begin; update t1 set b=11 where a=2; + +connection con2; +send update t1 set b=b+10; + +connection con1; +--replace_result $ID ID +eval kill query $ID; +rollback; + +connection con2; +--error ER_QUERY_INTERRUPTED +reap; +select * from t1 /* must be the same as before (1,1),(2,2) */; + +# +# multi update +# commented out as Bug #31807 multi-update,delete killing does not report with ER_QUERY_INTERRUPTED +# in the way +# +# connection con1; +# begin; update t1 set b=b+10; + +# connection con2; +# send update t1 as t_1,t1 as t_2 set t_1.b=11 where t_2.a=2; + +# connection con1; +# --replace_result $ID ID +# eval kill query $ID; +# rollback; + +# disable_abort_on_error; + +# connection con2; +# --error HY000,ER_QUERY_INTERRUPTED +# reap; +# select * from t1 /* must be the same as before (1,1),(2,2) */; + +# enable_abort_on_error; +# +# simple delete +# +connection con1; +begin; delete from t1 where a=2; + +connection con2; +send delete from t1 where a=2; + +connection con1; +--replace_result $ID ID +eval kill query $ID; +rollback; + +connection con2; +--error ER_QUERY_INTERRUPTED +reap; +select * from t1 /* must be the same as before (1,1),(2,2) */; + +# +# multi delete +# the same as for multi-update +# +# connection con1; +# begin; delete from t1 where a=2; + +# connection con2; +# send delete t1 from t1 where t1.a=2; + +# connection con1; +# --replace_result $ID ID +# eval kill query $ID; +# rollback; + +# connection con2; +# --error 0,ER_QUERY_INTERRUPTED +# reap; +# select * from t1 /* must be the same as before (1,1),(2,2) */; +# +# insert select +# +connection con1; +--disable_warnings +drop table if exists t4; +--enable_warnings +create table t4 (a int, b int) engine=innodb; +insert into t4 values (3, 3); +begin; insert into t1 values (3, 3); + +connection con2; +begin; +send insert into t1 select * from t4 for update; + +connection con1; +--replace_result $ID ID +eval kill query $ID; +rollback; + +connection con2; +--error ER_QUERY_INTERRUPTED +reap; +rollback; +select * from t1 /* must be the same as before (1,1),(2,2) */; + +drop table t4; # cleanup for the sub-case + +### +## non-ta table case: killing must be recorded in binlog +### delimiter |; -create function bug27563() +create function bug27563(n int) RETURNS int(11) DETERMINISTIC begin - select get_lock("a", 10) into @a; - return 1; + if n > 1 then + select get_lock("a", 10) into @a; + end if; + return n; end| delimiter ;| -# the function is sensitive to killing requiring innodb though with wrong client error -# TO FIX in BUG#27565; TODO: remove --error 1105 afterwards -delimiter |; -create function bug27565() -RETURNS int(11) -DETERMINISTIC -begin - select a from t1 where a=1 into @a for update; - return 1; -end| -delimiter ;| +# +# update +# +delete from t2; +insert into t2 values (1,1), (2,2); reset master; - - -### ta table case: killing causes rollback - -# A. autocommit ON connection con1; select get_lock("a", 20); connection con2; let $ID= `select connection_id()`; -send insert into t1 values (bug27563(),1); +send update t2 set b=b + bug27563(b) order by a; connection con1; +--replace_result $ID ID eval kill query $ID; connection con2; -# todo (re-record test): after bugs 27563,27565 got fixed affected rows will report zero ---enable_info -# todo: remove 0 return after fixing Bug#27563 ---error 0,ER_QUERY_INTERRUPTED -reap; ### pb: wrong error ---disable_info -###--replace_column 2 # 5 # -### show binlog events from 98 /* nothing in binlog unless Bug#27563 */; -show master status /* must be only FD event unless Bug#27563 */; -select count(*) from t1 /* must be zero unless Bug#27563 */; - -# M. multi-statement-ta -connection con2; -let $ID= `select connection_id()`; -begin; -send insert into t1 values (bug27563(),1); - -connection con1; -eval kill query $ID; -connection con2; -# todo (re-record test): after bugs 27563,27565 got fixed affected rows will report zero ---enable_info -# todo: remove 0 return after fixing Bug#27563 ---error 0,ER_QUERY_INTERRUPTED +--error ER_QUERY_INTERRUPTED reap; ---disable_info -select count(*) from t1 /* must be zero unless Bug#27563 */; -commit; +select * from t2 /* must be (1,2), (2,2) */; +show master status /* must have the update event more to FD */; +# a proof the query is binlogged with an error -### non-ta table case: killing must be recorded in binlog - -reset master; - -connection con2; -let $ID= `select connection_id()`; -send insert into t2 values (bug27563(),1); - -connection con1; -eval kill query $ID; - -connection con2; -# todo: remove 0 return after fixing Bug#27563 ---error 0,ER_QUERY_INTERRUPTED -reap; -select count(*) from t2 /* must be one */; -#show binlog events from 98 /* must have the insert on non-ta table */; -show master status /* must have the insert event more to FD */; -# the value of the error flag of KILLED_QUERY is tested further +--exec $MYSQL_BINLOG --start-position=98 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +eval select +(@a:=load_file("$MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) +is not null; +--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR +let $error_code= `select @a like "%#%error_code=0%" /* must return 0*/`; +eval select $error_code /* must return 0 to mean the killed query is in */; +# cleanup for the sub-case connection con1; select RELEASE_LOCK("a"); +--remove_file $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog -### test with effective killing of SF() - -delete from t1; -delete from t2; -insert into t1 values (1,1); -insert into t2 values (1,1); - -# -# Bug#27565 -# test where KILL is propagated as error to the top level -# still another bug with the error message to the user -# todo: fix reexecute the result file after fixing -# -begin; update t1 set b=0 where a=1; - -connection con2; -let $ID= `select connection_id()`; -send update t2 set b=bug27565()-1 where a=1; - -connection con1; -eval kill query $ID; -commit; - -connection con2; -# todo: fix Bug #27565 killed query of SF() is not reported correctly and -# remove 1105 (wrong) -#--error ER_QUERY_INTERRUPTED ---error 1105,ER_QUERY_INTERRUPTED -reap; ### pb: wrong error -select * from t1 /* must be: (1,0) */; -select * from t2 /* must be as before: (1,1) */; - -## bug#22725 with effective and propagating killing # -# top-level ta-table -connection con1; -delete from t3; -reset master; -begin; update t1 set b=0 where a=1; +# delete +# -connection con2; -let $ID= `select connection_id()`; -# the query won't perform completely since the function gets interrupted -send insert into t3 values (0,0),(1,bug27565()); - -connection con1; -eval kill query $ID; -rollback; - -connection con2; -# todo: fix Bug #27565 killed query of SF() is not reported correctly and -# remove 1105 (wrong) -#--error ER_QUERY_INTERRUPTED ---error 1105,ER_QUERY_INTERRUPTED -reap; ### pb: wrong error -select count(*) from t3 /* must be zero */; -show master status /* nothing in binlog */; - -# top-level non-ta-table -connection con1; delete from t2; +insert into t2 values (1,1), (2,2); reset master; -begin; update t1 set b=0 where a=1; +connection con1; +select get_lock("a", 20); connection con2; let $ID= `select connection_id()`; -# the query won't perform completely since the function gets intrurrupted -send insert into t2 values (0,0),(1,bug27565()) /* non-ta t2 */; +send delete from t2 where a=1 or a=bug27563(2) order by a; connection con1; +--replace_result $ID ID eval kill query $ID; -rollback; connection con2; -# todo: fix Bug #27565 killed query of SF() is not reported correctly and -# remove 1105 (wrong) -#--error ER_QUERY_INTERRUPTED ---error 1105,ER_QUERY_INTERRUPTED -reap; ### pb: wrong error +--error ER_QUERY_INTERRUPTED +reap; +select * from t2 /* must be (1,2), (2,2) */; +show master status /* must have the update event more to FD */; -select count(*) from t2 /* count must be one */; -show master status /* insert into non-ta must be in binlog */; +# a proof the query is binlogged with an error + +--exec $MYSQL_BINLOG --start-position=98 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +eval select +(@a:=load_file("$MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) +is not null; +--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR +let $error_code= `select @a like "%#%error_code=0%" /* must return 0*/`; +eval select $error_code /* must return 0 to mean the killed query is in */; + +# cleanup for the sub-case +connection con1; +select RELEASE_LOCK("a"); +--remove_file $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog + +# +# load data - see simulation tests +# + + +# bug#27571 cleanup drop function bug27563; -drop function bug27565; -} -system rm $MYSQLTEST_VARDIR/tmp/kill_query_calling_sp.binlog ; + +# +# common cleanup +# drop table t1,t2,t3; +--echo end of the tests diff --git a/mysql-test/t/binlog_killed_bug27571-master.opt b/mysql-test/t/binlog_killed_bug27571-master.opt new file mode 100644 index 00000000000..d269cf246d5 --- /dev/null +++ b/mysql-test/t/binlog_killed_bug27571-master.opt @@ -0,0 +1 @@ +--loose-debug=d,stop_after_row_loop_done diff --git a/mysql-test/t/binlog_killed_bug27571.test b/mysql-test/t/binlog_killed_bug27571.test new file mode 100644 index 00000000000..6fa3c6d256f --- /dev/null +++ b/mysql-test/t/binlog_killed_bug27571.test @@ -0,0 +1,68 @@ +--source include/have_innodb.inc +--source include/not_embedded.inc +--source include/have_log_bin.inc + +# +# bug#27571 asynchronous setting mysql_`query`::error and Query_log_e::error_code +# +# Checking that if killing happens inbetween of the end of rows loop and +# recording into binlog that will not lead to recording any error incl +# the killed error. +# + +connect (looser, localhost, root,,); +connect (killer, localhost, root,,); + +create table t1 (a int auto_increment, b int, PRIMARY KEY (a)) ENGINE=InnoDB; + +delete from t1; +insert into t1 values (1,1),(2,2); +reset master; + +connection looser; +let $ID= `select connection_id()`; +send update t1 set b=11 where a=2; + +connection killer; +sleep 1; # let 1 second for the update to get to the sleeping point +--replace_result $ID ID +eval kill query $ID; + +connection looser; +--error 0 # zero even though the query must be got killed while it was sleepin for 5 secs +reap; + +# +# this is another possible artifact. The killed error was not caught +# as that is logical as killing was not effective: +# data are ok and well as binlog event is without killed error (further). +# The reason of the following `show error' is to prove that +# killing simulation was effective +# +show errors; + +connection killer; + +# nothing is rolled back + +select * from t1 where a=2 /* must be 11 */; + +# a proof the query is binlogged with an error + +--exec $MYSQL_BINLOG --start-position=98 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +eval select +(@a:=load_file("$MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) +is not null; +--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR +let $error_code= `select @a like "%#%error_code=0%"`; + +eval select $error_code /* must return 1*/; + +# +# cleanup +# + +drop table t1; + +--echo end of the tests diff --git a/mysql-test/t/binlog_killed_simulate-master.opt b/mysql-test/t/binlog_killed_simulate-master.opt new file mode 100644 index 00000000000..90c70ecee29 --- /dev/null +++ b/mysql-test/t/binlog_killed_simulate-master.opt @@ -0,0 +1 @@ +--loose-debug=d,simulate_kill_bug27571 diff --git a/mysql-test/t/binlog_killed_simulate.test b/mysql-test/t/binlog_killed_simulate.test new file mode 100644 index 00000000000..d6234d1bfd7 --- /dev/null +++ b/mysql-test/t/binlog_killed_simulate.test @@ -0,0 +1,65 @@ +# +# bug#27571 asynchronous setting mysql_$query()'s local error and +# Query_log_event::error_code +# + +--disable_warnings +drop table if exists t1,t2; +--enable_warnings + +# +# Checking that killing upon successful row-loop does not affect binlogging +# + +create table t1 (a int) engine=MyISAM; +insert into t1 set a=1; +reset master; + +update t1 set a=2 /* will be "killed" after work has been done */; + +# a proof the query is binlogged with no error + +--exec $MYSQL_BINLOG --start-position=98 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +eval select +(@a:=load_file("$MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) +is not null; +--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR +let $error_code= `select @a like "%#%error_code=0%" /* must return 1 */`; +eval select $error_code /* must return 1 as query completed before got killed*/; + +# cleanup for the sub-case +system rm $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog; + + +# +# Checking that killing inside of row-loop for LOAD DATA into +# non-transactional table affects binlogging +# + +create table t2 (a int, b int) ENGINE=MyISAM; +reset master; +--error ER_QUERY_INTERRUPTED +load data infile '../std_data_ln/rpl_loaddata.dat' into table t2 /* will be "killed" in the middle */; + + +# a proof the query is binlogged with an error + +source include/show_binlog_events.inc; + +--exec $MYSQL_BINLOG --start-position=98 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +eval select +(@a:=load_file("$MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) +is not null; +--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR +let $error_code= `select @a like "%#%error_code=0%" /* must return 0*/`; +eval select $error_code /* must return 0 to mean the killed query is in */; + +# cleanup for the sub-case +system rm $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog; + + +drop table t1,t2; + +--echo end of the tests diff --git a/sql/log_event.cc b/sql/log_event.cc index 3899e772bf8..da616adbb09 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -4994,12 +4994,13 @@ int Begin_load_query_log_event::get_create_or_append() const #ifndef MYSQL_CLIENT Execute_load_query_log_event:: Execute_load_query_log_event(THD* thd_arg, const char* query_arg, - ulong query_length_arg, uint fn_pos_start_arg, - uint fn_pos_end_arg, - enum_load_dup_handling dup_handling_arg, - bool using_trans, bool suppress_use): + ulong query_length_arg, uint fn_pos_start_arg, + uint fn_pos_end_arg, + enum_load_dup_handling dup_handling_arg, + bool using_trans, bool suppress_use, + THD::killed_state killed_err_arg): Query_log_event(thd_arg, query_arg, query_length_arg, using_trans, - suppress_use), + suppress_use, killed_err_arg), file_id(thd_arg->file_id), fn_pos_start(fn_pos_start_arg), fn_pos_end(fn_pos_end_arg), dup_handling(dup_handling_arg) { diff --git a/sql/log_event.h b/sql/log_event.h index 04aac5d08fc..5b065a33dd1 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -1619,10 +1619,12 @@ public: #ifndef MYSQL_CLIENT Execute_load_query_log_event(THD* thd, const char* query_arg, - ulong query_length, uint fn_pos_start_arg, - uint fn_pos_end_arg, - enum_load_dup_handling dup_handling_arg, - bool using_trans, bool suppress_use); + ulong query_length, uint fn_pos_start_arg, + uint fn_pos_end_arg, + enum_load_dup_handling dup_handling_arg, + bool using_trans, bool suppress_use, + THD::killed_state + killed_err_arg= THD::KILLED_NO_VALUE); #ifdef HAVE_REPLICATION void pack_info(Protocol* protocol); int exec_event(struct st_relay_log_info* rli); diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index add37c8c552..a28a39a769d 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -38,6 +38,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ha_rows deleted; uint usable_index= MAX_KEY; SELECT_LEX *select_lex= &thd->lex->select_lex; + THD::killed_state killed_status= THD::NOT_KILLED; DBUG_ENTER("mysql_delete"); if (open_and_lock_tables(thd, table_list)) @@ -280,8 +281,8 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, else table->file->unlock_row(); // Row failed selection, release lock on it } - if (thd->killed && !error) - error= 1; // Aborted + killed_status= thd->killed; + error= (killed_status == THD::NOT_KILLED)? error : 1; thd->proc_info="end"; end_read_record(&info); free_io_cache(table); // Will not do any harm @@ -326,7 +327,7 @@ cleanup: if (error < 0) thd->clear_error(); Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_table, FALSE); + transactional_table, FALSE, killed_status); if (mysql_bin_log.write(&qinfo) && transactional_table) error=1; } @@ -729,7 +730,8 @@ void multi_delete::send_error(uint errcode,const char *err) } thd->transaction.all.modified_non_trans_table= true; } - DBUG_ASSERT(!normal_tables || !deleted || thd->transaction.stmt.modified_non_trans_table); + DBUG_ASSERT(!normal_tables || !deleted || + thd->transaction.stmt.modified_non_trans_table); DBUG_VOID_RETURN; } @@ -817,6 +819,7 @@ int multi_delete::do_deletes() bool multi_delete::send_eof() { + THD::killed_state killed_status= THD::NOT_KILLED; thd->proc_info="deleting from reference tables"; /* Does deletes for the last n - 1 tables, returns 0 if ok */ @@ -824,7 +827,7 @@ bool multi_delete::send_eof() /* compute a total error to know if something failed */ local_error= local_error || error; - + killed_status= (local_error == 0)? THD::NOT_KILLED : thd->killed; /* reset used flags */ thd->proc_info="end"; @@ -836,7 +839,8 @@ bool multi_delete::send_eof() { query_cache_invalidate3(thd, delete_tables, 1); } - DBUG_ASSERT(!normal_tables || !deleted || thd->transaction.stmt.modified_non_trans_table); + DBUG_ASSERT(!normal_tables || !deleted || + thd->transaction.stmt.modified_non_trans_table); if ((local_error == 0) || thd->transaction.stmt.modified_non_trans_table) { if (mysql_bin_log.is_open()) @@ -844,7 +848,7 @@ bool multi_delete::send_eof() if (local_error == 0) thd->clear_error(); Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_tables, FALSE); + transactional_tables, FALSE, killed_status); if (mysql_bin_log.write(&qinfo) && !normal_tables) local_error=1; // Log write failed: roll back the SQL statement } diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index d33e8509eaf..c5f6575b756 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -2936,6 +2936,7 @@ bool select_insert::send_eof() { int error, error2; bool changed, transactional_table= table->file->has_transactions(); + THD::killed_state killed_status= thd->killed; DBUG_ENTER("select_insert::send_eof"); error= (!thd->prelocked_mode) ? table->file->end_bulk_insert():0; @@ -2964,7 +2965,7 @@ bool select_insert::send_eof() if (!error) thd->clear_error(); Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_table, FALSE); + transactional_table, FALSE, killed_status); mysql_bin_log.write(&qinfo); } if ((error2=ha_autocommit_or_rollback(thd,error)) && ! error) diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 0dc02ac4a68..d687ceff393 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -85,7 +85,8 @@ static int read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, #ifndef EMBEDDED_LIBRARY static bool write_execute_load_query_log_event(THD *thd, bool duplicates, bool ignore, - bool transactional_table); + bool transactional_table, + THD::killed_state killed_status); #endif /* EMBEDDED_LIBRARY */ /* @@ -135,6 +136,7 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, char *tdb= thd->db ? thd->db : db; // Result is never null ulong skip_lines= ex->skip_lines; bool transactional_table; + THD::killed_state killed_status= THD::NOT_KILLED; DBUG_ENTER("mysql_load"); #ifdef EMBEDDED_LIBRARY @@ -404,7 +406,16 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, free_blobs(table); /* if pack_blob was used */ table->copy_blobs=0; thd->count_cuted_fields= CHECK_FIELD_IGNORE; - + /* + simulated killing in the middle of per-row loop + must be effective for binlogging + */ + DBUG_EXECUTE_IF("simulate_kill_bug27571", + { + error=1; + thd->killed= THD::KILL_QUERY; + };); + killed_status= (error == 0)? THD::NOT_KILLED : thd->killed; /* We must invalidate the table in query cache before binlog writing and ha_autocommit_... @@ -446,7 +457,8 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, { if (thd->transaction.stmt.modified_non_trans_table) write_execute_load_query_log_event(thd, handle_duplicates, - ignore, transactional_table); + ignore, transactional_table, + killed_status); else { Delete_file_log_event d(thd, db, transactional_table); @@ -477,7 +489,8 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, read_info.end_io_cache(); if (lf_info.wrote_create_file) write_execute_load_query_log_event(thd, handle_duplicates, - ignore, transactional_table); + ignore, transactional_table, + killed_status); } #endif /*!EMBEDDED_LIBRARY*/ if (transactional_table) @@ -504,7 +517,8 @@ err: /* Not a very useful function; just to avoid duplication of code */ static bool write_execute_load_query_log_event(THD *thd, bool duplicates, bool ignore, - bool transactional_table) + bool transactional_table, + THD::killed_state killed_err_arg) { Execute_load_query_log_event e(thd, thd->query, thd->query_length, @@ -512,7 +526,7 @@ static bool write_execute_load_query_log_event(THD *thd, (char*)thd->lex->fname_end - (char*)thd->query, (duplicates == DUP_REPLACE) ? LOAD_DUP_REPLACE : (ignore ? LOAD_DUP_IGNORE : LOAD_DUP_ERROR), - transactional_table, FALSE); + transactional_table, FALSE, killed_err_arg); return mysql_bin_log.write(&e); } diff --git a/sql/sql_update.cc b/sql/sql_update.cc index f3695976508..14c34b6e0f1 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -134,6 +134,7 @@ int mysql_update(THD *thd, SELECT_LEX *select_lex= &thd->lex->select_lex; bool need_reopen; List all_fields; + THD::killed_state killed_status= THD::NOT_KILLED; DBUG_ENTER("mysql_update"); LINT_INIT(timestamp_query_id); @@ -519,43 +520,26 @@ int mysql_update(THD *thd, table->file->unlock_row(); thd->row_count++; } + /* + Caching the killed status to pass as the arg to query event constuctor; + The cached value can not change whereas the killed status can + (externally) since this point and change of the latter won't affect + binlogging. + It's assumed that if an error was set in combination with an effective + killed status then the error is due to killing. + */ + killed_status= thd->killed; // get the status of the volatile + // simulated killing after the loop must be ineffective for binlogging + DBUG_EXECUTE_IF("simulate_kill_bug27571", + { + thd->killed= THD::KILL_QUERY; + };); + error= (killed_status == THD::NOT_KILLED)? error : 1; + if (!transactional_table && updated > 0) thd->transaction.stmt.modified_non_trans_table= TRUE; - - /* - todo bug#27571: to avoid asynchronization of `error' and - `error_code' of binlog event constructor - - The concept, which is a bit different for insert(!), is to - replace `error' assignment with the following lines - - killed_status= thd->killed; // get the status of the volatile - - Notice: thd->killed is type of "state" whereas the lhs has - "status" the suffix which translates according to WordNet: a state - at a particular time - at the time of the end of per-row loop in - our case. Binlogging ops are conducted with the status. - - error= (killed_status == THD::NOT_KILLED)? error : 1; - - which applies to most mysql_$query functions. - Event's constructor will accept `killed_status' as an argument: - - Query_log_event qinfo(..., killed_status); - - thd->killed might be changed after killed_status had got cached and this - won't affect binlogging event but other effects remain. - - Open issue: In a case the error happened not because of KILLED - - and then KILLED was caught later still within the loop - we shall - do something to avoid binlogging of incorrect ER_SERVER_SHUTDOWN - error_code. - */ - - if (thd->killed && !error) - error= 1; // Aborted end_read_record(&info); free_io_cache(table); // If ORDER BY delete select; @@ -587,7 +571,7 @@ int mysql_update(THD *thd, if (error < 0) thd->clear_error(); Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_table, FALSE); + transactional_table, FALSE, killed_status); if (mysql_bin_log.write(&qinfo) && transactional_table) error=1; // Rollback update } @@ -1522,6 +1506,11 @@ void multi_update::send_error(uint errcode,const char *err) */ if (mysql_bin_log.is_open()) { + /* + THD::killed status might not have been set ON at time of an error + got caught and if happens later the killed error is written + into repl event. + */ Query_log_event qinfo(thd, thd->query, thd->query_length, transactional_tables, FALSE); mysql_bin_log.write(&qinfo); @@ -1709,10 +1698,19 @@ err2: bool multi_update::send_eof() { char buff[STRING_BUFFER_USUAL_SIZE]; + THD::killed_state killed_status= THD::NOT_KILLED; thd->proc_info="updating reference tables"; - /* Does updates for the last n - 1 tables, returns 0 if ok */ + /* + Does updates for the last n - 1 tables, returns 0 if ok; + error takes into account killed status gained in do_updates() + */ int local_error = (table_count) ? do_updates(0) : 0; + /* + if local_error is not set ON until after do_updates() then + later carried out killing should not affect binlogging. + */ + killed_status= (local_error == 0)? THD::NOT_KILLED : thd->killed; thd->proc_info= "end"; /* We must invalidate the query cache before binlog writing and @@ -1740,7 +1738,7 @@ bool multi_update::send_eof() if (local_error == 0) thd->clear_error(); Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_tables, FALSE); + transactional_tables, FALSE, killed_status); if (mysql_bin_log.write(&qinfo) && trans_safe) local_error= 1; // Rollback update } From 9d57de144fc58ca230801b517300a39a98c3fcd1 Mon Sep 17 00:00:00 2001 From: "ramil/ram@mysql.com/ramil.myoffice.izhnet.ru" <> Date: Mon, 29 Oct 2007 20:31:03 +0400 Subject: [PATCH 102/336] after-merge fix-up. --- mysql-test/include/mix1.inc | 9 +++++++ mysql-test/r/innodb_mysql.result | 15 +++++++++++ mysql-test/r/key.result | 45 ++++++++++++++++++++++++++++++++ mysql-test/t/key.test | 20 ++++++++++++++ 4 files changed, 89 insertions(+) diff --git a/mysql-test/include/mix1.inc b/mysql-test/include/mix1.inc index aee5613ff35..4d910e86e0f 100644 --- a/mysql-test/include/mix1.inc +++ b/mysql-test/include/mix1.inc @@ -1019,6 +1019,15 @@ SELECT * FROM t1 ORDER BY b DESC, a ASC; DROP TABLE t1; +# +# Bug #31137: Assertion failed: primary_key_no == -1 || primary_key_no == 0 +# +create table t1(a char(10) not null, unique key aa(a(1)), + b char(4) not null, unique key bb(b(4))) engine=innodb; +desc t1; +show create table t1; +drop table t1; + --echo End of 5.0 tests # Fix for BUG#19243 "wrong LAST_INSERT_ID() after ON DUPLICATE KEY diff --git a/mysql-test/r/innodb_mysql.result b/mysql-test/r/innodb_mysql.result index 3a6758b38f4..8f46df311ad 100644 --- a/mysql-test/r/innodb_mysql.result +++ b/mysql-test/r/innodb_mysql.result @@ -1287,6 +1287,21 @@ a b 3 2 1 1 DROP TABLE t1; +create table t1(a char(10) not null, unique key aa(a(1)), +b char(4) not null, unique key bb(b(4))) engine=innodb; +desc t1; +Field Type Null Key Default Extra +a char(10) NO UNI NULL +b char(4) NO PRI NULL +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` char(10) NOT NULL, + `b` char(4) NOT NULL, + UNIQUE KEY `bb` (`b`), + UNIQUE KEY `aa` (`a`(1)) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +drop table t1; End of 5.0 tests CREATE TABLE `t2` ( `k` int(11) NOT NULL auto_increment, diff --git a/mysql-test/r/key.result b/mysql-test/r/key.result index a2bed75a709..a3e63a0bdf4 100644 --- a/mysql-test/r/key.result +++ b/mysql-test/r/key.result @@ -530,3 +530,48 @@ ORDER BY c.b, c.d a b c d e f g h i j a b c d 2 2 1 2004-11-30 12:00:00 1 0 0 0 0 0 2 3388000 -553000 NULL DROP TABLE t1, t2; +create table t1(a int not null, key aa(a), +b char(10) not null, unique key bb(b(1)), +c char(4) not null, unique key cc(c)); +desc t1; +Field Type Null Key Default Extra +a int(11) NO MUL NULL +b char(10) NO UNI NULL +c char(4) NO PRI NULL +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL, + `b` char(10) NOT NULL, + `c` char(4) NOT NULL, + UNIQUE KEY `cc` (`c`), + UNIQUE KEY `bb` (`b`(1)), + KEY `aa` (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create table t1(a int not null, key aa(a), +b char(10) not null, unique key bb(b(1)), +c char(4) not null); +desc t1; +Field Type Null Key Default Extra +a int(11) NO MUL NULL +b char(10) NO UNI NULL +c char(4) NO NULL +alter table t1 add unique key cc(c); +desc t1; +Field Type Null Key Default Extra +a int(11) NO MUL NULL +b char(10) NO UNI NULL +c char(4) NO PRI NULL +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL, + `b` char(10) NOT NULL, + `c` char(4) NOT NULL, + UNIQUE KEY `cc` (`c`), + UNIQUE KEY `bb` (`b`(1)), + KEY `aa` (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +End of 5.0 tests diff --git a/mysql-test/t/key.test b/mysql-test/t/key.test index f1eb8e68b49..f4d99024206 100644 --- a/mysql-test/t/key.test +++ b/mysql-test/t/key.test @@ -501,3 +501,23 @@ ORDER BY c.b, c.d ; DROP TABLE t1, t2; + +# +# Bug #31137: Assertion failed: primary_key_no == -1 || primary_key_no == 0 +# +create table t1(a int not null, key aa(a), + b char(10) not null, unique key bb(b(1)), + c char(4) not null, unique key cc(c)); +desc t1; +show create table t1; +drop table t1; +create table t1(a int not null, key aa(a), + b char(10) not null, unique key bb(b(1)), + c char(4) not null); +desc t1; +alter table t1 add unique key cc(c); +desc t1; +show create table t1; +drop table t1; + +--echo End of 5.0 tests From e93574e9d16efc747a88875325469e2b029e5eb8 Mon Sep 17 00:00:00 2001 From: "holyfoot/hf@mysql.com/hfmain.(none)" <> Date: Tue, 30 Oct 2007 12:35:03 +0400 Subject: [PATCH 103/336] Bug #31758 inet_ntoa, oct crashes server with null+filesort Item_func_inet_ntoa and Item_func_conv inherit 'maybe_null' flag from an argument, which is wrong. Both can be NULL with notnull arguments, so that's fixed. --- mysql-test/r/func_str.result | 18 +++++++++++++++--- mysql-test/t/func_str.test | 13 +++++++++++++ sql/item_strfunc.h | 3 ++- 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index af6a4d20cff..3a429765c98 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -711,9 +711,9 @@ Warning 1265 Data truncated for column 'format(130,10)' at row 1 show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `bin(130)` char(64) NOT NULL default '', - `oct(130)` char(64) NOT NULL default '', - `conv(130,16,10)` char(64) NOT NULL default '', + `bin(130)` char(64) default NULL, + `oct(130)` char(64) default NULL, + `conv(130,16,10)` char(64) default NULL, `hex(130)` char(6) NOT NULL default '', `char(130)` char(1) NOT NULL default '', `format(130,10)` char(4) NOT NULL default '', @@ -1075,5 +1075,17 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 system NULL NULL NULL NULL 0 const row not found Warnings: Note 1003 select decode(test.t1.f1,'zxcv') AS `enc` from test.t1 +drop table t1; +create table t1 (a bigint not null)engine=myisam; +insert into t1 set a = 1024*1024*1024*4; +delete from t1 order by (inet_ntoa(a)) desc limit 10; +drop table t1; +create table t1 (a char(36) not null)engine=myisam; +insert ignore into t1 set a = ' '; +insert ignore into t1 set a = ' '; +select * from t1 order by (oct(a)); +a + + drop table t1; End of 4.1 tests diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index 5897674d1d4..f2991cc3b1d 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -721,4 +721,17 @@ explain extended select encode(f1,'zxcv') as 'enc' from t1; explain extended select decode(f1,'zxcv') as 'enc' from t1; drop table t1; +# +# Bug #31758 inet_ntoa, oct, crashes server with null + filesort +# +create table t1 (a bigint not null)engine=myisam; +insert into t1 set a = 1024*1024*1024*4; +delete from t1 order by (inet_ntoa(a)) desc limit 10; +drop table t1; +create table t1 (a char(36) not null)engine=myisam; +insert ignore into t1 set a = ' '; +insert ignore into t1 set a = ' '; +select * from t1 order by (oct(a)); +drop table t1; + --echo End of 4.1 tests diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 4bd8574ff04..b438ac81763 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -531,6 +531,7 @@ public: { collation.set(default_charset()); decimals=0; max_length=64; + maybe_null= 1; } }; @@ -623,7 +624,7 @@ public: } String* val_str(String* str); const char *func_name() const { return "inet_ntoa"; } - void fix_length_and_dec() { decimals = 0; max_length=3*8+7; } + void fix_length_and_dec() { decimals = 0; max_length=3*8+7; maybe_null=1;} }; class Item_func_quote :public Item_str_func From 38b3b367545e34c7759fa8ee45c78e85765706b0 Mon Sep 17 00:00:00 2001 From: "ramil/ram@mysql.com/ramil.myoffice.izhnet.ru" <> Date: Tue, 30 Oct 2007 12:51:57 +0400 Subject: [PATCH 104/336] Fix for bug #30654: mysqlcheck fails during upgrade of tables whose names include backticks or blank Problem: mysqlcheck doesn't escape backtick characters in the table names. Fix: escape them. --- client/mysqlcheck.c | 52 +++++++++++++++++++++++++--------- mysql-test/r/mysqlcheck.result | 7 ++++- mysql-test/t/mysqlcheck.test | 11 ++++++- 3 files changed, 54 insertions(+), 16 deletions(-) diff --git a/client/mysqlcheck.c b/client/mysqlcheck.c index 8205a83fdf4..3b504eb50b0 100644 --- a/client/mysqlcheck.c +++ b/client/mysqlcheck.c @@ -186,6 +186,7 @@ static void dbDisconnect(char *host); static void DBerror(MYSQL *mysql, const char *when); static void safe_exit(int error); static void print_result(); +static uint fixed_name_length(const char *name); static char *fix_table_name(char *dest, char *src); int what_to_do = 0; @@ -409,14 +410,14 @@ static int process_selected_tables(char *db, char **table_names, int tables) { /* We need table list in form `a`, `b`, `c` - that's why we need 4 more chars added to to each table name + that's why we need 2 more chars added to to each table name space is for more readable output in logs and in case of error */ char *table_names_comma_sep, *end; int i, tot_length = 0; for (i = 0; i < tables; i++) - tot_length += strlen(*(table_names + i)) + 4; + tot_length+= fixed_name_length(*(table_names + i)) + 2; if (!(table_names_comma_sep = (char *) my_malloc((sizeof(char) * tot_length) + 4, MYF(MY_WME)))) @@ -434,23 +435,46 @@ static int process_selected_tables(char *db, char **table_names, int tables) } else for (; tables > 0; tables--, table_names++) - handle_request_for_tables(*table_names, strlen(*table_names)); + handle_request_for_tables(*table_names, fixed_name_length(*table_names)); return 0; } /* process_selected_tables */ +static uint fixed_name_length(const char *name) +{ + const char *p; + uint extra_length= 2; /* count the first/last backticks */ + + for (p= name; *p; p++) + { + if (*p == '`') + extra_length++; + else if (*p == '.') + extra_length+= 2; + } + return (p - name) + extra_length; +} + + static char *fix_table_name(char *dest, char *src) { - char *db_sep; - *dest++= '`'; - if ((db_sep= strchr(src, '.'))) + for (; *src; src++) { - dest= strmake(dest, src, (uint) (db_sep - src)); - dest= strmov(dest, "`.`"); - src= db_sep + 1; + switch (*src) { + case '.': /* add backticks around '.' */ + *dest++= '`'; + *dest++= '.'; + *dest++= '`'; + break; + case '`': /* escape backtick character */ + *dest++= '`'; + /* fall through */ + default: + *dest++= *src; + } } - dest= strxmov(dest, src, "`", NullS); + *dest++= '`'; return dest; } @@ -471,7 +495,7 @@ static int process_all_tables_in_db(char *database) { /* We need table list in form `a`, `b`, `c` - that's why we need 4 more chars added to to each table name + that's why we need 2 more chars added to to each table name space is for more readable output in logs and in case of error */ @@ -479,7 +503,7 @@ static int process_all_tables_in_db(char *database) uint tot_length = 0; while ((row = mysql_fetch_row(res))) - tot_length += strlen(row[0]) + 4; + tot_length+= fixed_name_length(row[0]) + 2; mysql_data_seek(res, 0); if (!(tables=(char *) my_malloc(sizeof(char)*tot_length+4, MYF(MY_WME)))) @@ -507,7 +531,7 @@ static int process_all_tables_in_db(char *database) /* Skip tables with an engine of NULL (probably a view). */ if (row[1]) { - handle_request_for_tables(row[0], strlen(row[0])); + handle_request_for_tables(row[0], fixed_name_length(row[0])); } } mysql_free_result(res); @@ -741,7 +765,7 @@ int main(int argc, char **argv) for (i = 0; i < tables4repair.elements ; i++) { char *name= (char*) dynamic_array_ptr(&tables4repair, i); - handle_request_for_tables(name, strlen(name)); + handle_request_for_tables(name, fixed_name_length(name)); } } end: diff --git a/mysql-test/r/mysqlcheck.result b/mysql-test/r/mysqlcheck.result index b2820df8f4c..f8a28009c42 100644 --- a/mysql-test/r/mysqlcheck.result +++ b/mysql-test/r/mysqlcheck.result @@ -1,4 +1,4 @@ -DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t1, `t``1`, `t 1`; drop view if exists v1; drop database if exists client_test_db; mysql.columns_priv OK @@ -41,4 +41,9 @@ test.t1 OK test.t1 OK drop view v1; drop table t1; +create table `t``1`(a int); +create table `t 1`(a int); +test.t 1 OK +test.t`1 OK +drop table `t``1`, `t 1`; End of 5.0 tests diff --git a/mysql-test/t/mysqlcheck.test b/mysql-test/t/mysqlcheck.test index f4e18d4004f..04e7b6b4bdb 100644 --- a/mysql-test/t/mysqlcheck.test +++ b/mysql-test/t/mysqlcheck.test @@ -2,7 +2,7 @@ # --disable_warnings -DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t1, `t``1`, `t 1`; drop view if exists v1; drop database if exists client_test_db; --enable_warnings @@ -31,4 +31,13 @@ create view v1 as select * from t1; drop view v1; drop table t1; +# +# Bug #30654: mysqlcheck fails during upgrade of tables whose names include backticks +# +create table `t``1`(a int); +create table `t 1`(a int); +--replace_result 'Table is already up to date' OK +--exec $MYSQL_CHECK --databases test +drop table `t``1`, `t 1`; + --echo End of 5.0 tests From cbd3dfbbcb85ffd4c3aecbf238857e9dc0a95be8 Mon Sep 17 00:00:00 2001 From: "svoj@mysql.com/june.mysql.com" <> Date: Tue, 30 Oct 2007 14:46:43 +0400 Subject: [PATCH 105/336] BUG#11392 - fulltext search bug Fulltext boolean mode phrase search may crash server on platforms where size of pointer is not equal to size of unsigned integer (in other words some 64-bit platforms). The problem was integer overflow. Affects 4.1 only. --- myisam/ft_boolean_search.c | 3 ++- mysql-test/r/fulltext.result | 6 ++++++ mysql-test/t/fulltext.test | 8 ++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/myisam/ft_boolean_search.c b/myisam/ft_boolean_search.c index f1ff8f6d886..fad25abcc6c 100644 --- a/myisam/ft_boolean_search.c +++ b/myisam/ft_boolean_search.c @@ -446,7 +446,8 @@ static int _ftb_strstr(const byte *s0, const byte *e0, { if (cs->coll->instr(cs, p0, e0 - p0, s1, e1 - s1, m, 2) != 2) return(0); - if ((!s_after || p0 + m[1].beg == s0 || !true_word_char(cs, p0[m[1].beg-1])) && + if ((!s_after || p0 + m[1].beg == s0 || + !true_word_char(cs, p0[(int) m[1].beg - 1])) && (!e_before || p0 + m[1].end == e0 || !true_word_char(cs, p0[m[1].end]))) return(1); p0+= m[1].beg; diff --git a/mysql-test/r/fulltext.result b/mysql-test/r/fulltext.result index 3700ace4b19..af41adf3a24 100644 --- a/mysql-test/r/fulltext.result +++ b/mysql-test/r/fulltext.result @@ -454,3 +454,9 @@ ALTER TABLE t1 DISABLE KEYS; SELECT * FROM t1 WHERE MATCH(a) AGAINST('test'); ERROR HY000: Can't find FULLTEXT index matching the column list DROP TABLE t1; +CREATE TABLE t1(a TEXT); +INSERT INTO t1 VALUES(' aaaaa aaaa'); +SELECT * FROM t1 WHERE MATCH(a) AGAINST ('"aaaa"' IN BOOLEAN MODE); +a + aaaaa aaaa +DROP TABLE t1; diff --git a/mysql-test/t/fulltext.test b/mysql-test/t/fulltext.test index 1a9a6b578dc..661e93d8d87 100644 --- a/mysql-test/t/fulltext.test +++ b/mysql-test/t/fulltext.test @@ -379,4 +379,12 @@ ALTER TABLE t1 DISABLE KEYS; SELECT * FROM t1 WHERE MATCH(a) AGAINST('test'); DROP TABLE t1; +# +# BUG#11392 - fulltext search bug +# +CREATE TABLE t1(a TEXT); +INSERT INTO t1 VALUES(' aaaaa aaaa'); +SELECT * FROM t1 WHERE MATCH(a) AGAINST ('"aaaa"' IN BOOLEAN MODE); +DROP TABLE t1; + # End of 4.1 tests From 250f5769bf37d5de5c02b25e08567e7814a37f6d Mon Sep 17 00:00:00 2001 From: "istruewing@stella.local" <> Date: Tue, 30 Oct 2007 12:03:44 +0100 Subject: [PATCH 106/336] Post-merge fix --- mysql-test/t/variables.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/t/variables.test b/mysql-test/t/variables.test index f474d166fae..9fa14ba3907 100644 --- a/mysql-test/t/variables.test +++ b/mysql-test/t/variables.test @@ -161,7 +161,7 @@ select * from information_schema.session_variables where variable_name like 'net set net_buffer_length=1; show variables like 'net_buffer_length'; select * from information_schema.session_variables where variable_name like 'net_buffer_length'; ---warning 1292 +#warning 1292 set net_buffer_length=2000000000; show variables like 'net_buffer_length'; select * from information_schema.session_variables where variable_name like 'net_buffer_length'; From 01f86563cb27b6af4ebaea75ef3bac4a9c956cc9 Mon Sep 17 00:00:00 2001 From: "aelkin/elkin@koti.dsl.inet.fi" <> Date: Tue, 30 Oct 2007 13:49:42 +0200 Subject: [PATCH 107/336] Manual merge 5.0-rpl -> 5.1-rpl. involved bug#12691, bug#27571 --- mysql-test/suite/rpl/r/rpl_sp_effects.result | 41 ++++++ sql/slave.cc | 79 ++-------- sql/sql_delete.cc | 25 +--- sql/sql_insert.cc | 26 +--- sql/sql_load.cc | 49 +------ sql/sql_update.cc | 145 ++----------------- 6 files changed, 71 insertions(+), 294 deletions(-) diff --git a/mysql-test/suite/rpl/r/rpl_sp_effects.result b/mysql-test/suite/rpl/r/rpl_sp_effects.result index c2c44b06972..a39d189aa3a 100644 --- a/mysql-test/suite/rpl/r/rpl_sp_effects.result +++ b/mysql-test/suite/rpl/r/rpl_sp_effects.result @@ -235,4 +235,45 @@ drop table t1; drop function f1; drop function f2; drop procedure p1; +create table t2 (b BIT(7)); +create procedure sp_bug26199(bitvalue BIT(7)) +begin +insert into t2 set b = bitvalue; +end // +create function sf_bug26199(b BIT(7)) returns int +begin +insert into t2 values(b); +return 0; +end// +call sp_bug26199(b'1110'); +call sp_bug26199('\0'); +select sf_bug26199(b'1111111'); +sf_bug26199(b'1111111') +0 +select sf_bug26199(b'101111111'); +sf_bug26199(b'101111111') +0 +Warnings: +Warning 1264 Out of range value for column 'b' at row 1 +select sf_bug26199('\''); +sf_bug26199('\'') +0 +select hex(b) from t2; +hex(b) +E +0 +7F +7F +27 +select hex(b) from t2; +hex(b) +E +0 +7F +7F +27 +drop table t2; +drop procedure sp_bug26199; +drop function sf_bug26199; SET GLOBAL log_bin_trust_function_creators = 0; +end of the tests diff --git a/sql/slave.cc b/sql/slave.cc index a3ac0c2f34f..9ea7732aa92 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1804,70 +1804,6 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli) int const type_code= ev->get_type_code(); int exec_res= 0; - /* - */ - -<<<<<<< gca sql/slave.cc 1.241.1.61 - DBUG_PRINT("info",("type_code=%d, server_id=%d",type_code,ev->server_id)); - - if ((ev->server_id == (uint32) ::server_id && - !replicate_same_server_id && - type_code != FORMAT_DESCRIPTION_EVENT) || - (rli->slave_skip_counter && - type_code != ROTATE_EVENT && type_code != STOP_EVENT && - type_code != START_EVENT_V3 && type_code!= FORMAT_DESCRIPTION_EVENT)) - { - DBUG_PRINT("info", ("event skipped")); - if (thd->options & OPTION_BEGIN) - rli->inc_event_relay_log_pos(); - else - { - rli->inc_group_relay_log_pos((type_code == ROTATE_EVENT || - type_code == STOP_EVENT || - type_code == FORMAT_DESCRIPTION_EVENT) ? - LL(0) : ev->log_pos, - 1/* skip lock*/); - flush_relay_log_info(rli); - } - - /* - Protect against common user error of setting the counter to 1 - instead of 2 while recovering from an insert which used auto_increment, - rand or user var. - */ - if (rli->slave_skip_counter && - !((type_code == INTVAR_EVENT || - type_code == RAND_EVENT || - type_code == USER_VAR_EVENT) && - rli->slave_skip_counter == 1) && - /* - The events from ourselves which have something to do with the relay - log itself must be skipped, true, but they mustn't decrement - rli->slave_skip_counter, because the user is supposed to not see - these events (they are not in the master's binlog) and if we - decremented, START SLAVE would for example decrement when it sees - the Rotate, so the event which the user probably wanted to skip - would not be skipped. - */ - !(ev->server_id == (uint32) ::server_id && - (type_code == ROTATE_EVENT || type_code == STOP_EVENT || - type_code == START_EVENT_V3 || type_code == FORMAT_DESCRIPTION_EVENT))) - --rli->slave_skip_counter; - pthread_mutex_unlock(&rli->data_lock); - delete ev; - return 0; // avoid infinite update loops - } - pthread_mutex_unlock(&rli->data_lock); -<<<<<<< local sql/slave.cc 1.321 - DBUG_PRINT("exec_event",("%s(type_code: %d; server_id: %d)", - ev->get_type_str(), type_code, ev->server_id)); - DBUG_PRINT("info", ("thd->options: %s%s; rli->last_event_start_time: %lu", - FLAGSTR(thd->options, OPTION_NOT_AUTOCOMMIT), - FLAGSTR(thd->options, OPTION_BEGIN), - rli->last_event_start_time)); - - - /* Execute the event to change the database and update the binary log coordinates, but first we set some data that is needed for @@ -1891,10 +1827,15 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli) log (remember that now the relay log starts with its Format_desc, has a Rotate etc). */ -<<<<<<< remote sql/slave.cc 1.241.1.62 + DBUG_PRINT("info",("type_code: %d; server_id: %d; slave_skip_counter: %d", type_code, ev->server_id, rli->slave_skip_counter)); + DBUG_PRINT("info", ("thd->options: %s%s; rli->last_event_start_time: %lu", + FLAGSTR(thd->options, OPTION_NOT_AUTOCOMMIT), + FLAGSTR(thd->options, OPTION_BEGIN), + rli->last_event_start_time)); + /* If the slave skip counter is positive, we still need to set the OPTION_BEGIN flag correctly and not skip the log events that @@ -1951,7 +1892,7 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli) } DBUG_PRINT("info", ("thd->options: %s", - (thd->options & OPTION_BEGIN) ? "OPTION_BEGIN" : "")) + (thd->options & OPTION_BEGIN) ? "OPTION_BEGIN" : "")); /* Protect against common user error of setting the counter to 1 @@ -1991,8 +1932,6 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli) delete ev; return 0; // avoid infinite update loops } - pthread_mutex_unlock(&rli->data_lock); ->>>>>>> thd->server_id = ev->server_id; // use the original server id for logging thd->set_time(); // time the query @@ -2132,7 +2071,7 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli) non-transient error, the slave will stop with an error. */ rli->trans_retries= 0; // restart from fresh - DBUG_PRINT("info", ("Resetting retry counter, rli->trans_retries: %d", + DBUG_PRINT("info", ("Resetting retry counter, rli->trans_retries: %lu", rli->trans_retries)); } } @@ -2622,7 +2561,7 @@ pthread_handler_t handle_slave_sql(void *arg) rli->ignore_log_space_limit= 0; pthread_mutex_unlock(&rli->log_space_lock); rli->trans_retries= 0; // start from "no error" - DBUG_PRINT("info", ("rli->trans_retries: %d", rli->trans_retries)); + DBUG_PRINT("info", ("rli->trans_retries: %lu", rli->trans_retries)); if (init_relay_log_pos(rli, rli->group_relay_log_name, diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 33d19852371..81bfaadd4ce 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -352,12 +352,6 @@ cleanup: { if (error < 0) thd->clear_error(); -<<<<<<< gca sql/sql_delete.cc 1.144.1.57 - Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_table, FALSE); - if (mysql_bin_log.write(&qinfo) && transactional_table) -<<<<<<< local sql/sql_delete.cc 1.230 - /* [binlog]: If 'handler::delete_all_rows()' was called and the storage engine does not inject the rows itself, we replicate @@ -366,15 +360,10 @@ cleanup: */ int log_result= thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query, thd->query_length, - transactional_table, FALSE); + transactional_table, FALSE, killed_status); if (log_result && transactional_table) { -<<<<<<< remote sql/sql_delete.cc 1.144.1.58 - Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_table, FALSE, killed_status); - if (mysql_bin_log.write(&qinfo) && transactional_table) ->>>>>>> error=1; } } @@ -902,21 +891,11 @@ bool multi_delete::send_eof() { if (local_error == 0) thd->clear_error(); -<<<<<<< gca sql/sql_delete.cc 1.144.1.57 - Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_tables, FALSE); - if (mysql_bin_log.write(&qinfo) && !normal_tables) -<<<<<<< local sql/sql_delete.cc 1.230 if (thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query, thd->query_length, - transactional_tables, FALSE) && + transactional_tables, FALSE, killed_status) && !normal_tables) { -<<<<<<< remote sql/sql_delete.cc 1.144.1.58 - Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_tables, FALSE, killed_status); - if (mysql_bin_log.write(&qinfo) && !normal_tables) ->>>>>>> local_error=1; // Log write failed: roll back the SQL statement } } diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index a631a82be1e..2f255b82fde 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -3084,19 +3084,11 @@ void select_insert::send_error(uint errcode,const char *err) bool select_insert::send_eof() { -<<<<<<< gca sql/sql_insert.cc 1.146.1.105 - int error, error2; - bool changed, transactional_table= table->file->has_transactions(); -<<<<<<< local sql/sql_insert.cc 1.300 int error; bool const trans_table= table->file->has_transactions(); ulonglong id; bool changed; -<<<<<<< remote sql/sql_insert.cc 1.146.1.106 - int error, error2; - bool changed, transactional_table= table->file->has_transactions(); THD::killed_state killed_status= thd->killed; ->>>>>>> DBUG_ENTER("select_insert::send_eof"); DBUG_PRINT("enter", ("trans_table=%d, table_type='%s'", trans_table, table->file->table_type())); @@ -3129,17 +3121,9 @@ bool select_insert::send_eof() { if (!error) thd->clear_error(); -<<<<<<< gca sql/sql_insert.cc 1.146.1.105 - Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_table, FALSE); - mysql_bin_log.write(&qinfo); - } - if ((error2=ha_autocommit_or_rollback(thd,error)) && ! error) - error=error2; -<<<<<<< local sql/sql_insert.cc 1.300 thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query, thd->query_length, - trans_table, FALSE); + trans_table, FALSE, killed_status); } /* We will call ha_autocommit_or_rollback() also for @@ -3155,14 +3139,6 @@ bool select_insert::send_eof() } table->file->ha_release_auto_increment(); -<<<<<<< remote sql/sql_insert.cc 1.146.1.106 - Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_table, FALSE, killed_status); - mysql_bin_log.write(&qinfo); - } - if ((error2=ha_autocommit_or_rollback(thd,error)) && ! error) - error=error2; ->>>>>>> if (error) { table->file->print_error(error,MYF(0)); diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 3a4df7ccc9b..c96fbb80b0c 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -430,12 +430,6 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, if (mysql_bin_log.is_open()) { { -<<<<<<< gca sql/sql_load.cc 1.78.1.39 - if (thd->transaction.stmt.modified_non_trans_table) - write_execute_load_query_log_event(thd, handle_duplicates, - ignore, transactional_table); - else -<<<<<<< local sql/sql_load.cc 1.131 /* Make sure last block (the one which caused the error) gets logged. This is needed because otherwise after write of (to @@ -461,17 +455,11 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, read_info.end_io_cache(); /* If the file was not empty, wrote_create_file is true */ if (lf_info.wrote_create_file) -<<<<<<< remote sql/sql_load.cc 1.78.1.40 - if (thd->transaction.stmt.modified_non_trans_table) - write_execute_load_query_log_event(thd, handle_duplicates, - ignore, transactional_table, - killed_status); - else ->>>>>>> { if (thd->transaction.stmt.modified_non_trans_table) write_execute_load_query_log_event(thd, handle_duplicates, - ignore, transactional_table); + ignore, transactional_table, + killed_status); else { Delete_file_log_event d(thd, db, transactional_table); @@ -497,16 +485,6 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, if (mysql_bin_log.is_open()) { /* -<<<<<<< gca sql/sql_load.cc 1.78.1.39 - As already explained above, we need to call end_io_cache() or the last - block will be logged only after Execute_load_query_log_event (which is - wrong), when read_info is destroyed. - */ - read_info.end_io_cache(); - if (lf_info.wrote_create_file) - write_execute_load_query_log_event(thd, handle_duplicates, - ignore, transactional_table); -<<<<<<< local sql/sql_load.cc 1.131 We need to do the job that is normally done inside binlog_query() here, which is to ensure that the pending event is written before tables are unlocked and before any other @@ -526,21 +504,10 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, read_info.end_io_cache(); if (lf_info.wrote_create_file) { - write_execute_load_query_log_event(thd, handle_duplicates, - ignore, transactional_table); + write_execute_load_query_log_event(thd, handle_duplicates, ignore, + transactional_table,killed_status); } } -<<<<<<< remote sql/sql_load.cc 1.78.1.40 - As already explained above, we need to call end_io_cache() or the last - block will be logged only after Execute_load_query_log_event (which is - wrong), when read_info is destroyed. - */ - read_info.end_io_cache(); - if (lf_info.wrote_create_file) - write_execute_load_query_log_event(thd, handle_duplicates, - ignore, transactional_table, - killed_status); ->>>>>>> } #endif /*!EMBEDDED_LIBRARY*/ if (transactional_table) @@ -577,14 +544,8 @@ static bool write_execute_load_query_log_event(THD *thd, (char*)thd->lex->fname_end - (char*)thd->query, (duplicates == DUP_REPLACE) ? LOAD_DUP_REPLACE : (ignore ? LOAD_DUP_IGNORE : LOAD_DUP_ERROR), -<<<<<<< gca sql/sql_load.cc 1.78.1.39 - transactional_table, FALSE); -<<<<<<< local sql/sql_load.cc 1.131 - transactional_table, FALSE); - e.flags|= LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F; -<<<<<<< remote sql/sql_load.cc 1.78.1.40 transactional_table, FALSE, killed_err_arg); ->>>>>>> + e.flags|= LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F; return mysql_bin_log.write(&e); } diff --git a/sql/sql_update.cc b/sql/sql_update.cc index f07437f044f..6f7719b5127 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -200,18 +200,10 @@ int mysql_update(THD *thd, SQL_SELECT *select; READ_RECORD info; SELECT_LEX *select_lex= &thd->lex->select_lex; -<<<<<<< gca sql/sql_update.cc 1.154.2.70 - bool need_reopen; - List all_fields; -<<<<<<< local sql/sql_update.cc 1.258 bool need_reopen; ulonglong id; List all_fields; -<<<<<<< remote sql/sql_update.cc 1.154.2.71 - bool need_reopen; - List all_fields; THD::killed_state killed_status= THD::NOT_KILLED; ->>>>>>> DBUG_ENTER("mysql_update"); for ( ; ; ) @@ -722,10 +714,7 @@ int mysql_update(THD *thd, table->file->unlock_row(); thd->row_count++; } -<<<<<<< gca sql/sql_update.cc 1.154.2.70 -<<<<<<< local sql/sql_update.cc 1.258 dup_key_found= 0; -<<<<<<< remote sql/sql_update.cc 1.154.2.71 /* Caching the killed status to pass as the arg to query event constuctor; The cached value can not change whereas the killed status can @@ -742,81 +731,9 @@ int mysql_update(THD *thd, };); error= (killed_status == THD::NOT_KILLED)? error : 1; ->>>>>>> - - if (!transactional_table && updated > 0) - thd->transaction.stmt.modified_non_trans_table= TRUE; - -<<<<<<< gca sql/sql_update.cc 1.154.2.70 - - /* - todo bug#27571: to avoid asynchronization of `error' and - `error_code' of binlog event constructor - - The concept, which is a bit different for insert(!), is to - replace `error' assignment with the following lines - - killed_status= thd->killed; // get the status of the volatile - - Notice: thd->killed is type of "state" whereas the lhs has - "status" the suffix which translates according to WordNet: a state - at a particular time - at the time of the end of per-row loop in - our case. Binlogging ops are conducted with the status. - - error= (killed_status == THD::NOT_KILLED)? error : 1; - - which applies to most mysql_$query functions. - Event's constructor will accept `killed_status' as an argument: - - Query_log_event qinfo(..., killed_status); - - thd->killed might be changed after killed_status had got cached and this - won't affect binlogging event but other effects remain. - - Open issue: In a case the error happened not because of KILLED - - and then KILLED was caught later still within the loop - we shall - do something to avoid binlogging of incorrect ER_SERVER_SHUTDOWN - error_code. - */ - - if (thd->killed && !error) - error= 1; // Aborted -<<<<<<< local sql/sql_update.cc 1.258 - - /* - todo bug#27571: to avoid asynchronization of `error' and - `error_code' of binlog event constructor - - The concept, which is a bit different for insert(!), is to - replace `error' assignment with the following lines - - killed_status= thd->killed; // get the status of the volatile - - Notice: thd->killed is type of "state" whereas the lhs has - "status" the suffix which translates according to WordNet: a state - at a particular time - at the time of the end of per-row loop in - our case. Binlogging ops are conducted with the status. - - error= (killed_status == THD::NOT_KILLED)? error : 1; - - which applies to most mysql_$query functions. - Event's constructor will accept `killed_status' as an argument: - - Query_log_event qinfo(..., killed_status); - - thd->killed might be changed after killed_status had got cached and this - won't affect binlogging event but other effects remain. - - Open issue: In a case the error happened not because of KILLED - - and then KILLED was caught later still within the loop - we shall - do something to avoid binlogging of incorrect ER_SERVER_SHUTDOWN - error_code. - */ - - if (thd->killed && !error) - error= 1; // Aborted - else if (will_batch && - (loc_error= table->file->exec_bulk_update(&dup_key_found))) + if (error && + will_batch && + (loc_error= table->file->exec_bulk_update(&dup_key_found))) /* An error has occurred when a batched update was performed and returned an error indication. It cannot be an allowed duplicate key error since @@ -838,8 +755,10 @@ int mysql_update(THD *thd, if (will_batch) table->file->end_bulk_update(); table->file->try_semi_consistent_read(0); -<<<<<<< remote sql/sql_update.cc 1.154.2.71 ->>>>>>> + + if (!transactional_table && updated > 0) + thd->transaction.stmt.modified_non_trans_table= TRUE; + end_read_record(&info); delete select; thd->proc_info= "end"; @@ -869,25 +788,13 @@ int mysql_update(THD *thd, { if (error < 0) thd->clear_error(); -<<<<<<< gca sql/sql_update.cc 1.154.2.70 - Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_table, FALSE); - if (mysql_bin_log.write(&qinfo) && transactional_table) - error=1; // Rollback update -<<<<<<< local sql/sql_update.cc 1.258 if (thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query, thd->query_length, - transactional_table, FALSE) && + transactional_table, FALSE, killed_status) && transactional_table) { error=1; // Rollback update } -<<<<<<< remote sql/sql_update.cc 1.154.2.71 - Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_table, FALSE, killed_status); - if (mysql_bin_log.write(&qinfo) && transactional_table) - error=1; // Rollback update ->>>>>>> } if (thd->transaction.stmt.modified_non_trans_table) thd->transaction.all.modified_non_trans_table= TRUE; @@ -1829,24 +1736,14 @@ void multi_update::send_error(uint errcode,const char *err) */ if (mysql_bin_log.is_open()) { -<<<<<<< gca sql/sql_update.cc 1.154.2.70 - Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_tables, FALSE); - mysql_bin_log.write(&qinfo); -<<<<<<< local sql/sql_update.cc 1.258 - thd->binlog_query(THD::ROW_QUERY_TYPE, - thd->query, thd->query_length, - transactional_tables, FALSE); -<<<<<<< remote sql/sql_update.cc 1.154.2.71 /* THD::killed status might not have been set ON at time of an error got caught and if happens later the killed error is written into repl event. */ - Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_tables, FALSE); - mysql_bin_log.write(&qinfo); ->>>>>>> + thd->binlog_query(THD::ROW_QUERY_TYPE, + thd->query, thd->query_length, + transactional_tables, FALSE); } thd->transaction.all.modified_non_trans_table= TRUE; } @@ -2039,13 +1936,9 @@ err2: bool multi_update::send_eof() { char buff[STRING_BUFFER_USUAL_SIZE]; -<<<<<<< gca sql/sql_update.cc 1.154.2.70 -<<<<<<< local sql/sql_update.cc 1.258 ulonglong id; - DBUG_ENTER("multi_update::send_eof"); -<<<<<<< remote sql/sql_update.cc 1.154.2.71 THD::killed_state killed_status= THD::NOT_KILLED; ->>>>>>> + DBUG_ENTER("multi_update::send_eof"); thd->proc_info="updating reference tables"; /* @@ -2084,25 +1977,13 @@ bool multi_update::send_eof() { if (local_error == 0) thd->clear_error(); -<<<<<<< gca sql/sql_update.cc 1.154.2.70 - Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_tables, FALSE); - if (mysql_bin_log.write(&qinfo) && trans_safe) - local_error= 1; // Rollback update -<<<<<<< local sql/sql_update.cc 1.258 if (thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query, thd->query_length, - transactional_tables, FALSE) && + transactional_tables, FALSE, killed_status) && trans_safe) { local_error= 1; // Rollback update } -<<<<<<< remote sql/sql_update.cc 1.154.2.71 - Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_tables, FALSE, killed_status); - if (mysql_bin_log.write(&qinfo) && trans_safe) - local_error= 1; // Rollback update ->>>>>>> } if (thd->transaction.stmt.modified_non_trans_table) thd->transaction.all.modified_non_trans_table= TRUE; From 01fe24cd68bfd00183745df215c98175bf898afe Mon Sep 17 00:00:00 2001 From: "gkodinov/kgeorge@magare.gmz" <> Date: Tue, 30 Oct 2007 14:27:21 +0200 Subject: [PATCH 108/336] Bug #31884: Assertion + crash in subquery in the SELECT clause. Item_in_subselect's only externally callable method is val_bool(). However the nullability in the wrapper class (Item_in_optimizer) is established by calling the "forbidden" method val_int(). Fixed to use the correct method (val_bool() ) to establish nullability of Item_in_subselect in Item_in_optimizer. --- mysql-test/r/subselect.result | 11 +++++++++++ mysql-test/t/subselect.test | 15 +++++++++++++++ sql/item_subselect.h | 1 + 3 files changed, 27 insertions(+) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index be99bdb1afc..bfacfc86eef 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -4139,4 +4139,15 @@ SELECT (SELECT SUM(t1.a) FROM t2 WHERE a=1) FROM t1; (SELECT SUM(t1.a) FROM t2 WHERE a=1) 3 DROP TABLE t1,t2; +CREATE TABLE t1 (a1 INT, a2 INT); +CREATE TABLE t2 (b1 INT, b2 INT); +INSERT INTO t1 VALUES (100, 200); +INSERT INTO t1 VALUES (101, 201); +INSERT INTO t2 VALUES (101, 201); +INSERT INTO t2 VALUES (103, 203); +SELECT ((a1,a2) IN (SELECT * FROM t2 WHERE b2 > 0)) IS NULL FROM t1; +((a1,a2) IN (SELECT * FROM t2 WHERE b2 > 0)) IS NULL +0 +0 +DROP TABLE t1, t2; End of 5.0 tests. diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index d076ca6bd33..b5279331a5f 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -2987,4 +2987,19 @@ SELECT (SELECT SUM(t1.a) FROM t2 WHERE a!=0) FROM t1; SELECT (SELECT SUM(t1.a) FROM t2 WHERE a=1) FROM t1; DROP TABLE t1,t2; +# +# Bug #31884: Assertion + crash in subquery in the SELECT clause. +# + +CREATE TABLE t1 (a1 INT, a2 INT); +CREATE TABLE t2 (b1 INT, b2 INT); + +INSERT INTO t1 VALUES (100, 200); +INSERT INTO t1 VALUES (101, 201); +INSERT INTO t2 VALUES (101, 201); +INSERT INTO t2 VALUES (103, 203); + +SELECT ((a1,a2) IN (SELECT * FROM t2 WHERE b2 > 0)) IS NULL FROM t1; +DROP TABLE t1, t2; + --echo End of 5.0 tests. diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 118609671b8..51dcd3ca175 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -306,6 +306,7 @@ public: double val_real(); String *val_str(String*); my_decimal *val_decimal(my_decimal *); + void update_null_value () { (void) val_bool(); } bool val_bool(); void top_level_item() { abort_on_null=1; } inline bool is_top_level_item() { return abort_on_null; } From c2b0410ca193567138b8285a8067feef46dc16f5 Mon Sep 17 00:00:00 2001 From: "aelkin@dl145j.mysql.com" <> Date: Tue, 30 Oct 2007 14:08:37 +0100 Subject: [PATCH 109/336] manual merge --- mysql-test/r/rpl_slave_skip.result | 144 ------------------ mysql-test/t/rpl_slave_skip-slave.opt | 1 - mysql-test/t/rpl_slave_skip.test | 203 -------------------------- sql/slave.cc | 113 +------------- 4 files changed, 8 insertions(+), 453 deletions(-) delete mode 100644 mysql-test/r/rpl_slave_skip.result delete mode 100644 mysql-test/t/rpl_slave_skip-slave.opt delete mode 100644 mysql-test/t/rpl_slave_skip.test diff --git a/mysql-test/r/rpl_slave_skip.result b/mysql-test/r/rpl_slave_skip.result deleted file mode 100644 index a59ac3eb884..00000000000 --- a/mysql-test/r/rpl_slave_skip.result +++ /dev/null @@ -1,144 +0,0 @@ -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; -**** On Master **** -CREATE TABLE t1 (a INT, b SET('master','slave')) ENGINE=INNODB; -CREATE TABLE t2 (a INT, b SET('master','slave')) ENGINE=MYISAM; -==== Skipping normal transactions ==== -**** On Slave **** -STOP SLAVE; -**** On Master **** -BEGIN; -INSERT INTO t1 VALUES (1, 'master'); -INSERT INTO t1 VALUES (2, 'master'); -INSERT INTO t1 VALUES (3, 'master'); -COMMIT; -BEGIN; -INSERT INTO t1 VALUES (4, 'master,slave'); -INSERT INTO t1 VALUES (5, 'master,slave'); -INSERT INTO t1 VALUES (6, 'master,slave'); -COMMIT; -SELECT * FROM t1 ORDER BY a; -a b -1 master -2 master -3 master -4 master,slave -5 master,slave -6 master,slave -**** On Slave **** -SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; -START SLAVE; -SELECT * FROM t1 ORDER BY a; -a b -4 master,slave -5 master,slave -6 master,slave -**** On Master **** -DELETE FROM t1; -==== Skipping two normal transactions ==== -**** On Slave **** -STOP SLAVE; -**** On Master **** -BEGIN; -INSERT INTO t1 VALUES (1, 'master'); -INSERT INTO t1 VALUES (2, 'master'); -INSERT INTO t1 VALUES (3, 'master'); -COMMIT; -BEGIN; -INSERT INTO t1 VALUES (4, 'master'); -INSERT INTO t1 VALUES (5, 'master'); -INSERT INTO t1 VALUES (6, 'master'); -COMMIT; -BEGIN; -INSERT INTO t1 VALUES (7, 'master,slave'); -INSERT INTO t1 VALUES (8, 'master,slave'); -INSERT INTO t1 VALUES (9, 'master,slave'); -COMMIT; -SELECT * FROM t1 ORDER BY a; -a b -1 master -2 master -3 master -4 master -5 master -6 master -7 master,slave -8 master,slave -9 master,slave -**** On Slave **** -SET GLOBAL SQL_SLAVE_SKIP_COUNTER=8; -START SLAVE; -SELECT * FROM t1 ORDER BY a; -a b -7 master,slave -8 master,slave -9 master,slave -**** On Master **** -DELETE FROM t1; -==== Skipping without autocommit ==== -**** On Slave **** -STOP SLAVE; -**** On Master **** -SET AUTOCOMMIT=0; -INSERT INTO t1 VALUES (1, 'master'); -INSERT INTO t1 VALUES (2, 'master'); -INSERT INTO t1 VALUES (3, 'master'); -COMMIT; -INSERT INTO t1 VALUES (4, 'master,slave'); -INSERT INTO t1 VALUES (5, 'master,slave'); -INSERT INTO t1 VALUES (6, 'master,slave'); -COMMIT; -SELECT * FROM t1 ORDER BY a; -a b -1 master -2 master -3 master -4 master,slave -5 master,slave -6 master,slave -**** On Slave **** -SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; -START SLAVE; -SELECT * FROM t1 ORDER BY a; -a b -4 master,slave -5 master,slave -6 master,slave -==== Rollback of transaction with non-transactional change ==== -**** On Master **** -DELETE FROM t1; -SET AUTOCOMMIT=1; -**** On Slave **** -STOP SLAVE; -**** On Master **** -BEGIN; -INSERT INTO t1 VALUES (1, ''); -INSERT INTO t2 VALUES (2, 'master'); -INSERT INTO t1 VALUES (3, ''); -ROLLBACK; -BEGIN; -INSERT INTO t1 VALUES (4, ''); -INSERT INTO t2 VALUES (5, 'master,slave'); -INSERT INTO t1 VALUES (6, ''); -ROLLBACK; -SELECT * FROM t1 ORDER BY a; -a b -SELECT * FROM t2 ORDER BY a; -a b -2 master -5 master,slave -**** On Slave **** -SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; -START SLAVE; -SELECT * FROM t1 ORDER BY a; -a b -SELECT * FROM t2 ORDER BY a; -a b -5 master,slave -==== Cleanup ==== -**** On Master **** -DROP TABLE t1, t2; diff --git a/mysql-test/t/rpl_slave_skip-slave.opt b/mysql-test/t/rpl_slave_skip-slave.opt deleted file mode 100644 index 627becdbfb5..00000000000 --- a/mysql-test/t/rpl_slave_skip-slave.opt +++ /dev/null @@ -1 +0,0 @@ ---innodb diff --git a/mysql-test/t/rpl_slave_skip.test b/mysql-test/t/rpl_slave_skip.test deleted file mode 100644 index 04aafc51129..00000000000 --- a/mysql-test/t/rpl_slave_skip.test +++ /dev/null @@ -1,203 +0,0 @@ -source include/have_innodb.inc; -source include/master-slave.inc; - -# This test is for checking that the use of SQL_SLAVE_SKIP_COUNTER -# behaves as expected, i.e., that it is guaranteed to skip an entire -# group and not start executing in the middle of a transaction. - -# We are checking the correct behaviour when using both a -# transactional and non-transactional table. The non-transactional -# table comes into play when rolling back a transaction containing a -# write to this table. In that case, the transaction should still be -# written to the binary log, and the slave will apply it and then roll -# it back to get the non-transactional change into the table. - ---echo **** On Master **** -CREATE TABLE t1 (a INT, b SET('master','slave')) ENGINE=INNODB; -CREATE TABLE t2 (a INT, b SET('master','slave')) ENGINE=MYISAM; - ---echo ==== Skipping normal transactions ==== - ---echo **** On Slave **** -sync_slave_with_master; -STOP SLAVE; -source include/wait_for_slave_to_stop.inc; - ---echo **** On Master **** -connection master; - -BEGIN; -INSERT INTO t1 VALUES (1, 'master'); -INSERT INTO t1 VALUES (2, 'master'); -INSERT INTO t1 VALUES (3, 'master'); -COMMIT; - -BEGIN; -INSERT INTO t1 VALUES (4, 'master,slave'); -INSERT INTO t1 VALUES (5, 'master,slave'); -INSERT INTO t1 VALUES (6, 'master,slave'); -COMMIT; - -save_master_pos; - -SELECT * FROM t1 ORDER BY a; - -# This will skip a begin event and the first INSERT of the -# transaction, and it should keep skipping until it has reached the -# transaction terminator. - ---echo **** On Slave **** -connection slave; -SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; -START SLAVE; -source include/wait_for_slave_to_start.inc; -sync_with_master; -SELECT * FROM t1 ORDER BY a; - ---echo **** On Master **** -connection master; -DELETE FROM t1; -sync_slave_with_master; - ---echo ==== Skipping two normal transactions ==== - ---echo **** On Slave **** -connection slave; -STOP SLAVE; -source include/wait_for_slave_to_stop.inc; - ---echo **** On Master **** -connection master; - -BEGIN; -INSERT INTO t1 VALUES (1, 'master'); -INSERT INTO t1 VALUES (2, 'master'); -INSERT INTO t1 VALUES (3, 'master'); -COMMIT; - -BEGIN; -INSERT INTO t1 VALUES (4, 'master'); -INSERT INTO t1 VALUES (5, 'master'); -INSERT INTO t1 VALUES (6, 'master'); -COMMIT; - -BEGIN; -INSERT INTO t1 VALUES (7, 'master,slave'); -INSERT INTO t1 VALUES (8, 'master,slave'); -INSERT INTO t1 VALUES (9, 'master,slave'); -COMMIT; - -save_master_pos; - -SELECT * FROM t1 ORDER BY a; - -# This will skip a begin event and the first INSERT of the -# transaction, and it should keep skipping until it has reached the -# transaction terminator. - ---echo **** On Slave **** -connection slave; -SET GLOBAL SQL_SLAVE_SKIP_COUNTER=8; -START SLAVE; -source include/wait_for_slave_to_start.inc; -sync_with_master; -SELECT * FROM t1 ORDER BY a; - ---echo **** On Master **** -connection master; -DELETE FROM t1; -sync_slave_with_master; - ---echo ==== Skipping without autocommit ==== - -# Testing without using autocommit instead. It should still write a -# BEGIN event, so the behaviour should be the same - ---echo **** On Slave **** -connection slave; -STOP SLAVE; -source include/wait_for_slave_to_stop.inc; - ---echo **** On Master **** -connection master; -SET AUTOCOMMIT=0; - -INSERT INTO t1 VALUES (1, 'master'); -INSERT INTO t1 VALUES (2, 'master'); -INSERT INTO t1 VALUES (3, 'master'); -COMMIT; - -INSERT INTO t1 VALUES (4, 'master,slave'); -INSERT INTO t1 VALUES (5, 'master,slave'); -INSERT INTO t1 VALUES (6, 'master,slave'); -COMMIT; - -save_master_pos; - -SELECT * FROM t1 ORDER BY a; - -# This will skip a begin event and the first INSERT of the -# transaction, and it should keep skipping until it has reached the -# transaction terminator. - ---echo **** On Slave **** -connection slave; -SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; -START SLAVE; -source include/wait_for_slave_to_start.inc; -sync_with_master; -SELECT * FROM t1 ORDER BY a; - -# Testing with a non-transactional table in the transaction. This will -# log a ROLLBACK as a transaction terminator, which is a normal Query -# log event. - ---echo ==== Rollback of transaction with non-transactional change ==== - ---echo **** On Master **** -connection master; -DELETE FROM t1; -SET AUTOCOMMIT=1; - ---echo **** On Slave **** -sync_slave_with_master; -STOP SLAVE; -source include/wait_for_slave_to_stop.inc; - ---echo **** On Master **** -connection master; -disable_warnings; -BEGIN; -INSERT INTO t1 VALUES (1, ''); -INSERT INTO t2 VALUES (2, 'master'); -INSERT INTO t1 VALUES (3, ''); -ROLLBACK; - -BEGIN; -INSERT INTO t1 VALUES (4, ''); -INSERT INTO t2 VALUES (5, 'master,slave'); -INSERT INTO t1 VALUES (6, ''); -ROLLBACK; -enable_warnings; - -save_master_pos; - -SELECT * FROM t1 ORDER BY a; -SELECT * FROM t2 ORDER BY a; - ---echo **** On Slave **** -connection slave; -SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; -START SLAVE; -source include/wait_for_slave_to_start.inc; -sync_with_master; - -SELECT * FROM t1 ORDER BY a; -SELECT * FROM t2 ORDER BY a; - ---echo ==== Cleanup ==== - ---echo **** On Master **** -connection master; -DROP TABLE t1, t2; -sync_slave_with_master; diff --git a/sql/slave.cc b/sql/slave.cc index 9ea7732aa92..79437dda67f 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1804,6 +1804,14 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli) int const type_code= ev->get_type_code(); int exec_res= 0; + DBUG_PRINT("exec_event",("%s(type_code: %d; server_id: %d)", + ev->get_type_str(), type_code, ev->server_id)); + DBUG_PRINT("info", ("thd->options: %s%s; rli->last_event_start_time: %lu", + FLAGSTR(thd->options, OPTION_NOT_AUTOCOMMIT), + FLAGSTR(thd->options, OPTION_BEGIN), + rli->last_event_start_time)); + + /* Execute the event to change the database and update the binary log coordinates, but first we set some data that is needed for @@ -1828,111 +1836,6 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli) has a Rotate etc). */ - DBUG_PRINT("info",("type_code: %d; server_id: %d; slave_skip_counter: %d", - type_code, ev->server_id, rli->slave_skip_counter)); - - DBUG_PRINT("info", ("thd->options: %s%s; rli->last_event_start_time: %lu", - FLAGSTR(thd->options, OPTION_NOT_AUTOCOMMIT), - FLAGSTR(thd->options, OPTION_BEGIN), - rli->last_event_start_time)); - - /* - If the slave skip counter is positive, we still need to set the - OPTION_BEGIN flag correctly and not skip the log events that - start or end a transaction. If we do this, the slave will not - notice that it is inside a transaction, and happily start - executing from inside the transaction. - - Note that the code block below is strictly 5.0. - */ -#if MYSQL_VERSION_ID < 50100 - if (unlikely(rli->slave_skip_counter > 0)) - { - switch (type_code) - { - case QUERY_EVENT: - { - Query_log_event* const qev= (Query_log_event*) ev; - DBUG_PRINT("info", ("QUERY_EVENT { query: '%s', q_len: %u }", - qev->query, qev->q_len)); - if (memcmp("BEGIN", qev->query, qev->q_len+1) == 0) - thd->options|= OPTION_BEGIN; - else if (memcmp("COMMIT", qev->query, qev->q_len+1) == 0 || - memcmp("ROLLBACK", qev->query, qev->q_len+1) == 0) - thd->options&= ~OPTION_BEGIN; - } - break; - - case XID_EVENT: - DBUG_PRINT("info", ("XID_EVENT")); - thd->options&= ~OPTION_BEGIN; - break; - } - } -#endif - - if ((ev->server_id == (uint32) ::server_id && - !replicate_same_server_id && - type_code != FORMAT_DESCRIPTION_EVENT) || - (rli->slave_skip_counter && - type_code != ROTATE_EVENT && type_code != STOP_EVENT && - type_code != START_EVENT_V3 && type_code!= FORMAT_DESCRIPTION_EVENT)) - { - DBUG_PRINT("info", ("event skipped")); - if (thd->options & OPTION_BEGIN) - rli->inc_event_relay_log_pos(); - else - { - rli->inc_group_relay_log_pos((type_code == ROTATE_EVENT || - type_code == STOP_EVENT || - type_code == FORMAT_DESCRIPTION_EVENT) ? - LL(0) : ev->log_pos, - 1/* skip lock*/); - flush_relay_log_info(rli); - } - - DBUG_PRINT("info", ("thd->options: %s", - (thd->options & OPTION_BEGIN) ? "OPTION_BEGIN" : "")); - - /* - Protect against common user error of setting the counter to 1 - instead of 2 while recovering from an insert which used auto_increment, - rand or user var. - */ - if (rli->slave_skip_counter && - !((type_code == INTVAR_EVENT || - type_code == RAND_EVENT || - type_code == USER_VAR_EVENT) && - rli->slave_skip_counter == 1) && -#if MYSQL_VERSION_ID < 50100 - /* - Decrease the slave skip counter only if we are not inside - a transaction or the slave skip counter is more than - 1. The slave skip counter will be decreased from 1 to 0 - when reaching the final ROLLBACK, COMMIT, or XID_EVENT. - */ - (!(thd->options & OPTION_BEGIN) || rli->slave_skip_counter > 1) && -#endif - /* - The events from ourselves which have something to do with the relay - log itself must be skipped, true, but they mustn't decrement - rli->slave_skip_counter, because the user is supposed to not see - these events (they are not in the master's binlog) and if we - decremented, START SLAVE would for example decrement when it sees - the Rotate, so the event which the user probably wanted to skip - would not be skipped. - */ - !(ev->server_id == (uint32) ::server_id && - (type_code == ROTATE_EVENT || - type_code == STOP_EVENT || - type_code == START_EVENT_V3 || - type_code == FORMAT_DESCRIPTION_EVENT))) - --rli->slave_skip_counter; - pthread_mutex_unlock(&rli->data_lock); - delete ev; - return 0; // avoid infinite update loops - } - thd->server_id = ev->server_id; // use the original server id for logging thd->set_time(); // time the query thd->lex->current_select= 0; From 9cc4b8dd80fb00d0593fba0f9d5c146bbb7d9439 Mon Sep 17 00:00:00 2001 From: "mats@kindahl-laptop.dnsalias.net" <> Date: Tue, 30 Oct 2007 21:17:19 +0100 Subject: [PATCH 110/336] BUG#19958 (RBR idempotency issue for UPDATE and DELETE): The rpl_trigger test case indicated a problem with idempotency support when run under row-based replication, which this patch fixes. However, despite this, the test is not designed for execution under row-based replication and hence rpl_trigger.test is not executed under row-based replication. The problem is that the test expects triggers to be executed when the slave updates rows on the slave, and this is (deliberately) not done with row-based replication. --- mysql-test/suite/rpl/r/rpl_idempotency.result | 71 +++++++++++++++++ mysql-test/suite/rpl/t/rpl_idempotency.test | 79 +++++++++++++++++++ sql/log_event.cc | 71 ++++++++++++++++- 3 files changed, 217 insertions(+), 4 deletions(-) create mode 100644 mysql-test/suite/rpl/r/rpl_idempotency.result create mode 100644 mysql-test/suite/rpl/t/rpl_idempotency.test diff --git a/mysql-test/suite/rpl/r/rpl_idempotency.result b/mysql-test/suite/rpl/r/rpl_idempotency.result new file mode 100644 index 00000000000..f17fbd82c44 --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_idempotency.result @@ -0,0 +1,71 @@ +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; +CREATE TABLE t1 (a INT PRIMARY KEY); +CREATE TABLE t2 (a INT); +INSERT INTO t1 VALUES (-1),(-2),(-3); +INSERT INTO t2 VALUES (-1),(-2),(-3); +DELETE FROM t1 WHERE a = -2; +DELETE FROM t2 WHERE a = -2; +DELETE FROM t1 WHERE a = -2; +DELETE FROM t2 WHERE a = -2; +SELECT * FROM t1 ORDER BY a; +a +-3 +-1 +SELECT * FROM t2 ORDER BY a; +a +-3 +-1 +SELECT * FROM t1 ORDER BY a; +a +-3 +-1 +SELECT * FROM t2 ORDER BY a; +a +-3 +-1 +Last_SQL_Error +0 +INSERT IGNORE INTO t1 VALUES (-2); +INSERT IGNORE INTO t1 VALUES (-2); +SELECT * FROM t1 ORDER BY a; +a +-3 +-2 +-1 +SELECT * FROM t1 ORDER BY a; +a +-3 +-2 +-1 +Last_SQL_Error +0 +UPDATE t1 SET a = 1 WHERE a = -1; +UPDATE t2 SET a = 1 WHERE a = -1; +UPDATE t1 SET a = 1 WHERE a = -1; +UPDATE t2 SET a = 1 WHERE a = -1; +SELECT * FROM t1 ORDER BY a; +a +-3 +-2 +1 +SELECT * FROM t2 ORDER BY a; +a +-3 +1 +SELECT * FROM t1 ORDER BY a; +a +-3 +-2 +1 +SELECT * FROM t2 ORDER BY a; +a +-3 +1 +Last_SQL_Error +0 +DROP TABLE t1, t2; diff --git a/mysql-test/suite/rpl/t/rpl_idempotency.test b/mysql-test/suite/rpl/t/rpl_idempotency.test new file mode 100644 index 00000000000..44956b7b459 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_idempotency.test @@ -0,0 +1,79 @@ +# Testing various forms of idempotency for replication that should +# work the same way under statement based as under row based. + +source include/master-slave.inc; + +connection master; +CREATE TABLE t1 (a INT PRIMARY KEY); +CREATE TABLE t2 (a INT); +INSERT INTO t1 VALUES (-1),(-2),(-3); +INSERT INTO t2 VALUES (-1),(-2),(-3); +sync_slave_with_master; + +# A delete for a row that does not exist, the statement is +# deliberately written to be idempotent for statement-based +# replication as well. We test this towards both a table with a +# primary key and without a primary key. + +connection slave; +DELETE FROM t1 WHERE a = -2; +DELETE FROM t2 WHERE a = -2; +connection master; +DELETE FROM t1 WHERE a = -2; +DELETE FROM t2 WHERE a = -2; +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +sync_slave_with_master; +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Errno, 1); +disable_query_log; +eval SELECT "$last_error" AS Last_SQL_Error; +enable_query_log; + +# An insert of a row that already exists. Since we are replacing the +# row if it already exists, the most apropriate representation is +# INSERT IGNORE. We only test this towards a table with a primary key, +# since the other case does not make sense. + +INSERT IGNORE INTO t1 VALUES (-2); +connection master; +INSERT IGNORE INTO t1 VALUES (-2); +SELECT * FROM t1 ORDER BY a; +sync_slave_with_master; +SELECT * FROM t1 ORDER BY a; +let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Errno, 1); +disable_query_log; +eval SELECT "$last_error" AS Last_SQL_Error; +enable_query_log; + +# BUG#19958: RBR idempotency issue for UPDATE and DELETE + +# Statement-based and row-based replication have different behaviour +# when updating a row with an explicit WHERE-clause that matches +# exactly one row (or no row at all). For statement-based replication, +# the statement is idempotent since the first time it is executed, it +# will update exactly one row, and the second time it will not update +# any row at all. This was not the case for row-based replication, so +# we test under both row-based and statement-based replication both +# for tables with and without primary keys. + +connection slave; +UPDATE t1 SET a = 1 WHERE a = -1; +UPDATE t2 SET a = 1 WHERE a = -1; +connection master; +UPDATE t1 SET a = 1 WHERE a = -1; +UPDATE t2 SET a = 1 WHERE a = -1; +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +sync_slave_with_master; +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Errno, 1); +disable_query_log; +eval SELECT "$last_error" AS Last_SQL_Error; +enable_query_log; + +connection master; +DROP TABLE t1, t2; +sync_slave_with_master; diff --git a/sql/log_event.cc b/sql/log_event.cc index c0fbfb1000d..3dcc4535d94 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -36,6 +36,63 @@ #define FLAGSTR(V,F) ((V)&(F)?#F" ":"") +#ifndef MYSQL_CLIENT +static const char *HA_ERR(int i) +{ + switch (i) { + case HA_ERR_KEY_NOT_FOUND: return "HA_ERR_KEY_NOT_FOUND"; + case HA_ERR_FOUND_DUPP_KEY: return "HA_ERR_FOUND_DUPP_KEY"; + case HA_ERR_RECORD_CHANGED: return "HA_ERR_RECORD_CHANGED"; + case HA_ERR_WRONG_INDEX: return "HA_ERR_WRONG_INDEX"; + case HA_ERR_CRASHED: return "HA_ERR_CRASHED"; + case HA_ERR_WRONG_IN_RECORD: return "HA_ERR_WRONG_IN_RECORD"; + case HA_ERR_OUT_OF_MEM: return "HA_ERR_OUT_OF_MEM"; + case HA_ERR_NOT_A_TABLE: return "HA_ERR_NOT_A_TABLE"; + case HA_ERR_WRONG_COMMAND: return "HA_ERR_WRONG_COMMAND"; + case HA_ERR_OLD_FILE: return "HA_ERR_OLD_FILE"; + case HA_ERR_NO_ACTIVE_RECORD: return "HA_ERR_NO_ACTIVE_RECORD"; + case HA_ERR_RECORD_DELETED: return "HA_ERR_RECORD_DELETED"; + case HA_ERR_RECORD_FILE_FULL: return "HA_ERR_RECORD_FILE_FULL"; + case HA_ERR_INDEX_FILE_FULL: return "HA_ERR_INDEX_FILE_FULL"; + case HA_ERR_END_OF_FILE: return "HA_ERR_END_OF_FILE"; + case HA_ERR_UNSUPPORTED: return "HA_ERR_UNSUPPORTED"; + case HA_ERR_TO_BIG_ROW: return "HA_ERR_TO_BIG_ROW"; + case HA_WRONG_CREATE_OPTION: return "HA_WRONG_CREATE_OPTION"; + case HA_ERR_FOUND_DUPP_UNIQUE: return "HA_ERR_FOUND_DUPP_UNIQUE"; + case HA_ERR_UNKNOWN_CHARSET: return "HA_ERR_UNKNOWN_CHARSET"; + case HA_ERR_WRONG_MRG_TABLE_DEF: return "HA_ERR_WRONG_MRG_TABLE_DEF"; + case HA_ERR_CRASHED_ON_REPAIR: return "HA_ERR_CRASHED_ON_REPAIR"; + case HA_ERR_CRASHED_ON_USAGE: return "HA_ERR_CRASHED_ON_USAGE"; + case HA_ERR_LOCK_WAIT_TIMEOUT: return "HA_ERR_LOCK_WAIT_TIMEOUT"; + case HA_ERR_LOCK_TABLE_FULL: return "HA_ERR_LOCK_TABLE_FULL"; + case HA_ERR_READ_ONLY_TRANSACTION: return "HA_ERR_READ_ONLY_TRANSACTION"; + case HA_ERR_LOCK_DEADLOCK: return "HA_ERR_LOCK_DEADLOCK"; + case HA_ERR_CANNOT_ADD_FOREIGN: return "HA_ERR_CANNOT_ADD_FOREIGN"; + case HA_ERR_NO_REFERENCED_ROW: return "HA_ERR_NO_REFERENCED_ROW"; + case HA_ERR_ROW_IS_REFERENCED: return "HA_ERR_ROW_IS_REFERENCED"; + case HA_ERR_NO_SAVEPOINT: return "HA_ERR_NO_SAVEPOINT"; + case HA_ERR_NON_UNIQUE_BLOCK_SIZE: return "HA_ERR_NON_UNIQUE_BLOCK_SIZE"; + case HA_ERR_NO_SUCH_TABLE: return "HA_ERR_NO_SUCH_TABLE"; + case HA_ERR_TABLE_EXIST: return "HA_ERR_TABLE_EXIST"; + case HA_ERR_NO_CONNECTION: return "HA_ERR_NO_CONNECTION"; + case HA_ERR_NULL_IN_SPATIAL: return "HA_ERR_NULL_IN_SPATIAL"; + case HA_ERR_TABLE_DEF_CHANGED: return "HA_ERR_TABLE_DEF_CHANGED"; + case HA_ERR_NO_PARTITION_FOUND: return "HA_ERR_NO_PARTITION_FOUND"; + case HA_ERR_RBR_LOGGING_FAILED: return "HA_ERR_RBR_LOGGING_FAILED"; + case HA_ERR_DROP_INDEX_FK: return "HA_ERR_DROP_INDEX_FK"; + case HA_ERR_FOREIGN_DUPLICATE_KEY: return "HA_ERR_FOREIGN_DUPLICATE_KEY"; + case HA_ERR_TABLE_NEEDS_UPGRADE: return "HA_ERR_TABLE_NEEDS_UPGRADE"; + case HA_ERR_TABLE_READONLY: return "HA_ERR_TABLE_READONLY"; + case HA_ERR_AUTOINC_READ_FAILED: return "HA_ERR_AUTOINC_READ_FAILED"; + case HA_ERR_AUTOINC_ERANGE: return "HA_ERR_AUTOINC_ERANGE"; + case HA_ERR_GENERIC: return "HA_ERR_GENERIC"; + case HA_ERR_RECORD_IS_THE_SAME: return "HA_ERR_RECORD_IS_THE_SAME"; + case HA_ERR_LOGGING_IMPOSSIBLE: return "HA_ERR_LOGGING_IMPOSSIBLE"; + case HA_ERR_CORRUPT_EVENT: return "HA_ERR_CORRUPT_EVENT"; + } +} +#endif + /* Cache that will automatically be written to a dedicated file on destruction. @@ -6228,8 +6285,11 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) /* Some recoverable errors */ case HA_ERR_RECORD_CHANGED: - case HA_ERR_KEY_NOT_FOUND: /* Idempotency support: OK if - tuple does not exist */ + case HA_ERR_RECORD_DELETED: + case HA_ERR_KEY_NOT_FOUND: + case HA_ERR_END_OF_FILE: + /* Idempotency support: OK if tuple does not exist */ + DBUG_PRINT("info", ("error: %s", HA_ERR(error))); error= 0; break; @@ -7467,6 +7527,9 @@ static bool record_compare(TABLE *table) records. Check that the other engines also return correct records. */ + DBUG_DUMP("record[0]", table->record[0], table->s->reclength); + DBUG_DUMP("record[1]", table->record[1], table->s->reclength); + bool result= FALSE; uchar saved_x[2], saved_filler[2]; @@ -7555,7 +7618,7 @@ record_compare_exit: int Rows_log_event::find_row(const Relay_log_info *rli) { - DBUG_ENTER("find_row"); + DBUG_ENTER("Rows_log_event::find_row"); DBUG_ASSERT(m_table && m_table->in_use != NULL); @@ -7784,7 +7847,7 @@ int Rows_log_event::find_row(const Relay_log_info *rli) DBUG_DUMP("record found", table->record[0], table->s->reclength); table->file->ha_rnd_end(); - DBUG_ASSERT(error == HA_ERR_END_OF_FILE || error == 0); + DBUG_ASSERT(error == HA_ERR_END_OF_FILE || error == HA_ERR_RECORD_DELETED || error == 0); DBUG_RETURN(error); } From 5dc5fc82923e32dfd4a112c696810d77619e02e5 Mon Sep 17 00:00:00 2001 From: "knielsen@loke.(none)" <> Date: Wed, 31 Oct 2007 10:34:26 +0100 Subject: [PATCH 111/336] BUG#31799: Scrambled number output due to integer overflow An integer overflow in number->string conversion caused completely wrong output of the number LONGLONG_MIN with gcc 4.2.1. Fixed by eliminating the overflow, using only operations that are well-defined in ANSI C. --- strings/ctype-simple.c | 24 ++++++++++++++---------- strings/ctype-ucs2.c | 24 ++++++++++++++---------- strings/int2str.c | 16 ++++++++++------ strings/longlong2str.c | 32 ++++++++++++++++++-------------- 4 files changed, 56 insertions(+), 40 deletions(-) diff --git a/strings/ctype-simple.c b/strings/ctype-simple.c index e073262cd4c..99e02e02014 100644 --- a/strings/ctype-simple.c +++ b/strings/ctype-simple.c @@ -837,6 +837,7 @@ int my_long10_to_str_8bit(CHARSET_INFO *cs __attribute__((unused)), register char *p, *e; long int new_val; uint sign=0; + unsigned long int uval = (unsigned long int) val; e = p = &buffer[sizeof(buffer)-1]; *p= 0; @@ -845,15 +846,16 @@ int my_long10_to_str_8bit(CHARSET_INFO *cs __attribute__((unused)), { if (val < 0) { - val= -val; + /* Avoid integer overflow in (-val) for LONGLONG_MIN (BUG#31799). */ + uval= (unsigned long int)0 - uval; *dst++= '-'; len--; sign= 1; } } - new_val = (long) ((unsigned long int) val / 10); - *--p = '0'+ (char) ((unsigned long int) val - (unsigned long) new_val * 10); + new_val = (long) (uval / 10); + *--p = '0'+ (char) (uval - (unsigned long) new_val * 10); val = new_val; while (val != 0) @@ -876,12 +878,14 @@ int my_longlong10_to_str_8bit(CHARSET_INFO *cs __attribute__((unused)), register char *p, *e; long long_val; uint sign= 0; + ulonglong uval = (ulonglong)val; if (radix < 0) { if (val < 0) { - val = -val; + /* Avoid integer overflow in (-val) for LONGLONG_MIN (BUG#31799). */ + uval = (ulonglong)0 - uval; *dst++= '-'; len--; sign= 1; @@ -891,22 +895,22 @@ int my_longlong10_to_str_8bit(CHARSET_INFO *cs __attribute__((unused)), e = p = &buffer[sizeof(buffer)-1]; *p= 0; - if (val == 0) + if (uval == 0) { *--p= '0'; len= 1; goto cnv; } - while ((ulonglong) val > (ulonglong) LONG_MAX) + while (uval > (ulonglong) LONG_MAX) { - ulonglong quo=(ulonglong) val/(uint) 10; - uint rem= (uint) (val- quo* (uint) 10); + ulonglong quo= uval/(uint) 10; + uint rem= (uint) (uval- quo* (uint) 10); *--p = '0' + rem; - val= quo; + uval= quo; } - long_val= (long) val; + long_val= (long) uval; while (long_val != 0) { long quo= long_val/10; diff --git a/strings/ctype-ucs2.c b/strings/ctype-ucs2.c index b5353c55e4c..97e5defdec1 100644 --- a/strings/ctype-ucs2.c +++ b/strings/ctype-ucs2.c @@ -1018,6 +1018,7 @@ int my_l10tostr_ucs2(CHARSET_INFO *cs, register char *p, *db, *de; long int new_val; int sl=0; + unsigned long int uval = (unsigned long int) val; p = &buffer[sizeof(buffer)-1]; *p='\0'; @@ -1027,12 +1028,13 @@ int my_l10tostr_ucs2(CHARSET_INFO *cs, if (val < 0) { sl = 1; - val = -val; + /* Avoid integer overflow in (-val) for LONGLONG_MIN (BUG#31799). */ + uval = (unsigned long int)0 - uval; } } - new_val = (long) ((unsigned long int) val / 10); - *--p = '0'+ (char) ((unsigned long int) val - (unsigned long) new_val * 10); + new_val = (long) (uval / 10); + *--p = '0'+ (char) (uval - (unsigned long) new_val * 10); val = new_val; while (val != 0) @@ -1065,34 +1067,36 @@ int my_ll10tostr_ucs2(CHARSET_INFO *cs __attribute__((unused)), register char *p, *db, *de; long long_val; int sl=0; + ulonglong uval= (ulonglong) val; if (radix < 0) { if (val < 0) { sl=1; - val = -val; + /* Avoid integer overflow in (-val) for LONGLONG_MIN (BUG#31799). */ + uval = (ulonglong)0 - uval; } } p = &buffer[sizeof(buffer)-1]; *p='\0'; - if (val == 0) + if (uval == 0) { *--p='0'; goto cnv; } - while ((ulonglong) val > (ulonglong) LONG_MAX) + while (uval > (ulonglong) LONG_MAX) { - ulonglong quo=(ulonglong) val/(uint) 10; - uint rem= (uint) (val- quo* (uint) 10); + ulonglong quo= uval/(uint) 10; + uint rem= (uint) (uval- quo* (uint) 10); *--p = '0' + rem; - val= quo; + uval= quo; } - long_val= (long) val; + long_val= (long) uval; while (long_val != 0) { long quo= long_val/10; diff --git a/strings/int2str.c b/strings/int2str.c index 9fc53032819..fba98aac3f1 100644 --- a/strings/int2str.c +++ b/strings/int2str.c @@ -57,6 +57,7 @@ int2str(register long int val, register char *dst, register int radix, register char *p; long int new_val; char *dig_vec= upcase ? _dig_vec_upper : _dig_vec_lower; + ulong uval= (ulong) val; if (radix < 0) { @@ -65,7 +66,8 @@ int2str(register long int val, register char *dst, register int radix, if (val < 0) { *dst++ = '-'; - val = -val; + /* Avoid integer overflow in (-val) for LONGLONG_MIN (BUG#31799). */ + uval = (ulong)0 - uval; } radix = -radix; } @@ -86,8 +88,8 @@ int2str(register long int val, register char *dst, register int radix, */ p = &buffer[sizeof(buffer)-1]; *p = '\0'; - new_val=(ulong) val / (ulong) radix; - *--p = dig_vec[(uchar) ((ulong) val- (ulong) new_val*(ulong) radix)]; + new_val= uval / (ulong) radix; + *--p = dig_vec[(uchar) (uval- (ulong) new_val*(ulong) radix)]; val = new_val; #ifdef HAVE_LDIV while (val != 0) @@ -133,20 +135,22 @@ char *int10_to_str(long int val,char *dst,int radix) char buffer[65]; register char *p; long int new_val; + unsigned long int uval = (unsigned long int) val; if (radix < 0) /* -10 */ { if (val < 0) { *dst++ = '-'; - val = -val; + /* Avoid integer overflow in (-val) for LONGLONG_MIN (BUG#31799). */ + uval = (unsigned long int)0 - uval; } } p = &buffer[sizeof(buffer)-1]; *p = '\0'; - new_val= (long) ((unsigned long int) val / 10); - *--p = '0'+ (char) ((unsigned long int) val - (unsigned long) new_val * 10); + new_val= (long) (uval / 10); + *--p = '0'+ (char) (uval - (unsigned long) new_val * 10); val = new_val; while (val != 0) diff --git a/strings/longlong2str.c b/strings/longlong2str.c index c464abcfccd..d7de5bb0f7c 100644 --- a/strings/longlong2str.c +++ b/strings/longlong2str.c @@ -51,13 +51,15 @@ char *longlong2str(longlong val,char *dst,int radix) char buffer[65]; register char *p; long long_val; + ulonglong uval= (ulonglong) val; if (radix < 0) { if (radix < -36 || radix > -2) return (char*) 0; if (val < 0) { *dst++ = '-'; - val = -val; + /* Avoid integer overflow in (-val) for LONGLONG_MIN (BUG#31799). */ + uval = (ulonglong)0 - uval; } radix = -radix; } @@ -65,7 +67,7 @@ char *longlong2str(longlong val,char *dst,int radix) { if (radix > 36 || radix < 2) return (char*) 0; } - if (val == 0) + if (uval == 0) { *dst++='0'; *dst='\0'; @@ -74,14 +76,14 @@ char *longlong2str(longlong val,char *dst,int radix) p = &buffer[sizeof(buffer)-1]; *p = '\0'; - while ((ulonglong) val > (ulonglong) LONG_MAX) + while (uval > (ulonglong) LONG_MAX) { - ulonglong quo=(ulonglong) val/(uint) radix; - uint rem= (uint) (val- quo* (uint) radix); + ulonglong quo= uval/(uint) radix; + uint rem= (uint) (uval- quo* (uint) radix); *--p = _dig_vec_upper[rem]; - val= quo; + uval= quo; } - long_val= (long) val; + long_val= (long) uval; while (long_val != 0) { long quo= long_val/radix; @@ -100,17 +102,19 @@ char *longlong10_to_str(longlong val,char *dst,int radix) char buffer[65]; register char *p; long long_val; + ulonglong uval= (ulonglong) val; if (radix < 0) { if (val < 0) { *dst++ = '-'; - val = -val; + /* Avoid integer overflow in (-val) for LONGLONG_MIN (BUG#31799). */ + uval = (ulonglong)0 - uval; } } - if (val == 0) + if (uval == 0) { *dst++='0'; *dst='\0'; @@ -119,14 +123,14 @@ char *longlong10_to_str(longlong val,char *dst,int radix) p = &buffer[sizeof(buffer)-1]; *p = '\0'; - while ((ulonglong) val > (ulonglong) LONG_MAX) + while (uval > (ulonglong) LONG_MAX) { - ulonglong quo=(ulonglong) val/(uint) 10; - uint rem= (uint) (val- quo* (uint) 10); + ulonglong quo= uval/(uint) 10; + uint rem= (uint) (uval- quo* (uint) 10); *--p = _dig_vec_upper[rem]; - val= quo; + uval= quo; } - long_val= (long) val; + long_val= (long) uval; while (long_val != 0) { long quo= long_val/10; From afc90970760284885764a85574d5189571203e97 Mon Sep 17 00:00:00 2001 From: "mats@kindahl-laptop.dnsalias.net" <> Date: Wed, 31 Oct 2007 10:45:31 +0100 Subject: [PATCH 112/336] Post-merge fixes to handle some test failures. --- .../suite/rpl/r/rpl_innodb_bug28430.result | 16 ++++++++-------- mysql-test/suite/rpl/t/rpl_innodb_bug28430.test | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/mysql-test/suite/rpl/r/rpl_innodb_bug28430.result b/mysql-test/suite/rpl/r/rpl_innodb_bug28430.result index fb2782ed9f4..c46b4016715 100644 --- a/mysql-test/suite/rpl/r/rpl_innodb_bug28430.result +++ b/mysql-test/suite/rpl/r/rpl_innodb_bug28430.result @@ -114,30 +114,30 @@ Create Table CREATE TABLE `byrange_tbl` ( `filler` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=latin1 /*!50100 PARTITION BY RANGE (id) SUBPARTITION BY HASH (id) SUBPARTITIONS 2 (PARTITION pa1 VALUES LESS THAN (10) ENGINE = InnoDB, PARTITION pa2 VALUES LESS THAN (20) ENGINE = InnoDB, PARTITION pa3 VALUES LESS THAN (30) ENGINE = InnoDB, PARTITION pa4 VALUES LESS THAN (40) ENGINE = InnoDB, PARTITION pa5 VALUES LESS THAN (50) ENGINE = InnoDB, PARTITION pa6 VALUES LESS THAN (60) ENGINE = InnoDB, PARTITION pa7 VALUES LESS THAN (70) ENGINE = InnoDB, PARTITION pa8 VALUES LESS THAN (80) ENGINE = InnoDB, PARTITION pa9 VALUES LESS THAN (90) ENGINE = InnoDB, PARTITION pa10 VALUES LESS THAN (100) ENGINE = InnoDB, PARTITION pa11 VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */ -show slave status; -Slave_IO_State Waiting for master to send event +SHOW SLAVE STATUS; +Slave_IO_State # Master_Host 127.0.0.1 Master_User root Master_Port MASTER_PORT Connect_Retry 1 Master_Log_File master-bin.000001 Read_Master_Log_Pos 945470 -Relay_Log_File slave-relay-bin.000003 -Relay_Log_Pos 945616 +Relay_Log_File # +Relay_Log_Pos # Relay_Master_Log_File master-bin.000001 Slave_IO_Running Yes Slave_SQL_Running Yes Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table -Replicate_Ignore_Table +Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno 0 Last_Error Skip_Counter 0 Exec_Master_Log_Pos 945470 -Relay_Log_Space 945771 +Relay_Log_Space # Until_Condition None Until_Log_File Until_Log_Pos 0 @@ -149,8 +149,8 @@ Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No -Last_IO_Errno 0 -Last_IO_Error +Last_IO_Errno # +Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error SELECT count(*) "Slave norm" FROM test.regular_tbl; diff --git a/mysql-test/suite/rpl/t/rpl_innodb_bug28430.test b/mysql-test/suite/rpl/t/rpl_innodb_bug28430.test index fe3881ab08f..aa56d0a106a 100644 --- a/mysql-test/suite/rpl/t/rpl_innodb_bug28430.test +++ b/mysql-test/suite/rpl/t/rpl_innodb_bug28430.test @@ -136,7 +136,7 @@ SELECT count(*) as "Master byrange" FROM test.byrange_tbl; connection slave; show create table test.byrange_tbl; --replace_column 4 MASTER_PORT 33 # -show slave status; +source include/show_slave_status.inc; SELECT count(*) "Slave norm" FROM test.regular_tbl; SELECT count(*) "Slave bykey" FROM test.bykey_tbl; SELECT count(*) "Slave byrange" FROM test.byrange_tbl; From 68a52c42f97be0071372fabcf85409808bbfe878 Mon Sep 17 00:00:00 2001 From: "aelkin/elkin@koti.dsl.inet.fi" <> Date: Wed, 31 Oct 2007 11:48:49 +0200 Subject: [PATCH 113/336] bug#27571 merging. Fixing offsets and moving tests to the corrent destination. Removing wrong (local temp) tests. --- .../suite/binlog/r/binlog_killed.result | 13 ++-- .../binlog/r/binlog_killed_simulate.result | 33 +++++++++ mysql-test/suite/binlog/t/binlog_killed.test | 10 +-- .../t/binlog_killed_simulate-master.opt | 0 .../binlog}/t/binlog_killed_simulate.test | 7 +- .../t/binlog_killed_bug27571-master.opt | 1 - mysql-test/t/binlog_killed_bug27571.test | 68 ------------------- 7 files changed, 51 insertions(+), 81 deletions(-) create mode 100644 mysql-test/suite/binlog/r/binlog_killed_simulate.result rename mysql-test/{ => suite/binlog}/t/binlog_killed_simulate-master.opt (100%) rename mysql-test/{ => suite/binlog}/t/binlog_killed_simulate.test (83%) delete mode 100644 mysql-test/t/binlog_killed_bug27571-master.opt delete mode 100644 mysql-test/t/binlog_killed_bug27571.test diff --git a/mysql-test/suite/binlog/r/binlog_killed.result b/mysql-test/suite/binlog/r/binlog_killed.result index ddd80283eca..60b2ff6cfc4 100644 --- a/mysql-test/suite/binlog/r/binlog_killed.result +++ b/mysql-test/suite/binlog/r/binlog_killed.result @@ -70,9 +70,10 @@ select * from t2 /* must be (1,2), (2,2) */; a b 1 2 2 2 -show master status /* must have the update event more to FD */; -File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 211 +must have the update event more to FD +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; update t2 set b=b + bug27563(b) order by a select (@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) is not null; @@ -98,9 +99,9 @@ select * from t2 /* must be (1,2), (2,2) */; a b 1 1 2 2 -show master status /* must have the update event more to FD */; -File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 98 +must have the update event more to FD +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info select (@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) is not null; diff --git a/mysql-test/suite/binlog/r/binlog_killed_simulate.result b/mysql-test/suite/binlog/r/binlog_killed_simulate.result new file mode 100644 index 00000000000..f6a5ddade51 --- /dev/null +++ b/mysql-test/suite/binlog/r/binlog_killed_simulate.result @@ -0,0 +1,33 @@ +drop table if exists t1,t2; +create table t1 (a int) engine=MyISAM; +insert into t1 set a=1; +reset master; +update t1 set a=2 /* will be "killed" after work has been done */; +select +(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) +is not null; +(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) +is not null +1 +select 1 /* must return 1 as query completed before got killed*/; +1 +1 +create table t2 (a int, b int) ENGINE=MyISAM; +reset master; +load data infile '../std_data_ln/rpl_loaddata.dat' into table t2 /* will be "killed" in the middle */; +ERROR 70100: Query execution was interrupted +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Begin_load_query # # ;file_id=1;block_len=12 +master-bin.000001 # Execute_load_query # # use `test`; load data infile '../std_data_ln/rpl_loaddata.dat' into table t2 /* will be "killed" in the middle */ ;file_id=1 +select +(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) +is not null; +(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) +is not null +1 +select 0 /* must return 0 to mean the killed query is in */; +0 +0 +drop table t1,t2; +end of the tests diff --git a/mysql-test/suite/binlog/t/binlog_killed.test b/mysql-test/suite/binlog/t/binlog_killed.test index 89028d1c6b7..792b7a3dc57 100644 --- a/mysql-test/suite/binlog/t/binlog_killed.test +++ b/mysql-test/suite/binlog/t/binlog_killed.test @@ -216,11 +216,12 @@ connection con2; --error ER_QUERY_INTERRUPTED reap; select * from t2 /* must be (1,2), (2,2) */; -show master status /* must have the update event more to FD */; +--echo must have the update event more to FD +source include/show_binlog_events.inc; # a proof the query is binlogged with an error ---exec $MYSQL_BINLOG --start-position=98 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog +--exec $MYSQL_BINLOG --start-position=106 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR eval select (@a:=load_file("$MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) @@ -256,11 +257,12 @@ connection con2; --error ER_QUERY_INTERRUPTED reap; select * from t2 /* must be (1,2), (2,2) */; -show master status /* must have the update event more to FD */; +--echo must have the update event more to FD +source include/show_binlog_events.inc; # a proof the query is binlogged with an error ---exec $MYSQL_BINLOG --start-position=98 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog +--exec $MYSQL_BINLOG --start-position=106 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR eval select (@a:=load_file("$MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) diff --git a/mysql-test/t/binlog_killed_simulate-master.opt b/mysql-test/suite/binlog/t/binlog_killed_simulate-master.opt similarity index 100% rename from mysql-test/t/binlog_killed_simulate-master.opt rename to mysql-test/suite/binlog/t/binlog_killed_simulate-master.opt diff --git a/mysql-test/t/binlog_killed_simulate.test b/mysql-test/suite/binlog/t/binlog_killed_simulate.test similarity index 83% rename from mysql-test/t/binlog_killed_simulate.test rename to mysql-test/suite/binlog/t/binlog_killed_simulate.test index d6234d1bfd7..772736d89e9 100644 --- a/mysql-test/t/binlog_killed_simulate.test +++ b/mysql-test/suite/binlog/t/binlog_killed_simulate.test @@ -1,3 +1,4 @@ +-- source include/have_binlog_format_mixed_or_statement.inc # # bug#27571 asynchronous setting mysql_$query()'s local error and # Query_log_event::error_code @@ -18,8 +19,10 @@ reset master; update t1 set a=2 /* will be "killed" after work has been done */; # a proof the query is binlogged with no error - ---exec $MYSQL_BINLOG --start-position=98 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog +#todo: introduce a suite private macro that provides numeric values +# for some constants like the offset of the first real event +# that is different between severs versions. +--exec $MYSQL_BINLOG --start-position=106 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR eval select (@a:=load_file("$MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) diff --git a/mysql-test/t/binlog_killed_bug27571-master.opt b/mysql-test/t/binlog_killed_bug27571-master.opt deleted file mode 100644 index d269cf246d5..00000000000 --- a/mysql-test/t/binlog_killed_bug27571-master.opt +++ /dev/null @@ -1 +0,0 @@ ---loose-debug=d,stop_after_row_loop_done diff --git a/mysql-test/t/binlog_killed_bug27571.test b/mysql-test/t/binlog_killed_bug27571.test deleted file mode 100644 index 6fa3c6d256f..00000000000 --- a/mysql-test/t/binlog_killed_bug27571.test +++ /dev/null @@ -1,68 +0,0 @@ ---source include/have_innodb.inc ---source include/not_embedded.inc ---source include/have_log_bin.inc - -# -# bug#27571 asynchronous setting mysql_`query`::error and Query_log_e::error_code -# -# Checking that if killing happens inbetween of the end of rows loop and -# recording into binlog that will not lead to recording any error incl -# the killed error. -# - -connect (looser, localhost, root,,); -connect (killer, localhost, root,,); - -create table t1 (a int auto_increment, b int, PRIMARY KEY (a)) ENGINE=InnoDB; - -delete from t1; -insert into t1 values (1,1),(2,2); -reset master; - -connection looser; -let $ID= `select connection_id()`; -send update t1 set b=11 where a=2; - -connection killer; -sleep 1; # let 1 second for the update to get to the sleeping point ---replace_result $ID ID -eval kill query $ID; - -connection looser; ---error 0 # zero even though the query must be got killed while it was sleepin for 5 secs -reap; - -# -# this is another possible artifact. The killed error was not caught -# as that is logical as killing was not effective: -# data are ok and well as binlog event is without killed error (further). -# The reason of the following `show error' is to prove that -# killing simulation was effective -# -show errors; - -connection killer; - -# nothing is rolled back - -select * from t1 where a=2 /* must be 11 */; - -# a proof the query is binlogged with an error - ---exec $MYSQL_BINLOG --start-position=98 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog ---replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR -eval select -(@a:=load_file("$MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) -is not null; ---replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR -let $error_code= `select @a like "%#%error_code=0%"`; - -eval select $error_code /* must return 1*/; - -# -# cleanup -# - -drop table t1; - ---echo end of the tests From edbf4120f6da3bd39fd3464f27b8a53bee525d10 Mon Sep 17 00:00:00 2001 From: "holyfoot/hf@mysql.com/hfmain.(none)" <> Date: Wed, 31 Oct 2007 16:01:29 +0400 Subject: [PATCH 114/336] Bug #31893 Partitions: crash if subpartitions and engine change. The new default database engine for altered table was reassigned to the old one. That's wrong thing by itself, and (as the engine for a subpartition gets that new value) leads to DBUG_ASSERTION in mysql_unpack_partition() --- mysql-test/r/partition.result | 14 ++++++++++++++ mysql-test/t/partition.test | 11 +++++++++++ sql/sql_partition.cc | 5 ++++- 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/partition.result b/mysql-test/r/partition.result index 4e4bd0bbc0a..e39e84fdd69 100644 --- a/mysql-test/r/partition.result +++ b/mysql-test/r/partition.result @@ -1291,4 +1291,18 @@ t1 CREATE TABLE `t1` ( `b` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 /*!50100 PARTITION BY RANGE (b) (PARTITION p1 VALUES LESS THAN (10) ENGINE = MyISAM, PARTITION p2 VALUES LESS THAN (20) ENGINE = MyISAM) */ drop table t1, t2; +create table t1 (int_column int, char_column char(5)) +PARTITION BY RANGE (int_column) subpartition by key (char_column) +(PARTITION p1 VALUES LESS THAN (5) ENGINE = InnoDB); +Warnings: +Warning 1286 Unknown table engine 'InnoDB' +alter table t1 PARTITION BY RANGE (int_column) subpartition by key (char_column) +(PARTITION p1 VALUES LESS THAN (5) ENGINE = myisam); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `int_column` int(11) DEFAULT NULL, + `char_column` char(5) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 /*!50100 PARTITION BY RANGE (int_column) SUBPARTITION BY KEY (char_column) (PARTITION p1 VALUES LESS THAN (5) ENGINE = MyISAM) */ +drop table t1; End of 5.1 tests diff --git a/mysql-test/t/partition.test b/mysql-test/t/partition.test index 2906b4640cd..82a8759e910 100644 --- a/mysql-test/t/partition.test +++ b/mysql-test/t/partition.test @@ -1528,4 +1528,15 @@ PARTITION BY RANGE (b) ( show create table t1; drop table t1, t2; +# +# Bug #31893 Partitions: crash if subpartitions and engine change +# +create table t1 (int_column int, char_column char(5)) + PARTITION BY RANGE (int_column) subpartition by key (char_column) + (PARTITION p1 VALUES LESS THAN (5) ENGINE = InnoDB); +alter table t1 PARTITION BY RANGE (int_column) subpartition by key (char_column) + (PARTITION p1 VALUES LESS THAN (5) ENGINE = myisam); +show create table t1; +drop table t1; + --echo End of 5.1 tests diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 0cc2cac2a1a..e5466599429 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5031,7 +5031,10 @@ the generated partition syntax in a correct manner. *partition_changed= TRUE; } if (create_info->db_type == partition_hton) - part_info->default_engine_type= table->part_info->default_engine_type; + { + if (!part_info->default_engine_type) + part_info->default_engine_type= table->part_info->default_engine_type; + } else part_info->default_engine_type= create_info->db_type; if (check_native_partitioned(create_info, &is_native_partitioned, From 770a6de90cd45e24126eb17afc7ebd28d80a732b Mon Sep 17 00:00:00 2001 From: "mleich@four.local.lan" <> Date: Wed, 31 Oct 2007 17:40:29 +0100 Subject: [PATCH 115/336] Fix for Bug#29290 type_datetime.test failure in 5.1 --- mysql-test/t/type_datetime.test | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/mysql-test/t/type_datetime.test b/mysql-test/t/type_datetime.test index 20733a14d46..1b893fd376e 100644 --- a/mysql-test/t/type_datetime.test +++ b/mysql-test/t/type_datetime.test @@ -155,13 +155,13 @@ set @@sql_mode='ansi,traditional'; insert into t1 values ('2007-03-23 13:49:38','2007-03-23 13:49:38'); insert into t1 set dt='2007-03-23 13:49:38',da=dt; # Test error handling ---error 1292 +--error ER_TRUNCATED_WRONG_VALUE insert into t1 values ('2007-03-32','2007-03-23 13:49:38'); select * from t1; drop table t1; ---error 1067 +--error ER_INVALID_DEFAULT create table t1 (da date default '1962-03-32 23:33:34', dt datetime default '1962-03-03'); ---error 1067 +--error ER_INVALID_DEFAULT create table t1 (t time default '916:00:00 a'); set @@sql_mode= @org_mode; @@ -169,6 +169,19 @@ set @@sql_mode= @org_mode; # # Bug#27590: Wrong DATE/DATETIME comparison. # +## The following sub test will fail (difference to expected result) if the +## select curdate() < now(), f1 < now(), cast(f1 as date) < now() from t1; +## runs exact at midnight ('00:00:00'). +## ( Bug#29290 type_datetime.test failure in 5.1 ) +## Therefore we sleep a bit if we are too close to midnight. +## The complete test itself needs around 1 second. +## Therefore a time_distance to midnight of 5 seconds should be sufficient. +if (`SELECT CURTIME() > SEC_TO_TIME(24 * 3600 - 5)`) +{ + # We are here when CURTIME() is between '23:59:56' and '23:59:59'. + # So a sleep time of 5 seconds brings us between '00:00:01' and '00:00:04'. + --real_sleep 5 +} create table t1 (f1 date, f2 datetime, f3 timestamp); insert into t1(f1) values(curdate()); select curdate() < now(), f1 < now(), cast(f1 as date) < now() from t1; From 9e9ff4b420955fabd26bc1de5ff491f37f3b27bb Mon Sep 17 00:00:00 2001 From: "jmiller/jbmiller@mysql.com/ndbqa01.mysql.com" <> Date: Wed, 31 Oct 2007 14:01:01 -0500 Subject: [PATCH 116/336] rpl_extraSlave_Col.test: Corrected issues found in preparing to push code --- mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test b/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test index 3ad178e7610..6fa2c9ac1b5 100644 --- a/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test +++ b/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test @@ -920,7 +920,10 @@ sync_slave_with_master; #### Clean Up #### --disable_warnings --disable_query_log +connection master; DROP TABLE IF EXISTS t1, t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t14a,t15,t16,t17; +sync_slave_with_master; +connection master; --enable_query_log --enable_warnings From 16c165547169cdf46a0b07c8fd0063709a2c20a1 Mon Sep 17 00:00:00 2001 From: "mats@kindahl-laptop.dnsalias.net" <> Date: Wed, 31 Oct 2007 21:09:52 +0100 Subject: [PATCH 117/336] BUG#28086 (SBR of USER() becomes corrupted on slave): Marking statements containing USER() or CURRENT_USER() as unsafe, causing them to switch to using row-based logging in MIXED mode and generate a warning in STATEMENT mode. --- .../rpl/r/rpl_switch_stm_row_mixed.result | 68 +++++++++++++++++++ .../suite/rpl/t/rpl_switch_stm_row_mixed.test | 36 ++++++++++ sql/sql_yacc.yy | 2 + 3 files changed, 106 insertions(+) diff --git a/mysql-test/suite/rpl/r/rpl_switch_stm_row_mixed.result b/mysql-test/suite/rpl/r/rpl_switch_stm_row_mixed.result index c3f0c07b92c..8ed9ff5dc2f 100644 --- a/mysql-test/suite/rpl/r/rpl_switch_stm_row_mixed.result +++ b/mysql-test/suite/rpl/r/rpl_switch_stm_row_mixed.result @@ -405,6 +405,26 @@ CREATE TABLE t12 (data LONG); LOCK TABLES t12 WRITE; INSERT INTO t12 VALUES(UUID()); UNLOCK TABLES; +CREATE FUNCTION my_user() +RETURNS CHAR(64) +BEGIN +DECLARE user CHAR(64); +SELECT USER() INTO user; +RETURN user; +END $$ +CREATE FUNCTION my_current_user() +RETURNS CHAR(64) +BEGIN +DECLARE user CHAR(64); +SELECT CURRENT_USER() INTO user; +RETURN user; +END $$ +DROP TABLE IF EXISTS t13; +CREATE TABLE t13 (data CHAR(64)); +INSERT INTO t13 VALUES (USER()); +INSERT INTO t13 VALUES (my_user()); +INSERT INTO t13 VALUES (CURRENT_USER()); +INSERT INTO t13 VALUES (my_current_user()); show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # drop database if exists mysqltest1 @@ -709,6 +729,30 @@ master-bin.000001 # Query # # use `mysqltest1`; DROP TABLE IF EXISTS t12 master-bin.000001 # Query # # use `mysqltest1`; CREATE TABLE t12 (data LONG) master-bin.000001 # Table_map # # table_id: # (mysqltest1.t12) master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` FUNCTION my_user() +RETURNS CHAR(64) +BEGIN +DECLARE user CHAR(64); +SELECT USER() INTO user; +RETURN user; +END +master-bin.000001 # Query # # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` FUNCTION my_current_user() +RETURNS CHAR(64) +BEGIN +DECLARE user CHAR(64); +SELECT CURRENT_USER() INTO user; +RETURN user; +END +master-bin.000001 # Query # # use `mysqltest1`; DROP TABLE IF EXISTS t13 +master-bin.000001 # Query # # use `mysqltest1`; CREATE TABLE t13 (data CHAR(64)) +master-bin.000001 # Table_map # # table_id: # (mysqltest1.t13) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (mysqltest1.t13) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (mysqltest1.t13) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (mysqltest1.t13) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # drop database if exists mysqltest1 @@ -1013,5 +1057,29 @@ master-bin.000001 # Query # # use `mysqltest1`; DROP TABLE IF EXISTS t12 master-bin.000001 # Query # # use `mysqltest1`; CREATE TABLE t12 (data LONG) master-bin.000001 # Table_map # # table_id: # (mysqltest1.t12) master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` FUNCTION my_user() +RETURNS CHAR(64) +BEGIN +DECLARE user CHAR(64); +SELECT USER() INTO user; +RETURN user; +END +master-bin.000001 # Query # # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` FUNCTION my_current_user() +RETURNS CHAR(64) +BEGIN +DECLARE user CHAR(64); +SELECT CURRENT_USER() INTO user; +RETURN user; +END +master-bin.000001 # Query # # use `mysqltest1`; DROP TABLE IF EXISTS t13 +master-bin.000001 # Query # # use `mysqltest1`; CREATE TABLE t13 (data CHAR(64)) +master-bin.000001 # Table_map # # table_id: # (mysqltest1.t13) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (mysqltest1.t13) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (mysqltest1.t13) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (mysqltest1.t13) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F drop database mysqltest1; set global binlog_format =@my_binlog_format; diff --git a/mysql-test/suite/rpl/t/rpl_switch_stm_row_mixed.test b/mysql-test/suite/rpl/t/rpl_switch_stm_row_mixed.test index b0012827db8..05dcb91ca28 100644 --- a/mysql-test/suite/rpl/t/rpl_switch_stm_row_mixed.test +++ b/mysql-test/suite/rpl/t/rpl_switch_stm_row_mixed.test @@ -518,6 +518,42 @@ CREATE TABLE t12 (data LONG); LOCK TABLES t12 WRITE; INSERT INTO t12 VALUES(UUID()); UNLOCK TABLES; +sync_slave_with_master; + +# +# BUG#28086: SBR of USER() becomes corrupted on slave +# + +connection master; + +# Just to get something that is non-trivial, albeit still simple, we +# stuff the result of USER() and CURRENT_USER() into a variable. +--delimiter $$ +CREATE FUNCTION my_user() + RETURNS CHAR(64) +BEGIN + DECLARE user CHAR(64); + SELECT USER() INTO user; + RETURN user; +END $$ +--delimiter ; + +--delimiter $$ +CREATE FUNCTION my_current_user() + RETURNS CHAR(64) +BEGIN + DECLARE user CHAR(64); + SELECT CURRENT_USER() INTO user; + RETURN user; +END $$ +--delimiter ; + +DROP TABLE IF EXISTS t13; +CREATE TABLE t13 (data CHAR(64)); +INSERT INTO t13 VALUES (USER()); +INSERT INTO t13 VALUES (my_user()); +INSERT INTO t13 VALUES (CURRENT_USER()); +INSERT INTO t13 VALUES (my_current_user()); source include/show_binlog_events.inc; sync_slave_with_master; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 109e8f5434f..bb25d9c4c7f 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -6745,6 +6745,7 @@ function_call_keyword: | CURRENT_USER optional_braces { $$= new (YYTHD->mem_root) Item_func_current_user(Lex->current_context()); + Lex->set_stmt_unsafe(); Lex->safe_to_cache_query= 0; } | DATE_SYM '(' expr ')' @@ -6790,6 +6791,7 @@ function_call_keyword: | USER '(' ')' { $$= new (YYTHD->mem_root) Item_func_user(); + Lex->set_stmt_unsafe(); Lex->safe_to_cache_query=0; } | YEAR_SYM '(' expr ')' From ec5ee6f5e4bdf7c698924469bc0dca30d367401c Mon Sep 17 00:00:00 2001 From: "msvensson@pilot.mysql.com" <> Date: Thu, 1 Nov 2007 11:01:05 +0100 Subject: [PATCH 118/336] Fix comment --- client/mysqltest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index eae3b05f61a..e5ae9e80a88 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -2675,7 +2675,7 @@ void do_copy_file(struct st_command *command) command command handle DESCRIPTION - chmod_file + chmod Change file permission of */ From 441bb13e0d46222b05a4310cab3490c7f0e3a1be Mon Sep 17 00:00:00 2001 From: "msvensson@pilot.mysql.com" <> Date: Thu, 1 Nov 2007 11:02:28 +0100 Subject: [PATCH 119/336] Bug#27753 enable mysql-test-run.pl to ignore tests based on wildcard - Fix problem in first implementation --- mysql-test/lib/mtr_cases.pl | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/mysql-test/lib/mtr_cases.pl b/mysql-test/lib/mtr_cases.pl index 5aabb7f8863..b9943fb6cfa 100644 --- a/mysql-test/lib/mtr_cases.pl +++ b/mysql-test/lib/mtr_cases.pl @@ -32,16 +32,14 @@ my $skip_test; sub init_pattern { my ($from, $what)= @_; - if ( $from =~ /[a-z0-9]/ ) { + if ( $from =~ /^[a-z0-9]$/ ) { # Does not contain any regex, make the pattern match # beginning of string $from= "^$from"; } - else { - # Check that pattern is a valid regex - eval { "" =~/$from/; 1 } or - mtr_error("Invalid regex '$from' passed to $what\nPerl says: $@"); - } + # Check that pattern is a valid regex + eval { "" =~/$from/; 1 } or + mtr_error("Invalid regex '$from' passed to $what\nPerl says: $@"); return $from; } From 39c22a5be02d328a63a5689fb00d948ee1f5b0c0 Mon Sep 17 00:00:00 2001 From: "msvensson@pilot.mysql.com" <> Date: Thu, 1 Nov 2007 11:33:35 +0100 Subject: [PATCH 120/336] Bug#32023 ndb_mgmd is slow to repsond when no nodes are up --- mysql-test/r/bdb_notembedded.result | 35 -------------------------- mysql-test/t/bdb_notembedded.test | 38 ----------------------------- ndb/src/mgmsrv/Services.cpp | 2 +- ndb/src/ndbapi/ClusterMgr.cpp | 5 +++- 4 files changed, 5 insertions(+), 75 deletions(-) delete mode 100644 mysql-test/r/bdb_notembedded.result delete mode 100644 mysql-test/t/bdb_notembedded.test diff --git a/mysql-test/r/bdb_notembedded.result b/mysql-test/r/bdb_notembedded.result deleted file mode 100644 index 14cb5fad915..00000000000 --- a/mysql-test/r/bdb_notembedded.result +++ /dev/null @@ -1,35 +0,0 @@ -set autocommit=1; -reset master; -create table bug16206 (a int); -insert into bug16206 values(1); -start transaction; -insert into bug16206 values(2); -commit; -show binlog events; -Log_name Pos Event_type Server_id End_log_pos Info -f n Format_desc 1 n Server ver: VERSION, Binlog ver: 4 -f n Query 1 n use `test`; create table bug16206 (a int) -f n Query 1 n use `test`; insert into bug16206 values(1) -f n Query 1 n use `test`; insert into bug16206 values(2) -drop table bug16206; -reset master; -create table bug16206 (a int) engine= bdb; -insert into bug16206 values(0); -insert into bug16206 values(1); -start transaction; -insert into bug16206 values(2); -commit; -insert into bug16206 values(3); -show binlog events; -Log_name Pos Event_type Server_id End_log_pos Info -f n Format_desc 1 n Server ver: VERSION, Binlog ver: 4 -f n Query 1 n use `test`; create table bug16206 (a int) engine= bdb -f n Query 1 n use `test`; insert into bug16206 values(0) -f n Query 1 n use `test`; insert into bug16206 values(1) -f n Query 1 n use `test`; BEGIN -f n Query 1 n use `test`; insert into bug16206 values(2) -f n Query 1 n use `test`; COMMIT -f n Query 1 n use `test`; insert into bug16206 values(3) -drop table bug16206; -set autocommit=0; -End of 5.0 tests diff --git a/mysql-test/t/bdb_notembedded.test b/mysql-test/t/bdb_notembedded.test deleted file mode 100644 index 24e64ebbfb2..00000000000 --- a/mysql-test/t/bdb_notembedded.test +++ /dev/null @@ -1,38 +0,0 @@ --- source include/not_embedded.inc --- source include/have_bdb.inc - -# -# Bug #16206: Superfluous COMMIT event in binlog when updating BDB in autocommit mode -# -set autocommit=1; - -let $VERSION=`select version()`; - -reset master; -create table bug16206 (a int); -insert into bug16206 values(1); -start transaction; -insert into bug16206 values(2); -commit; ---replace_result $VERSION VERSION ---replace_column 1 f 2 n 5 n -show binlog events; -drop table bug16206; - -reset master; -create table bug16206 (a int) engine= bdb; -insert into bug16206 values(0); -insert into bug16206 values(1); -start transaction; -insert into bug16206 values(2); -commit; -insert into bug16206 values(3); ---replace_result $VERSION VERSION ---replace_column 1 f 2 n 5 n -show binlog events; -drop table bug16206; - -set autocommit=0; - - ---echo End of 5.0 tests diff --git a/ndb/src/mgmsrv/Services.cpp b/ndb/src/mgmsrv/Services.cpp index b7ff4df7012..31218df019b 100644 --- a/ndb/src/mgmsrv/Services.cpp +++ b/ndb/src/mgmsrv/Services.cpp @@ -923,7 +923,6 @@ printNodeStatus(OutputStream *output, MgmtSrvr &mgmsrv, enum ndb_mgm_node_type type) { NodeId nodeId = 0; - mgmsrv.updateStatus(); while(mgmsrv.getNextNodeId(&nodeId, type)) { enum ndb_mgm_node_status status; Uint32 startPhase = 0, @@ -972,6 +971,7 @@ MgmApiSession::getStatus(Parser::Context &, m_output->println("node status"); m_output->println("nodes: %d", noOfNodes); + m_mgmsrv.updateStatus(); printNodeStatus(m_output, m_mgmsrv, NDB_MGM_NODE_TYPE_NDB); printNodeStatus(m_output, m_mgmsrv, NDB_MGM_NODE_TYPE_MGM); printNodeStatus(m_output, m_mgmsrv, NDB_MGM_NODE_TYPE_API); diff --git a/ndb/src/ndbapi/ClusterMgr.cpp b/ndb/src/ndbapi/ClusterMgr.cpp index d3946dddfb7..a8fcb756cdf 100644 --- a/ndb/src/ndbapi/ClusterMgr.cpp +++ b/ndb/src/ndbapi/ClusterMgr.cpp @@ -222,7 +222,10 @@ ClusterMgr::forceHB() theFacade.sendSignalUnCond(&signal, nodeId); } - NdbCondition_WaitTimeout(waitForHBCond, theFacade.theMutexPtr, 1000); + /* Wait for nodes to reply - if any heartbeats was sent */ + if (!waitForHBFromNodes.isclear()) + NdbCondition_WaitTimeout(waitForHBCond, theFacade.theMutexPtr, 1000); + waitingForHB= false; #ifdef DEBUG_REG ndbout << "Still waiting for HB from " << waitForHBFromNodes.getText(buf) << endl; From f8c2f9d195a9aa0fd0ba53f1ed0fec6589e19749 Mon Sep 17 00:00:00 2001 From: "svoj@mysql.com/june.mysql.com" <> Date: Thu, 1 Nov 2007 16:27:01 +0400 Subject: [PATCH 121/336] BUG#31950 - repair table hangs while processing multicolumn utf8 fulltext index Having a table with broken multibyte characters may cause fulltext parser dead-loop. Since normally it is not possible to insert broken multibyte sequence into a table, this problem may arise only if table is damaged. Affected statements are: - CHECK/REPAIR against damaged table with fulltext index; - boolean mode phrase search against damaged table with or without fulltext inex; - boolean mode searches without index; - nlq searches. No test case for this fix. Affects 5.0 only. --- myisam/ft_parser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/myisam/ft_parser.c b/myisam/ft_parser.c index 6d68542e4e2..1d3a19dd8c6 100644 --- a/myisam/ft_parser.c +++ b/myisam/ft_parser.c @@ -188,7 +188,7 @@ byte ft_simple_get_word(CHARSET_INFO *cs, byte **start, const byte *end, do { - for (;; doc+= mbl) + for (;; doc+= (mbl ? mbl : 1)) { if (doc >= end) DBUG_RETURN(0); if (true_word_char(cs, *doc)) break; From 447eff2d98af4bd229f71e109ae568d4155c30cf Mon Sep 17 00:00:00 2001 From: "gkodinov/kgeorge@magare.gmz" <> Date: Thu, 1 Nov 2007 14:42:14 +0200 Subject: [PATCH 122/336] Bug #31866: MySQL Server crashes on SHOW CREATE TRIGGER statement SHOW CREATE TRIGGER was not checking for detected errors opening/reading the trigger file. Fixed to return the already generated error. --- mysql-test/r/trigger.result | 6 ++++++ mysql-test/t/trigger.test | 12 ++++++++++++ sql/sql_show.cc | 3 +++ 3 files changed, 21 insertions(+) diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result index 189722bfe9b..47ffc90e3cd 100644 --- a/mysql-test/r/trigger.result +++ b/mysql-test/r/trigger.result @@ -1978,3 +1978,9 @@ a 1 drop table table_25411_a; drop table table_25411_b; +DROP TRIGGER IF EXISTS trg; +Warnings: +Note 1360 Trigger does not exist +SHOW CREATE TRIGGER trg; +ERROR HY000: Trigger does not exist +End of 5.1 tests. diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test index 9f4634e1e17..1c98a0f8d29 100644 --- a/mysql-test/t/trigger.test +++ b/mysql-test/t/trigger.test @@ -2246,3 +2246,15 @@ select * from table_25411_a; drop table table_25411_a; drop table table_25411_b; +# +# Bug #31866: MySQL Server crashes on SHOW CREATE TRIGGER statement +# + +--disable-warnings +DROP TRIGGER IF EXISTS trg; +--enable-warnings + +--error ER_TRG_DOES_NOT_EXIST +SHOW CREATE TRIGGER trg; + +--echo End of 5.1 tests. diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 049c050c288..1969472dff4 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -6862,6 +6862,9 @@ bool show_create_trigger(THD *thd, const sp_name *trg_name) { TABLE_LIST *lst= get_trigger_table(thd, trg_name); + if (!lst) + return TRUE; + /* Open the table by name in order to load Table_triggers_list object. From 382f62b10b63894faa739cc61d18e3d5a268713a Mon Sep 17 00:00:00 2001 From: "istruewing@stella.local" <> Date: Thu, 1 Nov 2007 15:03:09 +0100 Subject: [PATCH 123/336] Bug#31909 - New gis.test creates warnings files Comment sign of -- at line begin in test files lead to warnings from mysqltest. Changed -- to #. --- mysql-test/include/gis_keys.inc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/mysql-test/include/gis_keys.inc b/mysql-test/include/gis_keys.inc index 295e0c48234..c75311f062a 100644 --- a/mysql-test/include/gis_keys.inc +++ b/mysql-test/include/gis_keys.inc @@ -13,20 +13,20 @@ CREATE TABLE t2 (p POINT, INDEX(p)); INSERT INTO t1 VALUES (POINTFROMTEXT('POINT(1 2)')); INSERT INTO t2 VALUES (POINTFROMTEXT('POINT(1 2)')); --- no index, returns 1 as expected +# no index, returns 1 as expected SELECT COUNT(*) FROM t1 WHERE p=POINTFROMTEXT('POINT(1 2)'); --- with index, returns 1 as expected --- EXPLAIN shows that the index is not used though --- due to the "most rows covered anyway, so a scan is more effective" rule +# with index, returns 1 as expected +# EXPLAIN shows that the index is not used though +# due to the "most rows covered anyway, so a scan is more effective" rule EXPLAIN SELECT COUNT(*) FROM t2 WHERE p=POINTFROMTEXT('POINT(1 2)'); SELECT COUNT(*) FROM t2 WHERE p=POINTFROMTEXT('POINT(1 2)'); --- adding another row to the table so that --- the "most rows covered" rule doesn't kick in anymore --- now EXPLAIN shows the index used on the table --- and we're getting the wrong result again +# adding another row to the table so that +# the "most rows covered" rule doesn't kick in anymore +# now EXPLAIN shows the index used on the table +# and we're getting the wrong result again INSERT INTO t1 VALUES (POINTFROMTEXT('POINT(1 2)')); INSERT INTO t2 VALUES (POINTFROMTEXT('POINT(1 2)')); EXPLAIN From 1b165ef41f8ef2283264ff1ef6c5e719fea60e4e Mon Sep 17 00:00:00 2001 From: "istruewing@stella.local" <> Date: Thu, 1 Nov 2007 15:04:23 +0100 Subject: [PATCH 124/336] Post-merge fix --- mysql-test/t/variables.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/t/variables.test b/mysql-test/t/variables.test index 63bc3c5e273..b661d0e8ae7 100644 --- a/mysql-test/t/variables.test +++ b/mysql-test/t/variables.test @@ -139,7 +139,7 @@ show global variables like 'net_%'; show session variables like 'net_%'; set net_buffer_length=1; show variables like 'net_buffer_length'; ---warning 1292 +#warning 1292 set net_buffer_length=2000000000; show variables like 'net_buffer_length'; From 92a5605d439feb4d044bb2c27fb06a7d4f5cc197 Mon Sep 17 00:00:00 2001 From: "gkodinov/kgeorge@magare.gmz" <> Date: Thu, 1 Nov 2007 18:36:24 +0200 Subject: [PATCH 125/336] Bug #31794: no syntax error on SELECT id FROM t HAVING count(*)>2 The HAVING clause is subject to the same rules as the SELECT list about using aggregated and non-aggregated columns. But this was not enforced when processing implicit grouping from using aggregate functions. Fixed by performing the same checks for HAVING as for SELECT. --- mysql-test/r/func_group.result | 15 +++++++++++++++ mysql-test/t/func_group.test | 19 +++++++++++++++++++ sql/sql_select.cc | 12 ++++++++++-- 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result index e7f27ebb07e..1e130877088 100644 --- a/mysql-test/r/func_group.result +++ b/mysql-test/r/func_group.result @@ -1392,4 +1392,19 @@ SELECT MIN(b) FROM t1 WHERE a=1 AND b>'2007-08-01'; MIN(b) NULL DROP TABLE t1; +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1),(2),(3),(4); +SET SQL_MODE=ONLY_FULL_GROUP_BY; +SELECT a FROM t1 HAVING COUNT(*)>2; +ERROR 42000: Mixing of GROUP columns (MIN(),MAX(),COUNT(),...) with no GROUP columns is illegal if there is no GROUP BY clause +SELECT COUNT(*), a FROM t1; +ERROR 42000: Mixing of GROUP columns (MIN(),MAX(),COUNT(),...) with no GROUP columns is illegal if there is no GROUP BY clause +SET SQL_MODE=DEFAULT; +SELECT a FROM t1 HAVING COUNT(*)>2; +a +1 +SELECT COUNT(*), a FROM t1; +COUNT(*) a +4 1 +DROP TABLE t1; End of 5.0 tests diff --git a/mysql-test/t/func_group.test b/mysql-test/t/func_group.test index 7e115707625..25cb13a2f75 100644 --- a/mysql-test/t/func_group.test +++ b/mysql-test/t/func_group.test @@ -882,5 +882,24 @@ CREATE TABLE t1 (a int, b date NOT NULL, KEY k1 (a,b)); SELECT MIN(b) FROM t1 WHERE a=1 AND b>'2007-08-01'; DROP TABLE t1; +# +# Bug #31794: no syntax error on SELECT id FROM t HAVING count(*)>2; +# + +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1),(2),(3),(4); + +SET SQL_MODE=ONLY_FULL_GROUP_BY; +--error ER_MIX_OF_GROUP_FUNC_AND_FIELDS +SELECT a FROM t1 HAVING COUNT(*)>2; +--error ER_MIX_OF_GROUP_FUNC_AND_FIELDS +SELECT COUNT(*), a FROM t1; + +SET SQL_MODE=DEFAULT; +SELECT a FROM t1 HAVING COUNT(*)>2; +SELECT COUNT(*), a FROM t1; + +DROP TABLE t1; + ### --echo End of 5.0 tests diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 7af39071561..e7d778de991 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -565,11 +565,12 @@ JOIN::prepare(Item ***rref_pointer_array, /* - Check if one one uses a not constant column with group functions - and no GROUP BY. + Check if there are references to un-aggregated columns when computing + aggregate functions with implicit grouping (there is no GROUP BY). TODO: Add check of calculation of GROUP functions and fields: SELECT COUNT(*)+table.col1 from table1; */ + if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY) { if (!group_list) { @@ -583,6 +584,13 @@ JOIN::prepare(Item ***rref_pointer_array, else if (!(flag & 2) && !item->const_during_execution()) flag|=2; } + if (having) + { + if (having->with_sum_func) + flag |= 1; + else if (!having->const_during_execution()) + flag |= 2; + } if (flag == 3) { my_message(ER_MIX_OF_GROUP_FUNC_AND_FIELDS, From f6ffb2cf8ce71a25717896d35158a8094cb85238 Mon Sep 17 00:00:00 2001 From: "msvensson@pilot.mysql.com" <> Date: Thu, 1 Nov 2007 19:40:27 +0100 Subject: [PATCH 126/336] Bug#30630 mysql-test-run all tests fail with MySQL 5.0.41 & 5.0.45 on Mac OS X Server 10.5 --- mysql-test/mysql-test-run.pl | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index b81d2eb0019..b123c377ce7 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -3727,6 +3727,16 @@ sub mysqld_arguments ($$$$) { # see BUG#28359 mtr_add_arg($args, "%s--connect-timeout=60", $prefix); + + # When mysqld is run by a root user(euid is 0), it will fail + # to start unless we specify what user to run as. If not running + # as root it will be ignored, see BUG#30630 + my $euid= $>; + if (!$glob_win32 and $euid == 0 and + grep(/^--user/, @$extra_opt, @opt_extra_mysqld_opt) == 0) { + mtr_add_arg($args, "%s--user=root"); + } + if ( $opt_valgrind_mysqld ) { mtr_add_arg($args, "%s--skip-safemalloc", $prefix); From bcfe0fa67eb32df9ab3df117c9ff11f1d271da5b Mon Sep 17 00:00:00 2001 From: "antony@pcg5ppc.xiphis.org" <> Date: Thu, 1 Nov 2007 12:30:03 -0700 Subject: [PATCH 127/336] Bug#30671 "ALTER SERVER can cause server to crash" While retrieving values, it would erronously set the socket value to NULL and attempt to use it in strcmp(). Ensure it is correctly set to "" so that strcmp may not crash. --- mysql-test/r/federated_server.result | 10 +++++++++- mysql-test/t/federated_server.test | 14 +++++++++++++- sql/sql_servers.cc | 4 ++-- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/federated_server.result b/mysql-test/r/federated_server.result index 0905aabb075..32717b4f0e3 100644 --- a/mysql-test/r/federated_server.result +++ b/mysql-test/r/federated_server.result @@ -253,6 +253,14 @@ drop user guest_usage@localhost; drop user guest_select@localhost; drop table federated.t1; drop server 's1'; +create server 's1' foreign data wrapper 'mysql' options (port 3306); +alter server 's1' options +(host 'localhost', database '', user '', +password '', socket '', owner '', port 3306); +alter server 's1' options +(host 'localhost', database 'database1', user '', +password '', socket '', owner '', port 3306); +drop server 's1'; # End of 5.1 tests use test; create procedure p1 () @@ -262,7 +270,7 @@ DECLARE e INT DEFAULT 0; DECLARE i INT; DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET e = e + 1; SET i = sleep(5); -WHILE v < 20000 do +WHILE v < 10000 do CREATE SERVER s FOREIGN DATA WRAPPER mysql OPTIONS (USER 'Remote', HOST '192.168.1.106', DATABASE 'test'); diff --git a/mysql-test/t/federated_server.test b/mysql-test/t/federated_server.test index 87b67720104..444285ac045 100644 --- a/mysql-test/t/federated_server.test +++ b/mysql-test/t/federated_server.test @@ -2,7 +2,7 @@ # if federated can utilise the servers table # should work with embedded server after mysqltest is fixed -- source include/not_embedded.inc --- source include/federated.inc; +-- source include/federated.inc -- source include/big_test.inc connection slave; @@ -282,6 +282,18 @@ drop user guest_select@localhost; drop table federated.t1; drop server 's1'; +# +# Bug#30671 - ALTER SERVER causes the server to crash +# +create server 's1' foreign data wrapper 'mysql' options (port 3306); +alter server 's1' options + (host 'localhost', database '', user '', + password '', socket '', owner '', port 3306); +# The next statement would crash unpatched server +alter server 's1' options + (host 'localhost', database 'database1', user '', + password '', socket '', owner '', port 3306); +drop server 's1'; --echo # End of 5.1 tests diff --git a/sql/sql_servers.cc b/sql/sql_servers.cc index a780c561ffe..543884fdfa6 100644 --- a/sql/sql_servers.cc +++ b/sql/sql_servers.cc @@ -289,7 +289,7 @@ get_server_from_table_to_cache(TABLE *table) { /* alloc a server struct */ char *ptr; - char *blank= (char*)""; + char * const blank= (char*)""; FOREIGN_SERVER *server= (FOREIGN_SERVER *)alloc_root(&mem, sizeof(FOREIGN_SERVER)); DBUG_ENTER("get_server_from_table_to_cache"); @@ -312,7 +312,7 @@ get_server_from_table_to_cache(TABLE *table) server->port= server->sport ? atoi(server->sport) : 0; ptr= get_field(&mem, table->field[6]); - server->socket= ptr && strlen(ptr) ? ptr : NULL; + server->socket= ptr && strlen(ptr) ? ptr : blank; ptr= get_field(&mem, table->field[7]); server->scheme= ptr ? ptr : blank; ptr= get_field(&mem, table->field[8]); From b0e9fa31afb8c110bb1dcef0f1f46d20279ba6b6 Mon Sep 17 00:00:00 2001 From: "gluh@mysql.com/eagle.(none)" <> Date: Fri, 2 Nov 2007 12:24:45 +0400 Subject: [PATCH 128/336] Bug#31113 mysqldump 5.1 can't handle a dash ("-") in database names db name should be quoted. this code does communication with the server. it's always ok to quote names in this case. --- client/mysqldump.c | 4 +++- mysql-test/r/mysqldump.result | 19 +++++++++++++++++++ mysql-test/t/mysqldump.test | 12 ++++++++++++ 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/client/mysqldump.c b/client/mysqldump.c index d504d177490..f5362b272cd 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -1040,8 +1040,10 @@ static int fetch_db_collation(const char *db_name, char query[QUERY_LENGTH]; MYSQL_RES *db_cl_res; MYSQL_ROW db_cl_row; + char quoted_database_buf[NAME_LEN*2+3]; + char *qdatabase= quote_name(db_name, quoted_database_buf, 1); - my_snprintf(query, sizeof (query), "use %s", db_name); + my_snprintf(query, sizeof (query), "use %s", qdatabase); if (mysql_query_with_error_report(mysql, NULL, query)) return 1; diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index c0856314ba5..d07aed5317a 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -4212,5 +4212,24 @@ TRUNCATE mysql.event; SHOW EVENTS; Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status Originator character_set_client collation_connection Database Collation # +# Bug#31113 mysqldump 5.1 can't handle a dash ("-") in database names +# +create database `test-database`; +use `test-database`; +create table test (a int); +DROP TABLE IF EXISTS `test`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `test` ( + `a` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; +LOCK TABLES `test` WRITE; +/*!40000 ALTER TABLE `test` DISABLE KEYS */; +/*!40000 ALTER TABLE `test` ENABLE KEYS */; +UNLOCK TABLES; +drop database `test-database`; +use test; +# # End of 5.1 tests # diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test index 158e8a769bd..0e4e9989ffa 100644 --- a/mysql-test/t/mysqldump.test +++ b/mysql-test/t/mysqldump.test @@ -1788,6 +1788,18 @@ TRUNCATE mysql.event; --exec $MYSQL < $MYSQLTEST_VARDIR/tmp/bug29938.sql SHOW EVENTS; + +--echo # +--echo # Bug#31113 mysqldump 5.1 can't handle a dash ("-") in database names +--echo # +create database `test-database`; +use `test-database`; +create table test (a int); +--exec $MYSQL_DUMP --compact --opt --quote-names test-database +drop database `test-database`; +use test; + + --echo # --echo # End of 5.1 tests --echo # From 4198c2bcf5f28a088bc9610fb2d2fbe9f9548309 Mon Sep 17 00:00:00 2001 From: "gluh@mysql.com/eagle.(none)" <> Date: Fri, 2 Nov 2007 12:39:14 +0400 Subject: [PATCH 129/336] Bug#31630 debug assert with explain extended select ... from i_s added 'in_rows' column value for 'describe extended' for the case when 'describe' handles I_S table --- mysql-test/r/information_schema.result | 5 +++++ mysql-test/t/information_schema.test | 5 +++++ sql/sql_select.cc | 4 ++++ 3 files changed, 14 insertions(+) diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index 7693fe628ef..18ffb4a37ea 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -1604,4 +1604,9 @@ select * from `information_schema`.`VIEWS` where `TABLE_SCHEMA` = NULL; TABLE_CATALOG TABLE_SCHEMA TABLE_NAME VIEW_DEFINITION CHECK_OPTION IS_UPDATABLE DEFINER SECURITY_TYPE CHARACTER_SET_CLIENT COLLATION_CONNECTION select * from `information_schema`.`VIEWS` where `TABLE_NAME` = NULL; TABLE_CATALOG TABLE_SCHEMA TABLE_NAME VIEW_DEFINITION CHECK_OPTION IS_UPDATABLE DEFINER SECURITY_TYPE CHARACTER_SET_CLIENT COLLATION_CONNECTION +explain extended select 1 from information_schema.TABLES; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE TABLES ALL NULL NULL NULL NULL NULL NULL Skip_open_table; Scanned all databases +Warnings: +Note 1003 select 1 AS `1` from `information_schema`.`TABLES` End of 5.1 tests. diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test index 1987d9d5773..5ac7ffa42ad 100644 --- a/mysql-test/t/information_schema.test +++ b/mysql-test/t/information_schema.test @@ -1232,4 +1232,9 @@ select * from `information_schema`.`TRIGGERS` where `EVENT_OBJECT_TABLE` = NULL; select * from `information_schema`.`VIEWS` where `TABLE_SCHEMA` = NULL; select * from `information_schema`.`VIEWS` where `TABLE_NAME` = NULL; +# +# Bug#31630 debug assert with explain extended select ... from i_s +# +explain extended select 1 from information_schema.TABLES; + --echo End of 5.1 tests. diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 140daf8b55d..596f8d8a294 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -15819,6 +15819,10 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, /* Add "rows" field to item_list. */ if (table_list->schema_table) { + /* in_rows */ + if (join->thd->lex->describe & DESCRIBE_EXTENDED) + item_list.push_back(item_null); + /* rows */ item_list.push_back(item_null); } else From 3afce4aa2ca1bd0dcf694e23163d05ff8a9d96ce Mon Sep 17 00:00:00 2001 From: "istruewing@stella.local" <> Date: Fri, 2 Nov 2007 09:58:29 +0100 Subject: [PATCH 130/336] Bug#32048 - innodb_mysql.test produces warnings files Typo --#echo at line begin in test files lead to warnings from mysqltest. Changed to --echo #. --- mysql-test/include/mix1.inc | 2 +- mysql-test/r/innodb_mysql.result | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/mysql-test/include/mix1.inc b/mysql-test/include/mix1.inc index c8d3ba79e39..211bd0b4908 100644 --- a/mysql-test/include/mix1.inc +++ b/mysql-test/include/mix1.inc @@ -1163,7 +1163,7 @@ CREATE TABLE t1 (a INT PRIMARY KEY, b VARCHAR(256)) ENGINE = $engine_type; INSERT INTO t1 VALUES (1,2); ---#echo 1. test for locking: +--echo # 1. test for locking: BEGIN; --enable_info diff --git a/mysql-test/r/innodb_mysql.result b/mysql-test/r/innodb_mysql.result index 44d874ef018..2332056ec39 100644 --- a/mysql-test/r/innodb_mysql.result +++ b/mysql-test/r/innodb_mysql.result @@ -1426,6 +1426,7 @@ SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; CREATE TABLE t1 (a INT PRIMARY KEY, b VARCHAR(256)) ENGINE = InnoDB; INSERT INTO t1 VALUES (1,2); +# 1. test for locking: BEGIN; UPDATE t1 SET b = 12 WHERE a = 1; affected rows: 1 From 8d4b8423f71d0fe64e4ed293470698c4ac6f60dc Mon Sep 17 00:00:00 2001 From: "istruewing@stella.local" <> Date: Fri, 2 Nov 2007 10:11:26 +0100 Subject: [PATCH 131/336] Bug#31030 - rpl000015.test fails if $MYSQL_TCP_PORT != 3306 Preliminarily disabled test case --- mysql-test/t/disabled.def | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index 9bfe9567d83..80b28e11da6 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -10,3 +10,4 @@ # ############################################################################## +rpl000015 : Bug#31030 - rpl000015.test fails if $MYSQL_TCP_PORT != 3306 From 9cd5f49c538dc266b41479d9e0bc63a47f4d766c Mon Sep 17 00:00:00 2001 From: "kaa@polly.(none)" <> Date: Fri, 2 Nov 2007 13:40:34 +0300 Subject: [PATCH 132/336] Fix for: bug #26215: mysql command line client should not strip comments from SQL statements and bug #11230: Keeping comments when storing stored procedures With the introduction of multiline comments support in the command line client (mysql) in MySQL 4.1, it became impossible to preserve client-side comments within single SQL statements or stored routines. This feature was useful for monitoring tools and maintenance. The patch adds a new option to the command line client ('--enable-comments', '-c') which allows to preserve SQL comments and send them to the server for single SQL statements, and to keep comments in the code for stored procedures / functions / triggers. The patch is a modification of the contributed patch from bug #11230 with the following changes: - code style changes to conform to the coding guidelines - changed is_prefix() to my_strnncoll() to detect the DELIMITER command, since the first one is case-sensitive and not charset-aware - renamed t/comments-51.* to t/mysql_comments.* - removed tests for comments in triggers since 5.0 does not have SHOW CREATE TRIGGER (those tests will be added back in 5.1). The test cases are only for bug #11230. No automated test case for bug #26215 is possible due to the test suite deficiencies (though the cases from the bug report were tested manually). --- client/mysql.cc | 168 ++++++++++++++++++++------- mysql-test/r/mysql_comments.result | 50 ++++++++ mysql-test/t/mysql_comments.sql | 177 +++++++++++++++++++++++++++++ mysql-test/t/mysql_comments.test | 37 ++++++ 4 files changed, 389 insertions(+), 43 deletions(-) create mode 100644 mysql-test/r/mysql_comments.result create mode 100644 mysql-test/t/mysql_comments.sql create mode 100644 mysql-test/t/mysql_comments.test diff --git a/client/mysql.cc b/client/mysql.cc index 8e1b6c2a9b4..2c6d0df2274 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -140,6 +140,7 @@ static my_bool info_flag=0,ignore_errors=0,wait_flag=0,quick=0, default_pager_set= 0, opt_sigint_ignore= 0, show_warnings= 0; static volatile int executing_query= 0, interrupted_query= 0; +static my_bool preserve_comments= 0; static ulong opt_max_allowed_packet, opt_net_buffer_length; static uint verbose=0,opt_silent=0,opt_mysql_port=0, opt_local_infile=0; static my_string opt_mysql_unix_port=0; @@ -754,6 +755,10 @@ static struct my_option my_long_options[] = {"show-warnings", OPT_SHOW_WARNINGS, "Show warnings after every statement.", (gptr*) &show_warnings, (gptr*) &show_warnings, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"comments", 'c', "Preserve comments. Send comments to the server." + " Comments are discarded by default, enable with --enable-comments", + (gptr*) &preserve_comments, (gptr*) &preserve_comments, + 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; @@ -1131,10 +1136,6 @@ static int read_and_execute(bool interactive) status.exit_status=0; break; } - if (!in_string && (line[0] == '#' || - (line[0] == '-' && line[1] == '-') || - line[0] == 0)) - continue; // Skip comment lines /* Check if line is a mysql command line @@ -1260,15 +1261,21 @@ static bool add_line(String &buffer,char *line,char *in_string, for (pos=out=line ; (inchar= (uchar) *pos) ; pos++) { - if (my_isspace(charset_info,inchar) && out == line && - buffer.is_empty()) - continue; + if (!preserve_comments) + { + // Skip spaces at the beggining of a statement + if (my_isspace(charset_info,inchar) && (out == line) && + buffer.is_empty()) + continue; + } + #ifdef USE_MB + // Accept multi-byte characters as-is int length; if (use_mb(charset_info) && (length= my_ismbchar(charset_info, pos, end_of_line))) { - if (!*ml_comment) + if (!*ml_comment || preserve_comments) { while (length--) *out++ = *pos++; @@ -1294,8 +1301,13 @@ static bool add_line(String &buffer,char *line,char *in_string, } if ((com=find_command(NullS,(char) inchar))) { - const String tmp(line,(uint) (out-line), charset_info); - buffer.append(tmp); + // Flush previously accepted characters + if (out != line) + { + buffer.append(line, (uint) (out-line)); + out= line; + } + if ((*com->func)(&buffer,pos-1) > 0) DBUG_RETURN(1); // Quit if (com->takes_params) @@ -1323,7 +1335,6 @@ static bool add_line(String &buffer,char *line,char *in_string, pos+= delimiter_length - 1; // Point at last delim char } } - out=line; } else { @@ -1336,46 +1347,106 @@ static bool add_line(String &buffer,char *line,char *in_string, } } else if (!*ml_comment && !*in_string && - (*pos == *delimiter && is_prefix(pos + 1, delimiter + 1) || - buffer.length() == 0 && (out - line) >= 9 && - !my_strcasecmp(charset_info, line, "delimiter"))) - { - uint old_delimiter_length= delimiter_length; + (out - line) >= 9 && + !my_strnncoll(charset_info, (uchar*) pos, 9, + (const uchar*) "delimiter", 9) && + my_isspace(charset_info, pos[9])) + { + // Flush previously accepted characters if (out != line) - buffer.append(line, (uint) (out - line)); // Add this line + { + buffer.append(line, (uint32) (out - line)); + out= line; + } + + // Flush possible comments in the buffer + if (!buffer.is_empty()) + { + if (com_go(&buffer, 0) > 0) // < 0 is not fatal + DBUG_RETURN(1); + buffer.length(0); + } + + /* + Delimiter wants the get rest of the given line as argument to + allow one to change ';' to ';;' and back + */ + buffer.append(pos); + if (com_delimiter(&buffer, pos) > 0) + DBUG_RETURN(1); + + buffer.length(0); + break; + } + else if (!*ml_comment && !*in_string && is_prefix(pos, delimiter)) + { + // Found a statement. Continue parsing after the delimiter + pos+= delimiter_length; + + if (preserve_comments) + { + while (my_isspace(charset_info, *pos)) + *out++= *pos++; + } + // Flush previously accepted characters + if (out != line) + { + buffer.append(line, (uint32) (out-line)); + out= line; + } + + if (preserve_comments && ((*pos == '#') || + ((*pos == '-') && + (pos[1] == '-') && + my_isspace(charset_info, pos[2])))) + { + // Add trailing single line comments to this statement + buffer.append(pos); + pos+= strlen(pos); + } + + pos--; + if ((com= find_command(buffer.c_ptr(), 0))) { - if (com->func == com_delimiter) - { - /* - Delimiter wants the get rest of the given line as argument to - allow one to change ';' to ';;' and back - */ - char *end= strend(pos); - buffer.append(pos, (uint) (end - pos)); - /* Ensure pos will point at \0 after the pos+= below */ - pos= end - old_delimiter_length + 1; - } - if ((*com->func)(&buffer, buffer.c_ptr()) > 0) - DBUG_RETURN(1); // Quit + + if ((*com->func)(&buffer, buffer.c_ptr()) > 0) + DBUG_RETURN(1); // Quit } else { - if (com_go(&buffer, 0) > 0) // < 0 is not fatal - DBUG_RETURN(1); + if (com_go(&buffer, 0) > 0) // < 0 is not fatal + DBUG_RETURN(1); } buffer.length(0); - out= line; - pos+= old_delimiter_length - 1; } else if (!*ml_comment && (!*in_string && (inchar == '#' || inchar == '-' && pos[1] == '-' && my_isspace(charset_info,pos[2])))) - break; // comment to end of line + { + // Flush previously accepted characters + if (out != line) + { + buffer.append(line, (uint32) (out - line)); + out= line; + } + + // comment to end of line + if (preserve_comments) + buffer.append(pos); + + break; + } else if (!*in_string && inchar == '/' && *(pos+1) == '*' && *(pos+2) != '!') { - pos++; + if (preserve_comments) + { + *out++= *pos++; // copy '/' + *out++= *pos; // copy '*' + } + else + pos++; *ml_comment= 1; if (out != line) { @@ -1385,8 +1456,21 @@ static bool add_line(String &buffer,char *line,char *in_string, } else if (*ml_comment && !ss_comment && inchar == '*' && *(pos + 1) == '/') { - pos++; + if (preserve_comments) + { + *out++= *pos++; // copy '*' + *out++= *pos; // copy '/' + } + else + pos++; *ml_comment= 0; + if (out != line) + { + buffer.append(line, (uint32) (out - line)); + out= line; + } + // Consumed a 2 chars or more, and will add 1 at most, + // so using the 'line' buffer to edit data in place is ok. need_space= 1; } else @@ -1401,14 +1485,12 @@ static bool add_line(String &buffer,char *line,char *in_string, else if (!*ml_comment && !*in_string && (inchar == '\'' || inchar == '"' || inchar == '`')) *in_string= (char) inchar; - if (!*ml_comment) + if (!*ml_comment || preserve_comments) { if (need_space && !my_isspace(charset_info, (char)inchar)) - { *out++= ' '; - need_space= 0; - } - *out++= (char) inchar; + need_space= 0; + *out++= (char) inchar; } } } @@ -1418,7 +1500,7 @@ static bool add_line(String &buffer,char *line,char *in_string, uint length=(uint) (out-line); if (buffer.length() + length >= buffer.alloced_length()) buffer.realloc(buffer.length()+length+IO_SIZE); - if (!(*ml_comment) && buffer.append(line,length)) + if ((!*ml_comment || preserve_comments) && buffer.append(line, length)) DBUG_RETURN(1); } DBUG_RETURN(0); diff --git a/mysql-test/r/mysql_comments.result b/mysql-test/r/mysql_comments.result new file mode 100644 index 00000000000..366ceeb5bbf --- /dev/null +++ b/mysql-test/r/mysql_comments.result @@ -0,0 +1,50 @@ +drop table if exists t1; +drop function if exists foofct; +drop procedure if exists empty; +drop procedure if exists foosp; +drop procedure if exists nicesp; +drop trigger if exists t1_empty; +drop trigger if exists t1_bi; +"Pass 1 : --disable-comments" +1 +1 +2 +2 +foofct("call 1") +call 1 +Function sql_mode Create Function +foofct CREATE DEFINER=`root`@`localhost` FUNCTION `foofct`(x char(20)) RETURNS char(20) CHARSET latin1\nreturn\n\n\n\nx +foofct("call 2") +call 2 +Function sql_mode Create Function +foofct CREATE DEFINER=`root`@`localhost` FUNCTION `foofct`(x char(20)) RETURNS char(20) CHARSET latin1\nbegin\n \n \n \n\n \n\n \n return x;\nend +Procedure sql_mode Create Procedure +empty CREATE DEFINER=`root`@`localhost` PROCEDURE `empty`()\nbegin\nend +id data +foo 42 +Procedure sql_mode Create Procedure +foosp CREATE DEFINER=`root`@`localhost` PROCEDURE `foosp`()\ninsert into test.t1\n\n\n\n\n \n\n \n values ("foo", 42) +Procedure sql_mode Create Procedure +nicesp CREATE DEFINER=`root`@`localhost` PROCEDURE `nicesp`(a int)\nbegin\n \n declare b int;\n declare c float;\n\n \n \n\n \nend +"Pass 2 : --enable-comments" +1 +1 +2 +2 +foofct("call 1") +call 1 +Function sql_mode Create Function +foofct CREATE DEFINER=`root`@`localhost` FUNCTION `foofct`(x char(20)) RETURNS char(20) CHARSET latin1\nreturn\n-- comment 1a\n# comment 1b\n/* comment 1c */\nx # after body, on same line +foofct("call 2") +call 2 +Function sql_mode Create Function +foofct CREATE DEFINER=`root`@`localhost` FUNCTION `foofct`(x char(20)) RETURNS char(20) CHARSET latin1\nbegin\n -- comment 1a\n # comment 1b\n /*\n comment 1c\n */\n\n -- empty line below\n\n -- empty line above\n return x;\nend +Procedure sql_mode Create Procedure +empty CREATE DEFINER=`root`@`localhost` PROCEDURE `empty`()\nbegin\nend +id data +foo 42 +Procedure sql_mode Create Procedure +foosp CREATE DEFINER=`root`@`localhost` PROCEDURE `foosp`()\ninsert into test.t1\n## These comments are part of the procedure body, and should be kept.\n# Comment 2a\n-- Comment 2b\n/* Comment 2c */\n -- empty line below\n\n -- empty line above\n values ("foo", 42) # comment 3, still part of the body +Procedure sql_mode Create Procedure +nicesp CREATE DEFINER=`root`@`localhost` PROCEDURE `nicesp`(a int)\nbegin\n -- declare some variables here\n declare b int;\n declare c float;\n\n -- do more stuff here\n -- commented nicely and so on\n\n -- famous last words ...\nend +End of 5.0 tests diff --git a/mysql-test/t/mysql_comments.sql b/mysql-test/t/mysql_comments.sql new file mode 100644 index 00000000000..60b223a240f --- /dev/null +++ b/mysql-test/t/mysql_comments.sql @@ -0,0 +1,177 @@ +##============================================================================ +## Notes +##============================================================================ + +# Test case for Bug#11230 + +# The point of this test is to make sure that '#', '-- ' and '/* ... */' +# comments, as well as empty lines, are sent from the client to the server. +# This is to ensure better error reporting, and to keep comments in the code +# for stored procedures / functions / triggers (Bug#11230). +# As a result, be careful when editing comments in this script, they do +# matter. +# +# Also, note that this is a script for **mysql**, not mysqltest. +# This is critical, as the mysqltest client interprets comments differently. + +##============================================================================ +## Setup +##============================================================================ + +## See mysql_comments.test for initial cleanup + +# Test tables +# +# t1 is reused throughout the file, and dropped at the end. +# +drop table if exists t1; +create table t1 ( + id char(16) not null default '', + data int not null +); + +##============================================================================ +## Comments outside statements +##============================================================================ + +# Ignored 1a +-- Ignored 1b +/* + Ignored 1c +*/ + +select 1; + +##============================================================================ +## Comments inside statements +##============================================================================ + +select # comment 1a +# comment 2a +-- comment 2b +/* + comment 2c +*/ +2 +; # not strictly inside, but on same line +# ignored + +##============================================================================ +## Comments inside functions +##============================================================================ + +drop function if exists foofct ; + +create function foofct (x char(20)) +returns char(20) +/* not inside the body yet */ +return +-- comment 1a +# comment 1b +/* comment 1c */ +x; # after body, on same line + +select foofct("call 1"); + +show create function foofct; +drop function foofct; + +delimiter | + +create function foofct(x char(20)) +returns char(20) +begin + -- comment 1a + # comment 1b + /* + comment 1c + */ + + -- empty line below + + -- empty line above + return x; +end| + +delimiter ; + +select foofct("call 2"); + +show create function foofct; +drop function foofct; + +##============================================================================ +## Comments inside stored procedures +##============================================================================ + +# Empty statement +drop procedure if exists empty; +create procedure empty() +begin +end; + +call empty(); +show create procedure empty; +drop procedure empty; + +drop procedure if exists foosp; + +## These comments are before the create, and will be lost +# Comment 1a +-- Comment 1b +/* + Comment 1c + */ +create procedure foosp() +/* Comment not quiet in the body yet */ + insert into test.t1 +## These comments are part of the procedure body, and should be kept. +# Comment 2a +-- Comment 2b +/* Comment 2c */ + -- empty line below + + -- empty line above + values ("foo", 42); # comment 3, still part of the body +## After the ';', therefore not part of the body +# comment 4a +-- Comment 4b +/* + Comment 4c + */ + +call foosp(); +select * from t1; +delete from t1; +show create procedure foosp; +drop procedure foosp; + +drop procedure if exists nicesp; + +delimiter | + +create procedure nicesp(a int) +begin + -- declare some variables here + declare b int; + declare c float; + + -- do more stuff here + -- commented nicely and so on + + -- famous last words ... +end| + +delimiter ; + +show create procedure nicesp; +drop procedure nicesp; + +# Triggers can be tested only in 5.1, since 5.0 does not have +# SHOW CREATE TRIGGER + +##============================================================================ +## Cleanup +##============================================================================ + +drop table t1; diff --git a/mysql-test/t/mysql_comments.test b/mysql-test/t/mysql_comments.test new file mode 100644 index 00000000000..1f997aeb1ab --- /dev/null +++ b/mysql-test/t/mysql_comments.test @@ -0,0 +1,37 @@ +# This test should work in embedded server after we fix mysqltest +-- source include/not_embedded.inc +###################### mysql_comments.test ############################# +# # +# Testing of comments handling by the command line client (mysql) # +# # +# Creation: # +# 2007-10-29 akopytov Implemented this test as a part of fixes for # +# bug #26215 and bug #11230 # +# # +######################################################################## + +# +# Bug #11230: Keeping comments when storing stored procedures +# + +# See the content of mysql_comments.sql +# Set the test database to a known state before running the tests. +--disable_warnings +drop table if exists t1; +drop function if exists foofct; +drop procedure if exists empty; +drop procedure if exists foosp; +drop procedure if exists nicesp; +drop trigger if exists t1_empty; +drop trigger if exists t1_bi; +--enable_warnings + +# Test without comments +--echo "Pass 1 : --disable-comments" +--exec $MYSQL --disable-comments test 2>&1 < "./t/mysql_comments.sql" + +# Test with comments +--echo "Pass 2 : --enable-comments" +--exec $MYSQL --enable-comments test 2>&1 < "./t/mysql_comments.sql" + +--echo End of 5.0 tests From fe129ce235908d8ad2194ca70027067cc2d05d22 Mon Sep 17 00:00:00 2001 From: "kent@mysql.com/kent-amd64.(none)" <> Date: Fri, 2 Nov 2007 12:29:13 +0100 Subject: [PATCH 133/336] mysql.info, INSTALL-BINARY, INSTALL-SOURCE, ReadMe.txt, Docs/Makefile.am: Let place holders for real documentation have text that makes sense to the user (Bug#25205) --- Docs/INSTALL-BINARY | 8 ++++++ Docs/Makefile.am | 29 ++----------------- Docs/Support/generate-text-files.pl | 43 ----------------------------- Docs/mysql.info | 29 ++----------------- INSTALL-SOURCE | 8 ++++++ support-files/MacOSX/ReadMe.txt | 8 ++++++ 6 files changed, 30 insertions(+), 95 deletions(-) create mode 100644 Docs/INSTALL-BINARY delete mode 100755 Docs/Support/generate-text-files.pl create mode 100644 INSTALL-SOURCE create mode 100644 support-files/MacOSX/ReadMe.txt diff --git a/Docs/INSTALL-BINARY b/Docs/INSTALL-BINARY new file mode 100644 index 00000000000..54d10028dc3 --- /dev/null +++ b/Docs/INSTALL-BINARY @@ -0,0 +1,8 @@ + +You can find information about how to install binary distributions at + + http://dev.mysql.com/doc/refman/4.1/en/quick-standard-installation.html + +The MySQL Reference Manual is also available in various formats on +http://dev.mysql.com/doc; if you're interested in the DocBook XML +sources go to http://svn.mysql.com. diff --git a/Docs/Makefile.am b/Docs/Makefile.am index 6a1ee131d1a..31bc14af4ab 100644 --- a/Docs/Makefile.am +++ b/Docs/Makefile.am @@ -14,38 +14,15 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -noinst_SCRIPTS = Support/generate-text-files.pl - -EXTRA_DIST = $(noinst_SCRIPTS) mysql.info INSTALL-BINARY - -all: txt_files - -txt_files: ../INSTALL-SOURCE \ - INSTALL-BINARY ../support-files/MacOSX/ReadMe.txt +EXTRA_DIST = mysql.info INSTALL-BINARY # make sure that "make install" installs the info page, too # automake only seems to take care of this automatically, # if we're building the info page from texi directly. -install-data-hook: mysql.info +install-data-hook: $(EXTRA_DIST) $(mkinstalldirs) $(DESTDIR)$(infodir) $(INSTALL_DATA) $(srcdir)/mysql.info $(DESTDIR)$(infodir) - -CLEAN_FILES: $(txt_files) - touch $(txt_files) - -GT = $(srcdir)/Support/generate-text-files.pl - -../INSTALL-SOURCE: mysql.info $(GT) - perl -w $(GT) mysql.info "installing-source" "windows-source-build" > $@ - -# We put the description for the binary installation here so that -# people who download source wont have to see it. It is moved up to -# the toplevel by the script that makes the binary tar files. -INSTALL-BINARY: mysql.info $(GT) - perl -w $(GT) mysql.info "installing-binary" "installing-source" > $@ - -../support-files/MacOSX/ReadMe.txt: mysql.info $(GT) - perl -w $(GT) mysql.info "mac-os-x-installation" "netware-installation" > $@ + $(INSTALL_DATA) $(srcdir)/INSTALL-BINARY $(DESTDIR)$(infodir) # Don't update the files from bitkeeper %::SCCS/s.% diff --git a/Docs/Support/generate-text-files.pl b/Docs/Support/generate-text-files.pl deleted file mode 100755 index 0829525f679..00000000000 --- a/Docs/Support/generate-text-files.pl +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/perl -w -*- perl -*- -# Generate text files from top directory from the manual. - -$from = shift(@ARGV); -$fnode = shift(@ARGV); -$tnode = shift(@ARGV); - -open(IN, "$from") || die "Cannot open $from: $!"; - -$in = 0; - -while () -{ - if ($in) - { - if (/Node: $tnode,/ || /\[index/) - { - $in = 0; - } - elsif (/^File: mysql.info/ || (/^/)) - { - # Just Skip node beginnings - } - else - { - print; - } - } - else - { - if (/Node: $fnode,/) - { - $in = 1; - # Skip first empty line - ; - } - } -} - -close(IN); - -die "Could not find node \"$tnode\"" if ($in == 1); -exit 0; diff --git a/Docs/mysql.info b/Docs/mysql.info index 5846d7aadf6..b2c411e51ab 100644 --- a/Docs/mysql.info +++ b/Docs/mysql.info @@ -1,27 +1,4 @@ -This is mysql.info, produced by makeinfo version 4.8 from manual.texi. -START-INFO-DIR-ENTRY -* mysql: (mysql). MySQL documentation. -END-INFO-DIR-ENTRY - - -File: mysql.info, Node: Top, Next: (dir), Prev: (dir), Up: (dir) - -This is an empty placeholder file for the MySQL manual. - -The MySQL manual is now maintained in a separate BitKeeper source tree! -Please see `http://www.mysql.com/doc/en/Installing_source_tree.html' -for more info on how to work with BitKeeper. - -This file will be replaced with the current `mysql.info' when building -the official source distribution. - -You can find a specific manual for any older version of MySQL in the -binary or source distribution for that version. - - - -Tag Table: -Node: Top166 - -End Tag Table +The MySQL Reference Manual is available in various formats on +http://dev.mysql.com/doc; if you're interested in the DocBook XML +sources go to http://svn.mysql.com. diff --git a/INSTALL-SOURCE b/INSTALL-SOURCE new file mode 100644 index 00000000000..5c54869f1bf --- /dev/null +++ b/INSTALL-SOURCE @@ -0,0 +1,8 @@ + +You can find information about how to install from a source distributions at + + http://dev.mysql.com/doc/refman/4.1/en/installing-source.html + +The MySQL Reference Manual is also available in various formats on +http://dev.mysql.com/doc; if you're interested in the DocBook XML +sources go to http://svn.mysql.com. diff --git a/support-files/MacOSX/ReadMe.txt b/support-files/MacOSX/ReadMe.txt new file mode 100644 index 00000000000..8e721448c8d --- /dev/null +++ b/support-files/MacOSX/ReadMe.txt @@ -0,0 +1,8 @@ + +You can find information about how to install on Mac OS X at + + http://dev.mysql.com/doc/refman/4.1/en/mac-os-x-installation.html + +The MySQL Reference Manual is also available in various formats on +http://dev.mysql.com/doc; if you're interested in the DocBook XML +sources go to http://svn.mysql.com. From e22bb190d76431ce752623051d4810c0082e1c31 Mon Sep 17 00:00:00 2001 From: "kent@mysql.com/kent-amd64.(none)" <> Date: Fri, 2 Nov 2007 12:36:44 +0100 Subject: [PATCH 134/336] INSTALL-WIN-SOURCE: BitKeeper file /home/kent/bk/bug25205/mysql-4.1-build/INSTALL-WIN-SOURCE --- INSTALL-WIN-SOURCE | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 INSTALL-WIN-SOURCE diff --git a/INSTALL-WIN-SOURCE b/INSTALL-WIN-SOURCE new file mode 100644 index 00000000000..60eb2ff0cfc --- /dev/null +++ b/INSTALL-WIN-SOURCE @@ -0,0 +1,9 @@ + +You can find information about how to install from a Windows source +distributions at + + http://dev.mysql.com/doc/refman/4.1/en/windows-source-build.html + +The MySQL Reference Manual is also available in various formats on +http://dev.mysql.com/doc; if you're interested in the DocBook XML +sources go to http://svn.mysql.com. From ee295affba6b71679af7fb873c225b27629b17a1 Mon Sep 17 00:00:00 2001 From: "kent@mysql.com/kent-amd64.(none)" <> Date: Fri, 2 Nov 2007 12:59:45 +0100 Subject: [PATCH 135/336] Makefile.am: Added manual.chm to EXTRA_DIST Removed install of INSTALL-BINARY, handled by install scripts. ReadMe.txt, INSTALL-WIN-SOURCE, INSTALL-BINARY, INSTALL-SOURCE: Updated links to version 5.0 of the manual --- Docs/INSTALL-BINARY | 2 +- Docs/Makefile.am | 6 ++---- INSTALL-SOURCE | 2 +- INSTALL-WIN-SOURCE | 2 +- support-files/MacOSX/ReadMe.txt | 2 +- 5 files changed, 6 insertions(+), 8 deletions(-) diff --git a/Docs/INSTALL-BINARY b/Docs/INSTALL-BINARY index 54d10028dc3..ba7e72af94d 100644 --- a/Docs/INSTALL-BINARY +++ b/Docs/INSTALL-BINARY @@ -1,7 +1,7 @@ You can find information about how to install binary distributions at - http://dev.mysql.com/doc/refman/4.1/en/quick-standard-installation.html + http://dev.mysql.com/doc/refman/5.0/en/quick-standard-installation.html The MySQL Reference Manual is also available in various formats on http://dev.mysql.com/doc; if you're interested in the DocBook XML diff --git a/Docs/Makefile.am b/Docs/Makefile.am index 95a04862406..d161836aaca 100644 --- a/Docs/Makefile.am +++ b/Docs/Makefile.am @@ -13,19 +13,17 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -EXTRA_DIST = mysql.info INSTALL-BINARY +EXTRA_DIST = manual.chm mysql.info INSTALL-BINARY # make sure that "make install" installs the info page, too # automake only seems to take care of this automatically, # if we're building the info page from texi directly. -install-data-hook: $(srcdir)/mysql.info $(srcdir)/INSTALL-BINARY +install-data-hook: $(srcdir)/mysql.info $(mkinstalldirs) $(DESTDIR)$(infodir) $(INSTALL_DATA) $(srcdir)/mysql.info $(DESTDIR)$(infodir) - $(INSTALL_DATA) $(srcdir)/INSTALL-BINARY $(DESTDIR)$(infodir) uninstall-local: @RM@ -f $(DESTDIR)$(infodir)/mysql.info - @RM@ -f $(DESTDIR)$(infodir)/INSTALL-BINARY # Don't update the files from bitkeeper %::SCCS/s.% diff --git a/INSTALL-SOURCE b/INSTALL-SOURCE index 5c54869f1bf..3d9d7d41114 100644 --- a/INSTALL-SOURCE +++ b/INSTALL-SOURCE @@ -1,7 +1,7 @@ You can find information about how to install from a source distributions at - http://dev.mysql.com/doc/refman/4.1/en/installing-source.html + http://dev.mysql.com/doc/refman/5.0/en/installing-source.html The MySQL Reference Manual is also available in various formats on http://dev.mysql.com/doc; if you're interested in the DocBook XML diff --git a/INSTALL-WIN-SOURCE b/INSTALL-WIN-SOURCE index 60eb2ff0cfc..2478e2cf609 100644 --- a/INSTALL-WIN-SOURCE +++ b/INSTALL-WIN-SOURCE @@ -2,7 +2,7 @@ You can find information about how to install from a Windows source distributions at - http://dev.mysql.com/doc/refman/4.1/en/windows-source-build.html + http://dev.mysql.com/doc/refman/5.0/en/windows-source-build.html The MySQL Reference Manual is also available in various formats on http://dev.mysql.com/doc; if you're interested in the DocBook XML diff --git a/support-files/MacOSX/ReadMe.txt b/support-files/MacOSX/ReadMe.txt index 8e721448c8d..485dbaeaa37 100644 --- a/support-files/MacOSX/ReadMe.txt +++ b/support-files/MacOSX/ReadMe.txt @@ -1,7 +1,7 @@ You can find information about how to install on Mac OS X at - http://dev.mysql.com/doc/refman/4.1/en/mac-os-x-installation.html + http://dev.mysql.com/doc/refman/5.0/en/mac-os-x-installation.html The MySQL Reference Manual is also available in various formats on http://dev.mysql.com/doc; if you're interested in the DocBook XML From 4b9b01545764aa39f702f6720c877c0b26a8810c Mon Sep 17 00:00:00 2001 From: "aelkin/elkin@koti.dsl.inet.fi" <> Date: Fri, 2 Nov 2007 14:00:38 +0200 Subject: [PATCH 136/336] Bug #31554 rpl.rpl_truncate_2myisam test failure: wrong master binlog file name Actually, the failure happened with 3innodb as well. Most probably the reason is in failing to delete a binlog file on __NT__ so that that master increments the index of the binlog file. The test results hide valueable warning that windows could generate about that. The scope of this fix is to make sure we have such warning and to lessen chances for binlog file being held at time of closing. The dump thread is getting a good chance to leave and release the file for its successful deletion. We shall watch over the two tests as regression is not excluded. In that case we would have an extra info possibly explaining why __NT__ env can not close/delete the file. However, regardless of that reason, there is alwasy workaround to mask out non-deterministic binlog index number. --- .../extra/rpl_tests/rpl_truncate_helper.test | 14 ++++--- .../suite/rpl/r/rpl_truncate_2myisam.result | 42 +++++++++++++++++++ .../suite/rpl/r/rpl_truncate_3innodb.result | 42 +++++++++++++++++++ 3 files changed, 92 insertions(+), 6 deletions(-) diff --git a/mysql-test/extra/rpl_tests/rpl_truncate_helper.test b/mysql-test/extra/rpl_tests/rpl_truncate_helper.test index 64a8de7c6a0..76db74acfa1 100644 --- a/mysql-test/extra/rpl_tests/rpl_truncate_helper.test +++ b/mysql-test/extra/rpl_tests/rpl_truncate_helper.test @@ -1,17 +1,16 @@ - ---disable_query_log ---disable_warnings connection slave; STOP SLAVE; +source include/wait_for_slave_to_stop.inc; connection master; +--disable_warnings DROP TABLE IF EXISTS t1; -RESET MASTER; +--enable_warnings connection slave; +--disable_warnings DROP TABLE IF EXISTS t1; +--enable_warnings RESET SLAVE; START SLAVE; ---enable_warnings ---enable_query_log --echo **** On Master **** connection master; @@ -38,3 +37,6 @@ connection master; DROP TABLE t1; let $SERVER_VERSION=`select version()`; source include/show_binlog_events.inc; + +connection master; +RESET MASTER; diff --git a/mysql-test/suite/rpl/r/rpl_truncate_2myisam.result b/mysql-test/suite/rpl/r/rpl_truncate_2myisam.result index c7ef28ba56b..7eee31dab7a 100644 --- a/mysql-test/suite/rpl/r/rpl_truncate_2myisam.result +++ b/mysql-test/suite/rpl/r/rpl_truncate_2myisam.result @@ -4,6 +4,11 @@ reset master; reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; +STOP SLAVE; +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t1; +RESET SLAVE; +START SLAVE; **** On Master **** SET SESSION BINLOG_FORMAT=STATEMENT; SET GLOBAL BINLOG_FORMAT=STATEMENT; @@ -31,10 +36,17 @@ a b DROP TABLE t1; show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS t1 master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT, b LONG) ENGINE=MyISAM master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (1,1), (2,2) master-bin.000001 # Query # # use `test`; TRUNCATE TABLE t1 master-bin.000001 # Query # # use `test`; DROP TABLE t1 +RESET MASTER; +STOP SLAVE; +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t1; +RESET SLAVE; +START SLAVE; **** On Master **** SET SESSION BINLOG_FORMAT=MIXED; SET GLOBAL BINLOG_FORMAT=MIXED; @@ -62,10 +74,17 @@ a b DROP TABLE t1; show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS t1 master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT, b LONG) ENGINE=MyISAM master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (1,1), (2,2) master-bin.000001 # Query # # use `test`; TRUNCATE TABLE t1 master-bin.000001 # Query # # use `test`; DROP TABLE t1 +RESET MASTER; +STOP SLAVE; +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t1; +RESET SLAVE; +START SLAVE; **** On Master **** SET SESSION BINLOG_FORMAT=ROW; SET GLOBAL BINLOG_FORMAT=ROW; @@ -93,11 +112,18 @@ a b DROP TABLE t1; show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS t1 master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT, b LONG) ENGINE=MyISAM master-bin.000001 # Table_map # # table_id: # (test.t1) master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F master-bin.000001 # Query # # use `test`; TRUNCATE TABLE t1 master-bin.000001 # Query # # use `test`; DROP TABLE t1 +RESET MASTER; +STOP SLAVE; +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t1; +RESET SLAVE; +START SLAVE; **** On Master **** SET SESSION BINLOG_FORMAT=STATEMENT; SET GLOBAL BINLOG_FORMAT=STATEMENT; @@ -125,10 +151,17 @@ a b DROP TABLE t1; show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS t1 master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT, b LONG) ENGINE=MyISAM master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (1,1), (2,2) master-bin.000001 # Query # # use `test`; DELETE FROM t1 master-bin.000001 # Query # # use `test`; DROP TABLE t1 +RESET MASTER; +STOP SLAVE; +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t1; +RESET SLAVE; +START SLAVE; **** On Master **** SET SESSION BINLOG_FORMAT=MIXED; SET GLOBAL BINLOG_FORMAT=MIXED; @@ -156,10 +189,17 @@ a b DROP TABLE t1; show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS t1 master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT, b LONG) ENGINE=MyISAM master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (1,1), (2,2) master-bin.000001 # Query # # use `test`; DELETE FROM t1 master-bin.000001 # Query # # use `test`; DROP TABLE t1 +RESET MASTER; +STOP SLAVE; +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t1; +RESET SLAVE; +START SLAVE; **** On Master **** SET SESSION BINLOG_FORMAT=ROW; SET GLOBAL BINLOG_FORMAT=ROW; @@ -188,9 +228,11 @@ a b DROP TABLE t1; show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS t1 master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT, b LONG) ENGINE=MyISAM master-bin.000001 # Table_map # # table_id: # (test.t1) master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F master-bin.000001 # Table_map # # table_id: # (test.t1) master-bin.000001 # Delete_rows # # table_id: # flags: STMT_END_F master-bin.000001 # Query # # use `test`; DROP TABLE t1 +RESET MASTER; diff --git a/mysql-test/suite/rpl/r/rpl_truncate_3innodb.result b/mysql-test/suite/rpl/r/rpl_truncate_3innodb.result index 7ce48c2e983..a6580a5685b 100644 --- a/mysql-test/suite/rpl/r/rpl_truncate_3innodb.result +++ b/mysql-test/suite/rpl/r/rpl_truncate_3innodb.result @@ -4,6 +4,11 @@ reset master; reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; +STOP SLAVE; +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t1; +RESET SLAVE; +START SLAVE; **** On Master **** SET SESSION BINLOG_FORMAT=STATEMENT; SET GLOBAL BINLOG_FORMAT=STATEMENT; @@ -31,12 +36,19 @@ a b DROP TABLE t1; show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS t1 master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT, b LONG) ENGINE=InnoDB master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (1,1), (2,2) master-bin.000001 # Xid # # COMMIT /* XID */ master-bin.000001 # Query # # use `test`; TRUNCATE TABLE t1 master-bin.000001 # Xid # # COMMIT /* XID */ master-bin.000001 # Query # # use `test`; DROP TABLE t1 +RESET MASTER; +STOP SLAVE; +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t1; +RESET SLAVE; +START SLAVE; **** On Master **** SET SESSION BINLOG_FORMAT=MIXED; SET GLOBAL BINLOG_FORMAT=MIXED; @@ -64,12 +76,19 @@ a b DROP TABLE t1; show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS t1 master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT, b LONG) ENGINE=InnoDB master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (1,1), (2,2) master-bin.000001 # Xid # # COMMIT /* XID */ master-bin.000001 # Query # # use `test`; TRUNCATE TABLE t1 master-bin.000001 # Xid # # COMMIT /* XID */ master-bin.000001 # Query # # use `test`; DROP TABLE t1 +RESET MASTER; +STOP SLAVE; +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t1; +RESET SLAVE; +START SLAVE; **** On Master **** SET SESSION BINLOG_FORMAT=ROW; SET GLOBAL BINLOG_FORMAT=ROW; @@ -97,6 +116,7 @@ a b DROP TABLE t1; show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS t1 master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT, b LONG) ENGINE=InnoDB master-bin.000001 # Table_map # # table_id: # (test.t1) master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F @@ -104,6 +124,12 @@ master-bin.000001 # Xid # # COMMIT /* XID */ master-bin.000001 # Query # # use `test`; TRUNCATE TABLE t1 master-bin.000001 # Xid # # COMMIT /* XID */ master-bin.000001 # Query # # use `test`; DROP TABLE t1 +RESET MASTER; +STOP SLAVE; +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t1; +RESET SLAVE; +START SLAVE; **** On Master **** SET SESSION BINLOG_FORMAT=STATEMENT; SET GLOBAL BINLOG_FORMAT=STATEMENT; @@ -131,12 +157,19 @@ a b DROP TABLE t1; show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS t1 master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT, b LONG) ENGINE=InnoDB master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (1,1), (2,2) master-bin.000001 # Xid # # COMMIT /* XID */ master-bin.000001 # Query # # use `test`; DELETE FROM t1 master-bin.000001 # Xid # # COMMIT /* XID */ master-bin.000001 # Query # # use `test`; DROP TABLE t1 +RESET MASTER; +STOP SLAVE; +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t1; +RESET SLAVE; +START SLAVE; **** On Master **** SET SESSION BINLOG_FORMAT=MIXED; SET GLOBAL BINLOG_FORMAT=MIXED; @@ -164,12 +197,19 @@ a b DROP TABLE t1; show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS t1 master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT, b LONG) ENGINE=InnoDB master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (1,1), (2,2) master-bin.000001 # Xid # # COMMIT /* XID */ master-bin.000001 # Query # # use `test`; DELETE FROM t1 master-bin.000001 # Xid # # COMMIT /* XID */ master-bin.000001 # Query # # use `test`; DROP TABLE t1 +RESET MASTER; +STOP SLAVE; +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t1; +RESET SLAVE; +START SLAVE; **** On Master **** SET SESSION BINLOG_FORMAT=ROW; SET GLOBAL BINLOG_FORMAT=ROW; @@ -198,6 +238,7 @@ a b DROP TABLE t1; show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS t1 master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT, b LONG) ENGINE=InnoDB master-bin.000001 # Table_map # # table_id: # (test.t1) master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F @@ -206,3 +247,4 @@ master-bin.000001 # Table_map # # table_id: # (test.t1) master-bin.000001 # Delete_rows # # table_id: # flags: STMT_END_F master-bin.000001 # Xid # # COMMIT /* XID */ master-bin.000001 # Query # # use `test`; DROP TABLE t1 +RESET MASTER; From 2bced2297cd51e93d066735f9a263560c1ff02c6 Mon Sep 17 00:00:00 2001 From: "kent@mysql.com/kent-amd64.(none)" <> Date: Fri, 2 Nov 2007 13:12:19 +0100 Subject: [PATCH 137/336] Makefile.am: Don't install INSTALL-BINARY, handled by build scripts --- Docs/Makefile.am | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Docs/Makefile.am b/Docs/Makefile.am index 31bc14af4ab..3b5aced4001 100644 --- a/Docs/Makefile.am +++ b/Docs/Makefile.am @@ -19,10 +19,9 @@ EXTRA_DIST = mysql.info INSTALL-BINARY # make sure that "make install" installs the info page, too # automake only seems to take care of this automatically, # if we're building the info page from texi directly. -install-data-hook: $(EXTRA_DIST) +install-data-hook: mysql.info $(mkinstalldirs) $(DESTDIR)$(infodir) $(INSTALL_DATA) $(srcdir)/mysql.info $(DESTDIR)$(infodir) - $(INSTALL_DATA) $(srcdir)/INSTALL-BINARY $(DESTDIR)$(infodir) # Don't update the files from bitkeeper %::SCCS/s.% From 01903380d549e5b338f43dab8b413ef741524393 Mon Sep 17 00:00:00 2001 From: "kent@mysql.com/kent-amd64.(none)" <> Date: Fri, 2 Nov 2007 13:16:23 +0100 Subject: [PATCH 138/336] Makefile.am: Removed place holder for 'manual.chm' .del-manual.chm: Delete: Docs/manual.chm --- Docs/Makefile.am | 2 +- Docs/manual.chm | 14 -------------- 2 files changed, 1 insertion(+), 15 deletions(-) delete mode 100644 Docs/manual.chm diff --git a/Docs/Makefile.am b/Docs/Makefile.am index d161836aaca..dac256f8fd6 100644 --- a/Docs/Makefile.am +++ b/Docs/Makefile.am @@ -13,7 +13,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -EXTRA_DIST = manual.chm mysql.info INSTALL-BINARY +EXTRA_DIST = mysql.info INSTALL-BINARY # make sure that "make install" installs the info page, too # automake only seems to take care of this automatically, diff --git a/Docs/manual.chm b/Docs/manual.chm deleted file mode 100644 index 28c3e1b5a86..00000000000 --- a/Docs/manual.chm +++ /dev/null @@ -1,14 +0,0 @@ - -********************************************************* - -This is a dummy placeholder file for "manual.chm" in the -MySQL source trees. - -Note, that the documentation has been moved into a separate -BitKeeper source tree named "mysqldoc" - do not attempt to edit this -file! All changes to it should be done in the mysqldoc tree. - -This dummy file is being replaced with the actual file from the -mysqldoc tree when building the official source distribution. - -********************************************************* From 794274ab10c1ac08e3596d6551f26f545dc8cbc6 Mon Sep 17 00:00:00 2001 From: "kaa@polly.(none)" <> Date: Fri, 2 Nov 2007 16:40:08 +0300 Subject: [PATCH 139/336] 5.1-specific changes for bug #26215 after merging the patch from 5.0: - Added trigger tests back. - Fixed test cases to match the extended output format of SHOW CREATE ... - Replaced 'gptr' with 'uchar *'. --- client/mysql.cc | 2 +- mysql-test/r/mysql_comments.result | 52 ++++++++++++++++++------------ mysql-test/t/mysql_comments.sql | 45 ++++++++++++++++++++++++-- 3 files changed, 76 insertions(+), 23 deletions(-) diff --git a/client/mysql.cc b/client/mysql.cc index 699fd3ea19d..3a89dec2557 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -776,7 +776,7 @@ static struct my_option my_long_options[] = 0, 0, 0, 0, 0, 0}, {"comments", 'c', "Preserve comments. Send comments to the server." " Comments are discarded by default, enable with --enable-comments", - (gptr*) &preserve_comments, (gptr*) &preserve_comments, + (uchar**) &preserve_comments, (uchar**) &preserve_comments, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; diff --git a/mysql-test/r/mysql_comments.result b/mysql-test/r/mysql_comments.result index 366ceeb5bbf..7f1c0b50c5e 100644 --- a/mysql-test/r/mysql_comments.result +++ b/mysql-test/r/mysql_comments.result @@ -12,20 +12,26 @@ drop trigger if exists t1_bi; 2 foofct("call 1") call 1 -Function sql_mode Create Function -foofct CREATE DEFINER=`root`@`localhost` FUNCTION `foofct`(x char(20)) RETURNS char(20) CHARSET latin1\nreturn\n\n\n\nx +Function sql_mode Create Function character_set_client collation_connection Database Collation +foofct CREATE DEFINER=`root`@`localhost` FUNCTION `foofct`(x char(20)) RETURNS char(20) CHARSET latin1\nreturn\n\n\n\nx latin1 latin1_swedish_ci latin1_swedish_ci foofct("call 2") call 2 -Function sql_mode Create Function -foofct CREATE DEFINER=`root`@`localhost` FUNCTION `foofct`(x char(20)) RETURNS char(20) CHARSET latin1\nbegin\n \n \n \n\n \n\n \n return x;\nend -Procedure sql_mode Create Procedure -empty CREATE DEFINER=`root`@`localhost` PROCEDURE `empty`()\nbegin\nend +Function sql_mode Create Function character_set_client collation_connection Database Collation +foofct CREATE DEFINER=`root`@`localhost` FUNCTION `foofct`(x char(20)) RETURNS char(20) CHARSET latin1\nbegin\n \n \n \n\n \n\n \n return x;\nend latin1 latin1_swedish_ci latin1_swedish_ci +Procedure sql_mode Create Procedure character_set_client collation_connection Database Collation +empty CREATE DEFINER=`root`@`localhost` PROCEDURE `empty`()\nbegin\nend latin1 latin1_swedish_ci latin1_swedish_ci id data foo 42 -Procedure sql_mode Create Procedure -foosp CREATE DEFINER=`root`@`localhost` PROCEDURE `foosp`()\ninsert into test.t1\n\n\n\n\n \n\n \n values ("foo", 42) -Procedure sql_mode Create Procedure -nicesp CREATE DEFINER=`root`@`localhost` PROCEDURE `nicesp`(a int)\nbegin\n \n declare b int;\n declare c float;\n\n \n \n\n \nend +Procedure sql_mode Create Procedure character_set_client collation_connection Database Collation +foosp CREATE DEFINER=`root`@`localhost` PROCEDURE `foosp`()\ninsert into test.t1\n\n\n\n\n \n\n \n values ("foo", 42) latin1 latin1_swedish_ci latin1_swedish_ci +Procedure sql_mode Create Procedure character_set_client collation_connection Database Collation +nicesp CREATE DEFINER=`root`@`localhost` PROCEDURE `nicesp`(a int)\nbegin\n \n declare b int;\n declare c float;\n\n \n \n\n \nend latin1 latin1_swedish_ci latin1_swedish_ci +Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation +t1_empty CREATE DEFINER=`root`@`localhost` trigger t1_empty after delete on t1\nfor each row\nbegin\nend latin1 latin1_swedish_ci latin1_swedish_ci +Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation +t1_bi CREATE DEFINER=`root`@`localhost` trigger t1_bi before insert on t1\nfor each row\nbegin\n\n\n\n \n declare b int;\n declare c float;\n\n \n \n\n \n set NEW.data := 12;\nend latin1 latin1_swedish_ci latin1_swedish_ci +id data +trig 12 "Pass 2 : --enable-comments" 1 1 @@ -33,18 +39,24 @@ nicesp CREATE DEFINER=`root`@`localhost` PROCEDURE `nicesp`(a int)\nbegin\n \n 2 foofct("call 1") call 1 -Function sql_mode Create Function -foofct CREATE DEFINER=`root`@`localhost` FUNCTION `foofct`(x char(20)) RETURNS char(20) CHARSET latin1\nreturn\n-- comment 1a\n# comment 1b\n/* comment 1c */\nx # after body, on same line +Function sql_mode Create Function character_set_client collation_connection Database Collation +foofct CREATE DEFINER=`root`@`localhost` FUNCTION `foofct`(x char(20)) RETURNS char(20) CHARSET latin1\nreturn\n-- comment 1a\n# comment 1b\n/* comment 1c */\nx # after body, on same line latin1 latin1_swedish_ci latin1_swedish_ci foofct("call 2") call 2 -Function sql_mode Create Function -foofct CREATE DEFINER=`root`@`localhost` FUNCTION `foofct`(x char(20)) RETURNS char(20) CHARSET latin1\nbegin\n -- comment 1a\n # comment 1b\n /*\n comment 1c\n */\n\n -- empty line below\n\n -- empty line above\n return x;\nend -Procedure sql_mode Create Procedure -empty CREATE DEFINER=`root`@`localhost` PROCEDURE `empty`()\nbegin\nend +Function sql_mode Create Function character_set_client collation_connection Database Collation +foofct CREATE DEFINER=`root`@`localhost` FUNCTION `foofct`(x char(20)) RETURNS char(20) CHARSET latin1\nbegin\n -- comment 1a\n # comment 1b\n /*\n comment 1c\n */\n\n -- empty line below\n\n -- empty line above\n return x;\nend latin1 latin1_swedish_ci latin1_swedish_ci +Procedure sql_mode Create Procedure character_set_client collation_connection Database Collation +empty CREATE DEFINER=`root`@`localhost` PROCEDURE `empty`()\nbegin\nend latin1 latin1_swedish_ci latin1_swedish_ci id data foo 42 -Procedure sql_mode Create Procedure -foosp CREATE DEFINER=`root`@`localhost` PROCEDURE `foosp`()\ninsert into test.t1\n## These comments are part of the procedure body, and should be kept.\n# Comment 2a\n-- Comment 2b\n/* Comment 2c */\n -- empty line below\n\n -- empty line above\n values ("foo", 42) # comment 3, still part of the body -Procedure sql_mode Create Procedure -nicesp CREATE DEFINER=`root`@`localhost` PROCEDURE `nicesp`(a int)\nbegin\n -- declare some variables here\n declare b int;\n declare c float;\n\n -- do more stuff here\n -- commented nicely and so on\n\n -- famous last words ...\nend +Procedure sql_mode Create Procedure character_set_client collation_connection Database Collation +foosp CREATE DEFINER=`root`@`localhost` PROCEDURE `foosp`()\ninsert into test.t1\n## These comments are part of the procedure body, and should be kept.\n# Comment 2a\n-- Comment 2b\n/* Comment 2c */\n -- empty line below\n\n -- empty line above\n values ("foo", 42) # comment 3, still part of the body latin1 latin1_swedish_ci latin1_swedish_ci +Procedure sql_mode Create Procedure character_set_client collation_connection Database Collation +nicesp CREATE DEFINER=`root`@`localhost` PROCEDURE `nicesp`(a int)\nbegin\n -- declare some variables here\n declare b int;\n declare c float;\n\n -- do more stuff here\n -- commented nicely and so on\n\n -- famous last words ...\nend latin1 latin1_swedish_ci latin1_swedish_ci +Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation +t1_empty CREATE DEFINER=`root`@`localhost` trigger t1_empty after delete on t1\nfor each row\nbegin\nend latin1 latin1_swedish_ci latin1_swedish_ci +Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation +t1_bi CREATE DEFINER=`root`@`localhost` trigger t1_bi before insert on t1\nfor each row\nbegin\n# comment 1a\n-- comment 1b\n/*\n comment 1c\n*/\n -- declare some variables here\n declare b int;\n declare c float;\n\n -- do more stuff here\n -- commented nicely and so on\n\n -- famous last words ...\n set NEW.data := 12;\nend latin1 latin1_swedish_ci latin1_swedish_ci +id data +trig 12 End of 5.0 tests diff --git a/mysql-test/t/mysql_comments.sql b/mysql-test/t/mysql_comments.sql index 60b223a240f..2497c35e465 100644 --- a/mysql-test/t/mysql_comments.sql +++ b/mysql-test/t/mysql_comments.sql @@ -167,8 +167,49 @@ delimiter ; show create procedure nicesp; drop procedure nicesp; -# Triggers can be tested only in 5.1, since 5.0 does not have -# SHOW CREATE TRIGGER +##============================================================================ +## Comments inside triggers +##============================================================================ + +drop trigger if exists t1_empty; + +create trigger t1_empty after delete on t1 +for each row +begin +end; + +show create trigger t1_empty; + +drop trigger if exists t1_bi; + +delimiter | + +create trigger t1_bi before insert on t1 +for each row +begin +# comment 1a +-- comment 1b +/* + comment 1c +*/ + -- declare some variables here + declare b int; + declare c float; + + -- do more stuff here + -- commented nicely and so on + + -- famous last words ... + set NEW.data := 12; +end| + +delimiter ; + +show create trigger t1_bi; + +# also make sure the trigger still works +insert into t1(id) value ("trig"); +select * from t1; ##============================================================================ ## Cleanup From f9518db25f68233bcde8724e25284ce27643a5c5 Mon Sep 17 00:00:00 2001 From: "iggy@alf.(none)" <> Date: Fri, 2 Nov 2007 15:16:45 -0400 Subject: [PATCH 140/336] Bug#31319 CMake build does not check for minimum required version - Add check --- CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index b7b546ab72c..27b2bf9b70e 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,6 +13,8 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +CMAKE_MINIMUM_REQUIRED(VERSION 2.4.7 FATAL_ERROR) + PROJECT(MySql) # This reads user configuration, generated by configure.js. From 02601fff850904e06d9a83842ac9eb4965a280c4 Mon Sep 17 00:00:00 2001 From: "iggy@alf.(none)" <> Date: Fri, 2 Nov 2007 15:30:39 -0400 Subject: [PATCH 141/336] Bug#31217 C1033 compilation error on Windows - This workaround is no longer necessary with cmake 2.4.7. --- sql/CMakeLists.txt | 7 ------- 1 file changed, 7 deletions(-) diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 299f4ae4285..77f8bb9e5b2 100755 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -90,13 +90,6 @@ TARGET_LINK_LIBRARIES(mysqld SET_TARGET_PROPERTIES(mysqld PROPERTIES OUTPUT_NAME mysqld${MYSQLD_EXE_SUFFIX}) -# Work around for 2.4.6 bug, OUTPUT_NAME will not set the right .PDB -# file name. Note that COMPILE_FLAGS set some temporary pdb during build, -# LINK_FLAGS sets the real one. -SET_TARGET_PROPERTIES(mysqld PROPERTIES - COMPILE_FLAGS "/Fd${CMAKE_CFG_INTDIR}/mysqld${MYSQLD_EXE_SUFFIX}.pdb" - LINK_FLAGS "/PDB:${CMAKE_CFG_INTDIR}/mysqld${MYSQLD_EXE_SUFFIX}.pdb") - IF(EMBED_MANIFESTS) MYSQL_EMBED_MANIFEST("mysqld" "asInvoker") ENDIF(EMBED_MANIFESTS) From 626e12624e15a2fd2e7c61eb8bbcf3e6497bc57d Mon Sep 17 00:00:00 2001 From: "antony@pcg5ppc.xiphis.org" <> Date: Fri, 2 Nov 2007 14:25:48 -0700 Subject: [PATCH 142/336] fix for 2.4.6 bug should be properly enclosed to not break other versions. --- sql/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 299f4ae4285..77abc4e6fa5 100755 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -90,12 +90,14 @@ TARGET_LINK_LIBRARIES(mysqld SET_TARGET_PROPERTIES(mysqld PROPERTIES OUTPUT_NAME mysqld${MYSQLD_EXE_SUFFIX}) +IF(cmake_version EQUAL 20406) # Work around for 2.4.6 bug, OUTPUT_NAME will not set the right .PDB # file name. Note that COMPILE_FLAGS set some temporary pdb during build, # LINK_FLAGS sets the real one. SET_TARGET_PROPERTIES(mysqld PROPERTIES COMPILE_FLAGS "/Fd${CMAKE_CFG_INTDIR}/mysqld${MYSQLD_EXE_SUFFIX}.pdb" LINK_FLAGS "/PDB:${CMAKE_CFG_INTDIR}/mysqld${MYSQLD_EXE_SUFFIX}.pdb") +ENDIF(cmake_version EQUAL 20406) IF(EMBED_MANIFESTS) MYSQL_EMBED_MANIFEST("mysqld" "asInvoker") From 6c67d11f204ce8f77ac8662fd268ffbca44b7f2c Mon Sep 17 00:00:00 2001 From: "skozlov/ksm@mysql.com/virtop.localdomain" <> Date: Sat, 3 Nov 2007 00:32:17 +0300 Subject: [PATCH 143/336] WL#3949. Added an option for support "combinations" of mysqld arguments for a suite --- mysql-test/lib/mtr_cases.pl | 99 ++++++++++++++++++++++++++++++++++++ mysql-test/mysql-test-run.pl | 5 ++ 2 files changed, 104 insertions(+) diff --git a/mysql-test/lib/mtr_cases.pl b/mysql-test/lib/mtr_cases.pl index 3d5752b4ec8..992d645f038 100644 --- a/mysql-test/lib/mtr_cases.pl +++ b/mysql-test/lib/mtr_cases.pl @@ -214,17 +214,44 @@ sub collect_one_suite($$) mtr_verbose("Collecting: $suite"); + my $combination_file= "combinations"; + my $combinations = []; + my $suitedir= "$::glob_mysql_test_dir"; # Default + my $combination_file= "$::glob_mysql_test_dir/$combination_file"; if ( $suite ne "main" ) { $suitedir= mtr_path_exists("$suitedir/suite/$suite", "$suitedir/$suite"); mtr_verbose("suitedir: $suitedir"); + $combination_file= "$suitedir/$combination_file"; } my $testdir= "$suitedir/t"; my $resdir= "$suitedir/r"; + if (!@::opt_combination) + { + # Read combinations file + if ( open(COMB,$combination_file) ) + { + while () + { + chomp; + s/\ +/ /g; + push (@$combinations, $_) unless ($_ eq ''); + } + close COMB; + } + } + else + { + # take the combination from command-line + @$combinations = @::opt_combination; + } + # Remember last element position + my $begin_index = $#{@$cases} + 1; + # ---------------------------------------------------------------------- # Build a hash of disabled testcases for this suite # ---------------------------------------------------------------------- @@ -335,6 +362,78 @@ sub collect_one_suite($$) closedir TESTDIR; } + # ---------------------------------------------------------------------- + # Proccess combinations only if new tests were added + # ---------------------------------------------------------------------- + if ($combinations && $begin_index <= $#{@$cases}) + { + my $end_index = $#{@$cases}; + my $is_copy; + # Keep original master/slave options + my @orig_opts; + for (my $idx = $begin_index; $idx <= $end_index; $idx++) + { + foreach my $param (('master_opt','slave_opt','slave_mi')) + { + @{$orig_opts[$idx]{$param}} = @{$cases->[$idx]->{$param}}; + } + } + my $comb_index = 1; + # Copy original test cases + foreach my $comb_set (@$combinations) + { + for (my $idx = $begin_index; $idx <= $end_index; $idx++) + { + my $test = $cases->[$idx]; + my $copied_test = {}; + foreach my $param (keys %{$test}) + { + # Scalar. Copy as is. + $copied_test->{$param} = $test->{$param}; + # Array. Copy reference instead itself + if ($param =~ /(master_opt|slave_opt|slave_mi)/) + { + my $new_arr = []; + @$new_arr = @{$orig_opts[$idx]{$param}}; + $copied_test->{$param} = $new_arr; + } + elsif ($param =~ /(comment|combinations)/) + { + $copied_test->{$param} = ''; + } + } + if ($is_copy) + { + push(@$cases, $copied_test); + $test = $cases->[$#{@$cases}]; + } + foreach my $comb_opt (split(/ /,$comb_set)) + { + push(@{$test->{'master_opt'}},$comb_opt); + push(@{$test->{'slave_opt'}},$comb_opt); + # Enable rpl if added option is --binlog-format and test case supports that + if ($comb_opt =~ /^--binlog-format=.+$/) + { + my @opt_pairs = split(/=/, $comb_opt); + if ($test->{'binlog_format'} =~ /^$opt_pairs[1]$/ || $test->{'binlog_format'} eq '') + { + $test->{'skip'} = 0; + $test->{'comment'} = ''; + } + else + { + $test->{'skip'} = 1; + $test->{'comment'} = "Requiring binlog format '$test->{'binlog_format'}'";; + } + } + } + $test->{'combination'} = $comb_set; + } + $is_copy = 1; + $comb_index++; + } + } + return $cases; } diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index eda268bcedf..11dbfbd14a8 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -164,6 +164,8 @@ our $opt_bench= 0; our $opt_small_bench= 0; our $opt_big_test= 0; +our @opt_combination; + our @opt_extra_mysqld_opt; our $opt_compress; @@ -529,6 +531,7 @@ sub command_line_setup () { 'skip-im' => \$opt_skip_im, 'skip-test=s' => \$opt_skip_test, 'big-test' => \$opt_big_test, + 'combination=s' => \@opt_combination, # Specify ports 'master_port=i' => \$opt_master_myport, @@ -5134,6 +5137,8 @@ Options to control what test suites or cases to run skip-im Don't start IM, and skip the IM test cases big-test Set the environment variable BIG_TEST, which can be checked from test cases. + combination="ARG1 .. ARG2" Specify a set of "mysqld" arguments for one + combination. Options that specify ports From 241cd5f969e04c0b9e294f7c2d7c3c7e708d86b8 Mon Sep 17 00:00:00 2001 From: "istruewing@stella.local" <> Date: Mon, 5 Nov 2007 10:57:52 +0100 Subject: [PATCH 144/336] Bug#4692 - DISABLE/ENABLE KEYS waste a space Fixed absurd compiler warnings of a Suse 10.1 system. --- storage/myisam/mi_check.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/storage/myisam/mi_check.c b/storage/myisam/mi_check.c index feb639d48f9..7cd35295cb0 100644 --- a/storage/myisam/mi_check.c +++ b/storage/myisam/mi_check.c @@ -2225,6 +2225,7 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info, SORT_INFO sort_info; ulonglong key_map; DBUG_ENTER("mi_repair_by_sort"); + LINT_INIT(key_map); start_records=info->state->records; got_error=1; @@ -2649,6 +2650,7 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info, ulonglong key_map; pthread_attr_t thr_attr; DBUG_ENTER("mi_repair_parallel"); + LINT_INIT(key_map); start_records=info->state->records; got_error=1; From 910003b54493e65861f1a4f1e96997b1f93a9f00 Mon Sep 17 00:00:00 2001 From: "kaa@polly.(none)" <> Date: Mon, 5 Nov 2007 13:30:31 +0300 Subject: [PATCH 145/336] Fixed code that parses the DELIMITER command to correctly calculate the length of the remaining input string. This is to fix mysqldump test failure in PB introduced by the patch for bug #26215. --- client/mysql.cc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/client/mysql.cc b/client/mysql.cc index 2c6d0df2274..a8d88bec274 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -1347,10 +1347,9 @@ static bool add_line(String &buffer,char *line,char *in_string, } } else if (!*ml_comment && !*in_string && - (out - line) >= 9 && - !my_strnncoll(charset_info, (uchar*) pos, 9, - (const uchar*) "delimiter", 9) && - my_isspace(charset_info, pos[9])) + strlen(pos) >= 10 && + !my_strnncoll(charset_info, (uchar*) pos, 10, + (const uchar*) "delimiter ", 10)) { // Flush previously accepted characters if (out != line) From aac68041eff685f94d8a88bfb86d2d45e6116504 Mon Sep 17 00:00:00 2001 From: "istruewing@stella.local" <> Date: Mon, 5 Nov 2007 14:37:00 +0100 Subject: [PATCH 146/336] Bug#32107 - ctype_uca.test produces warnings files Comment sign of -- at line begin in test files lead to warnings from mysqltest. Changed -- to #. --- mysql-test/t/ctype_uca.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/t/ctype_uca.test b/mysql-test/t/ctype_uca.test index 17632e7c8fc..695a21adbf5 100644 --- a/mysql-test/t/ctype_uca.test +++ b/mysql-test/t/ctype_uca.test @@ -530,7 +530,7 @@ create table t1 ( a varchar(255), key a(a) ) character set utf8 collate utf8_czech_ci; --- In Czech 'ch' is a single letter between 'h' and 'i' +# In Czech 'ch' is a single letter between 'h' and 'i' insert into t1 values ('b'),('c'),('d'),('e'),('f'),('g'),('h'),('ch'),('i'),('j'); select * from t1 where a like 'c%'; From 2481d2c1e30b07640c2c45af56e08a89acd79b96 Mon Sep 17 00:00:00 2001 From: "istruewing@stella.local" <> Date: Mon, 5 Nov 2007 14:44:38 +0100 Subject: [PATCH 147/336] Bug#32108 - subselect.test produces warnings files Comment sign of -- at line begin in test files lead to warnings from mysqltest. Changed -- to #. --- mysql-test/t/subselect.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index d076ca6bd33..86d2aec870c 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -2970,7 +2970,7 @@ DROP TABLE t1,t2; CREATE TABLE t1 (a INT, b INT); INSERT INTO t1 VALUES (1, 2), (1,3), (1,4), (2,1), (2,2); --- returns no rows, when it should +# returns no rows, when it should SELECT a1.a, COUNT(*) FROM t1 a1 WHERE a1.a = 1 AND EXISTS( SELECT a2.a FROM t1 a2 WHERE a2.a = a1.a) GROUP BY a1.a; From 18ab121a3c695ed296e97da3fbe43ca4caa29be9 Mon Sep 17 00:00:00 2001 From: "holyfoot/hf@mysql.com/hfmain.(none)" <> Date: Mon, 5 Nov 2007 18:23:55 +0400 Subject: [PATCH 148/336] merging --- mysql-test/r/func_str.result | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index d6879a8e756..d0809eca65b 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -722,9 +722,9 @@ Warning 1265 Data truncated for column 'format(130,10)' at row 1 show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `bin(130)` varchar(64) NOT NULL default '', - `oct(130)` varchar(64) NOT NULL default '', - `conv(130,16,10)` varchar(64) NOT NULL default '', + `bin(130)` varchar(64) default NULL, + `oct(130)` varchar(64) default NULL, + `conv(130,16,10)` varchar(64) default NULL, `hex(130)` varchar(6) NOT NULL default '', `char(130)` varbinary(4) NOT NULL default '', `format(130,10)` varchar(4) NOT NULL default '', From 0cccdaba06251a70be3280e5cb777ab823a8260c Mon Sep 17 00:00:00 2001 From: "holyfoot/hf@mysql.com/hfmain.(none)" <> Date: Mon, 5 Nov 2007 18:43:13 +0400 Subject: [PATCH 149/336] merging --- mysql-test/r/func_str.result | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index 237c5eced39..6f6edd5112b 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -723,7 +723,7 @@ show create table t1; Table Create Table t1 CREATE TABLE `t1` ( `bin(130)` varchar(64) DEFAULT NULL, - `oct(130)` varchar(64) EFAULT NULL, + `oct(130)` varchar(64) DEFAULT NULL, `conv(130,16,10)` varchar(64) DEFAULT NULL, `hex(130)` varchar(6) NOT NULL DEFAULT '', `char(130)` varbinary(4) NOT NULL DEFAULT '', From 571f8be43057e82eda6cd5250ebb2c36b0ba8aea Mon Sep 17 00:00:00 2001 From: "aelkin/elkin@koti.dsl.inet.fi" <> Date: Mon, 5 Nov 2007 17:20:10 +0200 Subject: [PATCH 150/336] Bug #28597 Replication doesn't start after upgrading to 5.1.18 Since bug@20166, which replaced the binlog file name generating to base on pidfile_name instead of the previous glob_hostname, the binlog file name suddenly started to be stored solely in the absolute path format, including a case when --log-bin option meant a relative path. What's more serious, the path for binlog file can lead unrequestedly to pid-file directory so that after any proper fix for this bug there might be similar to the bug report consequences for one who upgrades from post-fix-bug@20166-pre-fix-bug@28597 to post-fix-bug@28597. Fixed with preserving`pidfile_name' (intr.by bug@20166) but stripping off its directory part. This restores the original logics of storing the names in compatible with --log-bin option format and with the requirement for --log-bin ralative path to corresond to the data directory. Side effects for this fix: effective fixing bug@27070, refining its test; ensuring no overrun for buff can happen anymore (Bug#31836 insufficient space reserved for the suffix of relay log file name); bug#31837 --remove_file $MYSQLTEST_VARDIR/tmp/bug14157.sql missed in rpl_temporary.test; fixes Bug@28603 Invalid log-bin default location; --- mysql-test/t/rpl_dual_pos_advance.test | 6 ------ mysql-test/t/rpl_temporary.test | 2 ++ sql/log.cc | 11 ++++------- 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/mysql-test/t/rpl_dual_pos_advance.test b/mysql-test/t/rpl_dual_pos_advance.test index 074aeec63b1..518fa9df885 100644 --- a/mysql-test/t/rpl_dual_pos_advance.test +++ b/mysql-test/t/rpl_dual_pos_advance.test @@ -106,9 +106,3 @@ connection slave; sync_with_master; # End of 4.1 tests - -# Cleanup -# The A->B->A replication causes the master to start writing relay logs -# in var/run, remove them -remove_file $MYSQLTEST_VARDIR/run/master-relay-bin.000001; -remove_file $MYSQLTEST_VARDIR/run/master-relay-bin.index; diff --git a/mysql-test/t/rpl_temporary.test b/mysql-test/t/rpl_temporary.test index d09049af217..a7a15aebe7a 100644 --- a/mysql-test/t/rpl_temporary.test +++ b/mysql-test/t/rpl_temporary.test @@ -211,6 +211,8 @@ select * from t1; connection master; drop table t1; +--remove_file $MYSQLTEST_VARDIR/tmp/bug14157.sql + # Delete the anonymous users source include/delete_anonymous_users.inc; diff --git a/sql/log.cc b/sql/log.cc index e9aa273676a..af03cecd462 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -448,13 +448,10 @@ const char *MYSQL_LOG::generate_name(const char *log_name, { if (!log_name || !log_name[0]) { - /* - TODO: The following should be using fn_format(); We just need to - first change fn_format() to cut the file name if it's too long. - */ - strmake(buff, pidfile_name,FN_REFLEN-5); - strmov(fn_ext(buff),suffix); - return (const char *)buff; + strmake(buff, pidfile_name, FN_REFLEN - strlen(suffix) - 1); + return (const char *) + fn_format(buff, buff, "", suffix, MYF(MY_REPLACE_EXT|MY_REPLACE_DIR)); + } // get rid of extension if the log is binary to avoid problems if (strip_ext) From 3eaf82a17504158aa29b1f39360f365428943de4 Mon Sep 17 00:00:00 2001 From: "istruewing@stella.local" <> Date: Mon, 5 Nov 2007 16:25:40 +0100 Subject: [PATCH 151/336] Bug#31210 - INSERT DELAYED crashes server when used on partitioned table Trying INSERT DELAYED on a partitioned table, that has not been used right before, crashes the server. When a table is used for select or update, it is kept open for some time. This period I mean with "right before". Information about partitioning of a table is stored in form of a string in the .frm file. Parsing of this string requires a correctly set up lexical analyzer (lex). The partitioning code uses a new temporary instance of a lex. But it does still refer to the previously active lex. The delayd insert thread does not initialize its lex though... Added initialization for thd->lex before open table in the delayed thread and at all other places where it is necessary to call lex_start() if all tables would be partitioned and need to parse the .frm file. --- mysql-test/r/partition_hash.result | 4 ++++ mysql-test/t/partition_hash.test | 8 ++++++++ sql/event_scheduler.cc | 1 + sql/events.cc | 1 + sql/ha_ndbcluster_binlog.cc | 1 + sql/slave.cc | 1 + sql/sql_acl.cc | 2 ++ sql/sql_base.cc | 3 +++ sql/sql_connect.cc | 1 + sql/sql_insert.cc | 7 ++++++- sql/sql_lex.cc | 3 ++- sql/sql_lex.h | 1 + sql/sql_plugin.cc | 1 + sql/sql_servers.cc | 1 + sql/sql_udf.cc | 1 + sql/table.cc | 3 +++ sql/tztime.cc | 1 + 17 files changed, 38 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/partition_hash.result b/mysql-test/r/partition_hash.result index 9a82a36d902..3ebbd020db4 100644 --- a/mysql-test/r/partition_hash.result +++ b/mysql-test/r/partition_hash.result @@ -183,3 +183,7 @@ c1 c2 c3 182 abc 2002-11-09 184 abc 2002-11-22 drop table t1; +CREATE TABLE t1 (c1 INT) ENGINE=MyISAM PARTITION BY HASH(c1) PARTITIONS 1; +INSERT DELAYED INTO t1 VALUES (1); +ERROR HY000: Table storage engine for 't1' doesn't have this option +DROP TABLE t1; diff --git a/mysql-test/t/partition_hash.test b/mysql-test/t/partition_hash.test index 98add060a76..16c3e2b3b9b 100644 --- a/mysql-test/t/partition_hash.test +++ b/mysql-test/t/partition_hash.test @@ -144,3 +144,11 @@ select * from t1 where c3 between '2002-01-01' and '2002-12-31'; drop table t1; +# +# Bug#31210 - INSERT DELAYED crashes server when used on partitioned table +# +CREATE TABLE t1 (c1 INT) ENGINE=MyISAM PARTITION BY HASH(c1) PARTITIONS 1; +--error ER_ILLEGAL_HA +INSERT DELAYED INTO t1 VALUES (1); +DROP TABLE t1; + diff --git a/sql/event_scheduler.cc b/sql/event_scheduler.cc index b03b51f1134..52c7d291da7 100644 --- a/sql/event_scheduler.cc +++ b/sql/event_scheduler.cc @@ -127,6 +127,7 @@ post_init_event_thread(THD *thd) thd->cleanup(); return TRUE; } + lex_start(thd); pthread_mutex_lock(&LOCK_thread_count); threads.append(thd); diff --git a/sql/events.cc b/sql/events.cc index 5246bccc388..84301d811f0 100644 --- a/sql/events.cc +++ b/sql/events.cc @@ -884,6 +884,7 @@ Events::init(my_bool opt_noacl) */ thd->thread_stack= (char*) &thd; thd->store_globals(); + lex_start(thd); /* We will need Event_db_repository anyway, even if the scheduler is diff --git a/sql/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc index 5d5c8a26447..5f67c6f73ea 100644 --- a/sql/ha_ndbcluster_binlog.cc +++ b/sql/ha_ndbcluster_binlog.cc @@ -3621,6 +3621,7 @@ pthread_handler_t ndb_binlog_thread_func(void *arg) pthread_exit(0); DBUG_RETURN(NULL); } + lex_start(thd); thd->init_for_queries(); thd->command= COM_DAEMON; diff --git a/sql/slave.cc b/sql/slave.cc index fcbd4eb841b..a89d5262cbf 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1510,6 +1510,7 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type) delete thd; DBUG_RETURN(-1); } + lex_start(thd); if (thd_type == SLAVE_THD_SQL) thd->proc_info= "Waiting for the next event in relay log"; diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 7e017d7d028..495b7e06c8a 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -277,6 +277,7 @@ my_bool acl_init(bool dont_read_acl_tables) DBUG_RETURN(1); /* purecov: inspected */ thd->thread_stack= (char*) &thd; thd->store_globals(); + lex_start(thd); /* It is safe to call acl_reload() since acl_* arrays and hashes which will be freed there are global static objects and thus are initialized @@ -3493,6 +3494,7 @@ my_bool grant_init() DBUG_RETURN(1); /* purecov: deadcode */ thd->thread_stack= (char*) &thd; thd->store_globals(); + lex_start(thd); return_val= grant_reload(thd); delete thd; /* Remember that we don't have a THD */ diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 337fde53dac..119da29c316 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2248,6 +2248,9 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, HASH_SEARCH_STATE state; DBUG_ENTER("open_table"); + /* Parsing of partitioning information from .frm needs thd->lex set up. */ + DBUG_ASSERT(thd->lex->is_lex_started); + /* find a unused table in the open table cache */ if (refresh) *refresh=0; diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 6bb0f62d843..225a54448ac 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -1087,6 +1087,7 @@ pthread_handler_t handle_one_connection(void *arg) { NET *net= &thd->net; + lex_start(thd); if (login_connection(thd)) goto end_thread; diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index ebbf4cafb19..fb4a563c4d6 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -2264,7 +2264,12 @@ pthread_handler_t handle_delayed_insert(void *arg) goto err; } - /* open table */ + /* + Open table requires an initialized lex in case the table is + partitioned. The .frm file contains a partial SQL string which is + parsed using a lex, that depends on initialized thd->lex. + */ + lex_start(thd); if (!(di->table=open_ltable(thd, &di->table_list, TL_WRITE_DELAYED, 0))) { thd->fatal_error(); // Abort waiting inserts diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 0a5f83af400..26c9790923a 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -362,6 +362,7 @@ void lex_start(THD *thd) lex->server_options.owner= 0; lex->server_options.port= -1; + lex->is_lex_started= TRUE; DBUG_VOID_RETURN; } @@ -2138,7 +2139,7 @@ void Query_tables_list::destroy_query_tables_list() st_lex::st_lex() :result(0), yacc_yyss(0), yacc_yyvs(0), - sql_command(SQLCOM_END), option_type(OPT_DEFAULT) + sql_command(SQLCOM_END), option_type(OPT_DEFAULT), is_lex_started(0) { my_init_dynamic_array2(&plugins, sizeof(plugin_ref), diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 08104769704..d0822fed3c2 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1703,6 +1703,7 @@ typedef struct st_lex : public Query_tables_list st_alter_tablespace *alter_tablespace_info; bool escape_used; + bool is_lex_started; /* If lex_start() did run. For debugging. */ st_lex(); diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index 2af528f6699..c8d9116f196 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -1329,6 +1329,7 @@ static void plugin_load(MEM_ROOT *tmp_root, int *argc, char **argv) } new_thd->thread_stack= (char*) &tables; new_thd->store_globals(); + lex_start(new_thd); new_thd->db= my_strdup("mysql", MYF(0)); new_thd->db_length= 5; bzero((uchar*)&tables, sizeof(tables)); diff --git a/sql/sql_servers.cc b/sql/sql_servers.cc index a780c561ffe..d1d7801538c 100644 --- a/sql/sql_servers.cc +++ b/sql/sql_servers.cc @@ -140,6 +140,7 @@ bool servers_init(bool dont_read_servers_table) DBUG_RETURN(TRUE); thd->thread_stack= (char*) &thd; thd->store_globals(); + lex_start(thd); /* It is safe to call servers_reload() since servers_* arrays and hashes which will be freed there are global static objects and thus are initialized diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc index 19582af38f4..112280a10b2 100644 --- a/sql/sql_udf.cc +++ b/sql/sql_udf.cc @@ -135,6 +135,7 @@ void udf_init() initialized = 1; new_thd->thread_stack= (char*) &new_thd; new_thd->store_globals(); + lex_start(new_thd); new_thd->set_db(db, sizeof(db)-1); bzero((uchar*) &tables,sizeof(tables)); diff --git a/sql/table.cc b/sql/table.cc index ccddbf8134b..26008f0aa19 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -1608,6 +1608,9 @@ int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias, DBUG_PRINT("enter",("name: '%s.%s' form: 0x%lx", share->db.str, share->table_name.str, (long) outparam)); + /* Parsing of partitioning information from .frm needs thd->lex set up. */ + DBUG_ASSERT(thd->lex->is_lex_started); + error= 1; bzero((char*) outparam, sizeof(*outparam)); outparam->in_use= thd; diff --git a/sql/tztime.cc b/sql/tztime.cc index 9eb38e97827..920f8e87d13 100644 --- a/sql/tztime.cc +++ b/sql/tztime.cc @@ -1575,6 +1575,7 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap) DBUG_RETURN(1); thd->thread_stack= (char*) &thd; thd->store_globals(); + lex_start(thd); /* Init all memory structures that require explicit destruction */ if (hash_init(&tz_names, &my_charset_latin1, 20, From 51be103e131206a3beffa5f8445c880b89229613 Mon Sep 17 00:00:00 2001 From: "jperkin@production.mysql.com" <> Date: Mon, 5 Nov 2007 17:48:11 +0100 Subject: [PATCH 152/336] Provide better feedback to the user when unable to find MySQL files usually caused by a bad basedir setting. --- support-files/mysql.server.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/support-files/mysql.server.sh b/support-files/mysql.server.sh index c68d30daafb..0a87b04c992 100644 --- a/support-files/mysql.server.sh +++ b/support-files/mysql.server.sh @@ -311,7 +311,7 @@ case "$mode" in fi exit $return_value else - log_failure_msg "Couldn't find MySQL manager or server" + log_failure_msg "Couldn't find MySQL manager ($manager) or server ($bindir/mysqld_safe)" fi ;; From 3f7bf5888420a4064cf9d40bc5a55a338588e8b9 Mon Sep 17 00:00:00 2001 From: "aelkin/elkin@koti.dsl.inet.fi" <> Date: Mon, 5 Nov 2007 22:10:25 +0200 Subject: [PATCH 153/336] bug#27571 asynchronous setting mysql_`query`::error and Query_log_e::error_code refining tests as they appear to be non-deterministic. --- .../suite/binlog/r/binlog_killed.result | 93 ++++++++++--------- mysql-test/suite/binlog/t/binlog_killed.test | 50 ++++++---- .../binlog/t/binlog_killed_simulate.test | 1 + 3 files changed, 83 insertions(+), 61 deletions(-) diff --git a/mysql-test/suite/binlog/r/binlog_killed.result b/mysql-test/suite/binlog/r/binlog_killed.result index 60b2ff6cfc4..9e8f9828d9f 100644 --- a/mysql-test/suite/binlog/r/binlog_killed.result +++ b/mysql-test/suite/binlog/r/binlog_killed.result @@ -17,8 +17,7 @@ update t1 set b=11 where a=2; update t1 set b=b+10; kill query ID; rollback; -ERROR 70100: Query execution was interrupted -select * from t1 /* must be the same as before (1,1),(2,2) */; +select * from t1 order by a /* must be the same as before (1,1),(2,2) */; a b 1 1 2 2 @@ -27,8 +26,7 @@ delete from t1 where a=2; delete from t1 where a=2; kill query ID; rollback; -ERROR 70100: Query execution was interrupted -select * from t1 /* must be the same as before (1,1),(2,2) */; +select * from t1 order by a /* must be the same as before (1,1),(2,2) */; a b 1 1 2 2 @@ -41,67 +39,45 @@ begin; insert into t1 select * from t4 for update; kill query ID; rollback; -ERROR 70100: Query execution was interrupted rollback; select * from t1 /* must be the same as before (1,1),(2,2) */; a b 1 1 2 2 drop table t4; +create table t4 (a int, b int) ENGINE=MyISAM /* for killing update and delete */; create function bug27563(n int) RETURNS int(11) DETERMINISTIC begin -if n > 1 then +if @b > 0 then select get_lock("a", 10) into @a; +else +set @b= 1; end if; return n; end| -delete from t2; -insert into t2 values (1,1), (2,2); +delete from t4; +insert into t4 values (1,1), (1,1); reset master; select get_lock("a", 20); get_lock("a", 20) 1 -update t2 set b=b + bug27563(b) order by a; +set @b= 0; +update t4 set b=b + bug27563(b); kill query ID; -ERROR 70100: Query execution was interrupted -select * from t2 /* must be (1,2), (2,2) */; -a b -1 2 -2 2 -must have the update event more to FD -show binlog events from ; -Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Query # # use `test`; update t2 set b=b + bug27563(b) order by a -select -(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) -is not null; -(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) -is not null -1 -select 0 /* must return 0 to mean the killed query is in */; -0 -0 -select RELEASE_LOCK("a"); -RELEASE_LOCK("a") -1 -delete from t2; -insert into t2 values (1,1), (2,2); -reset master; -select get_lock("a", 20); -get_lock("a", 20) -1 -delete from t2 where a=1 or a=bug27563(2) order by a; -kill query ID; -ERROR 70100: Query execution was interrupted -select * from t2 /* must be (1,2), (2,2) */; +select * from t4 order by b /* must be (1,1), (1,2) */; a b 1 1 -2 2 -must have the update event more to FD +1 2 +select @b /* must be 1 at the end of a stmt calling bug27563() */; +@b +1 +must have the update query event more to FD show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # User var # # @`b`=0 +master-bin.000001 # Query # # use `test`; update t4 set b=b + bug27563(b) select (@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) is not null; @@ -114,6 +90,39 @@ select 0 /* must return 0 to mean the killed query is in */; select RELEASE_LOCK("a"); RELEASE_LOCK("a") 1 +delete from t4; +insert into t4 values (1,1), (2,2); +reset master; +select get_lock("a", 20); +get_lock("a", 20) +1 +set @b= 0; +delete from t4 where b=bug27563(1) or b=bug27563(2); +kill query ID; +select count(*) from t4 /* must be 1 */; +count(*) +1 +select @b /* must be 1 at the end of a stmt calling bug27563() */; +@b +1 +must have the delete query event more to FD +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # User var # # @`b`=0 +master-bin.000001 # Query # # use `test`; delete from t4 where b=bug27563(1) or b=bug27563(2) +select +(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) +is not null; +(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) +is not null +1 +select 0 /* must return 0 to mean the killed query is in */; +0 +0 +select RELEASE_LOCK("a"); +RELEASE_LOCK("a") +1 +drop table t4; drop function bug27563; drop table t1,t2,t3; end of the tests diff --git a/mysql-test/suite/binlog/t/binlog_killed.test b/mysql-test/suite/binlog/t/binlog_killed.test index 792b7a3dc57..4c2e6fbdc3c 100644 --- a/mysql-test/suite/binlog/t/binlog_killed.test +++ b/mysql-test/suite/binlog/t/binlog_killed.test @@ -68,7 +68,6 @@ select @result /* must be zero either way */; delete from t1; delete from t2; insert into t1 values (1,1),(2,2); -let $ID= `select connection_id()`; # # simple update @@ -77,6 +76,7 @@ connection con1; begin; update t1 set b=11 where a=2; connection con2; +let $ID= `select connection_id()`; send update t1 set b=b+10; connection con1; @@ -85,9 +85,9 @@ eval kill query $ID; rollback; connection con2; ---error ER_QUERY_INTERRUPTED +--error 0,ER_QUERY_INTERRUPTED reap; -select * from t1 /* must be the same as before (1,1),(2,2) */; +select * from t1 order by a /* must be the same as before (1,1),(2,2) */; # # multi update @@ -120,6 +120,7 @@ connection con1; begin; delete from t1 where a=2; connection con2; +let $ID= `select connection_id()`; send delete from t1 where a=2; connection con1; @@ -128,9 +129,9 @@ eval kill query $ID; rollback; connection con2; ---error ER_QUERY_INTERRUPTED +--error 0,ER_QUERY_INTERRUPTED reap; -select * from t1 /* must be the same as before (1,1),(2,2) */; +select * from t1 order by a /* must be the same as before (1,1),(2,2) */; # # multi delete @@ -163,6 +164,7 @@ insert into t4 values (3, 3); begin; insert into t1 values (3, 3); connection con2; +let $ID= `select connection_id()`; begin; send insert into t1 select * from t4 for update; @@ -172,7 +174,7 @@ eval kill query $ID; rollback; connection con2; ---error ER_QUERY_INTERRUPTED +--error 0,ER_QUERY_INTERRUPTED reap; rollback; select * from t1 /* must be the same as before (1,1),(2,2) */; @@ -182,13 +184,17 @@ drop table t4; # cleanup for the sub-case ### ## non-ta table case: killing must be recorded in binlog ### +create table t4 (a int, b int) ENGINE=MyISAM /* for killing update and delete */; + delimiter |; create function bug27563(n int) RETURNS int(11) DETERMINISTIC begin - if n > 1 then + if @b > 0 then select get_lock("a", 10) into @a; + else + set @b= 1; end if; return n; end| @@ -198,25 +204,27 @@ delimiter ;| # update # -delete from t2; -insert into t2 values (1,1), (2,2); +delete from t4; +insert into t4 values (1,1), (1,1); reset master; connection con1; select get_lock("a", 20); connection con2; let $ID= `select connection_id()`; -send update t2 set b=b + bug27563(b) order by a; +set @b= 0; +send update t4 set b=b + bug27563(b); connection con1; --replace_result $ID ID eval kill query $ID; connection con2; ---error ER_QUERY_INTERRUPTED +--error 0,ER_QUERY_INTERRUPTED reap; -select * from t2 /* must be (1,2), (2,2) */; ---echo must have the update event more to FD +select * from t4 order by b /* must be (1,1), (1,2) */; +select @b /* must be 1 at the end of a stmt calling bug27563() */; +--echo must have the update query event more to FD source include/show_binlog_events.inc; # a proof the query is binlogged with an error @@ -239,25 +247,27 @@ select RELEASE_LOCK("a"); # delete # -delete from t2; -insert into t2 values (1,1), (2,2); +delete from t4; +insert into t4 values (1,1), (2,2); reset master; connection con1; select get_lock("a", 20); connection con2; let $ID= `select connection_id()`; -send delete from t2 where a=1 or a=bug27563(2) order by a; +set @b= 0; +send delete from t4 where b=bug27563(1) or b=bug27563(2); connection con1; --replace_result $ID ID eval kill query $ID; connection con2; ---error ER_QUERY_INTERRUPTED +--error 0,ER_QUERY_INTERRUPTED reap; -select * from t2 /* must be (1,2), (2,2) */; ---echo must have the update event more to FD +select count(*) from t4 /* must be 1 */; +select @b /* must be 1 at the end of a stmt calling bug27563() */; +--echo must have the delete query event more to FD source include/show_binlog_events.inc; # a proof the query is binlogged with an error @@ -276,6 +286,8 @@ connection con1; select RELEASE_LOCK("a"); --remove_file $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog +drop table t4; + # # load data - see simulation tests # diff --git a/mysql-test/suite/binlog/t/binlog_killed_simulate.test b/mysql-test/suite/binlog/t/binlog_killed_simulate.test index 772736d89e9..2121a90dc8c 100644 --- a/mysql-test/suite/binlog/t/binlog_killed_simulate.test +++ b/mysql-test/suite/binlog/t/binlog_killed_simulate.test @@ -1,3 +1,4 @@ +-- source include/have_debug.inc -- source include/have_binlog_format_mixed_or_statement.inc # # bug#27571 asynchronous setting mysql_$query()'s local error and From d9045a76687fdafd1b5d3a649c8d72edc48cfd9a Mon Sep 17 00:00:00 2001 From: "aelkin/elkin@koti.dsl.inet.fi" <> Date: Tue, 6 Nov 2007 11:53:47 +0200 Subject: [PATCH 154/336] bug#27571 non-deterministic tests execution on some platforms. --- mysql-test/suite/binlog/r/binlog_killed.result | 5 ++++- mysql-test/suite/binlog/t/binlog_killed.test | 8 +++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/mysql-test/suite/binlog/r/binlog_killed.result b/mysql-test/suite/binlog/r/binlog_killed.result index 9e8f9828d9f..3cd21e3bca1 100644 --- a/mysql-test/suite/binlog/r/binlog_killed.result +++ b/mysql-test/suite/binlog/r/binlog_killed.result @@ -9,6 +9,9 @@ insert into t2 values (null, null), (null, get_lock("a", 10)); select @result /* must be zero either way */; @result 0 +select RELEASE_LOCK("a"); +RELEASE_LOCK("a") +1 delete from t1; delete from t2; insert into t1 values (1,1),(2,2); @@ -51,7 +54,7 @@ RETURNS int(11) DETERMINISTIC begin if @b > 0 then -select get_lock("a", 10) into @a; +select get_lock("a", 20) into @a; else set @b= 1; end if; diff --git a/mysql-test/suite/binlog/t/binlog_killed.test b/mysql-test/suite/binlog/t/binlog_killed.test index 4c2e6fbdc3c..4810246437f 100644 --- a/mysql-test/suite/binlog/t/binlog_killed.test +++ b/mysql-test/suite/binlog/t/binlog_killed.test @@ -57,6 +57,8 @@ select @result /* must be zero either way */; --remove_file $MYSQLTEST_VARDIR/tmp/kill_query_calling_sp.binlog +connection con1; +select RELEASE_LOCK("a"); # # bug#27571 asynchronous setting mysql_`query`::error and Query_log_e::error_code @@ -192,7 +194,7 @@ RETURNS int(11) DETERMINISTIC begin if @b > 0 then - select get_lock("a", 10) into @a; + select get_lock("a", 20) into @a; else set @b= 1; end if; @@ -220,7 +222,7 @@ connection con1; eval kill query $ID; connection con2; ---error 0,ER_QUERY_INTERRUPTED +--error 0,ER_QUERY_INTERRUPTED,ER_SP_PROC_TABLE_CORRUPT reap; select * from t4 order by b /* must be (1,1), (1,2) */; select @b /* must be 1 at the end of a stmt calling bug27563() */; @@ -263,7 +265,7 @@ connection con1; eval kill query $ID; connection con2; ---error 0,ER_QUERY_INTERRUPTED +--error 0,ER_QUERY_INTERRUPTED,ER_SP_PROC_TABLE_CORRUPT reap; select count(*) from t4 /* must be 1 */; select @b /* must be 1 at the end of a stmt calling bug27563() */; From fe60ebdc2550d04824f5106b2b053c66016a6e8d Mon Sep 17 00:00:00 2001 From: "aelkin/elkin@koti.dsl.inet.fi" <> Date: Tue, 6 Nov 2007 13:08:37 +0200 Subject: [PATCH 155/336] bug#27571 non-deterministic tests refining. This particular patch tested on two archs. --- mysql-test/suite/binlog/t/binlog_killed.test | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/binlog/t/binlog_killed.test b/mysql-test/suite/binlog/t/binlog_killed.test index 4810246437f..c8809648098 100644 --- a/mysql-test/suite/binlog/t/binlog_killed.test +++ b/mysql-test/suite/binlog/t/binlog_killed.test @@ -218,11 +218,15 @@ set @b= 0; send update t4 set b=b + bug27563(b); connection con1; +let $wait_condition= select count(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST where state='User lock'; +source include/wait_condition.inc; +select count(*) FROM INFORMATION_SCHEMA.PROCESSLIST where state='User lock'; + --replace_result $ID ID eval kill query $ID; connection con2; ---error 0,ER_QUERY_INTERRUPTED,ER_SP_PROC_TABLE_CORRUPT +--error ER_QUERY_INTERRUPTED reap; select * from t4 order by b /* must be (1,1), (1,2) */; select @b /* must be 1 at the end of a stmt calling bug27563() */; @@ -261,11 +265,14 @@ set @b= 0; send delete from t4 where b=bug27563(1) or b=bug27563(2); connection con1; +let $wait_condition= select count(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST where state='User lock'; +source include/wait_condition.inc; +select count(*) FROM INFORMATION_SCHEMA.PROCESSLIST where state='User lock'; --replace_result $ID ID eval kill query $ID; connection con2; ---error 0,ER_QUERY_INTERRUPTED,ER_SP_PROC_TABLE_CORRUPT +--error ER_QUERY_INTERRUPTED reap; select count(*) from t4 /* must be 1 */; select @b /* must be 1 at the end of a stmt calling bug27563() */; From 122005894f865c13f46b460adc1c0885a78f0c0c Mon Sep 17 00:00:00 2001 From: "aelkin/elkin@koti.dsl.inet.fi" <> Date: Tue, 6 Nov 2007 13:53:26 +0200 Subject: [PATCH 156/336] bug#27571 commit is specific for 5.0 to eliminated non-deterministic tests. Those tests run only in 5.1 env where there is a necessary devices such as processlist table of info_schema. --- mysql-test/r/binlog_killed.result | 76 +-------------- mysql-test/t/binlog_killed.test | 118 +++-------------------- mysql-test/t/binlog_killed_simulate.test | 1 + 3 files changed, 19 insertions(+), 176 deletions(-) diff --git a/mysql-test/r/binlog_killed.result b/mysql-test/r/binlog_killed.result index ddd80283eca..eaafc9727cd 100644 --- a/mysql-test/r/binlog_killed.result +++ b/mysql-test/r/binlog_killed.result @@ -9,6 +9,9 @@ insert into t2 values (null, null), (null, get_lock("a", 10)); select @result /* must be zero either way */; @result 0 +select RELEASE_LOCK("a"); +RELEASE_LOCK("a") +1 delete from t1; delete from t2; insert into t1 values (1,1),(2,2); @@ -17,8 +20,7 @@ update t1 set b=11 where a=2; update t1 set b=b+10; kill query ID; rollback; -ERROR 70100: Query execution was interrupted -select * from t1 /* must be the same as before (1,1),(2,2) */; +select * from t1 order by a /* must be the same as before (1,1),(2,2) */; a b 1 1 2 2 @@ -27,8 +29,7 @@ delete from t1 where a=2; delete from t1 where a=2; kill query ID; rollback; -ERROR 70100: Query execution was interrupted -select * from t1 /* must be the same as before (1,1),(2,2) */; +select * from t1 order by a /* must be the same as before (1,1),(2,2) */; a b 1 1 2 2 @@ -41,78 +42,11 @@ begin; insert into t1 select * from t4 for update; kill query ID; rollback; -ERROR 70100: Query execution was interrupted rollback; select * from t1 /* must be the same as before (1,1),(2,2) */; a b 1 1 2 2 drop table t4; -create function bug27563(n int) -RETURNS int(11) -DETERMINISTIC -begin -if n > 1 then -select get_lock("a", 10) into @a; -end if; -return n; -end| -delete from t2; -insert into t2 values (1,1), (2,2); -reset master; -select get_lock("a", 20); -get_lock("a", 20) -1 -update t2 set b=b + bug27563(b) order by a; -kill query ID; -ERROR 70100: Query execution was interrupted -select * from t2 /* must be (1,2), (2,2) */; -a b -1 2 -2 2 -show master status /* must have the update event more to FD */; -File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 211 -select -(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) -is not null; -(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) -is not null -1 -select 0 /* must return 0 to mean the killed query is in */; -0 -0 -select RELEASE_LOCK("a"); -RELEASE_LOCK("a") -1 -delete from t2; -insert into t2 values (1,1), (2,2); -reset master; -select get_lock("a", 20); -get_lock("a", 20) -1 -delete from t2 where a=1 or a=bug27563(2) order by a; -kill query ID; -ERROR 70100: Query execution was interrupted -select * from t2 /* must be (1,2), (2,2) */; -a b -1 1 -2 2 -show master status /* must have the update event more to FD */; -File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 98 -select -(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) -is not null; -(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) -is not null -1 -select 0 /* must return 0 to mean the killed query is in */; -0 -0 -select RELEASE_LOCK("a"); -RELEASE_LOCK("a") -1 -drop function bug27563; drop table t1,t2,t3; end of the tests diff --git a/mysql-test/t/binlog_killed.test b/mysql-test/t/binlog_killed.test index 0e35e46c845..f8ba7c00f48 100644 --- a/mysql-test/t/binlog_killed.test +++ b/mysql-test/t/binlog_killed.test @@ -57,6 +57,8 @@ select @result /* must be zero either way */; --remove_file $MYSQLTEST_VARDIR/tmp/kill_query_calling_sp.binlog +connection con1; +select RELEASE_LOCK("a"); # # bug#27571 asynchronous setting mysql_`query`::error and Query_log_e::error_code @@ -68,7 +70,6 @@ select @result /* must be zero either way */; delete from t1; delete from t2; insert into t1 values (1,1),(2,2); -let $ID= `select connection_id()`; # # simple update @@ -77,6 +78,7 @@ connection con1; begin; update t1 set b=11 where a=2; connection con2; +let $ID= `select connection_id()`; send update t1 set b=b+10; connection con1; @@ -85,9 +87,9 @@ eval kill query $ID; rollback; connection con2; ---error ER_QUERY_INTERRUPTED +--error 0,ER_QUERY_INTERRUPTED reap; -select * from t1 /* must be the same as before (1,1),(2,2) */; +select * from t1 order by a /* must be the same as before (1,1),(2,2) */; # # multi update @@ -120,6 +122,7 @@ connection con1; begin; delete from t1 where a=2; connection con2; +let $ID= `select connection_id()`; send delete from t1 where a=2; connection con1; @@ -128,9 +131,9 @@ eval kill query $ID; rollback; connection con2; ---error ER_QUERY_INTERRUPTED +--error 0,ER_QUERY_INTERRUPTED reap; -select * from t1 /* must be the same as before (1,1),(2,2) */; +select * from t1 order by a /* must be the same as before (1,1),(2,2) */; # # multi delete @@ -163,6 +166,7 @@ insert into t4 values (3, 3); begin; insert into t1 values (3, 3); connection con2; +let $ID= `select connection_id()`; begin; send insert into t1 select * from t4 for update; @@ -172,7 +176,7 @@ eval kill query $ID; rollback; connection con2; ---error ER_QUERY_INTERRUPTED +--error 0,ER_QUERY_INTERRUPTED reap; rollback; select * from t1 /* must be the same as before (1,1),(2,2) */; @@ -182,106 +186,10 @@ drop table t4; # cleanup for the sub-case ### ## non-ta table case: killing must be recorded in binlog ### -delimiter |; -create function bug27563(n int) -RETURNS int(11) -DETERMINISTIC -begin - if n > 1 then - select get_lock("a", 10) into @a; - end if; - return n; -end| -delimiter ;| -# -# update -# - -delete from t2; -insert into t2 values (1,1), (2,2); -reset master; -connection con1; -select get_lock("a", 20); - -connection con2; -let $ID= `select connection_id()`; -send update t2 set b=b + bug27563(b) order by a; - -connection con1; ---replace_result $ID ID -eval kill query $ID; - -connection con2; ---error ER_QUERY_INTERRUPTED -reap; -select * from t2 /* must be (1,2), (2,2) */; -show master status /* must have the update event more to FD */; - -# a proof the query is binlogged with an error - ---exec $MYSQL_BINLOG --start-position=98 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog ---replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR -eval select -(@a:=load_file("$MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) -is not null; ---replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR -let $error_code= `select @a like "%#%error_code=0%" /* must return 0*/`; -eval select $error_code /* must return 0 to mean the killed query is in */; - -# cleanup for the sub-case -connection con1; -select RELEASE_LOCK("a"); ---remove_file $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog - -# -# delete -# - -delete from t2; -insert into t2 values (1,1), (2,2); -reset master; -connection con1; -select get_lock("a", 20); - -connection con2; -let $ID= `select connection_id()`; -send delete from t2 where a=1 or a=bug27563(2) order by a; - -connection con1; ---replace_result $ID ID -eval kill query $ID; - -connection con2; ---error ER_QUERY_INTERRUPTED -reap; -select * from t2 /* must be (1,2), (2,2) */; -show master status /* must have the update event more to FD */; - -# a proof the query is binlogged with an error - ---exec $MYSQL_BINLOG --start-position=98 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog ---replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR -eval select -(@a:=load_file("$MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) -is not null; ---replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR -let $error_code= `select @a like "%#%error_code=0%" /* must return 0*/`; -eval select $error_code /* must return 0 to mean the killed query is in */; - -# cleanup for the sub-case -connection con1; -select RELEASE_LOCK("a"); ---remove_file $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog - -# -# load data - see simulation tests -# - - -# bug#27571 cleanup - -drop function bug27563; +# In order to be deterministic the test needs INFORMATION_SCHEMA.PROCESSLIST +# which is not available on 5.0 at this time. +# Therefore, skip this part on 5.0. # diff --git a/mysql-test/t/binlog_killed_simulate.test b/mysql-test/t/binlog_killed_simulate.test index d6234d1bfd7..670cd756803 100644 --- a/mysql-test/t/binlog_killed_simulate.test +++ b/mysql-test/t/binlog_killed_simulate.test @@ -1,3 +1,4 @@ +-- source include/have_debug.inc # # bug#27571 asynchronous setting mysql_$query()'s local error and # Query_log_event::error_code From 30b409bd6fc66c5c2cfde023810c837a72fb2b50 Mon Sep 17 00:00:00 2001 From: "istruewing@stella.local" <> Date: Tue, 6 Nov 2007 13:41:32 +0100 Subject: [PATCH 157/336] Bug#4692 - DISABLE/ENABLE KEYS waste a space Disabling and enabling indexes on a non-empty table grows the index file. Disabling indexes just sets a flag per non-unique index and does not free the index blocks of the affected indexes. Re-enabling indexes creates new indexes with new blocks. The old blocks remain unused in the index file. Fixed by dropping and re-creating all indexes if non-empty disabled indexes exist when enabling indexes. Dropping all indexes resets the internal end-of-file marker to the end of the index file header. It also clears the root block pointers of every index and clears the deleted blocks chains. This way all blocks are declared as free. --- myisam/mi_check.c | 224 +++++++++++++++++++++++++++---------- mysql-test/r/myisam.result | 25 +++++ mysql-test/t/myisam.test | 26 +++++ 3 files changed, 218 insertions(+), 57 deletions(-) diff --git a/myisam/mi_check.c b/myisam/mi_check.c index ed0a84e737d..ba308f75d24 100644 --- a/myisam/mi_check.c +++ b/myisam/mi_check.c @@ -1375,6 +1375,139 @@ int chk_data_link(MI_CHECK *param, MI_INFO *info,int extend) } /* chk_data_link */ +/** + @brief Drop all indexes + + @param[in] param check parameters + @param[in] info MI_INFO handle + @param[in] force if to force drop all indexes + + @return status + @retval 0 OK + @retval != 0 Error + + @note + Once allocated, index blocks remain part of the key file forever. + When indexes are disabled, no block is freed. When enabling indexes, + no block is freed either. The new indexes are create from new + blocks. (Bug #4692) + + Before recreating formerly disabled indexes, the unused blocks + must be freed. There are two options to do this: + - Follow the tree of disabled indexes, add all blocks to the + deleted blocks chain. Would require a lot of random I/O. + - Drop all blocks by clearing all index root pointers and all + delete chain pointers and resetting key_file_length to the end + of the index file header. This requires to recreate all indexes, + even those that may still be intact. + The second method is probably faster in most cases. + + When disabling indexes, MySQL disables either all indexes or all + non-unique indexes. When MySQL [re-]enables disabled indexes + (T_CREATE_MISSING_KEYS), then we either have "lost" blocks in the + index file, or there are no non-unique indexes. In the latter case, + mi_repair*() would not be called as there would be no disabled + indexes. + + If there would be more unique indexes than disabled (non-unique) + indexes, we could do the first method. But this is not implemented + yet. By now we drop and recreate all indexes when repair is called. + + However, there is an exception. Sometimes MySQL disables non-unique + indexes when the table is empty (e.g. when copying a table in + mysql_alter_table()). When enabling the non-unique indexes, they + are still empty. So there is no index block that can be lost. This + optimization is implemented in this function. + + Note that in normal repair (T_CREATE_MISSING_KEYS not set) we + recreate all enabled indexes unconditonally. We do not change the + key_map. Otherwise we invert the key map temporarily (outside of + this function) and recreate the then "seemingly" enabled indexes. + When we cannot use the optimization, and drop all indexes, we + pretend that all indexes were disabled. By the inversion, we will + then recrate all indexes. +*/ + +static int mi_drop_all_indexes(MI_CHECK *param, MI_INFO *info, my_bool force) +{ + MYISAM_SHARE *share= info->s; + MI_STATE_INFO *state= &share->state; + uint i; + int error; + DBUG_ENTER("mi_drop_all_indexes"); + + /* + If any of the disabled indexes has a key block assigned, we must + drop and recreate all indexes to avoid losing index blocks. + + If we want to recreate disabled indexes only _and_ all of these + indexes are empty, we don't need to recreate the existing indexes. + */ + if (!force && (param->testflag & T_CREATE_MISSING_KEYS)) + { + DBUG_PRINT("repair", ("creating missing indexes")); + for (i= 0; i < share->base.keys; i++) + { + DBUG_PRINT("repair", ("index #: %u key_root: 0x%lx active: %d", + i, (long) state->key_root[i], + mi_is_key_active(state->key_map, i))); + if ((state->key_root[i] != HA_OFFSET_ERROR) && + !mi_is_key_active(state->key_map, i)) + { + /* + This index has at least one key block and it is disabled. + We would lose its block(s) if would just recreate it. + So we need to drop and recreate all indexes. + */ + DBUG_PRINT("repair", ("nonempty and disabled: recreate all")); + break; + } + } + if (i >= share->base.keys) + { + /* + All of the disabled indexes are empty. We can just recreate them. + Flush dirty blocks of this index file from key cache and remove + all blocks of this index file from key cache. + */ + DBUG_PRINT("repair", ("all disabled are empty: create missing")); + error= flush_key_blocks(share->key_cache, share->kfile, + FLUSH_FORCE_WRITE); + goto end; + } + /* + We do now drop all indexes and declare them disabled. With the + T_CREATE_MISSING_KEYS flag, mi_repair*() will recreate all + disabled indexes and enable them. + */ + mi_clear_all_keys_active(state->key_map); + DBUG_PRINT("repair", ("declared all indexes disabled")); + } + + /* Remove all key blocks of this index file from key cache. */ + if ((error= flush_key_blocks(share->key_cache, share->kfile, + FLUSH_IGNORE_CHANGED))) + goto end; + + /* Clear index root block pointers. */ + for (i= 0; i < share->base.keys; i++) + state->key_root[i]= HA_OFFSET_ERROR; + + /* Clear the delete chains. */ + for (i= 0; i < state->header.max_block_size; i++) + state->key_del[i]= HA_OFFSET_ERROR; + + /* Reset index file length to end of index file header. */ + info->state->key_file_length= share->base.keystart; + + DBUG_PRINT("repair", ("dropped all indexes")); + /* error= 0; set by last (error= flush_key_bocks()). */ + + end: + DBUG_RETURN(error); +} + + /* Recover old table by reading each record and writing all keys */ /* Save new datafile-name in temp_filename */ @@ -1382,7 +1515,6 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info, my_string name, int rep_quick) { int error,got_error; - uint i; ha_rows start_records,new_header_length; my_off_t del; File new_file; @@ -1486,25 +1618,10 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info, info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED); - /* - Clear all keys. Note that all key blocks allocated until now remain - "dead" parts of the key file. (Bug #4692) - */ - for (i=0 ; i < info->s->base.keys ; i++) - share->state.key_root[i]= HA_OFFSET_ERROR; - - /* Drop the delete chain. */ - for (i=0 ; i < share->state.header.max_block_size ; i++) - share->state.key_del[i]= HA_OFFSET_ERROR; - - /* - If requested, activate (enable) all keys in key_map. In this case, - all indexes will be (re-)built. - */ + /* This function always recreates all enabled indexes. */ if (param->testflag & T_CREATE_MISSING_KEYS) mi_set_all_keys_active(share->state.key_map, share->base.keys); - - info->state->key_file_length=share->base.keystart; + mi_drop_all_indexes(param, info, TRUE); lock_memory(param); /* Everything is alloced */ @@ -2105,8 +2222,9 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info, ulong *rec_per_key_part; char llbuff[22]; SORT_INFO sort_info; - ulonglong key_map=share->state.key_map; + ulonglong key_map; DBUG_ENTER("mi_repair_by_sort"); + LINT_INIT(key_map); start_records=info->state->records; got_error=1; @@ -2179,25 +2297,14 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info, } info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED); - if (!(param->testflag & T_CREATE_MISSING_KEYS)) + + /* Optionally drop indexes and optionally modify the key_map. */ + mi_drop_all_indexes(param, info, FALSE); + key_map= share->state.key_map; + if (param->testflag & T_CREATE_MISSING_KEYS) { - /* - Flush key cache for this file if we are calling this outside - myisamchk - */ - flush_key_blocks(share->key_cache,share->kfile, FLUSH_IGNORE_CHANGED); - /* Clear the pointers to the given rows */ - for (i=0 ; i < share->base.keys ; i++) - share->state.key_root[i]= HA_OFFSET_ERROR; - for (i=0 ; i < share->state.header.max_block_size ; i++) - share->state.key_del[i]= HA_OFFSET_ERROR; - info->state->key_file_length=share->base.keystart; - } - else - { - if (flush_key_blocks(share->key_cache,share->kfile, FLUSH_FORCE_WRITE)) - goto err; - key_map= ~key_map; /* Create the missing keys */ + /* Invert the copied key_map to recreate all disabled indexes. */ + key_map= ~key_map; } sort_info.info=info; @@ -2240,6 +2347,10 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info, sort_param.read_cache=param->read_cache; sort_param.keyinfo=share->keyinfo+sort_param.key; sort_param.seg=sort_param.keyinfo->seg; + /* + Skip this index if it is marked disabled in the copied + (and possibly inverted) key_map. + */ if (! mi_is_key_active(key_map, sort_param.key)) { /* Remember old statistics for key */ @@ -2247,6 +2358,8 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info, (char*) (share->state.rec_per_key_part + (uint) (rec_per_key_part - param->rec_per_key_part)), sort_param.keyinfo->keysegs*sizeof(*rec_per_key_part)); + DBUG_PRINT("repair", ("skipping seemingly disabled index #: %u", + sort_param.key)); continue; } @@ -2302,8 +2415,11 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info, if (param->testflag & T_STATISTICS) update_key_parts(sort_param.keyinfo, rec_per_key_part, sort_param.unique, param->stats_method == MI_STATS_METHOD_IGNORE_NULLS? - sort_param.notnull: NULL,(ulonglong) info->state->records); + sort_param.notnull: NULL, + (ulonglong) info->state->records); + /* Enable this index in the permanent (not the copied) key_map. */ mi_set_key_active(share->state.key_map, sort_param.key); + DBUG_PRINT("repair", ("set enabled index #: %u", sort_param.key)); if (sort_param.fix_datafile) { @@ -2504,9 +2620,10 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info, IO_CACHE new_data_cache; /* For non-quick repair. */ IO_CACHE_SHARE io_share; SORT_INFO sort_info; - ulonglong key_map=share->state.key_map; + ulonglong key_map; pthread_attr_t thr_attr; DBUG_ENTER("mi_repair_parallel"); + LINT_INIT(key_map); start_records=info->state->records; got_error=1; @@ -2608,25 +2725,14 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info, } info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED); - if (!(param->testflag & T_CREATE_MISSING_KEYS)) + + /* Optionally drop indexes and optionally modify the key_map. */ + mi_drop_all_indexes(param, info, FALSE); + key_map= share->state.key_map; + if (param->testflag & T_CREATE_MISSING_KEYS) { - /* - Flush key cache for this file if we are calling this outside - myisamchk - */ - flush_key_blocks(share->key_cache,share->kfile, FLUSH_IGNORE_CHANGED); - /* Clear the pointers to the given rows */ - for (i=0 ; i < share->base.keys ; i++) - share->state.key_root[i]= HA_OFFSET_ERROR; - for (i=0 ; i < share->state.header.max_block_size ; i++) - share->state.key_del[i]= HA_OFFSET_ERROR; - info->state->key_file_length=share->base.keystart; - } - else - { - if (flush_key_blocks(share->key_cache,share->kfile, FLUSH_FORCE_WRITE)) - goto err; - key_map= ~key_map; /* Create the missing keys */ + /* Invert the copied key_map to recreate all disabled indexes. */ + key_map= ~key_map; } sort_info.info=info; @@ -2682,6 +2788,10 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info, sort_param[i].key=key; sort_param[i].keyinfo=share->keyinfo+key; sort_param[i].seg=sort_param[i].keyinfo->seg; + /* + Skip this index if it is marked disabled in the copied + (and possibly inverted) key_map. + */ if (! mi_is_key_active(key_map, key)) { /* Remember old statistics for key */ diff --git a/mysql-test/r/myisam.result b/mysql-test/r/myisam.result index 7fc29cd13ca..176d0e97012 100644 --- a/mysql-test/r/myisam.result +++ b/mysql-test/r/myisam.result @@ -1806,4 +1806,29 @@ SELECT a FROM t1 FORCE INDEX (inx) WHERE a=1; a 1 DROP TABLE t1; +CREATE TABLE t1 (c1 INT, c2 INT, UNIQUE INDEX (c1), INDEX (c2)) ENGINE=MYISAM; +SHOW TABLE STATUS LIKE 't1'; +Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment +t1 MyISAM 10 Fixed 0 # # # 1024 # # # # # # # +INSERT INTO t1 VALUES (1,1); +SHOW TABLE STATUS LIKE 't1'; +Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment +t1 MyISAM 10 Fixed 1 # # # 3072 # # # # # # # +ALTER TABLE t1 DISABLE KEYS; +SHOW TABLE STATUS LIKE 't1'; +Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment +t1 MyISAM 10 Fixed 1 # # # 3072 # # # # # # # +ALTER TABLE t1 ENABLE KEYS; +SHOW TABLE STATUS LIKE 't1'; +Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment +t1 MyISAM 10 Fixed 1 # # # 3072 # # # # # # # +ALTER TABLE t1 DISABLE KEYS; +SHOW TABLE STATUS LIKE 't1'; +Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment +t1 MyISAM 10 Fixed 1 # # # 3072 # # # # # # # +ALTER TABLE t1 ENABLE KEYS; +SHOW TABLE STATUS LIKE 't1'; +Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment +t1 MyISAM 10 Fixed 1 # # # 3072 # # # # # # # +DROP TABLE t1; End of 5.0 tests diff --git a/mysql-test/t/myisam.test b/mysql-test/t/myisam.test index d5f403616c8..ad223dc2664 100644 --- a/mysql-test/t/myisam.test +++ b/mysql-test/t/myisam.test @@ -1161,4 +1161,30 @@ ALTER TABLE t1 ENABLE KEYS; SELECT a FROM t1 FORCE INDEX (inx) WHERE a=1; DROP TABLE t1; +# +# Bug#4692 - DISABLE/ENABLE KEYS waste a space +# +CREATE TABLE t1 (c1 INT, c2 INT, UNIQUE INDEX (c1), INDEX (c2)) ENGINE=MYISAM; +--replace_column 6 # 7 # 8 # 10 # 11 # 12 # 13 # 14 # 15 # 16 # +SHOW TABLE STATUS LIKE 't1'; +INSERT INTO t1 VALUES (1,1); +--replace_column 6 # 7 # 8 # 10 # 11 # 12 # 13 # 14 # 15 # 16 # +SHOW TABLE STATUS LIKE 't1'; +ALTER TABLE t1 DISABLE KEYS; +--replace_column 6 # 7 # 8 # 10 # 11 # 12 # 13 # 14 # 15 # 16 # +SHOW TABLE STATUS LIKE 't1'; +ALTER TABLE t1 ENABLE KEYS; +--replace_column 6 # 7 # 8 # 10 # 11 # 12 # 13 # 14 # 15 # 16 # +SHOW TABLE STATUS LIKE 't1'; +ALTER TABLE t1 DISABLE KEYS; +--replace_column 6 # 7 # 8 # 10 # 11 # 12 # 13 # 14 # 15 # 16 # +SHOW TABLE STATUS LIKE 't1'; +ALTER TABLE t1 ENABLE KEYS; +--replace_column 6 # 7 # 8 # 10 # 11 # 12 # 13 # 14 # 15 # 16 # +SHOW TABLE STATUS LIKE 't1'; +#--exec ls -log var/master-data/test/t1.MYI +#--exec myisamchk -dvv var/master-data/test/t1.MYI +#--exec myisamchk -iev var/master-data/test/t1.MYI +DROP TABLE t1; + --echo End of 5.0 tests From a34c1d5a36da650ec5e7c2a674c5c1d82b750673 Mon Sep 17 00:00:00 2001 From: "gluh@mysql.com/eagle.(none)" <> Date: Tue, 6 Nov 2007 16:53:02 +0400 Subject: [PATCH 158/336] fix for pushbuild 'powermacg5' failure --- mysql-test/r/information_schema.result | 6 +++--- mysql-test/t/information_schema.test | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index 18ffb4a37ea..007bd112ccc 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -1604,9 +1604,9 @@ select * from `information_schema`.`VIEWS` where `TABLE_SCHEMA` = NULL; TABLE_CATALOG TABLE_SCHEMA TABLE_NAME VIEW_DEFINITION CHECK_OPTION IS_UPDATABLE DEFINER SECURITY_TYPE CHARACTER_SET_CLIENT COLLATION_CONNECTION select * from `information_schema`.`VIEWS` where `TABLE_NAME` = NULL; TABLE_CATALOG TABLE_SCHEMA TABLE_NAME VIEW_DEFINITION CHECK_OPTION IS_UPDATABLE DEFINER SECURITY_TYPE CHARACTER_SET_CLIENT COLLATION_CONNECTION -explain extended select 1 from information_schema.TABLES; +explain extended select 1 from information_schema.tables; id select_type table type possible_keys key key_len ref rows filtered Extra -1 SIMPLE TABLES ALL NULL NULL NULL NULL NULL NULL Skip_open_table; Scanned all databases +1 SIMPLE tables ALL NULL NULL NULL NULL NULL NULL Skip_open_table; Scanned all databases Warnings: -Note 1003 select 1 AS `1` from `information_schema`.`TABLES` +Note 1003 select 1 AS `1` from `information_schema`.`tables` End of 5.1 tests. diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test index 5ac7ffa42ad..e9b025692e2 100644 --- a/mysql-test/t/information_schema.test +++ b/mysql-test/t/information_schema.test @@ -1235,6 +1235,6 @@ select * from `information_schema`.`VIEWS` where `TABLE_NAME` = NULL; # # Bug#31630 debug assert with explain extended select ... from i_s # -explain extended select 1 from information_schema.TABLES; +explain extended select 1 from information_schema.tables; --echo End of 5.1 tests. From 84d4f588cbfa573382968e30df43730e47a8a1b0 Mon Sep 17 00:00:00 2001 From: "aelkin/elkin@koti.dsl.inet.fi" <> Date: Tue, 6 Nov 2007 15:11:59 +0200 Subject: [PATCH 159/336] bug#27571 removing extra tests (on 5.1 that's been already done) --- .../t/binlog_killed_bug27571-master.opt | 1 - mysql-test/t/binlog_killed_bug27571.test | 68 ------------------- 2 files changed, 69 deletions(-) delete mode 100644 mysql-test/t/binlog_killed_bug27571-master.opt delete mode 100644 mysql-test/t/binlog_killed_bug27571.test diff --git a/mysql-test/t/binlog_killed_bug27571-master.opt b/mysql-test/t/binlog_killed_bug27571-master.opt deleted file mode 100644 index d269cf246d5..00000000000 --- a/mysql-test/t/binlog_killed_bug27571-master.opt +++ /dev/null @@ -1 +0,0 @@ ---loose-debug=d,stop_after_row_loop_done diff --git a/mysql-test/t/binlog_killed_bug27571.test b/mysql-test/t/binlog_killed_bug27571.test deleted file mode 100644 index 6fa3c6d256f..00000000000 --- a/mysql-test/t/binlog_killed_bug27571.test +++ /dev/null @@ -1,68 +0,0 @@ ---source include/have_innodb.inc ---source include/not_embedded.inc ---source include/have_log_bin.inc - -# -# bug#27571 asynchronous setting mysql_`query`::error and Query_log_e::error_code -# -# Checking that if killing happens inbetween of the end of rows loop and -# recording into binlog that will not lead to recording any error incl -# the killed error. -# - -connect (looser, localhost, root,,); -connect (killer, localhost, root,,); - -create table t1 (a int auto_increment, b int, PRIMARY KEY (a)) ENGINE=InnoDB; - -delete from t1; -insert into t1 values (1,1),(2,2); -reset master; - -connection looser; -let $ID= `select connection_id()`; -send update t1 set b=11 where a=2; - -connection killer; -sleep 1; # let 1 second for the update to get to the sleeping point ---replace_result $ID ID -eval kill query $ID; - -connection looser; ---error 0 # zero even though the query must be got killed while it was sleepin for 5 secs -reap; - -# -# this is another possible artifact. The killed error was not caught -# as that is logical as killing was not effective: -# data are ok and well as binlog event is without killed error (further). -# The reason of the following `show error' is to prove that -# killing simulation was effective -# -show errors; - -connection killer; - -# nothing is rolled back - -select * from t1 where a=2 /* must be 11 */; - -# a proof the query is binlogged with an error - ---exec $MYSQL_BINLOG --start-position=98 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog ---replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR -eval select -(@a:=load_file("$MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) -is not null; ---replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR -let $error_code= `select @a like "%#%error_code=0%"`; - -eval select $error_code /* must return 1*/; - -# -# cleanup -# - -drop table t1; - ---echo end of the tests From e85cc0000aa47896780854a584f979f4bc2389df Mon Sep 17 00:00:00 2001 From: "istruewing@stella.local" <> Date: Tue, 6 Nov 2007 14:47:15 +0100 Subject: [PATCH 160/336] Bug#4692 - DISABLE/ENABLE KEYS waste a space Post-merge fix. Moved test into 5.0 section. --- mysql-test/r/myisam.result | 50 ++++++++++++++++++------------------- mysql-test/t/myisam.test | 51 +++++++++++++++++++------------------- 2 files changed, 51 insertions(+), 50 deletions(-) diff --git a/mysql-test/r/myisam.result b/mysql-test/r/myisam.result index e3ff66afeab..3125660643c 100644 --- a/mysql-test/r/myisam.result +++ b/mysql-test/r/myisam.result @@ -1794,6 +1794,31 @@ SELECT a FROM t1 FORCE INDEX (inx) WHERE a=1; a 1 DROP TABLE t1; +CREATE TABLE t1 (c1 INT, c2 INT, UNIQUE INDEX (c1), INDEX (c2)) ENGINE=MYISAM; +SHOW TABLE STATUS LIKE 't1'; +Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment +t1 MyISAM 10 Fixed 0 # # # 1024 # # # # # # # +INSERT INTO t1 VALUES (1,1); +SHOW TABLE STATUS LIKE 't1'; +Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment +t1 MyISAM 10 Fixed 1 # # # 3072 # # # # # # # +ALTER TABLE t1 DISABLE KEYS; +SHOW TABLE STATUS LIKE 't1'; +Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment +t1 MyISAM 10 Fixed 1 # # # 3072 # # # # # # # +ALTER TABLE t1 ENABLE KEYS; +SHOW TABLE STATUS LIKE 't1'; +Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment +t1 MyISAM 10 Fixed 1 # # # 3072 # # # # # # # +ALTER TABLE t1 DISABLE KEYS; +SHOW TABLE STATUS LIKE 't1'; +Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment +t1 MyISAM 10 Fixed 1 # # # 3072 # # # # # # # +ALTER TABLE t1 ENABLE KEYS; +SHOW TABLE STATUS LIKE 't1'; +Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment +t1 MyISAM 10 Fixed 1 # # # 3072 # # # # # # # +DROP TABLE t1; End of 5.0 tests create table t1 (a int not null, key `a` (a) key_block_size=1024); show create table t1; @@ -1987,28 +2012,3 @@ Table Op Msg_type Msg_text test.t1 check status OK DROP TABLE t1; End of 5.1 tests -CREATE TABLE t1 (c1 INT, c2 INT, UNIQUE INDEX (c1), INDEX (c2)) ENGINE=MYISAM; -SHOW TABLE STATUS LIKE 't1'; -Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment -t1 MyISAM 10 Fixed 0 # # # 1024 # # # # # # # -INSERT INTO t1 VALUES (1,1); -SHOW TABLE STATUS LIKE 't1'; -Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment -t1 MyISAM 10 Fixed 1 # # # 3072 # # # # # # # -ALTER TABLE t1 DISABLE KEYS; -SHOW TABLE STATUS LIKE 't1'; -Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment -t1 MyISAM 10 Fixed 1 # # # 3072 # # # # # # # -ALTER TABLE t1 ENABLE KEYS; -SHOW TABLE STATUS LIKE 't1'; -Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment -t1 MyISAM 10 Fixed 1 # # # 3072 # # # # # # # -ALTER TABLE t1 DISABLE KEYS; -SHOW TABLE STATUS LIKE 't1'; -Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment -t1 MyISAM 10 Fixed 1 # # # 3072 # # # # # # # -ALTER TABLE t1 ENABLE KEYS; -SHOW TABLE STATUS LIKE 't1'; -Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment -t1 MyISAM 10 Fixed 1 # # # 3072 # # # # # # # -DROP TABLE t1; diff --git a/mysql-test/t/myisam.test b/mysql-test/t/myisam.test index 0c5a2e621d1..6f24d84f4c0 100644 --- a/mysql-test/t/myisam.test +++ b/mysql-test/t/myisam.test @@ -1146,6 +1146,32 @@ ALTER TABLE t1 ENABLE KEYS; SELECT a FROM t1 FORCE INDEX (inx) WHERE a=1; DROP TABLE t1; +# +# Bug#4692 - DISABLE/ENABLE KEYS waste a space +# +CREATE TABLE t1 (c1 INT, c2 INT, UNIQUE INDEX (c1), INDEX (c2)) ENGINE=MYISAM; +--replace_column 6 # 7 # 8 # 10 # 11 # 12 # 13 # 14 # 15 # 16 # +SHOW TABLE STATUS LIKE 't1'; +INSERT INTO t1 VALUES (1,1); +--replace_column 6 # 7 # 8 # 10 # 11 # 12 # 13 # 14 # 15 # 16 # +SHOW TABLE STATUS LIKE 't1'; +ALTER TABLE t1 DISABLE KEYS; +--replace_column 6 # 7 # 8 # 10 # 11 # 12 # 13 # 14 # 15 # 16 # +SHOW TABLE STATUS LIKE 't1'; +ALTER TABLE t1 ENABLE KEYS; +--replace_column 6 # 7 # 8 # 10 # 11 # 12 # 13 # 14 # 15 # 16 # +SHOW TABLE STATUS LIKE 't1'; +ALTER TABLE t1 DISABLE KEYS; +--replace_column 6 # 7 # 8 # 10 # 11 # 12 # 13 # 14 # 15 # 16 # +SHOW TABLE STATUS LIKE 't1'; +ALTER TABLE t1 ENABLE KEYS; +--replace_column 6 # 7 # 8 # 10 # 11 # 12 # 13 # 14 # 15 # 16 # +SHOW TABLE STATUS LIKE 't1'; +#--exec ls -log var/master-data/test/t1.MYI +#--exec myisamchk -dvv var/master-data/test/t1.MYI +#--exec myisamchk -iev var/master-data/test/t1.MYI +DROP TABLE t1; + --echo End of 5.0 tests @@ -1256,29 +1282,4 @@ CHECK TABLE t1; DROP TABLE t1; --echo End of 5.1 tests -# -# Bug#4692 - DISABLE/ENABLE KEYS waste a space -# -CREATE TABLE t1 (c1 INT, c2 INT, UNIQUE INDEX (c1), INDEX (c2)) ENGINE=MYISAM; ---replace_column 6 # 7 # 8 # 10 # 11 # 12 # 13 # 14 # 15 # 16 # -SHOW TABLE STATUS LIKE 't1'; -INSERT INTO t1 VALUES (1,1); ---replace_column 6 # 7 # 8 # 10 # 11 # 12 # 13 # 14 # 15 # 16 # -SHOW TABLE STATUS LIKE 't1'; -ALTER TABLE t1 DISABLE KEYS; ---replace_column 6 # 7 # 8 # 10 # 11 # 12 # 13 # 14 # 15 # 16 # -SHOW TABLE STATUS LIKE 't1'; -ALTER TABLE t1 ENABLE KEYS; ---replace_column 6 # 7 # 8 # 10 # 11 # 12 # 13 # 14 # 15 # 16 # -SHOW TABLE STATUS LIKE 't1'; -ALTER TABLE t1 DISABLE KEYS; ---replace_column 6 # 7 # 8 # 10 # 11 # 12 # 13 # 14 # 15 # 16 # -SHOW TABLE STATUS LIKE 't1'; -ALTER TABLE t1 ENABLE KEYS; ---replace_column 6 # 7 # 8 # 10 # 11 # 12 # 13 # 14 # 15 # 16 # -SHOW TABLE STATUS LIKE 't1'; -#--exec ls -log var/master-data/test/t1.MYI -#--exec myisamchk -dvv var/master-data/test/t1.MYI -#--exec myisamchk -iev var/master-data/test/t1.MYI -DROP TABLE t1; From d06e2f922354bb1f98f5fe434ea5445c99af215d Mon Sep 17 00:00:00 2001 From: "svoj@mysql.com/june.mysql.com" <> Date: Tue, 6 Nov 2007 18:09:33 +0400 Subject: [PATCH 161/336] BUG#32111 - Security Breach via DATA/INDEX DIRECORY and RENAME TABLE RENAME TABLE against a table with DATA/INDEX DIRECTORY overwrites the file to which the symlink points. This is security issue, because it is possible to create a table with some name in some non-system database and set DATA/INDEX DIRECTORY to mysql system database. Renaming this table to one of mysql system tables (e.g. user, host) would overwrite the system table. Return an error when the file to which the symlink points exist. --- mysql-test/r/symlink.result | 6 ++++++ mysql-test/t/symlink.test | 12 ++++++++++++ mysys/my_symlink2.c | 11 ++++++++++- 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/symlink.result b/mysql-test/r/symlink.result index d07a8613883..e2b26cb508c 100644 --- a/mysql-test/r/symlink.result +++ b/mysql-test/r/symlink.result @@ -84,3 +84,9 @@ t1 CREATE TABLE `t1` ( `b` int(11) default NULL ) TYPE=MyISAM drop table t1; +CREATE TABLE t1(a INT) +DATA DIRECTORY='TEST_DIR/var/master-data/mysql' +INDEX DIRECTORY='TEST_DIR/var/master-data/mysql'; +RENAME TABLE t1 TO user; +Can't create/write to file 'TEST_DIR/var/master-data/mysql/user.MYI' (Errcode: 17) +DROP TABLE t1; diff --git a/mysql-test/t/symlink.test b/mysql-test/t/symlink.test index 7a42a60054e..9750e6fdfdd 100644 --- a/mysql-test/t/symlink.test +++ b/mysql-test/t/symlink.test @@ -112,3 +112,15 @@ eval alter table t1 index directory="$MYSQL_TEST_DIR/var/log"; enable_query_log; show create table t1; drop table t1; + +# +# BUG#32111 - Security Breach via DATA/INDEX DIRECORY and RENAME TABLE +# +--replace_result $MYSQL_TEST_DIR TEST_DIR +eval CREATE TABLE t1(a INT) +DATA DIRECTORY='$MYSQL_TEST_DIR/var/master-data/mysql' +INDEX DIRECTORY='$MYSQL_TEST_DIR/var/master-data/mysql'; +--replace_result $MYSQL_TEST_DIR TEST_DIR +--error 1 +RENAME TABLE t1 TO user; +DROP TABLE t1; diff --git a/mysys/my_symlink2.c b/mysys/my_symlink2.c index 913f632fbb4..4d58699412a 100644 --- a/mysys/my_symlink2.c +++ b/mysys/my_symlink2.c @@ -120,6 +120,7 @@ int my_rename_with_symlink(const char *from, const char *to, myf MyFlags) int was_symlink= (!my_disable_symlinks && !my_readlink(link_name, from, MYF(0))); int result=0; + int name_is_different; DBUG_ENTER("my_rename_with_symlink"); if (!was_symlink) @@ -128,6 +129,14 @@ int my_rename_with_symlink(const char *from, const char *to, myf MyFlags) /* Change filename that symlink pointed to */ strmov(tmp_name, to); fn_same(tmp_name,link_name,1); /* Copy dir */ + name_is_different= strcmp(link_name, tmp_name); + if (name_is_different && !access(tmp_name, F_OK)) + { + my_errno= EEXIST; + if (MyFlags & MY_WME) + my_error(EE_CANTCREATEFILE, MYF(0), tmp_name, EEXIST); + DBUG_RETURN(1); + } /* Create new symlink */ if (my_symlink(tmp_name, to, MyFlags)) @@ -139,7 +148,7 @@ int my_rename_with_symlink(const char *from, const char *to, myf MyFlags) the same basename and different directories. */ - if (strcmp(link_name, tmp_name) && my_rename(link_name, tmp_name, MyFlags)) + if (name_is_different && my_rename(link_name, tmp_name, MyFlags)) { int save_errno=my_errno; my_delete(to, MyFlags); /* Remove created symlink */ From a179cf154054127beadb095f181db3eba4e9cd7d Mon Sep 17 00:00:00 2001 From: "aelkin/elkin@koti.dsl.inet.fi" <> Date: Tue, 6 Nov 2007 16:25:32 +0200 Subject: [PATCH 162/336] bug#27571 fixing tests --- mysql-test/r/binlog_killed_simulate.result | 33 ++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 mysql-test/r/binlog_killed_simulate.result diff --git a/mysql-test/r/binlog_killed_simulate.result b/mysql-test/r/binlog_killed_simulate.result new file mode 100644 index 00000000000..a21ac5b1e32 --- /dev/null +++ b/mysql-test/r/binlog_killed_simulate.result @@ -0,0 +1,33 @@ +drop table if exists t1,t2; +create table t1 (a int) engine=MyISAM; +insert into t1 set a=1; +reset master; +update t1 set a=2 /* will be "killed" after work has been done */; +select +(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) +is not null; +(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) +is not null +1 +select 1 /* must return 1 as query completed before got killed*/; +1 +1 +create table t2 (a int, b int) ENGINE=MyISAM; +reset master; +load data infile '../std_data_ln/rpl_loaddata.dat' into table t2 /* will be "killed" in the middle */; +ERROR 70100: Query execution was interrupted +show binlog events from 98; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 98 Begin_load_query 1 # ;file_id=1;block_len=12 +master-bin.000001 133 Execute_load_query 1 # use `test`; load data infile '../std_data_ln/rpl_loaddata.dat' into table t2 /* will be "killed" in the middle */ ;file_id=1 +select +(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) +is not null; +(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) +is not null +1 +select 0 /* must return 0 to mean the killed query is in */; +0 +0 +drop table t1,t2; +end of the tests From ba8fc4fed1c4e618d1dada748b83fc4fc181a3f1 Mon Sep 17 00:00:00 2001 From: "aelkin/elkin@koti.dsl.inet.fi" <> Date: Tue, 6 Nov 2007 16:32:55 +0200 Subject: [PATCH 163/336] results from 5.0 is not needed --- mysql-test/r/binlog_killed_simulate.result | 33 ---------------------- 1 file changed, 33 deletions(-) delete mode 100644 mysql-test/r/binlog_killed_simulate.result diff --git a/mysql-test/r/binlog_killed_simulate.result b/mysql-test/r/binlog_killed_simulate.result deleted file mode 100644 index a21ac5b1e32..00000000000 --- a/mysql-test/r/binlog_killed_simulate.result +++ /dev/null @@ -1,33 +0,0 @@ -drop table if exists t1,t2; -create table t1 (a int) engine=MyISAM; -insert into t1 set a=1; -reset master; -update t1 set a=2 /* will be "killed" after work has been done */; -select -(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) -is not null; -(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) -is not null -1 -select 1 /* must return 1 as query completed before got killed*/; -1 -1 -create table t2 (a int, b int) ENGINE=MyISAM; -reset master; -load data infile '../std_data_ln/rpl_loaddata.dat' into table t2 /* will be "killed" in the middle */; -ERROR 70100: Query execution was interrupted -show binlog events from 98; -Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 98 Begin_load_query 1 # ;file_id=1;block_len=12 -master-bin.000001 133 Execute_load_query 1 # use `test`; load data infile '../std_data_ln/rpl_loaddata.dat' into table t2 /* will be "killed" in the middle */ ;file_id=1 -select -(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) -is not null; -(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) -is not null -1 -select 0 /* must return 0 to mean the killed query is in */; -0 -0 -drop table t1,t2; -end of the tests From 21497124eac4966f9d52ecbe4d52999b650404a9 Mon Sep 17 00:00:00 2001 From: "mats@kindahl-laptop.dnsalias.net" <> Date: Tue, 6 Nov 2007 17:51:32 +0100 Subject: [PATCH 164/336] BUG#12092 (FOUND_ROWS() not replicated): In BUG#30244 added FOUND_ROWS() as an unsafe function, but that works only in mixed mode under 5.1. There is a workaround that can be used in statement-based mode either under 5.0 or 5.1 where the result of FOUND_ROWS() is stored into a user vari- able and used that way instead. This will replicate correctly even under statement-based replication, since it will write a User_var entry to the binary log. For some other cases, the value has to be passed explicitly. This patch adds tests to demonstrate that the workarounds docu- mented for statement-based replication works as advertised, and does more extensive tests for cases that does not work under sta- tement-based replication actually work under mixed mode by switch- ing to row-based replication. --- mysql-test/include/reset_master_and_slave.inc | 10 + mysql-test/suite/rpl/r/rpl_found_rows.result | 228 ++++++++++++++++ mysql-test/suite/rpl/t/rpl_found_rows.test | 251 ++++++++++++++++++ 3 files changed, 489 insertions(+) create mode 100644 mysql-test/include/reset_master_and_slave.inc create mode 100644 mysql-test/suite/rpl/r/rpl_found_rows.result create mode 100644 mysql-test/suite/rpl/t/rpl_found_rows.test diff --git a/mysql-test/include/reset_master_and_slave.inc b/mysql-test/include/reset_master_and_slave.inc new file mode 100644 index 00000000000..c2d4120ddc9 --- /dev/null +++ b/mysql-test/include/reset_master_and_slave.inc @@ -0,0 +1,10 @@ +--echo **** Resetting master and slave **** +connection slave; +STOP SLAVE; +source include/wait_for_slave_to_stop.inc; +RESET SLAVE; +connection master; +RESET MASTER; +connection slave; +START SLAVE; +source include/wait_for_slave_to_start.inc; diff --git a/mysql-test/suite/rpl/r/rpl_found_rows.result b/mysql-test/suite/rpl/r/rpl_found_rows.result new file mode 100644 index 00000000000..cec5071eecd --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_found_rows.result @@ -0,0 +1,228 @@ +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; +==== 0. Setting it all up ==== +SET BINLOG_FORMAT=STATEMENT; +**** On Master **** +CREATE TABLE t1 (a INT); +CREATE TABLE logtbl (sect INT, test INT, count INT); +INSERT INTO t1 VALUES (1),(2),(3); +INSERT INTO t1 SELECT 2*a+3 FROM t1; +INSERT INTO t1 SELECT 2*a+3 FROM t1; +INSERT INTO t1 SELECT 2*a+3 FROM t1; +INSERT INTO t1 SELECT 2*a+3 FROM t1; +INSERT INTO t1 SELECT 2*a+3 FROM t1; +INSERT INTO t1 SELECT 2*a+3 FROM t1; +#### 1. Using statement mode #### +==== 1.1. Simple test ==== +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; +a +7 +SELECT FOUND_ROWS() INTO @a; +INSERT INTO logtbl VALUES(1,1,@a); +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a < 5 ORDER BY a LIMIT 1; +a +1 +SELECT FOUND_ROWS() INTO @a; +INSERT INTO logtbl VALUES(1,2,@a); +SELECT * FROM logtbl WHERE sect = 1; +sect test count +1 1 183 +1 2 3 +**** On Slave **** +SELECT * FROM logtbl WHERE sect = 1; +sect test count +1 1 183 +1 2 3 +==== 1.2. Stored procedure ==== +**** On Master **** +CREATE PROCEDURE calc_and_log(sect INT, test INT) BEGIN +DECLARE cnt INT; +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a < 5 ORDER BY a LIMIT 1; +SELECT FOUND_ROWS() INTO cnt; +INSERT INTO logtbl VALUES(sect,test,cnt); +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; +SELECT FOUND_ROWS() INTO cnt; +INSERT INTO logtbl VALUES(sect,test+1,cnt); +END $$ +CALL calc_and_log(2,1); +a +1 +a +7 +CREATE PROCEDURE just_log(sect INT, test INT, found_rows INT) BEGIN +INSERT INTO logtbl VALUES (sect,test,found_rows); +END $$ +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; +a +7 +SELECT FOUND_ROWS() INTO @found_rows; +CALL just_log(2,3,@found_rows); +SELECT * FROM logtbl WHERE sect = 2; +sect test count +2 1 3 +2 2 183 +2 3 183 +**** On Slave **** +SELECT * FROM logtbl WHERE sect = 2; +sect test count +2 1 3 +2 2 183 +2 3 183 +==== 1.3. Stored functions ==== +**** On Master **** +CREATE FUNCTION log_rows(sect INT, test INT, found_rows INT) +RETURNS INT +BEGIN +INSERT INTO logtbl VALUES(sect,test,found_rows); +RETURN found_rows; +END $$ +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; +a +7 +SELECT FOUND_ROWS() INTO @found_rows; +SELECT log_rows(3,1,@found_rows), log_rows(3,2,@found_rows); +log_rows(3,1,@found_rows) log_rows(3,2,@found_rows) +183 183 +SELECT * FROM logtbl WHERE sect = 3; +sect test count +3 1 183 +3 2 183 +**** On Slave **** +SELECT * FROM logtbl WHERE sect = 3; +sect test count +3 1 183 +3 2 183 +==== 1.9. Cleanup ==== +**** On Master **** +DELETE FROM logtbl; +DROP PROCEDURE just_log; +DROP PROCEDURE calc_and_log; +DROP FUNCTION log_rows; +**** Resetting master and slave **** +STOP SLAVE; +RESET SLAVE; +RESET MASTER; +START SLAVE; +#### 2. Using mixed mode #### +==== 2.1. Checking a procedure ==== +**** On Master **** +SET BINLOG_FORMAT=MIXED; +CREATE PROCEDURE just_log(sect INT, test INT) BEGIN +INSERT INTO logtbl VALUES (sect,test,FOUND_ROWS()); +END $$ +**** On Master 1 **** +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; +a +7 +CALL just_log(1,1); +**** On Master **** +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; +a +7 +CALL just_log(1,2); +**** On Master 1 **** +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a < 5 ORDER BY a LIMIT 1; +a +1 +CALL just_log(1,3); +**** On Master **** +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; +a +7 +CALL just_log(1,4); +SELECT * FROM logtbl WHERE sect = 1; +sect test count +1 1 183 +1 2 183 +1 3 3 +1 4 183 +**** On Slave **** +SELECT * FROM logtbl WHERE sect = 1; +sect test count +1 1 183 +1 2 183 +1 3 3 +1 4 183 +==== 2.1. Checking a stored function ==== +**** On Master **** +CREATE FUNCTION log_rows(sect INT, test INT) +RETURNS INT +BEGIN +DECLARE found_rows INT; +SELECT FOUND_ROWS() INTO found_rows; +INSERT INTO logtbl VALUES(sect,test,found_rows); +RETURN found_rows; +END $$ +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a < 5 ORDER BY a LIMIT 1; +a +1 +SELECT log_rows(2,1), log_rows(2,2); +log_rows(2,1) log_rows(2,2) +3 3 +CREATE TABLE t2 (a INT, b INT); +CREATE TRIGGER t2_tr BEFORE INSERT ON t2 FOR EACH ROW +BEGIN +INSERT INTO logtbl VALUES (NEW.a, NEW.b, FOUND_ROWS()); +END $$ +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a < 5 ORDER BY a LIMIT 1; +a +1 +INSERT INTO t2 VALUES (2,3), (2,4); +DROP TRIGGER t2_tr; +CREATE TRIGGER t2_tr BEFORE INSERT ON t2 FOR EACH ROW +BEGIN +DECLARE dummy INT; +SELECT log_rows(NEW.a, NEW.b) INTO dummy; +END $$ +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; +a +7 +INSERT INTO t2 VALUES (2,5), (2,6); +DROP TRIGGER t2_tr; +CREATE PROCEDURE log_me_inner(sect INT, test INT) +BEGIN +DECLARE dummy INT; +SELECT log_rows(sect, test) INTO dummy; +SELECT log_rows(sect, test+1) INTO dummy; +END $$ +CREATE PROCEDURE log_me(sect INT, test INT) +BEGIN +CALL log_me_inner(sect,test); +END $$ +CREATE TRIGGER t2_tr BEFORE INSERT ON t2 FOR EACH ROW +BEGIN +CALL log_me(NEW.a, NEW.b); +END $$ +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; +a +7 +INSERT INTO t2 VALUES (2,5), (2,6); +SELECT * FROM logtbl WHERE sect = 2; +sect test count +2 1 3 +2 2 3 +2 3 3 +2 4 3 +2 5 183 +2 6 183 +2 5 183 +2 6 0 +2 6 183 +2 7 0 +SELECT * FROM logtbl WHERE sect = 2; +sect test count +2 1 3 +2 2 3 +2 3 3 +2 4 3 +2 5 183 +2 6 183 +2 5 183 +2 6 0 +2 6 183 +2 7 0 +DROP TABLE t1, logtbl; diff --git a/mysql-test/suite/rpl/t/rpl_found_rows.test b/mysql-test/suite/rpl/t/rpl_found_rows.test new file mode 100644 index 00000000000..5d67b2ba6b7 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_found_rows.test @@ -0,0 +1,251 @@ +source include/master-slave.inc; + +# It is not possible to replicate FOUND_ROWS() using statement-based +# replication, but there is a workaround that stores the result of +# FOUND_ROWS() into a user variable and then replicates this instead. + +# The purpose of this test case is to test that the workaround +# function properly even when inside stored programs (i.e., stored +# routines and triggers). + +--echo ==== 0. Setting it all up ==== + +SET BINLOG_FORMAT=STATEMENT; + +--echo **** On Master **** +connection master; +CREATE TABLE t1 (a INT); +CREATE TABLE logtbl (sect INT, test INT, count INT); + +INSERT INTO t1 VALUES (1),(2),(3); +INSERT INTO t1 SELECT 2*a+3 FROM t1; +INSERT INTO t1 SELECT 2*a+3 FROM t1; +INSERT INTO t1 SELECT 2*a+3 FROM t1; +INSERT INTO t1 SELECT 2*a+3 FROM t1; +INSERT INTO t1 SELECT 2*a+3 FROM t1; +INSERT INTO t1 SELECT 2*a+3 FROM t1; + +--echo #### 1. Using statement mode #### + +--echo ==== 1.1. Simple test ==== + +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; + +# Instead of +# INSERT INTO logtbl VALUES(1, 1, FOUND_ROWS()); +# we write +SELECT FOUND_ROWS() INTO @a; +INSERT INTO logtbl VALUES(1,1,@a); + +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a < 5 ORDER BY a LIMIT 1; +# Instead of +# INSERT INTO logtbl VALUES(1, 2, FOUND_ROWS()); +# we write +SELECT FOUND_ROWS() INTO @a; +INSERT INTO logtbl VALUES(1,2,@a); + +SELECT * FROM logtbl WHERE sect = 1; +--echo **** On Slave **** +sync_slave_with_master; +SELECT * FROM logtbl WHERE sect = 1; + +--echo ==== 1.2. Stored procedure ==== + +# Here we do both the calculation and the logging. We also do it twice +# to make sure that there are no limitations on how many times it can +# be used. + +--echo **** On Master **** +connection master; +--delimiter $$ +CREATE PROCEDURE calc_and_log(sect INT, test INT) BEGIN + DECLARE cnt INT; + SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a < 5 ORDER BY a LIMIT 1; + SELECT FOUND_ROWS() INTO cnt; + INSERT INTO logtbl VALUES(sect,test,cnt); + SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; + SELECT FOUND_ROWS() INTO cnt; + INSERT INTO logtbl VALUES(sect,test+1,cnt); +END $$ +--delimiter ; + +CALL calc_and_log(2,1); + +--delimiter $$ +CREATE PROCEDURE just_log(sect INT, test INT, found_rows INT) BEGIN + INSERT INTO logtbl VALUES (sect,test,found_rows); +END $$ +--delimiter ; + +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; +SELECT FOUND_ROWS() INTO @found_rows; +CALL just_log(2,3,@found_rows); + +SELECT * FROM logtbl WHERE sect = 2; +--echo **** On Slave **** +sync_slave_with_master; +SELECT * FROM logtbl WHERE sect = 2; + +--echo ==== 1.3. Stored functions ==== +--echo **** On Master **** +connection master; +--delimiter $$ +CREATE FUNCTION log_rows(sect INT, test INT, found_rows INT) + RETURNS INT +BEGIN + INSERT INTO logtbl VALUES(sect,test,found_rows); + RETURN found_rows; +END $$ +--delimiter ; + +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; +SELECT FOUND_ROWS() INTO @found_rows; +SELECT log_rows(3,1,@found_rows), log_rows(3,2,@found_rows); + +SELECT * FROM logtbl WHERE sect = 3; +--echo **** On Slave **** +sync_slave_with_master; +SELECT * FROM logtbl WHERE sect = 3; + +--echo ==== 1.9. Cleanup ==== +--echo **** On Master **** +connection master; +DELETE FROM logtbl; +DROP PROCEDURE just_log; +DROP PROCEDURE calc_and_log; +DROP FUNCTION log_rows; +sync_slave_with_master; + +source include/reset_master_and_slave.inc; + +--echo #### 2. Using mixed mode #### + +--echo ==== 2.1. Checking a procedure ==== + +--echo **** On Master **** +connection master; +SET BINLOG_FORMAT=MIXED; + +# We will now check some stuff that will not work in statement-based +# replication, but which should cause the binary log to switch to +# row-based logging. + +--delimiter $$ +CREATE PROCEDURE just_log(sect INT, test INT) BEGIN + INSERT INTO logtbl VALUES (sect,test,FOUND_ROWS()); +END $$ +--delimiter ; +sync_slave_with_master; + +--echo **** On Master 1 **** +connection master1; +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; +CALL just_log(1,1); + +--echo **** On Master **** +connection master; +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; +CALL just_log(1,2); + +--echo **** On Master 1 **** + +connection master1; +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a < 5 ORDER BY a LIMIT 1; +CALL just_log(1,3); +sync_slave_with_master; + +--echo **** On Master **** +connection master; +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; +CALL just_log(1,4); +sync_slave_with_master; + +connection master; +SELECT * FROM logtbl WHERE sect = 1; +--echo **** On Slave **** +sync_slave_with_master; +SELECT * FROM logtbl WHERE sect = 1; + +--echo ==== 2.1. Checking a stored function ==== +--echo **** On Master **** +connection master; +--delimiter $$ +CREATE FUNCTION log_rows(sect INT, test INT) + RETURNS INT +BEGIN + DECLARE found_rows INT; + SELECT FOUND_ROWS() INTO found_rows; + INSERT INTO logtbl VALUES(sect,test,found_rows); + RETURN found_rows; +END $$ +--delimiter ; + +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a < 5 ORDER BY a LIMIT 1; +SELECT log_rows(2,1), log_rows(2,2); + +CREATE TABLE t2 (a INT, b INT); + +# Trying with referencing FOUND_ROWS() directly in the trigger. + +--delimiter $$ +CREATE TRIGGER t2_tr BEFORE INSERT ON t2 FOR EACH ROW +BEGIN + INSERT INTO logtbl VALUES (NEW.a, NEW.b, FOUND_ROWS()); +END $$ +--delimiter ; + +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a < 5 ORDER BY a LIMIT 1; +INSERT INTO t2 VALUES (2,3), (2,4); + +# Referencing FOUND_ROWS() indirectly. + +DROP TRIGGER t2_tr; + +--delimiter $$ +CREATE TRIGGER t2_tr BEFORE INSERT ON t2 FOR EACH ROW +BEGIN + DECLARE dummy INT; + SELECT log_rows(NEW.a, NEW.b) INTO dummy; +END $$ +--delimiter ; + +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; +INSERT INTO t2 VALUES (2,5), (2,6); + +# Putting FOUND_ROWS() even lower in the call chain. + +connection master; +DROP TRIGGER t2_tr; + +--delimiter $$ +CREATE PROCEDURE log_me_inner(sect INT, test INT) +BEGIN + DECLARE dummy INT; + SELECT log_rows(sect, test) INTO dummy; + SELECT log_rows(sect, test+1) INTO dummy; +END $$ + +CREATE PROCEDURE log_me(sect INT, test INT) +BEGIN + CALL log_me_inner(sect,test); +END $$ +--delimiter ; + +--delimiter $$ +CREATE TRIGGER t2_tr BEFORE INSERT ON t2 FOR EACH ROW +BEGIN + CALL log_me(NEW.a, NEW.b); +END $$ +--delimiter ; + +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; +INSERT INTO t2 VALUES (2,5), (2,6); + +SELECT * FROM logtbl WHERE sect = 2; +sync_slave_with_master; +SELECT * FROM logtbl WHERE sect = 2; + +connection master; +DROP TABLE t1, logtbl; +sync_slave_with_master; + From 904db2cf960749916b3b8cd18304387d0330e399 Mon Sep 17 00:00:00 2001 From: "aelkin/elkin@koti.dsl.inet.fi" <> Date: Tue, 6 Nov 2007 20:09:45 +0200 Subject: [PATCH 165/336] bug#27571 tests fixing: refreshing the results file. --- mysql-test/suite/binlog/r/binlog_killed.result | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/mysql-test/suite/binlog/r/binlog_killed.result b/mysql-test/suite/binlog/r/binlog_killed.result index 3cd21e3bca1..35b1eaea4b7 100644 --- a/mysql-test/suite/binlog/r/binlog_killed.result +++ b/mysql-test/suite/binlog/r/binlog_killed.result @@ -68,7 +68,11 @@ get_lock("a", 20) 1 set @b= 0; update t4 set b=b + bug27563(b); +select count(*) FROM INFORMATION_SCHEMA.PROCESSLIST where state='User lock'; +count(*) +1 kill query ID; +ERROR 70100: Query execution was interrupted select * from t4 order by b /* must be (1,1), (1,2) */; a b 1 1 @@ -101,7 +105,11 @@ get_lock("a", 20) 1 set @b= 0; delete from t4 where b=bug27563(1) or b=bug27563(2); +select count(*) FROM INFORMATION_SCHEMA.PROCESSLIST where state='User lock'; +count(*) +1 kill query ID; +ERROR 70100: Query execution was interrupted select count(*) from t4 /* must be 1 */; count(*) 1 From b9e4fdb2806f430fc7311cc1ba9316d355e0b573 Mon Sep 17 00:00:00 2001 From: "aelkin/elkin@koti.dsl.inet.fi" <> Date: Tue, 6 Nov 2007 20:31:40 +0200 Subject: [PATCH 166/336] bug#27571 refining non-deterministic tests. The new Bug@32148 is in the way. Adjuting the tests to be somehow useful. --- mysql-test/r/binlog_killed.result | 4 ++++ mysql-test/t/binlog_killed.test | 15 +++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/mysql-test/r/binlog_killed.result b/mysql-test/r/binlog_killed.result index eaafc9727cd..e04cc192876 100644 --- a/mysql-test/r/binlog_killed.result +++ b/mysql-test/r/binlog_killed.result @@ -17,18 +17,22 @@ delete from t2; insert into t1 values (1,1),(2,2); begin; update t1 set b=11 where a=2; +begin; update t1 set b=b+10; kill query ID; rollback; +rollback; select * from t1 order by a /* must be the same as before (1,1),(2,2) */; a b 1 1 2 2 begin; delete from t1 where a=2; +begin; delete from t1 where a=2; kill query ID; rollback; +rollback; select * from t1 order by a /* must be the same as before (1,1),(2,2) */; a b 1 1 diff --git a/mysql-test/t/binlog_killed.test b/mysql-test/t/binlog_killed.test index f8ba7c00f48..af78adf0abc 100644 --- a/mysql-test/t/binlog_killed.test +++ b/mysql-test/t/binlog_killed.test @@ -79,6 +79,7 @@ begin; update t1 set b=11 where a=2; connection con2; let $ID= `select connection_id()`; +begin; send update t1 set b=b+10; connection con1; @@ -86,9 +87,18 @@ connection con1; eval kill query $ID; rollback; +# Bug #32148 killi query may be ineffective +# forced to comment out the test's outcome +# and mask out ineffective ER_QUERY_INTERRUPTED +# todo1: revert back upon fixing bug#32148 +# todo2: the tests need refining in that +# killing should wait till the victim requested +# its lock (wait_condition available in 5.1 tests) + connection con2; --error 0,ER_QUERY_INTERRUPTED reap; +rollback; select * from t1 order by a /* must be the same as before (1,1),(2,2) */; # @@ -123,6 +133,7 @@ begin; delete from t1 where a=2; connection con2; let $ID= `select connection_id()`; +begin; send delete from t1 where a=2; connection con1; @@ -133,8 +144,11 @@ rollback; connection con2; --error 0,ER_QUERY_INTERRUPTED reap; +rollback; +# todo1,2 above select * from t1 order by a /* must be the same as before (1,1),(2,2) */; + # # multi delete # the same as for multi-update @@ -178,6 +192,7 @@ rollback; connection con2; --error 0,ER_QUERY_INTERRUPTED reap; +# todo 1,2 above rollback; select * from t1 /* must be the same as before (1,1),(2,2) */; From 9f6febf93367b419a6e5de861574ea8ef6a8472e Mon Sep 17 00:00:00 2001 From: "sergefp@mysql.com" <> Date: Tue, 6 Nov 2007 21:57:51 +0300 Subject: [PATCH 167/336] Better comments --- sql/opt_range.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sql/opt_range.h b/sql/opt_range.h index dd219129167..4f5cce28bf2 100644 --- a/sql/opt_range.h +++ b/sql/opt_range.h @@ -24,9 +24,14 @@ #endif typedef struct st_key_part { - uint16 key,part, store_length, length; + uint16 key,part; + /* See KEY_PART_INFO for meaning of the next two: */ + uint16 store_length, length; uint8 null_bit; - /* Keypart flags (0 if partition pruning is used) */ + /* + Keypart flags (0 when this structure is used by partition pruning code + for fake partitioning index description) + */ uint8 flag; Field *field; Field::imagetype image_type; From eb654791271ceb11baa5d110df6fde38b3442385 Mon Sep 17 00:00:00 2001 From: "tsmith@ramayana.hindu.god" <> Date: Tue, 6 Nov 2007 15:42:58 -0700 Subject: [PATCH 168/336] Apply snapshot innodb-5.1-ss1989 Fixes the following bugs: Bug #30706: SQL thread on slave is allowed to block client queries when slave load is high Add (innodb|innobase|srv)_replication_delay MySQL config parameter. Bug #30888: Innodb table + stored procedure + row deletion = server crash While adding code for the low level read of the AUTOINC value from the index, the case for MEDIUM ints which are 3 bytes was missed triggering an assertion. Bug #30907: Regression: "--innodb_autoinc_lock_mode=0" (off) not same as older releases We don't rely on *first_value to be 0 when checking whether get_auto_increment() has been invoked for the first time in a multi-row INSERT. We instead use trx_t::n_autoinc_rows. Initialize trx::n_autoinc_rows inside ha_innobase::start_stmt() too. Bug #31444: "InnoDB: Error: MySQL is freeing a thd" in innodb_mysql.test ha_innobase::external_lock(): Update prebuilt->mysql_has_locked and trx->n_mysql_tables_in_use only after row_lock_table_for_mysql() returns DB_SUCCESS. A timeout on LOCK TABLES would lead to an inconsistent state, which would cause trx_free() to print a warning. Bug #31494: innodb + 5.1 + read committed crash, assertion Set an error code when a deadlock occurs in semi-consistent read. --- mysql-test/r/innodb-semi-consistent.result | 36 +++++++ mysql-test/r/innodb.result | 76 +++++++------- .../r/innodb_autoinc_lock_mode_zero.result | 39 ++++++++ .../t/innodb-semi-consistent-master.opt | 1 + mysql-test/t/innodb-semi-consistent.test | 46 +++++++++ mysql-test/t/innodb.test | 75 +++++++------- .../innodb_autoinc_lock_mode_zero-master.opt | 1 + .../t/innodb_autoinc_lock_mode_zero.test | 44 +++++++++ storage/innobase/buf/buf0lru.c | 2 +- storage/innobase/dict/dict0dict.c | 4 + storage/innobase/dict/dict0load.c | 78 +++++++++------ storage/innobase/handler/ha_innodb.cc | 98 +++++++++++++------ storage/innobase/handler/ha_innodb.h | 14 --- storage/innobase/ibuf/ibuf0ibuf.c | 4 +- storage/innobase/include/db0err.h | 6 +- storage/innobase/include/ha_prototypes.h | 16 +++ storage/innobase/include/mach0data.h | 11 +++ storage/innobase/include/mach0data.ic | 37 +++++++ storage/innobase/include/mem0dbg.h | 16 +-- storage/innobase/include/mem0mem.ic | 16 +-- storage/innobase/include/rem0rec.ic | 1 + storage/innobase/include/row0mysql.h | 13 ++- storage/innobase/include/sync0rw.h | 2 + storage/innobase/include/univ.i | 28 ++++++ storage/innobase/include/ut0ut.h | 18 ++++ storage/innobase/mem/mem0dbg.c | 40 +++++--- storage/innobase/mem/mem0mem.c | 6 +- storage/innobase/row/row0mysql.c | 82 +++++++--------- storage/innobase/row/row0sel.c | 69 ++++++++----- storage/innobase/sync/sync0rw.c | 6 +- storage/innobase/ut/ut0ut.c | 71 ++++++++++---- 31 files changed, 671 insertions(+), 285 deletions(-) create mode 100644 mysql-test/r/innodb-semi-consistent.result create mode 100644 mysql-test/r/innodb_autoinc_lock_mode_zero.result create mode 100644 mysql-test/t/innodb-semi-consistent-master.opt create mode 100644 mysql-test/t/innodb-semi-consistent.test create mode 100644 mysql-test/t/innodb_autoinc_lock_mode_zero-master.opt create mode 100644 mysql-test/t/innodb_autoinc_lock_mode_zero.test diff --git a/mysql-test/r/innodb-semi-consistent.result b/mysql-test/r/innodb-semi-consistent.result new file mode 100644 index 00000000000..ad7b70d0497 --- /dev/null +++ b/mysql-test/r/innodb-semi-consistent.result @@ -0,0 +1,36 @@ +set session transaction isolation level read committed; +create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1; +insert into t1 values (1),(2),(3),(4),(5),(6),(7); +set autocommit=0; +select * from t1 where a=3 lock in share mode; +a +3 +set session transaction isolation level read committed; +set autocommit=0; +update t1 set a=10 where a=5; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +commit; +update t1 set a=10 where a=5; +select * from t1 where a=2 for update; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +select * from t1 where a=2 limit 1 for update; +a +2 +update t1 set a=11 where a=6; +update t1 set a=12 where a=2; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +update t1 set a=13 where a=1; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +commit; +update t1 set a=14 where a=1; +commit; +select * from t1; +a +14 +2 +3 +4 +10 +11 +7 +drop table t1; diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index d0b67e90afb..9f6cde0292f 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -472,43 +472,6 @@ a b 3 3 drop table t1,t2; CREATE TABLE t1 ( -id int(11) NOT NULL auto_increment, -ggid varchar(32) binary DEFAULT '' NOT NULL, -email varchar(64) DEFAULT '' NOT NULL, -passwd varchar(32) binary DEFAULT '' NOT NULL, -PRIMARY KEY (id), -UNIQUE ggid (ggid) -) ENGINE=innodb; -insert into t1 (ggid,passwd) values ('test1','xxx'); -insert into t1 (ggid,passwd) values ('test2','yyy'); -insert into t1 (ggid,passwd) values ('test2','this will fail'); -ERROR 23000: Duplicate entry 'test2' for key 'ggid' -insert into t1 (ggid,id) values ('this will fail',1); -ERROR 23000: Duplicate entry '1' for key 'PRIMARY' -select * from t1 where ggid='test1'; -id ggid email passwd -1 test1 xxx -select * from t1 where passwd='xxx'; -id ggid email passwd -1 test1 xxx -select * from t1 where id=2; -id ggid email passwd -2 test2 yyy -replace into t1 (ggid,id) values ('this will work',1); -replace into t1 (ggid,passwd) values ('test2','this will work'); -update t1 set id=100,ggid='test2' where id=1; -ERROR 23000: Duplicate entry 'test2' for key 'ggid' -select * from t1; -id ggid email passwd -1 this will work -4 test2 this will work -select * from t1 where id=1; -id ggid email passwd -1 this will work -select * from t1 where id=999; -id ggid email passwd -drop table t1; -CREATE TABLE t1 ( user_name varchar(12), password text, subscribed char(1), @@ -1751,13 +1714,13 @@ Variable_name Value Innodb_page_size 16384 show status like "Innodb_rows_deleted"; Variable_name Value -Innodb_rows_deleted 70 +Innodb_rows_deleted 69 show status like "Innodb_rows_inserted"; Variable_name Value -Innodb_rows_inserted 1083 +Innodb_rows_inserted 1080 show status like "Innodb_rows_updated"; Variable_name Value -Innodb_rows_updated 886 +Innodb_rows_updated 885 show status like "Innodb_row_lock_waits"; Variable_name Value Innodb_row_lock_waits 0 @@ -3189,3 +3152,36 @@ c25 CHAR(255), c26 CHAR(255), c27 CHAR(255), c28 CHAR(255), c29 CHAR(255), c30 CHAR(255), c31 CHAR(255), c32 CHAR(255) ) ENGINE = InnoDB; ERROR 42000: Row size too large. The maximum row size for the used table type, not counting BLOBs, is 8126. You have to change some columns to TEXT or BLOBs +SET TX_ISOLATION='read-committed'; +SET AUTOCOMMIT=0; +DROP TABLE IF EXISTS t1, t2; +Warnings: +Note 1051 Unknown table 't1' +Note 1051 Unknown table 't2' +CREATE TABLE t1 ( a int ) ENGINE=InnoDB; +CREATE TABLE t2 LIKE t1; +SELECT * FROM t2; +a +SET TX_ISOLATION='read-committed'; +SET AUTOCOMMIT=0; +INSERT INTO t1 VALUES (1); +COMMIT; +SELECT * FROM t1 WHERE a=1; +a +1 +SET TX_ISOLATION='read-committed'; +SET AUTOCOMMIT=0; +SELECT * FROM t2; +a +SET TX_ISOLATION='read-committed'; +SET AUTOCOMMIT=0; +INSERT INTO t1 VALUES (2); +COMMIT; +SELECT * FROM t1 WHERE a=2; +a +2 +SELECT * FROM t1 WHERE a=2; +a +2 +DROP TABLE t1; +DROP TABLE t2; diff --git a/mysql-test/r/innodb_autoinc_lock_mode_zero.result b/mysql-test/r/innodb_autoinc_lock_mode_zero.result new file mode 100644 index 00000000000..3d016684338 --- /dev/null +++ b/mysql-test/r/innodb_autoinc_lock_mode_zero.result @@ -0,0 +1,39 @@ +drop table if exists t1; +CREATE TABLE t1 ( +id int(11) NOT NULL auto_increment, +ggid varchar(32) binary DEFAULT '' NOT NULL, +email varchar(64) DEFAULT '' NOT NULL, +passwd varchar(32) binary DEFAULT '' NOT NULL, +PRIMARY KEY (id), +UNIQUE ggid (ggid) +) ENGINE=innodb; +insert into t1 (ggid,passwd) values ('test1','xxx'); +insert into t1 (ggid,passwd) values ('test2','yyy'); +insert into t1 (ggid,passwd) values ('test2','this will fail'); +ERROR 23000: Duplicate entry 'test2' for key 'ggid' +insert into t1 (ggid,id) values ('this will fail',1); +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +select * from t1 where ggid='test1'; +id ggid email passwd +1 test1 xxx +select * from t1 where passwd='xxx'; +id ggid email passwd +1 test1 xxx +select * from t1 where id=2; +id ggid email passwd +2 test2 yyy +replace into t1 (ggid,id) values ('this will work',1); +replace into t1 (ggid,passwd) values ('test2','this will work'); +update t1 set id=100,ggid='test2' where id=1; +ERROR 23000: Duplicate entry 'test2' for key 'ggid' +select * from t1; +id ggid email passwd +1 this will work +3 test2 this will work +select * from t1 where id=1; +id ggid email passwd +1 this will work +select * from t1 where id=999; +id ggid email passwd +drop table t1; +End of tests diff --git a/mysql-test/t/innodb-semi-consistent-master.opt b/mysql-test/t/innodb-semi-consistent-master.opt new file mode 100644 index 00000000000..2746e4e184e --- /dev/null +++ b/mysql-test/t/innodb-semi-consistent-master.opt @@ -0,0 +1 @@ +--innodb_locks_unsafe_for_binlog=true --innodb_lock_wait_timeout=2 diff --git a/mysql-test/t/innodb-semi-consistent.test b/mysql-test/t/innodb-semi-consistent.test new file mode 100644 index 00000000000..7a9231b508f --- /dev/null +++ b/mysql-test/t/innodb-semi-consistent.test @@ -0,0 +1,46 @@ +-- source include/not_embedded.inc +-- source include/have_innodb.inc + +# basic tests of semi-consistent reads + +connect (a,localhost,root,,); +connect (b,localhost,root,,); +connection a; +set session transaction isolation level read committed; +create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1; +insert into t1 values (1),(2),(3),(4),(5),(6),(7); +set autocommit=0; +# this should lock the entire table +select * from t1 where a=3 lock in share mode; +connection b; +set session transaction isolation level read committed; +set autocommit=0; +-- error ER_LOCK_WAIT_TIMEOUT +update t1 set a=10 where a=5; +connection a; +commit; +connection b; +update t1 set a=10 where a=5; +connection a; +-- error ER_LOCK_WAIT_TIMEOUT +select * from t1 where a=2 for update; +# this should lock the records (1),(2) +select * from t1 where a=2 limit 1 for update; +connection b; +update t1 set a=11 where a=6; +-- error ER_LOCK_WAIT_TIMEOUT +update t1 set a=12 where a=2; +-- error ER_LOCK_WAIT_TIMEOUT +update t1 set a=13 where a=1; +connection a; +commit; +connection b; +update t1 set a=14 where a=1; +commit; +connection a; +select * from t1; +drop table t1; + +connection default; +disconnect a; +disconnect b; diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index cc1ef6f9730..77c450035c7 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -326,39 +326,6 @@ select * from t1; select * from t2; drop table t1,t2; -# -# Search on unique key -# - -CREATE TABLE t1 ( - id int(11) NOT NULL auto_increment, - ggid varchar(32) binary DEFAULT '' NOT NULL, - email varchar(64) DEFAULT '' NOT NULL, - passwd varchar(32) binary DEFAULT '' NOT NULL, - PRIMARY KEY (id), - UNIQUE ggid (ggid) -) ENGINE=innodb; - -insert into t1 (ggid,passwd) values ('test1','xxx'); -insert into t1 (ggid,passwd) values ('test2','yyy'); --- error ER_DUP_ENTRY -insert into t1 (ggid,passwd) values ('test2','this will fail'); --- error ER_DUP_ENTRY -insert into t1 (ggid,id) values ('this will fail',1); - -select * from t1 where ggid='test1'; -select * from t1 where passwd='xxx'; -select * from t1 where id=2; - -replace into t1 (ggid,id) values ('this will work',1); -replace into t1 (ggid,passwd) values ('test2','this will work'); --- error ER_DUP_ENTRY -update t1 set id=100,ggid='test2' where id=1; -select * from t1; -select * from t1 where id=1; -select * from t1 where id=999; -drop table t1; - # # ORDER BY on not primary key # @@ -2323,6 +2290,48 @@ CREATE TABLE t1 ( c29 CHAR(255), c30 CHAR(255), c31 CHAR(255), c32 CHAR(255) ) ENGINE = InnoDB; +# +# Bug #21409 Incorrect result returned when in READ-COMMITTED with +# query_cache ON +# +CONNECT (c1,localhost,root,,); +CONNECT (c2,localhost,root,,); +CONNECTION c1; +SET TX_ISOLATION='read-committed'; +SET AUTOCOMMIT=0; +DROP TABLE IF EXISTS t1, t2; +CREATE TABLE t1 ( a int ) ENGINE=InnoDB; +CREATE TABLE t2 LIKE t1; +SELECT * FROM t2; +CONNECTION c2; +SET TX_ISOLATION='read-committed'; +SET AUTOCOMMIT=0; +INSERT INTO t1 VALUES (1); +COMMIT; +CONNECTION c1; +SELECT * FROM t1 WHERE a=1; +DISCONNECT c1; +DISCONNECT c2; +CONNECT (c1,localhost,root,,); +CONNECT (c2,localhost,root,,); +CONNECTION c1; +SET TX_ISOLATION='read-committed'; +SET AUTOCOMMIT=0; +SELECT * FROM t2; +CONNECTION c2; +SET TX_ISOLATION='read-committed'; +SET AUTOCOMMIT=0; +INSERT INTO t1 VALUES (2); +COMMIT; +CONNECTION c1; +# The result set below should be the same for both selects +SELECT * FROM t1 WHERE a=2; +SELECT * FROM t1 WHERE a=2; +DROP TABLE t1; +DROP TABLE t2; +DISCONNECT c1; +DISCONNECT c2; + ####################################################################### # # # Please, DO NOT TOUCH this file as well as the innodb.result file. # diff --git a/mysql-test/t/innodb_autoinc_lock_mode_zero-master.opt b/mysql-test/t/innodb_autoinc_lock_mode_zero-master.opt new file mode 100644 index 00000000000..fad0da2ac2e --- /dev/null +++ b/mysql-test/t/innodb_autoinc_lock_mode_zero-master.opt @@ -0,0 +1 @@ +--innodb-autoinc-lock-mode=0 diff --git a/mysql-test/t/innodb_autoinc_lock_mode_zero.test b/mysql-test/t/innodb_autoinc_lock_mode_zero.test new file mode 100644 index 00000000000..96f748673c0 --- /dev/null +++ b/mysql-test/t/innodb_autoinc_lock_mode_zero.test @@ -0,0 +1,44 @@ +# This test runs with old-style locking, as: +# --innodb-autoinc-lock-mode=0 + +-- source include/have_innodb.inc + +--disable_warnings +drop table if exists t1; +--enable_warnings + + +# +# Search on unique key +# + +CREATE TABLE t1 ( + id int(11) NOT NULL auto_increment, + ggid varchar(32) binary DEFAULT '' NOT NULL, + email varchar(64) DEFAULT '' NOT NULL, + passwd varchar(32) binary DEFAULT '' NOT NULL, + PRIMARY KEY (id), + UNIQUE ggid (ggid) +) ENGINE=innodb; + +insert into t1 (ggid,passwd) values ('test1','xxx'); +insert into t1 (ggid,passwd) values ('test2','yyy'); +-- error ER_DUP_ENTRY +insert into t1 (ggid,passwd) values ('test2','this will fail'); +-- error ER_DUP_ENTRY +insert into t1 (ggid,id) values ('this will fail',1); + +select * from t1 where ggid='test1'; +select * from t1 where passwd='xxx'; +select * from t1 where id=2; + +replace into t1 (ggid,id) values ('this will work',1); +replace into t1 (ggid,passwd) values ('test2','this will work'); +-- error ER_DUP_ENTRY +update t1 set id=100,ggid='test2' where id=1; +select * from t1; +select * from t1 where id=1; +select * from t1 where id=999; +drop table t1; + +--echo End of tests diff --git a/storage/innobase/buf/buf0lru.c b/storage/innobase/buf/buf0lru.c index 7b49a7641af..f3913ed49b7 100644 --- a/storage/innobase/buf/buf0lru.c +++ b/storage/innobase/buf/buf0lru.c @@ -881,7 +881,7 @@ buf_LRU_block_free_non_file_page( UT_LIST_ADD_FIRST(free, buf_pool->free, block); block->in_free_list = TRUE; - UNIV_MEM_FREE(block->frame, UNIV_PAGE_SIZE); + UNIV_MEM_ASSERT_AND_FREE(block->frame, UNIV_PAGE_SIZE); if (srv_use_awe && block->frame) { /* Add to the list of mapped pages */ diff --git a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.c index 595dfb06ee5..368ff3c2bc2 100644 --- a/storage/innobase/dict/dict0dict.c +++ b/storage/innobase/dict/dict0dict.c @@ -441,6 +441,8 @@ dict_table_autoinc_initialize( dict_table_t* table, /* in: table */ ib_longlong value) /* in: next value to assign to a row */ { + ut_ad(mutex_own(&table->autoinc_mutex)); + table->autoinc_inited = TRUE; table->autoinc = value; } @@ -457,6 +459,8 @@ dict_table_autoinc_read( { ib_longlong value; + ut_ad(mutex_own(&table->autoinc_mutex)); + if (!table->autoinc_inited) { value = 0; diff --git a/storage/innobase/dict/dict0load.c b/storage/innobase/dict/dict0load.c index 1ff1fd54cec..f594e64f517 100644 --- a/storage/innobase/dict/dict0load.c +++ b/storage/innobase/dict/dict0load.c @@ -551,11 +551,13 @@ dict_load_fields( Loads definitions for table indexes. Adds them to the data dictionary cache. */ static -ibool +ulint dict_load_indexes( /*==============*/ - /* out: TRUE if ok, FALSE if corruption - of dictionary table */ + /* out: DB_SUCCESS if ok, DB_CORRUPTION + if corruption of dictionary table or + DB_UNSUPPORTED if table has unknown index + type */ dict_table_t* table, /* in: table */ mem_heap_t* heap) /* in: memory heap for temporary storage */ { @@ -578,6 +580,7 @@ dict_load_indexes( ibool is_sys_table; dulint id; mtr_t mtr; + ulint error = DB_SUCCESS; ut_ad(mutex_own(&(dict_sys->mutex))); @@ -624,10 +627,8 @@ dict_load_indexes( dict_load_report_deleted_index(table->name, ULINT_UNDEFINED); - btr_pcur_close(&pcur); - mtr_commit(&mtr); - - return(FALSE); + error = DB_CORRUPTION; + goto func_exit; } field = rec_get_nth_field_old(rec, 1, &len); @@ -653,7 +654,18 @@ dict_load_indexes( field = rec_get_nth_field_old(rec, 8, &len); page_no = mach_read_from_4(field); - if (page_no == FIL_NULL) { + /* We check for unsupported types first, so that the + subsequent checks are relevant for the supported types. */ + if (type & ~(DICT_CLUSTERED | DICT_UNIQUE)) { + + fprintf(stderr, + "InnoDB: Error: unknown type %lu" + " of index %s of table %s\n", + (ulong) type, name_buf, table->name); + + error = DB_UNSUPPORTED; + goto func_exit; + } else if (page_no == FIL_NULL) { fprintf(stderr, "InnoDB: Error: trying to load index %s" @@ -661,14 +673,10 @@ dict_load_indexes( "InnoDB: but the index tree has been freed!\n", name_buf, table->name); - btr_pcur_close(&pcur); - mtr_commit(&mtr); - - return(FALSE); - } - - if ((type & DICT_CLUSTERED) == 0 - && NULL == dict_table_get_first_index(table)) { + error = DB_CORRUPTION; + goto func_exit; + } else if ((type & DICT_CLUSTERED) == 0 + && NULL == dict_table_get_first_index(table)) { fprintf(stderr, "InnoDB: Error: trying to load index %s" @@ -677,18 +685,14 @@ dict_load_indexes( " is not clustered!\n", name_buf, table->name); - btr_pcur_close(&pcur); - mtr_commit(&mtr); - - return(FALSE); - } - - if (is_sys_table - && ((type & DICT_CLUSTERED) - || ((table == dict_sys->sys_tables) - && (name_len == (sizeof "ID_IND") - 1) - && (0 == ut_memcmp(name_buf, "ID_IND", - name_len))))) { + error = DB_CORRUPTION; + goto func_exit; + } else if (is_sys_table + && ((type & DICT_CLUSTERED) + || ((table == dict_sys->sys_tables) + && (name_len == (sizeof "ID_IND") - 1) + && (0 == ut_memcmp(name_buf, + "ID_IND", name_len))))) { /* The index was created in memory already at booting of the database server */ @@ -704,10 +708,11 @@ dict_load_indexes( btr_pcur_move_to_next_user_rec(&pcur, &mtr); } +func_exit: btr_pcur_close(&pcur); mtr_commit(&mtr); - return(TRUE); + return(error); } /************************************************************************ @@ -857,11 +862,20 @@ err_exit: mem_heap_empty(heap); - dict_load_indexes(table, heap); + err = dict_load_indexes(table, heap); - err = dict_load_foreigns(table->name, TRUE); + /* If the force recovery flag is set, we open the table irrespective + of the error condition, since the user may want to dump data from the + clustered index. However we load the foreign key information only if + all indexes were loaded. */ + if (err != DB_SUCCESS && !srv_force_recovery) { + dict_mem_table_free(table); + table = NULL; + } else if (err == DB_SUCCESS) { + err = dict_load_foreigns(table->name, TRUE); + } #if 0 - if (err != DB_SUCCESS) { + if (err != DB_SUCCESS && table != NULL) { mutex_enter(&dict_foreign_err_mutex); diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 783553f5d87..61f16522cff 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -129,6 +129,7 @@ static my_bool innobase_locks_unsafe_for_binlog = FALSE; static my_bool innobase_rollback_on_timeout = FALSE; static my_bool innobase_create_status_file = FALSE; static my_bool innobase_stats_on_metadata = TRUE; +static my_bool innobase_use_adaptive_hash_indexes = TRUE; static char* internal_innobase_data_file_path = NULL; @@ -1246,8 +1247,7 @@ innobase_invalidate_query_cache( } /********************************************************************* -Display an SQL identifier. -This definition must match the one in innobase/ut/ut0ut.c! */ +Display an SQL identifier. */ extern "C" void innobase_print_identifier( @@ -1635,6 +1635,9 @@ innobase_init( srv_stats_on_metadata = (ibool) innobase_stats_on_metadata; + srv_use_adaptive_hash_indexes = + (ibool) innobase_use_adaptive_hash_indexes; + srv_print_verbose_log = mysqld_embedded ? 0 : 1; /* Store the default charset-collation number of this MySQL @@ -2320,13 +2323,18 @@ ha_innobase::open( if (NULL == ib_table) { ut_print_timestamp(stderr); - sql_print_error("Cannot find table %s from the internal data " - "dictionary\nof InnoDB though the .frm file " - "for the table exists. Maybe you\nhave " - "deleted and recreated InnoDB data files but " - "have forgotten\nto delete the corresponding " - ".frm files of InnoDB tables, or you\n" - "have moved .frm files to another database?\n" + sql_print_error("Cannot find or open table %s from\n" + "the internal data dictionary of InnoDB " + "though the .frm file for the\n" + "table exists. Maybe you have deleted and " + "recreated InnoDB data\n" + "files but have forgotten to delete the " + "corresponding .frm files\n" + "of InnoDB tables, or you have moved .frm " + "files to another database?\n" + "or, the table contains indexes that this " + "version of the engine\n" + "doesn't support.\n" "See http://dev.mysql.com/doc/refman/5.1/en/innodb-troubleshooting.html\n" "how you can resolve the problem.\n", norm_name); @@ -3476,6 +3484,7 @@ no_commit: /* Handle duplicate key errors */ if (auto_inc_used) { + ulint err; ulonglong auto_inc; /* Note the number of rows processed for this statement, used @@ -3529,7 +3538,11 @@ set_max_autoinc: ut_a(prebuilt->table->autoinc_increment > 0); auto_inc += prebuilt->table->autoinc_increment; - innobase_set_max_autoinc(auto_inc); + err = innobase_set_max_autoinc(auto_inc); + + if (err != DB_SUCCESS) { + error = err; + } } break; } @@ -3765,7 +3778,7 @@ ha_innobase::update_row( if (auto_inc != 0) { auto_inc += prebuilt->table->autoinc_increment; - innobase_set_max_autoinc(auto_inc); + error = innobase_set_max_autoinc(auto_inc); } } @@ -6304,6 +6317,9 @@ ha_innobase::start_stmt( innobase_release_stat_resources(trx); + /* Reset the AUTOINC statement level counter for multi-row INSERTs. */ + trx->n_autoinc_rows = 0; + prebuilt->sql_stat_start = TRUE; prebuilt->hint_need_to_fetch_extra_cols = 0; reset_template(prebuilt); @@ -6446,9 +6462,6 @@ ha_innobase::external_lock( innobase_register_stmt(ht, thd); } - trx->n_mysql_tables_in_use++; - prebuilt->mysql_has_locked = TRUE; - if (trx->isolation_level == TRX_ISO_SERIALIZABLE && prebuilt->select_lock_type == LOCK_NONE && thd_test_options(thd, @@ -6497,6 +6510,9 @@ ha_innobase::external_lock( trx->mysql_n_tables_locked++; } + trx->n_mysql_tables_in_use++; + prebuilt->mysql_has_locked = TRUE; + DBUG_RETURN(0); } @@ -7120,8 +7136,8 @@ the value of the auto-inc counter. */ int ha_innobase::innobase_read_and_init_auto_inc( /*=========================================*/ - /* out: 0 or error code: - deadlock or lock wait timeout */ + /* out: 0 or generic MySQL + error code */ longlong* value) /* out: the autoinc value */ { longlong auto_inc; @@ -7178,9 +7194,9 @@ ha_innobase::innobase_read_and_init_auto_inc( ++auto_inc; dict_table_autoinc_initialize(innodb_table, auto_inc); } else { - fprintf(stderr, " InnoDB error: Couldn't read the " - "max AUTOINC value from index (%s).\n", - index->name); + fprintf(stderr, " InnoDB error (%lu): Couldn't read " + "the max AUTOINC value from the index (%s).\n", + error, index->name); mysql_error = 1; } @@ -7217,6 +7233,11 @@ ha_innobase::innobase_get_auto_increment( { ulong error; + *value = 0; + + /* Note: If the table is not initialized when we attempt the + read below. We initialize the table's auto-inc counter and + always do a reread of the AUTOINC value. */ do { error = innobase_autoinc_lock(); @@ -7256,7 +7277,16 @@ ha_innobase::innobase_get_auto_increment( } else { *value = (ulonglong) autoinc; } + /* A deadlock error during normal processing is OK + and can be ignored. */ + } else if (error != DB_DEADLOCK) { + + ut_print_timestamp(stderr); + sql_print_error(" InnoDB Error %lu in " + "::innobase_get_auto_increment()", + error); } + } while (*value == 0 && error == DB_SUCCESS); return(error); @@ -7272,7 +7302,7 @@ we have a table-level lock). offset, increment, nb_desired_values are ignored. void ha_innobase::get_auto_increment( -/*=================================*/ +/*============================*/ ulonglong offset, /* in: */ ulonglong increment, /* in: table autoinc increment */ ulonglong nb_desired_values, /* in: number of values reqd */ @@ -7289,13 +7319,6 @@ ha_innobase::get_auto_increment( error = innobase_get_auto_increment(&autoinc); if (error != DB_SUCCESS) { - /* This should never happen in the code > ver 5.0.6, - since we call this function only after the counter - has been initialized. */ - - ut_print_timestamp(stderr); - sql_print_error("Error %lu in ::get_auto_increment()", error); - *first_value = (~(ulonglong) 0); return; } @@ -7310,6 +7333,11 @@ ha_innobase::get_auto_increment( trx = prebuilt->trx; + /* Note: We can't rely on *first_value since some MySQL engines, + in particular the partition engine, don't initialize it to 0 when + invoking this method. So we are not sure if it's guaranteed to + be 0 or not. */ + /* Called for the first time ? */ if (trx->n_autoinc_rows == 0) { @@ -7318,16 +7346,16 @@ ha_innobase::get_auto_increment( /* It's possible for nb_desired_values to be 0: e.g., INSERT INTO T1(C) SELECT C FROM T2; */ if (nb_desired_values == 0) { - + trx->n_autoinc_rows = 1; } - + set_if_bigger(*first_value, autoinc); /* Not in the middle of a mult-row INSERT. */ } else if (prebuilt->last_value == 0) { set_if_bigger(*first_value, autoinc); } - + *nb_reserved_values = trx->n_autoinc_rows; /* With old style AUTOINC locking we only update the table's @@ -7359,7 +7387,9 @@ ha_innobase::get_auto_increment( /* See comment in handler.h */ int -ha_innobase::reset_auto_increment(ulonglong value) +ha_innobase::reset_auto_increment( +/*==============================*/ + ulonglong value) /* in: new value for table autoinc */ { DBUG_ENTER("ha_innobase::reset_auto_increment"); @@ -7923,6 +7953,11 @@ static MYSQL_SYSVAR_BOOL(stats_on_metadata, innobase_stats_on_metadata, "Enable statistics gathering for metadata commands such as SHOW TABLE STATUS (on by default)", NULL, NULL, TRUE); +static MYSQL_SYSVAR_BOOL(use_adaptive_hash_indexes, innobase_use_adaptive_hash_indexes, + PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY, + "Enable the InnoDB adaptive hash indexes (enabled by default)", + NULL, NULL, TRUE); + static MYSQL_SYSVAR_LONG(additional_mem_pool_size, innobase_additional_mem_pool_size, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, "Size of a memory pool InnoDB uses to store data dictionary information and other internal data structures.", @@ -8051,6 +8086,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { MYSQL_SYSVAR(open_files), MYSQL_SYSVAR(rollback_on_timeout), MYSQL_SYSVAR(stats_on_metadata), + MYSQL_SYSVAR(use_adaptive_hash_indexes), MYSQL_SYSVAR(status_file), MYSQL_SYSVAR(support_xa), MYSQL_SYSVAR(sync_spin_loops), diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h index fe5ebd57990..773884b6584 100644 --- a/storage/innobase/handler/ha_innodb.h +++ b/storage/innobase/handler/ha_innodb.h @@ -250,17 +250,3 @@ int thd_binlog_format(const MYSQL_THD thd); */ void thd_mark_transaction_to_rollback(MYSQL_THD thd, bool all); } - -/* - don't delete it - it may be re-enabled later - as an optimization for the most common case InnoDB+binlog -*/ -#if 0 -int innobase_report_binlog_offset_and_commit( - THD* thd, - void* trx_handle, - char* log_file_name, - my_off_t end_offset); -int innobase_commit_complete(void* trx_handle); -void innobase_store_binlog_offset_and_flush_log(char *binlog_name,longlong offset); -#endif diff --git a/storage/innobase/ibuf/ibuf0ibuf.c b/storage/innobase/ibuf/ibuf0ibuf.c index 44972356304..126fd9fdd33 100644 --- a/storage/innobase/ibuf/ibuf0ibuf.c +++ b/storage/innobase/ibuf/ibuf0ibuf.c @@ -2900,7 +2900,7 @@ dump: ut_print_timestamp(stderr); fprintf(stderr, - "InnoDB: Error: Insert buffer insert" + " InnoDB: Error: Insert buffer insert" " fails; page free %lu," " dtuple size %lu\n", (ulong) page_get_max_insert_size( @@ -2925,7 +2925,7 @@ dump: buf_frame_get_page_no(page), IBUF_BITMAP_FREE, mtr); - fprintf(stderr, "Bitmap bits %lu\n", + fprintf(stderr, "InnoDB: Bitmap bits %lu\n", (ulong) old_bits); fputs("InnoDB: Submit a detailed bug report" diff --git a/storage/innobase/include/db0err.h b/storage/innobase/include/db0err.h index 0aa1b87e470..ed7ce151718 100644 --- a/storage/innobase/include/db0err.h +++ b/storage/innobase/include/db0err.h @@ -61,12 +61,14 @@ Created 5/24/1996 Heikki Tuuri activated by the operation would lead to a duplicate key in some table */ - #define DB_TOO_MANY_CONCURRENT_TRXS 47 /* when InnoDB runs out of the preconfigured undo slots, this can only happen when there are too many concurrent transactions */ - +#define DB_UNSUPPORTED 48 /* when InnoDB sees any artefact or + a feature that it can't recoginize or + work with e.g., FT indexes created by + a later version of the engine. */ /* The following are partial failure codes */ #define DB_FAIL 1000 #define DB_OVERFLOW 1001 diff --git a/storage/innobase/include/ha_prototypes.h b/storage/innobase/include/ha_prototypes.h index 7fb50988941..ef0722321af 100644 --- a/storage/innobase/include/ha_prototypes.h +++ b/storage/innobase/include/ha_prototypes.h @@ -1,6 +1,8 @@ #ifndef HA_INNODB_PROTOTYPES_H #define HA_INNODB_PROTOTYPES_H +#ifndef UNIV_HOTBACKUP + #include "univ.i" /* ulint, uint */ #include "m_ctype.h" /* CHARSET_INFO */ @@ -22,6 +24,19 @@ innobase_convert_string( CHARSET_INFO* from_cs, uint* errors); +/********************************************************************* +Display an SQL identifier. */ + +void +innobase_print_identifier( +/*======================*/ + FILE* f, /* in: output stream */ + trx_t* trx, /* in: transaction */ + ibool table_id,/* in: TRUE=print a table name, + FALSE=print other identifier */ + const char* name, /* in: name to print */ + ulint namelen);/* in: length of name */ + /********************************************************************** Returns true if the thread is the replication thread on the slave server. Used in srv_conc_enter_innodb() to determine if the thread @@ -49,3 +64,4 @@ thd_has_edited_nontrans_tables( void* thd); /* in: thread handle (THD*) */ #endif +#endif diff --git a/storage/innobase/include/mach0data.h b/storage/innobase/include/mach0data.h index 8377114a723..37d862cc678 100644 --- a/storage/innobase/include/mach0data.h +++ b/storage/innobase/include/mach0data.h @@ -327,6 +327,17 @@ mach_write_to_2_little_endian( byte* dest, /* in: where to write */ ulint n); /* in: unsigned long int to write */ +/************************************************************* +Convert integral type from storage byte order (big endian) to +host byte order. */ +UNIV_INLINE +void +mach_read_int_type( +/*===============*/ + byte* dest, /* out: where to write */ + const byte* src, /* in: where to read from */ + ulint len, /* in: length of src */ + ibool unsigned_type); /* in: signed or unsigned flag */ #ifndef UNIV_NONINL #include "mach0data.ic" #endif diff --git a/storage/innobase/include/mach0data.ic b/storage/innobase/include/mach0data.ic index 03ece7529a8..64fb87f56ed 100644 --- a/storage/innobase/include/mach0data.ic +++ b/storage/innobase/include/mach0data.ic @@ -7,6 +7,8 @@ to the machine format. Created 11/28/1995 Heikki Tuuri ***********************************************************************/ +#include "ut0mem.h" + /*********************************************************** The following function is used to store data in one byte. */ UNIV_INLINE @@ -689,3 +691,38 @@ mach_write_to_2_little_endian( *dest = (byte)(n & 0xFFUL); } + +/************************************************************* +Convert integral type from storage byte order (big endian) to +host byte order. */ +UNIV_INLINE +void +mach_read_int_type( +/*===============*/ + byte* dest, /* out: where to write */ + const byte* src, /* in: where to read from */ + ulint len, /* in: length of src */ + ibool unsigned_type) /* in: signed or unsigned flag */ +{ +#ifdef WORDS_BIGENDIAN + memcpy(dest, src, len); + + if (!unsigned_type) { + dest[0] ^= 128; + } +#else + byte* ptr; + + /* Convert integer data from Innobase to a little-endian format, + sign bit restored to normal. */ + + for (ptr = dest + len; ptr != dest; ++src) { + --ptr; + *ptr = *src; + } + + if (!unsigned_type) { + dest[len - 1] ^= 128; + } +#endif +} diff --git a/storage/innobase/include/mem0dbg.h b/storage/innobase/include/mem0dbg.h index 36cd7a89565..2393e4edb54 100644 --- a/storage/innobase/include/mem0dbg.h +++ b/storage/innobase/include/mem0dbg.h @@ -60,6 +60,14 @@ mem_heap_validate_or_print( ulint* n_blocks); /* out: number of blocks in the heap, if a NULL pointer is passed as this argument, it is ignored */ +/****************************************************************** +Validates the contents of a memory heap. */ + +ibool +mem_heap_validate( +/*==============*/ + /* out: TRUE if ok */ + mem_heap_t* heap); /* in: memory heap */ #endif /* UNIV_MEM_DEBUG || UNIV_DEBUG */ #ifdef UNIV_DEBUG /****************************************************************** @@ -71,14 +79,6 @@ mem_heap_check( /* out: TRUE if ok */ mem_heap_t* heap); /* in: memory heap */ #endif /* UNIV_DEBUG */ -/****************************************************************** -Validates the contents of a memory heap. */ - -ibool -mem_heap_validate( -/*==============*/ - /* out: TRUE if ok */ - mem_heap_t* heap); /* in: memory heap */ #ifdef UNIV_MEM_DEBUG /********************************************************************* TRUE if no memory is currently allocated. */ diff --git a/storage/innobase/include/mem0mem.ic b/storage/innobase/include/mem0mem.ic index adae9ad8a33..6227a27f277 100644 --- a/storage/innobase/include/mem0mem.ic +++ b/storage/innobase/include/mem0mem.ic @@ -271,19 +271,16 @@ mem_heap_free_heap_top( ut_ad(mem_block_get_start(block) <= mem_block_get_free(block)); /* In the debug version erase block from top up */ - { - ulint len = (byte*)block + block->len - old_top; - mem_erase_buf(old_top, len); - UNIV_MEM_FREE(old_top, len); - } + mem_erase_buf(old_top, (byte*)block + block->len - old_top); /* Update allocated memory count */ mutex_enter(&mem_hash_mutex); mem_current_allocated_memory -= (total_size - size); mutex_exit(&mem_hash_mutex); #else /* UNIV_MEM_DEBUG */ - UNIV_MEM_FREE(old_top, (byte*)block + block->len - old_top); + UNIV_MEM_ASSERT_W(old_top, (byte*)block + block->len - old_top); #endif /* UNIV_MEM_DEBUG */ + UNIV_MEM_ALLOC(old_top, (byte*)block + block->len - old_top); /* If free == start, we may free the block if it is not the first one */ @@ -363,6 +360,7 @@ mem_heap_free_top( /* Subtract the free field of block */ mem_block_set_free(block, mem_block_get_free(block) - MEM_SPACE_NEEDED(n)); + UNIV_MEM_ASSERT_W((byte*) block + mem_block_get_free(block), n); #ifdef UNIV_MEM_DEBUG ut_ad(mem_block_get_start(block) <= mem_block_get_free(block)); @@ -378,7 +376,11 @@ mem_heap_free_top( == mem_block_get_start(block))) { mem_heap_block_free(heap, block); } else { - UNIV_MEM_FREE((byte*) block + mem_block_get_free(block), n); + /* Avoid a bogus UNIV_MEM_ASSERT_W() warning in a + subsequent invocation of mem_heap_free_top(). + Originally, this was UNIV_MEM_FREE(), to catch writes + to freed memory. */ + UNIV_MEM_ALLOC((byte*) block + mem_block_get_free(block), n); } } diff --git a/storage/innobase/include/rem0rec.ic b/storage/innobase/include/rem0rec.ic index 95aa65fabba..5a4a0a0b5df 100644 --- a/storage/innobase/include/rem0rec.ic +++ b/storage/innobase/include/rem0rec.ic @@ -801,6 +801,7 @@ rec_offs_set_n_alloc( { ut_ad(offsets); ut_ad(n_alloc > 0); + UNIV_MEM_ASSERT_AND_ALLOC(offsets, n_alloc * sizeof *offsets); offsets[0] = n_alloc; } diff --git a/storage/innobase/include/row0mysql.h b/storage/innobase/include/row0mysql.h index aabb7f5f047..fd7ec8918ee 100644 --- a/storage/innobase/include/row0mysql.h +++ b/storage/innobase/include/row0mysql.h @@ -319,9 +319,11 @@ row_mysql_unfreeze_data_dictionary( /*===============================*/ trx_t* trx); /* in: transaction */ /************************************************************************* -Does a table creation operation for MySQL. If the name of the created -table ends to characters INNODB_MONITOR, then this also starts -printing of monitor output by the master thread. */ +Drops a table for MySQL. If the name of the table ends in +one of "innodb_monitor", "innodb_lock_monitor", "innodb_tablespace_monitor", +"innodb_table_monitor", then this will also start the printing of monitor +output by the master thread. If the table name ends in "innodb_mem_validate", +InnoDB will try to invoke mem_validate(). */ int row_create_table_for_mysql( @@ -399,8 +401,9 @@ row_truncate_table_for_mysql( dict_table_t* table, /* in: table handle */ trx_t* trx); /* in: transaction handle */ /************************************************************************* -Drops a table for MySQL. If the name of the dropped table ends to -characters INNODB_MONITOR, then this also stops printing of monitor +Drops a table for MySQL. If the name of the dropped table ends in +one of "innodb_monitor", "innodb_lock_monitor", "innodb_tablespace_monitor", +"innodb_table_monitor", then this will also stop the printing of monitor output by the master thread. */ int diff --git a/storage/innobase/include/sync0rw.h b/storage/innobase/include/sync0rw.h index abf04253141..7d2f63803d0 100644 --- a/storage/innobase/include/sync0rw.h +++ b/storage/innobase/include/sync0rw.h @@ -101,6 +101,7 @@ void rw_lock_free( /*=========*/ rw_lock_t* lock); /* in: rw-lock */ +#ifdef UNIV_DEBUG /********************************************************************** Checks that the rw-lock has been initialized and that there are no simultaneous shared and exclusive locks. */ @@ -109,6 +110,7 @@ ibool rw_lock_validate( /*=============*/ rw_lock_t* lock); +#endif /* UNIV_DEBUG */ /****************************************************************** NOTE! The following macros should be used in rw s-locking, not the corresponding function. */ diff --git a/storage/innobase/include/univ.i b/storage/innobase/include/univ.i index ba8e6e56219..d845c1006ee 100644 --- a/storage/innobase/include/univ.i +++ b/storage/innobase/include/univ.i @@ -308,11 +308,39 @@ typedef void* os_thread_ret_t; # define UNIV_MEM_INVALID(addr, size) VALGRIND_MAKE_MEM_UNDEFINED(addr, size) # define UNIV_MEM_FREE(addr, size) VALGRIND_MAKE_MEM_NOACCESS(addr, size) # define UNIV_MEM_ALLOC(addr, size) VALGRIND_MAKE_MEM_UNDEFINED(addr, size) +# define UNIV_MEM_ASSERT_RW(addr, size) do { \ + const void* _p = (const void*) \ + VALGRIND_CHECK_MEM_IS_DEFINED(addr, size); \ + if (UNIV_LIKELY_NULL(_p)) \ + fprintf(stderr, "%s:%d: %p[%u] undefined at %d\n", \ + __FILE__, __LINE__, \ + (const void*) (addr), (unsigned) (size), \ + ((const char*) _p) - ((const char*) (addr))); \ + } while (0) +# define UNIV_MEM_ASSERT_W(addr, size) do { \ + const void* _p = (const void*) \ + VALGRIND_CHECK_MEM_IS_ADDRESSABLE(addr, size); \ + if (UNIV_LIKELY_NULL(_p)) \ + fprintf(stderr, "%s:%d: %p[%u] unwritable at %d\n", \ + __FILE__, __LINE__, \ + (const void*) (addr), (unsigned) (size), \ + ((const char*) _p) - ((const char*) (addr))); \ + } while (0) #else # define UNIV_MEM_VALID(addr, size) do {} while(0) # define UNIV_MEM_INVALID(addr, size) do {} while(0) # define UNIV_MEM_FREE(addr, size) do {} while(0) # define UNIV_MEM_ALLOC(addr, size) do {} while(0) +# define UNIV_MEM_ASSERT_RW(addr, size) do {} while(0) +# define UNIV_MEM_ASSERT_W(addr, size) do {} while(0) #endif +#define UNIV_MEM_ASSERT_AND_FREE(addr, size) do { \ + UNIV_MEM_ASSERT_W(addr, size); \ + UNIV_MEM_FREE(addr, size); \ +} while (0) +#define UNIV_MEM_ASSERT_AND_ALLOC(addr, size) do { \ + UNIV_MEM_ASSERT_W(addr, size); \ + UNIV_MEM_ALLOC(addr, size); \ +} while (0) #endif diff --git a/storage/innobase/include/ut0ut.h b/storage/innobase/include/ut0ut.h index 825c10d5f11..a60ce73c35a 100644 --- a/storage/innobase/include/ut0ut.h +++ b/storage/innobase/include/ut0ut.h @@ -263,6 +263,24 @@ ut_copy_file( FILE* dest, /* in: output file */ FILE* src); /* in: input file to be appended to output */ +/************************************************************************** +snprintf(). */ + +#ifdef __WIN__ +int +ut_snprintf( + /* out: number of characters that would + have been printed if the size were + unlimited, not including the terminating + '\0'. */ + char* str, /* out: string */ + size_t size, /* in: str size */ + const char* fmt, /* in: format */ + ...); /* in: format values */ +#else +#define ut_snprintf snprintf +#endif /* __WIN__ */ + #ifndef UNIV_NONINL #include "ut0ut.ic" #endif diff --git a/storage/innobase/mem/mem0dbg.c b/storage/innobase/mem/mem0dbg.c index eb77dd01f6d..72452907c3f 100644 --- a/storage/innobase/mem/mem0dbg.c +++ b/storage/innobase/mem/mem0dbg.c @@ -223,6 +223,8 @@ mem_init_buf( { byte* ptr; + UNIV_MEM_ASSERT_W(buf, n); + for (ptr = buf; ptr < buf + n; ptr++) { if (ut_rnd_gen_ibool()) { @@ -231,6 +233,8 @@ mem_init_buf( *ptr = 0xBE; } } + + UNIV_MEM_INVALID(buf, n); } /******************************************************************* @@ -245,6 +249,8 @@ mem_erase_buf( { byte* ptr; + UNIV_MEM_ASSERT_W(buf, n); + for (ptr = buf; ptr < buf + n; ptr++) { if (ut_rnd_gen_ibool()) { *ptr = 0xDE; @@ -252,6 +258,8 @@ mem_erase_buf( *ptr = 0xAD; } } + + UNIV_MEM_FREE(buf, n); } /******************************************************************* @@ -546,9 +554,7 @@ completed: } *error = FALSE; } -#endif /* UNIV_MEM_DEBUG || UNIV_DEBUG */ -#ifdef UNIV_DEBUG /****************************************************************** Prints the contents of a memory heap. */ static @@ -574,20 +580,6 @@ mem_heap_print( ut_a(!error); } -/****************************************************************** -Checks that an object is a memory heap (or a block of it). */ - -ibool -mem_heap_check( -/*===========*/ - /* out: TRUE if ok */ - mem_heap_t* heap) /* in: memory heap */ -{ - ut_a(heap->magic_n == MEM_BLOCK_MAGIC_N); - - return(TRUE); -} - /****************************************************************** Validates the contents of a memory heap. */ @@ -614,6 +606,22 @@ mem_heap_validate( return(TRUE); } +#endif /* UNIV_MEM_DEBUG || UNIV_DEBUG */ + +#ifdef UNIV_DEBUG +/****************************************************************** +Checks that an object is a memory heap (or a block of it). */ + +ibool +mem_heap_check( +/*===========*/ + /* out: TRUE if ok */ + mem_heap_t* heap) /* in: memory heap */ +{ + ut_a(heap->magic_n == MEM_BLOCK_MAGIC_N); + + return(TRUE); +} #endif /* UNIV_DEBUG */ #ifdef UNIV_MEM_DEBUG diff --git a/storage/innobase/mem/mem0mem.c b/storage/innobase/mem/mem0mem.c index d89a3a55d88..f4fd178a39c 100644 --- a/storage/innobase/mem/mem0mem.c +++ b/storage/innobase/mem/mem0mem.c @@ -512,9 +512,9 @@ mem_heap_block_free( of hex 0xDE and 0xAD. */ mem_erase_buf((byte*)block, len); - -#endif - UNIV_MEM_FREE(block, len); +#else /* UNIV_MEM_DEBUG */ + UNIV_MEM_ASSERT_AND_FREE(block, len); +#endif /* UNIV_MEM_DEBUG */ if (init_block) { /* Do not have to free: do nothing */ diff --git a/storage/innobase/row/row0mysql.c b/storage/innobase/row/row0mysql.c index b8d201e3da2..b3cf20b78b8 100644 --- a/storage/innobase/row/row0mysql.c +++ b/storage/innobase/row/row0mysql.c @@ -1728,10 +1728,11 @@ row_mysql_unlock_data_dictionary( } /************************************************************************* -Does a table creation operation for MySQL. If the name of the table -to be created is equal with one of the predefined magic table names, -then this also starts printing the corresponding monitor output by -the master thread. */ +Drops a table for MySQL. If the name of the table ends in +one of "innodb_monitor", "innodb_lock_monitor", "innodb_tablespace_monitor", +"innodb_table_monitor", then this will also start the printing of monitor +output by the master thread. If the table name ends in "innodb_mem_validate", +InnoDB will try to invoke mem_validate(). */ int row_create_table_for_mysql( @@ -1756,13 +1757,11 @@ row_create_table_for_mysql( ut_ad(trx->dict_operation_lock_mode == RW_X_LATCH); if (srv_created_new_raw) { - fputs("InnoDB: A new raw disk partition was initialized or\n" - "InnoDB: innodb_force_recovery is on: we do not allow\n" - "InnoDB: database modifications by the user. Shut down\n" - "InnoDB: mysqld and edit my.cnf so that newraw" - " is replaced\n" - "InnoDB: with raw, and innodb_force_... is removed.\n", - stderr); + fputs("InnoDB: A new raw disk partition was initialized:\n" + "InnoDB: we do not allow database modifications" + " by the user.\n" + "InnoDB: Shut down mysqld and edit my.cnf so that newraw" + " is replaced with raw.\n", stderr); dict_mem_table_free(table); trx_commit_for_mysql(trx); @@ -2703,13 +2702,11 @@ row_truncate_table_for_mysql( ut_ad(table); if (srv_created_new_raw) { - fputs("InnoDB: A new raw disk partition was initialized or\n" - "InnoDB: innodb_force_recovery is on: we do not allow\n" - "InnoDB: database modifications by the user. Shut down\n" - "InnoDB: mysqld and edit my.cnf so that newraw" - " is replaced\n" - "InnoDB: with raw, and innodb_force_... is removed.\n", - stderr); + fputs("InnoDB: A new raw disk partition was initialized:\n" + "InnoDB: we do not allow database modifications" + " by the user.\n" + "InnoDB: Shut down mysqld and edit my.cnf so that newraw" + " is replaced with raw.\n", stderr); return(DB_ERROR); } @@ -2898,7 +2895,9 @@ next_rec: /* MySQL calls ha_innobase::reset_auto_increment() which does the same thing. */ + dict_table_autoinc_lock(table); dict_table_autoinc_initialize(table, 0); + dict_table_autoinc_unlock(table); dict_update_statistics(table); trx_commit_for_mysql(trx); @@ -2916,9 +2915,10 @@ funct_exit: #endif /* !UNIV_HOTBACKUP */ /************************************************************************* -Drops a table for MySQL. If the name of the table to be dropped is equal -with one of the predefined magic table names, then this also stops printing -the corresponding monitor output by the master thread. */ +Drops a table for MySQL. If the name of the dropped table ends in +one of "innodb_monitor", "innodb_lock_monitor", "innodb_tablespace_monitor", +"innodb_table_monitor", then this will also stop the printing of monitor +output by the master thread. */ int row_drop_table_for_mysql( @@ -2934,21 +2934,17 @@ row_drop_table_for_mysql( ulint err; const char* table_name; ulint namelen; - char* dir_path_of_temp_table = NULL; - ibool success; ibool locked_dictionary = FALSE; pars_info_t* info = NULL; ut_a(name != NULL); if (srv_created_new_raw) { - fputs("InnoDB: A new raw disk partition was initialized or\n" - "InnoDB: innodb_force_recovery is on: we do not allow\n" - "InnoDB: database modifications by the user. Shut down\n" - "InnoDB: mysqld and edit my.cnf so that newraw" - " is replaced\n" - "InnoDB: with raw, and innodb_force_... is removed.\n", - stderr); + fputs("InnoDB: A new raw disk partition was initialized:\n" + "InnoDB: we do not allow database modifications" + " by the user.\n" + "InnoDB: Shut down mysqld and edit my.cnf so that newraw" + " is replaced with raw.\n", stderr); return(DB_ERROR); } @@ -3232,14 +3228,20 @@ check_next_foreign: } else { ibool is_path; const char* name_or_path; + mem_heap_t* heap; + heap = mem_heap_create(200); + + /* Clone the name, in case it has been allocated + from table->heap, which will be freed by + dict_table_remove_from_cache(table) below. */ + name = mem_heap_strdup(heap, name); space_id = table->space; if (table->dir_path_of_temp_table != NULL) { - dir_path_of_temp_table = mem_strdup( - table->dir_path_of_temp_table); is_path = TRUE; - name_or_path = dir_path_of_temp_table; + name_or_path = mem_heap_strdup( + heap, table->dir_path_of_temp_table); } else { is_path = FALSE; name_or_path = name; @@ -3272,13 +3274,7 @@ check_next_foreign: "InnoDB: of table "); ut_print_name(stderr, trx, TRUE, name); fprintf(stderr, ".\n"); - - goto funct_exit; - } - - success = fil_delete_tablespace(space_id); - - if (!success) { + } else if (!fil_delete_tablespace(space_id)) { fprintf(stderr, "InnoDB: We removed now the InnoDB" " internal data dictionary entry\n" @@ -3296,6 +3292,8 @@ check_next_foreign: err = DB_ERROR; } } + + mem_heap_free(heap); } funct_exit: @@ -3305,10 +3303,6 @@ funct_exit: row_mysql_unlock_data_dictionary(trx); } - if (dir_path_of_temp_table) { - mem_free(dir_path_of_temp_table); - } - trx->op_info = ""; #ifndef UNIV_HOTBACKUP diff --git a/storage/innobase/row/row0sel.c b/storage/innobase/row/row0sel.c index fdf6aa46351..51f76036aae 100644 --- a/storage/innobase/row/row0sel.c +++ b/storage/innobase/row/row0sel.c @@ -531,12 +531,13 @@ row_sel_build_prev_vers( /*====================*/ /* out: DB_SUCCESS or error code */ read_view_t* read_view, /* in: read view */ - plan_t* plan, /* in: plan node for table */ + dict_index_t* index, /* in: plan node for table */ rec_t* rec, /* in: record in a clustered index */ ulint** offsets, /* in/out: offsets returned by rec_get_offsets(rec, plan->index) */ mem_heap_t** offset_heap, /* in/out: memory heap from which the offsets are allocated */ + mem_heap_t** old_vers_heap, /* out: old version heap to use */ rec_t** old_vers, /* out: old version, or NULL if the record does not exist in the view: i.e., it was freshly inserted @@ -545,15 +546,15 @@ row_sel_build_prev_vers( { ulint err; - if (plan->old_vers_heap) { - mem_heap_empty(plan->old_vers_heap); + if (*old_vers_heap) { + mem_heap_empty(*old_vers_heap); } else { - plan->old_vers_heap = mem_heap_create(512); + *old_vers_heap = mem_heap_create(512); } err = row_vers_build_for_consistent_read( - rec, mtr, plan->index, offsets, read_view, offset_heap, - plan->old_vers_heap, old_vers); + rec, mtr, index, offsets, read_view, offset_heap, + *old_vers_heap, old_vers); return(err); } @@ -765,9 +766,11 @@ row_sel_get_clust_rec( if (!lock_clust_rec_cons_read_sees(clust_rec, index, offsets, node->read_view)) { - err = row_sel_build_prev_vers(node->read_view, plan, - clust_rec, &offsets, - &heap, &old_vers, mtr); + err = row_sel_build_prev_vers( + node->read_view, index, clust_rec, + &offsets, &heap, &plan->old_vers_heap, + &old_vers, mtr); + if (err != DB_SUCCESS) { goto err_exit; @@ -1490,10 +1493,11 @@ skip_lock: if (!lock_clust_rec_cons_read_sees(rec, index, offsets, node->read_view)) { - err = row_sel_build_prev_vers(node->read_view, - plan, rec, - &offsets, &heap, - &old_vers, &mtr); + err = row_sel_build_prev_vers( + node->read_view, index, rec, + &offsets, &heap, &plan->old_vers_heap, + &old_vers, &mtr); + if (err != DB_SUCCESS) { goto lock_wait_or_error; @@ -3999,6 +4003,7 @@ no_gap_lock: mutex_enter(&kernel_mutex); if (trx->was_chosen_as_deadlock_victim) { mutex_exit(&kernel_mutex); + err = DB_DEADLOCK; goto lock_wait_or_error; } @@ -4536,6 +4541,7 @@ row_search_autoinc_read_column( const byte* data; ib_longlong value; mem_heap_t* heap = NULL; + /* Our requirement is that dest should be word aligned. */ byte dest[sizeof(value)]; ulint offsets_[REC_OFFS_NORMAL_SIZE]; ulint* offsets = offsets_; @@ -4554,20 +4560,35 @@ row_search_autoinc_read_column( ut_a(len != UNIV_SQL_NULL); ut_a(len <= sizeof value); - /* Copy integer data and restore sign bit */ - if (unsigned_type || (data[0] & 128)) - memset(dest, 0x00, sizeof(dest)); - else - memset(dest, 0xff, sizeof(dest)); + mach_read_int_type(dest, data, len, unsigned_type); - memcpy(dest + (sizeof(value) - len), data, len); + /* The assumption here is that the AUTOINC value can't be negative + and that dest is word aligned. */ + switch (len) { + case 8: + value = *(ib_longlong*) dest; + break; - if (!unsigned_type) - dest[sizeof(value) - len] ^= 128; + case 4: + value = *(ib_uint32_t*) dest; + break; - /* The assumption here is that the AUTOINC value can't be negative.*/ - value = (((ib_longlong) mach_read_from_4(dest)) << 32) | - ((ib_longlong) mach_read_from_4(dest + 4)); + case 3: + value = *(ib_uint32_t*) dest; + value &= 0xFFFFFF; + break; + + case 2: + value = *(uint16 *) dest; + break; + + case 1: + value = *dest; + break; + + default: + ut_error; + } if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); diff --git a/storage/innobase/sync/sync0rw.c b/storage/innobase/sync/sync0rw.c index 4db780c8b3f..8dbc69816e9 100644 --- a/storage/innobase/sync/sync0rw.c +++ b/storage/innobase/sync/sync0rw.c @@ -174,9 +174,7 @@ rw_lock_free( /*=========*/ rw_lock_t* lock) /* in: rw-lock */ { -#ifdef UNIV_DEBUG - ut_a(rw_lock_validate(lock)); -#endif /* UNIV_DEBUG */ + ut_ad(rw_lock_validate(lock)); ut_a(rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED); ut_a(rw_lock_get_waiters(lock) == 0); ut_a(rw_lock_get_reader_count(lock) == 0); @@ -199,6 +197,7 @@ rw_lock_free( mutex_exit(&rw_lock_list_mutex); } +#ifdef UNIV_DEBUG /********************************************************************** Checks that the rw-lock has been initialized and that there are no simultaneous shared and exclusive locks. */ @@ -226,6 +225,7 @@ rw_lock_validate( return(TRUE); } +#endif /* UNIV_DEBUG */ /********************************************************************** Lock an rw-lock in shared mode for the current thread. If the rw-lock is diff --git a/storage/innobase/ut/ut0ut.c b/storage/innobase/ut/ut0ut.c index 389063ad821..1ca278cd633 100644 --- a/storage/innobase/ut/ut0ut.c +++ b/storage/innobase/ut/ut0ut.c @@ -18,6 +18,7 @@ Created 5/11/1994 Heikki Tuuri #include "ut0sort.h" #include "trx0trx.h" +#include "ha_prototypes.h" ibool ut_always_false = FALSE; @@ -70,22 +71,6 @@ ut_gettimeofday( #define ut_gettimeofday gettimeofday #endif -#ifndef UNIV_HOTBACKUP -/********************************************************************* -Display an SQL identifier. -This definition must match the one in sql/ha_innodb.cc! */ -extern -void -innobase_print_identifier( -/*======================*/ - FILE* f, /* in: output stream */ - trx_t* trx, /* in: transaction */ - ibool table_id,/* in: TRUE=print a table name, - FALSE=print other identifier */ - const char* name, /* in: name to print */ - ulint namelen);/* in: length of name */ -#endif /* !UNIV_HOTBACKUP */ - /************************************************************ Gets the high 32 bits in a ulint. That is makes a shift >> 32, but since there seem to be compiler bugs in both gcc and Visual C++, @@ -360,6 +345,8 @@ ut_print_buf( const byte* data; ulint i; + UNIV_MEM_ASSERT_RW(buf, len); + fprintf(file, " len %lu; hex ", len); for (data = (const byte*)buf, i = 0; i < len; i++) { @@ -474,17 +461,20 @@ ut_print_namel( #ifdef UNIV_HOTBACKUP fwrite(name, 1, namelen, f); #else - char* slash = memchr(name, '/', namelen); + if (table_id) { + char* slash = memchr(name, '/', namelen); + if (!slash) { + + goto no_db_name; + } - if (UNIV_LIKELY_NULL(slash)) { /* Print the database name and table name separately. */ - ut_ad(table_id); - innobase_print_identifier(f, trx, TRUE, name, slash - name); putc('.', f); innobase_print_identifier(f, trx, TRUE, slash + 1, namelen - (slash - name) - 1); } else { +no_db_name: innobase_print_identifier(f, trx, table_id, name, namelen); } #endif @@ -515,3 +505,44 @@ ut_copy_file( } } while (len > 0); } + +/************************************************************************** +snprintf(). */ + +#ifdef __WIN__ +#include +int +ut_snprintf( + /* out: number of characters that would + have been printed if the size were + unlimited, not including the terminating + '\0'. */ + char* str, /* out: string */ + size_t size, /* in: str size */ + const char* fmt, /* in: format */ + ...) /* in: format values */ +{ + int res; + va_list ap1; + va_list ap2; + + va_start(ap1, fmt); + va_start(ap2, fmt); + + res = _vscprintf(fmt, ap1); + ut_a(res != -1); + + if (size > 0) { + _vsnprintf(str, size, fmt, ap2); + + if ((size_t) res >= size) { + str[size - 1] = '\0'; + } + } + + va_end(ap1); + va_end(ap2); + + return(res); +} +#endif /* __WIN__ */ From a88d94614c565e0805ca95f5f8b651e2c6f1034a Mon Sep 17 00:00:00 2001 From: "tsmith@ramayana.hindu.god" <> Date: Tue, 6 Nov 2007 16:40:50 -0700 Subject: [PATCH 169/336] Apply snapshot innodb-5.1-ss2034 The following bugs are fixed: Bug #31860: Server crashes after inserting into InnoDB table with auto_increment column In the Bug 16979 fix there was an erroneous assertion that autoincrement columns can't contain negative values. With the fix, the autoincrement table counter is set to 0 if the maximum value read from the autoinc column index is negative. --- mysql-test/r/innodb.result | 16 +++++++++++++ mysql-test/t/innodb.test | 19 +++++++++++++++ storage/innobase/handler/ha_innodb.cc | 33 ++++++++++++--------------- storage/innobase/include/univ.i | 16 ++++++------- storage/innobase/row/row0sel.c | 7 ++++-- storage/innobase/sync/sync0sync.c | 2 +- 6 files changed, 64 insertions(+), 29 deletions(-) diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index 9f6cde0292f..051a9e1dc0b 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -3152,6 +3152,22 @@ c25 CHAR(255), c26 CHAR(255), c27 CHAR(255), c28 CHAR(255), c29 CHAR(255), c30 CHAR(255), c31 CHAR(255), c32 CHAR(255) ) ENGINE = InnoDB; ERROR 42000: Row size too large. The maximum row size for the used table type, not counting BLOBs, is 8126. You have to change some columns to TEXT or BLOBs +DROP TABLE IF EXISTS t1; +Warnings: +Note 1051 Unknown table 't1' +CREATE TABLE t1( +id BIGINT(20) NOT NULL AUTO_INCREMENT PRIMARY KEY +) ENGINE=InnoDB; +INSERT INTO t1 VALUES(-10); +SELECT * FROM t1; +id +-10 +INSERT INTO t1 VALUES(NULL); +SELECT * FROM t1; +id +-10 +1 +DROP TABLE t1; SET TX_ISOLATION='read-committed'; SET AUTOCOMMIT=0; DROP TABLE IF EXISTS t1, t2; diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index 77c450035c7..f68bb87655e 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -2290,6 +2290,25 @@ CREATE TABLE t1 ( c29 CHAR(255), c30 CHAR(255), c31 CHAR(255), c32 CHAR(255) ) ENGINE = InnoDB; +# +# Bug #31860 InnoDB assumes AUTOINC values can only be positive. +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1( + id BIGINT(20) NOT NULL AUTO_INCREMENT PRIMARY KEY + ) ENGINE=InnoDB; +INSERT INTO t1 VALUES(-10); +SELECT * FROM t1; +# +# NOTE: The server really needs to be restarted at this point +# for the test to be useful. +# +# Without the fix InnoDB would trip over an assertion here. +INSERT INTO t1 VALUES(NULL); +# The next value should be 1 and not -9 or a -ve number +SELECT * FROM t1; +DROP TABLE t1; + # # Bug #21409 Incorrect result returned when in READ-COMMITTED with # query_cache ON diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 61f16522cff..f38afbba33d 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -1144,7 +1144,6 @@ innobase_query_caching_of_table_permitted( } if (trx->has_search_latch) { - ut_print_timestamp(stderr); sql_print_error("The calling thread is holding the adaptive " "search, latch though calling " "innobase_query_caching_of_table_permitted."); @@ -2322,7 +2321,6 @@ ha_innobase::open( ib_table = dict_table_get(norm_name, TRUE); if (NULL == ib_table) { - ut_print_timestamp(stderr); sql_print_error("Cannot find or open table %s from\n" "the internal data dictionary of InnoDB " "though the .frm file for the\n" @@ -2346,7 +2344,6 @@ ha_innobase::open( } if (ib_table->ibd_file_missing && !thd_tablespace_op(thd)) { - ut_print_timestamp(stderr); sql_print_error("MySQL is trying to open a table handle but " "the .ibd file for\ntable %s does not exist.\n" "Have you deleted the .ibd file from the " @@ -3420,7 +3417,7 @@ no_commit: /* ut_print_timestamp(stderr); fprintf(stderr, - " InnoDB error: ALTER TABLE is holding lock" + " InnoDB: ALTER TABLE is holding lock" " on %lu tables!\n", prebuilt->trx->mysql_n_tables_locked); */ @@ -5723,7 +5720,6 @@ ha_innobase::info( for (i = 0; i < table->s->keys; i++) { if (index == NULL) { - ut_print_timestamp(stderr); sql_print_error("Table %s contains fewer " "indexes inside InnoDB than " "are defined in the MySQL " @@ -5739,7 +5735,6 @@ ha_innobase::info( for (j = 0; j < table->key_info[i].key_parts; j++) { if (j + 1 > index->n_uniq) { - ut_print_timestamp(stderr); sql_print_error( "Index %s of %s has %lu columns unique inside InnoDB, but MySQL is asking " "statistics for %lu columns. Have you mixed up .frm files from different " @@ -5804,7 +5799,6 @@ ha_innobase::info( ret = innobase_read_and_init_auto_inc(&auto_inc); if (ret != 0) { - ut_print_timestamp(stderr); sql_print_error("Cannot get table %s auto-inc" "counter value in ::info\n", ib_table->name); @@ -6578,14 +6572,17 @@ ha_innobase::transactional_table_lock( if (prebuilt->table->ibd_file_missing && !thd_tablespace_op(thd)) { ut_print_timestamp(stderr); - fprintf(stderr, " InnoDB error:\n" -"MySQL is trying to use a table handle but the .ibd file for\n" -"table %s does not exist.\n" -"Have you deleted the .ibd file from the database directory under\n" -"the MySQL datadir?" -"See http://dev.mysql.com/doc/refman/5.1/en/innodb-troubleshooting.html\n" -"how you can resolve the problem.\n", - prebuilt->table->name); + fprintf(stderr, + " InnoDB: MySQL is trying to use a table handle" + " but the .ibd file for\n" + "InnoDB: table %s does not exist.\n" + "InnoDB: Have you deleted the .ibd file" + " from the database directory under\n" + "InnoDB: the MySQL datadir?" + "InnoDB: See" + " http://dev.mysql.com/doc/refman/5.1/en/innodb-troubleshooting.html\n" + "InnoDB: how you can resolve the problem.\n", + prebuilt->table->name); DBUG_RETURN(HA_ERR_CRASHED); } @@ -7194,7 +7191,8 @@ ha_innobase::innobase_read_and_init_auto_inc( ++auto_inc; dict_table_autoinc_initialize(innodb_table, auto_inc); } else { - fprintf(stderr, " InnoDB error (%lu): Couldn't read " + ut_print_timestamp(stderr); + fprintf(stderr, " InnoDB: Error: (%lu) Couldn't read " "the max AUTOINC value from the index (%s).\n", error, index->name); @@ -7281,8 +7279,7 @@ ha_innobase::innobase_get_auto_increment( and can be ignored. */ } else if (error != DB_DEADLOCK) { - ut_print_timestamp(stderr); - sql_print_error(" InnoDB Error %lu in " + sql_print_error("InnoDB: Error: %lu in " "::innobase_get_auto_increment()", error); } diff --git a/storage/innobase/include/univ.i b/storage/innobase/include/univ.i index d845c1006ee..8163ae16e4e 100644 --- a/storage/innobase/include/univ.i +++ b/storage/innobase/include/univ.i @@ -309,22 +309,22 @@ typedef void* os_thread_ret_t; # define UNIV_MEM_FREE(addr, size) VALGRIND_MAKE_MEM_NOACCESS(addr, size) # define UNIV_MEM_ALLOC(addr, size) VALGRIND_MAKE_MEM_UNDEFINED(addr, size) # define UNIV_MEM_ASSERT_RW(addr, size) do { \ - const void* _p = (const void*) \ + const void* _p = (const void*) (ulint) \ VALGRIND_CHECK_MEM_IS_DEFINED(addr, size); \ if (UNIV_LIKELY_NULL(_p)) \ - fprintf(stderr, "%s:%d: %p[%u] undefined at %d\n", \ + fprintf(stderr, "%s:%d: %p[%u] undefined at %ld\n", \ __FILE__, __LINE__, \ - (const void*) (addr), (unsigned) (size), \ - ((const char*) _p) - ((const char*) (addr))); \ + (const void*) (addr), (unsigned) (size), (long) \ + (((const char*) _p) - ((const char*) (addr)))); \ } while (0) # define UNIV_MEM_ASSERT_W(addr, size) do { \ - const void* _p = (const void*) \ + const void* _p = (const void*) (ulint) \ VALGRIND_CHECK_MEM_IS_ADDRESSABLE(addr, size); \ if (UNIV_LIKELY_NULL(_p)) \ - fprintf(stderr, "%s:%d: %p[%u] unwritable at %d\n", \ + fprintf(stderr, "%s:%d: %p[%u] unwritable at %ld\n", \ __FILE__, __LINE__, \ - (const void*) (addr), (unsigned) (size), \ - ((const char*) _p) - ((const char*) (addr))); \ + (const void*) (addr), (unsigned) (size), (long) \ + (((const char*) _p) - ((const char*) (addr)))); \ } while (0) #else # define UNIV_MEM_VALID(addr, size) do {} while(0) diff --git a/storage/innobase/row/row0sel.c b/storage/innobase/row/row0sel.c index 51f76036aae..29bded114e0 100644 --- a/storage/innobase/row/row0sel.c +++ b/storage/innobase/row/row0sel.c @@ -4526,7 +4526,8 @@ row_search_check_if_query_cache_permitted( } /*********************************************************************** -Read the AUTOINC column from the current row. */ +Read the AUTOINC column from the current row. If the value is less than +0 and the type is not unsigned then we reset the value to 0. */ static ib_longlong row_search_autoinc_read_column( @@ -4594,7 +4595,9 @@ row_search_autoinc_read_column( mem_heap_free(heap); } - ut_a(value >= 0); + if (!unsigned_type && value < 0) { + value = 0; + } return(value); } diff --git a/storage/innobase/sync/sync0sync.c b/storage/innobase/sync/sync0sync.c index bf3f4d1ff20..39872f72204 100644 --- a/storage/innobase/sync/sync0sync.c +++ b/storage/innobase/sync/sync0sync.c @@ -830,7 +830,7 @@ sync_thread_levels_g( mutex = slot->latch; fprintf(stderr, - "InnoDB error: sync levels should be" + "InnoDB: sync levels should be" " > %lu but a level is %lu\n", (ulong) limit, (ulong) slot->level); From 9de5a2424fff878e6f0074bc6b214f065b4c494e Mon Sep 17 00:00:00 2001 From: "istruewing@stella.local" <> Date: Wed, 7 Nov 2007 09:30:41 +0100 Subject: [PATCH 170/336] Bug#22351 - handler::index_next_same() call to key_cmp_if_same() uses the wrong buffer handler::index_next_same() did not take into account that the internally called function key_cmp_if_same() uses the fixed buffer table->record[0] for key comparison instead of the buffer provided by the caller of handler::index_next_same(). Added code to temporarily redirect table->record[0] and the fields used for the key to the record buffer provided by the caller of handler::index_next_same(). The test case is in partition.test already. --- sql/handler.cc | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/sql/handler.cc b/sql/handler.cc index 75c3a64bc27..7891661cefc 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -2522,15 +2522,56 @@ int ha_enable_transaction(THD *thd, bool on) int handler::index_next_same(uchar *buf, const uchar *key, uint keylen) { int error; + DBUG_ENTER("index_next_same"); if (!(error=index_next(buf))) { + my_ptrdiff_t ptrdiff= buf - table->record[0]; + uchar *save_record_0; + KEY *key_info; + KEY_PART_INFO *key_part; + KEY_PART_INFO *key_part_end; + LINT_INIT(save_record_0); + LINT_INIT(key_info); + LINT_INIT(key_part); + LINT_INIT(key_part_end); + + /* + key_cmp_if_same() compares table->record[0] against 'key'. + In parts it uses table->record[0] directly, in parts it uses + field objects with their local pointers into table->record[0]. + If 'buf' is distinct from table->record[0], we need to move + all record references. This is table->record[0] itself and + the field pointers of the fields used in this key. + */ + if (ptrdiff) + { + save_record_0= table->record[0]; + table->record[0]= buf; + key_info= table->key_info + active_index; + key_part= key_info->key_part; + key_part_end= key_part + key_info->key_parts; + for (; key_part < key_part_end; key_part++) + { + DBUG_ASSERT(key_part->field); + key_part->field->move_field_offset(ptrdiff); + } + } + if (key_cmp_if_same(table, key, active_index, keylen)) { table->status=STATUS_NOT_FOUND; error=HA_ERR_END_OF_FILE; } + + /* Move back if necessary. */ + if (ptrdiff) + { + table->record[0]= save_record_0; + for (key_part= key_info->key_part; key_part < key_part_end; key_part++) + key_part->field->move_field_offset(-ptrdiff); + } } - return error; + DBUG_RETURN(error); } From 173c2bb0b9f21cefe7505b1b4e8d8c35549f6fe4 Mon Sep 17 00:00:00 2001 From: "ramil/ram@mysql.com/ramil.myoffice.izhnet.ru" <> Date: Wed, 7 Nov 2007 12:47:19 +0400 Subject: [PATCH 171/336] Fix for bug #32137: prepared statement crash with str_to_date in update clause Problem: calling non-constant argument's val_xxx() methods in the ::fix_length_and_dec() is inadmissible. Fix: call the method only for constant arguments. --- mysql-test/r/ps.result | 5 +++++ mysql-test/t/ps.test | 9 ++++++++ sql/item_timefunc.cc | 49 ++++++++++++++++++++++-------------------- 3 files changed, 40 insertions(+), 23 deletions(-) diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result index 49e4bf2f318..49643dd3f78 100644 --- a/mysql-test/r/ps.result +++ b/mysql-test/r/ps.result @@ -1109,4 +1109,9 @@ a 13 DEALLOCATE PREPARE st1; DROP TABLE t1; +create table t1 (a int, b tinyint); +prepare st1 from 'update t1 set b= (str_to_date(a, a))'; +execute st1; +deallocate prepare st1; +drop table t1; End of 4.1 tests. diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test index 5e5dcc36b19..18beb357d05 100644 --- a/mysql-test/t/ps.test +++ b/mysql-test/t/ps.test @@ -1146,4 +1146,13 @@ EXECUTE st1; DEALLOCATE PREPARE st1; DROP TABLE t1; +# +# Bug #32137: prepared statement crash with str_to_date in update clause +# +create table t1 (a int, b tinyint); +prepare st1 from 'update t1 set b= (str_to_date(a, a))'; +execute st1; +deallocate prepare st1; +drop table t1; + --echo End of 4.1 tests. diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 4bd3d68b9c1..08e0a727544 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -2958,39 +2958,42 @@ Field *Item_func_str_to_date::tmp_table_field(TABLE *t_arg) void Item_func_str_to_date::fix_length_and_dec() { - char format_buff[64]; - String format_str(format_buff, sizeof(format_buff), &my_charset_bin); - String *format; maybe_null= 1; decimals=0; cached_field_type= MYSQL_TYPE_STRING; max_length= MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; cached_timestamp_type= MYSQL_TIMESTAMP_NONE; - format= args[1]->val_str(&format_str); - if (!args[1]->null_value && (const_item= args[1]->const_item())) + if ((const_item= args[1]->const_item())) { - cached_format_type= get_date_time_result_type(format->ptr(), - format->length()); - switch (cached_format_type) { - case DATE_ONLY: - cached_timestamp_type= MYSQL_TIMESTAMP_DATE; - cached_field_type= MYSQL_TYPE_DATE; - max_length= MAX_DATE_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; - break; - case TIME_ONLY: - case TIME_MICROSECOND: - cached_timestamp_type= MYSQL_TIMESTAMP_TIME; - cached_field_type= MYSQL_TYPE_TIME; - max_length= MAX_TIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; - break; - default: - cached_timestamp_type= MYSQL_TIMESTAMP_DATETIME; - cached_field_type= MYSQL_TYPE_DATETIME; - break; + char format_buff[64]; + String format_str(format_buff, sizeof(format_buff), &my_charset_bin); + String *format= args[1]->val_str(&format_str); + if (!args[1]->null_value) + { + cached_format_type= get_date_time_result_type(format->ptr(), + format->length()); + switch (cached_format_type) { + case DATE_ONLY: + cached_timestamp_type= MYSQL_TIMESTAMP_DATE; + cached_field_type= MYSQL_TYPE_DATE; + max_length= MAX_DATE_WIDTH * MY_CHARSET_BIN_MB_MAXLEN; + break; + case TIME_ONLY: + case TIME_MICROSECOND: + cached_timestamp_type= MYSQL_TIMESTAMP_TIME; + cached_field_type= MYSQL_TYPE_TIME; + max_length= MAX_TIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN; + break; + default: + cached_timestamp_type= MYSQL_TIMESTAMP_DATETIME; + cached_field_type= MYSQL_TYPE_DATETIME; + break; + } } } } + bool Item_func_str_to_date::get_date(TIME *ltime, uint fuzzy_date) { DATE_TIME_FORMAT date_time_format; From 7bd370fe87711d97443db1757d12e175c306d58b Mon Sep 17 00:00:00 2001 From: "svoj@mysql.com/june.mysql.com" <> Date: Wed, 7 Nov 2007 12:55:28 +0400 Subject: [PATCH 172/336] BUG#31277 - myisamchk --unpack corrupts a table With certain data sets (when compressed record length gets bigger than uncompressed) myisamchk --unpack may corrupt data file. Fixed that record length was wrongly restored from compressed table. --- myisam/mi_check.c | 39 ++++++++++++++++++---------------- myisam/mi_open.c | 7 ++++-- myisam/mi_packrec.c | 1 - myisam/myisamchk.c | 7 +++--- mysql-test/mysql-test-run.pl | 15 +++++++++++++ mysql-test/r/myisampack.result | 29 +++++++++++++++++++++++++ mysql-test/t/myisampack.test | 33 ++++++++++++++++++++++++++++ 7 files changed, 107 insertions(+), 24 deletions(-) create mode 100644 mysql-test/r/myisampack.result create mode 100644 mysql-test/t/myisampack.test diff --git a/myisam/mi_check.c b/myisam/mi_check.c index ce8fb04874e..0b786ca5332 100644 --- a/myisam/mi_check.c +++ b/myisam/mi_check.c @@ -940,7 +940,7 @@ int chk_data_link(MI_CHECK *param, MI_INFO *info,int extend) ha_rows records,del_blocks; my_off_t used,empty,pos,splits,start_recpos, del_length,link_used,start_block; - byte *record,*to; + byte *record= 0, *to; char llbuff[22],llbuff2[22],llbuff3[22]; ha_checksum intern_record_checksum; ha_checksum key_checksum[MI_MAX_POSSIBLE_KEY]; @@ -957,7 +957,7 @@ int chk_data_link(MI_CHECK *param, MI_INFO *info,int extend) puts("- check record links"); } - if (!(record= (byte*) my_malloc(info->s->base.pack_reclength,MYF(0)))) + if (!mi_alloc_rec_buff(info, -1, &record)) { mi_check_print_error(param,"Not enough memory for record"); DBUG_RETURN(-1); @@ -1364,12 +1364,12 @@ int chk_data_link(MI_CHECK *param, MI_INFO *info,int extend) printf("Lost space: %12s Linkdata: %10s\n", llstr(empty,llbuff),llstr(link_used,llbuff2)); } - my_free((gptr) record,MYF(0)); + my_free(mi_get_rec_buff_ptr(info, record), MYF(0)); DBUG_RETURN (error); err: mi_check_print_error(param,"got error: %d when reading datafile at record: %s",my_errno, llstr(records,llbuff)); err2: - my_free((gptr) record,MYF(0)); + my_free(mi_get_rec_buff_ptr(info, record), MYF(0)); param->testflag|=T_RETRY_WITHOUT_QUICK; DBUG_RETURN(1); } /* chk_data_link */ @@ -1428,8 +1428,7 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info, MYF(MY_WME | MY_WAIT_IF_FULL))) goto err; info->opt_flag|=WRITE_CACHE_USED; - if (!(sort_param.record=(byte*) my_malloc((uint) share->base.pack_reclength, - MYF(0))) || + if (!mi_alloc_rec_buff(info, -1, &sort_param.record) || !mi_alloc_rec_buff(info, -1, &sort_param.rec_buff)) { mi_check_print_error(param, "Not enough memory for extra record"); @@ -1631,7 +1630,8 @@ err: } my_free(mi_get_rec_buff_ptr(info, sort_param.rec_buff), MYF(MY_ALLOW_ZERO_PTR)); - my_free(sort_param.record,MYF(MY_ALLOW_ZERO_PTR)); + my_free(mi_get_rec_buff_ptr(info, sort_param.record), + MYF(MY_ALLOW_ZERO_PTR)); my_free(sort_info.buff,MYF(MY_ALLOW_ZERO_PTR)); VOID(end_io_cache(¶m->read_cache)); info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED); @@ -2129,8 +2129,7 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info, info->opt_flag|=WRITE_CACHE_USED; info->rec_cache.file=info->dfile; /* for sort_delete_record */ - if (!(sort_param.record=(byte*) my_malloc((uint) share->base.pack_reclength, - MYF(0))) || + if (!mi_alloc_rec_buff(info, -1, &sort_param.record) || !mi_alloc_rec_buff(info, -1, &sort_param.rec_buff)) { mi_check_print_error(param, "Not enough memory for extra record"); @@ -2415,7 +2414,8 @@ err: my_free(mi_get_rec_buff_ptr(info, sort_param.rec_buff), MYF(MY_ALLOW_ZERO_PTR)); - my_free(sort_param.record,MYF(MY_ALLOW_ZERO_PTR)); + my_free(mi_get_rec_buff_ptr(info, sort_param.record), + MYF(MY_ALLOW_ZERO_PTR)); my_free((gptr) sort_info.key_block,MYF(MY_ALLOW_ZERO_PTR)); my_free((gptr) sort_info.ft_buf, MYF(MY_ALLOW_ZERO_PTR)); my_free(sort_info.buff,MYF(MY_ALLOW_ZERO_PTR)); @@ -2493,6 +2493,7 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info, SORT_INFO sort_info; ulonglong key_map=share->state.key_map; pthread_attr_t thr_attr; + ulong max_pack_reclength; DBUG_ENTER("mi_repair_parallel"); start_records=info->state->records; @@ -2649,10 +2650,13 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info, del=info->state->del; param->glob_crc=0; - + /* for compressed tables */ + max_pack_reclength= share->base.pack_reclength; + if (share->options & HA_OPTION_COMPRESS_RECORD) + set_if_bigger(max_pack_reclength, share->max_pack_length); if (!(sort_param=(MI_SORT_PARAM *) my_malloc((uint) share->base.keys * - (sizeof(MI_SORT_PARAM) + share->base.pack_reclength), + (sizeof(MI_SORT_PARAM) + max_pack_reclength), MYF(MY_ZEROFILL)))) { mi_check_print_error(param,"Not enough memory for key!"); @@ -2704,7 +2708,7 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info, sort_param[i].max_pos=sort_param[i].pos=share->pack.header_length; sort_param[i].record= (((char *)(sort_param+share->base.keys))+ - (share->base.pack_reclength * i)); + (max_pack_reclength * i)); if (!mi_alloc_rec_buff(info, -1, &sort_param[i].rec_buff)) { mi_check_print_error(param,"Not enough memory!"); @@ -4320,7 +4324,7 @@ err: void update_auto_increment_key(MI_CHECK *param, MI_INFO *info, my_bool repair_only) { - byte *record; + byte *record= 0; DBUG_ENTER("update_auto_increment_key"); if (!info->s->base.auto_key || @@ -4340,8 +4344,7 @@ void update_auto_increment_key(MI_CHECK *param, MI_INFO *info, We have to use an allocated buffer instead of info->rec_buff as _mi_put_key_in_record() may use info->rec_buff */ - if (!(record= (byte*) my_malloc((uint) info->s->base.pack_reclength, - MYF(0)))) + if (!mi_alloc_rec_buff(info, -1, &record)) { mi_check_print_error(param,"Not enough memory for extra record"); DBUG_VOID_RETURN; @@ -4353,7 +4356,7 @@ void update_auto_increment_key(MI_CHECK *param, MI_INFO *info, if (my_errno != HA_ERR_END_OF_FILE) { mi_extra(info,HA_EXTRA_NO_KEYREAD,0); - my_free((char*) record, MYF(0)); + my_free(mi_get_rec_buff_ptr(info, record), MYF(0)); mi_check_print_error(param,"%d when reading last record",my_errno); DBUG_VOID_RETURN; } @@ -4369,7 +4372,7 @@ void update_auto_increment_key(MI_CHECK *param, MI_INFO *info, set_if_bigger(info->s->state.auto_increment,auto_increment); } mi_extra(info,HA_EXTRA_NO_KEYREAD,0); - my_free((char*) record, MYF(0)); + my_free(mi_get_rec_buff_ptr(info, record), MYF(0)); update_state_info(param, info, UPDATE_AUTO_INC); DBUG_VOID_RETURN; } diff --git a/myisam/mi_open.c b/myisam/mi_open.c index b007eb63e63..7543bdf2bf1 100644 --- a/myisam/mi_open.c +++ b/myisam/mi_open.c @@ -659,8 +659,11 @@ byte *mi_alloc_rec_buff(MI_INFO *info, ulong length, byte **buf) /* to simplify initial init of info->rec_buf in mi_open and mi_extra */ if (length == (ulong) -1) { - length= max(info->s->base.pack_reclength, - info->s->base.max_key_length); + if (info->s->options & HA_OPTION_COMPRESS_RECORD) + length= max(info->s->base.pack_reclength, info->s->max_pack_length); + else + length= info->s->base.pack_reclength; + length= max(length, info->s->base.max_key_length); /* Avoid unnecessary realloc */ if (newptr && length == old_length) return newptr; diff --git a/myisam/mi_packrec.c b/myisam/mi_packrec.c index 51b0222e876..e931cc770ed 100644 --- a/myisam/mi_packrec.c +++ b/myisam/mi_packrec.c @@ -164,7 +164,6 @@ my_bool _mi_read_pack_info(MI_INFO *info, pbool fix_keys) share->pack.header_length= uint4korr(header+4); share->min_pack_length=(uint) uint4korr(header+8); share->max_pack_length=(uint) uint4korr(header+12); - set_if_bigger(share->base.pack_reclength,share->max_pack_length); elements=uint4korr(header+16); intervall_length=uint4korr(header+20); trees=uint2korr(header+24); diff --git a/myisam/myisamchk.c b/myisam/myisamchk.c index a259fbf2c19..34b89967ca7 100644 --- a/myisam/myisamchk.c +++ b/myisam/myisamchk.c @@ -1543,8 +1543,8 @@ static int mi_sort_records(MI_CHECK *param, mi_check_print_error(param,"Not enough memory for key block"); goto err; } - if (!(sort_param.record=(byte*) my_malloc((uint) share->base.pack_reclength, - MYF(0)))) + + if (!mi_alloc_rec_buff(info, -1, &sort_param.record)) { mi_check_print_error(param,"Not enough memory for record"); goto err; @@ -1639,7 +1639,8 @@ err: { my_afree((gptr) temp_buff); } - my_free(sort_param.record,MYF(MY_ALLOW_ZERO_PTR)); + my_free(mi_get_rec_buff_ptr(info, sort_param.record), + MYF(MY_ALLOW_ZERO_PTR)); info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED); VOID(end_io_cache(&info->rec_cache)); my_free(sort_info.buff,MYF(MY_ALLOW_ZERO_PTR)); diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 6df64ced2f9..d60bb4663f2 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -1880,6 +1880,21 @@ sub environment_setup () { ($lib_udf_example ? dirname($lib_udf_example) : "") . ($ENV{'LD_LIBRARY_PATH'} ? ":$ENV{'LD_LIBRARY_PATH'}" : ""); + # ---------------------------------------------------- + # Setup env so childs can execute myisampack and myisamchk + # ---------------------------------------------------- + $ENV{'MYISAMCHK'}= mtr_native_path(mtr_exe_exists( + vs_config_dirs('storage/myisam', 'myisamchk'), + vs_config_dirs('myisam', 'myisamchk'), + "$path_client_bindir/myisamchk", + "$glob_basedir/storage/myisam/myisamchk", + "$glob_basedir/myisam/myisamchk")); + $ENV{'MYISAMPACK'}= mtr_native_path(mtr_exe_exists( + vs_config_dirs('storage/myisam', 'myisampack'), + vs_config_dirs('myisam', 'myisampack'), + "$path_client_bindir/myisampack", + "$glob_basedir/storage/myisam/myisampack", + "$glob_basedir/myisam/myisampack")); # ---------------------------------------------------- # We are nice and report a bit about our settings diff --git a/mysql-test/r/myisampack.result b/mysql-test/r/myisampack.result new file mode 100644 index 00000000000..5f39d318234 --- /dev/null +++ b/mysql-test/r/myisampack.result @@ -0,0 +1,29 @@ +CREATE TABLE t1(c1 DOUBLE, c2 DOUBLE, c3 DOUBLE, c4 DOUBLE, c5 DOUBLE, +c6 DOUBLE, c7 DOUBLE, c8 DOUBLE, c9 DOUBLE, a INT PRIMARY KEY); +INSERT INTO t1 VALUES +(-3.31168791059336e-06,-3.19054655887874e-06,-1.06528081684847e-05,-1.227278240089e-06,-1.66718069164799e-06,-2.59038972510885e-06,-2.83145227805303e-06,-4.09678491270648e-07,-2.22610091291797e-06,6), +(0.0030743000272545,2.53222044316438e-05,2.78674650061845e-05,1.95914465544536e-05,1.7347572525984e-05,1.87513810069614e-05,1.69882826885005e-05,2.44449336987598e-05,1.89914629921774e-05,9), +(2.85229319423495e-05,3.05970988282259e-05,3.77161100113133e-05,2.3055238978766e-05,2.08241267364615e-05,2.28009504270553e-05,2.12070165658947e-05,2.84350091565409e-05,2.3366822910704e-05,3), +(0,0,0,0,0,0,0,0,0,12), +(3.24544577570754e-05,3.44619021870993e-05,4.37561613201124e-05,2.57556808726748e-05,2.3195354640561e-05,2.58532400758869e-05,2.34934241667179e-05,3.1621640063232e-05,2.58229982746189e-05,19), +(2.53222044316438e-05,0.00445071933455582,2.97447268116016e-05,2.12379514059868e-05,1.86777776502663e-05,2.0170058676712e-05,1.8946030385445e-05,2.66040037173511e-05,2.09161899668946e-05,20), +(3.03462382611645e-05,3.26517930083994e-05,3.5242025468662e-05,2.53219745106391e-05,2.24384532945004e-05,2.4052346047657e-05,2.23865572957053e-05,3.1634313969082e-05,2.48285463481801e-05,21), +(1.95914465544536e-05,2.12379514059868e-05,2.27808649037128e-05,0.000341724375366877,1.4512761275113e-05,1.56475828693953e-05,1.44372366441415e-05,2.07952121981765e-05,1.61488256935919e-05,28), +(1.7347572525984e-05,1.86777776502663e-05,2.04116907052727e-05,1.4512761275113e-05,0.000432162526082388,1.38116514014465e-05,1.2712914948904e-05,1.82503165178506e-05,1.43043075345922e-05,30), +(1.68339762136661e-05,1.77836497166611e-05,2.36328309295222e-05,1.30183423732016e-05,1.18674654241553e-05,1.32467273128652e-05,1.24581739117775e-05,1.55624190959406e-05,1.33010638508213e-05,31), +(1.89643062824415e-05,2.06997140070717e-05,2.29045490159364e-05,1.57918175731019e-05,1.39864987449492e-05,1.50580274578455e-05,1.45908734129609e-05,1.95329296993327e-05,1.5814709481221e-05,32), +(1.69882826885005e-05,1.8946030385445e-05,2.00820439721439e-05,1.44372366441415e-05,1.2712914948904e-05,1.35209686474184e-05,0.00261563314789896,1.78285095864627e-05,1.46699314500019e-05,34), +(2.0278186540684e-05,2.18923409729654e-05,2.39981539939738e-05,1.71774589459438e-05,1.54654355357383e-05,1.62731485707636e-05,1.49253140625051e-05,2.18229800160297e-05,1.71923561673718e-05,35), +(2.44449336987598e-05,2.66040037173511e-05,2.84860148925308e-05,2.07952121981765e-05,1.82503165178506e-05,1.97667730441441e-05,1.78285095864627e-05,0.00166478601822712,2.0299952103232e-05,36), +(1.89914629921774e-05,2.09161899668946e-05,2.26026841007872e-05,1.61488256935919e-05,1.43043075345922e-05,1.52609063290127e-05,1.46699314500019e-05,2.0299952103232e-05,0.00306670170971682,39), +(0,0,0,0,0,0,0,0,0,41), +(0,0,0,0,0,0,0,0,0,17), +(0,0,0,0,0,0,0,0,0,18), +(2.51880677333017e-05,2.63051795435778e-05,2.79874748974906e-05,2.02888886670845e-05,1.8178636318197e-05,1.91308527003585e-05,1.83260023644133e-05,2.4422300558171e-05,1.96411467520551e-05,44), +(2.22402118719591e-05,2.37546284320705e-05,2.58463051055541e-05,1.83391609130854e-05,1.6300720519646e-05,1.74559091886791e-05,1.63733785575587e-05,2.26616253279828e-05,1.79541237435621e-05,45), +(3.01092775359837e-05,3.23865212934412e-05,4.09444584045994e-05,0,2.15470966302776e-05,2.39082636344032e-05,2.28296706429177e-05,2.9007671511595e-05,2.44201138973326e-05,46); +FLUSH TABLES; +CHECK TABLE t1 EXTENDED; +Table Op Msg_type Msg_text +test.t1 check status OK +DROP TABLE t1; diff --git a/mysql-test/t/myisampack.test b/mysql-test/t/myisampack.test new file mode 100644 index 00000000000..6598af6318a --- /dev/null +++ b/mysql-test/t/myisampack.test @@ -0,0 +1,33 @@ +# +# BUG#31277 - myisamchk --unpack corrupts a table +# +CREATE TABLE t1(c1 DOUBLE, c2 DOUBLE, c3 DOUBLE, c4 DOUBLE, c5 DOUBLE, + c6 DOUBLE, c7 DOUBLE, c8 DOUBLE, c9 DOUBLE, a INT PRIMARY KEY); +INSERT INTO t1 VALUES +(-3.31168791059336e-06,-3.19054655887874e-06,-1.06528081684847e-05,-1.227278240089e-06,-1.66718069164799e-06,-2.59038972510885e-06,-2.83145227805303e-06,-4.09678491270648e-07,-2.22610091291797e-06,6), +(0.0030743000272545,2.53222044316438e-05,2.78674650061845e-05,1.95914465544536e-05,1.7347572525984e-05,1.87513810069614e-05,1.69882826885005e-05,2.44449336987598e-05,1.89914629921774e-05,9), +(2.85229319423495e-05,3.05970988282259e-05,3.77161100113133e-05,2.3055238978766e-05,2.08241267364615e-05,2.28009504270553e-05,2.12070165658947e-05,2.84350091565409e-05,2.3366822910704e-05,3), +(0,0,0,0,0,0,0,0,0,12), +(3.24544577570754e-05,3.44619021870993e-05,4.37561613201124e-05,2.57556808726748e-05,2.3195354640561e-05,2.58532400758869e-05,2.34934241667179e-05,3.1621640063232e-05,2.58229982746189e-05,19), +(2.53222044316438e-05,0.00445071933455582,2.97447268116016e-05,2.12379514059868e-05,1.86777776502663e-05,2.0170058676712e-05,1.8946030385445e-05,2.66040037173511e-05,2.09161899668946e-05,20), +(3.03462382611645e-05,3.26517930083994e-05,3.5242025468662e-05,2.53219745106391e-05,2.24384532945004e-05,2.4052346047657e-05,2.23865572957053e-05,3.1634313969082e-05,2.48285463481801e-05,21), +(1.95914465544536e-05,2.12379514059868e-05,2.27808649037128e-05,0.000341724375366877,1.4512761275113e-05,1.56475828693953e-05,1.44372366441415e-05,2.07952121981765e-05,1.61488256935919e-05,28), +(1.7347572525984e-05,1.86777776502663e-05,2.04116907052727e-05,1.4512761275113e-05,0.000432162526082388,1.38116514014465e-05,1.2712914948904e-05,1.82503165178506e-05,1.43043075345922e-05,30), +(1.68339762136661e-05,1.77836497166611e-05,2.36328309295222e-05,1.30183423732016e-05,1.18674654241553e-05,1.32467273128652e-05,1.24581739117775e-05,1.55624190959406e-05,1.33010638508213e-05,31), +(1.89643062824415e-05,2.06997140070717e-05,2.29045490159364e-05,1.57918175731019e-05,1.39864987449492e-05,1.50580274578455e-05,1.45908734129609e-05,1.95329296993327e-05,1.5814709481221e-05,32), +(1.69882826885005e-05,1.8946030385445e-05,2.00820439721439e-05,1.44372366441415e-05,1.2712914948904e-05,1.35209686474184e-05,0.00261563314789896,1.78285095864627e-05,1.46699314500019e-05,34), +(2.0278186540684e-05,2.18923409729654e-05,2.39981539939738e-05,1.71774589459438e-05,1.54654355357383e-05,1.62731485707636e-05,1.49253140625051e-05,2.18229800160297e-05,1.71923561673718e-05,35), +(2.44449336987598e-05,2.66040037173511e-05,2.84860148925308e-05,2.07952121981765e-05,1.82503165178506e-05,1.97667730441441e-05,1.78285095864627e-05,0.00166478601822712,2.0299952103232e-05,36), +(1.89914629921774e-05,2.09161899668946e-05,2.26026841007872e-05,1.61488256935919e-05,1.43043075345922e-05,1.52609063290127e-05,1.46699314500019e-05,2.0299952103232e-05,0.00306670170971682,39), +(0,0,0,0,0,0,0,0,0,41), +(0,0,0,0,0,0,0,0,0,17), +(0,0,0,0,0,0,0,0,0,18), +(2.51880677333017e-05,2.63051795435778e-05,2.79874748974906e-05,2.02888886670845e-05,1.8178636318197e-05,1.91308527003585e-05,1.83260023644133e-05,2.4422300558171e-05,1.96411467520551e-05,44), +(2.22402118719591e-05,2.37546284320705e-05,2.58463051055541e-05,1.83391609130854e-05,1.6300720519646e-05,1.74559091886791e-05,1.63733785575587e-05,2.26616253279828e-05,1.79541237435621e-05,45), +(3.01092775359837e-05,3.23865212934412e-05,4.09444584045994e-05,0,2.15470966302776e-05,2.39082636344032e-05,2.28296706429177e-05,2.9007671511595e-05,2.44201138973326e-05,46); +FLUSH TABLES; +--exec $MYISAMPACK -s $MYSQLTEST_VARDIR/master-data/test/t1 +--exec $MYISAMCHK -srq $MYSQLTEST_VARDIR/master-data/test/t1 +--exec $MYISAMCHK -s --unpack $MYSQLTEST_VARDIR/master-data/test/t1 +CHECK TABLE t1 EXTENDED; +DROP TABLE t1; From 4aa04022245ca0ec4186683ea2c8ef7399db7055 Mon Sep 17 00:00:00 2001 From: "kaa@polly.(none)" <> Date: Wed, 7 Nov 2007 14:00:45 +0300 Subject: [PATCH 173/336] Fix for bug #30666: Incorrect order when using range conditions on 2 tables or more The problem was that the optimizer used the join buffer in cases when the result set is ordered by filesort. This resulted in the ORDER BY clause being ignored, and the records being returned in the order determined by the order of matching records in the last table in join. Fixed by relaxing the condition in make_join_readinfo() to take filesort-ordered result sets into account, not only index-ordered ones. --- mysql-test/r/select.result | 39 ++++++++++++++++++++++++++++++++++++++ mysql-test/t/select.test | 36 +++++++++++++++++++++++++++++++++++ sql/sql_select.cc | 7 +++---- 3 files changed, 78 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index ed120a1bbb8..649fe262679 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -4096,4 +4096,43 @@ SELECT `x` FROM v3; x 1 DROP VIEW v1, v2, v3; +CREATE TABLE t1 (c11 INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY); +CREATE TABLE t2 (c21 INT UNSIGNED NOT NULL, +c22 INT DEFAULT NULL, +KEY(c21, c22)); +CREATE TABLE t3 (c31 INT UNSIGNED NOT NULL DEFAULT 0, +c32 INT DEFAULT NULL, +c33 INT NOT NULL, +c34 INT UNSIGNED DEFAULT 0, +KEY (c33, c34, c32)); +INSERT INTO t1 values (),(),(),(),(); +INSERT INTO t2 SELECT a.c11, b.c11 FROM t1 a, t1 b; +INSERT INTO t3 VALUES (1, 1, 1, 0), +(2, 2, 0, 0), +(3, 3, 1, 0), +(4, 4, 0, 0), +(5, 5, 1, 0); +SELECT c32 FROM t1, t2, t3 WHERE t1.c11 IN (1, 3, 5) AND +t3.c31 = t1.c11 AND t2.c21 = t1.c11 AND +t3.c33 = 1 AND t2.c22 in (1, 3) +ORDER BY c32; +c32 +1 +1 +3 +3 +5 +5 +SELECT c32 FROM t1, t2, t3 WHERE t1.c11 IN (1, 3, 5) AND +t3.c31 = t1.c11 AND t2.c21 = t1.c11 AND +t3.c33 = 1 AND t2.c22 in (1, 3) +ORDER BY c32 DESC; +c32 +5 +5 +3 +3 +1 +1 +DROP TABLE t1, t2, t3; End of 5.0 tests diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index 5c30a17e08e..7fe866e6495 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -3484,4 +3484,40 @@ DROP VIEW v1, v2, v3; --enable_ps_protocol +# +# Bug #30666: Incorrect order when using range conditions on 2 tables or more +# + +CREATE TABLE t1 (c11 INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY); +CREATE TABLE t2 (c21 INT UNSIGNED NOT NULL, + c22 INT DEFAULT NULL, + KEY(c21, c22)); +CREATE TABLE t3 (c31 INT UNSIGNED NOT NULL DEFAULT 0, + c32 INT DEFAULT NULL, + c33 INT NOT NULL, + c34 INT UNSIGNED DEFAULT 0, + KEY (c33, c34, c32)); + +INSERT INTO t1 values (),(),(),(),(); +INSERT INTO t2 SELECT a.c11, b.c11 FROM t1 a, t1 b; +INSERT INTO t3 VALUES (1, 1, 1, 0), + (2, 2, 0, 0), + (3, 3, 1, 0), + (4, 4, 0, 0), + (5, 5, 1, 0); + +# Show that ORDER BY produces the correct results order +SELECT c32 FROM t1, t2, t3 WHERE t1.c11 IN (1, 3, 5) AND + t3.c31 = t1.c11 AND t2.c21 = t1.c11 AND + t3.c33 = 1 AND t2.c22 in (1, 3) + ORDER BY c32; + +# Show that ORDER BY DESC produces the correct results order +SELECT c32 FROM t1, t2, t3 WHERE t1.c11 IN (1, 3, 5) AND + t3.c31 = t1.c11 AND t2.c21 = t1.c11 AND + t3.c33 = 1 AND t2.c22 in (1, 3) + ORDER BY c32 DESC; + +DROP TABLE t1, t2, t3; + --echo End of 5.0 tests diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 3529de1c28a..24d1639edf1 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -6071,10 +6071,9 @@ make_join_readinfo(JOIN *join, ulonglong options) ordered. If there is a temp table the ordering is done as a last operation and doesn't prevent join cache usage. */ - if (!ordered_set && !join->need_tmp && - ((table == join->sort_by_table && - (!join->order || join->skip_sort_order)) || - (join->sort_by_table == (TABLE *) 1 && i != join->const_tables))) + if (!ordered_set && !join->need_tmp && + (table == join->sort_by_table || + (join->sort_by_table == (TABLE *) 1 && i != join->const_tables))) ordered_set= 1; switch (tab->type) { From 3ebb915d718c0e8432aea529578e846bf2dd9ceb Mon Sep 17 00:00:00 2001 From: "kaa@polly.(none)" <> Date: Wed, 7 Nov 2007 15:08:50 +0300 Subject: [PATCH 174/336] Fix for bug #25421: MySQL threads don't respond to the kill command Calculating the estimated number of records for a range scan may take a significant time, and it was impossible for a user to interrupt that process by killing the connection or the query. Fixed by checking the thread's 'killed' status in check_quick_keys() and interrupting the calculation process if it is set to a non-zero value. --- sql/opt_range.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 99c28be36b0..c1c2ea17715 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -7352,6 +7352,9 @@ check_quick_keys(PARAM *param, uint idx, SEL_ARG *key_tree, tmp_max_flag= max_key_flag | key_tree->max_flag; } + if (unlikely(param->thd->killed != 0)) + return HA_POS_ERROR; + keynr=param->real_keynr[idx]; param->range_count++; if (!tmp_min_flag && ! tmp_max_flag && From 484de4fc6d11f41f2b7494ab86529a8c85a896e6 Mon Sep 17 00:00:00 2001 From: "mats@kindahl-laptop.dnsalias.net" <> Date: Wed, 7 Nov 2007 15:23:57 +0100 Subject: [PATCH 175/336] Adding return value, which is not used, and wrapped debug function in DBUG_OFF #ifdefs to eliminate two warnings in replication tree. --- sql/log_event.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sql/log_event.cc b/sql/log_event.cc index 77cf719fde5..7c0de27cd87 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -36,7 +36,7 @@ #define FLAGSTR(V,F) ((V)&(F)?#F" ":"") -#ifndef MYSQL_CLIENT +#if !defined(MYSQL_CLIENT) && !defined(DBUG_OFF) static const char *HA_ERR(int i) { switch (i) { @@ -90,6 +90,7 @@ static const char *HA_ERR(int i) case HA_ERR_LOGGING_IMPOSSIBLE: return "HA_ERR_LOGGING_IMPOSSIBLE"; case HA_ERR_CORRUPT_EVENT: return "HA_ERR_CORRUPT_EVENT"; } + return ""; } #endif From f1a3c36403fb0a566a6d9da1c6b9fb74e4c8681a Mon Sep 17 00:00:00 2001 From: "kaa@polly.(none)" <> Date: Wed, 7 Nov 2007 18:45:04 +0300 Subject: [PATCH 176/336] Fix for bug #32103: optimizer crash when join on int and mediumint with variable in where clause. Problem: the new_item() method of Item_uint used an incorrect constructor. "new Item_uint(name, max_length)" calls Item_uint::Item_uint(const char *str_arg, uint length) which assumes the first argument to be the string representation of the value, not the item's name. This could result in either a server crash or incorrect results depending on usage scenarios. Fixed by using the correct constructor in new_item(): Item_uint::Item_uint(const char *str_arg, longlong i, uint length). --- mysql-test/r/select.result | 8 ++++++++ mysql-test/t/select.test | 21 +++++++++++++++++++++ sql/item.h | 2 +- 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index 6dc971a953c..53ab13fe084 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -2835,4 +2835,12 @@ FFFFFFFFFFFFFFFF 7FFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF 7FFFFFFFFFFFFFFF 8FFFFFFFFFFFFFFF 7FFFFFFFFFFFFFFF drop table t1; +CREATE TABLE t1 (c0 int); +CREATE TABLE t2 (c0 int); +INSERT INTO t1 VALUES(@@connect_timeout); +INSERT INTO t2 VALUES(@@connect_timeout); +SELECT * FROM t1 JOIN t2 ON t1.c0 = t2.c0 WHERE (t1.c0 <=> @@connect_timeout); +c0 c0 +X X +DROP TABLE t1, t2; End of 4.1 tests diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index 0dc179e9b4b..b41deed65d2 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -2353,4 +2353,25 @@ insert into t1 values (0xfffffffffffffffff, 0xfffffffffffffffff), select hex(a), hex(b) from t1; drop table t1; +# +# Bug #32103: optimizer crash when join on int and mediumint with variable in +# where clause +# + +CREATE TABLE t1 (c0 int); +CREATE TABLE t2 (c0 int); + +# We need any variable that: +# 1. has integer type, +# 2. can be used with the "@@name" syntax +# 3. available in every server build +INSERT INTO t1 VALUES(@@connect_timeout); +INSERT INTO t2 VALUES(@@connect_timeout); + +# We only need to ensure 1 row is returned to validate the results +--replace_column 1 X 2 X +SELECT * FROM t1 JOIN t2 ON t1.c0 = t2.c0 WHERE (t1.c0 <=> @@connect_timeout); + +DROP TABLE t1, t2; + --echo End of 4.1 tests diff --git a/sql/item.h b/sql/item.h index f2136c4997a..7a073b7165c 100644 --- a/sql/item.h +++ b/sql/item.h @@ -690,7 +690,7 @@ public: double val() { DBUG_ASSERT(fixed == 1); return ulonglong2double((ulonglong)value); } String *val_str(String*); - Item *new_item() { return new Item_uint(name,max_length); } + Item *new_item() { return new Item_uint(name, value, max_length); } int save_in_field(Field *field, bool no_conversions); void print(String *str); Item_num *neg (); From dc8d3d0becd35419a9581f3e0195f19052e13546 Mon Sep 17 00:00:00 2001 From: "ramil/ram@mysql.com/ramil.myoffice.izhnet.ru" <> Date: Wed, 7 Nov 2007 19:59:58 +0400 Subject: [PATCH 177/336] Fix for bug #26447: "ALTER TABLE .. ORDER" does not work with InnoDB and auto_increment keys Problems: 1. ALTER TABLE ... ORDER BY... doesn't make sence if there's a user-defined clustered index in the table. 2. using a secondary index is slower than using a clustered one for a table scan. Fixes: 1. raise a warning. 2. use the clustered index. --- mysql-test/include/mix1.inc | 8 +++++ mysql-test/r/innodb.result | 30 +++++++++--------- mysql-test/r/innodb_mysql.result | 21 ++++++++----- mysql-test/r/join_outer_innodb.result | 4 +-- sql/sql_select.cc | 10 +++++- sql/sql_table.cc | 44 +++++++++++++++++---------- 6 files changed, 75 insertions(+), 42 deletions(-) diff --git a/mysql-test/include/mix1.inc b/mysql-test/include/mix1.inc index 4d910e86e0f..2887a1ac40a 100644 --- a/mysql-test/include/mix1.inc +++ b/mysql-test/include/mix1.inc @@ -1189,4 +1189,12 @@ if ($test_foreign_keys) DROP TABLE t1; } +# +# Bug #26447: "ALTER TABLE .. ORDER" does not work with InnoDB and +# auto_increment keys +# +create table t1 (a int auto_increment primary key) engine=innodb; +alter table t1 order by a; +drop table t1; + --echo End of 5.1 tests diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index d0b67e90afb..086bd714078 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -962,7 +962,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 index NULL b 4 NULL # Using index explain select a,b from t1; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL b 4 NULL # Using index +1 SIMPLE t1 index NULL PRIMARY 4 NULL # explain select a,b,c from t1; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL # @@ -1177,14 +1177,14 @@ UPDATE t1 set a=a+100 where b between 2 and 3 and a < 1000; SELECT * from t1; a b 1 1 -102 2 -103 3 4 4 5 5 6 6 7 7 8 8 9 9 +102 2 +103 3 drop table t1; CREATE TABLE t1 (a int not null primary key, b int not null, key (b)) engine=innodb; CREATE TABLE t2 (a int not null primary key, b int not null, key (b)) engine=innodb; @@ -1208,7 +1208,6 @@ a b update t1,t2 set t1.a=t1.a+100 where t1.a=101; select * from t1; a b -201 1 102 2 103 3 104 4 @@ -1220,10 +1219,11 @@ a b 110 10 111 11 112 12 +201 1 update t1,t2 set t1.b=t1.b+10 where t1.b=2; select * from t1; a b -201 1 +102 12 103 3 104 4 105 5 @@ -1233,34 +1233,34 @@ a b 109 9 110 10 111 11 -102 12 112 12 +201 1 update t1,t2 set t1.b=t1.b+2,t2.b=t1.b+10 where t1.b between 3 and 5 and t1.a=t2.a+100; select * from t1; a b -201 1 +102 12 103 5 104 6 -106 6 105 7 +106 6 107 7 108 8 109 9 110 10 111 11 -102 12 112 12 +201 1 select * from t2; a b 1 1 2 2 +3 13 +4 14 +5 15 6 6 7 7 8 8 9 9 -3 13 -4 14 -5 15 drop table t1,t2; CREATE TABLE t2 ( NEXT_T BIGINT NOT NULL PRIMARY KEY) ENGINE=MyISAM; CREATE TABLE t1 ( B_ID INTEGER NOT NULL PRIMARY KEY) ENGINE=InnoDB; @@ -1311,11 +1311,11 @@ insert into t1 (id) values (null),(null),(null),(null),(null); update t1 set fk=69 where fk is null order by id limit 1; SELECT * from t1; id fk +1 69 2 NULL 3 NULL 4 NULL 5 NULL -1 69 drop table t1; create table t1 (a int not null, b int not null, key (a)); insert into t1 values (1,1),(1,2),(1,3),(3,1),(3,2),(3,3),(3,1),(3,2),(3,3),(2,1),(2,2),(2,3); @@ -2444,8 +2444,8 @@ insert into t1 (b) values (1); replace into t1 (b) values (2), (1), (3); select * from t1; a b -3 1 2 2 +3 1 4 3 truncate table t1; insert into t1 (b) values (1); @@ -2454,8 +2454,8 @@ replace into t1 (b) values (1); replace into t1 (b) values (3); select * from t1; a b -3 1 2 2 +3 1 4 3 drop table t1; create table t1 (rowid int not null auto_increment, val int not null,primary diff --git a/mysql-test/r/innodb_mysql.result b/mysql-test/r/innodb_mysql.result index 8f46df311ad..775151db9f0 100644 --- a/mysql-test/r/innodb_mysql.result +++ b/mysql-test/r/innodb_mysql.result @@ -352,13 +352,13 @@ EXPLAIN SELECT COUNT(*) FROM t2 LEFT JOIN t1 ON t2.fkey = t1.id WHERE t1.name LIKE 'A%'; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index PRIMARY,name name 23 NULL 3 Using where; Using index +1 SIMPLE t1 index PRIMARY,name PRIMARY 4 NULL 3 Using where 1 SIMPLE t2 ref fkey fkey 5 test.t1.id 1 Using where; Using index EXPLAIN SELECT COUNT(*) FROM t2 LEFT JOIN t1 ON t2.fkey = t1.id WHERE t1.name LIKE 'A%' OR FALSE; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 index NULL fkey 5 NULL 5 Using index +1 SIMPLE t2 index NULL PRIMARY 4 NULL 5 1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.fkey 1 Using where DROP TABLE t1,t2; CREATE TABLE t1 ( @@ -1260,11 +1260,11 @@ select_type SIMPLE table t1 type index possible_keys NULL -key b -key_len 5 +key PRIMARY +key_len 4 ref NULL rows 3 -Extra Using index; Using filesort +Extra Using filesort SELECT * FROM t1 ORDER BY b ASC, a DESC; a b 1 1 @@ -1276,11 +1276,11 @@ select_type SIMPLE table t1 type index possible_keys NULL -key b -key_len 5 +key PRIMARY +key_len 4 ref NULL rows 3 -Extra Using index; Using filesort +Extra Using filesort SELECT * FROM t1 ORDER BY b DESC, a ASC; a b 2 2 @@ -1470,4 +1470,9 @@ t2 CREATE TABLE `t2` ( ) ENGINE=InnoDB DEFAULT CHARSET=latin1 DROP TABLE t2; DROP TABLE t1; +create table t1 (a int auto_increment primary key) engine=innodb; +alter table t1 order by a; +Warnings: +Warning 1105 ORDER BY ignored as there is a user-defined clustered index in the table 't1' +drop table t1; End of 5.1 tests diff --git a/mysql-test/r/join_outer_innodb.result b/mysql-test/r/join_outer_innodb.result index e8a2d6f668b..24a11b12b03 100644 --- a/mysql-test/r/join_outer_innodb.result +++ b/mysql-test/r/join_outer_innodb.result @@ -8,12 +8,12 @@ EXPLAIN SELECT COUNT(*) FROM t2 LEFT JOIN t1 ON t2.fkey = t1.id WHERE t1.name LIKE 'A%'; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index PRIMARY,name name 23 NULL 3 Using where; Using index +1 SIMPLE t1 index PRIMARY,name PRIMARY 4 NULL 3 Using where 1 SIMPLE t2 ref fkey fkey 5 test.t1.id 1 Using where; Using index EXPLAIN SELECT COUNT(*) FROM t2 LEFT JOIN t1 ON t2.fkey = t1.id WHERE t1.name LIKE 'A%' OR FALSE; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 index NULL fkey 5 NULL 5 Using index +1 SIMPLE t2 index NULL PRIMARY 4 NULL 5 1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.fkey 1 Using where DROP TABLE t1,t2; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 1c8ff12eb92..2e28663e383 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -6436,7 +6436,15 @@ make_join_readinfo(JOIN *join, ulonglong options) else if (!table->covering_keys.is_clear_all() && !(tab->select && tab->select->quick)) { // Only read index tree - tab->index=find_shortest_key(table, & table->covering_keys); + /* + See bug #26447: "Using the clustered index for a table scan + is always faster than using a secondary index". + */ + if (table->s->primary_key != MAX_KEY && + table->file->primary_key_is_clustered()) + tab->index= table->s->primary_key; + else + tab->index=find_shortest_key(table, & table->covering_keys); tab->read_first_record= join_read_first; tab->type=JT_NEXT; // Read with index_first / index_next } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index e6d84d0ef45..d63a6d7d3fc 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -6813,23 +6813,35 @@ copy_data_between_tables(TABLE *from,TABLE *to, if (order) { - from->sort.io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE), - MYF(MY_FAE | MY_ZEROFILL)); - bzero((char*) &tables,sizeof(tables)); - tables.table= from; - tables.alias= tables.table_name= from->s->table_name.str; - tables.db= from->s->db.str; - error=1; + if (to->s->primary_key != MAX_KEY && to->file->primary_key_is_clustered()) + { + char warn_buff[MYSQL_ERRMSG_SIZE]; + my_snprintf(warn_buff, sizeof(warn_buff), + "ORDER BY ignored as there is a user-defined clustered index" + " in the table '%-.192s'", from->s->table_name.str); + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR, + warn_buff); + } + else + { + from->sort.io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE), + MYF(MY_FAE | MY_ZEROFILL)); + bzero((char *) &tables, sizeof(tables)); + tables.table= from; + tables.alias= tables.table_name= from->s->table_name.str; + tables.db= from->s->db.str; + error= 1; - if (thd->lex->select_lex.setup_ref_array(thd, order_num) || - setup_order(thd, thd->lex->select_lex.ref_pointer_array, - &tables, fields, all_fields, order) || - !(sortorder=make_unireg_sortorder(order, &length, NULL)) || - (from->sort.found_records = filesort(thd, from, sortorder, length, - (SQL_SELECT *) 0, HA_POS_ERROR, 1, - &examined_rows)) == - HA_POS_ERROR) - goto err; + if (thd->lex->select_lex.setup_ref_array(thd, order_num) || + setup_order(thd, thd->lex->select_lex.ref_pointer_array, + &tables, fields, all_fields, order) || + !(sortorder= make_unireg_sortorder(order, &length, NULL)) || + (from->sort.found_records= filesort(thd, from, sortorder, length, + (SQL_SELECT *) 0, HA_POS_ERROR, + 1, &examined_rows)) == + HA_POS_ERROR) + goto err; + } }; /* Tell handler that we have values for all columns in the to table */ From 21f5bd1074e77492c348db3879856820933c404e Mon Sep 17 00:00:00 2001 From: "mats@kindahl-laptop.dnsalias.net" <> Date: Wed, 7 Nov 2007 18:12:21 +0100 Subject: [PATCH 178/336] Second attempt at getting rid of warnings in replication tree. --- sql/log_event.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/log_event.cc b/sql/log_event.cc index 7c0de27cd87..508d8377ae1 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -36,7 +36,7 @@ #define FLAGSTR(V,F) ((V)&(F)?#F" ":"") -#if !defined(MYSQL_CLIENT) && !defined(DBUG_OFF) +#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) && !defined(DBUG_OFF) && !defined(_lint) static const char *HA_ERR(int i) { switch (i) { From b0d01ab27d686b1fb545e9dc961ec7b4778ce226 Mon Sep 17 00:00:00 2001 From: "tsmith@ramayana.hindu.god" <> Date: Wed, 7 Nov 2007 12:59:22 -0700 Subject: [PATCH 179/336] Cast away compiler warning on Windows. --- storage/innobase/handler/ha_innodb.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index f38afbba33d..f075fe6c3b4 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -3538,7 +3538,7 @@ set_max_autoinc: err = innobase_set_max_autoinc(auto_inc); if (err != DB_SUCCESS) { - error = err; + error = (int) err; } } break; From ef59ca3d78b80285c11e59b20451c88496abe513 Mon Sep 17 00:00:00 2001 From: "tsmith@ramayana.hindu.god" <> Date: Wed, 7 Nov 2007 15:23:50 -0700 Subject: [PATCH 180/336] Bug #20748: Configuration files should not be read more than once A user could not override system-wide settings in their ~/.my.cnf, because the DEFAULT_SYSCONFDIR was being searched last. Also, in some configurations (especially when the --sysconfdir compile-time option is set to /etc or /etc/mysql), the system-wide my.cnf file was read multiple times, causing confusion and potential problems. Rearrange default directories to conform to the manual and logic. Move --sysconfdir= (DEFAULT_SYSCONFDIR) from the last default directory to the middle of the list. $HOME/.my.cnf should be last, so the user is able to override the system-wide settings. Change init_default_directories() to remove duplicates from the list. --- include/my_sys.h | 2 + libmysql/Makefile.shared | 2 +- mysys/CMakeLists.txt | 2 +- mysys/Makefile.am | 2 +- mysys/default.c | 192 ++++++++++++++++++++++++++------------- mysys/mf_arr_appstr.c | 61 +++++++++++++ 6 files changed, 195 insertions(+), 66 deletions(-) create mode 100644 mysys/mf_arr_appstr.c diff --git a/include/my_sys.h b/include/my_sys.h index 7df2718c7b1..8c0d620984c 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -691,6 +691,8 @@ extern WF_PACK *wf_comp(my_string str); extern int wf_test(struct wild_file_pack *wf_pack,const char *name); extern void wf_end(struct wild_file_pack *buffer); extern size_s strip_sp(my_string str); +extern my_bool array_append_string_unique(const char *str, + const char **array, size_t size); extern void get_date(my_string to,int timeflag,time_t use_time); extern void soundex(CHARSET_INFO *, my_string out_pntr, my_string in_pntr,pbool remove_garbage); extern int init_record_cache(RECORD_CACHE *info,uint cachesize,File file, diff --git a/libmysql/Makefile.shared b/libmysql/Makefile.shared index dc6d658fcdf..7839c117432 100644 --- a/libmysql/Makefile.shared +++ b/libmysql/Makefile.shared @@ -59,7 +59,7 @@ mysysobjects1 = my_init.lo my_static.lo my_malloc.lo my_realloc.lo \ mf_pack.lo my_messnc.lo mf_dirname.lo mf_fn_ext.lo\ mf_wcomp.lo typelib.lo safemalloc.lo my_alloc.lo \ mf_format.lo mf_path.lo mf_unixpath.lo my_fopen.lo \ - my_symlink.lo my_fstream.lo \ + my_symlink.lo my_fstream.lo mf_arr_appstr.lo \ mf_loadpath.lo my_pthread.lo my_thr_init.lo \ thr_mutex.lo mulalloc.lo string.lo \ default.lo default_modify.lo \ diff --git a/mysys/CMakeLists.txt b/mysys/CMakeLists.txt index 8aaf0b5f00f..cd3e7afd6a5 100755 --- a/mysys/CMakeLists.txt +++ b/mysys/CMakeLists.txt @@ -26,7 +26,7 @@ ADD_LIBRARY(mysys array.c charset-def.c charset.c checksum.c default.c default_m errors.c hash.c list.c md5.c mf_brkhant.c mf_cache.c mf_dirname.c mf_fn_ext.c mf_format.c mf_getdate.c mf_iocache.c mf_iocache2.c mf_keycache.c mf_keycaches.c mf_loadpath.c mf_pack.c mf_path.c mf_qsort.c mf_qsort2.c - mf_radix.c mf_same.c mf_sort.c mf_soundex.c mf_strip.c mf_tempdir.c + mf_radix.c mf_same.c mf_sort.c mf_soundex.c mf_strip.c mf_arr_appstr.c mf_tempdir.c mf_tempfile.c mf_unixpath.c mf_wcomp.c mf_wfile.c mulalloc.c my_access.c my_aes.c my_alarm.c my_alloc.c my_append.c my_bit.c my_bitmap.c my_chsize.c my_clock.c my_compress.c my_conio.c my_copy.c my_crc32.c my_create.c my_delete.c diff --git a/mysys/Makefile.am b/mysys/Makefile.am index a835492e670..8c6bf5f7006 100644 --- a/mysys/Makefile.am +++ b/mysys/Makefile.am @@ -38,7 +38,7 @@ libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c my_mmap.c \ my_error.c errors.c my_div.c my_messnc.c \ mf_format.c mf_same.c mf_dirname.c mf_fn_ext.c \ my_symlink.c my_symlink2.c \ - mf_pack.c mf_unixpath.c mf_strip.c \ + mf_pack.c mf_unixpath.c mf_strip.c mf_arr_appstr.c \ mf_wcomp.c mf_wfile.c my_gethwaddr.c \ mf_qsort.c mf_qsort2.c mf_sort.c \ ptr_cmp.c mf_radix.c queues.c \ diff --git a/mysys/default.c b/mysys/default.c index aff38b6af0b..74d016ce53c 100644 --- a/mysys/default.c +++ b/mysys/default.c @@ -47,7 +47,7 @@ char *my_defaults_extra_file=0; /* Which directories are searched for options (and in which order) */ -#define MAX_DEFAULT_DIRS 7 +#define MAX_DEFAULT_DIRS 6 const char *default_directories[MAX_DEFAULT_DIRS + 1]; #ifdef __WIN__ @@ -83,7 +83,22 @@ static int search_default_file_with_ext(Process_option_func func, void *func_ctx, const char *dir, const char *ext, const char *config_file, int recursion_level); -static void init_default_directories(); + + + +/** + Create the list of default directories. + + @details + On all systems, if a directory is already in the list, it will be moved + to the end of the list. This avoids reading defaults files multiple times, + while ensuring the correct precedence. + + @return void +*/ + +static void (*init_default_directories)(); + static char *remove_end_comment(char *ptr); @@ -913,6 +928,25 @@ void print_defaults(const char *conf_file, const char **groups) #include +#define ADD_DIRECTORY(DIR) \ + do { \ + my_bool rc= \ + array_append_string_unique((DIR), default_directories, \ + array_elements(default_directories)); \ + DBUG_ASSERT(rc == FALSE); /* Success */ \ + } while (0) + + +#define ADD_COMMON_DIRECTORIES() \ + do { \ + char *env; \ + if ((env= getenv(STRINGIFY_ARG(DEFAULT_HOME_ENV)))) \ + ADD_DIRECTORY(env); \ + /* Placeholder for --defaults-extra-file= */ \ + ADD_DIRECTORY(""); \ + } while (0) + + #ifdef __WIN__ /* This wrapper for GetSystemWindowsDirectory() will dynamically bind to the @@ -947,73 +981,33 @@ static uint my_get_system_windows_directory(char *buffer, uint size) } return count; } -#endif -/* - Create the list of default directories. +/** + Initialize default directories for Microsoft Windows - On Microsoft Windows, this is: - 1. C:/ + @details + 1. GetSystemWindowsDirectory() 2. GetWindowsDirectory() - 3. GetSystemWindowsDirectory() - 4. getenv(DEFAULT_HOME_ENV) - 5. Directory above where the executable is located - 6. "" - 7. --sysconfdir= + 3. C:/ + 4. Directory above where the executable is located + 5. getenv(DEFAULT_HOME_ENV) + 6. --defaults-extra-file= (run-time option) +*/ - On Novell NetWare, this is: - 1. sys:/etc/ - 2. getenv(DEFAULT_HOME_ENV) - 3. "" - 4. --sysconfdir= - - On OS/2, this is: - 1. getenv(ETC) - 2. /etc/ - 3. getenv(DEFAULT_HOME_ENV) - 4. "" - 5. "~/" - 6. --sysconfdir= - - Everywhere else, this is: - 1. /etc/ - 2. getenv(DEFAULT_HOME_ENV) - 3. "" - 4. "~/" - 5. --sysconfdir= - - */ - -static void init_default_directories() +static void init_default_directories_win() { - const char *env, **ptr= default_directories; + bzero(default_directories, sizeof(default_directories)); -#ifdef __WIN__ - *ptr++= "C:/"; + if (my_get_system_windows_directory(shared_system_dir, + sizeof(shared_system_dir))) + ADD_DIRECTORY(&shared_system_dir); if (GetWindowsDirectory(system_dir,sizeof(system_dir))) - *ptr++= (char*)&system_dir; - if (my_get_system_windows_directory(shared_system_dir, - sizeof(shared_system_dir)) && - strcmp(system_dir, shared_system_dir)) - *ptr++= (char *)&shared_system_dir; + ADD_DIRECTORY(&system_dir); + + ADD_DIRECTORY("C:/"); -#elif defined(__NETWARE__) - *ptr++= "sys:/etc/"; -#else -#if defined(__EMX__) || defined(OS2) - if ((env= getenv("ETC"))) - *ptr++= env; -#endif - *ptr++= "/etc/"; -#endif - if ((env= getenv(STRINGIFY_ARG(DEFAULT_HOME_ENV)))) - *ptr++= env; - *ptr++= ""; /* Place for defaults_extra_file */ -#if !defined(__WIN__) && !defined(__NETWARE__) - *ptr++= "~/";; -#elif defined(__WIN__) if (GetModuleFileName(NULL, config_dir, sizeof(config_dir))) { char *last= NULL, *end= strend(config_dir); @@ -1043,12 +1037,84 @@ static void init_default_directories() last= end; } } - *ptr++= (char *)&config_dir; + ADD_DIRECTORY(&config_dir); } -#endif + + ADD_COMMON_DIRECTORIES(); +} + +static void (*init_default_directories)()= init_default_directories_win; + +#elif defined(__NETWARE__) + +/** + Initialize default directories for Novell Netware + + @details + 1. sys:/etc/ + 2. getenv(DEFAULT_HOME_ENV) + 3. --defaults-extra-file= (run-time option) +*/ + +static void init_default_directories_netware() +{ + bzero(default_directories, sizeof(default_directories)); + ADD_DIRECTORY("sys:/etc/"); + ADD_COMMON_DIRECTORIES(); +} + +static void (*init_default_directories)()= init_default_directories_netware; + +#elif defined(__EMX__) || defined(OS2) + +/** + Initialize default directories for OS/2 + + @details + 1. /etc/ + 2. getenv(ETC) + 3. getenv(DEFAULT_HOME_ENV) + 4. --defaults-extra-file= (run-time option) +*/ + +static void init_default_directories_os2() +{ + const char *env; + + bzero(default_directories, sizeof(default_directories)); + ADD_DIRECTORY("/etc/"); + if ((env= getenv("ETC"))) + ADD_DIRECTORY(env); + ADD_COMMON_DIRECTORIES(); +} + +static void (*init_default_directories)()= init_default_directories_os2; + +#else + +/** + Initialize default directories for Unix + + @details + 1. /etc/ + 2. --sysconfdir= (compile-time option) + 3. getenv(DEFAULT_HOME_ENV) + 4. --defaults-extra-file= (run-time option) + 5. "~/" +*/ + +static void init_default_directories_unix() +{ + bzero(default_directories, sizeof(default_directories)); + ADD_DIRECTORY("/etc/"); #ifdef DEFAULT_SYSCONFDIR if (DEFAULT_SYSCONFDIR != "") - *ptr++= DEFAULT_SYSCONFDIR; + ADD_DIRECTORY(DEFAULT_SYSCONFDIR); #endif - *ptr= 0; /* end marker */ + ADD_COMMON_DIRECTORIES(); + ADD_DIRECTORY("~/"); } + +static void (*init_default_directories)()= init_default_directories_unix; + +#endif diff --git a/mysys/mf_arr_appstr.c b/mysys/mf_arr_appstr.c new file mode 100644 index 00000000000..1edbea9df4a --- /dev/null +++ b/mysys/mf_arr_appstr.c @@ -0,0 +1,61 @@ +/* Copyright (C) 2007 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include "mysys_priv.h" +#include /* strcmp() */ + + +/** + Append str to array, or move to the end if it already exists + + @param str String to be appended + @param array The array, terminated by a NULL element, all unused elements + pre-initialized to NULL + @param size Size of the array; array must be terminated by a NULL + pointer, so can hold size - 1 elements + + @retval FALSE Success + @retval TRUE Failure, array is full +*/ + +my_bool array_append_string_unique(const char *str, + const char **array, size_t size) +{ + const char **p; + /* end points at the terminating NULL element */ + const char **end= array + size - 1; + DBUG_ASSERT(*end == NULL); + + for (p= array; *p; ++p) + { + if (strcmp(*p, str) == 0) + break; + } + if (p >= end) + return TRUE; /* Array is full */ + + DBUG_ASSERT(*p == NULL || strcmp(*p, str) == 0); + + while (*(p + 1)) + { + *p= *(p + 1); + ++p; + } + + DBUG_ASSERT(p < end); + *p= str; + + return FALSE; /* Success */ +} From 5a5ed2a5095c98ae56c766b5a8fbc7ca2fe28e7c Mon Sep 17 00:00:00 2001 From: "tnurnberg@mysql.com/white.intern.koehntopp.de" <> Date: Thu, 8 Nov 2007 06:08:44 +0100 Subject: [PATCH 181/336] Bug#31990: MINUTE() and SECOND() return bogus results when used on a DATE HOUR(), MINUTE(), ... returned spurious results when used on a DATE-cast. This happened because DATE-cast object did not overload get_time() method in superclass Item. The default method was inappropriate here and misinterpreted the data. Patch adds missing method; get_time() on DATE-casts now returns SQL-NULL on NULL input, 0 otherwise. This coincides with the way DATE-columns behave. --- mysql-test/r/cast.result | 24 ++++++++++++++++++++++++ mysql-test/t/cast.test | 22 ++++++++++++++++++++++ sql/item_timefunc.cc | 7 +++++++ sql/item_timefunc.h | 1 + 4 files changed, 54 insertions(+) diff --git a/mysql-test/r/cast.result b/mysql-test/r/cast.result index 524ff48d69e..88601eceb0a 100644 --- a/mysql-test/r/cast.result +++ b/mysql-test/r/cast.result @@ -414,4 +414,28 @@ NULL NULL 20070719 drop table t1; +CREATE TABLE t1 (f1 DATE); +INSERT INTO t1 VALUES ('2007-07-19'), (NULL); +SELECT HOUR(f1), +MINUTE(f1), +SECOND(f1) FROM t1; +HOUR(f1) MINUTE(f1) SECOND(f1) +0 0 0 +NULL NULL NULL +SELECT HOUR(CAST('2007-07-19' AS DATE)), +MINUTE(CAST('2007-07-19' AS DATE)), +SECOND(CAST('2007-07-19' AS DATE)); +HOUR(CAST('2007-07-19' AS DATE)) MINUTE(CAST('2007-07-19' AS DATE)) SECOND(CAST('2007-07-19' AS DATE)) +0 0 0 +SELECT HOUR(CAST(NULL AS DATE)), +MINUTE(CAST(NULL AS DATE)), +SECOND(CAST(NULL AS DATE)); +HOUR(CAST(NULL AS DATE)) MINUTE(CAST(NULL AS DATE)) SECOND(CAST(NULL AS DATE)) +NULL NULL NULL +SELECT HOUR(NULL), +MINUTE(NULL), +SECOND(NULL); +HOUR(NULL) MINUTE(NULL) SECOND(NULL) +NULL NULL NULL +DROP TABLE t1; End of 5.0 tests diff --git a/mysql-test/t/cast.test b/mysql-test/t/cast.test index 316b79efe4d..df475b49746 100644 --- a/mysql-test/t/cast.test +++ b/mysql-test/t/cast.test @@ -246,4 +246,26 @@ INSERT INTO t1(d1) VALUES ('2007-07-19 08:30:00'), (NULL), SELECT cast(date(d1) as signed) FROM t1; drop table t1; +# +# Bug #31990: MINUTE() and SECOND() return bogus results when used on a DATE +# + +# Show that HH:MM:SS of a DATE are 0, and that it's the same for columns +# and typecasts (NULL in, NULL out). +CREATE TABLE t1 (f1 DATE); +INSERT INTO t1 VALUES ('2007-07-19'), (NULL); +SELECT HOUR(f1), + MINUTE(f1), + SECOND(f1) FROM t1; +SELECT HOUR(CAST('2007-07-19' AS DATE)), + MINUTE(CAST('2007-07-19' AS DATE)), + SECOND(CAST('2007-07-19' AS DATE)); +SELECT HOUR(CAST(NULL AS DATE)), + MINUTE(CAST(NULL AS DATE)), + SECOND(CAST(NULL AS DATE)); +SELECT HOUR(NULL), + MINUTE(NULL), + SECOND(NULL); +DROP TABLE t1; + --echo End of 5.0 tests diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index c1fa9dce038..7ed5e375f5b 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -2645,6 +2645,13 @@ bool Item_date_typecast::get_date(MYSQL_TIME *ltime, uint fuzzy_date) } +bool Item_date_typecast::get_time(MYSQL_TIME *ltime) +{ + bzero((char *)ltime, sizeof(MYSQL_TIME)); + return args[0]->null_value; +} + + String *Item_date_typecast::val_str(String *str) { DBUG_ASSERT(fixed == 1); diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index a5ecbc57e8d..b647e93b700 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -779,6 +779,7 @@ public: const char *func_name() const { return "cast_as_date"; } String *val_str(String *str); bool get_date(MYSQL_TIME *ltime, uint fuzzy_date); + bool get_time(MYSQL_TIME *ltime); const char *cast_type() const { return "date"; } enum_field_types field_type() const { return MYSQL_TYPE_DATE; } Field *tmp_table_field(TABLE *t_arg) From ba2256e262788a8839a63241dda5a5fe065fffde Mon Sep 17 00:00:00 2001 From: "mats@kindahl-laptop.dnsalias.net" <> Date: Thu, 8 Nov 2007 09:25:03 +0100 Subject: [PATCH 182/336] Fixing test case to not print warnings causing a result mismatch for rpl_trigger. --- mysql-test/suite/rpl/t/rpl_trigger.test | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mysql-test/suite/rpl/t/rpl_trigger.test b/mysql-test/suite/rpl/t/rpl_trigger.test index 9f5f6fc9b4c..4a496ea4923 100644 --- a/mysql-test/suite/rpl/t/rpl_trigger.test +++ b/mysql-test/suite/rpl/t/rpl_trigger.test @@ -316,8 +316,13 @@ SELECT * FROM t2; # 2. Check that the trigger is non-SUID on the slave; # 3. Check that the trigger can be activated on the slave. +# +# We disable warnings here since it affects the result file in +# different ways depending on the mode being used. +disable_warnings; INSERT INTO t1 VALUES(2); +enable_warnings; SELECT * FROM t1; SELECT * FROM t2; From 8cde2055ad02e23fe75c3471146e7540a6057433 Mon Sep 17 00:00:00 2001 From: "jperkin@production.mysql.com" <> Date: Thu, 8 Nov 2007 13:43:40 +0100 Subject: [PATCH 183/336] Remove the --source-install option and instead make use of --srcdir to install system tables directly from the source tree (useful for testing purposes). This helps clean the script up a lot and clarify the three possible ways the script can be called (using compiled-in paths, passing --basedir pointing to alternative install location, or --srcdir). Include further tidying as well. This fixes bug#30759. --- scripts/mysql_install_db.sh | 331 +++++++++++++++--------------------- 1 file changed, 138 insertions(+), 193 deletions(-) diff --git a/scripts/mysql_install_db.sh b/scripts/mysql_install_db.sh index 6f147c45f3b..260c372c802 100644 --- a/scripts/mysql_install_db.sh +++ b/scripts/mysql_install_db.sh @@ -19,7 +19,7 @@ # All unrecognized arguments to this script are passed to mysqld. basedir="" -ldata="" +ldata="@localstatedir@" srcdir="" args="" @@ -31,7 +31,6 @@ force=0 in_rpm=0 ip_only=0 windows=0 -source_install=0 usage() { @@ -48,10 +47,10 @@ Usage: $0 [OPTIONS] --skip-name-resolve Use IP addresses rather than hostnames when creating grant table entries. This option can be useful if your DNS does not work. - --srcdir=path For internal use. The directory under which - mysql_install_db looks for support files such as the - error message file and the file for popoulating the - help tables. + --srcdir=path The path to the MySQL source directory. This option + uses the compiled binaries and support files within the + source tree, useful for if you don't want to install + MySQL yet and just want to create the system tables. --user=user_name The login username to use for running mysqld. Files and directories created by mysqld will be owned by this user. You must be root to use this option. By default @@ -121,13 +120,6 @@ parse_arguments() # package. windows=1 ;; - --source-install) - # This is used when you want to run mysqld directly from the - # source tree (for example when you are developing MySQL and - # only want to create the default tables but don't want to - # install mysqld yet. - source_install=1 ;; - *) if test -n "$pick_args" then @@ -155,41 +147,33 @@ find_in_basedir() file=$1; shift - base="$basedir" - if test -z "$base" - then - # Assume source installation if basedir is not given - base="." - fi - for dir in "$@" do - if test -f "$base/$dir/$file" + if test -f "$basedir/$dir/$file" then if test -n "$return_dir" then - echo "$base/$dir" + echo "$basedir/$dir" else - echo "$base/$dir/$file" + echo "$basedir/$dir/$file" fi break fi done } -missing_in_basedir() +cannot_find_file() { - if test -z "$basedir" - then - echo "FATAL ERROR: Could not find $* inside --basedir" - echo - echo "When using --basedir you must point either into a MySQL binary" - echo "distribution directory or a compiled tree previously populated" - echo "by 'make install'" - else - echo "FATAL ERROR: Can't find $*. Please specify your installation" - echo "directory with the '--basedir=' option." - fi + echo + echo "FATAL ERROR: Could not find $*" + echo + echo "If you compiled from source, you need to run 'make install' to" + echo "copy the software into the correct location ready for operation." + echo + echo "If you are using a binary release, you must either be at the top" + echo "level of the extracted archive, or pass the --basedir option" + echo "pointing to that location." + echo } # Ok, let's go. We first need to parse arguments which are required by @@ -197,23 +181,28 @@ missing_in_basedir() # the command line to add any extra bits that we need. parse_arguments PICK-ARGS-FROM-ARGV "$@" -# We can now find my_print_defaults, either in the supplied --basedir -# location or in the installed area. - -print_defaults=`find_in_basedir my_print_defaults bin extra` -if test -z "$print_defaults" +# +# We can now find my_print_defaults. This script supports: +# +# --srcdir=path pointing to compiled source tree +# --basedir=path pointing to installed binary location +# +# or default to compiled-in locations. +# +if test -n "$srcdir" then + print_defaults="$srcdir/extra/my_print_defaults" +elif test -n "$basedir" +then + print_defaults=`find_in_basedir my_print_defaults bin extra` +else print_defaults="@bindir@/my_print_defaults" - if ! test -x "$print_defaults" - then - echo "FATAL ERROR: Could not find $print_defaults" - echo - echo "If you are using a binary release, you must run this script from" - echo "within the directory the archive extracted into. If you compiled" - echo "MySQL yourself you must run 'make install' first or use" - echo "use --source-install --install-dir=xxx from the top source directory" - exit 1 - fi +fi + +if test ! -x "$print_defaults" +then + cannot_find_file "$print_defaults" + exit 1 fi # Now we can get arguments from the groups [mysqld] and [mysql_install_db] @@ -221,63 +210,33 @@ fi parse_arguments `$print_defaults $defaults mysqld mysql_install_db` parse_arguments PICK-ARGS-FROM-ARGV "$@" -# Path to MySQL installation directory -if test -z "$basedir" -a "$source_install" = 0 +# Configure paths to support files +if test -n "$srcdir" then + basedir="$srcdir" + bindir="$srcdir/client" + extra_bindir="$srcdir/extra" + mysqld="$srcdir/sql/mysqld" + mysqld_opt="--language=$srcdir/sql/share/english" + pkgdatadir="$srcdir/scripts" + scriptdir="$srcdir/scripts" +elif test -n "$basedir" +then + bindir="$basedir/bin" + extra_bindir="$bindir" + mysqld=`find_in_basedir mysqld libexec sbin bin` + pkgdatadir=`find_in_basedir --dir fill_help_tables.sql share share/mysql` + scriptdir="$basedir/scripts" +else basedir="@prefix@" bindir="@bindir@" extra_bindir="$bindir" mysqld="@libexecdir@/mysqld" pkgdatadir="@pkgdatadir@" -else - bindir="$basedir/bin" - extra_bindir="$bindir" - # We set up bootstrap-specific paths later, so skip this for --windows - if test "$windows" -eq 0 - then - mysqld=`find_in_basedir mysqld libexec sbin bin` - if test -z "$basedir" - then - # We come here when source-install is given - bindir="$basedir/bin" - extra_bindir="$bindir" - fi - if test -x "$mysqld" - then - pkgdatadir=`find_in_basedir --dir fill_help_tables.sql share share/mysql scripts` - if test -z "$pkgdatadir" - then - missing_in_basedir fill_help_tables.sql - exit 1 - fi - else - if test -x "./sql/mysqld" - then - # Source installation - mysqld="./sql/mysqld" - bindir="./client" - extra_bindir="./extra" - pkgdatadir="./scripts" - mysqld_opt="--language=./sql/share/english" - else - missing_in_basedir mysqld - fi - fi - fi -fi - -# Path to data directory -if test -z "$ldata" -then - ldata="@localstatedir@" -fi - -# Set up paths to SQL scripts required for bootstrap and ensure they exist. -if test -n "$srcdir" -then - pkgdatadir="$srcdir/scripts" + scriptdir="@scriptdir@" fi +# Set up paths to SQL scripts required for bootstrap fill_help_tables="$pkgdatadir/fill_help_tables.sql" create_system_tables="$pkgdatadir/mysql_system_tables.sql" fill_system_tables="$pkgdatadir/mysql_system_tables_data.sql" @@ -286,28 +245,14 @@ for f in $fill_help_tables $create_system_tables $fill_system_tables do if test ! -f "$f" then - echo "FATAL ERROR: Could not find SQL file '$f'" + cannot_find_file "$f" exit 1 fi done -# Set up Windows-specific paths -if test "$windows" -eq 1 -then - mysqld="./sql/mysqld" - if test -n "$srcdir" -a -f "$srcdir/sql/share/english/errmsg.sys" - then - mysqld_opt="--language=$srcdir/sql/share/english" - else - mysqld_opt="--language=./sql/share/english" - fi -fi - -# Make sure mysqld is available in default location (--basedir option is -# already tested above). if test ! -x "$mysqld" then - echo "FATAL ERROR: 'mysqld' executable not found!" + cannot_find_file "$mysqld" exit 1 fi @@ -318,10 +263,10 @@ hostname=`@HOSTNAME@` if test "$windows" -eq 0 -a "$in_rpm" -eq 0 -a "$force" -eq 0 then resolved=`$extra_bindir/resolveip $hostname 2>&1` - if [ $? -ne 0 ] + if test $? -ne 0 then resolved=`$extra_bindir/resolveip localhost 2>&1` - if [ $? -ne 0 ] + if test $? -ne 0 then echo "Neither host '$hostname' nor 'localhost' could be looked up with" echo "$extra_bindir/resolveip" @@ -345,7 +290,7 @@ then hostname=`echo "$resolved" | awk '/ /{print $6}'` fi -# Create database directories mysql & test +# Create database directories for dir in $ldata $ldata/mysql $ldata/test do if test ! -d $dir @@ -364,98 +309,98 @@ then args="$args --user=$user" fi -# Peform the install of system tables +# Configure mysqld command line mysqld_bootstrap="${MYSQLD_BOOTSTRAP-$mysqld}" mysqld_install_cmd_line="$mysqld_bootstrap $defaults $mysqld_opt --bootstrap \ --basedir=$basedir --datadir=$ldata --log-warnings=0 --loose-skip-innodb \ --loose-skip-ndbcluster $args --max_allowed_packet=8M \ --net_buffer_length=16K" -# Pipe mysql_system_tables.sql to "mysqld --bootstrap" +# Create the system and help tables by passing them to "mysqld --bootstrap" s_echo "Installing MySQL system tables..." if `(echo "use mysql;"; cat $create_system_tables $fill_system_tables) | $mysqld_install_cmd_line` then s_echo "OK" - - s_echo "Filling help tables..." - # Pipe fill_help_tables.sql to "mysqld --bootstrap" - if `(echo "use mysql;"; cat $fill_help_tables) | $mysqld_install_cmd_line` - then - # Fill suceeded - s_echo "OK" - else - echo - echo "WARNING: HELP FILES ARE NOT COMPLETELY INSTALLED!" - echo "The \"HELP\" command might not work properly" - echo - fi - - s_echo - s_echo "To start mysqld at boot time you have to copy" - s_echo "support-files/mysql.server to the right place for your system" - s_echo - - if test "$windows" -eq 0 - then - # A root password should of course also be set on Windows! - # The reason for not displaying these prompts here is that when - # executing this script with the --windows argument the script - # is used to generate system tables mainly used by the - # windows installer. And thus the password should not be set until - # those files has been copied to the target system - echo "PLEASE REMEMBER TO SET A PASSWORD FOR THE MySQL root USER !" - echo "To do so, start the server, then issue the following commands:" - echo "$bindir/mysqladmin -u root password 'new-password'" - echo "$bindir/mysqladmin -u root -h $hostname password 'new-password'" - echo - echo "Alternatively you can run:" - echo "$bindir/mysql_secure_installation" - echo - echo "which will also give you the option of removing the test" - echo "databases and anonymous user created by default. This is" - echo "strongly recommended for production servers." - echo - echo "See the manual for more instructions." - echo - - if test "$in_rpm" -eq 0 -a "$source_install" -eq 0 - then - echo "You can start the MySQL daemon with:" - echo "cd @prefix@ ; $bindir/mysqld_safe &" - echo - echo "You can test the MySQL daemon with mysql-test-run.pl" - echo "cd mysql-test ; perl mysql-test-run.pl" - echo - fi - echo "Please report any problems with the @scriptdir@/mysqlbug script!" - echo - echo "The latest information about MySQL is available on the web at" - echo "http://www.mysql.com" - echo "Support MySQL by buying support/licenses at http://shop.mysql.com" - fi - exit 0 else - echo "Installation of system tables failed!" echo - echo "Examine the logs in $ldata for more information." + echo "Installation of system tables failed! Examine the logs in" + echo "$ldata for more information." + echo echo "You can try to start the mysqld daemon with:" - echo "$mysqld --skip-grant &" - echo "and use the command line tool" - echo "$bindir/mysql to connect to the mysql" - echo "database and look at the grant tables:" echo - echo "shell> $bindir/mysql -u root mysql" - echo "mysql> show tables" + echo " shell> $mysqld --skip-grant &" echo - echo "Try 'mysqld --help' if you have problems with paths. Using --log" + echo "and use the command line tool $bindir/mysql" + echo "to connect to the mysql database and look at the grant tables:" + echo + echo " shell> $bindir/mysql -u root mysql" + echo " mysql> show tables" + echo + echo "Try 'mysqld --help' if you have problems with paths. Using --log" echo "gives you a log in $ldata that may be helpful." echo echo "The latest information about MySQL is available on the web at" - echo "http://www.mysql.com" - echo "Please consult the MySQL manual section: 'Problems running mysql_install_db'," - echo "and the manual section that describes problems on your OS." - echo "Another information source is the MySQL email archive." - echo "Please check all of the above before mailing us!" - echo "And if you do mail us, you MUST use the @scriptdir@/mysqlbug script!" + echo "http://www.mysql.com/. Please consult the MySQL manual section" + echo "'Problems running mysql_install_db', and the manual section that" + echo "describes problems on your OS. Another information source are the" + echo "MySQL email archives available at http://lists.mysql.com/." + echo + echo "Please check all of the above before mailing us! And remember, if" + echo "you do mail us, you MUST use the $scriptdir/mysqlbug script!" + echo exit 1 fi + +s_echo "Filling help tables..." +if `(echo "use mysql;"; cat $fill_help_tables) | $mysqld_install_cmd_line` +then + s_echo "OK" +else + echo + echo "WARNING: HELP FILES ARE NOT COMPLETELY INSTALLED!" + echo "The \"HELP\" command might not work properly." +fi + +# Don't output verbose information if running inside bootstrap or using +# --srcdir for testing. +if test "$windows" -eq 0 && test -z "$srcdir" +then + s_echo + s_echo "To start mysqld at boot time you have to copy" + s_echo "support-files/mysql.server to the right place for your system" + + echo + echo "PLEASE REMEMBER TO SET A PASSWORD FOR THE MySQL root USER !" + echo "To do so, start the server, then issue the following commands:" + echo + echo "$bindir/mysqladmin -u root password 'new-password'" + echo "$bindir/mysqladmin -u root -h $hostname password 'new-password'" + echo + echo "Alternatively you can run:" + echo "$bindir/mysql_secure_installation" + echo + echo "which will also give you the option of removing the test" + echo "databases and anonymous user created by default. This is" + echo "strongly recommended for production servers." + echo + echo "See the manual for more instructions." + + if test "$in_rpm" -eq 0 + then + echo + echo "You can start the MySQL daemon with:" + echo "cd $basedir ; $bindir/mysqld_safe &" + echo + echo "You can test the MySQL daemon with mysql-test-run.pl" + echo "cd $basedir/mysql-test ; perl mysql-test-run.pl" + fi + + echo + echo "Please report any problems with the $scriptdir/mysqlbug script!" + echo + echo "The latest information about MySQL is available at http://www.mysql.com/" + echo "Support MySQL by buying support/licenses from http://shop.mysql.com/" + echo +fi + +exit 0 From e8cd70868e7e62c6aab28f23c69c68162b07d054 Mon Sep 17 00:00:00 2001 From: "aelkin/elkin@koti.dsl.inet.fi" <> Date: Fri, 9 Nov 2007 10:10:15 +0200 Subject: [PATCH 184/336] Bug #31170 rpl_innodb_bug28430 fails: varying timing, ports, and log use Non-deterministic parameters of SHOW SLAVE STATUS are masked out by means of using the standard include-macro. The masked-out parameters are not needed by the logics of the original tests. What is need to demonstre that replication is not stopped remains. --- .../suite/rpl/r/rpl_innodb_bug28430.result | 16 ++++++++-------- mysql-test/suite/rpl/t/rpl_innodb_bug28430.test | 3 +-- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/mysql-test/suite/rpl/r/rpl_innodb_bug28430.result b/mysql-test/suite/rpl/r/rpl_innodb_bug28430.result index fb2782ed9f4..c46b4016715 100644 --- a/mysql-test/suite/rpl/r/rpl_innodb_bug28430.result +++ b/mysql-test/suite/rpl/r/rpl_innodb_bug28430.result @@ -114,30 +114,30 @@ Create Table CREATE TABLE `byrange_tbl` ( `filler` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=latin1 /*!50100 PARTITION BY RANGE (id) SUBPARTITION BY HASH (id) SUBPARTITIONS 2 (PARTITION pa1 VALUES LESS THAN (10) ENGINE = InnoDB, PARTITION pa2 VALUES LESS THAN (20) ENGINE = InnoDB, PARTITION pa3 VALUES LESS THAN (30) ENGINE = InnoDB, PARTITION pa4 VALUES LESS THAN (40) ENGINE = InnoDB, PARTITION pa5 VALUES LESS THAN (50) ENGINE = InnoDB, PARTITION pa6 VALUES LESS THAN (60) ENGINE = InnoDB, PARTITION pa7 VALUES LESS THAN (70) ENGINE = InnoDB, PARTITION pa8 VALUES LESS THAN (80) ENGINE = InnoDB, PARTITION pa9 VALUES LESS THAN (90) ENGINE = InnoDB, PARTITION pa10 VALUES LESS THAN (100) ENGINE = InnoDB, PARTITION pa11 VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */ -show slave status; -Slave_IO_State Waiting for master to send event +SHOW SLAVE STATUS; +Slave_IO_State # Master_Host 127.0.0.1 Master_User root Master_Port MASTER_PORT Connect_Retry 1 Master_Log_File master-bin.000001 Read_Master_Log_Pos 945470 -Relay_Log_File slave-relay-bin.000003 -Relay_Log_Pos 945616 +Relay_Log_File # +Relay_Log_Pos # Relay_Master_Log_File master-bin.000001 Slave_IO_Running Yes Slave_SQL_Running Yes Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table -Replicate_Ignore_Table +Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno 0 Last_Error Skip_Counter 0 Exec_Master_Log_Pos 945470 -Relay_Log_Space 945771 +Relay_Log_Space # Until_Condition None Until_Log_File Until_Log_Pos 0 @@ -149,8 +149,8 @@ Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No -Last_IO_Errno 0 -Last_IO_Error +Last_IO_Errno # +Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error SELECT count(*) "Slave norm" FROM test.regular_tbl; diff --git a/mysql-test/suite/rpl/t/rpl_innodb_bug28430.test b/mysql-test/suite/rpl/t/rpl_innodb_bug28430.test index fe3881ab08f..80d8a8ee6c6 100644 --- a/mysql-test/suite/rpl/t/rpl_innodb_bug28430.test +++ b/mysql-test/suite/rpl/t/rpl_innodb_bug28430.test @@ -135,8 +135,7 @@ SELECT count(*) as "Master byrange" FROM test.byrange_tbl; --sync_slave_with_master connection slave; show create table test.byrange_tbl; ---replace_column 4 MASTER_PORT 33 # -show slave status; +source include/show_slave_status.inc; SELECT count(*) "Slave norm" FROM test.regular_tbl; SELECT count(*) "Slave bykey" FROM test.bykey_tbl; SELECT count(*) "Slave byrange" FROM test.byrange_tbl; From 9b728dde4ba1e237a41d29b6c6e87f150f6438dd Mon Sep 17 00:00:00 2001 From: "mats@kindahl-laptop.dnsalias.net" <> Date: Fri, 9 Nov 2007 09:13:47 +0100 Subject: [PATCH 185/336] Fixing some tests to make the replication team tree green. --- mysql-test/suite/rpl/r/rpl_found_rows.result | 29 ++++++++++++-------- mysql-test/suite/rpl/t/rpl_found_rows.test | 25 ++++++++++------- 2 files changed, 32 insertions(+), 22 deletions(-) diff --git a/mysql-test/suite/rpl/r/rpl_found_rows.result b/mysql-test/suite/rpl/r/rpl_found_rows.result index cec5071eecd..7e757a1d141 100644 --- a/mysql-test/suite/rpl/r/rpl_found_rows.result +++ b/mysql-test/suite/rpl/r/rpl_found_rows.result @@ -28,12 +28,12 @@ a 1 SELECT FOUND_ROWS() INTO @a; INSERT INTO logtbl VALUES(1,2,@a); -SELECT * FROM logtbl WHERE sect = 1; +SELECT * FROM logtbl WHERE sect = 1 ORDER BY sect,test; sect test count 1 1 183 1 2 3 **** On Slave **** -SELECT * FROM logtbl WHERE sect = 1; +SELECT * FROM logtbl WHERE sect = 1 ORDER BY sect,test; sect test count 1 1 183 1 2 3 @@ -61,13 +61,13 @@ a 7 SELECT FOUND_ROWS() INTO @found_rows; CALL just_log(2,3,@found_rows); -SELECT * FROM logtbl WHERE sect = 2; +SELECT * FROM logtbl WHERE sect = 2 ORDER BY sect,test; sect test count 2 1 3 2 2 183 2 3 183 **** On Slave **** -SELECT * FROM logtbl WHERE sect = 2; +SELECT * FROM logtbl WHERE sect = 2 ORDER BY sect,test; sect test count 2 1 3 2 2 183 @@ -87,12 +87,12 @@ SELECT FOUND_ROWS() INTO @found_rows; SELECT log_rows(3,1,@found_rows), log_rows(3,2,@found_rows); log_rows(3,1,@found_rows) log_rows(3,2,@found_rows) 183 183 -SELECT * FROM logtbl WHERE sect = 3; +SELECT * FROM logtbl WHERE sect = 3 ORDER BY sect,test; sect test count 3 1 183 3 2 183 **** On Slave **** -SELECT * FROM logtbl WHERE sect = 3; +SELECT * FROM logtbl WHERE sect = 3 ORDER BY sect,test; sect test count 3 1 183 3 2 183 @@ -115,6 +115,7 @@ CREATE PROCEDURE just_log(sect INT, test INT) BEGIN INSERT INTO logtbl VALUES (sect,test,FOUND_ROWS()); END $$ **** On Master 1 **** +SET BINLOG_FORMAT=MIXED; SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; a 7 @@ -134,14 +135,14 @@ SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; a 7 CALL just_log(1,4); -SELECT * FROM logtbl WHERE sect = 1; +SELECT * FROM logtbl WHERE sect = 1 ORDER BY sect,test; sect test count 1 1 183 1 2 183 1 3 3 1 4 183 **** On Slave **** -SELECT * FROM logtbl WHERE sect = 1; +SELECT * FROM logtbl WHERE sect = 1 ORDER BY sect,test; sect test count 1 1 183 1 2 183 @@ -201,28 +202,32 @@ SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; a 7 INSERT INTO t2 VALUES (2,5), (2,6); -SELECT * FROM logtbl WHERE sect = 2; +SELECT * FROM logtbl WHERE sect = 2 ORDER BY sect,test; sect test count 2 1 3 2 2 3 2 3 3 2 4 3 2 5 183 -2 6 183 2 5 183 +2 6 183 2 6 0 2 6 183 2 7 0 -SELECT * FROM logtbl WHERE sect = 2; +SELECT * FROM logtbl WHERE sect = 2 ORDER BY sect,test; sect test count 2 1 3 2 2 3 2 3 3 2 4 3 2 5 183 -2 6 183 2 5 183 +2 6 183 2 6 0 2 6 183 2 7 0 DROP TABLE t1, logtbl; +DROP PROCEDURE just_log; +DROP PROCEDURE log_me; +DROP PROCEDURE log_me_inner; +DROP FUNCTION log_rows; diff --git a/mysql-test/suite/rpl/t/rpl_found_rows.test b/mysql-test/suite/rpl/t/rpl_found_rows.test index 5d67b2ba6b7..f868061c951 100644 --- a/mysql-test/suite/rpl/t/rpl_found_rows.test +++ b/mysql-test/suite/rpl/t/rpl_found_rows.test @@ -44,10 +44,10 @@ SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a < 5 ORDER BY a LIMIT 1; SELECT FOUND_ROWS() INTO @a; INSERT INTO logtbl VALUES(1,2,@a); -SELECT * FROM logtbl WHERE sect = 1; +SELECT * FROM logtbl WHERE sect = 1 ORDER BY sect,test; --echo **** On Slave **** sync_slave_with_master; -SELECT * FROM logtbl WHERE sect = 1; +SELECT * FROM logtbl WHERE sect = 1 ORDER BY sect,test; --echo ==== 1.2. Stored procedure ==== @@ -81,10 +81,10 @@ SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; SELECT FOUND_ROWS() INTO @found_rows; CALL just_log(2,3,@found_rows); -SELECT * FROM logtbl WHERE sect = 2; +SELECT * FROM logtbl WHERE sect = 2 ORDER BY sect,test; --echo **** On Slave **** sync_slave_with_master; -SELECT * FROM logtbl WHERE sect = 2; +SELECT * FROM logtbl WHERE sect = 2 ORDER BY sect,test; --echo ==== 1.3. Stored functions ==== --echo **** On Master **** @@ -102,10 +102,10 @@ SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; SELECT FOUND_ROWS() INTO @found_rows; SELECT log_rows(3,1,@found_rows), log_rows(3,2,@found_rows); -SELECT * FROM logtbl WHERE sect = 3; +SELECT * FROM logtbl WHERE sect = 3 ORDER BY sect,test; --echo **** On Slave **** sync_slave_with_master; -SELECT * FROM logtbl WHERE sect = 3; +SELECT * FROM logtbl WHERE sect = 3 ORDER BY sect,test; --echo ==== 1.9. Cleanup ==== --echo **** On Master **** @@ -139,6 +139,7 @@ sync_slave_with_master; --echo **** On Master 1 **** connection master1; +SET BINLOG_FORMAT=MIXED; SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; CALL just_log(1,1); @@ -161,10 +162,10 @@ CALL just_log(1,4); sync_slave_with_master; connection master; -SELECT * FROM logtbl WHERE sect = 1; +SELECT * FROM logtbl WHERE sect = 1 ORDER BY sect,test; --echo **** On Slave **** sync_slave_with_master; -SELECT * FROM logtbl WHERE sect = 1; +SELECT * FROM logtbl WHERE sect = 1 ORDER BY sect,test; --echo ==== 2.1. Checking a stored function ==== --echo **** On Master **** @@ -241,11 +242,15 @@ END $$ SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; INSERT INTO t2 VALUES (2,5), (2,6); -SELECT * FROM logtbl WHERE sect = 2; +SELECT * FROM logtbl WHERE sect = 2 ORDER BY sect,test; sync_slave_with_master; -SELECT * FROM logtbl WHERE sect = 2; +SELECT * FROM logtbl WHERE sect = 2 ORDER BY sect,test; connection master; DROP TABLE t1, logtbl; +DROP PROCEDURE just_log; +DROP PROCEDURE log_me; +DROP PROCEDURE log_me_inner; +DROP FUNCTION log_rows; sync_slave_with_master; From 240f3fa2b47cd46770ec1d8201737e3c342ec023 Mon Sep 17 00:00:00 2001 From: "mats@kindahl-laptop.dnsalias.net" <> Date: Fri, 9 Nov 2007 11:02:51 +0100 Subject: [PATCH 186/336] BUG#31552 (Replication breaks when deleting rows from out-of-sync table without PK): Pushing test case for bug only. Bug already fixed as a result of the patch for BUG#19958. --- mysql-test/extra/rpl_tests/rpl_row_basic.test | 36 ++++++++++++++++--- .../suite/rpl/r/rpl_row_basic_2myisam.result | 19 ++++++++++ .../suite/rpl/r/rpl_row_basic_3innodb.result | 19 ++++++++++ .../suite/rpl_ndb/r/rpl_row_basic_7ndb.result | 19 ++++++++++ 4 files changed, 88 insertions(+), 5 deletions(-) diff --git a/mysql-test/extra/rpl_tests/rpl_row_basic.test b/mysql-test/extra/rpl_tests/rpl_row_basic.test index 6de254d9931..c35a53f15bc 100644 --- a/mysql-test/extra/rpl_tests/rpl_row_basic.test +++ b/mysql-test/extra/rpl_tests/rpl_row_basic.test @@ -215,11 +215,36 @@ sync_slave_with_master; --echo --- on slave --- SELECT * FROM t8 ORDER BY a; -# -# Test conflicting operations when changing in a table referenced by a -# foreign key. We'll reuse the above table and just add a table that -# references it. -# +# BUG#31552: Replication breaks when deleting rows from out-of-sync +# table without PK + +--echo **** Test for BUG#31552 **** + +--echo **** On Master **** +# Clean up t1 so that we can use it. +connection master; +DELETE FROM t1; +sync_slave_with_master; + +# Just to get a clean binary log +source include/reset_master_and_slave.inc; + +--echo **** On Master **** +connection master; +INSERT INTO t1 VALUES ('K','K'), ('L','L'), ('M','M'); +--echo **** On Master **** +sync_slave_with_master; +DELETE FROM t1 WHERE C1 = 'L'; + +connection master; +DELETE FROM t1; +query_vertical SELECT COUNT(*) FROM t1 ORDER BY c1,c2; +sync_slave_with_master; +let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Errno, 1); +disable_query_log; +eval SELECT "$last_error" AS Last_SQL_Error; +enable_query_log; +query_vertical SELECT COUNT(*) FROM t1 ORDER BY c1,c2; # # cleanup @@ -227,3 +252,4 @@ SELECT * FROM t8 ORDER BY a; connection master; DROP TABLE IF EXISTS t1,t2,t3,t4,t5,t6,t7,t8; +sync_slave_with_master; diff --git a/mysql-test/suite/rpl/r/rpl_row_basic_2myisam.result b/mysql-test/suite/rpl/r/rpl_row_basic_2myisam.result index a6877b27b95..2efe3a3e486 100644 --- a/mysql-test/suite/rpl/r/rpl_row_basic_2myisam.result +++ b/mysql-test/suite/rpl/r/rpl_row_basic_2myisam.result @@ -415,4 +415,23 @@ a b c 2 4 8 3 6 9 99 99 99 +**** Test for BUG#31552 **** +**** On Master **** +DELETE FROM t1; +**** Resetting master and slave **** +STOP SLAVE; +RESET SLAVE; +RESET MASTER; +START SLAVE; +**** On Master **** +INSERT INTO t1 VALUES ('K','K'), ('L','L'), ('M','M'); +**** On Master **** +DELETE FROM t1 WHERE C1 = 'L'; +DELETE FROM t1; +SELECT COUNT(*) FROM t1 ORDER BY c1,c2; +COUNT(*) 0 +Last_SQL_Error +0 +SELECT COUNT(*) FROM t1 ORDER BY c1,c2; +COUNT(*) 0 DROP TABLE IF EXISTS t1,t2,t3,t4,t5,t6,t7,t8; diff --git a/mysql-test/suite/rpl/r/rpl_row_basic_3innodb.result b/mysql-test/suite/rpl/r/rpl_row_basic_3innodb.result index 4c6ec627db5..fc78abfbe2e 100644 --- a/mysql-test/suite/rpl/r/rpl_row_basic_3innodb.result +++ b/mysql-test/suite/rpl/r/rpl_row_basic_3innodb.result @@ -415,4 +415,23 @@ a b c 2 4 8 3 6 9 99 99 99 +**** Test for BUG#31552 **** +**** On Master **** +DELETE FROM t1; +**** Resetting master and slave **** +STOP SLAVE; +RESET SLAVE; +RESET MASTER; +START SLAVE; +**** On Master **** +INSERT INTO t1 VALUES ('K','K'), ('L','L'), ('M','M'); +**** On Master **** +DELETE FROM t1 WHERE C1 = 'L'; +DELETE FROM t1; +SELECT COUNT(*) FROM t1 ORDER BY c1,c2; +COUNT(*) 0 +Last_SQL_Error +0 +SELECT COUNT(*) FROM t1 ORDER BY c1,c2; +COUNT(*) 0 DROP TABLE IF EXISTS t1,t2,t3,t4,t5,t6,t7,t8; diff --git a/mysql-test/suite/rpl_ndb/r/rpl_row_basic_7ndb.result b/mysql-test/suite/rpl_ndb/r/rpl_row_basic_7ndb.result index 5519e0dcd0c..abd5bad8e49 100644 --- a/mysql-test/suite/rpl_ndb/r/rpl_row_basic_7ndb.result +++ b/mysql-test/suite/rpl_ndb/r/rpl_row_basic_7ndb.result @@ -415,4 +415,23 @@ a b c 2 4 8 3 6 9 99 99 99 +**** Test for BUG#31552 **** +**** On Master **** +DELETE FROM t1; +**** Resetting master and slave **** +STOP SLAVE; +RESET SLAVE; +RESET MASTER; +START SLAVE; +**** On Master **** +INSERT INTO t1 VALUES ('K','K'), ('L','L'), ('M','M'); +**** On Master **** +DELETE FROM t1 WHERE C1 = 'L'; +DELETE FROM t1; +SELECT COUNT(*) FROM t1 ORDER BY c1,c2; +COUNT(*) 0 +Last_SQL_Error +0 +SELECT COUNT(*) FROM t1 ORDER BY c1,c2; +COUNT(*) 0 DROP TABLE IF EXISTS t1,t2,t3,t4,t5,t6,t7,t8; From 04ed1811e30c40b249b8b3bfa60cc3b684a21d5c Mon Sep 17 00:00:00 2001 From: "msvensson@pilot.mysql.com" <> Date: Fri, 9 Nov 2007 11:16:47 +0100 Subject: [PATCH 187/336] Bug#32217 rpl_ssl fails with different number of records on master and slave - Add debug queries --- mysql-test/suite/rpl/t/rpl_ssl.test | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/mysql-test/suite/rpl/t/rpl_ssl.test b/mysql-test/suite/rpl/t/rpl_ssl.test index c1b7bc2097b..59f0bf6a6f8 100644 --- a/mysql-test/suite/rpl/t/rpl_ssl.test +++ b/mysql-test/suite/rpl/t/rpl_ssl.test @@ -76,6 +76,16 @@ if (`select $slave_count != $master_count`) echo master and slave differed in number of rows; echo master: $master_count; echo slave: $slave_count; + + connection master; + echo === master ===; + select count(*) t1; + select * from t1; + connection slave; + echo === slave ===; + select count(*) t1; + select * from t1; + query_vertical show slave status; } connection master; From e703c6a78c97eddf6a8fbf20bebe89d1ae504f93 Mon Sep 17 00:00:00 2001 From: "kaa@polly.(none)" <> Date: Fri, 9 Nov 2007 13:29:43 +0300 Subject: [PATCH 188/336] Fix for bug #32020: loading udfs while --skip-grant-tables is enabled causes out of memory errors The code in mysql_create_function() and mysql_drop_function() assumed that the only reason for UDFs being uninitialized at that point is an out-of-memory error during initialization. However, another possible reason for that is the --skip-grant-tables option in which case UDF initialization is skipped and UDFs are unavailable. The solution is to check whether mysqld is running with --skip-grant-tables and issue a proper error in such a case. --- mysql-test/r/skip_grants.result | 5 +++++ mysql-test/t/skip_grants.test | 12 ++++++++++++ sql/sql_udf.cc | 12 ++++++++++-- 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/skip_grants.result b/mysql-test/r/skip_grants.result index 3052bae8e97..1ef35b051d6 100644 --- a/mysql-test/r/skip_grants.result +++ b/mysql-test/r/skip_grants.result @@ -70,3 +70,8 @@ count(*) select count(*) from information_schema.USER_PRIVILEGES; count(*) 0 +CREATE FUNCTION a RETURNS STRING SONAME ''; +ERROR HY000: Can't initialize function 'a'; UDFs are unavailable with the --skip-grant-tables option +DROP FUNCTION a; +ERROR 42000: FUNCTION test.a does not exist +End of 5.0 tests diff --git a/mysql-test/t/skip_grants.test b/mysql-test/t/skip_grants.test index 75694672a17..02a381063ee 100644 --- a/mysql-test/t/skip_grants.test +++ b/mysql-test/t/skip_grants.test @@ -116,3 +116,15 @@ select count(*) from information_schema.COLUMN_PRIVILEGES; select count(*) from information_schema.SCHEMA_PRIVILEGES; select count(*) from information_schema.TABLE_PRIVILEGES; select count(*) from information_schema.USER_PRIVILEGES; + +# +# Bug #32020: loading udfs while --skip-grant-tables is enabled causes out of +# memory errors +# + +--error ER_CANT_INITIALIZE_UDF +CREATE FUNCTION a RETURNS STRING SONAME ''; +--error ER_SP_DOES_NOT_EXIST +DROP FUNCTION a; + +--echo End of 5.0 tests diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc index 077660f0bb9..e53dce1be13 100644 --- a/sql/sql_udf.cc +++ b/sql/sql_udf.cc @@ -410,7 +410,12 @@ int mysql_create_function(THD *thd,udf_func *udf) if (!initialized) { - my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); + if (opt_noacl) + my_error(ER_CANT_INITIALIZE_UDF, MYF(0), + udf->name.str, + "UDFs are unavailable with the --skip-grant-tables option"); + else + my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); DBUG_RETURN(1); } @@ -514,7 +519,10 @@ int mysql_drop_function(THD *thd,const LEX_STRING *udf_name) DBUG_ENTER("mysql_drop_function"); if (!initialized) { - my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); + if (opt_noacl) + my_error(ER_FUNCTION_NOT_DEFINED, MYF(0), udf_name->str); + else + my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); DBUG_RETURN(1); } rw_wrlock(&THR_LOCK_udf); From c6abad79c8592cae49102c4402a497ea0a8de89f Mon Sep 17 00:00:00 2001 From: "svoj@mysql.com/june.mysql.com" <> Date: Fri, 9 Nov 2007 16:05:01 +0400 Subject: [PATCH 189/336] BUG#29083 - test suite times out on OS X 64bit - also in older releases The "mysql client in mysqld"(which is used by replication and federated) should use alarms instead of setting socket timeout value if the rest of the server uses alarm. By always calling 'my_net_set_write_timeout' or 'net_set_read_timeout' when changing the timeout value(s), the selection whether to use alarms or timeouts will be handled by ifdef's in those two functions. This is minimal backport of patch for BUG#26664, which was pushed to 5.0 and up. Affects 4.1 only. --- include/mysql_com.h | 5 +++++ sql-common/client.c | 6 ++---- sql/mysql_priv.h | 3 --- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/mysql_com.h b/include/mysql_com.h index 56c7f7d2ab5..daeb540c7c8 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -291,6 +291,11 @@ my_bool net_write_command(NET *net,unsigned char command, int net_real_write(NET *net,const char *packet,unsigned long len); unsigned long my_net_read(NET *net); +#ifdef _global_h +void net_set_write_timeout(NET *net, uint timeout); +void net_set_read_timeout(NET *net, uint timeout); +#endif + /* The following function is not meant for normal usage Currently it's used internally by manager.c diff --git a/sql-common/client.c b/sql-common/client.c index bf9c7252283..82a2f9d7bd0 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -1884,13 +1884,11 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user, /* If user set read_timeout, let it override the default */ if (mysql->options.read_timeout) - net->read_timeout= mysql->options.read_timeout; - vio_timeout(net->vio, 0, net->read_timeout); + net_set_read_timeout(net, mysql->options.read_timeout); /* If user set write_timeout, let it override the default */ if (mysql->options.write_timeout) - net->write_timeout= mysql->options.write_timeout; - vio_timeout(net->vio, 1, net->write_timeout); + net_set_write_timeout(net, mysql->options.write_timeout); if (mysql->options.max_allowed_packet) net->max_packet_size= mysql->options.max_allowed_packet; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index b5100c15473..b6170ba35f9 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -59,9 +59,6 @@ void kill_one_thread(THD *thd, ulong id); bool net_request_file(NET* net, const char* fname); char* query_table_status(THD *thd,const char *db,const char *table_name); -void net_set_write_timeout(NET *net, uint timeout); -void net_set_read_timeout(NET *net, uint timeout); - #define x_free(A) { my_free((gptr) (A),MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR)); } #define safeFree(x) { if(x) { my_free((gptr) x,MYF(0)); x = NULL; } } #define PREV_BITS(type,A) ((type) (((type) 1 << (A)) -1)) From a432d3dec4c4f63c206db62b1dd6112197f5512a Mon Sep 17 00:00:00 2001 From: "mats@capulet.net" <> Date: Fri, 9 Nov 2007 13:43:09 +0100 Subject: [PATCH 190/336] BUG#31793 (log event corruption causes crash): When running mysqlbinlog on a 64-bit machine with a corrupt relay log, it causes mysqlbinlog to crash. In this case, the crash is caused because a request for 18446744073709534806U bytes is issued, which apparantly can be served on a 64-bit machine (speculatively, I assume) but this causes the memcpy() issued later to copy the data to segfault. The request for the number of bytes is caused by a computation of data_len - server_vars_len where server_vars_len is corrupt in such a sense that it is > data_len. This causes a wrap-around, with the the data_len given above. This patch adds a check that if server_vars_len is greater than data_len before the substraction, and aborts reading the event in that case marking the event as invalid. It also adds checks to see that reading the server variables does not go outside the bounds of the available space, giving a limited amount of integrity check. --- mysql-test/r/mysqlbinlog.result | 1 + mysql-test/std_data/corrupt-relay-bin.000624 | Bin 0 -> 91418 bytes mysql-test/t/mysqlbinlog.test | 4 + sql/log_event.cc | 95 ++++++++++++++++--- 4 files changed, 89 insertions(+), 11 deletions(-) create mode 100644 mysql-test/std_data/corrupt-relay-bin.000624 diff --git a/mysql-test/r/mysqlbinlog.result b/mysql-test/r/mysqlbinlog.result index d16a4c39a11..9f001c293de 100644 --- a/mysql-test/r/mysqlbinlog.result +++ b/mysql-test/r/mysqlbinlog.result @@ -325,4 +325,5 @@ flush logs; drop table t1; 1 drop table t1; +shell> mysqlbinlog std_data/corrupt-relay-bin.000624 > var/tmp/bug31793.sql End of 5.0 tests diff --git a/mysql-test/std_data/corrupt-relay-bin.000624 b/mysql-test/std_data/corrupt-relay-bin.000624 new file mode 100644 index 0000000000000000000000000000000000000000..21b4901211c939eff162cc9e3d12ea56240c0b65 GIT binary patch literal 91418 zcmdsg2Y_8wwe}E-6-7`~RJ@O;Z-P#e)5}0YPP=hPW)fy5U=WQd0|};?48~vqpCCnw z4a5ebf>IQbA}9g^3W|Ufp9NIj14SP{`eQ-F!u!@fXP>fXpSkzk%Z>NuDq%8vW^vB` zR$ptc{m+$aH+=gWFIn)yn@0Nj-qP3Cw-W#K_3hGU&Q@j{)~tyQlM|aaZC<-&V%AZc z*3DYC@hG-l_Qzh%?tRbh+p}*MeD>_?TiCbDK8)Orp#J*wmu9|yXZH2_ZCl>HZWf+k zwxTMUrI_>}^rQ43@h5%|U3mr`WG<-B_{{72`VIi;RqPSI{LW|d|IkbD#r(d$o%r8( z`L{m$U!NZ>7#g8p-Iadzl~|^K`ub)Z^t^jMKwqR}Uy0v!*za?)yY=(9@T-EHSB zldBWjqtPO7JnCD!Vavqk$=cctlN)QJQLuP4tj#4K=Qri<3q#IK&?Ky zczAi>jVvA+3cN*ZeSER-4fZqR%a-8Bu{Ja^9*vB%FO%;@W8=%mqVe&ekp*Ln!qD)N z(P(UJXz|GYwRfyocg)0=+Du0usP$`#V$V{QS*l%AltEn`RNVf7nyI*>g!&^l%>ONIQo3z~#^Y@1qivuu zPekKY_>Z^@4NkU~(a^1F&~Qw`1AA|{rfQm|okIgCs)j3rBl-Zr@mm=j$FrqRwgJb* zJI}6xdWP~P_{**Iojy*sIvh))(XquNwV6wol30Y0o#nx3gnxw@+xEM4OE*l_k95~| z6wS8HFs#=@$ICa$hK7_^j+6feAV(bUkUX7fpT78rh=aP zd8g8Izv&~fsn|Zx?OCQ78is1C^|}=(fnxZI9=JOGrKpzK@VQB;*4cBPi~VM5u&=MO ziMym+iaFU1NwH?@ieWe*MA$M+Pjy3EsT&Y&*Q?usrB;$+UzFlkV?$;zDQ^8Wx<`st z9fnxS$C()012x@-VK6na&xshjE*T0#BikYx>s6-_)6ct6FxDgwuQ;8S-oGv8tL-8W zuB-Zv=V@N3N1<*RifK8%6?uMLa}9`enLNznE+0Mjz3jR7-JWtBhH7Z*j^l?`5L&Jg zd5UiaKG@p#>XELX^uONRAsTU^(YXt#K&IF?rli zvrTFJHM&QRiypVs8pj^DX=n};-9{ew%nuRg+%F0-i+|YCC2bgoK!!#f|8TO^nW|gS zD8@hJ8^J4rQdMTV_><=orPW==+`w)O&Z&tVMi zWNNEoNEs{|3Kq^xoF+KVQzJ+*fXoG-<6^8h8XdBfzQ;nz7_B%mU9uPfD~lix^%mhr zW}3RA>bB$B0|*jbg!h($uXICoVB815>=Y&T6N%yBXao)%ez`;+4(R*SmZXtn-$!XD zue>GO$y8Y$z?Qz2IGOmVX`LP!2n!OvPC?ig01Pq^IN4t2Yn7tI>AVHgGVv3JV(7Y~ zxJAZR4b{YNkMtMu_|V4)k6UDT+|HKBSx7#W@%Tz&yiz=}P?D3ajz@E$WJ9k*vXNxI z3vBfed+`}{k*zZ0)%t7nj=Ho=ayp?2Y}Ev7$<-z8TPozgI-8j4j)bWW`lV3vcEtS?Tk_ji<%Xkz6xHM#l@jx=w)=kn;It0mb)LfDtaLCowZ$Cq5yfHx| z^?*oSz2;n6x~L6DcSz=u!~q;9yW^mdhSRa}a5PJGY%(5}X=!juO3)~HBwNp;Enh7| z<7;f`Lv5gOa5);BY%il>Qrs}5oCs$brd+X9RaY%aZlK<1I2jfy(^@D$;Fpo1ETFOL z`Gm%iGBoD1r5Vsv$!A*2LH0OLprH?HlvX#PpA=LR zVJ=DwKZIohM;v&=$C+fVIN$T;Hs_d4t5-};)KKUiu5Fo^tSucKn%lp1>(<#@S8Q3c zcEeGV8#ip)xMgzos*UUCY~3_#^|lRjR&7K>!iLE?D>hHAUA1mv4zbi6RhgrjbG%Xd zi>koZDYos*UNgCV9bPDm#)8qIC6r#6+ds6S=5JhC^H*$s+r;K0`nS}^)@+>EGEfUv zY@XOw3-R@aBl;(6W0S|MU%74qzfI4^k{u|N&sA*;+mfY6=F&dqOHXq%7RRP)g9_Xu zyT7(|&BW%3+S=7~(;Y2v@?D=NPF^FkxzGIqEuGYc&3#PdQMqYW*;s9ei)vO5kM+yi1- z9ynMqvo2);EXrUjT1miGkc~$#Bs4xKla2rQA}y_LLpB~4Wh2w_oNO`4RcU~ zY_Jv{6r~Uq*oYuB+caFbKuJyp-(gnQb*ZYDglnmJT*{)^8UH=+Z`k_2zBGXT3jVS) zvjDAc98>lJ)n>+_FY8cZ-zl_0Wi1~Xd^x03bOnO$xU;D;lBwa`TNeY* z@FL=#Gej|`LgC-p(#I1q2M6qjZ_e*%qk?7{bzKQe%W`bpusjb900uJXq3UUVU4c5w zUMVM5%p*!06|TIPUg>k&^SQkUHZinp4QVacGgQ~sL&MSQW~c`E4jhUG&rPAs@7Z&I zw~ZX}h^SUGLFQz8S&)nFS`L45*AUw~EShA_g`z0TkB*HT$u!H6ad$0^^Mgx?SAHO} zKf&={wsd?Oa14uZWIhKc+skmskw8P?j%|yUYy>~L7qhRIk{xYF)r-%kA zqf@>@OGXmQY!_t&{bOsM>8g$e`L;seaY7#*x~_t3wPSbJ%GrzmpylC#fbag&7S*(ZFm(=h+ahvM)N>sI62u~=6;pZ zCYe@OpkW40b5Nnmg{j%drzj2ukB)1aj>6pvR{UXNp|Iv)<1tWD1k6)*(N<$I9y-6j!7iVINBJ0u@B+&Z_}oqmf%qcD{o^S##g?82Kv=@MfrQYnipib}6Tc)So3+++vef};&M&bn-M3tH zdZ_5Nbde~eiew!PuxJTVl|Y^ebK~Qd>1#ZMt-A1Nw!|2e%_fe*f6)){hnqd9-ZNyfW$>jVVwzR1YIe%}toO80( z*{XZ+C_9#wDqh1hp>3cg$exg!clmel2Bdl?Y9;~vky(On(g z+^n*TVxxsNvyzNYK|HR$ozVD$OgtWEOY_N8%V#J8jqyl@%jXflx&tN;beOm4SA|W zp@TpsI)OAtwNv9^Q(IOsRgx6vXme8Aaqpc3$Lw3<%vEZ1S^f7eS~|K7mt;^>RT&(d z><$P=+~aZM1R15E2$>kB_%vAzML07H(A?>-6z(InOp0NH5TRN=`UA0iuRat`s zC)>+#Ojo@|X%?MwwhMcK>a}K?hLy`Q=yXo5q@m;M(v|lcd zXgS&HXfzek1`X$c$%43&h&B?1d>?GcKiHd9+y+a1shp)a*$%Ok=7fP6grV-B=S&YZo94@Drmy;z8lm5_ zQj)|KS&AI1*lTY6HM)nTO8nf^u>wn>EYG0$t~x-*RZp;`_qD-Q z7nE}qC)**e^4y^A_}Bz9)ICQx@P((iK2D(Ha3@-ED{+-3a#dCmZ2dL5hpVQwe(}^z zas!c8aB-lK!rE9_6|7&u7un+hVybyEUt}R$dS@HH$QKf(N?n{RpUcU1h^Z6{?elJg z(#xy0OjTn2()1xz6}U)8 zBZ=m+Tw`hhkqFKzn+2!ps9z9Uc?nw;g22zQrGFrOn0zW1(vDB?NXce}G)}fUTXhc} zW%*n-EX6{K3M0{C+fkuz^W-lHkWdDQ{va*!VXN85nFG!*DpOPXVlH@?_-aVTR}ZqK-QkoZpUTQ=l?X_dLgZwt^Hui%f+H@n z@@x!<=1__~nfI^YSiPR5bPa`$ZL6AtKc|dow0}*AEJ_eb{W(fmZDvaYZMccgP7q1S zW+^L9wwDnp(YvXCWx_XQde<~{n|hXHPJ6+-`pzSS#)wQl`hG)8Z)ih4jxCoDPPUiP z5K`=|pFu2G!oz+`+rC6Zgif=*@PBEE2By#lTelznHNT@H0Tc}bo$jajO8Pu6F5?`nVRKf zdl`-rHOt*w8%K%>1A;}>O~Rm2Ze-vwLSw1S=pDtD#@aA?uM>@4RyX5hdm0USlNhV> zqe%>x!qC+dIFXAIGp5L-Xb4SW1+#bE?+A~>WO)3AE&TyWg;x76W{G%Y(!t60G#*l~ zkfy`L^Kea<4Z)=@7z}I3yuw1}uz<$F|DVuUCYn4l9VfD-$u^vj(?rverFb~mUPglz zk1`va&cn4B9Eh24;Rm87-PLpp6-~$GO93mQ52u;jEDEJ`vKTd$WNe0N?f1ss$ z8-ScD0+NXbC)>+_$c;xXiq%ze%yk`uL0rAWcofiB`$yXHH_OoYLcG)l8fS`VWX9vo z3E5soqhV4(SLreV&BFZ|G=D4=57upL&c5NjeX@h3L1dH?Kt$|HhaO0QnbP={z_Z9I=7W+`{SqC(pTDus810Y zJJb7|Y)><`G-ybyFm(o?I~YNOX<>|ynmb1=1Puk&e*7uI<3ln$2L47%SGIx2St1^p zqTytF8V_mEka$NnSD;Sm(l1< z=JG}VBt#b6CYk%Nh%NoOjY|FJMMN_B;ADFl5xF5&;wTQnVJqwsTusGnyV8R`1#NZS z(}c#542_?$B@Ob?OahRoiZ=Yxax^&E9TW}2!i--G)1pJim{AY&PA6X*x<#{g+68DV zl%cVPEm2m#RWzQ7w%XP?5&8=qx}JGXA1n35_Kp8dSOa9$TU-R0s`hTjwixI+g80RkiE7=HUuV z9do_wL16muc!R)0x;D!ia%O}-R;=9ZvKzh9>^5}MdF4}2Ioax5^vq2?)o?0}?h9+M z7isfO2M*Mz5RTAiP|M=J@QITy^t5oCSYEO4b` zdokzobUri|*$L^;*-M^7Vmu~lCMvM}nk^mQhJ;@xB9awYIN6>?gfd{6dMFfFFboI- zn=G4B38+8P3GhOJ1vcBJNflEJ_kqtNK;9?=WGh>GM;m}#UJeK++tYwhxwimF{U7;cH0xoKkamW>;huU$Q`bzrZ_*2dqQ zoY*qC9M@G%;)bd%@zSb|n^!NNT)TcEyOo69zzFZfp;RO^2JXJbN%(B@QvHI{dh}vx zKkmlsKF)dpEghY`bLZ_~WYmqoH|maq6BoXMvtu|W>*8Vq%g3yJt1h*J zYWzy+a}U3eo;x>(qVvxkScV@sx@8%fK^FkHZr#MmH`UM`zaDCS*>h9Ko#uK^X3zbc zHWb3OqC&_#c}})E>voULY_6tcP}UdGRqDu3Q&PHr4`P*1%hdDUFQTQFwt>d=A{tqR zkCW|XG%PBamfW$3^sYk(+@YQEm5l=^nRZqw!KK-ev2FC?#>HIdr-0zmd z!O8YA9P+F~oOs7YXbw)c^Q;3}smO&)dfDQvgS7s=7s2u2@5OoE)E-idboq;E>Dr_Y zf_>|}j*XyH^*{@asBU;BMz8rk?jeXm$5bN4tcOkM*#F0#`;ScyqLO7qZxY!k^MX0q zUS=ctq&CJzxM>SKWKt^&OI|rR+@7)#>S@d)X18`@dPN~c?e9(8^7(|33P$feY^kpe zHG7u`2nC7H+d+u#*aMGP3CuQyvC)>-MR7`}X5doE+(Eo(No)}#T zd4|QtRW9si8%eiwL9X}NhgjvXgo_GjEM-f7X+zQeKtv;RpE%iGMx$u2isC)>+#l%1gF zX8|y?i4Fh&kLgcP7lP}-R}mn0%K$lsE%D&G6+ph8#xy0F>6ujBB_|qVZ~`)YJ#EalgVzf<6;isPft)6 znCi?|6I0zUW2*17C7St|d@4)%gCZK4(&c2UGgbGXQB=Cz1ZLey7|jNoM@pAmT|mIm zh=U~L6ez=6fMef(BRC$H!Lf`j@wwpmsmgHtM1&*rNI2PEhNCDP1vuzJM_k*@A`Cbr zlmg5$I)xJ^1vD<*kI;DT?SfxRCh!rq#M6SUpm9yP#^q$IqtTScZJb}MpmBdGW2#u= zw*DI3BjeLBRdSV?1{tSw8R!VrN;(h=OtsT%iK(71W2yt$(&9EW?!zJ)nP0`pR%fd2 zK|}DX3RN{6HMVR6XDhj1OlAV9PPkV4#X2V3F|7>%Tyel>MSk~6PY z%j)O1f)ZMSv%Zdw)Xy7sa>%4SY2`>?Bk`+#l<-x$JDFeA`fGF#Up1C;l?Ahg>L?~V zw-JE=NOSBE5hNx|+sVANX)fX_0OBYF$UGS!Ti6mW zAL6Gf19EM7EXK)J2c)T3tZ^MuzLQL!r$#LC(ta=URpzC&{u8o{8kKRHzs$r1txG_S{c5d1i`4Eajra6?#g>Me%jmoNRSr=yon*7b+OGgMolJ zsY6_(A)s`%%zl@1(Y*$-N+@y>rHNi((h|+nNj{ZT(?3NtGH;5L?P)Y1rc$m>#=_uA z9ys`{a0M{3{EBemwqPn&S+wbO86M}dC0>rkPgTa_8|9{gldXLPEU0c4BQd994 zk*zXQ(fVt2yO0-51roCf10%SS-fI;%#-|ZI@4d!%rj$yC1__XbA|PbD zcRGNUh7&-rbDg){cBn>v=vp|CZrN%*KnFP;0dqq=QXIcz;-T1Ud@XzKbGB!*jA`TU z0~fh#14rmXFY+TFK`VykI-%w{boqf)I~RS9Ke6Y2R~rJblPCaLMvIf}WdSJhT-A8m zmWp$B)agdeGAcSF zFRc5f;x)xZgY)Q>oHn@VS>;^B$?l+BL?cOT$8yL)!ufKV64p#!^z?&h%SS~nBG2_U zwzNwdXgps;BQt88Y%ilRb%b8ljDhAu3<$GnFc{34gIgSWOMV-GyjTPzQ?i_FF9T9kvbo$h3nerg!@=Srj)O~YnZ9kLWH0pzjYDNGH(p z;ioFcb$f|$WWvG8_A(qr;Yf35u?ON(t%A*5#Xx?Hi_V>|DbIR*FCsJ!m!YvsotBoi zAsqiMqLI}sIN4rCqcb&&H!YxT-ylQeY__zb4MaYhOk_wy)T{8{x*Pvsh+;yvIwH^9 zL1zPPRIWbrB-PkpNS4u!EaZ2oW@e>zbRp z7)4bG8o9%`cp(9Dg$$5W+0uL4konh$fMhn2lkH_drn8C23mTYRO3h@3hGdSCn<`sw z6Mw#l(6~y5#><9jX>%KB>{pHkC%Xfpp-_$x2|~?QF^GWGWn4GD+`5tb{Hv*XjdHzTw1P>=_;n&vkYL?!#mRPvuNs%1Wjk4N5a-q9 zeAW7EbP->%3lOHxE8y`IZctzsDLd#$cJ16{FY(D{jcz)d65qaJjQHw08DAaBmM(0= zx#|}I$!s|%Tb-}E2axG(Ij&AHs3(LfOel1i81d6YhW(;(LgNM*8V|Fj%i2KW1tJ<* z@`sb{Wi+Ns{^%}lvBzv$=INqF5S#VHmX{}goI?qYZ_D7=!j>*=1CG7R;oxL@8IIy` zm10A+ikrdElgHq|MPaU!o7Z0)u2KjDZ#|6QxLF3rj5pE}uRr0-%D&b0#xy0Y&E^@!1Mxk0Ee-aqvnrs#ld+4(a}MixVx3)SAM`Nw|h*K(?Og^uAu#RDz_i3t&pUA-<7mPBZ%k& z)zo<@S4<~DGnuWco?;r1b=}wex*uXlQ-s@4jp?L3eeVBa&;6yu{%@D(w!Fykbi-AH zAhayc39P{KkcW)wKITfU8lReSUVP7zmoaC z<>iA{P7tf?a))Hz#9?fSCVeKK%6`g%ax^&E9SRL=&`<}p_$nM!ax|PI02;W<)Uopy znwFz+@sWha5*Zr5VoS@~Kx3hZM%LiK$@VfDf|YN5&R`+waNrt3WW9(8Y1u!qrQD2* z&TCo24{@VU;3@T}jz(`yu{=`?l_*5TFi>6jH4FKcZ)&rgvzA_o-(ZL@E6cSfa#B_` z=VW`DlcvmVHwQIkP@_?52AYjEl*(CV7jxSUi;ZcBbBX-y0CEshGVLcGO}qX+86(Yo z8!hE->FhisX_{}$avfH>dp1?73HNPq!`%abIOrcX2Na zqBYlzEVZsicA&fPn+z*z%B}nII@<63w&!z4IOTv-8aQOBYASff2ysOUq*&MSkE`en zpPK~tH|)7-c4YFYEV#?c1(%cEfdn@fs!&p}#X~>yHW0U*E($IIvW+eAxCY;-49JbL z1VTKkhm)-iNK-^h^@{P*@_&C;kVP$vSYVnxa|6BXsZZ3Q5w^tI?m6y^#Fy-Fw`uZD?sl; zc~UG5mv`Mv&z(CW+<80Z`3`Qysw;lo#>r_P3N{Rb$oE{hL>B&N_}nDM^VxIra2emI zEXFsLi!mqLAu(dz+=DyB2LM~sWn^VDWY%yxpL;uyYb;zsvO zjLYM-!zYR3KPCz>G1XaYiO(a%H!3sLY8e{wPy|l4I#cxs8YUbin_YndG%Uk%2$`sG!9+KMxW}t8Y~(L7S4>lpyfm1Kz(%a z@bbVLSv)cnc#G&eXcQ2$~}(b)L%v1ojJXk@_{ePc8_WGQ`beA$u+e+d?k zhRer?hNFQci}5?S0Bir+q240=$V~LFV+0p+w*$JP<2aszB)X0}zA&K+tPCdtRcUpg zpJ)sZMg4csZo{w`%pG(E3X zu6mmYN0x8oWUF&k_rTGaeB-6>CPaK0B9E{oO1HF%$al)+oRh7NNKHAT*|>|;``<~JDWj^*YYqgc-A3|2DZotX$9+~V&Hrs}JPR%Bw7lM3YfiSa{W4l&tWtcj1Da!Gdj25KW59C z+VI50=9aAM0QTrF7(@Sk3BL_dCF#pVrkqa=v1&J{Ax zFxPWcT&p=y%MAKl+D@3-Xn8Oi;a}n0ERscAqBdw+gYa@{Th~l%o~W%|J(t>i*v1y> z0O9c@m+zLz<#B9@>Hw|E<;~@C$;oy|E*lpVD#+y;Q7*IavGv#J9=R-rk3#X4-Go6^ zfn*j&Q^nU${3kKhIWnfYk1g%j22*{voT)h34lz~ZWOoIo+EmU|t-nUMGL;Z^#Z1L2 z`skQON+Rdf(L4`T)_M556NstKmoe4;C(;rn=vviOx0N#$C)**WYMkk-z*KKNeg-xo zH~ee{Hsn`qQ(AwGVCmTS;^Am?`O-1`fe@2>M#Tk$l(j52%~`7KGUWdHj&vwbSd&%MRHb-8FK!f{u}u^?%I3eCxe%@I zPWOl$UOV5LTBs6n2aBaT4AdG;hgvvzsskN0=n}+lj|i9OtU8$_>xVL-JC`ld7}HjT z?idk|tf`5UtuA!kgGbS>auuki=h}3aU5$=XJEj^L&7@@?KZVfvFBuvGr_$1&+d$*k zax^&E9TW|NU7m_MDtS3*m35gc@GL{AK|1b(wB^4|(3me7|Ena8vb4rxmh8s*)(`#1 zI<|9-vdD-cORZq$MdLSk?VF z?{wOazssccXKd-DHXN4Y%cYf*t-h5#p*s!AMdMaf=02jM7za`j7&nyGS!WU&FS{#F z38oTBb?INRrPH=&JGAF`b;r~q%!=|A)pIq6Ci#bT3w2Ml7R%eAwb(eP3G&*9=#^-y zZL1deT_P7{6R|njUgjcse?v05*u-G~i*6j#bqq}_v=yrgwHV9$8;M%8U~&g zxSkeSPCf8ZVu~;;%}0NR7NAj2T0NS={~x9OrU`$o^8Xnk|JOk2Kt_#|?PdP&Oe%lt z$7tK%@?6L7MySelhiK)^0lS_}Xsk@o zD9H7<*i!Bqv(D=y%kxyvx1f7485Av{A*#k`V1i+DpkqDx^kPx2pJdNX!wFlJ>kpT6 z5huIja8a7EjjzPERTonTSS+I}iVD-v1Q#tlhq&lCnM{9xE$!0=8XpnS$h-_rwwKYM z&>)wi1003Imf>QYA|+T{T-bzbX^?`+=UprsXFMhEa{ng?kN=e6vG*rw$!`OX(?mS7 zmLE>Gm+>$Zlq>SZFtvDo35`A^9*84U)5Uc46pwhIkZV&KO-zKX`xNc^CuM5(HJ_%X zT%UR8)hsf2j<4ysWWY8&7xx+=Xm{#$%W^T9*$QxhUiSWJ;z@M-9$?R%yCtpj&+V$A ztKv+$7b%_{1vpUYo4TrbwiPHLjtn$>Zt6gM>1Sxa|JdYl0kVi7F#d7P}}t>9$P-lVCWqtB%+KUd^_LgNCqWI!DypK1F+ zWoUe+91Tu(M@0kYxbZ)-4oEyA4UE)ds*TFgc=9|#IR&&&@+;e4{cKeLtz-r80d9sKh5u zIN9o4#4BA(mr`{r-))gAYIzM~@SHUgwQ;JNk`pKAiNcWe0JZ)a-ILcV_5kHJBP-y+ zU1bw#OboNngrU&uSI|wneV$nU^P)5mS9xq{_cnCX`7$_M7M5_b)w!yB;IImwl29?k z$rHzZr8&OjC>7v1>k9OHOa>}P4?LxaVBOGF|mf{ zJeQjBZL=tNoFY;5I7 z07kw<&%Iqw*4v?Lhjo-lFd)WIeZ|7$mAX^MAi2ncb#6`oPGQf@Z@9)QRJP97iUN>% z+?;GL3&1oUx2YI58k~|AIzz#@&SreP2QDI3`GLs&q>f&CF)cl-4Rv&lh{nrd(M)F5 zIN4rCqgeLg=`lSXRE>m~Vw2s&-3%5hB4!y@cIKx)6fD|Nm(YIyPzJ^4*b)!@@l%xr zC`sl`zjHQtgOY!R%fd2LE{-KYZVX~xr`9`gA9>V*wUNZK;%jh zk<9*avb~H*Q9h=Gb+~eZjd0gBoUqi(uKy^Y@xWIJjX%lIct6b@F zvenUOO6fLEmQ+x>H^`VOR=TafM)!z$1EwOSOIZQjvW84%etIqZtF(o@z*OoL#5qsM zm}(tc;>qwJ^ykI+3Ze1XSy<(LGF6OhCbs7ivSylC$~k2#{dO ziN6x}Fit?BZbXOB3S4#4Rm4?)6}gH6zJso&r9HQ2po;vfUDusRQ9|2N>KZa2mKKJ( z8R@3w*UhHVvB$FK<`@08A`Q2QY?K*1PPV!Gs zPmySai@sCNMV#!8!$rmPE1ma5))m?ZM@vz(!?cAaxM;6$5UcdvBP7izZ7{-?_HV<9 z{h^3P7FKYwy^IF#49xcph+ZuED_xtNpFv8;U^594+h8D34s6(jtSR~M3%*H+%#b1S zAY0;TO#D=3NA~V=pM#UFj!09EY~y@r1)t+yk+HJuLF=#46UHJrmlYp9(G3j!vYW{c zKJ_hPs$FDEWnNE9JjdJ$Q{7X}RGe&wn5uEIx&l+(Co)y$$hQ6(-NRHxM^;o;%#n?i zm1^j^ksbD9fjA1R5=VB)jl??7l5y1s*%F<~OForV)z3sYvYay~Tb--A2aaZQ&bWND zXvgI_=lj1+P%M-|vG+~1#Lti6%gRvvT!bRC#xy0>T;U+nY%=!CUKv-YT}4rDx&30al7A2 zO!XESQ@w#Ly|0bP=K&FoOk;Ag)tRb$(CAD-<-FSnkrgsTe#Vym(S|$mu!snGcX4AD zC)>-26urANO^L?t8g2kYZor`ME}9a4cJi93Q>rCDYIIU7PgW-(=7I>FwEViW4lM7e=@+EDThfeT?)- z(=l~E^a90E!qQXCX~aNz+9%j^AKiwx@;gy#Guz0?R#!gVBeg}_Sjc=Bj;33hPG`Ev zHX62)8*`LoJ}Aj6mhcX~n|OSWdnHGjPh?A90UNRYxCXX>W-E$j)lT3@XF+GBFiy6Y z;V4m}Y|IfFgLTVvsdlRCaO91q=AHlK9zx?SGBozOmzJ(<0}V?=BWuOxWP2HnvR3SL z>XfP5ae;gKR_wx%(6#r`t{<5ILfT5?aZk*B>;Y*RU=s87OaoWEVc}ny`+!r8DTL@% zhqJ8=;NUJsBDqQ4Lu+={xsdnx>W^p}Ps(j$>Ty2Gmj2L2K=i1n^fN8P$@Vf|7qv{W zRI1~oiiv4Dq-8W0L+M#LE(wTA3-0rNOlX`bqCu|16Kv_J1PyFk=UpBXH{ao=J9s=1 zF6CBq+@pnKWnn$CFis)xN(TZJTnF_h^h*5FLws2|Zh5kti#XXGhl_Y-IPMHb+z4r> zn^H8J<|g3I(Iy=J6Mjlte!a|A-N2SEZo^iMinc0~X-;;>K_hkKQd4ChR}To#P>ue+ zrtYoT^L|3(Mp358tsZ7e{MN2kWaDq5Y-CA5PPUiP=u8su3l9(?H^~tBC0jbBjX>uw zA|hF!!^!qCBE>)l+DaQVl)*$>VS+0f&5|S_0v(+uzBEh%>c1d3ZV}-iqxUFV$~6vm z-smZ6sCXC|gbKAD;hr|QSalWmZAYq$;iw7}K~}~~)k6~Jiyo+6p1h>-rSz%J3ms2h zYRuRJH+k|hhk3Dt_P1XWjz5>-c*TRXlxwo=JdR#q*@1>k4Vq3>HF7Mk4i`qZea)$> zN9eZw`AHyqDc3yr|o^<78TV;XT%xOmeG)}ZtNV+~PYPBrs+WKpBPx_|l z$rno-C^}PHKULv%cwx9ewwZ3IXFo(7zuSG1rpJISo!Ewr*>(4OJ^<={siU0@ui|8@ zGgbGXQS4jEDcNKo1BQx|jj>G)?c=$VJ7@|f*NhgYWYf-hnDBUx43B%+(mQ}hGubp* zrr~)a9+?-$$@VfHf)~aCLG=nK;P@0~Gt+!3Of=9;6IX$zMxVkL`~`zFC5XK4*M!J? z86p#GiH3i+ipcHdY8PZnCq0#D#8>t8J;sDBHSoz~6n-!T^7p$;8ndRpDyLJPLJDh_ jn@0NjUXN|rXM*0GHi$l(C)TalHf!bD4YOg*EY18s!pkWV literal 0 HcmV?d00001 diff --git a/mysql-test/t/mysqlbinlog.test b/mysql-test/t/mysqlbinlog.test index 451eef17108..c83fe94f2eb 100644 --- a/mysql-test/t/mysqlbinlog.test +++ b/mysql-test/t/mysqlbinlog.test @@ -237,4 +237,8 @@ let $c= `select $a=$b`; --echo $c drop table t1; +echo shell> mysqlbinlog std_data/corrupt-relay-bin.000624 > var/tmp/bug31793.sql; +error 1; +exec $MYSQL_BINLOG $MYSQL_TEST_DIR/std_data/corrupt-relay-bin.000624 > $MYSQLTEST_VARDIR/tmp/bug31793.sql; + --echo End of 5.0 tests diff --git a/sql/log_event.cc b/sql/log_event.cc index 3899e772bf8..0e257bf7f6c 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1400,17 +1400,46 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, /* 2 utility functions for the next method */ -/* - Get the pointer for a string (src) that contains the length in - the first byte. Set the output string (dst) to the string value - and place the length of the string in the byte after the string. +/** + Read a string with length from memory. + + This function reads the string-with-length stored at + src and extract the length into *len and + a pointer to the start of the string into *dst. The + string can then be copied using memcpy() with the + number of bytes given in *len. + + @param src Pointer to variable holding a pointer to the memory to + read the string from. + @param dst Pointer to variable holding a pointer where the actual + string starts. Starting from this position, the string + can be copied using @c memcpy(). + @param len Pointer to variable where the length will be stored. + @param end One-past-the-end of the memory where the string is + stored. + + @return Zero if the entire string can be copied successfully, + @c UINT_MAX if the length could not be read from memory + (that is, if *src >= end), otherwise the + number of bytes that are missing to read the full + string, which happends *dst + *len >= end. */ -static void get_str_len_and_pointer(const Log_event::Byte **src, - const char **dst, - uint *len) +static int +get_str_len_and_pointer(const Log_event::Byte **src, + const char **dst, + uint *len, + const Log_event::Byte *end) { - if ((*len= **src)) - *dst= (char *)*src + 1; // Will be copied later + if (*src >= end) + return -1; // Will be UINT_MAX in two-complement arithmetics + uint length= **src; + if (length > 0) + { + if (*src + length >= end) + return *src + length - end; // Number of bytes missing + *dst= (char *)*src + 1; // Will be copied later + } + *len= length; (*src)+= *len + 1; } @@ -1424,6 +1453,23 @@ static void copy_str_and_move(const char **src, *(*dst)++= 0; } + +/** + Macro to check that there is enough space to read from memory. + + @param PTR Pointer to memory + @param END End of memory + @param CNT Number of bytes that should be read. + */ +#define CHECK_SPACE(PTR,END,CNT) \ + do { \ + DBUG_ASSERT((PTR) + (CNT) <= (END)); \ + if ((PTR) + (CNT) > (END)) { \ + query= 0; \ + DBUG_VOID_RETURN; \ + } \ + } while (0) + /* Query_log_event::Query_log_event() This is used by the SQL slave thread to prepare the event before execution. @@ -1475,6 +1521,17 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, if (tmp) { status_vars_len= uint2korr(buf + Q_STATUS_VARS_LEN_OFFSET); + /* + Check if status variable length is corrupt and will lead to very + wrong data. We could be even more strict and require data_len to + be even bigger, but this will suffice to catch most corruption + errors that can lead to a crash. + */ + if (status_vars_len >= min(data_len + 1, MAX_SIZE_LOG_EVENT_STATUS)) + { + query= 0; + DBUG_VOID_RETURN; + } data_len-= status_vars_len; DBUG_PRINT("info", ("Query_log_event has status_vars_len: %u", (uint) status_vars_len)); @@ -1494,6 +1551,7 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, { switch (*pos++) { case Q_FLAGS2_CODE: + CHECK_SPACE(pos, end, 4); flags2_inited= 1; flags2= uint4korr(pos); DBUG_PRINT("info",("In Query_log_event, read flags2: %lu", (ulong) flags2)); @@ -1504,6 +1562,7 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, #ifndef DBUG_OFF char buff[22]; #endif + CHECK_SPACE(pos, end, 8); sql_mode_inited= 1; sql_mode= (ulong) uint8korr(pos); // QQ: Fix when sql_mode is ulonglong DBUG_PRINT("info",("In Query_log_event, read sql_mode: %s", @@ -1512,15 +1571,21 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, break; } case Q_CATALOG_NZ_CODE: - get_str_len_and_pointer(&pos, &catalog, &catalog_len); + if (get_str_len_and_pointer(&pos, &catalog, &catalog_len, end)) + { + query= 0; + DBUG_VOID_RETURN; + } break; case Q_AUTO_INCREMENT: + CHECK_SPACE(pos, end, 4); auto_increment_increment= uint2korr(pos); auto_increment_offset= uint2korr(pos+2); pos+= 4; break; case Q_CHARSET_CODE: { + CHECK_SPACE(pos, end, 6); charset_inited= 1; memcpy(charset, pos, 6); pos+= 6; @@ -1528,20 +1593,28 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, } case Q_TIME_ZONE_CODE: { - get_str_len_and_pointer(&pos, &time_zone_str, &time_zone_len); + if (get_str_len_and_pointer(&pos, &time_zone_str, &time_zone_len, end)) + { + query= 0; + DBUG_VOID_RETURN; + } break; } case Q_CATALOG_CODE: /* for 5.0.x where 0<=x<=3 masters */ + CHECK_SPACE(pos, end, 1); if ((catalog_len= *pos)) catalog= (char*) pos+1; // Will be copied later + CHECK_SPACE(pos, end, catalog_len + 2); pos+= catalog_len+2; // leap over end 0 catalog_nz= 0; // catalog has end 0 in event break; case Q_LC_TIME_NAMES_CODE: + CHECK_SPACE(pos, end, 2); lc_time_names_number= uint2korr(pos); pos+= 2; break; case Q_CHARSET_DATABASE_CODE: + CHECK_SPACE(pos, end, 2); charset_database_number= uint2korr(pos); pos+= 2; break; From 66db290abd17a3fb1b398278f8cc67a1589389f7 Mon Sep 17 00:00:00 2001 From: "mleich@five.local.lan" <> Date: Fri, 9 Nov 2007 14:08:12 +0100 Subject: [PATCH 191/336] Fix for Bug#32153 Status output differs - scheduling ? Modifications: 1. Introduce additional poll routines + adjust queries as fixes for Bug#32153 and another non reported bug found during stability testing 2. Replace builtin poll routines by wait_condition.inc. 3. Update the comments --- .../funcs_1/datadict/processlist_val.inc | 123 ++++++++---------- .../r/a_processlist_val_no_prot.result | 8 +- .../funcs_1/r/b_processlist_val_ps.result | 8 +- 3 files changed, 62 insertions(+), 77 deletions(-) diff --git a/mysql-test/suite/funcs_1/datadict/processlist_val.inc b/mysql-test/suite/funcs_1/datadict/processlist_val.inc index da2c2950095..62e5d95f875 100644 --- a/mysql-test/suite/funcs_1/datadict/processlist_val.inc +++ b/mysql-test/suite/funcs_1/datadict/processlist_val.inc @@ -94,14 +94,25 @@ connect (ddicttestuser1,localhost,ddicttestuser1,ddictpass,information_schema); --echo ----- switch to connection default (user = root) ----- connection default; # - We have now a second connection. -# - important values in second connection +# First working phase for this connection is "Connect". +# This is a very short phase and the likelihood to meet it is +# - nearly zero on average boxes with low parallel load +# - around some percent on weak or overloaded boxes +# (Bug#32153 Status output differs - scheduling ?) +# Therefore we poll till we reach the long lasting phase with: # - USER = ddicttestuser1 # - HOST = 'localhost' # - DB = 'information_schema' # - Command = 'Sleep' -# - TIME = 0, I hope the testing machines are all time fast enough +# - TIME >= 0 Overloaded boxes can cause that we do not hit TIME = 0. # - State IS NULL # - INFO must be empty +# +let $wait_condition= SELECT COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST + WHERE COMMAND = 'Sleep' AND TIME > 0; +--source include/wait_condition.inc +# +# Expect to hit TIME = 1. --replace_column 1 SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST; # Change the SQL command (affects content of INFO) @@ -109,25 +120,19 @@ SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST; SHOW FULL PROCESSLIST; # --echo # Sleep some time -# The value of TIME must increase after some sleeps. -# So poll till TIME changes. -let $run= 10; -while ($run) -{ - dec $run; - if (`SELECT COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST - WHERE ID = @my_proclist_id + 1 AND TIME > 0`) - { - let $run= 0; - } - --real_sleep 0.2 -} -# Either we have now reached TIME = 1 or we fail with unexpected result. -# Expect to see now TIME = 1 +# The value of TIME must increase and reach 2 after some sleeps. +let $wait_timeout= 2; +let $wait_condition= SELECT COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST + WHERE TIME > 1; +--source include/wait_condition.inc +# +# Expect to hit TIME = 2. --replace_column 1 SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST; --replace_column 1 SHOW FULL PROCESSLIST; +# +# # The second connection must have an ID = my ID + 1; SELECT ID = @my_proclist_id + 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'ddicttestuser1'; @@ -150,6 +155,12 @@ SHOW FULL PROCESSLIST; --echo --echo ----- establish connection con2 (user = ddicttestuser1) ------ connect (con2,localhost,ddicttestuser1,ddictpass,information_schema); +# +# If the testing box is under heavy load we might see connection ddicttestuser1 +# within the short phase INFO = 'SHOW FULL PROCESSLIST' and STATE = 'Writing to net'. +let $wait_condition= SELECT COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST + WHERE COMMAND = 'Sleep'; +--source include/wait_condition.inc --replace_column 1 6