From 7e66213444a5af73879b57ad0b5bd7476b5c6f4d Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Tue, 23 Aug 2011 19:28:32 +0400 Subject: [PATCH 001/289] MWL#182: Explain running statements First code - "Asynchronous procedure call" system - new THD::check_killed() that serves APC request is called from within most important loops - EXPLAIN code is now able to generate EXPLAIN output on-the-fly [incomplete] Parts that are still missing: - put THD::check_killed() call into every loop where we could spend significant amount of time - Make sure EXPLAIN code works for group-by queries that replace JOIN::join_tab with make_simple_join() and other such cases. - User interface: what error code to use, where to get timeout settings from, etc. --- libmysqld/Makefile.am | 2 +- sql/Makefile.am | 7 +- sql/my_apc.cc | 355 ++++++++++++++++++++++++++++++++++++++++++ sql/my_apc.h | 98 ++++++++++++ sql/mysql_priv.h | 2 + sql/mysqld.cc | 1 + sql/protocol.h | 19 +++ sql/sp_head.cc | 1 + sql/sql_class.cc | 119 +++++++++++++- sql/sql_class.h | 94 ++++++++++- sql/sql_lex.cc | 34 ++++ sql/sql_lex.h | 6 + sql/sql_parse.cc | 27 ++++ sql/sql_prepare.cc | 1 + sql/sql_select.cc | 81 +++++++--- sql/sql_select.h | 7 +- sql/sql_show.cc | 91 +++++++++++ sql/sql_yacc.yy | 6 + 18 files changed, 915 insertions(+), 36 deletions(-) create mode 100644 sql/my_apc.cc create mode 100644 sql/my_apc.h diff --git a/libmysqld/Makefile.am b/libmysqld/Makefile.am index bf2231f47a1..980de9a08ba 100644 --- a/libmysqld/Makefile.am +++ b/libmysqld/Makefile.am @@ -81,7 +81,7 @@ sqlsources = derror.cc field.cc field_conv.cc strfunc.cc filesort.cc \ rpl_injector.cc my_user.c partition_info.cc \ sql_servers.cc event_parse_data.cc opt_table_elimination.cc \ multi_range_read.cc opt_index_cond_pushdown.cc \ - sql_expression_cache.cc + sql_expression_cache.cc my_apc.cc # automake misses these sql_yacc.cc sql_yacc.h: $(top_srcdir)/sql/sql_yacc.yy diff --git a/sql/Makefile.am b/sql/Makefile.am index cde8962b8d0..8ef828dd243 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -84,7 +84,8 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \ multi_range_read.h sql_handler.h \ sql_join_cache.h \ create_options.h \ - sql_expression_cache.h + sql_expression_cache.h \ + my_apc.h mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \ item.cc item_sum.cc item_buff.cc item_func.cc \ @@ -134,7 +135,9 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \ sql_servers.cc event_parse_data.cc \ opt_table_elimination.cc create_options.cc \ multi_range_read.cc \ - opt_index_cond_pushdown.cc sql_expression_cache.cc + opt_index_cond_pushdown.cc sql_expression_cache.cc \ + my_apc.cc + nodist_mysqld_SOURCES = mini_client_errors.c pack.c client.c my_time.c my_user.c client_plugin.c diff --git a/sql/my_apc.cc b/sql/my_apc.cc new file mode 100644 index 00000000000..3842947f3bb --- /dev/null +++ b/sql/my_apc.cc @@ -0,0 +1,355 @@ +/* + TODO: MP AB Copyright +*/ + + +#ifdef MY_APC_STANDALONE + +#include +#include +#include + +#else + +#include "mysql_priv.h" + +#endif + +//#include "my_apc.h" + +/* + Standalone testing: + g++ -c -DMY_APC_STANDALONE -g -I.. -I../include -o my_apc.o my_apc.cc + g++ -L../mysys -L../dbug -L../strings my_apc.o -lmysys -ldbug -lmystrings -lpthread -lrt +*/ + + +void Apc_target::init() +{ + // todo: should use my_pthread_... functions instead? + DBUG_ASSERT(!enabled); + (void)pthread_mutex_init(&LOCK_apc_queue, MY_MUTEX_INIT_SLOW); +} + + +void Apc_target::destroy() +{ + DBUG_ASSERT(!enabled); + pthread_mutex_destroy(&LOCK_apc_queue); +} + + +void Apc_target::enable() +{ + pthread_mutex_lock(&LOCK_apc_queue); + enabled++; + pthread_mutex_unlock(&LOCK_apc_queue); +} + + +void Apc_target::disable() +{ + bool process= FALSE; + pthread_mutex_lock(&LOCK_apc_queue); + if (!(--enabled)) + process= TRUE; + pthread_mutex_unlock(&LOCK_apc_queue); + if (process) + process_apc_requests(); +} + +void Apc_target::enqueue_request(Call_request *qe) +{ + //call_queue_size++; + if (apc_calls) + { + Call_request *after= apc_calls->prev; + qe->next= apc_calls; + apc_calls->prev= qe; + + qe->prev= after; + after->next= qe; + } + else + { + apc_calls= qe; + qe->next= qe->prev= qe; + } +} + +void Apc_target::dequeue_request(Call_request *qe) +{ + //call_queue_size--; + if (apc_calls == qe) + { + if ((apc_calls= apc_calls->next) == qe) + { + //DBUG_ASSERT(!call_queue_size); + apc_calls= NULL; + } + } + + qe->prev->next= qe->next; + qe->next->prev= qe->prev; +} + + +/* + Make an apc call in another thread. The caller is responsible so + that we're not calling to ourselves. + +*/ + +bool Apc_target::make_apc_call(apc_func_t func, void *func_arg, + int timeout_sec, bool *timed_out) +{ + bool res= TRUE; + *timed_out= FALSE; + + pthread_mutex_lock(&LOCK_apc_queue); + if (enabled) + { + /* Create and post the request */ + Call_request apc_request; + apc_request.func= func; + apc_request.func_arg= func_arg; + apc_request.done= FALSE; + (void)pthread_cond_init(&apc_request.COND_request, NULL); + (void)pthread_mutex_init(&apc_request.LOCK_request, MY_MUTEX_INIT_SLOW); + pthread_mutex_lock(&apc_request.LOCK_request); + enqueue_request(&apc_request); + apc_request.what="enqueued by make_apc_call"; + pthread_mutex_unlock(&LOCK_apc_queue); + + struct timespec abstime; + const int timeout= timeout_sec; + set_timespec(abstime, timeout); + + int wait_res= 0; + /* todo: how about processing other errors here? */ + while (!apc_request.done && (wait_res != ETIMEDOUT)) + { + wait_res= pthread_cond_timedwait(&apc_request.COND_request, + &apc_request.LOCK_request, &abstime); + } + + if (!apc_request.done) + { + /* We timed out */ + apc_request.done= TRUE; + *timed_out= TRUE; + pthread_mutex_unlock(&apc_request.LOCK_request); + + pthread_mutex_lock(&LOCK_apc_queue); + dequeue_request(&apc_request); + pthread_mutex_unlock(&LOCK_apc_queue); + res= TRUE; + } + else + { + /* Request was successfully executed and dequeued by the target thread */ + pthread_mutex_unlock(&apc_request.LOCK_request); + res= FALSE; + } + + /* Destroy all APC request data */ + pthread_mutex_destroy(&apc_request.LOCK_request); + pthread_cond_destroy(&apc_request.COND_request); + } + else + { + pthread_mutex_unlock(&LOCK_apc_queue); + } + return res; +} + + +/* + Process all APC requests +*/ + +void Apc_target::process_apc_requests() +{ + while (1) + { + Call_request *request; + + pthread_mutex_lock(&LOCK_apc_queue); + if (!(request= get_first_in_queue())) + { + pthread_mutex_unlock(&LOCK_apc_queue); + break; + } + + request->what="seen by process_apc_requests"; + pthread_mutex_lock(&request->LOCK_request); + + if (request->done) + { + /* + We can get here when + - the requestor thread has been waiting for this request + - the wait has timed out + - it has set request->done=TRUE + - it has released LOCK_request, because its next action + will be to remove the request from the queue, however, + it could not attempt to lock the queue while holding the lock on + request, because that would deadlock with this function + (we here first lock the queue and then lock the request) + */ + pthread_mutex_unlock(&request->LOCK_request); + pthread_mutex_unlock(&LOCK_apc_queue); + fprintf(stderr, "Whoa rare event #1!\n"); + continue; + } + /* + Remove the request from the queue (we're holding its lock so we can be + sure that request owner won't try to remove it) + */ + request->what="dequeued by process_apc_requests"; + dequeue_request(request); + request->done= TRUE; + + pthread_mutex_unlock(&LOCK_apc_queue); + + request->func(request->func_arg); + request->what="func called by process_apc_requests"; + + pthread_cond_signal(&request->COND_request); + + pthread_mutex_unlock(&request->LOCK_request); + } +} + +/***************************************************************************** + * Testing + *****************************************************************************/ +#ifdef MY_APC_STANDALONE + +volatile bool started= FALSE; +volatile bool service_should_exit= FALSE; +volatile bool requestors_should_exit=FALSE; + +volatile int apcs_served= 0; +volatile int apcs_missed=0; +volatile int apcs_timed_out=0; + +Apc_target apc_target; + +int int_rand(int size) +{ + return round (((double)rand() / RAND_MAX) * size); +} + +/* An APC-serving thread */ +void *test_apc_service_thread(void *ptr) +{ + my_thread_init(); + apc_target.init(); + apc_target.enable(); + started= TRUE; + fprintf(stderr, "# test_apc_service_thread started\n"); + while (!service_should_exit) + { + //apc_target.disable(); + usleep(10000); + //apc_target.enable(); + for (int i = 0; i < 10 && !service_should_exit; i++) + { + apc_target.process_apc_requests(); + usleep(int_rand(30)); + } + } + apc_target.disable(); + apc_target.destroy(); + my_thread_end(); + pthread_exit(0); +} + +class Apc_order +{ +public: + int value; // The value + int *where_to; // Where to write it + Apc_order(int a, int *b) : value(a), where_to(b) {} +}; + +void test_apc_func(void *arg) +{ + Apc_order *order=(Apc_order*)arg; + usleep(int_rand(1000)); + *(order->where_to) = order->value; + __sync_fetch_and_add(&apcs_served, 1); +} + +void *test_apc_requestor_thread(void *ptr) +{ + my_thread_init(); + fprintf(stderr, "# test_apc_requestor_thread started\n"); + while (!requestors_should_exit) + { + int dst_value= 0; + int src_value= int_rand(4*1000*100); + /* Create APC to do dst_value= src_value */ + Apc_order apc_order(src_value, &dst_value); + bool timed_out; + + bool res= apc_target.make_apc_call(test_apc_func, (void*)&apc_order, 60, &timed_out); + if (res) + { + if (timed_out) + __sync_fetch_and_add(&apcs_timed_out, 1); + else + __sync_fetch_and_add(&apcs_missed, 1); + + if (dst_value != 0) + fprintf(stderr, "APC was done even though return value says it wasnt!\n"); + } + else + { + if (dst_value != src_value) + fprintf(stderr, "APC was not done even though return value says it was!\n"); + } + //usleep(300); + } + fprintf(stderr, "# test_apc_requestor_thread exiting\n"); + my_thread_end(); +} + +const int N_THREADS=23; +int main(int args, char **argv) +{ + pthread_t service_thr; + pthread_t request_thr[N_THREADS]; + int i, j; + my_thread_global_init(); + + pthread_create(&service_thr, NULL, test_apc_service_thread, (void*)NULL); + while (!started) + usleep(1000); + for (i = 0; i < N_THREADS; i++) + pthread_create(&request_thr[i], NULL, test_apc_requestor_thread, (void*)NULL); + + for (i = 0; i < 15; i++) + { + usleep(500*1000); + fprintf(stderr, "# %d APCs served %d missed\n", apcs_served, apcs_missed); + } + fprintf(stderr, "# Shutting down requestors\n"); + requestors_should_exit= TRUE; + for (i = 0; i < N_THREADS; i++) + pthread_join(request_thr[i], NULL); + + fprintf(stderr, "# Shutting down service\n"); + service_should_exit= TRUE; + pthread_join(service_thr, NULL); + fprintf(stderr, "# Done.\n"); + my_thread_end(); + my_thread_global_end(); + return 0; +} + +#endif // MY_APC_STANDALONE + + + diff --git a/sql/my_apc.h b/sql/my_apc.h new file mode 100644 index 00000000000..3783bd28f54 --- /dev/null +++ b/sql/my_apc.h @@ -0,0 +1,98 @@ +/* + TODO: MP AB Copyright +*/ + +/* + Design + - Mutex-guarded request queue (it belongs to the target), which can be enabled/ + disabled (when empty). + + - After the request has been put into queue, the requestor waits for request + to be satisfied. The worker satisifes the request and signals the + requestor. +*/ + +/* + Target for asynchronous calls. +*/ +class Apc_target +{ +public: + Apc_target() : enabled(0), apc_calls(NULL) /*, call_queue_size(0)*/ {} + ~Apc_target() { DBUG_ASSERT(!enabled && !apc_calls);} + + /* + Initialize the target. This must be called before anything else. Right + after initialization, the target is disabled. + */ + void init(); + + /* + Destroy the target. The target must be disabled when this call is made. + */ + void destroy(); + + /* + Enter into state where this target will be serving APC requests + */ + void enable(); + + /* + Leave the state where we could serve APC requests (will serve all already + enqueued requests) + */ + void disable(); + + /* + This should be called periodically to serve observation requests. + */ + void process_apc_requests(); + + typedef void (*apc_func_t)(void *arg); + + /* + Make an APC call: schedule it for execution and wait until the target + thread has executed it. This function must not be called from a thread + that's different from the target thread. + + @retval FALSE - Ok, the call has been made + @retval TRUE - Call wasnt made (either the target is in disabled state or + timeout occured) + */ + bool make_apc_call(apc_func_t func, void *func_arg, + int timeout_sec, bool *timed_out); + +private: + class Call_request; + int enabled; + + Call_request *apc_calls; + pthread_mutex_t LOCK_apc_queue; + //int call_queue_size; + + class Call_request + { + public: + apc_func_t func; + void *func_arg; + bool done; + + pthread_mutex_t LOCK_request; + pthread_cond_t COND_request; + + Call_request *next; + Call_request *prev; + + const char *what; + }; + + void enqueue_request(Call_request *qe); + void dequeue_request(Call_request *qe); + Call_request *get_first_in_queue() + { + return apc_calls; + } +}; + +/////////////////////////////////////////////////////////////////////// + diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 24e637df497..a19cca31d1c 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -803,6 +803,7 @@ typedef my_bool (*qc_engine_callback)(THD *thd, char *table_key, ulonglong *engine_data); #include "sql_string.h" #include "my_decimal.h" +#include "my_apc.h" /* to unify the code that differs only in the argument passed to the @@ -1544,6 +1545,7 @@ bool mysqld_show_create(THD *thd, TABLE_LIST *table_list); bool mysqld_show_create_db(THD *thd, char *dbname, HA_CREATE_INFO *create); void mysqld_list_processes(THD *thd,const char *user,bool verbose); +void mysqld_show_explain(THD *thd, ulong thread_id); int mysqld_show_status(THD *thd); int mysqld_show_variables(THD *thd,const char *wild); bool mysqld_show_storage_engines(THD *thd); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 1c9b6a19d38..04439b470ce 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -3430,6 +3430,7 @@ SHOW_VAR com_status_vars[]= { {"show_engine_status", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_ENGINE_STATUS]), SHOW_LONG_STATUS}, {"show_events", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_EVENTS]), SHOW_LONG_STATUS}, {"show_errors", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_ERRORS]), SHOW_LONG_STATUS}, + {"show_explain", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_EXPLAIN]), SHOW_LONG_STATUS}, {"show_fields", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_FIELDS]), SHOW_LONG_STATUS}, #ifndef DBUG_OFF {"show_function_code", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_FUNC_CODE]), SHOW_LONG_STATUS}, diff --git a/sql/protocol.h b/sql/protocol.h index e07af5208db..7a882e8a10d 100644 --- a/sql/protocol.h +++ b/sql/protocol.h @@ -28,6 +28,7 @@ class Protocol protected: THD *thd; String *packet; + /* Used by net_store_data() for charset conversions */ String *convert; uint field_pos; #ifndef DBUG_OFF @@ -42,6 +43,10 @@ protected: MYSQL_FIELD *next_mysql_field; MEM_ROOT *alloc; #endif + /* + The following two are low-level functions that are invoked from + higher-level store_xxx() funcs. The data is stored into this->packet. + */ bool net_store_data(const uchar *from, size_t length, CHARSET_INFO *fromcs, CHARSET_INFO *tocs); bool store_string_aux(const char *from, size_t length, @@ -55,6 +60,20 @@ public: enum { SEND_NUM_ROWS= 1, SEND_DEFAULTS= 2, SEND_EOF= 4 }; virtual bool send_fields(List *list, uint flags); + void get_packet(const char **start, size_t *length) + { + *start= packet->ptr(); + *length= packet->length(); + } + void set_packet(const char *start, size_t len) + { + packet->length(0); + packet->append(start, len); +#ifndef DBUG_OFF + field_pos= field_count - 1; +#endif + } + bool store(I_List *str_list); bool store(const char *from, CHARSET_INFO *cs); String *storage_packet() { return packet; } diff --git a/sql/sp_head.cc b/sql/sp_head.cc index bd2dcfd8653..93743c2985b 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -204,6 +204,7 @@ sp_get_flags_for_command(LEX *lex) case SQLCOM_SHOW_CREATE_TRIGGER: case SQLCOM_SHOW_DATABASES: case SQLCOM_SHOW_ERRORS: + case SQLCOM_SHOW_EXPLAIN: case SQLCOM_SHOW_FIELDS: case SQLCOM_SHOW_FUNC_CODE: case SQLCOM_SHOW_GRANTS: diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 9bb1f83b06d..12709e23a34 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -964,6 +964,7 @@ void THD::init(void) /* Initialize the Debug Sync Facility. See debug_sync.cc. */ debug_sync_init_thread(this); #endif /* defined(ENABLED_DEBUG_SYNC) */ + apc_target.init(); } @@ -1122,7 +1123,8 @@ void THD::cleanup(void) pthread_mutex_unlock(&LOCK_user_locks); ull= NULL; } - + + apc_target.destroy(); cleanup_done=1; DBUG_VOID_RETURN; } @@ -1666,6 +1668,14 @@ CHANGED_TABLE_LIST* THD::changed_table_dup(const char *key, long key_length) int THD::send_explain_fields(select_result *result) { List field_list; + make_explain_field_list(field_list); + return (result->send_fields(field_list, + Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)); +} + + +void THD::make_explain_field_list(List &field_list) +{ Item *item; CHARSET_INFO *cs= system_charset_info; field_list.push_back(new Item_return_int("id",3, MYSQL_TYPE_LONGLONG)); @@ -1703,10 +1713,9 @@ int THD::send_explain_fields(select_result *result) } item->maybe_null= 1; field_list.push_back(new Item_empty_string("Extra", 255, cs)); - return (result->send_fields(field_list, - Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)); } + #ifdef SIGNAL_WITH_VIO_CLOSE void THD::close_active_vio() { @@ -1810,6 +1819,21 @@ void THD::rollback_item_tree_changes() } +/* + Check if the thread has been killed, and also process "APC requests" + + @retval true The thread is killed, execution should be interrupted + @retval false Not killed, continue execution +*/ + +bool THD::check_killed() +{ + if (killed) + return TRUE; + apc_target.process_apc_requests(); + return FALSE; +} + /***************************************************************************** ** Functions to provide a interface to select results *****************************************************************************/ @@ -1950,6 +1974,68 @@ int select_send::send_data(List &items) DBUG_RETURN(0); } + +////////////////////////////////////////////////////////////////////////////// +int select_result_explain_buffer::send_data(List &items) +{ + List_iterator_fast li(items); + char buff[MAX_FIELD_WIDTH]; + String buffer(buff, sizeof(buff), &my_charset_bin); + DBUG_ENTER("select_send::send_data"); + + protocol->prepare_for_resend(); + Item *item; + while ((item=li++)) + { + if (item->send(protocol, &buffer)) + { + protocol->free(); // Free used buffer + my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); + break; + } + /* + Reset buffer to its original state, as it may have been altered in + Item::send(). + */ + buffer.set(buff, sizeof(buff), &my_charset_bin); + } + //TODO: do we need the following: + if (thd->is_error()) + { + protocol->remove_last_row(); + DBUG_RETURN(1); + } + /* psergey-TODO: instead of protocol->write(), steal the packet here */ + const char *packet_data; + size_t len; + protocol->get_packet(&packet_data, &len); + + String *s= new (thd->mem_root) String; + s->append(packet_data, len); + data_rows.push_back(s); + protocol->remove_last_row(); // <-- this does nothing. Do we need it? + // prepare_for_resend() will wipe out the packet + DBUG_RETURN(0); +} + + +void select_result_explain_buffer::flush_data() +{ + List_iterator it(data_rows); + String *str; + while ((str= it++)) + { + /* TODO: write out the lines. */ + protocol->set_packet(str->ptr(), str->length()); + protocol->write(); + delete str; + } + data_rows.empty(); +} + +////////////////////////////////////////////////////////////////////////////// + + bool select_send::send_eof() { /* @@ -2810,6 +2896,10 @@ void THD::end_statement() } +/* + Start using arena specified by @set. Current arena data will be saved to + *backup. +*/ void THD::set_n_backup_active_arena(Query_arena *set, Query_arena *backup) { DBUG_ENTER("THD::set_n_backup_active_arena"); @@ -2824,6 +2914,12 @@ void THD::set_n_backup_active_arena(Query_arena *set, Query_arena *backup) } +/* + Stop using the temporary arena, and start again using the arena that is + specified in *backup. + The temporary arena is returned back into *set. +*/ + void THD::restore_active_arena(Query_arena *set, Query_arena *backup) { DBUG_ENTER("THD::restore_active_arena"); @@ -2836,6 +2932,23 @@ void THD::restore_active_arena(Query_arena *set, Query_arena *backup) DBUG_VOID_RETURN; } +// psergey +void Show_explain_request::get_explain_data(void *arg) +{ + Show_explain_request *req= (Show_explain_request*)arg; + //TODO: change mem_root to point to request_thd->mem_root. + // Actually, change the ARENA, because we're going to allocate items! + Query_arena backup_arena; + req->target_thd->set_n_backup_active_arena((Query_arena*)req->request_thd, + &backup_arena); + + req->target_thd->lex->unit.print_explain(req->explain_buf); + + req->target_thd->restore_active_arena((Query_arena*)req->request_thd, + &backup_arena); +} + + Statement::~Statement() { } diff --git a/sql/sql_class.h b/sql/sql_class.h index c97cc34e166..5d55d7182fc 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1420,6 +1420,19 @@ struct Ha_data }; +class select_result_explain_buffer; + +class Show_explain_request +{ +public: + THD *target_thd; + THD *request_thd; + + select_result_explain_buffer *explain_buf; + + static void get_explain_data(void *arg); +}; + /** @class THD For each client connection we create a separate thread with THD serving as @@ -1990,6 +2003,8 @@ public: }; killed_state volatile killed; + bool check_killed(); + /* scramble - random string sent to client on handshake */ char scramble[SCRAMBLE_LENGTH+1]; @@ -2171,6 +2186,16 @@ public: void close_active_vio(); #endif void awake(THD::killed_state state_to_set); + + + /* + This is what allows this thread to serve as a target for others to + schedule Async Procedure Calls on. + + It's possible to schedule arbitrary C function call but currently this + facility is used only by SHOW EXPLAIN code (See Show_explain_request) + */ + Apc_target apc_target; #ifndef MYSQL_CLIENT enum enum_binlog_query_type { @@ -2302,6 +2327,7 @@ public: void add_changed_table(const char *key, long key_length); CHANGED_TABLE_LIST * changed_table_dup(const char *key, long key_length); int send_explain_fields(select_result *result); + void make_explain_field_list(List &field_list); #ifndef EMBEDDED_LIBRARY /** Clear the current error, if any. @@ -2750,10 +2776,42 @@ public: class JOIN; -class select_result :public Sql_alloc { +/* Pure interface for sending tabular data */ +class select_result_sink: public Sql_alloc +{ +public: + /* + send_data returns 0 on ok, 1 on error and -1 if data was ignored, for + example for a duplicate row entry written to a temp table. + */ + virtual int send_data(List &items)=0; + virtual ~select_result_sink() {}; +}; + + +/* + Interface for sending tabular data, together with some other stuff: + + - Primary purpose seems to be seding typed tabular data: + = the DDL is sent with send_fields() + = the rows are sent with send_data() + Besides that, + - there seems to be an assumption that the sent data is a result of + SELECT_LEX_UNIT *unit, + - nest_level is used by SQL parser +*/ + +class select_result :public select_result_sink +{ protected: THD *thd; + /* + All descendant classes have their send_data() skip the first + unit->offset_limit_cnt rows sent. Select_materialize + also uses unit->get_unit_column_types(). + */ SELECT_LEX_UNIT *unit; + /* Something used only by the parser: */ int nest_level; public: select_result(); @@ -2772,11 +2830,6 @@ public: virtual uint field_count(List &fields) const { return fields.elements; } virtual bool send_fields(List &list, uint flags)=0; - /* - send_data returns 0 on ok, 1 on error and -1 if data was ignored, for - example for a duplicate row entry written to a temp table. - */ - virtual int send_data(List &items)=0; virtual bool initialize_tables (JOIN *join=0) { return 0; } virtual void send_error(uint errcode,const char *err); virtual bool send_eof()=0; @@ -2809,6 +2862,35 @@ public: }; +/* + A select result sink that collects the sent data and then can flush it to + network when requested. + + This class is targeted at collecting EXPLAIN output: + - Unoptimized data storage (can't handle big datasets) + - Unlike select_result class, we don't assume that the sent data is an + output of a SELECT_LEX_UNIT (and so we dont apply "LIMIT x,y" from the + unit) +*/ + +class select_result_explain_buffer : public select_result_sink +{ +public: + THD *thd; + Protocol *protocol; + select_result_explain_buffer(){}; + + /* The following is called in the child thread: */ + int send_data(List &items); + + /* this will be called in the parent thread: */ + void flush_data(); + + List data_rows; +}; + + + /* Base class for select_result descendands which intercept and transform result set rows. As the rows are not sent to the client, diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 021e7a3b5e8..ae9c11c47e2 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -3623,6 +3623,40 @@ bool st_select_lex::save_prep_leaf_tables(THD *thd) } +int st_select_lex::print_explain(select_result_sink *output) +{ + if (join && join->optimized == 2) + { + //psergey-TODO: any? + return join->print_explain(output, TRUE, + FALSE, // need_tmp_table, + FALSE, // bool need_order, + FALSE, // bool distinct, + NULL); //const char *message + } + else + { + DBUG_ASSERT(0); + /* produce "not yet optimized" line */ + } + return 0; +} + + +int st_select_lex_unit::print_explain(select_result_sink *output) +{ + int res= 0; + SELECT_LEX *first= first_select(); + + for (SELECT_LEX *sl= first; sl; sl= sl->next_select()) + { + if ((res= sl->print_explain(output))) + break; + } + return res; +} + + /** A routine used by the parser to decide whether we are specifying a full partitioning or if only partitions to add or to split. diff --git a/sql/sql_lex.h b/sql/sql_lex.h index fe79e6e2908..d5dc4dc3a1f 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -120,6 +120,7 @@ enum enum_sql_command { SQLCOM_SHOW_PROFILE, SQLCOM_SHOW_PROFILES, SQLCOM_SHOW_USER_STATS, SQLCOM_SHOW_TABLE_STATS, SQLCOM_SHOW_INDEX_STATS, SQLCOM_SHOW_CLIENT_STATS, + SQLCOM_SHOW_EXPLAIN, /* When a command is added here, be sure it's also added in mysqld.cc @@ -253,6 +254,8 @@ typedef uchar index_clause_map; #define INDEX_HINT_MASK_ALL (INDEX_HINT_MASK_JOIN | INDEX_HINT_MASK_GROUP | \ INDEX_HINT_MASK_ORDER) +class select_result_sink; + /* Single element of an USE/FORCE/IGNORE INDEX list specified as a SQL hint */ class Index_hint : public Sql_alloc { @@ -591,6 +594,7 @@ public: friend int subselect_union_engine::exec(); List *get_unit_column_types(); + int print_explain(select_result_sink *output); }; typedef class st_select_lex_unit SELECT_LEX_UNIT; @@ -908,6 +912,8 @@ public: bool save_leaf_tables(THD *thd); bool save_prep_leaf_tables(THD *thd); + int print_explain(select_result_sink *output); + private: /* current index hint kind. used in filling up index_hints */ enum index_hint_type current_index_hint_type; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 18dad6cfff0..8e36da5f285 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -328,6 +328,7 @@ void init_update_queries(void) sql_command_flags[SQLCOM_SHOW_ENGINE_STATUS]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_ENGINE_MUTEX]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_ENGINE_LOGS]= CF_STATUS_COMMAND; + sql_command_flags[SQLCOM_SHOW_EXPLAIN]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_PROCESSLIST]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_GRANTS]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_CREATE_DB]= CF_STATUS_COMMAND; @@ -3402,6 +3403,32 @@ end_with_restore_list: thd->security_ctx->priv_user), lex->verbose); break; + case SQLCOM_SHOW_EXPLAIN: + { + /* Same security as SHOW PROCESSLIST (TODO check this) */ + if (!thd->security_ctx->priv_user[0] && + check_global_access(thd,PROCESS_ACL)) + break; + + Item *it= (Item *)lex->value_list.head(); + + if (lex->table_or_sp_used()) + { + my_error(ER_NOT_SUPPORTED_YET, MYF(0), "Usage of subqueries or stored " + "function calls as part of this statement"); + break; + } + + if ((!it->fixed && it->fix_fields(lex->thd, &it)) || it->check_cols(1)) + { + my_message(ER_SET_CONSTANTS_ONLY, ER(ER_SET_CONSTANTS_ONLY), + MYF(0)); + goto error; + } + + mysqld_show_explain(thd, (ulong)it->val_int()); + break; + } case SQLCOM_SHOW_AUTHORS: res= mysqld_show_authors(thd); break; diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 5b5ed004006..465a026ad6e 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2049,6 +2049,7 @@ static bool check_prepared_statement(Prepared_statement *stmt) case SQLCOM_SHOW_ENGINE_LOGS: case SQLCOM_SHOW_ENGINE_STATUS: case SQLCOM_SHOW_ENGINE_MUTEX: + case SQLCOM_SHOW_EXPLAIN: case SQLCOM_SHOW_CREATE_DB: case SQLCOM_SHOW_GRANTS: case SQLCOM_SHOW_BINLOG_EVENTS: diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 5cc8078b9f0..74d2bc7c356 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -846,6 +846,12 @@ inject_jtbm_conds(JOIN *join, List *join_list, Item **join_where) DBUG_VOID_RETURN; } +int JOIN::optimize() +{ + int res= optimize_inner(); + optimized= 2; + return res; +} /** global select optimisation. @@ -859,7 +865,7 @@ inject_jtbm_conds(JOIN *join, List *join_list, Item **join_where) */ int -JOIN::optimize() +JOIN::optimize_inner() { ulonglong select_opts_for_readinfo; uint no_jbuf_after; @@ -2888,7 +2894,9 @@ mysql_select(THD *thd, Item ***rref_pointer_array, if (thd->is_error()) goto err; + thd->apc_target.enable(); join->exec(); + thd->apc_target.disable(); if (thd->cursor && thd->cursor->is_open()) { @@ -3529,7 +3537,7 @@ make_join_statistics(JOIN *join, List &tables_list, goto error; /* Generate an execution plan from the found optimal join order. */ - DBUG_RETURN(join->thd->killed || get_best_combination(join)); + DBUG_RETURN(join->thd->check_killed() || get_best_combination(join)); error: /* @@ -6276,7 +6284,7 @@ best_extension_by_limited_search(JOIN *join, DBUG_ENTER("best_extension_by_limited_search"); THD *thd= join->thd; - if (thd->killed) // Abort + if (thd->check_killed()) // Abort DBUG_RETURN(TRUE); DBUG_EXECUTE("opt", print_plan(join, idx, read_time, record_count, idx, @@ -6436,7 +6444,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, { DBUG_ENTER("find_best"); THD *thd= join->thd; - if (thd->killed) + if (thd->check_killed()) DBUG_RETURN(TRUE); if (!rest_tables) { @@ -14452,7 +14460,7 @@ create_internal_tmp_table_from_heap2(THD *thd, TABLE *table, DBUG_EXECUTE_IF("raise_error", write_err= HA_ERR_FOUND_DUPP_KEY ;); if (write_err) goto err; - if (thd->killed) + if (thd->check_killed()) { thd->send_kill_message(); goto err_killed; @@ -14822,7 +14830,7 @@ sub_select_cache(JOIN *join, JOIN_TAB *join_tab, bool end_of_records) rc= sub_select(join, join_tab, end_of_records); DBUG_RETURN(rc); } - if (join->thd->killed) + if (join->thd->check_killed()) { /* The user has aborted the execution of the query */ join->thd->send_kill_message(); @@ -15121,7 +15129,7 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, DBUG_RETURN(NESTED_LOOP_ERROR); if (error < 0) DBUG_RETURN(NESTED_LOOP_NO_MORE_ROWS); - if (join->thd->killed) // Aborted by user + if (join->thd->check_killed()) // Aborted by user { join->thd->send_kill_message(); DBUG_RETURN(NESTED_LOOP_KILLED); /* purecov: inspected */ @@ -16250,7 +16258,7 @@ end_write(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), TABLE *table=join->tmp_table; DBUG_ENTER("end_write"); - if (join->thd->killed) // Aborted by user + if (join->thd->check_killed()) // Aborted by user { join->thd->send_kill_message(); DBUG_RETURN(NESTED_LOOP_KILLED); /* purecov: inspected */ @@ -16321,7 +16329,7 @@ end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), if (end_of_records) DBUG_RETURN(NESTED_LOOP_OK); - if (join->thd->killed) // Aborted by user + if (join->thd->check_killed()) // Aborted by user { join->thd->send_kill_message(); DBUG_RETURN(NESTED_LOOP_KILLED); /* purecov: inspected */ @@ -16402,7 +16410,7 @@ end_unique_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), if (end_of_records) DBUG_RETURN(NESTED_LOOP_OK); - if (join->thd->killed) // Aborted by user + if (join->thd->check_killed()) // Aborted by user { join->thd->send_kill_message(); DBUG_RETURN(NESTED_LOOP_KILLED); /* purecov: inspected */ @@ -16449,7 +16457,7 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), int idx= -1; DBUG_ENTER("end_write_group"); - if (join->thd->killed) + if (join->thd->check_killed()) { // Aborted by user join->thd->send_kill_message(); DBUG_RETURN(NESTED_LOOP_KILLED); /* purecov: inspected */ @@ -18226,7 +18234,7 @@ static int remove_dup_with_compare(THD *thd, TABLE *table, Field **first_field, error= file->ha_rnd_next(record); for (;;) { - if (thd->killed) + if (thd->check_killed()) { thd->send_kill_message(); error=0; @@ -18358,7 +18366,7 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table, for (;;) { uchar *org_key_pos; - if (thd->killed) + if (thd->check_killed()) { thd->send_kill_message(); error=0; @@ -20355,29 +20363,40 @@ void JOIN::clear() } } + /** EXPLAIN handling. Send a description about what how the select will be done to stdout. + + @param on_the_fly TRUE <=> we're being executed on-the-fly, so don't make + modifications to any select's data structures */ -static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, - bool distinct,const char *message) +int JOIN::print_explain(select_result_sink *result, bool on_the_fly, + bool need_tmp_table, bool need_order, + bool distinct, const char *message) { List field_list; List item_list; + JOIN *join= this; /* Legacy: this code used to be a non-member function */ THD *thd=join->thd; - select_result *result=join->result; Item *item_null= new Item_null(); CHARSET_INFO *cs= system_charset_info; int quick_type; - DBUG_ENTER("select_describe"); + int error= 0; + DBUG_ENTER("JOIN::print_explain"); DBUG_PRINT("info", ("Select 0x%lx, type %s, message %s", (ulong)join->select_lex, join->select_lex->type, message ? message : "NULL")); + DBUG_ASSERT(this->optimized == 2); /* Don't log this into the slow query log */ - thd->server_status&= ~(SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED); - join->unit->offset_limit_cnt= 0; + + if (!on_the_fly) + { + thd->server_status&= ~(SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED); + join->unit->offset_limit_cnt= 0; + } /* NOTE: the number/types of items pushed into item_list must be in sync with @@ -20398,10 +20417,11 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, item_list.push_back(new Item_string(message,strlen(message),cs)); if (result->send_data(item_list)) - join->error= 1; + error= 1; } else if (join->select_lex == join->unit->fake_select_lex) { + join->select_lex->set_explain_type(); //psergey /* here we assume that the query will return at least two rows, so we show "filesort" in EXPLAIN. Of course, sometimes we'll be wrong @@ -20468,12 +20488,13 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, item_list.push_back(new Item_string("", 0, cs)); if (result->send_data(item_list)) - join->error= 1; + error= 1; } else if (!join->select_lex->master_unit()->derived || join->select_lex->master_unit()->derived->is_materialized_derived()) { table_map used_tables=0; + join->select_lex->set_explain_type(); //psergey bool printing_materialize_nest= FALSE; uint select_id= join->select_lex->select_number; @@ -20965,9 +20986,23 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, // For next iteration used_tables|=table->map; if (result->send_data(item_list)) - join->error= 1; + error= 1; } } + DBUG_RETURN(error); +} + + +static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, + bool distinct,const char *message) +{ + THD *thd=join->thd; + select_result *result=join->result; + DBUG_ENTER("select_describe"); + join->error= join->print_explain(result, FALSE, /* Not on-the-fly */ + need_tmp_table, need_order, distinct, + message); + for (SELECT_LEX_UNIT *unit= join->select_lex->first_inner_unit(); unit; unit= unit->next_unit()) @@ -21010,7 +21045,7 @@ bool mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result) for (SELECT_LEX *sl= first; sl; sl= sl->next_select()) { - sl->set_explain_type(); + sl->set_explain_type(); //psergey-todo: maybe remove this from here? sl->options|= SELECT_DESCRIBE; } diff --git a/sql/sql_select.h b/sql/sql_select.h index bbf390aaf7e..e3b6b1f6cac 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -963,7 +963,7 @@ public: const char *zero_result_cause; ///< not 0 if exec must return zero result bool union_part; ///< this subselect is part of union - bool optimized; ///< flag to avoid double optimization in EXPLAIN + int optimized; ///< flag to avoid double optimization in EXPLAIN bool initialized; ///< flag to avoid double init_execution calls /* @@ -1074,6 +1074,7 @@ public: SELECT_LEX_UNIT *unit); bool prepare_stage2(); int optimize(); + int optimize_inner(); int reinit(); int init_execution(); void exec(); @@ -1167,6 +1168,10 @@ public: { return (unit->item && unit->item->is_in_predicate()); } + + int print_explain(select_result_sink *result, bool on_the_fly, + bool need_tmp_table, bool need_order, + bool distinct,const char *message); private: /** TRUE if the query contains an aggregate function but has no GROUP diff --git a/sql/sql_show.cc b/sql/sql_show.cc index e4981701025..770e4610fd8 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2024,6 +2024,97 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) DBUG_VOID_RETURN; } + +/* + SHOW EXPLAIN FOR command handler + + @param thd Current thread's thd + @param thread_id Thread whose explain we need + + @notes + - Attempt to do "SHOW EXPLAIN FOR " will properly produce "target not + running EXPLAINable command". + - todo: check how all this can/will work when using thread pools +*/ + +void mysqld_show_explain(THD *thd, ulong thread_id) +{ + THD *tmp; + Protocol *protocol= thd->protocol; + List field_list; + DBUG_ENTER("mysqld_show_explain"); + + thd->make_explain_field_list(field_list); + if (protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS | + Protocol::SEND_EOF)) + DBUG_VOID_RETURN; + + /* + Find the thread we need EXPLAIN for. Thread search code was copied from + kill_one_thread() + */ + VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list + I_List_iterator it(threads); + while ((tmp=it++)) + { + if (tmp->command == COM_DAEMON) + continue; + if (tmp->thread_id == thread_id) + { + pthread_mutex_lock(&tmp->LOCK_thd_data); // Lock from delete + break; + } + } + VOID(pthread_mutex_unlock(&LOCK_thread_count)); + + if (tmp) + { + bool bres; + /* + Ok we've found the thread of interest and it won't go away because + we're holding its LOCK_thd data. + Post it an EXPLAIN request. + todo: where to get timeout from? + */ + bool timed_out; + int timeout_sec= 30; + Show_explain_request explain_req; + select_result_explain_buffer *explain_buf; + + explain_buf= new select_result_explain_buffer; + explain_buf->thd=thd; + explain_buf->protocol= thd->protocol; + + explain_req.explain_buf= explain_buf; + explain_req.target_thd= tmp; + explain_req.request_thd= thd; + + bres= tmp->apc_target.make_apc_call(Show_explain_request::get_explain_data, + (void*)&explain_req, + timeout_sec, &timed_out); + if (bres) + { + /* TODO not enabled or time out */ + my_error(ER_ERROR_WHEN_EXECUTING_COMMAND, MYF(0), + "SHOW EXPLAIN", + "Target is not running EXPLAINable command"); + } + pthread_mutex_unlock(&tmp->LOCK_thd_data); + if (!bres) + { + explain_buf->flush_data(); + my_eof(thd); + } + } + else + { + my_error(ER_NO_SUCH_THREAD, MYF(0), thread_id); + } + + DBUG_VOID_RETURN; +} + + int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond) { TABLE *table= tables->table; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index c2fea985aa1..879c502a25f 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -10852,6 +10852,12 @@ show_param: Lex->spname= $3; Lex->sql_command = SQLCOM_SHOW_CREATE_EVENT; } + | describe_command FOR_SYM expr + { + Lex->sql_command= SQLCOM_SHOW_EXPLAIN; + Lex->value_list.empty(); + Lex->value_list.push_front($3); + } ; show_engine_param: From 84cb5de047e83ced6ac9490b9da630fe7dff3c4a Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Wed, 24 Aug 2011 14:41:13 +0400 Subject: [PATCH 002/289] MWL#182: Explain running statements - Further progress with the code - Testcases. --- mysql-test/r/show_explain.result | 26 ++++++++++++++++++ mysql-test/t/show_explain.test | 46 ++++++++++++++++++++++++++++++++ sql/sql_class.cc | 9 ++++++- sql/sql_lex.cc | 21 +++++++++------ sql/sql_select.cc | 17 +++++++++--- sql/sql_select.h | 1 + 6 files changed, 107 insertions(+), 13 deletions(-) create mode 100644 mysql-test/r/show_explain.result create mode 100644 mysql-test/t/show_explain.test diff --git a/mysql-test/r/show_explain.result b/mysql-test/r/show_explain.result new file mode 100644 index 00000000000..5aee9221d50 --- /dev/null +++ b/mysql-test/r/show_explain.result @@ -0,0 +1,26 @@ +drop table if exists t0, t1; +create table t0 (a int); +insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t1 (a int); +insert into t1 select A.a + 10*B.a + 100*C.a from t0 A, t0 B, t0 C; +show explain for 2*1000*1000*1000; +ERROR HY000: Unknown thread id: 2000000000 +show explain for 3; +ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EXPLAINable command +show explain for 2; +ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EXPLAINable command +select get_lock('optimizer_done', 10); +get_lock('optimizer_done', 10) +1 +select count(*) from t1 where a < 100000 and sleep(a*0 + release_lock('optimizer_done') +1); +select get_lock('optimizer_done', 100); +get_lock('optimizer_done', 100) +1 +show explain for 3; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 1000 Using where +select release_lock('optimizer_done'); +release_lock('optimizer_done') +1 +kill query 3; +drop table t0,t1; diff --git a/mysql-test/t/show_explain.test b/mysql-test/t/show_explain.test new file mode 100644 index 00000000000..fda31392e46 --- /dev/null +++ b/mysql-test/t/show_explain.test @@ -0,0 +1,46 @@ +# +# Tests for SHOW EXPLAIN FOR functionality +# +--disable_warnings +drop table if exists t0, t1; +--enable_warnings + +create table t0 (a int); +insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t1 (a int); +insert into t1 select A.a + 10*B.a + 100*C.a from t0 A, t0 B, t0 C; + +# +# Try killing a non-existent thread +# +--error ER_NO_SUCH_THREAD +show explain for 2*1000*1000*1000; + +# Setup two threads and their ids +let $thr1=`select connection_id()`; +connect (con1, localhost, root,,); +connection con1; +let $thr2=`select connection_id()`; +connection default; + +# SHOW EXPLAIN FOR +--error ER_ERROR_WHEN_EXECUTING_COMMAND +eval show explain for $thr2; + +# SHOW EXPLAIN FOR +--error ER_ERROR_WHEN_EXECUTING_COMMAND +eval show explain for $thr1; + +# SHOW EXPLAIN FOR +connection con1; +select get_lock('optimizer_done', 10); +send select count(*) from t1 where a < 100000 and sleep(a*0 + release_lock('optimizer_done') +1); +connection default; +select get_lock('optimizer_done', 100); +eval show explain for $thr2; +select release_lock('optimizer_done'); +eval kill query $thr2; + +#insert into t1 values ('one'),('two'),('three'); + +drop table t0,t1; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 12709e23a34..c9b99b5fd1f 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -2932,7 +2932,14 @@ void THD::restore_active_arena(Query_arena *set, Query_arena *backup) DBUG_VOID_RETURN; } -// psergey + +/* + Produce EXPLAIN data. + + This function is APC-scheduled to be run in the context of the thread that + we're producing EXPLAIN for. +*/ + void Show_explain_request::get_explain_data(void *arg) { Show_explain_request *req= (Show_explain_request*)arg; diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index ae9c11c47e2..454331a0859 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -3625,19 +3625,24 @@ bool st_select_lex::save_prep_leaf_tables(THD *thd) int st_select_lex::print_explain(select_result_sink *output) { + int res; if (join && join->optimized == 2) { - //psergey-TODO: any? - return join->print_explain(output, TRUE, - FALSE, // need_tmp_table, - FALSE, // bool need_order, - FALSE, // bool distinct, - NULL); //const char *message + res= join->print_explain(output, TRUE, + FALSE, // need_tmp_table, + FALSE, // bool need_order, + FALSE, // bool distinct, + NULL); //const char *message } else { - DBUG_ASSERT(0); - /* produce "not yet optimized" line */ + /* Produce "not yet optimized" line */ + const char *msg="Not yet optimized"; + res= join->print_explain(output, TRUE, + FALSE, // need_tmp_table, + FALSE, // bool need_order, + FALSE, // bool distinct, + msg); //const char *message } return 0; } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 74d2bc7c356..c3d1543b363 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2019,6 +2019,17 @@ JOIN::save_join_tab() } +void JOIN::exec() +{ + /* + Enable SHOW EXPLAIN only if we're in the top-level query. + */ + thd->apc_target.enable(); + exec_inner(); + thd->apc_target.disable(); +} + + /** Exec select. @@ -2030,8 +2041,8 @@ JOIN::save_join_tab() @todo When can we have here thd->net.report_error not zero? */ -void -JOIN::exec() + +void JOIN::exec_inner() { List *columns_list= &fields_list; int tmp_error; @@ -2894,9 +2905,7 @@ mysql_select(THD *thd, Item ***rref_pointer_array, if (thd->is_error()) goto err; - thd->apc_target.enable(); join->exec(); - thd->apc_target.disable(); if (thd->cursor && thd->cursor->is_open()) { diff --git a/sql/sql_select.h b/sql/sql_select.h index e3b6b1f6cac..f329f51707f 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -1078,6 +1078,7 @@ public: int reinit(); int init_execution(); void exec(); + void exec_inner(); int destroy(); void restore_tmp(); bool alloc_func_list(); From 0a08933036f0d3c499b7110ae2883fcc1796414f Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Thu, 25 Aug 2011 12:15:29 +0400 Subject: [PATCH 003/289] MWL#182: Explain running statements - Added TODO comments --- mysql-test/t/show_explain.test | 5 +++++ sql/my_apc.cc | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/mysql-test/t/show_explain.test b/mysql-test/t/show_explain.test index fda31392e46..e8f4a646a8a 100644 --- a/mysql-test/t/show_explain.test +++ b/mysql-test/t/show_explain.test @@ -43,4 +43,9 @@ eval kill query $thr2; #insert into t1 values ('one'),('two'),('three'); +## TODO: Test this: multiple SHOW EXPLAIN calls in course of running of one select +## +## TODO: Test this: have several SHOW EXPLAIN requests be queued up for a +## thread and served together. + drop table t0,t1; diff --git a/sql/my_apc.cc b/sql/my_apc.cc index 3842947f3bb..754b7880c42 100644 --- a/sql/my_apc.cc +++ b/sql/my_apc.cc @@ -97,7 +97,9 @@ void Apc_target::dequeue_request(Call_request *qe) /* Make an apc call in another thread. The caller is responsible so that we're not calling to ourselves. - + + psergey-todo: Should waits here be KILLable? (it seems one needs + to use thd->enter_cond() calls to be killable) */ bool Apc_target::make_apc_call(apc_func_t func, void *func_arg, From d3052e225a511cd28a41eb3444f36d2789e5dd6c Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Thu, 25 Aug 2011 13:04:09 +0400 Subject: [PATCH 004/289] Fix windows build: add my_apc.{h,cc} to CMakeLists.txt files --- libmysqld/CMakeLists.txt | 1 + sql/CMakeLists.txt | 1 + 2 files changed, 2 insertions(+) diff --git a/libmysqld/CMakeLists.txt b/libmysqld/CMakeLists.txt index 7c5b6bd5917..cf72cedb644 100644 --- a/libmysqld/CMakeLists.txt +++ b/libmysqld/CMakeLists.txt @@ -146,6 +146,7 @@ SET(LIBMYSQLD_SOURCES libmysqld.c emb_qcache.cc lib_sql.cc ../sql/create_options.cc ../sql/rpl_utility.cc ../sql/rpl_reporting.cc ../sql/sql_expression_cache.cc + ../sql/my_apc.cc ../sql/my_apc.h ${GEN_SOURCES} ${LIB_SOURCES}) diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 8d2aeca17db..597ca7d874b 100644 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -83,6 +83,7 @@ SET (SQL_SOURCE opt_index_cond_pushdown.cc create_options.cc sql_expression_cache.cc + my_apc.cc my_apc.h ${CMAKE_BINARY_DIR}/sql/sql_yacc.cc ${CMAKE_BINARY_DIR}/sql/sql_yacc.h ${CMAKE_BINARY_DIR}/include/mysqld_error.h From f4dd6831f5863ea5f239ca24c5b3c03bd2575c4a Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Fri, 26 Aug 2011 16:04:30 +0400 Subject: [PATCH 005/289] Fix for previous csets: let set_explain_type() produce correct types for "UNION RESULT" selects --- sql/sql_lex.cc | 2 +- sql/sql_select.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 454331a0859..82b171789bc 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -3520,7 +3520,7 @@ void st_select_lex::set_explain_type() ((is_uncacheable & UNCACHEABLE_DEPENDENT) ? "DEPENDENT UNION": is_uncacheable ? "UNCACHEABLE UNION": - "UNION"))); + (this == master_unit()->fake_select_lex)? "UNION RESULT" : "UNION"))); options|= SELECT_DESCRIBE; } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index c3d1543b363..55ca42f797b 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -20503,7 +20503,7 @@ int JOIN::print_explain(select_result_sink *result, bool on_the_fly, join->select_lex->master_unit()->derived->is_materialized_derived()) { table_map used_tables=0; - join->select_lex->set_explain_type(); //psergey + join->select_lex->set_explain_type(); //psergey-todo: this adds SELECT_DESCRIBE to options! bad for on-the-fly bool printing_materialize_nest= FALSE; uint select_id= join->select_lex->select_number; From d9045bce1ddf1f017f0e127606c809271c953ef0 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Sat, 27 Aug 2011 09:47:21 +0400 Subject: [PATCH 006/289] -Make show_explain.test stable - Fix st_select_lex::set_explain_type() to allow producing exactly the same EXPLAINs as it did before. SHOW EXPLAIN output may produce select_type=SIMPLE instead or select_type=PRIMARY or vice versa (which is ok because values of select_type weren't self-consistent in this regard to begin with) --- mysql-test/r/show_explain.result | 8 ++++---- mysql-test/t/show_explain.test | 12 ++++++++++++ sql/opt_subselect.cc | 5 ++++- sql/sql_lex.cc | 14 +++++++++++--- sql/sql_lex.h | 8 +++++++- sql/sql_select.cc | 10 +++++++--- 6 files changed, 45 insertions(+), 12 deletions(-) diff --git a/mysql-test/r/show_explain.result b/mysql-test/r/show_explain.result index 5aee9221d50..4ff89069c5c 100644 --- a/mysql-test/r/show_explain.result +++ b/mysql-test/r/show_explain.result @@ -5,9 +5,9 @@ create table t1 (a int); insert into t1 select A.a + 10*B.a + 100*C.a from t0 A, t0 B, t0 C; show explain for 2*1000*1000*1000; ERROR HY000: Unknown thread id: 2000000000 -show explain for 3; +SHOW explain for thr2 ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EXPLAINable command -show explain for 2; +SHOW explain for thr1 ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EXPLAINable command select get_lock('optimizer_done', 10); get_lock('optimizer_done', 10) @@ -16,11 +16,11 @@ select count(*) from t1 where a < 100000 and sleep(a*0 + release_lock('optimizer select get_lock('optimizer_done', 100); get_lock('optimizer_done', 100) 1 -show explain for 3; +SHOW explain for thr2 id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 1000 Using where select release_lock('optimizer_done'); release_lock('optimizer_done') 1 -kill query 3; +kill query thr2 drop table t0,t1; diff --git a/mysql-test/t/show_explain.test b/mysql-test/t/show_explain.test index e8f4a646a8a..fc83613ae0e 100644 --- a/mysql-test/t/show_explain.test +++ b/mysql-test/t/show_explain.test @@ -24,12 +24,18 @@ let $thr2=`select connection_id()`; connection default; # SHOW EXPLAIN FOR +echo SHOW explain for thr2; +--disable_query_log --error ER_ERROR_WHEN_EXECUTING_COMMAND eval show explain for $thr2; +--enable_query_log # SHOW EXPLAIN FOR +echo SHOW explain for thr1; +--disable_query_log --error ER_ERROR_WHEN_EXECUTING_COMMAND eval show explain for $thr1; +--enable_query_log # SHOW EXPLAIN FOR connection con1; @@ -37,9 +43,15 @@ select get_lock('optimizer_done', 10); send select count(*) from t1 where a < 100000 and sleep(a*0 + release_lock('optimizer_done') +1); connection default; select get_lock('optimizer_done', 100); +echo SHOW explain for thr2; +--disable_query_log eval show explain for $thr2; +--enable_query_log select release_lock('optimizer_done'); +--disable_query_log eval kill query $thr2; +--enable_query_log +echo kill query thr2; #insert into t1 values ('one'),('two'),('three'); diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index 6c5e177fe1d..f8b6f80eb14 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -1346,7 +1346,8 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred) while ((ifm= li++)) parent_lex->ftfunc_list->push_front(ifm); } - + + parent_lex->have_merged_subqueries= TRUE; DBUG_RETURN(FALSE); } @@ -1458,6 +1459,8 @@ static bool convert_subq_to_jtbm(JOIN *parent_join, create_subquery_temptable_name(tbl_alias, hash_sj_engine->materialize_join-> select_lex->select_number); jtbm->alias= tbl_alias; + + parent_lex->have_merged_subqueries= TRUE; #if 0 /* Inject sj_on_expr into the parent's WHERE or ON */ if (emb_tbl_nest) diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 82b171789bc..a9f07c337fa 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1640,7 +1640,8 @@ void st_select_lex::init_query() link_next= 0; lock_option= TL_READ_DEFAULT; is_prep_leaf_list_saved= FALSE; - + + have_merged_subqueries= FALSE; bzero((char*) expr_cache_may_be_used, sizeof(expr_cache_may_be_used)); } @@ -3119,7 +3120,7 @@ bool st_select_lex::optimize_unflattened_subqueries() if (options & SELECT_DESCRIBE) { /* Optimize the subquery in the context of EXPLAIN. */ - sl->set_explain_type(); + sl->set_explain_type(FALSE); sl->options|= SELECT_DESCRIBE; inner_join->select_options|= SELECT_DESCRIBE; } @@ -3482,7 +3483,7 @@ void SELECT_LEX::update_used_tables() Set the EXPLAIN type for this subquery. */ -void st_select_lex::set_explain_type() +void st_select_lex::set_explain_type(bool on_the_fly) { bool is_primary= FALSE; if (next_select()) @@ -3504,6 +3505,9 @@ void st_select_lex::set_explain_type() } } + if (on_the_fly && !is_primary && have_merged_subqueries) + is_primary= TRUE; + SELECT_LEX *first= master_unit()->first_select(); /* drop UNCACHEABLE_EXPLAIN, because it is for internal usage only */ uint8 is_uncacheable= (uncacheable & ~UNCACHEABLE_EXPLAIN); @@ -3521,6 +3525,10 @@ void st_select_lex::set_explain_type() "DEPENDENT UNION": is_uncacheable ? "UNCACHEABLE UNION": (this == master_unit()->fake_select_lex)? "UNION RESULT" : "UNION"))); + + if (this == master_unit()->fake_select_lex) + type= "UNION RESULT"; + options|= SELECT_DESCRIBE; } diff --git a/sql/sql_lex.h b/sql/sql_lex.h index d5dc4dc3a1f..b5131ded136 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -646,6 +646,12 @@ public: those converted to jtbm nests. The list is emptied when conversion is done. */ List sj_subselects; + + /* + Needed to correctly generate 'PRIMARY' or 'SIMPLE' for select_type column + of EXPLAIN + */ + bool have_merged_subqueries; List leaf_tables; List leaf_tables_exec; @@ -888,7 +894,7 @@ public: */ bool optimize_unflattened_subqueries(); /* Set the EXPLAIN type for this subquery. */ - void set_explain_type(); + void set_explain_type(bool on_the_fly); bool handle_derived(struct st_lex *lex, uint phases); void append_table_to_list(TABLE_LIST *TABLE_LIST::*link, TABLE_LIST *table); bool get_free_table_map(table_map *map, uint *tablenr); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 55ca42f797b..2a895bb2798 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -20430,7 +20430,9 @@ int JOIN::print_explain(select_result_sink *result, bool on_the_fly, } else if (join->select_lex == join->unit->fake_select_lex) { - join->select_lex->set_explain_type(); //psergey + //if (!join->select_lex->type) + if (on_the_fly) + join->select_lex->set_explain_type(on_the_fly); //psergey /* here we assume that the query will return at least two rows, so we show "filesort" in EXPLAIN. Of course, sometimes we'll be wrong @@ -20503,7 +20505,9 @@ int JOIN::print_explain(select_result_sink *result, bool on_the_fly, join->select_lex->master_unit()->derived->is_materialized_derived()) { table_map used_tables=0; - join->select_lex->set_explain_type(); //psergey-todo: this adds SELECT_DESCRIBE to options! bad for on-the-fly + //if (!join->select_lex->type) + if (on_the_fly) + join->select_lex->set_explain_type(on_the_fly); //psergey-todo: this adds SELECT_DESCRIBE to options! bad for on-the-fly bool printing_materialize_nest= FALSE; uint select_id= join->select_lex->select_number; @@ -21054,7 +21058,7 @@ bool mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result) for (SELECT_LEX *sl= first; sl; sl= sl->next_select()) { - sl->set_explain_type(); //psergey-todo: maybe remove this from here? + sl->set_explain_type(FALSE); //psergey-todo: maybe remove this from here? sl->options|= SELECT_DESCRIBE; } From 203bbfe5693a95e01c84d1e4b788b76645df2d11 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Sat, 24 Sep 2011 21:56:42 +0400 Subject: [PATCH 007/289] MWL#182: Explain running statements - Implement new approach to testing (the DBUG_EXECUTE_IF variant) - add an 'evalp' mysqltest command that is like 'eval' except that it prints the original query. - Fix select_describe() not to change join_tab[i]->type - More tests --- client/mysqltest.cc | 25 ++++++++++-- mysql-test/r/show_explain.result | 43 +++++++++++++-------- mysql-test/t/show_explain.test | 65 +++++++++++++++++++++----------- sql/my_apc.cc | 8 ++++ sql/my_apc.h | 6 ++- sql/mysql_priv.h | 4 ++ sql/sql_select.cc | 43 +++++++++++++++------ 7 files changed, 141 insertions(+), 53 deletions(-) diff --git a/client/mysqltest.cc b/client/mysqltest.cc index a3689a7b757..d33db945aee 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -75,6 +75,8 @@ #define QUERY_SEND_FLAG 1 #define QUERY_REAP_FLAG 2 +#define QUERY_PRINT_ORIGINAL_FLAG 4 + #ifndef HAVE_SETENV static int setenv(const char *name, const char *value, int overwrite); #endif @@ -288,7 +290,8 @@ enum enum_commands { Q_ERROR, Q_SEND, Q_REAP, Q_DIRTY_CLOSE, Q_REPLACE, Q_REPLACE_COLUMN, - Q_PING, Q_EVAL, + Q_PING, Q_EVAL, + Q_EVALP, Q_RPL_PROBE, Q_ENABLE_RPL_PARSE, Q_DISABLE_RPL_PARSE, Q_EVAL_RESULT, Q_ENABLE_QUERY_LOG, Q_DISABLE_QUERY_LOG, @@ -353,6 +356,7 @@ const char *command_names[]= "replace_column", "ping", "eval", + "evalp", "rpl_probe", "enable_rpl_parse", "disable_rpl_parse", @@ -7532,7 +7536,8 @@ void run_query(struct st_connection *cn, struct st_command *command, int flags) /* Evaluate query if this is an eval command */ - if (command->type == Q_EVAL || command->type == Q_SEND_EVAL) + if (command->type == Q_EVAL || command->type == Q_SEND_EVAL || + command->type == Q_EVALP) { init_dynamic_string(&eval_query, "", command->query_len+256, 1024); do_eval(&eval_query, command->query, command->end, FALSE); @@ -7564,10 +7569,20 @@ void run_query(struct st_connection *cn, struct st_command *command, int flags) */ if (!disable_query_log && (flags & QUERY_SEND_FLAG)) { - replace_dynstr_append_mem(ds, query, query_len); + char *print_query= query; + int print_len= query_len; + if (flags & QUERY_PRINT_ORIGINAL_FLAG) + { + print_query= command->query; + print_len= command->end - command->query; + } + replace_dynstr_append_mem(ds, print_query, print_len); dynstr_append_mem(ds, delimiter, delimiter_length); dynstr_append_mem(ds, "\n", 1); } + + /* We're done with this flag */ + flags &= ~QUERY_PRINT_ORIGINAL_FLAG; /* Write the command to the result file before we execute the query @@ -8420,6 +8435,7 @@ int main(int argc, char **argv) case Q_EVAL_RESULT: die("'eval_result' command is deprecated"); case Q_EVAL: + case Q_EVALP: case Q_QUERY_VERTICAL: case Q_QUERY_HORIZONTAL: if (command->query == command->query_buf) @@ -8447,6 +8463,9 @@ int main(int argc, char **argv) flags= QUERY_REAP_FLAG; } + if (command->type == Q_EVALP) + flags |= QUERY_PRINT_ORIGINAL_FLAG; + /* Check for special property for this query */ display_result_vertically|= (command->type == Q_QUERY_VERTICAL); diff --git a/mysql-test/r/show_explain.result b/mysql-test/r/show_explain.result index 4ff89069c5c..6a142e676fa 100644 --- a/mysql-test/r/show_explain.result +++ b/mysql-test/r/show_explain.result @@ -3,24 +3,37 @@ create table t0 (a int); insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); create table t1 (a int); insert into t1 select A.a + 10*B.a + 100*C.a from t0 A, t0 B, t0 C; +alter table t1 add b int, add c int, add filler char(32); +update t1 set b=a, c=a, filler='fooo'; +alter table t1 add key(a), add key(b); show explain for 2*1000*1000*1000; ERROR HY000: Unknown thread id: 2000000000 -SHOW explain for thr2 +show explain for (select max(a) from t0); +ERROR 42000: This version of MySQL doesn't yet support 'Usage of subqueries or stored function calls as part of this statement' +show explain for $thr2; ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EXPLAINable command -SHOW explain for thr1 +show explain for $thr1; ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EXPLAINable command -select get_lock('optimizer_done', 10); -get_lock('optimizer_done', 10) -1 -select count(*) from t1 where a < 100000 and sleep(a*0 + release_lock('optimizer_done') +1); -select get_lock('optimizer_done', 100); -get_lock('optimizer_done', 100) -1 -SHOW explain for thr2 +set debug='d,show_explain_probe_1'; +select count(*) from t1 where a < 100000; +show explain for $thr2; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 1000 Using where -select release_lock('optimizer_done'); -release_lock('optimizer_done') -1 -kill query thr2 +1 SIMPLE t1 index a a 5 NULL 1000 Using where; Using index +count(*) +1000 +set debug='d,show_explain_probe_1'; +select max(c) from t1 where a < 10; +show explain for $thr2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 10 Using where +max(c) +9 +set optimizer_switch='index_condition_pushdown=on,mrr=on,mrr_sort_keys=on'; +set debug='d,show_explain_probe_1'; +explain select max(c) from t1 where a < 10; +show explain for $thr2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 10 Using index condition; Rowid-ordered scan +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 10 Using index condition; Rowid-ordered scan drop table t0,t1; diff --git a/mysql-test/t/show_explain.test b/mysql-test/t/show_explain.test index fc83613ae0e..1ee66e3ca2c 100644 --- a/mysql-test/t/show_explain.test +++ b/mysql-test/t/show_explain.test @@ -9,6 +9,9 @@ create table t0 (a int); insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); create table t1 (a int); insert into t1 select A.a + 10*B.a + 100*C.a from t0 A, t0 B, t0 C; +alter table t1 add b int, add c int, add filler char(32); +update t1 set b=a, c=a, filler='fooo'; +alter table t1 add key(a), add key(b); # # Try killing a non-existent thread @@ -16,7 +19,12 @@ insert into t1 select A.a + 10*B.a + 100*C.a from t0 A, t0 B, t0 C; --error ER_NO_SUCH_THREAD show explain for 2*1000*1000*1000; +--error ER_NOT_SUPPORTED_YET +show explain for (select max(a) from t0); + +# # Setup two threads and their ids +# let $thr1=`select connection_id()`; connect (con1, localhost, root,,); connection con1; @@ -24,36 +32,47 @@ let $thr2=`select connection_id()`; connection default; # SHOW EXPLAIN FOR -echo SHOW explain for thr2; ---disable_query_log --error ER_ERROR_WHEN_EXECUTING_COMMAND -eval show explain for $thr2; ---enable_query_log +evalp show explain for $thr2; # SHOW EXPLAIN FOR -echo SHOW explain for thr1; ---disable_query_log --error ER_ERROR_WHEN_EXECUTING_COMMAND -eval show explain for $thr1; ---enable_query_log +evalp show explain for $thr1; -# SHOW EXPLAIN FOR +let $wait_condition= select State='show_explain_trap' from information_schema.processlist where id=$thr2; + +# +# Test SHOW EXPLAIN for simple queries +# connection con1; -select get_lock('optimizer_done', 10); -send select count(*) from t1 where a < 100000 and sleep(a*0 + release_lock('optimizer_done') +1); -connection default; -select get_lock('optimizer_done', 100); -echo SHOW explain for thr2; ---disable_query_log -eval show explain for $thr2; ---enable_query_log -select release_lock('optimizer_done'); ---disable_query_log -eval kill query $thr2; ---enable_query_log -echo kill query thr2; +set debug='d,show_explain_probe_1'; +send select count(*) from t1 where a < 100000; + +connection default; +--source include/wait_condition.inc +evalp show explain for $thr2; +connection con1; +reap; + + +set debug='d,show_explain_probe_1'; +send select max(c) from t1 where a < 10; +connection default; +--source include/wait_condition.inc +evalp show explain for $thr2; +connection con1; +reap; + +# We can catch EXPLAIN, too. +set optimizer_switch='index_condition_pushdown=on,mrr=on,mrr_sort_keys=on'; +set debug='d,show_explain_probe_1'; +send explain select max(c) from t1 where a < 10; +connection default; +--source include/wait_condition.inc +evalp show explain for $thr2; +connection con1; +reap; -#insert into t1 values ('one'),('two'),('three'); ## TODO: Test this: multiple SHOW EXPLAIN calls in course of running of one select ## diff --git a/sql/my_apc.cc b/sql/my_apc.cc index 754b7880c42..91559483b1f 100644 --- a/sql/my_apc.cc +++ b/sql/my_apc.cc @@ -29,6 +29,10 @@ void Apc_target::init() // todo: should use my_pthread_... functions instead? DBUG_ASSERT(!enabled); (void)pthread_mutex_init(&LOCK_apc_queue, MY_MUTEX_INIT_SLOW); + +#ifndef DBUG_OFF + n_calls_processed= 0; +#endif } @@ -217,6 +221,10 @@ void Apc_target::process_apc_requests() request->func(request->func_arg); request->what="func called by process_apc_requests"; +#ifndef DBUG_OFF + n_calls_processed++; +#endif + pthread_cond_signal(&request->COND_request); pthread_mutex_unlock(&request->LOCK_request); diff --git a/sql/my_apc.h b/sql/my_apc.h index 3783bd28f54..3906aa24408 100644 --- a/sql/my_apc.h +++ b/sql/my_apc.h @@ -62,13 +62,17 @@ public: bool make_apc_call(apc_func_t func, void *func_arg, int timeout_sec, bool *timed_out); +#ifndef DBUG_OFF + int n_calls_processed; + //int call_queue_size; +#endif private: class Call_request; int enabled; Call_request *apc_calls; pthread_mutex_t LOCK_apc_queue; - //int call_queue_size; + class Call_request { diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index a19cca31d1c..e20702b497d 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -2404,6 +2404,10 @@ int rea_create_table(THD *thd, const char *path, int format_number(uint inputflag,uint max_length,char * pos,uint length, char * *errpos); +#ifndef DBUG_OFF +void dbug_serve_apcs(THD *thd, int n_calls); +#endif + /* table.cc */ TABLE_SHARE *alloc_table_share(TABLE_LIST *table_list, char *key, uint key_length); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 2a895bb2798..355b33fa353 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -245,6 +245,25 @@ Item_equal *find_item_equal(COND_EQUAL *cond_equal, Field *field, JOIN_TAB *first_depth_first_tab(JOIN* join); JOIN_TAB *next_depth_first_tab(JOIN* join, JOIN_TAB* tab); +#ifndef DBUG_OFF +// psergey: +void dbug_serve_apcs(THD *thd, int n_calls) +{ + // TODO how do we signal that we're SHOW-EXPLAIN-READY? + const char *save_proc_info= thd->proc_info; + thd_proc_info(thd, "show_explain_trap"); + + int n_apcs= thd->apc_target.n_calls_processed + n_calls; + while (thd->apc_target.n_calls_processed < n_apcs) + { + my_sleep(300); + if (thd->check_killed()) + break; + } + thd_proc_info(thd, save_proc_info); +} +#endif + /** This handles SELECT with and without UNION. */ @@ -2047,6 +2066,8 @@ void JOIN::exec_inner() List *columns_list= &fields_list; int tmp_error; DBUG_ENTER("JOIN::exec"); + + DBUG_EXECUTE_IF("show_explain_probe_1", dbug_serve_apcs(thd, 1);); thd_proc_info(thd, "executing"); error= 0; @@ -20430,7 +20451,6 @@ int JOIN::print_explain(select_result_sink *result, bool on_the_fly, } else if (join->select_lex == join->unit->fake_select_lex) { - //if (!join->select_lex->type) if (on_the_fly) join->select_lex->set_explain_type(on_the_fly); //psergey /* @@ -20561,6 +20581,7 @@ int JOIN::print_explain(select_result_sink *result, bool on_the_fly, join->select_lex->type; item_list.push_back(new Item_string(stype, strlen(stype), cs)); + enum join_type tab_type= tab->type; if ((tab->type == JT_ALL || tab->type == JT_HASH) && tab->select && tab->select->quick) { @@ -20569,9 +20590,9 @@ int JOIN::print_explain(select_result_sink *result, bool on_the_fly, (quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_INTERSECT) || (quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT) || (quick_type == QUICK_SELECT_I::QS_TYPE_ROR_UNION)) - tab->type= tab->type == JT_ALL ? JT_INDEX_MERGE : JT_HASH_INDEX_MERGE; + tab_type= tab->type == JT_ALL ? JT_INDEX_MERGE : JT_HASH_INDEX_MERGE; else - tab->type= tab->type == JT_ALL ? JT_RANGE : JT_HASH_RANGE; + tab_type= tab->type == JT_ALL ? JT_RANGE : JT_HASH_RANGE; } /* table */ @@ -20620,8 +20641,8 @@ int JOIN::print_explain(select_result_sink *result, bool on_the_fly, #endif } /* "type" column */ - item_list.push_back(new Item_string(join_type_str[tab->type], - strlen(join_type_str[tab->type]), + item_list.push_back(new Item_string(join_type_str[tab_type], + strlen(join_type_str[tab_type]), cs)); /* Build "possible_keys" value and add it to item_list */ if (!tab->keys.is_clear_all()) @@ -20645,7 +20666,7 @@ int JOIN::print_explain(select_result_sink *result, bool on_the_fly, item_list.push_back(item_null); /* Build "key", "key_len", and "ref" values and add them to item_list */ - if (tab->type == JT_NEXT) + if (tab_type == JT_NEXT) { key_info= table->key_info+tab->index; key_len= key_info->key_length; @@ -20674,12 +20695,12 @@ int JOIN::print_explain(select_result_sink *result, bool on_the_fly, } } } - if (is_hj && tab->type != JT_HASH) + if (is_hj && tab_type != JT_HASH) { tmp2.append(':'); tmp3.append(':'); } - if (tab->type == JT_HASH_NEXT) + if (tab_type == JT_HASH_NEXT) { register uint length; key_info= table->key_info+tab->index; @@ -20701,7 +20722,7 @@ int JOIN::print_explain(select_result_sink *result, bool on_the_fly, item_list.push_back(new Item_string(tmp3.ptr(),tmp3.length(),cs)); else item_list.push_back(item_null); - if (key_info && tab->type != JT_NEXT) + if (key_info && tab_type != JT_NEXT) item_list.push_back(new Item_string(tmp4.ptr(),tmp4.length(),cs)); else item_list.push_back(item_null); @@ -20754,7 +20775,7 @@ int JOIN::print_explain(select_result_sink *result, bool on_the_fly, ha_rows examined_rows; if (tab->select && tab->select->quick) examined_rows= tab->select->quick->records; - else if (tab->type == JT_NEXT || tab->type == JT_ALL || is_hj) + else if (tab_type == JT_NEXT || tab_type == JT_ALL || is_hj) { if (tab->limit) examined_rows= tab->limit; @@ -20793,7 +20814,7 @@ int JOIN::print_explain(select_result_sink *result, bool on_the_fly, /* Build "Extra" field and add it to item_list. */ key_read=table->key_read; - if ((tab->type == JT_NEXT || tab->type == JT_CONST) && + if ((tab_type == JT_NEXT || tab_type == JT_CONST) && table->covering_keys.is_set(tab->index)) key_read=1; if (quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT && From 27f760143c839d4ac8ecd4fd2764728e492e921c Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Sun, 25 Sep 2011 13:05:58 +0400 Subject: [PATCH 008/289] - Testing: add DBUG_EXECUTE_IF("show_explain_probe_2"... which fires only for selects with given select_id. - Steps towards making SHOW EXPLAIN work for UNIONs. --- mysql-test/r/show_explain.result | 3 +-- mysql-test/t/show_explain.test | 7 ++++-- sql/item_func.cc | 2 +- sql/sql_class.h | 2 ++ sql/sql_lex.cc | 3 ++- sql/sql_select.cc | 38 +++++++++++++++++++++++++++++--- 6 files changed, 46 insertions(+), 9 deletions(-) diff --git a/mysql-test/r/show_explain.result b/mysql-test/r/show_explain.result index 6a142e676fa..874af6e720e 100644 --- a/mysql-test/r/show_explain.result +++ b/mysql-test/r/show_explain.result @@ -14,6 +14,7 @@ show explain for $thr2; ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EXPLAINable command show explain for $thr1; ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EXPLAINable command +set @show_explain_probe_select_id=1; set debug='d,show_explain_probe_1'; select count(*) from t1 where a < 100000; show explain for $thr2; @@ -21,7 +22,6 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 index a a 5 NULL 1000 Using where; Using index count(*) 1000 -set debug='d,show_explain_probe_1'; select max(c) from t1 where a < 10; show explain for $thr2; id select_type table type possible_keys key key_len ref rows Extra @@ -29,7 +29,6 @@ id select_type table type possible_keys key key_len ref rows Extra max(c) 9 set optimizer_switch='index_condition_pushdown=on,mrr=on,mrr_sort_keys=on'; -set debug='d,show_explain_probe_1'; explain select max(c) from t1 where a < 10; show explain for $thr2; id select_type table type possible_keys key key_len ref rows Extra diff --git a/mysql-test/t/show_explain.test b/mysql-test/t/show_explain.test index 1ee66e3ca2c..4ed625c5bca 100644 --- a/mysql-test/t/show_explain.test +++ b/mysql-test/t/show_explain.test @@ -1,6 +1,8 @@ # # Tests for SHOW EXPLAIN FOR functionality # +--source include/have_debug.inc + --disable_warnings drop table if exists t0, t1; --enable_warnings @@ -45,6 +47,7 @@ let $wait_condition= select State='show_explain_trap' from information_schema.pr # Test SHOW EXPLAIN for simple queries # connection con1; +set @show_explain_probe_select_id=1; set debug='d,show_explain_probe_1'; send select count(*) from t1 where a < 100000; @@ -55,7 +58,6 @@ connection con1; reap; -set debug='d,show_explain_probe_1'; send select max(c) from t1 where a < 10; connection default; --source include/wait_condition.inc @@ -65,7 +67,6 @@ reap; # We can catch EXPLAIN, too. set optimizer_switch='index_condition_pushdown=on,mrr=on,mrr_sort_keys=on'; -set debug='d,show_explain_probe_1'; send explain select max(c) from t1 where a < 10; connection default; --source include/wait_condition.inc @@ -73,6 +74,8 @@ evalp show explain for $thr2; connection con1; reap; +# Let's try with a subquery + ## TODO: Test this: multiple SHOW EXPLAIN calls in course of running of one select ## diff --git a/sql/item_func.cc b/sql/item_func.cc index 033537092d8..2bca34f0a76 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -3871,7 +3871,7 @@ longlong Item_func_sleep::val_int() #define extra_size sizeof(double) -static user_var_entry *get_variable(HASH *hash, LEX_STRING &name, +user_var_entry *get_variable(HASH *hash, LEX_STRING &name, bool create_if_not_exists) { user_var_entry *entry; diff --git a/sql/sql_class.h b/sql/sql_class.h index 5d55d7182fc..cec37de6a61 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -3474,6 +3474,8 @@ class user_var_entry DTCollation collation; }; +user_var_entry *get_variable(HASH *hash, LEX_STRING &name, + bool create_if_not_exists); /* Unique -- class for unique (removing of duplicates). diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index a9f07c337fa..3d2f7013a35 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -3529,7 +3529,8 @@ void st_select_lex::set_explain_type(bool on_the_fly) if (this == master_unit()->fake_select_lex) type= "UNION RESULT"; - options|= SELECT_DESCRIBE; + if (!on_the_fly) + options|= SELECT_DESCRIBE; } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 355b33fa353..1d2c8a10b75 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -262,8 +262,34 @@ void dbug_serve_apcs(THD *thd, int n_calls) } thd_proc_info(thd, save_proc_info); } + + +/* + Usage + + DBUG_EXECUTE_IF("show_explain_probe_2", + if (dbug_user_var_equals_int(thd, "select_id", select_id)) + dbug_serve_apcs(thd, 1); + ); + +*/ + +bool dbug_user_var_equals_int(THD *thd, const char *name, int value) +{ + user_var_entry *var; + LEX_STRING varname= {(char*)name, strlen(name)}; + if ((var= get_variable(&thd->user_vars, varname, FALSE))) + { + bool null_value; + longlong var_value= var->val_int(&null_value); + if (!null_value && var_value == value) + return TRUE; + } + return FALSE; +} #endif + /** This handles SELECT with and without UNION. */ @@ -2067,7 +2093,13 @@ void JOIN::exec_inner() int tmp_error; DBUG_ENTER("JOIN::exec"); - DBUG_EXECUTE_IF("show_explain_probe_1", dbug_serve_apcs(thd, 1);); + DBUG_EXECUTE_IF("show_explain_probe_2", dbug_serve_apcs(thd, 1);); + DBUG_EXECUTE_IF("show_explain_probe_1", + if (dbug_user_var_equals_int(thd, + "show_explain_probe_select_id", + select_lex->select_number)) + dbug_serve_apcs(thd, 1); + ); thd_proc_info(thd, "executing"); error= 0; @@ -20397,8 +20429,8 @@ void JOIN::clear() /** EXPLAIN handling. - Send a description about what how the select will be done to stdout. - + Produce lines explaining execution of *this* select (not including children + selects) @param on_the_fly TRUE <=> we're being executed on-the-fly, so don't make modifications to any select's data structures */ From 2bf31b094118059b6a488c7f1f8f97dfe3d829a3 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Mon, 26 Sep 2011 18:24:49 +0400 Subject: [PATCH 009/289] Don't run show_explain.test for embedded server (the patch explains why) --- mysql-test/t/show_explain.test | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/mysql-test/t/show_explain.test b/mysql-test/t/show_explain.test index 4ed625c5bca..dc54ebb9c52 100644 --- a/mysql-test/t/show_explain.test +++ b/mysql-test/t/show_explain.test @@ -7,6 +7,28 @@ drop table if exists t0, t1; --enable_warnings +# +# Testcases in this file do not work with embedded server. The reason for this +# is that we use the following commands for synchronization: +# +# set @show_explain_probe_select_id=1; +# set debug='d,show_explain_probe_1'; +# send select count(*) from t1 where a < 100000; +# +# When ran with mysqltest_embedded, this translates into: +# +# Thread1> DBUG_PUSH("d,show_explain_probe_1"); +# Thread1> create another thread for doing "send ... reap" +# Thread2> mysql_parse("select count(*) from t1 where a < 100000"); +# +# That is, "select count(*) ..." is ran in a thread for which DBUG_PUSH(...) +# has not been called. As a result, show_explain_probe_1 does not fire, and +# "select count(*) ..." does not wait till its SHOW EXPLAIN command, and the +# test fails. +# +-- source include/not_embedded.inc + + create table t0 (a int); insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); create table t1 (a int); From b7a340eeb0acceb23fbc9cb5684200aaff790f98 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Thu, 27 Oct 2011 01:12:02 +0400 Subject: [PATCH 010/289] Fix SHOW EXPLAIN for UNIONs. --- sql/sql_lex.cc | 5 ++ sql/sql_select.cc | 148 +++++++++++++++++++++++++--------------------- sql/sql_select.h | 3 + 3 files changed, 88 insertions(+), 68 deletions(-) diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 3d2f7013a35..f42b9d9ee0e 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -3667,6 +3667,11 @@ int st_select_lex_unit::print_explain(select_result_sink *output) if ((res= sl->print_explain(output))) break; } + if (!fake_select_lex->join) + { + res= print_fake_select_lex_join(output, TRUE /* on the fly */, + fake_select_lex, 0 /* flags */); + } return res; } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 1d2c8a10b75..ee06ce0c8a6 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -20425,6 +20425,83 @@ void JOIN::clear() } } +int print_fake_select_lex_join(select_result_sink *result, bool on_the_fly, + SELECT_LEX *select_lex, uint8 select_options) +{ + const CHARSET_INFO *cs= system_charset_info; + Item *item_null= new Item_null(); + List item_list; + if (on_the_fly) + select_lex->set_explain_type(on_the_fly); //psergey + /* + here we assume that the query will return at least two rows, so we + show "filesort" in EXPLAIN. Of course, sometimes we'll be wrong + and no filesort will be actually done, but executing all selects in + the UNION to provide precise EXPLAIN information will hardly be + appreciated :) + */ + char table_name_buffer[SAFE_NAME_LEN]; + item_list.empty(); + /* id */ + item_list.push_back(new Item_null); + /* select_type */ + item_list.push_back(new Item_string(select_lex->type, + strlen(select_lex->type), + cs)); + /* table */ + { + SELECT_LEX *sl= select_lex->master_unit()->first_select(); + uint len= 6, lastop= 0; + memcpy(table_name_buffer, STRING_WITH_LEN("next_select()) + { + len+= lastop; + lastop= my_snprintf(table_name_buffer + len, NAME_LEN - len, + "%u,", sl->select_number); + } + if (sl || len + lastop >= NAME_LEN) + { + memcpy(table_name_buffer + len, STRING_WITH_LEN("...>") + 1); + len+= 4; + } + else + { + len+= lastop; + table_name_buffer[len - 1]= '>'; // change ',' to '>' + } + item_list.push_back(new Item_string(table_name_buffer, len, cs)); + } + /* partitions */ + if (/*join->thd->lex->describe*/ select_options & DESCRIBE_PARTITIONS) + item_list.push_back(item_null); + /* type */ + item_list.push_back(new Item_string(join_type_str[JT_ALL], + strlen(join_type_str[JT_ALL]), + cs)); + /* possible_keys */ + item_list.push_back(item_null); + /* key*/ + item_list.push_back(item_null); + /* key_len */ + item_list.push_back(item_null); + /* ref */ + item_list.push_back(item_null); + /* in_rows */ + if (select_options & DESCRIBE_EXTENDED) + item_list.push_back(item_null); + /* rows */ + item_list.push_back(item_null); + /* extra */ + if (select_lex->master_unit()->global_parameters->order_list.first) + item_list.push_back(new Item_string("Using filesort", + 14, cs)); + else + item_list.push_back(new Item_string("", 0, cs)); + + if (result->send_data(item_list)) + return 1; + return 0; +} /** EXPLAIN handling. @@ -20483,74 +20560,9 @@ int JOIN::print_explain(select_result_sink *result, bool on_the_fly, } else if (join->select_lex == join->unit->fake_select_lex) { - if (on_the_fly) - join->select_lex->set_explain_type(on_the_fly); //psergey - /* - here we assume that the query will return at least two rows, so we - show "filesort" in EXPLAIN. Of course, sometimes we'll be wrong - and no filesort will be actually done, but executing all selects in - the UNION to provide precise EXPLAIN information will hardly be - appreciated :) - */ - char table_name_buffer[SAFE_NAME_LEN]; - item_list.empty(); - /* id */ - item_list.push_back(new Item_null); - /* select_type */ - item_list.push_back(new Item_string(join->select_lex->type, - strlen(join->select_lex->type), - cs)); - /* table */ - { - SELECT_LEX *sl= join->unit->first_select(); - uint len= 6, lastop= 0; - memcpy(table_name_buffer, STRING_WITH_LEN("next_select()) - { - len+= lastop; - lastop= my_snprintf(table_name_buffer + len, NAME_LEN - len, - "%u,", sl->select_number); - } - if (sl || len + lastop >= NAME_LEN) - { - memcpy(table_name_buffer + len, STRING_WITH_LEN("...>") + 1); - len+= 4; - } - else - { - len+= lastop; - table_name_buffer[len - 1]= '>'; // change ',' to '>' - } - item_list.push_back(new Item_string(table_name_buffer, len, cs)); - } - /* partitions */ - if (join->thd->lex->describe & DESCRIBE_PARTITIONS) - item_list.push_back(item_null); - /* type */ - item_list.push_back(new Item_string(join_type_str[JT_ALL], - strlen(join_type_str[JT_ALL]), - cs)); - /* possible_keys */ - item_list.push_back(item_null); - /* key*/ - item_list.push_back(item_null); - /* key_len */ - item_list.push_back(item_null); - /* ref */ - item_list.push_back(item_null); - /* in_rows */ - if (join->thd->lex->describe & DESCRIBE_EXTENDED) - item_list.push_back(item_null); - /* rows */ - item_list.push_back(item_null); - /* extra */ - if (join->unit->global_parameters->order_list.first) - item_list.push_back(new Item_string("Using filesort", - 14, cs)); - else - item_list.push_back(new Item_string("", 0, cs)); - - if (result->send_data(item_list)) + if (print_fake_select_lex_join(result, on_the_fly, + join->select_lex, + join->thd->lex->describe)) error= 1; } else if (!join->select_lex->master_unit()->derived || diff --git a/sql/sql_select.h b/sql/sql_select.h index f329f51707f..d6379f3ea92 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -1465,6 +1465,9 @@ inline bool optimizer_flag(THD *thd, uint flag) return (thd->variables.optimizer_switch & flag); } +int print_fake_select_lex_join(select_result_sink *result, bool on_the_fly, + SELECT_LEX *select_lex, uint8 select_options); + /* Table elimination entry point function */ void eliminate_tables(JOIN *join); From ba09d25abc1fd3dbe55f1d7974cfe6a1ebda4df0 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Thu, 27 Oct 2011 21:34:41 +0400 Subject: [PATCH 011/289] Fix typo bug in UNION handling, add tests for SHOW EXPLAIN for UNION. --- mysql-test/r/show_explain.result | 29 +++++++++++++++++++++++++++++ mysql-test/t/show_explain.test | 26 +++++++++++++++++++++++++- sql/sql_lex.cc | 6 +++++- 3 files changed, 59 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/show_explain.result b/mysql-test/r/show_explain.result index 874af6e720e..9197cc353c6 100644 --- a/mysql-test/r/show_explain.result +++ b/mysql-test/r/show_explain.result @@ -28,6 +28,8 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range a a 5 NULL 10 Using where max(c) 9 +# We can catch EXPLAIN, too. +set @show_expl_tmp= @@optimizer_switch; set optimizer_switch='index_condition_pushdown=on,mrr=on,mrr_sort_keys=on'; explain select max(c) from t1 where a < 10; show explain for $thr2; @@ -35,4 +37,31 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range a a 5 NULL 10 Using index condition; Rowid-ordered scan id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range a a 5 NULL 10 Using index condition; Rowid-ordered scan +set optimizer_switch= @show_expl_tmp; +# UNION, first branch +set @show_explain_probe_select_id=1; +set debug='d,show_explain_probe_1'; +explain select a from t0 A union select a+1 from t0 B; +show explain for $thr2; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY A ALL NULL NULL NULL NULL 10 +2 UNION B ALL NULL NULL NULL NULL 10 +NULL UNION RESULT ALL NULL NULL NULL NULL NULL +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY A ALL NULL NULL NULL NULL 10 +2 UNION B ALL NULL NULL NULL NULL 10 +NULL UNION RESULT ALL NULL NULL NULL NULL NULL +# UNION, second branch +set @show_explain_probe_select_id=1; +set debug='d,show_explain_probe_1'; +explain select a from t0 A union select a+1 from t0 B; +show explain for $thr2; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY A ALL NULL NULL NULL NULL 10 +2 UNION B ALL NULL NULL NULL NULL 10 +NULL UNION RESULT ALL NULL NULL NULL NULL NULL +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY A ALL NULL NULL NULL NULL 10 +2 UNION B ALL NULL NULL NULL NULL 10 +NULL UNION RESULT ALL NULL NULL NULL NULL NULL drop table t0,t1; diff --git a/mysql-test/t/show_explain.test b/mysql-test/t/show_explain.test index dc54ebb9c52..77d79fc78b3 100644 --- a/mysql-test/t/show_explain.test +++ b/mysql-test/t/show_explain.test @@ -87,7 +87,9 @@ evalp show explain for $thr2; connection con1; reap; -# We can catch EXPLAIN, too. + +--echo # We can catch EXPLAIN, too. +set @show_expl_tmp= @@optimizer_switch; set optimizer_switch='index_condition_pushdown=on,mrr=on,mrr_sort_keys=on'; send explain select max(c) from t1 where a < 10; connection default; @@ -95,6 +97,28 @@ connection default; evalp show explain for $thr2; connection con1; reap; +set optimizer_switch= @show_expl_tmp; + + +--echo # UNION, first branch +set @show_explain_probe_select_id=1; +set debug='d,show_explain_probe_1'; +send explain select a from t0 A union select a+1 from t0 B; +connection default; +--source include/wait_condition.inc +evalp show explain for $thr2; +connection con1; +reap; + +--echo # UNION, second branch +set @show_explain_probe_select_id=1; +set debug='d,show_explain_probe_1'; +send explain select a from t0 A union select a+1 from t0 B; +connection default; +--source include/wait_condition.inc +evalp show explain for $thr2; +connection con1; +reap; # Let's try with a subquery diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index f42b9d9ee0e..917502f2b5b 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -3667,7 +3667,11 @@ int st_select_lex_unit::print_explain(select_result_sink *output) if ((res= sl->print_explain(output))) break; } - if (!fake_select_lex->join) + + /* + Note: it could be that fake_select_lex->join == NULL still at this point + */ + if (fake_select_lex && !fake_select_lex->join) { res= print_fake_select_lex_join(output, TRUE /* on the fly */, fake_select_lex, 0 /* flags */); From ca020dfa9e8668ce52eaff92c157097bba671ec1 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Fri, 28 Oct 2011 02:30:02 +0400 Subject: [PATCH 012/289] MWL#182: Explain running statements - Get subqueries to work, part #1. --- mysql-test/r/show_explain.result | 61 ++++++++++++++++++++++++++++ mysql-test/t/show_explain.test | 69 +++++++++++++++++++++++++++++++- sql/sql_lex.cc | 17 ++++++++ sql/sql_select.cc | 11 ++++- 4 files changed, 155 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/show_explain.result b/mysql-test/r/show_explain.result index 9197cc353c6..b8b732f9607 100644 --- a/mysql-test/r/show_explain.result +++ b/mysql-test/r/show_explain.result @@ -64,4 +64,65 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY A ALL NULL NULL NULL NULL 10 2 UNION B ALL NULL NULL NULL NULL 10 NULL UNION RESULT ALL NULL NULL NULL NULL NULL +# Uncorrelated subquery, select +set @show_explain_probe_select_id=1; +set debug='d,show_explain_probe_1'; +select a, (select max(a) from t0 B) from t0 A where a<1; +show explain for $thr2; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY A ALL NULL NULL NULL NULL 10 Using where +2 SUBQUERY B ALL NULL NULL NULL NULL 10 +a (select max(a) from t0 B) +0 9 +# Uncorrelated subquery, explain +set @show_explain_probe_select_id=1; +set debug='d,show_explain_probe_1'; +explain select a, (select max(a) from t0 B) from t0 A where a<1; +show explain for $thr2; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY A ALL NULL NULL NULL NULL 10 Using where +2 SUBQUERY B ALL NULL NULL NULL NULL 10 +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY A ALL NULL NULL NULL NULL 10 Using where +2 SUBQUERY B ALL NULL NULL NULL NULL 10 +# correlated subquery, select +set @show_explain_probe_select_id=1; +set debug='d,show_explain_probe_1'; +select a, (select max(a) from t0 b where b.a+a.a<10) from t0 a where a<1; +show explain for $thr2; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY a ALL NULL NULL NULL NULL 10 Using where +2 DEPENDENT SUBQUERY b ALL NULL NULL NULL NULL 10 Using where +a (select max(a) from t0 b where b.a+a.a<10) +0 9 +# correlated subquery, explain +set @show_explain_probe_select_id=1; +set debug='d,show_explain_probe_1'; +select a, (select max(a) from t0 b where b.a+a.a<10) from t0 a where a<1; +show explain for $thr2; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY a ALL NULL NULL NULL NULL 10 Using where +2 DEPENDENT SUBQUERY b ALL NULL NULL NULL NULL 10 Using where +a (select max(a) from t0 b where b.a+a.a<10) +0 9 +# correlated subquery, select, while inside the subquery +set @show_explain_probe_select_id=2; +set debug='d,show_explain_probe_1'; +select a, (select max(a) from t0 b where b.a+a.a<10) from t0 a where a<1; +show explain for $thr2; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY a ALL NULL NULL NULL NULL 10 Using where +2 DEPENDENT SUBQUERY b ALL NULL NULL NULL NULL 10 Using where +a (select max(a) from t0 b where b.a+a.a<10) +0 9 +# correlated subquery, explain, while inside the subquery +set @show_explain_probe_select_id=2; +set debug='d,show_explain_probe_1'; +select a, (select max(a) from t0 b where b.a+a.a<10) from t0 a where a<1; +show explain for $thr2; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY a ALL NULL NULL NULL NULL 10 Using where +2 DEPENDENT SUBQUERY b ALL NULL NULL NULL NULL 10 Using where +a (select max(a) from t0 b where b.a+a.a<10) +0 9 drop table t0,t1; diff --git a/mysql-test/t/show_explain.test b/mysql-test/t/show_explain.test index 77d79fc78b3..5ed78be1ea4 100644 --- a/mysql-test/t/show_explain.test +++ b/mysql-test/t/show_explain.test @@ -110,6 +110,7 @@ evalp show explain for $thr2; connection con1; reap; + --echo # UNION, second branch set @show_explain_probe_select_id=1; set debug='d,show_explain_probe_1'; @@ -120,7 +121,73 @@ evalp show explain for $thr2; connection con1; reap; -# Let's try with a subquery + +--echo # Uncorrelated subquery, select +set @show_explain_probe_select_id=1; +set debug='d,show_explain_probe_1'; +send select a, (select max(a) from t0 B) from t0 A where a<1; +connection default; +--source include/wait_condition.inc +evalp show explain for $thr2; +connection con1; +reap; + + +--echo # Uncorrelated subquery, explain +set @show_explain_probe_select_id=1; +set debug='d,show_explain_probe_1'; +send explain select a, (select max(a) from t0 B) from t0 A where a<1; +connection default; +--source include/wait_condition.inc +evalp show explain for $thr2; +connection con1; +reap; + +--echo # correlated subquery, select +set @show_explain_probe_select_id=1; +set debug='d,show_explain_probe_1'; +send select a, (select max(a) from t0 b where b.a+a.a<10) from t0 a where a<1; +connection default; +--source include/wait_condition.inc +evalp show explain for $thr2; +connection con1; +reap; + +--echo # correlated subquery, explain +set @show_explain_probe_select_id=1; +set debug='d,show_explain_probe_1'; +send select a, (select max(a) from t0 b where b.a+a.a<10) from t0 a where a<1; +connection default; +--source include/wait_condition.inc +evalp show explain for $thr2; +connection con1; +reap; + +--echo # correlated subquery, select, while inside the subquery +set @show_explain_probe_select_id=2; # <--- +set debug='d,show_explain_probe_1'; +send select a, (select max(a) from t0 b where b.a+a.a<10) from t0 a where a<1; +connection default; +--source include/wait_condition.inc +evalp show explain for $thr2; +connection con1; +reap; + +--echo # correlated subquery, explain, while inside the subquery +set @show_explain_probe_select_id=2; +set debug='d,show_explain_probe_1'; +send select a, (select max(a) from t0 b where b.a+a.a<10) from t0 a where a<1; +connection default; +--source include/wait_condition.inc +evalp show explain for $thr2; +connection con1; +reap; + + +# TODO: explain in the parent subuqery when the un-correlated child has been +# run (and have done irreversible cleanups) + +# TODO: hit JOIN::optimize for non-select commands: UPDATE/DELETE, SET. ## TODO: Test this: multiple SHOW EXPLAIN calls in course of running of one select diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 9aee5caeb64..3b355a312af 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -3706,6 +3706,22 @@ int st_select_lex::print_explain(select_result_sink *output) FALSE, // bool need_order, FALSE, // bool distinct, NULL); //const char *message + if (res) + goto err; + + for (SELECT_LEX_UNIT *unit= join->select_lex->first_inner_unit(); + unit; + unit= unit->next_unit()) + { + /* + Display subqueries only if they are not parts of eliminated WHERE/ON + clauses. + */ + if (!(unit->item && unit->item->eliminated)) + { + unit->print_explain(output); + } + } } else { @@ -3717,6 +3733,7 @@ int st_select_lex::print_explain(select_result_sink *output) FALSE, // bool distinct, msg); //const char *message } +err: return 0; } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 4dc99cf006c..fcbd2615b9c 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -265,7 +265,9 @@ void dbug_serve_apcs(THD *thd, int n_calls) /* - Usage + Debugging: check if @name=value, comparing as integer + + Intended usage: DBUG_EXECUTE_IF("show_explain_probe_2", if (dbug_user_var_equals_int(thd, "select_id", select_id)) @@ -2102,7 +2104,6 @@ void JOIN::exec_inner() int tmp_error; DBUG_ENTER("JOIN::exec"); - DBUG_EXECUTE_IF("show_explain_probe_2", dbug_serve_apcs(thd, 1);); DBUG_EXECUTE_IF("show_explain_probe_1", if (dbug_user_var_equals_int(thd, "show_explain_probe_select_id", @@ -20516,6 +20517,7 @@ void JOIN::clear() } } + int print_fake_select_lex_join(select_result_sink *result, bool on_the_fly, SELECT_LEX *select_lex, uint8 select_options) { @@ -20594,6 +20596,7 @@ int print_fake_select_lex_join(select_result_sink *result, bool on_the_fly, return 0; } + /** EXPLAIN handling. @@ -21162,6 +21165,10 @@ int JOIN::print_explain(select_result_sink *result, bool on_the_fly, } +/* + See st_select_lex::print_explain() for the SHOW EXPLAIN counterpart +*/ + static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, bool distinct,const char *message) { From ee40ee9cb8c9bc673ba345abe260c9da7a05e45a Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Wed, 4 Jan 2012 04:57:01 +0400 Subject: [PATCH 013/289] Apply earlier patch: correct handling of subqueries that were not yet optimized or already executed and deleted. --- mysql-test/r/show_explain.result | 29 +++++++---- mysql-test/t/show_explain.test | 37 +++++++++----- sql/sql_lex.cc | 40 ++++++++++----- sql/sql_select.cc | 88 +++++++++++++++++++++++++++----- sql/sql_select.h | 5 +- 5 files changed, 150 insertions(+), 49 deletions(-) diff --git a/mysql-test/r/show_explain.result b/mysql-test/r/show_explain.result index b8b732f9607..e40c3b77780 100644 --- a/mysql-test/r/show_explain.result +++ b/mysql-test/r/show_explain.result @@ -15,7 +15,7 @@ ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EX show explain for $thr1; ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EXPLAINable command set @show_explain_probe_select_id=1; -set debug='d,show_explain_probe_1'; +set debug='d,show_explain_probe_join_exec_start'; select count(*) from t1 where a < 100000; show explain for $thr2; id select_type table type possible_keys key key_len ref rows Extra @@ -25,7 +25,7 @@ count(*) select max(c) from t1 where a < 10; show explain for $thr2; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range a a 5 NULL 10 Using where +1 SIMPLE t1 range a a 5 NULL 10 Using index condition max(c) 9 # We can catch EXPLAIN, too. @@ -40,7 +40,7 @@ id select_type table type possible_keys key key_len ref rows Extra set optimizer_switch= @show_expl_tmp; # UNION, first branch set @show_explain_probe_select_id=1; -set debug='d,show_explain_probe_1'; +set debug='d,show_explain_probe_join_exec_start'; explain select a from t0 A union select a+1 from t0 B; show explain for $thr2; id select_type table type possible_keys key key_len ref rows Extra @@ -53,7 +53,7 @@ id select_type table type possible_keys key key_len ref rows Extra NULL UNION RESULT ALL NULL NULL NULL NULL NULL # UNION, second branch set @show_explain_probe_select_id=1; -set debug='d,show_explain_probe_1'; +set debug='d,show_explain_probe_join_exec_start'; explain select a from t0 A union select a+1 from t0 B; show explain for $thr2; id select_type table type possible_keys key key_len ref rows Extra @@ -66,7 +66,7 @@ id select_type table type possible_keys key key_len ref rows Extra NULL UNION RESULT ALL NULL NULL NULL NULL NULL # Uncorrelated subquery, select set @show_explain_probe_select_id=1; -set debug='d,show_explain_probe_1'; +set debug='d,show_explain_probe_join_exec_start'; select a, (select max(a) from t0 B) from t0 A where a<1; show explain for $thr2; id select_type table type possible_keys key key_len ref rows Extra @@ -76,7 +76,7 @@ a (select max(a) from t0 B) 0 9 # Uncorrelated subquery, explain set @show_explain_probe_select_id=1; -set debug='d,show_explain_probe_1'; +set debug='d,show_explain_probe_join_exec_start'; explain select a, (select max(a) from t0 B) from t0 A where a<1; show explain for $thr2; id select_type table type possible_keys key key_len ref rows Extra @@ -87,7 +87,7 @@ id select_type table type possible_keys key key_len ref rows Extra 2 SUBQUERY B ALL NULL NULL NULL NULL 10 # correlated subquery, select set @show_explain_probe_select_id=1; -set debug='d,show_explain_probe_1'; +set debug='d,show_explain_probe_join_exec_start'; select a, (select max(a) from t0 b where b.a+a.a<10) from t0 a where a<1; show explain for $thr2; id select_type table type possible_keys key key_len ref rows Extra @@ -97,7 +97,7 @@ a (select max(a) from t0 b where b.a+a.a<10) 0 9 # correlated subquery, explain set @show_explain_probe_select_id=1; -set debug='d,show_explain_probe_1'; +set debug='d,show_explain_probe_join_exec_start'; select a, (select max(a) from t0 b where b.a+a.a<10) from t0 a where a<1; show explain for $thr2; id select_type table type possible_keys key key_len ref rows Extra @@ -107,7 +107,7 @@ a (select max(a) from t0 b where b.a+a.a<10) 0 9 # correlated subquery, select, while inside the subquery set @show_explain_probe_select_id=2; -set debug='d,show_explain_probe_1'; +set debug='d,show_explain_probe_join_exec_start'; select a, (select max(a) from t0 b where b.a+a.a<10) from t0 a where a<1; show explain for $thr2; id select_type table type possible_keys key key_len ref rows Extra @@ -117,7 +117,7 @@ a (select max(a) from t0 b where b.a+a.a<10) 0 9 # correlated subquery, explain, while inside the subquery set @show_explain_probe_select_id=2; -set debug='d,show_explain_probe_1'; +set debug='d,show_explain_probe_join_exec_start'; select a, (select max(a) from t0 b where b.a+a.a<10) from t0 a where a<1; show explain for $thr2; id select_type table type possible_keys key key_len ref rows Extra @@ -125,4 +125,13 @@ id select_type table type possible_keys key key_len ref rows Extra 2 DEPENDENT SUBQUERY b ALL NULL NULL NULL NULL 10 Using where a (select max(a) from t0 b where b.a+a.a<10) 0 9 +# correlated subquery, explain, while inside the subquery +set @show_explain_probe_select_id=1; +set debug='d,show_explain_probe_join_exec_end'; +select a, (select max(a) from t0 b where b.a+a.a<10) from t0 a where a<1; +show explain for $thr2; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Query plan already deleted +a (select max(a) from t0 b where b.a+a.a<10) +0 9 drop table t0,t1; diff --git a/mysql-test/t/show_explain.test b/mysql-test/t/show_explain.test index 5ed78be1ea4..4f04447d039 100644 --- a/mysql-test/t/show_explain.test +++ b/mysql-test/t/show_explain.test @@ -12,17 +12,17 @@ drop table if exists t0, t1; # is that we use the following commands for synchronization: # # set @show_explain_probe_select_id=1; -# set debug='d,show_explain_probe_1'; +# set debug='d,show_explain_probe_join_exec_start'; # send select count(*) from t1 where a < 100000; # # When ran with mysqltest_embedded, this translates into: # -# Thread1> DBUG_PUSH("d,show_explain_probe_1"); +# Thread1> DBUG_PUSH("d,show_explain_probe_join_exec_start"); # Thread1> create another thread for doing "send ... reap" # Thread2> mysql_parse("select count(*) from t1 where a < 100000"); # # That is, "select count(*) ..." is ran in a thread for which DBUG_PUSH(...) -# has not been called. As a result, show_explain_probe_1 does not fire, and +# has not been called. As a result, show_explain_probe_join_exec_start does not fire, and # "select count(*) ..." does not wait till its SHOW EXPLAIN command, and the # test fails. # @@ -70,7 +70,7 @@ let $wait_condition= select State='show_explain_trap' from information_schema.pr # connection con1; set @show_explain_probe_select_id=1; -set debug='d,show_explain_probe_1'; +set debug='d,show_explain_probe_join_exec_start'; send select count(*) from t1 where a < 100000; connection default; @@ -102,7 +102,7 @@ set optimizer_switch= @show_expl_tmp; --echo # UNION, first branch set @show_explain_probe_select_id=1; -set debug='d,show_explain_probe_1'; +set debug='d,show_explain_probe_join_exec_start'; send explain select a from t0 A union select a+1 from t0 B; connection default; --source include/wait_condition.inc @@ -113,7 +113,7 @@ reap; --echo # UNION, second branch set @show_explain_probe_select_id=1; -set debug='d,show_explain_probe_1'; +set debug='d,show_explain_probe_join_exec_start'; send explain select a from t0 A union select a+1 from t0 B; connection default; --source include/wait_condition.inc @@ -124,7 +124,7 @@ reap; --echo # Uncorrelated subquery, select set @show_explain_probe_select_id=1; -set debug='d,show_explain_probe_1'; +set debug='d,show_explain_probe_join_exec_start'; send select a, (select max(a) from t0 B) from t0 A where a<1; connection default; --source include/wait_condition.inc @@ -135,7 +135,7 @@ reap; --echo # Uncorrelated subquery, explain set @show_explain_probe_select_id=1; -set debug='d,show_explain_probe_1'; +set debug='d,show_explain_probe_join_exec_start'; send explain select a, (select max(a) from t0 B) from t0 A where a<1; connection default; --source include/wait_condition.inc @@ -145,7 +145,7 @@ reap; --echo # correlated subquery, select set @show_explain_probe_select_id=1; -set debug='d,show_explain_probe_1'; +set debug='d,show_explain_probe_join_exec_start'; send select a, (select max(a) from t0 b where b.a+a.a<10) from t0 a where a<1; connection default; --source include/wait_condition.inc @@ -155,7 +155,7 @@ reap; --echo # correlated subquery, explain set @show_explain_probe_select_id=1; -set debug='d,show_explain_probe_1'; +set debug='d,show_explain_probe_join_exec_start'; send select a, (select max(a) from t0 b where b.a+a.a<10) from t0 a where a<1; connection default; --source include/wait_condition.inc @@ -165,7 +165,7 @@ reap; --echo # correlated subquery, select, while inside the subquery set @show_explain_probe_select_id=2; # <--- -set debug='d,show_explain_probe_1'; +set debug='d,show_explain_probe_join_exec_start'; send select a, (select max(a) from t0 b where b.a+a.a<10) from t0 a where a<1; connection default; --source include/wait_condition.inc @@ -175,7 +175,7 @@ reap; --echo # correlated subquery, explain, while inside the subquery set @show_explain_probe_select_id=2; -set debug='d,show_explain_probe_1'; +set debug='d,show_explain_probe_join_exec_start'; send select a, (select max(a) from t0 b where b.a+a.a<10) from t0 a where a<1; connection default; --source include/wait_condition.inc @@ -184,6 +184,16 @@ connection con1; reap; +--echo # correlated subquery, explain, while inside the subquery +set @show_explain_probe_select_id=1; +set debug='d,show_explain_probe_join_exec_end'; +send select a, (select max(a) from t0 b where b.a+a.a<10) from t0 a where a<1; +connection default; +--source include/wait_condition.inc +evalp show explain for $thr2; +connection con1; +reap; + # TODO: explain in the parent subuqery when the un-correlated child has been # run (and have done irreversible cleanups) @@ -195,4 +205,7 @@ reap; ## TODO: Test this: have several SHOW EXPLAIN requests be queued up for a ## thread and served together. +## TODO: SHOW EXPLAIN while the primary query is running EXPLAIN EXTENDED/PARTITIONS +## + drop table t0,t1; diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index a1560953cd5..667d5a80c96 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -3555,16 +3555,11 @@ void st_select_lex::set_explain_type(bool on_the_fly) using_materialization= TRUE; } - if (this == master_unit()->fake_select_lex) - type= "UNION RESULT"; - if (&master_unit()->thd->lex->select_lex == this) { type= is_primary ? "PRIMARY" : "SIMPLE"; } - - if (!on_the_fly) - // else + else { if (this == first) { @@ -3594,9 +3589,14 @@ void st_select_lex::set_explain_type(bool on_the_fly) else { type= is_uncacheable ? "UNCACHEABLE UNION": "UNION"; + if (this == master_unit()->fake_select_lex) + type= "UNION RESULT"; + } } } + + if (!on_the_fly) options|= SELECT_DESCRIBE; } @@ -3744,10 +3744,17 @@ bool st_select_lex::is_merged_child_of(st_select_lex *ancestor) } +int print_explain_message_line(select_result_sink *result, + SELECT_LEX *select_lex, + bool on_the_fly, + uint8 options, + const char *message); + + int st_select_lex::print_explain(select_result_sink *output) { int res; - if (join && join->optimized == 2) + if (join && join->have_query_plan == JOIN::QEP_AVAILABLE) { res= join->print_explain(output, TRUE, FALSE, // need_tmp_table, @@ -3773,13 +3780,18 @@ int st_select_lex::print_explain(select_result_sink *output) } else { - /* Produce "not yet optimized" line */ - const char *msg="Not yet optimized"; - res= join->print_explain(output, TRUE, - FALSE, // need_tmp_table, - FALSE, // bool need_order, - FALSE, // bool distinct, - msg); //const char *message + const char *msg; + if (!join) + DBUG_ASSERT(0); // psergey: TODO: can this happen or not? + if (join->have_query_plan == JOIN::QEP_NOT_PRESENT_YET) + msg= "Not yet optimized"; + else + { + DBUG_ASSERT(join->have_query_plan == JOIN::QEP_DELETED); + msg= "Query plan already deleted"; + } + res= print_explain_message_line(output, this, TRUE /* on_the_fly */, + 0, msg); } err: return 0; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 6bed898ce5e..4b6ee431f05 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -931,7 +931,8 @@ err: int JOIN::optimize() { int res= optimize_inner(); - optimized= 2; + if (!res) + have_query_plan= QEP_AVAILABLE; return res; } /** @@ -2104,7 +2105,22 @@ void JOIN::exec() Enable SHOW EXPLAIN only if we're in the top-level query. */ thd->apc_target.enable(); + DBUG_EXECUTE_IF("show_explain_probe_join_exec_start", + if (dbug_user_var_equals_int(thd, + "show_explain_probe_select_id", + select_lex->select_number)) + dbug_serve_apcs(thd, 1); + ); + exec_inner(); + + DBUG_EXECUTE_IF("show_explain_probe_join_exec_end", + if (dbug_user_var_equals_int(thd, + "show_explain_probe_select_id", + select_lex->select_number)) + dbug_serve_apcs(thd, 1); + ); + thd->apc_target.disable(); } @@ -2127,13 +2143,6 @@ void JOIN::exec_inner() int tmp_error; DBUG_ENTER("JOIN::exec"); - DBUG_EXECUTE_IF("show_explain_probe_1", - if (dbug_user_var_equals_int(thd, - "show_explain_probe_select_id", - select_lex->select_number)) - dbug_serve_apcs(thd, 1); - ); - thd_proc_info(thd, "executing"); error= 0; if (procedure) @@ -2421,9 +2430,17 @@ void JOIN::exec_inner() DBUG_PRINT("info",("Creating group table")); /* Free first data from old join */ + + fprintf(stderr,"Q: %s\n", thd->query()); + //DBUG_ASSERT(0); + /* + psergey-todo: this is the place of pre-mature JOIN::free call. + */ curr_join->join_free(); + //psergey-todo: SHOW EXPLAIN probe here if (curr_join->make_simple_join(this, curr_tmp_table)) DBUG_VOID_RETURN; + //psergey-todo: SHOW EXPLAIN probe here calc_group_buffer(curr_join, group_list); count_field_types(select_lex, &curr_join->tmp_table_param, curr_join->tmp_all_fields1, @@ -2544,7 +2561,9 @@ void JOIN::exec_inner() if (curr_tmp_table->distinct) curr_join->select_distinct=0; /* Each row is unique */ + //psergey-todo: SHOW EXPLAIN probe here curr_join->join_free(); /* Free quick selects */ + //psergey-todo: SHOW EXPLAIN probe here if (curr_join->select_distinct && ! curr_join->group_list) { thd_proc_info(thd, "Removing duplicates"); @@ -10113,7 +10132,8 @@ void JOIN::cleanup(bool full) { DBUG_ENTER("JOIN::cleanup"); DBUG_PRINT("enter", ("full %u", (uint) full)); - + + have_query_plan= QEP_DELETED; if (table) { JOIN_TAB *tab; @@ -20706,6 +20726,41 @@ void JOIN::clear() } +/* + Print an EXPLAIN line with all NULLs and given message in the 'Extra' column +*/ +int print_explain_message_line(select_result_sink *result, + SELECT_LEX *select_lex, + bool on_the_fly, + uint8 options, + const char *message) +{ + const CHARSET_INFO *cs= system_charset_info; + Item *item_null= new Item_null(); + List item_list; + + if (on_the_fly) + select_lex->set_explain_type(on_the_fly); + + item_list.push_back(new Item_int((int32) + select_lex->select_number)); + item_list.push_back(new Item_string(select_lex->type, + strlen(select_lex->type), cs)); + for (uint i=0 ; i < 7; i++) + item_list.push_back(item_null); + if (options & DESCRIBE_PARTITIONS) + item_list.push_back(item_null); + if (options & DESCRIBE_EXTENDED) + item_list.push_back(item_null); + + item_list.push_back(new Item_string(message,strlen(message),cs)); + + if (result->send_data(item_list)) + return 1; + return 0; +} + + int print_fake_select_lex_join(select_result_sink *result, bool on_the_fly, SELECT_LEX *select_lex, uint8 select_options) { @@ -20810,7 +20865,7 @@ int JOIN::print_explain(select_result_sink *result, bool on_the_fly, DBUG_PRINT("info", ("Select 0x%lx, type %s, message %s", (ulong)join->select_lex, join->select_lex->type, message ? message : "NULL")); - DBUG_ASSERT(this->optimized == 2); + DBUG_ASSERT(this->have_query_plan == QEP_AVAILABLE); /* Don't log this into the slow query log */ if (!on_the_fly) @@ -20825,7 +20880,9 @@ int JOIN::print_explain(select_result_sink *result, bool on_the_fly, */ if (message) { - item_list.push_back(new Item_int((int32) + // join->thd->lex->describe <- as options +#if 0 + item_list.push_bace(new Item_int((int32) join->select_lex->select_number)); item_list.push_back(new Item_string(join->select_lex->type, strlen(join->select_lex->type), cs)); @@ -20839,9 +20896,16 @@ int JOIN::print_explain(select_result_sink *result, bool on_the_fly, item_list.push_back(new Item_string(message,strlen(message),cs)); if (result->send_data(item_list)) error= 1; +#endif + //psergey-todo: is passing join->thd->lex->describe correct for SHOW EXPLAIN? + if (print_explain_message_line(result, join->select_lex, on_the_fly, + join->thd->lex->describe, message)) + error= 1; + } else if (join->select_lex == join->unit->fake_select_lex) { + //psergey-todo: is passing join->thd->lex->describe correct for SHOW EXPLAIN? if (print_fake_select_lex_join(result, on_the_fly, join->select_lex, join->thd->lex->describe)) @@ -20853,7 +20917,7 @@ int JOIN::print_explain(select_result_sink *result, bool on_the_fly, table_map used_tables=0; //if (!join->select_lex->type) if (on_the_fly) - join->select_lex->set_explain_type(on_the_fly); //psergey-todo: this adds SELECT_DESCRIBE to options! bad for on-the-fly + join->select_lex->set_explain_type(on_the_fly); bool printing_materialize_nest= FALSE; uint select_id= join->select_lex->select_number; diff --git a/sql/sql_select.h b/sql/sql_select.h index ed5a551b1d8..5a60b3b865b 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -1137,8 +1137,10 @@ public: const char *zero_result_cause; ///< not 0 if exec must return zero result bool union_part; ///< this subselect is part of union - int optimized; ///< flag to avoid double optimization in EXPLAIN + bool optimized; ///< flag to avoid double optimization in EXPLAIN bool initialized; ///< flag to avoid double init_execution calls + + enum { QEP_NOT_PRESENT_YET, QEP_AVAILABLE, QEP_DELETED} have_query_plan; /* Additional WHERE and HAVING predicates to be considered for IN=>EXISTS @@ -1221,6 +1223,7 @@ public: ref_pointer_array_size= 0; zero_result_cause= 0; optimized= 0; + have_query_plan= QEP_NOT_PRESENT_YET; initialized= 0; cond_equal= 0; having_equal= 0; From 404a1565bfe02e3ce06843f6c5bf243503a2fe99 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Wed, 4 Jan 2012 04:58:09 +0400 Subject: [PATCH 014/289] bzr ignore libmysqld/my_apc.cc --- .bzrignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.bzrignore b/.bzrignore index a956e0c6ab4..e4fe3e8a9f2 100644 --- a/.bzrignore +++ b/.bzrignore @@ -1982,3 +1982,4 @@ plugin/handler_socket/perl-Net-HandlerSocket/HandlerSocket.bs plugin/handler_socket/perl-Net-HandlerSocket/Makefile.PL libmysqld/gcalc_slicescan.cc libmysqld/gcalc_tools.cc +libmysqld/my_apc.cc From ca8aa3901c5596d8d393f0f0ded5ea7292ed01c8 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Thu, 26 Apr 2012 06:40:36 +0530 Subject: [PATCH 015/289] MWL#182: Explain running statements - Code cleanup --- mysql-test/r/show_explain.result | 58 +++++++++++++++++++++++++- mysql-test/t/show_explain.test | 71 ++++++++++++++++++++++++++++++-- sql/my_apc.cc | 56 ++++++++++++++++++++----- sql/my_apc.h | 63 +++++++++++++++------------- sql/sql_class.cc | 3 +- sql/sql_class.h | 2 + sql/sql_lex.cc | 9 ++++ sql/sql_show.cc | 5 ++- 8 files changed, 220 insertions(+), 47 deletions(-) diff --git a/mysql-test/r/show_explain.result b/mysql-test/r/show_explain.result index 6742c6eacfe..07ccab1419e 100644 --- a/mysql-test/r/show_explain.result +++ b/mysql-test/r/show_explain.result @@ -1,4 +1,4 @@ -drop table if exists t0, t1; +drop table if exists t0, t1, t2; create table t0 (a int); insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); create table t1 (a int); @@ -125,4 +125,60 @@ id select_type table type possible_keys key key_len ref rows Extra 2 DEPENDENT SUBQUERY b ALL NULL NULL NULL NULL 10 Using where a (select max(a) from t0 b where b.a+a.a<10) 0 9 +# Try to do SHOW EXPLAIN for a query that runs a SET command: +# I've found experimentally that select_id==2 here... +# +set @show_explain_probe_select_id=2; +set debug='d,show_explain_probe_1'; +set @foo= (select max(a) from t0 where sin(a) >0); +show explain for $thr2; +ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EXPLAINable command +# +# Attempt SHOW EXPLAIN for an UPDATE +# +create table t2 as select a as a, a as dummy from t0 limit 2; +set @show_explain_probe_select_id=2; +set debug='d,show_explain_probe_1'; +update t2 set dummy=0 where (select max(a) from t0 where t2.a + t0.a <3) >3 ; +show explain for $thr2; +ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EXPLAINable command +show explain for $thr2; +ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EXPLAINable command +drop table t2; +# +# Attempt SHOW EXPLAIN for a DELETE +# +create table t2 as select a as a, a as dummy from t0 limit 2; +set @show_explain_probe_select_id=2; +set debug='d,show_explain_probe_1'; +delete from t2 where (select max(a) from t0 where t2.a + t0.a <3) >3 ; +show explain for $thr2; +ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EXPLAINable command +show explain for $thr2; +ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EXPLAINable command +drop table t2; +# +# Multiple SHOW EXPLAIN calls for one select +# +create table t2 as select a as a, a as dummy from t0 limit 3; +set @show_explain_probe_select_id=2; +set debug='d,show_explain_probe_1'; +select t2.a, ((select max(a) from t0 where t2.a + t0.a <3) >3) as SUBQ from t2; +show explain for $thr2; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t2 ALL NULL NULL NULL NULL 3 +2 DEPENDENT SUBQUERY t0 ALL NULL NULL NULL NULL 10 Using where +show explain for $thr2; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t2 ALL NULL NULL NULL NULL 3 +2 DEPENDENT SUBQUERY t0 ALL NULL NULL NULL NULL 10 Using where +show explain for $thr2; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t2 ALL NULL NULL NULL NULL 3 +2 DEPENDENT SUBQUERY t0 ALL NULL NULL NULL NULL 10 Using where +a SUBQ +0 0 +1 0 +2 0 +drop table t2; drop table t0,t1; diff --git a/mysql-test/t/show_explain.test b/mysql-test/t/show_explain.test index 5ed78be1ea4..717949d5cc5 100644 --- a/mysql-test/t/show_explain.test +++ b/mysql-test/t/show_explain.test @@ -4,7 +4,7 @@ --source include/have_debug.inc --disable_warnings -drop table if exists t0, t1; +drop table if exists t0, t1, t2; --enable_warnings # @@ -186,12 +186,75 @@ reap; # TODO: explain in the parent subuqery when the un-correlated child has been # run (and have done irreversible cleanups) +# ^^ Is this at all possible after 5.3? +# Maybe, for 5.3 try this: +# - run before/after the parent has invoked child's optimization +# - run after materialization -# TODO: hit JOIN::optimize for non-select commands: UPDATE/DELETE, SET. +--echo # Try to do SHOW EXPLAIN for a query that runs a SET command: +--echo # I've found experimentally that select_id==2 here... +--echo # +set @show_explain_probe_select_id=2; +set debug='d,show_explain_probe_1'; +send set @foo= (select max(a) from t0 where sin(a) >0); +connection default; +--source include/wait_condition.inc +--error ER_ERROR_WHEN_EXECUTING_COMMAND +evalp show explain for $thr2; +connection con1; +reap; + +--echo # +--echo # Attempt SHOW EXPLAIN for an UPDATE +--echo # +create table t2 as select a as a, a as dummy from t0 limit 2; +set @show_explain_probe_select_id=2; +set debug='d,show_explain_probe_1'; +send update t2 set dummy=0 where (select max(a) from t0 where t2.a + t0.a <3) >3 ; +connection default; +--source include/wait_condition.inc +--error ER_ERROR_WHEN_EXECUTING_COMMAND +evalp show explain for $thr2; +--error ER_ERROR_WHEN_EXECUTING_COMMAND +evalp show explain for $thr2; +connection con1; +reap; +drop table t2; + +--echo # +--echo # Attempt SHOW EXPLAIN for a DELETE +--echo # +create table t2 as select a as a, a as dummy from t0 limit 2; +set @show_explain_probe_select_id=2; +set debug='d,show_explain_probe_1'; +send delete from t2 where (select max(a) from t0 where t2.a + t0.a <3) >3 ; +connection default; +--source include/wait_condition.inc +--error ER_ERROR_WHEN_EXECUTING_COMMAND +evalp show explain for $thr2; +--error ER_ERROR_WHEN_EXECUTING_COMMAND +evalp show explain for $thr2; +connection con1; +reap; +drop table t2; -## TODO: Test this: multiple SHOW EXPLAIN calls in course of running of one select -## +--echo # +--echo # Multiple SHOW EXPLAIN calls for one select +--echo # +create table t2 as select a as a, a as dummy from t0 limit 3; +set @show_explain_probe_select_id=2; +set debug='d,show_explain_probe_1'; +send select t2.a, ((select max(a) from t0 where t2.a + t0.a <3) >3) as SUBQ from t2; +connection default; +--source include/wait_condition.inc +evalp show explain for $thr2; +evalp show explain for $thr2; +evalp show explain for $thr2; +connection con1; +reap; +drop table t2; + ## TODO: Test this: have several SHOW EXPLAIN requests be queued up for a ## thread and served together. diff --git a/sql/my_apc.cc b/sql/my_apc.cc index 91559483b1f..58290ece56b 100644 --- a/sql/my_apc.cc +++ b/sql/my_apc.cc @@ -24,6 +24,14 @@ */ +/* + Initialize the target. + + @note + Initialization must be done prior to enabling/disabling the target, or making + any call requests to it. + Initial state after initialization is 'disabled'. +*/ void Apc_target::init() { // todo: should use my_pthread_... functions instead? @@ -36,6 +44,9 @@ void Apc_target::init() } +/* + Destroy the target. The target must be disabled when this call is made. +*/ void Apc_target::destroy() { DBUG_ASSERT(!enabled); @@ -43,6 +54,9 @@ void Apc_target::destroy() } +/* + Enter ther state where the target is available for serving APC requests +*/ void Apc_target::enable() { pthread_mutex_lock(&LOCK_apc_queue); @@ -51,6 +65,13 @@ void Apc_target::enable() } +/* + Make the target unavailable for serving APC requests. + + @note + This call will serve all requests that were already enqueued +*/ + void Apc_target::disable() { bool process= FALSE; @@ -62,6 +83,9 @@ void Apc_target::disable() process_apc_requests(); } + +/* (internal) Put request into the request list */ + void Apc_target::enqueue_request(Call_request *qe) { //call_queue_size++; @@ -81,6 +105,13 @@ void Apc_target::enqueue_request(Call_request *qe) } } + +/* + (internal) Remove given request from the request queue. + + The request is not necessarily first in the queue. +*/ + void Apc_target::dequeue_request(Call_request *qe) { //call_queue_size--; @@ -99,8 +130,10 @@ void Apc_target::dequeue_request(Call_request *qe) /* - Make an apc call in another thread. The caller is responsible so - that we're not calling to ourselves. + Make an APC (Async Procedure Call) in another thread. + + The caller is responsible for making sure he's not calling an Apc_target + that is serviced by the same thread it is called from. psergey-todo: Should waits here be KILLable? (it seems one needs to use thd->enter_cond() calls to be killable) @@ -119,7 +152,7 @@ bool Apc_target::make_apc_call(apc_func_t func, void *func_arg, Call_request apc_request; apc_request.func= func; apc_request.func_arg= func_arg; - apc_request.done= FALSE; + apc_request.processed= FALSE; (void)pthread_cond_init(&apc_request.COND_request, NULL); (void)pthread_mutex_init(&apc_request.LOCK_request, MY_MUTEX_INIT_SLOW); pthread_mutex_lock(&apc_request.LOCK_request); @@ -133,19 +166,19 @@ bool Apc_target::make_apc_call(apc_func_t func, void *func_arg, int wait_res= 0; /* todo: how about processing other errors here? */ - while (!apc_request.done && (wait_res != ETIMEDOUT)) + while (!apc_request.processed && (wait_res != ETIMEDOUT)) { wait_res= pthread_cond_timedwait(&apc_request.COND_request, &apc_request.LOCK_request, &abstime); } - if (!apc_request.done) + if (!apc_request.processed) { - /* We timed out */ - apc_request.done= TRUE; + /* The wait has timed out. Remove the request from the queue */ + apc_request.processed= TRUE; *timed_out= TRUE; pthread_mutex_unlock(&apc_request.LOCK_request); - + //psergey-todo: "Whoa rare event" refers to this part, right? put a comment. pthread_mutex_lock(&LOCK_apc_queue); dequeue_request(&apc_request); pthread_mutex_unlock(&LOCK_apc_queue); @@ -171,7 +204,8 @@ bool Apc_target::make_apc_call(apc_func_t func, void *func_arg, /* - Process all APC requests + Process all APC requests. + This should be called periodically by the APC target thread. */ void Apc_target::process_apc_requests() @@ -190,7 +224,7 @@ void Apc_target::process_apc_requests() request->what="seen by process_apc_requests"; pthread_mutex_lock(&request->LOCK_request); - if (request->done) + if (request->processed) { /* We can get here when @@ -214,7 +248,7 @@ void Apc_target::process_apc_requests() */ request->what="dequeued by process_apc_requests"; dequeue_request(request); - request->done= TRUE; + request->processed= TRUE; pthread_mutex_unlock(&LOCK_apc_queue); diff --git a/sql/my_apc.h b/sql/my_apc.h index 3906aa24408..0698703ad40 100644 --- a/sql/my_apc.h +++ b/sql/my_apc.h @@ -3,9 +3,18 @@ */ /* - Design - - Mutex-guarded request queue (it belongs to the target), which can be enabled/ - disabled (when empty). + Interface + ~~~~~~~~~ + ( + - This is an APC request queue + - We assume there is a particular owner thread which periodically calls + process_apc_requests() to serve the call requests. + - Other threads can post call requests, and block until they are exectued. + ) + + Implementation + ~~~~~~~~~~~~~~ + - The target has a mutex-guarded request queue. - After the request has been put into queue, the requestor waits for request to be satisfied. The worker satisifes the request and signals the @@ -21,31 +30,11 @@ public: Apc_target() : enabled(0), apc_calls(NULL) /*, call_queue_size(0)*/ {} ~Apc_target() { DBUG_ASSERT(!enabled && !apc_calls);} - /* - Initialize the target. This must be called before anything else. Right - after initialization, the target is disabled. - */ void init(); - - /* - Destroy the target. The target must be disabled when this call is made. - */ void destroy(); - - /* - Enter into state where this target will be serving APC requests - */ void enable(); - - /* - Leave the state where we could serve APC requests (will serve all already - enqueued requests) - */ void disable(); - /* - This should be called periodically to serve observation requests. - */ void process_apc_requests(); typedef void (*apc_func_t)(void *arg); @@ -68,18 +57,32 @@ public: #endif private: class Call_request; + + /* + Non-zero value means we're enabled. It's an int, not bool, because one can + call enable() N times (and then needs to call disable() N times before the + target is really disabled) + */ int enabled; + /* + Circular, double-linked list of all enqueued call requests. + We use this structure, because we + - process requests sequentially + - a thread that has posted a request may time out (or be KILLed) and + cancel the request, which means we'll need to remove its request at + arbitrary point in time. + */ Call_request *apc_calls; - pthread_mutex_t LOCK_apc_queue; + pthread_mutex_t LOCK_apc_queue; class Call_request { public: - apc_func_t func; - void *func_arg; - bool done; + apc_func_t func; /* Function to call */ + void *func_arg; /* Argument to pass it */ + bool processed; pthread_mutex_t LOCK_request; pthread_cond_t COND_request; @@ -87,13 +90,15 @@ private: Call_request *next; Call_request *prev; - const char *what; + const char *what; /* State of the request */ }; void enqueue_request(Call_request *qe); void dequeue_request(Call_request *qe); + + /* return the first call request in queue, or NULL if there are none enqueued */ Call_request *get_first_in_queue() - { + { return apc_calls; } }; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index d6f976cb505..545c9aff5e9 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -3033,7 +3033,8 @@ void Show_explain_request::get_explain_data(void *arg) req->target_thd->set_n_backup_active_arena((Query_arena*)req->request_thd, &backup_arena); - req->target_thd->lex->unit.print_explain(req->explain_buf); + if (req->target_thd->lex->unit.print_explain(req->explain_buf)) + req->failed_to_produce= TRUE; req->target_thd->restore_active_arena((Query_arena*)req->request_thd, &backup_arena); diff --git a/sql/sql_class.h b/sql/sql_class.h index 85f5d35f3d2..de7c8de6c26 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1467,6 +1467,8 @@ public: THD *target_thd; THD *request_thd; + bool failed_to_produce; + select_result_explain_buffer *explain_buf; static void get_explain_data(void *arg); diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 544246a1a4d..661ca2b4383 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -3792,6 +3792,15 @@ int st_select_lex_unit::print_explain(select_result_sink *output) { int res= 0; SELECT_LEX *first= first_select(); + + if (first && !first->next_select() && !first->join) + { + /* + If there is only one child, 'first', and it has join==NULL, emit "not in + EXPLAIN state" error. + */ + return 1; + } for (SELECT_LEX *sl= first; sl; sl= sl->next_select()) { diff --git a/sql/sql_show.cc b/sql/sql_show.cc index c30a8aad1eb..dd1b749e8bd 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2112,16 +2112,19 @@ void mysqld_show_explain(THD *thd, ulong thread_id) explain_req.explain_buf= explain_buf; explain_req.target_thd= tmp; explain_req.request_thd= thd; + explain_req.failed_to_produce= FALSE; bres= tmp->apc_target.make_apc_call(Show_explain_request::get_explain_data, (void*)&explain_req, timeout_sec, &timed_out); - if (bres) + + if (bres || explain_req.failed_to_produce) { /* TODO not enabled or time out */ my_error(ER_ERROR_WHEN_EXECUTING_COMMAND, MYF(0), "SHOW EXPLAIN", "Target is not running EXPLAINable command"); + bres= TRUE; } pthread_mutex_unlock(&tmp->LOCK_thd_data); if (!bres) From 9b269ea11b49c186a12f1a877c1d7cfa26b8b5c1 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Thu, 26 Apr 2012 07:17:34 +0530 Subject: [PATCH 016/289] MWL#182: Explain running statements - Correct thd->killed checks in join cache and filesort modules. --- sql/filesort.cc | 20 +++++++++++--------- sql/sql_join_cache.cc | 6 +++--- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/sql/filesort.cc b/sql/filesort.cc index 772698c6e1a..3b551796ae1 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -493,7 +493,7 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select, my_off_t record; TABLE *sort_form; THD *thd= current_thd; - volatile killed_state *killed= &thd->killed; + //volatile killed_state *killed= &thd->killed; handler *file; MY_BITMAP *save_read_set, *save_write_set, *save_vcol_set; uchar *next_sort_key= sort_keys_buf; @@ -588,7 +588,7 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select, break; } - if (*killed) + if (thd->check_killed()) { DBUG_PRINT("info",("Sort killed by user")); if (!indexfile && !quick_select) @@ -1229,18 +1229,20 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file, void *first_cmp_arg; element_count dupl_count= 0; uchar *src; - killed_state not_killable; + /* killed_state not_killable; */ uchar *unique_buff= param->unique_buff; - volatile killed_state *killed= ¤t_thd->killed; + /* volatile killed_state *killed= ¤t_thd->killed; */ + const bool killable= !param->not_killable; + THD* const thd=current_thd; DBUG_ENTER("merge_buffers"); - status_var_increment(current_thd->status_var.filesort_merge_passes); - current_thd->query_plan_fsort_passes++; - if (param->not_killable) + status_var_increment(thd->status_var.filesort_merge_passes); + thd->query_plan_fsort_passes++; + /*if (param->not_killable) { killed= ¬_killable; not_killable= NOT_KILLED; - } + }*/ error=0; rec_length= param->rec_length; @@ -1317,7 +1319,7 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file, while (queue.elements > 1) { - if (*killed) + if (killable && thd->check_killed()) { error= 1; goto err; /* purecov: inspected */ } diff --git a/sql/sql_join_cache.cc b/sql/sql_join_cache.cc index d49be2e446c..6492fb6cd61 100644 --- a/sql/sql_join_cache.cc +++ b/sql/sql_join_cache.cc @@ -2235,7 +2235,7 @@ enum_nested_loop_state JOIN_CACHE::join_matching_records(bool skip_last) while (!(error= join_tab_scan->next())) { - if (join->thd->killed) + if (join->thd->check_killed()) { /* The user has aborted the execution of the query */ join->thd->send_kill_message(); @@ -2505,7 +2505,7 @@ enum_nested_loop_state JOIN_CACHE::join_null_complements(bool skip_last) for ( ; cnt; cnt--) { - if (join->thd->killed) + if (join->thd->check_killed()) { /* The user has aborted the execution of the query */ join->thd->send_kill_message(); @@ -3355,7 +3355,7 @@ int JOIN_TAB_SCAN::next() update_virtual_fields(thd, table); while (!err && select && (skip_rc= select->skip_record(thd)) <= 0) { - if (thd->killed || skip_rc < 0) + if (thd->check_killed() || skip_rc < 0) return 1; /* Move to the next record if the last retrieved record does not From ff40705f89b977d966427710e1b32a0774a2f0b3 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Thu, 26 Apr 2012 08:48:31 +0530 Subject: [PATCH 017/289] Make SHOW EXPLAIN FOR produce a warning with the original text of query that the EXPLAIN is for. --- mysql-test/r/show_explain.result | 28 ++++++++++++++++++++++++++++ sql/sql_class.cc | 16 +++++++++++----- sql/sql_class.h | 2 ++ sql/sql_show.cc | 5 +++++ 4 files changed, 46 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/show_explain.result b/mysql-test/r/show_explain.result index 07ccab1419e..e451ef3108b 100644 --- a/mysql-test/r/show_explain.result +++ b/mysql-test/r/show_explain.result @@ -20,12 +20,16 @@ select count(*) from t1 where a < 100000; show explain for $thr2; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 index a a 5 NULL 1000 Using where; Using index +Warnings: +Note 1003 select count(*) from t1 where a < 100000 count(*) 1000 select max(c) from t1 where a < 10; show explain for $thr2; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range a a 5 NULL 10 Using index condition +Warnings: +Note 1003 select max(c) from t1 where a < 10 max(c) 9 # We can catch EXPLAIN, too. @@ -35,6 +39,8 @@ explain select max(c) from t1 where a < 10; show explain for $thr2; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range a a 5 NULL 10 Using index condition; Rowid-ordered scan +Warnings: +Note 1003 explain select max(c) from t1 where a < 10 id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range a a 5 NULL 10 Using index condition; Rowid-ordered scan set optimizer_switch= @show_expl_tmp; @@ -47,6 +53,8 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY A ALL NULL NULL NULL NULL 10 2 UNION B ALL NULL NULL NULL NULL 10 NULL UNION RESULT ALL NULL NULL NULL NULL NULL +Warnings: +Note 1003 explain select a from t0 A union select a+1 from t0 B id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY A ALL NULL NULL NULL NULL 10 2 UNION B ALL NULL NULL NULL NULL 10 @@ -60,6 +68,8 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY A ALL NULL NULL NULL NULL 10 2 UNION B ALL NULL NULL NULL NULL 10 NULL UNION RESULT ALL NULL NULL NULL NULL NULL +Warnings: +Note 1003 explain select a from t0 A union select a+1 from t0 B id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY A ALL NULL NULL NULL NULL 10 2 UNION B ALL NULL NULL NULL NULL 10 @@ -72,6 +82,8 @@ show explain for $thr2; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY A ALL NULL NULL NULL NULL 10 Using where 2 SUBQUERY B ALL NULL NULL NULL NULL 10 +Warnings: +Note 1003 select a, (select max(a) from t0 B) from t0 A where a<1 a (select max(a) from t0 B) 0 9 # Uncorrelated subquery, explain @@ -82,6 +94,8 @@ show explain for $thr2; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY A ALL NULL NULL NULL NULL 10 Using where 2 SUBQUERY B ALL NULL NULL NULL NULL 10 +Warnings: +Note 1003 explain select a, (select max(a) from t0 B) from t0 A where a<1 id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY A ALL NULL NULL NULL NULL 10 Using where 2 SUBQUERY B ALL NULL NULL NULL NULL 10 @@ -93,6 +107,8 @@ show explain for $thr2; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY a ALL NULL NULL NULL NULL 10 Using where 2 DEPENDENT SUBQUERY b ALL NULL NULL NULL NULL 10 Using where +Warnings: +Note 1003 select a, (select max(a) from t0 b where b.a+a.a<10) from t0 a where a<1 a (select max(a) from t0 b where b.a+a.a<10) 0 9 # correlated subquery, explain @@ -103,6 +119,8 @@ show explain for $thr2; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY a ALL NULL NULL NULL NULL 10 Using where 2 DEPENDENT SUBQUERY b ALL NULL NULL NULL NULL 10 Using where +Warnings: +Note 1003 select a, (select max(a) from t0 b where b.a+a.a<10) from t0 a where a<1 a (select max(a) from t0 b where b.a+a.a<10) 0 9 # correlated subquery, select, while inside the subquery @@ -113,6 +131,8 @@ show explain for $thr2; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY a ALL NULL NULL NULL NULL 10 Using where 2 DEPENDENT SUBQUERY b ALL NULL NULL NULL NULL 10 Using where +Warnings: +Note 1003 select a, (select max(a) from t0 b where b.a+a.a<10) from t0 a where a<1 a (select max(a) from t0 b where b.a+a.a<10) 0 9 # correlated subquery, explain, while inside the subquery @@ -123,6 +143,8 @@ show explain for $thr2; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY a ALL NULL NULL NULL NULL 10 Using where 2 DEPENDENT SUBQUERY b ALL NULL NULL NULL NULL 10 Using where +Warnings: +Note 1003 select a, (select max(a) from t0 b where b.a+a.a<10) from t0 a where a<1 a (select max(a) from t0 b where b.a+a.a<10) 0 9 # Try to do SHOW EXPLAIN for a query that runs a SET command: @@ -168,14 +190,20 @@ show explain for $thr2; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 ALL NULL NULL NULL NULL 3 2 DEPENDENT SUBQUERY t0 ALL NULL NULL NULL NULL 10 Using where +Warnings: +Note 1003 select t2.a, ((select max(a) from t0 where t2.a + t0.a <3) >3) as SUBQ from t2 show explain for $thr2; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 ALL NULL NULL NULL NULL 3 2 DEPENDENT SUBQUERY t0 ALL NULL NULL NULL NULL 10 Using where +Warnings: +Note 1003 select t2.a, ((select max(a) from t0 where t2.a + t0.a <3) >3) as SUBQ from t2 show explain for $thr2; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 ALL NULL NULL NULL NULL 3 2 DEPENDENT SUBQUERY t0 ALL NULL NULL NULL NULL 10 Using where +Warnings: +Note 1003 select t2.a, ((select max(a) from t0 where t2.a + t0.a <3) >3) as SUBQ from t2 a SUBQ 0 0 1 0 diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 545c9aff5e9..4e9a0507bba 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -3030,14 +3030,20 @@ void Show_explain_request::get_explain_data(void *arg) //TODO: change mem_root to point to request_thd->mem_root. // Actually, change the ARENA, because we're going to allocate items! Query_arena backup_arena; - req->target_thd->set_n_backup_active_arena((Query_arena*)req->request_thd, - &backup_arena); + THD *target_thd= req->target_thd; - if (req->target_thd->lex->unit.print_explain(req->explain_buf)) + target_thd->set_n_backup_active_arena((Query_arena*)req->request_thd, + &backup_arena); + + req->query_str.copy(target_thd->query(), + target_thd->query_length(), + &my_charset_bin); + + if (target_thd->lex->unit.print_explain(req->explain_buf)) req->failed_to_produce= TRUE; - req->target_thd->restore_active_arena((Query_arena*)req->request_thd, - &backup_arena); + target_thd->restore_active_arena((Query_arena*)req->request_thd, + &backup_arena); } diff --git a/sql/sql_class.h b/sql/sql_class.h index de7c8de6c26..223a42b1d02 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1471,6 +1471,8 @@ public: select_result_explain_buffer *explain_buf; + String query_str; + static void get_explain_data(void *arg); }; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index dd1b749e8bd..a0c39ff6c8c 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2126,6 +2126,11 @@ void mysqld_show_explain(THD *thd, ulong thread_id) "Target is not running EXPLAINable command"); bres= TRUE; } + else + { + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, + ER_YES, explain_req.query_str.c_ptr_safe()); + } pthread_mutex_unlock(&tmp->LOCK_thd_data); if (!bres) { From cdc9a1172d7b75b16d92a6179478c2689ac04bae Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Thu, 10 May 2012 01:45:38 +0530 Subject: [PATCH 018/289] MWL#182: Explain running statements: Make SHOW EXPLAIN work for queries that do "Using temporary" and/or "Using filesort" - Patch#1: Don't lose "Using temporary/filesort" in the SHOW EXPLAIN output. --- mysql-test/r/show_explain.result | 75 ++++++++++++++++++++++++++++++++ mysql-test/t/show_explain.test | 46 ++++++++++++++++++++ sql/sql_lex.cc | 6 +-- 3 files changed, 124 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/show_explain.result b/mysql-test/r/show_explain.result index e451ef3108b..74def21585f 100644 --- a/mysql-test/r/show_explain.result +++ b/mysql-test/r/show_explain.result @@ -209,4 +209,79 @@ a SUBQ 1 0 2 0 drop table t2; +# +# SHOW EXPLAIN for SELECT ... ORDER BY with "Using filesort" +# +explain select * from t0 order by a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 ALL NULL NULL NULL NULL 10 Using filesort +set debug='d,show_explain_probe_1'; +set @show_explain_probe_select_id=1; +select * from t0 order by a; +show explain for $thr2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 ALL NULL NULL NULL NULL 10 Using filesort +Warnings: +Note 1003 select * from t0 order by a +a +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +# +# SHOW EXPLAIN for SELECT ... with "Using temporary" +# +explain select distinct a from t0; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 ALL NULL NULL NULL NULL 10 Using temporary +set debug='d,show_explain_probe_1'; +set @show_explain_probe_select_id=1; +select distinct a from t0; +show explain for $thr2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 ALL NULL NULL NULL NULL 10 Using temporary +Warnings: +Note 1003 select distinct a from t0 +a +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +# +# SHOW EXPLAIN for SELECT ... with "Using temporary; Using filesort" +# +explain select distinct a from t0; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 ALL NULL NULL NULL NULL 10 Using temporary +set debug='d,show_explain_probe_1'; +set @show_explain_probe_select_id=1; +select distinct a from t0; +show explain for $thr2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 ALL NULL NULL NULL NULL 10 Using temporary +Warnings: +Note 1003 select distinct a from t0 +a +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 drop table t0,t1; diff --git a/mysql-test/t/show_explain.test b/mysql-test/t/show_explain.test index 717949d5cc5..4fc6aaad932 100644 --- a/mysql-test/t/show_explain.test +++ b/mysql-test/t/show_explain.test @@ -255,6 +255,52 @@ connection con1; reap; drop table t2; +--echo # +--echo # SHOW EXPLAIN for SELECT ... ORDER BY with "Using filesort" +--echo # +explain select * from t0 order by a; + +set debug='d,show_explain_probe_1'; +set @show_explain_probe_select_id=1; +send select * from t0 order by a; +connection default; +--source include/wait_condition.inc +evalp show explain for $thr2; +connection con1; +reap; + +--echo # +--echo # SHOW EXPLAIN for SELECT ... with "Using temporary" +--echo # +connection default; +explain select distinct a from t0; +connection con1; + +set debug='d,show_explain_probe_1'; +set @show_explain_probe_select_id=1; +send select distinct a from t0; +connection default; +--source include/wait_condition.inc +evalp show explain for $thr2; +connection con1; +reap; + +--echo # +--echo # SHOW EXPLAIN for SELECT ... with "Using temporary; Using filesort" +--echo # +connection default; +explain select distinct a from t0; +connection con1; + +set debug='d,show_explain_probe_1'; +set @show_explain_probe_select_id=1; +send select distinct a from t0; +connection default; +--source include/wait_condition.inc +evalp show explain for $thr2; +connection con1; +reap; + ## TODO: Test this: have several SHOW EXPLAIN requests be queued up for a ## thread and served together. diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 661ca2b4383..a47ba9b5024 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -3752,9 +3752,9 @@ int st_select_lex::print_explain(select_result_sink *output) if (join && join->optimized == 2) { res= join->print_explain(output, TRUE, - FALSE, // need_tmp_table, - FALSE, // bool need_order, - FALSE, // bool distinct, + join->need_tmp, // need_tmp_table + (join->order != 0 && !join->skip_sort_order), // bool need_order + join->select_distinct, // bool distinct NULL); //const char *message if (res) goto err; From 58b9164f0468768eff64841f4f066840b9ff2206 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Thu, 10 May 2012 13:43:48 +0400 Subject: [PATCH 019/289] MDEV-238: SHOW EXPLAIN: Server crashes in JOIN::print_explain with FROM subquery and GROUP BY - Support SHOW EXPLAIN for selects that have "Using temporary; Using filesort". --- mysql-test/r/show_explain.result | 25 ++++++++++++++++++ mysql-test/t/show_explain.test | 22 ++++++++++++++++ sql/filesort.cc | 6 +++++ sql/sql_select.cc | 44 ++++++++++++++++++++++++-------- sql/sql_select.h | 14 ++++++++++ sql/table.h | 7 ++++- 6 files changed, 106 insertions(+), 12 deletions(-) diff --git a/mysql-test/r/show_explain.result b/mysql-test/r/show_explain.result index 74def21585f..db1d57b7004 100644 --- a/mysql-test/r/show_explain.result +++ b/mysql-test/r/show_explain.result @@ -284,4 +284,29 @@ a 7 8 9 +set debug=''; +# +# MDEV-238: SHOW EXPLAIN: Server crashes in JOIN::print_explain with FROM subquery and GROUP BY +# +CREATE TABLE t2 ( a INT ); +INSERT INTO t2 VALUES (1),(2),(1),(4),(2); +explain SELECT alias.a FROM t2, ( SELECT * FROM t2 ) AS alias GROUP BY alias.a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 5 Using temporary; Using filesort +1 SIMPLE t2 ALL NULL NULL NULL NULL 5 Using join buffer (flat, BNL join) +set debug='d,show_explain_in_find_all_keys'; +SELECT alias.a FROM t2, ( SELECT * FROM t2 ) AS alias GROUP BY alias.a; +# NOTE: current code will not show "Using join buffer": +show explain for $thr2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 5 Using temporary; Using filesort +1 SIMPLE t2 ALL NULL NULL NULL NULL 5 +Warnings: +Note 1003 SELECT alias.a FROM t2, ( SELECT * FROM t2 ) AS alias GROUP BY alias.a +a +1 +2 +4 +set debug=''; +DROP TABLE t2; drop table t0,t1; diff --git a/mysql-test/t/show_explain.test b/mysql-test/t/show_explain.test index 4fc6aaad932..8c9d5f4c1e8 100644 --- a/mysql-test/t/show_explain.test +++ b/mysql-test/t/show_explain.test @@ -300,8 +300,30 @@ connection default; evalp show explain for $thr2; connection con1; reap; +set debug=''; + +--echo # +--echo # MDEV-238: SHOW EXPLAIN: Server crashes in JOIN::print_explain with FROM subquery and GROUP BY +--echo # +CREATE TABLE t2 ( a INT ); +INSERT INTO t2 VALUES (1),(2),(1),(4),(2); +explain SELECT alias.a FROM t2, ( SELECT * FROM t2 ) AS alias GROUP BY alias.a; + +set debug='d,show_explain_in_find_all_keys'; +send SELECT alias.a FROM t2, ( SELECT * FROM t2 ) AS alias GROUP BY alias.a; + +connection default; +--source include/wait_condition.inc +--echo # NOTE: current code will not show "Using join buffer": +evalp show explain for $thr2; +connection con1; +reap; +set debug=''; + ## TODO: Test this: have several SHOW EXPLAIN requests be queued up for a ## thread and served together. +DROP TABLE t2; + drop table t0,t1; diff --git a/sql/filesort.cc b/sql/filesort.cc index 3b551796ae1..3e6588636fa 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -515,6 +515,12 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select, if (indexfile || flag) ref_pos= &file->ref[0]; next_pos=ref_pos; + + DBUG_EXECUTE_IF("show_explain_in_find_all_keys", + dbug_serve_apcs(thd, 1); + ); + + if (! indexfile && ! quick_select) { next_pos=(uchar*) 0; /* Find records in sequence */ diff --git a/sql/sql_select.cc b/sql/sql_select.cc index d739c6789c3..6a842ead2a4 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -7132,28 +7132,36 @@ prev_record_reads(POSITION *positions, uint idx, table_map found_ref) return found; } +enum enum_exec_or_opt {WALK_OPTIMIZATION_TABS , WALK_EXECUTION_TABS}; /* Enumerate join tabs in breadth-first fashion, including const tables. */ -JOIN_TAB *first_breadth_first_tab(JOIN *join) +JOIN_TAB *first_breadth_first_tab(JOIN *join, enum enum_exec_or_opt tabs_kind) { - return join->join_tab; /* There's always one (i.e. first) table */ + /* There's always one (i.e. first) table */ + return (tabs_kind == WALK_EXECUTION_TABS)? join->join_tab: + join->table_access_tabs; } -JOIN_TAB *next_breadth_first_tab(JOIN *join, JOIN_TAB *tab) +JOIN_TAB *next_breadth_first_tab(JOIN *join, enum enum_exec_or_opt tabs_kind, + JOIN_TAB *tab) { + JOIN_TAB* const first_top_tab= first_breadth_first_tab(join, tabs_kind); + const uint n_top_tabs_count= (tabs_kind == WALK_EXECUTION_TABS)? + join->top_join_tab_count: + join->top_table_access_tabs_count; if (!tab->bush_root_tab) { /* We're at top level. Get the next top-level tab */ tab++; - if (tab < join->join_tab + join->top_join_tab_count) + if (tab < first_top_tab + n_top_tabs_count) return tab; /* No more top-level tabs. Switch to enumerating SJM nest children */ - tab= join->join_tab; + tab= first_top_tab; } else { @@ -7177,7 +7185,7 @@ JOIN_TAB *next_breadth_first_tab(JOIN *join, JOIN_TAB *tab) Ok, "tab" points to a top-level table, and we need to find the next SJM nest and enter it. */ - for (; tab < join->join_tab + join->top_join_tab_count; tab++) + for (; tab < first_top_tab + n_top_tabs_count; tab++) { if (tab->bush_children) return tab->bush_children->start; @@ -7201,7 +7209,7 @@ JOIN_TAB *first_top_level_tab(JOIN *join, enum enum_with_const_tables with_const JOIN_TAB *next_top_level_tab(JOIN *join, JOIN_TAB *tab) { - tab= next_breadth_first_tab(join, tab); + tab= next_breadth_first_tab(join, WALK_EXECUTION_TABS, tab); if (tab && tab->bush_root_tab) tab= NULL; return tab; @@ -7501,6 +7509,13 @@ get_best_combination(JOIN *join) join->top_join_tab_count= join->join_tab_ranges.head()->end - join->join_tab_ranges.head()->start; + /* + Save pointers to select join tabs for SHOW EXPLAIN + */ + join->table_access_tabs= join->join_tab; + join->top_table_access_tabs_count= join->top_join_tab_count; + + update_depend_map(join); DBUG_RETURN(0); } @@ -7922,6 +7937,7 @@ JOIN::make_simple_join(JOIN *parent, TABLE *temp_table) !(parent->join_tab_reexec= (JOIN_TAB*) thd->alloc(sizeof(JOIN_TAB)))) DBUG_RETURN(TRUE); /* purecov: inspected */ + // psergey-todo: here, save the pointer for original join_tabs. join_tab= parent->join_tab_reexec; table= &parent->table_reexec[0]; parent->table_reexec[0]= temp_table; table_count= top_join_tab_count= 1; @@ -10077,7 +10093,12 @@ void JOIN_TAB::cleanup() if (cache) { cache->free(); - cache= 0; + cache= 0; // psergey: this is why we don't see "Using join cache" in SHOW EXPLAIN + // when it is run for "Using temporary+filesort" queries while they + // are at reading-from-tmp-table phase. + // + // TODO ask igor if this can be just moved to later phase + // (JOIN_CACHE objects themselves are not big, arent they) } limit= 0; if (table) @@ -21204,9 +21225,10 @@ int JOIN::print_explain(select_result_sink *result, bool on_the_fly, bool printing_materialize_nest= FALSE; uint select_id= join->select_lex->select_number; + JOIN_TAB* const first_top_tab= first_breadth_first_tab(join, WALK_OPTIMIZATION_TABS); - for (JOIN_TAB *tab= first_breadth_first_tab(join); tab; - tab= next_breadth_first_tab(join, tab)) + for (JOIN_TAB *tab= first_breadth_first_tab(join, WALK_OPTIMIZATION_TABS); tab; + tab= next_breadth_first_tab(join, WALK_OPTIMIZATION_TABS, tab)) { if (tab->bush_root_tab) { @@ -21643,7 +21665,7 @@ int JOIN::print_explain(select_result_sink *result, bool on_the_fly, extra.append(STRING_WITH_LEN("; End temporary")); else if (tab->do_firstmatch) { - if (tab->do_firstmatch == join->join_tab - 1) + if (tab->do_firstmatch == /*join->join_tab*/ first_top_tab - 1) extra.append(STRING_WITH_LEN("; FirstMatch")); else { diff --git a/sql/sql_select.h b/sql/sql_select.h index 779702e4b1c..c60419f1ffd 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -896,6 +896,20 @@ protected: public: JOIN_TAB *join_tab, **best_ref; + + /* + For "Using temporary+Using filesort" queries, JOIN::join_tab can point to + either: + 1. array of join tabs describing how to run the select, or + 2. array of single join tab describing read from the temporary table. + + SHOW EXPLAIN code needs to read/show #1. This is why two next members are + there for saving it. + */ + JOIN_TAB *table_access_tabs; + uint top_table_access_tabs_count; + + JOIN_TAB **map2table; ///< mapping between table indexes and JOIN_TABs JOIN_TAB *join_tab_save; ///< saved join_tab for subquery reexecution diff --git a/sql/table.h b/sql/table.h index da2109809d4..9b6d807b844 100644 --- a/sql/table.h +++ b/sql/table.h @@ -850,7 +850,12 @@ struct st_table { See TABLE_LIST::process_index_hints(). */ bool force_index_group; - bool distinct,const_table,no_rows, used_for_duplicate_elimination; + /* + TRUE<=> this table was created with create_tmp_table(... distinct=TRUE..) + call + */ + bool distinct; + bool const_table,no_rows, used_for_duplicate_elimination; /** If set, the optimizer has found that row retrieval should access index From 5116bed06c1a1641d54d8de8bc8770ad65ab165d Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Thu, 10 May 2012 13:44:57 +0400 Subject: [PATCH 020/289] bzr ignore libmysqld/my_apc.cc --- .bzrignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.bzrignore b/.bzrignore index a956e0c6ab4..e4fe3e8a9f2 100644 --- a/.bzrignore +++ b/.bzrignore @@ -1982,3 +1982,4 @@ plugin/handler_socket/perl-Net-HandlerSocket/HandlerSocket.bs plugin/handler_socket/perl-Net-HandlerSocket/Makefile.PL libmysqld/gcalc_slicescan.cc libmysqld/gcalc_tools.cc +libmysqld/my_apc.cc From 6fae4447f0873c159d94d1a3d8deafbd224d8100 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Thu, 10 May 2012 15:13:57 +0400 Subject: [PATCH 021/289] # MDEV-239: Assertion `field_types == 0 ... ' failed in Protocol_text::store... - Make all functions that produce parts of EXPLAIN output take explain_flags as parameter, instead of looking into thd->lex->describe --- mysql-test/r/show_explain.result | 28 ++++++++++++++++++++++++++ mysql-test/t/show_explain.test | 27 +++++++++++++++++++++++-- sql/sql_class.cc | 2 +- sql/sql_lex.cc | 16 ++++++++------- sql/sql_lex.h | 4 ++-- sql/sql_select.cc | 34 +++++++++++++++++++++----------- sql/sql_select.h | 3 ++- 7 files changed, 89 insertions(+), 25 deletions(-) diff --git a/mysql-test/r/show_explain.result b/mysql-test/r/show_explain.result index db1d57b7004..4f0e89975ff 100644 --- a/mysql-test/r/show_explain.result +++ b/mysql-test/r/show_explain.result @@ -309,4 +309,32 @@ a 4 set debug=''; DROP TABLE t2; +# +# MDEV-239: Assertion `field_types == 0 ... ' failed in Protocol_text::store(double, uint32, String*) with +# SHOW EXPLAIN over EXPLAIN EXTENDED +# +CREATE TABLE t2 (a INT); +INSERT INTO t2 VALUES (1),(2),(1),(4),(2); +EXPLAIN EXTENDED SELECT alias.a FROM t2, ( SELECT * FROM t2 ) AS alias GROUP BY alias.a ; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 5 100.00 Using temporary; Using filesort +1 SIMPLE t2 ALL NULL NULL NULL NULL 5 100.00 Using join buffer (flat, BNL join) +Warnings: +Note 1003 select `test`.`t2`.`a` AS `a` from `test`.`t2` join `test`.`t2` group by `test`.`t2`.`a` +set @show_explain_probe_select_id=1; +set debug='d,show_explain_probe_join_exec_end'; +EXPLAIN EXTENDED SELECT alias.a FROM t2, ( SELECT * FROM t2 ) AS alias GROUP BY alias.a ; +show explain for $thr2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 5 Using temporary; Using filesort +1 SIMPLE t2 ALL NULL NULL NULL NULL 5 Using join buffer (flat, BNL join) +Warnings: +Note 1003 EXPLAIN EXTENDED SELECT alias.a FROM t2, ( SELECT * FROM t2 ) AS alias GROUP BY alias.a +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 5 100.00 Using temporary; Using filesort +1 SIMPLE t2 ALL NULL NULL NULL NULL 5 100.00 Using join buffer (flat, BNL join) +Warnings: +Note 1003 select `test`.`t2`.`a` AS `a` from `test`.`t2` join `test`.`t2` group by `test`.`t2`.`a` +set debug=''; +DROP TABLE t2; drop table t0,t1; diff --git a/mysql-test/t/show_explain.test b/mysql-test/t/show_explain.test index 8c9d5f4c1e8..02850efedd8 100644 --- a/mysql-test/t/show_explain.test +++ b/mysql-test/t/show_explain.test @@ -319,11 +319,34 @@ evalp show explain for $thr2; connection con1; reap; set debug=''; +DROP TABLE t2; + + +--echo # +--echo # MDEV-239: Assertion `field_types == 0 ... ' failed in Protocol_text::store(double, uint32, String*) with +--echo # SHOW EXPLAIN over EXPLAIN EXTENDED +--echo # + + +CREATE TABLE t2 (a INT); +INSERT INTO t2 VALUES (1),(2),(1),(4),(2); + +EXPLAIN EXTENDED SELECT alias.a FROM t2, ( SELECT * FROM t2 ) AS alias GROUP BY alias.a ; + +set @show_explain_probe_select_id=1; +set debug='d,show_explain_probe_join_exec_end'; +send EXPLAIN EXTENDED SELECT alias.a FROM t2, ( SELECT * FROM t2 ) AS alias GROUP BY alias.a ; + +connection default; +--source include/wait_condition.inc +evalp show explain for $thr2; +connection con1; +reap; +set debug=''; +DROP TABLE t2; ## TODO: Test this: have several SHOW EXPLAIN requests be queued up for a ## thread and served together. -DROP TABLE t2; - drop table t0,t1; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 4e9a0507bba..89d80dc1ec2 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -3039,7 +3039,7 @@ void Show_explain_request::get_explain_data(void *arg) target_thd->query_length(), &my_charset_bin); - if (target_thd->lex->unit.print_explain(req->explain_buf)) + if (target_thd->lex->unit.print_explain(req->explain_buf, 0 /* explain flags */)) req->failed_to_produce= TRUE; target_thd->restore_active_arena((Query_arena*)req->request_thd, diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index a47ba9b5024..69bb822f05a 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -3746,12 +3746,13 @@ bool st_select_lex::is_merged_child_of(st_select_lex *ancestor) } -int st_select_lex::print_explain(select_result_sink *output) +int st_select_lex::print_explain(select_result_sink *output, + uint8 explain_flags) { int res; if (join && join->optimized == 2) { - res= join->print_explain(output, TRUE, + res= join->print_explain(output, explain_flags, TRUE, join->need_tmp, // need_tmp_table (join->order != 0 && !join->skip_sort_order), // bool need_order join->select_distinct, // bool distinct @@ -3769,7 +3770,7 @@ int st_select_lex::print_explain(select_result_sink *output) */ if (!(unit->item && unit->item->eliminated)) { - unit->print_explain(output); + unit->print_explain(output, explain_flags); } } } @@ -3777,7 +3778,7 @@ int st_select_lex::print_explain(select_result_sink *output) { /* Produce "not yet optimized" line */ const char *msg="Not yet optimized"; - res= join->print_explain(output, TRUE, + res= join->print_explain(output, explain_flags, TRUE, FALSE, // need_tmp_table, FALSE, // bool need_order, FALSE, // bool distinct, @@ -3788,7 +3789,8 @@ err: } -int st_select_lex_unit::print_explain(select_result_sink *output) +int st_select_lex_unit::print_explain(select_result_sink *output, + uint8 explain_flags) { int res= 0; SELECT_LEX *first= first_select(); @@ -3804,7 +3806,7 @@ int st_select_lex_unit::print_explain(select_result_sink *output) for (SELECT_LEX *sl= first; sl; sl= sl->next_select()) { - if ((res= sl->print_explain(output))) + if ((res= sl->print_explain(output, explain_flags))) break; } @@ -3814,7 +3816,7 @@ int st_select_lex_unit::print_explain(select_result_sink *output) if (fake_select_lex && !fake_select_lex->join) { res= print_fake_select_lex_join(output, TRUE /* on the fly */, - fake_select_lex, 0 /* flags */); + fake_select_lex, explain_flags); } return res; } diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 6f72c9e3f7b..8a7547691e9 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -595,7 +595,7 @@ public: friend int subselect_union_engine::exec(); List *get_unit_column_types(); - int print_explain(select_result_sink *output); + int print_explain(select_result_sink *output, uint8 explain_flags); }; typedef class st_select_lex_unit SELECT_LEX_UNIT; @@ -918,7 +918,7 @@ public: bool save_prep_leaf_tables(THD *thd); bool is_merged_child_of(st_select_lex *ancestor); - int print_explain(select_result_sink *output); + int print_explain(select_result_sink *output, uint8 explain_flags); /* For MODE_ONLY_FULL_GROUP_BY we need to maintain two flags: - Non-aggregated fields are used in this select. diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 6a842ead2a4..f48f180d1dd 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2123,6 +2123,14 @@ void JOIN::exec() */ thd->apc_target.enable(); exec_inner(); + + DBUG_EXECUTE_IF("show_explain_probe_join_exec_end", + if (dbug_user_var_equals_int(thd, + "show_explain_probe_select_id", + select_lex->select_number)) + dbug_serve_apcs(thd, 1); + ); + thd->apc_target.disable(); } @@ -21075,7 +21083,7 @@ void JOIN::clear() int print_fake_select_lex_join(select_result_sink *result, bool on_the_fly, - SELECT_LEX *select_lex, uint8 select_options) + SELECT_LEX *select_lex, uint8 explain_flags) { const CHARSET_INFO *cs= system_charset_info; Item *item_null= new Item_null(); @@ -21121,7 +21129,7 @@ int print_fake_select_lex_join(select_result_sink *result, bool on_the_fly, item_list.push_back(new Item_string(table_name_buffer, len, cs)); } /* partitions */ - if (/*join->thd->lex->describe*/ select_options & DESCRIBE_PARTITIONS) + if (explain_flags & DESCRIBE_PARTITIONS) item_list.push_back(item_null); /* type */ item_list.push_back(new Item_string(join_type_str[JT_ALL], @@ -21136,7 +21144,7 @@ int print_fake_select_lex_join(select_result_sink *result, bool on_the_fly, /* ref */ item_list.push_back(item_null); /* in_rows */ - if (select_options & DESCRIBE_EXTENDED) + if (explain_flags & DESCRIBE_EXTENDED) item_list.push_back(item_null); /* rows */ item_list.push_back(item_null); @@ -21162,7 +21170,8 @@ int print_fake_select_lex_join(select_result_sink *result, bool on_the_fly, modifications to any select's data structures */ -int JOIN::print_explain(select_result_sink *result, bool on_the_fly, +int JOIN::print_explain(select_result_sink *result, uint8 explain_flags, + bool on_the_fly, bool need_tmp_table, bool need_order, bool distinct, const char *message) { @@ -21199,9 +21208,9 @@ int JOIN::print_explain(select_result_sink *result, bool on_the_fly, strlen(join->select_lex->type), cs)); for (uint i=0 ; i < 7; i++) item_list.push_back(item_null); - if (join->thd->lex->describe & DESCRIBE_PARTITIONS) + if (explain_flags & DESCRIBE_PARTITIONS) item_list.push_back(item_null); - if (join->thd->lex->describe & DESCRIBE_EXTENDED) + if (explain_flags & DESCRIBE_EXTENDED) item_list.push_back(item_null); item_list.push_back(new Item_string(message,strlen(message),cs)); @@ -21212,7 +21221,7 @@ int JOIN::print_explain(select_result_sink *result, bool on_the_fly, { if (print_fake_select_lex_join(result, on_the_fly, join->select_lex, - join->thd->lex->describe)) + explain_flags)) error= 1; } else if (!join->select_lex->master_unit()->derived || @@ -21317,7 +21326,7 @@ int JOIN::print_explain(select_result_sink *result, bool on_the_fly, cs)); } /* "partitions" column */ - if (join->thd->lex->describe & DESCRIBE_PARTITIONS) + if (explain_flags & DESCRIBE_PARTITIONS) { #ifdef WITH_PARTITION_STORAGE_ENGINE partition_info *part_info; @@ -21460,7 +21469,7 @@ int JOIN::print_explain(select_result_sink *result, bool on_the_fly, table_list->schema_table) { /* in_rows */ - if (join->thd->lex->describe & DESCRIBE_EXTENDED) + if (explain_flags & DESCRIBE_EXTENDED) item_list.push_back(item_null); /* rows */ item_list.push_back(item_null); @@ -21497,7 +21506,7 @@ int JOIN::print_explain(select_result_sink *result, bool on_the_fly, MY_INT64_NUM_DECIMAL_DIGITS)); /* Add "filtered" field to item_list. */ - if (join->thd->lex->describe & DESCRIBE_EXTENDED) + if (explain_flags & DESCRIBE_EXTENDED) { float f= 0.0; if (examined_rows) @@ -21577,7 +21586,7 @@ int JOIN::print_explain(select_result_sink *result, bool on_the_fly, { extra.append(STRING_WITH_LEN("; Using where with pushed " "condition")); - if (thd->lex->describe & DESCRIBE_EXTENDED) + if (explain_flags & DESCRIBE_EXTENDED) { extra.append(STRING_WITH_LEN(": ")); ((COND *)pushed_cond)->print(&extra, QT_ORDINARY); @@ -21732,7 +21741,8 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, THD *thd=join->thd; select_result *result=join->result; DBUG_ENTER("select_describe"); - join->error= join->print_explain(result, FALSE, /* Not on-the-fly */ + join->error= join->print_explain(result, thd->lex->describe, + FALSE, /* Not on-the-fly */ need_tmp_table, need_order, distinct, message); diff --git a/sql/sql_select.h b/sql/sql_select.h index c60419f1ffd..a15720b4b30 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -1405,7 +1405,8 @@ public: return (unit->item && unit->item->is_in_predicate()); } - int print_explain(select_result_sink *result, bool on_the_fly, + int print_explain(select_result_sink *result, uint8 explain_flags, + bool on_the_fly, bool need_tmp_table, bool need_order, bool distinct,const char *message); private: From 6bce336624e84f5ec377926b105ec2002b38c96b Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Fri, 11 May 2012 18:13:06 +0400 Subject: [PATCH 022/289] MDEV-240: SHOW EXPLAIN: Assertion `this->optimized == 2' failed - Fix the bug: SHOW EXPLAIN may hit a case where a join is partially optimized. - Change JOIN::optimized to use enum instead of numeric constants --- mysql-test/r/show_explain.result | 33 ++++++++++++++++++++++++++++++++ mysql-test/t/show_explain.test | 25 ++++++++++++++++++++++++ sql/item_subselect.cc | 6 ++++-- sql/sql_lex.cc | 2 +- sql/sql_select.cc | 17 ++++++++++------ sql/sql_select.h | 8 ++++++-- 6 files changed, 80 insertions(+), 11 deletions(-) diff --git a/mysql-test/r/show_explain.result b/mysql-test/r/show_explain.result index 4f0e89975ff..2051a409178 100644 --- a/mysql-test/r/show_explain.result +++ b/mysql-test/r/show_explain.result @@ -1,4 +1,5 @@ drop table if exists t0, t1, t2; +drop view if exists v1; create table t0 (a int); insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); create table t1 (a int); @@ -337,4 +338,36 @@ Warnings: Note 1003 select `test`.`t2`.`a` AS `a` from `test`.`t2` join `test`.`t2` group by `test`.`t2`.`a` set debug=''; DROP TABLE t2; +# +# MDEV-240: SHOW EXPLAIN: Assertion `this->optimized == 2' failed in +# JOIN::print_explain on query with a JOIN, TEMPTABLE view, +# +CREATE TABLE t3 (a INT); +CREATE ALGORITHM=TEMPTABLE VIEW v1 AS SELECT * FROM t3; +INSERT INTO t3 VALUES (8); +CREATE TABLE t2 (b INT); +INSERT INTO t2 VALUES (4),(5),(6),(7),(8),(9); +explain SELECT * FROM v1, t2; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY system NULL NULL NULL NULL 1 +1 PRIMARY t2 ALL NULL NULL NULL NULL 6 +2 DERIVED t3 system NULL NULL NULL NULL 1 +set @show_explain_probe_select_id=2; +set debug='d,show_explain_probe_join_exec_end'; +SELECT * FROM v1, t2; +show explain for $thr2; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Not yet optimized +Warnings: +Note 1003 SELECT * FROM v1, t2 +a b +8 4 +8 5 +8 6 +8 7 +8 8 +8 9 +set debug=''; +DROP VIEW v1; +DROP TABLE t2, t3; drop table t0,t1; diff --git a/mysql-test/t/show_explain.test b/mysql-test/t/show_explain.test index 02850efedd8..36c34c8df5c 100644 --- a/mysql-test/t/show_explain.test +++ b/mysql-test/t/show_explain.test @@ -5,6 +5,7 @@ --disable_warnings drop table if exists t0, t1, t2; +drop view if exists v1; --enable_warnings # @@ -346,6 +347,30 @@ set debug=''; DROP TABLE t2; +--echo # +--echo # MDEV-240: SHOW EXPLAIN: Assertion `this->optimized == 2' failed in +--echo # JOIN::print_explain on query with a JOIN, TEMPTABLE view, +--echo # +CREATE TABLE t3 (a INT); +CREATE ALGORITHM=TEMPTABLE VIEW v1 AS SELECT * FROM t3; +INSERT INTO t3 VALUES (8); +CREATE TABLE t2 (b INT); +INSERT INTO t2 VALUES (4),(5),(6),(7),(8),(9); +explain SELECT * FROM v1, t2; + +set @show_explain_probe_select_id=2; +set debug='d,show_explain_probe_join_exec_end'; +send SELECT * FROM v1, t2; + +connection default; +--source include/wait_condition.inc +evalp show explain for $thr2; +connection con1; +reap; +set debug=''; +DROP VIEW v1; +DROP TABLE t2, t3; + ## TODO: Test this: have several SHOW EXPLAIN requests be queued up for a ## thread and served together. diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 8b720b350a5..1780953bd7e 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -2910,7 +2910,7 @@ int subselect_single_select_engine::exec() SELECT_LEX *save_select= thd->lex->current_select; thd->lex->current_select= select_lex; - if (!join->optimized) + if (join->optimized != JOIN::OPTIMIZATION_DONE) { SELECT_LEX_UNIT *unit= select_lex->master_unit(); @@ -4647,7 +4647,9 @@ int subselect_hash_sj_engine::exec() */ thd->lex->current_select= materialize_engine->select_lex; /* The subquery should be optimized, and materialized only once. */ - DBUG_ASSERT(materialize_join->optimized && !is_materialized); + DBUG_ASSERT(materialize_join->optimized == JOIN::OPTIMIZATION_DONE && + !is_materialized); + materialize_join->exec(); if ((res= test(materialize_join->error || thd->is_fatal_error || thd->is_error()))) diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 69bb822f05a..29d0a9e9888 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -3750,7 +3750,7 @@ int st_select_lex::print_explain(select_result_sink *output, uint8 explain_flags) { int res; - if (join && join->optimized == 2) + if (join && join->optimized == JOIN::OPTIMIZATION_DONE) { res= join->print_explain(output, explain_flags, TRUE, join->need_tmp, // need_tmp_table diff --git a/sql/sql_select.cc b/sql/sql_select.cc index f48f180d1dd..af7a06e424d 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -608,7 +608,7 @@ JOIN::prepare(Item ***rref_pointer_array, DBUG_ENTER("JOIN::prepare"); // to prevent double initialization on EXPLAIN - if (optimized) + if (optimized != JOIN::NOT_OPTIMIZED) DBUG_RETURN(0); conds= conds_init; @@ -936,7 +936,7 @@ err: int JOIN::optimize() { int res= optimize_inner(); - optimized= 2; + optimized= JOIN::OPTIMIZATION_DONE; return res; } /** @@ -960,9 +960,9 @@ JOIN::optimize_inner() DBUG_ENTER("JOIN::optimize"); do_send_rows = (unit->select_limit_cnt) ? 1 : 0; // to prevent double initialization on EXPLAIN - if (optimized) + if (optimized != JOIN::NOT_OPTIMIZED) DBUG_RETURN(0); - optimized= 1; + optimized= JOIN::OPTIMIZATION_IN_PROGRESS; thd_proc_info(thd, "optimizing"); set_allowed_join_cache_types(); @@ -1731,7 +1731,7 @@ int JOIN::init_execution() { DBUG_ENTER("JOIN::init_execution"); - DBUG_ASSERT(optimized); + DBUG_ASSERT(optimized == JOIN::OPTIMIZATION_DONE); DBUG_ASSERT(!(select_options & SELECT_DESCRIBE)); initialized= true; @@ -21187,7 +21187,7 @@ int JOIN::print_explain(select_result_sink *result, uint8 explain_flags, DBUG_PRINT("info", ("Select 0x%lx, type %s, message %s", (ulong)join->select_lex, join->select_lex->type, message ? message : "NULL")); - DBUG_ASSERT(this->optimized == 2); + /* Don't log this into the slow query log */ if (!on_the_fly) @@ -21204,6 +21204,10 @@ int JOIN::print_explain(select_result_sink *result, uint8 explain_flags, { item_list.push_back(new Item_int((int32) join->select_lex->select_number)); + + if (on_the_fly) + join->select_lex->set_explain_type(on_the_fly); + item_list.push_back(new Item_string(join->select_lex->type, strlen(join->select_lex->type), cs)); for (uint i=0 ; i < 7; i++) @@ -21227,6 +21231,7 @@ int JOIN::print_explain(select_result_sink *result, uint8 explain_flags, else if (!join->select_lex->master_unit()->derived || join->select_lex->master_unit()->derived->is_materialized_derived()) { + DBUG_ASSERT(optimized == JOIN::OPTIMIZATION_DONE); table_map used_tables=0; //if (!join->select_lex->type) if (on_the_fly) diff --git a/sql/sql_select.h b/sql/sql_select.h index a15720b4b30..3bb007f0d93 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -1178,7 +1178,11 @@ public: const char *zero_result_cause; ///< not 0 if exec must return zero result bool union_part; ///< this subselect is part of union - int optimized; ///< flag to avoid double optimization in EXPLAIN + + enum join_optimization_state { NOT_OPTIMIZED=0, + OPTIMIZATION_IN_PROGRESS=1, + OPTIMIZATION_DONE=2}; + join_optimization_state optimized; ///< flag to avoid double optimization in EXPLAIN bool initialized; ///< flag to avoid double init_execution calls /* @@ -1261,7 +1265,7 @@ public: ref_pointer_array= items0= items1= items2= items3= 0; ref_pointer_array_size= 0; zero_result_cause= 0; - optimized= 0; + optimized= JOIN::NOT_OPTIMIZED; initialized= 0; cond_equal= 0; having_equal= 0; From d8faf3f1798eeea3147fb6cc95d8bd96c3a3878c Mon Sep 17 00:00:00 2001 From: Joerg Bruehe Date: Mon, 14 May 2012 15:15:13 +0200 Subject: [PATCH 023/289] Raise version after cloning 5.5.25 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 6111f6d453f..a6ecc1acc76 100644 --- a/VERSION +++ b/VERSION @@ -1,4 +1,4 @@ MYSQL_VERSION_MAJOR=5 MYSQL_VERSION_MINOR=5 -MYSQL_VERSION_PATCH=25 +MYSQL_VERSION_PATCH=26 MYSQL_VERSION_EXTRA= From b3841ae9e4754e2aae1c106767d4ba50236cbf9b Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Mon, 14 May 2012 22:39:00 +0400 Subject: [PATCH 024/289] MDEV-267: SHOW EXPLAIN: Server crashes in JOIN::print_explain on most of queries - Make SHOW EXPLAIN code handle degenerate subquery cases (No tables, impossible where, etc) --- mysql-test/r/show_explain.result | 44 ++++++++++++++++++++++++++++++++ mysql-test/t/show_explain.test | 43 +++++++++++++++++++++++++++++++ sql/sql_lex.cc | 21 +++++++++++---- 3 files changed, 103 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/show_explain.result b/mysql-test/r/show_explain.result index 2051a409178..b09903a617a 100644 --- a/mysql-test/r/show_explain.result +++ b/mysql-test/r/show_explain.result @@ -370,4 +370,48 @@ a b set debug=''; DROP VIEW v1; DROP TABLE t2, t3; +# +# MDEV-267: SHOW EXPLAIN: Server crashes in JOIN::print_explain on most of queries +# +set @show_explain_probe_select_id=1; +set debug='d,show_explain_probe_join_exec_end'; +select sleep(1); +show explain for $thr2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select sleep(1) +sleep(1) +0 +set debug=''; +# +# Same as above, but try another reason for JOIN to be degenerate +# +set @show_explain_probe_select_id=1; +set debug='d,show_explain_probe_join_exec_end'; +select * from t0 where 1>10; +show explain for $thr2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +Warnings: +Note 1003 select * from t0 where 1>10 +a +set debug=''; +# +# Same as above, but try another reason for JOIN to be degenerate (2) +# +create table t3(a int primary key); +insert into t3 select a from t0; +set @show_explain_probe_select_id=1; +set debug='d,show_explain_probe_join_exec_end'; +select * from t0,t3 where t3.a=112233; +show explain for $thr2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t3 const PRIMARY PRIMARY 4 0 unique row not found +1 SIMPLE t0 ALL NULL NULL NULL NULL 10 +Warnings: +Note 1003 select * from t0,t3 where t3.a=112233 +a a +set debug=''; +drop table t3; drop table t0,t1; diff --git a/mysql-test/t/show_explain.test b/mysql-test/t/show_explain.test index 36c34c8df5c..c9f715bbb67 100644 --- a/mysql-test/t/show_explain.test +++ b/mysql-test/t/show_explain.test @@ -371,6 +371,49 @@ set debug=''; DROP VIEW v1; DROP TABLE t2, t3; +--echo # +--echo # MDEV-267: SHOW EXPLAIN: Server crashes in JOIN::print_explain on most of queries +--echo # +set @show_explain_probe_select_id=1; +set debug='d,show_explain_probe_join_exec_end'; +send select sleep(1); +connection default; +--source include/wait_condition.inc +evalp show explain for $thr2; +connection con1; +reap; +set debug=''; + + +--echo # +--echo # Same as above, but try another reason for JOIN to be degenerate +--echo # +set @show_explain_probe_select_id=1; +set debug='d,show_explain_probe_join_exec_end'; +send select * from t0 where 1>10; +connection default; +--source include/wait_condition.inc +evalp show explain for $thr2; +connection con1; +reap; +set debug=''; + +--echo # +--echo # Same as above, but try another reason for JOIN to be degenerate (2) +--echo # +create table t3(a int primary key); +insert into t3 select a from t0; +set @show_explain_probe_select_id=1; +set debug='d,show_explain_probe_join_exec_end'; +send select * from t0,t3 where t3.a=112233; +connection default; +--source include/wait_condition.inc +evalp show explain for $thr2; +connection con1; +reap; +set debug=''; +drop table t3; + ## TODO: Test this: have several SHOW EXPLAIN requests be queued up for a ## thread and served together. diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 29d0a9e9888..8838abae735 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -3752,11 +3752,22 @@ int st_select_lex::print_explain(select_result_sink *output, int res; if (join && join->optimized == JOIN::OPTIMIZATION_DONE) { - res= join->print_explain(output, explain_flags, TRUE, - join->need_tmp, // need_tmp_table - (join->order != 0 && !join->skip_sort_order), // bool need_order - join->select_distinct, // bool distinct - NULL); //const char *message + if (!join->table_count) + { + /* It's a degenerate join */ + const char *cause= join->zero_result_cause ? join-> zero_result_cause : + "No tables used"; + res= join->print_explain(output, explain_flags, TRUE, FALSE, FALSE, + FALSE, cause); + } + else + { + res= join->print_explain(output, explain_flags, TRUE, + join->need_tmp, // need_tmp_table + (join->order != 0 && !join->skip_sort_order), // bool need_order + join->select_distinct, // bool distinct + NULL); //const char *message + } if (res) goto err; From e72278fd423d98181d1c4da34e8369e7219b05f8 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Tue, 15 May 2012 09:14:44 +0200 Subject: [PATCH 025/289] Added some extra optional path to test suites --- mysql-test/lib/My/Find.pm | 7 ++++--- mysql-test/lib/mtr_cases.pm | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/mysql-test/lib/My/Find.pm b/mysql-test/lib/My/Find.pm index 0fffc0d7fd7..2730f83a496 100644 --- a/mysql-test/lib/My/Find.pm +++ b/mysql-test/lib/My/Find.pm @@ -126,9 +126,9 @@ sub my_find_file { # # sub my_find_dir { - my ($base, $paths, $dirs, $required)= @_; - croak "usage: my_find_dir(, [, ])" - unless (@_ == 3 or @_ == 2); + my ($base, $paths, $dirs, $optional)= @_; + croak "usage: my_find_dir(, [, [, ]])" + unless (@_ == 3 or @_ == 2 or @_ == 4); # ------------------------------------------------------- # Find and return the first directory @@ -136,6 +136,7 @@ sub my_find_dir { foreach my $path (my_find_paths($base, $paths, $dirs)) { return $path if ( -d $path ); } + return "" if $optional; find_error($base, $paths, $dirs); } diff --git a/mysql-test/lib/mtr_cases.pm b/mysql-test/lib/mtr_cases.pm index 90045d855ab..19eaac6747c 100644 --- a/mysql-test/lib/mtr_cases.pm +++ b/mysql-test/lib/mtr_cases.pm @@ -127,6 +127,7 @@ sub collect_test_cases ($$$) { { push(@$cases, collect_one_suite($suite, $opt_cases)); last if $some_test_found; + push(@$cases, collect_one_suite("i_".$suite, $opt_cases)); } } @@ -277,10 +278,10 @@ sub collect_one_suite($) $suitedir= my_find_dir($suitedir, ["suite", ".", - # Look in storage engine specific suite dirs - "../storage/*/mysql-test-suites" + "../internal/mysql-test/suite" ], - [$suite]); + [$suite], ($suite =~ /^i_/)); + return unless $suitedir; } mtr_verbose("suitedir: $suitedir"); } From fcb033053d72502366f890c4652603c6cbc4fadb Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Tue, 15 May 2012 13:12:22 +0300 Subject: [PATCH 026/289] Bug #11761822: yassl rejects valid certificate which openssl accepts Applied the fix that updates yaSSL to 2.2.1 and fixes parsing this particular certificate. Added a test case with the certificate itself. --- extra/yassl/taocrypt/src/asn.cpp | 4 ++++ vio/viosslfactories.c | 10 ++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/extra/yassl/taocrypt/src/asn.cpp b/extra/yassl/taocrypt/src/asn.cpp index a502666d15b..5ec4cac1c44 100644 --- a/extra/yassl/taocrypt/src/asn.cpp +++ b/extra/yassl/taocrypt/src/asn.cpp @@ -758,6 +758,10 @@ void CertDecoder::GetName(NameType nt) while (source_.get_index() < length) { GetSet(); + if (source_.GetError().What() == SET_E) { + source_.SetError(NO_ERROR_E); // extensions may only have sequence + source_.prev(); + } GetSequence(); byte b = source_.next(); diff --git a/vio/viosslfactories.c b/vio/viosslfactories.c index 3c0c2f3a7ec..945e288a799 100644 --- a/vio/viosslfactories.c +++ b/vio/viosslfactories.c @@ -201,7 +201,7 @@ static void check_ssl_init() static struct st_VioSSLFd * new_VioSSLFd(const char *key_file, const char *cert_file, const char *ca_file, const char *ca_path, - const char *cipher, SSL_METHOD *method, + const char *cipher, my_bool is_client_method, enum enum_ssl_init_error* error) { DH *dh; @@ -222,7 +222,9 @@ new_VioSSLFd(const char *key_file, const char *cert_file, my_malloc(sizeof(struct st_VioSSLFd),MYF(0))))) DBUG_RETURN(0); - if (!(ssl_fd->ssl_context= SSL_CTX_new(method))) + if (!(ssl_fd->ssl_context= SSL_CTX_new(is_client_method ? + TLSv1_client_method() : + TLSv1_server_method()))) { *error= SSL_INITERR_MEMFAIL; DBUG_PRINT("error", ("%s", sslGetErrString(*error))); @@ -300,7 +302,7 @@ new_VioSSLConnectorFd(const char *key_file, const char *cert_file, verify= SSL_VERIFY_NONE; if (!(ssl_fd= new_VioSSLFd(key_file, cert_file, ca_file, - ca_path, cipher, TLSv1_client_method(), &dummy))) + ca_path, cipher, TRUE, &dummy))) { return 0; } @@ -322,7 +324,7 @@ new_VioSSLAcceptorFd(const char *key_file, const char *cert_file, struct st_VioSSLFd *ssl_fd; int verify= SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE; if (!(ssl_fd= new_VioSSLFd(key_file, cert_file, ca_file, - ca_path, cipher, TLSv1_server_method(), error))) + ca_path, cipher, FALSE, error))) { return 0; } From 3780f47339ce54186a03fcc4feefd5011967db12 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 16 May 2012 09:18:57 +0200 Subject: [PATCH 027/289] From c5dc1ea52654627ac2f6f406a16bc04bead9ed0d Mon Sep 17 00:00:00 2001 From: Olav Sandstaa Date: Wed, 16 May 2012 09:49:23 +0200 Subject: [PATCH 028/289] Fix for Bug#12667154 SAME QUERY EXEC AS WHERE SUBQ GIVES DIFFERENT RESULTS ON IN() & NOT IN() COMP #3 This bug causes a wrong result in mysql-trunk when ICP is used and bad performance in mysql-5.5 and mysql-trunk. Using the query from bug report to explain what happens and causes the wrong result from the query when ICP is enabled: 1. The t3 table contains four records. The outer query will read these and for each of these it will execute the subquery. 2. Before the first execution of the subquery it will be optimized. In this case the important is what happens to the first table t1: -make_join_select() will call the range optimizer which decides that t1 should be accessed using a range scan on the k1 index It creates a QUICK_RANGE_SELECT object for this. -As the last part of optimization the ICP code pushes the condition down to the storage engine for table t1 on the k1 index. This produces the following information in the explain for this table: 2 DEPENDENT SUBQUERY t1 range k1 k1 5 NULL 3 Using index condition; Using filesort Note the use of filesort. 3. The first execution of the subquery does (among other things) due to the need for sorting: a. Call create_sort_index() which again will call find_all_keys(): b. find_all_keys() will read the required keys for all qualifying rows from the storage engine. To do this it checks if it has a quick-select for the table. It will use the quick-select for reading records. In this case it will read four records from the storage engine (based on the range criteria). The storage engine will evaluate the pushed index condition for each record. c. At the end of create_sort_index() there is code that cleans up a lot of stuff on the join tab. One of the things that is cleaned is the select object. The result of this is that the quick-select object created in make_join_select is deleted. 4. The second execution of the subquery does the same as the first but the result is different: a. Call create_sort_index() which again will call find_all_keys() (same as for the first execution) b. find_all_keys() will read the keys from the storage engine. To do this it checks if it has a quick-select for the table. Now there is NO quick-select object(!) (since it was deleted in step 3c). So find_all_keys defaults to read the table using a table scan instead. So instead of reading the four relevant records in the range it reads the entire table (6 records). It then evaluates the table's condition (and here it goes wrong). Since the entire condition has been pushed down to the storage engine using ICP all 6 records qualify. (Note that the storage engine will not evaluate the pushed index condition in this case since it was pushed for the k1 index and now we do a table scan without any index being used). The result is that here we return six qualifying key values instead of four due to not evaluating the table's condition. c. As above. 5. The two last execution of the subquery will also produce wrong results for the same reason. Summary: The problem occurs due to all but the first executions of the subquery is done as a table scan without evaluating the table's condition (which is pushed to the storage engine on a different index). This is caused by the create_sort_index() function deleting the quick-select object that should have been used for executing the subquery as a range scan. Note that this bug in addition to causing wrong results also can result in bad performance due to executing the subquery using a table scan instead of a range scan. This is an issue in MySQL 5.5. The fix for this problem is to avoid that the Quick-select-object that the optimizer created is deleted when create_sort_index() is doing clean-up of the join-tab. This will ensure that the quick-select object and the corresponding pushed index condition will be available and used by all following executions of the subquery. sql/sql_select.cc: Fix for Bug#12667154: Change how create_sort_index() cleans up the join_tab's select and quick-select objects in order to avoid that a quick-select object created outside of create_sort_index() is deleted. --- sql/sql_select.cc | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 3c709e3c0ea..193121c9a95 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -14066,6 +14066,14 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order, table= tab->table; select= tab->select; + /* + If we have a select->quick object that is created outside of + create_sort_index() and this is part of a subquery that + potentially can be executed multiple times then we should not + delete the quick object on exit from this function. + */ + bool keep_quick= select && select->quick && join->join_tab_save; + /* When there is SQL_BIG_RESULT do not sort using index for GROUP BY, and thus force sorting on disk unless a group min-max optimization @@ -14117,6 +14125,7 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order, get_quick_select_for_ref(thd, table, &tab->ref, tab->found_records)))) goto err; + DBUG_ASSERT(!keep_quick); } } @@ -14147,9 +14156,25 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order, tablesort_result_cache= table->sort.io_cache; table->sort.io_cache= NULL; - select->cleanup(); // filesort did select - tab->select= 0; - table->quick_keys.clear_all(); // as far as we cleanup select->quick + /* + If a quick object was created outside of create_sort_index() + that might be reused, then do not call select->cleanup() since + it will delete the quick object. + */ + if (!keep_quick) + { + select->cleanup(); + /* + The select object should now be ready for the next use. If it + is re-used then there exists a backup copy of this join tab + which has the pointer to it. The join tab will be restored in + JOIN::reset(). So here we just delete the pointer to it. + */ + tab->select= NULL; + // If we deleted the quick select object we need to clear quick_keys + table->quick_keys.clear_all(); + } + // Restore the output resultset table->sort.io_cache= tablesort_result_cache; } tab->select_cond=0; From 0e9c1e9fc395f3afe1e6b5a2d758eb42d765ec15 Mon Sep 17 00:00:00 2001 From: Venkata Sidagam Date: Wed, 16 May 2012 13:55:22 +0530 Subject: [PATCH 029/289] Bug #13955256: KEYCACHE CRASHES, CORRUPTIONS/HANGS WITH, FULLTEXT INDEX AND CONCURRENT DML. Problem Statement: ------------------ 1) Create a table with FT index. 2) Enable concurrent inserts. 3) In multiple threads do below operations repeatedly a) truncate table b) insert into table .... c) select ... match .. against .. non-boolean/boolean mode After some time we could observe two different assert core dumps Analysis: -------- 1)assert core dump at key_read_cache(): Two select threads operating in-parallel on same key root block. 1st select thread block->status is set to BLOCK_ERROR because the my_pread() in read_block() is returning '0'. Truncate table made the index file size as 1024 and pread was asked to get the block of count bytes(1024 bytes) from offset of 1024 which it cannot read since its "end of file" and retuning '0' setting "my_errno= HA_ERR_FILE_TOO_SHORT" and the key_file_length, key_root[0] is same i.e. 1024. Since block status has BLOCK_ERROR the 1st select thread enter into the free_block() and will be under wait on conditional mutex by making status as BLOCK_REASSIGNED and goes for wait_on_readers(). Other select thread will also work on the same block and sees the status as BLOCK_ERROR and enters into free_block(), checks for BLOCK_REASSIGNED and asserting the server. 2)assert core dump at key_write_cache(): One select thread and One insert thread. Select thread gets the unlocks the 'keycache->cache_lock', which allows other threads to continue and gets the pread() return value as'0'(please see the explanation above) and tries to get the lock on 'keycache->cache_lock' and waits there for the lock. Insert thread requests for the block, block will be assigned from the hash list and makes the page_status as 'PAGE_WAIT_TO_BE_READ' and goes for the read_block(), waits in the queue since there are some other threads performing reads on the same block. Select thread which was waiting for the 'keycache->cache_lock' mutex in the read_block() will continue after getting the my_pread() value as '0' and sets the block status as BLOCK_ERROR and goes to the free_block() and go to the wait_for_readers(). Now the insert thread will awake and continues. and checks block->status as not BLOCK_READ and it asserts. Fix: --- In the full text code, multiple readers of index file is not guarded. Hence added below below code in _ft2_search() and walk_and_match(). to lock the key_root I have used below code in _ft2_search() if (info->s->concurrent_insert) mysql_rwlock_rdlock(&share->key_root_lock[0]); and to unlock if (info->s->concurrent_insert) mysql_rwlock_unlock(&share->key_root_lock[0]); storage/myisam/ft_boolean_search.c: Since its a recursion function, to avoid confusion in taking and releasing the locks, renamed _ft2_search() to _ft2_search_internal() function. And _ft2_search() will take the lock, call _ft2_search_internal() and release the lock in case of concurrent inserts. storage/myisam/ft_nlq_search.c: Added read locks code in walk_and_match() --- storage/myisam/ft_boolean_search.c | 16 ++++++++++++++-- storage/myisam/ft_nlq_search.c | 18 +++++++++++++++++- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/storage/myisam/ft_boolean_search.c b/storage/myisam/ft_boolean_search.c index 62d912a0fd0..16cf2669c6d 100644 --- a/storage/myisam/ft_boolean_search.c +++ b/storage/myisam/ft_boolean_search.c @@ -354,7 +354,7 @@ static int _ftb_no_dupes_cmp(void* not_used __attribute__((unused)), returns 1 if the search was finished (must-word wasn't found) */ -static int _ft2_search(FTB *ftb, FTB_WORD *ftbw, my_bool init_search) +static int _ft2_search_no_lock(FTB *ftb, FTB_WORD *ftbw, my_bool init_search) { int r; int subkeys=1; @@ -454,7 +454,7 @@ static int _ft2_search(FTB *ftb, FTB_WORD *ftbw, my_bool init_search) ftbw->key_root=info->s->state.key_root[ftb->keynr]; ftbw->keyinfo=info->s->keyinfo+ftb->keynr; ftbw->off=0; - return _ft2_search(ftb, ftbw, 0); + return _ft2_search_no_lock(ftb, ftbw, 0); } /* matching key found */ @@ -482,6 +482,18 @@ static int _ft2_search(FTB *ftb, FTB_WORD *ftbw, my_bool init_search) return 0; } +static int _ft2_search(FTB *ftb, FTB_WORD *ftbw, my_bool init_search) +{ + int r; + MYISAM_SHARE *share= ftb->info->s; + if (share->concurrent_insert) + rw_rdlock(&share->key_root_lock[ftb->keynr]); + r= _ft2_search_no_lock(ftb, ftbw, init_search); + if (share->concurrent_insert) + rw_unlock(&share->key_root_lock[ftb->keynr]); + return r; +} + static void _ftb_init_index_search(FT_INFO *ftb) { int i; diff --git a/storage/myisam/ft_nlq_search.c b/storage/myisam/ft_nlq_search.c index 333ec5d0b4f..c74451828a4 100644 --- a/storage/myisam/ft_nlq_search.c +++ b/storage/myisam/ft_nlq_search.c @@ -71,9 +71,10 @@ static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio) TREE_ELEMENT *selem; double gweight=1; MI_INFO *info=aio->info; + MYISAM_SHARE *share= info->s; uchar *keybuff=aio->keybuff; MI_KEYDEF *keyinfo=info->s->keyinfo+aio->keynr; - my_off_t key_root=info->s->state.key_root[aio->keynr]; + my_off_t key_root; uint extra= HA_FT_WLEN + info->s->rec_reflength; #if HA_FT_WTYPE == HA_KEYTYPE_FLOAT float tmp_weight; @@ -89,6 +90,11 @@ static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio) keylen-=HA_FT_WLEN; doc_cnt=0; + if (share->concurrent_insert) + rw_rdlock(&share->key_root_lock[aio->keynr]); + + key_root= share->state.key_root[aio->keynr]; + /* Skip rows inserted by current inserted */ for (r=_mi_search(info, keyinfo, keybuff, keylen, SEARCH_FIND, key_root) ; !r && @@ -98,6 +104,9 @@ static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio) info->lastkey_length, SEARCH_BIGGER, key_root)) ; + if (share->concurrent_insert) + rw_unlock(&share->key_root_lock[aio->keynr]); + info->update|= HA_STATE_AKTIV; /* for _mi_test_if_changed() */ /* The following should be safe, even if we compare doubles */ @@ -121,6 +130,8 @@ static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio) keyinfo=& info->s->ft2_keyinfo; key_root=info->lastpos; keylen=0; + if (share->concurrent_insert) + rw_rdlock(&share->key_root_lock[aio->keynr]); r=_mi_search_first(info, keyinfo, key_root); goto do_skip; } @@ -155,6 +166,9 @@ static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio) if (gweight < 0 || doc_cnt > 2000000) gweight=0; + if (share->concurrent_insert) + rw_rdlock(&share->key_root_lock[aio->keynr]); + if (_mi_test_if_changed(info) == 0) r=_mi_search_next(info, keyinfo, info->lastkey, info->lastkey_length, SEARCH_BIGGER, key_root); @@ -167,6 +181,8 @@ do_skip: r= _mi_search_next(info, keyinfo, info->lastkey, info->lastkey_length, SEARCH_BIGGER, key_root); + if (share->concurrent_insert) + rw_unlock(&share->key_root_lock[aio->keynr]); } word->weight=gweight; From 7a6c449c62ae86872aeef489895e1f016b921da6 Mon Sep 17 00:00:00 2001 From: Annamalai Gurusami Date: Wed, 16 May 2012 15:23:56 +0530 Subject: [PATCH 030/289] Bug #13943231: ALTER TABLE AFTER DISCARD MAY CRASH THE SERVER The following scenario crashes our mysql server: 1. set global innodb_file_per_table=1; 2. create table t1(c1 int) engine=innodb; 3. alter table t1 discard tablespace; 4. alter table t1 add unique index(c1); Step 4 crashes the server. This patch introduces a check on discarded tablespace to avoid the crash. rb://1041 approved by Marko Makela --- storage/innodb_plugin/handler/handler0alter.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/storage/innodb_plugin/handler/handler0alter.cc b/storage/innodb_plugin/handler/handler0alter.cc index e2702b157af..6f02b500d96 100644 --- a/storage/innodb_plugin/handler/handler0alter.cc +++ b/storage/innodb_plugin/handler/handler0alter.cc @@ -665,6 +665,10 @@ ha_innobase::add_index( DBUG_RETURN(HA_ERR_NO_SUCH_TABLE); } + if (innodb_table->tablespace_discarded) { + DBUG_RETURN(-1); + } + /* Check that index keys are sensible */ error = innobase_check_index_keys(key_info, num_of_keys, innodb_table); From 0581d1c46c1bbe3f87ac4cef697af3b75392b815 Mon Sep 17 00:00:00 2001 From: Mayank Prasad Date: Thu, 17 May 2012 22:24:23 +0530 Subject: [PATCH 031/289] Bug#11766101 : 59140: LIKE CONCAT('%',@A,'%') DOESN'T MATCH WHEN @A CONTAINS LATIN1 STRING Issue/Cause: Issue is of memory corruption.During optimization phase, pattern to be matched in where clause, is prepared. This is done in Item_func_concat::val_str() function which forms the resultant string (tmp_value) and return its pointer. In caller, Item_func_like::fix_fields, pattern is made to point to this string (tmp_value). In further processing, tmp_value is getting modified which causes pattern to have changed/wrong values. Fix: Allocate its own memroy location in caller, copy value of resultant string (tmp_value) into that and make pattern to point to that. This makes sure no further changes to tmp_value will affect pattern. --- 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 fb9878ccb0a..657bc3ed234 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -4877,8 +4877,8 @@ bool Item_func_like::fix_fields(THD *thd, Item **ref) } if (canDoTurboBM) { - pattern = first + 1; pattern_len = (int) len - 2; + pattern = thd->strmake(first + 1, pattern_len); DBUG_PRINT("info", ("Initializing pattern: '%s'", first)); int *suff = (int*) thd->alloc((int) (sizeof(int)* ((pattern_len + 1)*2+ From 02f90402c8218227c81f86f0b56cd283f7a2eb64 Mon Sep 17 00:00:00 2001 From: Tor Didriksen Date: Fri, 18 May 2012 12:57:38 +0200 Subject: [PATCH 032/289] Bug#14039955 RPAD FUNCTION LEADS TO UNINITIALIZED VALUES WARNING IN MY_STRTOD Rewrite the "parser" in my_strtod_int() to avoid reading past the end of the input string. --- strings/dtoa.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/strings/dtoa.c b/strings/dtoa.c index ef1c141ec44..4086bf412fe 100644 --- a/strings/dtoa.c +++ b/strings/dtoa.c @@ -1416,20 +1416,27 @@ static double my_strtod_int(const char *s00, char **se, int *error, char *buf, s c= *++s; if (!nd) { - for (; s < end && c == '0'; c= *++s) + for (; s < end; ++s) + { + c= *s; + if (c != '0') + break; nz++; + } if (s < end && c > '0' && c <= '9') { s0= s; nf+= nz; nz= 0; - goto have_dig; } - goto dig_done; + else + goto dig_done; } - for (; s < end && c >= '0' && c <= '9'; c = *++s) + for (; s < end; ++s) { - have_dig: + c= *s; + if (c < '0' || c > '9') + break; /* Here we are parsing the fractional part. We can stop counting digits after a while: the extra digits From f436b188e24e35e155497bbcdae7c8b2c97cb2e5 Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Tue, 15 May 2012 12:45:52 +0200 Subject: [PATCH 033/289] bug#13949735: crash regression from bug#13694811. There can be cases when the optimizer calls ha_partition::records_in_range when there are no matching partitions. So the DBUG_ASSERT of !tot_used_partitions does assert. Fixed by returning 0 instead when no matching partitions are found. This will avoid the crash. records_in_range will then try to find the biggest used partition, which will not find any partition and records_in_range will then return 0, meaning non rows can be found. Patch contributed by Davi Arnaut at twitter. --- sql/ha_partition.cc | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 5b25bd26298..1debc02d7f2 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -6322,7 +6322,17 @@ ha_rows ha_partition::min_rows_for_estimate() DBUG_ENTER("ha_partition::min_rows_for_estimate"); tot_used_partitions= bitmap_bits_set(&m_part_info->used_partitions); - DBUG_ASSERT(tot_used_partitions); + + /* + All partitions might have been left as unused during partition pruning + due to, for example, an impossible WHERE condition. Nonetheless, the + optimizer might still attempt to perform (e.g. range) analysis where an + estimate of the the number of rows is calculated using records_in_range. + Hence, to handle this and other possible cases, use zero as the minimum + number of rows to base the estimate on if no partition is being used. + */ + if (!tot_used_partitions) + DBUG_RETURN(0); /* Allow O(log2(tot_partitions)) increase in number of used partitions. From 382e81ca84a51fded86df6f21e0b4e003fc94388 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Tue, 15 May 2012 15:56:50 +0400 Subject: [PATCH 034/289] MDEV-270: SHOW EXPLAIN: server crashes in JOIN::print_explain on a query with select tables optimized away - Take into account, that for some degenerate joins instead of "join->table_count=0" the code sets "join->tables_list=0". --- mysql-test/r/show_explain.result | 39 ++++++++++++++++++++++++++++++++ mysql-test/t/show_explain.test | 34 ++++++++++++++++++++++++++++ sql/sql_lex.cc | 2 +- sql/sql_select.cc | 9 ++++++++ 4 files changed, 83 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/show_explain.result b/mysql-test/r/show_explain.result index b09903a617a..1b1c30b56df 100644 --- a/mysql-test/r/show_explain.result +++ b/mysql-test/r/show_explain.result @@ -414,4 +414,43 @@ Note 1003 select * from t0,t3 where t3.a=112233 a a set debug=''; drop table t3; +# +# MDEV-270: SHOW EXPLAIN: server crashes in JOIN::print_explain on a query with +# select tables optimized away +# +CREATE TABLE t2 (pk INT PRIMARY KEY, a INT ) ENGINE=MyISAM; +INSERT INTO t2 VALUES +(1,4),(2,62),(3,7),(4,1),(5,0),(6,7),(7,7),(8,1),(9,7),(10,1), +(11,5),(12,2),(13,0),(14,1),(15,8),(16,1),(17,1),(18,9),(19,1),(20,5) ; +explain SELECT * FROM t2 WHERE a = +(SELECT MAX(a) FROM t2 +WHERE pk= (SELECT MAX(pk) FROM t2 WHERE pk = 3) +); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t2 ALL NULL NULL NULL NULL 20 Using where +2 SUBQUERY t2 const PRIMARY PRIMARY 4 const 1 Using where +3 SUBQUERY NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +set @show_explain_probe_select_id=2; +set debug='d,show_explain_probe_do_select'; +SELECT * FROM t2 WHERE a = +(SELECT MAX(a) FROM t2 +WHERE pk= (SELECT MAX(pk) FROM t2 WHERE pk = 3) +); +show explain for $thr2; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t2 ALL NULL NULL NULL NULL 20 Using where +2 SUBQUERY t2 const PRIMARY PRIMARY 4 1 Using where +3 SUBQUERY NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +Warnings: +Note 1003 SELECT * FROM t2 WHERE a = +(SELECT MAX(a) FROM t2 +WHERE pk= (SELECT MAX(pk) FROM t2 WHERE pk = 3) +) +pk a +3 7 +6 7 +7 7 +9 7 +set debug=''; +drop table t2; drop table t0,t1; diff --git a/mysql-test/t/show_explain.test b/mysql-test/t/show_explain.test index c9f715bbb67..d813956a1fe 100644 --- a/mysql-test/t/show_explain.test +++ b/mysql-test/t/show_explain.test @@ -414,6 +414,40 @@ reap; set debug=''; drop table t3; +--echo # +--echo # MDEV-270: SHOW EXPLAIN: server crashes in JOIN::print_explain on a query with +--echo # select tables optimized away +--echo # + +CREATE TABLE t2 (pk INT PRIMARY KEY, a INT ) ENGINE=MyISAM; +INSERT INTO t2 VALUES + (1,4),(2,62),(3,7),(4,1),(5,0),(6,7),(7,7),(8,1),(9,7),(10,1), + (11,5),(12,2),(13,0),(14,1),(15,8),(16,1),(17,1),(18,9),(19,1),(20,5) ; + +explain SELECT * FROM t2 WHERE a = + (SELECT MAX(a) FROM t2 + WHERE pk= (SELECT MAX(pk) FROM t2 WHERE pk = 3) + ); + +set @show_explain_probe_select_id=2; +set debug='d,show_explain_probe_do_select'; +send SELECT * FROM t2 WHERE a = + (SELECT MAX(a) FROM t2 + WHERE pk= (SELECT MAX(pk) FROM t2 WHERE pk = 3) + ); +connection default; +--source include/wait_condition.inc +evalp show explain for $thr2; +connection con1; +reap; +set debug=''; +drop table t2; + + + + + + ## TODO: Test this: have several SHOW EXPLAIN requests be queued up for a ## thread and served together. diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 8838abae735..556077220de 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -3752,7 +3752,7 @@ int st_select_lex::print_explain(select_result_sink *output, int res; if (join && join->optimized == JOIN::OPTIMIZATION_DONE) { - if (!join->table_count) + if (!join->table_count || !join->tables_list) { /* It's a degenerate join */ const char *cause= join->zero_result_cause ? join-> zero_result_cause : diff --git a/sql/sql_select.cc b/sql/sql_select.cc index af7a06e424d..7af818ba147 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -15399,6 +15399,15 @@ do_select(JOIN *join,List *fields,TABLE *table,Procedure *procedure) else { DBUG_ASSERT(join->table_count); + + THD *thd= join->thd; + DBUG_EXECUTE_IF("show_explain_probe_do_select", + if (dbug_user_var_equals_int(thd, + "show_explain_probe_select_id", + join->select_lex->select_number)) + dbug_serve_apcs(thd, 1); + ); + if (join->outer_ref_cond && !join->outer_ref_cond->val_int()) error= NESTED_LOOP_NO_MORE_ROWS; else From 5917c58a5d23e30ed33ca9559ac3a8010d182d40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 15 May 2012 15:04:39 +0300 Subject: [PATCH 035/289] Bug#14025221 FOREIGN KEY REFERENCES FREED MEMORY AFTER DROP INDEX dict_table_replace_index_in_foreign_list(): Replace the dropped index also in the foreign key constraints of child tables that are referencing this table. row_ins_check_foreign_constraint(): If the underlying index is missing, refuse the operation. rb:1051 approved by Jimmy Yang --- storage/innodb_plugin/dict/dict0dict.c | 22 ++++++++++++++++++++++ storage/innodb_plugin/row/row0ins.c | 6 ++---- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/storage/innodb_plugin/dict/dict0dict.c b/storage/innodb_plugin/dict/dict0dict.c index df7ac85681c..cfeba015723 100644 --- a/storage/innodb_plugin/dict/dict0dict.c +++ b/storage/innodb_plugin/dict/dict0dict.c @@ -4872,6 +4872,28 @@ dict_table_replace_index_in_foreign_list( foreign->foreign_index = new_index; } } + + + for (foreign = UT_LIST_GET_FIRST(table->referenced_list); + foreign; + foreign = UT_LIST_GET_NEXT(referenced_list, foreign)) { + + dict_index_t* new_index; + + if (foreign->referenced_index == index) { + ut_ad(foreign->referenced_table == index->table); + + new_index = dict_foreign_find_index( + foreign->referenced_table, + foreign->referenced_col_names, + foreign->n_fields, index, + /*check_charsets=*/TRUE, /*check_null=*/FALSE); + ut_ad(new_index || !trx->check_foreigns); + ut_ad(!new_index || new_index->table == index->table); + + foreign->referenced_index = new_index; + } + } } /**********************************************************************//** diff --git a/storage/innodb_plugin/row/row0ins.c b/storage/innodb_plugin/row/row0ins.c index 2d4afa6c5ed..4994a91dd23 100644 --- a/storage/innodb_plugin/row/row0ins.c +++ b/storage/innodb_plugin/row/row0ins.c @@ -1296,7 +1296,8 @@ run_again: check_index = foreign->foreign_index; } - if (check_table == NULL || check_table->ibd_file_missing) { + if (check_table == NULL || check_table->ibd_file_missing + || check_index == NULL) { if (check_ref) { FILE* ef = dict_foreign_err_file; @@ -1331,9 +1332,6 @@ run_again: goto exit_func; } - ut_a(check_table); - ut_a(check_index); - if (check_table != table) { /* We already have a LOCK_IX on table, but not necessarily on check_table */ From 5d8b38df4c6166bb7f52d6602c2b7eb48628c233 Mon Sep 17 00:00:00 2001 From: Nuno Carvalho Date: Tue, 15 May 2012 22:06:48 +0100 Subject: [PATCH 036/289] BUG#11754117 - 45670: INTVAR_EVENTS FOR FILTERED-OUT QUERY_LOG_EVENTS ARE EXECUTED Improved random number filtering verification on rpl_filter_tables_not_exist test. --- .../rpl/r/rpl_filter_tables_not_exist.result | 9 +++++---- .../rpl/t/rpl_filter_tables_not_exist.test | 17 +++++++++-------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/mysql-test/suite/rpl/r/rpl_filter_tables_not_exist.result b/mysql-test/suite/rpl/r/rpl_filter_tables_not_exist.result index f0dc97b71f2..e11c54499fe 100644 --- a/mysql-test/suite/rpl/r/rpl_filter_tables_not_exist.result +++ b/mysql-test/suite/rpl/r/rpl_filter_tables_not_exist.result @@ -114,17 +114,17 @@ id c 3 3 [on master] drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; -CREATE TABLE test.t5 (a INT AUTO_INCREMENT PRIMARY KEY, b INT, c INT); +CREATE TABLE test.t5 (a INT AUTO_INCREMENT PRIMARY KEY, b DECIMAL(20,20), c INT); CREATE TABLE test.t1 (a INT); INSERT INTO test.t1 VALUES(1); call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT"); -CREATE TABLE test.t_slave (a INT AUTO_INCREMENT PRIMARY KEY, b INT, c INT); +CREATE TABLE test.t_slave (a INT AUTO_INCREMENT PRIMARY KEY, b DECIMAL(20,20), c INT); CREATE TRIGGER t1_update AFTER UPDATE ON test.t1 FOR EACH ROW -INSERT INTO test.t_slave VALUES(NULL, ROUND(RAND() * 1000), @c); +INSERT INTO test.t_slave VALUES(NULL, RAND(), @c); SET INSERT_ID=2; SET @c=2; SET @@rand_seed1=10000000, @@rand_seed2=1000000; -INSERT INTO t5 VALUES (NULL, ROUND(RAND() * 1000), @c); +INSERT INTO t5 VALUES (NULL, RAND(), @c); Warnings: Note 1592 Statement may not be safe to log in statement format. SELECT b into @b FROM test.t5; @@ -132,6 +132,7 @@ UPDATE test.t1 SET a=2; SELECT a AS 'ONE' into @a FROM test.t_slave; SELECT c AS 'NULL' into @c FROM test.t_slave; SELECT b into @b FROM test.t_slave; +include/assert.inc [Random values from master and slave must be different] drop table test.t5; drop table test.t1; drop table test.t_slave; diff --git a/mysql-test/suite/rpl/t/rpl_filter_tables_not_exist.test b/mysql-test/suite/rpl/t/rpl_filter_tables_not_exist.test index b62a6e96437..3572dd53ea7 100644 --- a/mysql-test/suite/rpl/t/rpl_filter_tables_not_exist.test +++ b/mysql-test/suite/rpl/t/rpl_filter_tables_not_exist.test @@ -215,21 +215,23 @@ drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; # be filtered as well. # connection master; -CREATE TABLE test.t5 (a INT AUTO_INCREMENT PRIMARY KEY, b INT, c INT); # ignored on slave +# Although RAND() is from 0 to 1.0, DECIMAL(M,D), requires that M must be >= D. +CREATE TABLE test.t5 (a INT AUTO_INCREMENT PRIMARY KEY, b DECIMAL(20,20), c INT); # ignored on slave CREATE TABLE test.t1 (a INT); # accepted on slave INSERT INTO test.t1 VALUES(1); --sync_slave_with_master call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT"); -CREATE TABLE test.t_slave (a INT AUTO_INCREMENT PRIMARY KEY, b INT, c INT); +# Although RAND() is from 0 to 1.0, DECIMAL(M,D), requires that M must be >= D. +CREATE TABLE test.t_slave (a INT AUTO_INCREMENT PRIMARY KEY, b DECIMAL(20,20), c INT); CREATE TRIGGER t1_update AFTER UPDATE ON test.t1 FOR EACH ROW - INSERT INTO test.t_slave VALUES(NULL, ROUND(RAND() * 1000), @c); + INSERT INTO test.t_slave VALUES(NULL, RAND(), @c); connection master; SET INSERT_ID=2; SET @c=2; SET @@rand_seed1=10000000, @@rand_seed2=1000000; -INSERT INTO t5 VALUES (NULL, ROUND(RAND() * 1000), @c); # to be ignored +INSERT INTO t5 VALUES (NULL, RAND(), @c); # to be ignored SELECT b into @b FROM test.t5; --let $b_master=`select @b` UPDATE test.t1 SET a=2; # to run trigger on slave @@ -253,10 +255,9 @@ if (`SELECT @a != 2 and @c != NULL`) SELECT b into @b FROM test.t_slave; --let $b_slave=`select @b` -if (`SELECT $b_slave = $b_master`) -{ - --echo Might be pure coincidence of two randoms from master and slave table. Don not panic yet. -} +--let $assert_text= Random values from master and slave must be different +--let $assert_cond= $b_master != $b_slave +--source include/assert.inc # cleanup BUG#11754117 connection master; From bcb5d73767fbc04c88d3c8b05eafbdc9a905ea1f Mon Sep 17 00:00:00 2001 From: Annamalai Gurusami Date: Wed, 16 May 2012 11:17:48 +0530 Subject: [PATCH 037/289] Bug #12752572 61579: REPLICATION FAILURE WHILE INNODB_AUTOINC_LOCK_MODE=1 AND USING TRIGGER When an insert stmt like "insert into t values (1),(2),(3)" is executed, the autoincrement values assigned to these three rows are expected to be contiguous. In the given lock mode (innodb_autoinc_lock_mode=1), the auto inc lock will be released before the end of the statement. So to make the autoincrement contiguous for a given statement, we need to reserve the auto inc values at the beginning of the statement. rb://1074 approved by Alexander Nozdrin --- sql/handler.cc | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sql/handler.cc b/sql/handler.cc index d2eaab19ad8..20bf2355c25 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -2397,6 +2397,17 @@ int handler::update_auto_increment() reservation means potentially losing unused values). Note that in prelocked mode no estimation is given. */ + + /* + For multi-row inserts, if the bulk inserts cannot be started, the + handler::estimation_rows_to_insert will not be set. Set it here. + */ + if ((estimation_rows_to_insert == 0) && + (thd->lex->many_values.elements > 0)) + { + estimation_rows_to_insert= thd->lex->many_values.elements; + } + if ((auto_inc_intervals_count == 0) && (estimation_rows_to_insert > 0)) nb_desired_values= estimation_rows_to_insert; else /* go with the increasing defaults */ @@ -4690,6 +4701,8 @@ int handler::ha_write_row(uchar *buf) DBUG_RETURN(error); if (unlikely(error= binlog_log_row(table, 0, buf, log_func))) DBUG_RETURN(error); /* purecov: inspected */ + + DEBUG_SYNC_C("ha_write_row_end"); DBUG_RETURN(0); } From 533e1d28459ab5aa0604560bf8885ae18e553295 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Wed, 16 May 2012 12:49:22 +0400 Subject: [PATCH 038/289] MDEV-273: SHOW EXPLAIN: server crashes in JOIN::print_explain on a query with impossible WHERE - It turns out, there is a case where the join is degenerate, but join->table_count!= && join->tables_list!=NULL. Need to also check if join->zero_result_cause!=NULL, too. - There is a slight problem: The code sets zero_result_cause= "no matching row in const table" when NOT running EXPLAIN. The result is that SHOW EXPLAIN will show this line while regular EXPLAIN will not. --- mysql-test/r/show_explain.result | 56 ++++++++++++++++++++++++++++++-- mysql-test/t/show_explain.test | 43 +++++++++++++++++++++++- sql/sql_lex.cc | 6 +++- 3 files changed, 100 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/show_explain.result b/mysql-test/r/show_explain.result index 1b1c30b56df..d19a6f29539 100644 --- a/mysql-test/r/show_explain.result +++ b/mysql-test/r/show_explain.result @@ -1,4 +1,4 @@ -drop table if exists t0, t1, t2; +drop table if exists t0, t1, t2, t3, t4; drop view if exists v1; create table t0 (a int); insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); @@ -407,8 +407,7 @@ set debug='d,show_explain_probe_join_exec_end'; select * from t0,t3 where t3.a=112233; show explain for $thr2; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t3 const PRIMARY PRIMARY 4 0 unique row not found -1 SIMPLE t0 ALL NULL NULL NULL NULL 10 +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL no matching row in const table Warnings: Note 1003 select * from t0,t3 where t3.a=112233 a a @@ -453,4 +452,55 @@ pk a 9 7 set debug=''; drop table t2; +# +# MDEV-273: SHOW EXPLAIN: server crashes in JOIN::print_explain on a query with impossible WHERE +# +CREATE TABLE t2 (a1 INT, KEY(a1)) ENGINE=MyISAM; +INSERT INTO t2 VALUES +(4),(6),(7),(1),(0),(7),(7),(1),(7),(1), +(5),(2),(0),(1),(8),(1),(1),(9),(1),(5); +CREATE TABLE t3 (b1 INT) ENGINE=MyISAM; +INSERT INTO t3 VALUES +(4),(5),(8),(4),(8),(2),(9),(6),(4),(8), +(3),(5),(9),(6),(8),(3),(2),(6),(3),(1), +(4),(3),(1),(7),(0),(0),(9),(5),(9),(0), +(2),(2),(5),(9),(1),(4),(8),(6),(5),(5), +(1),(7),(2),(8),(9),(3),(2),(6),(6),(5), +(4),(3),(2),(7),(4),(6),(0),(8),(5),(8), +(2),(9),(7),(5),(7),(0),(4),(3),(1),(0), +(6),(2),(8),(3),(7),(3),(5),(5),(1),(2), +(1),(7),(1),(9),(9),(8),(3); +CREATE TABLE t4 (c1 INT) ENGINE=MyISAM; +EXPLAIN +SELECT count(*) FROM t2, t3 +WHERE a1 < ALL ( +SELECT a1 FROM t2 +WHERE a1 IN ( SELECT a1 FROM t2, t4 ) +); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t2 index NULL a1 5 NULL 20 Using where; Using index +1 PRIMARY t3 ALL NULL NULL NULL NULL 87 Using join buffer (flat, BNL join) +2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +set @show_explain_probe_select_id=1; +set debug='d,show_explain_probe_do_select'; +SELECT count(*) FROM t2, t3 +WHERE a1 < ALL ( +SELECT a1 FROM t2 +WHERE a1 IN ( SELECT a1 FROM t2, t4 ) +); +show explain for $thr2; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t2 index NULL a1 5 NULL 20 Using where; Using index +1 PRIMARY t3 ALL NULL NULL NULL NULL 87 Using join buffer (flat, BNL join) +2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL no matching row in const table +Warnings: +Note 1003 SELECT count(*) FROM t2, t3 +WHERE a1 < ALL ( +SELECT a1 FROM t2 +WHERE a1 IN ( SELECT a1 FROM t2, t4 ) +) +count(*) +1740 +set debug=''; +drop table t2, t3, t4; drop table t0,t1; diff --git a/mysql-test/t/show_explain.test b/mysql-test/t/show_explain.test index d813956a1fe..35694e97111 100644 --- a/mysql-test/t/show_explain.test +++ b/mysql-test/t/show_explain.test @@ -4,7 +4,7 @@ --source include/have_debug.inc --disable_warnings -drop table if exists t0, t1, t2; +drop table if exists t0, t1, t2, t3, t4; drop view if exists v1; --enable_warnings @@ -444,9 +444,50 @@ set debug=''; drop table t2; +--echo # +--echo # MDEV-273: SHOW EXPLAIN: server crashes in JOIN::print_explain on a query with impossible WHERE +--echo # +CREATE TABLE t2 (a1 INT, KEY(a1)) ENGINE=MyISAM; +INSERT INTO t2 VALUES + (4),(6),(7),(1),(0),(7),(7),(1),(7),(1), + (5),(2),(0),(1),(8),(1),(1),(9),(1),(5); +CREATE TABLE t3 (b1 INT) ENGINE=MyISAM; +INSERT INTO t3 VALUES + (4),(5),(8),(4),(8),(2),(9),(6),(4),(8), + (3),(5),(9),(6),(8),(3),(2),(6),(3),(1), + (4),(3),(1),(7),(0),(0),(9),(5),(9),(0), + (2),(2),(5),(9),(1),(4),(8),(6),(5),(5), + (1),(7),(2),(8),(9),(3),(2),(6),(6),(5), + (4),(3),(2),(7),(4),(6),(0),(8),(5),(8), + (2),(9),(7),(5),(7),(0),(4),(3),(1),(0), + (6),(2),(8),(3),(7),(3),(5),(5),(1),(2), + (1),(7),(1),(9),(9),(8),(3); +CREATE TABLE t4 (c1 INT) ENGINE=MyISAM; +EXPLAIN +SELECT count(*) FROM t2, t3 +WHERE a1 < ALL ( + SELECT a1 FROM t2 + WHERE a1 IN ( SELECT a1 FROM t2, t4 ) +); +set @show_explain_probe_select_id=1; +set debug='d,show_explain_probe_do_select'; +send +SELECT count(*) FROM t2, t3 +WHERE a1 < ALL ( + SELECT a1 FROM t2 + WHERE a1 IN ( SELECT a1 FROM t2, t4 ) +); + +connection default; +--source include/wait_condition.inc +evalp show explain for $thr2; +connection con1; +reap; +set debug=''; +drop table t2, t3, t4; ## TODO: Test this: have several SHOW EXPLAIN requests be queued up for a ## thread and served together. diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 556077220de..13972d56605 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -3752,7 +3752,11 @@ int st_select_lex::print_explain(select_result_sink *output, int res; if (join && join->optimized == JOIN::OPTIMIZATION_DONE) { - if (!join->table_count || !join->tables_list) + /* + There is a number of reasons join can be marked as degenerate, so all + three conditions below can happen simultaneously, or individually: + */ + if (!join->table_count || !join->tables_list || join->zero_result_cause) { /* It's a degenerate join */ const char *cause= join->zero_result_cause ? join-> zero_result_cause : From 6b05e434bff43365add2a9636edbace157c84e89 Mon Sep 17 00:00:00 2001 From: Venkata Sidagam Date: Wed, 16 May 2012 16:14:27 +0530 Subject: [PATCH 039/289] Bug #13955256: KEYCACHE CRASHES, CORRUPTIONS/HANGS WITH, FULLTEXT INDEX AND CONCURRENT DML. Problem Statement: ------------------ 1) Create a table with FT index. 2) Enable concurrent inserts. 3) In multiple threads do below operations repeatedly a) truncate table b) insert into table .... c) select ... match .. against .. non-boolean/boolean mode After some time we could observe two different assert core dumps Analysis: -------- 1)assert core dump at key_read_cache(): Two select threads operating in-parallel on same key root block. 1st select thread block->status is set to BLOCK_ERROR because the my_pread() in read_block() is returning '0'. Truncate table made the index file size as 1024 and pread was asked to get the block of count bytes(1024 bytes) from offset of 1024 which it cannot read since its "end of file" and retuning '0' setting "my_errno= HA_ERR_FILE_TOO_SHORT" and the key_file_length, key_root[0] is same i.e. 1024. Since block status has BLOCK_ERROR the 1st select thread enter into the free_block() and will be under wait on conditional mutex by making status as BLOCK_REASSIGNED and goes for wait_on_readers(). Other select thread will also work on the same block and sees the status as BLOCK_ERROR and enters into free_block(), checks for BLOCK_REASSIGNED and asserting the server. 2)assert core dump at key_write_cache(): One select thread and One insert thread. Select thread gets the unlocks the 'keycache->cache_lock', which allows other threads to continue and gets the pread() return value as'0'(please see the explanation above) and tries to get the lock on 'keycache->cache_lock' and waits there for the lock. Insert thread requests for the block, block will be assigned from the hash list and makes the page_status as 'PAGE_WAIT_TO_BE_READ' and goes for the read_block(), waits in the queue since there are some other threads performing reads on the same block. Select thread which was waiting for the 'keycache->cache_lock' mutex in the read_block() will continue after getting the my_pread() value as '0' and sets the block status as BLOCK_ERROR and goes to the free_block() and go to the wait_for_readers(). Now the insert thread will awake and continues. and checks block->status as not BLOCK_READ and it asserts. Fix: --- In the full text code, multiple readers of index file is not guarded. Hence added below below code in _ft2_search() and walk_and_match(). to lock the key_root I have used below code in _ft2_search() if (info->s->concurrent_insert) mysql_rwlock_rdlock(&share->key_root_lock[0]); and to unlock if (info->s->concurrent_insert) mysql_rwlock_unlock(&share->key_root_lock[0]); storage/myisam/ft_boolean_search.c: Since its a recursion function, to avoid confusion in taking and releasing the locks, renamed _ft2_search() to _ft2_search_internal() function. And _ft2_search() will take the lock, call _ft2_search_internal() and release the lock in case of concurrent inserts. storage/myisam/ft_nlq_search.c: Added read locks code in walk_and_match() --- storage/myisam/ft_boolean_search.c | 16 ++++++++++++++-- storage/myisam/ft_nlq_search.c | 18 +++++++++++++++++- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/storage/myisam/ft_boolean_search.c b/storage/myisam/ft_boolean_search.c index 62d912a0fd0..16cf2669c6d 100644 --- a/storage/myisam/ft_boolean_search.c +++ b/storage/myisam/ft_boolean_search.c @@ -354,7 +354,7 @@ static int _ftb_no_dupes_cmp(void* not_used __attribute__((unused)), returns 1 if the search was finished (must-word wasn't found) */ -static int _ft2_search(FTB *ftb, FTB_WORD *ftbw, my_bool init_search) +static int _ft2_search_no_lock(FTB *ftb, FTB_WORD *ftbw, my_bool init_search) { int r; int subkeys=1; @@ -454,7 +454,7 @@ static int _ft2_search(FTB *ftb, FTB_WORD *ftbw, my_bool init_search) ftbw->key_root=info->s->state.key_root[ftb->keynr]; ftbw->keyinfo=info->s->keyinfo+ftb->keynr; ftbw->off=0; - return _ft2_search(ftb, ftbw, 0); + return _ft2_search_no_lock(ftb, ftbw, 0); } /* matching key found */ @@ -482,6 +482,18 @@ static int _ft2_search(FTB *ftb, FTB_WORD *ftbw, my_bool init_search) return 0; } +static int _ft2_search(FTB *ftb, FTB_WORD *ftbw, my_bool init_search) +{ + int r; + MYISAM_SHARE *share= ftb->info->s; + if (share->concurrent_insert) + rw_rdlock(&share->key_root_lock[ftb->keynr]); + r= _ft2_search_no_lock(ftb, ftbw, init_search); + if (share->concurrent_insert) + rw_unlock(&share->key_root_lock[ftb->keynr]); + return r; +} + static void _ftb_init_index_search(FT_INFO *ftb) { int i; diff --git a/storage/myisam/ft_nlq_search.c b/storage/myisam/ft_nlq_search.c index 333ec5d0b4f..c74451828a4 100644 --- a/storage/myisam/ft_nlq_search.c +++ b/storage/myisam/ft_nlq_search.c @@ -71,9 +71,10 @@ static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio) TREE_ELEMENT *selem; double gweight=1; MI_INFO *info=aio->info; + MYISAM_SHARE *share= info->s; uchar *keybuff=aio->keybuff; MI_KEYDEF *keyinfo=info->s->keyinfo+aio->keynr; - my_off_t key_root=info->s->state.key_root[aio->keynr]; + my_off_t key_root; uint extra= HA_FT_WLEN + info->s->rec_reflength; #if HA_FT_WTYPE == HA_KEYTYPE_FLOAT float tmp_weight; @@ -89,6 +90,11 @@ static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio) keylen-=HA_FT_WLEN; doc_cnt=0; + if (share->concurrent_insert) + rw_rdlock(&share->key_root_lock[aio->keynr]); + + key_root= share->state.key_root[aio->keynr]; + /* Skip rows inserted by current inserted */ for (r=_mi_search(info, keyinfo, keybuff, keylen, SEARCH_FIND, key_root) ; !r && @@ -98,6 +104,9 @@ static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio) info->lastkey_length, SEARCH_BIGGER, key_root)) ; + if (share->concurrent_insert) + rw_unlock(&share->key_root_lock[aio->keynr]); + info->update|= HA_STATE_AKTIV; /* for _mi_test_if_changed() */ /* The following should be safe, even if we compare doubles */ @@ -121,6 +130,8 @@ static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio) keyinfo=& info->s->ft2_keyinfo; key_root=info->lastpos; keylen=0; + if (share->concurrent_insert) + rw_rdlock(&share->key_root_lock[aio->keynr]); r=_mi_search_first(info, keyinfo, key_root); goto do_skip; } @@ -155,6 +166,9 @@ static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio) if (gweight < 0 || doc_cnt > 2000000) gweight=0; + if (share->concurrent_insert) + rw_rdlock(&share->key_root_lock[aio->keynr]); + if (_mi_test_if_changed(info) == 0) r=_mi_search_next(info, keyinfo, info->lastkey, info->lastkey_length, SEARCH_BIGGER, key_root); @@ -167,6 +181,8 @@ do_skip: r= _mi_search_next(info, keyinfo, info->lastkey, info->lastkey_length, SEARCH_BIGGER, key_root); + if (share->concurrent_insert) + rw_unlock(&share->key_root_lock[aio->keynr]); } word->weight=gweight; From ce9e6b5a9a8b10ec9b09ea4349c811cdff2ab95f Mon Sep 17 00:00:00 2001 From: Annamalai Gurusami Date: Wed, 16 May 2012 16:36:49 +0530 Subject: [PATCH 040/289] Bug #13943231: ALTER TABLE AFTER DISCARD MAY CRASH THE SERVER The following scenario crashes our mysql server: 1. set global innodb_file_per_table=1; 2. create table t1(c1 int) engine=innodb; 3. alter table t1 discard tablespace; 4. alter table t1 add unique index(c1); Step 4 crashes the server. This patch introduces a check on discarded tablespace to avoid the crash. rb://1041 approved by Marko Makela --- storage/innodb_plugin/handler/handler0alter.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/storage/innodb_plugin/handler/handler0alter.cc b/storage/innodb_plugin/handler/handler0alter.cc index e2702b157af..6f02b500d96 100644 --- a/storage/innodb_plugin/handler/handler0alter.cc +++ b/storage/innodb_plugin/handler/handler0alter.cc @@ -665,6 +665,10 @@ ha_innobase::add_index( DBUG_RETURN(HA_ERR_NO_SUCH_TABLE); } + if (innodb_table->tablespace_discarded) { + DBUG_RETURN(-1); + } + /* Check that index keys are sensible */ error = innobase_check_index_keys(key_info, num_of_keys, innodb_table); From 483ae4bf81851a16e27cfc67b0eb474fed0a97dd Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Wed, 16 May 2012 20:22:54 +0400 Subject: [PATCH 041/289] Make SHOW EXPLAIN give a separate timeout error. --- sql/sql_show.cc | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/sql/sql_show.cc b/sql/sql_show.cc index a0c39ff6c8c..2a9e5fa4954 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2121,9 +2121,18 @@ void mysqld_show_explain(THD *thd, ulong thread_id) if (bres || explain_req.failed_to_produce) { /* TODO not enabled or time out */ - my_error(ER_ERROR_WHEN_EXECUTING_COMMAND, MYF(0), - "SHOW EXPLAIN", - "Target is not running EXPLAINable command"); + if (timed_out) + { + my_error(ER_ERROR_WHEN_EXECUTING_COMMAND, MYF(0), + "SHOW EXPLAIN", + "Timeout"); + } + else + { + my_error(ER_ERROR_WHEN_EXECUTING_COMMAND, MYF(0), + "SHOW EXPLAIN", + "Target is not running EXPLAINable command"); + } bres= TRUE; } else From 932376f97ad4e085926ba39ddc61542561d95ea0 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 17 May 2012 10:15:54 +0530 Subject: [PATCH 042/289] From 3e1758d36a76e1b5c2333b3a137446afb61f80fe Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 17 May 2012 11:41:46 +0100 Subject: [PATCH 043/289] From 21faded51e8389d72cc1a729a5e40a5e41aa4540 Mon Sep 17 00:00:00 2001 From: Gopal Shankar Date: Thu, 17 May 2012 18:07:59 +0530 Subject: [PATCH 044/289] Bug#12636001 : deadlock from thd_security_context PROBLEM: Threads end-up in deadlock due to locks acquired as described below, con1: Run Query on a table. It is important that this SELECT must back-off while trying to open the t1 and enter into wait_for_condition(). The SELECT then is blocked trying to lock mysys_var->mutex which is held by con3. The very significant fact here is that mysys_var->current_mutex will still point to LOCK_open, even if LOCK_open is no longer held by con1 at this point. con2: Try dropping table used in con1 or query some table. It will hold LOCK_open and be blocked trying to lock kernel_mutex held by con4. con3: Try killing the query run by con1. It will hold THD::LOCK_thd_data belonging to con1 while trying to lock mysys_var->current_mutex belonging to con1. But current_mutex will point to LOCK_open which is held by con2. con4: Get innodb engine status It will hold kernel_mutex, trying to lock THD::LOCK_thd_data belonging to con1 which is held by con3. So while technically only con2, con3 and con4 participate in the deadlock, con1's mysys_var->current_mutex pointing to LOCK_open is a vital component of the deadlock. CYCLE = (THD::LOCK_thd_data -> LOCK_open -> kernel_mutex -> THD::LOCK_thd_data) FIX: LOCK_thd_data has responsibility of protecting, 1) thd->query, thd->query_length 2) VIO 3) thd->mysys_var (used by KILL statement and shutdown) 4) THD during thread delete. Among above responsibilities, 1), 2)and (3,4) seems to be three independent group of responsibility. If there is different LOCK owning responsibility of (3,4), the above mentioned deadlock cycle can be avoid. This fix introduces LOCK_thd_kill to handle responsibility (3,4), which eliminates the deadlock issue. Note: The problem is not found in 5.5. Introduction MDL subsystem caused metadata locking responsibility to be moved from TDC/TC to MDL subsystem. Due to this, responsibility of LOCK_open is reduced. As the use of LOCK_open is removed in open_table() and mysql_rm_table() the above mentioned CYCLE does not form. Revision ID for changes, open_table() = dlenev@mysql.com-20100727133458-m3ua9oslnx8fbbvz mysql_rm_table() = jon.hauglid@oracle.com-20101116100012-kxep9txz2fxy3nmw --- sql/event_scheduler.cc | 4 ++-- sql/slave.cc | 4 ++-- sql/sql_base.cc | 2 ++ sql/sql_class.cc | 13 +++++++++++-- sql/sql_class.h | 16 ++++++++++++++-- sql/sql_parse.cc | 5 +++-- sql/sql_repl.cc | 4 ++-- 7 files changed, 36 insertions(+), 12 deletions(-) diff --git a/sql/event_scheduler.cc b/sql/event_scheduler.cc index a24c70a8494..d217d8d76cd 100755 --- a/sql/event_scheduler.cc +++ b/sql/event_scheduler.cc @@ -632,13 +632,13 @@ Event_scheduler::stop() DBUG_PRINT("info", ("Scheduler thread has id %lu", scheduler_thd->thread_id)); /* Lock from delete */ - pthread_mutex_lock(&scheduler_thd->LOCK_thd_data); + pthread_mutex_lock(&scheduler_thd->LOCK_thd_kill); /* This will wake up the thread if it waits on Queue's conditional */ sql_print_information("Event Scheduler: Killing the scheduler thread, " "thread id %lu", scheduler_thd->thread_id); scheduler_thd->awake(THD::KILL_CONNECTION); - pthread_mutex_unlock(&scheduler_thd->LOCK_thd_data); + pthread_mutex_unlock(&scheduler_thd->LOCK_thd_kill); /* thd could be 0x0, when shutting down */ sql_print_information("Event Scheduler: " diff --git a/sql/slave.cc b/sql/slave.cc index 0910d196583..437762cc318 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -515,7 +515,7 @@ terminate_slave_thread(THD *thd, int error; DBUG_PRINT("loop", ("killing slave thread")); - pthread_mutex_lock(&thd->LOCK_thd_data); + pthread_mutex_lock(&thd->LOCK_thd_kill); #ifndef DONT_USE_THR_ALARM /* Error codes from pthread_kill are: @@ -526,7 +526,7 @@ terminate_slave_thread(THD *thd, DBUG_ASSERT(err != EINVAL); #endif thd->awake(THD::NOT_KILLED); - pthread_mutex_unlock(&thd->LOCK_thd_data); + pthread_mutex_unlock(&thd->LOCK_thd_kill); /* There is a small chance that slave thread might miss the first diff --git a/sql/sql_base.cc b/sql/sql_base.cc index ca24830db63..2ce5ec81917 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2203,6 +2203,8 @@ void wait_for_condition(THD *thd, pthread_mutex_t *mutex, pthread_cond_t *cond) */ pthread_mutex_unlock(mutex); + DEBUG_SYNC(thd, "waiting_for_table_unlock"); + DBUG_EXECUTE_IF("sleep_after_waiting_for_table", my_sleep(1000000);); pthread_mutex_lock(&thd->mysys_var->mutex); thd->mysys_var->current_mutex= 0; thd->mysys_var->current_cond= 0; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 2f3e8153cbd..0f6bd4c1954 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -365,6 +365,7 @@ extern "C" char *thd_security_context(THD *thd, char *buffer, unsigned int length, unsigned int max_query_len) { + DEBUG_SYNC(thd, "thd_security_context"); String str(buffer, length, &my_charset_latin1); const Security_context *sctx= &thd->main_security_ctx; char header[64]; @@ -695,6 +696,7 @@ THD::THD() active_vio = 0; #endif pthread_mutex_init(&LOCK_thd_data, MY_MUTEX_INIT_FAST); + pthread_mutex_init(&LOCK_thd_kill, MY_MUTEX_INIT_FAST); /* Variables with default values */ proc_info="login"; @@ -999,6 +1001,8 @@ THD::~THD() /* Ensure that no one is using THD */ pthread_mutex_lock(&LOCK_thd_data); pthread_mutex_unlock(&LOCK_thd_data); + pthread_mutex_lock(&LOCK_thd_kill); + pthread_mutex_unlock(&LOCK_thd_kill); add_to_status(&global_status_var, &status_var); /* Close connection */ @@ -1026,6 +1030,7 @@ THD::~THD() #endif mysys_var=0; // Safety (shouldn't be needed) pthread_mutex_destroy(&LOCK_thd_data); + pthread_mutex_destroy(&LOCK_thd_kill); #ifndef DBUG_OFF dbug_sentry= THD_SENTRY_GONE; #endif @@ -1104,9 +1109,11 @@ void add_diff_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var, void THD::awake(THD::killed_state state_to_set) { DBUG_ENTER("THD::awake"); - DBUG_PRINT("enter", ("this: 0x%lx", (long) this)); + DBUG_PRINT("enter", ("this: 0x%lx thread_id=%lu killed_state=%d", + (long) this, thread_id, state_to_set)); THD_CHECK_SENTRY(this); - safe_mutex_assert_owner(&LOCK_thd_data); + safe_mutex_assert_not_owner(&LOCK_thd_data); + safe_mutex_assert_owner(&LOCK_thd_kill); killed= state_to_set; if (state_to_set != THD::KILL_QUERY) @@ -1127,7 +1134,9 @@ void THD::awake(THD::killed_state state_to_set) hack is not used. */ + pthread_mutex_lock(&LOCK_thd_data); close_active_vio(); + pthread_mutex_unlock(&LOCK_thd_data); } #endif } diff --git a/sql/sql_class.h b/sql/sql_class.h index 31d2c664aae..3ecf032db71 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1342,11 +1342,23 @@ public: Protects THD data accessed from other threads: - thd->query and thd->query_length (used by SHOW ENGINE INNODB STATUS and SHOW PROCESSLIST - - thd->mysys_var (used by KILL statement and shutdown). - Is locked when THD is deleted. */ pthread_mutex_t LOCK_thd_data; + /** + - Protects thd->mysys_var (used during KILL statement and shutdown). + - Is Locked when THD is deleted. + + Note: This responsibility was earlier handled by LOCK_thd_data. + This lock is introduced to solve a deadlock issue waiting for + LOCK_thd_data. As this lock reduces responsibility of LOCK_thd_data + the deadlock issues is solved. + Caution: LOCK_thd_kill should not be taken while holding LOCK_thd_data. + THD::awake() currently takes LOCK_thd_data after holding + LOCK_thd_kill. + */ + pthread_mutex_t LOCK_thd_kill; + /* all prepared statements and cursors of this connection */ Statement_map stmt_map; /* diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 729a963eef1..6c376d2c0da 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -7187,7 +7187,7 @@ uint kill_one_thread(THD *thd, ulong id, bool only_kill_query) continue; if (tmp->thread_id == id) { - pthread_mutex_lock(&tmp->LOCK_thd_data); // Lock from delete + pthread_mutex_lock(&tmp->LOCK_thd_kill); // Lock from delete break; } } @@ -7215,12 +7215,13 @@ uint kill_one_thread(THD *thd, ulong id, bool only_kill_query) if ((thd->security_ctx->master_access & SUPER_ACL) || thd->security_ctx->user_matches(tmp->security_ctx)) { + DEBUG_SYNC(thd, "kill_one_thread_before_kill"); tmp->awake(only_kill_query ? THD::KILL_QUERY : THD::KILL_CONNECTION); error=0; } else error=ER_KILL_DENIED_ERROR; - pthread_mutex_unlock(&tmp->LOCK_thd_data); + pthread_mutex_unlock(&tmp->LOCK_thd_kill); } DBUG_PRINT("exit", ("%d", error)); DBUG_RETURN(error); diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index b985805a827..c92d2db2c1e 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -1133,7 +1133,7 @@ void kill_zombie_dump_threads(uint32 slave_server_id) if (tmp->command == COM_BINLOG_DUMP && tmp->server_id == slave_server_id) { - pthread_mutex_lock(&tmp->LOCK_thd_data); // Lock from delete + pthread_mutex_lock(&tmp->LOCK_thd_kill); // Lock from delete break; } } @@ -1146,7 +1146,7 @@ void kill_zombie_dump_threads(uint32 slave_server_id) again. We just to do kill the thread ourselves. */ tmp->awake(THD::KILL_QUERY); - pthread_mutex_unlock(&tmp->LOCK_thd_data); + pthread_mutex_unlock(&tmp->LOCK_thd_kill); } } From 781137c0dddc3c9315a8d40e579fe82f6a900d61 Mon Sep 17 00:00:00 2001 From: Rohit Kalhans Date: Fri, 18 May 2012 14:44:40 +0530 Subject: [PATCH 045/289] BUG#14005409 - 64624 Problem: After the fix for Bug#12589870, a new field that stores the length of db name was added in the buffer that stores the query to be executed. Unlike for the plain user session, the replication execution did not allocate the necessary chunk in Query-event constructor. This caused an invalid read while accessing this field. Solution: We fix this problem by allocating a necessary chunk in the buffer created in the Query_log_event::Query_log_event() and store the length of database name. sql/log_event.cc: Added a new field in the buffer created in the Query_log_event's constructor and store the length of database name. --- sql/log_event.cc | 50 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/sql/log_event.cc b/sql/log_event.cc index 8606964113c..afcc283a6d1 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -2835,24 +2835,34 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, pos= (const uchar*) end; // Break loop } } - + + /** + Layout for the data buffer is as follows + +--------+-----------+------+------+---------+----+-------+ + | catlog | time_zone | user | host | db name | \0 | Query | + +--------+-----------+------+------+---------+----+-------+ + + To support the query cache we append the following buffer to the above + +-------+----------------------------------------+-------+ + |db len | uninitiatlized space of size of db len | FLAGS | + +-------+----------------------------------------+-------+ + + The area of buffer starting from Query field all the way to the end belongs + to the Query buffer and its structure is described in alloc_query() in + sql_parse.cc + */ + + if (!(start= data_buf = (Log_event::Byte*) my_malloc(catalog_len + 1 + + time_zone_len + 1 + + user.length + 1 + + host.length + 1 + + data_len + 1 #if !defined(MYSQL_CLIENT) && defined(HAVE_QUERY_CACHE) - if (!(start= data_buf = (Log_event::Byte*) my_malloc(catalog_len + 1 + - time_zone_len + 1 + - data_len + 1 + - QUERY_CACHE_FLAGS_SIZE + - user.length + 1 + - host.length + 1 + - db_len + 1, - MYF(MY_WME)))) -#else - if (!(start= data_buf = (Log_event::Byte*) my_malloc(catalog_len + 1 + - time_zone_len + 1 + - data_len + 1 + - user.length + 1 + - host.length + 1, - MYF(MY_WME)))) + + sizeof(size_t)//for db_len + + db_len + 1 + + QUERY_CACHE_FLAGS_SIZE #endif + , MYF(MY_WME)))) DBUG_VOID_RETURN; if (catalog_len) // If catalog is given { @@ -2891,6 +2901,14 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, db= (char *)start; query= (char *)(start + db_len + 1); q_len= data_len - db_len -1; + /** + Append the db length at the end of the buffer. This will be used by + Query_cache::send_result_to_client() in case the query cache is On. + */ +#if !defined(MYSQL_CLIENT) && defined(HAVE_QUERY_CACHE) + size_t db_length= (size_t)db_len; + memcpy(start + data_len + 1, &db_length, sizeof(size_t)); +#endif DBUG_VOID_RETURN; } From 1605b7f68f30038ea0a9ce16e688f5827057f64f Mon Sep 17 00:00:00 2001 From: Manish Kumar Date: Mon, 21 May 2012 12:57:39 +0530 Subject: [PATCH 046/289] BUG#12400221 - 60926: BINARY LOG EVENTS LARGER THAN MAX_ALLOWED_PACKET Problem ======== SQL statements close to the size of max_allowed_packet produce binary log events larger than max_allowed_packet. The reason why this failure is occuring is because the event length is more than the total size of the max_allowed_packet + max_event_header length. Now since the event length exceeds this size master Dump thread is unable to send the packet on to the slave. That can happen e.g with row-based replication in Update_rows event. Fix ==== The problem was fixed by increasing the max_allowed_packet for the slave's threads (IO/SQL) by increasing it to 1GB. This is done using the new server option included which is used to regulate the max_allowed_packet of the slave thread (IO/SQL). This causes the large packets to be received by the slave and apply it successfully. sql/log_event.h: Added the new option in the log_event.h file. sql/mysqld.cc: Added a new option to the server. sql/slave.cc: Increasing the session max_allowed_packet to a large value , i.e. not taking global(max_allowed) into consideration, for the slave's threads. --- mysql-test/suite/rpl/r/rpl_log_pos.result | 2 +- mysql-test/suite/rpl/r/rpl_packet.result | 11 +- mysql-test/suite/rpl/t/rpl_packet-slave.opt | 2 +- mysql-test/suite/rpl/t/rpl_packet.test | 11 +- .../inc/slave_max_allowed_packet_basic.inc | 177 ++++++++++++++++++ .../r/max_allowed_packet_basic.result | 12 ++ .../sys_vars/r/max_allowed_packet_func.result | 2 + .../sys_vars/r/net_buffer_length_basic.result | 2 + .../t/slave_max_allowed_packet_basic.test | 3 + sql/log_event.cc | 2 +- sql/log_event.h | 7 + sql/mysql_priv.h | 1 + sql/mysqld.cc | 7 + sql/set_var.cc | 2 + sql/share/errmsg.txt | 34 ++-- sql/slave.cc | 11 +- sql/sql_repl.cc | 2 +- 17 files changed, 252 insertions(+), 36 deletions(-) create mode 100644 mysql-test/suite/sys_vars/inc/slave_max_allowed_packet_basic.inc create mode 100644 mysql-test/suite/sys_vars/t/slave_max_allowed_packet_basic.test diff --git a/mysql-test/suite/rpl/r/rpl_log_pos.result b/mysql-test/suite/rpl/r/rpl_log_pos.result index 91d307008f0..b2224dcd725 100644 --- a/mysql-test/suite/rpl/r/rpl_log_pos.result +++ b/mysql-test/suite/rpl/r/rpl_log_pos.result @@ -9,7 +9,7 @@ change master to master_log_pos=MASTER_LOG_POS; Read_Master_Log_Pos = '75' start slave; include/wait_for_slave_io_error.inc [errno=1236] -Last_IO_Error = 'Got fatal error 1236 from master when reading data from binary log: 'log event entry exceeded max_allowed_packet; Increase max_allowed_packet on master'' +Last_IO_Error = 'Got fatal error 1236 from master when reading data from binary log: 'binlog truncated in the middle of event'' include/stop_slave_sql.inc show master status; File Position Binlog_Do_DB Binlog_Ignore_DB diff --git a/mysql-test/suite/rpl/r/rpl_packet.result b/mysql-test/suite/rpl/r/rpl_packet.result index 7a7f8141ac8..6d68a094594 100644 --- a/mysql-test/suite/rpl/r/rpl_packet.result +++ b/mysql-test/suite/rpl/r/rpl_packet.result @@ -1,7 +1,7 @@ include/master-slave.inc [connection master] -call mtr.add_suppression("Slave I/O: Got a packet bigger than 'max_allowed_packet' bytes, Error_code: 1153"); -call mtr.add_suppression("Slave I/O: Got fatal error 1236 from master when reading data from binary log:"); +call mtr.add_suppression("Slave I/O: Got a packet bigger than 'slave_max_allowed_packet' bytes, Error_code: 1153"); +call mtr.add_suppression("Log entry on master is longer than slave_max_allowed_packet"); drop database if exists DB_NAME_OF_MAX_LENGTH_AKA_NAME_LEN_64_BYTES_____________________; create database DB_NAME_OF_MAX_LENGTH_AKA_NAME_LEN_64_BYTES_____________________; SET @@global.max_allowed_packet=1024; @@ -30,14 +30,14 @@ include/start_slave.inc CREATE TABLE `t1` (`f1` LONGTEXT) ENGINE=MyISAM; INSERT INTO `t1`(`f1`) VALUES ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa2048'); include/wait_for_slave_io_error.inc [errno=1153] -Last_IO_Error = 'Got a packet bigger than 'max_allowed_packet' bytes' +Last_IO_Error = 'Got a packet bigger than 'slave_max_allowed_packet' bytes' include/stop_slave_sql.inc include/rpl_reset.inc DROP TABLE t1; CREATE TABLE t1 (f1 int PRIMARY KEY, f2 LONGTEXT, f3 LONGTEXT) ENGINE=MyISAM; INSERT INTO t1(f1, f2, f3) VALUES(1, REPEAT('a', @@global.max_allowed_packet), REPEAT('b', @@global.max_allowed_packet)); -include/wait_for_slave_io_error.inc [errno=1236] -Last_IO_Error = 'Got fatal error 1236 from master when reading data from binary log: 'log event entry exceeded max_allowed_packet; Increase max_allowed_packet on master'' +include/wait_for_slave_io_error.inc [errno=1153] +Last_IO_Error = 'Got a packet bigger than 'slave_max_allowed_packet' bytes' STOP SLAVE; RESET SLAVE; RESET MASTER; @@ -52,6 +52,7 @@ SET @@global.max_allowed_packet= 1024; Warnings: Warning 1105 The value of 'max_allowed_packet' should be no less than the value of 'net_buffer_length' SET @@global.net_buffer_length= 1024; +SET @@global.slave_max_allowed_packet= 1073741824; DROP TABLE t1; RESET SLAVE; include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_packet-slave.opt b/mysql-test/suite/rpl/t/rpl_packet-slave.opt index 42d4f94c999..e0a7a203f99 100644 --- a/mysql-test/suite/rpl/t/rpl_packet-slave.opt +++ b/mysql-test/suite/rpl/t/rpl_packet-slave.opt @@ -1 +1 @@ --O max_allowed_packet=1024 -O net_buffer_length=1024 +-O max_allowed_packet=1024 -O net_buffer_length=1024 -O slave_max_allowed_packet=1024 diff --git a/mysql-test/suite/rpl/t/rpl_packet.test b/mysql-test/suite/rpl/t/rpl_packet.test index 3197b6160cd..7fbea87f71e 100644 --- a/mysql-test/suite/rpl/t/rpl_packet.test +++ b/mysql-test/suite/rpl/t/rpl_packet.test @@ -11,9 +11,8 @@ # max-out size db name source include/master-slave.inc; source include/have_binlog_format_row.inc; -call mtr.add_suppression("Slave I/O: Got a packet bigger than 'max_allowed_packet' bytes, Error_code: 1153"); -call mtr.add_suppression("Slave I/O: Got fatal error 1236 from master when reading data from binary log:"); - +call mtr.add_suppression("Slave I/O: Got a packet bigger than 'slave_max_allowed_packet' bytes, Error_code: 1153"); +call mtr.add_suppression("Log entry on master is longer than slave_max_allowed_packet"); let $db= DB_NAME_OF_MAX_LENGTH_AKA_NAME_LEN_64_BYTES_____________________; disable_warnings; eval drop database if exists $db; @@ -23,6 +22,7 @@ eval create database $db; connection master; let $old_max_allowed_packet= `SELECT @@global.max_allowed_packet`; let $old_net_buffer_length= `SELECT @@global.net_buffer_length`; +let $old_slave_max_allowed_packet= `SELECT @@global.slave_max_allowed_packet`; SET @@global.max_allowed_packet=1024; SET @@global.net_buffer_length=1024; @@ -124,8 +124,8 @@ INSERT INTO t1(f1, f2, f3) VALUES(1, REPEAT('a', @@global.max_allowed_packet), R connection slave; # The slave I/O thread must stop after receiving -# 1236=ER_MASTER_FATAL_ERROR_READING_BINLOG error message from master. ---let $slave_io_errno= 1236 +# 1153 = ER_NET_PACKET_TOO_LARGE +--let $slave_io_errno= 1153 --let $show_slave_io_error= 1 --source include/wait_for_slave_io_error.inc @@ -166,6 +166,7 @@ connection master; DROP TABLE t1; eval SET @@global.max_allowed_packet= $old_max_allowed_packet; eval SET @@global.net_buffer_length= $old_net_buffer_length; +eval SET @@global.slave_max_allowed_packet= $old_slave_max_allowed_packet; # slave is stopped connection slave; DROP TABLE t1; diff --git a/mysql-test/suite/sys_vars/inc/slave_max_allowed_packet_basic.inc b/mysql-test/suite/sys_vars/inc/slave_max_allowed_packet_basic.inc new file mode 100644 index 00000000000..4caaae84906 --- /dev/null +++ b/mysql-test/suite/sys_vars/inc/slave_max_allowed_packet_basic.inc @@ -0,0 +1,177 @@ +############## mysql-test\t\slave_max_allowed_packet_basic.test ################## +# # +# Variable Name: slave_max_allowed_packet # +# Scope: GLOBAL # +# Access Type: Dynamic # +# Data Type: numeric # +# Default Value:1073741824 # +# Range: 1024 - 1073741824 # +# # +# # +# # +# Description: Test Cases of Dynamic System Variable slave_max_allowed_packet # +# that checks the behavior of this variable in the following ways# +# * Default Value # +# * Valid & Invalid values # +# * Scope & Access method # +# * Data Integrity # +# # +############################################################################### + +--source include/load_sysvars.inc + +######################################################################## +# START OF slave_max_allowed_packet TESTS # +######################################################################## + + +########################################################################### +# Saving initial value of slave_max_allowed_packet in a temporary variable# +########################################################################### + +SET @start_value = @@global.slave_max_allowed_packet; +SELECT @start_value; + + +--echo '#--------------------FN_DYNVARS_072_01------------------------#' +######################################################################## +# Display the DEFAULT value of slave_max_allowed_packet # +######################################################################## + +SET @@global.slave_max_allowed_packet = 5000; +SET @@global.slave_max_allowed_packet = DEFAULT; +SELECT @@global.slave_max_allowed_packet; + + +--echo '#---------------------FN_DYNVARS_072_02-------------------------#' +############################################### +# Verify default value of variable # +############################################### + +SET @@global.slave_max_allowed_packet = @start_value; +SELECT @@global.slave_max_allowed_packet = 1073741824; +--echo 'Bug# 34876: Incorrect Default Value is assigned to variable'; + +--echo '#--------------------FN_DYNVARS_072_03------------------------#' +######################################################################## +# Change the value of slave_max_allowed_packet to a valid value # +######################################################################## + +SET @@global.slave_max_allowed_packet = 1024; +SELECT @@global.slave_max_allowed_packet; +SET @@global.slave_max_allowed_packet = 1073741824; +SELECT @@global.slave_max_allowed_packet; +SET @@global.slave_max_allowed_packet = 1073741824; +SELECT @@global.slave_max_allowed_packet; +SET @@global.slave_max_allowed_packet = 1025; +SELECT @@global.slave_max_allowed_packet; +SET @@global.slave_max_allowed_packet = 65535; +SELECT @@global.slave_max_allowed_packet; +--echo 'Bug# 34877: Invalid Values are coming in variable on assigning valid values'; + + +--echo '#--------------------FN_DYNVARS_072_04-------------------------#' +########################################################################### +# Change the value of slave_max_allowed_packet to invalid value # +########################################################################### + +SET @@global.slave_max_allowed_packet = -1; +SELECT @@global.slave_max_allowed_packet; +SET @@global.slave_max_allowed_packet = 100000000000; +SELECT @@global.slave_max_allowed_packet; +--Error ER_WRONG_TYPE_FOR_VAR +SET @@global.slave_max_allowed_packet = 10000.01; +SELECT @@global.slave_max_allowed_packet; +SET @@global.slave_max_allowed_packet = -1024; +SELECT @@global.slave_max_allowed_packet; +SET @@global.slave_max_allowed_packet = 4294967296; +SELECT @@global.slave_max_allowed_packet; +SET @@global.slave_max_allowed_packet = 1023; +SELECT @@global.slave_max_allowed_packet; + +--echo 'Bug # 34837: Errors are not coming on assigning invalid values to variable'; + +--Error ER_WRONG_TYPE_FOR_VAR +SET @@global.slave_max_allowed_packet = ON; +SELECT @@global.slave_max_allowed_packet; +--Error ER_WRONG_TYPE_FOR_VAR +SET @@global.slave_max_allowed_packet = 'test'; +SELECT @@global.slave_max_allowed_packet; + + +--echo '#-------------------FN_DYNVARS_072_05----------------------------#' +########################################################################### +# Test if accessing session slave_max_allowed_packet gives error # +########################################################################### + +--Error ER_GLOBAL_VARIABLE +SET @@session.slave_max_allowed_packet = 4096; +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.slave_max_allowed_packet; + + +--echo '#----------------------FN_DYNVARS_072_06------------------------#' +############################################################################## +# Check if the value in GLOBAL & SESSION Tables matches values in variable # +############################################################################## + +SELECT @@global.slave_max_allowed_packet = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='slave_max_allowed_packet'; + +SELECT @@slave_max_allowed_packet = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.SESSION_VARIABLES +WHERE VARIABLE_NAME='slave_max_allowed_packet'; + + +--echo '#---------------------FN_DYNVARS_072_07----------------------#' +################################################################### +# Check if TRUE and FALSE values can be used on variable # +################################################################### + +SET @@global.slave_max_allowed_packet = TRUE; +SELECT @@global.slave_max_allowed_packet; +SET @@global.slave_max_allowed_packet = FALSE; +SELECT @@global.slave_max_allowed_packet; + + +--echo '#---------------------FN_DYNVARS_072_08----------------------#' +######################################################################################################## +# Check if accessing variable with SESSION,LOCAL and without SCOPE points to same session variable # +######################################################################################################## + +SET @@global.slave_max_allowed_packet = 5000; +SELECT @@slave_max_allowed_packet = @@global.slave_max_allowed_packet; + + +--echo '#---------------------FN_DYNVARS_072_09----------------------#' +################################################################################ +# Check if slave_max_allowed_packet can be accessed with and without @@ sign # +################################################################################ + +--Error ER_GLOBAL_VARIABLE +SET slave_max_allowed_packet = 6000; +SELECT @@slave_max_allowed_packet; +--Error ER_PARSE_ERROR +SET local.slave_max_allowed_packet = 7000; +--Error ER_UNKNOWN_TABLE +SELECT local.slave_max_allowed_packet; +--Error ER_PARSE_ERROR +SET global.slave_max_allowed_packet = 8000; +--Error ER_UNKNOWN_TABLE +SELECT global.slave_max_allowed_packet; +--Error ER_BAD_FIELD_ERROR +SELECT slave_max_allowed_packet = @@session.slave_max_allowed_packet; + + +############################## +# Restore initial value # +############################## + +SET @@global.slave_max_allowed_packet = @start_value; +SELECT @@global.slave_max_allowed_packet; + + +######################################################################## +# END OF slave_max_allowed_packet TESTS # +######################################################################## diff --git a/mysql-test/suite/sys_vars/r/max_allowed_packet_basic.result b/mysql-test/suite/sys_vars/r/max_allowed_packet_basic.result index ca5b87f19cb..810ddb00b79 100644 --- a/mysql-test/suite/sys_vars/r/max_allowed_packet_basic.result +++ b/mysql-test/suite/sys_vars/r/max_allowed_packet_basic.result @@ -7,6 +7,7 @@ SET @@global.max_allowed_packet = DEFAULT; SET @@global.max_allowed_packet = 1000; Warnings: Warning 1292 Truncated incorrect max_allowed_packet value: '1000' +Warning 1105 The value of 'max_allowed_packet' should be no less than the value of 'net_buffer_length' SET @@global.max_allowed_packet = DEFAULT; SELECT @@global.max_allowed_packet; @@global.max_allowed_packet @@ -25,10 +26,14 @@ SELECT @@global.max_allowed_packet = 1048576; 1 '#--------------------FN_DYNVARS_070_03-------------------------#' SET @@global.max_allowed_packet = 1024; +Warnings: +Warning 1105 The value of 'max_allowed_packet' should be no less than the value of 'net_buffer_length' SELECT @@global.max_allowed_packet; @@global.max_allowed_packet 1024 SET @@global.max_allowed_packet = 1025; +Warnings: +Warning 1105 The value of 'max_allowed_packet' should be no less than the value of 'net_buffer_length' SELECT @@global.max_allowed_packet; @@global.max_allowed_packet 1024 @@ -71,18 +76,21 @@ SELECT @@session.max_allowed_packet; SET @@global.max_allowed_packet = 0; Warnings: Warning 1292 Truncated incorrect max_allowed_packet value: '0' +Warning 1105 The value of 'max_allowed_packet' should be no less than the value of 'net_buffer_length' SELECT @@global.max_allowed_packet; @@global.max_allowed_packet 1024 SET @@global.max_allowed_packet = -1024; Warnings: Warning 1292 Truncated incorrect max_allowed_packet value: '-1024' +Warning 1105 The value of 'max_allowed_packet' should be no less than the value of 'net_buffer_length' SELECT @@global.max_allowed_packet; @@global.max_allowed_packet 1024 SET @@global.max_allowed_packet = 1023; Warnings: Warning 1292 Truncated incorrect max_allowed_packet value: '1023' +Warning 1105 The value of 'max_allowed_packet' should be no less than the value of 'net_buffer_length' SELECT @@global.max_allowed_packet; @@global.max_allowed_packet 1024 @@ -146,17 +154,21 @@ WHERE VARIABLE_NAME='max_allowed_packet'; SET @@global.max_allowed_packet = TRUE; Warnings: Warning 1292 Truncated incorrect max_allowed_packet value: '1' +Warning 1105 The value of 'max_allowed_packet' should be no less than the value of 'net_buffer_length' SELECT @@global.max_allowed_packet; @@global.max_allowed_packet 1024 SET @@global.max_allowed_packet = FALSE; Warnings: Warning 1292 Truncated incorrect max_allowed_packet value: '0' +Warning 1105 The value of 'max_allowed_packet' should be no less than the value of 'net_buffer_length' SELECT @@global.max_allowed_packet; @@global.max_allowed_packet 1024 '#---------------------FN_DYNVARS_070_09----------------------#' SET @@global.max_allowed_packet = 2048; +Warnings: +Warning 1105 The value of 'max_allowed_packet' should be no less than the value of 'net_buffer_length' SELECT @@max_allowed_packet = @@global.max_allowed_packet; @@max_allowed_packet = @@global.max_allowed_packet 0 diff --git a/mysql-test/suite/sys_vars/r/max_allowed_packet_func.result b/mysql-test/suite/sys_vars/r/max_allowed_packet_func.result index 0d682b65aea..a202701b60f 100644 --- a/mysql-test/suite/sys_vars/r/max_allowed_packet_func.result +++ b/mysql-test/suite/sys_vars/r/max_allowed_packet_func.result @@ -23,6 +23,8 @@ SELECT @@session.net_buffer_length; '#--------------------FN_DYNVARS_070_02-------------------------#' ## Setting value of max_allowed packet and net_buffer_length to 1024 ## SET @@global.max_allowed_packet = 1024; +Warnings: +Warning 1105 The value of 'max_allowed_packet' should be no less than the value of 'net_buffer_length' SET @@global.net_buffer_length = 1024; SELECT @@global.max_allowed_packet; @@global.max_allowed_packet diff --git a/mysql-test/suite/sys_vars/r/net_buffer_length_basic.result b/mysql-test/suite/sys_vars/r/net_buffer_length_basic.result index 07f933b5a4b..026c883e501 100644 --- a/mysql-test/suite/sys_vars/r/net_buffer_length_basic.result +++ b/mysql-test/suite/sys_vars/r/net_buffer_length_basic.result @@ -63,12 +63,14 @@ SELECT @@global.net_buffer_length; SET @@global.net_buffer_length = 1048577; Warnings: Warning 1292 Truncated incorrect net_buffer_length value: '1048577' +Warning 1105 The value of 'max_allowed_packet' should be no less than the value of 'net_buffer_length' SELECT @@global.net_buffer_length; @@global.net_buffer_length 1048576 SET @@global.net_buffer_length = 104857633; Warnings: Warning 1292 Truncated incorrect net_buffer_length value: '104857633' +Warning 1105 The value of 'max_allowed_packet' should be no less than the value of 'net_buffer_length' SELECT @@global.net_buffer_length; @@global.net_buffer_length 1048576 diff --git a/mysql-test/suite/sys_vars/t/slave_max_allowed_packet_basic.test b/mysql-test/suite/sys_vars/t/slave_max_allowed_packet_basic.test new file mode 100644 index 00000000000..5b6a557738b --- /dev/null +++ b/mysql-test/suite/sys_vars/t/slave_max_allowed_packet_basic.test @@ -0,0 +1,3 @@ +--source suite/sys_vars/inc/slave_max_allowed_packet_basic.inc + + diff --git a/sql/log_event.cc b/sql/log_event.cc index afcc283a6d1..958b7e4ef36 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1122,7 +1122,7 @@ failed my_b_read")); Log_event *res= 0; #ifndef max_allowed_packet THD *thd=current_thd; - uint max_allowed_packet= thd ? thd->variables.max_allowed_packet : ~(ulong)0; + uint max_allowed_packet= thd ? slave_max_allowed_packet:~(ulong)0; #endif if (data_len > max_allowed_packet) diff --git a/sql/log_event.h b/sql/log_event.h index 4c80148458c..39cd55f313e 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -275,6 +275,13 @@ struct sql_ex_info MAX_SIZE_LOG_EVENT_STATUS + /* status */ \ NAME_LEN + 1) +/* + The new option is added to handle large packets that are sent from the master + to the slave. It is used to increase the thd(max_allowed) for both the + DUMP thread on the master and the SQL/IO thread on the slave. +*/ +#define MAX_MAX_ALLOWED_PACKET 1024*1024*1024 + /* Event header offsets; these point to places inside the fixed header. diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 359e84a3370..937617032dd 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1944,6 +1944,7 @@ extern ulong slave_net_timeout, slave_trans_retries; extern uint max_user_connections; extern ulong what_to_log,flush_time; extern ulong query_buff_size; +extern ulong slave_max_allowed_packet; extern ulong max_prepared_stmt_count, prepared_stmt_count; extern ulong binlog_cache_size, open_files_limit; extern ulonglong max_binlog_cache_size; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 4a80fd043c8..db73504cb17 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -28,6 +28,7 @@ #include "mysys_err.h" #include "events.h" #include "debug_sync.h" +#include "log_event.h" #include "../storage/myisam/ha_myisam.h" @@ -574,6 +575,7 @@ static const char *slave_exec_mode_str= "STRICT"; ulong thread_cache_size=0, thread_pool_size= 0; ulong binlog_cache_size=0; ulonglong max_binlog_cache_size=0; +ulong slave_max_allowed_packet= 0; ulong query_cache_size=0; ulong refresh_version; /* Increments on each reload */ query_id_t global_query_id; @@ -5572,6 +5574,7 @@ enum options_mysqld OPT_KEY_CACHE_DIVISION_LIMIT, OPT_KEY_CACHE_AGE_THRESHOLD, OPT_LONG_QUERY_TIME, OPT_LOWER_CASE_TABLE_NAMES, OPT_MAX_ALLOWED_PACKET, + OPT_SLAVE_MAX_ALLOWED_PACKET, OPT_MAX_BINLOG_CACHE_SIZE, OPT_MAX_BINLOG_SIZE, OPT_MAX_CONNECTIONS, OPT_MAX_CONNECT_ERRORS, OPT_MAX_DELAYED_THREADS, OPT_MAX_HEP_TABLE_SIZE, @@ -6700,6 +6703,10 @@ thread is in the relay logs.", &global_system_variables.max_allowed_packet, &max_system_variables.max_allowed_packet, 0, GET_ULONG, REQUIRED_ARG, 1024*1024L, 1024, 1024L*1024L*1024L, MALLOC_OVERHEAD, 1024, 0}, + {"slave_max_allowed_packet", OPT_SLAVE_MAX_ALLOWED_PACKET, + "The maximum packet length to sent successfully from the master to slave.", + &slave_max_allowed_packet, &slave_max_allowed_packet, 0, GET_ULONG, + REQUIRED_ARG, MAX_MAX_ALLOWED_PACKET, 1024, MAX_MAX_ALLOWED_PACKET, MALLOC_OVERHEAD, 1024, 0}, {"max_binlog_cache_size", OPT_MAX_BINLOG_CACHE_SIZE, "Can be used to restrict the total size used to cache a multi-transaction query.", &max_binlog_cache_size, &max_binlog_cache_size, 0, diff --git a/sql/set_var.cc b/sql/set_var.cc index d9133a25d98..bbc47c2d7e8 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -366,6 +366,8 @@ static sys_var_const sys_lower_case_table_names(&vars, static sys_var_thd_ulong_session_readonly sys_max_allowed_packet(&vars, "max_allowed_packet", &SV::max_allowed_packet, check_max_allowed_packet); +static sys_var_long_ptr sys_slave_max_allowed_packet(&vars, "slave_max_allowed_packet", + &slave_max_allowed_packet); static sys_var_ulonglong_ptr sys_max_binlog_cache_size(&vars, "max_binlog_cache_size", &max_binlog_cache_size); static sys_var_long_ptr sys_max_binlog_size(&vars, "max_binlog_size", diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 7cb9d9ebcc1..99bae298e49 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -3512,23 +3512,23 @@ ER_ABORTING_CONNECTION 08S01 swe "Avbröt länken för tråd %ld till db '%-.192s', användare '%-.48s' (%-.64s)" ukr "ðÅÒÅÒ×ÁÎÏ Ú'¤ÄÎÁÎÎÑ %ld ÄÏ ÂÁÚÉ ÄÁÎÎÉÈ: '%-.192s' ËÏÒÉÓÔÕ×ÁÞÁ: '%-.48s' (%-.64s)" ER_NET_PACKET_TOO_LARGE 08S01 - cze "Zji-B¹tìn pøíchozí packet del¹í ne¾ 'max_allowed_packet'" - dan "Modtog en datapakke som var større end 'max_allowed_packet'" - nla "Groter pakket ontvangen dan 'max_allowed_packet'" - eng "Got a packet bigger than 'max_allowed_packet' bytes" - est "Saabus suurem pakett kui lubatud 'max_allowed_packet' muutujaga" - fre "Paquet plus grand que 'max_allowed_packet' reçu" - ger "Empfangenes Paket ist größer als 'max_allowed_packet' Bytes" - hun "A kapott csomag nagyobb, mint a maximalisan engedelyezett: 'max_allowed_packet'" - ita "Ricevuto un pacchetto piu` grande di 'max_allowed_packet'" - kor "'max_allowed_packet'º¸´Ù ´õÅ« ÆÐŶÀ» ¹Þ¾Ò½À´Ï´Ù." - por "Obteve um pacote maior do que a taxa máxima de pacotes definida (max_allowed_packet)" - rum "Un packet mai mare decit 'max_allowed_packet' a fost primit" - rus "ðÏÌÕÞÅÎÎÙÊ ÐÁËÅÔ ÂÏÌØÛÅ, ÞÅÍ 'max_allowed_packet'" - serbian "Primio sam mrežni paket veæi od definisane vrednosti 'max_allowed_packet'" - spa "Obtenido un paquete mayor que 'max_allowed_packet'" - swe "Kommunkationspaketet är större än 'max_allowed_packet'" - ukr "ïÔÒÉÍÁÎÏ ÐÁËÅÔ Â¦ÌØÛÉÊ Î¦Ö max_allowed_packet" + cze "Zji-B¹tìn pøíchozí packet del¹í ne¾ 'slave_max_allowed_packet'" + dan "Modtog en datapakke som var større end 'slave_max_allowed_packet'" + nla "Groter pakket ontvangen dan 'slave_max_allowed_packet'" + eng "Got a packet bigger than 'slave_max_allowed_packet' bytes" + est "Saabus suurem pakett kui lubatud 'slave_max_allowed_packet' muutujaga" + fre "Paquet plus grand que 'slave_max_allowed_packet' reçu" + ger "Empfangenes Paket ist größer als 'slave_max_allowed_packet' Bytes" + hun "A kapott csomag nagyobb, mint a maximalisan engedelyezett: 'slave_max_allowed_packet'" + ita "Ricevuto un pacchetto piu` grande di 'slave_max_allowed_packet'" + kor "'slave_max_allowed_packet'º¸´Ù ´õÅ« ÆÐŶÀ» ¹Þ¾Ò½À´Ï´Ù." + por "Obteve um pacote maior do que a taxa máxima de pacotes definida (slave_max_allowed_packet)" + rum "Un packet mai mare decit 'slave_max_allowed_packet' a fost primit" + rus "ðÏÌÕÞÅÎÎÙÊ ÐÁËÅÔ ÂÏÌØÛÅ, ÞÅÍ 'slave_max_allowed_packet'" + serbian "Primio sam mrežni paket veæi od definisane vrednosti 'slave_max_allowed_packet'" + spa "Obtenido un paquete mayor que 'slave_max_allowed_packet'" + swe "Kommunkationspaketet är större än 'slave_max_allowed_packet'" + ukr "ïÔÒÉÍÁÎÏ ÐÁËÅÔ Â¦ÌØÛÉÊ Î¦Ö slave_max_allowed_packet" ER_NET_READ_ERROR_FROM_PIPE 08S01 cze "Zji-B¹tìna chyba pøi ètení z roury spojení" dan "Fik læsefejl fra forbindelse (connection pipe)" diff --git a/sql/slave.cc b/sql/slave.cc index 437762cc318..b555d4351c9 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1884,8 +1884,8 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type) slave threads, since a replication event can become this much larger than the corresponding packet (query) sent from client to master. */ - thd->variables.max_allowed_packet= global_system_variables.max_allowed_packet - + MAX_LOG_EVENT_HEADER; /* note, incr over the global not session var */ + thd->variables.max_allowed_packet= slave_max_allowed_packet; + thd->net.max_packet_size= slave_max_allowed_packet; thd->slave_thread = 1; thd->enable_slow_log= opt_log_slow_slave_statements; set_slave_thread_options(thd); @@ -2630,6 +2630,7 @@ pthread_handler_t handle_slave_io(void *arg) thread, since a replication event can become this much larger than the corresponding packet (query) sent from client to master. */ + thd->net.max_packet_size= slave_max_allowed_packet; mysql->net.max_packet_size= thd->net.max_packet_size+= MAX_LOG_EVENT_HEADER; } else @@ -2761,10 +2762,10 @@ reading event")) switch (mysql_error_number) { case CR_NET_PACKET_TOO_LARGE: sql_print_error("\ -Log entry on master is longer than max_allowed_packet (%ld) on \ +Log entry on master is longer than slave_max_allowed_packet (%lu) on \ slave. If the entry is correct, restart the server with a higher value of \ -max_allowed_packet", - thd->variables.max_allowed_packet); +slave_max_allowed_packet", + slave_max_allowed_packet); mi->report(ERROR_LEVEL, ER_NET_PACKET_TOO_LARGE, "%s", ER(ER_NET_PACKET_TOO_LARGE)); goto err; diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index c92d2db2c1e..e3188def206 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -469,7 +469,7 @@ impossible position"; this larger than the corresponding packet (query) sent from client to master. */ - thd->variables.max_allowed_packet+= MAX_LOG_EVENT_HEADER; + thd->variables.max_allowed_packet= ULONG_MAX; /* We can set log_lock now, it does not move (it's a member of From a73d2ae02c594e74c6deb91a09a789a91e0dcc05 Mon Sep 17 00:00:00 2001 From: Tor Didriksen Date: Mon, 21 May 2012 10:47:12 +0200 Subject: [PATCH 047/289] Bug#13986705 CRASH IN GET_INTERVAL_VALUE() WITH DATE CALCULATION WITH UTF32 INTERVALS This is a followup to the fix for Bug#12340997 get_interval_value() was trying to parse the input string, looking for leading '-' while skipping whitespace. The macro my_isspace() does not work for utf32 character set, since my_charset_utf32_general_ci.ctype == NULL. Solution: convert input to ASCII before parsing, and use the character set of the returned ASCII string. --- sql/item_timefunc.cc | 162 +++++++++++++++++++++---------------------- 1 file changed, 78 insertions(+), 84 deletions(-) diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 6fc85a01668..840c8e55efe 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -865,28 +865,43 @@ 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. - @param length: length of str - @param cs: charset of str - @param values: array of results + @param args item expression which we convert to an ASCII string + @param str_value string buffer + @param is_negative set to true if interval is prefixed by '-' @param count: count of elements in result array + @param values: array of results @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, +static bool get_interval_info(Item *args, + String *str_value, + bool *is_negative, uint count, ulonglong *values, bool transform_msec) { - const char *end=str+length; - uint i; - long msec_length= 0; + String *res; + if (!(res= args->val_str_ascii(str_value))) + return true; - while (str != end && !my_isdigit(cs,*str)) + CHARSET_INFO *cs= res->charset(); + const char *str= res->ptr(); + const char *end= str + res->length(); + + str+= cs->cset->scan(cs, str, end, MY_SEQ_SPACES); + if (str < end && *str == '-') + { + *is_negative= true; + str++; + } + + while (str < end && !my_isdigit(cs,*str)) str++; - for (i=0 ; i < count ; i++) + long msec_length= 0; + for (uint i=0 ; i < count ; i++) { longlong value; const char *start= str; @@ -1427,45 +1442,24 @@ longlong Item_func_time_to_sec::val_int() To make code easy, allow interval objects without separators. */ -bool get_interval_value(Item *args,interval_type int_type, - String *str_value, INTERVAL *interval) +bool get_interval_value(Item *args, interval_type int_type, + String *str_value, INTERVAL *interval) { ulonglong array[5]; longlong UNINIT_VAR(value); - const char *UNINIT_VAR(str); - size_t UNINIT_VAR(length); - CHARSET_INFO *cs=str_value->charset(); bzero((char*) interval,sizeof(*interval)); if ((int) int_type <= INTERVAL_MICROSECOND) { value= args->val_int(); if (args->null_value) - return 1; + return true; if (value < 0) { - interval->neg=1; + interval->neg= true; value= -value; } } - else - { - String *res; - if (!(res= args->val_str_ascii(str_value))) - return (1); - - /* record negative intervalls in interval->neg */ - str=res->ptr(); - const char *end=str+res->length(); - while (str != end && my_isspace(cs,*str)) - str++; - if (str != end && *str == '-') - { - interval->neg=1; - str++; - } - length= (size_t) (end-str); // Set up pointers to new str - } switch (int_type) { case INTERVAL_YEAR: @@ -1486,88 +1480,88 @@ bool get_interval_value(Item *args,interval_type int_type, case INTERVAL_HOUR: interval->hour= (ulong) value; break; - case INTERVAL_MICROSECOND: - interval->second_part=value; - break; case INTERVAL_MINUTE: interval->minute=value; break; case INTERVAL_SECOND: interval->second=value; break; + case INTERVAL_MICROSECOND: + interval->second_part=value; + break; case INTERVAL_YEAR_MONTH: // Allow YEAR-MONTH YYYYYMM - if (get_interval_info(str,length,cs,2,array,0)) - return (1); + if (get_interval_info(args, str_value, &interval->neg, 2, array, false)) + return true; interval->year= (ulong) array[0]; interval->month= (ulong) array[1]; break; case INTERVAL_DAY_HOUR: - if (get_interval_info(str,length,cs,2,array,0)) - return (1); + if (get_interval_info(args, str_value, &interval->neg, 2, array, false)) + return true; interval->day= (ulong) array[0]; interval->hour= (ulong) array[1]; break; + case INTERVAL_DAY_MINUTE: + if (get_interval_info(args, str_value, &interval->neg, 3, array, false)) + return true; + interval->day= (ulong) array[0]; + interval->hour= (ulong) array[1]; + interval->minute= array[2]; + break; + case INTERVAL_DAY_SECOND: + if (get_interval_info(args, str_value, &interval->neg, 4, array, false)) + return true; + interval->day= (ulong) array[0]; + interval->hour= (ulong) array[1]; + interval->minute= array[2]; + interval->second= array[3]; + break; + case INTERVAL_HOUR_MINUTE: + if (get_interval_info(args, str_value, &interval->neg, 2, array, false)) + return true; + interval->hour= (ulong) array[0]; + interval->minute= array[1]; + break; + case INTERVAL_HOUR_SECOND: + if (get_interval_info(args, str_value, &interval->neg, 3, array, false)) + return true; + interval->hour= (ulong) array[0]; + interval->minute= array[1]; + interval->second= array[2]; + break; + case INTERVAL_MINUTE_SECOND: + if (get_interval_info(args, str_value, &interval->neg, 2, array, false)) + return true; + interval->minute= array[0]; + interval->second= array[1]; + break; case INTERVAL_DAY_MICROSECOND: - if (get_interval_info(str,length,cs,5,array,1)) - return (1); + if (get_interval_info(args, str_value, &interval->neg, 5, array, true)) + return true; interval->day= (ulong) array[0]; interval->hour= (ulong) array[1]; interval->minute= array[2]; interval->second= array[3]; interval->second_part= array[4]; break; - case INTERVAL_DAY_MINUTE: - if (get_interval_info(str,length,cs,3,array,0)) - return (1); - interval->day= (ulong) array[0]; - interval->hour= (ulong) array[1]; - interval->minute= array[2]; - break; - case INTERVAL_DAY_SECOND: - if (get_interval_info(str,length,cs,4,array,0)) - return (1); - interval->day= (ulong) array[0]; - interval->hour= (ulong) array[1]; - interval->minute= array[2]; - interval->second= array[3]; - break; case INTERVAL_HOUR_MICROSECOND: - if (get_interval_info(str,length,cs,4,array,1)) - return (1); + if (get_interval_info(args, str_value, &interval->neg, 4, array, true)) + return true; interval->hour= (ulong) array[0]; interval->minute= array[1]; interval->second= array[2]; interval->second_part= array[3]; break; - case INTERVAL_HOUR_MINUTE: - if (get_interval_info(str,length,cs,2,array,0)) - return (1); - interval->hour= (ulong) array[0]; - interval->minute= array[1]; - break; - case INTERVAL_HOUR_SECOND: - if (get_interval_info(str,length,cs,3,array,0)) - return (1); - interval->hour= (ulong) array[0]; - interval->minute= array[1]; - interval->second= array[2]; - break; case INTERVAL_MINUTE_MICROSECOND: - if (get_interval_info(str,length,cs,3,array,1)) - return (1); + if (get_interval_info(args, str_value, &interval->neg, 3, array, true)) + return true; interval->minute= array[0]; interval->second= array[1]; interval->second_part= array[2]; break; - case INTERVAL_MINUTE_SECOND: - if (get_interval_info(str,length,cs,2,array,0)) - return (1); - interval->minute= array[0]; - interval->second= array[1]; - break; case INTERVAL_SECOND_MICROSECOND: - if (get_interval_info(str,length,cs,2,array,1)) - return (1); + if (get_interval_info(args, str_value, &interval->neg, 2, array, true)) + return true; interval->second= array[0]; interval->second_part= array[1]; break; @@ -1575,7 +1569,7 @@ bool get_interval_value(Item *args,interval_type int_type, DBUG_ASSERT(0); break; /* purecov: end */ } - return 0; + return false; } From e979417c06f98f8ca81a7442d93f53d9aec79446 Mon Sep 17 00:00:00 2001 From: Annamalai Gurusami Date: Mon, 21 May 2012 17:25:40 +0530 Subject: [PATCH 048/289] Bug #12752572 61579: REPLICATION FAILURE WHILE INNODB_AUTOINC_LOCK_MODE=1 AND USING TRIGGER When an insert stmt like "insert into t values (1),(2),(3)" is executed, the autoincrement values assigned to these three rows are expected to be contiguous. In the given lock mode (innodb_autoinc_lock_mode=1), the auto inc lock will be released before the end of the statement. So to make the autoincrement contiguous for a given statement, we need to reserve the auto inc values at the beginning of the statement. Modified the fix based on review comment by Svoj. --- sql/handler.cc | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/sql/handler.cc b/sql/handler.cc index 20bf2355c25..9e43d5aba93 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -2398,18 +2398,18 @@ int handler::update_auto_increment() Note that in prelocked mode no estimation is given. */ - /* - For multi-row inserts, if the bulk inserts cannot be started, the - handler::estimation_rows_to_insert will not be set. Set it here. - */ - if ((estimation_rows_to_insert == 0) && - (thd->lex->many_values.elements > 0)) - { - estimation_rows_to_insert= thd->lex->many_values.elements; - } - if ((auto_inc_intervals_count == 0) && (estimation_rows_to_insert > 0)) nb_desired_values= estimation_rows_to_insert; + else if ((auto_inc_intervals_count == 0) && + (thd->lex->many_values.elements > 0)) + { + /* + For multi-row inserts, if the bulk inserts cannot be started, the + handler::estimation_rows_to_insert will not be set. But we still + want to reserve the autoinc values. + */ + nb_desired_values= thd->lex->many_values.elements; + } else /* go with the increasing defaults */ { /* avoid overflow in formula, with this if() */ From 8aedf7d30f4f2c19085407f6793bce84facdf1f5 Mon Sep 17 00:00:00 2001 From: Annamalai Gurusami Date: Wed, 23 May 2012 10:12:52 +0530 Subject: [PATCH 049/289] After the fix for Bug #12752572, there is a pb2 failure. Fixing it by updating the result file. Because a multi-row insert now reserves the auto increment values before hand, if any explicitly specified auto increment values are there, then some of the reserved values are lost. --- mysql-test/suite/rpl/r/rpl_trigger.result | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mysql-test/suite/rpl/r/rpl_trigger.result b/mysql-test/suite/rpl/r/rpl_trigger.result index 784cd1bcdff..e6e6763d76e 100644 --- a/mysql-test/suite/rpl/r/rpl_trigger.result +++ b/mysql-test/suite/rpl/r/rpl_trigger.result @@ -29,7 +29,7 @@ a b 1 2 3 0 4 0 -5 0 +6 0 500 0 select a,name, old_a, old_b, truncate(rand_value,4) from t3; a name old_a old_b truncate(rand_value,4) @@ -39,7 +39,7 @@ a name old_a old_b truncate(rand_value,4) 103 t2 1 2 0.9164 104 t2 3 0 0.8826 105 t2 4 0 0.6635 -106 t2 5 0 0.6699 +106 t2 6 0 0.6699 107 t2 500 0 0.3593 --- On slave -- @@ -52,7 +52,7 @@ a b 1 2 3 0 4 0 -5 0 +6 0 500 0 select a,name, old_a, old_b, truncate(rand_value,4) from t3; a name old_a old_b truncate(rand_value,4) @@ -62,7 +62,7 @@ a name old_a old_b truncate(rand_value,4) 103 t2 1 2 0.9164 104 t2 3 0 0.8826 105 t2 4 0 0.6635 -106 t2 5 0 0.6699 +106 t2 6 0 0.6699 107 t2 500 0 0.3593 drop table t1,t2,t3; select get_lock("bug12480",2); From be7a6d93ccc3a8304246183a44637b43bf2461d7 Mon Sep 17 00:00:00 2001 From: Marc Alff Date: Wed, 23 May 2012 10:21:35 +0200 Subject: [PATCH 050/289] Improved the test performance_schema.func_file_io, so that investigating test failures is easier. Detect cases when @before_count / @after_count is NULL. --- mysql-test/suite/perfschema/r/func_file_io.result | 12 ++++++++++++ mysql-test/suite/perfschema/t/func_file_io.test | 4 ++++ 2 files changed, 16 insertions(+) diff --git a/mysql-test/suite/perfschema/r/func_file_io.result b/mysql-test/suite/perfschema/r/func_file_io.result index d99e77dcd8c..c95fae94803 100644 --- a/mysql-test/suite/perfschema/r/func_file_io.result +++ b/mysql-test/suite/perfschema/r/func_file_io.result @@ -15,6 +15,9 @@ SET @before_count = (SELECT SUM(TIMER_WAIT) FROM performance_schema.events_waits_history_long WHERE (EVENT_NAME = 'wait/io/file/myisam/dfile') AND (OBJECT_NAME LIKE '%t1.MYD')); +SELECT (@before_count >= 0) as have_before_count; +have_before_count +1 SELECT IF(@before_count > 0, 'Success', 'Failure') has_instrumentation; has_instrumentation Success @@ -27,6 +30,9 @@ SET @after_count = (SELECT SUM(TIMER_WAIT) FROM performance_schema.events_waits_history_long WHERE (EVENT_NAME = 'wait/io/file/myisam/dfile') AND (OBJECT_NAME LIKE '%t1.MYD') AND (1 = 1)); +SELECT (@after_count >= 0) as have_after_count; +have_after_count +1 SELECT IF((@after_count - @before_count) > 0, 'Success', 'Failure') test_ff1_timed; test_ff1_timed Success @@ -35,6 +41,9 @@ SET @before_count = (SELECT SUM(TIMER_WAIT) FROM performance_schema.events_waits_history_long WHERE (EVENT_NAME = 'wait/io/file/myisam/dfile') AND (OBJECT_NAME LIKE '%t1.MYD') AND (2 = 2)); +SELECT (@before_count >= 0) as have_before_count; +have_before_count +1 SELECT * FROM t1 WHERE id < 6; id b 1 initial value @@ -46,6 +55,9 @@ SET @after_count = (SELECT SUM(TIMER_WAIT) FROM performance_schema.events_waits_history_long WHERE (EVENT_NAME = 'wait/io/file/myisam/dfile') AND (OBJECT_NAME LIKE '%t1.MYD') AND (3 = 3)); +SELECT (@after_count >= 0) as have_after_count; +have_after_count +1 SELECT IF((COALESCE(@after_count, 0) - COALESCE(@before_count, 0)) = 0, 'Success', 'Failure') test_ff2_timed; test_ff2_timed Success diff --git a/mysql-test/suite/perfschema/t/func_file_io.test b/mysql-test/suite/perfschema/t/func_file_io.test index bcf29a7daa2..e8b01a10bd1 100644 --- a/mysql-test/suite/perfschema/t/func_file_io.test +++ b/mysql-test/suite/perfschema/t/func_file_io.test @@ -41,6 +41,7 @@ SET @before_count = (SELECT SUM(TIMER_WAIT) WHERE (EVENT_NAME = 'wait/io/file/myisam/dfile') AND (OBJECT_NAME LIKE '%t1.MYD')); +SELECT (@before_count >= 0) as have_before_count; SELECT IF(@before_count > 0, 'Success', 'Failure') has_instrumentation; SELECT * FROM t1 WHERE id < 4; @@ -50,6 +51,7 @@ SET @after_count = (SELECT SUM(TIMER_WAIT) WHERE (EVENT_NAME = 'wait/io/file/myisam/dfile') AND (OBJECT_NAME LIKE '%t1.MYD') AND (1 = 1)); +SELECT (@after_count >= 0) as have_after_count; SELECT IF((@after_count - @before_count) > 0, 'Success', 'Failure') test_ff1_timed; UPDATE performance_schema.setup_instruments SET enabled='NO'; @@ -59,6 +61,7 @@ SET @before_count = (SELECT SUM(TIMER_WAIT) WHERE (EVENT_NAME = 'wait/io/file/myisam/dfile') AND (OBJECT_NAME LIKE '%t1.MYD') AND (2 = 2)); +SELECT (@before_count >= 0) as have_before_count; SELECT * FROM t1 WHERE id < 6; SET @after_count = (SELECT SUM(TIMER_WAIT) @@ -66,6 +69,7 @@ SET @after_count = (SELECT SUM(TIMER_WAIT) WHERE (EVENT_NAME = 'wait/io/file/myisam/dfile') AND (OBJECT_NAME LIKE '%t1.MYD') AND (3 = 3)); +SELECT (@after_count >= 0) as have_after_count; SELECT IF((COALESCE(@after_count, 0) - COALESCE(@before_count, 0)) = 0, 'Success', 'Failure') test_ff2_timed; # From 889ce031087dbe44cdbdbd2c93a7983667aec536 Mon Sep 17 00:00:00 2001 From: "Norvald H. Ryeng" Date: Wed, 23 May 2012 12:27:32 +0200 Subject: [PATCH 051/289] WL#6311 Remove --safe-mode Print deprecation warning if the --safe-mode command line option is used. --- mysql-test/r/mysqld--help-notwin.result | 2 +- mysql-test/r/mysqld--help-win.result | 2 +- sql/mysqld.cc | 4 +++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/mysqld--help-notwin.result b/mysql-test/r/mysqld--help-notwin.result index 36649cf761d..72f89ae3bc1 100644 --- a/mysql-test/r/mysqld--help-notwin.result +++ b/mysql-test/r/mysqld--help-notwin.result @@ -595,7 +595,7 @@ The following options may be given as the first argument: master during slave registration --rpl-recovery-rank=# Unused, will be removed - --safe-mode Skip some optimize stages (for testing). + --safe-mode Skip some optimize stages (for testing). Deprecated. --safe-user-create Don't allow new user creation by the user who has no write privileges to the mysql.user table. --secure-auth Disallow authentication for accounts that have old diff --git a/mysql-test/r/mysqld--help-win.result b/mysql-test/r/mysqld--help-win.result index db7dd264b76..2ab41913427 100644 --- a/mysql-test/r/mysqld--help-win.result +++ b/mysql-test/r/mysqld--help-win.result @@ -595,7 +595,7 @@ The following options may be given as the first argument: master during slave registration --rpl-recovery-rank=# Unused, will be removed - --safe-mode Skip some optimize stages (for testing). + --safe-mode Skip some optimize stages (for testing). Deprecated. --safe-user-create Don't allow new user creation by the user who has no write privileges to the mysql.user table. --secure-auth Disallow authentication for accounts that have old diff --git a/sql/mysqld.cc b/sql/mysqld.cc index a37a9701fe7..df9fbaa8652 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -5948,7 +5948,7 @@ struct my_option my_long_options[]= "will not do updates to tables in databases that start with foo and whose " "table names start with bar.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"safe-mode", OPT_SAFE, "Skip some optimize stages (for testing).", + {"safe-mode", OPT_SAFE, "Skip some optimize stages (for testing). Deprecated.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"safe-user-create", 0, "Don't allow new user creation by the user who has no write privileges to the mysql.user table.", @@ -7081,6 +7081,8 @@ mysqld_get_one_option(int optid, delay_key_write_options= DELAY_KEY_WRITE_NONE; myisam_recover_options= HA_RECOVER_DEFAULT; ha_open_options&= ~(HA_OPEN_DELAY_KEY_WRITE); + sql_print_warning("The syntax '--safe-mode' is deprecated and will be " + "removed in a future release."); break; case (int) OPT_SKIP_PRIOR: opt_specialflag|= SPECIAL_NO_PRIOR; From dcd4fa3fd5330945cb996081e521b2d9d635edab Mon Sep 17 00:00:00 2001 From: Sujatha Sivakumar Date: Thu, 24 May 2012 16:25:07 +0530 Subject: [PATCH 052/289] Bug#13833962:DISABLE [NOTE] START BINLOG_DUMP TO SLAVE_SERVER(0) MESSAGES IN THE ERROR LOG Problem: Using mysqlbinlog with the --read-from-remote-server option as shown below prints a message in error log for each call. This happens for 5.5 and above versions mysqlbinlog -uroot -p --read-from-remote-server --host=localhost test Message in error log file is given below: 120312 10:27:57 [Note] Start binlog_dump to slave_server(0), pos(test, 4) The problem is that it can fill up the error log if the command is called very often. Analysis: The below mentioned print function is called from "mysql_binlog_send" function which causes the "Start binlog_dump..." string to be printed in error log file. sql_print_information("Start binlog_dump to master_thread_id(%lu) slave_server(%d)..." Fix: A condition has been added in such a way that the 'sql_print_information' will be invoked only when the "log_warnings" variable is set to >1 otherwise don't call the 'sql_print_information' function. --- sql/sql_repl.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index ffc7aa4bf8a..5968c17f871 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -476,7 +476,8 @@ void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos, heartbeat_ts= &heartbeat_buf; set_timespec_nsec(*heartbeat_ts, 0); } - sql_print_information("Start binlog_dump to slave_server(%d), pos(%s, %lu)", + if (global_system_variables.log_warnings > 1) + sql_print_information("Start binlog_dump to slave_server(%d), pos(%s, %lu)", thd->server_id, log_ident, (ulong)pos); if (RUN_HOOK(binlog_transmit, transmit_start, (thd, flags, log_ident, pos))) { From 01748ce128ae4c29cfb63e88cd68918e7d48e946 Mon Sep 17 00:00:00 2001 From: Inaam Rana Date: Thu, 24 May 2012 12:37:03 -0400 Subject: [PATCH 053/289] Bug #14100254 65389: MVCC IS BROKEN WITH IMPLICIT LOCK rb://1088 approved by: Marko Makela This bug was introduced in early stages of plugin. We were not checking for an implicit lock on sec index rec for trx_id that is stamped on current version of the clust_index in case where the clust_index has a previous delete marked version. --- storage/innodb_plugin/row/row0vers.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/storage/innodb_plugin/row/row0vers.c b/storage/innodb_plugin/row/row0vers.c index 8a7bb842293..9aeaa2db6c0 100644 --- a/storage/innodb_plugin/row/row0vers.c +++ b/storage/innodb_plugin/row/row0vers.c @@ -208,18 +208,6 @@ row_vers_impl_x_locked_off_kernel( vers_del = rec_get_deleted_flag(prev_version, comp); prev_trx_id = row_get_rec_trx_id(prev_version, clust_index, clust_offsets); - - /* If the trx_id and prev_trx_id are different and if - the prev_version is marked deleted then the - prev_trx_id must have already committed for the trx_id - to be able to modify the row. Therefore, prev_trx_id - cannot hold any implicit lock. */ - if (vers_del && 0 != ut_dulint_cmp(trx_id, prev_trx_id)) { - - mutex_enter(&kernel_mutex); - break; - } - /* The stack of versions is locked by mtr. Thus, it is safe to fetch the prefixes for externally stored columns. */ From efe42792b363e97dd5ccb74be1abac2d4e79ca9e Mon Sep 17 00:00:00 2001 From: Mayank Prasad Date: Thu, 24 May 2012 23:00:32 +0530 Subject: [PATCH 054/289] Bug#13417440 : 63340: ARCHIVE FILE IO NOT INSTRUMENTED Details: - Archive storage engine file access were not instrumented and thus were not shown in PS tables. Fix: - Added instrumentation code by using PS Apis for I/O. --- .../suite/perfschema/r/query_cache.result | 4 +-- mysql-test/suite/perfschema/t/disabled.def | 2 +- storage/archive/azio.c | 25 +++++++++++-------- storage/archive/ha_archive.cc | 25 ++++++++++++++----- 4 files changed, 37 insertions(+), 19 deletions(-) diff --git a/mysql-test/suite/perfschema/r/query_cache.result b/mysql-test/suite/perfschema/r/query_cache.result index c7ac3d499b4..56511999ab2 100644 --- a/mysql-test/suite/perfschema/r/query_cache.result +++ b/mysql-test/suite/perfschema/r/query_cache.result @@ -38,7 +38,7 @@ spins NULL select name from performance_schema.setup_instruments order by name limit 1; name -wait/io/file/csv/data +wait/io/file/archive/data show status like "Qcache_queries_in_cache"; Variable_name Value Qcache_queries_in_cache 1 @@ -53,7 +53,7 @@ spins NULL select name from performance_schema.setup_instruments order by name limit 1; name -wait/io/file/csv/data +wait/io/file/archive/data show status like "Qcache_queries_in_cache"; Variable_name Value Qcache_queries_in_cache 1 diff --git a/mysql-test/suite/perfschema/t/disabled.def b/mysql-test/suite/perfschema/t/disabled.def index 8cae44a3607..6c496ec6d95 100644 --- a/mysql-test/suite/perfschema/t/disabled.def +++ b/mysql-test/suite/perfschema/t/disabled.def @@ -9,4 +9,4 @@ # Do not use any TAB characters for whitespace. # ############################################################################## - +misc.test : bug#14113704 24/04/2012 Mayank issure reported causing failure. diff --git a/storage/archive/azio.c b/storage/archive/azio.c index 5fc9bc875f8..ec4b5bcb7cd 100644 --- a/storage/archive/azio.c +++ b/storage/archive/azio.c @@ -37,6 +37,8 @@ void putLong(File file, uLong x); uLong getLong(azio_stream *s); void read_header(azio_stream *s, unsigned char *buffer); +extern PSI_file_key arch_key_file_data; + /* =========================================================================== Opens a gzip (.gz) file for reading or writing. The mode parameter is as in fopen ("rb" or "wb"). The file is given either by file descriptor @@ -113,7 +115,7 @@ int az_open (azio_stream *s, const char *path, int Flags, File fd) s->stream.avail_out = AZ_BUFSIZE_WRITE; errno = 0; - s->file = fd < 0 ? my_open(path, Flags, MYF(0)) : fd; + s->file = fd < 0 ? mysql_file_open(arch_key_file_data, path, Flags, MYF(0)) : fd; DBUG_EXECUTE_IF("simulate_archive_open_failure", { if (s->file >= 0) @@ -235,8 +237,8 @@ int get_byte(s) if (s->stream.avail_in == 0) { errno = 0; - s->stream.avail_in= (uInt) my_read(s->file, (uchar *)s->inbuf, - AZ_BUFSIZE_READ, MYF(0)); + s->stream.avail_in= (uInt) mysql_file_read(s->file, (uchar *)s->inbuf, + AZ_BUFSIZE_READ, MYF(0)); if (s->stream.avail_in == 0) { s->z_eof = 1; @@ -277,7 +279,8 @@ void check_header(azio_stream *s) if (len < 2) { if (len) s->inbuf[0] = s->stream.next_in[0]; errno = 0; - len = (uInt)my_read(s->file, (uchar *)s->inbuf + len, AZ_BUFSIZE_READ >> len, MYF(0)); + len = (uInt)mysql_file_read(s->file, (uchar *)s->inbuf + len, + AZ_BUFSIZE_READ >> len, MYF(0)); if (len == (uInt)-1) s->z_err = Z_ERRNO; s->stream.avail_in += len; s->stream.next_in = s->inbuf; @@ -468,7 +471,8 @@ unsigned int ZEXPORT azread ( azio_stream *s, voidp buf, size_t len, int *error) if (s->stream.avail_out > 0) { s->stream.avail_out -= - (uInt)my_read(s->file, (uchar *)next_out, s->stream.avail_out, MYF(0)); + (uInt)mysql_file_read(s->file, (uchar *)next_out, + s->stream.avail_out, MYF(0)); } len -= s->stream.avail_out; s->in += len; @@ -481,7 +485,8 @@ unsigned int ZEXPORT azread ( azio_stream *s, voidp buf, size_t len, int *error) if (s->stream.avail_in == 0 && !s->z_eof) { errno = 0; - s->stream.avail_in = (uInt)my_read(s->file, (uchar *)s->inbuf, AZ_BUFSIZE_READ, MYF(0)); + s->stream.avail_in = (uInt)mysql_file_read(s->file, (uchar *)s->inbuf, + AZ_BUFSIZE_READ, MYF(0)); if (s->stream.avail_in == 0) { s->z_eof = 1; @@ -548,8 +553,8 @@ unsigned int azwrite (azio_stream *s, const voidp buf, unsigned int len) { s->stream.next_out = s->outbuf; - if (my_write(s->file, (uchar *)s->outbuf, AZ_BUFSIZE_WRITE, - MYF(0)) != AZ_BUFSIZE_WRITE) + if (mysql_file_write(s->file, (uchar *)s->outbuf, AZ_BUFSIZE_WRITE, + MYF(0)) != AZ_BUFSIZE_WRITE) { s->z_err = Z_ERRNO; break; @@ -596,7 +601,7 @@ int do_flush (azio_stream *s, int flush) if (len != 0) { s->check_point= my_tell(s->file, MYF(0)); - if ((uInt)my_write(s->file, (uchar *)s->outbuf, len, MYF(0)) != len) + if ((uInt)mysql_file_write(s->file, (uchar *)s->outbuf, len, MYF(0)) != len) { s->z_err = Z_ERRNO; return Z_ERRNO; @@ -783,7 +788,7 @@ void putLong (File file, uLong x) for (n = 0; n < 4; n++) { buffer[0]= (int)(x & 0xff); - my_write(file, buffer, 1, MYF(0)); + mysql_file_write(file, buffer, 1, MYF(0)); x >>= 8; } } diff --git a/storage/archive/ha_archive.cc b/storage/archive/ha_archive.cc index d040d694e1f..dba647b8d1a 100644 --- a/storage/archive/ha_archive.cc +++ b/storage/archive/ha_archive.cc @@ -114,6 +114,8 @@ static HASH archive_open_tables; #define DATA_BUFFER_SIZE 2 // Size of the data used in the data file #define ARCHIVE_CHECK_HEADER 254 // The number we use to determine corruption +extern "C" PSI_file_key arch_key_file_data; + /* Static declarations for handerton */ static handler *archive_create_handler(handlerton *hton, TABLE_SHARE *table, @@ -159,6 +161,14 @@ static PSI_mutex_info all_archive_mutexes[]= { &az_key_mutex_ARCHIVE_SHARE_mutex, "ARCHIVE_SHARE::mutex", 0} }; +PSI_file_key arch_key_file_metadata, arch_key_file_data, arch_key_file_frm; +static PSI_file_info all_archive_files[]= +{ + { &arch_key_file_metadata, "metadata", 0}, + { &arch_key_file_data, "data", 0}, + { &arch_key_file_frm, "FRM", 0} +}; + static void init_archive_psi_keys(void) { const char* category= "archive"; @@ -169,6 +179,9 @@ static void init_archive_psi_keys(void) count= array_elements(all_archive_mutexes); PSI_server->register_mutex(category, all_archive_mutexes, count); + + count= array_elements(all_archive_files); + PSI_server->register_file(category, all_archive_files, count); } #endif /* HAVE_PSI_INTERFACE */ @@ -262,7 +275,7 @@ int archive_discover(handlerton *hton, THD* thd, const char *db, build_table_filename(az_file, sizeof(az_file) - 1, db, name, ARZ, 0); - if (!(my_stat(az_file, &file_stat, MYF(0)))) + if (!(mysql_file_stat(arch_key_file_data, az_file, &file_stat, MYF(0)))) goto err; if (!(azopen(&frm_stream, az_file, O_RDONLY|O_BINARY))) @@ -712,7 +725,7 @@ int ha_archive::create(const char *name, TABLE *table_arg, There is a chance that the file was "discovered". In this case just use whatever file is there. */ - if (!(my_stat(name_buff, &file_stat, MYF(0)))) + if (!(mysql_file_stat(arch_key_file_data, name_buff, &file_stat, MYF(0)))) { my_errno= 0; if (!(azopen(&create_stream, name_buff, O_CREAT|O_RDWR|O_BINARY))) @@ -729,19 +742,19 @@ int ha_archive::create(const char *name, TABLE *table_arg, /* Here is where we open up the frm and pass it to archive to store */ - if ((frm_file= my_open(name_buff, O_RDONLY, MYF(0))) > 0) + if ((frm_file= mysql_file_open(arch_key_file_frm, name_buff, O_RDONLY, MYF(0))) >= 0) { if (!mysql_file_fstat(frm_file, &file_stat, MYF(MY_WME))) { frm_ptr= (uchar *)my_malloc(sizeof(uchar) * file_stat.st_size, MYF(0)); if (frm_ptr) { - my_read(frm_file, frm_ptr, file_stat.st_size, MYF(0)); + mysql_file_read(frm_file, frm_ptr, file_stat.st_size, MYF(0)); azwrite_frm(&create_stream, (char *)frm_ptr, file_stat.st_size); my_free(frm_ptr); } } - my_close(frm_file, MYF(0)); + mysql_file_close(frm_file, MYF(0)); } if (create_info->comment.str) @@ -1607,7 +1620,7 @@ int ha_archive::info(uint flag) { MY_STAT file_stat; // Stat information for the data file - (void) my_stat(share->data_file_name, &file_stat, MYF(MY_WME)); + (void) mysql_file_stat(arch_key_file_data, share->data_file_name, &file_stat, MYF(MY_WME)); if (flag & HA_STATUS_TIME) stats.update_time= (ulong) file_stat.st_mtime; From 6f199f7c4f2fba51e938ba4b009c1bd173193ea0 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Thu, 24 May 2012 22:22:39 +0400 Subject: [PATCH 055/289] MDEV-275: SHOW EXPLAIN: server crashes in JOIN::print_explain with IN subquery and aggregate function - Don't try to produce plans after JOIN::cleanup() has been called, because: = JOIN::cleanup leaves data structures in partially-cleaned state = Walking them is hazardous (see this bug), and has funny effects (See previous commits, "Using join cache" may or may not be shown) = Changing data structures to be persisted may cause unwanted side effects - The consequence is that SHOW EXPLAIN will show "Query plan already deleted" when e.g. reading data after filesort. --- mysql-test/r/show_explain.result | 36 +++++++++++++++++++++++++------- mysql-test/t/show_explain.test | 22 +++++++++++++++++++ sql/sql_select.cc | 3 ++- 3 files changed, 52 insertions(+), 9 deletions(-) diff --git a/mysql-test/r/show_explain.result b/mysql-test/r/show_explain.result index 55bc875fe59..51c2a7341ee 100644 --- a/mysql-test/r/show_explain.result +++ b/mysql-test/r/show_explain.result @@ -154,8 +154,7 @@ set debug_dbug='d,show_explain_probe_join_exec_end'; select a, (select max(a) from t0 b where b.a+a.a<10) from t0 a where a<1; show explain for $thr2; id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY a ALL NULL NULL NULL NULL 10 -2 DEPENDENT SUBQUERY b ALL NULL NULL NULL NULL 10 +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Query plan already deleted Warnings: Note 1003 select a, (select max(a) from t0 b where b.a+a.a<10) from t0 a where a<1 a (select max(a) from t0 b where b.a+a.a<10) @@ -208,13 +207,13 @@ Note 1003 select t2.a, ((select max(a) from t0 where t2.a + t0.a <3) >3) as SUBQ show explain for $thr2; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 ALL NULL NULL NULL NULL 3 -2 DEPENDENT SUBQUERY t0 ALL NULL NULL NULL NULL 10 Using where +2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Query plan already deleted Warnings: Note 1003 select t2.a, ((select max(a) from t0 where t2.a + t0.a <3) >3) as SUBQ from t2 show explain for $thr2; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 ALL NULL NULL NULL NULL 3 -2 DEPENDENT SUBQUERY t0 ALL NULL NULL NULL NULL 10 Using where +2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Query plan already deleted Warnings: Note 1003 select t2.a, ((select max(a) from t0 where t2.a + t0.a <3) >3) as SUBQ from t2 a SUBQ @@ -312,8 +311,7 @@ SELECT alias.a FROM t2, ( SELECT * FROM t2 ) AS alias GROUP BY alias.a; # NOTE: current code will not show "Using join buffer": show explain for $thr2; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 ALL NULL NULL NULL NULL 5 Using temporary; Using filesort -1 SIMPLE t2 ALL NULL NULL NULL NULL 5 +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Query plan already deleted Warnings: Note 1003 SELECT alias.a FROM t2, ( SELECT * FROM t2 ) AS alias GROUP BY alias.a a @@ -404,7 +402,7 @@ set debug_dbug='d,show_explain_probe_join_exec_end'; select * from t0 where 1>10; show explain for $thr2; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Query plan already deleted Warnings: Note 1003 select * from t0 where 1>10 a @@ -419,7 +417,7 @@ set debug_dbug='d,show_explain_probe_join_exec_end'; select * from t0,t3 where t3.a=112233; show explain for $thr2; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE NULL NULL NULL NULL NULL NULL NULL no matching row in const table +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Query plan already deleted Warnings: Note 1003 select * from t0,t3 where t3.a=112233 a a @@ -515,4 +513,26 @@ count(*) 1740 set debug_dbug=''; drop table t2, t3, t4; +# +# MDEV-275: SHOW EXPLAIN: server crashes in JOIN::print_explain with IN subquery and aggregate function +# +CREATE TABLE t2 ( `pk` INT NOT NULL PRIMARY KEY, `a1` INT NOT NULL, KEY(`a1`)) ENGINE=MyISAM; +INSERT INTO t2 VALUES +(1,5),(2,4),(3,6),(4,9),(5,2),(6,8),(7,4),(8,8),(9,0),(10,43), +(11,23),(12,3),(13,45),(14,16),(15,2),(16,33),(17,2),(18,5),(19,9),(20,2); +set @show_explain_probe_select_id=1; +set debug='d,show_explain_probe_join_exec_end'; +Warnings: +Warning 1287 The syntax '@@debug' is deprecated and will be removed in MariaDB 5.6. Please use '@@debug_dbug' instead +SELECT * FROM t2 WHERE (5, 78) IN (SELECT `a1`, MAX(`a1`) FROM t2 GROUP BY `a1`); +show explain for $thr2; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Query plan already deleted +Warnings: +Note 1003 SELECT * FROM t2 WHERE (5, 78) IN (SELECT `a1`, MAX(`a1`) FROM t2 GROUP BY `a1`) +pk a1 +set debug=''; +Warnings: +Warning 1287 The syntax '@@debug' is deprecated and will be removed in MariaDB 5.6. Please use '@@debug_dbug' instead +DROP TABLE t2; drop table t0,t1; diff --git a/mysql-test/t/show_explain.test b/mysql-test/t/show_explain.test index 01dd7b8801d..57f0c48db3a 100644 --- a/mysql-test/t/show_explain.test +++ b/mysql-test/t/show_explain.test @@ -499,6 +499,28 @@ reap; set debug_dbug=''; drop table t2, t3, t4; +--echo # +--echo # MDEV-275: SHOW EXPLAIN: server crashes in JOIN::print_explain with IN subquery and aggregate function +--echo # +CREATE TABLE t2 ( `pk` INT NOT NULL PRIMARY KEY, `a1` INT NOT NULL, KEY(`a1`)) ENGINE=MyISAM; +INSERT INTO t2 VALUES + (1,5),(2,4),(3,6),(4,9),(5,2),(6,8),(7,4),(8,8),(9,0),(10,43), + (11,23),(12,3),(13,45),(14,16),(15,2),(16,33),(17,2),(18,5),(19,9),(20,2); + +set @show_explain_probe_select_id=1; +set debug='d,show_explain_probe_join_exec_end'; +send + SELECT * FROM t2 WHERE (5, 78) IN (SELECT `a1`, MAX(`a1`) FROM t2 GROUP BY `a1`); +connection default; +--source include/wait_condition.inc +evalp show explain for $thr2; +connection con1; +reap; +set debug=''; + +DROP TABLE t2; + + ## TODO: Test this: have several SHOW EXPLAIN requests be queued up for a ## thread and served together. diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 4d7f66388d9..070c5eb9e8c 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -10569,8 +10569,9 @@ void JOIN::cleanup(bool full) /* psergey: let's try without this first: - have_query_plan= QEP_DELETED; */ + have_query_plan= QEP_DELETED; + if (table) { JOIN_TAB *tab; From 1c1d19af8cc54127ff861d7fb0d92b6322b81f16 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 25 May 2012 13:19:44 +0530 Subject: [PATCH 056/289] From b2888adb701c1cfd1db137937d50f571fe8366d4 Mon Sep 17 00:00:00 2001 From: Mayank Prasad Date: Fri, 25 May 2012 15:44:27 +0530 Subject: [PATCH 057/289] PB2 Failure Fix : Disabled the test case in correct manner. --- mysql-test/suite/perfschema/t/disabled.def | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/suite/perfschema/t/disabled.def b/mysql-test/suite/perfschema/t/disabled.def index 6c496ec6d95..8a843692d2a 100644 --- a/mysql-test/suite/perfschema/t/disabled.def +++ b/mysql-test/suite/perfschema/t/disabled.def @@ -9,4 +9,4 @@ # Do not use any TAB characters for whitespace. # ############################################################################## -misc.test : bug#14113704 24/04/2012 Mayank issure reported causing failure. +misc : bug#14113704 24/04/2012 Mayank issue reported causing failure. From b2c3acc987193775d392e763c8b9eef3da7c65a8 Mon Sep 17 00:00:00 2001 From: Praveenkumar Hulakund Date: Mon, 28 May 2012 11:14:43 +0530 Subject: [PATCH 058/289] Bug#14003080:65104: MAX_USER_CONNECTIONS WITH PROCESSLIST EMPTY Analysis: ------------- If server is started with limit of MAX_CONNECTIONS and MAX_USER_CONNECTIONS then only MAX_USER_CONNECTIONS of any particular users can be connected to server and total MAX_CONNECTIONS of client can be connected to server. Server maintains a counter for total CONNECTIONS and total CONNECTIONS from particular user. Here, MAX_CONNECTIONS of connections are created to server. Out of this MAX_CONNECTIONS, connections from particular user (say USER1) are also created. The connections from USER1 is lesser than MAX_USER_CONNECTIONS. After that there was one more connection request from USER1. Since USER1 can still create connections as he havent reached MAX_USER_CONNECTIONS, server increments counter of CONNECTIONS per user. As server already has MAX_CONNECTIONS of connections, next check to total CONNECTION count fails. In this case control is returned WITHOUT decrementing the CONNECTIONS per user. So the counter per user CONNECTIONS goes on incrementing for each attempt until current connections are closed. And because of this counter per CONNECTIONS reached MAX_USER_CONNECTIONS. So, next connections form USER1 user always returns with MAX_USER_CONNECTION limit error, even when total connection to sever are less than MAX_CONNECTIONS. Fix: ------------- This issue is occurred because of not handling counters properly in the server. Changed the code to handle per user connection counters properly. --- sql/sql_acl.cc | 19 +++---- sql/sql_class.cc | 86 ++++++++++++++++++++++++++++- sql/sql_class.h | 21 +++++++- sql/sql_connect.cc | 132 +++++++++++++++++++++++++++------------------ sql/sql_connect.h | 3 +- sql/sql_parse.cc | 7 +-- sql/sys_vars.h | 5 +- 7 files changed, 200 insertions(+), 73 deletions(-) diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 3438e60683f..d3715fd2312 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -7810,8 +7810,6 @@ get_cached_table_access(GRANT_INTERNAL_INFO *grant_internal_info, #undef HAVE_OPENSSL #ifdef NO_EMBEDDED_ACCESS_CHECKS #define initialized 0 -#define decrease_user_connections(X) /* nothing */ -#define check_for_max_user_connections(X, Y) 0 #endif #endif #ifndef HAVE_OPENSSL @@ -9297,7 +9295,7 @@ acl_authenticate(THD *thd, uint connect_errors, uint com_change_user_pkt_len) mpvio.packets_read++; // take COM_CHANGE_USER packet into account /* Clear variables that are allocated */ - thd->user_connect= 0; + thd->set_user_connect(NULL); if (parse_com_change_user_packet(&mpvio, com_change_user_pkt_len)) { @@ -9460,11 +9458,11 @@ acl_authenticate(THD *thd, uint connect_errors, uint com_change_user_pkt_len) else sctx->skip_grants(); - if (thd->user_connect && - (thd->user_connect->user_resources.conn_per_hour || - thd->user_connect->user_resources.user_conn || + const USER_CONN *uc; + if ((uc= thd->get_user_connect()) && + (uc->user_resources.conn_per_hour || uc->user_resources.user_conn || global_system_variables.max_user_connections) && - check_for_max_user_connections(thd, thd->user_connect)) + check_for_max_user_connections(thd, uc)) { DBUG_RETURN(1); // The error is set in check_for_max_user_connections() } @@ -9486,6 +9484,7 @@ acl_authenticate(THD *thd, uint connect_errors, uint com_change_user_pkt_len) mysql_mutex_unlock(&LOCK_connection_count); if (!count_ok) { // too many connections + release_user_connection(thd); my_error(ER_CON_COUNT_ERROR, MYF(0)); DBUG_RETURN(1); } @@ -9504,11 +9503,7 @@ acl_authenticate(THD *thd, uint connect_errors, uint com_change_user_pkt_len) if (mysql_change_db(thd, &mpvio.db, FALSE)) { /* mysql_change_db() has pushed the error message. */ - if (thd->user_connect) - { - decrease_user_connections(thd->user_connect); - thd->user_connect= 0; - } + release_user_connection(thd); DBUG_RETURN(1); } } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index bdcb85218c3..7e93157c69e 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -852,7 +852,7 @@ THD::THD() #if defined(ENABLED_PROFILING) profiling.set_thd(this); #endif - user_connect=(USER_CONN *)0; + m_user_connect= NULL; my_hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0, (my_hash_get_key) get_var_key, (my_hash_free_key) free_user_var, 0); @@ -5009,3 +5009,87 @@ bool Discrete_intervals_list::append(Discrete_interval *new_interval) } #endif /* !defined(MYSQL_CLIENT) */ + +void THD::set_user_connect(USER_CONN *uc) +{ + DBUG_ENTER("THD::set_user_connect"); + + m_user_connect= uc; + + DBUG_VOID_RETURN; +} + +void THD::increment_user_connections_counter() +{ + DBUG_ENTER("THD::increment_user_connections_counter"); + + m_user_connect->connections++; + + DBUG_VOID_RETURN; +} + +void THD::decrement_user_connections_counter() +{ + DBUG_ENTER("THD::decrement_user_connections_counter"); + + DBUG_ASSERT(m_user_connect->connections > 0); + m_user_connect->connections--; + + DBUG_VOID_RETURN; +} + +void THD::increment_con_per_hour_counter() +{ + DBUG_ENTER("THD::decrement_conn_per_hour_counter"); + + m_user_connect->conn_per_hour++; + + DBUG_VOID_RETURN; +} + +void THD::increment_updates_counter() +{ + DBUG_ENTER("THD::increment_updates_counter"); + + m_user_connect->updates++; + + DBUG_VOID_RETURN; +} + +void THD::increment_questions_counter() +{ + DBUG_ENTER("THD::increment_updates_counter"); + + m_user_connect->questions++; + + DBUG_VOID_RETURN; +} + +/* + Reset per-hour user resource limits when it has been more than + an hour since they were last checked + + SYNOPSIS: + time_out_user_resource_limits() + + NOTE: + This assumes that the LOCK_user_conn mutex has been acquired, so it is + safe to test and modify members of the USER_CONN structure. +*/ +void THD::time_out_user_resource_limits() +{ + mysql_mutex_assert_owner(&LOCK_user_conn); + ulonglong check_time= start_utime; + DBUG_ENTER("time_out_user_resource_limits"); + + /* If more than a hour since last check, reset resource checking */ + if (check_time - m_user_connect->reset_utime >= LL(3600000000)) + { + m_user_connect->questions=1; + m_user_connect->updates=0; + m_user_connect->conn_per_hour=0; + m_user_connect->reset_utime= check_time; + } + + DBUG_VOID_RETURN; +} diff --git a/sql/sql_class.h b/sql/sql_class.h index bffa490ebe3..d799980f8e1 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1960,7 +1960,26 @@ public: */ ha_rows examined_row_count; - USER_CONN *user_connect; +private: + USER_CONN *m_user_connect; + +public: + void set_user_connect(USER_CONN *uc); + const USER_CONN* get_user_connect() + { return m_user_connect; } + + void increment_user_connections_counter(); + void decrement_user_connections_counter(); + + void increment_con_per_hour_counter(); + + void increment_updates_counter(); + + void increment_questions_counter(); + + void time_out_user_resource_limits(); + +public: CHARSET_INFO *db_charset; Warning_info *warning_info; Diagnostics_area *stmt_da; diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 366dec733c4..cdb0f5de049 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -105,8 +105,8 @@ int get_or_create_user_conn(THD *thd, const char *user, goto end; } } - thd->user_connect=uc; - uc->connections++; + thd->set_user_connect(uc); + thd->increment_user_connections_counter(); end: mysql_mutex_unlock(&LOCK_user_conn); return return_val; @@ -131,7 +131,7 @@ end: 1 error */ -int check_for_max_user_connections(THD *thd, USER_CONN *uc) +int check_for_max_user_connections(THD *thd, const USER_CONN *uc) { int error=0; DBUG_ENTER("check_for_max_user_connections"); @@ -145,7 +145,7 @@ int check_for_max_user_connections(THD *thd, USER_CONN *uc) error=1; goto end; } - time_out_user_resource_limits(thd, uc); + thd->time_out_user_resource_limits(); if (uc->user_resources.user_conn && uc->user_resources.user_conn < uc->connections) { @@ -164,18 +164,18 @@ int check_for_max_user_connections(THD *thd, USER_CONN *uc) error=1; goto end; } - uc->conn_per_hour++; + thd->increment_con_per_hour_counter(); end: if (error) { - uc->connections--; // no need for decrease_user_connections() here + thd->decrement_user_connections_counter(); /* The thread may returned back to the pool and assigned to a user that doesn't have a limit. Ensure the user is not using resources of someone else. */ - thd->user_connect= NULL; + thd->set_user_connect(NULL); } mysql_mutex_unlock(&LOCK_user_conn); DBUG_RETURN(error); @@ -214,38 +214,37 @@ void decrease_user_connections(USER_CONN *uc) DBUG_VOID_RETURN; } - /* - Reset per-hour user resource limits when it has been more than - an hour since they were last checked + Decrements user connections count from the USER_CONN held by THD + And removes USER_CONN from the hash if no body else is using it. - SYNOPSIS: - time_out_user_resource_limits() - thd Thread handler - uc User connection details - - NOTE: - This assumes that the LOCK_user_conn mutex has been acquired, so it is - safe to test and modify members of the USER_CONN structure. -*/ - -void time_out_user_resource_limits(THD *thd, USER_CONN *uc) + SYNOPSIS + release_user_connection() + THD Thread context object. + */ +void release_user_connection(THD *thd) { - ulonglong check_time= thd->start_utime; - DBUG_ENTER("time_out_user_resource_limits"); + const USER_CONN *uc= thd->get_user_connect(); + DBUG_ENTER("release_user_connection"); - /* If more than a hour since last check, reset resource checking */ - if (check_time - uc->reset_utime >= LL(3600000000)) + if (uc) { - uc->questions=1; - uc->updates=0; - uc->conn_per_hour=0; - uc->reset_utime= check_time; + mysql_mutex_lock(&LOCK_user_conn); + DBUG_ASSERT(uc->connections > 0); + thd->decrement_user_connections_counter(); + if (!uc->connections && !mqh_used) + { + /* Last connection for user; Delete it */ + (void) my_hash_delete(&hash_user_connections,(uchar*) uc); + } + mysql_mutex_unlock(&LOCK_user_conn); + thd->set_user_connect(NULL); } DBUG_VOID_RETURN; } + /* Check if maximum queries per hour limit has been reached returns 0 if OK. @@ -254,40 +253,70 @@ void time_out_user_resource_limits(THD *thd, USER_CONN *uc) bool check_mqh(THD *thd, uint check_command) { bool error= 0; - USER_CONN *uc=thd->user_connect; + const USER_CONN *uc=thd->get_user_connect(); DBUG_ENTER("check_mqh"); DBUG_ASSERT(uc != 0); mysql_mutex_lock(&LOCK_user_conn); - time_out_user_resource_limits(thd, uc); + thd->time_out_user_resource_limits(); /* Check that we have not done too many questions / hour */ - if (uc->user_resources.questions && - uc->questions++ >= uc->user_resources.questions) + if (uc->user_resources.questions) { - my_error(ER_USER_LIMIT_REACHED, MYF(0), uc->user, "max_questions", - (long) uc->user_resources.questions); - error=1; - goto end; + thd->increment_questions_counter(); + if ((uc->questions - 1) >= uc->user_resources.questions) + { + my_error(ER_USER_LIMIT_REACHED, MYF(0), uc->user, "max_questions", + (long) uc->user_resources.questions); + error=1; + goto end; + } } if (check_command < (uint) SQLCOM_END) { /* Check that we have not done too many updates / hour */ if (uc->user_resources.updates && - (sql_command_flags[check_command] & CF_CHANGES_DATA) && - uc->updates++ >= uc->user_resources.updates) + (sql_command_flags[check_command] & CF_CHANGES_DATA)) { - my_error(ER_USER_LIMIT_REACHED, MYF(0), uc->user, "max_updates", - (long) uc->user_resources.updates); - error=1; - goto end; + thd->increment_updates_counter(); + if ((uc->updates - 1) >= uc->user_resources.updates) + { + my_error(ER_USER_LIMIT_REACHED, MYF(0), uc->user, "max_updates", + (long) uc->user_resources.updates); + error=1; + goto end; + } } } end: mysql_mutex_unlock(&LOCK_user_conn); DBUG_RETURN(error); } +#else + +int check_for_max_user_connections(THD *thd, const USER_CONN *uc) +{ + return 0; +} + +void decrease_user_connections(USER_CONN *uc) +{ + return; +} + +void release_user_connection(THD *thd) +{ + const USER_CONN *uc= thd->get_user_connect(); + DBUG_ENTER("release_user_connection"); + + if (uc) + { + thd->set_user_connect(NULL); + } + + DBUG_VOID_RETURN; +} #endif /* NO_EMBEDDED_ACCESS_CHECKS */ @@ -609,16 +638,13 @@ void end_connection(THD *thd) { NET *net= &thd->net; plugin_thdvar_cleanup(thd); - if (thd->user_connect) - { - decrease_user_connections(thd->user_connect); - /* - The thread may returned back to the pool and assigned to a user - that doesn't have a limit. Ensure the user is not using resources - of someone else. - */ - thd->user_connect= NULL; - } + + /* + The thread may returned back to the pool and assigned to a user + that doesn't have a limit. Ensure the user is not using resources + of someone else. + */ + release_user_connection(thd); if (thd->killed || (net->error && net->vio != 0)) { diff --git a/sql/sql_connect.h b/sql/sql_connect.h index df6ac789709..2257a970ffa 100644 --- a/sql/sql_connect.h +++ b/sql/sql_connect.h @@ -33,6 +33,7 @@ void reset_mqh(LEX_USER *lu, bool get_them); bool check_mqh(THD *thd, uint check_command); void time_out_user_resource_limits(THD *thd, USER_CONN *uc); void decrease_user_connections(USER_CONN *uc); +void release_user_connection(THD *thd); bool thd_init_client_charset(THD *thd, uint cs_number); bool setup_connection_thread_globals(THD *thd); bool thd_prepare_connection(THD *thd); @@ -47,6 +48,6 @@ void prepare_new_connection_state(THD* thd); void end_connection(THD *thd); int get_or_create_user_conn(THD *thd, const char *user, const char *host, const USER_RESOURCES *mqh); -int check_for_max_user_connections(THD *thd, USER_CONN *uc); +int check_for_max_user_connections(THD *thd, const USER_CONN *uc); #endif /* SQL_CONNECT_INCLUDED */ diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 3e5dfa43d41..ea07bfce0cb 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -949,7 +949,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd, uint save_db_length= thd->db_length; char *save_db= thd->db; - USER_CONN *save_user_connect= thd->user_connect; + USER_CONN *save_user_connect= + const_cast(thd->get_user_connect()); Security_context save_security_ctx= *thd->security_ctx; CHARSET_INFO *save_character_set_client= thd->variables.character_set_client; @@ -964,7 +965,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, { my_free(thd->security_ctx->user); *thd->security_ctx= save_security_ctx; - thd->user_connect= save_user_connect; + thd->set_user_connect(save_user_connect); thd->reset_db (save_db, save_db_length); thd->variables.character_set_client= save_character_set_client; thd->variables.collation_connection= save_collation_connection; @@ -5583,7 +5584,7 @@ void mysql_parse(THD *thd, char *rawbuf, uint length, if (!err) { #ifndef NO_EMBEDDED_ACCESS_CHECKS - if (mqh_used && thd->user_connect && + if (mqh_used && thd->get_user_connect() && check_mqh(thd, lex->sql_command)) { thd->net.error = 0; diff --git a/sql/sys_vars.h b/sql/sys_vars.h index d9d83ed5615..a69a91f7eb7 100644 --- a/sql/sys_vars.h +++ b/sql/sys_vars.h @@ -799,8 +799,9 @@ public: { } uchar *session_value_ptr(THD *thd, LEX_STRING *base) { - if (thd->user_connect && thd->user_connect->user_resources.user_conn) - return (uchar*) &(thd->user_connect->user_resources.user_conn); + const USER_CONN *uc= thd->get_user_connect(); + if (uc && uc->user_resources.user_conn) + return (uchar*) &(uc->user_resources.user_conn); return global_value_ptr(thd, base); } }; From d8b2d4a0694156848db0862a230d248653f8ebe5 Mon Sep 17 00:00:00 2001 From: Rohit Kalhans Date: Tue, 29 May 2012 12:11:30 +0530 Subject: [PATCH 059/289] Bug#11762667: MYSQLBINLOG IGNORES ERRORS WHILE WRITING OUTPUT Problem: mysqlbinlog exits without any error code in case of file write error. It is because of the fact that the calls to Log_event::print() method does not return a value and the thus any error were being ignored. Resolution: We resolve this problem by checking for the IO_CACHE::error == -1 after every call to Log_event:: print() and terminating the further execution. client/mysqlbinlog.cc: - handled error conditions during event->print() calls - added check for error in end_io_cache() mysys/my_write.c: Added debug code to simulate file write error. error returned will be ENOSPC=> error no space on the disk sql/log_event.cc: Added debug code to simulate file write error, by reducing the size of io cache. --- client/mysqlbinlog.cc | 21 ++++++++++++++++++++- mysys/my_write.c | 12 +++++++++++- sql/log_event.cc | 6 ++++++ 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index db48675ade2..dd09e7a0938 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -690,6 +690,7 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, DBUG_ENTER("process_event"); print_event_info->short_form= short_form; Exit_status retval= OK_CONTINUE; + IO_CACHE *const head= &print_event_info->head_cache; /* Format events are not concerned by --offset and such, we always need to @@ -753,6 +754,8 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, } else ev->print(result_file, print_event_info); + if (head->error == -1) + goto err; break; case CREATE_FILE_EVENT: @@ -804,6 +807,8 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, output of Append_block_log_event::print is only a comment. */ ev->print(result_file, print_event_info); + if (head->error == -1) + goto err; if ((retval= load_processor.process((Append_block_log_event*) ev)) != OK_CONTINUE) goto end; @@ -812,6 +817,8 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, case EXEC_LOAD_EVENT: { ev->print(result_file, print_event_info); + if (head->error == -1) + goto err; Execute_load_log_event *exv= (Execute_load_log_event*)ev; Create_file_log_event *ce= load_processor.grab_event(exv->file_id); /* @@ -841,6 +848,8 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, print_event_info->common_header_len= glob_description_event->common_header_len; ev->print(result_file, print_event_info); + if (head->error == -1) + goto err; if (!remote_opt) ev->free_temp_buf(); // free memory allocated in dump_local_log_entries else @@ -864,6 +873,8 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, break; case BEGIN_LOAD_QUERY_EVENT: ev->print(result_file, print_event_info); + if (head->error == -1) + goto err; if ((retval= load_processor.process((Begin_load_query_log_event*) ev)) != OK_CONTINUE) goto end; @@ -974,6 +985,8 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, } default: ev->print(result_file, print_event_info); + if (head->error == -1) + goto err; } } @@ -2012,7 +2025,13 @@ err: end: if (fd >= 0) my_close(fd, MYF(MY_WME)); - end_io_cache(file); + /* + Since the end_io_cache() writes to the + file errors may happen. + */ + if (end_io_cache(file)) + retval= ERROR_STOP; + return retval; } diff --git a/mysys/my_write.c b/mysys/my_write.c index f261c768dcb..b545ab776b0 100644 --- a/mysys/my_write.c +++ b/mysys/my_write.c @@ -38,7 +38,17 @@ size_t my_write(int Filedes, const uchar *Buffer, size_t Count, myf MyFlags) for (;;) { - if ((writenbytes= write(Filedes, Buffer, Count)) == Count) + writenbytes= write(Filedes, Buffer, Count); + /** + To simulate the write error set the errno = error code + and the number pf written bytes to -1. + */ + DBUG_EXECUTE_IF ("simulate_file_write_error", + { + errno= ENOSPC; + writenbytes= (size_t) -1; + }); + if (writenbytes == Count) break; if (writenbytes != (size_t) -1) { /* Safeguard */ diff --git a/sql/log_event.cc b/sql/log_event.cc index afcc283a6d1..e7c3419c34f 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -3090,6 +3090,12 @@ void Query_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info) { Write_on_release_cache cache(&print_event_info->head_cache, file); + /** + reduce the size of io cache so that the write function is called + for every call to my_b_write(). + */ + DBUG_EXECUTE_IF ("simulate_file_write_error", + {(&cache)->write_pos= (&cache)->write_end- 500;}); print_query_header(&cache, print_event_info); my_b_write(&cache, (uchar*) query, q_len); my_b_printf(&cache, "\n%s\n", print_event_info->delimiter); From 31a93ea75d00b54326e7f1975dccafdad4e35c5e Mon Sep 17 00:00:00 2001 From: Tor Didriksen Date: Tue, 29 May 2012 10:54:57 +0200 Subject: [PATCH 060/289] Bug#12845091 .EMPTY FILE IN /DATA/TEST PREVENTS USERS FROM DROPPING TEST DB ON 5.5 AND 5.6 --- sql/CMakeLists.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 09672561c11..a3df9e7948b 100644 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -264,7 +264,10 @@ IF(INSTALL_LAYOUT STREQUAL "STANDALONE") # We need to create empty directories (data/test) the installation. # This does not work with current CPack due to http://www.cmake.org/Bug/view.php?id=8767 # Avoid completely empty directories and install dummy file instead. -SET(DUMMY_FILE ${CMAKE_CURRENT_BINARY_DIR}/.empty ) +# Use a file extension so that it will be deleted in case someone does +# 'drop database test' +# See deletable_extentions. +SET(DUMMY_FILE ${CMAKE_CURRENT_BINARY_DIR}/dummy.bak ) FILE(WRITE ${DUMMY_FILE} "") INSTALL(FILES ${DUMMY_FILE} DESTINATION data/test COMPONENT DataFiles) From a2bc9b36696efb97879bc1bd4500156ea52a1b1a Mon Sep 17 00:00:00 2001 From: Annamalai Gurusami Date: Wed, 30 May 2012 10:05:04 +0530 Subject: [PATCH 061/289] Bug #13933132: [ERROR] GOT ERROR -1 WHEN READING TABLE APPEARED WHEN KILLING Suppose there is a query waiting for a lock. If the user kills this query, then "Got error -1 when reading table" error message must not be logged in the server log file. Since this is a user requested interruption, no spurious error message must be logged in the server log. This patch will remove the error message from the log. approved by joh and tatjana --- sql/sql_select.cc | 3 ++- storage/innobase/handler/ha_innodb.cc | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 1cf52e88c12..7c3d2de22bc 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -11791,7 +11791,8 @@ int report_error(TABLE *table, int error) Locking reads can legally return also these errors, do not print them to the .err log */ - if (error != HA_ERR_LOCK_DEADLOCK && error != HA_ERR_LOCK_WAIT_TIMEOUT) + if (error != HA_ERR_LOCK_DEADLOCK && error != HA_ERR_LOCK_WAIT_TIMEOUT + && !table->in_use->killed) sql_print_error("Got error %d when reading table '%s'", error, table->s->path.str); table->file->print_error(error,MYF(0)); diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 8ed082037f0..51b7007145c 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -4893,6 +4893,7 @@ ha_innobase::index_read( ulint ret; DBUG_ENTER("index_read"); + DEBUG_SYNC_C("ha_innobase_index_read_begin"); ut_a(prebuilt->trx == thd_to_trx(user_thd)); ut_ad(key_len != 0 || find_flag != HA_READ_KEY_EXACT); From 96eb519eb77b078f9f96935aacaded44e20ed95c Mon Sep 17 00:00:00 2001 From: Rohit Kalhans Date: Wed, 30 May 2012 13:54:15 +0530 Subject: [PATCH 062/289] Fixing the build failure on Windows debug build. --- sql/log_event.cc | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/sql/log_event.cc b/sql/log_event.cc index e7c3419c34f..a79797e4bc9 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -2852,17 +2852,24 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, sql_parse.cc */ +#if !defined(MYSQL_CLIENT) && defined(HAVE_QUERY_CACHE) if (!(start= data_buf = (Log_event::Byte*) my_malloc(catalog_len + 1 + time_zone_len + 1 + user.length + 1 + host.length + 1 + data_len + 1 -#if !defined(MYSQL_CLIENT) && defined(HAVE_QUERY_CACHE) - + sizeof(size_t)//for db_len - + db_len + 1 - + QUERY_CACHE_FLAGS_SIZE + + sizeof(size_t)//for db_len + + db_len + 1 + + QUERY_CACHE_FLAGS_SIZE, + MYF(MY_WME)))) +#else + if (!(start= data_buf = (Log_event::Byte*) my_malloc(catalog_len + 1 + + time_zone_len + 1 + + user.length + 1 + + host.length + 1 + + data_len + 1, + MYF(MY_WME)))) #endif - , MYF(MY_WME)))) DBUG_VOID_RETURN; if (catalog_len) // If catalog is given { From f8a6521789eadeebc64c3001a1d5f04ef3c31a2e Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 30 May 2012 14:00:29 +0530 Subject: [PATCH 063/289] From f20a4c912dd1034d17f094804a15e0f4807922dd Mon Sep 17 00:00:00 2001 From: Tor Didriksen Date: Wed, 30 May 2012 12:47:29 +0200 Subject: [PATCH 064/289] Bug#12845091 .EMPTY FILE IN /DATA/TEST PREVENTS USERS FROM DROPPING TEST DB ON 5.5 AND 5.6 For those who build in-source, we need to change .bzrignore: s/.empty/dummy.bak/ --- .bzrignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.bzrignore b/.bzrignore index c54083a4209..655cea20bc5 100644 --- a/.bzrignore +++ b/.bzrignore @@ -3059,7 +3059,7 @@ libmysql/merge_archives_mysqlclient.cmake libmysqld/merge_archives_mysqlserver.cmake libmysqld/mysqlserver_depends.c libmysqld/examples/mysql_embedded -sql/.empty +sql/dummy.bak mysys/thr_lock VERSION.dep info_macros.cmake From 367de4de2d62310fd0546a3fa1fab1e2b69b35b3 Mon Sep 17 00:00:00 2001 From: Nuno Carvalho Date: Wed, 30 May 2012 14:55:13 +0100 Subject: [PATCH 065/289] BUG#14135691: MISSING INITIALIZATION OF MYSQL_BIN_LOG::SYNC_COUNTER MYSQL_BIN_LOG::sync_counter is not initialized on MYSQL_BIN_LOG object creation. Added missing sync_counter initialization. --- sql/log.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/log.cc b/sql/log.cc index 7f629658311..24cee143c71 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -2814,7 +2814,7 @@ const char *MYSQL_LOG::generate_name(const char *log_name, MYSQL_BIN_LOG::MYSQL_BIN_LOG(uint *sync_period) :bytes_written(0), prepared_xids(0), file_id(1), open_count(1), need_start_event(TRUE), - sync_period_ptr(sync_period), + sync_period_ptr(sync_period), sync_counter(0), is_relay_log(0), signal_cnt(0), description_event_for_exec(0), description_event_for_queue(0) { From 70d01f5182429751171b71246ef0e3fea30667af Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 31 May 2012 14:32:29 +0530 Subject: [PATCH 066/289] From cf48fcfba33c3c48aa52290a33a7b825e89827c2 Mon Sep 17 00:00:00 2001 From: Marc Alff Date: Thu, 31 May 2012 11:47:13 +0200 Subject: [PATCH 067/289] Bug 14116252 - CANNOT BUILD ARCHIVE ENGINE WHEN WITH_PERFSCHEMA_STORAGE_ENGINE=0 Fixed a build break with compiling without the performance schema, instrumentation should be protected by HAVE_PSI_INTERFACE --- storage/archive/azio.c | 2 ++ storage/archive/ha_archive.cc | 2 ++ 2 files changed, 4 insertions(+) diff --git a/storage/archive/azio.c b/storage/archive/azio.c index ec4b5bcb7cd..15b3434ab32 100644 --- a/storage/archive/azio.c +++ b/storage/archive/azio.c @@ -37,7 +37,9 @@ void putLong(File file, uLong x); uLong getLong(azio_stream *s); void read_header(azio_stream *s, unsigned char *buffer); +#ifdef HAVE_PSI_INTERFACE extern PSI_file_key arch_key_file_data; +#endif /* =========================================================================== Opens a gzip (.gz) file for reading or writing. The mode parameter diff --git a/storage/archive/ha_archive.cc b/storage/archive/ha_archive.cc index dba647b8d1a..24dbaefce27 100644 --- a/storage/archive/ha_archive.cc +++ b/storage/archive/ha_archive.cc @@ -114,7 +114,9 @@ static HASH archive_open_tables; #define DATA_BUFFER_SIZE 2 // Size of the data used in the data file #define ARCHIVE_CHECK_HEADER 254 // The number we use to determine corruption +#ifdef HAVE_PSI_INTERFACE extern "C" PSI_file_key arch_key_file_data; +#endif /* Static declarations for handerton */ static handler *archive_create_handler(handlerton *hton, From 2ebd927ec0ba2de6219dc23a01c3988273302b3e Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 31 May 2012 22:28:18 +0530 Subject: [PATCH 068/289] From 1c0388a5be8346a0a2c0e00caaf2a9c11f26830c Mon Sep 17 00:00:00 2001 From: Jon Olav Hauglid Date: Fri, 1 Jun 2012 09:31:24 +0200 Subject: [PATCH 069/289] Bug#13982017: ALTER TABLE RENAME ENDS UP WITH ERROR 1050 (42S01) Fixed by backport of: ------------------------------------------------------------ revno: 3402.50.156 committer: Jon Olav Hauglid branch nick: mysql-trunk-test timestamp: Wed 2012-02-08 14:10:23 +0100 message: Bug#13417754 ASSERT IN ROW_DROP_DATABASE_FOR_MYSQL DURING DROP SCHEMA This assert could be triggered if an InnoDB table was being moved to a different database using ALTER TABLE ... RENAME, while this database concurrently was being dropped by DROP DATABASE. The reason for the problem was that no metadata lock was taken on the target database by ALTER TABLE ... RENAME. DROP DATABASE was therefore not blocked and could remove the database while ALTER TABLE ... RENAME was executing. This could cause the assert in InnoDB to be triggered. This patch fixes the problem by taking a IX metadata lock on the target database before ALTER TABLE ... RENAME starts moving a table to a different database. Note that this problem did not occur with RENAME TABLE which already takes the correct metadata locks. Also note that this patch slightly changes the behavior of ALTER TABLE ... RENAME. Before, the statement would abort and return an error if a lock on the target table name could not be taken immediately. With this patch, ALTER TABLE ... RENAME will instead block and wait until the lock can be taken (or until we get a lock timeout). This also means that it is possible to get ER_LOCK_DEADLOCK errors in this situation since we allow ALTER TABLE ... RENAME to wait and not just abort immediately. --- mysql-test/r/create-big.result | 4 ++-- mysql-test/t/create-big.test | 27 ++++++++++++++++++++++---- sql/sql_table.cc | 28 ++++++++++++++++++++------- storage/innobase/handler/ha_innodb.cc | 3 +++ 4 files changed, 49 insertions(+), 13 deletions(-) diff --git a/mysql-test/r/create-big.result b/mysql-test/r/create-big.result index 34293d7e5cd..4cce5d8618c 100644 --- a/mysql-test/r/create-big.result +++ b/mysql-test/r/create-big.result @@ -53,8 +53,8 @@ set debug_sync='create_table_select_before_create SIGNAL parked WAIT_FOR go'; create table t1 select 1 as i;; set debug_sync='now WAIT_FOR parked'; alter table t3 rename to t1; -ERROR 42S01: Table 't1' already exists set debug_sync='now SIGNAL go'; +ERROR 42S01: Table 't1' already exists show create table t1; Table Create Table t1 CREATE TABLE `t1` ( @@ -65,8 +65,8 @@ set debug_sync='create_table_select_before_create SIGNAL parked WAIT_FOR go'; create table t1 select 1 as i;; set debug_sync='now WAIT_FOR parked'; alter table t3 rename to t1, add k int; -ERROR 42S01: Table 't1' already exists set debug_sync='now SIGNAL go'; +ERROR 42S01: Table 't1' already exists show create table t1; Table Create Table t1 CREATE TABLE `t1` ( diff --git a/mysql-test/t/create-big.test b/mysql-test/t/create-big.test index d487608f7e1..8d916f8da82 100644 --- a/mysql-test/t/create-big.test +++ b/mysql-test/t/create-big.test @@ -132,11 +132,20 @@ set debug_sync='create_table_select_before_create SIGNAL parked WAIT_FOR go'; --send create table t1 select 1 as i; connection addconroot1; set debug_sync='now WAIT_FOR parked'; ---error ER_TABLE_EXISTS_ERROR -alter table t3 rename to t1; +--send alter table t3 rename to t1 +connection addconroot2; +# Wait until the above ALTER TABLE RENAME is blocked due to CREATE +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Waiting for table metadata lock" and + info = "alter table t3 rename to t1"; +--source include/wait_condition.inc set debug_sync='now SIGNAL go'; connection default; --reap +connection addconroot1; +--error ER_TABLE_EXISTS_ERROR +--reap connection default; show create table t1; drop table t1; @@ -146,11 +155,21 @@ set debug_sync='create_table_select_before_create SIGNAL parked WAIT_FOR go'; --send create table t1 select 1 as i; connection addconroot1; set debug_sync='now WAIT_FOR parked'; ---error ER_TABLE_EXISTS_ERROR -alter table t3 rename to t1, add k int; +--send alter table t3 rename to t1, add k int +connection addconroot2; +# Wait until the above ALTER TABLE RENAME is blocked due to CREATE +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Waiting for table metadata lock" and + info = "alter table t3 rename to t1, add k int"; +--source include/wait_condition.inc set debug_sync='now SIGNAL go'; connection default; --reap +connection addconroot1; +--error ER_TABLE_EXISTS_ERROR +--reap +connection default; show create table t1; drop table t1,t3; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index c146079fdb3..60ae2ed800b 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -5872,8 +5872,26 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, } else { + MDL_request_list mdl_requests; + MDL_request target_db_mdl_request; + target_mdl_request.init(MDL_key::TABLE, new_db, new_name, MDL_EXCLUSIVE, MDL_TRANSACTION); + mdl_requests.push_front(&target_mdl_request); + + /* + If we are moving the table to a different database, we also + need IX lock on the database name so that the target database + is protected by MDL while the table is moved. + */ + if (new_db != db) + { + target_db_mdl_request.init(MDL_key::SCHEMA, new_db, "", + MDL_INTENTION_EXCLUSIVE, + MDL_TRANSACTION); + mdl_requests.push_front(&target_db_mdl_request); + } + /* Global intention exclusive lock must have been already acquired when table to be altered was open, so there is no need to do it here. @@ -5882,14 +5900,10 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, "", "", MDL_INTENTION_EXCLUSIVE)); - if (thd->mdl_context.try_acquire_lock(&target_mdl_request)) + if (thd->mdl_context.acquire_locks(&mdl_requests, + thd->variables.lock_wait_timeout)) DBUG_RETURN(TRUE); - if (target_mdl_request.ticket == NULL) - { - /* Table exists and is locked by some thread. */ - my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias); - DBUG_RETURN(TRUE); - } + DEBUG_SYNC(thd, "locked_table_name"); /* Table maybe does not exist, but we got an exclusive lock diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 19644ddc966..9f7290f5b2d 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -47,6 +47,7 @@ this program; if not, write to the Free Software Foundation, Inc., #include // PROCESS_ACL #include +#include // DEBUG_SYNC #include #include #include @@ -7691,6 +7692,8 @@ ha_innobase::rename_table( error = innobase_rename_table(trx, from, to, TRUE); + DEBUG_SYNC(thd, "after_innobase_rename_table"); + /* Tell the InnoDB server that there might be work for utility threads: */ From a28a2ca798e8a4912cf1b91b6e71eaa0a9fb8bb7 Mon Sep 17 00:00:00 2001 From: Annamalai Gurusami Date: Fri, 1 Jun 2012 14:12:57 +0530 Subject: [PATCH 070/289] Bug #13933132: [ERROR] GOT ERROR -1 WHEN READING TABLE APPEARED WHEN KILLING Suppose there is a query waiting for a lock. If the user kills this query, then "Got error -1 when reading table" error message must not be logged in the server log file. Since this is a user requested interruption, no spurious error message must be logged in the server log. This patch will remove the error message from the log. approved by joh and tatjana --- sql/sql_select.cc | 3 ++- storage/innobase/handler/ha_innodb.cc | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 1cf52e88c12..7c3d2de22bc 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -11791,7 +11791,8 @@ int report_error(TABLE *table, int error) Locking reads can legally return also these errors, do not print them to the .err log */ - if (error != HA_ERR_LOCK_DEADLOCK && error != HA_ERR_LOCK_WAIT_TIMEOUT) + if (error != HA_ERR_LOCK_DEADLOCK && error != HA_ERR_LOCK_WAIT_TIMEOUT + && !table->in_use->killed) sql_print_error("Got error %d when reading table '%s'", error, table->s->path.str); table->file->print_error(error,MYF(0)); diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 8ed082037f0..51b7007145c 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -4893,6 +4893,7 @@ ha_innobase::index_read( ulint ret; DBUG_ENTER("index_read"); + DEBUG_SYNC_C("ha_innobase_index_read_begin"); ut_a(prebuilt->trx == thd_to_trx(user_thd)); ut_ad(key_len != 0 || find_flag != HA_READ_KEY_EXACT); From a8b2e831f06d37e1de9a8bd3bd9fee5e0a1e9b6a Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Mon, 4 Jun 2012 19:48:53 +0400 Subject: [PATCH 071/289] MDEV-305: SHOW EXPLAIN: ref returned by SHOW EXPLAIN is different from the normal EXPLAIN ('const' vs empty string) - The problem was that create_ref_for_key() would act differently, depending on whether we're running EXPLAIN or the actual query. - As the first step, fixed the EXPLAIN printout not to depend on actions in create_ref_for_key(). --- mysql-test/r/show_explain.result | 31 +++++++++++++++++++++++-------- mysql-test/t/show_explain.test | 29 ++++++++++++++++++++++++++--- sql/sql_select.cc | 16 +++++++++++++--- sql/sql_select.h | 7 +++++++ 4 files changed, 69 insertions(+), 14 deletions(-) diff --git a/mysql-test/r/show_explain.result b/mysql-test/r/show_explain.result index 51c2a7341ee..18fd01e3284 100644 --- a/mysql-test/r/show_explain.result +++ b/mysql-test/r/show_explain.result @@ -448,7 +448,7 @@ WHERE pk= (SELECT MAX(pk) FROM t2 WHERE pk = 3) show explain for $thr2; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 ALL NULL NULL NULL NULL 20 Using where -2 SUBQUERY t2 const PRIMARY PRIMARY 4 1 Using where +2 SUBQUERY t2 const PRIMARY PRIMARY 4 const 1 Using where 3 SUBQUERY NULL NULL NULL NULL NULL NULL NULL Select tables optimized away Warnings: Note 1003 SELECT * FROM t2 WHERE a = @@ -521,9 +521,7 @@ INSERT INTO t2 VALUES (1,5),(2,4),(3,6),(4,9),(5,2),(6,8),(7,4),(8,8),(9,0),(10,43), (11,23),(12,3),(13,45),(14,16),(15,2),(16,33),(17,2),(18,5),(19,9),(20,2); set @show_explain_probe_select_id=1; -set debug='d,show_explain_probe_join_exec_end'; -Warnings: -Warning 1287 The syntax '@@debug' is deprecated and will be removed in MariaDB 5.6. Please use '@@debug_dbug' instead +set debug_dbug='d,show_explain_probe_join_exec_end'; SELECT * FROM t2 WHERE (5, 78) IN (SELECT `a1`, MAX(`a1`) FROM t2 GROUP BY `a1`); show explain for $thr2; id select_type table type possible_keys key key_len ref rows Extra @@ -531,8 +529,25 @@ id select_type table type possible_keys key key_len ref rows Extra Warnings: Note 1003 SELECT * FROM t2 WHERE (5, 78) IN (SELECT `a1`, MAX(`a1`) FROM t2 GROUP BY `a1`) pk a1 -set debug=''; -Warnings: -Warning 1287 The syntax '@@debug' is deprecated and will be removed in MariaDB 5.6. Please use '@@debug_dbug' instead +set debug_dbug=''; DROP TABLE t2; -drop table t0,t1; +DROP TABLE t1; +# +# MDEV-305: SHOW EXPLAIN: ref returned by SHOW EXPLAIN is different from the normal EXPLAIN ('const' vs empty string) +# +CREATE TABLE t1(a INT, KEY(a)); +INSERT INTO t1 VALUES (3),(1),(5),(1); +set @show_explain_probe_select_id=1; +set debug_dbug='d,show_explain_probe_join_exec_start'; +SELECT 'test' FROM t1 WHERE a=1; +show explain for $thr2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref a a 5 const 1 Using index +Warnings: +Note 1003 SELECT 'test' FROM t1 WHERE a=1 +test +test +test +set debug_dbug=''; +DROP TABLE t1; +drop table t0; diff --git a/mysql-test/t/show_explain.test b/mysql-test/t/show_explain.test index 57f0c48db3a..6c087a3c0fc 100644 --- a/mysql-test/t/show_explain.test +++ b/mysql-test/t/show_explain.test @@ -508,7 +508,7 @@ INSERT INTO t2 VALUES (11,23),(12,3),(13,45),(14,16),(15,2),(16,33),(17,2),(18,5),(19,9),(20,2); set @show_explain_probe_select_id=1; -set debug='d,show_explain_probe_join_exec_end'; +set debug_dbug='d,show_explain_probe_join_exec_end'; send SELECT * FROM t2 WHERE (5, 78) IN (SELECT `a1`, MAX(`a1`) FROM t2 GROUP BY `a1`); connection default; @@ -516,10 +516,33 @@ connection default; evalp show explain for $thr2; connection con1; reap; -set debug=''; +set debug_dbug=''; DROP TABLE t2; +DROP TABLE t1; + +--echo # +--echo # MDEV-305: SHOW EXPLAIN: ref returned by SHOW EXPLAIN is different from the normal EXPLAIN ('const' vs empty string) +--echo # +CREATE TABLE t1(a INT, KEY(a)); +INSERT INTO t1 VALUES (3),(1),(5),(1); + +set @show_explain_probe_select_id=1; +set debug_dbug='d,show_explain_probe_join_exec_start'; + +send SELECT 'test' FROM t1 WHERE a=1; +connection default; +--source include/wait_condition.inc +evalp show explain for $thr2; +connection con1; +reap; +set debug_dbug=''; + +DROP TABLE t1; + + + ## TODO: Test this: have several SHOW EXPLAIN requests be queued up for a ## thread and served together. @@ -527,4 +550,4 @@ DROP TABLE t2; ## TODO: SHOW EXPLAIN while the primary query is running EXPLAIN EXTENDED/PARTITIONS ## -drop table t0,t1; +drop table t0; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 070c5eb9e8c..e1086342636 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -7905,6 +7905,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, j->ref.null_rejecting= 0; j->ref.disable_cache= FALSE; j->ref.null_ref_part= NO_REF_PART; + j->ref.const_ref_part_map= 0; keyuse=org_keyuse; store_key **ref_key= j->ref.key_copy; @@ -7952,6 +7953,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, if (thd->is_fatal_error) DBUG_RETURN(TRUE); tmp.copy(); + j->ref.const_ref_part_map |= key_part_map(1) << i ; } else *ref_key++= get_store_key(thd, @@ -21521,13 +21523,21 @@ int JOIN::print_explain(select_result_sink *result, uint8 explain_flags, length= (longlong10_to_str(key_len, keylen_str_buf, 10) - keylen_str_buf); tmp3.append(keylen_str_buf, length, cs); - if (tab->ref.key_parts) + if (tab->ref.key_parts && tab_type != JT_FT) { - for (store_key **ref=tab->ref.key_copy ; *ref ; ref++) + store_key **ref=tab->ref.key_copy; + for (uint kp= 0; kp < tab->ref.key_parts; kp++) { if (tmp4.length()) tmp4.append(','); - tmp4.append((*ref)->name(), strlen((*ref)->name()), cs); + + if ((key_part_map(1) << kp) & tab->ref.const_ref_part_map) + tmp4.append("const"); + else + { + tmp4.append((*ref)->name(), strlen((*ref)->name()), cs); + ref++; + } } } } diff --git a/sql/sql_select.h b/sql/sql_select.h index 00af5e14607..84d7529de49 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -101,6 +101,13 @@ typedef struct st_table_ref uchar *key_buff; ///< value to look for with key uchar *key_buff2; ///< key_buff+key_length store_key **key_copy; // + + /* + Bitmap of key parts which refer to constants. key_copy only has copiers for + non-const key parts. + */ + key_part_map const_ref_part_map; + Item **items; ///< val()'s for each keypart /* Array of pointers to trigger variables. Some/all of the pointers may be From 13e985787e4459e867fe028018f2638326c6d52f Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Mon, 4 Jun 2012 20:07:02 +0400 Subject: [PATCH 072/289] Added comments about create_ref_for_key() --- sql/sql_select.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index e1086342636..42f475e2904 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -7941,6 +7941,13 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, if (keyuse->null_rejecting) j->ref.null_rejecting |= 1 << i; keyuse_uses_no_tables= keyuse_uses_no_tables && !keyuse->used_tables; + /* + Todo: we should remove this check for thd->lex->describe on the next + line. With SHOW EXPLAIN code, EXPLAIN printout code no longer depends + on it. However, removing the check caused change in lots of query + plans! Does the optimizer depend on the contents of + table_ref->key_copy ? If yes, do we produce incorrect EXPLAINs? + */ if (!keyuse->val->used_tables() && !thd->lex->describe) { // Compare against constant store_key_item tmp(thd, From 9a7b3bf4b7b08f9fd1d26260131696475998ab81 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Mon, 4 Jun 2012 23:37:45 +0400 Subject: [PATCH 073/289] MDEV-299: SHOW EXPLAIN: Plan produced by SHOW EXPLAIN changes back and forth during query execution - Make SHOW EXPLAIN ignore range accesses when printing "Range checked for each record" plans. --- mysql-test/r/show_explain.result | 46 ++++++++++++++++++++++++++++++++ mysql-test/t/show_explain.test | 38 ++++++++++++++++++++++++++ sql/sql_select.cc | 26 ++++++++++++------ 3 files changed, 102 insertions(+), 8 deletions(-) diff --git a/mysql-test/r/show_explain.result b/mysql-test/r/show_explain.result index 18fd01e3284..515118b1cd8 100644 --- a/mysql-test/r/show_explain.result +++ b/mysql-test/r/show_explain.result @@ -550,4 +550,50 @@ test test set debug_dbug=''; DROP TABLE t1; +# +# MDEV-299: SHOW EXPLAIN: Plan produced by SHOW EXPLAIN changes back and forth during query execution +# +create table t1 (key1 int, col1 int, col2 int, filler char(100), key(key1)); +insert into t1 select A.a+ 10 * B.a, 10, 10, 'filler-data' from t0 A, t0 B; +update t1 set col1=3, col2=10 where key1=1; +update t1 set col1=3, col2=1000 where key1=2; +update t1 set col1=3, col2=10 where key1=3; +update t1 set col1=3, col2=1000 where key1=4; +set @tmp_mdev299_jcl= @@join_cache_level; +set join_cache_level=0; +explain select count(*) from t1 A, t1 B where B.key1 < A.col2 and A.col1=3 AND B.col2 + 1 < 100; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE A ALL NULL NULL NULL NULL 100 Using where +1 SIMPLE B ALL key1 NULL NULL NULL 100 Range checked for each record (index map: 0x1) +set @show_explain_probe_select_id=1; +set debug_dbug='d,show_explain_probe_test_if_quick_select'; +select count(*) from t1 A, t1 B where B.key1 < A.col2 and A.col1=3 AND B.col2 + 1 < 100; +show explain for $thr2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE A ALL NULL NULL NULL NULL 100 Using where +1 SIMPLE B ALL key1 NULL NULL NULL 100 Range checked for each record (index map: 0x1) +Warnings: +Note 1003 select count(*) from t1 A, t1 B where B.key1 < A.col2 and A.col1=3 AND B.col2 + 1 < 100 +show explain for $thr2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE A ALL NULL NULL NULL NULL 100 Using where +1 SIMPLE B ALL key1 NULL NULL NULL 100 Range checked for each record (index map: 0x1) +Warnings: +Note 1003 select count(*) from t1 A, t1 B where B.key1 < A.col2 and A.col1=3 AND B.col2 + 1 < 100 +show explain for $thr2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE A ALL NULL NULL NULL NULL 100 Using where +1 SIMPLE B ALL key1 NULL NULL NULL 100 Range checked for each record (index map: 0x1) +Warnings: +Note 1003 select count(*) from t1 A, t1 B where B.key1 < A.col2 and A.col1=3 AND B.col2 + 1 < 100 +show explain for $thr2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE A ALL NULL NULL NULL NULL 100 Using where +1 SIMPLE B ALL key1 NULL NULL NULL 100 Range checked for each record (index map: 0x1) +Warnings: +Note 1003 select count(*) from t1 A, t1 B where B.key1 < A.col2 and A.col1=3 AND B.col2 + 1 < 100 +count(*) +212 +set debug_dbug=''; +drop table t1; drop table t0; diff --git a/mysql-test/t/show_explain.test b/mysql-test/t/show_explain.test index 6c087a3c0fc..2baccea93be 100644 --- a/mysql-test/t/show_explain.test +++ b/mysql-test/t/show_explain.test @@ -542,6 +542,44 @@ set debug_dbug=''; DROP TABLE t1; +--echo # +--echo # MDEV-299: SHOW EXPLAIN: Plan produced by SHOW EXPLAIN changes back and forth during query execution +--echo # + +create table t1 (key1 int, col1 int, col2 int, filler char(100), key(key1)); +insert into t1 select A.a+ 10 * B.a, 10, 10, 'filler-data' from t0 A, t0 B; + +# Make matches 3 records +update t1 set col1=3, col2=10 where key1=1; # small range +update t1 set col1=3, col2=1000 where key1=2; # big range +update t1 set col1=3, col2=10 where key1=3; # small range again +update t1 set col1=3, col2=1000 where key1=4; # big range + +set @tmp_mdev299_jcl= @@join_cache_level; +set join_cache_level=0; + +explain select count(*) from t1 A, t1 B where B.key1 < A.col2 and A.col1=3 AND B.col2 + 1 < 100; + +set @show_explain_probe_select_id=1; +set debug_dbug='d,show_explain_probe_test_if_quick_select'; + +send +select count(*) from t1 A, t1 B where B.key1 < A.col2 and A.col1=3 AND B.col2 + 1 < 100; + +connection default; +--source include/wait_condition.inc +evalp show explain for $thr2; +--source include/wait_condition.inc +evalp show explain for $thr2; +--source include/wait_condition.inc +evalp show explain for $thr2; +--source include/wait_condition.inc +evalp show explain for $thr2; +connection con1; +reap; + +set debug_dbug=''; +drop table t1; ## TODO: Test this: have several SHOW EXPLAIN requests be queued up for a diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 42f475e2904..aba5c0761c8 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -16912,6 +16912,14 @@ int read_first_record_seq(JOIN_TAB *tab) static int test_if_quick_select(JOIN_TAB *tab) { + DBUG_EXECUTE_IF("show_explain_probe_test_if_quick_select", + if (dbug_user_var_equals_int(tab->join->thd, + "show_explain_probe_select_id", + tab->join->select_lex->select_number)) + dbug_serve_apcs(tab->join->thd, 1); + ); + + delete tab->select->quick; tab->select->quick=0; return tab->select->test_quick_select(tab->join->thd, tab->keys, @@ -21410,6 +21418,7 @@ int JOIN::print_explain(select_result_sink *result, uint8 explain_flags, tmp3.length(0); tmp4.length(0); quick_type= -1; + QUICK_SELECT_I *quick= NULL; /* Don't show eliminated tables */ if (table->map & join->eliminated_tables) @@ -21428,8 +21437,9 @@ int JOIN::print_explain(select_result_sink *result, uint8 explain_flags, enum join_type tab_type= tab->type; if ((tab->type == JT_ALL || tab->type == JT_HASH) && - tab->select && tab->select->quick) + tab->select && tab->select->quick && tab->use_quick != 2) { + quick= tab->select->quick; quick_type= tab->select->quick->get_type(); if ((quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE) || (quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_INTERSECT) || @@ -21568,9 +21578,9 @@ int JOIN::print_explain(select_result_sink *result, uint8 explain_flags, tab->select && tab->select->quick) =======*/ } - if (tab->type != JT_CONST && tab->select && tab->select->quick) + if (tab->type != JT_CONST && tab->select && quick) tab->select->quick->add_keys_and_lengths(&tmp2, &tmp3); - if (key_info || (tab->select && tab->select->quick)) + if (key_info || (tab->select && quick)) { if (tmp2.length()) item_list.push_back(new Item_string(tmp2.ptr(),tmp2.length(),cs)); @@ -21631,8 +21641,8 @@ int JOIN::print_explain(select_result_sink *result, uint8 explain_flags, else { ha_rows examined_rows; - if (tab->select && tab->select->quick) - examined_rows= tab->select->quick->records; + if (tab->select && quick) + examined_rows= quick->records; else if (tab_type == JT_NEXT || tab_type == JT_ALL || is_hj) { if (tab->limit) @@ -21676,7 +21686,7 @@ int JOIN::print_explain(select_result_sink *result, uint8 explain_flags, table->covering_keys.is_set(tab->index)) key_read=1; if (quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT && - !((QUICK_ROR_INTERSECT_SELECT*)tab->select->quick)->need_to_fetch_row) + !((QUICK_ROR_INTERSECT_SELECT*)quick)->need_to_fetch_row) key_read=1; if (tab->info) @@ -21704,8 +21714,8 @@ int JOIN::print_explain(select_result_sink *result, uint8 explain_flags, uint keyno= MAX_KEY; if (tab->ref.key_parts) keyno= tab->ref.key; - else if (tab->select && tab->select->quick) - keyno = tab->select->quick->index; + else if (tab->select && quick) + keyno = quick->index; if (keyno != MAX_KEY && keyno == table->file->pushed_idx_cond_keyno && table->file->pushed_idx_cond) From 6e2ce8739c76fff5d5cf6ef9b7c9ae9dc157fc21 Mon Sep 17 00:00:00 2001 From: Tor Didriksen Date: Tue, 5 Jun 2012 12:27:20 +0200 Subject: [PATCH 074/289] Bug#13417440 : 63340: ARCHIVE FILE IO NOT INSTRUMENTED Followup patch: wrong result unless archive storage engine is available. --- mysql-test/suite/perfschema/t/query_cache.test | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/suite/perfschema/t/query_cache.test b/mysql-test/suite/perfschema/t/query_cache.test index 8c9e5fcd0ed..08292306a25 100644 --- a/mysql-test/suite/perfschema/t/query_cache.test +++ b/mysql-test/suite/perfschema/t/query_cache.test @@ -6,6 +6,7 @@ --source include/have_query_cache.inc --source include/not_embedded.inc --source include/have_perfschema.inc +--source include/have_archive.inc --disable_warnings drop table if exists t1; From 2b085e1fba410ceaea2585c9cff511a9cfd2f7ae Mon Sep 17 00:00:00 2001 From: Tor Didriksen Date: Tue, 5 Jun 2012 15:53:39 +0200 Subject: [PATCH 075/289] Bug#14051002 VALGRIND: CONDITIONAL JUMP OR MOVE IN RR_CMP / MY_QSORT Patch for 5.1 and 5.5: fix typo in byte comparison in rr_cmp() --- sql/records.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/records.cc b/sql/records.cc index e275db83c93..da876f7554c 100644 --- a/sql/records.cc +++ b/sql/records.cc @@ -631,7 +631,7 @@ static int rr_cmp(uchar *a,uchar *b) if (a[4] != b[4]) return (int) a[4] - (int) b[4]; if (a[5] != b[5]) - return (int) a[1] - (int) b[5]; + return (int) a[5] - (int) b[5]; if (a[6] != b[6]) return (int) a[6] - (int) b[6]; return (int) a[7] - (int) b[7]; From 2c1e737c6c955ef6e670514d3bd9031727f3602c Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Thu, 7 Jun 2012 12:19:06 +0400 Subject: [PATCH 076/289] MDEV-297: SHOW EXPLAIN: Server gets stuck until timeout occurs while executing SHOW INDEX and SHOW EXPLAIN in parallel - Rework locking code to use the LOCK_thd_data mutex for all synchronization. This also fixed MDEV-301. --- mysql-test/r/show_explain.result | 20 ++++++ mysql-test/t/show_explain.test | 20 ++++++ sql/my_apc.cc | 109 ++++++++++++------------------- sql/my_apc.h | 39 ++++++++--- sql/sql_class.cc | 4 +- sql/sql_show.cc | 5 +- 6 files changed, 119 insertions(+), 78 deletions(-) diff --git a/mysql-test/r/show_explain.result b/mysql-test/r/show_explain.result index 515118b1cd8..d6c46c81c79 100644 --- a/mysql-test/r/show_explain.result +++ b/mysql-test/r/show_explain.result @@ -596,4 +596,24 @@ count(*) 212 set debug_dbug=''; drop table t1; +# +# MDEV-297: SHOW EXPLAIN: Server gets stuck until timeout occurs while +# executing SHOW INDEX and SHOW EXPLAIN in parallel +# +CREATE TABLE t1(a INT, b INT, c INT, KEY(a), KEY(b), KEY(c)); +INSERT INTO t1 (a) VALUES (3),(1),(5),(1); +set @show_explain_probe_select_id=1; +set debug_dbug='d,show_explain_probe_join_exec_start'; +SHOW INDEX FROM t1; +show explain for $thr2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE STATISTICS ALL NULL NULL NULL NULL NULL Skip_open_table; Scanned all databases +Warnings: +Note 1003 SHOW INDEX FROM t1 +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 1 a 1 a A NULL NULL NULL YES BTREE +t1 1 b 1 b A NULL NULL NULL YES BTREE +t1 1 c 1 c A NULL NULL NULL YES BTREE +set debug_dbug=''; +DROP TABLE t1; drop table t0; diff --git a/mysql-test/t/show_explain.test b/mysql-test/t/show_explain.test index 2baccea93be..5605e304bcc 100644 --- a/mysql-test/t/show_explain.test +++ b/mysql-test/t/show_explain.test @@ -581,6 +581,26 @@ reap; set debug_dbug=''; drop table t1; +--echo # +--echo # MDEV-297: SHOW EXPLAIN: Server gets stuck until timeout occurs while +--echo # executing SHOW INDEX and SHOW EXPLAIN in parallel +--echo # +CREATE TABLE t1(a INT, b INT, c INT, KEY(a), KEY(b), KEY(c)); +INSERT INTO t1 (a) VALUES (3),(1),(5),(1); + +set @show_explain_probe_select_id=1; +set debug_dbug='d,show_explain_probe_join_exec_start'; + +send SHOW INDEX FROM t1; +connection default; +--source include/wait_condition.inc +evalp show explain for $thr2; +connection con1; +reap; +set debug_dbug=''; + +DROP TABLE t1; + ## TODO: Test this: have several SHOW EXPLAIN requests be queued up for a ## thread and served together. diff --git a/sql/my_apc.cc b/sql/my_apc.cc index 30adbaad1b6..d5e3eb080a2 100644 --- a/sql/my_apc.cc +++ b/sql/my_apc.cc @@ -9,6 +9,8 @@ #include #include +#include "my_apc.h" + #else #include "sql_priv.h" @@ -16,7 +18,6 @@ #endif -//#include "my_apc.h" /* Standalone testing: @@ -33,12 +34,10 @@ any call requests to it. Initial state after initialization is 'disabled'. */ -void Apc_target::init() +void Apc_target::init(mysql_mutex_t *target_mutex) { - // todo: should use my_pthread_... functions instead? DBUG_ASSERT(!enabled); - (void)pthread_mutex_init(&LOCK_apc_queue, MY_MUTEX_INIT_SLOW); - + LOCK_thd_data_ptr= target_mutex; #ifndef DBUG_OFF n_calls_processed= 0; #endif @@ -51,7 +50,6 @@ void Apc_target::init() void Apc_target::destroy() { DBUG_ASSERT(!enabled); - pthread_mutex_destroy(&LOCK_apc_queue); } @@ -60,9 +58,8 @@ void Apc_target::destroy() */ void Apc_target::enable() { - pthread_mutex_lock(&LOCK_apc_queue); + /* Ok to do without getting/releasing the mutex: */ enabled++; - pthread_mutex_unlock(&LOCK_apc_queue); } @@ -76,16 +73,16 @@ void Apc_target::enable() void Apc_target::disable() { bool process= FALSE; - pthread_mutex_lock(&LOCK_apc_queue); + mysql_mutex_lock(LOCK_thd_data_ptr); if (!(--enabled)) process= TRUE; - pthread_mutex_unlock(&LOCK_apc_queue); + mysql_mutex_unlock(LOCK_thd_data_ptr); if (process) process_apc_requests(); } -/* (internal) Put request into the request list */ +/* [internal] Put request qe into the request list */ void Apc_target::enqueue_request(Call_request *qe) { @@ -108,7 +105,7 @@ void Apc_target::enqueue_request(Call_request *qe) /* - (internal) Remove given request from the request queue. + [internal] Remove request qe from the request queue. The request is not necessarily first in the queue. */ @@ -131,11 +128,14 @@ void Apc_target::dequeue_request(Call_request *qe) /* - Make an APC (Async Procedure Call) in another thread. + Make an APC (Async Procedure Call) to another thread. + + - The caller is responsible for making sure he's not calling to the same + thread. + + - The caller should have locked target_thread_mutex. + - The caller is responsible for making sure he's not calling an Apc_target - that is serviced by the same thread it is called from. - psergey-todo: Should waits here be KILLable? (it seems one needs to use thd->enter_cond() calls to be killable) */ @@ -146,7 +146,6 @@ bool Apc_target::make_apc_call(apc_func_t func, void *func_arg, bool res= TRUE; *timed_out= FALSE; - pthread_mutex_lock(&LOCK_apc_queue); if (enabled) { /* Create and post the request */ @@ -154,51 +153,48 @@ bool Apc_target::make_apc_call(apc_func_t func, void *func_arg, apc_request.func= func; apc_request.func_arg= func_arg; apc_request.processed= FALSE; - (void)pthread_cond_init(&apc_request.COND_request, NULL); - (void)pthread_mutex_init(&apc_request.LOCK_request, MY_MUTEX_INIT_SLOW); - pthread_mutex_lock(&apc_request.LOCK_request); + mysql_cond_init(0 /* do not track in PS */, &apc_request.COND_request, NULL); enqueue_request(&apc_request); apc_request.what="enqueued by make_apc_call"; - pthread_mutex_unlock(&LOCK_apc_queue); struct timespec abstime; const int timeout= timeout_sec; set_timespec(abstime, timeout); - + int wait_res= 0; /* todo: how about processing other errors here? */ while (!apc_request.processed && (wait_res != ETIMEDOUT)) { - wait_res= pthread_cond_timedwait(&apc_request.COND_request, - &apc_request.LOCK_request, &abstime); + /* We own LOCK_thd_data_ptr */ + wait_res= mysql_cond_timedwait(&apc_request.COND_request, + LOCK_thd_data_ptr, &abstime); + // &apc_request.LOCK_request, &abstime); } if (!apc_request.processed) { - /* The wait has timed out. Remove the request from the queue */ + /* + The wait has timed out. Remove the request from the queue (ok to do + because we own LOCK_thd_data_ptr. + */ apc_request.processed= TRUE; - *timed_out= TRUE; - pthread_mutex_unlock(&apc_request.LOCK_request); - //psergey-todo: "Whoa rare event" refers to this part, right? put a comment. - pthread_mutex_lock(&LOCK_apc_queue); dequeue_request(&apc_request); - pthread_mutex_unlock(&LOCK_apc_queue); + *timed_out= TRUE; res= TRUE; } else { /* Request was successfully executed and dequeued by the target thread */ - pthread_mutex_unlock(&apc_request.LOCK_request); res= FALSE; } + mysql_mutex_unlock(LOCK_thd_data_ptr); /* Destroy all APC request data */ - pthread_mutex_destroy(&apc_request.LOCK_request); - pthread_cond_destroy(&apc_request.COND_request); + mysql_cond_destroy(&apc_request.COND_request); } else { - pthread_mutex_unlock(&LOCK_apc_queue); + mysql_mutex_unlock(LOCK_thd_data_ptr); } return res; } @@ -211,58 +207,37 @@ bool Apc_target::make_apc_call(apc_func_t func, void *func_arg, void Apc_target::process_apc_requests() { + if (!get_first_in_queue()) + return; + while (1) { Call_request *request; - - pthread_mutex_lock(&LOCK_apc_queue); + + mysql_mutex_lock(LOCK_thd_data_ptr); if (!(request= get_first_in_queue())) { - pthread_mutex_unlock(&LOCK_apc_queue); + /* No requests in the queue */ + mysql_mutex_unlock(LOCK_thd_data_ptr); break; } - request->what="seen by process_apc_requests"; - pthread_mutex_lock(&request->LOCK_request); - - if (request->processed) - { - /* - We can get here when - - the requestor thread has been waiting for this request - - the wait has timed out - - it has set request->done=TRUE - - it has released LOCK_request, because its next action - will be to remove the request from the queue, however, - it could not attempt to lock the queue while holding the lock on - request, because that would deadlock with this function - (we here first lock the queue and then lock the request) - */ - pthread_mutex_unlock(&request->LOCK_request); - pthread_mutex_unlock(&LOCK_apc_queue); - fprintf(stderr, "Whoa rare event #1!\n"); - continue; - } /* - Remove the request from the queue (we're holding its lock so we can be + Remove the request from the queue (we're holding queue lock so we can be sure that request owner won't try to remove it) */ request->what="dequeued by process_apc_requests"; dequeue_request(request); request->processed= TRUE; - pthread_mutex_unlock(&LOCK_apc_queue); - request->func(request->func_arg); request->what="func called by process_apc_requests"; #ifndef DBUG_OFF n_calls_processed++; #endif - - pthread_cond_signal(&request->COND_request); - - pthread_mutex_unlock(&request->LOCK_request); + mysql_cond_signal(&request->COND_request); + mysql_mutex_unlock(LOCK_thd_data_ptr); } } @@ -280,6 +255,7 @@ volatile int apcs_missed=0; volatile int apcs_timed_out=0; Apc_target apc_target; +mysql_mutex_t target_mutex; int int_rand(int size) { @@ -290,7 +266,8 @@ int int_rand(int size) void *test_apc_service_thread(void *ptr) { my_thread_init(); - apc_target.init(); + mysql_mutex_init(0, &target_mutex, MY_MUTEX_INIT_FAST); + apc_target.init(&target_mutex); apc_target.enable(); started= TRUE; fprintf(stderr, "# test_apc_service_thread started\n"); diff --git a/sql/my_apc.h b/sql/my_apc.h index 0698703ad40..8e6980fa855 100644 --- a/sql/my_apc.h +++ b/sql/my_apc.h @@ -22,15 +22,16 @@ */ /* - Target for asynchronous calls. + Target for asynchronous procedue calls (APCs). */ class Apc_target { + mysql_mutex_t *LOCK_thd_data_ptr; public: Apc_target() : enabled(0), apc_calls(NULL) /*, call_queue_size(0)*/ {} ~Apc_target() { DBUG_ASSERT(!enabled && !apc_calls);} - void init(); + void init(mysql_mutex_t *target_mutex); void destroy(); void enable(); void disable(); @@ -68,14 +69,31 @@ private: /* Circular, double-linked list of all enqueued call requests. We use this structure, because we - - process requests sequentially + - process requests sequentially (i.e. they are removed from the front) - a thread that has posted a request may time out (or be KILLed) and - cancel the request, which means we'll need to remove its request at - arbitrary point in time. + cancel the request, which means we need a fast request-removal + operation. */ Call_request *apc_calls; + - pthread_mutex_t LOCK_apc_queue; + /* + This mutex is used to + - make queue put/remove operations atomic (one must be in posession of the + mutex when putting/removing something from the queue) + + - make sure that nobody enqueues a request onto an Apc_target which has + disabled==TRUE. The idea is: + = requestor must be in possession of the mutex and check that + disabled==FALSE when he is putting his request into the queue. + = When the owner (ie. service) thread changes the Apc_target from + enabled to disabled, it will acquire the mutex, disable the + Apc_target (preventing any new requests), and then serve all pending + requests. + That way, we will never have the situation where the Apc_target is + disabled, but there are some un-served requests. + */ + //pthread_mutex_t LOCK_apc_queue; class Call_request { @@ -84,13 +102,16 @@ private: void *func_arg; /* Argument to pass it */ bool processed; - pthread_mutex_t LOCK_request; - pthread_cond_t COND_request; + //pthread_mutex_t LOCK_request; + //pthread_cond_t COND_request; + + /* Condition that will be signalled when the request has been served */ + mysql_cond_t COND_request; Call_request *next; Call_request *prev; - const char *what; /* State of the request */ + const char *what; /* (debug) state of the request */ }; void enqueue_request(Call_request *qe); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 2ad4e77405d..f477c0fe0ec 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1196,7 +1196,7 @@ void THD::init(void) /* Initialize the Debug Sync Facility. See debug_sync.cc. */ debug_sync_init_thread(this); #endif /* defined(ENABLED_DEBUG_SYNC) */ - apc_target.init(); + apc_target.init(&LOCK_thd_data); } @@ -1372,6 +1372,8 @@ THD::~THD() { THD_CHECK_SENTRY(this); DBUG_ENTER("~THD()"); + //psergey-todo: assert that the queue is disabled and empty. + /* Ensure that no one is using THD */ mysql_mutex_lock(&LOCK_thd_data); mysys_var=0; // Safety (shouldn't be needed) diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 87f46abb23c..5079e82fa40 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2063,7 +2063,8 @@ void mysqld_show_explain(THD *thd, ulong thread_id) explain_req.target_thd= tmp; explain_req.request_thd= thd; explain_req.failed_to_produce= FALSE; - + + /* Ok, we have a lock on target->LOCK_thd_data, can call: */ bres= tmp->apc_target.make_apc_call(Show_explain_request::get_explain_data, (void*)&explain_req, timeout_sec, &timed_out); @@ -2090,7 +2091,7 @@ void mysqld_show_explain(THD *thd, ulong thread_id) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_YES, explain_req.query_str.c_ptr_safe()); } - mysql_mutex_unlock(&tmp->LOCK_thd_data); + //mysql_mutex_unlock(&tmp->LOCK_thd_data); if (!bres) { explain_buf->flush_data(); From 164080e4a8ec5ebb6b466eafe82bfa90e4a59fc0 Mon Sep 17 00:00:00 2001 From: Narayanan Venkateswaran Date: Thu, 7 Jun 2012 19:14:26 +0530 Subject: [PATCH 077/289] WL#6161 Integrating with InnoDB codebase in MySQL 5.5 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes in the InnoDB codebase required to compile and integrate the MEB codebase with MySQL 5.5. @ storage/innobase/btr/btr0btr.c Excluded buffer pool usage from MEB build. buf_pool_from_bpage calls are in buf0buf.ic, and the buffer pool functions from that file are disabled in MEB. @ storage/innobase/buf/buf0buf.c Disabling more buffer pool functions unused in MEB. @ storage/innobase/dict/dict0dict.c Disabling dict_ind_free that is unused in MEB. @ storage/innobase/dict/dict0mem.c The include #include "ha_prototypes.h" Was causing conflicts with definitions in my_global.h Linking C executable mysqlbackup libinnodb.a(dict0mem.c.o): In function `dict_mem_foreign_table_name_lookup_set': dict0mem.c:(.text+0x91c): undefined reference to `innobase_get_lower_case_table_names' libinnodb.a(dict0mem.c.o): In function `dict_mem_referenced_table_name_lookup_set': dict0mem.c:(.text+0x9fc): undefined reference to `innobase_get_lower_case_table_names' libinnodb.a(dict0mem.c.o): In function `dict_mem_foreign_table_name_lookup_set': dict0mem.c:(.text+0x96e): undefined reference to `innobase_casedn_str' libinnodb.a(dict0mem.c.o): In function `dict_mem_referenced_table_name_lookup_set': dict0mem.c:(.text+0xa4e): undefined reference to `innobase_casedn_str' collect2: ld returned 1 exit status make[2]: *** [mysqlbackup] Error 1 innobase_get_lower_case_table_names innobase_casedn_str are functions that are part of ha_innodb.cc that is not part of the build dict_mem_foreign_table_name_lookup_set function is not there in the current codebase, meaning we do not use it in MEB. @ storage/innobase/fil/fil0fil.c The srv_fast_shutdown variable is declared in srv0srv.c that is not compiled in the mysqlbackup codebase. This throws an undeclared error. From the Manual --------------- innodb_fast_shutdown -------------------- The InnoDB shutdown mode. The default value is 1 as of MySQL 3.23.50, which causes a “fast� shutdown (the normal type of shutdown). If the value is 0, InnoDB does a full purge and an insert buffer merge before a shutdown. These operations can take minutes, or even hours in extreme cases. If the value is 1, InnoDB skips these operations at shutdown. This ideally does not matter from mysqlbackup @ storage/innobase/ha/ha0ha.c In file included from /home/narayanan/mysql-server/mysql-5.5-meb-rel3.8-innodb-integration-1/storage/innobase/ha/ha0ha.c:34:0: /home/narayanan/mysql-server/mysql-5.5-meb-rel3.8-innodb-integration-1/storage/innobase/include/btr0sea.h:286:17: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘*’ token make[2]: *** [CMakeFiles/innodb.dir/home/narayanan/mysql-server/mysql-5.5-meb-rel3.8-innodb-integration-1/storage/innobase/ha/ha0ha.c.o] Error 1 make[1]: *** [CMakeFiles/innodb.dir/all] Error 2 make: *** [all] Error 2 # include "sync0rw.h" is excluded from hotbackup compilation in dict0dict.h This causes extern rw_lock_t* btr_search_latch_temp; to throw a failure because the definition of rw_lock_t is not found. @ storage/innobase/include/buf0buf.h Excluding buffer pool functions that are unused from the MEB codebase. @ storage/innobase/include/buf0buf.ic replicated the exclusion of #include "buf0flu.h" #include "buf0lru.h" #include "buf0rea.h" by looking at the current codebase in /src/innodb @ storage/innobase/include/dict0dict.h dict_table_x_lock_indexes, dict_table_x_unlock_indexes, dict_table_is_corrupted, dict_index_is_corrupted, buf_block_buf_fix_inc_func are unused in MEB and was leading to compilation errors and hence excluded. @ storage/innobase/include/dict0dict.ic dict_table_x_lock_indexes, dict_table_x_unlock_indexes, dict_table_is_corrupted, dict_index_is_corrupted, buf_block_buf_fix_inc_func are unused in MEB and was leading to compilation errors and hence excluded. @ storage/innobase/include/log0log.h /home/narayanan/mysql-server/mysql-5.5-meb-rel3.8-innodb-integration-1/storage/innobase/include/log0log.h: At top level: /home/narayanan/mysql-server/mysql-5.5-meb-rel3.8-innodb-integration-1/storage/innobase/include/log0log.h:767:2: error: expected specifier-qualifier-list before ââ ‚¬Ëœmutex_t’ mutex_t definitions were excluded as seen from ambient code hence excluding definition for log_flush_order_mutex also. @ storage/innobase/include/os0file.h Bug in InnoDB code, create_mode should have been create. @ storage/innobase/include/srv0srv.h In file included from /home/narayanan/mysql-server/mysql-5.5-meb-rel3.8-innodb-integration-1/storage/innobase/buf/buf0buf.c:50:0: /home/narayanan/mysql-server/mysql-5.5-meb-rel3.8-innodb-integration-1/storage/innobase/include/srv0srv.h: At top level: /home/narayanan/mysql-server/mysql-5.5-meb-rel3.8-innodb-integration-1/storage/innobase/include/srv0srv.h:120:16: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘srv_use_native_aio’ srv_use_native_aio - we do not use native aio of the OS anyway from MEB. MEB does not compile InnoDB with this option. Hence disabling it. @ storage/innobase/include/trx0sys.h [ 56%] Building C object CMakeFiles/innodb.dir/home/narayanan/mysql-server/mysql-5.5-meb-rel3.8-innodb-integration-1/storage/innobase/trx/trx0sys.c.o /home/narayanan/mysql-server/mysql-5.5-meb-rel3.8-innodb-integration-1/storage/innobase/trx/trx0sys.c: In function ‘trx_sys_read_file_format_id’: /home/narayanan/mysql-server/mysql-5.5-meb-rel3.8-innodb-integration-1/storage/innobase/trx/trx0sys.c:1499:20: error: ‘TRX_SYS_FILE_FORMAT_TAG_MAGIC_N’ undeclared (first use in this function) /home/narayanan/mysql-server/mysql-5.5-meb-rel3.8-innodb-integration-1/storage/innobase/trx/trx0sys.c:1499:20: note: each undeclared identifier is reported only once for each function it appears in /home/narayanan/mysql-server/mysql-5.5-meb-rel3.8-innodb-integration-1/storage/innobase/trx/trx0sys.c: At top level: /home/narayanan/mysql-server/mysql-5.5-meb-rel3.8-innodb-integration-1/storage/innobase/include/buf0buf.h:607:1: warning: ‘buf_block_buf_fix_inc_func’ declared ‘static’ but never defined make[2]: *** [CMakeFiles/innodb.dir/home/narayanan/mysql-server/mysql-5.5-meb-rel3.8-innodb-integration-1/storage/innobase/trx/trx0sys.c.o] Error 1 unused calls excluded to enable compilation @ storage/innobase/mem/mem0dbg.c excluding #include "ha_prototypes.h" that lead to definitions in ha_innodb.cc @ storage/innobase/os/os0file.c InnoDB not compiled with aio support from MEB anyway. Hence excluding this from the compilation. @ storage/innobase/page/page0zip.c page0zip.c:(.text+0x4e9e): undefined reference to `buf_pool_from_block' collect2: ld returned 1 exit status buf_pool_from_block defined in buf0buf.ic, most of the file is excluded for compilation of MEB @ storage/innobase/ut/ut0dbg.c excluding #include "ha_prototypes.h" since it leads to definitions in ha_innodb.cc innobase_basename(file) is defined in ha_innodb.cc. Hence excluding that also. @ storage/innobase/ut/ut0ut.c cal_tm unused from MEB, was leading to earnings, hence disabling for MEB. --- storage/innobase/btr/btr0btr.c | 4 ++++ storage/innobase/buf/buf0buf.c | 2 +- storage/innobase/dict/dict0dict.c | 14 ++++++++++++-- storage/innobase/dict/dict0mem.c | 4 +++- storage/innobase/fil/fil0fil.c | 2 ++ storage/innobase/ha/ha0ha.c | 16 +--------------- storage/innobase/include/btr0btr.h | 3 +++ storage/innobase/include/btr0types.h | 4 ++++ storage/innobase/include/buf0buf.h | 16 ++++++++-------- storage/innobase/include/buf0buf.ic | 2 ++ storage/innobase/include/dict0dict.h | 5 ++++- storage/innobase/include/dict0dict.ic | 2 ++ storage/innobase/include/log0log.h | 2 +- storage/innobase/include/os0file.h | 2 +- storage/innobase/include/srv0srv.h | 2 +- storage/innobase/include/trx0sys.h | 4 +--- storage/innobase/mem/mem0dbg.c | 4 +++- storage/innobase/os/os0file.c | 2 ++ storage/innobase/page/page0zip.c | 2 ++ storage/innobase/trx/trx0sys.c | 2 +- storage/innobase/ut/ut0dbg.c | 6 ++++-- storage/innobase/ut/ut0ut.c | 8 ++++++++ 22 files changed, 70 insertions(+), 38 deletions(-) diff --git a/storage/innobase/btr/btr0btr.c b/storage/innobase/btr/btr0btr.c index fc3cdaf3cf1..b714219e304 100644 --- a/storage/innobase/btr/btr0btr.c +++ b/storage/innobase/btr/btr0btr.c @@ -42,6 +42,7 @@ Created 6/2/1994 Heikki Tuuri #include "ibuf0ibuf.h" #include "trx0trx.h" +#endif /* UNIV_HOTBACKUP */ /**************************************************************//** Report that an index page is corrupted. */ UNIV_INTERN @@ -64,6 +65,7 @@ btr_corruption_report( buf_page_print(buf_block_get_frame(block), 0, 0); } +#ifndef UNIV_HOTBACKUP #ifdef UNIV_BLOB_DEBUG # include "srv0srv.h" # include "ut0rbt.h" @@ -1575,7 +1577,9 @@ btr_page_reorganize_low( dict_index_t* index, /*!< in: record descriptor */ mtr_t* mtr) /*!< in: mtr */ { +#ifndef UNIV_HOTBACKUP buf_pool_t* buf_pool = buf_pool_from_bpage(&block->page); +#endif /* !UNIV_HOTBACKUP */ page_t* page = buf_block_get_frame(block); page_zip_des_t* page_zip = buf_block_get_page_zip(block); buf_block_t* temp_block; diff --git a/storage/innobase/buf/buf0buf.c b/storage/innobase/buf/buf0buf.c index 1672057d552..fed07129b65 100644 --- a/storage/innobase/buf/buf0buf.c +++ b/storage/innobase/buf/buf0buf.c @@ -302,7 +302,6 @@ struct buf_chunk_struct{ was allocated for the frames */ buf_block_t* blocks; /*!< array of buffer control blocks */ }; -#endif /* !UNIV_HOTBACKUP */ /********************************************************************//** Gets the smallest oldest_modification lsn for any page in the pool. Returns @@ -438,6 +437,7 @@ buf_block_alloc( return(block); } +#endif /* !UNIV_HOTBACKUP */ /********************************************************************//** Calculates a page checksum which is stored to the page when it is written diff --git a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.c index a59401e8edf..6f2c2caffaf 100644 --- a/storage/innobase/dict/dict0dict.c +++ b/storage/innobase/dict/dict0dict.c @@ -169,6 +169,7 @@ void dict_field_print_low( /*=================*/ const dict_field_t* field); /*!< in: field */ +#ifndef UNIV_HOTBACKUP /*********************************************************************//** Frees a foreign key struct. */ static @@ -182,7 +183,7 @@ and unique key errors */ UNIV_INTERN FILE* dict_foreign_err_file = NULL; /* mutex protecting the foreign and unique error buffers */ UNIV_INTERN mutex_t dict_foreign_err_mutex; - +#endif /* !UNIV_HOTBACKUP */ /******************************************************************//** Makes all characters in a NUL-terminated UTF-8 string lower case. */ UNIV_INTERN @@ -2247,6 +2248,7 @@ dict_index_build_internal_non_clust( return(new_index); } +#ifndef UNIV_HOTBACKUP /*====================== FOREIGN KEY PROCESSING ========================*/ /*********************************************************************//** @@ -2511,6 +2513,7 @@ dict_foreign_find_equiv_index( FALSE/* allow columns to be NULL */)); } +#endif /* !UNIV_HOTBACKUP */ /**********************************************************************//** Returns an index object by matching on the name and column names and if more than one index matches return the index with the max id @@ -2570,6 +2573,7 @@ dict_table_get_index_by_max_id( return(found); } +#ifndef UNIV_HOTBACKUP /**********************************************************************//** Report an error in a foreign key definition. */ static @@ -2735,6 +2739,7 @@ dict_foreign_add_to_cache( return(DB_SUCCESS); } +#endif /* !UNIV_HOTBACKUP */ /*********************************************************************//** Scans from pointer onwards. Stops if is at the start of a copy of 'string' where characters are compared without case sensitivity, and @@ -3214,6 +3219,7 @@ end_of_string: } } +#ifndef UNIV_HOTBACKUP /*********************************************************************//** Finds the highest [number] for foreign key constraints of the table. Looks only at the >= 4.0.18-format id's, which are of the form @@ -4050,7 +4056,7 @@ syntax_error: } /*==================== END OF FOREIGN KEY PROCESSING ====================*/ - +#endif /* !UNIV_HOTBACKUP */ /**********************************************************************//** Returns an index object if it is found in the dictionary cache. Assumes that dict_sys->mutex is already being held. @@ -4411,6 +4417,7 @@ fake_statistics: dict_table_stats_unlock(table, RW_X_LATCH); } +#ifndef UNIV_HOTBACKUP /**********************************************************************//** Prints info of a foreign key constraint. */ static @@ -4441,6 +4448,7 @@ dict_foreign_print_low( fputs(" )\n", stderr); } +#endif /* !UNIV_HOTBACKUP */ /**********************************************************************//** Prints a table data. */ UNIV_INTERN @@ -4622,6 +4630,7 @@ dict_field_print_low( } } +#ifndef UNIV_HOTBACKUP /**********************************************************************//** Outputs info on a foreign key of a table in a format suitable for CREATE TABLE. */ @@ -4810,6 +4819,7 @@ dict_print_info_on_foreign_keys( mutex_exit(&(dict_sys->mutex)); } +#endif /* !UNIV_HOTBACKUP */ /********************************************************************//** Displays the names of the index and the table. */ UNIV_INTERN diff --git a/storage/innobase/dict/dict0mem.c b/storage/innobase/dict/dict0mem.c index 982cca5a796..a8ff501a700 100644 --- a/storage/innobase/dict/dict0mem.c +++ b/storage/innobase/dict/dict0mem.c @@ -33,8 +33,8 @@ Created 1/8/1996 Heikki Tuuri #include "data0type.h" #include "mach0data.h" #include "dict0dict.h" -#include "ha_prototypes.h" /* innobase_casedn_str()*/ #ifndef UNIV_HOTBACKUP +# include "ha_prototypes.h" /* innobase_casedn_str()*/ # include "lock0lock.h" #endif /* !UNIV_HOTBACKUP */ #ifdef UNIV_BLOB_DEBUG @@ -272,6 +272,7 @@ dict_mem_index_create( return(index); } +#ifndef UNIV_HOTBACKUP /**********************************************************************//** Creates and initializes a foreign constraint memory object. @return own: foreign constraint struct */ @@ -346,6 +347,7 @@ dict_mem_referenced_table_name_lookup_set( } } +#endif /* !UNIV_HOTBACKUP */ /**********************************************************************//** Adds a field definition to an index. NOTE: does not take a copy of the column name if the field is a column. The memory occupied diff --git a/storage/innobase/fil/fil0fil.c b/storage/innobase/fil/fil0fil.c index 0a467d40345..23fe76f2281 100644 --- a/storage/innobase/fil/fil0fil.c +++ b/storage/innobase/fil/fil0fil.c @@ -857,8 +857,10 @@ fil_node_close_file( ut_a(node->open); ut_a(node->n_pending == 0); ut_a(node->n_pending_flushes == 0); +#ifndef UNIV_HOTBACKUP ut_a(node->modification_counter == node->flush_counter || srv_fast_shutdown == 2); +#endif /* !UNIV_HOTBACKUP */ ret = os_file_close(node->handle); ut_a(ret); diff --git a/storage/innobase/ha/ha0ha.c b/storage/innobase/ha/ha0ha.c index 65046138275..4be0d296c7c 100644 --- a/storage/innobase/ha/ha0ha.c +++ b/storage/innobase/ha/ha0ha.c @@ -28,6 +28,7 @@ Created 8/22/1994 Heikki Tuuri #include "ha0ha.ic" #endif +#ifndef UNIV_HOTBACKUP #ifdef UNIV_DEBUG # include "buf0buf.h" #endif /* UNIV_DEBUG */ @@ -51,17 +52,13 @@ ha_create_func( hash table: must be a power of 2, or 0 */ { hash_table_t* table; -#ifndef UNIV_HOTBACKUP ulint i; -#endif /* !UNIV_HOTBACKUP */ ut_ad(ut_is_2pow(n_mutexes)); table = hash_create(n); #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG -# ifndef UNIV_HOTBACKUP table->adaptive = TRUE; -# endif /* !UNIV_HOTBACKUP */ #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ /* Creating MEM_HEAP_BTR_SEARCH type heaps can potentially fail, but in practise it never should in this case, hence the asserts. */ @@ -74,7 +71,6 @@ ha_create_func( return(table); } -#ifndef UNIV_HOTBACKUP hash_create_mutexes(table, n_mutexes, mutex_level); table->heaps = mem_alloc(n_mutexes * sizeof(void*)); @@ -83,7 +79,6 @@ ha_create_func( table->heaps[i] = mem_heap_create_in_btr_search(4096); ut_a(table->heaps[i]); } -#endif /* !UNIV_HOTBACKUP */ return(table); } @@ -134,7 +129,6 @@ ha_insert_for_fold_func( while (prev_node != NULL) { if (prev_node->fold == fold) { #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG -# ifndef UNIV_HOTBACKUP if (table->adaptive) { buf_block_t* prev_block = prev_node->block; ut_a(prev_block->frame @@ -143,7 +137,6 @@ ha_insert_for_fold_func( prev_block->n_pointers--; block->n_pointers++; } -# endif /* !UNIV_HOTBACKUP */ prev_node->block = block; #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ @@ -171,11 +164,9 @@ ha_insert_for_fold_func( ha_node_set_data(node, block, data); #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG -# ifndef UNIV_HOTBACKUP if (table->adaptive) { block->n_pointers++; } -# endif /* !UNIV_HOTBACKUP */ #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ node->fold = fold; @@ -217,13 +208,11 @@ ha_delete_hash_node( #endif /* UNIV_SYNC_DEBUG */ ut_ad(btr_search_enabled); #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG -# ifndef UNIV_HOTBACKUP if (table->adaptive) { ut_a(del_node->block->frame = page_align(del_node->data)); ut_a(del_node->block->n_pointers > 0); del_node->block->n_pointers--; } -# endif /* !UNIV_HOTBACKUP */ #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ HASH_DELETE_AND_COMPACT(ha_node_t, next, table, del_node); @@ -264,13 +253,11 @@ ha_search_and_update_if_found_func( if (node) { #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG -# ifndef UNIV_HOTBACKUP if (table->adaptive) { ut_a(node->block->n_pointers > 0); node->block->n_pointers--; new_block->n_pointers++; } -# endif /* !UNIV_HOTBACKUP */ node->block = new_block; #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ @@ -278,7 +265,6 @@ ha_search_and_update_if_found_func( } } -#ifndef UNIV_HOTBACKUP /*****************************************************************//** Removes from the chain determined by fold all nodes whose data pointer points to the page given. */ diff --git a/storage/innobase/include/btr0btr.h b/storage/innobase/include/btr0btr.h index f531b785786..5592995d4b2 100644 --- a/storage/innobase/include/btr0btr.h +++ b/storage/innobase/include/btr0btr.h @@ -92,6 +92,8 @@ insert/delete buffer when the record is not in the buffer pool. */ buffer when the record is not in the buffer pool. */ #define BTR_DELETE 8192 +#endif /* UNIV_HOTBACKUP */ + /**************************************************************//** Report that an index page is corrupted. */ UNIV_INTERN @@ -112,6 +114,7 @@ btr_corruption_report( ut_error; \ } +#ifndef UNIV_HOTBACKUP #ifdef UNIV_BLOB_DEBUG # include "ut0rbt.h" /** An index->blobs entry for keeping track of off-page column references */ diff --git a/storage/innobase/include/btr0types.h b/storage/innobase/include/btr0types.h index 5adc858b931..ef329af1aac 100644 --- a/storage/innobase/include/btr0types.h +++ b/storage/innobase/include/btr0types.h @@ -39,6 +39,8 @@ typedef struct btr_cur_struct btr_cur_t; /** B-tree search information for the adaptive hash index */ typedef struct btr_search_struct btr_search_t; +#ifndef UNIV_HOTBACKUP + /** @brief The latch protecting the adaptive search system This latch protects the @@ -54,6 +56,8 @@ Bear in mind (3) and (4) when using the hash index. */ extern rw_lock_t* btr_search_latch_temp; +#endif /* UNIV_HOTBACKUP */ + /** The latch protecting the adaptive search system */ #define btr_search_latch (*btr_search_latch_temp) diff --git a/storage/innobase/include/buf0buf.h b/storage/innobase/include/buf0buf.h index d9e6801eb86..7c81fe0c539 100644 --- a/storage/innobase/include/buf0buf.h +++ b/storage/innobase/include/buf0buf.h @@ -593,34 +593,34 @@ ib_uint64_t buf_block_get_modify_clock( /*=======================*/ buf_block_t* block); /*!< in: block */ -#else /* !UNIV_HOTBACKUP */ -# define buf_block_modify_clock_inc(block) ((void) 0) -#endif /* !UNIV_HOTBACKUP */ /*******************************************************************//** Increments the bufferfix count. */ UNIV_INLINE void buf_block_buf_fix_inc_func( /*=======================*/ -#ifdef UNIV_SYNC_DEBUG +# ifdef UNIV_SYNC_DEBUG const char* file, /*!< in: file name */ ulint line, /*!< in: line */ -#endif /* UNIV_SYNC_DEBUG */ +# endif /* UNIV_SYNC_DEBUG */ buf_block_t* block) /*!< in/out: block to bufferfix */ __attribute__((nonnull)); -#ifdef UNIV_SYNC_DEBUG +# ifdef UNIV_SYNC_DEBUG /** Increments the bufferfix count. @param b in/out: block to bufferfix @param f in: file name where requested @param l in: line number where requested */ # define buf_block_buf_fix_inc(b,f,l) buf_block_buf_fix_inc_func(f,l,b) -#else /* UNIV_SYNC_DEBUG */ +# else /* UNIV_SYNC_DEBUG */ /** Increments the bufferfix count. @param b in/out: block to bufferfix @param f in: file name where requested @param l in: line number where requested */ # define buf_block_buf_fix_inc(b,f,l) buf_block_buf_fix_inc_func(b) -#endif /* UNIV_SYNC_DEBUG */ +# endif /* UNIV_SYNC_DEBUG */ +#else /* !UNIV_HOTBACKUP */ +# define buf_block_modify_clock_inc(block) ((void) 0) +#endif /* !UNIV_HOTBACKUP */ /********************************************************************//** Calculates a page checksum which is stored to the page when it is written to a file. Note that we must be careful to calculate the same value diff --git a/storage/innobase/include/buf0buf.ic b/storage/innobase/include/buf0buf.ic index 917ee5dda84..0d9687e6b2a 100644 --- a/storage/innobase/include/buf0buf.ic +++ b/storage/innobase/include/buf0buf.ic @@ -31,6 +31,7 @@ Created 11/5/1995 Heikki Tuuri *******************************************************/ #include "mtr0mtr.h" +#ifndef UNIV_HOTBACKUP #include "buf0flu.h" #include "buf0lru.h" #include "buf0rea.h" @@ -180,6 +181,7 @@ buf_page_peek_if_too_old( return(!buf_page_peek_if_young(bpage)); } } +#endif /* !UNIV_HOTBACKUP */ /*********************************************************************//** Gets the state of a block. diff --git a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h index 89d6fc66635..b609bce9d41 100644 --- a/storage/innobase/include/dict0dict.h +++ b/storage/innobase/include/dict0dict.h @@ -750,6 +750,7 @@ ulint dict_table_zip_size( /*================*/ const dict_table_t* table); /*!< in: table */ +#ifndef UNIV_HOTBACKUP /*********************************************************************//** Obtain exclusive locks on all index trees of the table. This is to prevent accessing index trees while InnoDB is updating internal metadata for @@ -766,6 +767,7 @@ void dict_table_x_unlock_indexes( /*========================*/ dict_table_t* table); /*!< in: table */ +#endif /* !UNIV_HOTBACKUP */ /********************************************************************//** Checks if a column is in the ordering columns of the clustered index of a table. Column prefixes are treated like whole columns. @@ -1251,7 +1253,7 @@ UNIV_INTERN void dict_close(void); /*============*/ - +#ifndef UNIV_HOTBACKUP /**********************************************************************//** Check whether the table is corrupted. @return nonzero for corrupted table, zero for valid tables */ @@ -1272,6 +1274,7 @@ dict_index_is_corrupted( const dict_index_t* index) /*!< in: index */ __attribute__((nonnull, pure, warn_unused_result)); +#endif /* !UNIV_HOTBACKUP */ /**********************************************************************//** Flags an index and table corrupted both in the data dictionary cache and in the system table SYS_INDEXES. */ diff --git a/storage/innobase/include/dict0dict.ic b/storage/innobase/include/dict0dict.ic index 7533ce01401..faa28959c59 100644 --- a/storage/innobase/include/dict0dict.ic +++ b/storage/innobase/include/dict0dict.ic @@ -491,6 +491,7 @@ dict_table_zip_size( return(dict_table_flags_to_zip_size(table->flags)); } +#ifndef UNIV_HOTBACKUP /*********************************************************************//** Obtain exclusive locks on all index trees of the table. This is to prevent accessing index trees while InnoDB is updating internal metadata for @@ -533,6 +534,7 @@ dict_table_x_unlock_indexes( rw_lock_x_unlock(dict_index_get_lock(index)); } } +#endif /* !UNIV_HOTBACKUP */ /********************************************************************//** Gets the number of fields in the internal representation of an index, including fields added by the dictionary system. diff --git a/storage/innobase/include/log0log.h b/storage/innobase/include/log0log.h index f2ab6a9898d..30250d4fd27 100644 --- a/storage/innobase/include/log0log.h +++ b/storage/innobase/include/log0log.h @@ -762,7 +762,6 @@ struct log_struct{ buffer */ #ifndef UNIV_HOTBACKUP mutex_t mutex; /*!< mutex protecting the log */ -#endif /* !UNIV_HOTBACKUP */ mutex_t log_flush_order_mutex;/*!< mutex to serialize access to the flush list when we are putting @@ -772,6 +771,7 @@ struct log_struct{ mtr_commit and still ensure that insertions in the flush_list happen in the LSN order. */ +#endif /* !UNIV_HOTBACKUP */ byte* buf_ptr; /* unaligned log buffer */ byte* buf; /*!< log buffer */ ulint buf_size; /*!< log buffer size in bytes */ diff --git a/storage/innobase/include/os0file.h b/storage/innobase/include/os0file.h index fb13120a481..8ef0906ff5f 100644 --- a/storage/innobase/include/os0file.h +++ b/storage/innobase/include/os0file.h @@ -309,7 +309,7 @@ to original un-instrumented file I/O APIs */ os_file_create_func(name, create, purpose, type, success) # define os_file_create_simple(key, name, create, access, success) \ - os_file_create_simple_func(name, create_mode, access, success) + os_file_create_simple_func(name, create, access, success) # define os_file_create_simple_no_error_handling( \ key, name, create_mode, access, success) \ diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h index ed2f4672a99..5290ef5fe11 100644 --- a/storage/innobase/include/srv0srv.h +++ b/storage/innobase/include/srv0srv.h @@ -111,13 +111,13 @@ extern ulint srv_max_file_format_at_startup; /** Place locks to records only i.e. do not use next-key locking except on duplicate key checking and foreign key checking */ extern ibool srv_locks_unsafe_for_binlog; -#endif /* !UNIV_HOTBACKUP */ /* If this flag is TRUE, then we will use the native aio of the OS (provided we compiled Innobase with it in), otherwise we will use simulated aio we build below with threads. Currently we support native aio on windows and linux */ extern my_bool srv_use_native_aio; +#endif /* !UNIV_HOTBACKUP */ #ifdef __WIN__ extern ibool srv_use_native_conditions; #endif diff --git a/storage/innobase/include/trx0sys.h b/storage/innobase/include/trx0sys.h index 3913792d594..635e7ec30b6 100644 --- a/storage/innobase/include/trx0sys.h +++ b/storage/innobase/include/trx0sys.h @@ -222,7 +222,6 @@ UNIV_INLINE trx_id_t trx_sys_get_new_trx_id(void); /*========================*/ -#endif /* !UNIV_HOTBACKUP */ #ifdef UNIV_DEBUG /* Flag to control TRX_RSEG_N_SLOTS behavior debugging. */ @@ -239,7 +238,6 @@ trx_write_trx_id( /*=============*/ byte* ptr, /*!< in: pointer to memory where written */ trx_id_t id); /*!< in: id */ -#ifndef UNIV_HOTBACKUP /*****************************************************************//** Reads a trx id from an index page. In case that the id size changes in some future version, this function should be used instead of @@ -572,7 +570,6 @@ FIL_PAGE_ARCH_LOG_NO_OR_SPACE_NO. */ #define TRX_SYS_DOUBLEWRITE_BLOCK_SIZE FSP_EXTENT_SIZE /* @} */ -#ifndef UNIV_HOTBACKUP /** File format tag */ /* @{ */ /** The offset of the file format tag on the trx system header page @@ -591,6 +588,7 @@ identifier is added to this 64-bit constant. */ | TRX_SYS_FILE_FORMAT_TAG_MAGIC_N_LOW) /* @} */ +#ifndef UNIV_HOTBACKUP /** Doublewrite control struct */ struct trx_doublewrite_struct{ mutex_t mutex; /*!< mutex protecting the first_free field and diff --git a/storage/innobase/mem/mem0dbg.c b/storage/innobase/mem/mem0dbg.c index ae43d6097a6..0909b7c9a64 100644 --- a/storage/innobase/mem/mem0dbg.c +++ b/storage/innobase/mem/mem0dbg.c @@ -24,7 +24,9 @@ but is included in mem0mem.* ! Created 6/9/1994 Heikki Tuuri *************************************************************************/ -#include "ha_prototypes.h" +#ifndef UNIV_HOTBACKUP +# include "ha_prototypes.h" +#endif /* !UNIV_HOTBACKUP */ #ifdef UNIV_MEM_DEBUG # ifndef UNIV_HOTBACKUP diff --git a/storage/innobase/os/os0file.c b/storage/innobase/os/os0file.c index 502cb44a0fa..1c50e903965 100644 --- a/storage/innobase/os/os0file.c +++ b/storage/innobase/os/os0file.c @@ -303,6 +303,7 @@ UNIV_INTERN ulint os_n_pending_writes = 0; UNIV_INTERN ulint os_n_pending_reads = 0; #ifdef UNIV_DEBUG +# ifndef UNIV_HOTBACKUP /**********************************************************************//** Validates the consistency the aio system some of the time. @return TRUE if ok or the check was skipped */ @@ -329,6 +330,7 @@ os_aio_validate_skip(void) os_aio_validate_count = OS_AIO_VALIDATE_SKIP; return(os_aio_validate()); } +# endif /* !UNIV_HOTBACKUP */ #endif /* UNIV_DEBUG */ #ifdef __WIN__ diff --git a/storage/innobase/page/page0zip.c b/storage/innobase/page/page0zip.c index fb618beac7e..ca3836689d3 100644 --- a/storage/innobase/page/page0zip.c +++ b/storage/innobase/page/page0zip.c @@ -4433,7 +4433,9 @@ page_zip_reorganize( dict_index_t* index, /*!< in: index of the B-tree node */ mtr_t* mtr) /*!< in: mini-transaction */ { +#ifndef UNIV_HOTBACKUP buf_pool_t* buf_pool = buf_pool_from_block(block); +#endif /* !UNIV_HOTBACKUP */ page_zip_des_t* page_zip = buf_block_get_page_zip(block); page_t* page = buf_block_get_frame(block); buf_block_t* temp_block; diff --git a/storage/innobase/trx/trx0sys.c b/storage/innobase/trx/trx0sys.c index 78d11f2d248..3d1a6bbed33 100644 --- a/storage/innobase/trx/trx0sys.c +++ b/storage/innobase/trx/trx0sys.c @@ -134,12 +134,12 @@ UNIV_INTERN mysql_pfs_key_t trx_doublewrite_mutex_key; UNIV_INTERN mysql_pfs_key_t file_format_max_mutex_key; #endif /* UNIV_PFS_MUTEX */ +#ifndef UNIV_HOTBACKUP #ifdef UNIV_DEBUG /* Flag to control TRX_RSEG_N_SLOTS behavior debugging. */ uint trx_rseg_n_slots_debug = 0; #endif -#ifndef UNIV_HOTBACKUP /** This is used to track the maximum file format id known to InnoDB. It's updated via SET GLOBAL innodb_file_format_max = 'x' or when we open or create a table. */ diff --git a/storage/innobase/ut/ut0dbg.c b/storage/innobase/ut/ut0dbg.c index 64fadd76d1c..53ed4a53044 100644 --- a/storage/innobase/ut/ut0dbg.c +++ b/storage/innobase/ut/ut0dbg.c @@ -25,7 +25,9 @@ Created 1/30/1994 Heikki Tuuri #include "univ.i" #include "ut0dbg.h" -#include "ha_prototypes.h" +#ifndef UNIV_HOTBACKUP +# include "ha_prototypes.h" +#endif /* !UNIV_HOTBACKUP */ #if defined(__GNUC__) && (__GNUC__ > 2) #else @@ -56,7 +58,7 @@ ut_dbg_assertion_failed( ut_print_timestamp(stderr); #ifdef UNIV_HOTBACKUP fprintf(stderr, " InnoDB: Assertion failure in file %s line %lu\n", - innobase_basename(file), line); + file, line); #else /* UNIV_HOTBACKUP */ fprintf(stderr, " InnoDB: Assertion failure in thread %lu" diff --git a/storage/innobase/ut/ut0ut.c b/storage/innobase/ut/ut0ut.c index 117a777cb98..2fe45aad2a7 100644 --- a/storage/innobase/ut/ut0ut.c +++ b/storage/innobase/ut/ut0ut.c @@ -245,7 +245,9 @@ ut_print_timestamp( (int)cal_tm.wMinute, (int)cal_tm.wSecond); #else +#ifdef HAVE_LOCALTIME_R struct tm cal_tm; +#endif struct tm* cal_tm_ptr; time_t tm; @@ -288,7 +290,9 @@ ut_sprintf_timestamp( (int)cal_tm.wMinute, (int)cal_tm.wSecond); #else +#ifdef HAVE_LOCALTIME_R struct tm cal_tm; +#endif struct tm* cal_tm_ptr; time_t tm; @@ -333,7 +337,9 @@ ut_sprintf_timestamp_without_extra_chars( (int)cal_tm.wMinute, (int)cal_tm.wSecond); #else +#ifdef HAVE_LOCALTIME_R struct tm cal_tm; +#endif struct tm* cal_tm_ptr; time_t tm; @@ -374,7 +380,9 @@ ut_get_year_month_day( *month = (ulint)cal_tm.wMonth; *day = (ulint)cal_tm.wDay; #else +#ifdef HAVE_LOCALTIME_R struct tm cal_tm; +#endif struct tm* cal_tm_ptr; time_t tm; From 5eecea8cafff69d9a3e3816d860fd9018af013b3 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Thu, 7 Jun 2012 19:55:22 +0400 Subject: [PATCH 078/289] MDEV-324: SHOW EXPLAIN: Plan produced by SHOW EXPLAIN for a query with TEMPTABLE view loses 'DERIVED' line - Make SHOW EXPLAIN code take into account that st_select_lex object without joins can be a full-featured SELECTs which were already executed and cleaned up. --- mysql-test/r/show_explain.result | 59 ++++++++++++++++++-------------- mysql-test/t/show_explain.test | 35 ++++++++++++++++++- sql/sql_class.cc | 24 +++++++++++-- sql/sql_class.h | 2 ++ sql/sql_lex.cc | 22 ++++++++---- sql/sql_lex.h | 6 ++-- sql/sql_select.cc | 9 +++++ sql/sql_show.cc | 1 + 8 files changed, 121 insertions(+), 37 deletions(-) diff --git a/mysql-test/r/show_explain.result b/mysql-test/r/show_explain.result index d6c46c81c79..aa473eafd9b 100644 --- a/mysql-test/r/show_explain.result +++ b/mysql-test/r/show_explain.result @@ -153,10 +153,7 @@ set @show_explain_probe_select_id=1; set debug_dbug='d,show_explain_probe_join_exec_end'; select a, (select max(a) from t0 b where b.a+a.a<10) from t0 a where a<1; show explain for $thr2; -id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Query plan already deleted -Warnings: -Note 1003 select a, (select max(a) from t0 b where b.a+a.a<10) from t0 a where a<1 +ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EXPLAINable command a (select max(a) from t0 b where b.a+a.a<10) 0 9 # Try to do SHOW EXPLAIN for a query that runs a SET command: @@ -308,12 +305,10 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 5 Using join buffer (flat, BNL join) set debug_dbug='d,show_explain_in_find_all_keys'; SELECT alias.a FROM t2, ( SELECT * FROM t2 ) AS alias GROUP BY alias.a; -# NOTE: current code will not show "Using join buffer": +# FIXED by "conservative assumptions about when QEP is available" fix: +# NOTE: current code will not show "Using join buffer": show explain for $thr2; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Query plan already deleted -Warnings: -Note 1003 SELECT alias.a FROM t2, ( SELECT * FROM t2 ) AS alias GROUP BY alias.a +ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EXPLAINable command a 1 2 @@ -366,10 +361,7 @@ set @show_explain_probe_select_id=2; set debug_dbug='d,show_explain_probe_join_exec_end'; SELECT * FROM v1, t2; show explain for $thr2; -id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Not yet optimized -Warnings: -Note 1003 SELECT * FROM v1, t2 +ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EXPLAINable command a b 8 4 8 5 @@ -401,10 +393,7 @@ set @show_explain_probe_select_id=1; set debug_dbug='d,show_explain_probe_join_exec_end'; select * from t0 where 1>10; show explain for $thr2; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Query plan already deleted -Warnings: -Note 1003 select * from t0 where 1>10 +ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EXPLAINable command a set debug_dbug=''; # @@ -416,10 +405,7 @@ set @show_explain_probe_select_id=1; set debug_dbug='d,show_explain_probe_join_exec_end'; select * from t0,t3 where t3.a=112233; show explain for $thr2; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Query plan already deleted -Warnings: -Note 1003 select * from t0,t3 where t3.a=112233 +ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EXPLAINable command a a set debug_dbug=''; drop table t3; @@ -524,10 +510,7 @@ set @show_explain_probe_select_id=1; set debug_dbug='d,show_explain_probe_join_exec_end'; SELECT * FROM t2 WHERE (5, 78) IN (SELECT `a1`, MAX(`a1`) FROM t2 GROUP BY `a1`); show explain for $thr2; -id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Query plan already deleted -Warnings: -Note 1003 SELECT * FROM t2 WHERE (5, 78) IN (SELECT `a1`, MAX(`a1`) FROM t2 GROUP BY `a1`) +ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EXPLAINable command pk a1 set debug_dbug=''; DROP TABLE t2; @@ -616,4 +599,30 @@ t1 1 b 1 b A NULL NULL NULL YES BTREE t1 1 c 1 c A NULL NULL NULL YES BTREE set debug_dbug=''; DROP TABLE t1; +# +# MDEV-324: SHOW EXPLAIN: Plan produced by SHOW EXPLAIN for a query with TEMPTABLE view +# loses 'DERIVED' line on the way without saying that the plan was already deleted +# +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1),(2); +CREATE ALGORITHM=TEMPTABLE VIEW v1 AS SELECT * FROM t1; +EXPLAIN SELECT a + 1 FROM v1; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ALL NULL NULL NULL NULL 2 +2 DERIVED t1 ALL NULL NULL NULL NULL 2 +set debug_dbug='d,show_explain_probe_join_tab_preread'; +set @show_explain_probe_select_id=1; +SELECT a + 1 FROM v1; +show explain for $thr2; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ALL NULL NULL NULL NULL 2 +2 DERIVED NULL NULL NULL NULL NULL NULL NULL Query plan already deleted +Warnings: +Note 1003 SELECT a + 1 FROM v1 +a + 1 +2 +3 +set debug_dbug=''; +DROP VIEW v1; +DROP TABLE t1; drop table t0; diff --git a/mysql-test/t/show_explain.test b/mysql-test/t/show_explain.test index 5605e304bcc..8f6b6301671 100644 --- a/mysql-test/t/show_explain.test +++ b/mysql-test/t/show_explain.test @@ -191,6 +191,7 @@ set debug_dbug='d,show_explain_probe_join_exec_end'; send select a, (select max(a) from t0 b where b.a+a.a<10) from t0 a where a<1; connection default; --source include/wait_condition.inc +--error ER_ERROR_WHEN_EXECUTING_COMMAND evalp show explain for $thr2; connection con1; reap; @@ -325,7 +326,9 @@ send SELECT alias.a FROM t2, ( SELECT * FROM t2 ) AS alias GROUP BY alias.a; connection default; --source include/wait_condition.inc ---echo # NOTE: current code will not show "Using join buffer": +--echo # FIXED by "conservative assumptions about when QEP is available" fix: +--echo # NOTE: current code will not show "Using join buffer": +--error ER_ERROR_WHEN_EXECUTING_COMMAND evalp show explain for $thr2; connection con1; reap; @@ -374,6 +377,7 @@ send SELECT * FROM v1, t2; connection default; --source include/wait_condition.inc +--error ER_ERROR_WHEN_EXECUTING_COMMAND evalp show explain for $thr2; connection con1; reap; @@ -403,6 +407,7 @@ set debug_dbug='d,show_explain_probe_join_exec_end'; send select * from t0 where 1>10; connection default; --source include/wait_condition.inc +--error ER_ERROR_WHEN_EXECUTING_COMMAND evalp show explain for $thr2; connection con1; reap; @@ -418,6 +423,7 @@ set debug_dbug='d,show_explain_probe_join_exec_end'; send select * from t0,t3 where t3.a=112233; connection default; --source include/wait_condition.inc +--error ER_ERROR_WHEN_EXECUTING_COMMAND evalp show explain for $thr2; connection con1; reap; @@ -513,6 +519,7 @@ send SELECT * FROM t2 WHERE (5, 78) IN (SELECT `a1`, MAX(`a1`) FROM t2 GROUP BY `a1`); connection default; --source include/wait_condition.inc +--error ER_ERROR_WHEN_EXECUTING_COMMAND evalp show explain for $thr2; connection con1; reap; @@ -601,6 +608,32 @@ set debug_dbug=''; DROP TABLE t1; +--echo # +--echo # MDEV-324: SHOW EXPLAIN: Plan produced by SHOW EXPLAIN for a query with TEMPTABLE view +--echo # loses 'DERIVED' line on the way without saying that the plan was already deleted +--echo # +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1),(2); +CREATE ALGORITHM=TEMPTABLE VIEW v1 AS SELECT * FROM t1; + +EXPLAIN SELECT a + 1 FROM v1; + +set debug_dbug='d,show_explain_probe_join_tab_preread'; +set @show_explain_probe_select_id=1; + +send + SELECT a + 1 FROM v1; +connection default; +--source include/wait_condition.inc +evalp show explain for $thr2; +connection con1; +reap; +set debug_dbug=''; + +DROP VIEW v1; +DROP TABLE t1; + + ## TODO: Test this: have several SHOW EXPLAIN requests be queued up for a ## thread and served together. diff --git a/sql/sql_class.cc b/sql/sql_class.cc index f477c0fe0ec..65ead744ddb 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -2356,13 +2356,14 @@ int select_result_explain_buffer::send_data(List &items) } +/* Write all strings out to the output, and free them. */ + void select_result_explain_buffer::flush_data() { List_iterator it(data_rows); String *str; while ((str= it++)) { - /* TODO: write out the lines. */ protocol->set_packet(str->ptr(), str->length()); protocol->write(); delete str; @@ -2370,6 +2371,20 @@ void select_result_explain_buffer::flush_data() data_rows.empty(); } + +/* Just free all of the accumulated strings */ + +void select_result_explain_buffer::discard_data() +{ + List_iterator it(data_rows); + String *str; + while ((str= it++)) + { + delete str; + } + data_rows.empty(); +} + ////////////////////////////////////////////////////////////////////////////// @@ -3288,6 +3303,7 @@ void Show_explain_request::get_explain_data(void *arg) // Actually, change the ARENA, because we're going to allocate items! Query_arena backup_arena; THD *target_thd= req->target_thd; + bool printed_anything= FALSE; target_thd->set_n_backup_active_arena((Query_arena*)req->request_thd, &backup_arena); @@ -3296,7 +3312,11 @@ void Show_explain_request::get_explain_data(void *arg) target_thd->query_length(), &my_charset_bin); - if (target_thd->lex->unit.print_explain(req->explain_buf, 0 /* explain flags */)) + if (target_thd->lex->unit.print_explain(req->explain_buf, 0 /* explain flags*/, + &printed_anything)) + req->failed_to_produce= TRUE; + + if (!printed_anything) req->failed_to_produce= TRUE; target_thd->restore_active_arena((Query_arena*)req->request_thd, diff --git a/sql/sql_class.h b/sql/sql_class.h index 6be477605f1..0d58bb413f0 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -3328,6 +3328,8 @@ public: /* this will be called in the parent thread: */ void flush_data(); + void discard_data(); + List data_rows; }; diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index df0fcd24249..99320d88702 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -4074,7 +4074,8 @@ int print_explain_message_line(select_result_sink *result, int st_select_lex::print_explain(select_result_sink *output, - uint8 explain_flags) + uint8 explain_flags, + bool *printed_anything) { int res; if (join && join->have_query_plan == JOIN::QEP_AVAILABLE) @@ -4083,6 +4084,7 @@ int st_select_lex::print_explain(select_result_sink *output, There is a number of reasons join can be marked as degenerate, so all three conditions below can happen simultaneously, or individually: */ + *printed_anything= TRUE; if (!join->table_count || !join->tables_list || join->zero_result_cause) { /* It's a degenerate join */ @@ -4112,7 +4114,8 @@ int st_select_lex::print_explain(select_result_sink *output, */ if (!(unit->item && unit->item->eliminated)) { - unit->print_explain(output, explain_flags); + if ((res= unit->print_explain(output, explain_flags, printed_anything))) + goto err; } } } @@ -4120,7 +4123,9 @@ int st_select_lex::print_explain(select_result_sink *output, { const char *msg; if (!join) - DBUG_ASSERT(0); // psergey: TODO: can this happen or not? + DBUG_ASSERT(0); /* Seems not to be possible */ + + /* Not printing anything useful, don't touch *printed_anything here */ if (join->have_query_plan == JOIN::QEP_NOT_PRESENT_YET) msg= "Not yet optimized"; else @@ -4132,12 +4137,12 @@ int st_select_lex::print_explain(select_result_sink *output, 0, msg); } err: - return 0; + return res; } int st_select_lex_unit::print_explain(select_result_sink *output, - uint8 explain_flags) + uint8 explain_flags, bool *printed_anything) { int res= 0; SELECT_LEX *first= first_select(); @@ -4148,12 +4153,15 @@ int st_select_lex_unit::print_explain(select_result_sink *output, If there is only one child, 'first', and it has join==NULL, emit "not in EXPLAIN state" error. */ - return 1; + const char *msg="Query plan already deleted"; + res= print_explain_message_line(output, first, TRUE /* on_the_fly */, + 0, msg); + return 0; } for (SELECT_LEX *sl= first; sl; sl= sl->next_select()) { - if ((res= sl->print_explain(output, explain_flags))) + if ((res= sl->print_explain(output, explain_flags, printed_anything))) break; } diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 911a6b766f6..eb908089479 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -718,7 +718,8 @@ public: friend int subselect_union_engine::exec(); List *get_unit_column_types(); - int print_explain(select_result_sink *output, uint8 explain_flags); + int print_explain(select_result_sink *output, uint8 explain_flags, + bool *printed_anything); }; typedef class st_select_lex_unit SELECT_LEX_UNIT; @@ -1039,7 +1040,8 @@ public: bool save_prep_leaf_tables(THD *thd); bool is_merged_child_of(st_select_lex *ancestor); - int print_explain(select_result_sink *output, uint8 explain_flags); + int print_explain(select_result_sink *output, uint8 explain_flags, + bool *printed_anything); /* For MODE_ONLY_FULL_GROUP_BY we need to maintain two flags: - Non-aggregated fields are used in this select. diff --git a/sql/sql_select.cc b/sql/sql_select.cc index aba5c0761c8..5aa69f54fa3 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -10365,9 +10365,18 @@ bool JOIN_TAB::preread_init() mysql_handle_single_derived(join->thd->lex, derived, DT_CREATE | DT_FILL)) return TRUE; + preread_init_done= TRUE; if (select && select->quick) select->quick->replace_handler(table->file); + + DBUG_EXECUTE_IF("show_explain_probe_join_tab_preread", + if (dbug_user_var_equals_int(join->thd, + "show_explain_probe_select_id", + join->select_lex->select_number)) + dbug_serve_apcs(join->thd, 1); + ); + return FALSE; } diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 5079e82fa40..9f0adf4a608 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2085,6 +2085,7 @@ void mysqld_show_explain(THD *thd, ulong thread_id) "Target is not running EXPLAINable command"); } bres= TRUE; + explain_buf->discard_data(); } else { From a161c19bf25145f70c77561c38b99148deb84481 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Thu, 7 Jun 2012 20:03:36 +0400 Subject: [PATCH 079/289] Fix test results to deal with rounding error in #rows in EXPLAIN output. --- mysql-test/include/index_merge2.inc | 1 + mysql-test/r/index_merge_innodb.result | 2 +- mysql-test/r/index_merge_myisam.result | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/mysql-test/include/index_merge2.inc b/mysql-test/include/index_merge2.inc index 1d6b82e1787..99af143a4e0 100644 --- a/mysql-test/include/index_merge2.inc +++ b/mysql-test/include/index_merge2.inc @@ -343,6 +343,7 @@ alter table t1 add index i3(key3); update t1 set key2=key1,key3=key1; # to test the bug, the following must use "sort_union": +--replace_column 9 ROWS explain select * from t1 where (key3 > 30 and key3<35) or (key2 >32 and key2 < 40); select * from t1 where (key3 > 30 and key3<35) or (key2 >32 and key2 < 40); drop table t1; diff --git a/mysql-test/r/index_merge_innodb.result b/mysql-test/r/index_merge_innodb.result index b00a949fcbc..7a8a8db517e 100644 --- a/mysql-test/r/index_merge_innodb.result +++ b/mysql-test/r/index_merge_innodb.result @@ -313,7 +313,7 @@ alter table t1 add index i3(key3); update t1 set key2=key1,key3=key1; explain select * from t1 where (key3 > 30 and key3<35) or (key2 >32 and key2 < 40); id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge i2,i3 i3,i2 4,4 NULL 8 Using sort_union(i3,i2); Using where +1 SIMPLE t1 index_merge i2,i3 i3,i2 4,4 NULL ROWS Using sort_union(i3,i2); Using where select * from t1 where (key3 > 30 and key3<35) or (key2 >32 and key2 < 40); key1 key2 key3 31 31 31 diff --git a/mysql-test/r/index_merge_myisam.result b/mysql-test/r/index_merge_myisam.result index b560c1e5176..8bb3f95934d 100644 --- a/mysql-test/r/index_merge_myisam.result +++ b/mysql-test/r/index_merge_myisam.result @@ -1146,7 +1146,7 @@ alter table t1 add index i3(key3); update t1 set key2=key1,key3=key1; explain select * from t1 where (key3 > 30 and key3<35) or (key2 >32 and key2 < 40); id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge i2,i3 i3,i2 4,4 NULL 11 Using sort_union(i3,i2); Using where +1 SIMPLE t1 index_merge i2,i3 i3,i2 4,4 NULL ROWS Using sort_union(i3,i2); Using where select * from t1 where (key3 > 30 and key3<35) or (key2 >32 and key2 < 40); key1 key2 key3 31 31 31 From 950dc8022e64339abc93adc6953661cf38afa530 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Thu, 7 Jun 2012 21:19:22 +0400 Subject: [PATCH 080/289] MDEV-323: SHOW EXPLAIN: Plan produced by SHOW EXPLAIN loses 'UNION RESULT' line - Make SHOW EXPLAIN code correctly print fake_select_lex: both in the case where it has not yet been executed, and when it has been executed. --- mysql-test/r/show_explain.result | 34 ++++++++++++++++++++++++++++++++ mysql-test/t/show_explain.test | 27 +++++++++++++++++++++++++ sql/sql_lex.cc | 6 ++---- sql/sql_union.cc | 2 ++ 4 files changed, 65 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/show_explain.result b/mysql-test/r/show_explain.result index aa473eafd9b..14569b5c14b 100644 --- a/mysql-test/r/show_explain.result +++ b/mysql-test/r/show_explain.result @@ -625,4 +625,38 @@ a + 1 set debug_dbug=''; DROP VIEW v1; DROP TABLE t1; +# +# MDEV-323: SHOW EXPLAIN: Plan produced by SHOW EXPLAIN loses +# 'UNION RESULT' line on the way without saying that the plan was already deleted +# +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (4),(6); +EXPLAIN +SELECT a FROM t1 WHERE a IN ( SELECT 1+SLEEP(0.01) UNION SELECT 2 ); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where +2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL No tables used +3 DEPENDENT UNION NULL NULL NULL NULL NULL NULL NULL No tables used +NULL UNION RESULT ALL NULL NULL NULL NULL NULL +set debug_dbug='d,show_explain_probe_union_read'; +SELECT a FROM t1 WHERE a IN ( SELECT 1+SLEEP(0.01) UNION SELECT 2 ); +show explain for $thr2; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where +2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL No tables used +3 DEPENDENT UNION NULL NULL NULL NULL NULL NULL NULL No tables used +NULL UNION RESULT ALL NULL NULL NULL NULL NULL +Warnings: +Note 1003 SELECT a FROM t1 WHERE a IN ( SELECT 1+SLEEP(0.01) UNION SELECT 2 ) +show explain for $thr2; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where +2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL No tables used +3 DEPENDENT UNION NULL NULL NULL NULL NULL NULL NULL No tables used +NULL UNION RESULT ALL NULL NULL NULL NULL NULL +Warnings: +Note 1003 SELECT a FROM t1 WHERE a IN ( SELECT 1+SLEEP(0.01) UNION SELECT 2 ) +a +set debug_dbug=''; +DROP TABLE t1; drop table t0; diff --git a/mysql-test/t/show_explain.test b/mysql-test/t/show_explain.test index 8f6b6301671..1c890262758 100644 --- a/mysql-test/t/show_explain.test +++ b/mysql-test/t/show_explain.test @@ -634,6 +634,33 @@ DROP VIEW v1; DROP TABLE t1; +--echo # +--echo # MDEV-323: SHOW EXPLAIN: Plan produced by SHOW EXPLAIN loses +--echo # 'UNION RESULT' line on the way without saying that the plan was already deleted +--echo # +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (4),(6); + +EXPLAIN +SELECT a FROM t1 WHERE a IN ( SELECT 1+SLEEP(0.01) UNION SELECT 2 ); + +set debug_dbug='d,show_explain_probe_union_read'; +send +SELECT a FROM t1 WHERE a IN ( SELECT 1+SLEEP(0.01) UNION SELECT 2 ); + +connection default; +--source include/wait_condition.inc +evalp show explain for $thr2; + +--source include/wait_condition.inc +evalp show explain for $thr2; + +connection con1; +reap; + +set debug_dbug=''; + +DROP TABLE t1; ## TODO: Test this: have several SHOW EXPLAIN requests be queued up for a ## thread and served together. diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 99320d88702..fafa100396d 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -4165,10 +4165,8 @@ int st_select_lex_unit::print_explain(select_result_sink *output, break; } - /* - Note: it could be that fake_select_lex->join == NULL still at this point - */ - if (fake_select_lex && !fake_select_lex->join) + /* Note: fake_select_lex->join may be NULL or non-NULL at this point */ + if (fake_select_lex) { res= print_fake_select_lex_join(output, TRUE /* on the fly */, fake_select_lex, explain_flags); diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 021267b53bd..b0e4239e6cd 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -720,6 +720,8 @@ bool st_select_lex_unit::exec() } } + DBUG_EXECUTE_IF("show_explain_probe_union_read", + dbug_serve_apcs(thd, 1);); /* Send result to 'result' */ saved_error= TRUE; { From cf8461a0f75eebcc15cddd3c48d5e24f872930c2 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Fri, 8 Jun 2012 02:19:36 +0400 Subject: [PATCH 081/289] SHOW EXPLAIN: Code cleanup --- sql/filesort.cc | 3 --- sql/item_subselect.cc | 1 - sql/my_apc.h | 3 +-- sql/opt_subselect.cc | 2 +- sql/sql_class.cc | 13 +++++++------ sql/sql_select.cc | 6 +----- 6 files changed, 10 insertions(+), 18 deletions(-) diff --git a/sql/filesort.cc b/sql/filesort.cc index 5220d80767d..6d1cabb02b7 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -502,7 +502,6 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select, my_off_t record; TABLE *sort_form; THD *thd= current_thd; - //volatile killed_state *killed= &thd->killed; handler *file; MY_BITMAP *save_read_set, *save_write_set, *save_vcol_set; uchar *next_sort_key= sort_keys_buf; @@ -1236,9 +1235,7 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file, void *first_cmp_arg; element_count dupl_count= 0; uchar *src; - /* killed_state not_killable; */ uchar *unique_buff= param->unique_buff; - /* volatile killed_state *killed= ¤t_thd->killed; */ const bool killable= !param->not_killable; THD* const thd=current_thd; DBUG_ENTER("merge_buffers"); diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 7b1e4fc8b27..276f35fe301 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -4725,7 +4725,6 @@ int subselect_hash_sj_engine::exec() thd->lex->current_select= materialize_engine->select_lex; /* The subquery should be optimized, and materialized only once. */ DBUG_ASSERT(materialize_join->optimized && !is_materialized); - materialize_join->exec(); if ((res= test(materialize_join->error || thd->is_fatal_error || thd->is_error()))) diff --git a/sql/my_apc.h b/sql/my_apc.h index 8e6980fa855..5de1cf7d8d3 100644 --- a/sql/my_apc.h +++ b/sql/my_apc.h @@ -53,8 +53,7 @@ public: int timeout_sec, bool *timed_out); #ifndef DBUG_OFF - int n_calls_processed; - //int call_queue_size; + int n_calls_processed; /* Number of calls served by this target */ #endif private: class Call_request; diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index 34e73f5cac8..dfd0785cc4a 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -1656,7 +1656,7 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred) while ((ifm= li++)) parent_lex->ftfunc_list->push_front(ifm); } - + parent_lex->have_merged_subqueries= TRUE; DBUG_RETURN(FALSE); } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 65ead744ddb..ba9140fc9bc 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1361,7 +1361,7 @@ void THD::cleanup(void) mysql_mutex_unlock(&LOCK_user_locks); ull= NULL; } - + apc_target.destroy(); cleanup_done=1; DBUG_VOID_RETURN; @@ -1372,8 +1372,6 @@ THD::~THD() { THD_CHECK_SENTRY(this); DBUG_ENTER("~THD()"); - //psergey-todo: assert that the queue is disabled and empty. - /* Ensure that no one is using THD */ mysql_mutex_lock(&LOCK_thd_data); mysys_var=0; // Safety (shouldn't be needed) @@ -2311,8 +2309,8 @@ int select_send::send_data(List &items) DBUG_RETURN(0); } - ////////////////////////////////////////////////////////////////////////////// + int select_result_explain_buffer::send_data(List &items) { List_iterator_fast li(items); @@ -2336,13 +2334,16 @@ int select_result_explain_buffer::send_data(List &items) */ buffer.set(buff, sizeof(buff), &my_charset_bin); } - //TODO: do we need the following: + if (thd->is_error()) { protocol->remove_last_row(); DBUG_RETURN(1); } - /* psergey-TODO: instead of protocol->write(), steal the packet here */ + /* + Instead of calling protocol->write(), steal the packed and put it to our + buffer + */ const char *packet_data; size_t len; protocol->get_packet(&packet_data, &len); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 5aa69f54fa3..e1af5605d37 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2228,7 +2228,7 @@ void JOIN::exec_inner() List *columns_list= &fields_list; int tmp_error; DBUG_ENTER("JOIN::exec"); - + thd_proc_info(thd, "executing"); error= 0; if (procedure) @@ -2526,16 +2526,12 @@ void JOIN::exec_inner() /* Free first data from old join */ - fprintf(stderr,"Q: %s\n", thd->query()); - //DBUG_ASSERT(0); /* psergey-todo: this is the place of pre-mature JOIN::free call. */ curr_join->join_free(); - //psergey-todo: SHOW EXPLAIN probe here if (curr_join->make_simple_join(this, curr_tmp_table)) DBUG_VOID_RETURN; - //psergey-todo: SHOW EXPLAIN probe here calc_group_buffer(curr_join, group_list); count_field_types(select_lex, &curr_join->tmp_table_param, curr_join->tmp_all_fields1, From d74c3df6ce335a5febbc49530b5e43625b68352d Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Fri, 8 Jun 2012 16:31:03 +0200 Subject: [PATCH 082/289] Backport SuSE 11 fix to RPM spec file --- support-files/mysql.spec.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index a3d8554188e..5b9a296d90a 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -176,7 +176,7 @@ %endif %else %if %(test -f /etc/SuSE-release && echo 1 || echo 0) - %define susever %(rpm -qf --qf '%%{version}\\n' /etc/SuSE-release) + %define susever %(rpm -qf --qf '%%{version}\\n' /etc/SuSE-release | cut -d. -f1) %if "%susever" == "10" %define distro_description SUSE Linux Enterprise Server 10 %define distro_releasetag sles10 From 6094d190954285f43000dc44e03934ffb8582eb9 Mon Sep 17 00:00:00 2001 From: Jon Olav Hauglid Date: Tue, 12 Jun 2012 15:04:57 +0200 Subject: [PATCH 083/289] Bug#13586591 RQG GRAMMAR CONF/ENGINES/ENGINE_STRESS.YY CRASHES INNODB | TRX_STATE_NOT_STARTED The problem was that if DELETE with subselect caused a deadlock inside InnoDB, this deadlock was not properly handled by the SQL layer. This meant that the SQL layer would try to unlock the row after InnoDB had rolled back the transaction. This caused an assertion inside InnoDB. This patch fixes the problem by checking for errors reported by SQL_SELECT::skip_record() and not calling unlock_row() if any errors have been reported. --- sql/sql_delete.cc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 4fd1815ad7f..1bbc9af0835 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -341,8 +341,14 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, break; } } - else + /* + Don't try unlocking the row if skip_record reported an error since in + this case the transaction might have been rolled back already. + */ + else if (!thd->is_error()) table->file->unlock_row(); // Row failed selection, release lock on it + else + break; } killed_status= thd->killed; if (killed_status != THD::NOT_KILLED || thd->is_error()) From cf37a481f0114d4cdb40c4d8fb483939f6b1bc5a Mon Sep 17 00:00:00 2001 From: Harin Vadodaria Date: Wed, 13 Jun 2012 16:03:58 +0530 Subject: [PATCH 084/289] Bug#11753779: MAX_CONNECT_ERRORS WORKS ONLY WHEN 1ST INC_HOST_ERRORS() IS CALLED. Issue : Sequence of calling inc_host_errors() and reset_host_errors() required some changes in order to maintain correct connection error count. Solution : Call to reset_host_errors() is shifted to a location after which no calls to inc_host_errors() are made. --- sql/hostname.cc | 9 ++++++++ sql/sql_connect.cc | 54 ++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 59 insertions(+), 4 deletions(-) diff --git a/sql/hostname.cc b/sql/hostname.cc index 9796755e9fb..38316a8ee19 100644 --- a/sql/hostname.cc +++ b/sql/hostname.cc @@ -214,6 +214,15 @@ char * ip_to_hostname(struct in_addr *in, uint *errors) } my_gethostbyname_r_free(); #else + + DBUG_EXECUTE_IF("addr_fake_ipv4", + { + const char* fake_host= "santa.claus.ipv4.example.com"; + name=my_strdup(fake_host, MYF(0)); + add_hostname(in,name); + DBUG_RETURN(name); + };); + VOID(pthread_mutex_lock(&LOCK_hostname)); if (!(hp=gethostbyaddr((char*) in,sizeof(*in), AF_INET))) { diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 21e2701d06c..7a934541d53 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -360,7 +360,6 @@ check_user(THD *thd, enum enum_server_command command, if (send_old_password_request(thd) || my_net_read(net) != SCRAMBLE_LENGTH_323 + 1) { - inc_host_errors(&thd->remote.sin_addr); my_error(ER_HANDSHAKE_ERROR, MYF(0)); DBUG_RETURN(1); } @@ -832,6 +831,19 @@ static int check_connection(THD *thd) my_error(ER_BAD_HOST_ERROR, MYF(0)); return 1; } + /* BEGIN : DEBUG */ + DBUG_EXECUTE_IF("addr_fake_ipv4", + { + struct sockaddr *sa= (sockaddr *) &net->vio->remote; + sa->sa_family= AF_INET; + struct in_addr *ip4= &((struct sockaddr_in *)sa)->sin_addr; + /* See RFC 5737, 192.0.2.0/23 is reserved */ + const char* fake= "192.0.2.4"; + ip4->s_addr= inet_addr(fake); + strcpy(ip, fake); + };); + /* END : DEBUG */ + if (!(thd->main_security_ctx.ip= my_strdup(ip,MYF(MY_WME)))) return 1; /* The error is set by my_strdup(). */ thd->main_security_ctx.host_or_ip= thd->main_security_ctx.ip; @@ -935,8 +947,6 @@ static int check_connection(THD *thd) #ifdef _CUSTOMCONFIG_ #include "_cust_sql_parse.h" #endif - if (connect_errors) - reset_host_errors(&thd->remote.sin_addr); if (thd->packet.alloc(thd->variables.net_buffer_length)) return 1; /* The error is set by alloc(). */ @@ -953,6 +963,10 @@ static int check_connection(THD *thd) Peek ahead on the client capability packet and determine which version of the protocol should be used. */ + DBUG_EXECUTE_IF("host_error_packet_length", + { + bytes_remaining_in_packet= 0; + };); if (bytes_remaining_in_packet < 2) goto error; @@ -1011,6 +1025,10 @@ static int check_connection(THD *thd) skip_to_ssl: + DBUG_EXECUTE_IF("host_error_charset", + { + goto error; + };); DBUG_PRINT("info", ("client_character_set: %u", charset_code)); if (thd_init_client_charset(thd, charset_code)) goto error; @@ -1079,6 +1097,10 @@ skip_to_ssl: bytes_remaining_in_packet -= AUTH_PACKET_HEADER_SIZE_PROTO_40; } + DBUG_EXECUTE_IF("host_error_SSL_layering", + { + packet_has_required_size= 0; + };); if (!packet_has_required_size) goto error; } @@ -1104,6 +1126,11 @@ skip_to_ssl: get_string= get_40_protocol_string; user= get_string(&end, &bytes_remaining_in_packet, &user_len); + DBUG_EXECUTE_IF("host_error_user", + { + user= NULL; + };); + if (user == NULL) goto error; @@ -1131,6 +1158,11 @@ skip_to_ssl: passwd= get_string(&end, &bytes_remaining_in_packet, &passwd_len); } + DBUG_EXECUTE_IF("host_error_password", + { + passwd= NULL; + };); + if (passwd == NULL) goto error; @@ -1191,7 +1223,21 @@ skip_to_ssl: if (!(thd->main_security_ctx.user= my_strdup(user, MYF(MY_WME)))) return 1; /* The error is set by my_strdup(). */ - return check_user(thd, COM_CONNECT, passwd, passwd_len, db, TRUE); + + if (!check_user(thd, COM_CONNECT, passwd, passwd_len, db, TRUE)) + { + /* + Call to reset_host_errors() should be made only when all sanity checks + are done and connection is going to be a successful. + */ + reset_host_errors(&thd->remote.sin_addr); + return 0; + } + else + { + inc_host_errors(&thd->remote.sin_addr); + return 1; + } error: inc_host_errors(&thd->remote.sin_addr); From 775293b898aa6c5239b17de5d489768de5287803 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 14 Jun 2012 17:07:49 +0530 Subject: [PATCH 085/289] BUG #13946716: FEDERATED_PLUGIN TEST CASE FAIL ON 64BIT ARCHITECTURES --- mysql-test/mysql-test-run.pl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 294dcf13615..674abe7e102 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -1969,6 +1969,7 @@ sub environment_setup { my $lib_example_plugin= mtr_file_exists(vs_config_dirs('storage/example',$plugin_filename), "$basedir/storage/example/.libs/".$plugin_filename, + "$basedir/lib64/mysql/plugin/".$plugin_filename, "$basedir/lib/mysql/plugin/".$plugin_filename); $ENV{'EXAMPLE_PLUGIN'}= ($lib_example_plugin ? basename($lib_example_plugin) : ""); @@ -1991,6 +1992,7 @@ sub environment_setup { my $lib_fed_plugin= mtr_file_exists(vs_config_dirs('storage/federated',$fedplug_filename), "$basedir/storage/federated/.libs/".$fedplug_filename, + "$basedir/lib64/mysql/plugin/".$fedplug_filename, "$basedir/lib/mysql/plugin/".$fedplug_filename); $ENV{'FEDERATED_PLUGIN'}= $fedplug_filename; From bd223999dcd20f67a087ba1dadeecd41a0c5622f Mon Sep 17 00:00:00 2001 From: Sunanda Menon Date: Fri, 15 Jun 2012 10:34:18 +0200 Subject: [PATCH 086/289] Raising the VERSION number after 5.5.26 clone-off --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index a6ecc1acc76..2ac736f0617 100644 --- a/VERSION +++ b/VERSION @@ -1,4 +1,4 @@ MYSQL_VERSION_MAJOR=5 MYSQL_VERSION_MINOR=5 -MYSQL_VERSION_PATCH=26 +MYSQL_VERSION_PATCH=27 MYSQL_VERSION_EXTRA= From bc42eaf95283f66788a70acbed1d7368c784a9a1 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 15 Jun 2012 13:31:27 +0200 Subject: [PATCH 087/289] Raise version number after cloning 5.1.64 --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index 84295a15f4a..4e7a3303353 100644 --- a/configure.in +++ b/configure.in @@ -12,7 +12,7 @@ dnl dnl When changing the major version number please also check the switch dnl statement in mysqlbinlog::check_master_version(). You may also need dnl to update version.c in ndb. -AC_INIT([MySQL Server], [5.1.64], [], [mysql]) +AC_INIT([MySQL Server], [5.1.65], [], [mysql]) AC_CONFIG_SRCDIR([sql/mysqld.cc]) AC_CANONICAL_SYSTEM From cac1cd88abc2a610b42b89e5d39029f75a760ec4 Mon Sep 17 00:00:00 2001 From: "Norvald H. Ryeng" Date: Mon, 18 Jun 2012 09:20:12 +0200 Subject: [PATCH 088/289] Bug#13003736 CRASH IN ITEM_REF::WALK WITH SUBQUERIES Problem: Some queries with subqueries and a HAVING clause that consists only of a column not in the select or grouping lists causes the server to crash. During parsing, an Item_ref is constructed for the HAVING column. The name of the column is resolved when JOIN::prepare calls fix_fields() on its having clause. Since the column is not mentioned in the select or grouping lists, a ref pointer is not found and a new Item_field is created instead. The Item_ref is replaced by the Item_field in the tree of HAVING clauses. Since the tree consists only of this item, the pointer that is updated is JOIN::having. However, st_select_lex::having still points to the Item_ref as the root of the tree of HAVING clauses. The bug is triggered when doing filesort for create_sort_index(). When find_all_keys() calls select->cond->walk() it eventually reaches Item_subselect::walk() where it continues to walk the having clauses from lex->having. This means that it finds the Item_ref instead of the new Item_field, and Item_ref::walk() tries to dereference the ref pointer, which is still null. The crash is reproducible only in 5.5, but the problem lies latent in 5.1 and trunk as well. Fix: After calling fix_fields on the having clause in JOIN::prepare(), set select_lex::having to point to the same item as JOIN::having. This patch also fixes a bug in 5.1 and 5.5 that is triggered if the query is executed as a prepared statement. The Item_field is created in the runtime arena when the query is prepared, and the pointer to the item is saved by st_select_lex::fix_prepare_information() and brought back as a dangling pointer when the query is executed, after the runtime arena has been reclaimed. Fix: Backport fix from trunk that switches to the permanent arena before calling Item_ref::fix_fields() in JOIN::prepare(). sql/item.cc: Set context when creating Item_field. sql/sql_select.cc: Switch to permanent arena and update select_lex->having. --- sql/item.cc | 2 +- sql/sql_select.cc | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/sql/item.cc b/sql/item.cc index 90bfb0d2852..356fe4827c8 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -6010,7 +6010,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference) if (from_field != not_found_field) { Item_field* fld; - if (!(fld= new Item_field(from_field))) + if (!(fld= new Item_field(thd, last_checked_context, from_field))) goto error; thd->change_item_tree(reference, fld); mark_as_dependent(thd, last_checked_context->select_lex, diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 7c3d2de22bc..f2007f609e0 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -528,6 +528,8 @@ JOIN::prepare(Item ***rref_pointer_array, if (having) { + Query_arena backup, *arena; + arena= thd->activate_stmt_arena_if_needed(&backup); nesting_map save_allow_sum_func= thd->lex->allow_sum_func; thd->where="having clause"; thd->lex->allow_sum_func|= 1 << select_lex_arg->nest_level; @@ -536,6 +538,10 @@ JOIN::prepare(Item ***rref_pointer_array, (having->fix_fields(thd, &having) || having->check_cols(1))); select_lex->having_fix_field= 0; + select_lex->having= having; + if (arena) + thd->restore_active_arena(arena, &backup); + if (having_fix_rc || thd->is_error()) DBUG_RETURN(-1); /* purecov: inspected */ thd->lex->allow_sum_func= save_allow_sum_func; From 61e428eb846e820ba0764932d1604859e53abe52 Mon Sep 17 00:00:00 2001 From: Harin Vadodaria Date: Tue, 19 Jun 2012 12:56:40 +0530 Subject: [PATCH 089/289] Bug#11753779: MAX_CONNECT_ERRORS WORKS ONLY WHEN 1ST INC_HOST_ERRORS() IS CALLED. Description: Reverting patch 3755 for bug#11753779 --- sql/hostname.cc | 9 -------- sql/sql_connect.cc | 54 ++++------------------------------------------ 2 files changed, 4 insertions(+), 59 deletions(-) diff --git a/sql/hostname.cc b/sql/hostname.cc index 38316a8ee19..9796755e9fb 100644 --- a/sql/hostname.cc +++ b/sql/hostname.cc @@ -214,15 +214,6 @@ char * ip_to_hostname(struct in_addr *in, uint *errors) } my_gethostbyname_r_free(); #else - - DBUG_EXECUTE_IF("addr_fake_ipv4", - { - const char* fake_host= "santa.claus.ipv4.example.com"; - name=my_strdup(fake_host, MYF(0)); - add_hostname(in,name); - DBUG_RETURN(name); - };); - VOID(pthread_mutex_lock(&LOCK_hostname)); if (!(hp=gethostbyaddr((char*) in,sizeof(*in), AF_INET))) { diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 7a934541d53..21e2701d06c 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -360,6 +360,7 @@ check_user(THD *thd, enum enum_server_command command, if (send_old_password_request(thd) || my_net_read(net) != SCRAMBLE_LENGTH_323 + 1) { + inc_host_errors(&thd->remote.sin_addr); my_error(ER_HANDSHAKE_ERROR, MYF(0)); DBUG_RETURN(1); } @@ -831,19 +832,6 @@ static int check_connection(THD *thd) my_error(ER_BAD_HOST_ERROR, MYF(0)); return 1; } - /* BEGIN : DEBUG */ - DBUG_EXECUTE_IF("addr_fake_ipv4", - { - struct sockaddr *sa= (sockaddr *) &net->vio->remote; - sa->sa_family= AF_INET; - struct in_addr *ip4= &((struct sockaddr_in *)sa)->sin_addr; - /* See RFC 5737, 192.0.2.0/23 is reserved */ - const char* fake= "192.0.2.4"; - ip4->s_addr= inet_addr(fake); - strcpy(ip, fake); - };); - /* END : DEBUG */ - if (!(thd->main_security_ctx.ip= my_strdup(ip,MYF(MY_WME)))) return 1; /* The error is set by my_strdup(). */ thd->main_security_ctx.host_or_ip= thd->main_security_ctx.ip; @@ -947,6 +935,8 @@ static int check_connection(THD *thd) #ifdef _CUSTOMCONFIG_ #include "_cust_sql_parse.h" #endif + if (connect_errors) + reset_host_errors(&thd->remote.sin_addr); if (thd->packet.alloc(thd->variables.net_buffer_length)) return 1; /* The error is set by alloc(). */ @@ -963,10 +953,6 @@ static int check_connection(THD *thd) Peek ahead on the client capability packet and determine which version of the protocol should be used. */ - DBUG_EXECUTE_IF("host_error_packet_length", - { - bytes_remaining_in_packet= 0; - };); if (bytes_remaining_in_packet < 2) goto error; @@ -1025,10 +1011,6 @@ static int check_connection(THD *thd) skip_to_ssl: - DBUG_EXECUTE_IF("host_error_charset", - { - goto error; - };); DBUG_PRINT("info", ("client_character_set: %u", charset_code)); if (thd_init_client_charset(thd, charset_code)) goto error; @@ -1097,10 +1079,6 @@ skip_to_ssl: bytes_remaining_in_packet -= AUTH_PACKET_HEADER_SIZE_PROTO_40; } - DBUG_EXECUTE_IF("host_error_SSL_layering", - { - packet_has_required_size= 0; - };); if (!packet_has_required_size) goto error; } @@ -1126,11 +1104,6 @@ skip_to_ssl: get_string= get_40_protocol_string; user= get_string(&end, &bytes_remaining_in_packet, &user_len); - DBUG_EXECUTE_IF("host_error_user", - { - user= NULL; - };); - if (user == NULL) goto error; @@ -1158,11 +1131,6 @@ skip_to_ssl: passwd= get_string(&end, &bytes_remaining_in_packet, &passwd_len); } - DBUG_EXECUTE_IF("host_error_password", - { - passwd= NULL; - };); - if (passwd == NULL) goto error; @@ -1223,21 +1191,7 @@ skip_to_ssl: if (!(thd->main_security_ctx.user= my_strdup(user, MYF(MY_WME)))) return 1; /* The error is set by my_strdup(). */ - - if (!check_user(thd, COM_CONNECT, passwd, passwd_len, db, TRUE)) - { - /* - Call to reset_host_errors() should be made only when all sanity checks - are done and connection is going to be a successful. - */ - reset_host_errors(&thd->remote.sin_addr); - return 0; - } - else - { - inc_host_errors(&thd->remote.sin_addr); - return 1; - } + return check_user(thd, COM_CONNECT, passwd, passwd_len, db, TRUE); error: inc_host_errors(&thd->remote.sin_addr); From 1ce0c706b39018c09994ef133fdeeb93d750903c Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Tue, 19 Jun 2012 13:53:16 +0400 Subject: [PATCH 090/289] MDEV-327: SHOW EXPLAIN: Different select_type in plans produced by SHOW EXPLAIN and EXPLAIN - SHOW EXPLAIN actually produced correct plan - Apply fix for lp:1013343 to make EXPLAIN and SHOW EXPLAIN uniform. --- mysql-test/r/show_explain.result | 36 ++++++++++++++++++++++++++++++++ mysql-test/t/show_explain.test | 35 +++++++++++++++++++++++++++++++ sql/item_subselect.cc | 2 +- 3 files changed, 72 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/show_explain.result b/mysql-test/r/show_explain.result index 14569b5c14b..1c18112a7e5 100644 --- a/mysql-test/r/show_explain.result +++ b/mysql-test/r/show_explain.result @@ -659,4 +659,40 @@ Note 1003 SELECT a FROM t1 WHERE a IN ( SELECT 1+SLEEP(0.01) UNION SELECT 2 ) a set debug_dbug=''; DROP TABLE t1; +# +# MDEV-327: SHOW EXPLAIN: Different select_type in plans produced by SHOW EXPLAIN +# and standard EXPLAIN: 'SUBQUERY' vs 'DEPENDENT SUBQUERY' +# +CREATE TABLE t1 (a INT) ENGINE=Aria; +INSERT INTO t1 VALUES +(4),(6),(3),(5),(3),(246),(2),(9),(3),(8), +(1),(8),(8),(5),(7),(5),(1),(6),(2),(9); +CREATE TABLE t2 (b INT) ENGINE=Aria; +INSERT INTO t2 VALUES +(1),(7),(4),(7),(0),(2),(9),(4),(0),(9), +(1),(3),(8),(8),(18),(84),(6),(3),(6),(6); +EXPLAIN +SELECT * FROM t1, ( SELECT * FROM t2 ) AS alias +WHERE a < ALL ( SELECT b FROM t1, t2 WHERE a = b ); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 20 Using where +1 PRIMARY t2 ALL NULL NULL NULL NULL 20 +3 SUBQUERY t1 ALL NULL NULL NULL NULL 20 +3 SUBQUERY t2 ALL NULL NULL NULL NULL 20 Using where +set @show_explain_probe_select_id=1; +set debug_dbug='d,show_explain_probe_join_exec_start'; +SELECT * FROM t1, ( SELECT * FROM t2 ) AS alias +WHERE a < ALL ( SELECT b FROM t1, t2 WHERE a = b ); +show explain for $thr2; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 20 Using where +1 PRIMARY t2 ALL NULL NULL NULL NULL 20 +3 SUBQUERY t1 ALL NULL NULL NULL NULL 20 +3 SUBQUERY t2 ALL NULL NULL NULL NULL 20 Using where +Warnings: +Note 1003 SELECT * FROM t1, ( SELECT * FROM t2 ) AS alias +WHERE a < ALL ( SELECT b FROM t1, t2 WHERE a = b ) +a b +set debug_dbug=''; +DROP TABLE t1, t2; drop table t0; diff --git a/mysql-test/t/show_explain.test b/mysql-test/t/show_explain.test index 1c890262758..d7e5a0bc6fd 100644 --- a/mysql-test/t/show_explain.test +++ b/mysql-test/t/show_explain.test @@ -662,6 +662,41 @@ set debug_dbug=''; DROP TABLE t1; +--echo # +--echo # MDEV-327: SHOW EXPLAIN: Different select_type in plans produced by SHOW EXPLAIN +--echo # and standard EXPLAIN: 'SUBQUERY' vs 'DEPENDENT SUBQUERY' +--echo # +CREATE TABLE t1 (a INT) ENGINE=Aria; +INSERT INTO t1 VALUES +(4),(6),(3),(5),(3),(246),(2),(9),(3),(8), +(1),(8),(8),(5),(7),(5),(1),(6),(2),(9); + +CREATE TABLE t2 (b INT) ENGINE=Aria; +INSERT INTO t2 VALUES +(1),(7),(4),(7),(0),(2),(9),(4),(0),(9), +(1),(3),(8),(8),(18),(84),(6),(3),(6),(6); + +EXPLAIN +SELECT * FROM t1, ( SELECT * FROM t2 ) AS alias +WHERE a < ALL ( SELECT b FROM t1, t2 WHERE a = b ); + +set @show_explain_probe_select_id=1; +set debug_dbug='d,show_explain_probe_join_exec_start'; +--send +SELECT * FROM t1, ( SELECT * FROM t2 ) AS alias +WHERE a < ALL ( SELECT b FROM t1, t2 WHERE a = b ); + +connection default; +--source include/wait_condition.inc +evalp show explain for $thr2; + +connection con1; +reap; + +set debug_dbug=''; + +DROP TABLE t1, t2; + ## TODO: Test this: have several SHOW EXPLAIN requests be queued up for a ## thread and served together. diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 5458a2fb968..d94e395d356 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -1813,7 +1813,7 @@ bool Item_allany_subselect::is_maxmin_applicable(JOIN *join) WHERE condition. */ return (abort_on_null || (upper_item && upper_item->is_top_level_item())) && - !join->select_lex->master_unit()->uncacheable && !func->eqne_op(); + !(join->select_lex->master_unit()->uncacheable & ~UNCACHEABLE_EXPLAIN) && !func->eqne_op(); } From 6eb2ce58635dded450953bf18123fbd7d9dbfaea Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Tue, 19 Jun 2012 18:10:32 +0400 Subject: [PATCH 091/289] SHOW EXPLAIN: better comments --- sql/my_apc.h | 27 ++++----------------------- sql/sql_class.cc | 8 ++++++-- sql/sql_class.h | 29 +++++++++++++++++++++-------- 3 files changed, 31 insertions(+), 33 deletions(-) diff --git a/sql/my_apc.h b/sql/my_apc.h index 5de1cf7d8d3..5879a0070d6 100644 --- a/sql/my_apc.h +++ b/sql/my_apc.h @@ -75,38 +75,19 @@ private: */ Call_request *apc_calls; - - /* - This mutex is used to - - make queue put/remove operations atomic (one must be in posession of the - mutex when putting/removing something from the queue) - - - make sure that nobody enqueues a request onto an Apc_target which has - disabled==TRUE. The idea is: - = requestor must be in possession of the mutex and check that - disabled==FALSE when he is putting his request into the queue. - = When the owner (ie. service) thread changes the Apc_target from - enabled to disabled, it will acquire the mutex, disable the - Apc_target (preventing any new requests), and then serve all pending - requests. - That way, we will never have the situation where the Apc_target is - disabled, but there are some un-served requests. - */ - //pthread_mutex_t LOCK_apc_queue; - class Call_request { public: apc_func_t func; /* Function to call */ void *func_arg; /* Argument to pass it */ - bool processed; - //pthread_mutex_t LOCK_request; - //pthread_cond_t COND_request; + /* The caller will actually wait for "processed==TRUE" */ + bool processed; /* Condition that will be signalled when the request has been served */ mysql_cond_t COND_request; - + + /* Double linked-list linkage */ Call_request *next; Call_request *prev; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 040712fb42a..d694afebc2c 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -2311,6 +2311,10 @@ int select_send::send_data(List &items) ////////////////////////////////////////////////////////////////////////////// +/* + Save the data being sent in our internal buffer. +*/ + int select_result_explain_buffer::send_data(List &items) { List_iterator_fast li(items); @@ -2357,7 +2361,7 @@ int select_result_explain_buffer::send_data(List &items) } -/* Write all strings out to the output, and free them. */ +/* Write the saved resultset to the client (via this->protocol) and free it. */ void select_result_explain_buffer::flush_data() { @@ -2373,7 +2377,7 @@ void select_result_explain_buffer::flush_data() } -/* Just free all of the accumulated strings */ +/* Free the accumulated resultset */ void select_result_explain_buffer::discard_data() { diff --git a/sql/sql_class.h b/sql/sql_class.h index 345216dcdea..bfbc9e86611 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1522,16 +1522,29 @@ extern "C" void my_message_sql(uint error, const char *str, myf MyFlags); class select_result_explain_buffer; + +/* + SHOW EXPLAIN request object. + + The thread that runs SHOW EXPLAIN statement creates a Show_explain_request + object R, and then schedules APC call of + Show_explain_request::get_explain_data((void*)&R). + +*/ + class Show_explain_request { public: - THD *target_thd; - THD *request_thd; + THD *target_thd; /* thd that we're running SHOW EXPLAIN for */ + THD *request_thd; /* thd that run SHOW EXPLAIN command */ + /* If true, there was some error when producing EXPLAIN output. */ bool failed_to_produce; - + + /* SHOW EXPLAIN will be stored here */ select_result_explain_buffer *explain_buf; - + + /* Query that we've got SHOW EXPLAIN for */ String query_str; static void get_explain_data(void *arg); @@ -2414,11 +2427,11 @@ public: /* - This is what allows this thread to serve as a target for others to - schedule Async Procedure Calls on. + Allows this thread to serve as a target for others to schedule Async + Procedure Calls on. - It's possible to schedule arbitrary C function call but currently this - facility is used only by SHOW EXPLAIN code (See Show_explain_request) + It's possible to schedule arbitrary C++ function calls. Currently, only + Show_explain_request uses this. */ Apc_target apc_target; From 983fcfaf62fbd4169afd0a3e6182ea46705fa3f5 Mon Sep 17 00:00:00 2001 From: Kent Boortz Date: Wed, 20 Jun 2012 13:10:13 +0200 Subject: [PATCH 092/289] Version for this release build is 5.1.64 --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index 4e7a3303353..84295a15f4a 100644 --- a/configure.in +++ b/configure.in @@ -12,7 +12,7 @@ dnl dnl When changing the major version number please also check the switch dnl statement in mysqlbinlog::check_master_version(). You may also need dnl to update version.c in ndb. -AC_INIT([MySQL Server], [5.1.65], [], [mysql]) +AC_INIT([MySQL Server], [5.1.64], [], [mysql]) AC_CONFIG_SRCDIR([sql/mysqld.cc]) AC_CANONICAL_SYSTEM From 5c724f7b9430bb3794f6e12709268ce5502104e5 Mon Sep 17 00:00:00 2001 From: Joerg Bruehe Date: Thu, 21 Jun 2012 16:26:50 +0200 Subject: [PATCH 093/289] Fixing wrong comment syntax (discovered by Kent) --- sql/rpl_utility.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/rpl_utility.h b/sql/rpl_utility.h index 81a10cca814..b2577643add 100644 --- a/sql/rpl_utility.h +++ b/sql/rpl_utility.h @@ -300,7 +300,7 @@ private: public: Deferred_log_events(Relay_log_info *rli); ~Deferred_log_events(); - /* queue for exection at Query-log-event time prior the Query */; + /* queue for exection at Query-log-event time prior the Query */ int add(Log_event *ev); bool is_empty(); bool execute(Relay_log_info *rli); From 60561ae6133cf40f4fc445e1d6e8f395a20b2573 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 21 Jun 2012 18:47:13 +0300 Subject: [PATCH 094/289] Fix for LP bug#1001505 and LP bug#1001510 We set correct cmp_context during preparation to avoid changing it later by Item_field::equal_fields_propagator. (see mysql bugs #57135 #57692 during merging) --- mysql-test/r/case.result | 4 ++++ mysql-test/r/compare.result | 4 ++++ mysql-test/t/case.test | 10 ++++++++++ mysql-test/t/compare.test | 8 ++++++++ sql/item_cmpfunc.cc | 19 +++++++++++++++++++ 5 files changed, 45 insertions(+) diff --git a/mysql-test/r/case.result b/mysql-test/r/case.result index 0c0e2d623c8..811bbee1d91 100644 --- a/mysql-test/r/case.result +++ b/mysql-test/r/case.result @@ -218,3 +218,7 @@ a d 3 11120436154190595086 drop table t1, t2; End of 5.0 tests +CREATE TABLE t1(a YEAR); +SELECT 1 FROM t1 WHERE a=1 AND CASE 1 WHEN a THEN 1 ELSE 1 END; +1 +DROP TABLE t1; diff --git a/mysql-test/r/compare.result b/mysql-test/r/compare.result index 796821a87bd..5168eb38586 100644 --- a/mysql-test/r/compare.result +++ b/mysql-test/r/compare.result @@ -96,3 +96,7 @@ SELECT * FROM t1 WHERE a > '2008-01-01' AND a = '0000-00-00'; a DROP TABLE t1; End of 5.0 tests +CREATE TABLE t1(a INT ZEROFILL); +SELECT 1 FROM t1 WHERE t1.a IN (1, t1.a) AND t1.a=2; +1 +DROP TABLE t1; diff --git a/mysql-test/t/case.test b/mysql-test/t/case.test index 028c64d6de7..81855dfc97f 100644 --- a/mysql-test/t/case.test +++ b/mysql-test/t/case.test @@ -170,3 +170,13 @@ select t1.a, (case t1.a when 0 then 0 else t1.b end) d from t1 drop table t1, t2; --echo End of 5.0 tests + +# +# LP BUG#1001510 +# Bug #11764313 57135: CRASH IN ITEM_FUNC_CASE::FIND_ITEM WITH CASE WHEN +# ELSE CLAUSE +# + +CREATE TABLE t1(a YEAR); +SELECT 1 FROM t1 WHERE a=1 AND CASE 1 WHEN a THEN 1 ELSE 1 END; +DROP TABLE t1; diff --git a/mysql-test/t/compare.test b/mysql-test/t/compare.test index 103244eb2f7..d2b2a7e5523 100644 --- a/mysql-test/t/compare.test +++ b/mysql-test/t/compare.test @@ -86,3 +86,11 @@ SELECT * FROM t1 WHERE a > '2008-01-01' AND a = '0000-00-00'; DROP TABLE t1; --echo End of 5.0 tests + +# +# Bug #11764818 57692: Crash in item_func_in::val_int() with ZEROFILL +# + +CREATE TABLE t1(a INT ZEROFILL); +SELECT 1 FROM t1 WHERE t1.a IN (1, t1.a) AND t1.a=2; +DROP TABLE t1; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 61554bdf420..847c51b8a5e 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -3095,6 +3095,15 @@ void Item_func_case::fix_length_and_dec() return; } } + /* + Set cmp_context of all WHEN arguments. This prevents + Item_field::equal_fields_propagator() from transforming a + zerofill argument into a string constant. Such a change would + require rebuilding cmp_items. + */ + for (i= 0; i < ncases; i+= 2) + args[i]->cmp_context= item_cmp_type(left_result_type, + args[i]->result_type()); } if (else_expr_num == -1 || args[else_expr_num]->maybe_null) @@ -4081,6 +4090,16 @@ void Item_func_in::fix_length_and_dec() } } } + /* + Set cmp_context of all arguments. This prevents + Item_field::equal_fields_propagator() from transforming a zerofill integer + argument into a string constant. Such a change would require rebuilding + cmp_itmes. + */ + for (arg= args + 1, arg_end= args + arg_count; arg != arg_end ; arg++) + { + arg[0]->cmp_context= item_cmp_type(left_result_type, arg[0]->result_type()); + } max_length= 1; } From 45503698c13c55a6c21e02f4422bd3a4bcb02fd9 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Thu, 21 Jun 2012 22:15:13 +0400 Subject: [PATCH 095/289] Test that SHOW EXPLAIN will print 'Distinct'. --- mysql-test/r/show_explain.result | 33 +++++++++++++++++++++++++++++++ mysql-test/t/show_explain.test | 34 ++++++++++++++++++++++++++++++-- 2 files changed, 65 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/show_explain.result b/mysql-test/r/show_explain.result index 1c18112a7e5..07bcb29a7ea 100644 --- a/mysql-test/r/show_explain.result +++ b/mysql-test/r/show_explain.result @@ -695,4 +695,37 @@ WHERE a < ALL ( SELECT b FROM t1, t2 WHERE a = b ) a b set debug_dbug=''; DROP TABLE t1, t2; +# +# Test that SHOW EXPLAIN will print 'Distinct'. +# +CREATE TABLE t1 (a int(10) unsigned not null primary key,b int(10) unsigned); +INSERT INTO t1 VALUES (1,1),(2,1),(3,1),(4,1); +CREATE TABLE t3 (a int(10) unsigned, key(A), b text); +INSERT INTO t3 VALUES (1,'1'),(2,'2'); +create temporary table t4 select * from t3; +insert into t3 select * from t4; +insert into t4 select * from t3; +insert into t3 select * from t4; +insert into t4 select * from t3; +insert into t3 select * from t4; +insert into t4 select * from t3; +insert into t3 select * from t4; +explain select distinct t1.a from t1,t3 where t1.a=t3.a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index PRIMARY PRIMARY 4 NULL 4 Using index; Using temporary +1 SIMPLE t3 ref a a 5 test.t1.a 7 Using index; Distinct +set @show_explain_probe_select_id=1; +set debug_dbug='d,show_explain_probe_join_exec_start'; +select distinct t1.a from t1,t3 where t1.a=t3.a; +show explain for $thr2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index PRIMARY PRIMARY 4 NULL 4 Using index; Using temporary +1 SIMPLE t3 ref a a 5 test.t1.a 7 Using index; Distinct +Warnings: +Note 1003 select distinct t1.a from t1,t3 where t1.a=t3.a +a +1 +2 +set debug_dbug=''; +drop table t1,t3,t4; drop table t0; diff --git a/mysql-test/t/show_explain.test b/mysql-test/t/show_explain.test index d7e5a0bc6fd..ffd2c25dfd9 100644 --- a/mysql-test/t/show_explain.test +++ b/mysql-test/t/show_explain.test @@ -692,11 +692,41 @@ evalp show explain for $thr2; connection con1; reap; - set debug_dbug=''; - DROP TABLE t1, t2; +--echo # +--echo # Test that SHOW EXPLAIN will print 'Distinct'. +--echo # +CREATE TABLE t1 (a int(10) unsigned not null primary key,b int(10) unsigned); +INSERT INTO t1 VALUES (1,1),(2,1),(3,1),(4,1); + +CREATE TABLE t3 (a int(10) unsigned, key(A), b text); +INSERT INTO t3 VALUES (1,'1'),(2,'2'); + +create temporary table t4 select * from t3; +insert into t3 select * from t4; +insert into t4 select * from t3; +insert into t3 select * from t4; +insert into t4 select * from t3; +insert into t3 select * from t4; +insert into t4 select * from t3; +insert into t3 select * from t4; +explain select distinct t1.a from t1,t3 where t1.a=t3.a; + +set @show_explain_probe_select_id=1; +set debug_dbug='d,show_explain_probe_join_exec_start'; +--send +select distinct t1.a from t1,t3 where t1.a=t3.a; +connection default; +--source include/wait_condition.inc +evalp show explain for $thr2; + +connection con1; +reap; +set debug_dbug=''; + +drop table t1,t3,t4; ## TODO: Test this: have several SHOW EXPLAIN requests be queued up for a ## thread and served together. From c562c7447814f727893a5243efad9c2d00324f6f Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 8 Sep 2012 12:15:55 +0200 Subject: [PATCH 096/289] MDEV-457 Inconsistent data truncation on datetime values with fractional seconds represented as strings with no delimiters New implementation for str_to_datetime. Fix MDEV-457 and related issues. --- mysql-test/r/func_time.result | 6 +- mysql-test/r/loaddata.result | 6 +- mysql-test/r/str_to_datetime_457.result | 51 +++ .../suite/funcs_1/r/innodb_func_view.result | 4 +- .../suite/funcs_1/r/memory_func_view.result | 4 +- .../suite/funcs_1/r/myisam_func_view.result | 4 +- mysql-test/suite/rpl/r/rpl_rewrt_db.result | 6 +- mysql-test/t/func_time.test | 2 +- mysql-test/t/str_to_datetime_457.test | 26 ++ sql-common/my_time.c | 415 +++++++----------- 10 files changed, 256 insertions(+), 268 deletions(-) create mode 100644 mysql-test/r/str_to_datetime_457.result create mode 100644 mysql-test/t/str_to_datetime_457.test diff --git a/mysql-test/r/func_time.result b/mysql-test/r/func_time.result index bfc6b72caa1..3cc7675496a 100644 --- a/mysql-test/r/func_time.result +++ b/mysql-test/r/func_time.result @@ -1023,11 +1023,11 @@ MAKETIME(CAST(-1 AS UNSIGNED), 0, 0) Warnings: Note 1105 Cast to unsigned converted negative integer to it's positive complement Warning 1292 Truncated incorrect time value: '18446744073709551615:00:00' -SELECT EXTRACT(HOUR FROM '100000:02:03'); -EXTRACT(HOUR FROM '100000:02:03') +SELECT EXTRACT(HOUR FROM '10000:02:03'); +EXTRACT(HOUR FROM '10000:02:03') 838 Warnings: -Warning 1292 Truncated incorrect time value: '100000:02:03' +Warning 1292 Truncated incorrect time value: '10000:02:03' CREATE TABLE t1(f1 TIME); INSERT INTO t1 VALUES('916:00:00 a'); Warnings: diff --git a/mysql-test/r/loaddata.result b/mysql-test/r/loaddata.result index ee0e63706a1..c4c8216c14a 100644 --- a/mysql-test/r/loaddata.result +++ b/mysql-test/r/loaddata.result @@ -5,8 +5,8 @@ Warnings: Warning 1265 Data truncated for column 'a' at row 1 Warning 1265 Data truncated for column 'c' at row 1 Warning 1265 Data truncated for column 'd' at row 1 -Warning 1264 Out of range value for column 'a' at row 2 -Warning 1264 Out of range value for column 'b' at row 2 +Warning 1265 Data truncated for column 'a' at row 2 +Warning 1265 Data truncated for column 'b' at row 2 Warning 1265 Data truncated for column 'd' at row 2 load data infile '../../std_data/loaddata1.dat' into table t1 fields terminated by ',' IGNORE 2 LINES; SELECT * from t1; @@ -20,7 +20,7 @@ load data infile '../../std_data/loaddata1.dat' into table t1 fields terminated Warnings: Warning 1265 Data truncated for column 'c' at row 1 Warning 1265 Data truncated for column 'd' at row 1 -Warning 1264 Out of range value for column 'b' at row 2 +Warning 1265 Data truncated for column 'b' at row 2 Warning 1265 Data truncated for column 'd' at row 2 SELECT * from t1; a b c d diff --git a/mysql-test/r/str_to_datetime_457.result b/mysql-test/r/str_to_datetime_457.result new file mode 100644 index 00000000000..4fd0d00691c --- /dev/null +++ b/mysql-test/r/str_to_datetime_457.result @@ -0,0 +1,51 @@ +select cast('01:02:03 ' as time), cast('01:02:03 ' as time); +cast('01:02:03 ' as time) cast('01:02:03 ' as time) +01:02:03 00:00:00 +select cast('2002-011-012' as date), cast('2002.11.12' as date), cast('2002.011.012' as date); +cast('2002-011-012' as date) cast('2002.11.12' as date) cast('2002.011.012' as date) +2002-11-12 2002-11-12 2002-11-12 +select cast('2012103123595912' as datetime(6)), cast('20121031235959123' as datetime(6)); +cast('2012103123595912' as datetime(6)) cast('20121031235959123' as datetime(6)) +2012-10-31 23:59:59.000000 2012-10-31 23:59:59.000000 +Warnings: +Warning 1292 Truncated incorrect datetime value: '2012103123595912' +Warning 1292 Truncated incorrect datetime value: '20121031235959123' +select cast(0 as date), cast('0000-00-00' as date), cast('0' as date); +cast(0 as date) cast('0000-00-00' as date) cast('0' as date) +0000-00-00 0000-00-00 NULL +Warnings: +Warning 1292 Incorrect datetime value: '0' +select extract(hour from '100000:02:03'), extract(hour from '100000:02:03 '); +extract(hour from '100000:02:03') extract(hour from '100000:02:03 ') +NULL NULL +Warnings: +Warning 1292 Truncated incorrect time value: '100000:02:03' +Warning 1292 Truncated incorrect time value: '100000:02:03 ' +# +# backward compatibility craziness +# +select cast('12:00:00.12.34.56' as time); +cast('12:00:00.12.34.56' as time) +12:00:00 +Warnings: +Warning 1292 Truncated incorrect time value: '12:00:00.12.34.56' +select cast('12:00:00 12.34.56' as time); +cast('12:00:00 12.34.56' as time) +12:34:56 +select cast('12:00:00-12.34.56' as time); +cast('12:00:00-12.34.56' as time) +12:00:00 +Warnings: +Warning 1292 Truncated incorrect time value: '12:00:00-12.34.56' +select cast('12:00:00.12.34.56' as datetime); +cast('12:00:00.12.34.56' as datetime) +2012-00-00 12:34:56 +select cast('12:00:00-12.34.56' as datetime); +cast('12:00:00-12.34.56' as datetime) +2012-00-00 12:34:56 +select cast('12:00:00 12.34.56' as datetime); +cast('12:00:00 12.34.56' as datetime) +2012-00-00 12:34:56 +select cast('12:00:00.123456' as time); +cast('12:00:00.123456' as time) +12:00:00 diff --git a/mysql-test/suite/funcs_1/r/innodb_func_view.result b/mysql-test/suite/funcs_1/r/innodb_func_view.result index dd376154100..5504ec7efc2 100644 --- a/mysql-test/suite/funcs_1/r/innodb_func_view.result +++ b/mysql-test/suite/funcs_1/r/innodb_func_view.result @@ -3801,7 +3801,7 @@ NULL NULL 1 00:00:00 2 00:00:00 <--------30 characters-------> 3 -00:00:00 ---äÖüß@µ*$-- 4 -NULL -1 5 +-00:00:01 -1 5 41:58:00 1 17:58 22 Warnings: Warning 1292 Truncated incorrect time value: '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' @@ -3820,7 +3820,7 @@ NULL NULL 1 00:00:00 2 00:00:00 <--------30 characters-------> 3 -00:00:00 ---äÖüß@µ*$-- 4 -NULL -1 5 +-00:00:01 -1 5 41:58:00 1 17:58 22 Warnings: Warning 1292 Truncated incorrect time value: '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' diff --git a/mysql-test/suite/funcs_1/r/memory_func_view.result b/mysql-test/suite/funcs_1/r/memory_func_view.result index 03e4c647d6d..7f7baf65d1f 100644 --- a/mysql-test/suite/funcs_1/r/memory_func_view.result +++ b/mysql-test/suite/funcs_1/r/memory_func_view.result @@ -3802,7 +3802,7 @@ NULL NULL 1 00:00:00 2 00:00:00 <--------30 characters-------> 3 -00:00:00 ---äÖüß@µ*$-- 4 -NULL -1 5 +-00:00:01 -1 5 41:58:00 1 17:58 22 Warnings: Warning 1292 Truncated incorrect time value: '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' @@ -3821,7 +3821,7 @@ NULL NULL 1 00:00:00 2 00:00:00 <--------30 characters-------> 3 -00:00:00 ---äÖüß@µ*$-- 4 -NULL -1 5 +-00:00:01 -1 5 41:58:00 1 17:58 22 Warnings: Warning 1292 Truncated incorrect time value: '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' diff --git a/mysql-test/suite/funcs_1/r/myisam_func_view.result b/mysql-test/suite/funcs_1/r/myisam_func_view.result index 03e4c647d6d..7f7baf65d1f 100644 --- a/mysql-test/suite/funcs_1/r/myisam_func_view.result +++ b/mysql-test/suite/funcs_1/r/myisam_func_view.result @@ -3802,7 +3802,7 @@ NULL NULL 1 00:00:00 2 00:00:00 <--------30 characters-------> 3 -00:00:00 ---äÖüß@µ*$-- 4 -NULL -1 5 +-00:00:01 -1 5 41:58:00 1 17:58 22 Warnings: Warning 1292 Truncated incorrect time value: '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' @@ -3821,7 +3821,7 @@ NULL NULL 1 00:00:00 2 00:00:00 <--------30 characters-------> 3 -00:00:00 ---äÖüß@µ*$-- 4 -NULL -1 5 +-00:00:01 -1 5 41:58:00 1 17:58 22 Warnings: Warning 1292 Truncated incorrect time value: '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' diff --git a/mysql-test/suite/rpl/r/rpl_rewrt_db.result b/mysql-test/suite/rpl/r/rpl_rewrt_db.result index 6cbd107fdcf..12071faecfd 100644 --- a/mysql-test/suite/rpl/r/rpl_rewrt_db.result +++ b/mysql-test/suite/rpl/r/rpl_rewrt_db.result @@ -25,8 +25,8 @@ Warnings: Warning 1265 Data truncated for column 'a' at row 1 Warning 1265 Data truncated for column 'c' at row 1 Warning 1265 Data truncated for column 'd' at row 1 -Warning 1264 Out of range value for column 'a' at row 2 -Warning 1264 Out of range value for column 'b' at row 2 +Warning 1265 Data truncated for column 'a' at row 2 +Warning 1265 Data truncated for column 'b' at row 2 Warning 1265 Data truncated for column 'd' at row 2 load data infile '../../std_data/loaddata1.dat' into table t1 fields terminated by ',' IGNORE 2 LINES; select * from rewrite.t1; @@ -40,7 +40,7 @@ load data infile '../../std_data/loaddata1.dat' into table t1 fields terminated Warnings: Warning 1265 Data truncated for column 'c' at row 1 Warning 1265 Data truncated for column 'd' at row 1 -Warning 1264 Out of range value for column 'b' at row 2 +Warning 1265 Data truncated for column 'b' at row 2 Warning 1265 Data truncated for column 'd' at row 2 select * from rewrite.t1; a b c d diff --git a/mysql-test/t/func_time.test b/mysql-test/t/func_time.test index 42705975b88..d9de4103b13 100644 --- a/mysql-test/t/func_time.test +++ b/mysql-test/t/func_time.test @@ -526,7 +526,7 @@ SELECT MAKETIME(0, 0, 4294967296); SELECT MAKETIME(CAST(-1 AS UNSIGNED), 0, 0); # check if EXTRACT() handles out-of-range values correctly -SELECT EXTRACT(HOUR FROM '100000:02:03'); +SELECT EXTRACT(HOUR FROM '10000:02:03'); # check if we get proper warnings if both input string truncation # and out-of-range value occur diff --git a/mysql-test/t/str_to_datetime_457.test b/mysql-test/t/str_to_datetime_457.test new file mode 100644 index 00000000000..dd25f98ebdd --- /dev/null +++ b/mysql-test/t/str_to_datetime_457.test @@ -0,0 +1,26 @@ +# +# MDEV-457 Inconsistent data truncation on datetime values with fractional seconds represented as strings with no delimiters +# (and other problems with str_to_datetime) +# + +# first was ok, second was not +select cast('01:02:03 ' as time), cast('01:02:03 ' as time); +# first two were ok, third was not +select cast('2002-011-012' as date), cast('2002.11.12' as date), cast('2002.011.012' as date); +# only two microsecond digits were ok, third was truncated with a warning +select cast('2012103123595912' as datetime(6)), cast('20121031235959123' as datetime(6)); +# zero string date was considered 'out of range'. Must be either ok or invalid format +select cast(0 as date), cast('0000-00-00' as date), cast('0' as date); +# first was ok, second was not +select extract(hour from '100000:02:03'), extract(hour from '100000:02:03 '); + +--echo # +--echo # backward compatibility craziness +--echo # +select cast('12:00:00.12.34.56' as time); # was 12:00:00 +select cast('12:00:00 12.34.56' as time); # was 12:34:56 +select cast('12:00:00-12.34.56' as time); # was 12:00:00 +select cast('12:00:00.12.34.56' as datetime); +select cast('12:00:00-12.34.56' as datetime); +select cast('12:00:00 12.34.56' as datetime); +select cast('12:00:00.123456' as time); diff --git a/sql-common/my_time.c b/sql-common/my_time.c index df75bb49c89..fbcf52dbf19 100644 --- a/sql-common/my_time.c +++ b/sql-common/my_time.c @@ -104,6 +104,103 @@ my_bool check_date(const MYSQL_TIME *ltime, my_bool not_zero_date, return FALSE; } +static int get_number(uint *val, uint *number_of_fields, const char **str, + const char *end) +{ + const char *s = *str; + + if (s >= end) + return 0; + + if (!my_isdigit(&my_charset_latin1, *s)) + return 1; + *val= *s++ - '0'; + + for (; s < end && my_isdigit(&my_charset_latin1, *s); s++) + *val= *val * 10 + *s - '0'; + *str = s; + (*number_of_fields)++; + return 0; +} + +static int get_digits(uint *val, uint *number_of_fields, const char **str, + const char *end, uint length) +{ + return get_number(val, number_of_fields, str, min(end, *str + length)); +} + +static int get_punct(const char **str, const char *end) +{ + if (*str >= end) + return 0; + if (my_ispunct(&my_charset_latin1, **str)) + { + (*str)++; + return 0; + } + return 1; +} + +static int get_date_time_separator(uint *number_of_fields, ulonglong flags, + const char **str, const char *end) +{ + const char *s= *str; + if (s >= end) + return 0; + + if (*s == 'T') + { + (*str)++; + return 0; + } + + /* + now, this is tricky, for backward compatibility reasons. + cast("11:11:11.12.12.12" as datetime) should give 2011-11-11 12:12:12 + but + cast("11:11:11.12.12.12" as time) should give 11:11:11.12 + that is, a punctuation character can be accepted as a date/time separator + only if TIME_DATETIME_ONLY (see str_to_time) is not set. + */ + if (my_ispunct(&my_charset_latin1, *s)) + { + if (flags & TIME_DATETIME_ONLY) + { + /* see above, returning 1 is not enough, we need hard abort here */ + *number_of_fields= 0; + return 1; + } + + (*str)++; + return 0; + } + + if (!my_isspace(&my_charset_latin1, *s)) + return 1; + + do + { + s++; + } while (my_isspace(&my_charset_latin1, *s)); + *str= s; + return 0; +} + +static int get_maybe_T(const char **str, const char *end) +{ + if (*str < end && **str == 'T') + (*str)++; + return 0; +} + +static uint skip_digits(const char **str, const char *end) +{ + const char *start= *str, *s= *str; + while (s < end && my_isdigit(&my_charset_latin1, *s)) + s++; + *str= s; + return s - start; +} /* Convert a timestamp string to a MYSQL_TIME value. @@ -132,24 +229,9 @@ my_bool check_date(const MYSQL_TIME *ltime, my_bool not_zero_date, The second part may have an optional .###### fraction part. - NOTES - This function should work with a format position vector as long as the - following things holds: - - All date are kept together and all time parts are kept together - - Date and time parts must be separated by blank - - Second fractions must come after second part and be separated - by a '.'. (The second fractions are optional) - - AM/PM must come after second fractions (or after seconds if no fractions) - - Year must always been specified. - - If time is before date, then we will use datetime format only if - the argument consist of two parts, separated by space. - Otherwise we will assume the argument is a date. - - The hour part must be specified in hour-minute-second order. - RETURN VALUES MYSQL_TIMESTAMP_NONE String wasn't a timestamp, like [DD [HH:[MM:[SS]]]].fraction. - l_time is not changed. MYSQL_TIMESTAMP_DATE DATE string (YY MM and DD parts ok) MYSQL_TIMESTAMP_DATETIME Full timestamp MYSQL_TIMESTAMP_ERROR Timestamp with wrong values. @@ -162,18 +244,10 @@ enum enum_mysql_timestamp_type str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time, ulonglong flags, int *was_cut) { - uint UNINIT_VAR(field_length), UNINIT_VAR(year_length), digits, i, number_of_fields; - uint date[MAX_DATE_PARTS], date_len[MAX_DATE_PARTS]; - uint add_hours= 0, start_loop; - ulong not_zero_date, allow_space; - my_bool is_internal_format; - const char *pos, *UNINIT_VAR(last_field_pos); - const char *end=str+length; - const uchar *format_position; - my_bool found_delimitier= 0, found_space= 0; - uint frac_pos, frac_len; + const char *end=str+length, *pos; + uint number_of_fields= 0, digits, year_length, not_zero_date; DBUG_ENTER("str_to_datetime"); - DBUG_PRINT("enter",("str: %.*s",length,str)); + bzero(l_time, sizeof(*l_time)); if (flags & TIME_TIME_ONLY) { @@ -181,7 +255,6 @@ str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time, ret= str_to_time(str, length, l_time, flags, was_cut); DBUG_RETURN(ret); } - *was_cut= 0; /* Skip space at start */ @@ -193,254 +266,93 @@ str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time, DBUG_RETURN(MYSQL_TIMESTAMP_NONE); } - is_internal_format= 0; - /* This has to be changed if want to activate different timestamp formats */ - format_position= internal_format_positions; - /* Calculate number of digits in first part. If length= 8 or >= 14 then year is of format YYYY. (YYYY-MM-DD, YYYYMMDD, YYYYYMMDDHHMMSS) */ - for (pos=str; - pos != end && (my_isdigit(&my_charset_latin1,*pos) || *pos == 'T'); - pos++) - ; + pos= str; + digits= skip_digits(&pos, end); - digits= (uint) (pos-str); - start_loop= 0; /* Start of scan loop */ - date_len[format_position[0]]= 0; /* Length of year field */ - if (pos == end || *pos == '.') + if (pos < end && *pos == 'T') /* YYYYYMMDDHHMMSSThhmmss is supported too */ { - /* Found date in internal format (only numbers like YYYYMMDD) */ + pos++; + digits+= skip_digits(&pos, end); + } + if (pos < end && *pos == '.' && digits >= 12) /* YYYYYMMDDHHMMSShhmmss.uuuuuu is supported too */ + { + pos++; + skip_digits(&pos, end); // ignore the return value + } + + if (pos == end) + { + /* + Found date in internal format + (only numbers like [YY]YYMMDD[T][hhmmss[.uuuuuu]]) + */ year_length= (digits == 4 || digits == 8 || digits >= 14) ? 4 : 2; - field_length= year_length; - is_internal_format= 1; - format_position= internal_format_positions; + *was_cut= get_digits(&l_time->year, &number_of_fields, &str, end, year_length) + || get_digits(&l_time->month, &number_of_fields, &str, end, 2) + || get_digits(&l_time->day, &number_of_fields, &str, end, 2) + || get_maybe_T(&str, end) + || get_digits(&l_time->hour, &number_of_fields, &str, end, 2) + || get_digits(&l_time->minute, &number_of_fields, &str, end, 2) + || get_digits(&l_time->second, &number_of_fields, &str, end, 2); } else - { - if (format_position[0] >= 3) /* If year is after HHMMDD */ - { - /* - If year is not in first part then we have to determinate if we got - a date field or a datetime field. - We do this by checking if there is two numbers separated by - space in the input. - */ - while (pos < end && !my_isspace(&my_charset_latin1, *pos)) - pos++; - while (pos < end && !my_isdigit(&my_charset_latin1, *pos)) - pos++; - if (pos == end) - { - if (flags & TIME_DATETIME_ONLY) - { - *was_cut= 1; - DBUG_RETURN(MYSQL_TIMESTAMP_NONE); /* Can't be a full datetime */ - } - /* Date field. Set hour, minutes and seconds to 0 */ - date[0]= date[1]= date[2]= date[3]= date[4]= 0; - start_loop= 5; /* Start with first date part */ - } - } - - field_length= format_position[0] == 0 ? 4 : 2; - } - - /* - Only allow space in the first "part" of the datetime field and: - - after days, part seconds - - before and after AM/PM (handled by code later) - - 2003-03-03 20:00:20 AM - 20:00:20.000000 AM 03-03-2000 - */ - i= max((uint) format_position[0], (uint) format_position[1]); - set_if_bigger(i, (uint) format_position[2]); - allow_space= ((1 << i) | (1 << format_position[6])); - allow_space&= (1 | 2 | 4 | 8); - - not_zero_date= 0; - for (i = start_loop; - i < MAX_DATE_PARTS-1 && str != end && - my_isdigit(&my_charset_latin1,*str); - i++) { const char *start= str; - ulong tmp_value= (uint) (uchar) (*str++ - '0'); + *was_cut = get_number(&l_time->year, &number_of_fields, &str, end); + year_length= str - start; - /* - Internal format means no delimiters; every field has a fixed - width. Otherwise, we scan until we find a delimiter and discard - leading zeroes -- except for the microsecond part, where leading - zeroes are significant, and where we never process more than six - digits. - */ - my_bool scan_until_delim= !is_internal_format && - ((i != format_position[6])); - - while (str != end && my_isdigit(&my_charset_latin1,str[0]) && - (scan_until_delim || --field_length)) - { - tmp_value=tmp_value*10 + (ulong) (uchar) (*str - '0'); - str++; - } - date_len[i]= (uint) (str - start); - if (tmp_value > 999999) /* Impossible date part */ - { - *was_cut= 1; - DBUG_RETURN(MYSQL_TIMESTAMP_NONE); - } - date[i]=tmp_value; - not_zero_date|= tmp_value; - - /* Length of next field */ - field_length= format_position[i+1] == 0 ? 4 : 2; - - if ((last_field_pos= str) == end) - { - i++; /* Register last found part */ - break; - } - /* Allow a 'T' after day to allow CCYYMMDDT type of fields */ - if (i == format_position[2] && *str == 'T') - { - str++; /* ISO8601: CCYYMMDDThhmmss */ - continue; - } - if (i == format_position[5]) /* Seconds */ - { - if (*str == '.') /* Followed by part seconds */ - { - str++; - field_length= 6; /* 6 digits */ - } - continue; - } - while (str != end && - (my_ispunct(&my_charset_latin1,*str) || - my_isspace(&my_charset_latin1,*str))) - { - if (my_isspace(&my_charset_latin1,*str)) - { - if (!(allow_space & (1 << i))) - { - *was_cut= 1; - DBUG_RETURN(MYSQL_TIMESTAMP_NONE); - } - found_space= 1; - } - str++; - found_delimitier= 1; /* Should be a 'normal' date */ - } - /* Check if next position is AM/PM */ - if (i == format_position[6]) /* Seconds, time for AM/PM */ - { - i++; /* Skip AM/PM part */ - if (format_position[7] != 255) /* If using AM/PM */ - { - if (str+2 <= end && (str[1] == 'M' || str[1] == 'm')) - { - if (str[0] == 'p' || str[0] == 'P') - add_hours= 12; - else if (str[0] != 'a' && str[0] != 'A') - continue; /* Not AM/PM */ - str+= 2; /* Skip AM/PM */ - /* Skip space after AM/PM */ - while (str != end && my_isspace(&my_charset_latin1,*str)) - str++; - } - } - } - last_field_pos= str; + if (!*was_cut) + *was_cut= get_punct(&str, end) + || get_number(&l_time->month, &number_of_fields, &str, end) + || get_punct(&str, end) + || get_number(&l_time->day, &number_of_fields, &str, end) + || get_date_time_separator(&number_of_fields, flags, &str, end) + || get_number(&l_time->hour, &number_of_fields, &str, end) + || get_punct(&str, end) + || get_number(&l_time->minute, &number_of_fields, &str, end) + || get_punct(&str, end) + || get_number(&l_time->second, &number_of_fields, &str, end); } - if (found_delimitier && !found_space && (flags & TIME_DATETIME_ONLY)) - { + + if (number_of_fields < 3) *was_cut= 1; - DBUG_RETURN(MYSQL_TIMESTAMP_NONE); /* Can't be a datetime */ - } - str= last_field_pos; + /* we're ok if date part is correct. even if the rest is truncated */ + if (*was_cut && number_of_fields < 3) + DBUG_RETURN(MYSQL_TIMESTAMP_NONE); - number_of_fields= i - start_loop; - while (i < MAX_DATE_PARTS) + if (!*was_cut && str < end && *str == '.') { - date_len[i]= 0; - date[i++]= 0; - } - - if (!is_internal_format) - { - year_length= date_len[(uint) format_position[0]]; - if (!year_length) /* Year must be specified */ - { + uint second_part; + const char *start= ++str; + *was_cut= get_digits(&second_part, &number_of_fields, &str, end, 6); + if (str - start < 6) + second_part*= log_10_int[6 - (str - start)]; + l_time->second_part= second_part; + if (skip_digits(&str, end)) *was_cut= 1; - DBUG_RETURN(MYSQL_TIMESTAMP_NONE); - } - - l_time->year= date[(uint) format_position[0]]; - l_time->month= date[(uint) format_position[1]]; - l_time->day= date[(uint) format_position[2]]; - l_time->hour= date[(uint) format_position[3]]; - l_time->minute= date[(uint) format_position[4]]; - l_time->second= date[(uint) format_position[5]]; - - frac_pos= (uint) format_position[6]; - frac_len= date_len[frac_pos]; - if (frac_len < 6) - date[frac_pos]*= (uint) log_10_int[6 - frac_len]; - l_time->second_part= date[frac_pos]; - - if (format_position[7] != (uchar) 255) - { - if (l_time->hour > 12) - { - *was_cut= 1; - goto err; - } - l_time->hour= l_time->hour%12 + add_hours; - } } - else - { - l_time->year= date[0]; - l_time->month= date[1]; - l_time->day= date[2]; - l_time->hour= date[3]; - l_time->minute= date[4]; - l_time->second= date[5]; - if (date_len[6] < 6) - date[6]*= (uint) log_10_int[6 - date_len[6]]; - l_time->second_part=date[6]; - } - l_time->neg= 0; + + not_zero_date = l_time->year || l_time->month || l_time->day || + l_time->hour || l_time->minute || l_time->second || + l_time->second_part; if (year_length == 2 && not_zero_date) l_time->year+= (l_time->year < YY_PART_YEAR ? 2000 : 1900); - if (number_of_fields < 3 || - l_time->year > 9999 || l_time->month > 12 || - l_time->day > 31 || l_time->hour > 23 || - l_time->minute > 59 || l_time->second > 59) + if (l_time->year > 9999 || l_time->month > 12 || l_time->day > 31 || + l_time->hour > 23 || l_time->minute > 59 || l_time->second > 59) { - /* Only give warning for a zero date if there is some garbage after */ - if (!not_zero_date) /* If zero date */ - { - for (; str != end ; str++) - { - if (!my_isspace(&my_charset_latin1, *str)) - { - not_zero_date= 1; /* Give warning */ - break; - } - } - } - *was_cut= test(not_zero_date); + *was_cut= 1; goto err; } - if (check_date(l_time, not_zero_date != 0, flags, was_cut)) + if (check_date(l_time, not_zero_date, flags, was_cut)) goto err; l_time->time_type= (number_of_fields <= 3 ? @@ -495,16 +407,15 @@ str_to_time(const char *str, uint length, MYSQL_TIME *l_time, ulong date[5]; ulonglong value; const char *end=str+length, *end_of_days; - my_bool found_days,found_hours; - uint state; + my_bool found_days,found_hours, neg= 0; + uint UNINIT_VAR(state); - l_time->neg=0; *warning= 0; for (; str != end && my_isspace(&my_charset_latin1,*str) ; str++) length--; if (str != end && *str == '-') { - l_time->neg=1; + neg=1; str++; length--; } @@ -527,6 +438,7 @@ str_to_time(const char *str, uint length, MYSQL_TIME *l_time, } } + l_time->neg= neg; /* Not a timestamp. Try to get this as a DAYS_TO_SECOND string */ for (value=0; str != end && my_isdigit(&my_charset_latin1,*str) ; str++) value=value*10L + (long) (*str - '0'); @@ -536,7 +448,6 @@ str_to_time(const char *str, uint length, MYSQL_TIME *l_time, for (; str != end && my_isspace(&my_charset_latin1, str[0]) ; str++) ; - LINT_INIT(state); found_days=found_hours=0; if ((uint) (end-str) > 1 && str != end_of_days && my_isdigit(&my_charset_latin1, *str)) From 9fe317ffd6e3545e7896389641b74c2977a5e4b4 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 22 Jun 2012 11:40:40 +0200 Subject: [PATCH 097/289] MDEV-225: Replace with dummy events an event that is not understood by a slave to which it should be sent Add function to replace arbitrary event with dummy event. Add code which uses this to fix the bug that enabling row_annotate events on the master breaks slaves which do not request such events. Add that slaves set a variable @mariadb_slave_capability to inform the master in a robust way about which events it can, and cannot, handle. Add tests. --- client/mysqlbinlog.cc | 13 +++ mysql-test/include/mtr_warnings.sql | 2 + .../rpl/r/rpl_mariadb_slave_capability.result | 98 ++++++++++++++++ .../rpl/t/rpl_mariadb_slave_capability.test | 104 +++++++++++++++++ sql/log_event.cc | 109 ++++++++++++++++++ sql/log_event.h | 38 ++++++ sql/slave.cc | 32 +++++ sql/sql_repl.cc | 69 ++++++++++- 8 files changed, 459 insertions(+), 6 deletions(-) create mode 100644 mysql-test/suite/rpl/r/rpl_mariadb_slave_capability.result create mode 100644 mysql-test/suite/rpl/t/rpl_mariadb_slave_capability.test diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index d10504425f5..f604b8bc84f 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -1807,6 +1807,19 @@ static Exit_status check_master_version() "Master returned '%s'", mysql_error(mysql)); goto err; } + + /* + Announce our capabilities to the server, so it will send us all the events + that we know about. + */ + if (mysql_query(mysql, "SET @mariadb_slave_capability=" + STRINGIFY_ARG(MARIA_SLAVE_CAPABILITY_MINE))) + { + error("Could not inform master about capability. Master returned '%s'", + mysql_error(mysql)); + goto err; + } + delete glob_description_event; switch (version) { case 3: diff --git a/mysql-test/include/mtr_warnings.sql b/mysql-test/include/mtr_warnings.sql index a690ca4b334..c30cb7d1ff4 100644 --- a/mysql-test/include/mtr_warnings.sql +++ b/mysql-test/include/mtr_warnings.sql @@ -225,6 +225,8 @@ INSERT INTO global_suppressions VALUES ("Slave I/O: The slave I/O thread stops because a fatal error is encountered when it tried to SET @master_binlog_checksum on master.*"), ("Slave I/O: Get master BINLOG_CHECKSUM failed with error.*"), ("Slave I/O: Notifying master by SET @master_binlog_checksum= @@global.binlog_checksum failed with error.*"), + ("Slave I/O: Setting master-side filtering of @@skip_replication failed with error:.*"), + ("Slave I/O: Setting @mariadb_slave_capability failed with error:.*"), ("THE_LAST_SUPPRESSION")|| diff --git a/mysql-test/suite/rpl/r/rpl_mariadb_slave_capability.result b/mysql-test/suite/rpl/r/rpl_mariadb_slave_capability.result new file mode 100644 index 00000000000..5eae28441c2 --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_mariadb_slave_capability.result @@ -0,0 +1,98 @@ +include/master-slave.inc +[connection master] +set @old_master_binlog_checksum= @@global.binlog_checksum; +set @old_slave_dbug= @@global.debug_dbug; +CREATE TABLE t1 (a INT PRIMARY KEY); +INSERT INTO t1 VALUES (0); +# Test slave with no capability gets dummy event, which is ignored. +include/stop_slave.inc +SET @@global.debug_dbug='+d,simulate_slave_capability_none'; +include/start_slave.inc +ALTER TABLE t1 ORDER BY a; +SET SESSION binlog_annotate_row_events = ON; +DELETE FROM t1; +INSERT INTO t1 /* A comment just to make the annotate event sufficiently long that the dummy event will need to get padded with spaces so that we can test that this works */ VALUES(1); +show binlog events in 'master-bin.000001' from limit 0, 10; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Annotate_rows # # DELETE FROM t1 +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Delete_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Annotate_rows # # INSERT INTO t1 /* A comment just to make the annotate event sufficiently long that the dummy event will need to get padded with spaces so that we can test that this works */ VALUES(1) +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +SELECT * FROM t1; +a +1 +show relaylog events in 'slave-relay-bin.000003' from limit 0,10; +Log_name Pos Event_type Server_id End_log_pos Info +slave-relay-bin.000003 # Query # # BEGIN +slave-relay-bin.000003 # User var # # @`!dummyvar`=NULL +slave-relay-bin.000003 # Table_map # # table_id: # (test.t1) +slave-relay-bin.000003 # Delete_rows # # table_id: # flags: STMT_END_F +slave-relay-bin.000003 # Query # # COMMIT +slave-relay-bin.000003 # Query # # BEGIN +slave-relay-bin.000003 # Query # # # Dummy event replacing event type 160 that slave cannot handle. +slave-relay-bin.000003 # Table_map # # table_id: # (test.t1) +slave-relay-bin.000003 # Write_rows # # table_id: # flags: STMT_END_F +slave-relay-bin.000003 # Query # # COMMIT +set @@global.debug_dbug= @old_slave_dbug; +# Test dummy event is checksummed correctly. +set @@global.binlog_checksum = CRC32; +TRUNCATE t1; +INSERT INTO t1 VALUES(2); +show binlog events in 'master-bin.000002' from limit 0, 5; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000002 # Query # # BEGIN +master-bin.000002 # Annotate_rows # # INSERT INTO t1 VALUES(2) +master-bin.000002 # Table_map # # table_id: # (test.t1) +master-bin.000002 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000002 # Query # # COMMIT +SELECT * FROM t1; +a +2 +show relaylog events in 'slave-relay-bin.000005' from limit 3,5; +Log_name Pos Event_type Server_id End_log_pos Info +slave-relay-bin.000005 # Query # # BEGIN +slave-relay-bin.000005 # Query # # # Dummy ev +slave-relay-bin.000005 # Table_map # # table_id: # (test.t1) +slave-relay-bin.000005 # Write_rows # # table_id: # flags: STMT_END_F +slave-relay-bin.000005 # Query # # COMMIT +# Test that slave which cannot tolerate holes in binlog stream but +# knows the event does not get dummy event +include/stop_slave.inc +SET @@global.debug_dbug='+d,simulate_slave_capability_old_53'; +include/start_slave.inc +ALTER TABLE t1 ORDER BY a; +UPDATE t1 SET a = 3; +show binlog events in 'master-bin.000002' from limit 0, 5; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000002 # Query # # BEGIN +master-bin.000002 # Annotate_rows # # UPDATE t1 SET a = 3 +master-bin.000002 # Table_map # # table_id: # (test.t1) +master-bin.000002 # Update_rows # # table_id: # flags: STMT_END_F +master-bin.000002 # Query # # COMMIT +SELECT * FROM t1; +a +3 +show relaylog events in 'slave-relay-bin.000006' from limit 0,5; +Log_name Pos Event_type Server_id End_log_pos Info +slave-relay-bin.000006 # Query # # BEGIN +slave-relay-bin.000006 # Annotate_rows # # UPDATE t1 SET a = 3 +slave-relay-bin.000006 # Table_map # # table_id: # (test.t1) +slave-relay-bin.000006 # Update_rows # # table_id: # flags: STMT_END_F +slave-relay-bin.000006 # Query # # COMMIT +select @@global.log_slave_updates; +@@global.log_slave_updates +1 +select @@global.replicate_annotate_row_events; +@@global.replicate_annotate_row_events +0 +set @@global.debug_dbug= @old_slave_dbug; +Clean up. +set @@global.binlog_checksum = @old_master_binlog_checksum; +DROP TABLE t1; +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_mariadb_slave_capability.test b/mysql-test/suite/rpl/t/rpl_mariadb_slave_capability.test new file mode 100644 index 00000000000..77aa9341ff4 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_mariadb_slave_capability.test @@ -0,0 +1,104 @@ +--source include/master-slave.inc +--source include/have_debug.inc +--source include/have_binlog_format_row.inc + +connection master; + +set @old_master_binlog_checksum= @@global.binlog_checksum; +set @old_slave_dbug= @@global.debug_dbug; +CREATE TABLE t1 (a INT PRIMARY KEY); +INSERT INTO t1 VALUES (0); + +sync_slave_with_master; +connection slave; + +--echo # Test slave with no capability gets dummy event, which is ignored. +--source include/stop_slave.inc +SET @@global.debug_dbug='+d,simulate_slave_capability_none'; +--source include/start_slave.inc +connection master; +# Add a dummy event just to have something to sync_slave_with_master on. +# Otherwise we occasionally get different $relaylog_start, depending on +# whether Format_description_log_event was written to relay log or not +# at the time of SHOW SLAVE STATUS. +ALTER TABLE t1 ORDER BY a; +sync_slave_with_master; +connection slave; +let $relaylog_start= query_get_value(SHOW SLAVE STATUS, Relay_Log_Pos, 1); + +connection master; +SET SESSION binlog_annotate_row_events = ON; +let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1); +let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1); +# A short event, to test when we need to use user_var_event for dummy event. +DELETE FROM t1; +INSERT INTO t1 /* A comment just to make the annotate event sufficiently long that the dummy event will need to get padded with spaces so that we can test that this works */ VALUES(1); +let $binlog_limit= 0, 10; +--source include/show_binlog_events.inc +sync_slave_with_master; +connection slave; + +SELECT * FROM t1; +let $binlog_file= query_get_value(SHOW SLAVE STATUS, Relay_Log_File, 1); +let $binlog_start= $relaylog_start; +let $binlog_limit=0,10; +--source include/show_relaylog_events.inc +set @@global.debug_dbug= @old_slave_dbug; + +--echo # Test dummy event is checksummed correctly. + +connection master; +set @@global.binlog_checksum = CRC32; +TRUNCATE t1; +let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1); +let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1); +INSERT INTO t1 VALUES(2); +let $binlog_limit= 0, 5; +--source include/show_binlog_events.inc +sync_slave_with_master; +connection slave; + +SELECT * FROM t1; +let $binlog_file= query_get_value(SHOW SLAVE STATUS, Relay_Log_File, 1); +let $binlog_start= 0; +let $binlog_limit=3,5; +--source include/show_relaylog_events.inc + +--echo # Test that slave which cannot tolerate holes in binlog stream but +--echo # knows the event does not get dummy event + +--source include/stop_slave.inc +SET @@global.debug_dbug='+d,simulate_slave_capability_old_53'; +--source include/start_slave.inc +connection master; +ALTER TABLE t1 ORDER BY a; +sync_slave_with_master; +connection slave; +let $relaylog_start= query_get_value(SHOW SLAVE STATUS, Relay_Log_Pos, 1); + +connection master; +let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1); +let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1); +UPDATE t1 SET a = 3; +let $binlog_limit= 0, 5; +--source include/show_binlog_events.inc +sync_slave_with_master; +connection slave; + +SELECT * FROM t1; +let $binlog_file= query_get_value(SHOW SLAVE STATUS, Relay_Log_File, 1); +let $binlog_start= $relaylog_start; +let $binlog_limit=0,5; +--source include/show_relaylog_events.inc + +select @@global.log_slave_updates; +select @@global.replicate_annotate_row_events; + +set @@global.debug_dbug= @old_slave_dbug; + +--echo Clean up. +connection master; +set @@global.binlog_checksum = @old_master_binlog_checksum; +DROP TABLE t1; +sync_slave_with_master; +--source include/rpl_end.inc diff --git a/sql/log_event.cc b/sql/log_event.cc index dca9091e03d..f9849fa0ff5 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -3300,6 +3300,115 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, } +/* + Replace a binlog event read into a packet with a dummy event. Either a + Query_log_event that has just a comment, or if that will not fit in the + space used for the event to be replaced, then a NULL user_var event. + + This is used when sending binlog data to a slave which does not understand + this particular event and which is too old to support informational events + or holes in the event stream. + + This allows to write such events into the binlog on the master and still be + able to replicate against old slaves without them breaking. + + Clears the flag LOG_EVENT_THREAD_SPECIFIC_F and set LOG_EVENT_SUPPRESS_USE_F. + Overwrites the type with QUERY_EVENT (or USER_VAR_EVENT), and replaces the + body with a minimal query / NULL user var. + + Returns zero on success, -1 if error due to too little space in original + event. A minimum of 25 bytes (19 bytes fixed header + 6 bytes in the body) + is needed in any event to be replaced with a dummy event. +*/ +int +Query_log_event::dummy_event(String *packet, ulong ev_offset, + uint8 checksum_alg) +{ + uchar *p= (uchar *)packet->ptr() + ev_offset; + size_t data_len= packet->length() - ev_offset; + uint16 flags; + static const size_t min_user_var_event_len= + LOG_EVENT_HEADER_LEN + UV_NAME_LEN_SIZE + 1 + UV_VAL_IS_NULL; // 25 + static const size_t min_query_event_len= + LOG_EVENT_HEADER_LEN + QUERY_HEADER_LEN + 1 + 1; // 34 + + if (checksum_alg == BINLOG_CHECKSUM_ALG_CRC32) + data_len-= BINLOG_CHECKSUM_LEN; + else + DBUG_ASSERT(checksum_alg == BINLOG_CHECKSUM_ALG_UNDEF || + checksum_alg == BINLOG_CHECKSUM_ALG_OFF); + + if (data_len < min_user_var_event_len) + /* Cannot replace with dummy, event too short. */ + return -1; + + flags= uint2korr(p + FLAGS_OFFSET); + flags&= ~LOG_EVENT_THREAD_SPECIFIC_F; + flags|= LOG_EVENT_SUPPRESS_USE_F; + int2store(p + FLAGS_OFFSET, flags); + + if (data_len < min_query_event_len) + { + /* + Have to use dummy user_var event for such a short packet. + + This works, but the event will be considered part of an event group with + the following event. So for example @@global.sql_slave_skip_counter=1 + will skip not only the dummy event, but also the immediately following + event. + + We write a NULL user var with the name @`!dummyvar` (or as much + as that as will fit within the size of the original event - so + possibly just @`!`). + */ + static const char var_name[]= "!dummyvar"; + uint name_len= data_len - (min_user_var_event_len - 1); + + p[EVENT_TYPE_OFFSET]= USER_VAR_EVENT; + int4store(p + LOG_EVENT_HEADER_LEN, name_len); + memcpy(p + LOG_EVENT_HEADER_LEN + UV_NAME_LEN_SIZE, var_name, name_len); + p[LOG_EVENT_HEADER_LEN + UV_NAME_LEN_SIZE + name_len]= 1; // indicates NULL + } + else + { + /* + Use a dummy query event, just a comment. + */ + static const char message[]= + "# Dummy event replacing event type %u that slave cannot handle."; + char buf[sizeof(message)+1]; /* +1, as %u can expand to 3 digits. */ + uchar old_type= p[EVENT_TYPE_OFFSET]; + uchar *q= p + LOG_EVENT_HEADER_LEN; + size_t comment_len, len; + + p[EVENT_TYPE_OFFSET]= QUERY_EVENT; + int4store(q + Q_THREAD_ID_OFFSET, 0); + int4store(q + Q_EXEC_TIME_OFFSET, 0); + q[Q_DB_LEN_OFFSET]= 0; + int2store(q + Q_ERR_CODE_OFFSET, 0); + int2store(q + Q_STATUS_VARS_LEN_OFFSET, 0); + q[Q_DATA_OFFSET]= 0; /* Zero terminator for empty db */ + q+= Q_DATA_OFFSET + 1; + len= my_snprintf(buf, sizeof(buf), message, old_type); + comment_len= data_len - (min_query_event_len - 1); + if (comment_len <= len) + memcpy(q, buf, comment_len); + else + { + memcpy(q, buf, len); + memset(q+len, ' ', comment_len - len); + } + } + + if (checksum_alg == BINLOG_CHECKSUM_ALG_CRC32) + { + ha_checksum crc= my_checksum(0L, p, data_len); + int4store(p + data_len, crc); + } + return 0; +} + + #ifdef MYSQL_CLIENT /** Query_log_event::print(). diff --git a/sql/log_event.h b/sql/log_event.h index bf45dd0cc93..12d5e1417f4 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -573,6 +573,43 @@ enum enum_binlog_checksum_alg { #define BINLOG_CHECKSUM_LEN CHECKSUM_CRC32_SIGNATURE_LEN #define BINLOG_CHECKSUM_ALG_DESC_LEN 1 /* 1 byte checksum alg descriptor */ +/* + These are capability numbers for MariaDB slave servers. + + Newer MariaDB slaves set this to inform the master about their capabilities. + This allows the master to decide which events it can send to the slave + without breaking replication on old slaves that maybe do not understand + all events from newer masters. + + As new releases are backwards compatible, a given capability implies also + all capabilities with smaller number. + + Older MariaDB slaves and other MySQL slave servers do not set this, so they + are recorded with capability 0. +*/ + +/* MySQL or old MariaDB slave with no announced capability. */ +#define MARIA_SLAVE_CAPABILITY_UNKNOWN 0 +/* MariaDB >= 5.3, which understands ANNOTATE_ROWS_EVENT. */ +#define MARIA_SLAVE_CAPABILITY_ANNOTATE 1 +/* + MariaDB >= 5.5. This version has the capability to tolerate events omitted + from the binlog stream without breaking replication (MySQL slaves fail + because they mis-compute the offsets into the master's binlog). +*/ +#define MARIA_SLAVE_CAPABILITY_TOLERATE_HOLES 2 +/* MariaDB > 5.5, which knows about binlog_checkpoint_log_event. */ +#define MARIA_SLAVE_CAPABILITY_BINLOG_CHECKPOINT 3 +/* + MariaDB server which understands MySQL 5.6 ignorable events. This server + can tolerate receiving any event with the LOG_EVENT_IGNORABLE_F flag set. +*/ +#define MARIA_SLAVE_CAPABILITY_IGNORABLE 4 + +/* Our capability. */ +#define MARIA_SLAVE_CAPABILITY_MINE MARIA_SLAVE_CAPABILITY_BINLOG_CHECKPOINT + + /** @enum Log_event_type @@ -1827,6 +1864,7 @@ public: my_free(data_buf); } Log_event_type get_type_code() { return QUERY_EVENT; } + static int dummy_event(String *packet, ulong ev_offset, uint8 checksum_alg); #ifdef MYSQL_SERVER bool write(IO_CACHE* file); virtual bool write_post_header_for_derived(IO_CACHE* file) { return FALSE; } diff --git a/sql/slave.cc b/sql/slave.cc index ac42e72978d..8869ccb7004 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1753,6 +1753,38 @@ past_checksum: } } } + + /* Announce MariaDB slave capabilities. */ + DBUG_EXECUTE_IF("simulate_slave_capability_none", goto after_set_capability;); + { + const char *q= + DBUG_EVALUATE_IF("simulate_slave_capability_old_53", + "SET @mariadb_slave_capability=" + STRINGIFY_ARG(MARIA_SLAVE_CAPABILITY_ANNOTATE), + "SET @mariadb_slave_capability=" + STRINGIFY_ARG(MARIA_SLAVE_CAPABILITY_MINE)); + if (mysql_real_query(mysql, q, strlen(q))) + { + err_code= mysql_errno(mysql); + if (is_network_error(err_code)) + { + mi->report(ERROR_LEVEL, err_code, + "Setting @mariadb_slave_capability failed with error: %s", + mysql_error(mysql)); + goto network_err; + } + else + { + /* Fatal error */ + errmsg= "The slave I/O thread stops because a fatal error is " + "encountered when it tries to set @mariadb_slave_capability."; + sprintf(err_buff, "%s Error: %s", errmsg, mysql_error(mysql)); + goto err; + } + } + } +after_set_capability: + err: if (errmsg) { diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 53ac103dda1..d7308eddb7f 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -491,6 +491,27 @@ static ulonglong get_heartbeat_period(THD * thd) return entry? entry->val_int(&null_value) : 0; } +/* + Lookup the capabilities of the slave, which it announces by setting a value + MARIA_SLAVE_CAPABILITY_XXX in @mariadb_slave_capability. + + Older MariaDB slaves, and other MySQL slaves, do not set + @mariadb_slave_capability, corresponding to a capability of + MARIA_SLAVE_CAPABILITY_UNKNOWN (0). +*/ +static int +get_mariadb_slave_capability(THD *thd) +{ + bool null_value; + const LEX_STRING name= { C_STRING_WITH_LEN("mariadb_slave_capability") }; + const user_var_entry *entry= + (user_var_entry*) my_hash_search(&thd->user_vars, (uchar*) name.str, + name.length); + return entry ? + (int)(entry->val_int(&null_value)) : MARIA_SLAVE_CAPABILITY_UNKNOWN; +} + + /* Function prepares and sends repliation heartbeat event. @@ -563,14 +584,44 @@ static int send_heartbeat_event(NET* net, String* packet, static const char * send_event_to_slave(THD *thd, NET *net, String* const packet, ushort flags, Log_event_type event_type, char *log_file_name, - IO_CACHE *log) + IO_CACHE *log, int mariadb_slave_capability, + ulong ev_offset, uint8 current_checksum_alg) { my_off_t pos; /* Do not send annotate_rows events unless slave requested it. */ - if (event_type == ANNOTATE_ROWS_EVENT && - !(flags & BINLOG_SEND_ANNOTATE_ROWS_EVENT)) - return NULL; + if (event_type == ANNOTATE_ROWS_EVENT && !(flags & BINLOG_SEND_ANNOTATE_ROWS_EVENT)) + { + if (mariadb_slave_capability >= MARIA_SLAVE_CAPABILITY_TOLERATE_HOLES) + { + /* This slave can tolerate events omitted from the binlog stream. */ + return NULL; + } + else if (mariadb_slave_capability >= MARIA_SLAVE_CAPABILITY_ANNOTATE) + { + /* + The slave did not request ANNOTATE_ROWS_EVENT (it does not need them as + it will not log them in its own binary log). However, it understands the + event and will just ignore it, and it would break if we omitted it, + leaving a hole in the binlog stream. So just send the event as-is. + */ + } + else + { + /* + The slave does not understand ANNOTATE_ROWS_EVENT. + + Older MariaDB slaves (and MySQL slaves) will break replication if there + are holes in the binlog stream (they will miscompute the binlog offset + and request the wrong position when reconnecting). + + So replace the event with a dummy event of the same size that will be + a no-operation on the slave. + */ + if (Query_log_event::dummy_event(packet, ev_offset, current_checksum_alg)) + return "Failed to replace row annotate event with dummy: too small event."; + } + } /* Skip events with the @@skip_replication flag set, if slave requested @@ -628,6 +679,7 @@ void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos, NET* net = &thd->net; mysql_mutex_t *log_lock; mysql_cond_t *log_cond; + int mariadb_slave_capability; uint8 current_checksum_alg= BINLOG_CHECKSUM_ALG_UNDEF; int old_max_allowed_packet= thd->variables.max_allowed_packet; @@ -653,6 +705,7 @@ void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos, heartbeat_ts= &heartbeat_buf; set_timespec_nsec(*heartbeat_ts, 0); } + mariadb_slave_capability= get_mariadb_slave_capability(thd); if (global_system_variables.log_warnings > 1) sql_print_information("Start binlog_dump to slave_server(%d), pos(%s, %lu)", thd->server_id, log_ident, (ulong)pos); @@ -939,7 +992,9 @@ impossible position"; } if ((tmp_msg= send_event_to_slave(thd, net, packet, flags, event_type, - log_file_name, &log))) + log_file_name, &log, + mariadb_slave_capability, ev_offset, + current_checksum_alg))) { errmsg= tmp_msg; my_errno= ER_UNKNOWN_ERROR; @@ -1097,7 +1152,9 @@ impossible position"; if (read_packet && (tmp_msg= send_event_to_slave(thd, net, packet, flags, event_type, - log_file_name, &log))) + log_file_name, &log, + mariadb_slave_capability, ev_offset, + current_checksum_alg))) { errmsg= tmp_msg; my_errno= ER_UNKNOWN_ERROR; From 0697ee265fa4fe4d617dc96194fcf2532fd73402 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 22 Jun 2012 11:46:28 +0200 Subject: [PATCH 098/289] MDEV-181: XID crash recovery across binlog boundaries Keep track of how many pending XIDs (transactions that are prepared in storage engine and written into binlog, but not yet durably committed on disk in the engine) there are in each binlog. When the count of one binlog drops to zero, write a new binlog checkpoint event, telling which is the oldest binlog with pending XIDs. When doing XA recovery after a crash, check the last binlog checkpoint event, and scan all binlog files from that point onwards for XIDs that must be committed if found in prepared state inside engine. Remove the code in binlog rotation that waits for all prepared XIDs to be committed before writing a new binlog file (this is no longer necessary when recovery can scan multiple binlog files). --- .../mix_innodb_myisam_binlog.test | 4 +- .../rpl_tests/create_recursive_construct.inc | 17 +- mysql-test/extra/rpl_tests/rpl_deadlock.test | 2 +- mysql-test/include/binlog_start_pos.inc | 8 +- mysql-test/include/show_binlog_events.inc | 2 +- mysql-test/include/show_binlog_events2.inc | 2 +- mysql-test/include/show_events.inc | 29 +- mysql-test/r/mysqlbinlog_row.result | 2 + mysql-test/r/mysqlbinlog_row_innodb.result | 8 + mysql-test/r/mysqlbinlog_row_myisam.result | 8 + mysql-test/r/mysqlbinlog_row_trans.result | 2 + mysql-test/r/mysqldump-max.result | 10 +- mysql-test/r/xa_binlog.result | 2 +- mysql-test/suite/binlog/r/binlog_ioerr.result | 1 + .../suite/binlog/r/binlog_row_annotate.result | 13 + .../suite/binlog/r/binlog_row_binlog.result | 1 + .../r/binlog_row_mysqlbinlog_options.result | 4 + .../suite/binlog/r/binlog_server_id.result | 3 + .../suite/binlog/r/binlog_stm_binlog.result | 1 + .../binlog/r/binlog_stm_blackhole.result | 1 + .../suite/binlog/r/binlog_xa_recover.result | 175 ++++++ mysql-test/suite/binlog/t/binlog_killed.test | 12 +- .../binlog/t/binlog_killed_simulate.test | 4 +- .../binlog/t/binlog_xa_recover-master.opt | 1 + .../suite/binlog/t/binlog_xa_recover.test | 174 ++++++ .../suite/innodb/r/binlog_consistent.result | 69 +-- .../innodb/r/group_commit_binlog_pos.result | 2 +- ...ommit_binlog_pos_no_optimize_thread.result | 2 +- .../suite/innodb/r/group_commit_crash.result | 10 +- ...oup_commit_crash_no_optimize_thread.result | 10 +- .../suite/innodb/t/group_commit_crash.test | 2 +- ...group_commit_crash_no_optimize_thread.test | 2 +- mysql-test/suite/maria/maria-connect.result | 1 + .../suite/perfschema/r/all_instances.result | 2 + mysql-test/suite/perfschema/r/relaylog.result | 8 +- mysql-test/suite/rpl/r/rpl_checksum.result | 2 +- .../rpl/r/rpl_mariadb_slave_capability.result | 2 +- .../suite/rpl/r/rpl_row_annotate_do.result | 1 + .../suite/rpl/r/rpl_row_annotate_dont.result | 1 + .../rpl/r/rpl_row_show_relaylog_events.result | 5 +- .../r/rpl_stm_mix_show_relaylog_events.result | 5 +- .../rpl/t/rpl_mariadb_slave_capability.test | 2 +- mysql-test/t/mysqlbinlog2.test | 38 +- mysql-test/t/mysqldump-max.test | 2 +- mysql-test/t/xa_binlog.test | 2 +- sql/handler.cc | 1 + sql/log.cc | 528 +++++++++++++++--- sql/log.h | 53 +- sql/log_event.cc | 88 ++- sql/log_event.h | 35 ++ sql/mysqld.cc | 8 +- sql/mysqld.h | 4 +- sql/sql_repl.cc | 24 + 53 files changed, 1174 insertions(+), 221 deletions(-) create mode 100644 mysql-test/suite/binlog/r/binlog_xa_recover.result create mode 100644 mysql-test/suite/binlog/t/binlog_xa_recover-master.opt create mode 100644 mysql-test/suite/binlog/t/binlog_xa_recover.test 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 b41bfeaba74..4ce001cfdd7 100644 --- a/mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test +++ b/mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test @@ -318,8 +318,8 @@ connection con4; select get_lock("a",10); # wait for rollback to finish if (`select @@binlog_format = 'STATEMENT' || @@binlog_format = 'MIXED'`) { - --let $binlog_rollback= query_get_value(SHOW BINLOG EVENTS, Pos, 7) - --let $binlog_query= query_get_value(SHOW BINLOG EVENTS, Info, 7) + --let $binlog_rollback= query_get_value(SHOW BINLOG EVENTS, Pos, 8) + --let $binlog_query= query_get_value(SHOW BINLOG EVENTS, Info, 8) if ($binlog_query != ROLLBACK) { --echo Wrong query from SHOW BINLOG EVENTS. Expected ROLLBACK, got '$binlog_query' --source include/show_rpl_debug_info.inc diff --git a/mysql-test/extra/rpl_tests/create_recursive_construct.inc b/mysql-test/extra/rpl_tests/create_recursive_construct.inc index 6e130a8154f..e790a1db41f 100644 --- a/mysql-test/extra/rpl_tests/create_recursive_construct.inc +++ b/mysql-test/extra/rpl_tests/create_recursive_construct.inc @@ -325,7 +325,8 @@ if ($CRC_RET_stmt_sidef) { SHOW BINLOG EVENTS; --die Wrong number of warnings. } - --let $binlog_event= query_get_value(SHOW BINLOG EVENTS, Event_type, 2) + # There should be no events after format description and binlog checkpoint. + --let $binlog_event= query_get_value(SHOW BINLOG EVENTS, Event_type, 3) if ($binlog_event != No such row) { --enable_query_log --echo ******** Failure! Something was written to the binlog despite SQL_LOG_BIN=0 ******** @@ -345,23 +346,23 @@ if ($CRC_RET_stmt_sidef) { SHOW BINLOG EVENTS; --die Warnings printed } - --let $event_type= query_get_value(SHOW BINLOG EVENTS, Event_type, 3) - # The first event is format_description, the second is - # Query_event('BEGIN'), and the third should be our Query + --let $event_type= query_get_value(SHOW BINLOG EVENTS, Event_type, 4) + # The first event is format_description, the second is Binlog_checkpoint, + # the third Query_event('BEGIN'), and the fourth should be our Query # for 'INSERT DELAYED' unsafe_type 3, which is safe after # the fix of bug#54579. if (`SELECT $unsafe_type = 3 AND '$event_type' != 'Query'`) { --enable_query_log - --echo ******** Failure! Event number 3 was a '$event_type', not a 'Query'. ******** + --echo ******** Failure! Event number 4 was a '$event_type', not a 'Query'. ******** SHOW BINLOG EVENTS; --die Wrong events in binlog. } - # The first event is format_description, the second is - # Query_event('BEGIN'), and the third should be our Table_map + # The first event is format_description, the second is Binlog_checkpoint, + # the third is Query_event('BEGIN'), and the fourth should be our Table_map # for unsafe statement. if (`SELECT $unsafe_type != 3 AND '$event_type' != 'Table_map'`) { --enable_query_log - --echo ******** Failure! Event number 3 was a '$event_type', not a 'Table_map'. ******** + --echo ******** Failure! Event number 4 was a '$event_type', not a 'Table_map'. ******** SHOW BINLOG EVENTS; --die Wrong events in binlog. } diff --git a/mysql-test/extra/rpl_tests/rpl_deadlock.test b/mysql-test/extra/rpl_tests/rpl_deadlock.test index 0e862e041e6..56ff4683df8 100644 --- a/mysql-test/extra/rpl_tests/rpl_deadlock.test +++ b/mysql-test/extra/rpl_tests/rpl_deadlock.test @@ -34,7 +34,7 @@ INSERT INTO t3 VALUES (3); COMMIT; save_master_pos; # Save BEGIN event into variable -let $master_pos_begin= query_get_value(SHOW BINLOG EVENTS, Pos, 5); +let $master_pos_begin= query_get_value(SHOW BINLOG EVENTS, Pos, 6); --echo # 1) Test deadlock diff --git a/mysql-test/include/binlog_start_pos.inc b/mysql-test/include/binlog_start_pos.inc index add5a42a426..5237e357b28 100644 --- a/mysql-test/include/binlog_start_pos.inc +++ b/mysql-test/include/binlog_start_pos.inc @@ -15,14 +15,14 @@ # 1 /* Checksum algorithm */ + # 4 /* CRC32 length */ # -# With current number of events = 160, +# With current number of events = 161, # -# binlog_start_pos = 4 + 19 + 57 + 160 + 1 + 4 = 245. +# binlog_start_pos = 4 + 19 + 57 + 161 + 1 + 4 = 246. # ############################################################################## -let $binlog_start_pos=245; +let $binlog_start_pos=246; --disable_query_log -SET @binlog_start_pos=245; +SET @binlog_start_pos=246; --enable_query_log diff --git a/mysql-test/include/show_binlog_events.inc b/mysql-test/include/show_binlog_events.inc index e5670c054fa..5ab837f0e6b 100644 --- a/mysql-test/include/show_binlog_events.inc +++ b/mysql-test/include/show_binlog_events.inc @@ -9,7 +9,7 @@ # # It shows the first binary log file if $binlog_file is not given. # -# It shows events from the end position of the description event if +# It shows events from the end position of the binlog checkpoint event if # $binlog_start is not given. # # It shows all of the events if $binlog_limit is not given. diff --git a/mysql-test/include/show_binlog_events2.inc b/mysql-test/include/show_binlog_events2.inc index c32d12537fd..1fd9ce96d53 100644 --- a/mysql-test/include/show_binlog_events2.inc +++ b/mysql-test/include/show_binlog_events2.inc @@ -1,4 +1,4 @@ ---let $binlog_start=245 +--let $binlog_start=246 --replace_result $binlog_start --replace_column 2 # 5 # --replace_regex /\/\* xid=.* \*\//\/* XID *\// /table_id: [0-9]+/table_id: #/ diff --git a/mysql-test/include/show_events.inc b/mysql-test/include/show_events.inc index ff5a7105c24..878773d2b5b 100644 --- a/mysql-test/include/show_events.inc +++ b/mysql-test/include/show_events.inc @@ -3,13 +3,28 @@ # It is only called by show_binlog_events.inc and show_relaylog_events.inc. ############################################################################## +# Do not modify $binlog_start - if we did, it could wrongly persist until a +# later call of show_events.inc. +if ($binlog_start) +{ + --let $_binlog_start= $binlog_start +} if (!$binlog_start) { - # If $binlog_start is not set, we will set it as the second event's - # position. The first event(Description Event) is always ignored. For - # description event's length might be changed because of adding new events, - # 'SHOW BINLOG EVENTS LIMIT 1' is used to get the right value. - --let $binlog_start= query_get_value(SHOW BINLOG EVENTS LIMIT 1, End_log_pos, 1) + # If $binlog_start is not set, we will set it as the third event's + # position (second in relay log which has not Binlog Checkpoing event). + # The first two events (Description Event and Binlog Checkpoint + # event) are always ignored. For description event's length might be changed + # because of adding new events, 'SHOW BINLOG EVENTS LIMIT 2' is used to get + # the right value. + if ($is_relay_log) + { + --let $_binlog_start= query_get_value(SHOW BINLOG EVENTS LIMIT 1, End_log_pos, 1) + } + if (!$is_relay_log) + { + --let $_binlog_start= query_get_value(SHOW BINLOG EVENTS LIMIT 2, End_log_pos, 2) + } } --let $_statement=show binlog events @@ -23,7 +38,7 @@ if ($binlog_file) --let $_statement= $_statement in '$binlog_file' } ---let $_statement= $_statement from $binlog_start +--let $_statement= $_statement from $_binlog_start # Cannot use if($binlog_limit) since the variable may begin with a 0 @@ -32,7 +47,7 @@ if (`SELECT '$binlog_limit' <> ''`) --let $_statement= $_statement limit $binlog_limit } ---replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR $binlog_start +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR $_binlog_start --replace_column 2 # 4 # 5 # --replace_regex /\/\* xid=.* \*\//\/* XID *\// /table_id: [0-9]+/table_id: #/ /file_id=[0-9]+/file_id=#/ /block_len=[0-9]+/block_len=#/ /Server ver:.*$/SERVER_VERSION, BINLOG_VERSION/ --eval $_statement diff --git a/mysql-test/r/mysqlbinlog_row.result b/mysql-test/r/mysqlbinlog_row.result index ce46b7ea898..6361cdadb32 100644 --- a/mysql-test/r/mysqlbinlog_row.result +++ b/mysql-test/r/mysqlbinlog_row.result @@ -335,6 +335,8 @@ DELIMITER /*!*/; #010909 4:46:40 server id 1 end_log_pos # Start: binlog v 4, server v #.##.## created 010909 4:46:40 at startup ROLLBACK/*!*/; # at # +#010909 4:46:40 server id 1 end_log_pos # Binlog checkpoint master-bin.000001 +# at # #010909 4:46:40 server id 1 end_log_pos # Query thread_id=# exec_time=# error_code=0 use `test`/*!*/; SET TIMESTAMP=1000000000/*!*/; diff --git a/mysql-test/r/mysqlbinlog_row_innodb.result b/mysql-test/r/mysqlbinlog_row_innodb.result index 63b64489a37..4be266d586c 100644 --- a/mysql-test/r/mysqlbinlog_row_innodb.result +++ b/mysql-test/r/mysqlbinlog_row_innodb.result @@ -2252,6 +2252,8 @@ DELIMITER /*!*/; #010909 4:46:40 server id 1 end_log_pos # Start: binlog v 4, server v #.##.## created 010909 4:46:40 at startup ROLLBACK/*!*/; # at # +#010909 4:46:40 server id 1 end_log_pos # Binlog checkpoint master-bin.000001 +# at # #010909 4:46:40 server id 1 end_log_pos # Query thread_id=# exec_time=# error_code=0 use `test`/*!*/; SET TIMESTAMP=1000000000/*!*/; @@ -3875,6 +3877,8 @@ DELIMITER /*!*/; #010909 4:46:40 server id 1 end_log_pos # Start: binlog v 4, server v #.##.## created 010909 4:46:40 at startup ROLLBACK/*!*/; # at # +#010909 4:46:40 server id 1 end_log_pos # Binlog checkpoint master-bin.000001 +# at # #010909 4:46:40 server id 1 end_log_pos # Query thread_id=# exec_time=# error_code=0 use `test`/*!*/; SET TIMESTAMP=1000000000/*!*/; @@ -4242,6 +4246,8 @@ DELIMITER /*!*/; #010909 4:46:40 server id 1 end_log_pos # Start: binlog v 4, server v #.##.## created 010909 4:46:40 at startup ROLLBACK/*!*/; # at # +#010909 4:46:40 server id 1 end_log_pos # Binlog checkpoint master-bin.000001 +# at # #010909 4:46:40 server id 1 end_log_pos # Query thread_id=# exec_time=# error_code=0 use `test`/*!*/; SET TIMESTAMP=1000000000/*!*/; @@ -4803,6 +4809,8 @@ DELIMITER /*!*/; #010909 4:46:40 server id 1 end_log_pos # Start: binlog v 4, server v #.##.## created 010909 4:46:40 at startup ROLLBACK/*!*/; # at # +#010909 4:46:40 server id 1 end_log_pos # Binlog checkpoint master-bin.000001 +# at # #010909 4:46:40 server id 1 end_log_pos # Query thread_id=# exec_time=# error_code=0 use `test`/*!*/; SET TIMESTAMP=1000000000/*!*/; diff --git a/mysql-test/r/mysqlbinlog_row_myisam.result b/mysql-test/r/mysqlbinlog_row_myisam.result index 6e8c7cd64f9..d4062565320 100644 --- a/mysql-test/r/mysqlbinlog_row_myisam.result +++ b/mysql-test/r/mysqlbinlog_row_myisam.result @@ -2252,6 +2252,8 @@ DELIMITER /*!*/; #010909 4:46:40 server id 1 end_log_pos # Start: binlog v 4, server v #.##.## created 010909 4:46:40 at startup ROLLBACK/*!*/; # at # +#010909 4:46:40 server id 1 end_log_pos # Binlog checkpoint master-bin.000001 +# at # #010909 4:46:40 server id 1 end_log_pos # Query thread_id=# exec_time=# error_code=0 use `test`/*!*/; SET TIMESTAMP=1000000000/*!*/; @@ -3897,6 +3899,8 @@ DELIMITER /*!*/; #010909 4:46:40 server id 1 end_log_pos # Start: binlog v 4, server v #.##.## created 010909 4:46:40 at startup ROLLBACK/*!*/; # at # +#010909 4:46:40 server id 1 end_log_pos # Binlog checkpoint master-bin.000001 +# at # #010909 4:46:40 server id 1 end_log_pos # Query thread_id=# exec_time=# error_code=0 use `test`/*!*/; SET TIMESTAMP=1000000000/*!*/; @@ -4270,6 +4274,8 @@ DELIMITER /*!*/; #010909 4:46:40 server id 1 end_log_pos # Start: binlog v 4, server v #.##.## created 010909 4:46:40 at startup ROLLBACK/*!*/; # at # +#010909 4:46:40 server id 1 end_log_pos # Binlog checkpoint master-bin.000001 +# at # #010909 4:46:40 server id 1 end_log_pos # Query thread_id=# exec_time=# error_code=0 use `test`/*!*/; SET TIMESTAMP=1000000000/*!*/; @@ -4841,6 +4847,8 @@ DELIMITER /*!*/; #010909 4:46:40 server id 1 end_log_pos # Start: binlog v 4, server v #.##.## created 010909 4:46:40 at startup ROLLBACK/*!*/; # at # +#010909 4:46:40 server id 1 end_log_pos # Binlog checkpoint master-bin.000001 +# at # #010909 4:46:40 server id 1 end_log_pos # Query thread_id=# exec_time=# error_code=0 use `test`/*!*/; SET TIMESTAMP=1000000000/*!*/; diff --git a/mysql-test/r/mysqlbinlog_row_trans.result b/mysql-test/r/mysqlbinlog_row_trans.result index 33c997d76a7..85106ab9684 100644 --- a/mysql-test/r/mysqlbinlog_row_trans.result +++ b/mysql-test/r/mysqlbinlog_row_trans.result @@ -131,6 +131,8 @@ DELIMITER /*!*/; #010909 4:46:40 server id 1 end_log_pos # Start: binlog v 4, server v #.##.## created 010909 4:46:40 at startup ROLLBACK/*!*/; # at # +#010909 4:46:40 server id 1 end_log_pos # Binlog checkpoint master-bin.000001 +# at # #010909 4:46:40 server id 1 end_log_pos # Query thread_id=# exec_time=# error_code=0 use `test`/*!*/; SET TIMESTAMP=1000000000/*!*/; diff --git a/mysql-test/r/mysqldump-max.result b/mysql-test/r/mysqldump-max.result index 6722f308358..fb0be20c119 100644 --- a/mysql-test/r/mysqldump-max.result +++ b/mysql-test/r/mysqldump-max.result @@ -332,12 +332,12 @@ a b 2 1 DROP TABLE t1; DROP TABLE t2; -SHOW BINLOG EVENTS LIMIT 6,3; +SHOW BINLOG EVENTS LIMIT 7,3; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 663 Query 1 731 BEGIN -master-bin.000001 731 Query 1 828 use `test`; INSERT INTO t2 VALUES (1,0), (2,0) -master-bin.000001 828 Xid 1 855 COMMIT /* XID */ --- CHANGE MASTER TO MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=855; +master-bin.000001 704 Query 1 772 BEGIN +master-bin.000001 772 Query 1 869 use `test`; INSERT INTO t2 VALUES (1,0), (2,0) +master-bin.000001 869 Xid 1 896 COMMIT /* XID */ +-- CHANGE MASTER TO MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=896; SELECT * FROM t1 ORDER BY a; a 1 diff --git a/mysql-test/r/xa_binlog.result b/mysql-test/r/xa_binlog.result index 3ce64953902..395f0dc62a4 100644 --- a/mysql-test/r/xa_binlog.result +++ b/mysql-test/r/xa_binlog.result @@ -18,7 +18,7 @@ a 1 2 3 -SHOW BINLOG EVENTS LIMIT 1,9; +SHOW BINLOG EVENTS LIMIT 2,9; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query 1 # BEGIN master-bin.000001 # Query 1 # use `test`; INSERT INTO t1 VALUES (1) diff --git a/mysql-test/suite/binlog/r/binlog_ioerr.result b/mysql-test/suite/binlog/r/binlog_ioerr.result index f8e2d189f57..68ff5264aa3 100644 --- a/mysql-test/suite/binlog/r/binlog_ioerr.result +++ b/mysql-test/suite/binlog/r/binlog_ioerr.result @@ -16,6 +16,7 @@ a SHOW BINLOG EVENTS; Log_name Pos Event_type Server_id End_log_pos Info BINLOG POS Format_desc 1 ENDPOS Server ver: #, Binlog ver: # +BINLOG POS Binlog_checkpoint 1 ENDPOS master-bin.000001 BINLOG POS Query 1 ENDPOS use `test`; CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=innodb BINLOG POS Query 1 ENDPOS BEGIN BINLOG POS Query 1 ENDPOS use `test`; INSERT INTO t1 VALUES(0) diff --git a/mysql-test/suite/binlog/r/binlog_row_annotate.result b/mysql-test/suite/binlog/r/binlog_row_annotate.result index 0c008661784..58cac276c95 100644 --- a/mysql-test/suite/binlog/r/binlog_row_annotate.result +++ b/mysql-test/suite/binlog/r/binlog_row_annotate.result @@ -8,6 +8,7 @@ ##################################################################################### show binlog events in 'master-bin.000001' from ; Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Binlog_checkpoint 1 # master-bin.000001 master-bin.000001 # Query 1 # DROP DATABASE IF EXISTS test1 master-bin.000001 # Query 1 # DROP DATABASE IF EXISTS test2 master-bin.000001 # Query 1 # DROP DATABASE IF EXISTS test3 @@ -67,6 +68,8 @@ DELIMITER /*!*/; #010909 4:46:40 server id # end_log_pos # Start: binlog v 4, server v #.##.## created 010909 4:46:40 at startup ROLLBACK/*!*/; # at # +#010909 4:46:40 server id # end_log_pos # Binlog checkpoint master-bin.000001 +# at # #010909 4:46:40 server id # end_log_pos # Query thread_id=# exec_time=# error_code=0 SET TIMESTAMP=1000000000/*!*/; SET @@session.pseudo_thread_id=#/*!*/; @@ -293,6 +296,8 @@ DELIMITER /*!*/; #010909 4:46:40 server id # end_log_pos # Start: binlog v 4, server v #.##.## created 010909 4:46:40 at startup ROLLBACK/*!*/; # at # +#010909 4:46:40 server id # end_log_pos # Binlog checkpoint master-bin.000001 +# at # #010909 4:46:40 server id # end_log_pos # Query thread_id=# exec_time=# error_code=0 SET TIMESTAMP=1000000000/*!*/; SET @@session.pseudo_thread_id=#/*!*/; @@ -437,6 +442,8 @@ DELIMITER /*!*/; #010909 4:46:40 server id # end_log_pos # Start: binlog v 4, server v #.##.## created 010909 4:46:40 at startup ROLLBACK/*!*/; # at # +#010909 4:46:40 server id # end_log_pos # Binlog checkpoint master-bin.000001 +# at # #010909 4:46:40 server id # end_log_pos # Query thread_id=# exec_time=# error_code=0 SET TIMESTAMP=1000000000/*!*/; SET @@session.pseudo_thread_id=#/*!*/; @@ -653,6 +660,8 @@ DELIMITER /*!*/; #010909 4:46:40 server id # end_log_pos # Start: binlog v 4, server v #.##.## created 010909 4:46:40 at startup ROLLBACK/*!*/; # at # +#010909 4:46:40 server id # end_log_pos # Binlog checkpoint master-bin.000001 +# at # #010909 4:46:40 server id # end_log_pos # Query thread_id=# exec_time=# error_code=0 SET TIMESTAMP=1000000000/*!*/; SET @@session.pseudo_thread_id=#/*!*/; @@ -879,6 +888,8 @@ DELIMITER /*!*/; #010909 4:46:40 server id # end_log_pos # Start: binlog v 4, server v #.##.## created 010909 4:46:40 at startup ROLLBACK/*!*/; # at # +#010909 4:46:40 server id # end_log_pos # Binlog checkpoint master-bin.000001 +# at # #010909 4:46:40 server id # end_log_pos # Query thread_id=# exec_time=# error_code=0 SET TIMESTAMP=1000000000/*!*/; SET @@session.pseudo_thread_id=#/*!*/; @@ -1023,6 +1034,8 @@ DELIMITER /*!*/; #010909 4:46:40 server id # end_log_pos # Start: binlog v 4, server v #.##.## created 010909 4:46:40 at startup ROLLBACK/*!*/; # at # +#010909 4:46:40 server id # end_log_pos # Binlog checkpoint master-bin.000001 +# at # #010909 4:46:40 server id # end_log_pos # Query thread_id=# exec_time=# error_code=0 SET TIMESTAMP=1000000000/*!*/; SET @@session.pseudo_thread_id=#/*!*/; diff --git a/mysql-test/suite/binlog/r/binlog_row_binlog.result b/mysql-test/suite/binlog/r/binlog_row_binlog.result index 95477d13b50..26710178cd8 100644 --- a/mysql-test/suite/binlog/r/binlog_row_binlog.result +++ b/mysql-test/suite/binlog/r/binlog_row_binlog.result @@ -728,6 +728,7 @@ BINLOG ' SHOW BINLOG EVENTS; Log_name Pos Event_type Server_id End_log_pos Info # # Format_desc 1 # Server ver: #, Binlog ver: # +# # Binlog_checkpoint 1 # master-bin.000001 # # Query 1 # use `test`; CREATE TABLE t1 (a INT PRIMARY KEY) # # Query 1 # BEGIN # # Table_map 1 # table_id: # (test.t1) diff --git a/mysql-test/suite/binlog/r/binlog_row_mysqlbinlog_options.result b/mysql-test/suite/binlog/r/binlog_row_mysqlbinlog_options.result index 9c780390ca8..ae732ffcc08 100644 --- a/mysql-test/suite/binlog/r/binlog_row_mysqlbinlog_options.result +++ b/mysql-test/suite/binlog/r/binlog_row_mysqlbinlog_options.result @@ -34,6 +34,8 @@ DELIMITER /*!*/; # at # #010909 4:46:40 server id # end_log_pos # Start: binlog v 4, server v #.##.## created 010909 4:46:40 at startup ROLLBACK/*!*/; +#010909 4:46:40 server id # end_log_pos # Binlog checkpoint master-bin.000001 +# at # # at # use `new_test1`/*!*/; #010909 4:46:40 server id # end_log_pos # Query thread_id=# exec_time=# error_code=0 @@ -228,6 +230,8 @@ DELIMITER /*!*/; # at # #010909 4:46:40 server id # end_log_pos # Start: binlog v 4, server v #.##.## created 010909 4:46:40 at startup ROLLBACK/*!*/; +#010909 4:46:40 server id # end_log_pos # Binlog checkpoint master-bin.000001 +# at # # at # use `new_test1`/*!*/; #010909 4:46:40 server id # end_log_pos # Query thread_id=# exec_time=# error_code=0 diff --git a/mysql-test/suite/binlog/r/binlog_server_id.result b/mysql-test/suite/binlog/r/binlog_server_id.result index f7d778a288b..991fd6e476b 100644 --- a/mysql-test/suite/binlog/r/binlog_server_id.result +++ b/mysql-test/suite/binlog/r/binlog_server_id.result @@ -7,6 +7,7 @@ select @@server_id; 1 show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Binlog_checkpoint 1 # master-bin.000001 master-bin.000001 # Query 1 # use `test`; DROP TABLE IF EXISTS `t1`,`t2`,`t3` /* generated by server */ master-bin.000001 # Query 1 # use `test`; create table t1 (a int) set global server_id=2; @@ -16,6 +17,7 @@ select @@server_id; 2 show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Binlog_checkpoint 1 # master-bin.000001 master-bin.000001 # Query 1 # use `test`; DROP TABLE IF EXISTS `t1`,`t2`,`t3` /* generated by server */ master-bin.000001 # Query 1 # use `test`; create table t1 (a int) master-bin.000001 # Query 2 # use `test`; create table t2 (b int) @@ -26,6 +28,7 @@ select @@server_id; 3 show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Binlog_checkpoint 1 # master-bin.000001 master-bin.000001 # Query 1 # use `test`; DROP TABLE IF EXISTS `t1`,`t2`,`t3` /* generated by server */ master-bin.000001 # Query 1 # use `test`; create table t1 (a int) master-bin.000001 # Query 2 # use `test`; create table t2 (b int) diff --git a/mysql-test/suite/binlog/r/binlog_stm_binlog.result b/mysql-test/suite/binlog/r/binlog_stm_binlog.result index 062f4f4e906..f9d9fa1d18d 100644 --- a/mysql-test/suite/binlog/r/binlog_stm_binlog.result +++ b/mysql-test/suite/binlog/r/binlog_stm_binlog.result @@ -521,6 +521,7 @@ BINLOG ' SHOW BINLOG EVENTS; Log_name Pos Event_type Server_id End_log_pos Info # # Format_desc 1 # Server ver: #, Binlog ver: # +# # Binlog_checkpoint 1 # master-bin.000001 # # Query 1 # use `test`; CREATE TABLE t1 (a INT PRIMARY KEY) # # Query 1 # BEGIN # # Query 1 # use `test`; INSERT INTO t1 VALUES (1) diff --git a/mysql-test/suite/binlog/r/binlog_stm_blackhole.result b/mysql-test/suite/binlog/r/binlog_stm_blackhole.result index e76f6b494f9..2b5bd76a338 100644 --- a/mysql-test/suite/binlog/r/binlog_stm_blackhole.result +++ b/mysql-test/suite/binlog/r/binlog_stm_blackhole.result @@ -175,6 +175,7 @@ set insert_id= 5; insert into t1 values (55), (NULL); show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Binlog_checkpoint 1 # master-bin.000001 master-bin.000001 # Query 1 # use `test`; create table t1 (a int auto_increment, primary key (a)) engine=blackhole master-bin.000001 # Query 1 # BEGIN master-bin.000001 # Intvar 1 # INSERT_ID=1 diff --git a/mysql-test/suite/binlog/r/binlog_xa_recover.result b/mysql-test/suite/binlog/r/binlog_xa_recover.result new file mode 100644 index 00000000000..41df149a928 --- /dev/null +++ b/mysql-test/suite/binlog/r/binlog_xa_recover.result @@ -0,0 +1,175 @@ +SET GLOBAL max_binlog_size= 4096; +CREATE TABLE t1 (a INT PRIMARY KEY, b MEDIUMTEXT) ENGINE=Innodb; +CREATE TABLE t2 (a INT PRIMARY KEY, b MEDIUMTEXT) ENGINE=Myisam; +SET @@global.debug_dbug='+d,skip_commit_ordered'; +INSERT INTO t1 VALUES (0, REPEAT("x", 4100)); +SET DEBUG_SYNC= "ha_commit_trans_after_log_and_order SIGNAL con1_ready WAIT_FOR _ever"; +INSERT INTO t1 VALUES (1, REPEAT("x", 4100)); +SET DEBUG_SYNC= "now WAIT_FOR con1_ready"; +INSERT INTO t2 VALUES (1, "force binlog rotation"); +SET DEBUG_SYNC= "ha_commit_trans_after_log_and_order SIGNAL con2_ready WAIT_FOR _ever"; +INSERT INTO t1 VALUES (2, NULL); +SET DEBUG_SYNC= "now WAIT_FOR con2_ready"; +SET DEBUG_SYNC= "ha_commit_trans_after_log_and_order SIGNAL con3_ready WAIT_FOR _ever"; +INSERT INTO t1 VALUES (3, REPEAT("x", 4100)); +SET DEBUG_SYNC= "now WAIT_FOR con3_ready"; +INSERT INTO t2 VALUES (2, "force binlog rotation"); +FLUSH TABLES t2; +show binary logs; +Log_name File_size +master-bin.000001 # +master-bin.000002 # +master-bin.000003 # +master-bin.000004 # +show binlog events in 'master-bin.000001' from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +master-bin.000001 # Binlog_checkpoint # # master-bin.000001 +master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT PRIMARY KEY, b MEDIUMTEXT) ENGINE=Innodb +master-bin.000001 # Query # # use `test`; CREATE TABLE t2 (a INT PRIMARY KEY, b MEDIUMTEXT) ENGINE=Myisam +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Rotate # # master-bin.000002;pos= +show binlog events in 'master-bin.000002' from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000002 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +master-bin.000002 # Binlog_checkpoint # # master-bin.000002 +master-bin.000002 # Query # # BEGIN +master-bin.000002 # Table_map # # table_id: # (test.t1) +master-bin.000002 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000002 # Xid # # COMMIT /* XID */ +master-bin.000002 # Query # # BEGIN +master-bin.000002 # Table_map # # table_id: # (test.t2) +master-bin.000002 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000002 # Query # # COMMIT +master-bin.000002 # Rotate # # master-bin.000003;pos= +show binlog events in 'master-bin.000003' from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000003 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +master-bin.000003 # Binlog_checkpoint # # master-bin.000002 +master-bin.000003 # Query # # BEGIN +master-bin.000003 # Table_map # # table_id: # (test.t1) +master-bin.000003 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000003 # Xid # # COMMIT /* XID */ +master-bin.000003 # Query # # BEGIN +master-bin.000003 # Table_map # # table_id: # (test.t1) +master-bin.000003 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000003 # Xid # # COMMIT /* XID */ +master-bin.000003 # Query # # BEGIN +master-bin.000003 # Table_map # # table_id: # (test.t2) +master-bin.000003 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000003 # Query # # COMMIT +master-bin.000003 # Rotate # # master-bin.00000;pos= +show binlog events in 'master-bin.00000' from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.00000 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +master-bin.00000 # Binlog_checkpoint # # master-bin.000002 +master-bin.00000 # Query # # use `test`; FLUSH TABLES t2 +We should see only one entry here, a=0: +SELECT a FROM t1 ORDER BY a; +a +0 +PURGE BINARY LOGS TO "master-bin.000004"; +show binary logs; +Log_name File_size +master-bin.000002 # +master-bin.000003 # +master-bin.000004 # +SET SESSION debug_dbug="+d,crash_commit_after_log"; +INSERT INTO t1 VALUES (4, NULL); +Got one of the listed errors +SELECT a FROM t1 ORDER BY a; +a +0 +1 +2 +3 +4 +*** Test that RESET MASTER waits for pending XIDs to be unlogged. +SET @old_max_binlog_size= @@global.max_binlog_size; +SET GLOBAL max_binlog_size= 4096; +SET DEBUG_SYNC= "ha_commit_trans_after_log_and_order SIGNAL con10_ready WAIT_FOR con10_go"; +INSERT INTO t1 VALUES (10, NULL); +SET DEBUG_SYNC= "now WAIT_FOR con10_ready"; +INSERT INTO t2 VALUES (10, REPEAT("x", 4100)); +INSERT INTO t2 VALUES (11, REPEAT("x", 4100)); +show binary logs; +Log_name File_size +master-bin.000002 # +master-bin.000003 # +master-bin.000004 # +master-bin.000005 # +master-bin.000006 # +master-bin.000007 # +SET DEBUG_SYNC= "execute_command_after_close_tables SIGNAL reset_master_done"; +RESET MASTER; +This will timeout, as RESET MASTER is blocked +SET DEBUG_SYNC= "now WAIT_FOR reset_master_done TIMEOUT 1"; +Warnings: +Warning 1639 debug sync point wait timed out +SET DEBUG_SYNC= "now SIGNAL con10_go"; +show binary logs; +Log_name File_size +master-bin.000001 # +*** Test that binlog N is active, and last pending trx in (N-1) is +unlogged while there is still a pending trx in (N-2). +SET DEBUG_SYNC= "ha_commit_trans_after_log_and_order SIGNAL con10_ready WAIT_FOR con10_continue"; +INSERT INTO t1 VALUES (20, REPEAT("x", 4100)); +SET DEBUG_SYNC= "now WAIT_FOR con10_ready"; +INSERT INTO t2 VALUES (3, "force binlog rotation"); +SET DEBUG_SYNC= "ha_commit_trans_after_log_and_order SIGNAL con11_ready WAIT_FOR con11_continue"; +INSERT INTO t1 VALUES (21, REPEAT("x", 4100)); +SET DEBUG_SYNC= "now WAIT_FOR con11_ready"; +INSERT INTO t2 VALUES (4, "force binlog rotation"); +show binary logs; +Log_name File_size +master-bin.000001 # +master-bin.000002 # +master-bin.000003 # +show binlog events in 'master-bin.000001' from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +master-bin.000001 # Binlog_checkpoint # # master-bin.000001 +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Rotate # # master-bin.000002;pos= +show binlog events in 'master-bin.000002' from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000002 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +master-bin.000002 # Binlog_checkpoint # # master-bin.000001 +master-bin.000002 # Query # # BEGIN +master-bin.000002 # Table_map # # table_id: # (test.t1) +master-bin.000002 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000002 # Xid # # COMMIT /* XID */ +master-bin.000002 # Query # # BEGIN +master-bin.000002 # Table_map # # table_id: # (test.t2) +master-bin.000002 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000002 # Query # # COMMIT +master-bin.000002 # Rotate # # master-bin.000003;pos= +show binlog events in 'master-bin.000003' from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000003 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +master-bin.000003 # Binlog_checkpoint # # master-bin.000001 +SET DEBUG_SYNC= "now SIGNAL con11_continue"; +con10 is still pending, no new binlog checkpoint should have been logged. +show binlog events in 'master-bin.000003' from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000003 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +master-bin.000003 # Binlog_checkpoint # # master-bin.000001 +SET DEBUG_SYNC= "now SIGNAL con10_continue"; +No XIDs are pending, a new binlog checkpoint should have been logged. +show binlog events in 'master-bin.000003' from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000003 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +master-bin.000003 # Binlog_checkpoint # # master-bin.000001 +master-bin.000003 # Binlog_checkpoint # # master-bin.000003 +DROP TABLE t1, t2; +SET GLOBAL max_binlog_size= @old_max_binlog_size; diff --git a/mysql-test/suite/binlog/t/binlog_killed.test b/mysql-test/suite/binlog/t/binlog_killed.test index 9b6420df4b4..ff558ee2948 100644 --- a/mysql-test/suite/binlog/t/binlog_killed.test +++ b/mysql-test/suite/binlog/t/binlog_killed.test @@ -59,8 +59,8 @@ reap; let $rows= `select count(*) from t2 /* must be 2 or 0 */`; let $MYSQLD_DATADIR= `select @@datadir`; ---let $binlog_killed_pos=query_get_value(SHOW BINLOG EVENTS, Pos, 4) ---let $binlog_killed_end_log_pos=query_get_value(SHOW BINLOG EVENTS, End_log_pos, 4) +--let $binlog_killed_pos=query_get_value(SHOW BINLOG EVENTS, Pos, 5) +--let $binlog_killed_end_log_pos=query_get_value(SHOW BINLOG EVENTS, End_log_pos, 5) --exec $MYSQL_BINLOG --force-if-open --start-position=$binlog_killed_pos --stop-position=$binlog_killed_end_log_pos $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/kill_query_calling_sp.binlog --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR --disable_result_log @@ -270,8 +270,8 @@ 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 on the 4th line source include/show_binlog_events.inc; ---let $binlog_killed_pos= query_get_value(SHOW BINLOG EVENTS, Pos, 4) ---let $binlog_killed_end_log_pos= query_get_value(SHOW BINLOG EVENTS, End_log_pos, 4) +--let $binlog_killed_pos= query_get_value(SHOW BINLOG EVENTS, Pos, 5) +--let $binlog_killed_end_log_pos= query_get_value(SHOW BINLOG EVENTS, End_log_pos, 5) --echo *** a proof the query is binlogged with an error *** @@ -318,8 +318,8 @@ 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 on the 4th line source include/show_binlog_events.inc; ---let $binlog_killed_pos= query_get_value(SHOW BINLOG EVENTS, Pos, 4) ---let $binlog_killed_end_log_pos= query_get_value(SHOW BINLOG EVENTS, End_log_pos, 4) +--let $binlog_killed_pos= query_get_value(SHOW BINLOG EVENTS, Pos, 5) +--let $binlog_killed_end_log_pos= query_get_value(SHOW BINLOG EVENTS, End_log_pos, 5) # a proof the query is binlogged with an error diff --git a/mysql-test/suite/binlog/t/binlog_killed_simulate.test b/mysql-test/suite/binlog/t/binlog_killed_simulate.test index ba111fd0145..33037710379 100644 --- a/mysql-test/suite/binlog/t/binlog_killed_simulate.test +++ b/mysql-test/suite/binlog/t/binlog_killed_simulate.test @@ -50,8 +50,8 @@ load data infile '../../std_data/rpl_loaddata.dat' into table t2 /* will be "kil # a proof the query is binlogged with an error ---let $binlog_load_data= query_get_value(SHOW BINLOG EVENTS, Pos, 3) ---let $binlog_end= query_get_value(SHOW BINLOG EVENTS, Pos, 4) +--let $binlog_load_data= query_get_value(SHOW BINLOG EVENTS, Pos, 4) +--let $binlog_end= query_get_value(SHOW BINLOG EVENTS, Pos, 5) source include/show_binlog_events.inc; --exec $MYSQL_BINLOG --force-if-open --start-position=$binlog_load_data --stop-position=$binlog_end $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog diff --git a/mysql-test/suite/binlog/t/binlog_xa_recover-master.opt b/mysql-test/suite/binlog/t/binlog_xa_recover-master.opt new file mode 100644 index 00000000000..425fda95086 --- /dev/null +++ b/mysql-test/suite/binlog/t/binlog_xa_recover-master.opt @@ -0,0 +1 @@ +--skip-stack-trace --skip-core-file diff --git a/mysql-test/suite/binlog/t/binlog_xa_recover.test b/mysql-test/suite/binlog/t/binlog_xa_recover.test new file mode 100644 index 00000000000..7a4cc17112e --- /dev/null +++ b/mysql-test/suite/binlog/t/binlog_xa_recover.test @@ -0,0 +1,174 @@ +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc +--source include/have_binlog_format_row.inc +# Valgrind does not work well with test that crashes the server +--source include/not_valgrind.inc + +SET GLOBAL max_binlog_size= 4096; + +CREATE TABLE t1 (a INT PRIMARY KEY, b MEDIUMTEXT) ENGINE=Innodb; +CREATE TABLE t2 (a INT PRIMARY KEY, b MEDIUMTEXT) ENGINE=Myisam; + +# Transactions are not guaranteed stored durably on disk in the engine until +# they are fsync()ed, which normally happens during commit(). But there is no +# guarantee that they will _not_ be durable, in particular loosing results +# of a write(2) system call normally requires a kernel crash (as opposed to +# just mysqld crash), which is inconvenient to do in a test suite. +# So instead we do an error insert to prevent commit_ordered() from being +# called in the engine - so nothing will be written to disk at all, and crash +# recovery is sure to be needed. +SET @@global.debug_dbug='+d,skip_commit_ordered'; + +INSERT INTO t1 VALUES (0, REPEAT("x", 4100)); + +# Now start a bunch of transactions that span multiple binlog +# files. Leave then in the state prepared-but-not-committed in the engine +# and crash the server. Check that crash recovery is able to recover all +# of them. + +connect(con1,localhost,root,,); +SET DEBUG_SYNC= "ha_commit_trans_after_log_and_order SIGNAL con1_ready WAIT_FOR _ever"; +send INSERT INTO t1 VALUES (1, REPEAT("x", 4100)); + +connection default; +SET DEBUG_SYNC= "now WAIT_FOR con1_ready"; +INSERT INTO t2 VALUES (1, "force binlog rotation"); + +connect(con2,localhost,root,,); +SET DEBUG_SYNC= "ha_commit_trans_after_log_and_order SIGNAL con2_ready WAIT_FOR _ever"; +send INSERT INTO t1 VALUES (2, NULL); + +connection default; +SET DEBUG_SYNC= "now WAIT_FOR con2_ready"; + +connect(con3,localhost,root,,); +SET DEBUG_SYNC= "ha_commit_trans_after_log_and_order SIGNAL con3_ready WAIT_FOR _ever"; +send INSERT INTO t1 VALUES (3, REPEAT("x", 4100)); +connection default; +SET DEBUG_SYNC= "now WAIT_FOR con3_ready"; +INSERT INTO t2 VALUES (2, "force binlog rotation"); +# So we won't get warnings about t2 being crashed. +FLUSH TABLES t2; + +# Check that everything is committed in binary log. +--source include/show_binary_logs.inc +--let $binlog_file= master-bin.000001 +--let $binlog_start= 4 +--source include/show_binlog_events.inc +--let $binlog_file= master-bin.000002 +--source include/show_binlog_events.inc +--let $binlog_file= master-bin.000003 +--source include/show_binlog_events.inc +--let $binlog_file= master-bin.000004 +--source include/show_binlog_events.inc + +# Check that transactions really are not yet committed in engine. +# (This works because of debug_dbug='+d,skip_commit_ordered'). +--echo We should see only one entry here, a=0: +SELECT a FROM t1 ORDER BY a; + + +# Check that server will not purge too much. +PURGE BINARY LOGS TO "master-bin.000004"; +--source include/show_binary_logs.inc + +# Now crash the server with one more transaction in prepared state. +system echo wait-binlog_xa_recover.test >> $MYSQLTEST_VARDIR/tmp/mysqld.1.expect; +SET SESSION debug_dbug="+d,crash_commit_after_log"; +--error 2006,2013 +INSERT INTO t1 VALUES (4, NULL); + +system echo restart-group_commit_binlog_pos.test >> $MYSQLTEST_VARDIR/tmp/mysqld.1.expect; + +connection default; +--enable_reconnect +--source include/wait_until_connected_again.inc + +# Check that all transactions are recovered. +SELECT a FROM t1 ORDER BY a; + + +--echo *** Test that RESET MASTER waits for pending XIDs to be unlogged. + +SET @old_max_binlog_size= @@global.max_binlog_size; +SET GLOBAL max_binlog_size= 4096; +# con10 will hang with a pending XID, blocking RESET MASTER. +connect(con10,localhost,root,,); +SET DEBUG_SYNC= "ha_commit_trans_after_log_and_order SIGNAL con10_ready WAIT_FOR con10_go"; +send INSERT INTO t1 VALUES (10, NULL); + +connection default; +SET DEBUG_SYNC= "now WAIT_FOR con10_ready"; +# Let's add a few binlog rotations just for good measure. +INSERT INTO t2 VALUES (10, REPEAT("x", 4100)); +INSERT INTO t2 VALUES (11, REPEAT("x", 4100)); +--source include/show_binary_logs.inc +SET DEBUG_SYNC= "execute_command_after_close_tables SIGNAL reset_master_done"; +send RESET MASTER; + +connect(con11,localhost,root,,); +--echo This will timeout, as RESET MASTER is blocked +SET DEBUG_SYNC= "now WAIT_FOR reset_master_done TIMEOUT 1"; +# Wake up transaction to allow RESET MASTER to complete. +SET DEBUG_SYNC= "now SIGNAL con10_go"; + +connection con10; +reap; + +connection default; +reap; +--source include/show_binary_logs.inc + + +--echo *** Test that binlog N is active, and last pending trx in (N-1) is +--echo unlogged while there is still a pending trx in (N-2). + +connection con10; +SET DEBUG_SYNC= "ha_commit_trans_after_log_and_order SIGNAL con10_ready WAIT_FOR con10_continue"; +send INSERT INTO t1 VALUES (20, REPEAT("x", 4100)); + +connection default; +SET DEBUG_SYNC= "now WAIT_FOR con10_ready"; +INSERT INTO t2 VALUES (3, "force binlog rotation"); + +connection con11; +SET DEBUG_SYNC= "ha_commit_trans_after_log_and_order SIGNAL con11_ready WAIT_FOR con11_continue"; +send INSERT INTO t1 VALUES (21, REPEAT("x", 4100)); + +connection default; +SET DEBUG_SYNC= "now WAIT_FOR con11_ready"; +INSERT INTO t2 VALUES (4, "force binlog rotation"); +--source include/show_binary_logs.inc +--let $binlog_file= master-bin.000001 +--source include/show_binlog_events.inc +--let $binlog_file= master-bin.000002 +--source include/show_binlog_events.inc +--let $binlog_file= master-bin.000003 +--source include/show_binlog_events.inc + +SET DEBUG_SYNC= "now SIGNAL con11_continue"; + +connection con11; +reap; + +connection default; +--echo con10 is still pending, no new binlog checkpoint should have been logged. +--let $binlog_file= master-bin.000003 +--source include/show_binlog_events.inc + +SET DEBUG_SYNC= "now SIGNAL con10_continue"; + +connection con10; +reap; + +connection default; +--echo No XIDs are pending, a new binlog checkpoint should have been logged. +--let $binlog_file= master-bin.000003 +--source include/show_binlog_events.inc + + +# Cleanup +connection default; +DROP TABLE t1, t2; +SET GLOBAL max_binlog_size= @old_max_binlog_size; diff --git a/mysql-test/suite/innodb/r/binlog_consistent.result b/mysql-test/suite/innodb/r/binlog_consistent.result index 2e523c40a5b..68838e8d52b 100644 --- a/mysql-test/suite/innodb/r/binlog_consistent.result +++ b/mysql-test/suite/innodb/r/binlog_consistent.result @@ -3,11 +3,11 @@ RESET MASTER; CREATE TABLE t1 (a INT, b VARCHAR(100), PRIMARY KEY (a,b)) ENGINE=innodb; SHOW MASTER STATUS; File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 380 +master-bin.000001 421 SHOW STATUS LIKE 'binlog_snapshot_%'; Variable_name Value binlog_snapshot_file master-bin.000001 -binlog_snapshot_position 380 +binlog_snapshot_position 421 BEGIN; INSERT INTO t1 VALUES (0, ""); # Connection con1 @@ -38,10 +38,10 @@ a b SHOW STATUS LIKE 'binlog_snapshot_%'; Variable_name Value binlog_snapshot_file master-bin.000001 -binlog_snapshot_position 904 +binlog_snapshot_position 945 SHOW MASTER STATUS; File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 1316 +master-bin.000001 1357 SELECT * FROM t2 ORDER BY a; a 2 @@ -60,44 +60,45 @@ a b SHOW STATUS LIKE 'binlog_snapshot_%'; Variable_name Value binlog_snapshot_file master-bin.000001 -binlog_snapshot_position 904 +binlog_snapshot_position 945 SHOW MASTER STATUS; File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000002 245 +master-bin.000002 286 COMMIT; SHOW STATUS LIKE 'binlog_snapshot_%'; Variable_name Value binlog_snapshot_file master-bin.000002 -binlog_snapshot_position 245 +binlog_snapshot_position 286 SHOW MASTER STATUS; File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000002 245 +master-bin.000002 286 SHOW BINLOG EVENTS; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 4 Format_desc 1 245 Server ver: #, Binlog ver: # -master-bin.000001 245 Query 1 380 use `test`; CREATE TABLE t1 (a INT, b VARCHAR(100), PRIMARY KEY (a,b)) ENGINE=innodb -master-bin.000001 380 Query 1 492 use `test`; CREATE TABLE t2 (a INT PRIMARY KEY) ENGINE=myisam -master-bin.000001 492 Query 1 560 BEGIN -master-bin.000001 560 Query 1 648 use `test`; INSERT INTO t2 VALUES (2) -master-bin.000001 648 Query 1 717 COMMIT -master-bin.000001 717 Query 1 785 BEGIN -master-bin.000001 785 Query 1 877 use `test`; INSERT INTO t1 VALUES (0, "") -master-bin.000001 877 Xid 1 904 COMMIT /* XID */ -master-bin.000001 904 Query 1 972 BEGIN -master-bin.000001 972 Query 1 1060 use `test`; INSERT INTO t2 VALUES (3) -master-bin.000001 1060 Query 1 1129 COMMIT -master-bin.000001 1129 Query 1 1197 BEGIN -master-bin.000001 1197 Query 1 1289 use `test`; INSERT INTO t1 VALUES (4, "") -master-bin.000001 1289 Xid 1 1316 COMMIT /* XID */ -master-bin.000001 1316 Query 1 1384 BEGIN -master-bin.000001 1384 Query 1 1476 use `test`; INSERT INTO t1 VALUES (1, "") -master-bin.000001 1476 Xid 1 1503 COMMIT /* XID */ -master-bin.000001 1503 Query 1 1571 BEGIN -master-bin.000001 1571 Query 1 1668 use `test`; INSERT INTO t1 VALUES (2, "first") -master-bin.000001 1668 Query 1 1766 use `test`; INSERT INTO t1 VALUES (2, "second") -master-bin.000001 1766 Xid 1 1793 COMMIT /* XID */ -master-bin.000001 1793 Query 1 1861 BEGIN -master-bin.000001 1861 Query 1 1953 use `test`; INSERT INTO t1 VALUES (3, "") -master-bin.000001 1953 Xid 1 1980 COMMIT /* XID */ -master-bin.000001 1980 Rotate 1 2024 master-bin.000002;pos=4 +master-bin.000001 4 Format_desc 1 246 Server ver: #, Binlog ver: # +master-bin.000001 246 Binlog_checkpoint 1 286 master-bin.000001 +master-bin.000001 286 Query 1 421 use `test`; CREATE TABLE t1 (a INT, b VARCHAR(100), PRIMARY KEY (a,b)) ENGINE=innodb +master-bin.000001 421 Query 1 533 use `test`; CREATE TABLE t2 (a INT PRIMARY KEY) ENGINE=myisam +master-bin.000001 533 Query 1 601 BEGIN +master-bin.000001 601 Query 1 689 use `test`; INSERT INTO t2 VALUES (2) +master-bin.000001 689 Query 1 758 COMMIT +master-bin.000001 758 Query 1 826 BEGIN +master-bin.000001 826 Query 1 918 use `test`; INSERT INTO t1 VALUES (0, "") +master-bin.000001 918 Xid 1 945 COMMIT /* XID */ +master-bin.000001 945 Query 1 1013 BEGIN +master-bin.000001 1013 Query 1 1101 use `test`; INSERT INTO t2 VALUES (3) +master-bin.000001 1101 Query 1 1170 COMMIT +master-bin.000001 1170 Query 1 1238 BEGIN +master-bin.000001 1238 Query 1 1330 use `test`; INSERT INTO t1 VALUES (4, "") +master-bin.000001 1330 Xid 1 1357 COMMIT /* XID */ +master-bin.000001 1357 Query 1 1425 BEGIN +master-bin.000001 1425 Query 1 1517 use `test`; INSERT INTO t1 VALUES (1, "") +master-bin.000001 1517 Xid 1 1544 COMMIT /* XID */ +master-bin.000001 1544 Query 1 1612 BEGIN +master-bin.000001 1612 Query 1 1709 use `test`; INSERT INTO t1 VALUES (2, "first") +master-bin.000001 1709 Query 1 1807 use `test`; INSERT INTO t1 VALUES (2, "second") +master-bin.000001 1807 Xid 1 1834 COMMIT /* XID */ +master-bin.000001 1834 Query 1 1902 BEGIN +master-bin.000001 1902 Query 1 1994 use `test`; INSERT INTO t1 VALUES (3, "") +master-bin.000001 1994 Xid 1 2021 COMMIT /* XID */ +master-bin.000001 2021 Rotate 1 2065 master-bin.000002;pos=4 DROP TABLE t1,t2; diff --git a/mysql-test/suite/innodb/r/group_commit_binlog_pos.result b/mysql-test/suite/innodb/r/group_commit_binlog_pos.result index d28ad1fd70e..29aa765c1b4 100644 --- a/mysql-test/suite/innodb/r/group_commit_binlog_pos.result +++ b/mysql-test/suite/innodb/r/group_commit_binlog_pos.result @@ -30,6 +30,6 @@ a 1 2 3 -InnoDB: Last MySQL binlog file position 0 906, file name ./master-bin.000001 +InnoDB: Last MySQL binlog file position 0 947, file name ./master-bin.000001 SET DEBUG_SYNC= 'RESET'; DROP TABLE t1; diff --git a/mysql-test/suite/innodb/r/group_commit_binlog_pos_no_optimize_thread.result b/mysql-test/suite/innodb/r/group_commit_binlog_pos_no_optimize_thread.result index da8cff142b8..3c3b0709331 100644 --- a/mysql-test/suite/innodb/r/group_commit_binlog_pos_no_optimize_thread.result +++ b/mysql-test/suite/innodb/r/group_commit_binlog_pos_no_optimize_thread.result @@ -31,6 +31,6 @@ a 1 2 3 -InnoDB: Last MySQL binlog file position 0 906, file name ./master-bin.000001 +InnoDB: Last MySQL binlog file position 0 947, file name ./master-bin.000001 SET DEBUG_SYNC= 'RESET'; DROP TABLE t1; diff --git a/mysql-test/suite/innodb/r/group_commit_crash.result b/mysql-test/suite/innodb/r/group_commit_crash.result index cd47ba62ff2..c084f854e79 100644 --- a/mysql-test/suite/innodb/r/group_commit_crash.result +++ b/mysql-test/suite/innodb/r/group_commit_crash.result @@ -36,7 +36,7 @@ COMMIT; Got one of the listed errors SELECT * FROM t1 ORDER BY id; a b c d id -SHOW BINLOG EVENTS LIMIT 2,1; +SHOW BINLOG EVENTS LIMIT 3,1; Log_name Pos Event_type Server_id End_log_pos Info delete from t1; SET binlog_format= mixed; @@ -58,7 +58,7 @@ a b c d 7 a b c d 8 a b c d 9 a b c d 10 -SHOW BINLOG EVENTS LIMIT 2,1; +SHOW BINLOG EVENTS LIMIT 3,1; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query 1 # use `test`; insert into t1 select * from t2 delete from t1; @@ -81,7 +81,7 @@ a b c d 7 a b c d 8 a b c d 9 a b c d 10 -SHOW BINLOG EVENTS LIMIT 2,1; +SHOW BINLOG EVENTS LIMIT 3,1; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query 1 # use `test`; insert into t1 select * from t2 delete from t1; @@ -104,7 +104,7 @@ a b c d 7 a b c d 8 a b c d 9 a b c d 10 -SHOW BINLOG EVENTS LIMIT 2,1; +SHOW BINLOG EVENTS LIMIT 3,1; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query 1 # use `test`; insert into t1 select * from t2 delete from t1; @@ -117,7 +117,7 @@ COMMIT; Got one of the listed errors SELECT * FROM t1 ORDER BY id; a b c d id -SHOW BINLOG EVENTS LIMIT 2,1; +SHOW BINLOG EVENTS LIMIT 3,1; Log_name Pos Event_type Server_id End_log_pos Info delete from t1; DROP TABLE t1; diff --git a/mysql-test/suite/innodb/r/group_commit_crash_no_optimize_thread.result b/mysql-test/suite/innodb/r/group_commit_crash_no_optimize_thread.result index c1ae510d45b..40c270a76d3 100644 --- a/mysql-test/suite/innodb/r/group_commit_crash_no_optimize_thread.result +++ b/mysql-test/suite/innodb/r/group_commit_crash_no_optimize_thread.result @@ -36,7 +36,7 @@ COMMIT; Got one of the listed errors SELECT * FROM t1 ORDER BY id; a b c d id -SHOW BINLOG EVENTS LIMIT 2,1; +SHOW BINLOG EVENTS LIMIT 3,1; Log_name Pos Event_type Server_id End_log_pos Info delete from t1; SET binlog_format= mixed; @@ -58,7 +58,7 @@ a b c d 7 a b c d 8 a b c d 9 a b c d 10 -SHOW BINLOG EVENTS LIMIT 2,1; +SHOW BINLOG EVENTS LIMIT 3,1; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query 1 # use `test`; insert into t1 select * from t2 delete from t1; @@ -81,7 +81,7 @@ a b c d 7 a b c d 8 a b c d 9 a b c d 10 -SHOW BINLOG EVENTS LIMIT 2,1; +SHOW BINLOG EVENTS LIMIT 3,1; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query 1 # use `test`; insert into t1 select * from t2 delete from t1; @@ -104,7 +104,7 @@ a b c d 7 a b c d 8 a b c d 9 a b c d 10 -SHOW BINLOG EVENTS LIMIT 2,1; +SHOW BINLOG EVENTS LIMIT 3,1; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query 1 # use `test`; insert into t1 select * from t2 delete from t1; @@ -117,7 +117,7 @@ COMMIT; Got one of the listed errors SELECT * FROM t1 ORDER BY id; a b c d id -SHOW BINLOG EVENTS LIMIT 2,1; +SHOW BINLOG EVENTS LIMIT 3,1; Log_name Pos Event_type Server_id End_log_pos Info delete from t1; DROP TABLE t1; diff --git a/mysql-test/suite/innodb/t/group_commit_crash.test b/mysql-test/suite/innodb/t/group_commit_crash.test index 12c92d19244..0a297e3c570 100644 --- a/mysql-test/suite/innodb/t/group_commit_crash.test +++ b/mysql-test/suite/innodb/t/group_commit_crash.test @@ -66,7 +66,7 @@ while ($numtests) # table and binlog should be in sync. SELECT * FROM t1 ORDER BY id; --replace_column 2 # 5 # - SHOW BINLOG EVENTS LIMIT 2,1; + SHOW BINLOG EVENTS LIMIT 3,1; delete from t1; diff --git a/mysql-test/suite/innodb/t/group_commit_crash_no_optimize_thread.test b/mysql-test/suite/innodb/t/group_commit_crash_no_optimize_thread.test index 2de09d6b0b6..4214c2a6b03 100644 --- a/mysql-test/suite/innodb/t/group_commit_crash_no_optimize_thread.test +++ b/mysql-test/suite/innodb/t/group_commit_crash_no_optimize_thread.test @@ -66,7 +66,7 @@ while ($numtests) # table and binlog should be in sync. SELECT * FROM t1 ORDER BY id; --replace_column 2 # 5 # - SHOW BINLOG EVENTS LIMIT 2,1; + SHOW BINLOG EVENTS LIMIT 3,1; delete from t1; diff --git a/mysql-test/suite/maria/maria-connect.result b/mysql-test/suite/maria/maria-connect.result index ed626a003f5..d79ebbdb86c 100644 --- a/mysql-test/suite/maria/maria-connect.result +++ b/mysql-test/suite/maria/maria-connect.result @@ -16,6 +16,7 @@ a 4 SHOW BINLOG EVENTS FROM ; Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Binlog_checkpoint 1 # master-bin.000001 master-bin.000001 # Query 1 # use `test`; CREATE TABLE t1 (a int primary key) master-bin.000001 # Query 1 # BEGIN master-bin.000001 # Query 1 # use `test`; insert t1 values (1),(2),(3) diff --git a/mysql-test/suite/perfschema/r/all_instances.result b/mysql-test/suite/perfschema/r/all_instances.result index caf4f49034f..7d3484fc887 100644 --- a/mysql-test/suite/perfschema/r/all_instances.result +++ b/mysql-test/suite/perfschema/r/all_instances.result @@ -77,6 +77,7 @@ wait/synch/mutex/sql/Master_info::sleep_lock wait/synch/mutex/sql/MDL_map::mutex wait/synch/mutex/sql/MDL_wait::LOCK_wait_status wait/synch/mutex/sql/MYSQL_BIN_LOG::LOCK_index +wait/synch/mutex/sql/MYSQL_BIN_LOG::LOCK_xid_list wait/synch/mutex/sql/MYSQL_RELAY_LOG::LOCK_index wait/synch/mutex/sql/Query_cache::structure_guard_mutex wait/synch/mutex/sql/Relay_log_info::data_lock @@ -129,6 +130,7 @@ wait/synch/cond/sql/Master_info::start_cond wait/synch/cond/sql/Master_info::stop_cond wait/synch/cond/sql/MDL_context::COND_wait_status wait/synch/cond/sql/MYSQL_BIN_LOG::COND_queue_busy +wait/synch/cond/sql/MYSQL_BIN_LOG::COND_xid_list wait/synch/cond/sql/MYSQL_BIN_LOG::update_cond wait/synch/cond/sql/MYSQL_RELAY_LOG::COND_queue_busy wait/synch/cond/sql/MYSQL_RELAY_LOG::update_cond diff --git a/mysql-test/suite/perfschema/r/relaylog.result b/mysql-test/suite/perfschema/r/relaylog.result index a1d10265f4d..f8ff902245c 100644 --- a/mysql-test/suite/perfschema/r/relaylog.result +++ b/mysql-test/suite/perfschema/r/relaylog.result @@ -56,10 +56,10 @@ where event_name like "%MYSQL_BIN_LOG%" and event_name not like "%MYSQL_BIN_LOG::update_cond" order by event_name; EVENT_NAME COUNT_STAR -wait/synch/cond/sql/MYSQL_BIN_LOG::COND_prep_xids NONE wait/synch/cond/sql/MYSQL_BIN_LOG::COND_queue_busy NONE +wait/synch/cond/sql/MYSQL_BIN_LOG::COND_xid_list NONE wait/synch/mutex/sql/MYSQL_BIN_LOG::LOCK_index MANY -wait/synch/mutex/sql/MYSQL_BIN_LOG::LOCK_prep_xids NONE +wait/synch/mutex/sql/MYSQL_BIN_LOG::LOCK_xid_list MANY "Expect no slave relay log" select * from performance_schema.file_summary_by_instance where event_name like "%relaylog%" order by file_name; @@ -131,10 +131,10 @@ where event_name like "%MYSQL_BIN_LOG%" and event_name not like "%MYSQL_BIN_LOG::update_cond" order by event_name; EVENT_NAME COUNT_STAR -wait/synch/cond/sql/MYSQL_BIN_LOG::COND_prep_xids NONE wait/synch/cond/sql/MYSQL_BIN_LOG::COND_queue_busy NONE +wait/synch/cond/sql/MYSQL_BIN_LOG::COND_xid_list NONE wait/synch/mutex/sql/MYSQL_BIN_LOG::LOCK_index MANY -wait/synch/mutex/sql/MYSQL_BIN_LOG::LOCK_prep_xids NONE +wait/synch/mutex/sql/MYSQL_BIN_LOG::LOCK_xid_list MANY "Expect a slave relay log" select substring(file_name, locate("slave-", file_name)) as FILE_NAME, diff --git a/mysql-test/suite/rpl/r/rpl_checksum.result b/mysql-test/suite/rpl/r/rpl_checksum.result index ba5cb1b1b2b..9e561908a7b 100644 --- a/mysql-test/suite/rpl/r/rpl_checksum.result +++ b/mysql-test/suite/rpl/r/rpl_checksum.result @@ -71,7 +71,7 @@ insert into t1 values (1) /* will not be applied on slave due to simulation */; set @@global.debug_dbug='d,simulate_slave_unaware_checksum'; start slave; include/wait_for_slave_io_error.inc [errno=1236] -Last_IO_Error = 'Got fatal error 1236 from master when reading data from binary log: 'Slave can not handle replication events with the checksum that master is configured to log; the first event 'master-bin.000009' at 245, the last event read from 'master-bin.000010' at 245, the last byte read from 'master-bin.000010' at 245.'' +Last_IO_Error = 'Got fatal error 1236 from master when reading data from binary log: 'Slave can not handle replication events with the checksum that master is configured to log; the first event 'master-bin.000009' at 286, the last event read from 'master-bin.000010' at 246, the last byte read from 'master-bin.000010' at 246.'' select count(*) as zero from t1; zero 0 diff --git a/mysql-test/suite/rpl/r/rpl_mariadb_slave_capability.result b/mysql-test/suite/rpl/r/rpl_mariadb_slave_capability.result index 5eae28441c2..9af3d4bbfd2 100644 --- a/mysql-test/suite/rpl/r/rpl_mariadb_slave_capability.result +++ b/mysql-test/suite/rpl/r/rpl_mariadb_slave_capability.result @@ -54,7 +54,7 @@ master-bin.000002 # Query # # COMMIT SELECT * FROM t1; a 2 -show relaylog events in 'slave-relay-bin.000005' from limit 3,5; +show relaylog events in 'slave-relay-bin.000005' from limit 4,5; Log_name Pos Event_type Server_id End_log_pos Info slave-relay-bin.000005 # Query # # BEGIN slave-relay-bin.000005 # Query # # # Dummy ev diff --git a/mysql-test/suite/rpl/r/rpl_row_annotate_do.result b/mysql-test/suite/rpl/r/rpl_row_annotate_do.result index a7dc2a569a1..cb1aab28603 100644 --- a/mysql-test/suite/rpl/r/rpl_row_annotate_do.result +++ b/mysql-test/suite/rpl/r/rpl_row_annotate_do.result @@ -55,6 +55,7 @@ a b FLUSH LOGS; show binlog events in 'slave-bin.000001' from ; Log_name Pos Event_type Server_id End_log_pos Info +slave-bin.000001 # Binlog_checkpoint 2 # slave-bin.000001 slave-bin.000001 # Query 1 # DROP DATABASE IF EXISTS test1 slave-bin.000001 # Query 1 # CREATE DATABASE test1 slave-bin.000001 # Query 1 # use `test1`; CREATE TABLE t1(a int primary key, b int) diff --git a/mysql-test/suite/rpl/r/rpl_row_annotate_dont.result b/mysql-test/suite/rpl/r/rpl_row_annotate_dont.result index 2a3b5b1870e..b7648fd8592 100644 --- a/mysql-test/suite/rpl/r/rpl_row_annotate_dont.result +++ b/mysql-test/suite/rpl/r/rpl_row_annotate_dont.result @@ -47,6 +47,7 @@ a b FLUSH LOGS; show binlog events in 'slave-bin.000001' from ; Log_name Pos Event_type Server_id End_log_pos Info +slave-bin.000001 # Binlog_checkpoint 2 # slave-bin.000001 slave-bin.000001 # Query 1 # DROP DATABASE IF EXISTS test1 slave-bin.000001 # Query 1 # CREATE DATABASE test1 slave-bin.000001 # Query 1 # use `test1`; CREATE TABLE t1(a int primary key, b int) diff --git a/mysql-test/suite/rpl/r/rpl_row_show_relaylog_events.result b/mysql-test/suite/rpl/r/rpl_row_show_relaylog_events.result index 7c55e44ed59..8534bf00711 100644 --- a/mysql-test/suite/rpl/r/rpl_row_show_relaylog_events.result +++ b/mysql-test/suite/rpl/r/rpl_row_show_relaylog_events.result @@ -94,6 +94,7 @@ show relaylog events in 'slave-relay-bin.000003' from ; Log_name Pos Event_type Server_id End_log_pos Info slave-relay-bin.000003 # Rotate # # master-bin.000001;pos=4 slave-relay-bin.000003 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +slave-relay-bin.000003 # Binlog_checkpoint # # master-bin.000001 slave-relay-bin.000003 # Query # # use `test`; CREATE TABLE t1 (a INT) slave-relay-bin.000003 # Query # # BEGIN slave-relay-bin.000003 # Table_map # # table_id: # (test.t1) @@ -115,8 +116,8 @@ slave-relay-bin.000003 # Rotate # # master-bin.000001;pos=4 show relaylog events in 'slave-relay-bin.000003' from limit 1,3; Log_name Pos Event_type Server_id End_log_pos Info slave-relay-bin.000003 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +slave-relay-bin.000003 # Binlog_checkpoint # # master-bin.000001 slave-relay-bin.000003 # Query # # use `test`; CREATE TABLE t1 (a INT) -slave-relay-bin.000003 # Query # # BEGIN ******** [slave] SHOW RELAYLOG EVENTS ******** show relaylog events from ; Log_name Pos Event_type Server_id End_log_pos Info @@ -185,6 +186,7 @@ show relaylog events in 'slave-relay-bin.000006' from ; Log_name Pos Event_type Server_id End_log_pos Info slave-relay-bin.000006 # Rotate # # master-bin.000002;pos=4 slave-relay-bin.000006 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +slave-relay-bin.000006 # Binlog_checkpoint # # master-bin.000002 slave-relay-bin.000006 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ ******** [slave] SHOW RELAYLOG EVENTS IN LIMIT 1 ******** show relaylog events in 'slave-relay-bin.000006' from limit 1; @@ -194,6 +196,7 @@ slave-relay-bin.000006 # Rotate # # master-bin.000002;pos=4 show relaylog events in 'slave-relay-bin.000006' from limit 1,3; Log_name Pos Event_type Server_id End_log_pos Info slave-relay-bin.000006 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +slave-relay-bin.000006 # Binlog_checkpoint # # master-bin.000002 slave-relay-bin.000006 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ ******** [slave] SHOW RELAYLOG EVENTS ******** show relaylog events from ; diff --git a/mysql-test/suite/rpl/r/rpl_stm_mix_show_relaylog_events.result b/mysql-test/suite/rpl/r/rpl_stm_mix_show_relaylog_events.result index f706fa0fe75..a978c3c900c 100644 --- a/mysql-test/suite/rpl/r/rpl_stm_mix_show_relaylog_events.result +++ b/mysql-test/suite/rpl/r/rpl_stm_mix_show_relaylog_events.result @@ -82,6 +82,7 @@ show relaylog events in 'slave-relay-bin.000003' from ; Log_name Pos Event_type Server_id End_log_pos Info slave-relay-bin.000003 # Rotate # # master-bin.000001;pos=4 slave-relay-bin.000003 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +slave-relay-bin.000003 # Binlog_checkpoint # # master-bin.000001 slave-relay-bin.000003 # Query # # use `test`; CREATE TABLE t1 (a INT) slave-relay-bin.000003 # Query # # BEGIN slave-relay-bin.000003 # Query # # use `test`; INSERT INTO t1 VALUES (1) @@ -100,8 +101,8 @@ slave-relay-bin.000003 # Rotate # # master-bin.000001;pos=4 show relaylog events in 'slave-relay-bin.000003' from limit 1,3; Log_name Pos Event_type Server_id End_log_pos Info slave-relay-bin.000003 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +slave-relay-bin.000003 # Binlog_checkpoint # # master-bin.000001 slave-relay-bin.000003 # Query # # use `test`; CREATE TABLE t1 (a INT) -slave-relay-bin.000003 # Query # # BEGIN ******** [slave] SHOW RELAYLOG EVENTS ******** show relaylog events from ; Log_name Pos Event_type Server_id End_log_pos Info @@ -164,6 +165,7 @@ show relaylog events in 'slave-relay-bin.000006' from ; Log_name Pos Event_type Server_id End_log_pos Info slave-relay-bin.000006 # Rotate # # master-bin.000002;pos=4 slave-relay-bin.000006 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +slave-relay-bin.000006 # Binlog_checkpoint # # master-bin.000002 slave-relay-bin.000006 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ ******** [slave] SHOW RELAYLOG EVENTS IN LIMIT 1 ******** show relaylog events in 'slave-relay-bin.000006' from limit 1; @@ -173,6 +175,7 @@ slave-relay-bin.000006 # Rotate # # master-bin.000002;pos=4 show relaylog events in 'slave-relay-bin.000006' from limit 1,3; Log_name Pos Event_type Server_id End_log_pos Info slave-relay-bin.000006 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +slave-relay-bin.000006 # Binlog_checkpoint # # master-bin.000002 slave-relay-bin.000006 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ ******** [slave] SHOW RELAYLOG EVENTS ******** show relaylog events from ; diff --git a/mysql-test/suite/rpl/t/rpl_mariadb_slave_capability.test b/mysql-test/suite/rpl/t/rpl_mariadb_slave_capability.test index 77aa9341ff4..36f4defa252 100644 --- a/mysql-test/suite/rpl/t/rpl_mariadb_slave_capability.test +++ b/mysql-test/suite/rpl/t/rpl_mariadb_slave_capability.test @@ -61,7 +61,7 @@ connection slave; SELECT * FROM t1; let $binlog_file= query_get_value(SHOW SLAVE STATUS, Relay_Log_File, 1); let $binlog_start= 0; -let $binlog_limit=3,5; +let $binlog_limit=4,5; --source include/show_relaylog_events.inc --echo # Test that slave which cannot tolerate holes in binlog stream but diff --git a/mysql-test/t/mysqlbinlog2.test b/mysql-test/t/mysqlbinlog2.test index 740c4078f20..986e180db13 100644 --- a/mysql-test/t/mysqlbinlog2.test +++ b/mysql-test/t/mysqlbinlog2.test @@ -23,7 +23,7 @@ insert into t1 values(null, "b"); set timestamp=@a+2; --let $binlog_pos_760=query_get_value(SHOW MASTER STATUS, Position, 1) insert into t1 values(null, "c"); ---let $binlog_pos_951=query_get_value(SHOW BINLOG EVENTS in 'master-bin.000001' from $binlog_pos_760, Pos, 4) +--let $binlog_pos_951=query_get_value(SHOW BINLOG EVENTS in 'master-bin.000001' from $binlog_pos_760, Pos, 5) set timestamp=@a+4; insert into t1 values(null, "d"); insert into t1 values(null, "e"); @@ -31,8 +31,8 @@ insert into t1 values(null, "e"); flush logs; set timestamp=@a+1; # this could happen on a slave insert into t1 values(null, "f"); ---let $binlog_pos_135=query_get_value(SHOW BINLOG EVENTS in 'master-bin.000002', Pos, 3) ---let $binlog_pos_203=query_get_value(SHOW BINLOG EVENTS in 'master-bin.000002', Pos, 4) +--let $binlog_pos_135=query_get_value(SHOW BINLOG EVENTS in 'master-bin.000002', Pos, 4) +--let $binlog_pos_203=query_get_value(SHOW BINLOG EVENTS in 'master-bin.000002', Pos, 5) # delimiters are for easier debugging in future @@ -50,22 +50,22 @@ let $MYSQLD_DATADIR= `select @@datadir`; --disable_query_log select "--- offset --" as ""; --enable_query_log ---exec $MYSQL_BINLOG --short-form --offset=2 $MYSQLD_DATADIR/master-bin.000001 +--exec $MYSQL_BINLOG --short-form --offset=3 $MYSQLD_DATADIR/master-bin.000001 --disable_query_log select "--- start-position --" as ""; --enable_query_log -let $start_pos= `select @binlog_start_pos + 653`; +let $start_pos= `select @binlog_start_pos + 693`; --exec $MYSQL_BINLOG --short-form --start-position=$start_pos $MYSQLD_DATADIR/master-bin.000001 --disable_query_log select "--- stop-position --" as ""; --enable_query_log -let $stop_pos= `select @binlog_start_pos + 653`; +let $stop_pos= `select @binlog_start_pos + 693`; --exec $MYSQL_BINLOG --short-form --stop-position=$stop_pos $MYSQLD_DATADIR/master-bin.000001 --disable_query_log select "--- start and stop positions ---" as ""; --enable_query_log -let $start_pos= `select @binlog_start_pos + 653`; -let $stop_pos= `select @binlog_start_pos + 770`; +let $start_pos= `select @binlog_start_pos + 693`; +let $stop_pos= `select @binlog_start_pos + 810`; --exec $MYSQL_BINLOG --short-form --start-position=$start_pos --stop-position=$stop_pos $MYSQLD_DATADIR/master-bin.000001 --disable_query_log select "--- start-datetime --" as ""; @@ -88,16 +88,16 @@ flush logs; --disable_query_log select "--- offset --" as ""; --enable_query_log ---exec $MYSQL_BINLOG --short-form --offset=2 $MYSQLD_DATADIR/master-bin.000001 $MYSQLD_DATADIR/master-bin.000002 +--exec $MYSQL_BINLOG --short-form --offset=3 $MYSQLD_DATADIR/master-bin.000001 $MYSQLD_DATADIR/master-bin.000002 --disable_query_log select "--- start-position --" as ""; --enable_query_log -let $start_pos= `select @binlog_start_pos + 653`; +let $start_pos= `select @binlog_start_pos + 693`; --exec $MYSQL_BINLOG --short-form --start-position=$start_pos $MYSQLD_DATADIR/master-bin.000001 $MYSQLD_DATADIR/master-bin.000002 --disable_query_log select "--- stop-position --" as ""; --enable_query_log -let $stop_pos= `select @binlog_start_pos + 69`; +let $stop_pos= `select @binlog_start_pos + 109`; --exec $MYSQL_BINLOG --short-form --stop-position=$stop_pos $MYSQLD_DATADIR/master-bin.000001 $MYSQLD_DATADIR/master-bin.000002 --disable_query_log select "--- start-datetime --" as ""; @@ -117,22 +117,22 @@ select "--- Remote --" as ""; --disable_query_log select "--- offset --" as ""; --enable_query_log ---exec $MYSQL_BINLOG --short-form --offset=2 --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 +--exec $MYSQL_BINLOG --short-form --offset=3 --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 --disable_query_log select "--- start-position --" as ""; --enable_query_log -let $start_pos= `select @binlog_start_pos + 653`; +let $start_pos= `select @binlog_start_pos + 693`; --exec $MYSQL_BINLOG --short-form --start-position=$start_pos --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 --disable_query_log select "--- stop-position --" as ""; --enable_query_log -let $stop_pos= `select @binlog_start_pos + 653`; +let $stop_pos= `select @binlog_start_pos + 693`; --exec $MYSQL_BINLOG --short-form --stop-position=$stop_pos --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 --disable_query_log select "--- start and stop positions ---" as ""; --enable_query_log -let $start_pos= `select @binlog_start_pos + 653`; -let $stop_pos= `select @binlog_start_pos + 770`; +let $start_pos= `select @binlog_start_pos + 693`; +let $stop_pos= `select @binlog_start_pos + 810`; --exec $MYSQL_BINLOG --short-form --start-position=$start_pos --stop-position $stop_pos --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 --disable_query_log select "--- start-datetime --" as ""; @@ -152,16 +152,16 @@ select "--- Remote with 2 binlogs on command line --" as ""; --disable_query_log select "--- offset --" as ""; --enable_query_log ---exec $MYSQL_BINLOG --short-form --offset=2 --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 master-bin.000002 +--exec $MYSQL_BINLOG --short-form --offset=3 --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 master-bin.000002 --disable_query_log select "--- start-position --" as ""; --enable_query_log -let $start_pos= `select @binlog_start_pos + 653`; +let $start_pos= `select @binlog_start_pos + 693`; --exec $MYSQL_BINLOG --short-form --start-position=$start_pos --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 master-bin.000002 --disable_query_log select "--- stop-position --" as ""; --enable_query_log -let $stop_pos= `select @binlog_start_pos + 28`; +let $stop_pos= `select @binlog_start_pos + 68`; --exec $MYSQL_BINLOG --short-form --stop-position=$stop_pos --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 master-bin.000002 --disable_query_log select "--- start-datetime --" as ""; diff --git a/mysql-test/t/mysqldump-max.test b/mysql-test/t/mysqldump-max.test index 27c1a3ce20c..d0a4870ba31 100644 --- a/mysql-test/t/mysqldump-max.test +++ b/mysql-test/t/mysqldump-max.test @@ -1194,7 +1194,7 @@ DROP TABLE t2; --exec $MYSQL test < $MYSQLTEST_VARDIR/tmp/mwl136.sql --replace_regex /\/\* xid=.* \*\//\/* XID *\// /Server ver: .*, Binlog ver: .*/Server ver: #, Binlog ver: #/ /table_id: [0-9]+/table_id: #/ -SHOW BINLOG EVENTS LIMIT 6,3; +SHOW BINLOG EVENTS LIMIT 7,3; --perl my $f= "$ENV{MYSQLTEST_VARDIR}/tmp/mwl136.sql"; open F, '<', $f or die "Failed to open $f: $!\n"; diff --git a/mysql-test/t/xa_binlog.test b/mysql-test/t/xa_binlog.test index 48f1dc6dfaa..430d45ab86a 100644 --- a/mysql-test/t/xa_binlog.test +++ b/mysql-test/t/xa_binlog.test @@ -27,6 +27,6 @@ SELECT * FROM t1 ORDER BY a; --replace_column 2 # 5 # --replace_regex /xid=[0-9]+/xid=XX/ -SHOW BINLOG EVENTS LIMIT 1,9; +SHOW BINLOG EVENTS LIMIT 2,9; DROP TABLE t1; diff --git a/sql/handler.cc b/sql/handler.cc index 58d37532796..e7eddef55ed 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1286,6 +1286,7 @@ int ha_commit_trans(THD *thd, bool all) if (!cookie) goto err; + DEBUG_SYNC(thd, "ha_commit_trans_after_log_and_order"); DBUG_EXECUTE_IF("crash_commit_after_log", DBUG_SUICIDE();); error= commit_one_phase_2(thd, all, trans, is_real_trans) ? 2 : 0; diff --git a/sql/log.cc b/sql/log.cc index 56c07f81c9e..430f0a0bf60 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -479,6 +479,7 @@ public: */ bool using_xa; my_xid xa_xid; + ulong cookie; private: @@ -1665,6 +1666,21 @@ binlog_flush_cache(THD *thd, binlog_cache_mngr *cache_mngr, end_ev, all, using_stmt, using_trx); } + else + { + /* + This can happen in row-format binlog with something like + BEGIN; INSERT INTO nontrans_table; INSERT IGNORE INTO trans_table; + The nontrans_table is written directly into the binlog before commit, + and if the trans_table is ignored there will be no rows to write when + we get here. + + So there is no work to do. Therefore, we will not increment any XID + count, so we must not decrement any XID count in unlog(). + */ + if (cache_mngr->using_xa && cache_mngr->xa_xid) + cache_mngr->cookie= BINLOG_COOKIE_DUMMY; + } cache_mngr->reset(using_stmt, using_trx); DBUG_ASSERT((!using_stmt || cache_mngr->stmt_cache.empty()) && @@ -2888,7 +2904,8 @@ const char *MYSQL_LOG::generate_name(const char *log_name, MYSQL_BIN_LOG::MYSQL_BIN_LOG(uint *sync_period) - :bytes_written(0), prepared_xids(0), file_id(1), open_count(1), + :current_binlog_id(BINLOG_COOKIE_START), reset_master_pending(false), + bytes_written(0), file_id(1), open_count(1), need_start_event(TRUE), group_commit_queue(0), group_commit_queue_busy(FALSE), num_commits(0), num_group_commits(0), @@ -2916,13 +2933,30 @@ void MYSQL_BIN_LOG::cleanup() DBUG_ENTER("cleanup"); if (inited) { + xid_count_per_binlog *b; + inited= 0; close(LOG_CLOSE_INDEX|LOG_CLOSE_STOP_EVENT); delete description_event_for_queue; delete description_event_for_exec; + + while ((b= binlog_xid_count_list.get())) + { + /* + There should be no pending XIDs at shutdown, and only one entry (for + the active binlog file) in the list. + */ + DBUG_ASSERT(b->xid_count == 0); + DBUG_ASSERT(!binlog_xid_count_list.head()); + my_free(b); + } + mysql_mutex_destroy(&LOCK_log); mysql_mutex_destroy(&LOCK_index); + mysql_mutex_destroy(&LOCK_xid_list); mysql_cond_destroy(&update_cond); + mysql_cond_destroy(&COND_queue_busy); + mysql_cond_destroy(&COND_xid_list); } DBUG_VOID_RETURN; } @@ -2944,8 +2978,11 @@ void MYSQL_BIN_LOG::init_pthread_objects() MYSQL_LOG::init_pthread_objects(); mysql_mutex_init(m_key_LOCK_index, &LOCK_index, MY_MUTEX_INIT_SLOW); mysql_mutex_setflags(&LOCK_index, MYF_NO_DEADLOCK_DETECTION); + mysql_mutex_init(key_BINLOG_LOCK_xid_list, + &LOCK_xid_list, MY_MUTEX_INIT_FAST); mysql_cond_init(m_key_update_cond, &update_cond, 0); mysql_cond_init(m_key_COND_queue_busy, &COND_queue_busy, 0); + mysql_cond_init(key_BINLOG_COND_xid_list, &COND_xid_list, 0); } @@ -3149,6 +3186,51 @@ bool MYSQL_BIN_LOG::open(const char *log_name, if (s.write(&log_file)) goto err; bytes_written+= s.data_written; + + if (!is_relay_log) + { + char buf[FN_REFLEN]; + /* + Put this one into the list of active binlogs. + Write the current binlog checkpoint into the log, so XA recovery will + know from where to start recovery. + */ + uint off= dirname_length(log_file_name); + uint len= strlen(log_file_name) - off; + char *entry_mem, *name_mem; + xid_count_per_binlog *b, *b2; + if (!(b = (xid_count_per_binlog *) + my_multi_malloc(MYF(MY_WME), + &entry_mem, sizeof(xid_count_per_binlog), + &name_mem, len, + NULL))) + goto err; + memcpy(name_mem, log_file_name+off, len); + b->binlog_name= name_mem; + b->binlog_name_len= len; + b->xid_count= 0; + + mysql_mutex_lock(&LOCK_xid_list); + b->binlog_id= ++current_binlog_id; + + /* + Remove any initial entries with no pending XIDs. + Normally this will be done in unlog(), but if there are no + transactions with an XA-capable engine at all in a given binlog + file, unlog() will never be used and we will remove the entry here. + */ + while ((b2= binlog_xid_count_list.head()) && b2->xid_count == 0) + my_free(binlog_xid_count_list.get()); + + binlog_xid_count_list.push_back(b); + b2= binlog_xid_count_list.head(); + strmake(buf, b2->binlog_name, b2->binlog_name_len); + mysql_mutex_unlock(&LOCK_xid_list); + Binlog_checkpoint_log_event ev(buf, len); + if (ev.write(&log_file)) + goto err; + bytes_written+= ev.data_written; + } } if (description_event_for_queue && description_event_for_queue->binlog_version>=4) @@ -3514,6 +3596,42 @@ bool MYSQL_BIN_LOG::reset_logs(THD* thd) mysql_mutex_lock(&LOCK_log); mysql_mutex_lock(&LOCK_index); + if (!is_relay_log) + { + /* + We are going to nuke all binary log files. + So first wait until all pending binlog checkpoints have completed. + */ + mysql_mutex_lock(&LOCK_xid_list); + xid_count_per_binlog *b; + reset_master_pending= true; + for (;;) + { + I_List_iterator it(binlog_xid_count_list); + while ((b= it++)) + { + if (b->xid_count > 0) + break; + } + if (!b) + break; /* No more pending XIDs */ + /* + Wait until signalled that one more binlog dropped to zero, then check + again. + */ + mysql_cond_wait(&COND_xid_list, &LOCK_xid_list); + } + + /* + Now all XIDs are fully flushed to disk, and we are holding LOCK_log so + no new ones will be written. So we can proceed to delete the logs. + */ + while ((b= binlog_xid_count_list.get())) + my_free(b); + reset_master_pending= false; + mysql_mutex_unlock(&LOCK_xid_list); + } + /* The following mutex is needed to ensure that no threads call 'delete thd' as we would then risk missing a 'rollback' from this @@ -3824,8 +3942,7 @@ int MYSQL_BIN_LOG::purge_logs(const char *to_log, if ((error=find_log_pos(&log_info, NullS, 0 /*no mutex*/))) goto err; while ((strcmp(to_log,log_info.log_file_name) || (exit_loop=included)) && - !is_active(log_info.log_file_name) && - !log_in_use(log_info.log_file_name)) + can_purge_log(log_info.log_file_name)) { if ((error= register_purge_index_entry(log_info.log_file_name))) { @@ -4175,8 +4292,7 @@ int MYSQL_BIN_LOG::purge_logs_before_date(time_t purge_time) goto err; while (strcmp(log_file_name, log_info.log_file_name) && - !is_active(log_info.log_file_name) && - !log_in_use(log_info.log_file_name)) + can_purge_log(log_info.log_file_name)) { if (!mysql_file_stat(m_key_file_log, log_info.log_file_name, &stat_area, MYF(0))) @@ -4231,6 +4347,28 @@ err: mysql_mutex_unlock(&LOCK_index); DBUG_RETURN(error); } + + +bool +MYSQL_BIN_LOG::can_purge_log(const char *log_file_name) +{ + xid_count_per_binlog *b; + + if (is_active(log_file_name)) + return false; + mysql_mutex_lock(&LOCK_xid_list); + { + I_List_iterator it(binlog_xid_count_list); + while ((b= it++) && + 0 != strncmp(log_file_name+dirname_length(log_file_name), + b->binlog_name, b->binlog_name_len)) + ; + } + mysql_mutex_unlock(&LOCK_xid_list); + if (b) + return false; + return !log_in_use(log_file_name); +} #endif /* HAVE_REPLICATION */ @@ -4324,26 +4462,6 @@ int MYSQL_BIN_LOG::new_file_impl(bool need_lock) mysql_mutex_assert_owner(&LOCK_log); mysql_mutex_assert_owner(&LOCK_index); - /* - if binlog is used as tc log, be sure all xids are "unlogged", - so that on recover we only need to scan one - latest - binlog file - for prepared xids. As this is expected to be a rare event, - simple wait strategy is enough. We're locking LOCK_log to be sure no - new Xid_log_event's are added to the log (and prepared_xids is not - increased), and waiting on COND_prep_xids for late threads to - catch up. - */ - if (prepared_xids) - { - tc_log_page_waits++; - mysql_mutex_lock(&LOCK_prep_xids); - while (prepared_xids) { - DBUG_PRINT("info", ("prepared_xids=%lu", prepared_xids)); - mysql_cond_wait(&COND_prep_xids, &LOCK_prep_xids); - } - mysql_mutex_unlock(&LOCK_prep_xids); - } - /* Reuse old name if not binlog and not update log */ new_name_ptr= name; @@ -5792,6 +5910,37 @@ bool MYSQL_BIN_LOG::write_incident(THD *thd) DBUG_RETURN(error); } +void +MYSQL_BIN_LOG::write_binlog_checkpoint_event_already_locked(const char *name, + uint len) +{ + Binlog_checkpoint_log_event ev(name, len); + /* + Note that we must sync the binlog checkpoint to disk. + Otherwise a subsequent log purge could delete binlogs that XA recovery + thinks are needed (even though they are not really). + */ + if (!ev.write(&log_file) && !flush_and_sync(0)) + { + bool check_purge= false; + signal_update(); + rotate(false, &check_purge); + if (check_purge) + purge(); + return; + } + + /* + If we fail to write the checkpoint event, something is probably really + bad with the binlog. We complain in the error log. + Note that failure to write binlog checkpoint does not compromise the + ability to do crash recovery - crash recovery will just have to scan a + bit more of the binlog than strictly necessary. + */ + sql_print_error("Failed to write binlog checkpoint event to binary log\n"); +} + + /** Write a cached log entry to the binary log. - To support transaction over replication, we wrap the transaction @@ -5951,7 +6100,7 @@ MYSQL_BIN_LOG::write_transaction_to_binlog_events(group_commit_entry *entry) for a transaction if log_xid() fails). */ if (entry->cache_mngr->using_xa && entry->cache_mngr->xa_xid) - mark_xid_done(); + mark_xid_done(entry->cache_mngr->cookie); return 1; } @@ -5972,7 +6121,6 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader) uint xid_count= 0; my_off_t UNINIT_VAR(commit_offset); group_commit_entry *current; - group_commit_entry *last_in_queue; group_commit_entry *queue= NULL; bool check_purge= false; DBUG_ENTER("MYSQL_BIN_LOG::trx_group_commit_leader"); @@ -5993,7 +6141,6 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader) mysql_mutex_unlock(&LOCK_prepare_ordered); /* As the queue is in reverse order of entering, reverse it. */ - last_in_queue= current; while (current) { group_commit_entry *next= current->next; @@ -6032,7 +6179,10 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader) commit_offset= my_b_write_tell(&log_file); cache_mngr->last_commit_pos_offset= commit_offset; if (cache_mngr->using_xa && cache_mngr->xa_xid) + { xid_count++; + cache_mngr->cookie= current_binlog_id; + } } bool synced= 0; @@ -6075,16 +6225,14 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader) } /* - if any commit_events are Xid_log_event, increase the number of - prepared_xids (it's decreased in ::unlog()). Binlog cannot be rotated - if there're prepared xids in it - see the comment in new_file() for - an explanation. - If no Xid_log_events (then it's all Query_log_event) rotate binlog, - if necessary. + If any commit_events are Xid_log_event, increase the number of pending + XIDs in current binlog (it's decreased in ::unlog()). When the count in + a (not active) binlog file reaches zero, we know that it is no longer + needed in XA recovery, and we can log a new binlog checkpoint event. */ if (xid_count > 0) { - mark_xids_active(xid_count); + mark_xids_active(current_binlog_id, xid_count); } else { @@ -6092,11 +6240,11 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader) { /* If we fail to rotate, which thread should get the error? - We give the error to the *last* transaction thread; that seems to - make the most sense, as it was the last to write to the log. + We give the error to the leader, as any my_error() thrown inside + rotate() will have been registered for the leader THD. */ - last_in_queue->error= ER_ERROR_ON_WRITE; - last_in_queue->commit_errno= errno; + leader->error= ER_ERROR_ON_WRITE; + leader->commit_errno= errno; check_purge= false; } } @@ -6113,9 +6261,6 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader) */ mysql_mutex_unlock(&LOCK_log); - if (check_purge) - purge(); - DEBUG_SYNC(leader->thd, "commit_after_release_LOCK_log"); ++num_group_commits; @@ -6148,7 +6293,8 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader) DEBUG_SYNC(leader->thd, "commit_loop_entry_commit_ordered"); ++num_commits; - if (current->cache_mngr->using_xa && !current->error) + if (current->cache_mngr->using_xa && !current->error && + DBUG_EVALUATE_IF("skip_commit_ordered", 0, 1)) run_commit_ordered(current->thd, current->all); /* @@ -6163,6 +6309,9 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader) DEBUG_SYNC(leader->thd, "commit_after_group_run_commit_ordered"); mysql_mutex_unlock(&LOCK_commit_ordered); + if (check_purge) + purge(); + DBUG_VOID_RETURN; } @@ -7351,14 +7500,6 @@ 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 - (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! -*/ - int TC_LOG_BINLOG::open(const char *opt_name) { LOG_INFO log_info; @@ -7367,10 +7508,6 @@ int TC_LOG_BINLOG::open(const char *opt_name) DBUG_ASSERT(total_ha_2pc > 1); DBUG_ASSERT(opt_name && opt_name[0]); - mysql_mutex_init(key_BINLOG_LOCK_prep_xids, - &LOCK_prep_xids, MY_MUTEX_INIT_FAST); - mysql_cond_init(key_BINLOG_COND_prep_xids, &COND_prep_xids, 0); - if (!my_b_inited(&index_file)) { /* There was a failure to open the index file, can't open the binlog */ @@ -7429,7 +7566,8 @@ int TC_LOG_BINLOG::open(const char *opt_name) ev->flags & LOG_EVENT_BINLOG_IN_USE_F) { sql_print_information("Recovering after a crash using %s", opt_name); - error= recover(&log, (Format_description_log_event *)ev); + error= recover(&log_info, log_name, &log, + (Format_description_log_event *)ev); } else error=0; @@ -7449,9 +7587,6 @@ err: /** This is called on shutdown, after ha_panic. */ void TC_LOG_BINLOG::close() { - DBUG_ASSERT(prepared_xids==0); - mysql_mutex_destroy(&LOCK_prep_xids); - mysql_cond_destroy(&COND_prep_xids); } /* @@ -7471,11 +7606,23 @@ TC_LOG_BINLOG::log_and_order(THD *thd, my_xid xid, bool all, cache_mngr->using_xa= TRUE; cache_mngr->xa_xid= xid; +#ifndef DBUG_OFF + cache_mngr->cookie= 0; +#endif err= binlog_commit_flush_xid_caches(thd, cache_mngr, all, xid); DEBUG_SYNC(thd, "binlog_after_log_and_order"); - DBUG_RETURN(!err); + if (err) + DBUG_RETURN(0); + /* + If using explicit user XA, we will not have XID. We must still return a + non-zero cookie (as zero cookie signals error). + */ + if (!xid) + DBUG_RETURN(BINLOG_COOKIE_DUMMY); + DBUG_ASSERT(cache_mngr->cookie != 0); + DBUG_RETURN(cache_mngr->cookie); } /* @@ -7490,40 +7637,134 @@ TC_LOG_BINLOG::log_and_order(THD *thd, my_xid xid, bool all, binary log. */ void -TC_LOG_BINLOG::mark_xids_active(uint xid_count) +TC_LOG_BINLOG::mark_xids_active(ulong cookie, uint xid_count) { + xid_count_per_binlog *b; + DBUG_ENTER("TC_LOG_BINLOG::mark_xids_active"); - DBUG_PRINT("info", ("xid_count=%u", xid_count)); - mysql_mutex_lock(&LOCK_prep_xids); - prepared_xids+= xid_count; - mysql_mutex_unlock(&LOCK_prep_xids); + DBUG_PRINT("info", ("cookie=%lu xid_count=%u", cookie, xid_count)); + DBUG_ASSERT(cookie != 0 && cookie != BINLOG_COOKIE_DUMMY); + + mysql_mutex_lock(&LOCK_xid_list); + I_List_iterator it(binlog_xid_count_list); + while ((b= it++)) + { + if (b->binlog_id == cookie) + { + b->xid_count += xid_count; + break; + } + } + /* + As we do not delete elements until count reach zero, elements should always + be found. + */ + DBUG_ASSERT(b); + mysql_mutex_unlock(&LOCK_xid_list); DBUG_VOID_RETURN; } /* - Once an XID is committed, it is safe to rotate the binary log, as it can no - longer be needed during crash recovery. + Once an XID is committed, it can no longer be needed during crash recovery, + as it has been durably recorded on disk as "committed". This function is called to mark an XID this way. It needs to decrease the - count of pending XIDs, and signal the log rotator thread when it reaches zero. + count of pending XIDs in the corresponding binlog. When the count reaches + zero (for an "old" binlog that is not the active one), that binlog file no + longer need to be scanned during crash recovery, so we can log a new binlog + checkpoint. */ void -TC_LOG_BINLOG::mark_xid_done() +TC_LOG_BINLOG::mark_xid_done(ulong cookie) { - my_bool send_signal; + xid_count_per_binlog *b; + bool first; + ulong current; DBUG_ENTER("TC_LOG_BINLOG::mark_xid_done"); - mysql_mutex_lock(&LOCK_prep_xids); - // prepared_xids can be 0 if the transaction had ignorable errors. - DBUG_ASSERT(prepared_xids >= 0); - if (prepared_xids > 0) - prepared_xids--; - send_signal= (prepared_xids == 0); - mysql_mutex_unlock(&LOCK_prep_xids); - if (send_signal) { - DBUG_PRINT("info", ("prepared_xids=%lu", prepared_xids)); - mysql_cond_signal(&COND_prep_xids); + if (cookie == BINLOG_COOKIE_DUMMY) + DBUG_VOID_RETURN; /* Nothing to do. */ + + mysql_mutex_lock(&LOCK_xid_list); + current= current_binlog_id; + I_List_iterator it(binlog_xid_count_list); + first= true; + while ((b= it++)) + { + if (b->binlog_id == cookie) + { + --b->xid_count; + break; + } + first= false; } + /* Binlog is always found, as we do not remove until count reaches 0 */ + DBUG_ASSERT(b); + if (likely(cookie == current && !reset_master_pending) || + b->xid_count != 0 || !first) + { + /* No new binlog checkpoint reached yet. */ + mysql_mutex_unlock(&LOCK_xid_list); + DBUG_VOID_RETURN; + } + + /* + Now log a binlog checkpoint for the first binlog file with a non-zero count. + + Note that it is possible (though perhaps unlikely) that when count of + binlog (N-2) drops to zero, binlog (N-1) is already at zero. So we may + need to skip several entries before we find the one to log in the binlog + checkpoint event. + + We chain the locking of LOCK_xid_list and LOCK_log, so that we ensure that + Binlog_checkpoint_events are logged in order. This simplifies recovery a + bit, as it can just take the last binlog checkpoint in the log, rather + than compare all found against each other to find the one pointing to the + most recent binlog. + + Note also that we need to first release LOCK_xid_list, then aquire + LOCK_log, then re-aquire LOCK_xid_list. If we were to take LOCK_log while + holding LOCK_xid_list, we might deadlock with other threads that take the + locks in the opposite order. + + If a RESET MASTER is pending, we are about to remove all log files, and + the RESET MASTER thread is waiting for all pending unlog() calls to + complete while holding LOCK_log. In this case we should not log a binlog + checkpoint event (it would be deleted immediately anywat and we would + deadlock on LOCK_log) but just signal the thread. + */ + if (!reset_master_pending) + { + mysql_mutex_unlock(&LOCK_xid_list); + mysql_mutex_lock(&LOCK_log); + mysql_mutex_lock(&LOCK_xid_list); + } + for (;;) + { + /* Remove initial element(s) with zero count. */ + b= binlog_xid_count_list.head(); + /* + Normally, we must not remove all elements in the list. + Only if a RESET MASTER is in progress may we delete everything - RESET + MASTER has LOCK_log held, and will create a new initial element before + releasing the lock. + */ + DBUG_ASSERT(b || reset_master_pending); + if (unlikely(!b) || b->binlog_id == current || b->xid_count > 0) + break; + my_free(binlog_xid_count_list.get()); + } + if (reset_master_pending) + { + mysql_cond_signal(&COND_xid_list); + mysql_mutex_unlock(&LOCK_xid_list); + DBUG_VOID_RETURN; + } + + mysql_mutex_unlock(&LOCK_xid_list); + write_binlog_checkpoint_event_already_locked(b->binlog_name, + b->binlog_name_len); + mysql_mutex_unlock(&LOCK_log); DBUG_VOID_RETURN; } @@ -7531,16 +7772,24 @@ int TC_LOG_BINLOG::unlog(ulong cookie, my_xid xid) { DBUG_ENTER("TC_LOG_BINLOG::unlog"); if (xid) - mark_xid_done(); + mark_xid_done(cookie); /* As ::write_transaction_to_binlog() did not rotate, do it here. */ DBUG_RETURN(rotate_and_purge(0)); } -int TC_LOG_BINLOG::recover(IO_CACHE *log, Format_description_log_event *fdle) +int TC_LOG_BINLOG::recover(LOG_INFO *linfo, const char *last_log_name, + IO_CACHE *first_log, + Format_description_log_event *fdle) { Log_event *ev; HASH xids; MEM_ROOT mem_root; + char binlog_checkpoint_name[FN_REFLEN]; + bool binlog_checkpoint_found; + bool first_round; + IO_CACHE log; + File file= -1; + const char *errmsg; if (! fdle->is_valid() || my_hash_init(&xids, &my_charset_bin, TC_LOG_PAGE_SIZE/3, 0, @@ -7551,19 +7800,109 @@ int TC_LOG_BINLOG::recover(IO_CACHE *log, Format_description_log_event *fdle) fdle->flags&= ~LOG_EVENT_BINLOG_IN_USE_F; // abort on the first error - while ((ev= Log_event::read_log_event(log, 0, fdle, - opt_master_verify_checksum)) - && ev->is_valid()) + /* + Scan the binlog for XIDs that need to be committed if still in the + prepared stage. + + Start with the latest binlog file, then continue with any other binlog + files if the last found binlog checkpoint indicates it is needed. + */ + + binlog_checkpoint_found= false; + first_round= true; + for (;;) { - if (ev->get_type_code() == XID_EVENT) + while ((ev= Log_event::read_log_event(first_round ? first_log : &log, + 0, fdle, opt_master_verify_checksum)) + && ev->is_valid()) { - Xid_log_event *xev=(Xid_log_event *)ev; - uchar *x= (uchar *) memdup_root(&mem_root, (uchar*) &xev->xid, - sizeof(xev->xid)); - if (!x || my_hash_insert(&xids, x)) - goto err2; + switch (ev->get_type_code()) + { + case XID_EVENT: + { + Xid_log_event *xev=(Xid_log_event *)ev; + uchar *x= (uchar *) memdup_root(&mem_root, (uchar*) &xev->xid, + sizeof(xev->xid)); + if (!x || my_hash_insert(&xids, x)) + { + delete ev; + goto err2; + } + break; + } + case BINLOG_CHECKPOINT_EVENT: + if (first_round) + { + uint dir_len; + Binlog_checkpoint_log_event *cev= (Binlog_checkpoint_log_event *)ev; + if (cev->binlog_file_len >= FN_REFLEN) + sql_print_warning("Incorrect binlog checkpoint event with too " + "long file name found."); + else + { + /* + Note that we cannot use make_log_name() here, as we have not yet + initialised MYSQL_BIN_LOG::log_file_name. + */ + dir_len= dirname_length(last_log_name); + strmake(strnmov(binlog_checkpoint_name, last_log_name, dir_len), + cev->binlog_file_name, FN_REFLEN - 1 - dir_len); + binlog_checkpoint_found= true; + } + break; + } + default: + /* Nothing. */ + break; + } + delete ev; + } + + /* + If the last binlog checkpoint event points to an older log, we have to + scan all logs from there also, to get all possible XIDs to recover. + + If there was no binlog checkpoint event at all, this means the log was + written by an older version of MariaDB (or MySQL) - these always have an + (implicit) binlog checkpoint event at the start of the last binlog file. + */ + if (first_round) + { + if (!binlog_checkpoint_found) + break; + first_round= false; + if (find_log_pos(linfo, binlog_checkpoint_name, 1)) + { + sql_print_error("Binlog file '%s' not found in binlog index, needed " + "for recovery. Aborting.", binlog_checkpoint_name); + goto err2; + } + } + else + { + end_io_cache(&log); + mysql_file_close(file, MYF(MY_WME)); + file= -1; + } + + if (0 == strcmp(linfo->log_file_name, last_log_name)) + break; // No more files to do + if ((file= open_binlog(&log, linfo->log_file_name, &errmsg)) < 0) + { + sql_print_error("%s", errmsg); + goto err2; + } + /* + We do not need to read the Format_description_log_event of other binlog + files. It is not possible for a binlog checkpoint to span multiple + binlog files written by different versions of the server. So we can use + the first one read for reading from all binlog files. + */ + if (find_next_log(linfo, 1)) + { + sql_print_error("Error reading binlog files during recovery. Aborting."); + goto err2; } - delete ev; } if (ha_recover(&xids)) @@ -7574,6 +7913,11 @@ int TC_LOG_BINLOG::recover(IO_CACHE *log, Format_description_log_event *fdle) return 0; err2: + if (file >= 0) + { + end_io_cache(&log); + mysql_file_close(file, MYF(MY_WME)); + } free_root(&mem_root, MYF(0)); my_hash_free(&xids); err1: diff --git a/sql/log.h b/sql/log.h index 9b9bed1262a..179d302d2cc 100644 --- a/sql/log.h +++ b/sql/log.h @@ -354,6 +354,15 @@ private: time_t last_time; }; +/* + We assign each binlog file an internal ID, used to identify them for unlog(). + Ids start from BINLOG_COOKIE_START; the value BINLOG_COOKIE_DUMMY is special + meaning "no binlog" (we cannot use zero as that is reserved for error return + from log_and_order). +*/ +#define BINLOG_COOKIE_DUMMY 1 +#define BINLOG_COOKIE_START 2 + class binlog_cache_mngr; class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG { @@ -394,10 +403,40 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG bool all; }; + /* + A list of struct xid_count_per_binlog is used to keep track of how many + XIDs are in prepared, but not committed, state in each binlog. + + When count drops to zero in a binlog after rotation, it means that there + are no more XIDs in prepared state, so that binlog is no longer needed + for XA crash recovery, and we can log a new binlog checkpoint event. + + The list is protected against simultaneous access from multiple + threads by LOCK_xid_list. + */ + struct xid_count_per_binlog : public ilink { + char *binlog_name; + uint binlog_name_len; + ulong binlog_id; + long xid_count; + xid_count_per_binlog(); /* Give link error if constructor used. */ + }; + ulong current_binlog_id; + I_List binlog_xid_count_list; + /* + When this is set, a RESET MASTER is in progress. + + Then we should not write any binlog checkpoints into the binlog (that + could result in deadlock on LOCK_log, and we will delete all binlog files + anyway). Instead we should signal COND_xid_list whenever a new binlog + checkpoint arrives - when all have arrived, RESET MASTER will complete. + */ + bool reset_master_pending; + /* LOCK_log and LOCK_index are inited by init_pthread_objects() */ mysql_mutex_t LOCK_index; - mysql_mutex_t LOCK_prep_xids; - mysql_cond_t COND_prep_xids; + mysql_mutex_t LOCK_xid_list; + mysql_cond_t COND_xid_list; mysql_cond_t update_cond; ulonglong bytes_written; IO_CACHE index_file; @@ -421,7 +460,6 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG fix_max_relay_log_size). */ ulong max_size; - long prepared_xids; /* for tc log - number of xids to remember */ // current file sequence number for load data infile binary logging uint file_id; uint open_count; // For replication @@ -473,8 +511,8 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG int write_transaction_or_stmt(group_commit_entry *entry); bool write_transaction_to_binlog_events(group_commit_entry *entry); void trx_group_commit_leader(group_commit_entry *leader); - void mark_xid_done(); - void mark_xids_active(uint xid_count); + void mark_xid_done(ulong cookie); + void mark_xids_active(ulong cookie, uint xid_count); public: using MYSQL_LOG::generate_name; @@ -562,7 +600,8 @@ public: int log_and_order(THD *thd, my_xid xid, bool all, bool need_prepare_ordered, bool need_commit_ordered); int unlog(ulong cookie, my_xid xid); - int recover(IO_CACHE *log, Format_description_log_event *fdle); + int recover(LOG_INFO *linfo, const char *last_log_name, IO_CACHE *first_log, + Format_description_log_event *fdle); #if !defined(MYSQL_CLIENT) int flush_and_set_pending_rows_event(THD *thd, Rows_log_event* event, @@ -614,6 +653,7 @@ public: bool write_incident_already_locked(THD *thd); bool write_incident(THD *thd); + void write_binlog_checkpoint_event_already_locked(const char *name, uint len); int write_cache(THD *thd, IO_CACHE *cache); void set_write_error(THD *thd, bool is_transactional); bool check_write_error(THD *thd); @@ -631,6 +671,7 @@ public: void make_log_name(char* buf, const char* log_ident); bool is_active(const char* log_file_name); + bool can_purge_log(const char *log_file_name); int update_log_index(LOG_INFO* linfo, bool need_update_threads); int rotate(bool force_rotate, bool* check_purge); void purge(); diff --git a/sql/log_event.cc b/sql/log_event.cc index f9849fa0ff5..6cefdb4fa59 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -731,6 +731,7 @@ const char* Log_event::get_type_str(Log_event_type type) case EXECUTE_LOAD_QUERY_EVENT: return "Execute_load_query"; case INCIDENT_EVENT: return "Incident"; case ANNOTATE_ROWS_EVENT: return "Annotate_rows"; + case BINLOG_CHECKPOINT_EVENT: return "Binlog_checkpoint"; default: return "Unknown"; /* impossible */ } } @@ -1387,7 +1388,7 @@ err: DBUG_ASSERT(error != 0); sql_print_error("Error in Log_event::read_log_event(): " "'%s', data_len: %d, event_type: %d", - error,data_len,head[EVENT_TYPE_OFFSET]); + error,data_len,(uchar)(head[EVENT_TYPE_OFFSET])); my_free(buf); /* The SQL slave thread will check if file->error<0 to know @@ -1536,6 +1537,9 @@ Log_event* Log_event::read_log_event(const char* buf, uint event_len, case ROTATE_EVENT: ev = new Rotate_log_event(buf, event_len, description_event); break; + case BINLOG_CHECKPOINT_EVENT: + ev = new Binlog_checkpoint_log_event(buf, event_len, description_event); + break; #ifdef HAVE_REPLICATION case SLAVE_EVENT: /* can never happen (unused event) */ ev = new Slave_log_event(buf, event_len, description_event); @@ -4405,6 +4409,8 @@ Format_description_log_event(uint8 binlog_ver, const char* server_ver) // Set header lengths of Maria events post_header_len[ANNOTATE_ROWS_EVENT-1]= ANNOTATE_ROWS_HEADER_LEN; + post_header_len[BINLOG_CHECKPOINT_EVENT-1]= + BINLOG_CHECKPOINT_HEADER_LEN; // Sanity-check that all post header lengths are initialized. int i; @@ -5863,6 +5869,86 @@ Rotate_log_event::do_shall_skip(Relay_log_info *rli) #endif +/************************************************************************** + Binlog_checkpoint_log_event methods +**************************************************************************/ + +#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) +void Binlog_checkpoint_log_event::pack_info(Protocol *protocol) +{ + protocol->store(binlog_file_name, binlog_file_len, &my_charset_bin); +} +#endif + + +#ifdef MYSQL_CLIENT +void Binlog_checkpoint_log_event::print(FILE *file, + PRINT_EVENT_INFO *print_event_info) +{ + Write_on_release_cache cache(&print_event_info->head_cache, file, + Write_on_release_cache::FLUSH_F); + + if (print_event_info->short_form) + return; + print_header(&cache, print_event_info, FALSE); + my_b_printf(&cache, "\tBinlog checkpoint "); + my_b_write(&cache, (uchar*)binlog_file_name, binlog_file_len); + my_b_printf(&cache, "\n"); +} +#endif /* MYSQL_CLIENT */ + + +#ifdef MYSQL_SERVER +Binlog_checkpoint_log_event::Binlog_checkpoint_log_event( + const char *binlog_file_name_arg, + uint binlog_file_len_arg) + :Log_event(), + binlog_file_name(my_strndup(binlog_file_name_arg, binlog_file_len_arg, + MYF(MY_WME))), + binlog_file_len(binlog_file_len_arg) +{ + cache_type= EVENT_NO_CACHE; +} +#endif /* MYSQL_SERVER */ + + +Binlog_checkpoint_log_event::Binlog_checkpoint_log_event( + const char *buf, uint event_len, + const Format_description_log_event *description_event) + :Log_event(buf, description_event), binlog_file_name(0) +{ + uint8 header_size= description_event->common_header_len; + uint8 post_header_len= + description_event->post_header_len[BINLOG_CHECKPOINT_EVENT-1]; + if (event_len < header_size + post_header_len || + post_header_len < BINLOG_CHECKPOINT_HEADER_LEN) + return; + buf+= header_size; + /* See uint4korr and int4store below */ + compile_time_assert(BINLOG_CHECKPOINT_HEADER_LEN == 4); + binlog_file_len= uint4korr(buf); + if (event_len - (header_size + post_header_len) < binlog_file_len) + return; + binlog_file_name= my_strndup(buf + post_header_len, binlog_file_len, + MYF(MY_WME)); + return; +} + + +#ifndef MYSQL_CLIENT +bool Binlog_checkpoint_log_event::write(IO_CACHE *file) +{ + uchar buf[BINLOG_CHECKPOINT_HEADER_LEN]; + int4store(buf, binlog_file_len); + return write_header(file, BINLOG_CHECKPOINT_HEADER_LEN + binlog_file_len) || + wrapper_my_b_safe_write(file, buf, BINLOG_CHECKPOINT_HEADER_LEN) || + wrapper_my_b_safe_write(file, (const uchar *)binlog_file_name, + binlog_file_len) || + write_footer(file); +} +#endif /* MYSQL_CLIENT */ + + /************************************************************************** Intvar_log_event methods **************************************************************************/ diff --git a/sql/log_event.h b/sql/log_event.h index 12d5e1417f4..c76e538618b 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -259,6 +259,7 @@ struct sql_ex_info #define INCIDENT_HEADER_LEN 2 #define HEARTBEAT_HEADER_LEN 0 #define ANNOTATE_ROWS_HEADER_LEN 0 +#define BINLOG_CHECKPOINT_HEADER_LEN 4 /* Max number of possible extra bytes in a replication event compared to a @@ -685,6 +686,14 @@ enum Log_event_type MARIA_EVENTS_BEGIN= 160, /* New Maria event numbers start from here */ ANNOTATE_ROWS_EVENT= 160, + /* + Binlog checkpoint event. Used for XA crash recovery on the master, not used + in replication. + A binlog checkpoint event specifies a binlog file such that XA crash + recovery can start from that file - and it is guaranteed to find all XIDs + that are prepared in storage engines but not yet committed. + */ + BINLOG_CHECKPOINT_EVENT= 161, /* Add new MariaDB events here - right above this comment! */ @@ -2892,6 +2901,32 @@ private: }; +class Binlog_checkpoint_log_event: public Log_event +{ +public: + char *binlog_file_name; + uint binlog_file_len; + +#ifdef MYSQL_SERVER + Binlog_checkpoint_log_event(const char *binlog_file_name_arg, + uint binlog_file_len_arg); +#ifdef HAVE_REPLICATION + void pack_info(Protocol *protocol); +#endif +#else + void print(FILE *file, PRINT_EVENT_INFO *print_event_info); +#endif + Binlog_checkpoint_log_event(const char *buf, uint event_len, + const Format_description_log_event *description_event); + ~Binlog_checkpoint_log_event() { my_free(binlog_file_name); } + Log_event_type get_type_code() { return BINLOG_CHECKPOINT_EVENT;} + int get_data_size() { return binlog_file_len + BINLOG_CHECKPOINT_HEADER_LEN;} + bool is_valid() const { return binlog_file_name != 0; } +#ifdef MYSQL_SERVER + bool write(IO_CACHE* file); +#endif +}; + /* the classes below are for the new LOAD DATA INFILE logging */ /** diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 91bc2bfe226..3c0f209235a 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -722,7 +722,7 @@ PSI_mutex_key key_PAGE_lock, key_LOCK_sync, key_LOCK_active, key_LOCK_pool; PSI_mutex_key key_LOCK_des_key_file; #endif /* HAVE_OPENSSL */ -PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_prep_xids, +PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_xid_list, key_delayed_insert_mutex, key_hash_filo_lock, key_LOCK_active_mi, key_LOCK_connection_count, key_LOCK_crypt, key_LOCK_delayed_create, key_LOCK_delayed_insert, key_LOCK_delayed_status, key_LOCK_error_log, @@ -763,7 +763,7 @@ static PSI_mutex_info all_server_mutexes[]= #endif /* HAVE_OPENSSL */ { &key_BINLOG_LOCK_index, "MYSQL_BIN_LOG::LOCK_index", 0}, - { &key_BINLOG_LOCK_prep_xids, "MYSQL_BIN_LOG::LOCK_prep_xids", 0}, + { &key_BINLOG_LOCK_xid_list, "MYSQL_BIN_LOG::LOCK_xid_list", 0}, { &key_RELAYLOG_LOCK_index, "MYSQL_RELAY_LOG::LOCK_index", 0}, { &key_delayed_insert_mutex, "Delayed_insert::mutex", 0}, { &key_hash_filo_lock, "hash_filo::lock", 0}, @@ -831,7 +831,7 @@ static PSI_rwlock_info all_server_rwlocks[]= PSI_cond_key key_PAGE_cond, key_COND_active, key_COND_pool; #endif /* HAVE_MMAP */ -PSI_cond_key key_BINLOG_COND_prep_xids, key_BINLOG_update_cond, +PSI_cond_key key_BINLOG_COND_xid_list, key_BINLOG_update_cond, key_COND_cache_status_changed, key_COND_manager, key_COND_rpl_status, key_COND_server_started, key_delayed_insert_cond, key_delayed_insert_cond_client, @@ -859,7 +859,7 @@ static PSI_cond_info all_server_conds[]= { &key_COND_pool, "TC_LOG_MMAP::COND_pool", 0}, { &key_TC_LOG_MMAP_COND_queue_busy, "TC_LOG_MMAP::COND_queue_busy", 0}, #endif /* HAVE_MMAP */ - { &key_BINLOG_COND_prep_xids, "MYSQL_BIN_LOG::COND_prep_xids", 0}, + { &key_BINLOG_COND_xid_list, "MYSQL_BIN_LOG::COND_xid_list", 0}, { &key_BINLOG_update_cond, "MYSQL_BIN_LOG::update_cond", 0}, { &key_BINLOG_COND_queue_busy, "MYSQL_BIN_LOG::COND_queue_busy", 0}, { &key_RELAYLOG_update_cond, "MYSQL_RELAY_LOG::update_cond", 0}, diff --git a/sql/mysqld.h b/sql/mysqld.h index 56419acdcd4..28c4d771a48 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -225,7 +225,7 @@ extern PSI_mutex_key key_PAGE_lock, key_LOCK_sync, key_LOCK_active, extern PSI_mutex_key key_LOCK_des_key_file; #endif -extern PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_prep_xids, +extern PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_xid_list, key_delayed_insert_mutex, key_hash_filo_lock, key_LOCK_active_mi, key_LOCK_connection_count, key_LOCK_crypt, key_LOCK_delayed_create, key_LOCK_delayed_insert, key_LOCK_delayed_status, key_LOCK_error_log, @@ -256,7 +256,7 @@ extern PSI_rwlock_key key_rwlock_LOCK_grant, key_rwlock_LOCK_logger, extern PSI_cond_key key_PAGE_cond, key_COND_active, key_COND_pool; #endif /* HAVE_MMAP */ -extern PSI_cond_key key_BINLOG_COND_prep_xids, key_BINLOG_update_cond, +extern PSI_cond_key key_BINLOG_COND_xid_list, key_BINLOG_update_cond, key_COND_cache_status_changed, key_COND_manager, key_COND_rpl_status, key_COND_server_started, key_delayed_insert_cond, key_delayed_insert_cond_client, diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index d7308eddb7f..079aab27101 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -623,6 +623,30 @@ send_event_to_slave(THD *thd, NET *net, String* const packet, ushort flags, } } + /* + Do not send binlog checkpoint events to a slave that does not understand it. + */ + if (unlikely(event_type == BINLOG_CHECKPOINT_EVENT) && + mariadb_slave_capability < MARIA_SLAVE_CAPABILITY_BINLOG_CHECKPOINT) + { + if (mariadb_slave_capability >= MARIA_SLAVE_CAPABILITY_TOLERATE_HOLES) + { + /* This slave can tolerate events omitted from the binlog stream. */ + return NULL; + } + else + { + /* + The slave does not understand BINLOG_CHECKPOINT_EVENT. Send a dummy + event instead, with same length so slave does not get confused about + binlog positions. + */ + if (Query_log_event::dummy_event(packet, ev_offset, current_checksum_alg)) + return "Failed to replace binlog checkpoint event with dummy: " + "too small event."; + } + } + /* Skip events with the @@skip_replication flag set, if slave requested skipping of such events. From 66c62de1034e780144e6945b3a2150253e2a652c Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Mon, 25 Jun 2012 18:39:26 +0400 Subject: [PATCH 099/289] MWL#182: Explain running statements - Remove out-of-date comments, add dbug assertions. --- sql/filesort.cc | 5 ----- sql/my_apc.cc | 5 ++--- sql/my_apc.h | 2 +- sql/sql_class.cc | 6 ++++-- sql/sql_select.cc | 7 +------ sql/sql_show.cc | 1 - 6 files changed, 8 insertions(+), 18 deletions(-) diff --git a/sql/filesort.cc b/sql/filesort.cc index 6d1cabb02b7..f9f7288c93f 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -1242,11 +1242,6 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file, status_var_increment(thd->status_var.filesort_merge_passes); thd->query_plan_fsort_passes++; - /*if (param->not_killable) - { - killed= ¬_killable; - not_killable= NOT_KILLED; - }*/ error=0; rec_length= param->rec_length; diff --git a/sql/my_apc.cc b/sql/my_apc.cc index d5e3eb080a2..eae2843edb4 100644 --- a/sql/my_apc.cc +++ b/sql/my_apc.cc @@ -86,7 +86,7 @@ void Apc_target::disable() void Apc_target::enqueue_request(Call_request *qe) { - //call_queue_size++; + mysql_mutex_assert_owner(LOCK_thd_data_ptr); if (apc_calls) { Call_request *after= apc_calls->prev; @@ -112,12 +112,11 @@ void Apc_target::enqueue_request(Call_request *qe) void Apc_target::dequeue_request(Call_request *qe) { - //call_queue_size--; + mysql_mutex_assert_owner(LOCK_thd_data_ptr); if (apc_calls == qe) { if ((apc_calls= apc_calls->next) == qe) { - //DBUG_ASSERT(!call_queue_size); apc_calls= NULL; } } diff --git a/sql/my_apc.h b/sql/my_apc.h index 5879a0070d6..450e07b92a4 100644 --- a/sql/my_apc.h +++ b/sql/my_apc.h @@ -28,7 +28,7 @@ class Apc_target { mysql_mutex_t *LOCK_thd_data_ptr; public: - Apc_target() : enabled(0), apc_calls(NULL) /*, call_queue_size(0)*/ {} + Apc_target() : enabled(0), apc_calls(NULL) {} ~Apc_target() { DBUG_ASSERT(!enabled && !apc_calls);} void init(mysql_mutex_t *target_mutex); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index d694afebc2c..5408b10c6b1 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -3333,12 +3333,14 @@ void THD::restore_active_arena(Query_arena *set, Query_arena *backup) void Show_explain_request::get_explain_data(void *arg) { Show_explain_request *req= (Show_explain_request*)arg; - //TODO: change mem_root to point to request_thd->mem_root. - // Actually, change the ARENA, because we're going to allocate items! Query_arena backup_arena; THD *target_thd= req->target_thd; bool printed_anything= FALSE; + /* + Change the arena because JOIN::print_explain and co. are going to allocate + items. Let them allocate them on our arena. + */ target_thd->set_n_backup_active_arena((Query_arena*)req->request_thd, &backup_arena); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 60530670ac9..c0e765b7991 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -10321,12 +10321,7 @@ void JOIN_TAB::cleanup() if (cache) { cache->free(); - cache= 0; // psergey: this is why we don't see "Using join cache" in SHOW EXPLAIN - // when it is run for "Using temporary+filesort" queries while they - // are at reading-from-tmp-table phase. - // - // TODO ask igor if this can be just moved to later phase - // (JOIN_CACHE objects themselves are not big, arent they) + cache= 0; } limit= 0; if (table) diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 9f0adf4a608..0671ebae199 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2092,7 +2092,6 @@ void mysqld_show_explain(THD *thd, ulong thread_id) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_YES, explain_req.query_str.c_ptr_safe()); } - //mysql_mutex_unlock(&tmp->LOCK_thd_data); if (!bres) { explain_buf->flush_data(); From 5f86ecbf362bc32ec86d7118288b305af74e2fb3 Mon Sep 17 00:00:00 2001 From: Kent Boortz Date: Tue, 26 Jun 2012 16:30:15 +0200 Subject: [PATCH 100/289] Solve a linkage problem with "libmysqld" on several Solaris platforms: a multiple definition of 'THD::clear_error()' in (at least) libmysqld.a(lib_sql.o) and libmysqld.a(libfederated_a-ha_federated.o). Patch provided by Ramil Kalimullin. --- libmysqld/lib_sql.cc | 6 ------ sql/sql_class.h | 3 +-- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc index 4afe02efbdb..18b8383406a 100644 --- a/libmysqld/lib_sql.cc +++ b/libmysqld/lib_sql.cc @@ -756,12 +756,6 @@ void THD::clear_data_list() cur_data= 0; } -void THD::clear_error() -{ - if (main_da.is_error()) - main_da.reset_diagnostics_area(); -} - static char *dup_str_aux(MEM_ROOT *root, const char *from, uint length, CHARSET_INFO *fromcs, CHARSET_INFO *tocs) { diff --git a/sql/sql_class.h b/sql/sql_class.h index 3ecf032db71..5cdb005b517 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -2089,7 +2089,6 @@ public: void add_changed_table(const char *key, long key_length); CHANGED_TABLE_LIST * changed_table_dup(const char *key, long key_length); int send_explain_fields(select_result *result); -#ifndef EMBEDDED_LIBRARY /** Clear the current error, if any. We do not clear is_fatal_error or is_fatal_sub_stmt_error since we @@ -2105,9 +2104,9 @@ public: is_slave_error= 0; DBUG_VOID_RETURN; } +#ifndef EMBEDDED_LIBRARY inline bool vio_ok() const { return net.vio != 0; } #else - void clear_error(); inline bool vio_ok() const { return true; } #endif /** From 1b84c0cfee4db6f0a6c97459a47444ed1f0d6ce1 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 26 Jun 2012 21:43:34 +0300 Subject: [PATCH 101/289] Fix for LP bug#1007622 TABLE_LIST::check_single_table made aware about fact that now if table attached to a merged view it can be (unopened) temporary table (in 5.2 it was always leaf table or non (in case of several tables)). --- mysql-test/r/view.result | 13 +++++++++++++ mysql-test/t/view.test | 13 +++++++++++++ sql/table.cc | 9 ++++++++- 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 86ebc9a8ee7..56598583bb6 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -4472,6 +4472,19 @@ INSERT INTO t2 VALUES (1); DROP TRIGGER tr; DROP VIEW v1; DROP TABLE t1,t2,t3; +# +# LP bug#1007622 Server crashes in handler::increment_statistics on +# inserting into a view over a view +# +CREATE TABLE t1 (a INT); +CREATE ALGORITHM=MERGE VIEW v1 AS SELECT a1.* FROM t1 AS a1, t1 AS a2; +CREATE ALGORITHM=MERGE VIEW v2 AS SELECT * FROM v1; +INSERT INTO v2 (a) VALUES (1) ; +select * from t1; +a +1 +drop view v2,v1; +drop table t1; # ----------------------------------------------------------------- # -- End of 5.3 tests. # ----------------------------------------------------------------- diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 93e0cce8a5d..6f11d6909ea 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -4420,6 +4420,19 @@ DROP TRIGGER tr; DROP VIEW v1; DROP TABLE t1,t2,t3; +--echo # +--echo # LP bug#1007622 Server crashes in handler::increment_statistics on +--echo # inserting into a view over a view +--echo # + +CREATE TABLE t1 (a INT); +CREATE ALGORITHM=MERGE VIEW v1 AS SELECT a1.* FROM t1 AS a1, t1 AS a2; +CREATE ALGORITHM=MERGE VIEW v2 AS SELECT * FROM v1; +INSERT INTO v2 (a) VALUES (1) ; +select * from t1; +drop view v2,v1; +drop table t1; + --echo # ----------------------------------------------------------------- --echo # -- End of 5.3 tests. --echo # ----------------------------------------------------------------- diff --git a/sql/table.cc b/sql/table.cc index 05fb5593842..2eb7eca6fb0 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -4041,7 +4041,14 @@ bool TABLE_LIST::check_single_table(TABLE_LIST **table_arg, tbl; tbl= tbl->next_local) { - if (tbl->table) + /* + Merged view has also temporary table attached (in 5.2 if it has table + then it was real table), so we have filter such temporary tables out + by checking that it is not merged view + */ + if (tbl->table && + !(tbl->is_view() && + tbl->is_merged_derived())) { if (tbl->table->map & map) { From c62c0c551684d063e51024579a4956f66048bbf5 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Thu, 28 Jun 2012 13:58:37 +0400 Subject: [PATCH 102/289] MWL#182: Explain running statements: address review feedback - Add Monty Program Ab copyright in new files - Change Apc_target::make_apc_call() to accept a C++-style functor (instead of C-style function + parameter) --- sql/my_apc.cc | 25 ++++++++++++++++++------- sql/my_apc.h | 30 ++++++++++++++++++++++-------- sql/sql_class.cc | 23 +++++++++++------------ sql/sql_class.h | 9 +++++---- sql/sql_show.cc | 4 +--- 5 files changed, 57 insertions(+), 34 deletions(-) diff --git a/sql/my_apc.cc b/sql/my_apc.cc index eae2843edb4..212fbd0f6cb 100644 --- a/sql/my_apc.cc +++ b/sql/my_apc.cc @@ -1,6 +1,18 @@ /* - TODO: MP AB Copyright -*/ + Copyright (c) 2009, 2011, Monty Program 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 */ #ifdef MY_APC_STANDALONE @@ -139,8 +151,8 @@ void Apc_target::dequeue_request(Call_request *qe) to use thd->enter_cond() calls to be killable) */ -bool Apc_target::make_apc_call(apc_func_t func, void *func_arg, - int timeout_sec, bool *timed_out) +bool Apc_target::make_apc_call(Apc_call *call, int timeout_sec, + bool *timed_out) { bool res= TRUE; *timed_out= FALSE; @@ -149,8 +161,7 @@ bool Apc_target::make_apc_call(apc_func_t func, void *func_arg, { /* Create and post the request */ Call_request apc_request; - apc_request.func= func; - apc_request.func_arg= func_arg; + apc_request.call= call; apc_request.processed= FALSE; mysql_cond_init(0 /* do not track in PS */, &apc_request.COND_request, NULL); enqueue_request(&apc_request); @@ -229,7 +240,7 @@ void Apc_target::process_apc_requests() dequeue_request(request); request->processed= TRUE; - request->func(request->func_arg); + request->call->call_in_target_thread(); request->what="func called by process_apc_requests"; #ifndef DBUG_OFF diff --git a/sql/my_apc.h b/sql/my_apc.h index 450e07b92a4..3d9a2154af2 100644 --- a/sql/my_apc.h +++ b/sql/my_apc.h @@ -1,6 +1,18 @@ /* - TODO: MP AB Copyright -*/ + Copyright (c) 2009, 2011, Monty Program 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 */ /* Interface @@ -38,8 +50,12 @@ public: void process_apc_requests(); - typedef void (*apc_func_t)(void *arg); - + class Apc_call + { + public: + virtual void call_in_target_thread()= 0; + virtual ~Apc_call() {} + }; /* Make an APC call: schedule it for execution and wait until the target thread has executed it. This function must not be called from a thread @@ -49,8 +65,7 @@ public: @retval TRUE - Call wasnt made (either the target is in disabled state or timeout occured) */ - bool make_apc_call(apc_func_t func, void *func_arg, - int timeout_sec, bool *timed_out); + bool make_apc_call(Apc_call *call, int timeout_sec, bool *timed_out); #ifndef DBUG_OFF int n_calls_processed; /* Number of calls served by this target */ @@ -78,8 +93,7 @@ private: class Call_request { public: - apc_func_t func; /* Function to call */ - void *func_arg; /* Argument to pass it */ + Apc_call *call; /* Functor to be called */ /* The caller will actually wait for "processed==TRUE" */ bool processed; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 5408b10c6b1..35cc28bcae7 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -3330,33 +3330,32 @@ void THD::restore_active_arena(Query_arena *set, Query_arena *backup) we're producing EXPLAIN for. */ -void Show_explain_request::get_explain_data(void *arg) +void Show_explain_request::call_in_target_thread() { - Show_explain_request *req= (Show_explain_request*)arg; Query_arena backup_arena; - THD *target_thd= req->target_thd; bool printed_anything= FALSE; /* Change the arena because JOIN::print_explain and co. are going to allocate items. Let them allocate them on our arena. */ - target_thd->set_n_backup_active_arena((Query_arena*)req->request_thd, + target_thd->set_n_backup_active_arena((Query_arena*)request_thd, &backup_arena); - req->query_str.copy(target_thd->query(), - target_thd->query_length(), - &my_charset_bin); + query_str.copy(target_thd->query(), + target_thd->query_length(), + &my_charset_bin); - if (target_thd->lex->unit.print_explain(req->explain_buf, 0 /* explain flags*/, + if (target_thd->lex->unit.print_explain(explain_buf, 0 /* explain flags*/, &printed_anything)) - req->failed_to_produce= TRUE; + { + failed_to_produce= TRUE; + } if (!printed_anything) - req->failed_to_produce= TRUE; + failed_to_produce= TRUE; - target_thd->restore_active_arena((Query_arena*)req->request_thd, - &backup_arena); + target_thd->restore_active_arena((Query_arena*)request_thd, &backup_arena); } diff --git a/sql/sql_class.h b/sql/sql_class.h index bfbc9e86611..73123151738 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1528,11 +1528,11 @@ class select_result_explain_buffer; The thread that runs SHOW EXPLAIN statement creates a Show_explain_request object R, and then schedules APC call of - Show_explain_request::get_explain_data((void*)&R). + Show_explain_request::call((void*)&R). */ -class Show_explain_request +class Show_explain_request : public Apc_target::Apc_call { public: THD *target_thd; /* thd that we're running SHOW EXPLAIN for */ @@ -1546,8 +1546,9 @@ public: /* Query that we've got SHOW EXPLAIN for */ String query_str; - - static void get_explain_data(void *arg); + + /* Overloaded virtual function */ + void call_in_target_thread(); }; class THD; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 0671ebae199..145f4fbebcc 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2065,9 +2065,7 @@ void mysqld_show_explain(THD *thd, ulong thread_id) explain_req.failed_to_produce= FALSE; /* Ok, we have a lock on target->LOCK_thd_data, can call: */ - bres= tmp->apc_target.make_apc_call(Show_explain_request::get_explain_data, - (void*)&explain_req, - timeout_sec, &timed_out); + bres= tmp->apc_target.make_apc_call(&explain_req, timeout_sec, &timed_out); if (bres || explain_req.failed_to_produce) { From 84fd4e2542fa6483c20c27127294c83211888e9f Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Thu, 28 Jun 2012 16:46:24 +0400 Subject: [PATCH 103/289] MWL#182: Explain running statements: address review feedback - Move standalone tests to a unittest. - Added comments. --- CMakeLists.txt | 1 + sql/my_apc.cc | 158 ++-------------------------- sql/my_apc.h | 15 +-- unittest/sql/CMakeLists.txt | 3 + unittest/sql/my_apc-t.cc | 201 ++++++++++++++++++++++++++++++++++++ 5 files changed, 221 insertions(+), 157 deletions(-) create mode 100644 unittest/sql/CMakeLists.txt create mode 100644 unittest/sql/my_apc-t.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 8b0c4898785..ec8c602761a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -279,6 +279,7 @@ IF(WITH_UNIT_TESTS) ADD_SUBDIRECTORY(unittest/strings) ADD_SUBDIRECTORY(unittest/examples) ADD_SUBDIRECTORY(unittest/mysys) + ADD_SUBDIRECTORY(unittest/sql) ENDIF() IF(NOT WITHOUT_SERVER) diff --git a/sql/my_apc.cc b/sql/my_apc.cc index 212fbd0f6cb..48d539aed78 100644 --- a/sql/my_apc.cc +++ b/sql/my_apc.cc @@ -15,22 +15,13 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifdef MY_APC_STANDALONE - -#include -#include -#include - -#include "my_apc.h" - -#else +#ifndef MY_APC_STANDALONE #include "sql_priv.h" #include "sql_class.h" #endif - /* Standalone testing: g++ -c -DMY_APC_STANDALONE -g -I.. -I../include -o my_apc.o my_apc.cc @@ -140,12 +131,19 @@ void Apc_target::dequeue_request(Call_request *qe) /* Make an APC (Async Procedure Call) to another thread. + + @detail + Make an APC call: schedule it for execution and wait until the target + thread has executed it. - - The caller is responsible for making sure he's not calling to the same - thread. + - The caller is responsible for making sure he's not posting request + to the thread he's calling this function from. - - The caller should have locked target_thread_mutex. + - The caller must have locked target_mutex. The function will release it. + @retval FALSE - Ok, the call has been made + @retval TRUE - Call wasnt made (either the target is in disabled state or + timeout occured) psergey-todo: Should waits here be KILLable? (it seems one needs to use thd->enter_cond() calls to be killable) @@ -251,137 +249,3 @@ void Apc_target::process_apc_requests() } } -/***************************************************************************** - * Testing - *****************************************************************************/ -#ifdef MY_APC_STANDALONE - -volatile bool started= FALSE; -volatile bool service_should_exit= FALSE; -volatile bool requestors_should_exit=FALSE; - -volatile int apcs_served= 0; -volatile int apcs_missed=0; -volatile int apcs_timed_out=0; - -Apc_target apc_target; -mysql_mutex_t target_mutex; - -int int_rand(int size) -{ - return round (((double)rand() / RAND_MAX) * size); -} - -/* An APC-serving thread */ -void *test_apc_service_thread(void *ptr) -{ - my_thread_init(); - mysql_mutex_init(0, &target_mutex, MY_MUTEX_INIT_FAST); - apc_target.init(&target_mutex); - apc_target.enable(); - started= TRUE; - fprintf(stderr, "# test_apc_service_thread started\n"); - while (!service_should_exit) - { - //apc_target.disable(); - usleep(10000); - //apc_target.enable(); - for (int i = 0; i < 10 && !service_should_exit; i++) - { - apc_target.process_apc_requests(); - usleep(int_rand(30)); - } - } - apc_target.disable(); - apc_target.destroy(); - my_thread_end(); - pthread_exit(0); -} - -class Apc_order -{ -public: - int value; // The value - int *where_to; // Where to write it - Apc_order(int a, int *b) : value(a), where_to(b) {} -}; - -void test_apc_func(void *arg) -{ - Apc_order *order=(Apc_order*)arg; - usleep(int_rand(1000)); - *(order->where_to) = order->value; - __sync_fetch_and_add(&apcs_served, 1); -} - -void *test_apc_requestor_thread(void *ptr) -{ - my_thread_init(); - fprintf(stderr, "# test_apc_requestor_thread started\n"); - while (!requestors_should_exit) - { - int dst_value= 0; - int src_value= int_rand(4*1000*100); - /* Create APC to do dst_value= src_value */ - Apc_order apc_order(src_value, &dst_value); - bool timed_out; - - bool res= apc_target.make_apc_call(test_apc_func, (void*)&apc_order, 60, &timed_out); - if (res) - { - if (timed_out) - __sync_fetch_and_add(&apcs_timed_out, 1); - else - __sync_fetch_and_add(&apcs_missed, 1); - - if (dst_value != 0) - fprintf(stderr, "APC was done even though return value says it wasnt!\n"); - } - else - { - if (dst_value != src_value) - fprintf(stderr, "APC was not done even though return value says it was!\n"); - } - //usleep(300); - } - fprintf(stderr, "# test_apc_requestor_thread exiting\n"); - my_thread_end(); -} - -const int N_THREADS=23; -int main(int args, char **argv) -{ - pthread_t service_thr; - pthread_t request_thr[N_THREADS]; - int i, j; - my_thread_global_init(); - - pthread_create(&service_thr, NULL, test_apc_service_thread, (void*)NULL); - while (!started) - usleep(1000); - for (i = 0; i < N_THREADS; i++) - pthread_create(&request_thr[i], NULL, test_apc_requestor_thread, (void*)NULL); - - for (i = 0; i < 15; i++) - { - usleep(500*1000); - fprintf(stderr, "# %d APCs served %d missed\n", apcs_served, apcs_missed); - } - fprintf(stderr, "# Shutting down requestors\n"); - requestors_should_exit= TRUE; - for (i = 0; i < N_THREADS; i++) - pthread_join(request_thr[i], NULL); - - fprintf(stderr, "# Shutting down service\n"); - service_should_exit= TRUE; - pthread_join(service_thr, NULL); - fprintf(stderr, "# Done.\n"); - my_thread_end(); - my_thread_global_end(); - return 0; -} - -#endif // MY_APC_STANDALONE - - - diff --git a/sql/my_apc.h b/sql/my_apc.h index 3d9a2154af2..99861ca3194 100644 --- a/sql/my_apc.h +++ b/sql/my_apc.h @@ -49,22 +49,17 @@ public: void disable(); void process_apc_requests(); - + + /* Functor class for calls you can schedule */ class Apc_call { public: + /* This function will be called in the target thread */ virtual void call_in_target_thread()= 0; virtual ~Apc_call() {} }; - /* - Make an APC call: schedule it for execution and wait until the target - thread has executed it. This function must not be called from a thread - that's different from the target thread. - - @retval FALSE - Ok, the call has been made - @retval TRUE - Call wasnt made (either the target is in disabled state or - timeout occured) - */ + + /* Make a call in the target thread (see function definition for details) */ bool make_apc_call(Apc_call *call, int timeout_sec, bool *timed_out); #ifndef DBUG_OFF diff --git a/unittest/sql/CMakeLists.txt b/unittest/sql/CMakeLists.txt new file mode 100644 index 00000000000..36b14e9a08a --- /dev/null +++ b/unittest/sql/CMakeLists.txt @@ -0,0 +1,3 @@ + +MY_ADD_TESTS(my_apc LINK_LIBRARIES mysys EXT cc) + diff --git a/unittest/sql/my_apc-t.cc b/unittest/sql/my_apc-t.cc new file mode 100644 index 00000000000..ada09a1675c --- /dev/null +++ b/unittest/sql/my_apc-t.cc @@ -0,0 +1,201 @@ +/* + Copyright (c) 2012, Monty Program 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 */ + +/* + This file does standalone APC system tests. +*/ +#include +#include +#include +#include + +#include + +#include "../sql/my_apc.h" + +#define MY_APC_STANDALONE 1 +#include "../sql/my_apc.cc" + +volatile bool started= FALSE; +volatile bool service_should_exit= FALSE; +volatile bool requestors_should_exit=FALSE; + +/* Counters for APC calls */ +int apcs_served= 0; +int apcs_missed=0; +int apcs_timed_out=0; +mysql_mutex_t apc_counters_mutex; + +inline void increment_counter(int *var) +{ + mysql_mutex_lock(&apc_counters_mutex); + *var= *var+1; + mysql_mutex_unlock(&apc_counters_mutex); +} + +volatile bool have_errors= false; + +Apc_target apc_target; +mysql_mutex_t target_mutex; + +int int_rand(int size) +{ + return round (((double)rand() / RAND_MAX) * size); +} + +/* + APC target thread (the one that will serve the APC requests). We will have + one target. +*/ +void *test_apc_service_thread(void *ptr) +{ + my_thread_init(); + mysql_mutex_init(0, &target_mutex, MY_MUTEX_INIT_FAST); + apc_target.init(&target_mutex); + apc_target.enable(); + started= TRUE; + fprintf(stderr, "# test_apc_service_thread started\n"); + while (!service_should_exit) + { + //apc_target.disable(); + usleep(10000); + //apc_target.enable(); + for (int i = 0; i < 10 && !service_should_exit; i++) + { + apc_target.process_apc_requests(); + usleep(int_rand(30)); + } + } + apc_target.disable(); + apc_target.destroy(); + mysql_mutex_destroy(&target_mutex); + my_thread_end(); + pthread_exit(0); +} + + +/* + One APC request (to write 'value' into *where_to) +*/ +class Apc_order : public Apc_target::Apc_call +{ +public: + int value; // The value + int *where_to; // Where to write it + Apc_order(int a, int *b) : value(a), where_to(b) {} + + void call_in_target_thread() + { + usleep(int_rand(1000)); + *where_to = value; + increment_counter(&apcs_served); + } +}; + + +/* + APC requestor thread. It makes APC requests, and checks if they were actually + executed. +*/ +void *test_apc_requestor_thread(void *ptr) +{ + my_thread_init(); + fprintf(stderr, "# test_apc_requestor_thread started\n"); + while (!requestors_should_exit) + { + int dst_value= 0; + int src_value= int_rand(4*1000*100); + /* Create an APC to do "dst_value= src_value" assignment */ + Apc_order apc_order(src_value, &dst_value); + bool timed_out; + + mysql_mutex_lock(&target_mutex); + bool res= apc_target.make_apc_call(&apc_order, 60, &timed_out); + if (res) + { + if (timed_out) + increment_counter(&apcs_timed_out); + else + increment_counter(&apcs_missed); + + if (dst_value != 0) + { + fprintf(stderr, "APC was done even though return value says it wasnt!\n"); + have_errors= true; + } + } + else + { + if (dst_value != src_value) + { + fprintf(stderr, "APC was not done even though return value says it was!\n"); + have_errors= true; + } + } + //usleep(300); + } + fprintf(stderr, "# test_apc_requestor_thread exiting\n"); + my_thread_end(); + return NULL; +} + +/* Number of APC requestor threads */ +const int N_THREADS=23; + + +int main(int args, char **argv) +{ + pthread_t service_thr; + pthread_t request_thr[N_THREADS]; + int i; + + my_thread_global_init(); + + mysql_mutex_init(0, &apc_counters_mutex, MY_MUTEX_INIT_FAST); + + plan(1); + diag("Testing APC delivery and execution"); + + pthread_create(&service_thr, NULL, test_apc_service_thread, (void*)NULL); + while (!started) + usleep(1000); + for (i = 0; i < N_THREADS; i++) + pthread_create(&request_thr[i], NULL, test_apc_requestor_thread, (void*)NULL); + + for (i = 0; i < 15; i++) + { + usleep(500*1000); + fprintf(stderr, "# %d APCs served %d missed\n", apcs_served, apcs_missed); + } + fprintf(stderr, "# Shutting down requestors\n"); + requestors_should_exit= TRUE; + for (i = 0; i < N_THREADS; i++) + pthread_join(request_thr[i], NULL); + + fprintf(stderr, "# Shutting down service\n"); + service_should_exit= TRUE; + pthread_join(service_thr, NULL); + + mysql_mutex_destroy(&apc_counters_mutex); + + fprintf(stderr, "# Done.\n"); + my_thread_end(); + my_thread_global_end(); + + ok1(!have_errors); + return exit_status(); +} + From 247262347e00b1fa3e827b174b765564d6be3b1a Mon Sep 17 00:00:00 2001 From: Evgeny Potemkin Date: Thu, 28 Jun 2012 16:53:45 +0400 Subject: [PATCH 104/289] Bug#14248833: UPDATE ON INNODB TABLE ENTERS RECURSION Introduction of cost based decision on filesort vs index for UPDATE statements changed detection of the fact that the index used to scan the table is being updated. The new design missed the case of index merge when there is no single index to check. That was worked until a recent change in InnoDB after which it went into infinite recursion if update of the used index wasn't properly detected. The fix consists of 'used key being updated' detection code from 5.1. sql/sql_update.cc: Bug#14248833: UPDATE ON INNODB TABLE ENTERS RECURSION The check for used key being updated is extended to cover the case when index merge is used. --- sql/sql_update.cc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 754170e4c55..c4a95edcfc2 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -450,6 +450,15 @@ int mysql_update(THD *thd, { // Check if we are modifying a key that we are used to search with: used_key_is_modified= is_key_used(table, used_index, table->write_set); } + else if (select && select->quick) + { + /* + select->quick != NULL and used_index == MAX_KEY happens for index + merge and should be handled in a different way. + */ + used_key_is_modified= (!select->quick->unique_key_range() && + select->quick->is_keys_used(table->write_set)); + } #ifdef WITH_PARTITION_STORAGE_ENGINE if (used_key_is_modified || order || From 94bf016321825209353b41c03e0ea8399787303e Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Thu, 28 Jun 2012 17:34:26 +0400 Subject: [PATCH 105/289] sql_select.cc: work compiler warnings my_apc-t.cc: make it compile on Windows. --- sql/sql_select.cc | 5 ++--- unittest/sql/my_apc-t.cc | 14 +++++++------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index c0e765b7991..5cd7430050b 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -15804,12 +15804,11 @@ do_select(JOIN *join,List *fields,TABLE *table,Procedure *procedure) { DBUG_ASSERT(join->table_count); - THD *thd= join->thd; DBUG_EXECUTE_IF("show_explain_probe_do_select", - if (dbug_user_var_equals_int(thd, + if (dbug_user_var_equals_int(join->thd, "show_explain_probe_select_id", join->select_lex->select_number)) - dbug_serve_apcs(thd, 1); + dbug_serve_apcs(join->thd, 1); ); if (join->outer_ref_cond && !join->outer_ref_cond->val_int()) diff --git a/unittest/sql/my_apc-t.cc b/unittest/sql/my_apc-t.cc index ada09a1675c..741cfbdb124 100644 --- a/unittest/sql/my_apc-t.cc +++ b/unittest/sql/my_apc-t.cc @@ -53,7 +53,7 @@ mysql_mutex_t target_mutex; int int_rand(int size) { - return round (((double)rand() / RAND_MAX) * size); + return (int) (0.5 + ((double)rand() / RAND_MAX) * size); } /* @@ -71,12 +71,12 @@ void *test_apc_service_thread(void *ptr) while (!service_should_exit) { //apc_target.disable(); - usleep(10000); + my_sleep(10000); //apc_target.enable(); for (int i = 0; i < 10 && !service_should_exit; i++) { apc_target.process_apc_requests(); - usleep(int_rand(30)); + my_sleep(int_rand(30)); } } apc_target.disable(); @@ -99,7 +99,7 @@ public: void call_in_target_thread() { - usleep(int_rand(1000)); + my_sleep(int_rand(1000)); *where_to = value; increment_counter(&apcs_served); } @@ -145,7 +145,7 @@ void *test_apc_requestor_thread(void *ptr) have_errors= true; } } - //usleep(300); + //my_sleep(300); } fprintf(stderr, "# test_apc_requestor_thread exiting\n"); my_thread_end(); @@ -171,13 +171,13 @@ int main(int args, char **argv) pthread_create(&service_thr, NULL, test_apc_service_thread, (void*)NULL); while (!started) - usleep(1000); + my_sleep(1000); for (i = 0; i < N_THREADS; i++) pthread_create(&request_thr[i], NULL, test_apc_requestor_thread, (void*)NULL); for (i = 0; i < 15; i++) { - usleep(500*1000); + my_sleep(500*1000); fprintf(stderr, "# %d APCs served %d missed\n", apcs_served, apcs_missed); } fprintf(stderr, "# Shutting down requestors\n"); From 107c894a540d147338ab4e737eb9ef76e49c3493 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Thu, 28 Jun 2012 18:38:55 +0300 Subject: [PATCH 106/289] Bug #13708485: malformed resultset packet crashes client Several fixes : * sql-common/client.c Added a validity check of the fields metadata packet sent by the server. Now libmysql will check if the length of the data sent by the server matches what's expected by the protocol before using the data. * client/mysqltest.cc Fixed the error handling code in mysqltest to avoid sending new commands when the reading the result set failed (and there are unread data in the pipe). * sql_common.h + libmysql/libmysql.c + sql-common/client.c unpack_fields() now generates a proper error when it fails. Added a new argument to this function to support the error generation. * sql/protocol.cc Added a debug trigger to cause the server to send a NULL insted of the packet expected by the client for testing purposes. --- client/mysqltest.cc | 4 +++- include/sql_common.h | 8 +++++--- libmysql/libmysql.c | 8 ++++---- sql-common/client.c | 15 ++++++++++++--- sql/protocol.cc | 4 +++- 5 files changed, 27 insertions(+), 12 deletions(-) diff --git a/client/mysqltest.cc b/client/mysqltest.cc index 593bb8ea290..e595493ccf0 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. 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 @@ -6848,6 +6848,8 @@ void run_query_normal(struct st_connection *cn, struct st_command *command, */ if ((counter==0) && mysql_read_query_result(mysql)) { + /* we've failed to collect the result set */ + cn->pending= TRUE; handle_error(command, mysql_errno(mysql), mysql_error(mysql), mysql_sqlstate(mysql), ds); goto end; diff --git a/include/sql_common.h b/include/sql_common.h index 9e43d076ba9..b64277ce7e1 100644 --- a/include/sql_common.h +++ b/include/sql_common.h @@ -1,4 +1,5 @@ -/* Copyright (C) 2003-2004, 2006 MySQL AB +/* + Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. 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 @@ -23,8 +24,9 @@ extern "C" { #endif extern CHARSET_INFO *default_client_charset_info; -MYSQL_FIELD *unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields, - my_bool default_value, uint server_capabilities); +MYSQL_FIELD *unpack_fields(MYSQL *mysql, MYSQL_DATA *data,MEM_ROOT *alloc, + uint fields, my_bool default_value, + uint server_capabilities); void free_rows(MYSQL_DATA *cur); void free_old_query(MYSQL *mysql); void end_server(MYSQL *mysql); diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 562da594fea..5d153317150 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. 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 @@ -1254,7 +1254,7 @@ MYSQL_FIELD *cli_list_fields(MYSQL *mysql) return NULL; mysql->field_count= (uint) query->rows; - return unpack_fields(query,&mysql->field_alloc, + return unpack_fields(mysql, query,&mysql->field_alloc, mysql->field_count, 1, mysql->server_capabilities); } @@ -1314,7 +1314,7 @@ mysql_list_processes(MYSQL *mysql) if (!(fields = (*mysql->methods->read_rows)(mysql,(MYSQL_FIELD*) 0, protocol_41(mysql) ? 7 : 5))) DBUG_RETURN(NULL); - if (!(mysql->fields=unpack_fields(fields,&mysql->field_alloc,field_count,0, + if (!(mysql->fields=unpack_fields(mysql, fields,&mysql->field_alloc,field_count,0, mysql->server_capabilities))) DBUG_RETURN(0); mysql->status=MYSQL_STATUS_GET_RESULT; @@ -1891,7 +1891,7 @@ my_bool cli_read_prepare_result(MYSQL *mysql, MYSQL_STMT *stmt) if (!(fields_data= (*mysql->methods->read_rows)(mysql,(MYSQL_FIELD*)0,7))) DBUG_RETURN(1); - if (!(stmt->fields= unpack_fields(fields_data,&stmt->mem_root, + if (!(stmt->fields= unpack_fields(mysql, fields_data,&stmt->mem_root, field_count,0, mysql->server_capabilities))) DBUG_RETURN(1); diff --git a/sql-common/client.c b/sql-common/client.c index 0df7c242969..51911d913c7 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -1,5 +1,5 @@ /* - Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. 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 @@ -1268,7 +1268,7 @@ static void cli_fetch_lengths(ulong *to, MYSQL_ROW column, ***************************************************************************/ MYSQL_FIELD * -unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields, +unpack_fields(MYSQL *mysql, MYSQL_DATA *data,MEM_ROOT *alloc,uint fields, my_bool default_value, uint server_capabilities) { MYSQL_ROWS *row; @@ -1281,6 +1281,7 @@ unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields, if (!result) { free_rows(data); /* Free old data */ + set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate); DBUG_RETURN(0); } bzero((char*) field, (uint) sizeof(MYSQL_FIELD)*fields); @@ -1308,6 +1309,14 @@ unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields, field->org_name_length= lengths[5]; /* Unpack fixed length parts */ + if (lengths[6] != 12) + { + /* malformed packet. signal an error. */ + free_rows(data); /* Free old data */ + set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate); + DBUG_RETURN(0); + } + pos= (uchar*) row->data[6]; field->charsetnr= uint2korr(pos); field->length= (uint) uint4korr(pos+2); @@ -2868,7 +2877,7 @@ get_info: if (!(fields=cli_read_rows(mysql,(MYSQL_FIELD*)0, protocol_41(mysql) ? 7:5))) DBUG_RETURN(1); - if (!(mysql->fields=unpack_fields(fields,&mysql->field_alloc, + if (!(mysql->fields=unpack_fields(mysql, fields,&mysql->field_alloc, (uint) field_count,0, mysql->server_capabilities))) DBUG_RETURN(1); diff --git a/sql/protocol.cc b/sql/protocol.cc index 5a727d94c46..a74f6084df4 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. 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 @@ -620,6 +620,8 @@ bool Protocol::send_fields(List *list, uint flags) /* Store fixed length fields */ pos= (char*) local_packet->ptr()+local_packet->length(); *pos++= 12; // Length of packed fields + /* inject a NULL to test the client */ + DBUG_EXECUTE_IF("poison_rs_fields", pos[-1]= 0xfb;); if (item->collation.collation == &my_charset_bin || thd_charset == NULL) { /* No conversion */ From 59c79cc5d0f1dab2db65f3d55ffe6a5a777b85c1 Mon Sep 17 00:00:00 2001 From: Joerg Bruehe Date: Thu, 28 Jun 2012 20:03:53 +0200 Subject: [PATCH 107/289] Bug#65745: UPDATE ON INNODB TABLE ENTERS RECURSION Introduction of cost based decision on filesort vs index for UPDATE statements changed detection of the fact that the index used to scan the table is being updated. The new design missed the case of index merge when there is no single index to check. That was worked until a recent change in InnoDB after which it went into infinite recursion if update of the used index wasn't properly detected. The fix consists of 'used key being updated' detection code from 5.1. Patch done by Evgeny Potemkin and transferred into the 5.5.25a release build by Joerg Bruehe. This changeset is the difference between MySQL 5.5.25 and 5.5.25a. VERSION: Version number change. sql/sql_update.cc: Bug#65745: UPDATE ON INNODB TABLE ENTERS RECURSION The check for used key being updated is extended to cover the case when index merge is used. --- VERSION | 2 +- sql/sql_update.cc | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 6111f6d453f..48e6c183915 100644 --- a/VERSION +++ b/VERSION @@ -1,4 +1,4 @@ MYSQL_VERSION_MAJOR=5 MYSQL_VERSION_MINOR=5 -MYSQL_VERSION_PATCH=25 +MYSQL_VERSION_PATCH=25a MYSQL_VERSION_EXTRA= diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 754170e4c55..c4a95edcfc2 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -450,6 +450,15 @@ int mysql_update(THD *thd, { // Check if we are modifying a key that we are used to search with: used_key_is_modified= is_key_used(table, used_index, table->write_set); } + else if (select && select->quick) + { + /* + select->quick != NULL and used_index == MAX_KEY happens for index + merge and should be handled in a different way. + */ + used_key_is_modified= (!select->quick->unique_key_range() && + select->quick->is_keys_used(table->write_set)); + } #ifdef WITH_PARTITION_STORAGE_ENGINE if (used_key_is_modified || order || From 6058319dba910576e00b0b566697b95aff6cb52c Mon Sep 17 00:00:00 2001 From: Yasufumi Kinoshita Date: Fri, 29 Jun 2012 12:04:44 +0900 Subject: [PATCH 108/289] Bug#14251529 : FIX FOR BUG 13704145 CREATES POSSIBLE RACE CONDITION make buf_read_page_low() to treat DB_TABLESPACE_DELETED error correctly rb#1129 approved by Inaam --- storage/innobase/buf/buf0buf.c | 9 ++++-- storage/innobase/buf/buf0lru.c | 14 +++++++++ storage/innobase/buf/buf0rea.c | 48 +++++++++++++++++++++++++++++- storage/innobase/include/buf0buf.h | 5 ++-- 4 files changed, 70 insertions(+), 6 deletions(-) diff --git a/storage/innobase/buf/buf0buf.c b/storage/innobase/buf/buf0buf.c index fed07129b65..32d376136e6 100644 --- a/storage/innobase/buf/buf0buf.c +++ b/storage/innobase/buf/buf0buf.c @@ -3470,9 +3470,10 @@ buf_mark_space_corrupt( /********************************************************************//** Completes an asynchronous read or write request of a file page to or from -the buffer pool. */ +the buffer pool. +@return TRUE if successful */ UNIV_INTERN -void +ibool buf_page_io_complete( /*=================*/ buf_page_t* bpage) /*!< in: pointer to the block in question */ @@ -3599,7 +3600,7 @@ corrupt: table as corrupted instead of crashing server */ if (bpage->space > TRX_SYS_SPACE && buf_mark_space_corrupt(bpage)) { - return; + return(FALSE); } else { fputs("InnoDB: Ending processing" " because of" @@ -3689,6 +3690,8 @@ corrupt: mutex_exit(buf_page_get_mutex(bpage)); buf_pool_mutex_exit(buf_pool); + + return(TRUE); } /*********************************************************************//** diff --git a/storage/innobase/buf/buf0lru.c b/storage/innobase/buf/buf0lru.c index 8e787fdba17..7c8100df58e 100644 --- a/storage/innobase/buf/buf0lru.c +++ b/storage/innobase/buf/buf0lru.c @@ -2164,9 +2164,23 @@ buf_LRU_free_one_page( be in a state where it can be freed; there may or may not be a hash index to the page */ { +#ifdef UNIV_DEBUG + buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); +#endif + mutex_t* block_mutex = buf_page_get_mutex(bpage); + + ut_ad(buf_pool_mutex_own(buf_pool)); + ut_ad(mutex_own(block_mutex)); + if (buf_LRU_block_remove_hashed_page(bpage, TRUE) != BUF_BLOCK_ZIP_FREE) { buf_LRU_block_free_hashed_page((buf_block_t*) bpage); + } else { + /* The block_mutex should have been released by + buf_LRU_block_remove_hashed_page() when it returns + BUF_BLOCK_ZIP_FREE. */ + ut_ad(block_mutex == &buf_pool->zip_mutex); + mutex_enter(block_mutex); } } diff --git a/storage/innobase/buf/buf0rea.c b/storage/innobase/buf/buf0rea.c index da804a66b29..40550186191 100644 --- a/storage/innobase/buf/buf0rea.c +++ b/storage/innobase/buf/buf0rea.c @@ -50,6 +50,44 @@ read-ahead is not done: this is to prevent flooding the buffer pool with i/o-fixed buffer blocks */ #define BUF_READ_AHEAD_PEND_LIMIT 2 +/********************************************************************//** +Unfixes the pages, unlatches the page, +removes it from page_hash and removes it from LRU. */ +static +void +buf_read_page_handle_error( +/*=======================*/ + buf_page_t* bpage) /*!< in: pointer to the block */ +{ + buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); + const ibool uncompressed = (buf_page_get_state(bpage) + == BUF_BLOCK_FILE_PAGE); + + /* First unfix and release lock on the bpage */ + buf_pool_mutex_enter(buf_pool); + mutex_enter(buf_page_get_mutex(bpage)); + ut_ad(buf_page_get_io_fix(bpage) == BUF_IO_READ); + ut_ad(bpage->buf_fix_count == 0); + + /* Set BUF_IO_NONE before we remove the block from LRU list */ + buf_page_set_io_fix(bpage, BUF_IO_NONE); + + if (uncompressed) { + rw_lock_x_unlock_gen( + &((buf_block_t*) bpage)->lock, + BUF_IO_READ); + } + + /* remove the block from LRU list */ + buf_LRU_free_one_page(bpage); + + ut_ad(buf_pool->n_pend_reads > 0); + buf_pool->n_pend_reads--; + + mutex_exit(buf_page_get_mutex(bpage)); + buf_pool_mutex_exit(buf_pool); +} + /********************************************************************//** Low-level function which reads a page asynchronously from a file to the buffer buf_pool if it is not already there, in which case does nothing. @@ -152,12 +190,20 @@ buf_read_page_low( ((buf_block_t*) bpage)->frame, bpage); } thd_wait_end(NULL); + + if (*err == DB_TABLESPACE_DELETED) { + buf_read_page_handle_error(bpage); + return(0); + } + ut_a(*err == DB_SUCCESS); if (sync) { /* The i/o is already completed when we arrive from fil_read */ - buf_page_io_complete(bpage); + if (!buf_page_io_complete(bpage)) { + return(0); + } } return(1); diff --git a/storage/innobase/include/buf0buf.h b/storage/innobase/include/buf0buf.h index 7c81fe0c539..a39592943d8 100644 --- a/storage/innobase/include/buf0buf.h +++ b/storage/innobase/include/buf0buf.h @@ -1162,9 +1162,10 @@ buf_page_init_for_read( ulint offset);/*!< in: page number */ /********************************************************************//** Completes an asynchronous read or write request of a file page to or from -the buffer pool. */ +the buffer pool. +@return TRUE if successful */ UNIV_INTERN -void +ibool buf_page_io_complete( /*=================*/ buf_page_t* bpage); /*!< in: pointer to the block in question */ From 767501fb54f19adf3c136e5131daf11e34b3f039 Mon Sep 17 00:00:00 2001 From: Gleb Shchepa Date: Fri, 29 Jun 2012 12:55:45 +0400 Subject: [PATCH 109/289] Backport of the deprecation warning from WL#6219: "Deprecate and remove YEAR(2) type" Print the warning(note): YEAR(x) is deprecated and will be removed in a future release. Please use YEAR(4) instead on "CREATE TABLE ... YEAR(x)" or "ALTER TABLE MODIFY ... YEAR(x)", where x != 4 --- mysql-test/r/func_group.result | 2 ++ mysql-test/r/type_blob.result | 4 ++++ mysql-test/r/type_year.result | 15 +++++++++++++++ .../suite/engines/iuds/r/delete_year.result | 6 ++++++ .../suite/engines/iuds/r/insert_year.result | 12 ++++++++++++ .../suite/engines/iuds/r/update_year.result | 6 ++++++ mysql-test/suite/funcs_1/r/innodb_views.result | 4 ++++ .../suite/funcs_1/r/is_columns_innodb.result | 6 ++++++ .../suite/funcs_1/r/is_columns_memory.result | 6 ++++++ .../suite/funcs_1/r/is_columns_myisam.result | 6 ++++++ .../r/is_columns_myisam_embedded.result | 6 ++++++ mysql-test/suite/funcs_1/r/memory_views.result | 4 ++++ .../suite/funcs_1/r/myisam_views-big.result | 4 ++++ mysql-test/suite/funcs_1/r/ndb_views.result | 4 ++++ mysql-test/suite/funcs_1/r/storedproc.result | 4 ++++ .../innodb_plugin/r/innodb_bug52745.result | 1 + mysql-test/t/type_year.test | 8 ++++++++ sql/field.cc | 11 +++++++++++ sql/sql_yacc.yy | 18 +++++++++++++++++- 19 files changed, 126 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result index b90eb2a4c0f..74899a22636 100644 --- a/mysql-test/r/func_group.result +++ b/mysql-test/r/func_group.result @@ -1524,6 +1524,8 @@ DROP TABLE t1; # Bug#43668: Wrong comparison and MIN/MAX for YEAR(2) # create table t1 (f1 year(2), f2 year(4), f3 date, f4 datetime); +Warnings: +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead insert into t1 values (98,1998,19980101,"1998-01-01 00:00:00"), (00,2000,20000101,"2000-01-01 00:00:01"), diff --git a/mysql-test/r/type_blob.result b/mysql-test/r/type_blob.result index e6fd49b4247..8b4b6438842 100644 --- a/mysql-test/r/type_blob.result +++ b/mysql-test/r/type_blob.result @@ -878,6 +878,8 @@ ERROR 42000: Column length too big for column 'a' (max = 255); use BLOB or TEXT CREATE TABLE b15776 (a char(4294967296)); ERROR 42000: Display width out of range for column 'a' (max = 4294967295) CREATE TABLE b15776 (a year(4294967295)); +Warnings: +Note 1287 'YEAR(4294967295)' is deprecated and will be removed in a future release. Please use YEAR(4) instead INSERT INTO b15776 VALUES (42); SELECT * FROM b15776; a @@ -886,6 +888,8 @@ DROP TABLE b15776; CREATE TABLE b15776 (a year(4294967296)); ERROR 42000: Display width out of range for column 'a' (max = 4294967295) CREATE TABLE b15776 (a year(0)); +Warnings: +Note 1287 'YEAR(0)' is deprecated and will be removed in a future release. Please use YEAR(4) instead DROP TABLE b15776; CREATE TABLE b15776 (a year(-2)); ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '-2))' at line 1 diff --git a/mysql-test/r/type_year.result b/mysql-test/r/type_year.result index 2dc491c6166..e00569c93c1 100644 --- a/mysql-test/r/type_year.result +++ b/mysql-test/r/type_year.result @@ -1,5 +1,7 @@ drop table if exists t1; create table t1 (y year,y2 year(2)); +Warnings: +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead insert into t1 values (0,0),(1999,1999),(2000,2000),(2001,2001),(70,70),(69,69); select * from t1; y y2 @@ -50,6 +52,8 @@ End of 5.0 tests # Bug #49480: WHERE using YEAR columns returns unexpected results # CREATE TABLE t2(yy YEAR(2), c2 CHAR(4)); +Warnings: +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead CREATE TABLE t4(yyyy YEAR(4), c4 CHAR(4)); INSERT INTO t2 (c2) VALUES (NULL),(1970),(1999),(2000),(2001),(2069); INSERT INTO t4 (c4) SELECT c2 FROM t2; @@ -355,4 +359,15 @@ total_rows min_value MAX(c1) 3 0 2155 DROP TABLE t1; # +# WL#6219: Deprecate and remove YEAR(2) type +# +CREATE TABLE t1 (c1 YEAR(2), c2 YEAR(4)); +Warnings: +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead +ALTER TABLE t1 MODIFY COLUMN c2 YEAR(2); +Warnings: +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead +DROP TABLE t1; +# End of 5.1 tests diff --git a/mysql-test/suite/engines/iuds/r/delete_year.result b/mysql-test/suite/engines/iuds/r/delete_year.result index 02cbe24ecc9..c82f0dae7d9 100644 --- a/mysql-test/suite/engines/iuds/r/delete_year.result +++ b/mysql-test/suite/engines/iuds/r/delete_year.result @@ -2,7 +2,13 @@ DROP TABLE IF EXISTS t1,t2,t3,t4; CREATE TABLE t1(c1 YEAR NOT NULL,c2 YEAR, PRIMARY KEY(c1)); CREATE TABLE t2(c1 YEAR NOT NULL, c2 YEAR, UNIQUE INDEX idx(c1,c2)); CREATE TABLE t3(c1 YEAR(2) NOT NULL,c2 YEAR(2), PRIMARY KEY(c1)); +Warnings: +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead CREATE TABLE t4(c1 YEAR(2), c2 YEAR(2), UNIQUE INDEX idx(c1,c2)); +Warnings: +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead INSERT INTO t1 VALUES (1901,1901),(1970,1970),(1999,1999),(2000,2000),(2155,2155); INSERT INTO t2 VALUES (1901,1901),(1970,1970),(1999,1999),(2000,2000),(2155,2155); INSERT INTO t3 VALUES (1901,1901),(1970,1970),(1999,1999),(2000,2000),(2155,2155); diff --git a/mysql-test/suite/engines/iuds/r/insert_year.result b/mysql-test/suite/engines/iuds/r/insert_year.result index 386c8090434..b9618ba4e2d 100644 --- a/mysql-test/suite/engines/iuds/r/insert_year.result +++ b/mysql-test/suite/engines/iuds/r/insert_year.result @@ -3235,9 +3235,21 @@ c1 c2 c3 c4 1999 1999 1998-12-30 1998-12-30 11:30:45 DROP TABLE t1,t2,t3,t4; CREATE TABLE t1(c1 YEAR(2) NOT NULL, c2 YEAR(2) NULL, c3 DATE, c4 DATETIME, PRIMARY KEY(c1), UNIQUE INDEX(c2)); +Warnings: +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead CREATE TABLE t2(c1 YEAR(2) NOT NULL, c2 YEAR(2) NULL, c3 DATE, c4 DATETIME, PRIMARY KEY(c1,c2)); +Warnings: +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead CREATE TABLE t3(c1 YEAR(2) NOT NULL, c2 YEAR(2) NULL, c3 DATE, c4 DATETIME, UNIQUE INDEX idx(c1,c2)); +Warnings: +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead CREATE TABLE t4(c1 YEAR(2) NOT NULL, c2 YEAR(2) NULL, c3 DATE, c4 DATETIME); +Warnings: +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead INSERT INTO t1 VALUES('1901','1901','98-12-31','98.12.31 11:30:45'),('1999','1999','98-12-30','98.12.30 11:30:45'),('2000','2000','98-12-29','98.12.29 11:30:45'),('2001','2001','98-12-28','98.12.28 11:30:45'),('2099','2099','98-12-27','98.12.27 11:30:45'),('2100','2100','98-12-26','98.12.26 11:30:45'),('2155','2155','98-12-26','98.12.26 11:30:45'); INSERT INTO t2 VALUES('1901','1901','98-12-31','98.12.31 11:30:45'),('1999','1999','98-12-30','98.12.30 11:30:45'),('2000','2000','98-12-29','98.12.29 11:30:45'),('2001','2001','98-12-28','98.12.28 11:30:45'),('2099','2099','98-12-27','98.12.27 11:30:45'),('2100','2100','98-12-26','98.12.26 11:30:45'),('2155','2155','98-12-26','98.12.26 11:30:45'); INSERT INTO t3 VALUES('1901','1901','98-12-31','98.12.31 11:30:45'),('1999','1999','98-12-30','98.12.30 11:30:45'),('2000','2000','98-12-29','98.12.29 11:30:45'),('2001','2001','98-12-28','98.12.28 11:30:45'),('2099','2099','98-12-27','98.12.27 11:30:45'),('2100','2100','98-12-26','98.12.26 11:30:45'),('2155','2155','98-12-26','98.12.26 11:30:45'); diff --git a/mysql-test/suite/engines/iuds/r/update_year.result b/mysql-test/suite/engines/iuds/r/update_year.result index 1b0ead45314..c762d70a276 100644 --- a/mysql-test/suite/engines/iuds/r/update_year.result +++ b/mysql-test/suite/engines/iuds/r/update_year.result @@ -2,7 +2,13 @@ DROP TABLE IF EXISTS t1,t2,t3,t4; CREATE TABLE t1(c1 YEAR NOT NULL,c2 YEAR, PRIMARY KEY(c1)); CREATE TABLE t2(c1 YEAR NOT NULL, c2 YEAR, UNIQUE INDEX idx(c1,c2)); CREATE TABLE t3(c1 YEAR(2) NOT NULL,c2 YEAR(2), PRIMARY KEY(c1)); +Warnings: +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead CREATE TABLE t4(c1 YEAR(2), c2 YEAR(2), UNIQUE INDEX idx(c1,c2)); +Warnings: +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead INSERT INTO t1 VALUES (1901,1901),(1970,1970),(1999,1999),(2000,2000),(2155,2155); INSERT INTO t2 VALUES (1901,1901),(1970,1970),(1999,1999),(2000,2000),(2155,2155); INSERT INTO t3 VALUES (1901,1901),(1970,1970),(1999,1999),(2000,2000),(2155,2155); diff --git a/mysql-test/suite/funcs_1/r/innodb_views.result b/mysql-test/suite/funcs_1/r/innodb_views.result index a335e135a4f..951068e3300 100644 --- a/mysql-test/suite/funcs_1/r/innodb_views.result +++ b/mysql-test/suite/funcs_1/r/innodb_views.result @@ -53,6 +53,8 @@ f107 year(4) not null default 2000, f108 enum("1enum","2enum") not null default "1enum", f109 set("1set","2set") not null default "1set" ) engine = innodb; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/innodb_tb2.txt' into table tb2; DROP DATABASE IF EXISTS test1; @@ -112,6 +114,8 @@ f107 year(4) not null default 2000, f108 enum("1enum","2enum") not null default "1enum", f109 set("1set","2set") not null default "1set" ) engine = innodb; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/innodb_tb2.txt' into table tb2; USE test; diff --git a/mysql-test/suite/funcs_1/r/is_columns_innodb.result b/mysql-test/suite/funcs_1/r/is_columns_innodb.result index 61079b06666..0abe8e11cf3 100644 --- a/mysql-test/suite/funcs_1/r/is_columns_innodb.result +++ b/mysql-test/suite/funcs_1/r/is_columns_innodb.result @@ -132,6 +132,8 @@ f107 year(4) not null default 2000, f108 enum("1enum","2enum") not null default "1enum", f109 set("1set","2set") not null default "1set" ) engine = innodb; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/innodb_tb2.txt' into table tb2; drop table if exists tb3 ; @@ -262,6 +264,8 @@ f239 varchar(20000) binary, f240 varchar(2000), f241 char(100) ) engine = innodb; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/innodb_tb4.txt' into table tb4; USE test1; @@ -319,6 +323,8 @@ f107 year(4) not null default 2000, f108 enum("1enum","2enum") not null default "1enum", f109 set("1set","2set") not null default "1set" ) engine = innodb; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/innodb_tb2.txt' into table tb2; USE test; diff --git a/mysql-test/suite/funcs_1/r/is_columns_memory.result b/mysql-test/suite/funcs_1/r/is_columns_memory.result index 60dea25e0e3..c476b930f60 100644 --- a/mysql-test/suite/funcs_1/r/is_columns_memory.result +++ b/mysql-test/suite/funcs_1/r/is_columns_memory.result @@ -128,6 +128,8 @@ f107 year(4) not null default 2000, f108 enum("1enum","2enum") not null default "1enum", f109 set("1set","2set") not null default "1set" ) engine = memory; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/memory_tb2.txt' into table tb2 ; drop table if exists tb3; @@ -251,6 +253,8 @@ f238 varchar(25000) binary, f239 varbinary(0), f240 varchar(1200) ) engine = memory; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/memory_tb4.txt' into table tb4; USE test1; @@ -308,6 +312,8 @@ f107 year(4) not null default 2000, f108 enum("1enum","2enum") not null default "1enum", f109 set("1set","2set") not null default "1set" ) engine = memory; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/memory_tb2.txt' into table tb2 ; USE test; diff --git a/mysql-test/suite/funcs_1/r/is_columns_myisam.result b/mysql-test/suite/funcs_1/r/is_columns_myisam.result index 6d0a44d2223..0e464d0fbc1 100644 --- a/mysql-test/suite/funcs_1/r/is_columns_myisam.result +++ b/mysql-test/suite/funcs_1/r/is_columns_myisam.result @@ -144,6 +144,8 @@ f115 VARBINARY(27) null , f116 VARBINARY(64) null, f117 VARBINARY(192) null ) engine = myisam; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/myisam_tb2.txt' into table tb2; drop table if exists tb3 ; @@ -283,6 +285,8 @@ f240 varchar(120), f241 char(100), f242 bit(30) ) engine = myisam; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/myisam_tb4.txt' into table tb4; USE test1; @@ -348,6 +352,8 @@ f115 VARBINARY(27) null , f116 VARBINARY(64) null, f117 VARBINARY(192) null ) engine = myisam; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/myisam_tb2.txt' into table tb2; USE test; diff --git a/mysql-test/suite/funcs_1/r/is_columns_myisam_embedded.result b/mysql-test/suite/funcs_1/r/is_columns_myisam_embedded.result index 739f62e371a..7424ba8573d 100644 --- a/mysql-test/suite/funcs_1/r/is_columns_myisam_embedded.result +++ b/mysql-test/suite/funcs_1/r/is_columns_myisam_embedded.result @@ -144,6 +144,8 @@ f115 VARBINARY(27) null , f116 VARBINARY(64) null, f117 VARBINARY(192) null ) engine = myisam; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/myisam_tb2.txt' into table tb2; drop table if exists tb3 ; @@ -283,6 +285,8 @@ f240 varchar(120), f241 char(100), f242 bit(30) ) engine = myisam; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/myisam_tb4.txt' into table tb4; USE test1; @@ -348,6 +352,8 @@ f115 VARBINARY(27) null , f116 VARBINARY(64) null, f117 VARBINARY(192) null ) engine = myisam; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/myisam_tb2.txt' into table tb2; USE test; diff --git a/mysql-test/suite/funcs_1/r/memory_views.result b/mysql-test/suite/funcs_1/r/memory_views.result index ccbd086b71f..0bb03e62192 100644 --- a/mysql-test/suite/funcs_1/r/memory_views.result +++ b/mysql-test/suite/funcs_1/r/memory_views.result @@ -54,6 +54,8 @@ f107 year(4) not null default 2000, f108 enum("1enum","2enum") not null default "1enum", f109 set("1set","2set") not null default "1set" ) engine = memory; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/memory_tb2.txt' into table tb2 ; DROP DATABASE IF EXISTS test1; @@ -113,6 +115,8 @@ f107 year(4) not null default 2000, f108 enum("1enum","2enum") not null default "1enum", f109 set("1set","2set") not null default "1set" ) engine = memory; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/memory_tb2.txt' into table tb2 ; USE test; diff --git a/mysql-test/suite/funcs_1/r/myisam_views-big.result b/mysql-test/suite/funcs_1/r/myisam_views-big.result index 9b07a0ae45b..0afb1d7d6c8 100644 --- a/mysql-test/suite/funcs_1/r/myisam_views-big.result +++ b/mysql-test/suite/funcs_1/r/myisam_views-big.result @@ -62,6 +62,8 @@ f115 VARBINARY(27) null , f116 VARBINARY(64) null, f117 VARBINARY(192) null ) engine = myisam; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/myisam_tb2.txt' into table tb2; DROP DATABASE IF EXISTS test1; @@ -129,6 +131,8 @@ f115 VARBINARY(27) null , f116 VARBINARY(64) null, f117 VARBINARY(192) null ) engine = myisam; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/myisam_tb2.txt' into table tb2; USE test; diff --git a/mysql-test/suite/funcs_1/r/ndb_views.result b/mysql-test/suite/funcs_1/r/ndb_views.result index b75f4955986..17eaedce56b 100644 --- a/mysql-test/suite/funcs_1/r/ndb_views.result +++ b/mysql-test/suite/funcs_1/r/ndb_views.result @@ -53,6 +53,8 @@ f107 year(4) not null default 2000, f108 enum("1enum","2enum") not null default "1enum", f109 set("1set","2set") not null default "1set" ) engine = ndb; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/ndb_tb2.txt' into table tb2 ; DROP DATABASE IF EXISTS test1; @@ -112,6 +114,8 @@ f107 year(4) not null default 2000, f108 enum("1enum","2enum") not null default "1enum", f109 set("1set","2set") not null default "1set" ) engine = ndb; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/ndb_tb2.txt' into table tb2 ; USE test; diff --git a/mysql-test/suite/funcs_1/r/storedproc.result b/mysql-test/suite/funcs_1/r/storedproc.result index 8da7213bded..7647579820a 100644 --- a/mysql-test/suite/funcs_1/r/storedproc.result +++ b/mysql-test/suite/funcs_1/r/storedproc.result @@ -7526,9 +7526,13 @@ BEGIN declare x, y, z year(3) default 2005; SELECT x, y, z; END// +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead CALL sp1(); x y z 2005 2005 2005 +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead DROP PROCEDURE IF EXISTS sp1; CREATE PROCEDURE sp1( ) BEGIN diff --git a/mysql-test/suite/innodb_plugin/r/innodb_bug52745.result b/mysql-test/suite/innodb_plugin/r/innodb_bug52745.result index 74db8b0c20a..927ba0e0e53 100644 --- a/mysql-test/suite/innodb_plugin/r/innodb_bug52745.result +++ b/mysql-test/suite/innodb_plugin/r/innodb_bug52745.result @@ -58,6 +58,7 @@ col89 float unsigned zerofill DEFAULT NULL, col90 tinyblob ) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1; Warnings: +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead Note 1291 Column 'col82' has duplicated value '' in ENUM Note 1291 Column 'col82' has duplicated value '' in ENUM INSERT INTO bug52745 SET diff --git a/mysql-test/t/type_year.test b/mysql-test/t/type_year.test index 1a9e66478e1..8ba8260cfc4 100644 --- a/mysql-test/t/type_year.test +++ b/mysql-test/t/type_year.test @@ -159,6 +159,14 @@ SELECT * FROM t1; SELECT COUNT(*) AS total_rows, MIN(c1) AS min_value, MAX(c1) FROM t1; DROP TABLE t1; +--echo # +--echo # WL#6219: Deprecate and remove YEAR(2) type +--echo # + +CREATE TABLE t1 (c1 YEAR(2), c2 YEAR(4)); +ALTER TABLE t1 MODIFY COLUMN c2 YEAR(2); +DROP TABLE t1; + --echo # --echo End of 5.1 tests diff --git a/sql/field.cc b/sql/field.cc index f398642fdb0..1c937755c0c 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -10227,6 +10227,17 @@ Create_field::Create_field(Field *old_field,Field *orig_field) geom_type= ((Field_geom*)old_field)->geom_type; break; #endif + case MYSQL_TYPE_YEAR: + if (length != 4) + { + char buff[sizeof("YEAR()") + MY_INT64_NUM_DECIMAL_DIGITS + 1]; + snprintf(buff, sizeof(buff), "YEAR(%lu)", length); + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_NOTE, + ER_WARN_DEPRECATED_SYNTAX, + ER(ER_WARN_DEPRECATED_SYNTAX), + buff, "YEAR(4)"); + } + break; default: break; } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 7e7ff7e91ca..854ba432362 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -5034,7 +5034,23 @@ type: $$= MYSQL_TYPE_VARCHAR; } | YEAR_SYM opt_field_length field_options - { $$=MYSQL_TYPE_YEAR; } + { + if (Lex->length) + { + errno= 0; + ulong length= strtoul(Lex->length, NULL, 10); + if (errno == 0 && length <= MAX_FIELD_BLOBLENGTH && length != 4) + { + char buff[sizeof("YEAR()") + MY_INT64_NUM_DECIMAL_DIGITS + 1]; + snprintf(buff, sizeof(buff), "YEAR(%lu)", length); + push_warning_printf(YYTHD, MYSQL_ERROR::WARN_LEVEL_NOTE, + ER_WARN_DEPRECATED_SYNTAX, + ER(ER_WARN_DEPRECATED_SYNTAX), + buff, "YEAR(4)"); + } + } + $$=MYSQL_TYPE_YEAR; + } | DATE_SYM { $$=MYSQL_TYPE_DATE; } | TIME_SYM From d672a10593756b2252ca8d7340988c2ac6438cb8 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Fri, 29 Jun 2012 14:04:24 +0300 Subject: [PATCH 110/289] Bug #12910665: AUTH-PLUGIN-DATA-LEN NOT TESTED FOR VALIDITY BY THE CLIENT Added a check for a negative second part of the scramble length. --- sql-common/client.c | 6 ++++++ sql/sql_acl.cc | 1 + 2 files changed, 7 insertions(+) diff --git a/sql-common/client.c b/sql-common/client.c index be24c5e89e4..ef1e3c1b7d4 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -3415,6 +3415,12 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user, mysql->server_status=uint2korr(end+3); mysql->server_capabilities|= uint2korr(end+5) << 16; pkt_scramble_len= end[7]; + if (pkt_scramble_len < 0) + { + set_mysql_error(mysql, CR_MALFORMED_PACKET, + unknown_sqlstate); /* purecov: inspected */ + goto error; + } } end+= 18; diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index d3715fd2312..242967fff6a 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -8032,6 +8032,7 @@ static bool send_server_handshake_packet(MPVIO_EXT *mpvio, int2store(end + 3, mpvio->server_status[0]); int2store(end + 5, mpvio->client_capabilities >> 16); end[7]= data_len; + DBUG_EXECUTE_IF("poison_srv_handshake_scramble_len", end[7]= -100;); bzero(end + 8, 10); end+= 18; /* write scramble tail */ From 1ede2dd8146254951493081f2297b0832fdd4d13 Mon Sep 17 00:00:00 2001 From: Jon Olav Hauglid Date: Fri, 29 Jun 2012 13:25:57 +0200 Subject: [PATCH 111/289] Bug#14238406 NEW COMPILATION WARNINGS WITH GCC 4.7 (-WERROR=NARROWING) This patch fixes various compilation warnings of the type "error: narrowing conversion of 'x' from 'datatype1' to 'datatype2' --- client/mysqlbinlog.cc | 4 ++-- include/my_getopt.h | 4 ++-- sql/log.h | 6 ++--- sql/mysqld.cc | 27 +++++++++++----------- sql/sql_profile.cc | 6 ++--- storage/innobase/handler/ha_innodb.cc | 8 +++---- storage/innodb_plugin/handler/ha_innodb.cc | 12 +++++----- 7 files changed, 34 insertions(+), 33 deletions(-) diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index dd09e7a0938..e7840865a58 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. 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 @@ -1149,7 +1149,7 @@ static struct my_option my_long_options[] = "Stop reading the binlog at position N. Applies to the last binlog " "passed on the command line.", &stop_position, &stop_position, 0, GET_ULL, - REQUIRED_ARG, (ulonglong)(~(my_off_t)0), BIN_LOG_HEADER_SIZE, + REQUIRED_ARG, (longlong)(~(my_off_t)0), BIN_LOG_HEADER_SIZE, (ulonglong)(~(my_off_t)0), 0, 0, 0}, {"to-last-log", 't', "Requires -R. Will not stop at the end of the \ requested binlog but rather continue printing until the end of the last \ diff --git a/include/my_getopt.h b/include/my_getopt.h index 8112303a6a5..5824518a085 100644 --- a/include/my_getopt.h +++ b/include/my_getopt.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. 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 @@ -54,7 +54,7 @@ struct my_option enum get_opt_arg_type arg_type; longlong def_value; /* Default value */ longlong min_value; /* Min allowed value */ - longlong max_value; /* Max allowed value */ + ulonglong max_value; /* Max allowed value */ longlong sub_size; /* Subtract this from given value */ long block_size; /* Value should be a mult. of this */ void *app_type; /* To be used by an application */ diff --git a/sql/log.h b/sql/log.h index 9ed5db04e87..02721f1ddd0 100644 --- a/sql/log.h +++ b/sql/log.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. 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 @@ -294,8 +294,8 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG int new_file_impl(bool need_lock); public: - MYSQL_LOG::generate_name; - MYSQL_LOG::is_open; + using MYSQL_LOG::generate_name; + using MYSQL_LOG::is_open; /* This is relay log */ bool is_relay_log; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index db73504cb17..d6397280e0d 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. 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 @@ -6710,7 +6710,7 @@ thread is in the relay logs.", {"max_binlog_cache_size", OPT_MAX_BINLOG_CACHE_SIZE, "Can be used to restrict the total size used to cache a multi-transaction query.", &max_binlog_cache_size, &max_binlog_cache_size, 0, - GET_ULL, REQUIRED_ARG, ULONG_MAX, IO_SIZE, ULONGLONG_MAX, 0, IO_SIZE, 0}, + GET_ULL, REQUIRED_ARG, (longlong) ULONG_MAX, IO_SIZE, ULONGLONG_MAX, 0, IO_SIZE, 0}, {"max_binlog_size", OPT_MAX_BINLOG_SIZE, "Binary log will be rotated automatically when the size exceeds this " "value. Will also apply to relay logs if max_relay_log_size is 0. " @@ -6748,7 +6748,7 @@ thread is in the relay logs.", "Joins that are probably going to read more than max_join_size records return an error.", &global_system_variables.max_join_size, &max_system_variables.max_join_size, 0, GET_HA_ROWS, REQUIRED_ARG, - HA_POS_ERROR, 1, HA_POS_ERROR, 0, 1, 0}, + (longlong) HA_POS_ERROR, 1, HA_POS_ERROR, 0, 1, 0}, {"max_length_for_sort_data", OPT_MAX_LENGTH_FOR_SORT_DATA, "Max number of bytes in sorted records.", &global_system_variables.max_length_for_sort_data, @@ -6775,7 +6775,7 @@ thread is in the relay logs.", "Limit assumed max number of seeks when looking up rows based on a key.", &global_system_variables.max_seeks_for_key, &max_system_variables.max_seeks_for_key, 0, GET_ULONG, - REQUIRED_ARG, ULONG_MAX, 1, ULONG_MAX, 0, 1, 0 }, + REQUIRED_ARG, (longlong) ULONG_MAX, 1, ULONG_MAX, 0, 1, 0 }, {"max_sort_length", OPT_MAX_SORT_LENGTH, "The number of bytes to use when sorting BLOB or TEXT values (only the " "first max_sort_length bytes of each value are used; the rest are ignored).", @@ -6799,7 +6799,7 @@ thread is in the relay logs.", {"max_write_lock_count", OPT_MAX_WRITE_LOCK_COUNT, "After this many write locks, allow some read locks to run in between.", &max_write_lock_count, &max_write_lock_count, 0, GET_ULONG, - REQUIRED_ARG, ULONG_MAX, 1, ULONG_MAX, 0, 1, 0}, + REQUIRED_ARG, (longlong) ULONG_MAX, 1, ULONG_MAX, 0, 1, 0}, {"min_examined_row_limit", OPT_MIN_EXAMINED_ROW_LIMIT, "Don't log queries which examine less than min_examined_row_limit rows to file.", &global_system_variables.min_examined_row_limit, @@ -6826,18 +6826,19 @@ thread is in the relay logs.", &global_system_variables.myisam_max_extra_sort_file_size, &max_system_variables.myisam_max_extra_sort_file_size, 0, GET_ULL, REQUIRED_ARG, (ulonglong) INT_MAX32, - 0, (ulonglong) MAX_FILE_SIZE, 0, 1, 0}, + 0, MAX_FILE_SIZE, 0, 1, 0}, {"myisam_max_sort_file_size", OPT_MYISAM_MAX_SORT_FILE_SIZE, "Don't use the fast sort index method to created index if the temporary " "file would get bigger than this.", &global_system_variables.myisam_max_sort_file_size, &max_system_variables.myisam_max_sort_file_size, 0, - GET_ULL, REQUIRED_ARG, (longlong) LONG_MAX, 0, (ulonglong) MAX_FILE_SIZE, + GET_ULL, REQUIRED_ARG, (longlong) LONG_MAX, 0, MAX_FILE_SIZE, 0, 1024*1024, 0}, {"myisam_mmap_size", OPT_MYISAM_MMAP_SIZE, "Can be used to restrict the total memory used for memory mmaping of myisam files", &myisam_mmap_size, &myisam_mmap_size, 0, - GET_ULL, REQUIRED_ARG, SIZE_T_MAX, MEMMAP_EXTRA_MARGIN, SIZE_T_MAX, 0, 1, 0}, + GET_ULL, REQUIRED_ARG, (longlong) SIZE_T_MAX, MEMMAP_EXTRA_MARGIN, SIZE_T_MAX, + 0, 1, 0}, {"myisam_repair_threads", OPT_MYISAM_REPAIR_THREADS, "Specifies whether several threads should be used when repairing MyISAM " "tables. For values > 1, one thread is used per index. The value of 1 " @@ -6850,7 +6851,7 @@ thread is in the relay logs.", "or when creating indexes with CREATE INDEX or ALTER TABLE.", &global_system_variables.myisam_sort_buff_size, &max_system_variables.myisam_sort_buff_size, 0, - GET_ULONG, REQUIRED_ARG, 8192 * 1024, 4096, ~0L, 0, 1, 0}, + GET_ULONG, REQUIRED_ARG, 8192 * 1024, 4096, ~0ULL, 0, 1, 0}, {"myisam_use_mmap", OPT_MYISAM_USE_MMAP, "Use memory mapping for reading and writing MyISAM tables.", &opt_myisam_use_mmap, &opt_myisam_use_mmap, 0, GET_BOOL, NO_ARG, @@ -6953,7 +6954,7 @@ thread is in the relay logs.", {"query_cache_size", OPT_QUERY_CACHE_SIZE, "The memory allocated to store results from old queries.", &query_cache_size, &query_cache_size, 0, GET_ULONG, - REQUIRED_ARG, 0, 0, (longlong) ULONG_MAX, 0, 1024, 0}, + REQUIRED_ARG, 0, 0, ULONG_MAX, 0, 1024, 0}, #ifdef HAVE_QUERY_CACHE {"query_cache_type", OPT_QUERY_CACHE_TYPE, "0 = OFF = Don't cache or retrieve results. 1 = ON = Cache all results " @@ -7015,7 +7016,7 @@ thread is in the relay logs.", "Maximum space to use for all relay logs.", &relay_log_space_limit, &relay_log_space_limit, 0, GET_ULL, REQUIRED_ARG, 0L, 0L, - (longlong) ULONG_MAX, 0, 1, 0}, + ULONG_MAX, 0, 1, 0}, {"slave_compressed_protocol", OPT_SLAVE_COMPRESSED_PROTOCOL, "Use compression on master/slave protocol.", &opt_slave_compressed_protocol, @@ -7030,7 +7031,7 @@ thread is in the relay logs.", "it failed with a deadlock or elapsed lock wait timeout, " "before giving up and stopping.", &slave_trans_retries, &slave_trans_retries, 0, - GET_ULONG, REQUIRED_ARG, 10L, 0L, (longlong) ULONG_MAX, 0, 1, 0}, + GET_ULONG, REQUIRED_ARG, 10L, 0L, ULONG_MAX, 0, 1, 0}, #endif /* HAVE_REPLICATION */ {"slow_launch_time", OPT_SLOW_LAUNCH_TIME, "If creating the thread takes longer than this value (in seconds), " @@ -7041,7 +7042,7 @@ thread is in the relay logs.", "Each thread that needs to do a sort allocates a buffer of this size.", &global_system_variables.sortbuff_size, &max_system_variables.sortbuff_size, 0, GET_ULONG, REQUIRED_ARG, - MAX_SORT_MEMORY, MIN_SORT_MEMORY+MALLOC_OVERHEAD*2, ~0L, MALLOC_OVERHEAD, + MAX_SORT_MEMORY, MIN_SORT_MEMORY+MALLOC_OVERHEAD*2, ~0ULL, MALLOC_OVERHEAD, 1, 0}, {"sync-binlog", OPT_SYNC_BINLOG, "Synchronously flush binary log to disk after every #th event. " diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc index 1a6477e4c4d..49666dde476 100644 --- a/sql/sql_profile.cc +++ b/sql/sql_profile.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. 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 @@ -84,8 +84,8 @@ ST_FIELD_INFO query_profile_statistics_info[]= int make_profile_table_for_show(THD *thd, ST_SCHEMA_TABLE *schema_table) { - int profile_options = thd->lex->profile_options; - int fields_include_condition_truth_values[]= { + uint profile_options = thd->lex->profile_options; + uint fields_include_condition_truth_values[]= { FALSE, /* Query_id */ FALSE, /* Seq */ TRUE, /* Status */ diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 51b7007145c..796f51d737b 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -9128,7 +9128,7 @@ static MYSQL_SYSVAR_ULONG(max_dirty_pages_pct, srv_max_buf_pool_modified_pct, static MYSQL_SYSVAR_ULONG(max_purge_lag, srv_max_purge_lag, PLUGIN_VAR_RQCMDARG, "Desired maximum length of the purge queue (0 = no limit)", - NULL, NULL, 0, 0, ~0L, 0); + NULL, NULL, 0, 0, ~0UL, 0); static MYSQL_SYSVAR_BOOL(rollback_on_timeout, innobase_rollback_on_timeout, PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY, @@ -9182,7 +9182,7 @@ static MYSQL_SYSVAR_ULONG(commit_concurrency, innobase_commit_concurrency, static MYSQL_SYSVAR_ULONG(concurrency_tickets, srv_n_free_tickets_to_enter, PLUGIN_VAR_RQCMDARG, "Number of times a thread is allowed to enter InnoDB within the same SQL query after it has once got the ticket", - NULL, NULL, 500L, 1L, ~0L, 0); + NULL, NULL, 500L, 1L, ~0UL, 0); static MYSQL_SYSVAR_LONG(file_io_threads, innobase_file_io_threads, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, @@ -9227,7 +9227,7 @@ static MYSQL_SYSVAR_LONG(open_files, innobase_open_files, static MYSQL_SYSVAR_ULONG(sync_spin_loops, srv_n_spin_wait_rounds, PLUGIN_VAR_RQCMDARG, "Count of spin-loop rounds in InnoDB mutexes", - NULL, NULL, 20L, 0L, ~0L, 0); + NULL, NULL, 20L, 0L, ~0UL, 0); static MYSQL_SYSVAR_ULONG(thread_concurrency, srv_thread_concurrency, PLUGIN_VAR_RQCMDARG, @@ -9237,7 +9237,7 @@ static MYSQL_SYSVAR_ULONG(thread_concurrency, srv_thread_concurrency, static MYSQL_SYSVAR_ULONG(thread_sleep_delay, srv_thread_sleep_delay, PLUGIN_VAR_RQCMDARG, "Time of innodb thread sleeping before joining InnoDB queue (usec). Value 0 disable a sleep", - NULL, NULL, 10000L, 0L, ~0L, 0); + NULL, NULL, 10000L, 0L, ~0UL, 0); static MYSQL_SYSVAR_STR(data_file_path, innobase_data_file_path, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, diff --git a/storage/innodb_plugin/handler/ha_innodb.cc b/storage/innodb_plugin/handler/ha_innodb.cc index 2207f9d009d..412346e8349 100644 --- a/storage/innodb_plugin/handler/ha_innodb.cc +++ b/storage/innodb_plugin/handler/ha_innodb.cc @@ -10974,7 +10974,7 @@ static MYSQL_SYSVAR_BOOL(doublewrite, innobase_use_doublewrite, static MYSQL_SYSVAR_ULONG(io_capacity, srv_io_capacity, PLUGIN_VAR_RQCMDARG, "Number of IOPs the server can do. Tunes the background IO rate", - NULL, NULL, 200, 100, ~0L, 0); + NULL, NULL, 200, 100, ~0UL, 0); static MYSQL_SYSVAR_ULONG(fast_shutdown, innobase_fast_shutdown, PLUGIN_VAR_OPCMDARG, @@ -11052,7 +11052,7 @@ static MYSQL_SYSVAR_BOOL(adaptive_flushing, srv_adaptive_flushing, static MYSQL_SYSVAR_ULONG(max_purge_lag, srv_max_purge_lag, PLUGIN_VAR_RQCMDARG, "Desired maximum length of the purge queue (0 = no limit)", - NULL, NULL, 0, 0, ~0L, 0); + NULL, NULL, 0, 0, ~0UL, 0); static MYSQL_SYSVAR_BOOL(rollback_on_timeout, innobase_rollback_on_timeout, PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY, @@ -11109,7 +11109,7 @@ static MYSQL_SYSVAR_ULONG(commit_concurrency, innobase_commit_concurrency, static MYSQL_SYSVAR_ULONG(concurrency_tickets, srv_n_free_tickets_to_enter, PLUGIN_VAR_RQCMDARG, "Number of times a thread is allowed to enter InnoDB within the same SQL query after it has once got the ticket", - NULL, NULL, 500L, 1L, ~0L, 0); + NULL, NULL, 500L, 1L, ~0UL, 0); static MYSQL_SYSVAR_LONG(file_io_threads, innobase_file_io_threads, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY | PLUGIN_VAR_NOSYSVAR, @@ -11171,12 +11171,12 @@ static MYSQL_SYSVAR_LONG(open_files, innobase_open_files, static MYSQL_SYSVAR_ULONG(sync_spin_loops, srv_n_spin_wait_rounds, PLUGIN_VAR_RQCMDARG, "Count of spin-loop rounds in InnoDB mutexes (30 by default)", - NULL, NULL, 30L, 0L, ~0L, 0); + NULL, NULL, 30L, 0L, ~0UL, 0); static MYSQL_SYSVAR_ULONG(spin_wait_delay, srv_spin_wait_delay, PLUGIN_VAR_OPCMDARG, "Maximum delay between polling for a spin lock (6 by default)", - NULL, NULL, 6L, 0L, ~0L, 0); + NULL, NULL, 6L, 0L, ~0UL, 0); static MYSQL_SYSVAR_ULONG(thread_concurrency, srv_thread_concurrency, PLUGIN_VAR_RQCMDARG, @@ -11186,7 +11186,7 @@ static MYSQL_SYSVAR_ULONG(thread_concurrency, srv_thread_concurrency, static MYSQL_SYSVAR_ULONG(thread_sleep_delay, srv_thread_sleep_delay, PLUGIN_VAR_RQCMDARG, "Time of innodb thread sleeping before joining InnoDB queue (usec). Value 0 disable a sleep", - NULL, NULL, 10000L, 0L, ~0L, 0); + NULL, NULL, 10000L, 0L, ~0UL, 0); static MYSQL_SYSVAR_STR(data_file_path, innobase_data_file_path, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, From 5f5df5091e6ddaf445b281f16b7dcf950ed4af02 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Fri, 29 Jun 2012 14:19:31 +0200 Subject: [PATCH 112/289] Fix mysql_plugin test to handle version XXa --- mysql-test/t/mysql_plugin.test | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/t/mysql_plugin.test b/mysql-test/t/mysql_plugin.test index 71617b86330..a05b5a624d9 100644 --- a/mysql-test/t/mysql_plugin.test +++ b/mysql-test/t/mysql_plugin.test @@ -372,11 +372,11 @@ let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQL_DATADIR --basedir=$MYSQ --echo # Show the help. --echo # replace_result $MYSQL_PLUGIN mysql_plugin; ---replace_regex /Ver [0-9.]+ Distrib [0-9.]+/Ver V.V.VV Distrib XX.XX.XX/ /XX-m[0-9]+/XX/ +--replace_regex /Ver [0-9.]+ Distrib [0-9.]+/Ver V.V.VV Distrib XX.XX.XX/ /XX-m[0-9]+/XX/ /XX[a-z]/XX/ --exec $MYSQL_PLUGIN --help replace_result $MYSQL_PLUGIN mysql_plugin; ---replace_regex /Ver [0-9.]+ Distrib [0-9.]+/Ver V.V.VV Distrib XX.XX.XX/ /XX-m[0-9]+/XX/ +--replace_regex /Ver [0-9.]+ Distrib [0-9.]+/Ver V.V.VV Distrib XX.XX.XX/ /XX-m[0-9]+/XX/ /XX[a-z]/XX/ --exec $MYSQL_PLUGIN --version # From 521deaf36f3ae6686ebea64afe5d3195ad3f80d2 Mon Sep 17 00:00:00 2001 From: Gleb Shchepa Date: Fri, 29 Jun 2012 18:24:43 +0400 Subject: [PATCH 113/289] minor update to make MSVS happy --- sql/field.cc | 2 +- sql/sql_yacc.yy | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/field.cc b/sql/field.cc index 1c937755c0c..ff631edd8d4 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -10231,7 +10231,7 @@ Create_field::Create_field(Field *old_field,Field *orig_field) if (length != 4) { char buff[sizeof("YEAR()") + MY_INT64_NUM_DECIMAL_DIGITS + 1]; - snprintf(buff, sizeof(buff), "YEAR(%lu)", length); + my_snprintf(buff, sizeof(buff), "YEAR(%lu)", length); push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_WARN_DEPRECATED_SYNTAX, ER(ER_WARN_DEPRECATED_SYNTAX), diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 854ba432362..7a6981f778a 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -5042,7 +5042,7 @@ type: if (errno == 0 && length <= MAX_FIELD_BLOBLENGTH && length != 4) { char buff[sizeof("YEAR()") + MY_INT64_NUM_DECIMAL_DIGITS + 1]; - snprintf(buff, sizeof(buff), "YEAR(%lu)", length); + my_snprintf(buff, sizeof(buff), "YEAR(%lu)", length); push_warning_printf(YYTHD, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_WARN_DEPRECATED_SYNTAX, ER(ER_WARN_DEPRECATED_SYNTAX), From b9093d370bc8185ed067b41a6d5765a26ef21f89 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Fri, 29 Jun 2012 22:17:16 +0400 Subject: [PATCH 114/289] MWL#182: Explain running statements: address review feedback - Fix the year in Monty Program Ab copyrights in the new files. - Fix permissions handling so that SHOW EXPLAIN's handling is the same as SHOW PROCESSLIST's. --- mysql-test/r/show_explain.result | 45 +++++++++++++++++++++ mysql-test/t/show_explain.test | 67 ++++++++++++++++++++++++++++++-- sql/my_apc.cc | 2 +- sql/my_apc.h | 2 +- sql/sql_class.h | 2 +- sql/sql_parse.cc | 5 ++- sql/sql_show.cc | 25 ++++++++++-- 7 files changed, 138 insertions(+), 10 deletions(-) diff --git a/mysql-test/r/show_explain.result b/mysql-test/r/show_explain.result index 07bcb29a7ea..a4097b9d65e 100644 --- a/mysql-test/r/show_explain.result +++ b/mysql-test/r/show_explain.result @@ -728,4 +728,49 @@ a 2 set debug_dbug=''; drop table t1,t3,t4; +# +# ---------- SHOW EXPLAIN and permissions ----------------- +# +grant ALL on test.* to test2@localhost; +# +# First, make sure that user 'test2' cannot do SHOW EXPLAIN on us +# +set debug_dbug='d,show_explain_probe_join_exec_start'; +select * from t0 where a < 3; +show explain for $thr2; +ERROR 42000: Access denied; you need (at least one of) the PROCESSLIST privilege(s) for this operation +show explain for $thr2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 ALL NULL NULL NULL NULL 10 Using where +Warnings: +Note 1003 select * from t0 where a < 3 +a +0 +1 +2 +set debug_dbug=''; +# +# Unfortunately, our test setup doesn't allow to check that test2 +# can do SHOW EXPLAIN on his own queries. This is because SET debug_dbug +# requires SUPER privilege. Giving SUPER to test2 will make the test +# meaningless +# +# +# Now, grant test2 a PROCESSLIST permission, and see that he's able to observe us +# +grant process on *.* to test2@localhost; +set debug_dbug='d,show_explain_probe_join_exec_start'; +select * from t0 where a < 3; +show explain for $thr2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 ALL NULL NULL NULL NULL 10 Using where +Warnings: +Note 1003 select * from t0 where a < 3 +a +0 +1 +2 +set debug_dbug=''; +revoke all privileges on test.* from test2@localhost; +drop user test2@localhost; drop table t0; diff --git a/mysql-test/t/show_explain.test b/mysql-test/t/show_explain.test index ffd2c25dfd9..5db6b96d93b 100644 --- a/mysql-test/t/show_explain.test +++ b/mysql-test/t/show_explain.test @@ -727,10 +727,71 @@ reap; set debug_dbug=''; drop table t1,t3,t4; + +--echo # +--echo # ---------- SHOW EXPLAIN and permissions ----------------- +--echo # +grant ALL on test.* to test2@localhost; + +connect (con2, localhost, test2,,); +connection con1; + +--echo # +--echo # First, make sure that user 'test2' cannot do SHOW EXPLAIN on us +--echo # +set debug_dbug='d,show_explain_probe_join_exec_start'; +send +select * from t0 where a < 3; + +connection default; +--source include/wait_condition.inc + +connection con2; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +evalp show explain for $thr2; + +connection default; +evalp show explain for $thr2; + +connection con1; +reap; +set debug_dbug=''; + +--echo # +--echo # Unfortunately, our test setup doesn't allow to check that test2 +--echo # can do SHOW EXPLAIN on his own queries. This is because SET debug_dbug +--echo # requires SUPER privilege. Giving SUPER to test2 will make the test +--echo # meaningless +--echo # + +--echo # +--echo # Now, grant test2 a PROCESSLIST permission, and see that he's able to observe us +--echo # +disconnect con2; +grant process on *.* to test2@localhost; +connect (con2, localhost, test2,,); +connection con1; + +set debug_dbug='d,show_explain_probe_join_exec_start'; +send +select * from t0 where a < 3; + +connection default; +--source include/wait_condition.inc + +connection con2; +evalp show explain for $thr2; + +connection con1; +reap; +set debug_dbug=''; + + + +revoke all privileges on test.* from test2@localhost; +drop user test2@localhost; + ## TODO: Test this: have several SHOW EXPLAIN requests be queued up for a ## thread and served together. -## TODO: SHOW EXPLAIN while the primary query is running EXPLAIN EXTENDED/PARTITIONS -## - drop table t0; diff --git a/sql/my_apc.cc b/sql/my_apc.cc index 48d539aed78..b5f2300c17f 100644 --- a/sql/my_apc.cc +++ b/sql/my_apc.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2009, 2011, Monty Program Ab + Copyright (c) 2011 - 2012, Monty Program 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 diff --git a/sql/my_apc.h b/sql/my_apc.h index 99861ca3194..88df8145186 100644 --- a/sql/my_apc.h +++ b/sql/my_apc.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2009, 2011, Monty Program Ab + Copyright (c) 2011 - 2012, Monty Program 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 diff --git a/sql/sql_class.h b/sql/sql_class.h index 73123151738..d1183225a83 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1552,7 +1552,7 @@ public: }; class THD; -void mysqld_show_explain(THD *thd, ulong thread_id); +void mysqld_show_explain(THD *thd, const char *calling_user, ulong thread_id); #ifndef DBUG_OFF void dbug_serve_apcs(THD *thd, int n_calls); #endif diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 18db712d6cb..9ebb1b3f36e 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3130,6 +3130,7 @@ end_with_restore_list: break; case SQLCOM_SHOW_EXPLAIN: { + const char *effective_user; /* Same security as SHOW PROCESSLIST (TODO check this) */ if (!thd->security_ctx->priv_user[0] && check_global_access(thd,PROCESS_ACL)) @@ -3150,8 +3151,10 @@ end_with_restore_list: MYF(0)); goto error; } + effective_user=(thd->security_ctx->master_access & PROCESS_ACL ? NullS : + thd->security_ctx->priv_user); - mysqld_show_explain(thd, (ulong)it->val_int()); + mysqld_show_explain(thd, effective_user, (ulong)it->val_int()); break; } case SQLCOM_SHOW_AUTHORS: diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 145f4fbebcc..d26c8f18340 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2002,8 +2002,11 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) /* SHOW EXPLAIN FOR command handler - @param thd Current thread's thd - @param thread_id Thread whose explain we need + @param thd Current thread's thd + @param calling_user User that invoked SHOW EXPLAIN, or NULL if the user + has SUPER or PROCESS privileges, and so is allowed + to run SHOW EXPLAIN on anybody. + @param thread_id Thread whose explain we need @notes - Attempt to do "SHOW EXPLAIN FOR " will properly produce "target not @@ -2011,7 +2014,7 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) - todo: check how all this can/will work when using thread pools */ -void mysqld_show_explain(THD *thd, ulong thread_id) +void mysqld_show_explain(THD *thd, const char *calling_user, ulong thread_id) { THD *tmp; Protocol *protocol= thd->protocol; @@ -2043,6 +2046,22 @@ void mysqld_show_explain(THD *thd, ulong thread_id) if (tmp) { + Security_context *tmp_sctx= tmp->security_ctx; + /* + If calling_user==NULL, calling thread has SUPER or PROCESS + privilege, and so can do SHOW EXPLAIN on any user. + + if calling_user!=NULL, he's only allowed to view SHOW EXPLAIN on + his own threads. + */ + if (calling_user && (!tmp_sctx->user || strcmp(calling_user, + tmp_sctx->user))) + { + my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "PROCESSLIST"); + mysql_mutex_unlock(&tmp->LOCK_thd_data); + DBUG_VOID_RETURN; + } + bool bres; /* Ok we've found the thread of interest and it won't go away because From 00ff7345fa10fc0de924b7c2acd3ea9ea4cf50aa Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Sat, 30 Jun 2012 06:05:06 +0400 Subject: [PATCH 115/289] - More "local" code in show_explain.test - Better comments - Make unittest compile on Windows --- mysql-test/r/show_explain.result | 2 ++ mysql-test/t/show_explain.test | 2 ++ sql/my_apc.cc | 6 +----- sql/my_apc.h | 6 +++--- unittest/sql/my_apc-t.cc | 1 + 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/mysql-test/r/show_explain.result b/mysql-test/r/show_explain.result index a4097b9d65e..7c22a2c6435 100644 --- a/mysql-test/r/show_explain.result +++ b/mysql-test/r/show_explain.result @@ -735,6 +735,7 @@ grant ALL on test.* to test2@localhost; # # First, make sure that user 'test2' cannot do SHOW EXPLAIN on us # +set @show_explain_probe_select_id=1; set debug_dbug='d,show_explain_probe_join_exec_start'; select * from t0 where a < 3; show explain for $thr2; @@ -759,6 +760,7 @@ set debug_dbug=''; # Now, grant test2 a PROCESSLIST permission, and see that he's able to observe us # grant process on *.* to test2@localhost; +set @show_explain_probe_select_id=1; set debug_dbug='d,show_explain_probe_join_exec_start'; select * from t0 where a < 3; show explain for $thr2; diff --git a/mysql-test/t/show_explain.test b/mysql-test/t/show_explain.test index 5db6b96d93b..5cfc0a5e202 100644 --- a/mysql-test/t/show_explain.test +++ b/mysql-test/t/show_explain.test @@ -739,6 +739,7 @@ connection con1; --echo # --echo # First, make sure that user 'test2' cannot do SHOW EXPLAIN on us --echo # +set @show_explain_probe_select_id=1; set debug_dbug='d,show_explain_probe_join_exec_start'; send select * from t0 where a < 3; @@ -772,6 +773,7 @@ grant process on *.* to test2@localhost; connect (con2, localhost, test2,,); connection con1; +set @show_explain_probe_select_id=1; set debug_dbug='d,show_explain_probe_join_exec_start'; send select * from t0 where a < 3; diff --git a/sql/my_apc.cc b/sql/my_apc.cc index b5f2300c17f..1cc13f41566 100644 --- a/sql/my_apc.cc +++ b/sql/my_apc.cc @@ -22,11 +22,7 @@ #endif -/* - Standalone testing: - g++ -c -DMY_APC_STANDALONE -g -I.. -I../include -o my_apc.o my_apc.cc - g++ -L../mysys -L../dbug -L../strings my_apc.o -lmysys -ldbug -lmystrings -lpthread -lrt -*/ +/* For standalone testing of APC system, see unittest/sql/my_apc-t.cc */ /* diff --git a/sql/my_apc.h b/sql/my_apc.h index 88df8145186..160c19b6353 100644 --- a/sql/my_apc.h +++ b/sql/my_apc.h @@ -34,7 +34,9 @@ */ /* - Target for asynchronous procedue calls (APCs). + Target for asynchronous procedure calls (APCs). + - A target is running in some particular thread, + - One can make calls to it from other threads. */ class Apc_target { @@ -113,5 +115,3 @@ private: } }; -/////////////////////////////////////////////////////////////////////// - diff --git a/unittest/sql/my_apc-t.cc b/unittest/sql/my_apc-t.cc index 741cfbdb124..fccfb6ecd13 100644 --- a/unittest/sql/my_apc-t.cc +++ b/unittest/sql/my_apc-t.cc @@ -84,6 +84,7 @@ void *test_apc_service_thread(void *ptr) mysql_mutex_destroy(&target_mutex); my_thread_end(); pthread_exit(0); + return NULL; } From b97678f066dd9dfb32409c61028080ac14efb1eb Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Sat, 30 Jun 2012 08:29:29 +0400 Subject: [PATCH 116/289] Better comments --- sql/my_apc.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sql/my_apc.h b/sql/my_apc.h index 160c19b6353..93b934c9df1 100644 --- a/sql/my_apc.h +++ b/sql/my_apc.h @@ -80,7 +80,9 @@ private: /* Circular, double-linked list of all enqueued call requests. We use this structure, because we - - process requests sequentially (i.e. they are removed from the front) + - process requests sequentially: requests are added at the end of the + list and removed from the front. With circular list, we can keep one + pointer. - a thread that has posted a request may time out (or be KILLed) and cancel the request, which means we need a fast request-removal operation. From 2fc2d9a23287d71c665a81eac2ade64d2c22f183 Mon Sep 17 00:00:00 2001 From: Joerg Bruehe Date: Mon, 2 Jul 2012 13:09:33 +0200 Subject: [PATCH 117/289] Added some extra optional path to test suites. --- mysql-test/lib/My/Find.pm | 7 ++++--- mysql-test/lib/mtr_cases.pm | 5 ++++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/mysql-test/lib/My/Find.pm b/mysql-test/lib/My/Find.pm index 952a3c4143d..1f99c470e73 100644 --- a/mysql-test/lib/My/Find.pm +++ b/mysql-test/lib/My/Find.pm @@ -126,9 +126,9 @@ sub my_find_file { # # sub my_find_dir { - my ($base, $paths, $dirs, $required)= @_; - croak "usage: my_find_dir(, [, ])" - unless (@_ == 3 or @_ == 2); + my ($base, $paths, $dirs, $optional)= @_; + croak "usage: my_find_dir(, [, [, ]])" + unless (@_ == 3 or @_ == 2 or @_ == 4); # ------------------------------------------------------- # Find and return the first directory @@ -136,6 +136,7 @@ sub my_find_dir { foreach my $path (my_find_paths($base, $paths, $dirs)) { return $path if ( -d $path ); } + return "" if $optional; find_error($base, $paths, $dirs); } diff --git a/mysql-test/lib/mtr_cases.pm b/mysql-test/lib/mtr_cases.pm index c8381e16061..2f68b70e3e2 100644 --- a/mysql-test/lib/mtr_cases.pm +++ b/mysql-test/lib/mtr_cases.pm @@ -137,6 +137,7 @@ sub collect_test_cases ($$$$) { { push(@$cases, collect_one_suite($suite, $opt_cases, $opt_skip_test_list)); last if $some_test_found; + push(@$cases, collect_one_suite("i_".$suite, $opt_cases, $opt_skip_test_list)); } } @@ -288,13 +289,15 @@ sub collect_one_suite($) $suitedir= my_find_dir($::basedir, ["share/mysql-test/suite", "mysql-test/suite", + "internal/mysql-test/suite", "mysql-test", # Look in storage engine specific suite dirs "storage/*/mtr", # Look in plugin specific suite dir "plugin/$suite/tests", ], - [$suite, "mtr"]); + [$suite, "mtr"], ($suite =~ /^i_/)); + return unless $suitedir; } mtr_verbose("suitedir: $suitedir"); } From 608c2c018e27cd27df8cbd57e3538509734e8dc0 Mon Sep 17 00:00:00 2001 From: Mayank Prasad Date: Tue, 3 Jul 2012 09:55:51 +0530 Subject: [PATCH 118/289] Bug#13417440 : 63340: ARCHIVE FILE IO NOT INSTRUMENTED Details: - Modified test case to make sure its run for all and not only for archive Storage Engine. --- mysql-test/suite/perfschema/r/query_cache.result | 12 ++++++------ mysql-test/suite/perfschema/t/query_cache.test | 5 ++--- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/mysql-test/suite/perfschema/r/query_cache.result b/mysql-test/suite/perfschema/r/query_cache.result index 56511999ab2..8786cd055ca 100644 --- a/mysql-test/suite/perfschema/r/query_cache.result +++ b/mysql-test/suite/perfschema/r/query_cache.result @@ -36,9 +36,9 @@ Qcache_hits 1 select spins from performance_schema.events_waits_current order by event_name limit 1; spins NULL -select name from performance_schema.setup_instruments order by name limit 1; -name -wait/io/file/archive/data +select * from performance_schema.setup_timers where name='wait'; +NAME TIMER_NAME +wait CYCLE show status like "Qcache_queries_in_cache"; Variable_name Value Qcache_queries_in_cache 1 @@ -51,9 +51,9 @@ Qcache_hits 1 select spins from performance_schema.events_waits_current order by event_name limit 1; spins NULL -select name from performance_schema.setup_instruments order by name limit 1; -name -wait/io/file/archive/data +select * from performance_schema.setup_timers where name='wait'; +NAME TIMER_NAME +wait CYCLE show status like "Qcache_queries_in_cache"; Variable_name Value Qcache_queries_in_cache 1 diff --git a/mysql-test/suite/perfschema/t/query_cache.test b/mysql-test/suite/perfschema/t/query_cache.test index 08292306a25..60d4a648222 100644 --- a/mysql-test/suite/perfschema/t/query_cache.test +++ b/mysql-test/suite/perfschema/t/query_cache.test @@ -6,7 +6,6 @@ --source include/have_query_cache.inc --source include/not_embedded.inc --source include/have_perfschema.inc ---source include/have_archive.inc --disable_warnings drop table if exists t1; @@ -35,7 +34,7 @@ show status like "Qcache_hits"; select spins from performance_schema.events_waits_current order by event_name limit 1; -select name from performance_schema.setup_instruments order by name limit 1; +select * from performance_schema.setup_timers where name='wait'; show status like "Qcache_queries_in_cache"; show status like "Qcache_inserts"; @@ -43,7 +42,7 @@ show status like "Qcache_hits"; select spins from performance_schema.events_waits_current order by event_name limit 1; -select name from performance_schema.setup_instruments order by name limit 1; +select * from performance_schema.setup_timers where name='wait'; show status like "Qcache_queries_in_cache"; show status like "Qcache_inserts"; From 91c8e79fcd98bb586f32b22f5d67fcd5ae08ae28 Mon Sep 17 00:00:00 2001 From: Rohit Kalhans Date: Tue, 3 Jul 2012 18:00:21 +0530 Subject: [PATCH 119/289] BUG#11762667:MYSQLBINLOG IGNORES ERRORS WHILE WRITING OUTPUT This is a followup patch for the bug enabling the test i_binlog.binlog_mysqlbinlog_file_write.test this was disabled in mysql trunk and mysql 5.5 as in the release build mysqlbinlog was not debug compiled whereas the mysqld was. Since have_debug.inc script checks only for mysqld to be debug compiled, the test was not being skipped on release builds. We resolve this problem by creating a new inc file mysqlbinlog_have_debug.inc which checks exclusively for mysqlbinlog to be debug compiled. if not it skips the test. mysql-test/include/mysqlbinlog_have_debug.inc: new inc file to check if mysqlbinlog is debug compiled. --- mysql-test/include/mysqlbinlog_have_debug.inc | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 mysql-test/include/mysqlbinlog_have_debug.inc diff --git a/mysql-test/include/mysqlbinlog_have_debug.inc b/mysql-test/include/mysqlbinlog_have_debug.inc new file mode 100644 index 00000000000..14da1379ecd --- /dev/null +++ b/mysql-test/include/mysqlbinlog_have_debug.inc @@ -0,0 +1,34 @@ +############################################# +# checks if mysqlbinlog is debug compiled +# this "cannot" be done simply by using +# have_debug.inc +############################################# + +--disable_query_log +--let $temp_out_help_file=$MYSQL_TMP_DIR/mysqlbinlog_help.tmp +--exec $MYSQL_BINLOG --help>$temp_out_help_file +let log_tmp=$temp_out_help_file; +--let $temp_inc=$MYSQL_TMP_DIR/temp.inc +let inc_tmp=$temp_inc; + +--perl +use strict; +my $tmp_file= $ENV{'log_tmp'} or die "log_tmp not set"; +open(FILE, "$tmp_file") or die("Unable to open $tmp_file: $!\n"); +my $count = () = grep(/Output debug log/g,); +close FILE; + +my $temp_inc= $ENV{'inc_tmp'} or die "temp_inc not set"; +open(FILE_INC,">", "$temp_inc") or die("can't open file \"$temp_inc\": $!"); +print FILE_INC '--let $is_debug= '.$count; +close FILE_INC; +EOF +--source $temp_inc + +if (!$is_debug) +{ + --skip mysqlbinlog needs to be debug compiled +} +--remove_file $temp_out_help_file +--remove_file $temp_inc +--enable_query_log From 46525c35b084a8af4dc99c8da78cf9e40e69dee1 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Wed, 4 Jul 2012 14:34:45 +0400 Subject: [PATCH 120/289] MDEV-376: Wrong result (missing rows) with index_merge+index_merge_intersection, join - Let QUICK_RANGE_SELECT::init_ror_merged_scan() call quick->reset() only after we've set the column read bitmaps. --- mysql-test/r/index_merge_innodb.result | 15 +++++++++++++++ mysql-test/t/index_merge_innodb.test | 15 +++++++++++++++ sql/opt_range.cc | 17 ++++++++++++++--- 3 files changed, 44 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/index_merge_innodb.result b/mysql-test/r/index_merge_innodb.result index b8eda092291..92bcb2e88f0 100644 --- a/mysql-test/r/index_merge_innodb.result +++ b/mysql-test/r/index_merge_innodb.result @@ -777,4 +777,19 @@ commit; select * from t1 where t1.zone_id=830 AND modified=9; pk zone_id modified drop table t0, t1; +# +# MDEV-376: Wrong result (missing rows) with index_merge+index_merge_intersection, join +# +CREATE TABLE t1 ( +a INT, b CHAR(1), c CHAR(1), KEY(a), KEY(b) +) ENGINE=InnoDB; +INSERT INTO t1 VALUES (8,'v','v'),(8,'m','m'),(9,'d','d'); +SELECT ta.* FROM t1 AS ta, t1 AS tb +WHERE ( tb.b != ta.b OR tb.a = ta.a ) +AND ( tb.b = ta.c OR tb.b = ta.b ); +a b c +8 v v +8 m m +9 d d +DROP TABLE t1; set optimizer_switch= @optimizer_switch_save; diff --git a/mysql-test/t/index_merge_innodb.test b/mysql-test/t/index_merge_innodb.test index 0fd3c54c787..6a1cb53dc40 100644 --- a/mysql-test/t/index_merge_innodb.test +++ b/mysql-test/t/index_merge_innodb.test @@ -156,6 +156,21 @@ select * from t1 where t1.zone_id=830 AND modified=9; drop table t0, t1; +--echo # +--echo # MDEV-376: Wrong result (missing rows) with index_merge+index_merge_intersection, join +--echo # +CREATE TABLE t1 ( + a INT, b CHAR(1), c CHAR(1), KEY(a), KEY(b) +) ENGINE=InnoDB; + +INSERT INTO t1 VALUES (8,'v','v'),(8,'m','m'),(9,'d','d'); + + +SELECT ta.* FROM t1 AS ta, t1 AS tb +WHERE ( tb.b != ta.b OR tb.a = ta.a ) + AND ( tb.b = ta.c OR tb.b = ta.b ); + +DROP TABLE t1; set optimizer_switch= @optimizer_switch_save; diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 0390ac1101e..da328063e56 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -2008,7 +2008,7 @@ int QUICK_RANGE_SELECT::init_ror_merged_scan(bool reuse_handler) if (reuse_handler) { DBUG_PRINT("info", ("Reusing handler 0x%lx", (long) file)); - if (init() || reset()) + if (init()) { DBUG_RETURN(1); } @@ -2043,7 +2043,7 @@ int QUICK_RANGE_SELECT::init_ror_merged_scan(bool reuse_handler) if (file->ha_external_lock(thd, F_RDLCK)) goto failure; - if (init() || reset()) + if (init()) { file->ha_external_lock(thd, F_UNLCK); file->ha_close(); @@ -2090,7 +2090,18 @@ end: head->key_read= org_key_read; bitmap_copy(&column_bitmap, head->read_set); head->column_bitmaps_set(&column_bitmap, &column_bitmap); - + + if (reset()) + { + if (!reuse_handler) + { + file->ha_external_lock(thd, F_UNLCK); + file->ha_close(); + goto failure; + } + else + DBUG_RETURN(1); + } DBUG_RETURN(0); failure: From 9ce35ffc8677ff3c7171576497ed6c7330000b72 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Wed, 4 Jul 2012 17:48:58 +0300 Subject: [PATCH 121/289] Bug #11753490: 44939: sql dumps containing broad views fail when executing The problem is that mysql lacks information about the objects a view depends on so it can't dump views and tables in the proper order. Thus it needs to create "stand-in" myisam tables for each view while dumping the tables that it later drops and replaces with the actual view view definition. But since views can have much more columns than an actual table creating these stand-in tables may be problematic. There's no way to portably find out how many columns an mysiam table can have. It's a complicated formula depending on internal server constants. Thus we can't have a reliable error check without repeating the logic and the formula inside mysqldump. 1. Changed the type of the columns of the stand-in tables mysqldump makes to satisfy view dependencies from the original type to smallint to save on row space. 2. Added a warning on the mysqldump's standard error for a possible problems replaying the dump file if the columns of a view exceed 1000. 3. Added a test case. --- client/mysqldump.c | 35 ++++++++++++++++++++------ mysql-test/r/mysqldump.result | 46 +++++++++++++++++------------------ 2 files changed, 51 insertions(+), 30 deletions(-) diff --git a/client/mysqldump.c b/client/mysqldump.c index e273ca0e7fd..dcfe25a5f61 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -2558,6 +2558,7 @@ static uint get_table_structure(char *table, char *db, char *table_type, if (strcmp(field->name, "View") == 0) { char *scv_buff= NULL; + my_ulonglong n_cols; verbose_msg("-- It's a view, create dummy table for view\n"); @@ -2572,8 +2573,8 @@ static uint get_table_structure(char *table, char *db, char *table_type, the same name in order to satisfy views that depend on this view. The table will be removed when the actual view is created. - The properties of each column, aside from the data type, are not - preserved in this temporary table, because they are not necessary. + The properties of each column, are not preserved in this temporary + table, because they are not necessary. This will not be necessary once we can determine dependencies between views and can simply dump them in the appropriate order. @@ -2600,8 +2601,23 @@ static uint get_table_structure(char *table, char *db, char *table_type, else my_free(scv_buff); - if (mysql_num_rows(result)) + n_cols= mysql_num_rows(result); + if (0 != n_cols) { + + /* + The actual formula is based on the column names and how the .FRM + files are stored and is too volatile to be repeated here. + Thus we simply warn the user if the columns exceed a limit we + know works most of the time. + */ + if (n_cols >= 1000) + fprintf(stderr, + "-- Warning: Creating a stand-in table for view %s may" + " fail when replaying the dump file produced because " + "of the number of columns exceeding 1000. Exercise " + "caution when replaying the produced dump file.\n", + table); if (opt_drop) { /* @@ -2628,14 +2644,19 @@ static uint get_table_structure(char *table, char *db, char *table_type, row= mysql_fetch_row(result); - fprintf(sql_file, " %s %s", quote_name(row[0], name_buff, 0), - row[1]); + /* + The actual column type doesn't matter anyway, since the table will + be dropped at run time. + We do tinyint to avoid hitting the row size limit. + */ + fprintf(sql_file, " %s tinyint NOT NULL", + quote_name(row[0], name_buff, 0)); while((row= mysql_fetch_row(result))) { /* col name, col type */ - fprintf(sql_file, ",\n %s %s", - quote_name(row[0], name_buff, 0), row[1]); + fprintf(sql_file, ",\n %s tinyint NOT NULL", + quote_name(row[0], name_buff, 0)); } /* diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index 15fdddb18be..5f3b29f5f7c 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -1988,7 +1988,7 @@ DROP TABLE IF EXISTS `v2`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; /*!50001 CREATE TABLE `v2` ( - `a` varchar(30) + `a` tinyint NOT NULL ) ENGINE=MyISAM */; SET character_set_client = @saved_cs_client; /*!50001 DROP TABLE IF EXISTS `v2`*/; @@ -2082,7 +2082,7 @@ DROP TABLE IF EXISTS `v1`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; /*!50001 CREATE TABLE `v1` ( - `a` int(11) + `a` tinyint NOT NULL ) ENGINE=MyISAM */; SET character_set_client = @saved_cs_client; /*!50001 DROP TABLE IF EXISTS `v1`*/; @@ -2156,7 +2156,7 @@ DROP TABLE IF EXISTS `v2`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; /*!50001 CREATE TABLE `v2` ( - `a` varchar(30) + `a` tinyint NOT NULL ) ENGINE=MyISAM */; SET character_set_client = @saved_cs_client; /*!50001 DROP TABLE IF EXISTS `v2`*/; @@ -2270,9 +2270,9 @@ DROP TABLE IF EXISTS `v1`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; /*!50001 CREATE TABLE `v1` ( - `a` int(11), - `b` int(11), - `c` varchar(30) + `a` tinyint NOT NULL, + `b` tinyint NOT NULL, + `c` tinyint NOT NULL ) ENGINE=MyISAM */; SET character_set_client = @saved_cs_client; DROP TABLE IF EXISTS `v2`; @@ -2280,7 +2280,7 @@ DROP TABLE IF EXISTS `v2`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; /*!50001 CREATE TABLE `v2` ( - `a` int(11) + `a` tinyint NOT NULL ) ENGINE=MyISAM */; SET character_set_client = @saved_cs_client; DROP TABLE IF EXISTS `v3`; @@ -2288,9 +2288,9 @@ DROP TABLE IF EXISTS `v3`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; /*!50001 CREATE TABLE `v3` ( - `a` int(11), - `b` int(11), - `c` varchar(30) + `a` tinyint NOT NULL, + `b` tinyint NOT NULL, + `c` tinyint NOT NULL ) ENGINE=MyISAM */; SET character_set_client = @saved_cs_client; /*!50001 DROP TABLE IF EXISTS `v1`*/; @@ -3027,9 +3027,9 @@ DROP TABLE IF EXISTS `v0`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; /*!50001 CREATE TABLE `v0` ( - `a` int(11), - `b` varchar(32), - `c` varchar(32) + `a` tinyint NOT NULL, + `b` tinyint NOT NULL, + `c` tinyint NOT NULL ) ENGINE=MyISAM */; SET character_set_client = @saved_cs_client; DROP TABLE IF EXISTS `v1`; @@ -3037,9 +3037,9 @@ DROP TABLE IF EXISTS `v1`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; /*!50001 CREATE TABLE `v1` ( - `a` int(11), - `b` varchar(32), - `c` varchar(32) + `a` tinyint NOT NULL, + `b` tinyint NOT NULL, + `c` tinyint NOT NULL ) ENGINE=MyISAM */; SET character_set_client = @saved_cs_client; DROP TABLE IF EXISTS `v2`; @@ -3047,9 +3047,9 @@ DROP TABLE IF EXISTS `v2`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; /*!50001 CREATE TABLE `v2` ( - `a` int(11), - `b` varchar(32), - `c` varchar(32) + `a` tinyint NOT NULL, + `b` tinyint NOT NULL, + `c` tinyint NOT NULL ) ENGINE=MyISAM */; SET character_set_client = @saved_cs_client; @@ -3429,7 +3429,7 @@ DROP TABLE IF EXISTS `v1`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; /*!50001 CREATE TABLE `v1` ( - `id` int(11) + `id` tinyint NOT NULL ) ENGINE=MyISAM */; SET character_set_client = @saved_cs_client; @@ -3489,7 +3489,7 @@ USE `mysqldump_views`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; /*!50001 CREATE TABLE `nasishnasifu` ( - `id` bigint(20) unsigned + `id` tinyint NOT NULL ) ENGINE=MyISAM */; SET character_set_client = @saved_cs_client; @@ -3882,7 +3882,7 @@ DROP TABLE IF EXISTS `v2`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; /*!50001 CREATE TABLE `v2` ( - `c` int(11) + `c` tinyint NOT NULL ) ENGINE=MyISAM */; SET character_set_client = @saved_cs_client; /*!50001 DROP TABLE IF EXISTS `v2`*/; @@ -4299,7 +4299,7 @@ DROP TABLE IF EXISTS `v1`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; /*!50001 CREATE TABLE `v1` ( - `id` int(11) + `id` tinyint NOT NULL ) ENGINE=MyISAM */; SET character_set_client = @saved_cs_client; From 06f6e4fe957c6edd7b3655d4987d0fbd67cdb9d6 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Thu, 5 Jul 2012 09:55:20 +0300 Subject: [PATCH 122/289] Bug #12998841: libmysql divulges plaintext password upon request in 5.5 1. Clear text password client plugin disabled by default. 2. Added an environment variable LIBMYSQL_ENABLE_CLEARTEXT_PLUGIN, that when set to something starting with '1', 'Y' or 'y' will enable the clear text plugin for all connections. 3. Added a new mysql_options() option : MYSQL_ENABLE_CLEARTEXT_PLUGIN that takes an my_bool argument. When the value of the argument is non-zero the clear text plugin is enabled for this connection only. 4. Added an enable-cleartext-plugin config file option that takes a numeric argument. If the numeric value of the numeric argument is non-zero the clear text plugin is enabled for the connection 5. Added a boolean command line option "--enable_cleartext_plugin" to mysql, mysqlslap and mysqladmin. When specified it will call mysql_options with the effect of #3 6. Added a new CLEARTEXT option to the connect command in mysqltest. When specified it will enable the cleartext plugin for usage. 7. Added test cases and updated existing ones that need the clear text plugin. --- client/client_priv.h | 1 + client/mysql.cc | 13 +++++++ client/mysqladmin.cc | 13 +++++++ client/mysqlslap.c | 12 ++++++ client/mysqltest.cc | 8 +++- include/mysql.h | 3 +- include/mysql.h.pp | 3 +- include/sql_common.h | 2 + mysql-test/t/plugin_auth.test | 4 +- sql-common/client.c | 69 ++++++++++++++++++++++++++++++----- sql-common/client_plugin.c | 5 +++ 11 files changed, 119 insertions(+), 14 deletions(-) diff --git a/client/client_priv.h b/client/client_priv.h index b776dcf8014..2362811d2b3 100644 --- a/client/client_priv.h +++ b/client/client_priv.h @@ -87,6 +87,7 @@ enum options_client OPT_PLUGIN_DIR, OPT_DEFAULT_AUTH, OPT_DEFAULT_PLUGIN, + OPT_ENABLE_CLEARTEXT_PLUGIN, OPT_MAX_CLIENT_OPTION }; diff --git a/client/mysql.cc b/client/mysql.cc index b6bc2f4b68f..630c6215603 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -148,6 +148,8 @@ static my_bool column_types_flag; 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 uint opt_enable_cleartext_plugin= 0; +static my_bool using_opt_enable_cleartext_plugin= 0; static uint my_end_arg; static char * opt_mysql_unix_port=0; static int connect_flag=CLIENT_INTERACTIVE; @@ -1409,6 +1411,10 @@ static struct my_option my_long_options[] = &default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"delimiter", OPT_DELIMITER, "Delimiter to be used.", &delimiter_str, &delimiter_str, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"enable_cleartext_plugin", OPT_ENABLE_CLEARTEXT_PLUGIN, + "Enable/disable the clear text authentication plugin.", + &opt_enable_cleartext_plugin, &opt_enable_cleartext_plugin, + 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"execute", 'e', "Execute command and quit. (Disables --force and history file.)", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"vertical", 'E', "Print the output of a query (rows) vertically.", @@ -1636,6 +1642,9 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), case OPT_LOCAL_INFILE: using_opt_local_infile=1; break; + case OPT_ENABLE_CLEARTEXT_PLUGIN: + using_opt_enable_cleartext_plugin= TRUE; + break; case OPT_TEE: if (argument == disabled_my_option) { @@ -4321,6 +4330,10 @@ sql_real_connect(char *host,char *database,char *user,char *password, if (opt_default_auth && *opt_default_auth) mysql_options(&mysql, MYSQL_DEFAULT_AUTH, opt_default_auth); + if (using_opt_enable_cleartext_plugin) + mysql_options(&mysql, MYSQL_ENABLE_CLEARTEXT_PLUGIN, + (char*) &opt_enable_cleartext_plugin); + if (!mysql_real_connect(&mysql, host, user, password, database, opt_mysql_port, opt_mysql_unix_port, connect_flag | CLIENT_MULTI_STATEMENTS)) diff --git a/client/mysqladmin.cc b/client/mysqladmin.cc index 3f33c25e664..321efd36642 100644 --- a/client/mysqladmin.cc +++ b/client/mysqladmin.cc @@ -43,6 +43,8 @@ static uint opt_count_iterations= 0, my_end_arg; static ulong opt_connect_timeout, opt_shutdown_timeout; static char * unix_port=0; static char *opt_plugin_dir= 0, *opt_default_auth= 0; +static uint opt_enable_cleartext_plugin= 0; +static my_bool using_opt_enable_cleartext_plugin= 0; #ifdef HAVE_SMEM static char *shared_memory_base_name=0; @@ -212,6 +214,10 @@ static struct my_option my_long_options[] = "Default authentication client-side plugin to use.", &opt_default_auth, &opt_default_auth, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"enable_cleartext_plugin", OPT_ENABLE_CLEARTEXT_PLUGIN, + "Enable/disable the clear text authentication plugin.", + &opt_enable_cleartext_plugin, &opt_enable_cleartext_plugin, + 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; @@ -282,6 +288,9 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), opt_protocol= find_type_or_exit(argument, &sql_protocol_typelib, opt->name); break; + case OPT_ENABLE_CLEARTEXT_PLUGIN: + using_opt_enable_cleartext_plugin= TRUE; + break; } if (error) { @@ -354,6 +363,10 @@ int main(int argc,char *argv[]) if (opt_default_auth && *opt_default_auth) mysql_options(&mysql, MYSQL_DEFAULT_AUTH, opt_default_auth); + if (using_opt_enable_cleartext_plugin) + mysql_options(&mysql, MYSQL_ENABLE_CLEARTEXT_PLUGIN, + (char*) &opt_enable_cleartext_plugin); + if (sql_connect(&mysql, option_wait)) { /* diff --git a/client/mysqlslap.c b/client/mysqlslap.c index a2c01b85b5a..ac1cc31733c 100644 --- a/client/mysqlslap.c +++ b/client/mysqlslap.c @@ -125,6 +125,8 @@ static char *host= NULL, *opt_password= NULL, *user= NULL, *post_system= NULL, *opt_mysql_unix_port= NULL; static char *opt_plugin_dir= 0, *opt_default_auth= 0; +static uint opt_enable_cleartext_plugin= 0; +static my_bool using_opt_enable_cleartext_plugin= 0; const char *delimiter= "\n"; @@ -348,6 +350,9 @@ int main(int argc, char **argv) if (opt_default_auth && *opt_default_auth) mysql_options(&mysql, MYSQL_DEFAULT_AUTH, opt_default_auth); + if (using_opt_enable_cleartext_plugin) + mysql_options(&mysql, MYSQL_ENABLE_CLEARTEXT_PLUGIN, + (char*) &opt_enable_cleartext_plugin); if (!opt_only_print) { if (!(mysql_real_connect(&mysql, host, user, opt_password, @@ -603,6 +608,10 @@ static struct my_option my_long_options[] = "Detach (close and reopen) connections after X number of requests.", &detach_rate, &detach_rate, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"enable_cleartext_plugin", OPT_ENABLE_CLEARTEXT_PLUGIN, + "Enable/disable the clear text authentication plugin.", + &opt_enable_cleartext_plugin, &opt_enable_cleartext_plugin, + 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"engine", 'e', "Storage engine to use for creating the table.", &default_engine, &default_engine, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, @@ -761,6 +770,9 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), case 'I': /* Info */ usage(); exit(0); + case OPT_ENABLE_CLEARTEXT_PLUGIN: + using_opt_enable_cleartext_plugin= TRUE; + break; } DBUG_RETURN(0); } diff --git a/client/mysqltest.cc b/client/mysqltest.cc index b1784fdc7b6..34d8edcbe0b 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -5456,7 +5456,7 @@ void do_connect(struct st_command *command) int con_port= opt_port; char *con_options; my_bool con_ssl= 0, con_compress= 0; - my_bool con_pipe= 0, con_shm= 0; + my_bool con_pipe= 0, con_shm= 0, con_cleartext_enable= 0; struct st_connection* con_slot; static DYNAMIC_STRING ds_connection_name; @@ -5546,6 +5546,8 @@ void do_connect(struct st_command *command) con_pipe= 1; else if (!strncmp(con_options, "SHM", 3)) con_shm= 1; + else if (!strncmp(con_options, "CLEARTEXT", 9)) + con_cleartext_enable= 1; else die("Illegal option to connect: %.*s", (int) (end - con_options), con_options); @@ -5642,6 +5644,10 @@ void do_connect(struct st_command *command) if (ds_default_auth.length) mysql_options(&con_slot->mysql, MYSQL_DEFAULT_AUTH, ds_default_auth.str); + + if (con_cleartext_enable) + mysql_options(&con_slot->mysql, MYSQL_ENABLE_CLEARTEXT_PLUGIN, + (char*) &con_cleartext_enable); /* Special database to allow one to connect without a database name */ if (ds_database.length && !strcmp(ds_database.str,"*NO-ONE*")) dynstr_set(&ds_database, ""); diff --git a/include/mysql.h b/include/mysql.h index cff8c647152..0ed35413a1c 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -166,7 +166,8 @@ enum mysql_option MYSQL_OPT_USE_REMOTE_CONNECTION, MYSQL_OPT_USE_EMBEDDED_CONNECTION, MYSQL_OPT_GUESS_CONNECTION, MYSQL_SET_CLIENT_IP, MYSQL_SECURE_AUTH, MYSQL_REPORT_DATA_TRUNCATION, MYSQL_OPT_RECONNECT, - MYSQL_OPT_SSL_VERIFY_SERVER_CERT, MYSQL_PLUGIN_DIR, MYSQL_DEFAULT_AUTH + MYSQL_OPT_SSL_VERIFY_SERVER_CERT, MYSQL_PLUGIN_DIR, MYSQL_DEFAULT_AUTH, + MYSQL_ENABLE_CLEARTEXT_PLUGIN }; /** diff --git a/include/mysql.h.pp b/include/mysql.h.pp index 15ec563dfc2..c2c5ba35044 100644 --- a/include/mysql.h.pp +++ b/include/mysql.h.pp @@ -262,7 +262,8 @@ enum mysql_option MYSQL_OPT_USE_REMOTE_CONNECTION, MYSQL_OPT_USE_EMBEDDED_CONNECTION, MYSQL_OPT_GUESS_CONNECTION, MYSQL_SET_CLIENT_IP, MYSQL_SECURE_AUTH, MYSQL_REPORT_DATA_TRUNCATION, MYSQL_OPT_RECONNECT, - MYSQL_OPT_SSL_VERIFY_SERVER_CERT, MYSQL_PLUGIN_DIR, MYSQL_DEFAULT_AUTH + MYSQL_OPT_SSL_VERIFY_SERVER_CERT, MYSQL_PLUGIN_DIR, MYSQL_DEFAULT_AUTH, + MYSQL_ENABLE_CLEARTEXT_PLUGIN }; struct st_mysql_options_extention; struct st_mysql_options { diff --git a/include/sql_common.h b/include/sql_common.h index 307b443d6d6..a2ea3ac45e7 100644 --- a/include/sql_common.h +++ b/include/sql_common.h @@ -31,6 +31,7 @@ extern const char *not_error_sqlstate; struct st_mysql_options_extention { char *plugin_dir; char *default_auth; + my_bool enable_cleartext_plugin; }; typedef struct st_mysql_methods @@ -104,6 +105,7 @@ int mysql_client_plugin_init(); void mysql_client_plugin_deinit(); struct st_mysql_client_plugin; extern struct st_mysql_client_plugin *mysql_client_builtins[]; +extern my_bool libmysql_cleartext_plugin_enabled; #ifdef __cplusplus } diff --git a/mysql-test/t/plugin_auth.test b/mysql-test/t/plugin_auth.test index f169360cf2e..75d3ef3e807 100644 --- a/mysql-test/t/plugin_auth.test +++ b/mysql-test/t/plugin_auth.test @@ -422,10 +422,10 @@ CREATE USER uplain@localhost IDENTIFIED WITH 'cleartext_plugin_server' --echo ## test plugin auth --disable_query_log --error ER_ACCESS_DENIED_ERROR : this should fail : no grant -connect(cleartext_fail_con,localhost,uplain,cleartext_test2); +connect(cleartext_fail_con,localhost,uplain,cleartext_test2,,,,CLEARTEXT); --enable_query_log -connect(cleartext_con,localhost,uplain,cleartext_test); +connect(cleartext_con,localhost,uplain,cleartext_test,,,,CLEARTEXT); connection cleartext_con; select USER(),CURRENT_USER(); diff --git a/sql-common/client.c b/sql-common/client.c index 08f4bfb1151..381768834cd 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -1136,7 +1136,8 @@ static const char *default_options[]= "connect-timeout", "local-infile", "disable-local-infile", "ssl-cipher", "max-allowed-packet", "protocol", "shared-memory-base-name", "multi-results", "multi-statements", "multi-queries", "secure-auth", - "report-data-truncation", "plugin-dir", "default-auth", + "report-data-truncation", "plugin-dir", "default-auth", + "enable-cleartext-plugin", NullS }; enum option_id { @@ -1148,6 +1149,7 @@ enum option_id { OPT_ssl_cipher, OPT_max_allowed_packet, OPT_protocol, OPT_shared_memory_base_name, OPT_multi_results, OPT_multi_statements, OPT_multi_queries, OPT_secure_auth, OPT_report_data_truncation, OPT_plugin_dir, OPT_default_auth, + OPT_enable_cleartext_plugin, OPT_keep_this_one_last }; @@ -1180,14 +1182,27 @@ static int add_init_command(struct st_mysql_options *options, const char *cmd) return 0; } -#define EXTENSION_SET_STRING(OPTS, X, STR) \ - if ((OPTS)->extension) \ - my_free((OPTS)->extension->X); \ - else \ +#define ALLOCATE_EXTENSIONS(OPTS) \ (OPTS)->extension= (struct st_mysql_options_extention *) \ my_malloc(sizeof(struct st_mysql_options_extention), \ - MYF(MY_WME | MY_ZEROFILL)); \ - (OPTS)->extension->X= my_strdup((STR), MYF(MY_WME)); + MYF(MY_WME | MY_ZEROFILL)) \ + +#define ENSURE_EXTENSIONS_PRESENT(OPTS) \ + do { \ + if (!(OPTS)->extension) \ + ALLOCATE_EXTENSIONS(OPTS); \ + } while (0) + + +#define EXTENSION_SET_STRING(OPTS, X, STR) \ + do { \ + if ((OPTS)->extension) \ + my_free((OPTS)->extension->X); \ + else \ + ALLOCATE_EXTENSIONS(OPTS); \ + (OPTS)->extension->X= ((STR) != NULL) ? \ + my_strdup((STR), MYF(MY_WME)) : NULL; \ + } while (0) void mysql_read_default_options(struct st_mysql_options *options, const char *filename,const char *group) @@ -1386,6 +1401,12 @@ void mysql_read_default_options(struct st_mysql_options *options, case OPT_default_auth: EXTENSION_SET_STRING(options, default_auth, opt_arg); break; + + case OPT_enable_cleartext_plugin: + ENSURE_EXTENSIONS_PRESENT(options); + options->extension->enable_cleartext_plugin= + (!opt_arg || atoi(opt_arg) != 0) ? TRUE : FALSE; + default: DBUG_PRINT("warning",("unknown option: %s",option[0])); } @@ -2782,6 +2803,27 @@ static void client_mpvio_info(MYSQL_PLUGIN_VIO *vio, mpvio_info(mpvio->mysql->net.vio, info); } + +my_bool libmysql_cleartext_plugin_enabled= 0; + +static my_bool check_plugin_enabled(MYSQL *mysql, auth_plugin_t *plugin) +{ + if (plugin == &clear_password_client_plugin && + (!libmysql_cleartext_plugin_enabled && + (!mysql->options.extension || + !mysql->options.extension->enable_cleartext_plugin))) + { + set_mysql_extended_error(mysql, CR_AUTH_PLUGIN_CANNOT_LOAD, + unknown_sqlstate, + ER(CR_AUTH_PLUGIN_CANNOT_LOAD), + clear_password_client_plugin.name, + "plugin not enabled"); + return TRUE; + } + return FALSE; +} + + /** Client side of the plugin driver authentication. @@ -2824,6 +2866,9 @@ int run_plugin_auth(MYSQL *mysql, char *data, uint data_len, auth_plugin_name= auth_plugin->name; } + if (check_plugin_enabled(mysql, auth_plugin)) + DBUG_RETURN(1); + DBUG_PRINT ("info", ("using plugin %s", auth_plugin_name)); mysql->net.last_errno= 0; /* just in case */ @@ -2915,6 +2960,9 @@ int run_plugin_auth(MYSQL *mysql, char *data, uint data_len, auth_plugin_name, MYSQL_CLIENT_AUTHENTICATION_PLUGIN))) DBUG_RETURN (1); + if (check_plugin_enabled(mysql, auth_plugin)) + DBUG_RETURN(1); + mpvio.plugin= auth_plugin; res= auth_plugin->authenticate_user((struct st_plugin_vio *)&mpvio, mysql); @@ -4117,6 +4165,11 @@ mysql_options(MYSQL *mysql,enum mysql_option option, const void *arg) case MYSQL_DEFAULT_AUTH: EXTENSION_SET_STRING(&mysql->options, default_auth, arg); break; + case MYSQL_ENABLE_CLEARTEXT_PLUGIN: + ENSURE_EXTENSIONS_PRESENT(&mysql->options); + mysql->options.extension->enable_cleartext_plugin= + (*(my_bool*) arg) ? TRUE : FALSE; + break; default: DBUG_RETURN(1); } @@ -4336,5 +4389,3 @@ static int clear_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql) return res ? CR_ERROR : CR_OK; } - - diff --git a/sql-common/client_plugin.c b/sql-common/client_plugin.c index 4016f0744be..75faeb7ee97 100644 --- a/sql-common/client_plugin.c +++ b/sql-common/client_plugin.c @@ -197,6 +197,10 @@ err1: static void load_env_plugins(MYSQL *mysql) { char *plugs, *free_env, *s= getenv("LIBMYSQL_PLUGINS"); + char *enable_cleartext_plugin= getenv("LIBMYSQL_ENABLE_CLEARTEXT_PLUGIN"); + + if (enable_cleartext_plugin && strchr("1Yy", enable_cleartext_plugin[0])) + libmysql_cleartext_plugin_enabled= 1; /* no plugins to load */ if(!s) @@ -212,6 +216,7 @@ static void load_env_plugins(MYSQL *mysql) } while (s); my_free(free_env); + } /********** extern functions to be used by libmysql *********************/ From fb3e11d0ab9317a73619d1e5c01669a7c6e034f9 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Thu, 5 Jul 2012 10:18:18 +0300 Subject: [PATCH 123/289] fixed a missing break --- sql-common/client.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sql-common/client.c b/sql-common/client.c index 381768834cd..be24c5e89e4 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -1406,6 +1406,7 @@ void mysql_read_default_options(struct st_mysql_options *options, ENSURE_EXTENSIONS_PRESENT(options); options->extension->enable_cleartext_plugin= (!opt_arg || atoi(opt_arg) != 0) ? TRUE : FALSE; + break; default: DBUG_PRINT("warning",("unknown option: %s",option[0])); From 19e03c683edb4de91756c11f11e3528dd064ce7b Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 5 Jul 2012 09:29:34 +0200 Subject: [PATCH 124/289] The variable "table_cache" is deprecated, use the new name "table_open_cache" instead. Thanks to Ivoz for pointing this out. --- debian/additions/my.cnf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/additions/my.cnf b/debian/additions/my.cnf index fd9bcf19977..a27f8543f0b 100644 --- a/debian/additions/my.cnf +++ b/debian/additions/my.cnf @@ -65,7 +65,7 @@ max_heap_table_size = 32M myisam_recover = BACKUP key_buffer_size = 128M #open-files-limit = 2000 -table_cache = 400 +table_open_cache = 400 myisam_sort_buffer_size = 512M concurrent_insert = 2 read_buffer_size = 2M From 048577429f3adcb27100ace3dd6fd4579bcd9e53 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Thu, 5 Jul 2012 13:41:16 +0300 Subject: [PATCH 125/289] Bug #13889741: HANDLE_FATAL_SIGNAL IN _DB_ENTER_ | HANDLE_FATAL_SIGNAL IN STRNLEN Fixed the following bounds checking problems : 1. in check_if_legal_filename() make sure the null terminated string is long enough before accessing the bytes in it. Prevents pottential read-past-buffer-end 2. in my_wc_mb_filename() of the filename charset check for the end of the destination buffer before sending single byte characters into it. Prevents write-past-end-of-buffer (and garbaling stack in the cases reported here) errors. Added test cases. --- mysys/my_access.c | 3 ++- strings/ctype-utf8.c | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/mysys/my_access.c b/mysys/my_access.c index 210946d50a8..43917da7f98 100644 --- a/mysys/my_access.c +++ b/mysys/my_access.c @@ -148,7 +148,8 @@ static char reserved_map[256]= int check_if_legal_tablename(const char *name) { DBUG_ENTER("check_if_legal_tablename"); - DBUG_RETURN((reserved_map[(uchar) name[0]] & 1) && + DBUG_RETURN(name[0] != 0 && name[1] != 0 && + (reserved_map[(uchar) name[0]] & 1) && (reserved_map[(uchar) name[1]] & 2) && (reserved_map[(uchar) name[2]] & 4) && str_list_find(&reserved_names[1], name)); diff --git a/strings/ctype-utf8.c b/strings/ctype-utf8.c index 205f8c61ddd..a0e69feedab 100644 --- a/strings/ctype-utf8.c +++ b/strings/ctype-utf8.c @@ -4326,6 +4326,10 @@ my_wc_mb_filename(CHARSET_INFO *cs __attribute__((unused)), { int code; char hex[]= "0123456789abcdef"; + + if (s >= e) + return MY_CS_TOOSMALL; + if (wc < 128 && filename_safe_char[wc]) { *s= (uchar) wc; From e3c8fb4a1cf2984cf1aa1fe31ba828de550f619c Mon Sep 17 00:00:00 2001 From: Andrei Elkin Date: Thu, 5 Jul 2012 14:37:48 +0300 Subject: [PATCH 126/289] Bug#14275000 Fixes for BUG11761686 left a flaw that managed to slip away from testing. Only effective filtering branch was actually tested with a regression test added to rpl_filter_tables_not_exist. The reason of the failure is destuction of too early mem-root-allocated memory at the end of the deferred User-var's do_apply_event(). Fixed with bypassing free_root() in the deferred execution branch. Deallocation of created in do_apply_event() items is done by the base code through THD::cleanup_after_query() -> free_items() that the parent Query can't miss. sql/log_event.cc: Do not call free_root() in case the deferred User-var event. Necessary methods to the User-var class are added, do_apply_event() refined. sql/log_event.h: Necessary methods to avoid destoying mem-root-based memory at User-var applying are defined. --- sql/log_event.cc | 16 ++++++++++++---- sql/log_event.h | 11 ++++++++++- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/sql/log_event.cc b/sql/log_event.cc index a47b3680d82..1822951cccf 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -5640,6 +5640,9 @@ User_var_log_event:: User_var_log_event(const char* buf, const Format_description_log_event* description_event) :Log_event(buf, description_event) +#ifndef MYSQL_CLIENT + , deferred(false) +#endif { /* The Post-Header is empty. The Variable Data part begins immediately. */ buf+= description_event->common_header_len + @@ -5848,7 +5851,10 @@ int User_var_log_event::do_apply_event(Relay_log_info const *rli) CHARSET_INFO *charset; if (rli->deferred_events_collecting) + { + set_deferred(); return rli->deferred_events->add(this); + } if (!(charset= get_charset(charset_number, MYF(MY_WME)))) return 1; @@ -5900,7 +5906,8 @@ int User_var_log_event::do_apply_event(Relay_log_info const *rli) return 0; } } - Item_func_set_user_var e(user_var_name, it); + + Item_func_set_user_var *e= new Item_func_set_user_var(user_var_name, it); /* Item_func_set_user_var can't substitute something else on its place => 0 can be passed as last argument (reference on item) @@ -5909,7 +5916,7 @@ int User_var_log_event::do_apply_event(Relay_log_info const *rli) crash the server, so if fix fields fails, we just return with an error. */ - if (e.fix_fields(thd, 0)) + if (e->fix_fields(thd, 0)) return 1; /* @@ -5917,8 +5924,9 @@ int User_var_log_event::do_apply_event(Relay_log_info const *rli) a single record and with a single column. Thus, like a column value, it could always have IMPLICIT derivation. */ - e.update_hash(val, val_len, type, charset, DERIVATION_IMPLICIT, 0); - free_root(thd->mem_root,0); + e->update_hash(val, val_len, type, charset, DERIVATION_IMPLICIT, 0); + if (!is_deferred()) + free_root(thd->mem_root,0); return 0; } diff --git a/sql/log_event.h b/sql/log_event.h index 39cd55f313e..e755b6a5a41 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -2483,11 +2483,13 @@ public: uint charset_number; bool is_null; #ifndef MYSQL_CLIENT + bool deferred; User_var_log_event(THD* thd_arg, char *name_arg, uint name_len_arg, char *val_arg, ulong val_len_arg, Item_result type_arg, uint charset_number_arg) :Log_event(), name(name_arg), name_len(name_len_arg), val(val_arg), - val_len(val_len_arg), type(type_arg), charset_number(charset_number_arg) + val_len(val_len_arg), type(type_arg), charset_number(charset_number_arg), + deferred(false) { is_null= !val; } void pack_info(Protocol* protocol); #else @@ -2500,6 +2502,13 @@ public: Log_event_type get_type_code() { return USER_VAR_EVENT;} #ifndef MYSQL_CLIENT bool write(IO_CACHE* file); + /* + Getter and setter for deferred User-event. + Returns true if the event is not applied directly + and which case the applier adjusts execution path. + */ + bool is_deferred() { return deferred; } + void set_deferred() { deferred= val; } #endif bool is_valid() const { return 1; } From 3e90dc1f77dc3fa51d542bf82a336753310f7776 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Thu, 5 Jul 2012 22:04:13 +0400 Subject: [PATCH 127/289] MWL#182: Explain running statements - Make SHOW EXPLAIN command be KILLable with KILL QUERY. --- mysql-test/r/show_explain.result | 40 +++++++++++++++++++++++++ mysql-test/t/show_explain.test | 51 ++++++++++++++++++++++++++++++-- sql/my_apc.cc | 21 +++++++++---- sql/my_apc.h | 4 ++- sql/sql_show.cc | 8 +++-- unittest/sql/my_apc-t.cc | 27 ++++++++++++++++- 6 files changed, 140 insertions(+), 11 deletions(-) diff --git a/mysql-test/r/show_explain.result b/mysql-test/r/show_explain.result index 7c22a2c6435..c5891f96e82 100644 --- a/mysql-test/r/show_explain.result +++ b/mysql-test/r/show_explain.result @@ -775,4 +775,44 @@ a set debug_dbug=''; revoke all privileges on test.* from test2@localhost; drop user test2@localhost; +# +# Test that it is possible to KILL a SHOW EXPLAIN command that's waiting +# on its target thread +# +create table t1 (pk int primary key, data char(64)) engine=innodb; +insert into t1 select A.a + 10 * B.a + 100 * C.a, 'data1' from t0 A, t0 B, t0 C; +# Lock two threads +set autocommit=0; +select * from t1 where pk between 10 and 20 for update; +pk data +10 data1 +11 data1 +12 data1 +13 data1 +14 data1 +15 data1 +16 data1 +17 data1 +18 data1 +19 data1 +20 data1 +set autocommit=0; +select * from t1 where pk between 10 and 20 for update; +show explain for 3; +kill query $thr_default; +ERROR 70100: Query execution was interrupted +rollback; +pk data +10 data1 +11 data1 +12 data1 +13 data1 +14 data1 +15 data1 +16 data1 +17 data1 +18 data1 +19 data1 +20 data1 +drop table t1; drop table t0; diff --git a/mysql-test/t/show_explain.test b/mysql-test/t/show_explain.test index 5cfc0a5e202..c8d52ad7bb5 100644 --- a/mysql-test/t/show_explain.test +++ b/mysql-test/t/show_explain.test @@ -2,6 +2,7 @@ # Tests for SHOW EXPLAIN FOR functionality # --source include/have_debug.inc +--source include/have_innodb.inc --disable_warnings drop table if exists t0, t1, t2, t3, t4; @@ -788,11 +789,57 @@ connection con1; reap; set debug_dbug=''; - - revoke all privileges on test.* from test2@localhost; drop user test2@localhost; +disconnect con2; +--echo # +--echo # Test that it is possible to KILL a SHOW EXPLAIN command that's waiting +--echo # on its target thread +--echo # +connect (con2, localhost, root,,); +connect (con3, localhost, root,,); +connection con2; +create table t1 (pk int primary key, data char(64)) engine=innodb; +insert into t1 select A.a + 10 * B.a + 100 * C.a, 'data1' from t0 A, t0 B, t0 C; + +--echo # Lock two threads +set autocommit=0; +select * from t1 where pk between 10 and 20 for update; + +connection con1; +set autocommit=0; +# This will freeze +send +select * from t1 where pk between 10 and 20 for update; + +# run SHOW EXPLAIN on a frozen thread +connection default; +let $wait_condition= select State='Sending data' from information_schema.processlist where id=$thr2; +let $thr_default=`select connection_id()`; +--source include/wait_condition.inc +send_eval show explain for $thr2; + +# kill the SHOW EXPLAIN command +connection con3; +let $wait_condition= select State='show_explain' from information_schema.processlist where id=$thr_default; +--source include/wait_condition.inc +evalp kill query $thr_default; + +connection default; +--error ER_QUERY_INTERRUPTED +reap; + +connection con2; +rollback; + +connection con1; +reap; + +drop table t1; +disconnect con3; +disconnect con2; + ## TODO: Test this: have several SHOW EXPLAIN requests be queued up for a ## thread and served together. diff --git a/sql/my_apc.cc b/sql/my_apc.cc index 1cc13f41566..dd15daf48a2 100644 --- a/sql/my_apc.cc +++ b/sql/my_apc.cc @@ -145,8 +145,8 @@ void Apc_target::dequeue_request(Call_request *qe) to use thd->enter_cond() calls to be killable) */ -bool Apc_target::make_apc_call(Apc_call *call, int timeout_sec, - bool *timed_out) +bool Apc_target::make_apc_call(THD *caller_thd, Apc_call *call, + int timeout_sec, bool *timed_out) { bool res= TRUE; *timed_out= FALSE; @@ -166,6 +166,9 @@ bool Apc_target::make_apc_call(Apc_call *call, int timeout_sec, set_timespec(abstime, timeout); int wait_res= 0; + const char *old_msg; + old_msg= caller_thd->enter_cond(&apc_request.COND_request, + LOCK_thd_data_ptr, "show_explain"); /* todo: how about processing other errors here? */ while (!apc_request.processed && (wait_res != ETIMEDOUT)) { @@ -173,13 +176,18 @@ bool Apc_target::make_apc_call(Apc_call *call, int timeout_sec, wait_res= mysql_cond_timedwait(&apc_request.COND_request, LOCK_thd_data_ptr, &abstime); // &apc_request.LOCK_request, &abstime); + if (caller_thd->killed) + { + break; + } } if (!apc_request.processed) { /* - The wait has timed out. Remove the request from the queue (ok to do - because we own LOCK_thd_data_ptr. + The wait has timed out, or this thread was KILLed. + Remove the request from the queue (ok to do because we own + LOCK_thd_data_ptr) */ apc_request.processed= TRUE; dequeue_request(&apc_request); @@ -191,7 +199,10 @@ bool Apc_target::make_apc_call(Apc_call *call, int timeout_sec, /* Request was successfully executed and dequeued by the target thread */ res= FALSE; } - mysql_mutex_unlock(LOCK_thd_data_ptr); + /* + exit_cond() will call mysql_mutex_unlock(LOCK_thd_data_ptr) for us: + */ + caller_thd->exit_cond(old_msg); /* Destroy all APC request data */ mysql_cond_destroy(&apc_request.COND_request); diff --git a/sql/my_apc.h b/sql/my_apc.h index 93b934c9df1..84819b9beea 100644 --- a/sql/my_apc.h +++ b/sql/my_apc.h @@ -33,6 +33,8 @@ requestor. */ +class THD; + /* Target for asynchronous procedure calls (APCs). - A target is running in some particular thread, @@ -62,7 +64,7 @@ public: }; /* Make a call in the target thread (see function definition for details) */ - bool make_apc_call(Apc_call *call, int timeout_sec, bool *timed_out); + bool make_apc_call(THD *caller_thd, Apc_call *call, int timeout_sec, bool *timed_out); #ifndef DBUG_OFF int n_calls_processed; /* Number of calls served by this target */ diff --git a/sql/sql_show.cc b/sql/sql_show.cc index d26c8f18340..6c407f0cec3 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2084,11 +2084,15 @@ void mysqld_show_explain(THD *thd, const char *calling_user, ulong thread_id) explain_req.failed_to_produce= FALSE; /* Ok, we have a lock on target->LOCK_thd_data, can call: */ - bres= tmp->apc_target.make_apc_call(&explain_req, timeout_sec, &timed_out); + bres= tmp->apc_target.make_apc_call(thd, &explain_req, timeout_sec, &timed_out); if (bres || explain_req.failed_to_produce) { - /* TODO not enabled or time out */ + if (thd->killed) + { + thd->send_kill_message(); + } + else if (timed_out) { my_error(ER_ERROR_WHEN_EXECUTING_COMMAND, MYF(0), diff --git a/unittest/sql/my_apc-t.cc b/unittest/sql/my_apc-t.cc index fccfb6ecd13..3b837b4700e 100644 --- a/unittest/sql/my_apc-t.cc +++ b/unittest/sql/my_apc-t.cc @@ -24,6 +24,29 @@ #include +/* + A fake THD with enter_cond/exit_cond and some other members. +*/ +class THD +{ + mysql_mutex_t* thd_mutex; +public: + bool killed; + + THD() : killed(FALSE) {} + inline const char* enter_cond(mysql_cond_t *cond, mysql_mutex_t* mutex, + const char* msg) + { + mysql_mutex_assert_owner(mutex); + thd_mutex= mutex; + return NULL; + } + inline void exit_cond(const char* old_msg) + { + mysql_mutex_unlock(thd_mutex); + } +}; + #include "../sql/my_apc.h" #define MY_APC_STANDALONE 1 @@ -115,6 +138,8 @@ void *test_apc_requestor_thread(void *ptr) { my_thread_init(); fprintf(stderr, "# test_apc_requestor_thread started\n"); + THD my_thd; + while (!requestors_should_exit) { int dst_value= 0; @@ -124,7 +149,7 @@ void *test_apc_requestor_thread(void *ptr) bool timed_out; mysql_mutex_lock(&target_mutex); - bool res= apc_target.make_apc_call(&apc_order, 60, &timed_out); + bool res= apc_target.make_apc_call(&my_thd, &apc_order, 60, &timed_out); if (res) { if (timed_out) From 89820b4202f36353146ea4491569a06ccb0550fb Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Fri, 6 Jul 2012 00:28:30 +0400 Subject: [PATCH 128/289] Better comments. --- sql/my_apc.cc | 3 --- sql/sql_lex.cc | 4 +++- sql/sql_select.cc | 15 ++++++++------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/sql/my_apc.cc b/sql/my_apc.cc index dd15daf48a2..4a523fcd03e 100644 --- a/sql/my_apc.cc +++ b/sql/my_apc.cc @@ -140,9 +140,6 @@ void Apc_target::dequeue_request(Call_request *qe) @retval FALSE - Ok, the call has been made @retval TRUE - Call wasnt made (either the target is in disabled state or timeout occured) - - psergey-todo: Should waits here be KILLable? (it seems one needs - to use thd->enter_cond() calls to be killable) */ bool Apc_target::make_apc_call(THD *caller_thd, Apc_call *call, diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 349642f72b2..f918439d45a 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -3832,7 +3832,9 @@ void SELECT_LEX::update_used_tables() /** Set the EXPLAIN type for this subquery. - psergey-todo: comments about + + @param on_the_fly TRUE<=> We're running a SHOW EXPLAIN command, so we must + not change any variables */ void st_select_lex::set_explain_type(bool on_the_fly) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 5cd7430050b..486a55cf50e 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -273,13 +273,17 @@ JOIN_TAB *first_depth_first_tab(JOIN* join); JOIN_TAB *next_depth_first_tab(JOIN* join, JOIN_TAB* tab); #ifndef DBUG_OFF -// psergey: + +/* + SHOW EXPLAIN testing: wait for, and serve n_calls APC requests. +*/ void dbug_serve_apcs(THD *thd, int n_calls) { - // TODO how do we signal that we're SHOW-EXPLAIN-READY? const char *save_proc_info= thd->proc_info; + /* This is so that mysqltest knows we're ready to serve requests: */ thd_proc_info(thd, "show_explain_trap"); + /* Busy-wait for n_calls APC requests to arrive and be processed */ int n_apcs= thd->apc_target.n_calls_processed + n_calls; while (thd->apc_target.n_calls_processed < n_apcs) { @@ -10637,9 +10641,6 @@ void JOIN::cleanup(bool full) DBUG_ENTER("JOIN::cleanup"); DBUG_PRINT("enter", ("full %u", (uint) full)); - /* - psergey: let's try without this first: - */ have_query_plan= QEP_DELETED; if (table) @@ -21330,7 +21331,7 @@ int print_fake_select_lex_join(select_result_sink *result, bool on_the_fly, Item *item_null= new Item_null(); List item_list; if (on_the_fly) - select_lex->set_explain_type(on_the_fly); //psergey + select_lex->set_explain_type(on_the_fly); /* here we assume that the query will return at least two rows, so we show "filesort" in EXPLAIN. Of course, sometimes we'll be wrong @@ -22043,7 +22044,7 @@ bool mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result) for (SELECT_LEX *sl= first; sl; sl= sl->next_select()) { - sl->set_explain_type(FALSE); //psergey-todo: maybe remove this from here? + sl->set_explain_type(FALSE); sl->options|= SELECT_DESCRIBE; } From ae3bc191613fdec05d4d84a74648d1e84edc8ce4 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Fri, 6 Jul 2012 00:34:32 +0400 Subject: [PATCH 129/289] Remove out-of-date comments. --- sql/sql_show.cc | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 6c407f0cec3..2319a13de8c 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2011,7 +2011,6 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) @notes - Attempt to do "SHOW EXPLAIN FOR " will properly produce "target not running EXPLAINable command". - - todo: check how all this can/will work when using thread pools */ void mysqld_show_explain(THD *thd, const char *calling_user, ulong thread_id) @@ -2065,9 +2064,7 @@ void mysqld_show_explain(THD *thd, const char *calling_user, ulong thread_id) bool bres; /* Ok we've found the thread of interest and it won't go away because - we're holding its LOCK_thd data. - Post it an EXPLAIN request. - todo: where to get timeout from? + we're holding its LOCK_thd data. Post it a SHOW EXPLAIN request. */ bool timed_out; int timeout_sec= 30; From ca2baa0f3b4cf4d52ce6d0791dcd5acf85889d6e Mon Sep 17 00:00:00 2001 From: Andrei Elkin Date: Thu, 5 Jul 2012 23:53:07 +0300 Subject: [PATCH 130/289] merge bug14275000 fixes to 5.5: sql/log_event.h. --- sql/log_event.h | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/sql/log_event.h b/sql/log_event.h index 387f020ee8b..000c7420ca8 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -2562,23 +2562,15 @@ public: Item_result type; uint charset_number; bool is_null; -<<<<<<< TREE uchar flags; #ifdef MYSQL_SERVER -======= -#ifndef MYSQL_CLIENT bool deferred; ->>>>>>> MERGE-SOURCE User_var_log_event(THD* thd_arg, char *name_arg, uint name_len_arg, char *val_arg, ulong val_len_arg, Item_result type_arg, uint charset_number_arg, uchar flags_arg) :Log_event(), name(name_arg), name_len(name_len_arg), val(val_arg), val_len(val_len_arg), type(type_arg), charset_number(charset_number_arg), -<<<<<<< TREE - flags(flags_arg) -======= - deferred(false) ->>>>>>> MERGE-SOURCE + flags(flags_arg), deferred(false) { is_null= !val; } void pack_info(Protocol* protocol); #else From aa103d02257be42caecdeffd87f684e1840f25dd Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 6 Jul 2012 15:30:53 +0300 Subject: [PATCH 131/289] From f01bbb4cac83d08dec93d6feefdaf8fb13a467b1 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 6 Jul 2012 18:53:13 +0300 Subject: [PATCH 132/289] From a931467e17c4826ce4fa473de0479953d9bbcc59 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Sat, 7 Jul 2012 08:47:41 +0400 Subject: [PATCH 133/289] Enable PERFORMANCE_SCHEMA tracking for SHOW EXPLAIN's conditions. --- mysql-test/r/show_explain_ps.result | 27 ++++++++++++++++ mysql-test/t/show_explain_ps.test | 48 +++++++++++++++++++++++++++++ sql/my_apc.cc | 25 +++++++++++++-- sql/my_apc.h | 4 +++ sql/mysqld.cc | 1 + 5 files changed, 102 insertions(+), 3 deletions(-) create mode 100644 mysql-test/r/show_explain_ps.result create mode 100644 mysql-test/t/show_explain_ps.test diff --git a/mysql-test/r/show_explain_ps.result b/mysql-test/r/show_explain_ps.result new file mode 100644 index 00000000000..625b9cfddae --- /dev/null +++ b/mysql-test/r/show_explain_ps.result @@ -0,0 +1,27 @@ +drop table if exists t0, t1; +select * from performance_schema.setup_instruments where name like '%show_explain%'; +NAME ENABLED TIMED +wait/synch/cond/sql/show_explain YES YES +# We've got no instances +select * from performance_schema.cond_instances where name like '%show_explain%'; +NAME OBJECT_INSTANCE_BEGIN +# Check out if our cond is hit. +create table t0 (a int); +insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +set @show_explain_probe_select_id=1; +set debug_dbug='d,show_explain_probe_join_exec_start'; +select count(*) from t0 where a < 100000; +show explain for $thr2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 ALL NULL NULL NULL NULL 10 Using where +Warnings: +Note 1003 select count(*) from t0 where a < 100000 +count(*) +10 +set debug_dbug=''; +select event_name +from performance_schema.events_waits_history_long +where event_name='wait/synch/cond/sql/show_explain'; +event_name +wait/synch/cond/sql/show_explain +drop table t0; diff --git a/mysql-test/t/show_explain_ps.test b/mysql-test/t/show_explain_ps.test new file mode 100644 index 00000000000..67634ac57e2 --- /dev/null +++ b/mysql-test/t/show_explain_ps.test @@ -0,0 +1,48 @@ +# +# Test how SHOW EXPLAIN is represented in performance schema +# +--source include/have_perfschema.inc + +--disable_warnings +drop table if exists t0, t1; +--enable_warnings + +select * from performance_schema.setup_instruments where name like '%show_explain%'; + +--echo # We've got no instances +select * from performance_schema.cond_instances where name like '%show_explain%'; + +--echo # Check out if our cond is hit. + +create table t0 (a int); +insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); + +let $thr1=`select connection_id()`; +connect (con1, localhost, root,,); +connection con1; +let $thr2=`select connection_id()`; +connection default; + +let $wait_condition= select State='show_explain_trap' from information_schema.processlist where id=$thr2; + +# +# Test SHOW EXPLAIN for simple queries +# +connection con1; +set @show_explain_probe_select_id=1; +set debug_dbug='d,show_explain_probe_join_exec_start'; +send select count(*) from t0 where a < 100000; + +connection default; +--source include/wait_condition.inc +evalp show explain for $thr2; +connection con1; +reap; + +set debug_dbug=''; + +select event_name +from performance_schema.events_waits_history_long +where event_name='wait/synch/cond/sql/show_explain'; + +drop table t0; diff --git a/sql/my_apc.cc b/sql/my_apc.cc index 4a523fcd03e..c7ba25ad3ba 100644 --- a/sql/my_apc.cc +++ b/sql/my_apc.cc @@ -124,6 +124,26 @@ void Apc_target::dequeue_request(Call_request *qe) qe->next->prev= qe->prev; } +#ifdef HAVE_PSI_INTERFACE + +/* One key for all conds */ +PSI_cond_key key_show_explain_request_COND; + +static PSI_cond_info show_explain_psi_conds[]= +{ + { &key_show_explain_request_COND, "show_explain", 0 /* not using PSI_FLAG_GLOBAL*/ } +}; + +void init_show_explain_psi_keys(void) +{ + if (PSI_server == NULL) + return; + + PSI_server->register_cond("sql", show_explain_psi_conds, + array_elements(show_explain_psi_conds)); +} +#endif + /* Make an APC (Async Procedure Call) to another thread. @@ -154,7 +174,8 @@ bool Apc_target::make_apc_call(THD *caller_thd, Apc_call *call, Call_request apc_request; apc_request.call= call; apc_request.processed= FALSE; - mysql_cond_init(0 /* do not track in PS */, &apc_request.COND_request, NULL); + mysql_cond_init(key_show_explain_request_COND, &apc_request.COND_request, + NULL); enqueue_request(&apc_request); apc_request.what="enqueued by make_apc_call"; @@ -174,9 +195,7 @@ bool Apc_target::make_apc_call(THD *caller_thd, Apc_call *call, LOCK_thd_data_ptr, &abstime); // &apc_request.LOCK_request, &abstime); if (caller_thd->killed) - { break; - } } if (!apc_request.processed) diff --git a/sql/my_apc.h b/sql/my_apc.h index 84819b9beea..1c4cc25376b 100644 --- a/sql/my_apc.h +++ b/sql/my_apc.h @@ -119,3 +119,7 @@ private: } }; +#ifdef HAVE_PSI_INTERFACE +void init_show_explain_psi_keys(void); +#endif + diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 67446ef7239..54b5b95afaf 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -3909,6 +3909,7 @@ static int init_thread_environment() sp_cache_init(); #ifdef HAVE_EVENT_SCHEDULER Events::init_mutexes(); + init_show_explain_psi_keys(); #endif /* Parameter for threads created for connections */ (void) pthread_attr_init(&connection_attrib); From a1425b103248672ecb966cfc0efb0ba17d6b1d19 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Mon, 9 Jul 2012 15:10:07 +0200 Subject: [PATCH 134/289] Refactor mysql_client_test.c into a framework part and a test part --- tests/Makefile.am | 1 + tests/mysql_client_fw.c | 1375 +++++++++++++++++++++++++++++++++++++ tests/mysql_client_test.c | 1358 +----------------------------------- 3 files changed, 1381 insertions(+), 1353 deletions(-) create mode 100644 tests/mysql_client_fw.c diff --git a/tests/Makefile.am b/tests/Makefile.am index 876db7e8475..4929fa7ba9b 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -47,6 +47,7 @@ LDADD = @CLIENT_EXTRA_LDFLAGS@ \ mysql_client_test_LDADD= $(LDADD) $(CXXLDFLAGS) mysql_client_test_SOURCES= mysql_client_test.c\ $(top_srcdir)/mysys/my_memmem.c +mysql_client_test.o: mysql_client_fw.c insert_test_SOURCES= insert_test.c select_test_SOURCES= select_test.c diff --git a/tests/mysql_client_fw.c b/tests/mysql_client_fw.c new file mode 100644 index 00000000000..27a06501d7a --- /dev/null +++ b/tests/mysql_client_fw.c @@ -0,0 +1,1375 @@ +/* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + + 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 +#include +#include +#include +#include +#include +#include + +#define VER "2.1" +#define MAX_TEST_QUERY_LENGTH 300 /* MAX QUERY BUFFER LENGTH */ +#define MAX_KEY MAX_INDEXES +#define MAX_SERVER_ARGS 64 + +/* set default options */ +static int opt_testcase = 0; +static char *opt_db= 0; +static char *opt_user= 0; +static char *opt_password= 0; +static char *opt_host= 0; +static char *opt_unix_socket= 0; +#ifdef HAVE_SMEM +static char *shared_memory_base_name= 0; +#endif +static unsigned int opt_port; +static my_bool tty_password= 0, opt_silent= 0; + +static MYSQL *mysql= 0; +static char current_db[]= "client_test_db"; +static unsigned int test_count= 0; +static unsigned int opt_count= 0; +static unsigned int iter_count= 0; +static my_bool have_innodb= FALSE; + +static const char *opt_basedir= "./"; +static const char *opt_vardir= "mysql-test/var"; + +static longlong opt_getopt_ll_test= 0; + +static int embedded_server_arg_count= 0; +static char *embedded_server_args[MAX_SERVER_ARGS]; + +static const char *embedded_server_groups[]= { +"server", +"embedded", +"mysql_client_test_SERVER", +NullS +}; + +static time_t start_time, end_time; +static double total_time; + +const char *default_dbug_option= "d:t:o,/tmp/mysql_client_test.trace"; + +struct my_tests_st +{ +const char *name; +void (*function)(); +}; + +#define myheader(str) \ +DBUG_PRINT("test", ("name: %s", str)); \ + if (opt_silent < 2) \ + { \ + fprintf(stdout, "\n\n#####################################\n"); \ + fprintf(stdout, "%u of (%u/%u): %s", test_count++, iter_count, \ + opt_count, str); \ + fprintf(stdout, " \n#####################################\n"); \ + } + +#define myheader_r(str) \ +DBUG_PRINT("test", ("name: %s", str)); \ + if (!opt_silent) \ + { \ + fprintf(stdout, "\n\n#####################################\n"); \ + fprintf(stdout, "%s", str); \ + fprintf(stdout, " \n#####################################\n"); \ + } + +static void print_error(const char *msg); +static void print_st_error(MYSQL_STMT *stmt, const char *msg); +static void client_disconnect(MYSQL* mysql, my_bool drop_db); + + +/* +Abort unless given experssion is non-zero. + +SYNOPSIS +DIE_UNLESS(expr) + +DESCRIPTION +We can't use any kind of system assert as we need to +preserve tested invariants in release builds as well. +*/ + +#define DIE_UNLESS(expr) \ +((void) ((expr) ? 0 : (die(__FILE__, __LINE__, #expr), 0))) +#define DIE_IF(expr) \ +((void) ((expr) ? (die(__FILE__, __LINE__, #expr), 0) : 0)) +#define DIE(expr) \ +die(__FILE__, __LINE__, #expr) + +static void die(const char *file, int line, const char *expr) +{ + fflush(stdout); + fprintf(stderr, "%s:%d: check failed: '%s'\n", file, line, expr); + fflush(stderr); + exit(1); +} + + +#define myerror(msg) print_error(msg) +#define mysterror(stmt, msg) print_st_error(stmt, msg) + +#define myquery(RES) \ +{ \ + int r= (RES); \ + if (r) \ + myerror(NULL); \ + DIE_UNLESS(r == 0); \ +} + +#define myquery_r(r) \ +{ \ + if (r) \ + myerror(NULL); \ + DIE_UNLESS(r != 0); \ +} + +#define check_execute(stmt, r) \ +{ \ + if (r) \ + mysterror(stmt, NULL); \ + DIE_UNLESS(r == 0); \ +} + +#define check_execute_r(stmt, r) \ +{ \ + if (r) \ + mysterror(stmt, NULL); \ + DIE_UNLESS(r != 0); \ +} + +#define check_stmt(stmt) \ +{ \ + if ( stmt == 0) \ + myerror(NULL); \ + DIE_UNLESS(stmt != 0); \ +} + +#define check_stmt_r(stmt) \ +{ \ + if (stmt == 0) \ + myerror(NULL); \ + DIE_UNLESS(stmt == 0); \ +} + +#define mytest(x) if (!(x)) {myerror(NULL);DIE_UNLESS(FALSE);} +#define mytest_r(x) if ((x)) {myerror(NULL);DIE_UNLESS(FALSE);} + + +/* A workaround for Sun Forte 5.6 on Solaris x86 */ + +static int cmp_double(double *a, double *b) +{ + return *a == *b; +} + + +/* Print the error message */ + +static void print_error(const char *msg) +{ + if (!opt_silent) + { + if (mysql && mysql_errno(mysql)) + { + if (mysql->server_version) + fprintf(stdout, "\n [MySQL-%s]", mysql->server_version); + else + fprintf(stdout, "\n [MySQL]"); + fprintf(stdout, "[%d] %s\n", mysql_errno(mysql), mysql_error(mysql)); + } + else if (msg) + fprintf(stderr, " [MySQL] %s\n", msg); + } +} + + +static void print_st_error(MYSQL_STMT *stmt, const char *msg) +{ + if (!opt_silent) + { + if (stmt && mysql_stmt_errno(stmt)) + { + if (stmt->mysql && stmt->mysql->server_version) + fprintf(stdout, "\n [MySQL-%s]", stmt->mysql->server_version); + else + fprintf(stdout, "\n [MySQL]"); + + fprintf(stdout, "[%d] %s\n", mysql_stmt_errno(stmt), + mysql_stmt_error(stmt)); + } + else if (msg) + fprintf(stderr, " [MySQL] %s\n", msg); + } +} + +/* +Enhanced version of mysql_client_init(), which may also set shared memory +base on Windows. +*/ +static MYSQL *mysql_client_init(MYSQL* con) +{ + MYSQL* res = mysql_init(con); + #ifdef HAVE_SMEM + if (res && shared_memory_base_name) + mysql_options(res, MYSQL_SHARED_MEMORY_BASE_NAME, shared_memory_base_name); + #endif + return res; +} + +/* +Disable direct calls of mysql_init, as it disregards shared memory base. +*/ +#define mysql_init(A) Please use mysql_client_init instead of mysql_init + + +/* Check if the connection has InnoDB tables */ + +static my_bool check_have_innodb(MYSQL *conn) +{ + MYSQL_RES *res; + MYSQL_ROW row; + int rc; + my_bool result; + + rc= mysql_query(conn, "show variables like 'have_innodb'"); + myquery(rc); + res= mysql_use_result(conn); + DIE_UNLESS(res); + + row= mysql_fetch_row(res); + DIE_UNLESS(row); + + result= strcmp(row[1], "YES") == 0; + mysql_free_result(res); + return result; +} + + +/* +This is to be what mysql_query() is for mysql_real_query(), for +mysql_simple_prepare(): a variant without the 'length' parameter. +*/ + +static MYSQL_STMT *STDCALL +mysql_simple_prepare(MYSQL *mysql_arg, const char *query) +{ + MYSQL_STMT *stmt= mysql_stmt_init(mysql_arg); + if (stmt && mysql_stmt_prepare(stmt, query, (uint) strlen(query))) + { + mysql_stmt_close(stmt); + return 0; + } + return stmt; +} + + +/** +Connect to the server with options given by arguments to this application, +stored in global variables opt_host, opt_user, opt_password, opt_db, +opt_port and opt_unix_socket. + +@param flag[in] client_flag passed on to mysql_real_connect +@param protocol[in] MYSQL_PROTOCOL_* to use for this connection +@param auto_reconnect[in] set to 1 for auto reconnect + +@return pointer to initialized and connected MYSQL object +*/ +static MYSQL* client_connect(ulong flag, uint protocol, my_bool auto_reconnect) +{ + MYSQL* mysql; + int rc; + static char query[MAX_TEST_QUERY_LENGTH]; + myheader_r("client_connect"); + + if (!opt_silent) + fprintf(stdout, "\n Establishing a connection to '%s' ...", + opt_host ? opt_host : ""); + + if (!(mysql= mysql_client_init(NULL))) + { + opt_silent= 0; + myerror("mysql_client_init() failed"); + exit(1); + } + /* enable local infile, in non-binary builds often disabled by default */ + mysql_options(mysql, MYSQL_OPT_LOCAL_INFILE, 0); + mysql_options(mysql, MYSQL_OPT_PROTOCOL, &protocol); + + if (!(mysql_real_connect(mysql, opt_host, opt_user, + opt_password, opt_db ? opt_db:"test", opt_port, + opt_unix_socket, flag))) + { + opt_silent= 0; + myerror("connection failed"); + mysql_close(mysql); + fprintf(stdout, "\n Check the connection options using --help or -?\n"); + exit(1); + } + mysql->reconnect= auto_reconnect; + + if (!opt_silent) + fprintf(stdout, "OK"); + + /* set AUTOCOMMIT to ON*/ + mysql_autocommit(mysql, TRUE); + + if (!opt_silent) + { + fprintf(stdout, "\nConnected to MySQL server version: %s (%lu)\n", + mysql_get_server_info(mysql), + (ulong) mysql_get_server_version(mysql)); + fprintf(stdout, "\n Creating a test database '%s' ...", current_db); + } + strxmov(query, "CREATE DATABASE IF NOT EXISTS ", current_db, NullS); + + rc= mysql_query(mysql, query); + myquery(rc); + + strxmov(query, "USE ", current_db, NullS); + rc= mysql_query(mysql, query); + myquery(rc); + have_innodb= check_have_innodb(mysql); + + if (!opt_silent) + fprintf(stdout, "OK"); + + return mysql; +} + + +/* Close the connection */ + +static void client_disconnect(MYSQL* mysql, my_bool drop_db) +{ + static char query[MAX_TEST_QUERY_LENGTH]; + + myheader_r("client_disconnect"); + + if (mysql) + { + if (drop_db) + { + if (!opt_silent) + fprintf(stdout, "\n dropping the test database '%s' ...", current_db); + strxmov(query, "DROP DATABASE IF EXISTS ", current_db, NullS); + + mysql_query(mysql, query); + if (!opt_silent) + fprintf(stdout, "OK"); + } + + if (!opt_silent) + fprintf(stdout, "\n closing the connection ..."); + mysql_close(mysql); + if (!opt_silent) + fprintf(stdout, "OK\n"); + } +} + + +/* Print dashes */ + +static void my_print_dashes(MYSQL_RES *result) +{ + MYSQL_FIELD *field; + unsigned int i, j; + + mysql_field_seek(result, 0); + fputc('\t', stdout); + fputc('+', stdout); + + for(i= 0; i< mysql_num_fields(result); i++) + { + field= mysql_fetch_field(result); + for(j= 0; j < field->max_length+2; j++) + fputc('-', stdout); + fputc('+', stdout); + } + fputc('\n', stdout); +} + + +/* Print resultset metadata information */ + +static void my_print_result_metadata(MYSQL_RES *result) +{ + MYSQL_FIELD *field; + unsigned int i, j; + unsigned int field_count; + + mysql_field_seek(result, 0); + if (!opt_silent) + { + fputc('\n', stdout); + fputc('\n', stdout); + } + + field_count= mysql_num_fields(result); + for(i= 0; i< field_count; i++) + { + field= mysql_fetch_field(result); + j= strlen(field->name); + if (j < field->max_length) + j= field->max_length; + if (j < 4 && !IS_NOT_NULL(field->flags)) + j= 4; + field->max_length= j; + } + if (!opt_silent) + { + my_print_dashes(result); + fputc('\t', stdout); + fputc('|', stdout); + } + + mysql_field_seek(result, 0); + for(i= 0; i< field_count; i++) + { + field= mysql_fetch_field(result); + if (!opt_silent) + fprintf(stdout, " %-*s |", (int) field->max_length, field->name); + } + if (!opt_silent) + { + fputc('\n', stdout); + my_print_dashes(result); + } +} + + +/* Process the result set */ + +static int my_process_result_set(MYSQL_RES *result) +{ + MYSQL_ROW row; + MYSQL_FIELD *field; + unsigned int i; + unsigned int row_count= 0; + + if (!result) + return 0; + + my_print_result_metadata(result); + + while ((row= mysql_fetch_row(result)) != NULL) + { + mysql_field_seek(result, 0); + if (!opt_silent) + { + fputc('\t', stdout); + fputc('|', stdout); + } + + for(i= 0; i< mysql_num_fields(result); i++) + { + field= mysql_fetch_field(result); + if (!opt_silent) + { + if (row[i] == NULL) + fprintf(stdout, " %-*s |", (int) field->max_length, "NULL"); + else if (IS_NUM(field->type)) + fprintf(stdout, " %*s |", (int) field->max_length, row[i]); + else + fprintf(stdout, " %-*s |", (int) field->max_length, row[i]); + } + } + if (!opt_silent) + { + fputc('\t', stdout); + fputc('\n', stdout); + } + row_count++; + } + if (!opt_silent) + { + if (row_count) + my_print_dashes(result); + + if (mysql_errno(mysql) != 0) + fprintf(stderr, "\n\tmysql_fetch_row() failed\n"); + else + fprintf(stdout, "\n\t%d %s returned\n", row_count, + row_count == 1 ? "row" : "rows"); + } + return row_count; +} + + +static int my_process_result(MYSQL *mysql_arg) +{ + MYSQL_RES *result; + int row_count; + + if (!(result= mysql_store_result(mysql_arg))) + return 0; + + row_count= my_process_result_set(result); + + mysql_free_result(result); + return row_count; +} + + +/* Process the statement result set */ + +#define MAX_RES_FIELDS 50 +#define MAX_FIELD_DATA_SIZE 255 + +static int my_process_stmt_result(MYSQL_STMT *stmt) +{ + int field_count; + int row_count= 0; + MYSQL_BIND buffer[MAX_RES_FIELDS]; + MYSQL_FIELD *field; + MYSQL_RES *result; + char data[MAX_RES_FIELDS][MAX_FIELD_DATA_SIZE]; + ulong length[MAX_RES_FIELDS]; + my_bool is_null[MAX_RES_FIELDS]; + int rc, i; + + if (!(result= mysql_stmt_result_metadata(stmt))) /* No meta info */ + { + while (!mysql_stmt_fetch(stmt)) + row_count++; + return row_count; + } + + field_count= min(mysql_num_fields(result), MAX_RES_FIELDS); + + bzero((char*) buffer, sizeof(buffer)); + bzero((char*) length, sizeof(length)); + bzero((char*) is_null, sizeof(is_null)); + + for(i= 0; i < field_count; i++) + { + buffer[i].buffer_type= MYSQL_TYPE_STRING; + buffer[i].buffer_length= MAX_FIELD_DATA_SIZE; + buffer[i].length= &length[i]; + buffer[i].buffer= (void *) data[i]; + buffer[i].is_null= &is_null[i]; + } + + rc= mysql_stmt_bind_result(stmt, buffer); + check_execute(stmt, rc); + + rc= 1; + mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (void*)&rc); + rc= mysql_stmt_store_result(stmt); + check_execute(stmt, rc); + my_print_result_metadata(result); + + mysql_field_seek(result, 0); + while ((rc= mysql_stmt_fetch(stmt)) == 0) + { + if (!opt_silent) + { + fputc('\t', stdout); + fputc('|', stdout); + } + mysql_field_seek(result, 0); + for (i= 0; i < field_count; i++) + { + field= mysql_fetch_field(result); + if (!opt_silent) + { + if (is_null[i]) + fprintf(stdout, " %-*s |", (int) field->max_length, "NULL"); + else if (length[i] == 0) + { + data[i][0]= '\0'; /* unmodified buffer */ + fprintf(stdout, " %*s |", (int) field->max_length, data[i]); + } + else if (IS_NUM(field->type)) + fprintf(stdout, " %*s |", (int) field->max_length, data[i]); + else + fprintf(stdout, " %-*s |", (int) field->max_length, data[i]); + } + } + if (!opt_silent) + { + fputc('\t', stdout); + fputc('\n', stdout); + } + row_count++; + } + DIE_UNLESS(rc == MYSQL_NO_DATA); + if (!opt_silent) + { + if (row_count) + my_print_dashes(result); + fprintf(stdout, "\n\t%d %s returned\n", row_count, + row_count == 1 ? "row" : "rows"); + } + mysql_free_result(result); + return row_count; +} + + +/* Prepare statement, execute, and process result set for given query */ + +int my_stmt_result(const char *buff) +{ + MYSQL_STMT *stmt; + int row_count; + int rc; + + if (!opt_silent) + fprintf(stdout, "\n\n %s", buff); + stmt= mysql_simple_prepare(mysql, buff); + check_stmt(stmt); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + row_count= my_process_stmt_result(stmt); + mysql_stmt_close(stmt); + + return row_count; +} + + +/* Utility function to verify a particular column data */ + +static void verify_col_data(const char *table, const char *col, +const char *exp_data) +{ + static char query[MAX_TEST_QUERY_LENGTH]; + MYSQL_RES *result; + MYSQL_ROW row; + int rc, field= 1; + + if (table && col) + { + strxmov(query, "SELECT ", col, " FROM ", table, " LIMIT 1", NullS); + if (!opt_silent) + fprintf(stdout, "\n %s", query); + rc= mysql_query(mysql, query); + myquery(rc); + + field= 0; + } + + result= mysql_use_result(mysql); + mytest(result); + + if (!(row= mysql_fetch_row(result)) || !row[field]) + { + fprintf(stdout, "\n *** ERROR: FAILED TO GET THE RESULT ***"); + exit(1); + } + if (strcmp(row[field], exp_data)) + { + fprintf(stdout, "\n obtained: `%s` (expected: `%s`)", + row[field], exp_data); + DIE_UNLESS(FALSE); + } + mysql_free_result(result); +} + + +/* Utility function to verify the field members */ + +#define verify_prepare_field(result,no,name,org_name,type,table, \ +org_table,db,length,def) \ +do_verify_prepare_field((result),(no),(name),(org_name),(type), \ +(table),(org_table),(db),(length),(def), \ +__FILE__, __LINE__) + +static void do_verify_prepare_field(MYSQL_RES *result, +unsigned int no, const char *name, +const char *org_name, +enum enum_field_types type, +const char *table, +const char *org_table, const char *db, +unsigned long length, const char *def, +const char *file, int line) +{ + MYSQL_FIELD *field; + CHARSET_INFO *cs; + ulonglong expected_field_length; + + if (!(field= mysql_fetch_field_direct(result, no))) + { + fprintf(stdout, "\n *** ERROR: FAILED TO GET THE RESULT ***"); + exit(1); + } + cs= get_charset(field->charsetnr, 0); + DIE_UNLESS(cs); + if ((expected_field_length= length * cs->mbmaxlen) > UINT_MAX32) + expected_field_length= UINT_MAX32; + if (!opt_silent) + { + fprintf(stdout, "\n field[%d]:", no); + fprintf(stdout, "\n name :`%s`\t(expected: `%s`)", field->name, name); + fprintf(stdout, "\n org_name :`%s`\t(expected: `%s`)", + field->org_name, org_name); + fprintf(stdout, "\n type :`%d`\t(expected: `%d`)", field->type, type); + if (table) + fprintf(stdout, "\n table :`%s`\t(expected: `%s`)", + field->table, table); + if (org_table) + fprintf(stdout, "\n org_table:`%s`\t(expected: `%s`)", + field->org_table, org_table); + fprintf(stdout, "\n database :`%s`\t(expected: `%s`)", field->db, db); + fprintf(stdout, "\n length :`%lu`\t(expected: `%llu`)", + field->length, expected_field_length); + fprintf(stdout, "\n maxlength:`%ld`", field->max_length); + fprintf(stdout, "\n charsetnr:`%d`", field->charsetnr); + fprintf(stdout, "\n default :`%s`\t(expected: `%s`)", + field->def ? field->def : "(null)", def ? def: "(null)"); + fprintf(stdout, "\n"); + } + DIE_UNLESS(strcmp(field->name, name) == 0); + DIE_UNLESS(strcmp(field->org_name, org_name) == 0); + /* + XXX: silent column specification change works based on number of + bytes a column occupies. So CHAR -> VARCHAR upgrade is possible even + for CHAR(2) column if its character set is multibyte. + VARCHAR -> CHAR downgrade won't work for VARCHAR(3) as one would + expect. + */ + if (cs->mbmaxlen == 1) + { + if (field->type != type) + { + fprintf(stderr, + "Expected field type: %d, got type: %d in file %s, line %d\n", + (int) type, (int) field->type, file, line); + DIE_UNLESS(field->type == type); + } + } + if (table) + DIE_UNLESS(strcmp(field->table, table) == 0); + if (org_table) + DIE_UNLESS(strcmp(field->org_table, org_table) == 0); + DIE_UNLESS(strcmp(field->db, db) == 0); + /* + Character set should be taken into account for multibyte encodings, such + as utf8. Field length is calculated as number of characters * maximum + number of bytes a character can occupy. + */ + if (length && (field->length != expected_field_length)) + { + fprintf(stderr, "Expected field length: %llu, got length: %lu\n", + expected_field_length, field->length); + DIE_UNLESS(field->length == expected_field_length); + } + if (def) + DIE_UNLESS(strcmp(field->def, def) == 0); +} + + +/* Utility function to verify the parameter count */ + +static void verify_param_count(MYSQL_STMT *stmt, long exp_count) +{ + long param_count= mysql_stmt_param_count(stmt); + if (!opt_silent) + fprintf(stdout, "\n total parameters in stmt: `%ld` (expected: `%ld`)", + param_count, exp_count); + DIE_UNLESS(param_count == exp_count); +} + + +/* Utility function to verify the total affected rows */ + +static void verify_st_affected_rows(MYSQL_STMT *stmt, ulonglong exp_count) +{ + ulonglong affected_rows= mysql_stmt_affected_rows(stmt); + if (!opt_silent) + fprintf(stdout, "\n total affected rows: `%ld` (expected: `%ld`)", + (long) affected_rows, (long) exp_count); + DIE_UNLESS(affected_rows == exp_count); +} + + +/* Utility function to verify the total affected rows */ + +static void verify_affected_rows(ulonglong exp_count) +{ + ulonglong affected_rows= mysql_affected_rows(mysql); + if (!opt_silent) + fprintf(stdout, "\n total affected rows: `%ld` (expected: `%ld`)", + (long) affected_rows, (long) exp_count); + DIE_UNLESS(affected_rows == exp_count); +} + + +/* Utility function to verify the total fields count */ + +static void verify_field_count(MYSQL_RES *result, uint exp_count) +{ + uint field_count= mysql_num_fields(result); + if (!opt_silent) + fprintf(stdout, "\n total fields in the result set: `%d` (expected: `%d`)", + field_count, exp_count); + DIE_UNLESS(field_count == exp_count); +} + + +/* Utility function to execute a query using prepare-execute */ + +#ifndef EMBEDDED_LIBRARY +static void execute_prepare_query(const char *query, ulonglong exp_count) +{ + MYSQL_STMT *stmt; + ulonglong affected_rows; + int rc; + + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + rc= mysql_stmt_execute(stmt); + myquery(rc); + + affected_rows= mysql_stmt_affected_rows(stmt); + if (!opt_silent) + fprintf(stdout, "\n total affected rows: `%ld` (expected: `%ld`)", + (long) affected_rows, (long) exp_count); + + DIE_UNLESS(affected_rows == exp_count); + mysql_stmt_close(stmt); +} +#endif + +/* +Accepts arbitrary number of queries and runs them against the database. +Used to fill tables for each test. +*/ + +void fill_tables(const char **query_list, unsigned query_count) +{ + int rc; + const char **query; + DBUG_ENTER("fill_tables"); + for (query= query_list; query < query_list + query_count; + ++query) + { + rc= mysql_query(mysql, *query); + myquery(rc); + } + DBUG_VOID_RETURN; +} + +/* +All state of fetch from one statement: statement handle, out buffers, +fetch position. +See fetch_n for for the only use case. +*/ + +enum { MAX_COLUMN_LENGTH= 255 }; + +typedef struct st_stmt_fetch +{ +const char *query; +unsigned stmt_no; +MYSQL_STMT *handle; +my_bool is_open; +MYSQL_BIND *bind_array; +char **out_data; +unsigned long *out_data_length; +unsigned column_count; +unsigned row_count; +} Stmt_fetch; + + +/* +Create statement handle, prepare it with statement, execute and allocate +fetch buffers. +*/ + +void stmt_fetch_init(Stmt_fetch *fetch, unsigned stmt_no_arg, +const char *query_arg) +{ + unsigned long type= CURSOR_TYPE_READ_ONLY; + int rc; + unsigned i; + MYSQL_RES *metadata; + DBUG_ENTER("stmt_fetch_init"); + + /* Save query and statement number for error messages */ + fetch->stmt_no= stmt_no_arg; + fetch->query= query_arg; + + fetch->handle= mysql_stmt_init(mysql); + + rc= mysql_stmt_prepare(fetch->handle, fetch->query, strlen(fetch->query)); + check_execute(fetch->handle, rc); + + /* + The attribute is sent to server on execute and asks to open read-only + for result set + */ + mysql_stmt_attr_set(fetch->handle, STMT_ATTR_CURSOR_TYPE, + (const void*) &type); + + rc= mysql_stmt_execute(fetch->handle); + check_execute(fetch->handle, rc); + + /* Find out total number of columns in result set */ + metadata= mysql_stmt_result_metadata(fetch->handle); + fetch->column_count= mysql_num_fields(metadata); + mysql_free_result(metadata); + + /* + Now allocate bind handles and buffers for output data: + calloc memory to reduce number of MYSQL_BIND members we need to + set up. + */ + + fetch->bind_array= (MYSQL_BIND *) calloc(1, sizeof(MYSQL_BIND) * + fetch->column_count); + fetch->out_data= (char**) calloc(1, sizeof(char*) * fetch->column_count); + fetch->out_data_length= (ulong*) calloc(1, sizeof(ulong) * + fetch->column_count); + for (i= 0; i < fetch->column_count; ++i) + { + fetch->out_data[i]= (char*) calloc(1, MAX_COLUMN_LENGTH); + fetch->bind_array[i].buffer_type= MYSQL_TYPE_STRING; + fetch->bind_array[i].buffer= fetch->out_data[i]; + fetch->bind_array[i].buffer_length= MAX_COLUMN_LENGTH; + fetch->bind_array[i].length= fetch->out_data_length + i; + } + + mysql_stmt_bind_result(fetch->handle, fetch->bind_array); + + fetch->row_count= 0; + fetch->is_open= TRUE; + + /* Ready for reading rows */ + DBUG_VOID_RETURN; +} + + +/* Fetch and print one row from cursor */ + +int stmt_fetch_fetch_row(Stmt_fetch *fetch) +{ + int rc; + unsigned i; + DBUG_ENTER("stmt_fetch_fetch_row"); + + if ((rc= mysql_stmt_fetch(fetch->handle)) == 0) + { + ++fetch->row_count; + if (!opt_silent) + printf("Stmt %d fetched row %d:\n", fetch->stmt_no, fetch->row_count); + for (i= 0; i < fetch->column_count; ++i) + { + fetch->out_data[i][fetch->out_data_length[i]]= '\0'; + if (!opt_silent) + printf("column %d: %s\n", i+1, fetch->out_data[i]); + } + } + else + fetch->is_open= FALSE; + DBUG_RETURN(rc); +} + + +void stmt_fetch_close(Stmt_fetch *fetch) +{ + unsigned i; + DBUG_ENTER("stmt_fetch_close"); + + for (i= 0; i < fetch->column_count; ++i) + free(fetch->out_data[i]); + free(fetch->out_data); + free(fetch->out_data_length); + free(fetch->bind_array); + mysql_stmt_close(fetch->handle); + DBUG_VOID_RETURN; +} + +/* +For given array of queries, open query_count cursors and fetch +from them in simultaneous manner. +In case there was an error in one of the cursors, continue +reading from the rest. +*/ + +enum fetch_type { USE_ROW_BY_ROW_FETCH= 0, USE_STORE_RESULT= 1 }; + +my_bool fetch_n(const char **query_list, unsigned query_count, +enum fetch_type fetch_type) +{ + unsigned open_statements= query_count; + int rc, error_count= 0; + Stmt_fetch *fetch_array= (Stmt_fetch*) calloc(1, sizeof(Stmt_fetch) * + query_count); + Stmt_fetch *fetch; + DBUG_ENTER("fetch_n"); + + for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch) + { + /* Init will exit(1) in case of error */ + stmt_fetch_init(fetch, fetch - fetch_array, + query_list[fetch - fetch_array]); + } + + if (fetch_type == USE_STORE_RESULT) + { + for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch) + { + rc= mysql_stmt_store_result(fetch->handle); + check_execute(fetch->handle, rc); + } + } + + while (open_statements) + { + for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch) + { + if (fetch->is_open && (rc= stmt_fetch_fetch_row(fetch))) + { + open_statements--; + /* + We try to fetch from the rest of the statements in case of + error + */ + if (rc != MYSQL_NO_DATA) + { + fprintf(stderr, + "Got error reading rows from statement %d,\n" + "query is: %s,\n" + "error message: %s", (int) (fetch - fetch_array), + fetch->query, + mysql_stmt_error(fetch->handle)); + error_count++; + } + } + } + } + if (error_count) + fprintf(stderr, "Fetch FAILED"); + else + { + unsigned total_row_count= 0; + for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch) + total_row_count+= fetch->row_count; + if (!opt_silent) + printf("Success, total rows fetched: %d\n", total_row_count); + } + for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch) + stmt_fetch_close(fetch); + free(fetch_array); + DBUG_RETURN(error_count != 0); +} + +/* Separate thread query to test some cases */ + +static my_bool thread_query(const char *query) +{ + MYSQL *l_mysql; + my_bool error; + + error= 0; + if (!opt_silent) + fprintf(stdout, "\n in thread_query(%s)", query); + if (!(l_mysql= mysql_client_init(NULL))) + { + myerror("mysql_client_init() failed"); + return 1; + } + if (!(mysql_real_connect(l_mysql, opt_host, opt_user, + opt_password, current_db, opt_port, + opt_unix_socket, 0))) + { + myerror("connection failed"); + error= 1; + goto end; + } + l_mysql->reconnect= 1; + if (mysql_query(l_mysql, query)) + { + fprintf(stderr, "Query failed (%s)\n", mysql_error(l_mysql)); + error= 1; + goto end; + } + mysql_commit(l_mysql); + end: + mysql_close(l_mysql); + return error; +} + + +/* +Read and parse arguments and MySQL options from my.cnf +*/ + +static const char *client_test_load_default_groups[]= { "client", 0 }; +static char **defaults_argv; + +static struct my_option client_test_long_options[] = +{ +{"basedir", 'b', "Basedir for tests.", &opt_basedir, + &opt_basedir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +{"count", 't', "Number of times test to be executed", &opt_count, + &opt_count, 0, GET_UINT, REQUIRED_ARG, 1, 0, 0, 0, 0, 0}, +{"database", 'D', "Database to use", &opt_db, &opt_db, + 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +{"debug", '#', "Output debug log", &default_dbug_option, + &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, +{"help", '?', "Display this help and exit", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, + 0, 0, 0, 0, 0}, +{"host", 'h', "Connect to host", &opt_host, &opt_host, + 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +{"password", 'p', + "Password to use when connecting to server. If password is not given it's asked from the tty.", + 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, +{"port", 'P', "Port number to use for connection or 0 for default to, in " + "order of preference, my.cnf, $MYSQL_TCP_PORT, " + #if MYSQL_PORT_DEFAULT == 0 + "/etc/services, " + #endif + "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").", + &opt_port, &opt_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +{"server-arg", 'A', "Send embedded server this as a parameter.", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +{"show-tests", 'T', "Show all tests' names", 0, 0, 0, GET_NO_ARG, NO_ARG, + 0, 0, 0, 0, 0, 0}, +{"silent", 's', "Be more silent", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, + 0}, +#ifdef HAVE_SMEM +{"shared-memory-base-name", 'm', "Base name of shared memory.", + &shared_memory_base_name, (uchar**)&shared_memory_base_name, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +#endif +{"socket", 'S', "Socket file to use for connection", + &opt_unix_socket, &opt_unix_socket, 0, GET_STR, + REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +{"testcase", 'c', + "May disable some code when runs as mysql-test-run testcase.", + 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, +#ifndef DONT_ALLOW_USER_CHANGE +{"user", 'u', "User for login if not current user", &opt_user, + &opt_user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +#endif +{"vardir", 'v', "Data dir for tests.", &opt_vardir, + &opt_vardir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +{"getopt-ll-test", 'g', "Option for testing bug in getopt library", + &opt_getopt_ll_test, &opt_getopt_ll_test, 0, + GET_LL, REQUIRED_ARG, 0, 0, LONGLONG_MAX, 0, 0, 0}, +{ 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} +}; + + +static void usage(void) +{ +/* show the usage string when the user asks for this */ + putc('\n', stdout); + printf("%s Ver %s Distrib %s, for %s (%s)\n", + my_progname, VER, MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE); + puts("By Monty, Venu, Kent and others\n"); + printf("\ +Copyright (C) 2002-2004 MySQL AB\n\ +This software comes with ABSOLUTELY NO WARRANTY. This is free software,\n\ +and you are welcome to modify and redistribute it under the GPL license\n"); + printf("Usage: %s [OPTIONS] [TESTNAME1 TESTNAME2...]\n", my_progname); + my_print_help(client_test_long_options); + print_defaults("my", client_test_load_default_groups); + my_print_variables(client_test_long_options); +} + + +struct my_tests_st *get_my_tests(); /* Will be defined in main .c file */ + +static struct my_tests_st *my_testlist= 0; + +static my_bool +get_one_option(int optid, const struct my_option *opt __attribute__((unused)), +char *argument) +{ + switch (optid) { + case '#': + DBUG_PUSH(argument ? argument : default_dbug_option); + break; + case 'c': + opt_testcase = 1; + break; + case 'p': + if (argument) + { + char *start=argument; + my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR)); + opt_password= my_strdup(argument, MYF(MY_FAE)); + while (*argument) *argument++= 'x'; /* Destroy argument */ + if (*start) + start[1]=0; + } + else + tty_password= 1; + break; + case 's': + if (argument == disabled_my_option) + opt_silent= 0; + else + opt_silent++; + break; + case 'A': + /* + When the embedded server is being tested, the test suite needs to be + able to pass command-line arguments to the embedded server so it can + locate the language files and data directory. The test suite + (mysql-test-run) never uses config files, just command-line options. + */ + if (!embedded_server_arg_count) + { + embedded_server_arg_count= 1; + embedded_server_args[0]= (char*) ""; + } + if (embedded_server_arg_count == MAX_SERVER_ARGS-1 || + !(embedded_server_args[embedded_server_arg_count++]= + my_strdup(argument, MYF(MY_FAE)))) + { + DIE("Can't use server argument"); + } + break; + case 'T': + { + struct my_tests_st *fptr; + + printf("All possible test names:\n\n"); + for (fptr= my_testlist; fptr->name; fptr++) + printf("%s\n", fptr->name); + exit(0); + break; + } + case '?': + case 'I': /* Info */ + usage(); + exit(0); + break; + } + return 0; +} + +static void get_options(int *argc, char ***argv) +{ + int ho_error; + + if ((ho_error= handle_options(argc, argv, client_test_long_options, + get_one_option))) + exit(ho_error); + + if (tty_password) + opt_password= get_tty_password(NullS); + return; +} + +/* +Print the test output on successful execution before exiting +*/ + +static void print_test_output() +{ + if (opt_silent < 3) + { + fprintf(stdout, "\n\n"); + fprintf(stdout, "All '%d' tests were successful (in '%d' iterations)", + test_count-1, opt_count); + fprintf(stdout, "\n Total execution time: %g SECS", total_time); + if (opt_count > 1) + fprintf(stdout, " (Avg: %g SECS)", total_time/opt_count); + + fprintf(stdout, "\n\n!!! SUCCESS !!!\n"); + } +} + +/*************************************************************************** +main routine +***************************************************************************/ + + +int main(int argc, char **argv) +{ + struct my_tests_st *fptr; + my_testlist= get_my_tests(); + + MY_INIT(argv[0]); + + load_defaults("my", client_test_load_default_groups, &argc, &argv); + defaults_argv= argv; + get_options(&argc, &argv); + + if (mysql_server_init(embedded_server_arg_count, + embedded_server_args, + (char**) embedded_server_groups)) + DIE("Can't initialize MySQL server"); + + /* connect to server with no flags, default protocol, auto reconnect true */ + mysql= client_connect(0, MYSQL_PROTOCOL_DEFAULT, 1); + + total_time= 0; + for (iter_count= 1; iter_count <= opt_count; iter_count++) + { + /* Start of tests */ + test_count= 1; + start_time= time((time_t *)0); + if (!argc) + { + for (fptr= my_testlist; fptr->name; fptr++) + (*fptr->function)(); + } + else + { + for ( ; *argv ; argv++) + { + for (fptr= my_testlist; fptr->name; fptr++) + { + if (!strcmp(fptr->name, *argv)) + { + (*fptr->function)(); + break; + } + } + if (!fptr->name) + { + fprintf(stderr, "\n\nGiven test not found: '%s'\n", *argv); + fprintf(stderr, "See legal test names with %s -T\n\nAborting!\n", + my_progname); + client_disconnect(mysql, 1); + free_defaults(defaults_argv); + exit(1); + } + } + } + + end_time= time((time_t *)0); + total_time+= difftime(end_time, start_time); + + /* End of tests */ + } + + client_disconnect(mysql, 1); /* disconnect from server */ + + free_defaults(defaults_argv); + print_test_output(); + + while (embedded_server_arg_count > 1) + my_free(embedded_server_args[--embedded_server_arg_count],MYF(0)); + + mysql_server_end(); + + my_end(0); + + exit(0); +} diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index f553eb530ae..c38695db1b1 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. 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 @@ -25,378 +25,12 @@ DOESN'T CONTAIN WARNINGS/ERRORS BEFORE YOU PUSH. */ - -#include -#include -#include -#include -#include -#include -#include - -#define VER "2.1" -#define MAX_TEST_QUERY_LENGTH 300 /* MAX QUERY BUFFER LENGTH */ -#define MAX_KEY MAX_INDEXES -#define MAX_SERVER_ARGS 64 - -/* set default options */ -static int opt_testcase = 0; -static char *opt_db= 0; -static char *opt_user= 0; -static char *opt_password= 0; -static char *opt_host= 0; -static char *opt_unix_socket= 0; -#ifdef HAVE_SMEM -static char *shared_memory_base_name= 0; -#endif -static unsigned int opt_port; -static my_bool tty_password= 0, opt_silent= 0; - -static MYSQL *mysql= 0; -static char current_db[]= "client_test_db"; -static unsigned int test_count= 0; -static unsigned int opt_count= 0; -static unsigned int iter_count= 0; -static my_bool have_innodb= FALSE; - -static const char *opt_basedir= "./"; -static const char *opt_vardir= "mysql-test/var"; - -static longlong opt_getopt_ll_test= 0; - -static int embedded_server_arg_count= 0; -static char *embedded_server_args[MAX_SERVER_ARGS]; - -static const char *embedded_server_groups[]= { - "server", - "embedded", - "mysql_client_test_SERVER", - NullS -}; - -static time_t start_time, end_time; -static double total_time; - -const char *default_dbug_option= "d:t:o,/tmp/mysql_client_test.trace"; - -struct my_tests_st -{ - const char *name; - void (*function)(); -}; - -#define myheader(str) \ -DBUG_PRINT("test", ("name: %s", str)); \ -if (opt_silent < 2) \ -{ \ - fprintf(stdout, "\n\n#####################################\n"); \ - fprintf(stdout, "%u of (%u/%u): %s", test_count++, iter_count, \ - opt_count, str); \ - fprintf(stdout, " \n#####################################\n"); \ -} - -#define myheader_r(str) \ -DBUG_PRINT("test", ("name: %s", str)); \ -if (!opt_silent) \ -{ \ - fprintf(stdout, "\n\n#####################################\n"); \ - fprintf(stdout, "%s", str); \ - fprintf(stdout, " \n#####################################\n"); \ -} - -static void print_error(const char *msg); -static void print_st_error(MYSQL_STMT *stmt, const char *msg); -static void client_disconnect(MYSQL* mysql, my_bool drop_db); - - /* - Abort unless given experssion is non-zero. - - SYNOPSIS - DIE_UNLESS(expr) - - DESCRIPTION - We can't use any kind of system assert as we need to - preserve tested invariants in release builds as well. + The fw.c file includes all the mysql_client_test framework; this file + contains only the actual tests, plus the list of test functions to call. */ -#define DIE_UNLESS(expr) \ - ((void) ((expr) ? 0 : (die(__FILE__, __LINE__, #expr), 0))) -#define DIE_IF(expr) \ - ((void) ((expr) ? (die(__FILE__, __LINE__, #expr), 0) : 0)) -#define DIE(expr) \ - die(__FILE__, __LINE__, #expr) - -static void die(const char *file, int line, const char *expr) -{ - fflush(stdout); - fprintf(stderr, "%s:%d: check failed: '%s'\n", file, line, expr); - fflush(stderr); - exit(1); -} - - -#define myerror(msg) print_error(msg) -#define mysterror(stmt, msg) print_st_error(stmt, msg) - -#define myquery(RES) \ -{ \ - int r= (RES); \ - if (r) \ - myerror(NULL); \ - DIE_UNLESS(r == 0); \ -} - -#define myquery_r(r) \ -{ \ -if (r) \ - myerror(NULL); \ -DIE_UNLESS(r != 0); \ -} - -#define check_execute(stmt, r) \ -{ \ -if (r) \ - mysterror(stmt, NULL); \ -DIE_UNLESS(r == 0);\ -} - -#define check_execute_r(stmt, r) \ -{ \ -if (r) \ - mysterror(stmt, NULL); \ -DIE_UNLESS(r != 0);\ -} - -#define check_stmt(stmt) \ -{ \ -if ( stmt == 0) \ - myerror(NULL); \ -DIE_UNLESS(stmt != 0); \ -} - -#define check_stmt_r(stmt) \ -{ \ -if (stmt == 0) \ - myerror(NULL);\ -DIE_UNLESS(stmt == 0);\ -} - -#define mytest(x) if (!(x)) {myerror(NULL);DIE_UNLESS(FALSE);} -#define mytest_r(x) if ((x)) {myerror(NULL);DIE_UNLESS(FALSE);} - - -/* A workaround for Sun Forte 5.6 on Solaris x86 */ - -static int cmp_double(double *a, double *b) -{ - return *a == *b; -} - - -/* Print the error message */ - -static void print_error(const char *msg) -{ - if (!opt_silent) - { - if (mysql && mysql_errno(mysql)) - { - if (mysql->server_version) - fprintf(stdout, "\n [MySQL-%s]", mysql->server_version); - else - fprintf(stdout, "\n [MySQL]"); - fprintf(stdout, "[%d] %s\n", mysql_errno(mysql), mysql_error(mysql)); - } - else if (msg) - fprintf(stderr, " [MySQL] %s\n", msg); - } -} - - -static void print_st_error(MYSQL_STMT *stmt, const char *msg) -{ - if (!opt_silent) - { - if (stmt && mysql_stmt_errno(stmt)) - { - if (stmt->mysql && stmt->mysql->server_version) - fprintf(stdout, "\n [MySQL-%s]", stmt->mysql->server_version); - else - fprintf(stdout, "\n [MySQL]"); - - fprintf(stdout, "[%d] %s\n", mysql_stmt_errno(stmt), - mysql_stmt_error(stmt)); - } - else if (msg) - fprintf(stderr, " [MySQL] %s\n", msg); - } -} - -/* - Enhanced version of mysql_client_init(), which may also set shared memory - base on Windows. -*/ -static MYSQL *mysql_client_init(MYSQL* con) -{ - MYSQL* res = mysql_init(con); -#ifdef HAVE_SMEM - if (res && shared_memory_base_name) - mysql_options(res, MYSQL_SHARED_MEMORY_BASE_NAME, shared_memory_base_name); -#endif - return res; -} - -/* - Disable direct calls of mysql_init, as it disregards shared memory base. -*/ -#define mysql_init(A) Please use mysql_client_init instead of mysql_init - - -/* Check if the connection has InnoDB tables */ - -static my_bool check_have_innodb(MYSQL *conn) -{ - MYSQL_RES *res; - MYSQL_ROW row; - int rc; - my_bool result; - - rc= mysql_query(conn, "show variables like 'have_innodb'"); - myquery(rc); - res= mysql_use_result(conn); - DIE_UNLESS(res); - - row= mysql_fetch_row(res); - DIE_UNLESS(row); - - result= strcmp(row[1], "YES") == 0; - mysql_free_result(res); - return result; -} - - -/* - This is to be what mysql_query() is for mysql_real_query(), for - mysql_simple_prepare(): a variant without the 'length' parameter. -*/ - -static MYSQL_STMT *STDCALL -mysql_simple_prepare(MYSQL *mysql_arg, const char *query) -{ - MYSQL_STMT *stmt= mysql_stmt_init(mysql_arg); - if (stmt && mysql_stmt_prepare(stmt, query, (uint) strlen(query))) - { - mysql_stmt_close(stmt); - return 0; - } - return stmt; -} - - -/** - Connect to the server with options given by arguments to this application, - stored in global variables opt_host, opt_user, opt_password, opt_db, - opt_port and opt_unix_socket. - - @param flag[in] client_flag passed on to mysql_real_connect - @param protocol[in] MYSQL_PROTOCOL_* to use for this connection - @param auto_reconnect[in] set to 1 for auto reconnect - - @return pointer to initialized and connected MYSQL object -*/ -static MYSQL* client_connect(ulong flag, uint protocol, my_bool auto_reconnect) -{ - MYSQL* mysql; - int rc; - static char query[MAX_TEST_QUERY_LENGTH]; - myheader_r("client_connect"); - - if (!opt_silent) - fprintf(stdout, "\n Establishing a connection to '%s' ...", - opt_host ? opt_host : ""); - - if (!(mysql= mysql_client_init(NULL))) - { - opt_silent= 0; - myerror("mysql_client_init() failed"); - exit(1); - } - /* enable local infile, in non-binary builds often disabled by default */ - mysql_options(mysql, MYSQL_OPT_LOCAL_INFILE, 0); - mysql_options(mysql, MYSQL_OPT_PROTOCOL, &protocol); - - if (!(mysql_real_connect(mysql, opt_host, opt_user, - opt_password, opt_db ? opt_db:"test", opt_port, - opt_unix_socket, flag))) - { - opt_silent= 0; - myerror("connection failed"); - mysql_close(mysql); - fprintf(stdout, "\n Check the connection options using --help or -?\n"); - exit(1); - } - mysql->reconnect= auto_reconnect; - - if (!opt_silent) - fprintf(stdout, "OK"); - - /* set AUTOCOMMIT to ON*/ - mysql_autocommit(mysql, TRUE); - - if (!opt_silent) - { - fprintf(stdout, "\nConnected to MySQL server version: %s (%lu)\n", - mysql_get_server_info(mysql), - (ulong) mysql_get_server_version(mysql)); - fprintf(stdout, "\n Creating a test database '%s' ...", current_db); - } - strxmov(query, "CREATE DATABASE IF NOT EXISTS ", current_db, NullS); - - rc= mysql_query(mysql, query); - myquery(rc); - - strxmov(query, "USE ", current_db, NullS); - rc= mysql_query(mysql, query); - myquery(rc); - have_innodb= check_have_innodb(mysql); - - if (!opt_silent) - fprintf(stdout, "OK"); - - return mysql; -} - - -/* Close the connection */ - -static void client_disconnect(MYSQL* mysql, my_bool drop_db) -{ - static char query[MAX_TEST_QUERY_LENGTH]; - - myheader_r("client_disconnect"); - - if (mysql) - { - if (drop_db) - { - if (!opt_silent) - fprintf(stdout, "\n dropping the test database '%s' ...", current_db); - strxmov(query, "DROP DATABASE IF EXISTS ", current_db, NullS); - - mysql_query(mysql, query); - if (!opt_silent) - fprintf(stdout, "OK"); - } - - if (!opt_silent) - fprintf(stdout, "\n closing the connection ..."); - mysql_close(mysql); - if (!opt_silent) - fprintf(stdout, "OK\n"); - } -} - +#include "mysql_client_fw.c" /* Query processing */ @@ -443,471 +77,6 @@ static void client_query() } -/* Print dashes */ - -static void my_print_dashes(MYSQL_RES *result) -{ - MYSQL_FIELD *field; - unsigned int i, j; - - mysql_field_seek(result, 0); - fputc('\t', stdout); - fputc('+', stdout); - - for(i= 0; i< mysql_num_fields(result); i++) - { - field= mysql_fetch_field(result); - for(j= 0; j < field->max_length+2; j++) - fputc('-', stdout); - fputc('+', stdout); - } - fputc('\n', stdout); -} - - -/* Print resultset metadata information */ - -static void my_print_result_metadata(MYSQL_RES *result) -{ - MYSQL_FIELD *field; - unsigned int i, j; - unsigned int field_count; - - mysql_field_seek(result, 0); - if (!opt_silent) - { - fputc('\n', stdout); - fputc('\n', stdout); - } - - field_count= mysql_num_fields(result); - for(i= 0; i< field_count; i++) - { - field= mysql_fetch_field(result); - j= strlen(field->name); - if (j < field->max_length) - j= field->max_length; - if (j < 4 && !IS_NOT_NULL(field->flags)) - j= 4; - field->max_length= j; - } - if (!opt_silent) - { - my_print_dashes(result); - fputc('\t', stdout); - fputc('|', stdout); - } - - mysql_field_seek(result, 0); - for(i= 0; i< field_count; i++) - { - field= mysql_fetch_field(result); - if (!opt_silent) - fprintf(stdout, " %-*s |", (int) field->max_length, field->name); - } - if (!opt_silent) - { - fputc('\n', stdout); - my_print_dashes(result); - } -} - - -/* Process the result set */ - -static int my_process_result_set(MYSQL_RES *result) -{ - MYSQL_ROW row; - MYSQL_FIELD *field; - unsigned int i; - unsigned int row_count= 0; - - if (!result) - return 0; - - my_print_result_metadata(result); - - while ((row= mysql_fetch_row(result)) != NULL) - { - mysql_field_seek(result, 0); - if (!opt_silent) - { - fputc('\t', stdout); - fputc('|', stdout); - } - - for(i= 0; i< mysql_num_fields(result); i++) - { - field= mysql_fetch_field(result); - if (!opt_silent) - { - if (row[i] == NULL) - fprintf(stdout, " %-*s |", (int) field->max_length, "NULL"); - else if (IS_NUM(field->type)) - fprintf(stdout, " %*s |", (int) field->max_length, row[i]); - else - fprintf(stdout, " %-*s |", (int) field->max_length, row[i]); - } - } - if (!opt_silent) - { - fputc('\t', stdout); - fputc('\n', stdout); - } - row_count++; - } - if (!opt_silent) - { - if (row_count) - my_print_dashes(result); - - if (mysql_errno(mysql) != 0) - fprintf(stderr, "\n\tmysql_fetch_row() failed\n"); - else - fprintf(stdout, "\n\t%d %s returned\n", row_count, - row_count == 1 ? "row" : "rows"); - } - return row_count; -} - - -static int my_process_result(MYSQL *mysql_arg) -{ - MYSQL_RES *result; - int row_count; - - if (!(result= mysql_store_result(mysql_arg))) - return 0; - - row_count= my_process_result_set(result); - - mysql_free_result(result); - return row_count; -} - - -/* Process the statement result set */ - -#define MAX_RES_FIELDS 50 -#define MAX_FIELD_DATA_SIZE 255 - -static int my_process_stmt_result(MYSQL_STMT *stmt) -{ - int field_count; - int row_count= 0; - MYSQL_BIND buffer[MAX_RES_FIELDS]; - MYSQL_FIELD *field; - MYSQL_RES *result; - char data[MAX_RES_FIELDS][MAX_FIELD_DATA_SIZE]; - ulong length[MAX_RES_FIELDS]; - my_bool is_null[MAX_RES_FIELDS]; - int rc, i; - - if (!(result= mysql_stmt_result_metadata(stmt))) /* No meta info */ - { - while (!mysql_stmt_fetch(stmt)) - row_count++; - return row_count; - } - - field_count= min(mysql_num_fields(result), MAX_RES_FIELDS); - - bzero((char*) buffer, sizeof(buffer)); - bzero((char*) length, sizeof(length)); - bzero((char*) is_null, sizeof(is_null)); - - for(i= 0; i < field_count; i++) - { - buffer[i].buffer_type= MYSQL_TYPE_STRING; - buffer[i].buffer_length= MAX_FIELD_DATA_SIZE; - buffer[i].length= &length[i]; - buffer[i].buffer= (void *) data[i]; - buffer[i].is_null= &is_null[i]; - } - - rc= mysql_stmt_bind_result(stmt, buffer); - check_execute(stmt, rc); - - rc= 1; - mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (void*)&rc); - rc= mysql_stmt_store_result(stmt); - check_execute(stmt, rc); - my_print_result_metadata(result); - - mysql_field_seek(result, 0); - while ((rc= mysql_stmt_fetch(stmt)) == 0) - { - if (!opt_silent) - { - fputc('\t', stdout); - fputc('|', stdout); - } - mysql_field_seek(result, 0); - for (i= 0; i < field_count; i++) - { - field= mysql_fetch_field(result); - if (!opt_silent) - { - if (is_null[i]) - fprintf(stdout, " %-*s |", (int) field->max_length, "NULL"); - else if (length[i] == 0) - { - data[i][0]= '\0'; /* unmodified buffer */ - fprintf(stdout, " %*s |", (int) field->max_length, data[i]); - } - else if (IS_NUM(field->type)) - fprintf(stdout, " %*s |", (int) field->max_length, data[i]); - else - fprintf(stdout, " %-*s |", (int) field->max_length, data[i]); - } - } - if (!opt_silent) - { - fputc('\t', stdout); - fputc('\n', stdout); - } - row_count++; - } - DIE_UNLESS(rc == MYSQL_NO_DATA); - if (!opt_silent) - { - if (row_count) - my_print_dashes(result); - fprintf(stdout, "\n\t%d %s returned\n", row_count, - row_count == 1 ? "row" : "rows"); - } - mysql_free_result(result); - return row_count; -} - - -/* Prepare statement, execute, and process result set for given query */ - -int my_stmt_result(const char *buff) -{ - MYSQL_STMT *stmt; - int row_count; - int rc; - - if (!opt_silent) - fprintf(stdout, "\n\n %s", buff); - stmt= mysql_simple_prepare(mysql, buff); - check_stmt(stmt); - - rc= mysql_stmt_execute(stmt); - check_execute(stmt, rc); - - row_count= my_process_stmt_result(stmt); - mysql_stmt_close(stmt); - - return row_count; -} - - -/* Utility function to verify a particular column data */ - -static void verify_col_data(const char *table, const char *col, - const char *exp_data) -{ - static char query[MAX_TEST_QUERY_LENGTH]; - MYSQL_RES *result; - MYSQL_ROW row; - int rc, field= 1; - - if (table && col) - { - strxmov(query, "SELECT ", col, " FROM ", table, " LIMIT 1", NullS); - if (!opt_silent) - fprintf(stdout, "\n %s", query); - rc= mysql_query(mysql, query); - myquery(rc); - - field= 0; - } - - result= mysql_use_result(mysql); - mytest(result); - - if (!(row= mysql_fetch_row(result)) || !row[field]) - { - fprintf(stdout, "\n *** ERROR: FAILED TO GET THE RESULT ***"); - exit(1); - } - if (strcmp(row[field], exp_data)) - { - fprintf(stdout, "\n obtained: `%s` (expected: `%s`)", - row[field], exp_data); - DIE_UNLESS(FALSE); - } - mysql_free_result(result); -} - - -/* Utility function to verify the field members */ - -#define verify_prepare_field(result,no,name,org_name,type,table,\ - org_table,db,length,def) \ - do_verify_prepare_field((result),(no),(name),(org_name),(type), \ - (table),(org_table),(db),(length),(def), \ - __FILE__, __LINE__) - -static void do_verify_prepare_field(MYSQL_RES *result, - unsigned int no, const char *name, - const char *org_name, - enum enum_field_types type, - const char *table, - const char *org_table, const char *db, - unsigned long length, const char *def, - const char *file, int line) -{ - MYSQL_FIELD *field; - CHARSET_INFO *cs; - ulonglong expected_field_length; - - if (!(field= mysql_fetch_field_direct(result, no))) - { - fprintf(stdout, "\n *** ERROR: FAILED TO GET THE RESULT ***"); - exit(1); - } - cs= get_charset(field->charsetnr, 0); - DIE_UNLESS(cs); - if ((expected_field_length= length * cs->mbmaxlen) > UINT_MAX32) - expected_field_length= UINT_MAX32; - if (!opt_silent) - { - fprintf(stdout, "\n field[%d]:", no); - fprintf(stdout, "\n name :`%s`\t(expected: `%s`)", field->name, name); - fprintf(stdout, "\n org_name :`%s`\t(expected: `%s`)", - field->org_name, org_name); - fprintf(stdout, "\n type :`%d`\t(expected: `%d`)", field->type, type); - if (table) - fprintf(stdout, "\n table :`%s`\t(expected: `%s`)", - field->table, table); - if (org_table) - fprintf(stdout, "\n org_table:`%s`\t(expected: `%s`)", - field->org_table, org_table); - fprintf(stdout, "\n database :`%s`\t(expected: `%s`)", field->db, db); - fprintf(stdout, "\n length :`%lu`\t(expected: `%llu`)", - field->length, expected_field_length); - fprintf(stdout, "\n maxlength:`%ld`", field->max_length); - fprintf(stdout, "\n charsetnr:`%d`", field->charsetnr); - fprintf(stdout, "\n default :`%s`\t(expected: `%s`)", - field->def ? field->def : "(null)", def ? def: "(null)"); - fprintf(stdout, "\n"); - } - DIE_UNLESS(strcmp(field->name, name) == 0); - DIE_UNLESS(strcmp(field->org_name, org_name) == 0); - /* - XXX: silent column specification change works based on number of - bytes a column occupies. So CHAR -> VARCHAR upgrade is possible even - for CHAR(2) column if its character set is multibyte. - VARCHAR -> CHAR downgrade won't work for VARCHAR(3) as one would - expect. - */ - if (cs->mbmaxlen == 1) - { - if (field->type != type) - { - fprintf(stderr, - "Expected field type: %d, got type: %d in file %s, line %d\n", - (int) type, (int) field->type, file, line); - DIE_UNLESS(field->type == type); - } - } - if (table) - DIE_UNLESS(strcmp(field->table, table) == 0); - if (org_table) - DIE_UNLESS(strcmp(field->org_table, org_table) == 0); - DIE_UNLESS(strcmp(field->db, db) == 0); - /* - Character set should be taken into account for multibyte encodings, such - as utf8. Field length is calculated as number of characters * maximum - number of bytes a character can occupy. - */ - if (length && (field->length != expected_field_length)) - { - fprintf(stderr, "Expected field length: %llu, got length: %lu\n", - expected_field_length, field->length); - DIE_UNLESS(field->length == expected_field_length); - } - if (def) - DIE_UNLESS(strcmp(field->def, def) == 0); -} - - -/* Utility function to verify the parameter count */ - -static void verify_param_count(MYSQL_STMT *stmt, long exp_count) -{ - long param_count= mysql_stmt_param_count(stmt); - if (!opt_silent) - fprintf(stdout, "\n total parameters in stmt: `%ld` (expected: `%ld`)", - param_count, exp_count); - DIE_UNLESS(param_count == exp_count); -} - - -/* Utility function to verify the total affected rows */ - -static void verify_st_affected_rows(MYSQL_STMT *stmt, ulonglong exp_count) -{ - ulonglong affected_rows= mysql_stmt_affected_rows(stmt); - if (!opt_silent) - fprintf(stdout, "\n total affected rows: `%ld` (expected: `%ld`)", - (long) affected_rows, (long) exp_count); - DIE_UNLESS(affected_rows == exp_count); -} - - -/* Utility function to verify the total affected rows */ - -static void verify_affected_rows(ulonglong exp_count) -{ - ulonglong affected_rows= mysql_affected_rows(mysql); - if (!opt_silent) - fprintf(stdout, "\n total affected rows: `%ld` (expected: `%ld`)", - (long) affected_rows, (long) exp_count); - DIE_UNLESS(affected_rows == exp_count); -} - - -/* Utility function to verify the total fields count */ - -static void verify_field_count(MYSQL_RES *result, uint exp_count) -{ - uint field_count= mysql_num_fields(result); - if (!opt_silent) - fprintf(stdout, "\n total fields in the result set: `%d` (expected: `%d`)", - field_count, exp_count); - DIE_UNLESS(field_count == exp_count); -} - - -/* Utility function to execute a query using prepare-execute */ - -#ifndef EMBEDDED_LIBRARY -static void execute_prepare_query(const char *query, ulonglong exp_count) -{ - MYSQL_STMT *stmt; - ulonglong affected_rows; - int rc; - - stmt= mysql_simple_prepare(mysql, query); - check_stmt(stmt); - - rc= mysql_stmt_execute(stmt); - myquery(rc); - - affected_rows= mysql_stmt_affected_rows(stmt); - if (!opt_silent) - fprintf(stdout, "\n total affected rows: `%ld` (expected: `%ld`)", - (long) affected_rows, (long) exp_count); - - DIE_UNLESS(affected_rows == exp_count); - mysql_stmt_close(stmt); -} -#endif - /* Store result processing */ static void client_store_result() @@ -949,267 +118,6 @@ static void client_use_result() } -/* - Accepts arbitrary number of queries and runs them against the database. - Used to fill tables for each test. -*/ - -void fill_tables(const char **query_list, unsigned query_count) -{ - int rc; - const char **query; - DBUG_ENTER("fill_tables"); - for (query= query_list; query < query_list + query_count; - ++query) - { - rc= mysql_query(mysql, *query); - myquery(rc); - } - DBUG_VOID_RETURN; -} - -/* - All state of fetch from one statement: statement handle, out buffers, - fetch position. - See fetch_n for for the only use case. -*/ - -enum { MAX_COLUMN_LENGTH= 255 }; - -typedef struct st_stmt_fetch -{ - const char *query; - unsigned stmt_no; - MYSQL_STMT *handle; - my_bool is_open; - MYSQL_BIND *bind_array; - char **out_data; - unsigned long *out_data_length; - unsigned column_count; - unsigned row_count; -} Stmt_fetch; - - -/* - Create statement handle, prepare it with statement, execute and allocate - fetch buffers. -*/ - -void stmt_fetch_init(Stmt_fetch *fetch, unsigned stmt_no_arg, - const char *query_arg) -{ - unsigned long type= CURSOR_TYPE_READ_ONLY; - int rc; - unsigned i; - MYSQL_RES *metadata; - DBUG_ENTER("stmt_fetch_init"); - - /* Save query and statement number for error messages */ - fetch->stmt_no= stmt_no_arg; - fetch->query= query_arg; - - fetch->handle= mysql_stmt_init(mysql); - - rc= mysql_stmt_prepare(fetch->handle, fetch->query, strlen(fetch->query)); - check_execute(fetch->handle, rc); - - /* - The attribute is sent to server on execute and asks to open read-only - for result set - */ - mysql_stmt_attr_set(fetch->handle, STMT_ATTR_CURSOR_TYPE, - (const void*) &type); - - rc= mysql_stmt_execute(fetch->handle); - check_execute(fetch->handle, rc); - - /* Find out total number of columns in result set */ - metadata= mysql_stmt_result_metadata(fetch->handle); - fetch->column_count= mysql_num_fields(metadata); - mysql_free_result(metadata); - - /* - Now allocate bind handles and buffers for output data: - calloc memory to reduce number of MYSQL_BIND members we need to - set up. - */ - - fetch->bind_array= (MYSQL_BIND *) calloc(1, sizeof(MYSQL_BIND) * - fetch->column_count); - fetch->out_data= (char**) calloc(1, sizeof(char*) * fetch->column_count); - fetch->out_data_length= (ulong*) calloc(1, sizeof(ulong) * - fetch->column_count); - for (i= 0; i < fetch->column_count; ++i) - { - fetch->out_data[i]= (char*) calloc(1, MAX_COLUMN_LENGTH); - fetch->bind_array[i].buffer_type= MYSQL_TYPE_STRING; - fetch->bind_array[i].buffer= fetch->out_data[i]; - fetch->bind_array[i].buffer_length= MAX_COLUMN_LENGTH; - fetch->bind_array[i].length= fetch->out_data_length + i; - } - - mysql_stmt_bind_result(fetch->handle, fetch->bind_array); - - fetch->row_count= 0; - fetch->is_open= TRUE; - - /* Ready for reading rows */ - DBUG_VOID_RETURN; -} - - -/* Fetch and print one row from cursor */ - -int stmt_fetch_fetch_row(Stmt_fetch *fetch) -{ - int rc; - unsigned i; - DBUG_ENTER("stmt_fetch_fetch_row"); - - if ((rc= mysql_stmt_fetch(fetch->handle)) == 0) - { - ++fetch->row_count; - if (!opt_silent) - printf("Stmt %d fetched row %d:\n", fetch->stmt_no, fetch->row_count); - for (i= 0; i < fetch->column_count; ++i) - { - fetch->out_data[i][fetch->out_data_length[i]]= '\0'; - if (!opt_silent) - printf("column %d: %s\n", i+1, fetch->out_data[i]); - } - } - else - fetch->is_open= FALSE; - DBUG_RETURN(rc); -} - - -void stmt_fetch_close(Stmt_fetch *fetch) -{ - unsigned i; - DBUG_ENTER("stmt_fetch_close"); - - for (i= 0; i < fetch->column_count; ++i) - free(fetch->out_data[i]); - free(fetch->out_data); - free(fetch->out_data_length); - free(fetch->bind_array); - mysql_stmt_close(fetch->handle); - DBUG_VOID_RETURN; -} - -/* - For given array of queries, open query_count cursors and fetch - from them in simultaneous manner. - In case there was an error in one of the cursors, continue - reading from the rest. -*/ - -enum fetch_type { USE_ROW_BY_ROW_FETCH= 0, USE_STORE_RESULT= 1 }; - -my_bool fetch_n(const char **query_list, unsigned query_count, - enum fetch_type fetch_type) -{ - unsigned open_statements= query_count; - int rc, error_count= 0; - Stmt_fetch *fetch_array= (Stmt_fetch*) calloc(1, sizeof(Stmt_fetch) * - query_count); - Stmt_fetch *fetch; - DBUG_ENTER("fetch_n"); - - for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch) - { - /* Init will exit(1) in case of error */ - stmt_fetch_init(fetch, fetch - fetch_array, - query_list[fetch - fetch_array]); - } - - if (fetch_type == USE_STORE_RESULT) - { - for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch) - { - rc= mysql_stmt_store_result(fetch->handle); - check_execute(fetch->handle, rc); - } - } - - while (open_statements) - { - for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch) - { - if (fetch->is_open && (rc= stmt_fetch_fetch_row(fetch))) - { - open_statements--; - /* - We try to fetch from the rest of the statements in case of - error - */ - if (rc != MYSQL_NO_DATA) - { - fprintf(stderr, - "Got error reading rows from statement %d,\n" - "query is: %s,\n" - "error message: %s", (int) (fetch - fetch_array), - fetch->query, - mysql_stmt_error(fetch->handle)); - error_count++; - } - } - } - } - if (error_count) - fprintf(stderr, "Fetch FAILED"); - else - { - unsigned total_row_count= 0; - for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch) - total_row_count+= fetch->row_count; - if (!opt_silent) - printf("Success, total rows fetched: %d\n", total_row_count); - } - for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch) - stmt_fetch_close(fetch); - free(fetch_array); - DBUG_RETURN(error_count != 0); -} - -/* Separate thread query to test some cases */ - -static my_bool thread_query(const char *query) -{ - MYSQL *l_mysql; - my_bool error; - - error= 0; - if (!opt_silent) - fprintf(stdout, "\n in thread_query(%s)", query); - if (!(l_mysql= mysql_client_init(NULL))) - { - myerror("mysql_client_init() failed"); - return 1; - } - if (!(mysql_real_connect(l_mysql, opt_host, opt_user, - opt_password, current_db, opt_port, - opt_unix_socket, 0))) - { - myerror("connection failed"); - error= 1; - goto end; - } - l_mysql->reconnect= 1; - if (mysql_query(l_mysql, query)) - { - fprintf(stderr, "Query failed (%s)\n", mysql_error(l_mysql)); - error= 1; - goto end; - } - mysql_commit(l_mysql); -end: - mysql_close(l_mysql); - return error; -} - - /* Query processing */ static void test_debug_example() @@ -18593,85 +17501,6 @@ static void test_bug13001491() } -/* - Read and parse arguments and MySQL options from my.cnf -*/ - -static const char *client_test_load_default_groups[]= { "client", 0 }; -static char **defaults_argv; - -static struct my_option client_test_long_options[] = -{ - {"basedir", 'b', "Basedir for tests.", &opt_basedir, - &opt_basedir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"count", 't', "Number of times test to be executed", &opt_count, - &opt_count, 0, GET_UINT, REQUIRED_ARG, 1, 0, 0, 0, 0, 0}, - {"database", 'D', "Database to use", &opt_db, &opt_db, - 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"debug", '#', "Output debug log", &default_dbug_option, - &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, - {"help", '?', "Display this help and exit", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, - 0, 0, 0, 0, 0}, - {"host", 'h', "Connect to host", &opt_host, &opt_host, - 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"password", 'p', - "Password to use when connecting to server. If password is not given it's asked from the tty.", - 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, - {"port", 'P', "Port number to use for connection or 0 for default to, in " - "order of preference, my.cnf, $MYSQL_TCP_PORT, " -#if MYSQL_PORT_DEFAULT == 0 - "/etc/services, " -#endif - "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").", - &opt_port, &opt_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"server-arg", 'A', "Send embedded server this as a parameter.", - 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"show-tests", 'T', "Show all tests' names", 0, 0, 0, GET_NO_ARG, NO_ARG, - 0, 0, 0, 0, 0, 0}, - {"silent", 's', "Be more silent", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, - 0}, -#ifdef HAVE_SMEM - {"shared-memory-base-name", 'm', "Base name of shared memory.", - &shared_memory_base_name, (uchar**)&shared_memory_base_name, 0, - GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, -#endif - {"socket", 'S', "Socket file to use for connection", - &opt_unix_socket, &opt_unix_socket, 0, GET_STR, - REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"testcase", 'c', - "May disable some code when runs as mysql-test-run testcase.", - 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, -#ifndef DONT_ALLOW_USER_CHANGE - {"user", 'u', "User for login if not current user", &opt_user, - &opt_user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, -#endif - {"vardir", 'v', "Data dir for tests.", &opt_vardir, - &opt_vardir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"getopt-ll-test", 'g', "Option for testing bug in getopt library", - &opt_getopt_ll_test, &opt_getopt_ll_test, 0, - GET_LL, REQUIRED_ARG, 0, 0, LONGLONG_MAX, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} -}; - - -static void usage(void) -{ - /* show the usage string when the user asks for this */ - putc('\n', stdout); - printf("%s Ver %s Distrib %s, for %s (%s)\n", - my_progname, VER, MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE); - puts("By Monty, Venu, Kent and others\n"); - printf("\ -Copyright (C) 2002-2004 MySQL AB\n\ -This software comes with ABSOLUTELY NO WARRANTY. This is free software,\n\ -and you are welcome to modify and redistribute it under the GPL license\n"); - printf("Usage: %s [OPTIONS] [TESTNAME1 TESTNAME2...]\n", my_progname); - my_print_help(client_test_long_options); - print_defaults("my", client_test_load_default_groups); - my_print_variables(client_test_long_options); -} - - static struct my_tests_st my_tests[]= { { "disable_query_logs", disable_query_logs }, { "test_view_sp_list_fields", test_view_sp_list_fields }, @@ -18926,181 +17755,4 @@ static struct my_tests_st my_tests[]= { }; -static my_bool -get_one_option(int optid, const struct my_option *opt __attribute__((unused)), - char *argument) -{ - switch (optid) { - case '#': - DBUG_PUSH(argument ? argument : default_dbug_option); - break; - case 'c': - opt_testcase = 1; - break; - case 'p': - if (argument) - { - char *start=argument; - my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR)); - opt_password= my_strdup(argument, MYF(MY_FAE)); - while (*argument) *argument++= 'x'; /* Destroy argument */ - if (*start) - start[1]=0; - } - else - tty_password= 1; - break; - case 's': - if (argument == disabled_my_option) - opt_silent= 0; - else - opt_silent++; - break; - case 'A': - /* - When the embedded server is being tested, the test suite needs to be - able to pass command-line arguments to the embedded server so it can - locate the language files and data directory. The test suite - (mysql-test-run) never uses config files, just command-line options. - */ - if (!embedded_server_arg_count) - { - embedded_server_arg_count= 1; - embedded_server_args[0]= (char*) ""; - } - if (embedded_server_arg_count == MAX_SERVER_ARGS-1 || - !(embedded_server_args[embedded_server_arg_count++]= - my_strdup(argument, MYF(MY_FAE)))) - { - DIE("Can't use server argument"); - } - break; - case 'T': - { - struct my_tests_st *fptr; - - printf("All possible test names:\n\n"); - for (fptr= my_tests; fptr->name; fptr++) - printf("%s\n", fptr->name); - exit(0); - break; - } - case '?': - case 'I': /* Info */ - usage(); - exit(0); - break; - } - return 0; -} - -static void get_options(int *argc, char ***argv) -{ - int ho_error; - - if ((ho_error= handle_options(argc, argv, client_test_long_options, - get_one_option))) - exit(ho_error); - - if (tty_password) - opt_password= get_tty_password(NullS); - return; -} - -/* - Print the test output on successful execution before exiting -*/ - -static void print_test_output() -{ - if (opt_silent < 3) - { - fprintf(stdout, "\n\n"); - fprintf(stdout, "All '%d' tests were successful (in '%d' iterations)", - test_count-1, opt_count); - fprintf(stdout, "\n Total execution time: %g SECS", total_time); - if (opt_count > 1) - fprintf(stdout, " (Avg: %g SECS)", total_time/opt_count); - - fprintf(stdout, "\n\n!!! SUCCESS !!!\n"); - } -} - -/*************************************************************************** - main routine -***************************************************************************/ - - -int main(int argc, char **argv) -{ - struct my_tests_st *fptr; - - MY_INIT(argv[0]); - - load_defaults("my", client_test_load_default_groups, &argc, &argv); - defaults_argv= argv; - get_options(&argc, &argv); - - if (mysql_server_init(embedded_server_arg_count, - embedded_server_args, - (char**) embedded_server_groups)) - DIE("Can't initialize MySQL server"); - - /* connect to server with no flags, default protocol, auto reconnect true */ - mysql= client_connect(0, MYSQL_PROTOCOL_DEFAULT, 1); - - total_time= 0; - for (iter_count= 1; iter_count <= opt_count; iter_count++) - { - /* Start of tests */ - test_count= 1; - start_time= time((time_t *)0); - if (!argc) - { - for (fptr= my_tests; fptr->name; fptr++) - (*fptr->function)(); - } - else - { - for ( ; *argv ; argv++) - { - for (fptr= my_tests; fptr->name; fptr++) - { - if (!strcmp(fptr->name, *argv)) - { - (*fptr->function)(); - break; - } - } - if (!fptr->name) - { - fprintf(stderr, "\n\nGiven test not found: '%s'\n", *argv); - fprintf(stderr, "See legal test names with %s -T\n\nAborting!\n", - my_progname); - client_disconnect(mysql, 1); - free_defaults(defaults_argv); - exit(1); - } - } - } - - end_time= time((time_t *)0); - total_time+= difftime(end_time, start_time); - - /* End of tests */ - } - - client_disconnect(mysql, 1); /* disconnect from server */ - - free_defaults(defaults_argv); - print_test_output(); - - while (embedded_server_arg_count > 1) - my_free(embedded_server_args[--embedded_server_arg_count],MYF(0)); - - mysql_server_end(); - - my_end(0); - - exit(0); -} +static struct my_tests_st *get_my_tests() { return my_tests; } From aacb690bd52942d2152e661f451fb3b4dd8e0ccf Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Mon, 9 Jul 2012 16:36:50 +0200 Subject: [PATCH 135/289] Fixed compile error in mysql_client_test using gcc --- tests/mysql_client_fw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/mysql_client_fw.c b/tests/mysql_client_fw.c index 27a06501d7a..34a4c05215b 100644 --- a/tests/mysql_client_fw.c +++ b/tests/mysql_client_fw.c @@ -1190,7 +1190,7 @@ and you are welcome to modify and redistribute it under the GPL license\n"); } -struct my_tests_st *get_my_tests(); /* Will be defined in main .c file */ +static struct my_tests_st *get_my_tests(); /* To be defined in main .c file */ static struct my_tests_st *my_testlist= 0; From 703ee1ad1b0a2ae3af65236f03e588493f09f5d8 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Tue, 10 Jul 2012 09:02:12 +0300 Subject: [PATCH 136/289] Fixed MDEV-385: mysqltest running with continue-on-error crashes on a non-SQL command producing an error client/mysqltest.cc: Added missing DBUG_VOID_RETURN --- client/mysqltest.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/mysqltest.cc b/client/mysqltest.cc index 01613223d64..961114c9a40 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -1285,7 +1285,7 @@ void handle_command_error(struct st_command *command, uint error, "errno: %d", command->first_word_len, command->query, error, my_errno, sys_errno); - return; + DBUG_VOID_RETURN; } i= match_expected_error(command, error, NULL); From b21319483f708a9bdff43d2773b67043054f5a35 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Tue, 10 Jul 2012 10:04:57 +0200 Subject: [PATCH 137/289] mysql_client_test did not build within limbysqld/examples --- libmysqld/examples/CMakeLists.txt | 3 ++- libmysqld/examples/Makefile.am | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/libmysqld/examples/CMakeLists.txt b/libmysqld/examples/CMakeLists.txt index 2b900a1fa8f..d7f994d9b9f 100644 --- a/libmysqld/examples/CMakeLists.txt +++ b/libmysqld/examples/CMakeLists.txt @@ -17,7 +17,8 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/libmysqld/include ${CMAKE_SOURCE_DIR}/regex - ${CMAKE_SOURCE_DIR}/zlib + ${CMAKE_SOURCE_DIR}/zlib + ${CMAKE_SOURCE_DIR}/tests ${CMAKE_SOURCE_DIR}/extra/yassl/include) # Currently does not work with DBUG, there are missing symbols reported. diff --git a/libmysqld/examples/Makefile.am b/libmysqld/examples/Makefile.am index a732b209e27..a0f1a64ffdc 100644 --- a/libmysqld/examples/Makefile.am +++ b/libmysqld/examples/Makefile.am @@ -35,7 +35,7 @@ link_sources: DEFS = -DEMBEDDED_LIBRARY INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include -I$(srcdir) \ -I$(top_srcdir) -I$(top_srcdir)/client -I$(top_srcdir)/regex \ - $(openssl_includes) + -I$(top_srcdir)/tests $(openssl_includes) LIBS = @LIBS@ @WRAPLIBS@ @CLIENT_LIBS@ $(yassl_libs) LDADD = @CLIENT_EXTRA_LDFLAGS@ ../libmysqld.a @LIBDL@ $(CXXLDFLAGS) \ @NDB_SCI_LIBS@ @@ -51,6 +51,7 @@ mysql_LDADD = @readline_link@ @TERMCAP_LIB@ $(LDADD) mysql_client_test_embedded_LINK = $(CXXLINK) nodist_mysql_client_test_embedded_SOURCES = mysql_client_test.c +mysql_client_test.o: $(top_srcdir)/tests/mysql_client_fw.c # Don't update the files from bitkeeper %::SCCS/s.% From 13f7f002886c18fc911f6cf6d5bd672f8c96d844 Mon Sep 17 00:00:00 2001 From: Sujatha Sivakumar Date: Tue, 10 Jul 2012 14:23:17 +0530 Subject: [PATCH 138/289] BUG#11762670:MY_B_WRITE RETURN VALUE IGNORED Problem: ======= The return value from my_b_write is ignored by: `my_b_write_quoted', `my_b_write_bit',`Query_log_event::print_query_header' Most callers of `my_b_printf' ignore the return value. `log_event.cc' has many calls to it. Analysis: ======== `my_b_write' is used to write data into a file. If the write fails it sets appropriate error number and error message through my_error() function call and sets the IO_CACHE::error == -1. `my_b_printf' function is also used to write data into a file, it internally invokes my_b_write to do the write operation. Upon success it returns number of characters written to file and on error it returns -1 and sets the error through my_error() and also sets IO_CACHE::error == -1. Most of the event specific print functions for example `Create_file_log_event::print', `Execute_load_log_event::print' etc are the ones which make several calls to the above two functions and they do not check for the return value after the 'print' call. All the above mentioned abuse cases deal with the client side. Fix: === As part of bug fix a check for IO_CACHE::error == -1 has been added at a very high level after the call to the 'print' function. There are few more places where the return value of "my_b_write" is ignored those are mentioned below. +++ mysys/mf_iocache2.c 2012-06-04 07:03:15 +0000 @@ -430,7 +430,8 @@ memset(buffz, '0', minimum_width - length2); else memset(buffz, ' ', minimum_width - length2); - my_b_write(info, buffz, minimum_width - length2); +++ sql/log.cc 2012-06-08 09:04:46 +0000 @@ -2388,7 +2388,12 @@ { end= strxmov(buff, "# administrator command: ", NullS); buff_len= (ulong) (end - buff); - my_b_write(&log_file, (uchar*) buff, buff_len); At these places appropriate return value handlers have been added. client/mysqlbinlog.cc: check for IO_CACHE::error == -1 has been added after the call to the event specific print functions mysys/mf_iocache2.c: Added handler to check the written value of `my_b_write' sql/log.cc: Added handler to check the written value of `my_b_write' sql/log_event.cc: Added error simulation statements in `Create_file_log_event::print` and `Execute_load_query_log_event::print' sql/rpl_utility.h: Removed the extra ';' --- client/mysqlbinlog.cc | 13 ++++++++++++- mysys/mf_iocache2.c | 6 +++++- sql/log.cc | 5 ++++- sql/log_event.cc | 24 +++++++++++++++++++----- sql/rpl_utility.h | 2 +- 5 files changed, 41 insertions(+), 9 deletions(-) diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index e7840865a58..b5acfc5c169 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -784,8 +784,11 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, goto end; } else + { ce->print(result_file, print_event_info, TRUE); - + if (head->error == -1) + goto err; + } // If this binlog is not 3.23 ; why this test?? if (glob_description_event->binlog_version >= 3) { @@ -836,6 +839,8 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, ce->print(result_file, print_event_info, TRUE); my_free((char*)ce->fname,MYF(MY_WME)); delete ce; + if (head->error == -1) + goto err; } else warning("Ignoring Execute_load_log_event as there is no " @@ -890,6 +895,12 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, { convert_path_to_forward_slashes(fname); exlq->print(result_file, print_event_info, fname); + if (head->error == -1) + { + if (fname) + my_free(fname, MYF(MY_WME)); + goto err; + } } else warning("Ignoring Execute_load_query since there is no " diff --git a/mysys/mf_iocache2.c b/mysys/mf_iocache2.c index 828145b7931..dd56e332433 100644 --- a/mysys/mf_iocache2.c +++ b/mysys/mf_iocache2.c @@ -430,7 +430,11 @@ process_flags: memset(buffz, '0', minimum_width - length2); else memset(buffz, ' ', minimum_width - length2); - my_b_write(info, buffz, minimum_width - length2); + if (my_b_write(info, buffz, minimum_width - length2)) + { + my_afree(buffz); + goto err; + } my_afree(buffz); } diff --git a/sql/log.cc b/sql/log.cc index 3714f1190be..57c14b24782 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -2388,7 +2388,10 @@ bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time, { end= strxmov(buff, "# administrator command: ", NullS); buff_len= (ulong) (end - buff); - my_b_write(&log_file, (uchar*) buff, buff_len); + DBUG_EXECUTE_IF("simulate_slow_log_write_error", + {DBUG_SET("+d,simulate_file_write_error");}); + if(my_b_write(&log_file, (uchar*) buff, buff_len)) + tmp_errno= errno; } if (my_b_write(&log_file, (uchar*) sql_text, sql_text_len) || my_b_write(&log_file, (uchar*) ";\n",2) || diff --git a/sql/log_event.cc b/sql/log_event.cc index a47b3680d82..2ad740698c6 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -6312,11 +6312,18 @@ void Create_file_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info { Load_log_event::print(file, print_event_info, !check_fname_outside_temp_buf()); - /* - That one is for "file_id: etc" below: in mysqlbinlog we want the #, in - SHOW BINLOG EVENTS we don't. - */ - my_b_printf(&cache, "#"); + /** + reduce the size of io cache so that the write function is called + for every call to my_b_printf(). + */ + DBUG_EXECUTE_IF ("simulate_create_event_write_error", + {(&cache)->write_pos= (&cache)->write_end; + DBUG_SET("+d,simulate_file_write_error");}); + /* + That one is for "file_id: etc" below: in mysqlbinlog we want the #, in + SHOW BINLOG EVENTS we don't. + */ + my_b_printf(&cache, "#"); } my_b_printf(&cache, " file_id: %d block_len: %d\n", file_id, block_len); @@ -6992,6 +6999,13 @@ void Execute_load_query_log_event::print(FILE* file, Write_on_release_cache cache(&print_event_info->head_cache, file); print_query_header(&cache, print_event_info); + /** + reduce the size of io cache so that the write function is called + for every call to my_b_printf(). + */ + DBUG_EXECUTE_IF ("simulate_execute_event_write_error", + {(&cache)->write_pos= (&cache)->write_end; + DBUG_SET("+d,simulate_file_write_error");}); if (local_fname) { diff --git a/sql/rpl_utility.h b/sql/rpl_utility.h index 81a10cca814..b2577643add 100644 --- a/sql/rpl_utility.h +++ b/sql/rpl_utility.h @@ -300,7 +300,7 @@ private: public: Deferred_log_events(Relay_log_info *rli); ~Deferred_log_events(); - /* queue for exection at Query-log-event time prior the Query */; + /* queue for exection at Query-log-event time prior the Query */ int add(Log_event *ev); bool is_empty(); bool execute(Relay_log_info *rli); From dc050309716ec62531753a0edb0676fa03f138dc Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Tue, 10 Jul 2012 11:48:43 +0200 Subject: [PATCH 139/289] mysql_client_fw.c was not included in make dist --- tests/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Makefile.am b/tests/Makefile.am index 4929fa7ba9b..3da18683f85 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -33,6 +33,7 @@ EXTRA_DIST = auto_increment.res auto_increment.tst \ grant.pl grant.res test_delayed_insert.pl \ pmail.pl mail_to_db.pl table_types.pl \ myisam-big-rows.tst \ + mysql_client_fw.c \ CMakeLists.txt bin_PROGRAMS = mysql_client_test From 86476179479eb14343e1d434a2345d9cad47a28a Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Tue, 10 Jul 2012 11:57:24 +0200 Subject: [PATCH 140/289] mysql_client_fw.c was not included in make dist --- tests/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Makefile.am b/tests/Makefile.am index 4929fa7ba9b..3da18683f85 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -33,6 +33,7 @@ EXTRA_DIST = auto_increment.res auto_increment.tst \ grant.pl grant.res test_delayed_insert.pl \ pmail.pl mail_to_db.pl table_types.pl \ myisam-big-rows.tst \ + mysql_client_fw.c \ CMakeLists.txt bin_PROGRAMS = mysql_client_test From 6da51d170519ac6f0492eccdb33026e9031f653a Mon Sep 17 00:00:00 2001 From: Rohit Kalhans Date: Tue, 10 Jul 2012 18:24:11 +0530 Subject: [PATCH 141/289] BUG#11759333: SBR LOGGING WARNING MESSAGES FOR PRIMARY KEY UPDATES WITH A LIMIT OF 1 Problem: The unsafety warning for statements such as update...limit1 where pk=1 are thrown when binlog-format = STATEMENT,despite of the fact that such statements are actually safe. this leads to filling up of the disk space with false warnings. Solution: This is not a complete fix for the problem, but prevents the disks from getting filled up. This should therefore be regarded as a workaround. In the future this should be overriden by server general suppress/filtering framework. It should also be noted that another worklog is supposed to defeat this case's artificial unsafety. We use a warning suppression mechanism to detect warning flood, enable the suppression, and disable this when the average warnings/second has reduced to acceptable limits. Activation: The supression for LIMIT unsafe statements are activated when the last 50 warnings were logged in less than 50 seconds. Supression: Once activated this supression will prevent the individual warnings to be logged in the error log, but print the warning for every 50 warnings with the note: "The last warning was repeated N times in last S seconds" Noteworthy is the fact that this supression works only on the error logs and the warnings seen by the clients will remain as it is (i.e. one warning/ unsafe statement) Deactivation: The supression will be deactivated once the average # of warnings/sec have gone down to the acceptable limits. sql/sql_class.cc: Added code to supress warning while logging them to error-log. --- sql/sql_class.cc | 144 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 139 insertions(+), 5 deletions(-) diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 7e93157c69e..c118030e7b4 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -4806,6 +4806,140 @@ show_query_type(THD::enum_binlog_query_type qtype) } #endif +/* + Constants required for the limit unsafe warnings suppression +*/ +//seconds after which the limit unsafe warnings suppression will be activated +#define LIMIT_UNSAFE_WARNING_ACTIVATION_TIMEOUT 50 +//number of limit unsafe warnings after which the suppression will be activated +#define LIMIT_UNSAFE_WARNING_ACTIVATION_THRESHOLD_COUNT 50 + +static struct timeval limit_unsafe_suppression_start_time; +static struct timezone limit_unsafe_suppression_start_time_zone; +static bool unsafe_warning_suppression_is_activated= false; +static int limit_unsafe_warning_count= 0; + +/** + Auxiliary function to reset the limit unsafety warning suppression. +*/ +static void reset_binlog_unsafe_suppression() +{ + DBUG_ENTER("reset_binlog_unsafe_suppression"); + unsafe_warning_suppression_is_activated= false; + limit_unsafe_warning_count= 0; + gettimeofday(&limit_unsafe_suppression_start_time, + &limit_unsafe_suppression_start_time_zone); + DBUG_VOID_RETURN; +} + +/** + Auxiliary function to print warning in the error log. +*/ +static void print_unsafe_warning_to_log(int unsafe_type, char* buf, + char* query) +{ + DBUG_ENTER("print_unsafe_warning_in_log"); + sprintf(buf, ER(ER_BINLOG_UNSAFE_STATEMENT), + ER(LEX::binlog_stmt_unsafe_errcode[unsafe_type])); + sql_print_warning(ER(ER_MESSAGE_AND_STATEMENT), buf, query); + DBUG_VOID_RETURN; +} + +/** + Auxiliary function to check if the warning for limit unsafety should be + thrown or suppressed. Details of the implementation can be found in the + comments inline. + SYNOPSIS: + @params + buf - buffer to hold the warning message text + unsafe_type - The type of unsafety. + query - The actual query statement. + + TODO: Remove this function and implement a general service for all warnings + that would prevent flooding the error log. +*/ +static void do_unsafe_limit_checkout(char* buf, int unsafe_type, char* query) +{ + struct timeval now; + struct timezone tz_now; + DBUG_ENTER("do_unsafe_limit_checkout"); + DBUG_ASSERT(unsafe_type == LEX::BINLOG_STMT_UNSAFE_LIMIT); + limit_unsafe_warning_count++; + /* + INITIALIZING: + If this is the first time this function is called with log warning + enabled, the monitoring the unsafe warnings should start. + */ + if (limit_unsafe_suppression_start_time.tv_sec == 0) + { + gettimeofday(&limit_unsafe_suppression_start_time, + &limit_unsafe_suppression_start_time_zone); + print_unsafe_warning_to_log(unsafe_type, buf, query); + } + else + { + if (!unsafe_warning_suppression_is_activated) + print_unsafe_warning_to_log(unsafe_type, buf, query); + + if (limit_unsafe_warning_count >= + LIMIT_UNSAFE_WARNING_ACTIVATION_THRESHOLD_COUNT) + { + gettimeofday (&now, &tz_now); + if (!unsafe_warning_suppression_is_activated) + { + /* + ACTIVATION: + We got LIMIT_UNSAFE_WARNING_ACTIVATION_THRESHOLD_COUNT warnings in + less than LIMIT_UNSAFE_WARNING_ACTIVATION_TIMEOUT we activate the + suppression. + */ + if ((now.tv_sec-limit_unsafe_suppression_start_time.tv_sec) <= + LIMIT_UNSAFE_WARNING_ACTIVATION_TIMEOUT) + { + unsafe_warning_suppression_is_activated= true; + DBUG_PRINT("info",("A warning flood has been detected and the limit \ +unsafety warning suppression has been activated.")); + } + else + { + /* + there is no flooding till now, therefore we restart the monitoring + */ + gettimeofday(&limit_unsafe_suppression_start_time, + &limit_unsafe_suppression_start_time_zone); + limit_unsafe_warning_count= 0; + } + } + else + { + /* + Print the suppression note and the unsafe warning. + */ + sql_print_information("The following warning was suppressed %d times \ +during the last %d seconds in the error log", + limit_unsafe_warning_count, + (int) + (now.tv_sec - + limit_unsafe_suppression_start_time.tv_sec)); + print_unsafe_warning_to_log(unsafe_type, buf, query); + /* + DEACTIVATION: We got LIMIT_UNSAFE_WARNING_ACTIVATION_THRESHOLD_COUNT + warnings in more than LIMIT_UNSAFE_WARNING_ACTIVATION_TIMEOUT, the + suppression should be deactivated. + */ + if ((now.tv_sec - limit_unsafe_suppression_start_time.tv_sec) > + LIMIT_UNSAFE_WARNING_ACTIVATION_TIMEOUT) + { + reset_binlog_unsafe_suppression(); + DBUG_PRINT("info",("The limit unsafety warning supression has been \ +deactivated")); + } + } + limit_unsafe_warning_count= 0; + } + } + DBUG_VOID_RETURN; +} /** Auxiliary method used by @c binlog_query() to raise warnings. @@ -4815,6 +4949,7 @@ show_query_type(THD::enum_binlog_query_type qtype) */ void THD::issue_unsafe_warnings() { + char buf[MYSQL_ERRMSG_SIZE * 2]; DBUG_ENTER("issue_unsafe_warnings"); /* Ensure that binlog_unsafe_warning_flags is big enough to hold all @@ -4840,17 +4975,16 @@ void THD::issue_unsafe_warnings() ER(LEX::binlog_stmt_unsafe_errcode[unsafe_type])); if (global_system_variables.log_warnings) { - char buf[MYSQL_ERRMSG_SIZE * 2]; - sprintf(buf, ER(ER_BINLOG_UNSAFE_STATEMENT), - ER(LEX::binlog_stmt_unsafe_errcode[unsafe_type])); - sql_print_warning(ER(ER_MESSAGE_AND_STATEMENT), buf, query()); + if (unsafe_type == LEX::BINLOG_STMT_UNSAFE_LIMIT) + do_unsafe_limit_checkout( buf, unsafe_type, query()); + else //cases other than LIMIT unsafety + print_unsafe_warning_to_log(unsafe_type, buf, query()); } } } DBUG_VOID_RETURN; } - /** Log the current query. From dfa0093096f305a893fdd9baefe010523f94c4a5 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 10 Jul 2012 18:55:07 +0530 Subject: [PATCH 142/289] From a47e778a61e26a195642dde82f0062da2dfa2aaa Mon Sep 17 00:00:00 2001 From: Jon Olav Hauglid Date: Tue, 10 Jul 2012 16:13:02 +0200 Subject: [PATCH 143/289] Bug#12623923 Server can crash after failure to create primary key with innodb tables The bug was triggered if a single ALTER TABLE statement both added and dropped indexes and ALTER TABLE failed during drop (e.g. because the index was needed in a foreign key constraint). In such cases, the server index information would get out of sync with InnoDB - the added index would be present inside InnoDB, but not in the server. This could then lead to InnoDB error messages and/or server crashes. The root cause is that new indexes are added before old indexes are dropped. This means that if ALTER TABLE fails while dropping indexes, index changes will be reverted in the server but not inside InnoDB. This patch fixes the problem by dropping any added indexes if drop fails (for ALTER TABLE statements that both adds and drops indexes). However, this won't work if we added a primary key as this key might not be possible to drop inside InnoDB. Therefore, we resort to the copy algorithm if a primary key is added by an ALTER TABLE statement that also drops an index. In 5.6 this bug is more properly fixed by the handler interface changes done in the scope of WL#5534 "Online ALTER". --- sql/sql_table.cc | 49 +++++++++++++++++++---- storage/innobase/handler/ha_innodb.cc | 13 ++++-- storage/innobase/handler/handler0alter.cc | 14 +++---- 3 files changed, 57 insertions(+), 19 deletions(-) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 60ae2ed800b..7d70fa8afd2 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -6313,11 +6313,23 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, the primary key is not added and dropped in the same statement. Otherwise we have to recreate the table. need_copy_table is no-zero at this place. + + Also, in-place is not possible if we add a primary key + and drop another key in the same statement. If the drop fails, + we will not be able to revert adding of primary key. */ if ( pk_changed < 2 ) { - if ((alter_flags & needed_inplace_with_read_flags) == - needed_inplace_with_read_flags) + if ((needed_inplace_with_read_flags & HA_INPLACE_ADD_PK_INDEX_NO_WRITE) && + index_drop_count > 0) + { + /* + Do copy, not in-place ALTER. + Avoid setting ALTER_TABLE_METADATA_ONLY. + */ + } + else if ((alter_flags & needed_inplace_with_read_flags) == + needed_inplace_with_read_flags) { /* All required in-place flags to allow concurrent reads are present. */ need_copy_table= ALTER_TABLE_METADATA_ONLY; @@ -6579,17 +6591,38 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, Tell the handler to prepare for drop indexes. This re-numbers the indexes to get rid of gaps. */ - if ((error= table->file->prepare_drop_index(table, key_numbers, - index_drop_count))) + error= table->file->prepare_drop_index(table, key_numbers, + index_drop_count); + if (!error) { - table->file->print_error(error, MYF(0)); - goto err_new_table_cleanup; + /* Tell the handler to finally drop the indexes. */ + error= table->file->final_drop_index(table); } - /* Tell the handler to finally drop the indexes. */ - if ((error= table->file->final_drop_index(table))) + if (error) { table->file->print_error(error, MYF(0)); + if (index_add_count) // Drop any new indexes added. + { + /* + Temporarily set table-key_info to include information about the + indexes added above that we now need to drop. + */ + KEY *save_key_info= table->key_info; + table->key_info= key_info_buffer; + if ((error= table->file->prepare_drop_index(table, index_add_buffer, + index_add_count))) + table->file->print_error(error, MYF(0)); + else if ((error= table->file->final_drop_index(table))) + table->file->print_error(error, MYF(0)); + table->key_info= save_key_info; + } + + /* + Mark this TABLE instance as stale to avoid + out-of-sync index information. + */ + table->m_needs_reopen= true; goto err_new_table_cleanup; } } diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index ea47a8160f9..60a62482f9c 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -8010,10 +8010,15 @@ innobase_get_mysql_key_number_for_index( } } - /* Print an error message if we cannot find the index - ** in the "index translation table". */ - sql_print_error("Cannot find index %s in InnoDB index " - "translation table.", index->name); + /* If index_count in translation table is set to 0, it + is possible we are in the process of rebuilding table, + do not spit error in this case */ + if (share->idx_trans_tbl.index_count) { + /* Print an error message if we cannot find the index + ** in the "index translation table". */ + sql_print_error("Cannot find index %s in InnoDB index " + "translation table.", index->name); + } } /* If we do not have an "index translation table", or not able diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index e8e3cb0e5cd..5e20bea36dd 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -773,7 +773,7 @@ ha_innobase::add_index( row_mysql_lock_data_dictionary(trx); dict_locked = TRUE; - ut_d(dict_table_check_for_dup_indexes(prebuilt->table, FALSE)); + ut_d(dict_table_check_for_dup_indexes(prebuilt->table, TRUE)); /* If a new primary key is defined for the table we need to drop the original table and rebuild all indexes. */ @@ -809,7 +809,7 @@ ha_innobase::add_index( } ut_d(dict_table_check_for_dup_indexes(prebuilt->table, - FALSE)); + TRUE)); mem_heap_free(heap); trx_general_rollback_for_mysql(trx, NULL); row_mysql_unlock_data_dictionary(trx); @@ -1061,7 +1061,7 @@ ha_innobase::final_add_index( trx_commit_for_mysql(prebuilt->trx); } - ut_d(dict_table_check_for_dup_indexes(prebuilt->table, FALSE)); + ut_d(dict_table_check_for_dup_indexes(prebuilt->table, TRUE)); row_mysql_unlock_data_dictionary(trx); trx_free_for_mysql(trx); @@ -1104,7 +1104,7 @@ ha_innobase::prepare_drop_index( /* Test and mark all the indexes to be dropped */ row_mysql_lock_data_dictionary(trx); - ut_d(dict_table_check_for_dup_indexes(prebuilt->table, FALSE)); + ut_d(dict_table_check_for_dup_indexes(prebuilt->table, TRUE)); /* Check that none of the indexes have previously been flagged for deletion. */ @@ -1275,7 +1275,7 @@ func_exit: } while (index); } - ut_d(dict_table_check_for_dup_indexes(prebuilt->table, FALSE)); + ut_d(dict_table_check_for_dup_indexes(prebuilt->table, TRUE)); row_mysql_unlock_data_dictionary(trx); DBUG_RETURN(err); @@ -1322,7 +1322,7 @@ ha_innobase::final_drop_index( prebuilt->table->flags, user_thd); row_mysql_lock_data_dictionary(trx); - ut_d(dict_table_check_for_dup_indexes(prebuilt->table, FALSE)); + ut_d(dict_table_check_for_dup_indexes(prebuilt->table, TRUE)); if (UNIV_UNLIKELY(err)) { @@ -1366,7 +1366,7 @@ ha_innobase::final_drop_index( share->idx_trans_tbl.index_count = 0; func_exit: - ut_d(dict_table_check_for_dup_indexes(prebuilt->table, FALSE)); + ut_d(dict_table_check_for_dup_indexes(prebuilt->table, TRUE)); trx_commit_for_mysql(trx); trx_commit_for_mysql(prebuilt->trx); row_mysql_unlock_data_dictionary(trx); From 3a71ab0805f2e8cb46872d10b98d8355d15ddcb8 Mon Sep 17 00:00:00 2001 From: Mayank Prasad Date: Tue, 10 Jul 2012 19:59:59 +0530 Subject: [PATCH 144/289] Bug#13889741: HANDLE_FATAL_SIGNAL IN _DB_ENTER_ |HANDLE_FATAL_SIGNAL IN STRNLEN Follow up patch to resolve pb2 failure on windows platform --- sql/sql_show.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 189532b2479..e9873d2325f 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2784,9 +2784,12 @@ int make_db_list(THD *thd, List *files, /* If we have db lookup vaule we just add it to list and - exit from the function + exit from the function. + We don't do this for database names longer than the maximum + path length. */ - if (lookup_field_vals->db_value.str) + if (lookup_field_vals->db_value.str && + lookup_field_vals->db_value.length < FN_REFLEN) { if (is_infoschema_db(lookup_field_vals->db_value.str, lookup_field_vals->db_value.length)) From 6fe6288d837a1a3d6a78db9a230e009d039464ab Mon Sep 17 00:00:00 2001 From: Rohit Kalhans Date: Tue, 10 Jul 2012 22:02:25 +0530 Subject: [PATCH 145/289] bug#11759333: follow-up patch for the failure on pb2 windows build --- sql/sql_class.cc | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/sql/sql_class.cc b/sql/sql_class.cc index c118030e7b4..8931d67dd25 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -4814,8 +4814,7 @@ show_query_type(THD::enum_binlog_query_type qtype) //number of limit unsafe warnings after which the suppression will be activated #define LIMIT_UNSAFE_WARNING_ACTIVATION_THRESHOLD_COUNT 50 -static struct timeval limit_unsafe_suppression_start_time; -static struct timezone limit_unsafe_suppression_start_time_zone; +static ulonglong limit_unsafe_suppression_start_time= 0; static bool unsafe_warning_suppression_is_activated= false; static int limit_unsafe_warning_count= 0; @@ -4827,8 +4826,7 @@ static void reset_binlog_unsafe_suppression() DBUG_ENTER("reset_binlog_unsafe_suppression"); unsafe_warning_suppression_is_activated= false; limit_unsafe_warning_count= 0; - gettimeofday(&limit_unsafe_suppression_start_time, - &limit_unsafe_suppression_start_time_zone); + limit_unsafe_suppression_start_time= my_getsystime()/10000000; DBUG_VOID_RETURN; } @@ -4860,8 +4858,7 @@ static void print_unsafe_warning_to_log(int unsafe_type, char* buf, */ static void do_unsafe_limit_checkout(char* buf, int unsafe_type, char* query) { - struct timeval now; - struct timezone tz_now; + ulonglong now= 0; DBUG_ENTER("do_unsafe_limit_checkout"); DBUG_ASSERT(unsafe_type == LEX::BINLOG_STMT_UNSAFE_LIMIT); limit_unsafe_warning_count++; @@ -4870,10 +4867,9 @@ static void do_unsafe_limit_checkout(char* buf, int unsafe_type, char* query) If this is the first time this function is called with log warning enabled, the monitoring the unsafe warnings should start. */ - if (limit_unsafe_suppression_start_time.tv_sec == 0) + if (limit_unsafe_suppression_start_time == 0) { - gettimeofday(&limit_unsafe_suppression_start_time, - &limit_unsafe_suppression_start_time_zone); + limit_unsafe_suppression_start_time= my_getsystime()/10000000; print_unsafe_warning_to_log(unsafe_type, buf, query); } else @@ -4884,7 +4880,7 @@ static void do_unsafe_limit_checkout(char* buf, int unsafe_type, char* query) if (limit_unsafe_warning_count >= LIMIT_UNSAFE_WARNING_ACTIVATION_THRESHOLD_COUNT) { - gettimeofday (&now, &tz_now); + now= my_getsystime()/10000000; if (!unsafe_warning_suppression_is_activated) { /* @@ -4893,7 +4889,7 @@ static void do_unsafe_limit_checkout(char* buf, int unsafe_type, char* query) less than LIMIT_UNSAFE_WARNING_ACTIVATION_TIMEOUT we activate the suppression. */ - if ((now.tv_sec-limit_unsafe_suppression_start_time.tv_sec) <= + if ((now-limit_unsafe_suppression_start_time) <= LIMIT_UNSAFE_WARNING_ACTIVATION_TIMEOUT) { unsafe_warning_suppression_is_activated= true; @@ -4905,8 +4901,7 @@ unsafety warning suppression has been activated.")); /* there is no flooding till now, therefore we restart the monitoring */ - gettimeofday(&limit_unsafe_suppression_start_time, - &limit_unsafe_suppression_start_time_zone); + limit_unsafe_suppression_start_time= my_getsystime()/10000000; limit_unsafe_warning_count= 0; } } @@ -4919,15 +4914,14 @@ unsafety warning suppression has been activated.")); during the last %d seconds in the error log", limit_unsafe_warning_count, (int) - (now.tv_sec - - limit_unsafe_suppression_start_time.tv_sec)); + (now-limit_unsafe_suppression_start_time)); print_unsafe_warning_to_log(unsafe_type, buf, query); /* DEACTIVATION: We got LIMIT_UNSAFE_WARNING_ACTIVATION_THRESHOLD_COUNT warnings in more than LIMIT_UNSAFE_WARNING_ACTIVATION_TIMEOUT, the suppression should be deactivated. */ - if ((now.tv_sec - limit_unsafe_suppression_start_time.tv_sec) > + if ((now - limit_unsafe_suppression_start_time) > LIMIT_UNSAFE_WARNING_ACTIVATION_TIMEOUT) { reset_binlog_unsafe_suppression(); From 725d76e1e844b587eeeab23fb0caa670735e47b6 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Tue, 10 Jul 2012 21:23:00 +0400 Subject: [PATCH 146/289] MWL#182: Explain running statements: address review feedback - switch SHOW EXPLAIN to using an INFORMATION_SCHEMA table. --- mysql-test/r/show_explain.result | 7 ++- mysql-test/t/show_explain.test | 9 ++++ sql/handler.h | 1 + sql/my_apc.cc | 28 +++++++++++ sql/protocol.h | 14 ------ sql/sql_class.cc | 82 ++------------------------------ sql/sql_class.h | 23 ++++----- sql/sql_lex.h | 3 +- sql/sql_parse.cc | 55 ++++++++++----------- sql/sql_show.cc | 66 ++++++++++++------------- sql/sql_yacc.yy | 5 +- 11 files changed, 118 insertions(+), 175 deletions(-) diff --git a/mysql-test/r/show_explain.result b/mysql-test/r/show_explain.result index c5891f96e82..60341a5d68b 100644 --- a/mysql-test/r/show_explain.result +++ b/mysql-test/r/show_explain.result @@ -798,7 +798,7 @@ pk data 20 data1 set autocommit=0; select * from t1 where pk between 10 and 20 for update; -show explain for 3; +# do: send_eval show explain for 3; kill query $thr_default; ERROR 70100: Query execution was interrupted rollback; @@ -816,3 +816,8 @@ pk data 20 data1 drop table t1; drop table t0; +# +# Check that the I_S table is invisible +# +select table_name from information_schema.tables where table_schema='information_schema' and table_name like '%explain%'; +table_name diff --git a/mysql-test/t/show_explain.test b/mysql-test/t/show_explain.test index c8d52ad7bb5..2e47a2e9615 100644 --- a/mysql-test/t/show_explain.test +++ b/mysql-test/t/show_explain.test @@ -818,7 +818,10 @@ connection default; let $wait_condition= select State='Sending data' from information_schema.processlist where id=$thr2; let $thr_default=`select connection_id()`; --source include/wait_condition.inc +--echo # do: send_eval show explain for $thr2; +--disable_query_log send_eval show explain for $thr2; +--enable_query_log # kill the SHOW EXPLAIN command connection con3; @@ -844,3 +847,9 @@ disconnect con2; ## thread and served together. drop table t0; + +--echo # +--echo # Check that the I_S table is invisible +--echo # +select table_name from information_schema.tables where table_schema='information_schema' and table_name like '%explain%'; + diff --git a/sql/handler.h b/sql/handler.h index ee1731af563..148801f8fe7 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -600,6 +600,7 @@ enum enum_schema_tables SCH_COLUMN_PRIVILEGES, SCH_ENGINES, SCH_EVENTS, + SCH_EXPLAIN, SCH_FILES, SCH_GLOBAL_STATUS, SCH_GLOBAL_VARIABLES, diff --git a/sql/my_apc.cc b/sql/my_apc.cc index c7ba25ad3ba..8551c0187a4 100644 --- a/sql/my_apc.cc +++ b/sql/my_apc.cc @@ -24,7 +24,35 @@ /* For standalone testing of APC system, see unittest/sql/my_apc-t.cc */ +#ifndef MY_APC_STANDALONE +ST_FIELD_INFO show_explain_fields_info[]= +{ + /* field_name, length, type, value, field_flags, old_name*/ + {"id", 3, MYSQL_TYPE_LONGLONG, 0 /*value*/, MY_I_S_MAYBE_NULL, "id", + SKIP_OPEN_TABLE}, + {"select_type", 19, MYSQL_TYPE_STRING, 0 /*value*/, 0, "select_type", + SKIP_OPEN_TABLE}, + {"table", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0 /*value*/, MY_I_S_MAYBE_NULL, + "table", SKIP_OPEN_TABLE}, + {"type", 10, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL, "type", SKIP_OPEN_TABLE}, + {"possible_keys", NAME_CHAR_LEN*MAX_KEY, MYSQL_TYPE_STRING, 0/*value*/, + MY_I_S_MAYBE_NULL, "possible_keys", SKIP_OPEN_TABLE}, + {"key", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0/*value*/, MY_I_S_MAYBE_NULL, + "key", SKIP_OPEN_TABLE}, + {"key_len", NAME_CHAR_LEN*MAX_KEY, MYSQL_TYPE_STRING, 0/*value*/, + MY_I_S_MAYBE_NULL, "key_len", SKIP_OPEN_TABLE}, + {"ref", NAME_CHAR_LEN*MAX_REF_PARTS, MYSQL_TYPE_STRING, 0/*value*/, + MY_I_S_MAYBE_NULL, "ref", SKIP_OPEN_TABLE}, + {"rows", 10, MYSQL_TYPE_LONGLONG, 0/*value*/, MY_I_S_MAYBE_NULL, "rows", + SKIP_OPEN_TABLE}, + {"Extra", 255, MYSQL_TYPE_STRING, 0/*value*/, 0 /*flags*/, "Extra", + SKIP_OPEN_TABLE}, + {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE} +}; + + +#endif /* Initialize the target. diff --git a/sql/protocol.h b/sql/protocol.h index 3627e625c07..1c0a28560bd 100644 --- a/sql/protocol.h +++ b/sql/protocol.h @@ -78,20 +78,6 @@ public: virtual bool send_result_set_metadata(List *list, uint flags); bool send_result_set_row(List *row_items); - void get_packet(const char **start, size_t *length) - { - *start= packet->ptr(); - *length= packet->length(); - } - void set_packet(const char *start, size_t len) - { - packet->length(0); - packet->append(start, len); -#ifndef DBUG_OFF - field_pos= field_count - 1; -#endif - } - bool store(I_List *str_list); bool store(const char *from, CHARSET_INFO *cs); String *storage_packet() { return packet; } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 35cc28bcae7..d6d14c45b47 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -2309,90 +2309,16 @@ int select_send::send_data(List &items) DBUG_RETURN(0); } -////////////////////////////////////////////////////////////////////////////// - -/* - Save the data being sent in our internal buffer. -*/ int select_result_explain_buffer::send_data(List &items) { - List_iterator_fast li(items); - char buff[MAX_FIELD_WIDTH]; - String buffer(buff, sizeof(buff), &my_charset_bin); - DBUG_ENTER("select_send::send_data"); - - protocol->prepare_for_resend(); - Item *item; - while ((item=li++)) - { - if (item->send(protocol, &buffer)) - { - protocol->free(); // Free used buffer - my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); - break; - } - /* - Reset buffer to its original state, as it may have been altered in - Item::send(). - */ - buffer.set(buff, sizeof(buff), &my_charset_bin); - } - - if (thd->is_error()) - { - protocol->remove_last_row(); - DBUG_RETURN(1); - } - /* - Instead of calling protocol->write(), steal the packed and put it to our - buffer - */ - const char *packet_data; - size_t len; - protocol->get_packet(&packet_data, &len); - - String *s= new (thd->mem_root) String; - s->append(packet_data, len); - data_rows.push_back(s); - protocol->remove_last_row(); // <-- this does nothing. Do we need it? - // prepare_for_resend() will wipe out the packet - DBUG_RETURN(0); + fill_record(thd, dst_table->field, items, TRUE, FALSE); + if ((dst_table->file->ha_write_tmp_row(dst_table->record[0]))) + return 1; + return 0; } -/* Write the saved resultset to the client (via this->protocol) and free it. */ - -void select_result_explain_buffer::flush_data() -{ - List_iterator it(data_rows); - String *str; - while ((str= it++)) - { - protocol->set_packet(str->ptr(), str->length()); - protocol->write(); - delete str; - } - data_rows.empty(); -} - - -/* Free the accumulated resultset */ - -void select_result_explain_buffer::discard_data() -{ - List_iterator it(data_rows); - String *str; - while ((str= it++)) - { - delete str; - } - data_rows.empty(); -} - -////////////////////////////////////////////////////////////////////////////// - - bool select_send::send_eof() { /* diff --git a/sql/sql_class.h b/sql/sql_class.h index d1183225a83..d34e285ead9 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -3319,32 +3319,27 @@ public: /* - A select result sink that collects the sent data and then can flush it to - network when requested. - - This class is targeted at collecting EXPLAIN output: - - Unoptimized data storage (can't handle big datasets) + This is a select_result_sink which simply writes all data into a (temporary) + table. Creation/deletion of the table is outside of the scope of the class + + It is aimed at capturing SHOW EXPLAIN output, so: - Unlike select_result class, we don't assume that the sent data is an output of a SELECT_LEX_UNIT (and so we dont apply "LIMIT x,y" from the unit) + - We don't try to convert the target table to MyISAM */ class select_result_explain_buffer : public select_result_sink { public: + select_result_explain_buffer(THD *thd_arg, TABLE *table_arg) : + thd(thd_arg), dst_table(table_arg) {}; + THD *thd; - Protocol *protocol; - select_result_explain_buffer(){}; + TABLE *dst_table; /* table to write into */ /* The following is called in the child thread: */ int send_data(List &items); - - /* this will be called in the parent thread: */ - void flush_data(); - - void discard_data(); - - List data_rows; }; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 1967a15ef5a..d8316dcc03c 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -2357,7 +2357,8 @@ struct LEX: public Query_tables_list char *backup_dir; /* For RESTORE/BACKUP */ char* to_log; /* For PURGE MASTER LOGS TO */ char* x509_subject,*x509_issuer,*ssl_cipher; - String *wild; + String *wild; /* Wildcard in SHOW {something} LIKE 'wild'*/ + Item *show_explain_for_thread; /* id in SHOW EXPLAIN FOR id */ sql_exchange *exchange; select_result *result; Item *default_value, *on_update_value; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 9ebb1b3f36e..3a6bb4909f2 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2144,6 +2144,32 @@ mysql_execute_command(THD *thd) execute_show_status(thd, all_tables); break; } + case SQLCOM_SHOW_EXPLAIN: + { + if (!thd->security_ctx->priv_user[0] && + check_global_access(thd,PROCESS_ACL)) + break; + + /* + The select should use only one table, it's the SHOW EXPLAIN pseudo-table + */ + if (lex->sroutines.records || lex->query_tables->next_global) + { + my_error(ER_NOT_SUPPORTED_YET, MYF(0), "Usage of subqueries or stored " + "function calls as part of this statement"); + break; + } + + Item **it= &(lex->show_explain_for_thread); + if ((!(*it)->fixed && (*it)->fix_fields(lex->thd, it)) || + (*it)->check_cols(1)) + { + my_message(ER_SET_CONSTANTS_ONLY, ER(ER_SET_CONSTANTS_ONLY), + MYF(0)); + goto error; + } + /* no break; fall through */ + } case SQLCOM_SHOW_DATABASES: case SQLCOM_SHOW_TABLES: case SQLCOM_SHOW_TRIGGERS: @@ -3128,35 +3154,6 @@ end_with_restore_list: thd->security_ctx->priv_user), lex->verbose); break; - case SQLCOM_SHOW_EXPLAIN: - { - const char *effective_user; - /* Same security as SHOW PROCESSLIST (TODO check this) */ - if (!thd->security_ctx->priv_user[0] && - check_global_access(thd,PROCESS_ACL)) - break; - - Item *it= (Item *)lex->value_list.head(); - - if (lex->table_or_sp_used()) - { - my_error(ER_NOT_SUPPORTED_YET, MYF(0), "Usage of subqueries or stored " - "function calls as part of this statement"); - break; - } - - if ((!it->fixed && it->fix_fields(lex->thd, &it)) || it->check_cols(1)) - { - my_message(ER_SET_CONSTANTS_ONLY, ER(ER_SET_CONSTANTS_ONLY), - MYF(0)); - goto error; - } - effective_user=(thd->security_ctx->master_access & PROCESS_ACL ? NullS : - thd->security_ctx->priv_user); - - mysqld_show_explain(thd, effective_user, (ulong)it->val_int()); - break; - } case SQLCOM_SHOW_AUTHORS: res= mysqld_show_authors(thd); break; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 2319a13de8c..dc5f32b5728 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1999,32 +1999,24 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) } +static +const char *target_not_explainable_cmd="Target is not running EXPLAINable command"; + /* - SHOW EXPLAIN FOR command handler - - @param thd Current thread's thd - @param calling_user User that invoked SHOW EXPLAIN, or NULL if the user - has SUPER or PROCESS privileges, and so is allowed - to run SHOW EXPLAIN on anybody. - @param thread_id Thread whose explain we need - - @notes - - Attempt to do "SHOW EXPLAIN FOR " will properly produce "target not - running EXPLAINable command". + Store the SHOW EXPLAIN output in the temporary table. */ -void mysqld_show_explain(THD *thd, const char *calling_user, ulong thread_id) +int fill_show_explain(THD *thd, TABLE_LIST *table, COND *cond) { + const char *calling_user; THD *tmp; - Protocol *protocol= thd->protocol; - List field_list; - DBUG_ENTER("mysqld_show_explain"); - - thd->make_explain_field_list(field_list); - if (protocol->send_result_set_metadata(&field_list, Protocol::SEND_NUM_ROWS | - Protocol::SEND_EOF)) - DBUG_VOID_RETURN; - + my_thread_id thread_id; + DBUG_ENTER("fill_show_explain"); + + DBUG_ASSERT(cond==NULL); + thread_id= thd->lex->show_explain_for_thread->val_int(); + calling_user= (thd->security_ctx->master_access & PROCESS_ACL) ? NullS : + thd->security_ctx->priv_user; /* Find the thread we need EXPLAIN for. Thread search code was copied from kill_one_thread() @@ -2042,7 +2034,7 @@ void mysqld_show_explain(THD *thd, const char *calling_user, ulong thread_id) } } mysql_mutex_unlock(&LOCK_thread_count); - + if (tmp) { Security_context *tmp_sctx= tmp->security_ctx; @@ -2058,7 +2050,15 @@ void mysqld_show_explain(THD *thd, const char *calling_user, ulong thread_id) { my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "PROCESSLIST"); mysql_mutex_unlock(&tmp->LOCK_thd_data); - DBUG_VOID_RETURN; + DBUG_RETURN(1); + } + + if (tmp == thd) + { + mysql_mutex_unlock(&tmp->LOCK_thd_data); + my_error(ER_ERROR_WHEN_EXECUTING_COMMAND, MYF(0), "SHOW EXPLAIN", + target_not_explainable_cmd); + DBUG_RETURN(1); } bool bres; @@ -2071,9 +2071,7 @@ void mysqld_show_explain(THD *thd, const char *calling_user, ulong thread_id) Show_explain_request explain_req; select_result_explain_buffer *explain_buf; - explain_buf= new select_result_explain_buffer; - explain_buf->thd=thd; - explain_buf->protocol= thd->protocol; + explain_buf= new select_result_explain_buffer(thd, table->table); explain_req.explain_buf= explain_buf; explain_req.target_thd= tmp; @@ -2099,29 +2097,22 @@ void mysqld_show_explain(THD *thd, const char *calling_user, ulong thread_id) else { my_error(ER_ERROR_WHEN_EXECUTING_COMMAND, MYF(0), - "SHOW EXPLAIN", - "Target is not running EXPLAINable command"); + "SHOW EXPLAIN", target_not_explainable_cmd); } bres= TRUE; - explain_buf->discard_data(); } else { push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_YES, explain_req.query_str.c_ptr_safe()); } - if (!bres) - { - explain_buf->flush_data(); - my_eof(thd); - } + DBUG_RETURN(bres); } else { my_error(ER_NO_SUCH_THREAD, MYF(0), thread_id); + DBUG_RETURN(1); } - - DBUG_VOID_RETURN; } @@ -8436,6 +8427,7 @@ ST_FIELD_INFO keycache_fields_info[]= }; +extern ST_FIELD_INFO show_explain_fields_info[]; /* Description of ST_FIELD_INFO in table.h @@ -8467,6 +8459,8 @@ ST_SCHEMA_TABLE schema_tables[]= {"EVENTS", events_fields_info, create_schema_table, 0, make_old_format, 0, -1, -1, 0, 0}, #endif + {"EXPLAIN", show_explain_fields_info, create_schema_table, fill_show_explain, + make_old_format, 0, -1, -1, TRUE /*hidden*/ , 0}, {"FILES", files_fields_info, create_schema_table, hton_fill_schema_table, 0, 0, -1, -1, 0, 0}, {"GLOBAL_STATUS", variables_fields_info, create_schema_table, diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index d60fcbff35e..aed8edab027 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -11617,8 +11617,9 @@ show_param: | describe_command FOR_SYM expr { Lex->sql_command= SQLCOM_SHOW_EXPLAIN; - Lex->value_list.empty(); - Lex->value_list.push_front($3); + if (prepare_schema_table(YYTHD, Lex, 0, SCH_EXPLAIN)) + MYSQL_YYABORT; + Lex->show_explain_for_thread= $3; } ; From fc74e2e08f0332ff94cb536956f28177c4048c54 Mon Sep 17 00:00:00 2001 From: Chaithra Gopalareddy Date: Wed, 11 Jul 2012 08:19:17 +0530 Subject: [PATCH 147/289] Bug #13444084:PRIMARY KEY OR UNIQUE KEY >453 BYTES FAILS FOR COUNT DISTINCT GROUP BY PROBLEM: To calculate the final result of the count(distinct(select 1)) we call 'end_send' function instead of 'end_send_group'. 'end_send' cannot be called if we have aggregate functions that need to be evaluated. ANALYSIS: While evaluating for a possible loose_index_scan option for the query, the variable 'is_agg_distinct' is set to 'false' as the item in the distinct clause is not a field. But, we choose loose_index_scan by not taking this into consideration. So, while setting the final 'select_function' to evaluate the result, 'precomputed_group_by' is set to TRUE as in this case loose_index_scan is chosen and we do not have agg_distinct in the query (which is clearly wrong as we have one). As a result, 'end_send' function is chosen as the final select_function instead of 'end_send_group'. The difference between the two being, 'end_send_group' evaluates the aggregates while 'end_send' does not. Hence the wrong result. FIX: The variable 'is_agg_distinct' always represents if 'loose_idnex_scan' can be chosen for aggregate_distinct functions present in the select. So, we check for this variable to continue with loose_index_scan option. sql/opt_range.cc: Do not continue if is_agg_distinct is not set in case of agg_distinct functions. --- sql/opt_range.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 8a6607cf343..03f444c22b5 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -9463,9 +9463,10 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree, double read_time) have_min= TRUE; else if (min_max_item->sum_func() == Item_sum::MAX_FUNC) have_max= TRUE; - else if (min_max_item->sum_func() == Item_sum::COUNT_DISTINCT_FUNC || - min_max_item->sum_func() == Item_sum::SUM_DISTINCT_FUNC || - min_max_item->sum_func() == Item_sum::AVG_DISTINCT_FUNC) + else if (is_agg_distinct && + (min_max_item->sum_func() == Item_sum::COUNT_DISTINCT_FUNC || + min_max_item->sum_func() == Item_sum::SUM_DISTINCT_FUNC || + min_max_item->sum_func() == Item_sum::AVG_DISTINCT_FUNC)) continue; else DBUG_RETURN(NULL); From 28255d4c58945953b3d6e377165bfb38ef4060ad Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 11 Jul 2012 08:43:26 +0200 Subject: [PATCH 148/289] From f913ba7a605b965359b437db36b0baa5498ec2c0 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Wed, 11 Jul 2012 13:39:56 +0400 Subject: [PATCH 149/289] MWL#182: Explain running statements: address review feedback - Make THD::check_killed() an inline function which makes calls to non-inline functions only whern there are APC requests to be served. --- sql/my_apc.h | 9 +++++++++ sql/sql_class.cc | 15 --------------- sql/sql_class.h | 9 ++++++++- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/sql/my_apc.h b/sql/my_apc.h index 1c4cc25376b..5473600bae6 100644 --- a/sql/my_apc.h +++ b/sql/my_apc.h @@ -53,6 +53,15 @@ public: void disable(); void process_apc_requests(); + /* + A lightweight function, intended to be used in frequent checks like this: + + if (apc_target.have_requests()) apc_target.process_apc_requests() + */ + inline bool have_apc_requests() + { + return test(apc_calls); + } /* Functor class for calls you can schedule */ class Apc_call diff --git a/sql/sql_class.cc b/sql/sql_class.cc index d6d14c45b47..414b1ba3f7f 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -2166,21 +2166,6 @@ void THD::rollback_item_tree_changes() } -/* - Check if the thread has been killed, and also process "APC requests" - - @retval true The thread is killed, execution should be interrupted - @retval false Not killed, continue execution -*/ - -bool THD::check_killed() -{ - if (killed) - return TRUE; - apc_target.process_apc_requests(); - return FALSE; -} - /***************************************************************************** ** Functions to provide a interface to select results *****************************************************************************/ diff --git a/sql/sql_class.h b/sql/sql_class.h index d34e285ead9..50e445fe9c4 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -2222,7 +2222,14 @@ public: */ killed_state volatile killed; - bool check_killed(); + inline bool check_killed() + { + if (killed) + return TRUE; + if (apc_target.have_apc_requests()) + apc_target.process_apc_requests(); + return FALSE; + } /* scramble - random string sent to client on handshake */ char scramble[SCRAMBLE_LENGTH+1]; From de65de3baaa3c04711b84523a3b297a3a36c9b44 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Wed, 11 Jul 2012 14:27:59 +0400 Subject: [PATCH 150/289] Make test results stable --- mysql-test/r/show_explain.result | 2 +- mysql-test/t/show_explain.test | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/show_explain.result b/mysql-test/r/show_explain.result index 60341a5d68b..e5659bdf4ac 100644 --- a/mysql-test/r/show_explain.result +++ b/mysql-test/r/show_explain.result @@ -798,7 +798,7 @@ pk data 20 data1 set autocommit=0; select * from t1 where pk between 10 and 20 for update; -# do: send_eval show explain for 3; +# do: send_eval show explain for thr2; kill query $thr_default; ERROR 70100: Query execution was interrupted rollback; diff --git a/mysql-test/t/show_explain.test b/mysql-test/t/show_explain.test index 2e47a2e9615..6d4ddd79104 100644 --- a/mysql-test/t/show_explain.test +++ b/mysql-test/t/show_explain.test @@ -818,7 +818,7 @@ connection default; let $wait_condition= select State='Sending data' from information_schema.processlist where id=$thr2; let $thr_default=`select connection_id()`; --source include/wait_condition.inc ---echo # do: send_eval show explain for $thr2; +--echo # do: send_eval show explain for thr2; --disable_query_log send_eval show explain for $thr2; --enable_query_log From 21bc74e0c97be00d011676912e4f3226802ad1c6 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 11 Jul 2012 16:42:55 +0530 Subject: [PATCH 151/289] From a49b4c970fe582919d89109e0cc3ebe2558269cd Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Wed, 11 Jul 2012 16:33:10 +0400 Subject: [PATCH 152/289] t/show_explain_ps.test needs debug system to work. --- mysql-test/t/show_explain_ps.test | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/t/show_explain_ps.test b/mysql-test/t/show_explain_ps.test index 67634ac57e2..d891e118b24 100644 --- a/mysql-test/t/show_explain_ps.test +++ b/mysql-test/t/show_explain_ps.test @@ -1,6 +1,7 @@ # # Test how SHOW EXPLAIN is represented in performance schema # +--source include/have_debug.inc --source include/have_perfschema.inc --disable_warnings From 4c33e849f17d321b198d9e9fbcaa150358993bc4 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 11 Jul 2012 15:18:34 +0200 Subject: [PATCH 153/289] Raise version number after cloning 5.1.65 --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index 4e7a3303353..068328992e0 100644 --- a/configure.in +++ b/configure.in @@ -12,7 +12,7 @@ dnl dnl When changing the major version number please also check the switch dnl statement in mysqlbinlog::check_master_version(). You may also need dnl to update version.c in ndb. -AC_INIT([MySQL Server], [5.1.65], [], [mysql]) +AC_INIT([MySQL Server], [5.1.66], [], [mysql]) AC_CONFIG_SRCDIR([sql/mysqld.cc]) AC_CANONICAL_SYSTEM From a08631d6964141577fd345f34292de4ba90421ba Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 11 Jul 2012 16:19:05 +0200 Subject: [PATCH 154/289] lp:1023404 problems with savepoints and tokudb with 5.5 fix incorrect merge --- sql/handler.cc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sql/handler.cc b/sql/handler.cc index b7d545a75dc..ecd02e2a1be 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -504,10 +504,6 @@ int ha_initialize_handlerton(st_plugin_int *plugin) "Assigning value %d.", plugin->plugin->name, idx); hton->db_type= (enum legacy_db_type) idx; } - installed_htons[hton->db_type]= hton; - tmp= hton->savepoint_offset; - hton->savepoint_offset= savepoint_alloc_size; - savepoint_alloc_size+= tmp; /* In case a plugin is uninstalled and re-installed later, it should From 718bbcbfd0dd1aa858e4e3ba0583e85d81414df0 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Thu, 12 Jul 2012 15:32:35 +0200 Subject: [PATCH 155/289] MDEV-393. Remove --loose-pbxt=OFF/loose-skip-pbxt from bootstrapper calls to avoid "unknown parameter" warning --- debian/dist/Debian/mariadb-server-5.5.postinst | 2 +- debian/dist/Ubuntu/mariadb-server-5.5.postinst | 2 +- sql/mysql_install_db.cc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/debian/dist/Debian/mariadb-server-5.5.postinst b/debian/dist/Debian/mariadb-server-5.5.postinst index e3f2df13b4b..2e15b121db9 100644 --- a/debian/dist/Debian/mariadb-server-5.5.postinst +++ b/debian/dist/Debian/mariadb-server-5.5.postinst @@ -21,7 +21,7 @@ invoke() { fi } -MYSQL_BOOTSTRAP="/usr/sbin/mysqld --bootstrap --user=mysql --skip-grant-tables --loose-innodb=OFF --loose-pbxt=OFF --default-storage-engine=myisam" +MYSQL_BOOTSTRAP="/usr/sbin/mysqld --bootstrap --user=mysql --skip-grant-tables --loose-innodb=OFF --default-storage-engine=myisam" test_mysql_access() { mysql --no-defaults -u root -h localhost /dev/null 2>&1 diff --git a/debian/dist/Ubuntu/mariadb-server-5.5.postinst b/debian/dist/Ubuntu/mariadb-server-5.5.postinst index a0c351194bb..1c7aa37f69f 100644 --- a/debian/dist/Ubuntu/mariadb-server-5.5.postinst +++ b/debian/dist/Ubuntu/mariadb-server-5.5.postinst @@ -21,7 +21,7 @@ invoke() { fi } -MYSQL_BOOTSTRAP="/usr/sbin/mysqld --bootstrap --user=mysql --skip-grant-tables --loose-innodb=OFF --loose-pbxt=OFF --default-storage-engine=myisam" +MYSQL_BOOTSTRAP="/usr/sbin/mysqld --bootstrap --user=mysql --skip-grant-tables --loose-innodb=OFF --default-storage-engine=myisam" test_mysql_access() { mysql --no-defaults -u root -h localhost /dev/null 2>&1 diff --git a/sql/mysql_install_db.cc b/sql/mysql_install_db.cc index bde81d915b2..6e2c6ec07f3 100644 --- a/sql/mysql_install_db.cc +++ b/sql/mysql_install_db.cc @@ -247,7 +247,7 @@ static char *init_bootstrap_command_line(char *cmdline, size_t size) "\"\"%s\" --no-defaults --bootstrap" " \"--language=%s\\share\\english\"" " --basedir=. --datadir=. --default-storage-engine=myisam" - " --max_allowed_packet=9M --loose-skip-innodb --loose-skip-pbxt" + " --max_allowed_packet=9M --loose-skip-innodb" " --net-buffer-length=16k\"", mysqld_path, basedir); return cmdline; } From 9f6a1c5842fc8f71463d48e4da4ec692aadeacc1 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 13 Jul 2012 22:17:32 +0300 Subject: [PATCH 156/289] fixed MySQL bug#53775: Now partition engine adds underlying tables to the QC and ask underlying tables engine permittion to cache the query and return result of the query. Incorrect QC cleanup in case of table registration failure fixe. Unified interface for myisammrg & partitioned engnes for QC. --- mysql-test/include/query_cache_partitions.inc | 126 +++++++++++++++ mysql-test/r/partition_cache.result | 18 +-- mysql-test/r/partition_cache_innodb.result | 151 +++++++++++++++++ mysql-test/r/partition_cache_myisam.result | 153 ++++++++++++++++++ mysql-test/t/partition_cache_innodb.test | 14 ++ mysql-test/t/partition_cache_myisam.test | 14 ++ sql/ha_partition.cc | 116 +++++++++++++ sql/ha_partition.h | 26 ++- sql/handler.h | 42 +++++ sql/sql_cache.cc | 94 +++++------ sql/sql_cache.h | 31 ++-- storage/myisammrg/ha_myisammrg.cc | 41 +++++ storage/myisammrg/ha_myisammrg.h | 6 + 13 files changed, 739 insertions(+), 93 deletions(-) create mode 100644 mysql-test/include/query_cache_partitions.inc create mode 100644 mysql-test/r/partition_cache_innodb.result create mode 100644 mysql-test/r/partition_cache_myisam.result create mode 100644 mysql-test/t/partition_cache_innodb.test create mode 100644 mysql-test/t/partition_cache_myisam.test diff --git a/mysql-test/include/query_cache_partitions.inc b/mysql-test/include/query_cache_partitions.inc new file mode 100644 index 00000000000..e5bb7406c10 --- /dev/null +++ b/mysql-test/include/query_cache_partitions.inc @@ -0,0 +1,126 @@ +# include/query_cache_partitions.inc +# +# The variables +# $engine_type -- storage engine to be tested +# have to be set before sourcing this script. + +eval SET SESSION STORAGE_ENGINE = $engine_type; + +# Initialise +--disable_warnings +drop table if exists t1; +--enable_warnings + +set @save_query_cache_size = @@global.query_cache_size; + +--echo # Test that partitions works with query cache + +flush query cache; + +SET GLOBAL query_cache_size=1024*1024*512; + CREATE TABLE `t1` ( + `id` int(11) NOT NULL , + `created_at` datetime NOT NULL, + `cool` tinyint default 0 + ); + + ALTER TABLE t1 PARTITION BY RANGE (TO_DAYS(created_at)) ( + PARTITION month_2010_4 VALUES LESS THAN (734258), + PARTITION month_2010_5 VALUES LESS THAN (734289), + PARTITION month_max VALUES LESS THAN MAXVALUE + ); + +show create table t1; + +INSERT INTO t1 VALUES (1, now(), 0); + +flush status; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_hits"; + + +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; + +show status like "Qcache_queries_in_cache"; +show status like "Qcache_hits"; + +drop table t1; + +--echo # Test that sub-partitions works with query cache + +flush query cache; + +SET GLOBAL query_cache_size=1024*1024*512; + CREATE TABLE `t1` ( + `id` int(11) NOT NULL , + `created_at` datetime NOT NULL, + `cool` tinyint default 0 + ) + PARTITION BY RANGE (TO_DAYS(created_at)) + subpartition by hash(cool) subpartitions 3 ( + PARTITION month_2010_4 VALUES LESS THAN (734258), + PARTITION month_2010_5 VALUES LESS THAN (734289), + PARTITION month_max VALUES LESS THAN MAXVALUE + ); + +show create table t1; + +INSERT INTO t1 VALUES (1, now(), 0); + +flush status; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_hits"; + +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; + +show status like "Qcache_queries_in_cache"; +show status like "Qcache_hits"; + +drop table t1; + +--echo # +--echo # MySQL bug#53775 Query on partitioned table returns cached result +--echo # from previous transaction +--echo # + +flush query cache; +flush status; + +SET GLOBAL query_cache_size=1024*1024*512; + CREATE TABLE `t1` ( + `id` int(11) NOT NULL , + `created_at` datetime NOT NULL, + `cool` tinyint default 0 + ); + + ALTER TABLE t1 PARTITION BY RANGE (TO_DAYS(created_at)) ( + PARTITION month_2010_4 VALUES LESS THAN (734258), + PARTITION month_2010_5 VALUES LESS THAN (734289), + PARTITION month_max VALUES LESS THAN MAXVALUE + ); + +INSERT INTO t1 VALUES (1, now(), 0); + +show status like "Qcache_queries_in_cache"; +show status like "Qcache_hits"; + +BEGIN; +UPDATE `t1` SET `cool` = 1 WHERE `id` = 1; +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +ROLLBACK; +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +BEGIN; +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +ROLLBACK; +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; + +show status like "Qcache_queries_in_cache"; +show status like "Qcache_hits"; + +drop table t1; + +set @@global.query_cache_size = @save_query_cache_size; diff --git a/mysql-test/r/partition_cache.result b/mysql-test/r/partition_cache.result index ac2da9bb78a..cd579d00952 100644 --- a/mysql-test/r/partition_cache.result +++ b/mysql-test/r/partition_cache.result @@ -27,7 +27,7 @@ a 3 show status like "Qcache_queries_in_cache"; Variable_name Value -Qcache_queries_in_cache 0 +Qcache_queries_in_cache 1 drop table t1; commit; create table t1 (a int not null) PARTITION BY KEY (a) PARTITIONS 3; @@ -50,7 +50,7 @@ a 2 show status like "Qcache_queries_in_cache"; Variable_name Value -Qcache_queries_in_cache 0 +Qcache_queries_in_cache 3 show status like "Qcache_hits"; Variable_name Value Qcache_hits 0 @@ -69,7 +69,7 @@ a 2 show status like "Qcache_queries_in_cache"; Variable_name Value -Qcache_queries_in_cache 0 +Qcache_queries_in_cache 6 show status like "Qcache_hits"; Variable_name Value Qcache_hits 0 @@ -93,14 +93,14 @@ a 2 show status like "Qcache_queries_in_cache"; Variable_name Value -Qcache_queries_in_cache 0 +Qcache_queries_in_cache 2 show status like "Qcache_hits"; Variable_name Value -Qcache_hits 0 +Qcache_hits 1 commit; show status like "Qcache_queries_in_cache"; Variable_name Value -Qcache_queries_in_cache 0 +Qcache_queries_in_cache 2 drop table t3,t2,t1; CREATE TABLE t1 (id int(11) NOT NULL auto_increment, PRIMARY KEY (id)) PARTITION BY HASH (id) PARTITIONS 3; select count(*) from t1; @@ -164,7 +164,7 @@ count(*) 2 show status like "Qcache_queries_in_cache"; Variable_name Value -Qcache_queries_in_cache 0 +Qcache_queries_in_cache 1 connection connection1 SELECT sql_cache count(*) FROM t2 WHERE s2 = 'w'; count(*) @@ -197,9 +197,9 @@ count(*) 2 show status like "Qcache_queries_in_cache"; Variable_name Value -Qcache_queries_in_cache 0 +Qcache_queries_in_cache 1 show status like "Qcache_hits"; Variable_name Value -Qcache_hits 0 +Qcache_hits 1 set @@global.query_cache_size = @save_query_cache_size; drop table t2; diff --git a/mysql-test/r/partition_cache_innodb.result b/mysql-test/r/partition_cache_innodb.result new file mode 100644 index 00000000000..0d0abbb096c --- /dev/null +++ b/mysql-test/r/partition_cache_innodb.result @@ -0,0 +1,151 @@ +SET SESSION STORAGE_ENGINE = innodb; +drop table if exists t1; +set @save_query_cache_size = @@global.query_cache_size; +# Test that partitions works with query cache +flush query cache; +SET GLOBAL query_cache_size=1024*1024*512; +CREATE TABLE `t1` ( +`id` int(11) NOT NULL , +`created_at` datetime NOT NULL, +`cool` tinyint default 0 +); +ALTER TABLE t1 PARTITION BY RANGE (TO_DAYS(created_at)) ( +PARTITION month_2010_4 VALUES LESS THAN (734258), +PARTITION month_2010_5 VALUES LESS THAN (734289), +PARTITION month_max VALUES LESS THAN MAXVALUE +); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `id` int(11) NOT NULL, + `created_at` datetime NOT NULL, + `cool` tinyint(4) DEFAULT '0' +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +/*!50100 PARTITION BY RANGE (TO_DAYS(created_at)) +(PARTITION month_2010_4 VALUES LESS THAN (734258) ENGINE = InnoDB, + PARTITION month_2010_5 VALUES LESS THAN (734289) ENGINE = InnoDB, + PARTITION month_max VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */ +INSERT INTO t1 VALUES (1, now(), 0); +flush status; +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 0 +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +cool +0 +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +cool +0 +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +cool +0 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 2 +drop table t1; +# Test that sub-partitions works with query cache +flush query cache; +SET GLOBAL query_cache_size=1024*1024*512; +CREATE TABLE `t1` ( +`id` int(11) NOT NULL , +`created_at` datetime NOT NULL, +`cool` tinyint default 0 +) +PARTITION BY RANGE (TO_DAYS(created_at)) +subpartition by hash(cool) subpartitions 3 ( +PARTITION month_2010_4 VALUES LESS THAN (734258), +PARTITION month_2010_5 VALUES LESS THAN (734289), +PARTITION month_max VALUES LESS THAN MAXVALUE +); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `id` int(11) NOT NULL, + `created_at` datetime NOT NULL, + `cool` tinyint(4) DEFAULT '0' +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +/*!50100 PARTITION BY RANGE (TO_DAYS(created_at)) +SUBPARTITION BY HASH (cool) +SUBPARTITIONS 3 +(PARTITION month_2010_4 VALUES LESS THAN (734258) ENGINE = InnoDB, + PARTITION month_2010_5 VALUES LESS THAN (734289) ENGINE = InnoDB, + PARTITION month_max VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */ +INSERT INTO t1 VALUES (1, now(), 0); +flush status; +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 0 +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +cool +0 +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +cool +0 +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +cool +0 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 2 +drop table t1; +# +# MySQL bug#53775 Query on partitioned table returns cached result +# from previous transaction +# +flush query cache; +flush status; +SET GLOBAL query_cache_size=1024*1024*512; +CREATE TABLE `t1` ( +`id` int(11) NOT NULL , +`created_at` datetime NOT NULL, +`cool` tinyint default 0 +); +ALTER TABLE t1 PARTITION BY RANGE (TO_DAYS(created_at)) ( +PARTITION month_2010_4 VALUES LESS THAN (734258), +PARTITION month_2010_5 VALUES LESS THAN (734289), +PARTITION month_max VALUES LESS THAN MAXVALUE +); +INSERT INTO t1 VALUES (1, now(), 0); +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 0 +BEGIN; +UPDATE `t1` SET `cool` = 1 WHERE `id` = 1; +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +cool +1 +ROLLBACK; +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +cool +0 +BEGIN; +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +cool +0 +ROLLBACK; +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +cool +0 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 2 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 1 +drop table t1; +set @@global.query_cache_size = @save_query_cache_size; diff --git a/mysql-test/r/partition_cache_myisam.result b/mysql-test/r/partition_cache_myisam.result new file mode 100644 index 00000000000..0b617c03590 --- /dev/null +++ b/mysql-test/r/partition_cache_myisam.result @@ -0,0 +1,153 @@ +SET SESSION STORAGE_ENGINE = myisam; +drop table if exists t1; +set @save_query_cache_size = @@global.query_cache_size; +# Test that partitions works with query cache +flush query cache; +SET GLOBAL query_cache_size=1024*1024*512; +CREATE TABLE `t1` ( +`id` int(11) NOT NULL , +`created_at` datetime NOT NULL, +`cool` tinyint default 0 +); +ALTER TABLE t1 PARTITION BY RANGE (TO_DAYS(created_at)) ( +PARTITION month_2010_4 VALUES LESS THAN (734258), +PARTITION month_2010_5 VALUES LESS THAN (734289), +PARTITION month_max VALUES LESS THAN MAXVALUE +); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `id` int(11) NOT NULL, + `created_at` datetime NOT NULL, + `cool` tinyint(4) DEFAULT '0' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +/*!50100 PARTITION BY RANGE (TO_DAYS(created_at)) +(PARTITION month_2010_4 VALUES LESS THAN (734258) ENGINE = MyISAM, + PARTITION month_2010_5 VALUES LESS THAN (734289) ENGINE = MyISAM, + PARTITION month_max VALUES LESS THAN MAXVALUE ENGINE = MyISAM) */ +INSERT INTO t1 VALUES (1, now(), 0); +flush status; +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 0 +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +cool +0 +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +cool +0 +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +cool +0 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 2 +drop table t1; +# Test that sub-partitions works with query cache +flush query cache; +SET GLOBAL query_cache_size=1024*1024*512; +CREATE TABLE `t1` ( +`id` int(11) NOT NULL , +`created_at` datetime NOT NULL, +`cool` tinyint default 0 +) +PARTITION BY RANGE (TO_DAYS(created_at)) +subpartition by hash(cool) subpartitions 3 ( +PARTITION month_2010_4 VALUES LESS THAN (734258), +PARTITION month_2010_5 VALUES LESS THAN (734289), +PARTITION month_max VALUES LESS THAN MAXVALUE +); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `id` int(11) NOT NULL, + `created_at` datetime NOT NULL, + `cool` tinyint(4) DEFAULT '0' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +/*!50100 PARTITION BY RANGE (TO_DAYS(created_at)) +SUBPARTITION BY HASH (cool) +SUBPARTITIONS 3 +(PARTITION month_2010_4 VALUES LESS THAN (734258) ENGINE = MyISAM, + PARTITION month_2010_5 VALUES LESS THAN (734289) ENGINE = MyISAM, + PARTITION month_max VALUES LESS THAN MAXVALUE ENGINE = MyISAM) */ +INSERT INTO t1 VALUES (1, now(), 0); +flush status; +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 0 +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +cool +0 +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +cool +0 +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +cool +0 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 2 +drop table t1; +# +# MySQL bug#53775 Query on partitioned table returns cached result +# from previous transaction +# +flush query cache; +flush status; +SET GLOBAL query_cache_size=1024*1024*512; +CREATE TABLE `t1` ( +`id` int(11) NOT NULL , +`created_at` datetime NOT NULL, +`cool` tinyint default 0 +); +ALTER TABLE t1 PARTITION BY RANGE (TO_DAYS(created_at)) ( +PARTITION month_2010_4 VALUES LESS THAN (734258), +PARTITION month_2010_5 VALUES LESS THAN (734289), +PARTITION month_max VALUES LESS THAN MAXVALUE +); +INSERT INTO t1 VALUES (1, now(), 0); +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 0 +BEGIN; +UPDATE `t1` SET `cool` = 1 WHERE `id` = 1; +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +cool +1 +ROLLBACK; +Warnings: +Warning 1196 Some non-transactional changed tables couldn't be rolled back +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +cool +1 +BEGIN; +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +cool +1 +ROLLBACK; +SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1; +cool +1 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 2 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 2 +drop table t1; +set @@global.query_cache_size = @save_query_cache_size; diff --git a/mysql-test/t/partition_cache_innodb.test b/mysql-test/t/partition_cache_innodb.test new file mode 100644 index 00000000000..dbcfea3088c --- /dev/null +++ b/mysql-test/t/partition_cache_innodb.test @@ -0,0 +1,14 @@ +# t/cache_innodb.test +# +# Last update: +# 2006-07-26 ML test refactored (MySQL 5.1) +# main code t/innodb_cache.test --> include/query_cache.inc +# new wrapper t/cache_innodb.test +# + +--source include/have_query_cache.inc +--source include/have_innodb.inc +--source include/have_partition.inc +let $engine_type= innodb; + +--source include/query_cache_partitions.inc diff --git a/mysql-test/t/partition_cache_myisam.test b/mysql-test/t/partition_cache_myisam.test new file mode 100644 index 00000000000..5347225f6da --- /dev/null +++ b/mysql-test/t/partition_cache_myisam.test @@ -0,0 +1,14 @@ +# t/cache_innodb.test +# +# Last update: +# 2006-07-26 ML test refactored (MySQL 5.1) +# main code t/innodb_cache.test --> include/query_cache.inc +# new wrapper t/cache_innodb.test +# + +--source include/have_query_cache.inc + +--source include/have_partition.inc +let $engine_type= myisam; + +--source include/query_cache_partitions.inc diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index b4181fc6d7f..7c2ffeb1b44 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -2076,6 +2076,122 @@ partition_element *ha_partition::find_partition_element(uint part_id) return NULL; } +uint ha_partition::count_query_cache_dependant_tables(uint8 *tables_type) +{ + DBUG_ENTER("ha_partition::count_query_cache_dependant_tables"); + /* Here we rely on the fact that all tables are of the same type */ + (*tables_type)|= m_file[0]->table_cache_type(); + DBUG_PRINT("info", ("cnt: %u", (uint)m_tot_parts)); + DBUG_RETURN(m_tot_parts); +} + +my_bool ha_partition::reg_query_cache_dependant_table(THD *thd, + char *key, uint key_len, + uint8 type, + Query_cache *cache, + Query_cache_block_table **block_table, + handler *file, + uint *n) +{ + DBUG_ENTER("ha_partition::reg_query_cache_dependant_table"); + qc_engine_callback engine_callback; + ulonglong engine_data; + /* ask undelying engine */ + if (!file->register_query_cache_table(thd, key, + key_len, + &engine_callback, + &engine_data)) + { + DBUG_PRINT("qcache", ("Handler does not allow caching for %s.%s", + key, + key + table_share->db.length + 1)); + /* + As this can change from call to call, don't reset set + thd->lex->safe_to_cache_query + */ + thd->query_cache_is_applicable= 0; // Query can't be cached + DBUG_RETURN(TRUE); + } + (++(*block_table))->n= ++(*n); + if (!cache->insert_table(key_len, + key, (*block_table), + table_share->db.length, + type, + engine_callback, engine_data, + FALSE)) + DBUG_RETURN(TRUE); + DBUG_RETURN(FALSE); +} + + +my_bool ha_partition::register_query_cache_dependant_tables(THD *thd, + Query_cache *cache, + Query_cache_block_table **block_table, + uint *n) +{ + char *name; + uint prefix_length= table_share->table_cache_key.length + 3; + uint num_parts= m_part_info->num_parts; + uint num_subparts= m_part_info->num_subparts; + uint i= 0; + List_iterator part_it(m_part_info->partitions); + char key[FN_REFLEN]; + + DBUG_ENTER("ha_partition::register_query_cache_dependant_tables"); + + /* prepare static part of the key */ + memmove(key, table_share->table_cache_key.str, + table_share->table_cache_key.length); + + name= key + table_share->table_cache_key.length - 1; + name[0]= name[2]= '#'; + name[1]= 'P'; + name+= 3; + + do + { + partition_element *part_elem= part_it++; + uint part_len= strmov(name, part_elem->partition_name) - name; + if (m_is_sub_partitioned) + { + List_iterator subpart_it(part_elem->subpartitions); + partition_element *sub_elem; + char *sname= name + part_len; + uint j= 0, part; + sname[0]= sname[3]= '#'; + sname[1]= 'S'; + sname[2]= 'P'; + sname += 4; + do + { + sub_elem= subpart_it++; + part= i * num_subparts + j; + uint spart_len= strmov(sname, sub_elem->partition_name) - name + 1; + if (reg_query_cache_dependant_table(thd, key, + prefix_length + part_len + 4 + + spart_len, + m_file[part]->table_cache_type(), + cache, + block_table, m_file[part], + n)) + DBUG_RETURN(TRUE); + } while (++j < num_subparts); + } + else + { + if (reg_query_cache_dependant_table(thd, key, + prefix_length + part_len + 1, + m_file[i]->table_cache_type(), + cache, + block_table, m_file[i], + n)) + DBUG_RETURN(TRUE); + } + } while (++i < num_parts); + DBUG_PRINT("info", ("cnt: %u", (uint)m_tot_parts)); + DBUG_RETURN(FALSE); +} + /* Set up table share object before calling create on underlying handler diff --git a/sql/ha_partition.h b/sql/ha_partition.h index aa9179f9f69..0f922394ec5 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -544,22 +544,20 @@ public: virtual int extra(enum ha_extra_function operation); virtual int extra_opt(enum ha_extra_function operation, ulong cachesize); virtual int reset(void); - /* - Do not allow caching of partitioned tables, since we cannot return - a callback or engine_data that would work for a generic engine. - */ - virtual my_bool register_query_cache_table(THD *thd, char *table_key, - uint key_length, - qc_engine_callback - *engine_callback, - ulonglong *engine_data) - { - *engine_callback= NULL; - *engine_data= 0; - return FALSE; - } + virtual uint count_query_cache_dependant_tables(uint8 *tables_type); + virtual my_bool + register_query_cache_dependant_tables(THD *thd, + Query_cache *cache, + Query_cache_block_table **block, + uint *n); private: + my_bool reg_query_cache_dependant_table(THD *thd, + char *key, uint key_len, uint8 type, + Query_cache *cache, + Query_cache_block_table + **block_table, + handler *file, uint *n); static const uint NO_CURRENT_PART_ID; int loop_extra(enum ha_extra_function operation); void late_extra_cache(uint partition_id); diff --git a/sql/handler.h b/sql/handler.h index ee1731af563..217c8103cd7 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1689,6 +1689,8 @@ public: virtual ~handler_add_index() {} }; +class Query_cache; +class Query_cache_block_table; /** The handler class is the interface for dynamically loadable storage engines. Do not add ifdefs and take care when adding or @@ -2522,6 +2524,46 @@ public: return TRUE; } + /* + Count tables invisible from all tables list on which current one built + (like myisammrg and partitioned tables) + + tables_type mask for the tables should be added herdde + + returns number of such tables + */ + + virtual uint count_query_cache_dependant_tables(uint8 *tables_type + __attribute__((unused))) + { + return 0; + } + + /* + register tables invisible from all tables list on which current one built + (like myisammrg and partitioned tables). + + @note they should be counted by method above + + cache Query cache pointer + block Query cache block to write the table + n Number of the table + + @retval FALSE - OK + @retval TRUE - Error + */ + + virtual my_bool + register_query_cache_dependant_tables(THD *thd + __attribute__((unused)), + Query_cache *cache + __attribute__((unused)), + Query_cache_block_table **block + __attribute__((unused)), + uint *n __attribute__((unused))) + { + return FALSE; + } /* Check if the primary key (if there is one) is a clustered and a diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 96814562757..7edd28446a2 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -1533,7 +1533,7 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d", unlock(); goto end; } - if (!register_all_tables(query_block, tables_used, local_tables)) + if (!register_all_tables(thd, query_block, tables_used, local_tables)) { refused++; DBUG_PRINT("warning", ("tables list including failed")); @@ -3203,6 +3203,7 @@ Query_cache::invalidate_query_block_list(THD *thd, SYNOPSIS Query_cache::register_tables_from_list + thd thread handle tables_used given table list counter number current position in table of tables of block block_table pointer to current position in tables table of block @@ -3213,24 +3214,24 @@ Query_cache::invalidate_query_block_list(THD *thd, */ TABLE_COUNTER_TYPE -Query_cache::register_tables_from_list(TABLE_LIST *tables_used, +Query_cache::register_tables_from_list(THD *thd, TABLE_LIST *tables_used, TABLE_COUNTER_TYPE counter, - Query_cache_block_table *block_table) + Query_cache_block_table **block_table) { TABLE_COUNTER_TYPE n; DBUG_ENTER("Query_cache::register_tables_from_list"); for (n= counter; tables_used; - tables_used= tables_used->next_global, n++, block_table++) + tables_used= tables_used->next_global, n++, (*block_table)++) { if (tables_used->is_anonymous_derived_table()) { DBUG_PRINT("qcache", ("derived table skipped")); n--; - block_table--; + (*block_table)--; continue; } - block_table->n= n; + (*block_table)->n= n; if (tables_used->view) { char key[MAX_DBKEY_LENGTH]; @@ -3243,9 +3244,9 @@ Query_cache::register_tables_from_list(TABLE_LIST *tables_used, /* There are not callback function for for VIEWs */ - if (!insert_table(key_length, key, block_table, + if (!insert_table(key_length, key, (*block_table), tables_used->view_db.length + 1, - HA_CACHE_TBL_NONTRANSACT, 0, 0)) + HA_CACHE_TBL_NONTRANSACT, 0, 0, TRUE)) DBUG_RETURN(0); /* We do not need to register view tables here because they are already @@ -3264,42 +3265,17 @@ Query_cache::register_tables_from_list(TABLE_LIST *tables_used, if (!insert_table(tables_used->table->s->table_cache_key.length, tables_used->table->s->table_cache_key.str, - block_table, + (*block_table), tables_used->db_length, tables_used->table->file->table_cache_type(), tables_used->callback_func, - tables_used->engine_data)) + tables_used->engine_data, + TRUE)) DBUG_RETURN(0); -#ifdef WITH_MYISAMMRG_STORAGE_ENGINE - /* - XXX FIXME: Some generic mechanism is required here instead of this - MYISAMMRG-specific implementation. - */ - if (tables_used->table->s->db_type()->db_type == DB_TYPE_MRG_MYISAM) - { - ha_myisammrg *handler = (ha_myisammrg *) tables_used->table->file; - MYRG_INFO *file = handler->myrg_info(); - for (MYRG_TABLE *table = file->open_tables; - table != file->end_table ; - table++) - { - char key[MAX_DBKEY_LENGTH]; - uint32 db_length; - uint key_length= filename_2_table_key(key, table->table->filename, - &db_length); - (++block_table)->n= ++n; - /* - There are not callback function for for MyISAM, and engine data - */ - if (!insert_table(key_length, key, block_table, - db_length, - tables_used->table->file->table_cache_type(), - 0, 0)) - DBUG_RETURN(0); - } - } -#endif + if (tables_used->table->file-> + register_query_cache_dependant_tables(thd, this, block_table, &n)) + DBUG_RETURN(0); } } DBUG_RETURN(n - counter); @@ -3310,12 +3286,14 @@ Query_cache::register_tables_from_list(TABLE_LIST *tables_used, SYNOPSIS register_all_tables() + thd Thread handle block Store tables in this block tables_used List if used tables tables_arg Not used ? */ -my_bool Query_cache::register_all_tables(Query_cache_block *block, +my_bool Query_cache::register_all_tables(THD *thd, + Query_cache_block *block, TABLE_LIST *tables_used, TABLE_COUNTER_TYPE tables_arg) { @@ -3326,7 +3304,7 @@ my_bool Query_cache::register_all_tables(Query_cache_block *block, Query_cache_block_table *block_table = block->table(0); - n= register_tables_from_list(tables_used, 0, block_table); + n= register_tables_from_list(thd, tables_used, 0, &block_table); if (n==0) { @@ -3335,6 +3313,8 @@ my_bool Query_cache::register_all_tables(Query_cache_block *block, tmp != block_table; tmp++) unlink_table(tmp); + if (block_table->parent) + unlink_table(block_table); } return test(n); } @@ -3353,7 +3333,8 @@ Query_cache::insert_table(uint key_len, char *key, Query_cache_block_table *node, uint32 db_length, uint8 cache_type, qc_engine_callback callback, - ulonglong engine_data) + ulonglong engine_data, + my_bool hash) { DBUG_ENTER("Query_cache::insert_table"); DBUG_PRINT("qcache", ("insert table node 0x%lx, len %d", @@ -3361,8 +3342,10 @@ Query_cache::insert_table(uint key_len, char *key, THD *thd= current_thd; - Query_cache_block *table_block= - (Query_cache_block *) my_hash_search(&tables, (uchar*) key, key_len); + Query_cache_block *table_block= + (hash ? + (Query_cache_block *) my_hash_search(&tables, (uchar*) key, key_len) : + NULL); if (table_block && table_block->table()->engine_data() != engine_data) @@ -3412,7 +3395,8 @@ Query_cache::insert_table(uint key_len, char *key, */ list_root->next= list_root->prev= list_root; - if (my_hash_insert(&tables, (const uchar *) table_block)) + if (hash && + my_hash_insert(&tables, (const uchar *) table_block)) { DBUG_PRINT("qcache", ("Can't insert table to hash")); // write_block_data return locked block @@ -3425,6 +3409,7 @@ Query_cache::insert_table(uint key_len, char *key, header->type(cache_type); header->callback(callback); header->engine_data(engine_data); + header->set_hashed(hash); /* We insert this table without the assumption that it isn't refrenenced by @@ -3478,7 +3463,9 @@ void Query_cache::unlink_table(Query_cache_block_table *node) Query_cache_block *table_block= neighbour->block(); double_linked_list_exclude(table_block, &tables_blocks); - my_hash_delete(&tables,(uchar *) table_block); + Query_cache_table *header= table_block->table(); + if (header->is_hashed()) + my_hash_delete(&tables,(uchar *) table_block); free_memory_block(table_block); } DBUG_VOID_RETURN; @@ -3951,6 +3938,9 @@ Query_cache::process_and_count_tables(THD *thd, TABLE_LIST *tables_used, table_alias_charset used here because it depends of lower_case_table_names variable */ + table_count+= tables_used->table->file-> + count_query_cache_dependant_tables(tables_type); + if (tables_used->table->s->tmp_table != NO_TMP_TABLE || (*tables_type & HA_CACHE_TBL_NOCACHE) || (tables_used->db_length == 5 && @@ -3963,18 +3953,6 @@ Query_cache::process_and_count_tables(THD *thd, TABLE_LIST *tables_used, "other non-cacheable table(s)")); DBUG_RETURN(0); } -#ifdef WITH_MYISAMMRG_STORAGE_ENGINE - /* - XXX FIXME: Some generic mechanism is required here instead of this - MYISAMMRG-specific implementation. - */ - if (tables_used->table->s->db_type()->db_type == DB_TYPE_MRG_MYISAM) - { - ha_myisammrg *handler = (ha_myisammrg *)tables_used->table->file; - MYRG_INFO *file = handler->myrg_info(); - table_count+= (file->end_table - file->open_tables); - } -#endif } } DBUG_RETURN(table_count); diff --git a/sql/sql_cache.h b/sql/sql_cache.h index 87291e80a85..7444d444cf9 100644 --- a/sql/sql_cache.h +++ b/sql/sql_cache.h @@ -200,6 +200,10 @@ struct Query_cache_table The number of queries depending of this table. */ int32 m_cached_query_count; + /** + If table included in the table hash to be found by other queries + */ + my_bool hashed; inline char *db() { return (char *) data(); } inline char *table() { return tbl; } @@ -212,6 +216,8 @@ struct Query_cache_table inline void callback(qc_engine_callback fn){ callback_func= fn; } inline ulonglong engine_data() { return engine_data_buff; } inline void engine_data(ulonglong data_arg){ engine_data_buff= data_arg; } + inline my_bool is_hashed() { return hashed; } + inline void set_hashed(my_bool hash) { hashed= hash; } inline uchar* data() { return (uchar*)(((uchar*)this)+ @@ -343,10 +349,6 @@ protected: static void double_linked_list_join(Query_cache_block *head_tail, Query_cache_block *tail_head); - /* Table key generation */ - static uint filename_2_table_key (char *key, const char *filename, - uint32 *db_langth); - /* The following functions require that structure_guard_mutex is locked */ void flush_cache(); my_bool free_old_query(); @@ -363,17 +365,12 @@ protected: Query_cache_block_table *list_root); TABLE_COUNTER_TYPE - register_tables_from_list(TABLE_LIST *tables_used, + register_tables_from_list(THD *thd, TABLE_LIST *tables_used, TABLE_COUNTER_TYPE counter, - Query_cache_block_table *block_table); - my_bool register_all_tables(Query_cache_block *block, + Query_cache_block_table **block_table); + my_bool register_all_tables(THD *thd, Query_cache_block *block, TABLE_LIST *tables_used, TABLE_COUNTER_TYPE tables); - my_bool insert_table(uint key_len, char *key, - Query_cache_block_table *node, - uint32 db_length, uint8 cache_type, - qc_engine_callback callback, - ulonglong engine_data); void unlink_table(Query_cache_block_table *node); Query_cache_block *get_free_block (ulong len, my_bool not_less, ulong min); @@ -491,6 +488,12 @@ protected: const char *packet, ulong length, unsigned pkt_nr); + my_bool insert_table(uint key_len, char *key, + Query_cache_block_table *node, + uint32 db_length, uint8 cache_type, + qc_engine_callback callback, + ulonglong engine_data, + my_bool hash); void end_of_result(THD *thd); void abort(Query_cache_tls *query_cache_tls); @@ -513,6 +516,10 @@ protected: const char *name); my_bool in_blocks(Query_cache_block * point); + /* Table key generation */ + static uint filename_2_table_key (char *key, const char *filename, + uint32 *db_langth); + enum Cache_try_lock_mode {WAIT, TIMEOUT, TRY}; bool try_lock(THD *thd, Cache_try_lock_mode mode= WAIT); void lock(THD *thd); diff --git a/storage/myisammrg/ha_myisammrg.cc b/storage/myisammrg/ha_myisammrg.cc index e6bece5b7ff..47a3abb78d2 100644 --- a/storage/myisammrg/ha_myisammrg.cc +++ b/storage/myisammrg/ha_myisammrg.cc @@ -1652,6 +1652,47 @@ ha_rows ha_myisammrg::records() return myrg_records(file); } +uint ha_myisammrg::count_query_cache_dependant_tables(uint8 *tables_type) +{ + MYRG_INFO *file = myrg_info(); + /* + Here should be following statement + (*tables_type)|= HA_CACHE_TBL_NONTRANSACT; + but it has no effect because HA_CACHE_TBL_NONTRANSACT is 0 + */ + return (file->end_table - file->open_tables); +} + + +my_bool ha_myisammrg::register_query_cache_dependant_tables(THD *thd + __attribute__((unused)), + Query_cache *cache, + Query_cache_block_table **block_table, + uint *n) +{ + MYRG_INFO *file =myrg_info(); + DBUG_ENTER("ha_myisammrg::register_query_cache_dependant_tables"); + + for (MYRG_TABLE *table =file->open_tables; + table != file->end_table ; + table++) + { + char key[MAX_DBKEY_LENGTH]; + uint32 db_length; + uint key_length= cache->filename_2_table_key(key, table->table->filename, + &db_length); + (++(*block_table))->n= ++(*n); + /* + There are not callback function for for MyISAM, and engine data + */ + if (!cache->insert_table(key_length, key, (*block_table), + db_length, + table_cache_type(), + 0, 0, TRUE)) + DBUG_RETURN(TRUE); + } + DBUG_RETURN(FALSE); +} extern int myrg_panic(enum ha_panic_function flag); int myisammrg_panic(handlerton *hton, ha_panic_function flag) diff --git a/storage/myisammrg/ha_myisammrg.h b/storage/myisammrg/ha_myisammrg.h index e0dc6e07542..f5ba2ffef38 100644 --- a/storage/myisammrg/ha_myisammrg.h +++ b/storage/myisammrg/ha_myisammrg.h @@ -149,4 +149,10 @@ public: bool check_if_incompatible_data(HA_CREATE_INFO *info, uint table_changes); int check(THD* thd, HA_CHECK_OPT* check_opt); ha_rows records(); + virtual uint count_query_cache_dependant_tables(uint8 *tables_type); + virtual my_bool + register_query_cache_dependant_tables(THD *thd, + Query_cache *cache, + Query_cache_block_table **block, + uint *n); }; From 49da8e7e212ec2ba739b9a7e2f512f1f71c62f1e Mon Sep 17 00:00:00 2001 From: Elena Stepanova Date: Mon, 16 Jul 2012 06:12:11 +0400 Subject: [PATCH 157/289] Export sys_errno and errno to variables --- client/mysqltest.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/client/mysqltest.cc b/client/mysqltest.cc index 961114c9a40..57b7ff5fa0a 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -621,6 +621,8 @@ void free_all_replace(){ free_replace_column(); } +void var_set_int(const char* name, int value); + class LogFile { FILE* m_file; @@ -1275,6 +1277,8 @@ void handle_command_error(struct st_command *command, uint error, { DBUG_ENTER("handle_command_error"); DBUG_PRINT("enter", ("error: %d", error)); + var_set_int("$sys_errno",sys_errno); + var_set_int("$errno",error); if (error != 0) { int i; From 403cac0fe710bbd65a65f5b409cff6194ce6bace Mon Sep 17 00:00:00 2001 From: Elena Stepanova Date: Mon, 16 Jul 2012 06:14:53 +0400 Subject: [PATCH 158/289] Allow multiple error codes inside a variable in --error command --- client/mysqltest.cc | 33 +++++++++++++++++++++++++++------ mysql-test/r/mysqltest.result | 1 + mysql-test/t/mysqltest.test | 5 +++++ 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/client/mysqltest.cc b/client/mysqltest.cc index 57b7ff5fa0a..f204f359656 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -5205,15 +5205,32 @@ const char *get_errname_from_code (uint error_code) void do_get_errcodes(struct st_command *command) { struct st_match_err *to= saved_expected_errors.err; - char *p= command->first_argument; - uint count= 0; - char *next; - DBUG_ENTER("do_get_errcodes"); - if (!*p) + if (!*command->first_argument) die("Missing argument(s) to 'error'"); + /* TODO: Potentially, there is a possibility of variables + being expanded twice, e.g. + + let $errcodes = 1,\$a; + let $a = 1051; + error $errcodes; + DROP TABLE unknown_table; + ... + Got one of the listed errors + + But since it requires manual escaping, it does not seem + particularly dangerous or error-prone. + */ + DYNAMIC_STRING ds; + init_dynamic_string(&ds, 0, command->query_len + 64, 256); + do_eval(&ds, command->first_argument, command->end, !is_windows); + char *p= ds.str; + + uint count= 0; + char *next; + do { char *end; @@ -5323,11 +5340,15 @@ void do_get_errcodes(struct st_command *command) } while (*p); - command->last_argument= p; + command->last_argument= command->first_argument; + while (*command->last_argument) + command->last_argument++; + to->type= ERR_EMPTY; /* End of data */ DBUG_PRINT("info", ("Expected errors: %d", count)); saved_expected_errors.count= count; + dynstr_free(&ds); DBUG_VOID_RETURN; } diff --git a/mysql-test/r/mysqltest.result b/mysql-test/r/mysqltest.result index 25345227d59..fdb3029059f 100644 --- a/mysql-test/r/mysqltest.result +++ b/mysql-test/r/mysqltest.result @@ -690,6 +690,7 @@ Got one of the listed errors insert into t1 values ("Abcd"); Got one of the listed errors garbage; +SELECT * FROM non_existing_table; drop table t2; create table t1 ( f1 char(10)); insert into t1 values ("Abcd"); diff --git a/mysql-test/t/mysqltest.test b/mysql-test/t/mysqltest.test index a7585bea4f8..ffbec36873e 100644 --- a/mysql-test/t/mysqltest.test +++ b/mysql-test/t/mysqltest.test @@ -2120,6 +2120,11 @@ insert into t1 values ("Abcd"); --error $errno1,ER_PARSE_ERROR garbage; +let $errno_multi = $errno1,ER_NO_SUCH_TABLE,$errno2,1062; + +--error $errno_multi +SELECT * FROM non_existing_table; + drop table t2; From 72a5542f0ef1fbc36aabc511f18855f302906501 Mon Sep 17 00:00:00 2001 From: Elena Stepanova Date: Mon, 16 Jul 2012 06:17:56 +0400 Subject: [PATCH 159/289] MDEV-11: Generic storage engine test suite --- mysql-test/suite/storage_engine/1st.result | 11 + mysql-test/suite/storage_engine/1st.test | 81 + .../suite/storage_engine/alter_table.inc | 91 + .../suite/storage_engine/alter_table.result | 147 ++ .../suite/storage_engine/alter_table.test | 148 ++ .../storage_engine/alter_table_online.result | 35 + .../storage_engine/alter_table_online.test | 160 ++ .../storage_engine/alter_tablespace.result | 19 + .../storage_engine/alter_tablespace.test | 91 + .../suite/storage_engine/analyze_table.inc | 43 + .../suite/storage_engine/analyze_table.result | 29 + .../suite/storage_engine/analyze_table.test | 14 + .../storage_engine/autoinc_secondary.result | 40 + .../storage_engine/autoinc_secondary.test | 73 + .../suite/storage_engine/autoinc_vars.result | 55 + .../suite/storage_engine/autoinc_vars.test | 68 + .../suite/storage_engine/autoincrement.result | 133 ++ .../suite/storage_engine/autoincrement.test | 114 + .../suite/storage_engine/cache_index.result | 69 + .../suite/storage_engine/cache_index.test | 142 ++ .../suite/storage_engine/check_errors.inc | 80 + .../suite/storage_engine/check_table.inc | 62 + .../suite/storage_engine/check_table.result | 68 + .../suite/storage_engine/check_table.test | 14 + .../suite/storage_engine/checksum_table.inc | 31 + .../storage_engine/checksum_table.result | 20 + .../suite/storage_engine/checksum_table.test | 11 + .../storage_engine/checksum_table_live.inc | 30 + .../storage_engine/checksum_table_live.result | 20 + .../storage_engine/checksum_table_live.test | 13 + .../suite/storage_engine/cleanup_engine.inc | 11 + .../suite/storage_engine/col_not_null.inc | 92 + mysql-test/suite/storage_engine/col_null.inc | 65 + .../storage_engine/col_opt_default.result | 20 + .../suite/storage_engine/col_opt_default.test | 49 + .../storage_engine/col_opt_not_null.result | 2062 +++++++++++++++++ .../storage_engine/col_opt_not_null.test | 260 +++ .../suite/storage_engine/col_opt_null.result | 1991 ++++++++++++++++ .../suite/storage_engine/col_opt_null.test | 208 ++ .../storage_engine/col_opt_unsigned.result | 697 ++++++ .../storage_engine/col_opt_unsigned.test | 95 + .../storage_engine/col_opt_zerofill.result | 679 ++++++ .../storage_engine/col_opt_zerofill.test | 88 + .../suite/storage_engine/create_table.inc | 174 ++ .../suite/storage_engine/create_table.result | 45 + .../suite/storage_engine/create_table.test | 107 + .../suite/storage_engine/define_engine.inc | 45 + mysql-test/suite/storage_engine/delete.result | 77 + mysql-test/suite/storage_engine/delete.test | 68 + .../suite/storage_engine/delete_ignore.result | 59 + .../suite/storage_engine/delete_ignore.test | 44 + .../storage_engine/delete_low_prio.result | 59 + .../suite/storage_engine/delete_low_prio.test | 162 ++ .../suite/storage_engine/delete_quick.result | 25 + .../suite/storage_engine/delete_quick.test | 55 + .../storage_engine/delete_with_keys.result | 38 + .../storage_engine/delete_with_keys.test | 74 + .../suite/storage_engine/describe.result | 18 + mysql-test/suite/storage_engine/describe.test | 50 + mysql-test/suite/storage_engine/disabled.def | 0 .../suite/storage_engine/foreign_keys.result | 71 + .../suite/storage_engine/foreign_keys.test | 148 ++ .../storage_engine/fulltext_search.result | 132 ++ .../suite/storage_engine/fulltext_search.test | 187 ++ .../suite/storage_engine/handler.result | 77 + mysql-test/suite/storage_engine/handler.test | 81 + .../storage_engine/have_default_index.inc | 20 + .../suite/storage_engine/have_engine.inc | 127 + mysql-test/suite/storage_engine/index.inc | 194 ++ mysql-test/suite/storage_engine/index.result | 67 + mysql-test/suite/storage_engine/index.test | 23 + .../index_enable_disable.result | 45 + .../storage_engine/index_enable_disable.test | 88 + .../index_key_block_size.result | 43 + .../storage_engine/index_key_block_size.test | 125 + .../suite/storage_engine/index_primary.result | 53 + .../suite/storage_engine/index_primary.test | 136 ++ .../storage_engine/index_type_btree.result | 67 + .../storage_engine/index_type_btree.test | 12 + .../storage_engine/index_type_hash.result | 67 + .../suite/storage_engine/index_type_hash.test | 12 + mysql-test/suite/storage_engine/insert.result | 149 ++ mysql-test/suite/storage_engine/insert.test | 78 + .../storage_engine/insert_delayed.result | 25 + .../suite/storage_engine/insert_delayed.test | 62 + .../storage_engine/insert_high_prio.result | 64 + .../storage_engine/insert_high_prio.test | 143 ++ .../storage_engine/insert_low_prio.result | 39 + .../suite/storage_engine/insert_low_prio.test | 95 + .../storage_engine/insert_with_keys.result | 148 ++ .../storage_engine/insert_with_keys.test | 143 ++ .../suite/storage_engine/loaddata.result | 68 + mysql-test/suite/storage_engine/loaddata.test | 88 + mysql-test/suite/storage_engine/lock.result | 111 + mysql-test/suite/storage_engine/lock.test | 244 ++ .../storage_engine/lock_concurrent.result | 12 + .../suite/storage_engine/lock_concurrent.test | 52 + .../suite/storage_engine/mask_engine.inc | 14 + mysql-test/suite/storage_engine/misc.result | 79 + mysql-test/suite/storage_engine/misc.test | 47 + mysql-test/suite/storage_engine/my.cnf | 7 + mysql-test/suite/storage_engine/obfuscate.inc | 4 + .../suite/storage_engine/optimize_table.inc | 42 + .../storage_engine/optimize_table.result | 29 + .../suite/storage_engine/optimize_table.test | 14 + .../storage_engine/parts/alter_table.result | 42 + .../storage_engine/parts/alter_table.test | 107 + .../storage_engine/parts/analyze_table.result | 47 + .../storage_engine/parts/analyze_table.test | 61 + .../storage_engine/parts/check_table.result | 104 + .../storage_engine/parts/check_table.test | 82 + .../parts/checksum_table.result | 40 + .../storage_engine/parts/checksum_table.test | 13 + .../storage_engine/parts/create_table.result | 91 + .../storage_engine/parts/create_table.test | 179 ++ mysql-test/suite/storage_engine/parts/my.cnf | 9 + .../parts/optimize_table.result | 54 + .../storage_engine/parts/optimize_table.test | 69 + .../storage_engine/parts/repair_table.result | 236 ++ .../storage_engine/parts/repair_table.test | 78 + .../parts/truncate_table.result | 68 + .../storage_engine/parts/truncate_table.test | 111 + .../suite/storage_engine/repair_table.inc | 155 ++ .../suite/storage_engine/repair_table.result | 106 + .../suite/storage_engine/repair_table.test | 14 + .../suite/storage_engine/replace.result | 47 + mysql-test/suite/storage_engine/replace.test | 67 + mysql-test/suite/storage_engine/se-innodb.out | 1 + mysql-test/suite/storage_engine/select.result | 390 ++++ mysql-test/suite/storage_engine/select.test | 210 ++ .../storage_engine/select_high_prio.result | 45 + .../storage_engine/select_high_prio.test | 139 ++ .../suite/storage_engine/show_engine.result | 11 + .../suite/storage_engine/show_engine.test | 31 + .../storage_engine/show_table_status.result | 62 + .../storage_engine/show_table_status.test | 30 + .../storage_engine/strict_check_errors.inc | 23 + .../suite/storage_engine/tbl_opt_ai.result | 14 + .../suite/storage_engine/tbl_opt_ai.test | 35 + .../tbl_opt_avg_row_length.result | 16 + .../tbl_opt_avg_row_length.test | 35 + .../storage_engine/tbl_opt_checksum.result | 16 + .../storage_engine/tbl_opt_checksum.test | 30 + .../storage_engine/tbl_opt_connection.result | 24 + .../storage_engine/tbl_opt_connection.test | 52 + .../tbl_opt_data_index_dir.result | 16 + .../tbl_opt_data_index_dir.test | 51 + .../tbl_opt_delay_key_write.result | 16 + .../tbl_opt_delay_key_write.test | 35 + .../tbl_opt_insert_method.result | 16 + .../storage_engine/tbl_opt_insert_method.test | 35 + .../tbl_opt_key_block_size.result | 16 + .../tbl_opt_key_block_size.test | 35 + .../storage_engine/tbl_opt_max_rows.result | 16 + .../storage_engine/tbl_opt_max_rows.test | 35 + .../storage_engine/tbl_opt_min_rows.result | 16 + .../storage_engine/tbl_opt_min_rows.test | 35 + .../storage_engine/tbl_opt_pack_keys.result | 16 + .../storage_engine/tbl_opt_pack_keys.test | 35 + .../storage_engine/tbl_opt_password.result | 16 + .../storage_engine/tbl_opt_password.test | 40 + .../storage_engine/tbl_opt_row_format.result | 16 + .../storage_engine/tbl_opt_row_format.test | 35 + .../suite/storage_engine/tbl_opt_union.result | 14 + .../suite/storage_engine/tbl_opt_union.test | 41 + .../storage_engine/tbl_standard_opts.result | 40 + .../storage_engine/tbl_standard_opts.test | 60 + .../suite/storage_engine/tbl_temporary.result | 11 + .../suite/storage_engine/tbl_temporary.test | 32 + .../storage_engine/truncate_table.result | 41 + .../suite/storage_engine/truncate_table.test | 81 + .../trx/cons_snapshot_repeatable_read.result | 18 + .../trx/cons_snapshot_repeatable_read.test | 9 + .../trx/cons_snapshot_serializable.result | 18 + .../trx/cons_snapshot_serializable.test | 9 + .../trx/consistent_snapshot.inc | 50 + .../suite/storage_engine/trx/delete.result | 72 + .../suite/storage_engine/trx/delete.test | 51 + .../suite/storage_engine/trx/insert.result | 55 + .../suite/storage_engine/trx/insert.test | 44 + .../trx/level_read_committed.result | 91 + .../trx/level_read_committed.test | 10 + .../trx/level_read_uncommitted.result | 116 + .../trx/level_read_uncommitted.test | 9 + .../trx/level_repeatable_read.result | 69 + .../trx/level_repeatable_read.test | 8 + .../trx/level_serializable.result | 56 + .../trx/level_serializable.test | 8 + mysql-test/suite/storage_engine/trx/my.cnf | 7 + .../trx/select_for_update.result | 35 + .../storage_engine/trx/select_for_update.test | 87 + .../trx/select_lock_in_share_mode.result | 37 + .../trx/select_lock_in_share_mode.test | 82 + .../storage_engine/trx/support_savepoints.inc | 10 + .../trx/support_transactions.inc | 10 + .../suite/storage_engine/trx/support_xa.inc | 12 + .../trx/transaction_isolation.inc | 99 + .../suite/storage_engine/trx/update.result | 48 + .../suite/storage_engine/trx/update.test | 50 + mysql-test/suite/storage_engine/trx/xa.result | 96 + mysql-test/suite/storage_engine/trx/xa.test | 118 + .../storage_engine/trx/xa_recovery.result | 29 + .../suite/storage_engine/trx/xa_recovery.test | 71 + .../suite/storage_engine/type_binary.inc | 52 + .../suite/storage_engine/type_binary.result | 62 + .../suite/storage_engine/type_binary.test | 10 + .../storage_engine/type_binary_indexes.result | 126 + .../storage_engine/type_binary_indexes.test | 149 ++ mysql-test/suite/storage_engine/type_bit.inc | 76 + .../suite/storage_engine/type_bit.result | 47 + mysql-test/suite/storage_engine/type_bit.test | 10 + .../storage_engine/type_bit_indexes.result | 132 ++ .../storage_engine/type_bit_indexes.test | 175 ++ mysql-test/suite/storage_engine/type_blob.inc | 65 + .../suite/storage_engine/type_blob.result | 54 + .../suite/storage_engine/type_blob.test | 10 + .../storage_engine/type_blob_indexes.result | 152 ++ .../storage_engine/type_blob_indexes.test | 188 ++ mysql-test/suite/storage_engine/type_bool.inc | 81 + .../suite/storage_engine/type_bool.result | 70 + .../suite/storage_engine/type_bool.test | 10 + mysql-test/suite/storage_engine/type_char.inc | 59 + .../suite/storage_engine/type_char.result | 56 + .../suite/storage_engine/type_char.test | 10 + .../storage_engine/type_char_indexes.result | 144 ++ .../storage_engine/type_char_indexes.test | 186 ++ .../suite/storage_engine/type_date_time.inc | 55 + .../storage_engine/type_date_time.result | 48 + .../suite/storage_engine/type_date_time.test | 11 + .../type_date_time_indexes.result | 278 +++ .../type_date_time_indexes.test | 366 +++ mysql-test/suite/storage_engine/type_enum.inc | 69 + .../suite/storage_engine/type_enum.result | 46 + .../suite/storage_engine/type_enum.test | 10 + .../storage_engine/type_enum_indexes.result | 108 + .../storage_engine/type_enum_indexes.test | 146 ++ .../suite/storage_engine/type_fixed.inc | 89 + .../suite/storage_engine/type_fixed.result | 116 + .../suite/storage_engine/type_fixed.test | 10 + .../storage_engine/type_fixed_indexes.result | 148 ++ .../storage_engine/type_fixed_indexes.test | 167 ++ .../suite/storage_engine/type_float.inc | 111 + .../suite/storage_engine/type_float.result | 286 +++ .../suite/storage_engine/type_float.test | 10 + .../storage_engine/type_float_indexes.result | 146 ++ .../storage_engine/type_float_indexes.test | 203 ++ mysql-test/suite/storage_engine/type_int.inc | 84 + .../suite/storage_engine/type_int.result | 209 ++ mysql-test/suite/storage_engine/type_int.test | 10 + .../storage_engine/type_int_indexes.result | 133 ++ .../storage_engine/type_int_indexes.test | 146 ++ mysql-test/suite/storage_engine/type_set.inc | 69 + .../suite/storage_engine/type_set.result | 48 + mysql-test/suite/storage_engine/type_set.test | 10 + .../storage_engine/type_set_indexes.result | 137 ++ .../storage_engine/type_set_indexes.test | 167 ++ .../suite/storage_engine/type_spatial.inc | 738 ++++++ .../suite/storage_engine/type_spatial.result | 700 ++++++ .../suite/storage_engine/type_spatial.test | 10 + .../type_spatial_indexes.result | 1400 +++++++++++ .../storage_engine/type_spatial_indexes.test | 15 + mysql-test/suite/storage_engine/type_text.inc | 65 + .../suite/storage_engine/type_text.result | 54 + .../suite/storage_engine/type_text.test | 10 + .../storage_engine/type_text_indexes.result | 137 ++ .../storage_engine/type_text_indexes.test | 175 ++ .../suite/storage_engine/type_varbinary.inc | 101 + .../storage_engine/type_varbinary.result | 92 + .../suite/storage_engine/type_varbinary.test | 10 + .../suite/storage_engine/type_varchar.inc | 100 + .../suite/storage_engine/type_varchar.result | 127 + .../suite/storage_engine/type_varchar.test | 10 + .../storage_engine/unexpected_result.inc | 50 + mysql-test/suite/storage_engine/update.result | 50 + mysql-test/suite/storage_engine/update.test | 43 + .../suite/storage_engine/update_ignore.result | 54 + .../suite/storage_engine/update_ignore.test | 43 + .../storage_engine/update_low_prio.result | 66 + .../suite/storage_engine/update_low_prio.test | 167 ++ .../suite/storage_engine/update_multi.result | 65 + .../suite/storage_engine/update_multi.test | 44 + .../storage_engine/update_with_keys.result | 90 + .../storage_engine/update_with_keys.test | 152 ++ mysql-test/suite/storage_engine/vcol.result | 69 + mysql-test/suite/storage_engine/vcol.test | 72 + .../storage_engine/alter_tablespace.opt | 2 + .../storage_engine/autoinc_secondary.rdiff | 30 + .../storage_engine/cache_index.rdiff | 71 + .../storage_engine/checksum_table_live.rdiff | 13 + .../storage_engine/define_engine.inc | 45 + .../mysql-test/storage_engine/disabled.def | 9 + .../storage_engine/fulltext_search.rdiff | 150 ++ .../storage_engine/index_enable_disable.rdiff | 33 + .../storage_engine/index_type_hash.rdiff | 60 + .../storage_engine/insert_delayed.rdiff | 26 + .../storage_engine/lock_concurrent.rdiff | 22 + .../storage_engine/optimize_table.rdiff | 37 + .../storage_engine/parts/checksum_table.rdiff | 22 + .../storage_engine/parts/create_table.rdiff | 20 + .../storage_engine/parts/optimize_table.rdiff | 58 + .../storage_engine/parts/repair_table.rdiff | 228 ++ .../mysql-test/storage_engine/parts/suite.opt | 4 + .../storage_engine/repair_table.rdiff | 129 ++ .../mysql-test/storage_engine/suite.opt | 4 + .../tbl_opt_data_index_dir.rdiff | 18 + .../tbl_opt_insert_method.rdiff | 11 + .../storage_engine/tbl_opt_key_block_size.opt | 3 + .../storage_engine/tbl_opt_row_format.opt | 3 + .../storage_engine/tbl_opt_row_format.rdiff | 10 + .../storage_engine/tbl_opt_union.rdiff | 16 + .../storage_engine/trx/disabled.def | 2 + .../mysql-test/storage_engine/trx/suite.opt | 5 + .../storage_engine/type_char_indexes.rdiff | 20 + .../storage_engine/type_float_indexes.rdiff | 11 + .../storage_engine/type_spatial_indexes.rdiff | 712 ++++++ .../mysql-test/storage_engine/vcol.rdiff | 82 + .../storage_engine/alter_tablespace.rdiff | 32 + .../storage_engine/check_table.rdiff | 20 + .../storage_engine/define_engine.inc | 45 + .../storage_engine/foreign_keys.rdiff | 145 ++ .../storage_engine/index_type_hash.rdiff | 60 + .../storage_engine/show_engine.rdiff | 10 + .../tbl_opt_insert_method.rdiff | 11 + .../storage_engine/tbl_opt_union.rdiff | 16 + .../trx/cons_snapshot_repeatable_read.rdiff | 9 + .../trx/cons_snapshot_serializable.rdiff | 9 + .../storage_engine/trx/delete.rdiff | 50 + .../storage_engine/trx/insert.rdiff | 65 + .../trx/level_read_committed.rdiff | 44 + .../trx/level_read_uncommitted.rdiff | 7 + .../trx/level_repeatable_read.rdiff | 53 + .../trx/level_serializable.rdiff | 69 + .../trx/select_for_update.rdiff | 50 + .../trx/select_lock_in_share_mode.rdiff | 37 + .../storage_engine/trx/update.rdiff | 58 + .../mysql-test/storage_engine/trx/xa.rdiff | 89 + .../storage_engine/trx/xa_recovery.rdiff | 33 + .../mysql-test/storage_engine/alter_table.inc | 116 + .../storage_engine/alter_table.rdiff | 68 + .../storage_engine/alter_tablespace.rdiff | 27 + .../storage_engine/analyze_table.rdiff | 22 + .../storage_engine/autoincrement.rdiff | 34 + .../storage_engine/cache_index.rdiff | 46 + .../storage_engine/char_indexes.rdiff | 0 .../storage_engine/checksum_table_live.rdiff | 6 + .../storage_engine/cleanup_engine.inc | 16 + .../storage_engine/create_table.inc | 208 ++ .../storage_engine/create_table.rdiff | 37 + .../storage_engine/define_engine.inc | 49 + .../mysql-test/storage_engine/disabled.def | 2 + .../storage_engine/foreign_keys.rdiff | 138 ++ .../storage_engine/fulltext_search.rdiff | 142 ++ .../mysql-test/storage_engine/handler.rdiff | 79 + .../mysql-test/storage_engine/index.rdiff | 6 + .../storage_engine/index_enable_disable.rdiff | 17 + .../storage_engine/index_type_btree.rdiff | 6 + .../storage_engine/index_type_hash.rdiff | 34 + .../storage_engine/insert_delayed.rdiff | 14 + .../mysql-test/storage_engine/lock.rdiff | 62 + .../storage_engine/optimize_table.rdiff | 24 + .../storage_engine/parts/alter_table.rdiff | 63 + .../storage_engine/parts/analyze_table.rdiff | 83 + .../storage_engine/parts/check_table.rdiff | 172 ++ .../storage_engine/parts/checksum_table.rdiff | 81 + .../storage_engine/parts/create_table.rdiff | 156 ++ .../storage_engine/parts/optimize_table.rdiff | 91 + .../storage_engine/parts/repair_table.rdiff | 295 +++ .../storage_engine/parts/truncate_table.rdiff | 100 + .../storage_engine/repair_table.rdiff | 103 + .../storage_engine/show_engine.rdiff | 2 + .../storage_engine/tbl_opt_ai.rdiff | 8 + .../tbl_opt_avg_row_length.rdiff | 8 + .../storage_engine/tbl_opt_checksum.rdiff | 8 + .../storage_engine/tbl_opt_connection.rdiff | 8 + .../tbl_opt_data_index_dir.rdiff | 8 + .../tbl_opt_delay_key_write.rdiff | 8 + .../tbl_opt_insert_method.rdiff | 8 + .../tbl_opt_key_block_size.rdiff | 8 + .../storage_engine/tbl_opt_max_rows.rdiff | 8 + .../storage_engine/tbl_opt_min_rows.rdiff | 8 + .../storage_engine/tbl_opt_pack_keys.rdiff | 8 + .../storage_engine/tbl_opt_password.rdiff | 8 + .../storage_engine/tbl_opt_row_format.rdiff | 8 + .../storage_engine/tbl_opt_union.rdiff | 8 + .../storage_engine/tbl_standard_opts.rdiff | 8 + .../storage_engine/tbl_temporary.rdiff | 4 + .../storage_engine/truncate_table.rdiff | 35 + .../trx/cons_snapshot_repeatable_read.rdiff | 9 + .../trx/cons_snapshot_serializable.rdiff | 9 + .../storage_engine/trx/delete.rdiff | 34 + .../storage_engine/trx/insert.rdiff | 32 + .../trx/level_read_committed.rdiff | 44 + .../trx/level_read_uncommitted.rdiff | 7 + .../trx/level_repeatable_read.rdiff | 53 + .../trx/level_serializable.rdiff | 69 + .../trx/select_for_update.rdiff | 40 + .../trx/select_lock_in_share_mode.rdiff | 26 + .../storage_engine/trx/update.rdiff | 41 + .../mysql-test/storage_engine/trx/xa.rdiff | 34 + .../storage_engine/trx/xa_recovery.rdiff | 22 + .../storage_engine/type_char_indexes.rdiff | 8 + .../storage_engine/type_float_indexes.rdiff | 4 + .../storage_engine/type_spatial.rdiff | 706 ++++++ .../storage_engine/type_spatial_indexes.rdiff | 1412 +++++++++++ .../mysql-test/storage_engine/vcol.rdiff | 79 + 405 files changed, 36013 insertions(+) create mode 100644 mysql-test/suite/storage_engine/1st.result create mode 100644 mysql-test/suite/storage_engine/1st.test create mode 100644 mysql-test/suite/storage_engine/alter_table.inc create mode 100644 mysql-test/suite/storage_engine/alter_table.result create mode 100644 mysql-test/suite/storage_engine/alter_table.test create mode 100644 mysql-test/suite/storage_engine/alter_table_online.result create mode 100644 mysql-test/suite/storage_engine/alter_table_online.test create mode 100644 mysql-test/suite/storage_engine/alter_tablespace.result create mode 100644 mysql-test/suite/storage_engine/alter_tablespace.test create mode 100644 mysql-test/suite/storage_engine/analyze_table.inc create mode 100644 mysql-test/suite/storage_engine/analyze_table.result create mode 100644 mysql-test/suite/storage_engine/analyze_table.test create mode 100644 mysql-test/suite/storage_engine/autoinc_secondary.result create mode 100644 mysql-test/suite/storage_engine/autoinc_secondary.test create mode 100644 mysql-test/suite/storage_engine/autoinc_vars.result create mode 100644 mysql-test/suite/storage_engine/autoinc_vars.test create mode 100644 mysql-test/suite/storage_engine/autoincrement.result create mode 100644 mysql-test/suite/storage_engine/autoincrement.test create mode 100644 mysql-test/suite/storage_engine/cache_index.result create mode 100644 mysql-test/suite/storage_engine/cache_index.test create mode 100644 mysql-test/suite/storage_engine/check_errors.inc create mode 100644 mysql-test/suite/storage_engine/check_table.inc create mode 100644 mysql-test/suite/storage_engine/check_table.result create mode 100644 mysql-test/suite/storage_engine/check_table.test create mode 100644 mysql-test/suite/storage_engine/checksum_table.inc create mode 100644 mysql-test/suite/storage_engine/checksum_table.result create mode 100644 mysql-test/suite/storage_engine/checksum_table.test create mode 100644 mysql-test/suite/storage_engine/checksum_table_live.inc create mode 100644 mysql-test/suite/storage_engine/checksum_table_live.result create mode 100644 mysql-test/suite/storage_engine/checksum_table_live.test create mode 100644 mysql-test/suite/storage_engine/cleanup_engine.inc create mode 100644 mysql-test/suite/storage_engine/col_not_null.inc create mode 100644 mysql-test/suite/storage_engine/col_null.inc create mode 100644 mysql-test/suite/storage_engine/col_opt_default.result create mode 100644 mysql-test/suite/storage_engine/col_opt_default.test create mode 100644 mysql-test/suite/storage_engine/col_opt_not_null.result create mode 100644 mysql-test/suite/storage_engine/col_opt_not_null.test create mode 100644 mysql-test/suite/storage_engine/col_opt_null.result create mode 100644 mysql-test/suite/storage_engine/col_opt_null.test create mode 100644 mysql-test/suite/storage_engine/col_opt_unsigned.result create mode 100644 mysql-test/suite/storage_engine/col_opt_unsigned.test create mode 100644 mysql-test/suite/storage_engine/col_opt_zerofill.result create mode 100644 mysql-test/suite/storage_engine/col_opt_zerofill.test create mode 100644 mysql-test/suite/storage_engine/create_table.inc create mode 100644 mysql-test/suite/storage_engine/create_table.result create mode 100644 mysql-test/suite/storage_engine/create_table.test create mode 100644 mysql-test/suite/storage_engine/define_engine.inc create mode 100644 mysql-test/suite/storage_engine/delete.result create mode 100644 mysql-test/suite/storage_engine/delete.test create mode 100644 mysql-test/suite/storage_engine/delete_ignore.result create mode 100644 mysql-test/suite/storage_engine/delete_ignore.test create mode 100644 mysql-test/suite/storage_engine/delete_low_prio.result create mode 100644 mysql-test/suite/storage_engine/delete_low_prio.test create mode 100644 mysql-test/suite/storage_engine/delete_quick.result create mode 100644 mysql-test/suite/storage_engine/delete_quick.test create mode 100644 mysql-test/suite/storage_engine/delete_with_keys.result create mode 100644 mysql-test/suite/storage_engine/delete_with_keys.test create mode 100644 mysql-test/suite/storage_engine/describe.result create mode 100644 mysql-test/suite/storage_engine/describe.test create mode 100644 mysql-test/suite/storage_engine/disabled.def create mode 100644 mysql-test/suite/storage_engine/foreign_keys.result create mode 100644 mysql-test/suite/storage_engine/foreign_keys.test create mode 100644 mysql-test/suite/storage_engine/fulltext_search.result create mode 100644 mysql-test/suite/storage_engine/fulltext_search.test create mode 100644 mysql-test/suite/storage_engine/handler.result create mode 100644 mysql-test/suite/storage_engine/handler.test create mode 100644 mysql-test/suite/storage_engine/have_default_index.inc create mode 100644 mysql-test/suite/storage_engine/have_engine.inc create mode 100644 mysql-test/suite/storage_engine/index.inc create mode 100644 mysql-test/suite/storage_engine/index.result create mode 100644 mysql-test/suite/storage_engine/index.test create mode 100644 mysql-test/suite/storage_engine/index_enable_disable.result create mode 100644 mysql-test/suite/storage_engine/index_enable_disable.test create mode 100644 mysql-test/suite/storage_engine/index_key_block_size.result create mode 100644 mysql-test/suite/storage_engine/index_key_block_size.test create mode 100644 mysql-test/suite/storage_engine/index_primary.result create mode 100644 mysql-test/suite/storage_engine/index_primary.test create mode 100644 mysql-test/suite/storage_engine/index_type_btree.result create mode 100644 mysql-test/suite/storage_engine/index_type_btree.test create mode 100644 mysql-test/suite/storage_engine/index_type_hash.result create mode 100644 mysql-test/suite/storage_engine/index_type_hash.test create mode 100644 mysql-test/suite/storage_engine/insert.result create mode 100644 mysql-test/suite/storage_engine/insert.test create mode 100644 mysql-test/suite/storage_engine/insert_delayed.result create mode 100644 mysql-test/suite/storage_engine/insert_delayed.test create mode 100644 mysql-test/suite/storage_engine/insert_high_prio.result create mode 100644 mysql-test/suite/storage_engine/insert_high_prio.test create mode 100644 mysql-test/suite/storage_engine/insert_low_prio.result create mode 100644 mysql-test/suite/storage_engine/insert_low_prio.test create mode 100644 mysql-test/suite/storage_engine/insert_with_keys.result create mode 100644 mysql-test/suite/storage_engine/insert_with_keys.test create mode 100644 mysql-test/suite/storage_engine/loaddata.result create mode 100644 mysql-test/suite/storage_engine/loaddata.test create mode 100644 mysql-test/suite/storage_engine/lock.result create mode 100644 mysql-test/suite/storage_engine/lock.test create mode 100644 mysql-test/suite/storage_engine/lock_concurrent.result create mode 100644 mysql-test/suite/storage_engine/lock_concurrent.test create mode 100644 mysql-test/suite/storage_engine/mask_engine.inc create mode 100644 mysql-test/suite/storage_engine/misc.result create mode 100644 mysql-test/suite/storage_engine/misc.test create mode 100644 mysql-test/suite/storage_engine/my.cnf create mode 100644 mysql-test/suite/storage_engine/obfuscate.inc create mode 100644 mysql-test/suite/storage_engine/optimize_table.inc create mode 100644 mysql-test/suite/storage_engine/optimize_table.result create mode 100644 mysql-test/suite/storage_engine/optimize_table.test create mode 100644 mysql-test/suite/storage_engine/parts/alter_table.result create mode 100644 mysql-test/suite/storage_engine/parts/alter_table.test create mode 100644 mysql-test/suite/storage_engine/parts/analyze_table.result create mode 100644 mysql-test/suite/storage_engine/parts/analyze_table.test create mode 100644 mysql-test/suite/storage_engine/parts/check_table.result create mode 100644 mysql-test/suite/storage_engine/parts/check_table.test create mode 100644 mysql-test/suite/storage_engine/parts/checksum_table.result create mode 100644 mysql-test/suite/storage_engine/parts/checksum_table.test create mode 100644 mysql-test/suite/storage_engine/parts/create_table.result create mode 100644 mysql-test/suite/storage_engine/parts/create_table.test create mode 100644 mysql-test/suite/storage_engine/parts/my.cnf create mode 100644 mysql-test/suite/storage_engine/parts/optimize_table.result create mode 100644 mysql-test/suite/storage_engine/parts/optimize_table.test create mode 100644 mysql-test/suite/storage_engine/parts/repair_table.result create mode 100644 mysql-test/suite/storage_engine/parts/repair_table.test create mode 100644 mysql-test/suite/storage_engine/parts/truncate_table.result create mode 100644 mysql-test/suite/storage_engine/parts/truncate_table.test create mode 100644 mysql-test/suite/storage_engine/repair_table.inc create mode 100644 mysql-test/suite/storage_engine/repair_table.result create mode 100644 mysql-test/suite/storage_engine/repair_table.test create mode 100644 mysql-test/suite/storage_engine/replace.result create mode 100644 mysql-test/suite/storage_engine/replace.test create mode 100644 mysql-test/suite/storage_engine/se-innodb.out create mode 100644 mysql-test/suite/storage_engine/select.result create mode 100644 mysql-test/suite/storage_engine/select.test create mode 100644 mysql-test/suite/storage_engine/select_high_prio.result create mode 100644 mysql-test/suite/storage_engine/select_high_prio.test create mode 100644 mysql-test/suite/storage_engine/show_engine.result create mode 100644 mysql-test/suite/storage_engine/show_engine.test create mode 100644 mysql-test/suite/storage_engine/show_table_status.result create mode 100644 mysql-test/suite/storage_engine/show_table_status.test create mode 100644 mysql-test/suite/storage_engine/strict_check_errors.inc create mode 100644 mysql-test/suite/storage_engine/tbl_opt_ai.result create mode 100644 mysql-test/suite/storage_engine/tbl_opt_ai.test create mode 100644 mysql-test/suite/storage_engine/tbl_opt_avg_row_length.result create mode 100644 mysql-test/suite/storage_engine/tbl_opt_avg_row_length.test create mode 100644 mysql-test/suite/storage_engine/tbl_opt_checksum.result create mode 100644 mysql-test/suite/storage_engine/tbl_opt_checksum.test create mode 100644 mysql-test/suite/storage_engine/tbl_opt_connection.result create mode 100644 mysql-test/suite/storage_engine/tbl_opt_connection.test create mode 100644 mysql-test/suite/storage_engine/tbl_opt_data_index_dir.result create mode 100644 mysql-test/suite/storage_engine/tbl_opt_data_index_dir.test create mode 100644 mysql-test/suite/storage_engine/tbl_opt_delay_key_write.result create mode 100644 mysql-test/suite/storage_engine/tbl_opt_delay_key_write.test create mode 100644 mysql-test/suite/storage_engine/tbl_opt_insert_method.result create mode 100644 mysql-test/suite/storage_engine/tbl_opt_insert_method.test create mode 100644 mysql-test/suite/storage_engine/tbl_opt_key_block_size.result create mode 100644 mysql-test/suite/storage_engine/tbl_opt_key_block_size.test create mode 100644 mysql-test/suite/storage_engine/tbl_opt_max_rows.result create mode 100644 mysql-test/suite/storage_engine/tbl_opt_max_rows.test create mode 100644 mysql-test/suite/storage_engine/tbl_opt_min_rows.result create mode 100644 mysql-test/suite/storage_engine/tbl_opt_min_rows.test create mode 100644 mysql-test/suite/storage_engine/tbl_opt_pack_keys.result create mode 100644 mysql-test/suite/storage_engine/tbl_opt_pack_keys.test create mode 100644 mysql-test/suite/storage_engine/tbl_opt_password.result create mode 100644 mysql-test/suite/storage_engine/tbl_opt_password.test create mode 100644 mysql-test/suite/storage_engine/tbl_opt_row_format.result create mode 100644 mysql-test/suite/storage_engine/tbl_opt_row_format.test create mode 100644 mysql-test/suite/storage_engine/tbl_opt_union.result create mode 100644 mysql-test/suite/storage_engine/tbl_opt_union.test create mode 100644 mysql-test/suite/storage_engine/tbl_standard_opts.result create mode 100644 mysql-test/suite/storage_engine/tbl_standard_opts.test create mode 100644 mysql-test/suite/storage_engine/tbl_temporary.result create mode 100644 mysql-test/suite/storage_engine/tbl_temporary.test create mode 100644 mysql-test/suite/storage_engine/truncate_table.result create mode 100644 mysql-test/suite/storage_engine/truncate_table.test create mode 100644 mysql-test/suite/storage_engine/trx/cons_snapshot_repeatable_read.result create mode 100644 mysql-test/suite/storage_engine/trx/cons_snapshot_repeatable_read.test create mode 100644 mysql-test/suite/storage_engine/trx/cons_snapshot_serializable.result create mode 100644 mysql-test/suite/storage_engine/trx/cons_snapshot_serializable.test create mode 100644 mysql-test/suite/storage_engine/trx/consistent_snapshot.inc create mode 100644 mysql-test/suite/storage_engine/trx/delete.result create mode 100644 mysql-test/suite/storage_engine/trx/delete.test create mode 100644 mysql-test/suite/storage_engine/trx/insert.result create mode 100644 mysql-test/suite/storage_engine/trx/insert.test create mode 100644 mysql-test/suite/storage_engine/trx/level_read_committed.result create mode 100644 mysql-test/suite/storage_engine/trx/level_read_committed.test create mode 100644 mysql-test/suite/storage_engine/trx/level_read_uncommitted.result create mode 100644 mysql-test/suite/storage_engine/trx/level_read_uncommitted.test create mode 100644 mysql-test/suite/storage_engine/trx/level_repeatable_read.result create mode 100644 mysql-test/suite/storage_engine/trx/level_repeatable_read.test create mode 100644 mysql-test/suite/storage_engine/trx/level_serializable.result create mode 100644 mysql-test/suite/storage_engine/trx/level_serializable.test create mode 100644 mysql-test/suite/storage_engine/trx/my.cnf create mode 100644 mysql-test/suite/storage_engine/trx/select_for_update.result create mode 100644 mysql-test/suite/storage_engine/trx/select_for_update.test create mode 100644 mysql-test/suite/storage_engine/trx/select_lock_in_share_mode.result create mode 100644 mysql-test/suite/storage_engine/trx/select_lock_in_share_mode.test create mode 100644 mysql-test/suite/storage_engine/trx/support_savepoints.inc create mode 100644 mysql-test/suite/storage_engine/trx/support_transactions.inc create mode 100644 mysql-test/suite/storage_engine/trx/support_xa.inc create mode 100644 mysql-test/suite/storage_engine/trx/transaction_isolation.inc create mode 100644 mysql-test/suite/storage_engine/trx/update.result create mode 100644 mysql-test/suite/storage_engine/trx/update.test create mode 100644 mysql-test/suite/storage_engine/trx/xa.result create mode 100644 mysql-test/suite/storage_engine/trx/xa.test create mode 100644 mysql-test/suite/storage_engine/trx/xa_recovery.result create mode 100644 mysql-test/suite/storage_engine/trx/xa_recovery.test create mode 100644 mysql-test/suite/storage_engine/type_binary.inc create mode 100644 mysql-test/suite/storage_engine/type_binary.result create mode 100644 mysql-test/suite/storage_engine/type_binary.test create mode 100644 mysql-test/suite/storage_engine/type_binary_indexes.result create mode 100644 mysql-test/suite/storage_engine/type_binary_indexes.test create mode 100644 mysql-test/suite/storage_engine/type_bit.inc create mode 100644 mysql-test/suite/storage_engine/type_bit.result create mode 100644 mysql-test/suite/storage_engine/type_bit.test create mode 100644 mysql-test/suite/storage_engine/type_bit_indexes.result create mode 100644 mysql-test/suite/storage_engine/type_bit_indexes.test create mode 100644 mysql-test/suite/storage_engine/type_blob.inc create mode 100644 mysql-test/suite/storage_engine/type_blob.result create mode 100644 mysql-test/suite/storage_engine/type_blob.test create mode 100644 mysql-test/suite/storage_engine/type_blob_indexes.result create mode 100644 mysql-test/suite/storage_engine/type_blob_indexes.test create mode 100644 mysql-test/suite/storage_engine/type_bool.inc create mode 100644 mysql-test/suite/storage_engine/type_bool.result create mode 100644 mysql-test/suite/storage_engine/type_bool.test create mode 100644 mysql-test/suite/storage_engine/type_char.inc create mode 100644 mysql-test/suite/storage_engine/type_char.result create mode 100644 mysql-test/suite/storage_engine/type_char.test create mode 100644 mysql-test/suite/storage_engine/type_char_indexes.result create mode 100644 mysql-test/suite/storage_engine/type_char_indexes.test create mode 100644 mysql-test/suite/storage_engine/type_date_time.inc create mode 100644 mysql-test/suite/storage_engine/type_date_time.result create mode 100644 mysql-test/suite/storage_engine/type_date_time.test create mode 100644 mysql-test/suite/storage_engine/type_date_time_indexes.result create mode 100644 mysql-test/suite/storage_engine/type_date_time_indexes.test create mode 100644 mysql-test/suite/storage_engine/type_enum.inc create mode 100644 mysql-test/suite/storage_engine/type_enum.result create mode 100644 mysql-test/suite/storage_engine/type_enum.test create mode 100644 mysql-test/suite/storage_engine/type_enum_indexes.result create mode 100644 mysql-test/suite/storage_engine/type_enum_indexes.test create mode 100644 mysql-test/suite/storage_engine/type_fixed.inc create mode 100644 mysql-test/suite/storage_engine/type_fixed.result create mode 100644 mysql-test/suite/storage_engine/type_fixed.test create mode 100644 mysql-test/suite/storage_engine/type_fixed_indexes.result create mode 100644 mysql-test/suite/storage_engine/type_fixed_indexes.test create mode 100644 mysql-test/suite/storage_engine/type_float.inc create mode 100644 mysql-test/suite/storage_engine/type_float.result create mode 100644 mysql-test/suite/storage_engine/type_float.test create mode 100644 mysql-test/suite/storage_engine/type_float_indexes.result create mode 100644 mysql-test/suite/storage_engine/type_float_indexes.test create mode 100644 mysql-test/suite/storage_engine/type_int.inc create mode 100644 mysql-test/suite/storage_engine/type_int.result create mode 100644 mysql-test/suite/storage_engine/type_int.test create mode 100644 mysql-test/suite/storage_engine/type_int_indexes.result create mode 100644 mysql-test/suite/storage_engine/type_int_indexes.test create mode 100644 mysql-test/suite/storage_engine/type_set.inc create mode 100644 mysql-test/suite/storage_engine/type_set.result create mode 100644 mysql-test/suite/storage_engine/type_set.test create mode 100644 mysql-test/suite/storage_engine/type_set_indexes.result create mode 100644 mysql-test/suite/storage_engine/type_set_indexes.test create mode 100644 mysql-test/suite/storage_engine/type_spatial.inc create mode 100644 mysql-test/suite/storage_engine/type_spatial.result create mode 100644 mysql-test/suite/storage_engine/type_spatial.test create mode 100644 mysql-test/suite/storage_engine/type_spatial_indexes.result create mode 100644 mysql-test/suite/storage_engine/type_spatial_indexes.test create mode 100644 mysql-test/suite/storage_engine/type_text.inc create mode 100644 mysql-test/suite/storage_engine/type_text.result create mode 100644 mysql-test/suite/storage_engine/type_text.test create mode 100644 mysql-test/suite/storage_engine/type_text_indexes.result create mode 100644 mysql-test/suite/storage_engine/type_text_indexes.test create mode 100644 mysql-test/suite/storage_engine/type_varbinary.inc create mode 100644 mysql-test/suite/storage_engine/type_varbinary.result create mode 100644 mysql-test/suite/storage_engine/type_varbinary.test create mode 100644 mysql-test/suite/storage_engine/type_varchar.inc create mode 100644 mysql-test/suite/storage_engine/type_varchar.result create mode 100644 mysql-test/suite/storage_engine/type_varchar.test create mode 100644 mysql-test/suite/storage_engine/unexpected_result.inc create mode 100644 mysql-test/suite/storage_engine/update.result create mode 100644 mysql-test/suite/storage_engine/update.test create mode 100644 mysql-test/suite/storage_engine/update_ignore.result create mode 100644 mysql-test/suite/storage_engine/update_ignore.test create mode 100644 mysql-test/suite/storage_engine/update_low_prio.result create mode 100644 mysql-test/suite/storage_engine/update_low_prio.test create mode 100644 mysql-test/suite/storage_engine/update_multi.result create mode 100644 mysql-test/suite/storage_engine/update_multi.test create mode 100644 mysql-test/suite/storage_engine/update_with_keys.result create mode 100644 mysql-test/suite/storage_engine/update_with_keys.test create mode 100644 mysql-test/suite/storage_engine/vcol.result create mode 100644 mysql-test/suite/storage_engine/vcol.test create mode 100644 storage/innobase/mysql-test/storage_engine/alter_tablespace.opt create mode 100644 storage/innobase/mysql-test/storage_engine/autoinc_secondary.rdiff create mode 100644 storage/innobase/mysql-test/storage_engine/cache_index.rdiff create mode 100644 storage/innobase/mysql-test/storage_engine/checksum_table_live.rdiff create mode 100644 storage/innobase/mysql-test/storage_engine/define_engine.inc create mode 100644 storage/innobase/mysql-test/storage_engine/disabled.def create mode 100644 storage/innobase/mysql-test/storage_engine/fulltext_search.rdiff create mode 100644 storage/innobase/mysql-test/storage_engine/index_enable_disable.rdiff create mode 100644 storage/innobase/mysql-test/storage_engine/index_type_hash.rdiff create mode 100644 storage/innobase/mysql-test/storage_engine/insert_delayed.rdiff create mode 100644 storage/innobase/mysql-test/storage_engine/lock_concurrent.rdiff create mode 100644 storage/innobase/mysql-test/storage_engine/optimize_table.rdiff create mode 100644 storage/innobase/mysql-test/storage_engine/parts/checksum_table.rdiff create mode 100644 storage/innobase/mysql-test/storage_engine/parts/create_table.rdiff create mode 100644 storage/innobase/mysql-test/storage_engine/parts/optimize_table.rdiff create mode 100644 storage/innobase/mysql-test/storage_engine/parts/repair_table.rdiff create mode 100644 storage/innobase/mysql-test/storage_engine/parts/suite.opt create mode 100644 storage/innobase/mysql-test/storage_engine/repair_table.rdiff create mode 100644 storage/innobase/mysql-test/storage_engine/suite.opt create mode 100644 storage/innobase/mysql-test/storage_engine/tbl_opt_data_index_dir.rdiff create mode 100644 storage/innobase/mysql-test/storage_engine/tbl_opt_insert_method.rdiff create mode 100644 storage/innobase/mysql-test/storage_engine/tbl_opt_key_block_size.opt create mode 100644 storage/innobase/mysql-test/storage_engine/tbl_opt_row_format.opt create mode 100644 storage/innobase/mysql-test/storage_engine/tbl_opt_row_format.rdiff create mode 100644 storage/innobase/mysql-test/storage_engine/tbl_opt_union.rdiff create mode 100644 storage/innobase/mysql-test/storage_engine/trx/disabled.def create mode 100644 storage/innobase/mysql-test/storage_engine/trx/suite.opt create mode 100644 storage/innobase/mysql-test/storage_engine/type_char_indexes.rdiff create mode 100644 storage/innobase/mysql-test/storage_engine/type_float_indexes.rdiff create mode 100644 storage/innobase/mysql-test/storage_engine/type_spatial_indexes.rdiff create mode 100644 storage/innobase/mysql-test/storage_engine/vcol.rdiff create mode 100644 storage/myisam/mysql-test/storage_engine/alter_tablespace.rdiff create mode 100644 storage/myisam/mysql-test/storage_engine/check_table.rdiff create mode 100644 storage/myisam/mysql-test/storage_engine/define_engine.inc create mode 100644 storage/myisam/mysql-test/storage_engine/foreign_keys.rdiff create mode 100644 storage/myisam/mysql-test/storage_engine/index_type_hash.rdiff create mode 100644 storage/myisam/mysql-test/storage_engine/show_engine.rdiff create mode 100644 storage/myisam/mysql-test/storage_engine/tbl_opt_insert_method.rdiff create mode 100644 storage/myisam/mysql-test/storage_engine/tbl_opt_union.rdiff create mode 100644 storage/myisam/mysql-test/storage_engine/trx/cons_snapshot_repeatable_read.rdiff create mode 100644 storage/myisam/mysql-test/storage_engine/trx/cons_snapshot_serializable.rdiff create mode 100644 storage/myisam/mysql-test/storage_engine/trx/delete.rdiff create mode 100644 storage/myisam/mysql-test/storage_engine/trx/insert.rdiff create mode 100644 storage/myisam/mysql-test/storage_engine/trx/level_read_committed.rdiff create mode 100644 storage/myisam/mysql-test/storage_engine/trx/level_read_uncommitted.rdiff create mode 100644 storage/myisam/mysql-test/storage_engine/trx/level_repeatable_read.rdiff create mode 100644 storage/myisam/mysql-test/storage_engine/trx/level_serializable.rdiff create mode 100644 storage/myisam/mysql-test/storage_engine/trx/select_for_update.rdiff create mode 100644 storage/myisam/mysql-test/storage_engine/trx/select_lock_in_share_mode.rdiff create mode 100644 storage/myisam/mysql-test/storage_engine/trx/update.rdiff create mode 100644 storage/myisam/mysql-test/storage_engine/trx/xa.rdiff create mode 100644 storage/myisam/mysql-test/storage_engine/trx/xa_recovery.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/alter_table.inc create mode 100644 storage/myisammrg/mysql-test/storage_engine/alter_table.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/alter_tablespace.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/analyze_table.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/autoincrement.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/cache_index.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/char_indexes.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/checksum_table_live.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/cleanup_engine.inc create mode 100644 storage/myisammrg/mysql-test/storage_engine/create_table.inc create mode 100644 storage/myisammrg/mysql-test/storage_engine/create_table.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/define_engine.inc create mode 100644 storage/myisammrg/mysql-test/storage_engine/disabled.def create mode 100644 storage/myisammrg/mysql-test/storage_engine/foreign_keys.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/fulltext_search.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/handler.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/index.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/index_enable_disable.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/index_type_btree.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/index_type_hash.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/insert_delayed.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/lock.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/optimize_table.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/parts/alter_table.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/parts/analyze_table.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/parts/check_table.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/parts/checksum_table.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/parts/create_table.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/parts/optimize_table.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/parts/repair_table.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/parts/truncate_table.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/repair_table.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/show_engine.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/tbl_opt_ai.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/tbl_opt_avg_row_length.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/tbl_opt_checksum.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/tbl_opt_connection.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/tbl_opt_data_index_dir.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/tbl_opt_delay_key_write.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/tbl_opt_insert_method.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/tbl_opt_key_block_size.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/tbl_opt_max_rows.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/tbl_opt_min_rows.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/tbl_opt_pack_keys.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/tbl_opt_password.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/tbl_opt_row_format.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/tbl_opt_union.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/tbl_standard_opts.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/tbl_temporary.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/truncate_table.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/trx/cons_snapshot_repeatable_read.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/trx/cons_snapshot_serializable.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/trx/delete.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/trx/insert.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/trx/level_read_committed.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/trx/level_read_uncommitted.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/trx/level_repeatable_read.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/trx/level_serializable.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/trx/select_for_update.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/trx/select_lock_in_share_mode.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/trx/update.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/trx/xa.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/trx/xa_recovery.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/type_char_indexes.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/type_float_indexes.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/type_spatial.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/type_spatial_indexes.rdiff create mode 100644 storage/myisammrg/mysql-test/storage_engine/vcol.rdiff diff --git a/mysql-test/suite/storage_engine/1st.result b/mysql-test/suite/storage_engine/1st.result new file mode 100644 index 00000000000..6b686c2b2b4 --- /dev/null +++ b/mysql-test/suite/storage_engine/1st.result @@ -0,0 +1,11 @@ +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (a , b ) ENGINE= ; +SHOW CREATE TABLE t1; +SHOW COLUMNS IN t1; +INSERT INTO t1 VALUES (1,'a'); +INSERT INTO t1 (a,b) VALUES (2,'b'); +SELECT * FROM t1; +a b +1 a +2 b +DROP TABLE t1; diff --git a/mysql-test/suite/storage_engine/1st.test b/mysql-test/suite/storage_engine/1st.test new file mode 100644 index 00000000000..af7a4503948 --- /dev/null +++ b/mysql-test/suite/storage_engine/1st.test @@ -0,0 +1,81 @@ +# +# This test checks some very basic capabilities +# which will be used in almost every other test, +# and will not be checked through support* variables. +# If this test does not pass, there is no point +# at executing other ones. +# +# Minimal requirements: +# - supported column types: INT, CHAR (default CHAR(8), INT(11)); +# - column attributes as declared in define_engine.inc ($default_col_opts) +# (by default empty, which means no additional attributes apart from the type); +# - table attributes as declared in define_engine.inc ($default_tbl_opts) +# (by default empty, which means no additional attributes apart from ENGINE); +# - CREATE TABLE .. (column1 , column2 ) ENGINE=; +# - INSERT INTO TABLE .. VALUES (val1,val2); +# - DROP TABLE .. +# - SELECT * FROM .. +# - SHOW CREATE TABLE .. +# - SHOW COLUMNS IN ... +# + +--source have_engine.inc + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +--source create_table.inc +if ($mysql_errname) +{ + --let $functionality = CREATE TABLE + --source unexpected_result.inc +} +if (!$mysql_errname) +{ + --disable_result_log + SHOW CREATE TABLE t1; + if ($mysql_errname) + { + --let $functionality = SHOW CREATE TABLE + --source unexpected_result.inc + } + SHOW COLUMNS IN t1; + if ($mysql_errname) + { + --let $functionality = SHOW COLUMNS + --source unexpected_result.inc + } + --enable_result_log + + INSERT INTO t1 VALUES (1,'a'); + if ($mysql_errname) + { + --let $functionality = INSERT INTO .. VALUES + --source unexpected_result.inc + } + + INSERT INTO t1 (a,b) VALUES (2,'b'); + if ($mysql_errname) + { + --let $functionality = INSERT INTO .. (column_list) VALUES + --source unexpected_result.inc + } + + SELECT * FROM t1; + if ($mysql_errname) + { + --let $functionality = SELECT * FROM .. + --source unexpected_result.inc + } + + DROP TABLE t1; + if ($mysql_errname) + { + --let $functionality = DROP TABLE + --source unexpected_result.inc + } + +} +--source cleanup_engine.inc + diff --git a/mysql-test/suite/storage_engine/alter_table.inc b/mysql-test/suite/storage_engine/alter_table.inc new file mode 100644 index 00000000000..0f78c597455 --- /dev/null +++ b/mysql-test/suite/storage_engine/alter_table.inc @@ -0,0 +1,91 @@ +################################## +# +# This include file will be used for all ALTER TABLE statements in the suite. +# If you need to add additional steps or change the logic, copy the file +# to storage//mysql-test/storage_engine/ folder and modify it there. +# +################## +# +# Parameters: +# +# --let $alter_definition = # mandatory, everything that goes after the table name in ALTER statement +# --let $table_name = # optional, default t1 +# --let $error_codes = # optional, default 0 +# --let $online = [0|1] # optional, default 0 (1 adds ONLINE) +# --let $rename_to = # optional, default empty. +# # If set, means we are running RENAME TO, then alter definition is ignored +# +# Usage examples: +# +# --let $alter_definition = ADD COLUMN b $char_col DEFAULT '' +# + +if ($rename_to) +{ + --let $alter_definition = RENAME TO $rename_to +} + +if (!$alter_definition) +{ + --die # The ALTER statement is empty +} + +--let $alter_statement = ALTER + +if ($online) +{ + --let $alter_statement = $alter_statement ONLINE +} + +if (!$table_name) +{ + --let $table_name = t1 +} + +--let $alter_statement = $alter_statement TABLE $table_name $alter_definition + + +# We now have the complete ALTER statement in $alter_statement. +# If your ALTER statement should be composed differently, +# modify the logic above. + +##################### +# Here you can add logic needed BEFORE the main statement +# (e.g. base tables need to be altered, etc.). +# Surround it by --disable_query_log/--enable_query_log +# if you don't want it to appear in the result output. +##################### + +--source obfuscate.inc + +eval $alter_statement; +--source check_errors.inc + +# Make sure you don't add any statements between the main ALTER (above) +# and saving mysql_errno and mysql_errname (below) +# They are saved in case you want to add more logic after the main ALTER, +# because we need the result code of the statement. +# Also, do not change $alter_statement after it is executed! + +--let $my_errno = $mysql_errno +--let $my_errname = $mysql_errname + +##################### +# Here you can add logic needed AFTER the main statement. +# Surround it by --disable_query_log/--enable_query_log +# if you don't want it to appear in the result output. +##################### + +# Unset the parameters, we don't want them to be accidentally reused later +--let $alter_definition = +--let $table_name = +--let $error_codes = +--let $online = 0 +--let $rename_to = + +# Restore the error codes of the main statement +--let $mysql_errno = $my_errno +--let $mysql_errname = $my_errname +# Make sure you don't add any SQL statements after restoring +# mysql_errno and mysql_errname (above) + diff --git a/mysql-test/suite/storage_engine/alter_table.result b/mysql-test/suite/storage_engine/alter_table.result new file mode 100644 index 00000000000..6d868a27a36 --- /dev/null +++ b/mysql-test/suite/storage_engine/alter_table.result @@ -0,0 +1,147 @@ +DROP TABLE IF EXISTS t1, t2; +CREATE TABLE t1 (a , c ) ENGINE= ; +INSERT INTO t1 (a,c) VALUES (1,'a'),(5,'z'); +ALTER TABLE t1 ADD COLUMN b ; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL, + `c` char(8) DEFAULT NULL, + `b` int(11) DEFAULT NULL +) ENGINE= DEFAULT CHARSET=latin1 +ALTER TABLE t1 ALTER COLUMN a SET DEFAULT '0'; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT '0', + `c` char(8) DEFAULT NULL, + `b` int(11) DEFAULT NULL +) ENGINE= DEFAULT CHARSET=latin1 +ALTER TABLE t1 ALTER a DROP DEFAULT; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11), + `c` char(8) DEFAULT NULL, + `b` int(11) DEFAULT NULL +) ENGINE= DEFAULT CHARSET=latin1 +ALTER TABLE t1 CHANGE COLUMN b b1 FIRST; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `b1` char(8) DEFAULT NULL, + `a` int(11), + `c` char(8) DEFAULT NULL +) ENGINE= DEFAULT CHARSET=latin1 +ALTER TABLE t1 CHANGE b1 b AFTER c; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11), + `c` char(8) DEFAULT NULL, + `b` int(11) DEFAULT NULL +) ENGINE= DEFAULT CHARSET=latin1 +ALTER TABLE t1 CHANGE b b ; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11), + `c` char(8) DEFAULT NULL, + `b` char(8) DEFAULT NULL +) ENGINE= DEFAULT CHARSET=latin1 +ALTER TABLE t1 MODIFY COLUMN b ; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11), + `c` char(8) DEFAULT NULL, + `b` int(11) DEFAULT NULL +) ENGINE= DEFAULT CHARSET=latin1 +ALTER TABLE t1 MODIFY COLUMN b FIRST; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `b` char(8) DEFAULT NULL, + `a` int(11), + `c` char(8) DEFAULT NULL +) ENGINE= DEFAULT CHARSET=latin1 +ALTER TABLE t1 MODIFY COLUMN b AFTER a; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11), + `b` int(11) DEFAULT NULL, + `c` char(8) DEFAULT NULL +) ENGINE= DEFAULT CHARSET=latin1 +ALTER TABLE t1 DROP COLUMN b; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11), + `c` char(8) DEFAULT NULL +) ENGINE= DEFAULT CHARSET=latin1 +ALTER TABLE t1 RENAME TO t2; +SHOW CREATE TABLE t1; +ERROR 42S02: Table 'test.t1' doesn't exist +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` int(11), + `c` char(8) DEFAULT NULL +) ENGINE= DEFAULT CHARSET=latin1 +DROP TABLE t2; +CREATE TABLE t1 (a , b ) ENGINE= ; +INSERT INTO t1 (a,b) VALUES (1,5),(2,2),(4,3); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL, + `b` int(11) DEFAULT NULL +) ENGINE= DEFAULT CHARSET=latin1 +ALTER TABLE t1 ORDER BY b ASC, a DESC; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL, + `b` int(11) DEFAULT NULL +) ENGINE= DEFAULT CHARSET=latin1 +SELECT * FROM t1; +a b +2 2 +4 3 +1 5 +DROP TABLE t1; +CREATE TABLE t1 (a , b , c ) ENGINE= CHARACTER SET latin1 COLLATE latin1_general_cs; +INSERT INTO t1 (a,b,c) VALUES (5,'z','t'); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL, + `b` char(8) COLLATE latin1_general_cs DEFAULT NULL, + `c` char(8) COLLATE latin1_general_cs DEFAULT NULL +) ENGINE= DEFAULT CHARSET=latin1 COLLATE=latin1_general_cs +ALTER TABLE t1 CONVERT TO CHARACTER SET utf8; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL, + `b` char(8) DEFAULT NULL, + `c` char(8) DEFAULT NULL +) ENGINE= DEFAULT CHARSET=utf8 +ALTER TABLE t1 DEFAULT CHARACTER SET = latin1 COLLATE latin1_general_ci; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL, + `b` char(8) CHARACTER SET utf8 DEFAULT NULL, + `c` char(8) CHARACTER SET utf8 DEFAULT NULL +) ENGINE= DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci +ALTER TABLE t1 FORCE; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL, + `b` char(8) CHARACTER SET utf8 DEFAULT NULL, + `c` char(8) CHARACTER SET utf8 DEFAULT NULL +) ENGINE= DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci +DROP TABLE t1; diff --git a/mysql-test/suite/storage_engine/alter_table.test b/mysql-test/suite/storage_engine/alter_table.test new file mode 100644 index 00000000000..023d8927e16 --- /dev/null +++ b/mysql-test/suite/storage_engine/alter_table.test @@ -0,0 +1,148 @@ +# +# Basic ALTER TABLE statements. +# +# USAGE of table options in ALTER statements +# is covered in tbl_standard_opts and tbl_opt*.tests. +# +# Index operations are covered in index* tests. +# +# ALTER ONLINE syntax is covered in alter_online_table.test +# ALTER OFFLINE is not covered as it is not supported, as of 5.5.23 +# +# ALTER TABLE ... DISCARD|IMPORT TABLESPACE is covered in alter_tablespace.test +# + +--source have_engine.inc + +--disable_warnings +DROP TABLE IF EXISTS t1, t2; +--enable_warnings + +--let $create_definition = a $int_col, c $char_col +--source create_table.inc +INSERT INTO t1 (a,c) VALUES (1,'a'),(5,'z'); + +# Column operations + +--let $alter_definition = ADD COLUMN b $int_col +--source alter_table.inc +if ($mysql_errname) +{ + --source unexpected_result.inc +} + +--source mask_engine.inc +SHOW CREATE TABLE t1; + +--let $alter_definition = ALTER COLUMN a SET DEFAULT '0' +--source alter_table.inc +--source mask_engine.inc +SHOW CREATE TABLE t1; + +--let $alter_definition = ALTER a DROP DEFAULT +--source alter_table.inc +--source mask_engine.inc +SHOW CREATE TABLE t1; + +--let $alter_definition = CHANGE COLUMN b b1 $char_col FIRST +--source alter_table.inc +--source mask_engine.inc +SHOW CREATE TABLE t1; + +--let $alter_definition = CHANGE b1 b $int_col AFTER c +--source alter_table.inc +--source mask_engine.inc +SHOW CREATE TABLE t1; + +--let $alter_definition = CHANGE b b $char_col +--source alter_table.inc +--source mask_engine.inc +SHOW CREATE TABLE t1; + +--let $alter_definition = MODIFY COLUMN b $int_col +--source alter_table.inc +--source mask_engine.inc +SHOW CREATE TABLE t1; + +--let $alter_definition = MODIFY COLUMN b $char_col FIRST +--source alter_table.inc +--source mask_engine.inc +SHOW CREATE TABLE t1; + +--let $alter_definition = MODIFY COLUMN b $int_col AFTER a +--source alter_table.inc +--source mask_engine.inc +SHOW CREATE TABLE t1; + +--let $alter_definition = DROP COLUMN b +--source alter_table.inc +--source mask_engine.inc +SHOW CREATE TABLE t1; + + +# Rename table + +--let $rename_to = t2 +--source alter_table.inc +--let $error_codes = ER_NO_SUCH_TABLE +SHOW CREATE TABLE t1; +--source check_errors.inc +if ($mysql_errname != 'ER_NO_SUCH_TABLE') +{ + --let $functionality = ALTER TABLE + --source unexpected_result.inc + DROP TABLE t1; +} +if ($mysql_errname == ER_NO_SUCH_TABLE) +{ + --source mask_engine.inc + SHOW CREATE TABLE t2; + DROP TABLE t2; +} + +# ORDER BY +--let $create_definition = a $int_col, b $int_col +--source create_table.inc +INSERT INTO t1 (a,b) VALUES (1,5),(2,2),(4,3); +--source mask_engine.inc +SHOW CREATE TABLE t1; + +--let $alter_definition = ORDER BY b ASC, a DESC +--source alter_table.inc +--source mask_engine.inc +SHOW CREATE TABLE t1; +SELECT * FROM t1; +DROP TABLE t1; + +# Character set, collate + +--let $table_options = CHARACTER SET latin1 COLLATE latin1_general_cs +--let $create_definition = a $int_col, b $char_col, c $char_col +--source create_table.inc +INSERT INTO t1 (a,b,c) VALUES (5,'z','t'); + +--source mask_engine.inc +SHOW CREATE TABLE t1; + +--let $alter_definition = CONVERT TO CHARACTER SET utf8 +--source alter_table.inc +--source mask_engine.inc +SHOW CREATE TABLE t1; + +--let $alter_definition = DEFAULT CHARACTER SET = latin1 COLLATE latin1_general_ci +--source alter_table.inc +--source mask_engine.inc +SHOW CREATE TABLE t1; + +# A 'null' ALTER operation + +--let $alter_definition = FORCE +--source alter_table.inc +--source mask_engine.inc +SHOW CREATE TABLE t1; + +# Cleanup +DROP TABLE t1; + +--source cleanup_engine.inc + diff --git a/mysql-test/suite/storage_engine/alter_table_online.result b/mysql-test/suite/storage_engine/alter_table_online.result new file mode 100644 index 00000000000..0e606bf1f7e --- /dev/null +++ b/mysql-test/suite/storage_engine/alter_table_online.result @@ -0,0 +1,35 @@ +DROP TABLE IF EXISTS t1,t2,t3; +CREATE TABLE t1 (a , b , c ) ENGINE= ; +INSERT INTO t1 (a,b,c) VALUES (1,100,'a'),(2,200,'b'),(3,300,'c'); +ALTER ONLINE TABLE t1 MODIFY b DEFAULT 5; +ALTER ONLINE TABLE t1 CHANGE b new_name ; +ALTER ONLINE TABLE t1 COMMENT 'new comment'; +ALTER ONLINE TABLE t1 RENAME TO t2; +DROP TABLE IF EXISTS t2; +CREATE TEMPORARY TABLE t1 (a , b ) ENGINE= ; +INSERT INTO t1 (a,b) VALUES (1,'a'),(2,'b'),(3,'c'); +ALTER ONLINE TABLE t1 MODIFY b DEFAULT 5; +ERROR HY000: Can't execute the given 'ALTER' command as online +ALTER ONLINE TABLE t1 CHANGE b new_name ; +ERROR HY000: Can't execute the given 'ALTER' command as online +ALTER ONLINE TABLE t1 COMMENT 'new comment'; +ERROR HY000: Can't execute the given 'ALTER' command as online +ALTER ONLINE TABLE t1 RENAME TO t2; +ERROR HY000: Can't execute the given 'ALTER' command as online +DROP TABLE t1; +CREATE TABLE t1 (a , b , c ) ENGINE= ; +INSERT INTO t1 (a,b,c) VALUES (1,100,'a'),(2,200,'b'),(3,300,'c'); +ALTER ONLINE TABLE t1 DROP COLUMN b, ADD b ; +ERROR HY000: Can't execute the given 'ALTER' command as online +ALTER ONLINE TABLE t1 MODIFY b BIGINT ; +ERROR HY000: Can't execute the given 'ALTER' command as online +ALTER ONLINE TABLE t1 ENGINE=MEMORY; +ERROR HY000: Can't execute the given 'ALTER' command as online +DROP TABLE t1; +CREATE TABLE t1 (a , b , c ) ENGINE= ; +ALTER ONLINE TABLE t1 ADD INDEX (b); +ERROR HY000: Can't execute the given 'ALTER' command as online +ALTER TABLE t1 ADD INDEX (b); +ALTER ONLINE TABLE t1 DROP INDEX b; +ERROR HY000: Can't execute the given 'ALTER' command as online +DROP TABLE t1; diff --git a/mysql-test/suite/storage_engine/alter_table_online.test b/mysql-test/suite/storage_engine/alter_table_online.test new file mode 100644 index 00000000000..94dec2a72bb --- /dev/null +++ b/mysql-test/suite/storage_engine/alter_table_online.test @@ -0,0 +1,160 @@ +# +# ALTER ONLINE TABLE +# + +--source have_engine.inc + +--disable_warnings +DROP TABLE IF EXISTS t1,t2,t3; +--enable_warnings + +# +# Test of things that can be done online +# We are repeating notification here, because for some engines +# only a part of these ALTER ONLINE statements might be supported. +# + +let $create_definition = a $int_col, b $int_col, c $char_col; +--source create_table.inc + +INSERT INTO t1 (a,b,c) VALUES (1,100,'a'),(2,200,'b'),(3,300,'c'); + +--let $online = 1 +--let $alter_definition = MODIFY b $int_col DEFAULT 5 +--source alter_table.inc +if ($mysql_errname) +{ + --source unexpected_result.inc +} + +--let $online = 1 +--let $alter_definition = CHANGE b new_name $int_col +--source alter_table.inc +if ($mysql_errname) +{ + --source unexpected_result.inc +} + +--let $online = 1 +--let $alter_definition = COMMENT 'new comment' +--source alter_table.inc +if ($mysql_errname) +{ + --source unexpected_result.inc +} + +--let $online = 1 +--let $rename_to = t2 +--source alter_table.inc +if ($mysql_errname) +{ + --source unexpected_result.inc + DROP TABLE t1; +} +DROP TABLE IF EXISTS t2; + +# +# temporary tables always require a copy +# + +--let $temporary = 1 +--source create_table.inc + +INSERT INTO t1 (a,b) VALUES (1,'a'),(2,'b'),(3,'c'); + +--let $error_codes = ER_CANT_DO_ONLINE +--let $online = 1 +--let $alter_definition = MODIFY b $int_col DEFAULT 5 +--source alter_table.inc +if ($mysql_errname != ER_CANT_DO_ONLINE) +{ + --source unexpected_result.inc +} + + +--let $error_codes = ER_CANT_DO_ONLINE +--let $online = 1 +--let $alter_definition = CHANGE b new_name $int_col +--source alter_table.inc + +--let $error_codes = ER_CANT_DO_ONLINE +--let $online = 1 +--let $alter_definition = COMMENT 'new comment' +--source alter_table.inc + +--let $error_codes = ER_CANT_DO_ONLINE +--let $online = 1 +--let $rename_to = t2 +--source alter_table.inc + +DROP TABLE t1; + +# +# Test of things that is not possible to do online +# + +--let $create_definition = a $int_col, b $int_col, c $char_col +--source create_table.inc + +INSERT INTO t1 (a,b,c) VALUES (1,100,'a'),(2,200,'b'),(3,300,'c'); + +--let $error_codes = ER_CANT_DO_ONLINE +--let $online = 1 +--let $alter_definition = DROP COLUMN b, ADD b $int_col +--source alter_table.inc +if ($mysql_errname!=ER_CANT_DO_ONLINE) +{ + --source unexpected_result.inc +} + +--let $error_codes = ER_CANT_DO_ONLINE +--let $online = 1 +--let $alter_definition = MODIFY b BIGINT $default_col_opts +--source alter_table.inc + +--let $alternative_engine = `SELECT engine FROM information_schema.engines WHERE engine != '$storage_engine' AND support IN ('YES','DEFAULT')` + +--let $error_codes = ER_CANT_DO_ONLINE +--let $online = 1 +--let $alter_definition = ENGINE=$alternative_engine +--source alter_table.inc + +DROP TABLE t1; + +--let $create_definition = a $int_col, b $int_indexed_col, c $char_col +--source create_table.inc +if ($mysql_errname) +{ + --let $functionality = Column options + --source unexpected_result.inc +} +if (!$mysql_errname) +{ + --let $error_codes = ER_CANT_DO_ONLINE + --let $online = 1 + --let $alter_definition = ADD INDEX (b) + --source alter_table.inc + if ($mysql_errname!=ER_CANT_DO_ONLINE) + { + --let $functionality = Adding an index or ALTER ONLINE + --source unexpected_result.inc + } + + --let $alter_definition = ADD INDEX (b) + --source alter_table.inc + if ($mysql_errname) + { + --let $functionality = Adding an index or ALTER TABLE + --source unexpected_result.inc + } + if (!$mysql_errname) + { + --let $error_codes = ER_CANT_DO_ONLINE + --let $online = 1 + --let $alter_definition = DROP INDEX b + --source alter_table.inc + } + DROP TABLE t1; +} + +--source cleanup_engine.inc diff --git a/mysql-test/suite/storage_engine/alter_tablespace.result b/mysql-test/suite/storage_engine/alter_tablespace.result new file mode 100644 index 00000000000..5d8709b2357 --- /dev/null +++ b/mysql-test/suite/storage_engine/alter_tablespace.result @@ -0,0 +1,19 @@ +DROP TABLE IF EXISTS t1, t2; +CREATE TABLE t1 (a ) ENGINE= ; +ALTER TABLE t1 DISCARD TABLESPACE; +DROP TABLE t1; +CREATE TABLE t1 (a ) ENGINE= ; +INSERT INTO t1 (a) VALUES (1),(2); +SELECT * FROM t1; +a +1 +2 +ALTER TABLE t1 DISCARD TABLESPACE; +SELECT * FROM t1; +ERROR HY000: Got error -1 from storage engine +ALTER TABLE t1 IMPORT TABLESPACE; +SELECT * FROM t1; +a +1 +2 +DROP TABLE t1; diff --git a/mysql-test/suite/storage_engine/alter_tablespace.test b/mysql-test/suite/storage_engine/alter_tablespace.test new file mode 100644 index 00000000000..6c429bb98ea --- /dev/null +++ b/mysql-test/suite/storage_engine/alter_tablespace.test @@ -0,0 +1,91 @@ +# +# IMPORT / DISCARD TABLESPACE +# +# The test might require additional engine options, +# e.g. for InnoDB it is --innodb-file-per-table + +--source have_engine.inc + +--disable_warnings +DROP TABLE IF EXISTS t1, t2; +--enable_warnings + +--let $create_definition = a $int_col +--source create_table.inc + +--let $alter_definition = DISCARD TABLESPACE + +--source alter_table.inc +if ($mysql_errname) +{ + --let $my_last_stmt = $alter_statement + --let $functionality = Tablespace operations + --source unexpected_result.inc +} +if (!$mysql_errname) +{ + DROP TABLE t1; + + --let $create_definition = a $int_col + --source create_table.inc + INSERT INTO t1 (a) VALUES (1),(2); + --sorted_result + SELECT * FROM t1; + +# http://dev.mysql.com/doc/mysql-enterprise-backup/3.5/en/partial.restoring.single.html +# To get a "clean" backup we need to either use innobackup, or to monitor show engine innodb status, +# and the documented conditions do not look exactly feasible. So, we will go a simple way: +# just restart the server, and take the backup while the server is down. +# (And we need to have a really clean backup, see MySQL:65429 / LP:1004910) + + --let $datadir = `SELECT @@datadir` + + --write_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +restart +wait +EOF + + --enable_reconnect + --shutdown_server 60 + + --source include/wait_until_disconnected.inc + + --replace_result $datadir + --copy_file $datadir/test/t1.ibd $datadir/test/t1.ibd.save + + --remove_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect + --write_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +restart +EOF + + --source include/wait_until_connected_again.inc + + --let $alter_definition = DISCARD TABLESPACE + --source alter_table.inc + + --let $error_codes = ER_GET_ERRNO + SELECT * FROM t1; + --source check_errors.inc + if ($mysql_errname != ER_GET_ERRNO) + { + --let $functionality = Tablespace operations + --source unexpected_result.inc + } + + --move_file $datadir/test/t1.ibd.save $datadir/test/t1.ibd + --let $alter_definition = IMPORT TABLESPACE + --source alter_table.inc + --sorted_result + SELECT * FROM t1; + + # Adding a warning suppression based on what InnoDB currently does + # when it attempts to access a table without an *.ibd file + --disable_query_log + eval CALL mtr.add_suppression('$storage_engine: Error:.*'); + --enable_query_log +} + +DROP TABLE t1; + +--source cleanup_engine.inc + diff --git a/mysql-test/suite/storage_engine/analyze_table.inc b/mysql-test/suite/storage_engine/analyze_table.inc new file mode 100644 index 00000000000..2cbfc17aaa9 --- /dev/null +++ b/mysql-test/suite/storage_engine/analyze_table.inc @@ -0,0 +1,43 @@ +# +# ANALYZE TABLE statements +# +# Note: the output is likely to be different for the engine under test, +# in which case rdiff will be needed. Or, the output might say that +# the storage engine does not support ANALYZE. +# + +--disable_warnings +DROP TABLE IF EXISTS t1,t2; +--enable_warnings + +--let $create_definition = a $int_col, b $char_col +--source create_table.inc +INSERT INTO t1 (a,b) VALUES (1,'a'),(2,'b'); +--let $create_definition = a $int_col, b $char_col +--let $table_name = t2 +--source create_table.inc + +INSERT INTO t1 (a,b) VALUES (3,'c'); +ANALYZE TABLE t1; +INSERT INTO t2 (a,b) VALUES (4,'d'); +ANALYZE NO_WRITE_TO_BINLOG TABLE t2; +INSERT INTO t1 (a,b) VALUES (5,'e'); +INSERT INTO t2 (a,b) VALUES (6,'f'); +ANALYZE LOCAL TABLE t1, t2; + +DROP TABLE t1, t2; + +--let $continue = 1 +--source have_default_index.inc + +if ($have_default_index) +{ + --let $create_definition = a $int_indexed_col, $default_index(a) + --source create_table.inc + INSERT INTO t1 (a) VALUES (1),(2),(4),(7); + ANALYZE TABLE t1; + INSERT INTO t1 (a) VALUES (8),(10),(11),(12); + ANALYZE TABLE t1; + DROP TABLE t1; +} + diff --git a/mysql-test/suite/storage_engine/analyze_table.result b/mysql-test/suite/storage_engine/analyze_table.result new file mode 100644 index 00000000000..42904ed334d --- /dev/null +++ b/mysql-test/suite/storage_engine/analyze_table.result @@ -0,0 +1,29 @@ +DROP TABLE IF EXISTS t1,t2; +CREATE TABLE t1 (a , b ) ENGINE= ; +INSERT INTO t1 (a,b) VALUES (1,'a'),(2,'b'); +CREATE TABLE t2 (a , b ) ENGINE= ; +INSERT INTO t1 (a,b) VALUES (3,'c'); +ANALYZE TABLE t1; +Table Op Msg_type Msg_text +test.t1 analyze status OK +INSERT INTO t2 (a,b) VALUES (4,'d'); +ANALYZE NO_WRITE_TO_BINLOG TABLE t2; +Table Op Msg_type Msg_text +test.t2 analyze status OK +INSERT INTO t1 (a,b) VALUES (5,'e'); +INSERT INTO t2 (a,b) VALUES (6,'f'); +ANALYZE LOCAL TABLE t1, t2; +Table Op Msg_type Msg_text +test.t1 analyze status OK +test.t2 analyze status OK +DROP TABLE t1, t2; +CREATE TABLE t1 (a , (a)) ENGINE= ; +INSERT INTO t1 (a) VALUES (1),(2),(4),(7); +ANALYZE TABLE t1; +Table Op Msg_type Msg_text +test.t1 analyze status OK +INSERT INTO t1 (a) VALUES (8),(10),(11),(12); +ANALYZE TABLE t1; +Table Op Msg_type Msg_text +test.t1 analyze status OK +DROP TABLE t1; diff --git a/mysql-test/suite/storage_engine/analyze_table.test b/mysql-test/suite/storage_engine/analyze_table.test new file mode 100644 index 00000000000..5222ec8af54 --- /dev/null +++ b/mysql-test/suite/storage_engine/analyze_table.test @@ -0,0 +1,14 @@ +# +# ANALYZE TABLE statements +# +# Note: the output is likely to be different for the engine under test, +# in which case rdiff will be needed. Or, the output might say that +# the storage engine does not support ANALYZE. +# + +--source have_engine.inc + +--source analyze_table.inc + +--source cleanup_engine.inc + diff --git a/mysql-test/suite/storage_engine/autoinc_secondary.result b/mysql-test/suite/storage_engine/autoinc_secondary.result new file mode 100644 index 00000000000..ad2b43bc6fe --- /dev/null +++ b/mysql-test/suite/storage_engine/autoinc_secondary.result @@ -0,0 +1,40 @@ +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (a AUTO_INCREMENT, b , PRIMARY KEY (a,b)) ENGINE= ; +INSERT INTO t1 (b) VALUES ('a'),('b'),('b'),('c'),('a'); +SELECT LAST_INSERT_ID(); +LAST_INSERT_ID() +1 +SELECT * FROM t1; +a b +1 a +2 b +3 b +4 c +5 a +DROP TABLE t1; +CREATE TABLE t1 (a , b AUTO_INCREMENT, PRIMARY KEY (a,b)) ENGINE= ; +INSERT INTO t1 (a) VALUES ('a'),('b'),('b'),('c'),('a'); +SELECT LAST_INSERT_ID(); +LAST_INSERT_ID() +1 +SELECT * FROM t1; +a b +a 1 +a 2 +b 1 +b 2 +c 1 +DROP TABLE t1; +CREATE TABLE t1 (a , b AUTO_INCREMENT, PRIMARY KEY (a,b), (b)) ENGINE= ; +INSERT INTO t1 (a) VALUES ('a'),('b'),('b'),('c'),('a'); +SELECT LAST_INSERT_ID(); +LAST_INSERT_ID() +1 +SELECT * FROM t1; +a b +a 1 +a 5 +b 2 +b 3 +c 4 +DROP TABLE t1; diff --git a/mysql-test/suite/storage_engine/autoinc_secondary.test b/mysql-test/suite/storage_engine/autoinc_secondary.test new file mode 100644 index 00000000000..8b95f1d859e --- /dev/null +++ b/mysql-test/suite/storage_engine/autoinc_secondary.test @@ -0,0 +1,73 @@ +# +# AUTO_INCREMENT on a secondary column in a multi-part key +# + +--source have_engine.inc +--source have_default_index.inc + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +# +# AUTO_INCREMENT is the primary column in a multiple-column index +# + +--let $create_definition = a $int_col AUTO_INCREMENT, b $char_col, PRIMARY KEY (a,b) +--source create_table.inc +if ($mysql_errname) +{ + --let $functionality = Multi-part keys or PK or AUTO_INCREMENT (on a primary column) + --source unexpected_result.inc +} +if (!$mysql_errname) +{ + INSERT INTO t1 (b) VALUES ('a'),('b'),('b'),('c'),('a'); + SELECT LAST_INSERT_ID(); + --sorted_result + SELECT * FROM t1; + DROP TABLE t1; +} + +# +# AUTO_INCREMENT is the secondary column in a multiple-column index +# + +--let $create_definition = a $char_col, b $int_col AUTO_INCREMENT, PRIMARY KEY (a,b) +--source create_table.inc +if ($mysql_errname) +{ + --let $functionality = Multi-part keys or PK or AUTO_INCREMENT (on a secondary column) + --source unexpected_result.inc +} +if (!$mysql_errname) +{ + INSERT INTO t1 (a) VALUES ('a'),('b'),('b'),('c'),('a'); + SELECT LAST_INSERT_ID(); + --sorted_result + SELECT * FROM t1; + DROP TABLE t1; +} + +# AUTO_INCREMENT is the secondary column in a multiple-column index, +# and primary in another index +# + +--let $create_definition = a $char_col, b $int_indexed_col AUTO_INCREMENT, PRIMARY KEY (a,b), $default_index(b) +--source create_table.inc +if ($mysql_errname) +{ + --let $functionality = Multi-part keys or AUTO_INCREMENT (on the secondary column) or multiple keys + --source unexpected_result.inc +} +if (!$mysql_errname) +{ + INSERT INTO t1 (a) VALUES ('a'),('b'),('b'),('c'),('a'); + SELECT LAST_INSERT_ID(); + --sorted_result + SELECT * FROM t1; + DROP TABLE t1; +} + +--source cleanup_engine.inc + diff --git a/mysql-test/suite/storage_engine/autoinc_vars.result b/mysql-test/suite/storage_engine/autoinc_vars.result new file mode 100644 index 00000000000..60e7d74a22a --- /dev/null +++ b/mysql-test/suite/storage_engine/autoinc_vars.result @@ -0,0 +1,55 @@ +DROP TABLE IF EXISTS t1; +SET auto_increment_offset = 200; +CREATE TABLE t1 (a AUTO_INCREMENT, b , (a)) ENGINE= ; +INSERT INTO t1 (a,b) VALUES (NULL,'a'),(NULL,'b'),(NULL,'c'); +SELECT LAST_INSERT_ID(); +LAST_INSERT_ID() +1 +SELECT * FROM t1; +a b +1 a +2 b +3 c +SET auto_increment_increment = 300; +INSERT INTO t1 (a,b) VALUES (NULL,'d'),(NULL,'e'),(NULL,'f'); +SELECT LAST_INSERT_ID(); +LAST_INSERT_ID() +200 +SELECT * FROM t1; +a b +1 a +2 b +200 d +3 c +500 e +800 f +SET auto_increment_increment = 50; +INSERT INTO t1 (a,b) VALUES (NULL,'g'),(NULL,'h'),(NULL,'i'); +SELECT LAST_INSERT_ID(); +LAST_INSERT_ID() +850 +SELECT * FROM t1; +a b +1 a +2 b +200 d +3 c +500 e +800 f +850 g +900 h +950 i +DROP TABLE t1; +SET auto_increment_increment = 500; +SET auto_increment_offset = 300; +CREATE TABLE t1 (a TINYINT AUTO_INCREMENT, (a)) ENGINE= ; +INSERT INTO t1 (a) VALUES (NULL); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +SELECT LAST_INSERT_ID(); +LAST_INSERT_ID() +127 +SELECT * FROM t1; +a +127 +DROP TABLE t1; diff --git a/mysql-test/suite/storage_engine/autoinc_vars.test b/mysql-test/suite/storage_engine/autoinc_vars.test new file mode 100644 index 00000000000..ceafcd7138f --- /dev/null +++ b/mysql-test/suite/storage_engine/autoinc_vars.test @@ -0,0 +1,68 @@ +# +# auto-increment-offset and auto-increment-increment +# + +--source have_engine.inc +--source have_default_index.inc + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +# auto_increment_offset +SET auto_increment_offset = 200; +--let $create_definition = a $int_indexed_col AUTO_INCREMENT, b $char_col, $default_index(a) +--source create_table.inc +if ($mysql_errname) +{ + --let $functionality = AUTO_INCREMENT + --source unexpected_result.inc +} +if (!$mysql_errname) +{ + # If auto_increment_offset is greater than auto_increment_increment, + # the offset is ignored + INSERT INTO t1 (a,b) VALUES (NULL,'a'),(NULL,'b'),(NULL,'c'); + SELECT LAST_INSERT_ID(); + --sorted_result + SELECT * FROM t1; + + # auto_increment_increment + + SET auto_increment_increment = 300; + # offset should not be ignored anymore + INSERT INTO t1 (a,b) VALUES (NULL,'d'),(NULL,'e'),(NULL,'f'); + SELECT LAST_INSERT_ID(); + --sorted_result + SELECT * FROM t1; + + SET auto_increment_increment = 50; + INSERT INTO t1 (a,b) VALUES (NULL,'g'),(NULL,'h'),(NULL,'i'); + SELECT LAST_INSERT_ID(); + --sorted_result + SELECT * FROM t1; + DROP TABLE t1; +} + +# offset is greater than the max value + +SET auto_increment_increment = 500; +SET auto_increment_offset = 300; +--let $create_definition = a TINYINT $default_col_indexed_opts AUTO_INCREMENT, $default_index(a) +--source create_table.inc +if ($mysql_errname) +{ + --let $functionality = AUTO_INCREMENT + --source unexpected_result.inc +} +if (!$mysql_errname) +{ + INSERT INTO t1 (a) VALUES (NULL); + SELECT LAST_INSERT_ID(); + --sorted_result + SELECT * FROM t1; + DROP TABLE t1; +} + +--source cleanup_engine.inc + diff --git a/mysql-test/suite/storage_engine/autoincrement.result b/mysql-test/suite/storage_engine/autoincrement.result new file mode 100644 index 00000000000..bc51a2a82af --- /dev/null +++ b/mysql-test/suite/storage_engine/autoincrement.result @@ -0,0 +1,133 @@ +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (a AUTO_INCREMENT, b , (a)) ENGINE= ; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL AUTO_INCREMENT, + `b` char(8) DEFAULT NULL, + KEY `a` (`a`) +) ENGINE= DEFAULT CHARSET=latin1 +INSERT INTO t1 (b) VALUES ('a'),('b'); +SELECT * FROM t1 ORDER BY a; +a b +1 a +2 b +SELECT LAST_INSERT_ID(); +LAST_INSERT_ID() +1 +INSERT INTO t1 (a,b) VALUES (NULL,'c'),(0,'d'); +SELECT * FROM t1 ORDER BY a; +a b +1 a +2 b +3 c +4 d +SELECT LAST_INSERT_ID(); +LAST_INSERT_ID() +3 +SET sql_mode = 'NO_AUTO_VALUE_ON_ZERO'; +INSERT INTO t1 (a,b) VALUES (NULL,'e'); +SELECT * FROM t1 ORDER BY a; +a b +1 a +2 b +3 c +4 d +5 e +SELECT LAST_INSERT_ID(); +LAST_INSERT_ID() +5 +INSERT INTO t1 (a,b) VALUES (0,'f'); +SELECT * FROM t1 ORDER BY a; +a b +0 f +1 a +2 b +3 c +4 d +5 e +SELECT LAST_INSERT_ID(); +LAST_INSERT_ID() +5 +SET sql_mode = ''; +SHOW TABLE STATUS FROM test 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 # # # # # # # # 6 # # # # # # # +INSERT INTO t1 (a,b) VALUES (6,'g'),(7,'h'); +SELECT LAST_INSERT_ID(); +LAST_INSERT_ID() +5 +SHOW TABLE STATUS FROM test 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 # # # # # # # # # 8 # # # # # # # +INSERT INTO t1 (a,b) VALUES (NULL,'i'),(9,'j'); +SELECT * FROM t1 ORDER BY a; +a b +0 f +1 a +2 b +3 c +4 d +5 e +6 g +7 h +8 i +9 j +SELECT LAST_INSERT_ID(); +LAST_INSERT_ID() +8 +SHOW TABLE STATUS FROM test 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 # # # # # # # # # 10 # # # # # # # +INSERT INTO t1 (a,b) VALUES (20,'k'); +SHOW TABLE STATUS FROM test 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 # # # # # # # # # 21 # # # # # # # +INSERT INTO t1 (a,b) VALUES (NULL,'l'); +SELECT * FROM t1 ORDER BY a; +a b +0 f +1 a +2 b +3 c +4 d +5 e +6 g +7 h +8 i +9 j +20 k +21 l +SELECT LAST_INSERT_ID(); +LAST_INSERT_ID() +21 +SHOW TABLE STATUS FROM test 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 # # # # # # # # # 22 # # # # # # # +INSERT INTO t1 (a,b) VALUES (-5,'m'); +SELECT * FROM t1 ORDER BY a; +a b +-5 m +0 f +1 a +2 b +3 c +4 d +5 e +6 g +7 h +8 i +9 j +20 k +21 l +DROP TABLE t1; +CREATE TABLE t1 (a AUTO_INCREMENT, b , (a)) ENGINE= AUTO_INCREMENT = 100; +INSERT INTO t1 (a,b) VALUES (NULL,'a'),(NULL,'b'); +SELECT * FROM t1; +a b +100 a +101 b +SELECT LAST_INSERT_ID(); +LAST_INSERT_ID() +100 +DROP TABLE t1; diff --git a/mysql-test/suite/storage_engine/autoincrement.test b/mysql-test/suite/storage_engine/autoincrement.test new file mode 100644 index 00000000000..fb07ea55c57 --- /dev/null +++ b/mysql-test/suite/storage_engine/autoincrement.test @@ -0,0 +1,114 @@ +# +# Basic AUTO_INCREMENT capabilities +# + +--source have_engine.inc + +--let $skip = 1 +--source have_default_index.inc + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +--let $create_definition = a $int_indexed_col AUTO_INCREMENT, b $char_col, $default_index(a) +--source create_table.inc +if ($mysql_errname) +{ + --let $functionality = AUTO_INCREMENT + --source unexpected_result.inc +} +if (!$mysql_errname) +{ + --source mask_engine.inc + SHOW CREATE TABLE t1; + + # Automatic values + + INSERT INTO t1 (b) VALUES ('a'),('b'); + SELECT * FROM t1 ORDER BY a; + SELECT LAST_INSERT_ID(); + + INSERT INTO t1 (a,b) VALUES (NULL,'c'),(0,'d'); + SELECT * FROM t1 ORDER BY a; + SELECT LAST_INSERT_ID(); + + let $sql_mode = `SELECT @@sql_mode`; + SET sql_mode = 'NO_AUTO_VALUE_ON_ZERO'; + + INSERT INTO t1 (a,b) VALUES (NULL,'e'); + SELECT * FROM t1 ORDER BY a; + SELECT LAST_INSERT_ID(); + + INSERT INTO t1 (a,b) VALUES (0,'f'); + SELECT * FROM t1 ORDER BY a; + SELECT LAST_INSERT_ID(); + + --replace_result $sql_mode + eval SET sql_mode = '$sql_mode'; + + # SHOW TABLE STATUS shows the auto-increment value in column 11, + # that's all we need here and further + --source mask_engine.inc + --replace_column 3 # 4 # 5 # 6 # 7 # 8 # 9 # 10 # 12 # 13 # 14 # 15 # 16 # 17 # 18 # + SHOW TABLE STATUS FROM test LIKE 't1'; + + # Mix of automatic and explicit values + + INSERT INTO t1 (a,b) VALUES (6,'g'),(7,'h'); + SELECT LAST_INSERT_ID(); + + --replace_column 2 # 3 # 4 # 5 # 6 # 7 # 8 # 9 # 10 # 12 # 13 # 14 # 15 # 16 # 17 # 18 # + SHOW TABLE STATUS FROM test LIKE 't1'; + + + INSERT INTO t1 (a,b) VALUES (NULL,'i'),(9,'j'); + SELECT * FROM t1 ORDER BY a; + SELECT LAST_INSERT_ID(); + + --replace_column 2 # 3 # 4 # 5 # 6 # 7 # 8 # 9 # 10 # 12 # 13 # 14 # 15 # 16 # 17 # 18 # + SHOW TABLE STATUS FROM test LIKE 't1'; + + # Creating a gap in the sequence + + INSERT INTO t1 (a,b) VALUES (20,'k'); + + --replace_column 2 # 3 # 4 # 5 # 6 # 7 # 8 # 9 # 10 # 12 # 13 # 14 # 15 # 16 # 17 # 18 # + SHOW TABLE STATUS FROM test LIKE 't1'; + + INSERT INTO t1 (a,b) VALUES (NULL,'l'); + SELECT * FROM t1 ORDER BY a; + SELECT LAST_INSERT_ID(); + + --replace_column 2 # 3 # 4 # 5 # 6 # 7 # 8 # 9 # 10 # 12 # 13 # 14 # 15 # 16 # 17 # 18 # + SHOW TABLE STATUS FROM test LIKE 't1'; + + # Negative values: we will try to insert one just to check that it does not cause a crash, + # but won't check what happens to the sequence after that, since the behavior is undefined + + INSERT INTO t1 (a,b) VALUES (-5,'m'); + SELECT * FROM t1 ORDER BY a; + + DROP TABLE t1; +} + +# Autoincrement with table option AUTO_INCREMENT + +--let $create_definition = a $int_indexed_col AUTO_INCREMENT, b $char_col, $default_index(a) +--let $table_options = AUTO_INCREMENT = 100 +--source create_table.inc +if ($mysql_errname) +{ + --let $functionality = AUTO_INCREMENT column or table option + --source unexpected_result.inc +} +if (!$mysql_errname) +{ + INSERT INTO t1 (a,b) VALUES (NULL,'a'),(NULL,'b'); + --sorted_result + SELECT * FROM t1; + SELECT LAST_INSERT_ID(); + DROP TABLE t1; +} +--source cleanup_engine.inc + diff --git a/mysql-test/suite/storage_engine/cache_index.result b/mysql-test/suite/storage_engine/cache_index.result new file mode 100644 index 00000000000..c8cf0ce2090 --- /dev/null +++ b/mysql-test/suite/storage_engine/cache_index.result @@ -0,0 +1,69 @@ +DROP TABLE IF EXISTS t1, t2; +CREATE TABLE t1 (a , +b , + (a) +) ENGINE= ; +CREATE TABLE t2 (a , +b , + (b) +) ENGINE= ; +CACHE INDEX t1 INDEX (a), t2 IN ; +ERROR HY000: Unknown key cache '' +SET GLOBAL .key_buffer_size=128*1024; +CACHE INDEX t1 INDEX (a), t2 IN ; +Table Op Msg_type Msg_text +test.t1 assign_to_keycache status OK +test.t2 assign_to_keycache status OK +LOAD INDEX INTO CACHE t1, t2; +Table Op Msg_type Msg_text +test.t1 preload_keys status OK +test.t2 preload_keys status OK +INSERT INTO t1 (a,b) VALUES (3,'c'),(4,'d'); +SET GLOBAL .key_buffer_size=8*1024; +LOAD INDEX INTO CACHE t1, t2 IGNORE LEAVES; +Table Op Msg_type Msg_text +test.t1 preload_keys status OK +test.t2 preload_keys status OK +SET GLOBAL .key_cache_age_threshold = 100, .key_cache_block_size = 512, .key_cache_division_limit = 1, .key_cache_segments=2; +INSERT INTO t1 (a,b) VALUES (5,'e'),(6,'f'); +LOAD INDEX INTO CACHE t1; +Table Op Msg_type Msg_text +test.t1 preload_keys status OK +SET GLOBAL new_.key_buffer_size=128*1024; +CACHE INDEX t1 IN new_; +Table Op Msg_type Msg_text +test.t1 assign_to_keycache status OK +INSERT INTO t1 (a,b) VALUES (7,'g'),(8,'h'); +LOAD INDEX INTO CACHE t1 IGNORE LEAVES; +Table Op Msg_type Msg_text +test.t1 preload_keys status OK +INSERT INTO t1 (a,b) VALUES (9,'i'); +DROP TABLE t2; +DROP TABLE t1; +CREATE TABLE t1 (a , +b , + (a), + (b) +) ENGINE= ; +CACHE INDEX t1 IN ; +Table Op Msg_type Msg_text +test.t1 assign_to_keycache status OK +INSERT INTO t1 (a,b) VALUES (1,'a'),(2,'b'); +LOAD INDEX INTO CACHE t1; +Table Op Msg_type Msg_text +test.t1 preload_keys status OK +DROP TABLE t1; +CREATE TABLE t1 (a , +b , + a_b (a,b) +) ENGINE= ; +CACHE INDEX t1 IN ; +Table Op Msg_type Msg_text +test.t1 assign_to_keycache status OK +INSERT INTO t1 (a,b) VALUES (1,'a'),(2,'b'); +LOAD INDEX INTO CACHE t1; +Table Op Msg_type Msg_text +test.t1 preload_keys status OK +DROP TABLE t1; +SET GLOBAL .key_buffer_size=0; +SET GLOBAL new_.key_buffer_size=0; diff --git a/mysql-test/suite/storage_engine/cache_index.test b/mysql-test/suite/storage_engine/cache_index.test new file mode 100644 index 00000000000..42ba9615a40 --- /dev/null +++ b/mysql-test/suite/storage_engine/cache_index.test @@ -0,0 +1,142 @@ +# +# CACHE INDEX and LOAD INDEX INTO CACHE +# + +--source have_engine.inc +--source have_default_index.inc + + +# Due to ancient MySQL bug#16111 we need to generate a unique cache name +--let $cache_name = `SELECT CONNECTION_ID()` +--let $cache_name = my_cache_$cache_name + +--disable_warnings +DROP TABLE IF EXISTS t1, t2; +--enable_warnings + +let $create_definition = + a $int_indexed_col, + b $char_col, + $default_index (a) +; +--source create_table.inc +if ($mysql_errname) +{ + --let $functionality = Indexes on INT columns + --source unexpected_result.inc +} +if (!$mysql_errname) +{ + let $create_definition = + a $int_col, + b $char_indexed_col, + $default_index (b) + ; + let $table_name = t2; + --source create_table.inc + if ($mysql_errname) + { + --let $functionality = Indexes on CHAR columns + --source unexpected_result.inc + } + if (!$mysql_errname) + { + --replace_result $cache_name + --let $error_codes = ER_UNKNOWN_KEY_CACHE + eval CACHE INDEX t1 INDEX (a), t2 IN $cache_name; + --source check_errors.inc + if ($mysql_errname != ER_UNKNOWN_KEY_CACHE) + { + --let $functionality = Key cache or indexes + --source unexpected_result.inc + } + + --replace_result $cache_name + eval SET GLOBAL $cache_name.key_buffer_size=128*1024; + --replace_result $cache_name + eval CACHE INDEX t1 INDEX (a), t2 IN $cache_name; + if ($mysql_errname) + { + --let $functionality = Indexes + --source unexpected_result.inc + } + + LOAD INDEX INTO CACHE t1, t2; + if ($mysql_errname) + { + --let $functionality = Indexes + --source unexpected_result.inc + } + + INSERT INTO t1 (a,b) VALUES (3,'c'),(4,'d'); + --replace_result $cache_name + eval SET GLOBAL $cache_name.key_buffer_size=8*1024; + LOAD INDEX INTO CACHE t1, t2 IGNORE LEAVES; + + --replace_result $cache_name + eval SET GLOBAL $cache_name.key_cache_age_threshold = 100, $cache_name.key_cache_block_size = 512, $cache_name.key_cache_division_limit = 1, $cache_name.key_cache_segments=2; + INSERT INTO t1 (a,b) VALUES (5,'e'),(6,'f'); + LOAD INDEX INTO CACHE t1; + + --replace_result $cache_name + eval SET GLOBAL new_$cache_name.key_buffer_size=128*1024; + --replace_result $cache_name + eval CACHE INDEX t1 IN new_$cache_name; + INSERT INTO t1 (a,b) VALUES (7,'g'),(8,'h'); + LOAD INDEX INTO CACHE t1 IGNORE LEAVES; + INSERT INTO t1 (a,b) VALUES (9,'i'); + DROP TABLE t2; + } + DROP TABLE t1; +} + +let $create_definition = + a $int_indexed_col, + b $char_indexed_col, + $default_index (a), + $default_index (b) +; +--source create_table.inc +if ($mysql_errname) +{ + --let $functionality = Multiple keys or indexes on INT or CHAR columns + --source unexpected_result.inc +} +if (!$mysql_errname) +{ + --replace_result $cache_name + eval CACHE INDEX t1 IN $cache_name; + INSERT INTO t1 (a,b) VALUES (1,'a'),(2,'b'); + LOAD INDEX INTO CACHE t1; + + DROP TABLE t1; + let $create_definition = + a $int_indexed_col, + b $char_indexed_col, + $default_index a_b (a,b) + ; + --source create_table.inc + if ($mysql_errname) + { + --let $functionality = Multi-part keys + --source unexpected_result.inc + } + + --replace_result $cache_name + eval CACHE INDEX t1 IN $cache_name; + INSERT INTO t1 (a,b) VALUES (1,'a'),(2,'b'); + LOAD INDEX INTO CACHE t1; + + DROP TABLE t1; +} + +# Cleanup + +--replace_result $cache_name +eval SET GLOBAL $cache_name.key_buffer_size=0; +--replace_result $cache_name +eval SET GLOBAL new_$cache_name.key_buffer_size=0; + + +--source cleanup_engine.inc + diff --git a/mysql-test/suite/storage_engine/check_errors.inc b/mysql-test/suite/storage_engine/check_errors.inc new file mode 100644 index 00000000000..e38ff2962f1 --- /dev/null +++ b/mysql-test/suite/storage_engine/check_errors.inc @@ -0,0 +1,80 @@ +# +# Since we run tests in disable_abort_on_error mode, we cannot use --error command, +# and need to check the result manually. +# Usage in a test: +# --let $error_codes = # optional, default '' +# --let $mysql_errname = # optional, default current $mysql_errname (from the last SQL command) +# --let $mysql_errno = # optional, default current $mysql_errno (from the last SQL command) +# + +if ($error_codes == '0') +{ + --let $error_codes = +} +if ($error_codes == '') +{ + if ($mysql_errname) + { + --echo # ERROR: Statement ended with errno $mysql_errno, errname $mysql_errname (expected to succeed) + } + + # If both error_codes and mysql_errname are false, all is good, no logic needed +} + +if ($error_codes != '') +{ + # If mysql_errname or mysql_errno is equal to $error_codes, it's good too, nothing to do + + if ($mysql_errname != $error_codes) + { + if ($mysql_errno != $error_codes) + { + --let $save_errno = $mysql_errno + --let $save_errname = $mysql_errname + + --let $codeline = `SELECT CONCAT('\'',REPLACE('$error_codes',',','\',\''),'\'')` + --let $result = `SELECT '$save_errname' IN($codeline) or '$save_errno' IN ($codeline)` + + --let $mysql_errno = $save_errno + --let $mysql_errname = $save_errname + + if (!$result) + { + if ($mysql_errname) + { + --echo # ERROR: Statement ended with errno $mysql_errno, errname $mysql_errname (expected results: $error_codes) + } + if (!$mysql_errname) + { + --echo # ERROR: Statement succeeded (expected results: $error_codes) + } + } + # If a list contained more than one error, it could be on one of two reasons: + # first, we do not care which code it is, as long as it is one of the listed errors. + # In this case we will suggest to add an rdiff file if the message differs. + # Second, check_errors might be called from a generalized include file or test, + # which runs with different parameters and thus might produce different results for the same statement. + # Then, the message will be stricter, as the difference with the result file is actually a problem + # which needs to be checked at least. + if ($result) + { + if (!$strict_check) + { + --echo # Statement ended with one of expected results ($error_codes). + --echo # If you got a difference in error message, just add it to rdiff file + } + if ($strict_check) + { + --echo # WARNING: Statement ended with errno $mysql_errno, errname '$mysql_errname'. + --echo # If it differs from the result file, it might indicate a problem. + } + + } + } + } +} + +# Don't want the variables to be accidentally reused later +--let $error_codes = +--let $strict_check = + diff --git a/mysql-test/suite/storage_engine/check_table.inc b/mysql-test/suite/storage_engine/check_table.inc new file mode 100644 index 00000000000..54bdf511cb8 --- /dev/null +++ b/mysql-test/suite/storage_engine/check_table.inc @@ -0,0 +1,62 @@ +# +# CHECK TABLE statements +# +# Note: the output is likely to be different for the engine under test, +# in which case rdiff will be needed. Or, the output might say that +# the storage engine does not support CHECK. +# + +--disable_warnings +DROP TABLE IF EXISTS t1,t2; +--enable_warnings + +--let $create_definition = a $int_col, b $char_col +--source create_table.inc +INSERT INTO t1 (a,b) VALUES (1,'a'),(2,'b'); + +--let $table_name = t2 +--let $create_definition = a $int_col, b $char_col +--source create_table.inc + +CHECK TABLE t1; +INSERT INTO t1 (a,b) VALUES (3,'c'); +INSERT INTO t2 (a,b) VALUES (4,'d'); +CHECK TABLE t1, t2 FOR UPGRADE; +INSERT INTO t2 (a,b) VALUES (5,'e'); +CHECK TABLE t2 QUICK; +INSERT INTO t1 (a,b) VALUES (6,'f'); +CHECK TABLE t1 FAST; +INSERT INTO t1 (a,b) VALUES (7,'g'); +INSERT INTO t2 (a,b) VALUES (8,'h'); +CHECK TABLE t2, t1 MEDIUM; +INSERT INTO t1 (a,b) VALUES (9,'i'); +INSERT INTO t2 (a,b) VALUES (10,'j'); +CHECK TABLE t1, t2 EXTENDED; +INSERT INTO t1 (a,b) VALUES (11,'k'); +CHECK TABLE t1 CHANGED; + +DROP TABLE t1, t2; + +--let $continue = 1 +--source have_default_index.inc +if ($have_default_index) +{ + --let $create_definition = a $int_indexed_col, $default_index(a) + --source create_table.inc + INSERT INTO t1 (a) VALUES (1),(2),(5); + CHECK TABLE t1; + INSERT INTO t1 (a) VALUES (6),(8),(12); + CHECK TABLE t1 FOR UPGRADE; + INSERT INTO t1 (a) VALUES (13),(15),(16); + CHECK TABLE t1 QUICK; + INSERT INTO t1 (a) VALUES (17),(120),(132); + CHECK TABLE t1 FAST; + INSERT INTO t1 (a) VALUES (801),(900),(7714); + CHECK TABLE t1 MEDIUM; + INSERT INTO t1 (a) VALUES (8760),(10023),(12000); + CHECK TABLE t1 EXTENDED; + INSERT INTO t1 (a) VALUES (13345),(24456),(78302),(143028); + CHECK TABLE t1 CHANGED; + DROP TABLE t1; +} + diff --git a/mysql-test/suite/storage_engine/check_table.result b/mysql-test/suite/storage_engine/check_table.result new file mode 100644 index 00000000000..83c32778959 --- /dev/null +++ b/mysql-test/suite/storage_engine/check_table.result @@ -0,0 +1,68 @@ +DROP TABLE IF EXISTS t1,t2; +CREATE TABLE t1 (a , b ) ENGINE= ; +INSERT INTO t1 (a,b) VALUES (1,'a'),(2,'b'); +CREATE TABLE t2 (a , b ) ENGINE= ; +CHECK TABLE t1; +Table Op Msg_type Msg_text +test.t1 check status OK +INSERT INTO t1 (a,b) VALUES (3,'c'); +INSERT INTO t2 (a,b) VALUES (4,'d'); +CHECK TABLE t1, t2 FOR UPGRADE; +Table Op Msg_type Msg_text +test.t1 check status OK +test.t2 check status OK +INSERT INTO t2 (a,b) VALUES (5,'e'); +CHECK TABLE t2 QUICK; +Table Op Msg_type Msg_text +test.t2 check status OK +INSERT INTO t1 (a,b) VALUES (6,'f'); +CHECK TABLE t1 FAST; +Table Op Msg_type Msg_text +test.t1 check status OK +INSERT INTO t1 (a,b) VALUES (7,'g'); +INSERT INTO t2 (a,b) VALUES (8,'h'); +CHECK TABLE t2, t1 MEDIUM; +Table Op Msg_type Msg_text +test.t2 check status OK +test.t1 check status OK +INSERT INTO t1 (a,b) VALUES (9,'i'); +INSERT INTO t2 (a,b) VALUES (10,'j'); +CHECK TABLE t1, t2 EXTENDED; +Table Op Msg_type Msg_text +test.t1 check status OK +test.t2 check status OK +INSERT INTO t1 (a,b) VALUES (11,'k'); +CHECK TABLE t1 CHANGED; +Table Op Msg_type Msg_text +test.t1 check status OK +DROP TABLE t1, t2; +CREATE TABLE t1 (a , (a)) ENGINE= ; +INSERT INTO t1 (a) VALUES (1),(2),(5); +CHECK TABLE t1; +Table Op Msg_type Msg_text +test.t1 check status OK +INSERT INTO t1 (a) VALUES (6),(8),(12); +CHECK TABLE t1 FOR UPGRADE; +Table Op Msg_type Msg_text +test.t1 check status OK +INSERT INTO t1 (a) VALUES (13),(15),(16); +CHECK TABLE t1 QUICK; +Table Op Msg_type Msg_text +test.t1 check status OK +INSERT INTO t1 (a) VALUES (17),(120),(132); +CHECK TABLE t1 FAST; +Table Op Msg_type Msg_text +test.t1 check status OK +INSERT INTO t1 (a) VALUES (801),(900),(7714); +CHECK TABLE t1 MEDIUM; +Table Op Msg_type Msg_text +test.t1 check status OK +INSERT INTO t1 (a) VALUES (8760),(10023),(12000); +CHECK TABLE t1 EXTENDED; +Table Op Msg_type Msg_text +test.t1 check status OK +INSERT INTO t1 (a) VALUES (13345),(24456),(78302),(143028); +CHECK TABLE t1 CHANGED; +Table Op Msg_type Msg_text +test.t1 check status OK +DROP TABLE t1; diff --git a/mysql-test/suite/storage_engine/check_table.test b/mysql-test/suite/storage_engine/check_table.test new file mode 100644 index 00000000000..243c8e07161 --- /dev/null +++ b/mysql-test/suite/storage_engine/check_table.test @@ -0,0 +1,14 @@ +# +# CHECK TABLE statements +# +# Note: the output is likely to be different for the engine under test, +# in which case rdiff will be needed. Or, the output might say that +# the storage engine does not support CHECK. +# + +--source have_engine.inc + +--source check_table.inc + +--source cleanup_engine.inc + diff --git a/mysql-test/suite/storage_engine/checksum_table.inc b/mysql-test/suite/storage_engine/checksum_table.inc new file mode 100644 index 00000000000..d4bacce93b7 --- /dev/null +++ b/mysql-test/suite/storage_engine/checksum_table.inc @@ -0,0 +1,31 @@ +# +# CHECKSUM TABLE statements for standard CHECKSUM properties. +# Live checksums are covered in checksum_table_live.test +# + +--disable_warnings +DROP TABLE IF EXISTS t1,t2; +--enable_warnings + +# For most engines CHECKSUM=0 option will be ignored, +# but we are setting it here for those which have it 1 by default +# (there will be another test for live checksum) + +--let $table_options = CHECKSUM=0 +--let $create_definition = a $int_col, b $char_col +--source create_table.inc +INSERT INTO t1 (a,b) VALUES (1,'a'),(2,'b'); + +--let $table_name = t2 +--let $table_options = CHECKSUM=0 +--let $create_definition = a $int_col, b $char_col +--source create_table.inc + +CHECKSUM TABLE t1; +CHECKSUM TABLE t2, t1; +CHECKSUM TABLE t1, t2 QUICK; +CHECKSUM TABLE t1, t2 EXTENDED; + +DROP TABLE t1, t2; + + diff --git a/mysql-test/suite/storage_engine/checksum_table.result b/mysql-test/suite/storage_engine/checksum_table.result new file mode 100644 index 00000000000..02d70491fa9 --- /dev/null +++ b/mysql-test/suite/storage_engine/checksum_table.result @@ -0,0 +1,20 @@ +DROP TABLE IF EXISTS t1,t2; +CREATE TABLE t1 (a , b ) ENGINE= CHECKSUM=0; +INSERT INTO t1 (a,b) VALUES (1,'a'),(2,'b'); +CREATE TABLE t2 (a , b ) ENGINE= CHECKSUM=0; +CHECKSUM TABLE t1; +Table Checksum +test.t1 4272806499 +CHECKSUM TABLE t2, t1; +Table Checksum +test.t2 0 +test.t1 4272806499 +CHECKSUM TABLE t1, t2 QUICK; +Table Checksum +test.t1 NULL +test.t2 NULL +CHECKSUM TABLE t1, t2 EXTENDED; +Table Checksum +test.t1 4272806499 +test.t2 0 +DROP TABLE t1, t2; diff --git a/mysql-test/suite/storage_engine/checksum_table.test b/mysql-test/suite/storage_engine/checksum_table.test new file mode 100644 index 00000000000..5693e9a1ad3 --- /dev/null +++ b/mysql-test/suite/storage_engine/checksum_table.test @@ -0,0 +1,11 @@ +# +# CHECKSUM TABLE statements for standard CHECKSUM properties. +# Live checksums are covered in checksum_table_live.test +# + +--source have_engine.inc + +--source checksum_table.inc + +--source cleanup_engine.inc + diff --git a/mysql-test/suite/storage_engine/checksum_table_live.inc b/mysql-test/suite/storage_engine/checksum_table_live.inc new file mode 100644 index 00000000000..9614494e620 --- /dev/null +++ b/mysql-test/suite/storage_engine/checksum_table_live.inc @@ -0,0 +1,30 @@ +# +# CHECKSUM TABLE statements for live CHECKSUM. +# +# Note: the feature is likely to be unsupported, in which case +# instead of numeric values some CHECKSUMs will produce NULL +# + +--disable_warnings +DROP TABLE IF EXISTS t1,t2; +--enable_warnings + +# For most engines CHECKSUM=1 option will be ignored, +# and the results will be different + +--let $table_options = CHECKSUM=1 +--let $create_definition = a $int_col, b $char_col +--source create_table.inc +INSERT INTO t1 (a,b) VALUES (1,'a'),(2,'b'); +--let $table_name = t2 +--let $table_options = CHECKSUM=1 +--let $create_definition = a $int_col, b $char_col +--source create_table.inc + +CHECKSUM TABLE t1; +CHECKSUM TABLE t2, t1; +CHECKSUM TABLE t1, t2 QUICK; +CHECKSUM TABLE t1, t2 EXTENDED; + +DROP TABLE t1, t2; + diff --git a/mysql-test/suite/storage_engine/checksum_table_live.result b/mysql-test/suite/storage_engine/checksum_table_live.result new file mode 100644 index 00000000000..59ab8f1688a --- /dev/null +++ b/mysql-test/suite/storage_engine/checksum_table_live.result @@ -0,0 +1,20 @@ +DROP TABLE IF EXISTS t1,t2; +CREATE TABLE t1 (a , b ) ENGINE= CHECKSUM=1; +INSERT INTO t1 (a,b) VALUES (1,'a'),(2,'b'); +CREATE TABLE t2 (a , b ) ENGINE= CHECKSUM=1; +CHECKSUM TABLE t1; +Table Checksum +test.t1 4272806499 +CHECKSUM TABLE t2, t1; +Table Checksum +test.t2 0 +test.t1 4272806499 +CHECKSUM TABLE t1, t2 QUICK; +Table Checksum +test.t1 4272806499 +test.t2 0 +CHECKSUM TABLE t1, t2 EXTENDED; +Table Checksum +test.t1 4272806499 +test.t2 0 +DROP TABLE t1, t2; diff --git a/mysql-test/suite/storage_engine/checksum_table_live.test b/mysql-test/suite/storage_engine/checksum_table_live.test new file mode 100644 index 00000000000..347755f24df --- /dev/null +++ b/mysql-test/suite/storage_engine/checksum_table_live.test @@ -0,0 +1,13 @@ +# +# CHECKSUM TABLE statements for live CHECKSUM. +# +# Note: the feature is likely to be unsupported, in which case +# instead of numeric values some CHECKSUMs will produce NULL +# + +--source have_engine.inc + +--source checksum_table_live.inc + +--source cleanup_engine.inc + diff --git a/mysql-test/suite/storage_engine/cleanup_engine.inc b/mysql-test/suite/storage_engine/cleanup_engine.inc new file mode 100644 index 00000000000..de3d57eeaeb --- /dev/null +++ b/mysql-test/suite/storage_engine/cleanup_engine.inc @@ -0,0 +1,11 @@ +########################################### +# +# This is a stub of the include file cleanup_engine.inc which +# should be placed in storage//mysql-test/storage_engine folder. +# +################################ +# +# Here you can add whatever is needed to cleanup +# in case your define_engine.inc created any artefacts, +# e.g. an additional schema and/or tables. + diff --git a/mysql-test/suite/storage_engine/col_not_null.inc b/mysql-test/suite/storage_engine/col_not_null.inc new file mode 100644 index 00000000000..5f980b0a915 --- /dev/null +++ b/mysql-test/suite/storage_engine/col_not_null.inc @@ -0,0 +1,92 @@ +# +# NOT NULL attribute in columns +# +# Usage: +# let $col_definition = ; +# let $col_default = ; +# --source col_not_null.inc +# +# We will add NOT NULL at the end of $col; +# +# Also, if $col_default is defined, +# we will create a table with 2 columns +# (one with DEFAULT $col_default, and one without any default), +# and will also attempt to add a column with DEFAULT NULL. +# + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +--let $create_definition = c $col_definition NOT NULL +--source create_table.inc +if ($mysql_errname) +{ + --source unexpected_result.inc +} +if (!$mysql_errname) +{ + SHOW COLUMNS IN t1; + + --let $error_codes = ER_BAD_NULL_ERROR + INSERT INTO t1 (c) VALUES (NULL); + --source check_errors.inc + + DROP TABLE t1; +} + +if ($col_default != '') +{ + let $create_definition = + c $col_definition NOT NULL, + c2 $col_definition NOT NULL DEFAULT $col_default + ; + --source create_table.inc + if ($mysql_errname) + { + --source unexpected_result.inc + } + if (!$mysql_errname) + { + SHOW COLUMNS IN t1; + + --let $error_codes = ER_INVALID_DEFAULT + --let $alter_definition = ADD COLUMN err $col_definition NOT NULL DEFAULT NULL + --source alter_table.inc + if ($mysql_errname != ER_INVALID_DEFAULT) + { + --let $functionality = ALTER or DEFAULT + --source unexpected_result.inc + } + + --let $error_codes = ER_BAD_NULL_ERROR + INSERT INTO t1 (c) VALUES (NULL); + --source check_errors.inc + if ($mysql_errname != ER_BAD_NULL_ERROR) + { + --let $functionality = NOT NULL columns + --source unexpected_result.inc + } + + # HEX should be universal for all column types + SELECT HEX(c), HEX(c2) FROM t1; + + --let $error_codes = ER_BAD_NULL_ERROR + INSERT INTO t1 (c2) VALUES (NULL); + --source check_errors.inc + + --eval INSERT INTO t1 (c) VALUES ($col_default) + if ($mysql_errname) + { + --let $functionality = DEFAULT + --source unexpected_result.inc + } + SELECT COUNT(c), COUNT(c2) FROM t1; + + DROP TABLE t1; + } +} + +# We don't want to preserve it +let $col_default = ; + diff --git a/mysql-test/suite/storage_engine/col_null.inc b/mysql-test/suite/storage_engine/col_null.inc new file mode 100644 index 00000000000..6f74609869f --- /dev/null +++ b/mysql-test/suite/storage_engine/col_null.inc @@ -0,0 +1,65 @@ +# +# NULL attribute and DEFAULT NULL in columns +# +# Usage: +# let $col_definition = ; +# let $col_default = ; +# --source col_null.inc +# +# We will add NULL at the end of $col; +# +# Also, if $col_default is defined, +# we will create a table with 3 columns (one with DEFAULT NULL, +# one with DEFAULT $col_default, and one without any default) +# + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +--let $create_definition = c $col_definition NULL +--source create_table.inc +SHOW COLUMNS IN t1; +if ($mysql_errname) +{ + --source unexpected_result.inc +} +if (!$mysql_errname) +{ + INSERT INTO t1 (c) VALUES (NULL); + if ($mysql_errname) + { + --let $functionality = NULLable columns + --source unexpected_result.inc + } + SELECT COUNT(c), COUNT(*) FROM t1; + + DROP TABLE t1; +} + +if ($col_default != '') +{ + let $create_definition = + c $col_definition NULL, + c1 $col_definition NULL DEFAULT NULL, + c2 $col_definition NULL DEFAULT $col_default + ; + --source create_table.inc + if ($mysql_errname) + { + --source unexpected_result.inc + } + if (!$mysql_errname) + { + SHOW COLUMNS IN t1; + + INSERT INTO t1 (c) VALUES (NULL); + SELECT COUNT(c2), COUNT(c1), COUNT(c), COUNT(*) FROM t1; + + DROP TABLE t1; + } +} + +# We don't want to preserve it +let $col_default = ; + diff --git a/mysql-test/suite/storage_engine/col_opt_default.result b/mysql-test/suite/storage_engine/col_opt_default.result new file mode 100644 index 00000000000..2d0a8508b99 --- /dev/null +++ b/mysql-test/suite/storage_engine/col_opt_default.result @@ -0,0 +1,20 @@ +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (a DEFAULT '0') ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +a int(11) # 0 +INSERT INTO t1 (a) VALUES (1); +SELECT * FROM t1; +a +1 +ALTER TABLE t1 ADD COLUMN b DEFAULT ''; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +a int(11) # 0 +b char(8) # +INSERT INTO t1 (b) VALUES ('a'); +SELECT * FROM t1; +a b +0 a +1 +DROP TABLE t1; diff --git a/mysql-test/suite/storage_engine/col_opt_default.test b/mysql-test/suite/storage_engine/col_opt_default.test new file mode 100644 index 00000000000..f59daef37fc --- /dev/null +++ b/mysql-test/suite/storage_engine/col_opt_default.test @@ -0,0 +1,49 @@ +# +# Check whether DEFAULT column attribute +# is supported in CREATE and ALTER TABLE. +# If the attribute is supported at all, it will be covered +# in more details in col_option_null and col_option_not_null tests. +# + +--source have_engine.inc + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +--let $create_definition = a $int_col DEFAULT '0' +--source create_table.inc +if ($mysql_errname) +{ + --let $functionality = DEFAULT values + --source unexpected_result.inc +} +if (!$mysql_errname) +{ + --replace_column 3 # + SHOW COLUMNS IN t1; + + INSERT INTO t1 (a) VALUES (1); + --sorted_result + SELECT * FROM t1; + + --let $alter_definition = ADD COLUMN b $char_col DEFAULT '' + --source alter_table.inc + if ($mysql_errname) + { + --let $functionality = ALTER or DEFAULT + --source unexpected_result.inc + } + if (!$mysql_errname) + { + --replace_column 3 # + SHOW COLUMNS IN t1; + + INSERT INTO t1 (b) VALUES ('a'); + --sorted_result + SELECT * FROM t1; + } + DROP TABLE t1; +} +--source cleanup_engine.inc + diff --git a/mysql-test/suite/storage_engine/col_opt_not_null.result b/mysql-test/suite/storage_engine/col_opt_not_null.result new file mode 100644 index 00000000000..00a863fccce --- /dev/null +++ b/mysql-test/suite/storage_engine/col_opt_not_null.result @@ -0,0 +1,2062 @@ +# +# BINARY columns +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (b BINARY NOT NULL, +b0 BINARY(0) NOT NULL, +b1 BINARY(1) NOT NULL, +b20 BINARY(20) NOT NULL, +b255 BINARY(255) NOT NULL +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +b binary(1) # # # # +b0 binary(0) # # # # +b1 binary(1) # # # # +b20 binary(20) # # # # +b255 binary(255) # # # # +INSERT INTO t1 VALUES ('','','','',''); +INSERT INTO t1 VALUES ('a','','b','abcdefghi klmnopqrst', 'Creating an article for the Knowledgebase is similar to asking questions. First, navigate to the category where you feel the article should be. Once there, double check that an article doesn\'t already exist which would work.'); +SELECT HEX(b), HEX(b0), HEX(b1), HEX(b20), HEX(b255) FROM t1; +HEX(b) HEX(b0) HEX(b1) HEX(b20) HEX(b255) +00 00 0000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +61 62 616263646566676869206B6C6D6E6F7071727374 4372656174696E6720616E2061727469636C6520666F7220746865204B6E6F776C65646765626173652069732073696D696C617220746F2061736B696E67207175657374696F6E732E2046697273742C206E6176696761746520746F207468652063617465676F727920776865726520796F75206665656C207468652061727469636C652073686F756C642062652E204F6E63652074686572652C20646F75626C6520636865636B207468617420616E2061727469636C6520646F65736E277420616C726561647920657869737420776869636820776F756C6420776F726B2E00000000000000000000000000000000000000000000000000000000000000 +INSERT INTO t1 VALUES ('abc', 'a', 'abc', REPEAT('a',21), REPEAT('x',256)); +Warnings: +Warning 1265 Data truncated for column 'b' at row 1 +Warning 1265 Data truncated for column 'b0' at row 1 +Warning 1265 Data truncated for column 'b1' at row 1 +Warning 1265 Data truncated for column 'b20' at row 1 +Warning 1265 Data truncated for column 'b255' at row 1 +INSERT INTO t1 SELECT b255, b255, b255, b255, CONCAT(b255,b255) FROM t1; +Warnings: +Warning 1265 Data truncated for column 'b' at row 1 +Warning 1265 Data truncated for column 'b0' at row 1 +Warning 1265 Data truncated for column 'b1' at row 1 +Warning 1265 Data truncated for column 'b20' at row 1 +Warning 1265 Data truncated for column 'b255' at row 1 +Warning 1265 Data truncated for column 'b' at row 2 +Warning 1265 Data truncated for column 'b0' at row 2 +Warning 1265 Data truncated for column 'b1' at row 2 +Warning 1265 Data truncated for column 'b20' at row 2 +Warning 1265 Data truncated for column 'b255' at row 2 +Warning 1265 Data truncated for column 'b' at row 3 +Warning 1265 Data truncated for column 'b0' at row 3 +Warning 1265 Data truncated for column 'b1' at row 3 +Warning 1265 Data truncated for column 'b20' at row 3 +Warning 1265 Data truncated for column 'b255' at row 3 +SELECT HEX(b), HEX(b0), HEX(b1), HEX(b20), HEX(b255) FROM t1; +HEX(b) HEX(b0) HEX(b1) HEX(b20) HEX(b255) +00 00 0000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00 00 0000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +43 43 4372656174696E6720616E2061727469636C6520 4372656174696E6720616E2061727469636C6520666F7220746865204B6E6F776C65646765626173652069732073696D696C617220746F2061736B696E67207175657374696F6E732E2046697273742C206E6176696761746520746F207468652063617465676F727920776865726520796F75206665656C207468652061727469636C652073686F756C642062652E204F6E63652074686572652C20646F75626C6520636865636B207468617420616E2061727469636C6520646F65736E277420616C726561647920657869737420776869636820776F756C6420776F726B2E00000000000000000000000000000000000000000000000000000000000000 +61 61 6161616161616161616161616161616161616161 787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878 +61 62 616263646566676869206B6C6D6E6F7071727374 4372656174696E6720616E2061727469636C6520666F7220746865204B6E6F776C65646765626173652069732073696D696C617220746F2061736B696E67207175657374696F6E732E2046697273742C206E6176696761746520746F207468652063617465676F727920776865726520796F75206665656C207468652061727469636C652073686F756C642062652E204F6E63652074686572652C20646F75626C6520636865636B207468617420616E2061727469636C6520646F65736E277420616C726561647920657869737420776869636820776F756C6420776F726B2E00000000000000000000000000000000000000000000000000000000000000 +78 78 7878787878787878787878787878787878787878 787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878 +ALTER TABLE t1 ADD COLUMN b257 BINARY(257) NOT NULL; +ERROR 42000: Column length too big for column 'b257' (max = 255); use BLOB or TEXT instead +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +b binary(1) # # # # +b0 binary(0) # # # # +b1 binary(1) # # # # +b20 binary(20) # # # # +b255 binary(255) # # # # +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c BINARY NOT NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c binary(1) NO NULL +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +DROP TABLE t1; +CREATE TABLE t1 (c BINARY NOT NULL, +c2 BINARY NOT NULL DEFAULT 0 +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c binary(1) NO NULL +c2 binary(1) NO 0 +ALTER TABLE t1 ADD COLUMN err BINARY NOT NULL DEFAULT NULL; +ERROR 42000: Invalid default value for 'err' +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +SELECT HEX(c), HEX(c2) FROM t1; +HEX(c) HEX(c2) +INSERT INTO t1 (c2) VALUES (NULL); +ERROR 23000: Column 'c2' cannot be null +INSERT INTO t1 (c) VALUES (0); +SELECT COUNT(c), COUNT(c2) FROM t1; +COUNT(c) COUNT(c2) +1 1 +DROP TABLE t1; +# +# VARBINARY columns +# +DROP TABLE IF EXISTS t1, t2; +CREATE TABLE t1 (v0 VARBINARY(0) NOT NULL, +v1 VARBINARY(1) NOT NULL, +v64 VARBINARY(64) NOT NULL, +v65000 VARBINARY(65000) NOT NULL +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +v0 varbinary(0) # # # +v1 varbinary(1) # # # +v64 varbinary(64) # # # +v65000 varbinary(65000) # # # +CREATE TABLE t2 (v VARBINARY(65532) NOT NULL) ENGINE= ; +SHOW COLUMNS IN t2; +Field Type Null Key Default Extra +v varbinary(65532) # # # +INSERT INTO t1 (v0,v1,v64,v65000) VALUES ('','','',''); +INSERT INTO t1 (v0,v1,v64,v65000) VALUES ('','y','Once there, double check that an article doesn\'t already exist','Here is a list of recommended books on MariaDB and MySQL. We\'ve provided links to Amazon.com here for convenience, but they can be found at many other bookstores, both online and off. + + If you want to have your favorite MySQL / MariaDB book listed here, please leave a comment. + For developers who want to code on MariaDB or MySQL + + * Understanding MySQL Internals by Sasha Pachev, former MySQL developer at MySQL AB. + o This is the only book we know about that describes the internals of MariaDB / MySQL. A must have for anyone who wants to understand and develop on MariaDB! + o Not all topics are covered and some parts are slightly outdated, but still the best book on this topic. + * MySQL 5.1 Plugin Development by Sergei Golubchik and Andrew Hutchings + o A must read for anyone wanting to write a plugin for MariaDB, written by the Sergei who designed the plugin interface for MySQL and MariaDB! + + For MariaDB / MySQL end users + + * MariaDB Crash Course by Ben Forta + o First MariaDB book! + o For people who want to learn SQL and the basics of MariaDB. + o Now shipping. Purchase at Amazon.com or your favorite bookseller. + + * SQL-99 Complete, Really by Peter Gulutzan & Trudy Pelzer. + o Everything you wanted to know about the SQL 99 standard. Excellent reference book! + o Free to read in the Knowledgebase! + + * MySQL (4th Edition) by Paul DuBois + o The \'default\' book to read if you wont to learn to use MySQL / MariaDB. + + * MySQL Cookbook by Paul DuBois + o A lot of examples of how to use MySQL. As with all of Paul\'s books, it\'s worth its weight in gold and even enjoyable reading for such a \'dry\' subject. + + * High Performance MySQL, Second Edition, By Baron Schwartz, Peter Zaitsev, Vadim Tkachenko, Jeremy D. Zawodny, Arjen Lentz, Derek J. Balling, et al. + o \"High Performance MySQL is the definitive guide to building fast, reliable systems with MySQL. Written by noted experts with years of real-world experience building very large systems, this book covers every aspect of MySQL performance in detail, and focuses on robustness, security, and data integrity. Learn advanced techniques in depth so you can bring out MySQL\'s full power.\" (From the book description at O\'Reilly) + + * MySQL Admin Cookbook + o A quick step-by-step guide for MySQL users and database administrators to tackle real-world challenges with MySQL configuration and administration + + * MySQL 5.0 Certification Study Guide, By Paul DuBois, Stefan Hinz, Carsten Pedersen + o This is the official guide to cover the passing of the two MySQL Certification examinations. It is valid till version 5.0 of the server, so while it misses all the features available in MySQL 5.1 and greater (including MariaDB 5.1 and greater), it provides a good basic understanding of MySQL for the end-user. '); +SELECT HEX(v0), HEX(v1), HEX(v64), HEX(v65000) FROM t1; +HEX(v0) HEX(v1) HEX(v64) HEX(v65000) + + 79 4F6E63652074686572652C20646F75626C6520636865636B207468617420616E2061727469636C6520646F65736E277420616C7265616479206578697374 486572652069732061206C697374206F66207265636F6D6D656E64656420626F6F6B73206F6E204D61726961444220616E64204D7953514C2E2057652776652070726F7669646564206C696E6B7320746F20416D617A6F6E2E636F6D206865726520666F7220636F6E76656E69656E63652C2062757420746865792063616E20626520666F756E64206174206D616E79206F7468657220626F6F6B73746F7265732C20626F7468206F6E6C696E6520616E64206F66662E0A0A2020496620796F752077616E7420746F206861766520796F7572206661766F72697465204D7953514C202F204D61726961444220626F6F6B206C697374656420686572652C20706C65617365206C65617665206120636F6D6D656E742E0A2020466F7220646576656C6F706572732077686F2077616E7420746F20636F6465206F6E204D617269614442206F72204D7953514C0A0A2020202020202A20556E6465727374616E64696E67204D7953514C20496E7465726E616C73206279205361736861205061636865762C20666F726D6572204D7953514C20646576656C6F706572206174204D7953514C2041422E0A2020202020202020202020206F205468697320697320746865206F6E6C7920626F6F6B207765206B6E6F772061626F75742074686174206465736372696265732074686520696E7465726E616C73206F66204D617269614442202F204D7953514C2E2041206D757374206861766520666F7220616E796F6E652077686F2077616E747320746F20756E6465727374616E6420616E6420646576656C6F70206F6E204D617269614442210A2020202020202020202020206F204E6F7420616C6C20746F706963732061726520636F766572656420616E6420736F6D652070617274732061726520736C696768746C79206F757464617465642C20627574207374696C6C20746865206265737420626F6F6B206F6E207468697320746F7069632E200A2020202020202A204D7953514C20352E3120506C7567696E20446576656C6F706D656E742062792053657267656920476F6C75626368696B20616E6420416E64726577204875746368696E67730A2020202020202020202020206F2041206D757374207265616420666F7220616E796F6E652077616E74696E6720746F207772697465206120706C7567696E20666F72204D6172696144422C207772697474656E20627920746865205365726765692077686F2064657369676E65642074686520706C7567696E20696E7465726661636520666F72204D7953514C20616E64204D61726961444221200A0A2020466F72204D617269614442202F204D7953514C20656E642075736572730A0A2020202020202A204D61726961444220437261736820436F757273652062792042656E20466F7274610A2020202020202020202020206F204669727374204D61726961444220626F6F6B210A2020202020202020202020206F20466F722070656F706C652077686F2077616E7420746F206C6561726E2053514C20616E642074686520626173696373206F66204D6172696144422E0A2020202020202020202020206F204E6F77207368697070696E672E20507572636861736520617420416D617A6F6E2E636F6D206F7220796F7572206661766F7269746520626F6F6B73656C6C65722E200A0A2020202020202A2053514C2D393920436F6D706C6574652C205265616C6C792062792050657465722047756C75747A616E20262054727564792050656C7A65722E0A2020202020202020202020206F2045766572797468696E6720796F752077616E74656420746F206B6E6F772061626F7574207468652053514C203939207374616E646172642E20457863656C6C656E74207265666572656E636520626F6F6B210A2020202020202020202020206F204672656520746F207265616420696E20746865204B6E6F776C656467656261736521200A0A2020202020202A204D7953514C20283474682045646974696F6E29206279205061756C204475426F69730A2020202020202020202020206F20546865202764656661756C742720626F6F6B20746F207265616420696620796F7520776F6E7420746F206C6561726E20746F20757365204D7953514C202F204D6172696144422E200A0A2020202020202A204D7953514C20436F6F6B626F6F6B206279205061756C204475426F69730A2020202020202020202020206F2041206C6F74206F66206578616D706C6573206F6620686F7720746F20757365204D7953514C2E204173207769746820616C6C206F66205061756C277320626F6F6B732C206974277320776F727468206974732077656967687420696E20676F6C6420616E64206576656E20656E6A6F7961626C652072656164696E6720666F7220737563682061202764727927207375626A6563742E200A0A2020202020202A204869676820506572666F726D616E6365204D7953514C2C205365636F6E642045646974696F6E2C204279204261726F6E20536368776172747A2C205065746572205A6169747365762C20566164696D20546B616368656E6B6F2C204A6572656D7920442E205A61776F646E792C2041726A656E204C656E747A2C20446572656B204A2E2042616C6C696E672C20657420616C2E0A2020202020202020202020206F20224869676820506572666F726D616E6365204D7953514C2069732074686520646566696E697469766520677569646520746F206275696C64696E6720666173742C2072656C6961626C652073797374656D732077697468204D7953514C2E205772697474656E206279206E6F74656420657870657274732077697468207965617273206F66207265616C2D776F726C6420657870657269656E6365206275696C64696E672076657279206C617267652073797374656D732C207468697320626F6F6B20636F7665727320657665727920617370656374206F66204D7953514C20706572666F726D616E636520696E2064657461696C2C20616E6420666F6375736573206F6E20726F627573746E6573732C2073656375726974792C20616E64206461746120696E746567726974792E204C6561726E20616476616E63656420746563686E697175657320696E20646570746820736F20796F752063616E206272696E67206F7574204D7953514C27732066756C6C20706F7765722E22202846726F6D2074686520626F6F6B206465736372697074696F6E206174204F275265696C6C7929200A0A2020202020202A204D7953514C2041646D696E20436F6F6B626F6F6B0A2020202020202020202020206F204120717569636B20737465702D62792D7374657020677569646520666F72204D7953514C20757365727320616E642064617461626173652061646D696E6973747261746F727320746F207461636B6C65207265616C2D776F726C64206368616C6C656E6765732077697468204D7953514C20636F6E66696775726174696F6E20616E642061646D696E697374726174696F6E200A0A2020202020202A204D7953514C20352E302043657274696669636174696F6E2053747564792047756964652C204279205061756C204475426F69732C2053746566616E2048696E7A2C204361727374656E20506564657273656E0A2020202020202020202020206F205468697320697320746865206F6666696369616C20677569646520746F20636F766572207468652070617373696E67206F66207468652074776F204D7953514C2043657274696669636174696F6E206578616D696E6174696F6E732E2049742069732076616C69642074696C6C2076657273696F6E20352E30206F6620746865207365727665722C20736F207768696C65206974206D697373657320616C6C2074686520666561747572657320617661696C61626C6520696E204D7953514C20352E3120616E6420677265617465722028696E636C7564696E67204D61726961444220352E3120616E642067726561746572292C2069742070726F7669646573206120676F6F6420626173696320756E6465727374616E64696E67206F66204D7953514C20666F722074686520656E642D757365722E20 +INSERT INTO t1 (v0,v1,v64,v65000) VALUES ('y', 'yy', REPEAT('c',65), REPEAT('abcdefghi ',6501)); +Warnings: +Warning 1265 Data truncated for column 'v0' at row 1 +Warning 1265 Data truncated for column 'v1' at row 1 +Warning 1265 Data truncated for column 'v64' at row 1 +Warning 1265 Data truncated for column 'v65000' at row 1 +INSERT INTO t1 (v0,v1,v64,v65000) SELECT v65000, v65000, v65000, CONCAT(v65000,v1) FROM t1; +Warnings: +Warning 1265 Data truncated for column 'v0' at row 2 +Warning 1265 Data truncated for column 'v1' at row 2 +Warning 1265 Data truncated for column 'v64' at row 2 +Warning 1265 Data truncated for column 'v0' at row 3 +Warning 1265 Data truncated for column 'v1' at row 3 +Warning 1265 Data truncated for column 'v64' at row 3 +Warning 1265 Data truncated for column 'v65000' at row 3 +SELECT HEX(v0), HEX(v1), HEX(v64), LENGTH(HEX(v65000)) FROM t1; +HEX(v0) HEX(v1) HEX(v64) LENGTH(HEX(v65000)) + 0 + 0 + 48 486572652069732061206C697374206F66207265636F6D6D656E64656420626F6F6B73206F6E204D61726961444220616E64204D7953514C2E20576527766520 5932 + 61 61626364656667686920616263646566676869206162636465666768692061626364656667686920616263646566676869206162636465666768692061626364 130000 + 79 4F6E63652074686572652C20646F75626C6520636865636B207468617420616E2061727469636C6520646F65736E277420616C7265616479206578697374 5930 + 79 63636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363 130000 +ALTER TABLE t1 ADD COLUMN v65536 VARBINARY(65536) NOT NULL; +Warnings: +Note 1246 Converting column 'v65536' from VARBINARY to BLOB +Note 1246 Converting column 'v65536' from VARBINARY to BLOB +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +v0 varbinary(0) # # # +v1 varbinary(1) # # # +v64 varbinary(64) # # # +v65000 varbinary(65000) # # # +v65536 mediumblob # # # +DROP TABLE t1, t2; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c VARBINARY(64) NOT NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c varbinary(64) NO NULL +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +DROP TABLE t1; +CREATE TABLE t1 (c VARBINARY(64) NOT NULL, +c2 VARBINARY(64) NOT NULL DEFAULT 'test' +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c varbinary(64) NO NULL +c2 varbinary(64) NO test +ALTER TABLE t1 ADD COLUMN err VARBINARY(64) NOT NULL DEFAULT NULL; +ERROR 42000: Invalid default value for 'err' +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +SELECT HEX(c), HEX(c2) FROM t1; +HEX(c) HEX(c2) +INSERT INTO t1 (c2) VALUES (NULL); +ERROR 23000: Column 'c2' cannot be null +INSERT INTO t1 (c) VALUES ('test'); +SELECT COUNT(c), COUNT(c2) FROM t1; +COUNT(c) COUNT(c2) +1 1 +DROP TABLE t1; +# +# BIT columns +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (a BIT NOT NULL, +b BIT(20) NOT NULL, +c BIT(64) NOT NULL, +d BIT(1) NOT NULL +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +a bit(1) # # # +b bit(20) # # # +c bit(64) # # # +d bit(1) # # # +ALTER TABLE t1 DROP COLUMN d; +ALTER TABLE t1 ADD COLUMN d BIT(0) NOT NULL; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +a bit(1) # # # +b bit(20) # # # +c bit(64) # # # +d bit(1) # # # +INSERT INTO t1 VALUES (0,POW(2,20)-1,b'1111111111111111111111111111111111111111111111111111111111111111',1); +SELECT BIN(a), HEX(b), c+0 FROM t1 WHERE d>0; +BIN(a) HEX(b) c+0 +0 FFFFF 18446744073709551615 +INSERT INTO t1 VALUES (1,0,-1,0); +SELECT a+0, b+0, c+0 FROM t1 WHERE d<100; +a+0 b+0 c+0 +0 1048575 18446744073709551615 +1 0 18446744073709551615 +INSERT INTO t1 VALUES (b'1', 'f', 0xFF, 0x0); +SELECT a+0, b+0, c+0 FROM t1 WHERE d IN (0, 2); +a+0 b+0 c+0 +1 0 18446744073709551615 +1 102 255 +INSERT INTO t1 VALUES (0x10,0,0,1); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +SELECT * FROM t1; +a b c d +INSERT INTO t1 VALUES (0x01,0,0x10000000000000000,0); +Warnings: +Warning 1264 Out of range value for column 'c' at row 1 +SELECT * FROM t1; +a b c d +DROP TABLE t1; +CREATE TABLE t1 (a BIT(65) NOT NULL) ENGINE= ; +ERROR 42000: Display width out of range for 'a' (max = 64) +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c BIT NOT NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c bit(1) NO NULL +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +DROP TABLE t1; +CREATE TABLE t1 (c BIT NOT NULL, +c2 BIT NOT NULL DEFAULT 1 +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c bit(1) NO NULL +c2 bit(1) NO b'1' +ALTER TABLE t1 ADD COLUMN err BIT NOT NULL DEFAULT NULL; +ERROR 42000: Invalid default value for 'err' +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +SELECT HEX(c), HEX(c2) FROM t1; +HEX(c) HEX(c2) +INSERT INTO t1 (c2) VALUES (NULL); +ERROR 23000: Column 'c2' cannot be null +INSERT INTO t1 (c) VALUES (1); +SELECT COUNT(c), COUNT(c2) FROM t1; +COUNT(c) COUNT(c2) +1 1 +DROP TABLE t1; +# +# BLOB columns +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (b BLOB NOT NULL, +b0 BLOB(0) NOT NULL, +b1 BLOB(1) NOT NULL, +b300 BLOB(300) NOT NULL, +bm BLOB(65535) NOT NULL, +b70k BLOB(70000) NOT NULL, +b17m BLOB(17000000) NOT NULL, +t TINYBLOB NOT NULL, +m MEDIUMBLOB NOT NULL, +l LONGBLOB NOT NULL +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +b blob # # # +b0 blob # # # +b1 tinyblob # # # +b300 blob # # # +bm blob # # # +b70k mediumblob # # # +b17m longblob # # # +t tinyblob # # # +m mediumblob # # # +l longblob # # # +INSERT INTO t1 VALUES +('','','','','','','','','',''), +('a','b','c','d','e','f','g','h','i','j'), +('test1','test2','test3','test4','test5','test6','test7','test8','test9','test10'), +( REPEAT('a',65535), REPEAT('b',65535), REPEAT('c',255), REPEAT('d',65535), REPEAT('e',65535), REPEAT('f',1048576), HEX(REPEAT('g',1048576)), REPEAT('h',255), REPEAT('i',1048576), HEX(REPEAT('j',1048576)) ); +SELECT LENGTH(b), LENGTH(b0), LENGTH(b1), LENGTH(b300), LENGTH(bm), LENGTH(b70k), LENGTH(b17m), LENGTH(t), LENGTH(m), LENGTH(l) FROM t1; +LENGTH(b) LENGTH(b0) LENGTH(b1) LENGTH(b300) LENGTH(bm) LENGTH(b70k) LENGTH(b17m) LENGTH(t) LENGTH(m) LENGTH(l) +0 0 0 0 0 0 0 0 0 0 +1 1 1 1 1 1 1 1 1 1 +5 5 5 5 5 5 5 5 5 6 +65535 65535 255 65535 65535 1048576 2097152 255 1048576 2097152 +INSERT INTO t1 VALUES +( REPEAT('a',65536), REPEAT('b',65536), REPEAT('c',256), REPEAT('d',65536), REPEAT('e',65536), REPEAT('f',1048576), REPEAT('g',1048576), REPEAT('h',256), REPEAT('i',1048576), REPEAT('j',1048576) ); +Warnings: +Warning 1265 Data truncated for column 'b' at row 1 +Warning 1265 Data truncated for column 'b0' at row 1 +Warning 1265 Data truncated for column 'b1' at row 1 +Warning 1265 Data truncated for column 'b300' at row 1 +Warning 1265 Data truncated for column 'bm' at row 1 +Warning 1265 Data truncated for column 't' at row 1 +SELECT LENGTH(b), LENGTH(b0), LENGTH(b1), LENGTH(b300), LENGTH(bm), LENGTH(b70k), LENGTH(b17m), LENGTH(t), LENGTH(m), LENGTH(l) FROM t1; +LENGTH(b) LENGTH(b0) LENGTH(b1) LENGTH(b300) LENGTH(bm) LENGTH(b70k) LENGTH(b17m) LENGTH(t) LENGTH(m) LENGTH(l) +0 0 0 0 0 0 0 0 0 0 +1 1 1 1 1 1 1 1 1 1 +5 5 5 5 5 5 5 5 5 6 +65535 65535 255 65535 65535 1048576 1048576 255 1048576 1048576 +65535 65535 255 65535 65535 1048576 2097152 255 1048576 2097152 +ALTER TABLE t1 ADD COLUMN bbb BLOB(4294967296); +ERROR 42000: Display width out of range for 'bbb' (max = 4294967295) +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c BLOB NOT NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c blob NO NULL +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c TINYBLOB NOT NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c tinyblob NO NULL +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c MEDIUMBLOB NOT NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c mediumblob NO NULL +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c LONGBLOB NOT NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c longblob NO NULL +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +DROP TABLE t1; +# +# BOOL columns +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (b1 BOOL NOT NULL, +b2 BOOLEAN NOT NULL +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +b1 tinyint(1) # # # +b2 tinyint(1) # # # +INSERT INTO t1 VALUES (1,TRUE); +SELECT * FROM t1; +b1 b2 +1 1 +INSERT INTO t1 VALUES (FALSE,0); +SELECT * FROM t1; +b1 b2 +0 0 +1 1 +INSERT INTO t1 VALUES (2,3); +SELECT * FROM t1; +b1 b2 +0 0 +1 1 +2 3 +INSERT INTO t1 VALUES (-1,-2); +SELECT * FROM t1; +b1 b2 +-1 -2 +0 0 +1 1 +2 3 +SELECT IF(b1,'true','false') AS a, IF(b2,'true','false') AS b FROM t1; +a b +false false +true true +true true +true true +SELECT * FROM t1 WHERE b1 = TRUE; +b1 b2 +1 1 +SELECT * FROM t1 WHERE b2 = FALSE; +b1 b2 +0 0 +INSERT INTO t1 VALUES ('a','b'); +Warnings: +Warning 1366 Incorrect integer value: 'a' for column 'b1' at row 1 +Warning 1366 Incorrect integer value: 'b' for column 'b2' at row 1 +SELECT * FROM t1; +b1 b2 +-1 -2 +0 0 +0 0 +1 1 +2 3 +INSERT INTO t1 VALUES (128,-129); +Warnings: +Warning 1264 Out of range value for column 'b1' at row 1 +Warning 1264 Out of range value for column 'b2' at row 1 +SELECT * FROM t1; +b1 b2 +-1 -2 +0 0 +0 0 +1 1 +127 -128 +2 3 +ALTER TABLE t1 ADD COLUMN b3 BOOLEAN UNSIGNED; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'UNSIGNED' at line 1 +ALTER TABLE t1 ADD COLUMN b3 BOOL ZEROFILL; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'ZEROFILL' at line 1 +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c BOOL NOT NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c tinyint(1) NO NULL +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +DROP TABLE t1; +CREATE TABLE t1 (c BOOL NOT NULL, +c2 BOOL NOT NULL DEFAULT '0' +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c tinyint(1) NO NULL +c2 tinyint(1) NO 0 +ALTER TABLE t1 ADD COLUMN err BOOL NOT NULL DEFAULT NULL; +ERROR 42000: Invalid default value for 'err' +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +SELECT HEX(c), HEX(c2) FROM t1; +HEX(c) HEX(c2) +INSERT INTO t1 (c2) VALUES (NULL); +ERROR 23000: Column 'c2' cannot be null +INSERT INTO t1 (c) VALUES ('0'); +SELECT COUNT(c), COUNT(c2) FROM t1; +COUNT(c) COUNT(c2) +1 1 +DROP TABLE t1; +# +# CHAR columns +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c CHAR NOT NULL, +c0 CHAR(0) NOT NULL, +c1 CHAR(1) NOT NULL, +c20 CHAR(20) NOT NULL, +c255 CHAR(255) NOT NULL +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c char(1) # # # +c0 char(0) # # # +c1 char(1) # # # +c20 char(20) # # # +c255 char(255) # # # +INSERT INTO t1 VALUES ('','','','',''); +INSERT INTO t1 VALUES ('a','','b','abcdefghi klmnopqrst', 'Creating an article for the Knowledgebase is similar to asking questions. First, navigate to the category where you feel the article should be. Once there, double check that an article doesn\'t already exist which would work.'); +SELECT * FROM t1; +c c0 c1 c20 c255 + +a b abcdefghi klmnopqrst Creating an article for the Knowledgebase is similar to asking questions. First, navigate to the category where you feel the article should be. Once there, double check that an article doesn't already exist which would work. +INSERT INTO t1 VALUES ('abc', 'a', 'abc', REPEAT('a',21), REPEAT('x',256)); +Warnings: +Warning 1265 Data truncated for column 'c' at row 1 +Warning 1265 Data truncated for column 'c0' at row 1 +Warning 1265 Data truncated for column 'c1' at row 1 +Warning 1265 Data truncated for column 'c20' at row 1 +Warning 1265 Data truncated for column 'c255' at row 1 +INSERT INTO t1 SELECT c255, c255, c255, c255, CONCAT(c255,c1) FROM t1; +Warnings: +Warning 1265 Data truncated for column 'c' at row 2 +Warning 1265 Data truncated for column 'c0' at row 2 +Warning 1265 Data truncated for column 'c1' at row 2 +Warning 1265 Data truncated for column 'c20' at row 2 +Warning 1265 Data truncated for column 'c' at row 3 +Warning 1265 Data truncated for column 'c0' at row 3 +Warning 1265 Data truncated for column 'c1' at row 3 +Warning 1265 Data truncated for column 'c20' at row 3 +Warning 1265 Data truncated for column 'c255' at row 3 +SELECT * FROM t1; +c c0 c1 c20 c255 + + +C C Creating an article Creating an article for the Knowledgebase is similar to asking questions. First, navigate to the category where you feel the article should be. Once there, double check that an article doesn't already exist which would work.b +a a aaaaaaaaaaaaaaaaaaaa xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +a b abcdefghi klmnopqrst Creating an article for the Knowledgebase is similar to asking questions. First, navigate to the category where you feel the article should be. Once there, double check that an article doesn't already exist which would work. +x x xxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +SELECT DISTINCT c20, REPEAT('a',LENGTH(c20)), COUNT(*) FROM t1 GROUP BY c1, c20; +c20 REPEAT('a',LENGTH(c20)) COUNT(*) + 2 +Creating an article aaaaaaaaaaaaaaaaaaa 1 +aaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaa 1 +abcdefghi klmnopqrst aaaaaaaaaaaaaaaaaaaa 1 +xxxxxxxxxxxxxxxxxxxx aaaaaaaaaaaaaaaaaaaa 1 +ALTER TABLE t1 ADD COLUMN c257 CHAR(257) NOT NULL; +ERROR 42000: Column length too big for column 'c257' (max = 255); use BLOB or TEXT instead +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c CHAR NOT NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c char(1) NO NULL +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +DROP TABLE t1; +CREATE TABLE t1 (c CHAR NOT NULL, +c2 CHAR NOT NULL DEFAULT '_' +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c char(1) NO NULL +c2 char(1) NO _ +ALTER TABLE t1 ADD COLUMN err CHAR NOT NULL DEFAULT NULL; +ERROR 42000: Invalid default value for 'err' +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +SELECT HEX(c), HEX(c2) FROM t1; +HEX(c) HEX(c2) +INSERT INTO t1 (c2) VALUES (NULL); +ERROR 23000: Column 'c2' cannot be null +INSERT INTO t1 (c) VALUES ('_'); +SELECT COUNT(c), COUNT(c2) FROM t1; +COUNT(c) COUNT(c2) +1 1 +DROP TABLE t1; +# +# VARCHAR columns +# +DROP TABLE IF EXISTS t1, t2; +CREATE TABLE t1 (v0 VARCHAR(0) NOT NULL, +v1 VARCHAR(1) NOT NULL, +v64 VARCHAR(64) NOT NULL, +v65000 VARCHAR(65000) NOT NULL +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +v0 varchar(0) # # # +v1 varchar(1) # # # +v64 varchar(64) # # # +v65000 varchar(65000) # # # +CREATE TABLE t2 (v VARCHAR(65532) NOT NULL) ENGINE= ; +SHOW COLUMNS IN t2; +Field Type Null Key Default Extra +v varchar(65532) # # # +INSERT INTO t1 (v0,v1,v64,v65000) VALUES ('','','',''); +INSERT INTO t1 (v0,v1,v64,v65000) VALUES ('','y','Once there, double check that an article doesn\'t already exist','Here is a list of recommended books on MariaDB and MySQL. We\'ve provided links to Amazon.com here for convenience, but they can be found at many other bookstores, both online and off. + + If you want to have your favorite MySQL / MariaDB book listed here, please leave a comment. + For developers who want to code on MariaDB or MySQL + + * Understanding MySQL Internals by Sasha Pachev, former MySQL developer at MySQL AB. + o This is the only book we know about that describes the internals of MariaDB / MySQL. A must have for anyone who wants to understand and develop on MariaDB! + o Not all topics are covered and some parts are slightly outdated, but still the best book on this topic. + * MySQL 5.1 Plugin Development by Sergei Golubchik and Andrew Hutchings + o A must read for anyone wanting to write a plugin for MariaDB, written by the Sergei who designed the plugin interface for MySQL and MariaDB! + + For MariaDB / MySQL end users + + * MariaDB Crash Course by Ben Forta + o First MariaDB book! + o For people who want to learn SQL and the basics of MariaDB. + o Now shipping. Purchase at Amazon.com or your favorite bookseller. + + * SQL-99 Complete, Really by Peter Gulutzan & Trudy Pelzer. + o Everything you wanted to know about the SQL 99 standard. Excellent reference book! + o Free to read in the Knowledgebase! + + * MySQL (4th Edition) by Paul DuBois + o The \'default\' book to read if you wont to learn to use MySQL / MariaDB. + + * MySQL Cookbook by Paul DuBois + o A lot of examples of how to use MySQL. As with all of Paul\'s books, it\'s worth its weight in gold and even enjoyable reading for such a \'dry\' subject. + + * High Performance MySQL, Second Edition, By Baron Schwartz, Peter Zaitsev, Vadim Tkachenko, Jeremy D. Zawodny, Arjen Lentz, Derek J. Balling, et al. + o \"High Performance MySQL is the definitive guide to building fast, reliable systems with MySQL. Written by noted experts with years of real-world experience building very large systems, this book covers every aspect of MySQL performance in detail, and focuses on robustness, security, and data integrity. Learn advanced techniques in depth so you can bring out MySQL\'s full power.\" (From the book description at O\'Reilly) + + * MySQL Admin Cookbook + o A quick step-by-step guide for MySQL users and database administrators to tackle real-world challenges with MySQL configuration and administration + + * MySQL 5.0 Certification Study Guide, By Paul DuBois, Stefan Hinz, Carsten Pedersen + o This is the official guide to cover the passing of the two MySQL Certification examinations. It is valid till version 5.0 of the server, so while it misses all the features available in MySQL 5.1 and greater (including MariaDB 5.1 and greater), it provides a good basic understanding of MySQL for the end-user. '); +SELECT * FROM t1; +v0 v1 v64 v65000 + + + + + + + + + + + + y Once there, double check that an article doesn't already exist Here is a list of recommended books on MariaDB and MySQL. We've provided links to Amazon.com here for convenience, but they can be found at many other bookstores, both online and off. + o "High Performance MySQL is the definitive guide to building fast, reliable systems with MySQL. Written by noted experts with years of real-world experience building very large systems, this book covers every aspect of MySQL performance in detail, and focuses on robustness, security, and data integrity. Learn advanced techniques in depth so you can bring out MySQL's full power." (From the book description at O'Reilly) + o A lot of examples of how to use MySQL. As with all of Paul's books, it's worth its weight in gold and even enjoyable reading for such a 'dry' subject. + o A must read for anyone wanting to write a plugin for MariaDB, written by the Sergei who designed the plugin interface for MySQL and MariaDB! + o A quick step-by-step guide for MySQL users and database administrators to tackle real-world challenges with MySQL configuration and administration + o Everything you wanted to know about the SQL 99 standard. Excellent reference book! + o First MariaDB book! + o For people who want to learn SQL and the basics of MariaDB. + o Free to read in the Knowledgebase! + o Not all topics are covered and some parts are slightly outdated, but still the best book on this topic. + o Now shipping. Purchase at Amazon.com or your favorite bookseller. + o The 'default' book to read if you wont to learn to use MySQL / MariaDB. + o This is the official guide to cover the passing of the two MySQL Certification examinations. It is valid till version 5.0 of the server, so while it misses all the features available in MySQL 5.1 and greater (including MariaDB 5.1 and greater), it provides a good basic understanding of MySQL for the end-user. + o This is the only book we know about that describes the internals of MariaDB / MySQL. A must have for anyone who wants to understand and develop on MariaDB! + * High Performance MySQL, Second Edition, By Baron Schwartz, Peter Zaitsev, Vadim Tkachenko, Jeremy D. Zawodny, Arjen Lentz, Derek J. Balling, et al. + * MariaDB Crash Course by Ben Forta + * MySQL (4th Edition) by Paul DuBois + * MySQL 5.0 Certification Study Guide, By Paul DuBois, Stefan Hinz, Carsten Pedersen + * MySQL 5.1 Plugin Development by Sergei Golubchik and Andrew Hutchings + * MySQL Admin Cookbook + * MySQL Cookbook by Paul DuBois + * SQL-99 Complete, Really by Peter Gulutzan & Trudy Pelzer. + * Understanding MySQL Internals by Sasha Pachev, former MySQL developer at MySQL AB. + For MariaDB / MySQL end users + For developers who want to code on MariaDB or MySQL + If you want to have your favorite MySQL / MariaDB book listed here, please leave a comment. +INSERT INTO t1 (v0,v1,v64,v65000) VALUES ('y', 'yy', REPEAT('c',65), REPEAT('abcdefghi ',6501)); +Warnings: +Warning 1265 Data truncated for column 'v0' at row 1 +Warning 1265 Data truncated for column 'v1' at row 1 +Warning 1265 Data truncated for column 'v64' at row 1 +Warning 1265 Data truncated for column 'v65000' at row 1 +INSERT INTO t1 (v0,v1,v64,v65000) SELECT v65000, v65000, v65000, CONCAT(v65000,v1) FROM t1; +Warnings: +Warning 1265 Data truncated for column 'v0' at row 2 +Warning 1265 Data truncated for column 'v1' at row 2 +Warning 1265 Data truncated for column 'v64' at row 2 +Warning 1265 Data truncated for column 'v0' at row 3 +Warning 1265 Data truncated for column 'v1' at row 3 +Warning 1265 Data truncated for column 'v64' at row 3 +Warning 1265 Data truncated for column 'v65000' at row 3 +SELECT v0, v1, v64, LENGTH(v65000) FROM t1; +v0 v1 v64 LENGTH(v65000) + 0 + 0 + H Here is a list of recommended books on MariaDB and MySQL. We've 2966 + a abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcd 65000 + y Once there, double check that an article doesn't already exist 2965 + y cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc 65000 +ALTER TABLE t1 ADD COLUMN v65536 VARCHAR(65536) NOT NULL; +Warnings: +Note 1246 Converting column 'v65536' from VARCHAR to TEXT +Note 1246 Converting column 'v65536' from VARCHAR to TEXT +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +v0 varchar(0) # # # +v1 varchar(1) # # # +v64 varchar(64) # # # +v65000 varchar(65000) # # # +v65536 mediumtext # # # +DROP TABLE t1, t2; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c VARCHAR(64) NOT NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c varchar(64) NO NULL +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +DROP TABLE t1; +CREATE TABLE t1 (c VARCHAR(64) NOT NULL, +c2 VARCHAR(64) NOT NULL DEFAULT 'test default' +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c varchar(64) NO NULL +c2 varchar(64) NO test default +ALTER TABLE t1 ADD COLUMN err VARCHAR(64) NOT NULL DEFAULT NULL; +ERROR 42000: Invalid default value for 'err' +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +SELECT HEX(c), HEX(c2) FROM t1; +HEX(c) HEX(c2) +INSERT INTO t1 (c2) VALUES (NULL); +ERROR 23000: Column 'c2' cannot be null +INSERT INTO t1 (c) VALUES ('test default'); +SELECT COUNT(c), COUNT(c2) FROM t1; +COUNT(c) COUNT(c2) +1 1 +DROP TABLE t1; +# +# date and time columns +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (d DATE NOT NULL, +dt DATETIME NOT NULL, +ts TIMESTAMP NOT NULL, +t TIME NOT NULL, +y YEAR NOT NULL, +y4 YEAR(4) NOT NULL, +y2 YEAR(2) NOT NULL +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +d date # # # +dt datetime # # # +ts timestamp # # # on update CURRENT_TIMESTAMP +t time # # # +y year(4) # # # +y4 year(4) # # # +y2 year(2) # # # +SET @tm = '2012-04-09 05:27:00'; +INSERT INTO t1 VALUES +('1000-01-01', '1000-01-01 00:00:00', FROM_UNIXTIME(1), '-838:59:59', '1901', '1901', '00'), +('9999-12-31', '9999-12-31 23:59:59', FROM_UNIXTIME(2147483647), '838:59:59', '2155', '2155', '99'), +('0000-00-00', '0000-00-00 00:00:00', '0000-00-00 00:00:00', '00:00:00', '0', '0', '0'), +(DATE(@tm),@tm,TIMESTAMP(@tm),TIME(@tm),YEAR(@tm),YEAR(@tm),YEAR(@tm)); +SELECT * FROM t1; +d dt ts t y y4 y2 +0000-00-00 0000-00-00 00:00:00 0000-00-00 00:00:00 00:00:00 2000 2000 00 +1000-01-01 1000-01-01 00:00:00 1970-01-01 03:00:01 -838:59:59 1901 1901 00 +2012-04-09 2012-04-09 05:27:00 2012-04-09 05:27:00 05:27:00 2012 2012 12 +9999-12-31 9999-12-31 23:59:59 2038-01-19 07:14:07 838:59:59 2155 2155 99 +INSERT INTO t1 VALUES +('999-13-32', '999-11-31 00:00:00', '0', '-839:00:00', '1900', '1900', '-1' ); +Warnings: +Warning 1265 Data truncated for column 'd' at row 1 +Warning 1265 Data truncated for column 'dt' at row 1 +Warning 1265 Data truncated for column 'ts' at row 1 +Warning 1264 Out of range value for column 't' at row 1 +Warning 1264 Out of range value for column 'y' at row 1 +Warning 1264 Out of range value for column 'y4' at row 1 +Warning 1264 Out of range value for column 'y2' at row 1 +SELECT * FROM t1; +d dt ts t y y4 y2 +0000-00-00 0000-00-00 00:00:00 0000-00-00 00:00:00 -838:59:59 0000 0000 00 +0000-00-00 0000-00-00 00:00:00 0000-00-00 00:00:00 00:00:00 2000 2000 00 +1000-01-01 1000-01-01 00:00:00 1970-01-01 03:00:01 -838:59:59 1901 1901 00 +2012-04-09 2012-04-09 05:27:00 2012-04-09 05:27:00 05:27:00 2012 2012 12 +9999-12-31 9999-12-31 23:59:59 2038-01-19 07:14:07 838:59:59 2155 2155 99 +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c DATE NOT NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c date NO NULL +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +DROP TABLE t1; +CREATE TABLE t1 (c DATE NOT NULL, +c2 DATE NOT NULL DEFAULT '2012-12-21' +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c date NO NULL +c2 date NO 2012-12-21 +ALTER TABLE t1 ADD COLUMN err DATE NOT NULL DEFAULT NULL; +ERROR 42000: Invalid default value for 'err' +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +SELECT HEX(c), HEX(c2) FROM t1; +HEX(c) HEX(c2) +INSERT INTO t1 (c2) VALUES (NULL); +ERROR 23000: Column 'c2' cannot be null +INSERT INTO t1 (c) VALUES ('2012-12-21'); +SELECT COUNT(c), COUNT(c2) FROM t1; +COUNT(c) COUNT(c2) +1 1 +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c DATETIME NOT NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c datetime NO NULL +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +DROP TABLE t1; +CREATE TABLE t1 (c DATETIME NOT NULL, +c2 DATETIME NOT NULL DEFAULT '2012-12-21 12:21:12' +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c datetime NO NULL +c2 datetime NO 2012-12-21 12:21:12 +ALTER TABLE t1 ADD COLUMN err DATETIME NOT NULL DEFAULT NULL; +ERROR 42000: Invalid default value for 'err' +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +SELECT HEX(c), HEX(c2) FROM t1; +HEX(c) HEX(c2) +INSERT INTO t1 (c2) VALUES (NULL); +ERROR 23000: Column 'c2' cannot be null +INSERT INTO t1 (c) VALUES ('2012-12-21 12:21:12'); +SELECT COUNT(c), COUNT(c2) FROM t1; +COUNT(c) COUNT(c2) +1 1 +DROP TABLE t1; +CREATE TABLE t1 (c TIMESTAMP NOT NULL, +c2 TIMESTAMP NOT NULL DEFAULT '2012-02-21 12:21:12' +) ENGINE= ; +ALTER TABLE t1 ADD COLUMN err TIMESTAMP NOT NULL DEFAULT NULL; +ERROR 42000: Invalid default value for 'err' +INSERT INTO t1 (c) VALUES (NULL); +INSERT INTO t1 (c2) VALUES (NULL); +SELECT c, c2 FROM t1; +c c2 + + +DROP TABLE t1; +CREATE TABLE t1 (c TIMESTAMP NOT NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c timestamp NO CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP +INSERT INTO t1 (c) VALUES (NULL); +SELECT * FROM t1; +c + +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c TIME NOT NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c time NO NULL +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +DROP TABLE t1; +CREATE TABLE t1 (c TIME NOT NULL, +c2 TIME NOT NULL DEFAULT '12:21:12' +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c time NO NULL +c2 time NO 12:21:12 +ALTER TABLE t1 ADD COLUMN err TIME NOT NULL DEFAULT NULL; +ERROR 42000: Invalid default value for 'err' +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +SELECT HEX(c), HEX(c2) FROM t1; +HEX(c) HEX(c2) +INSERT INTO t1 (c2) VALUES (NULL); +ERROR 23000: Column 'c2' cannot be null +INSERT INTO t1 (c) VALUES ('12:21:12'); +SELECT COUNT(c), COUNT(c2) FROM t1; +COUNT(c) COUNT(c2) +1 1 +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c YEAR NOT NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c year(4) NO NULL +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +DROP TABLE t1; +CREATE TABLE t1 (c YEAR NOT NULL, +c2 YEAR NOT NULL DEFAULT '2012' +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c year(4) NO NULL +c2 year(4) NO 2012 +ALTER TABLE t1 ADD COLUMN err YEAR NOT NULL DEFAULT NULL; +ERROR 42000: Invalid default value for 'err' +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +SELECT HEX(c), HEX(c2) FROM t1; +HEX(c) HEX(c2) +INSERT INTO t1 (c2) VALUES (NULL); +ERROR 23000: Column 'c2' cannot be null +INSERT INTO t1 (c) VALUES ('2012'); +SELECT COUNT(c), COUNT(c2) FROM t1; +COUNT(c) COUNT(c2) +1 1 +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c YEAR(2) NOT NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c year(2) NO NULL +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +DROP TABLE t1; +CREATE TABLE t1 (c YEAR(2) NOT NULL, +c2 YEAR(2) NOT NULL DEFAULT '12' +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c year(2) NO NULL +c2 year(2) NO 12 +ALTER TABLE t1 ADD COLUMN err YEAR(2) NOT NULL DEFAULT NULL; +ERROR 42000: Invalid default value for 'err' +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +SELECT HEX(c), HEX(c2) FROM t1; +HEX(c) HEX(c2) +INSERT INTO t1 (c2) VALUES (NULL); +ERROR 23000: Column 'c2' cannot be null +INSERT INTO t1 (c) VALUES ('12'); +SELECT COUNT(c), COUNT(c2) FROM t1; +COUNT(c) COUNT(c2) +1 1 +DROP TABLE t1; +# +# ENUM columns +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (a ENUM('') NOT NULL, +b ENUM('test1','test2','test3','test4','test5') NOT NULL, +c ENUM('1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',' ','11','12','13','14','15','16','17','18','19','1a','1b','1c','1d','1e','1f','1g','1h','1i','1j','1k','1l','1m','1n','1o','1p','1q','1r','1s','1t','1u','1v','1w','1x','1y','1z','20','21','22','23','24','25','26','27','28','29','2a','2b','2c','2d','2e','2f','2g','2h','2i','2j','2k','2l','2m','2n','2o','2p','2q','2r','2s','2t','2u','2v','2w','2x','2y','2z','30','31','32','33','34','35','36','37','38','39','3a','3b','3c','3d','3e','3f','3g','3h','3i','3j','3k','3l','3m','3n','3o','3p','3q','3r','3s','3t','3u','3v','3w','3x','3y','3z','40','41','42','43','44','45','46','47','48','49','4a','4b','4c','4d','4e','4f','4g','4h','4i','4j','4k','4l','4m','4n','4o','4p','4q','4r','4s','4t','4u','4v','4w','4x','4y','4z','50','51','52','53','54','55','56','57','58','59','5a','5b','5c','5d','5e','5f','5g','5h','5i','5j','5k','5l','5m','5n','5o','5p','5q','5r','5s','5t','5u','5v','5w','5x','5y','5z','60','61','62','63','64','65','66','67','68','69','6a','6b','6c','6d','6e','6f','6g','6h','6i','6j','6k','6l','6m','6n','6o','6p','6q','6r','6s','6t','6u','6v','6w','6x','6y','6z','70','71','72','73','74','75') NOT NULL +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +a enum('') # # # +b enum('test1','test2','test3','test4','test5') # # # +c enum('1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','','11','12','13','14','15','16','17','18','19','1a','1b','1c','1d','1e','1f','1g','1h','1i','1j','1k','1l','1m','1n','1o','1p','1q','1r','1s','1t','1u','1v','1w','1x','1y','1z','20','21','22','23','24','25','26','27','28','29','2a','2b','2c','2d','2e','2f','2g','2h','2i','2j','2k','2l','2m','2n','2o','2p','2q','2r','2s','2t','2u','2v','2w','2x','2y','2z','30','31','32','33','34','35','36','37','38','39','3a','3b','3c','3d','3e','3f','3g','3h','3i','3j','3k','3l','3m','3n','3o','3p','3q','3r','3s','3t','3u','3v','3w','3x','3y','3z','40','41','42','43','44','45','46','47','48','49','4a','4b','4c','4d','4e','4f','4g','4h','4i','4j','4k','4l','4m','4n','4o','4p','4q','4r','4s','4t','4u','4v','4w','4x','4y','4z','50','51','52','53','54','55','56','57','58','59','5a','5b','5c','5d','5e','5f','5g','5h','5i','5j','5k','5l','5m','5n','5o','5p','5q','5r','5s','5t','5u','5v','5w','5x','5y','5z','60','61','62','63','64','65','66','67','68','69','6a','6b','6c','6d','6e','6f','6g','6h','6i','6j','6k','6l','6m','6n','6o','6p','6q','6r','6s','6t','6u','6v','6w','6x','6y','6z','70','71','72','73','74','75') # # # +INSERT INTO t1 VALUES ('','test2','4'),('',5,2); +SELECT * FROM t1; +a b c + test2 4 + test5 2 +INSERT INTO t1 VALUES (0,'test6',-1); +Warnings: +Warning 1265 Data truncated for column 'a' at row 1 +Warning 1265 Data truncated for column 'b' at row 1 +Warning 1265 Data truncated for column 'c' at row 1 +SELECT * FROM t1; +a b c + + test2 4 + test5 2 +ALTER TABLE t1 ADD COLUMN e ENUM('a','A') NOT NULL; +Warnings: +Note 1291 Column 'e' has duplicated value 'a' in ENUM +Note 1291 Column 'e' has duplicated value 'a' in ENUM +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +a enum('') # # # +b enum('test1','test2','test3','test4','test5') # # # +c enum('1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','','11','12','13','14','15','16','17','18','19','1a','1b','1c','1d','1e','1f','1g','1h','1i','1j','1k','1l','1m','1n','1o','1p','1q','1r','1s','1t','1u','1v','1w','1x','1y','1z','20','21','22','23','24','25','26','27','28','29','2a','2b','2c','2d','2e','2f','2g','2h','2i','2j','2k','2l','2m','2n','2o','2p','2q','2r','2s','2t','2u','2v','2w','2x','2y','2z','30','31','32','33','34','35','36','37','38','39','3a','3b','3c','3d','3e','3f','3g','3h','3i','3j','3k','3l','3m','3n','3o','3p','3q','3r','3s','3t','3u','3v','3w','3x','3y','3z','40','41','42','43','44','45','46','47','48','49','4a','4b','4c','4d','4e','4f','4g','4h','4i','4j','4k','4l','4m','4n','4o','4p','4q','4r','4s','4t','4u','4v','4w','4x','4y','4z','50','51','52','53','54','55','56','57','58','59','5a','5b','5c','5d','5e','5f','5g','5h','5i','5j','5k','5l','5m','5n','5o','5p','5q','5r','5s','5t','5u','5v','5w','5x','5y','5z','60','61','62','63','64','65','66','67','68','69','6a','6b','6c','6d','6e','6f','6g','6h','6i','6j','6k','6l','6m','6n','6o','6p','6q','6r','6s','6t','6u','6v','6w','6x','6y','6z','70','71','72','73','74','75') # # # +e enum('a','A') # # # +INSERT INTO t1 VALUES ('','test3','75','A'); +SELECT * FROM t1; +a b c e + a + test2 4 a + test3 75 a + test5 2 a +SELECT * FROM t1 WHERE b='test2' OR a != ''; +a b c e + test2 4 a +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c ENUM('test1','test2','test3') NOT NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c enum('test1','test2','test3') NO NULL +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +DROP TABLE t1; +CREATE TABLE t1 (c ENUM('test1','test2','test3') NOT NULL, +c2 ENUM('test1','test2','test3') NOT NULL DEFAULT 'test2' +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c enum('test1','test2','test3') NO NULL +c2 enum('test1','test2','test3') NO test2 +ALTER TABLE t1 ADD COLUMN err ENUM('test1','test2','test3') NOT NULL DEFAULT NULL; +ERROR 42000: Invalid default value for 'err' +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +SELECT HEX(c), HEX(c2) FROM t1; +HEX(c) HEX(c2) +INSERT INTO t1 (c2) VALUES (NULL); +ERROR 23000: Column 'c2' cannot be null +INSERT INTO t1 (c) VALUES ('test2'); +SELECT COUNT(c), COUNT(c2) FROM t1; +COUNT(c) COUNT(c2) +1 1 +DROP TABLE t1; +# +# Fixed point columns (NUMERIC, DECIMAL) +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (d DECIMAL NOT NULL, +d0 DECIMAL(0) NOT NULL, +d1_1 DECIMAL(1,1) NOT NULL, +d10_2 DECIMAL(10,2) NOT NULL, +d60_10 DECIMAL(60,10) NOT NULL, +n NUMERIC NOT NULL, +n0_0 NUMERIC(0,0) NOT NULL, +n1 NUMERIC(1) NOT NULL, +n20_4 NUMERIC(20,4) NOT NULL, +n65_4 NUMERIC(65,4) NOT NULL +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +d decimal(10,0) # # # +d0 decimal(10,0) # # # +d1_1 decimal(1,1) # # # +d10_2 decimal(10,2) # # # +d60_10 decimal(60,10) # # # +n decimal(10,0) # # # +n0_0 decimal(10,0) # # # +n1 decimal(1,0) # # # +n20_4 decimal(20,4) # # # +n65_4 decimal(65,4) # # # +INSERT INTO t1 VALUES (100,123456,0.3,40000.25,123456789123456789.10001,1024,7000.0,8.0,999999.9,9223372036854775807); +INSERT INTO t1 VALUES (0,0,0,0,0,0,0,0,0,0); +INSERT INTO t1 VALUES (9999999999.0,9999999999.0,0.9,99999999.99,99999999999999999999999999999999999999999999999999.9999999999,9999999999.0,9999999999.0,9.0,9999999999999999.9999,9999999999999999999999999999999999999999999999999999999999999.9999); +SELECT * FROM t1; +d d0 d1_1 d10_2 d60_10 n n0_0 n1 n20_4 n65_4 +0 0 0.0 0.00 0.0000000000 0 0 0 0.0000 0.0000 +100 123456 0.3 40000.25 123456789123456789.1000100000 1024 7000 8 999999.9000 9223372036854775807.0000 +9999999999 9999999999 0.9 99999999.99 99999999999999999999999999999999999999999999999999.9999999999 9999999999 9999999999 9 9999999999999999.9999 9999999999999999999999999999999999999999999999999999999999999.9999 +INSERT INTO t1 VALUES (-100,-123456,-0.3,-40000.25,-123456789123456789.10001,-1024,-7000.0,-8.0,-999999.9,-9223372036854775807); +INSERT INTO t1 VALUES (-9999999999.0,-9999999999.0,-0.9,-99999999.99,-99999999999999999999999999999999999999999999999999.9999999999,-9999999999.0,-9999999999.0,-9.0,-9999999999999999.9999,-9999999999999999999999999999999999999999999999999999999999999.9999); +SELECT * FROM t1; +d d0 d1_1 d10_2 d60_10 n n0_0 n1 n20_4 n65_4 +-100 -123456 -0.3 -40000.25 -123456789123456789.1000100000 -1024 -7000 -8 -999999.9000 -9223372036854775807.0000 +-9999999999 -9999999999 -0.9 -99999999.99 -99999999999999999999999999999999999999999999999999.9999999999 -9999999999 -9999999999 -9 -9999999999999999.9999 -9999999999999999999999999999999999999999999999999999999999999.9999 +0 0 0.0 0.00 0.0000000000 0 0 0 0.0000 0.0000 +100 123456 0.3 40000.25 123456789123456789.1000100000 1024 7000 8 999999.9000 9223372036854775807.0000 +9999999999 9999999999 0.9 99999999.99 99999999999999999999999999999999999999999999999999.9999999999 9999999999 9999999999 9 9999999999999999.9999 9999999999999999999999999999999999999999999999999999999999999.9999 +SELECT * FROM t1 WHERE n20_4 = 9999999999999999.9999 OR d < 100; +d d0 d1_1 d10_2 d60_10 n n0_0 n1 n20_4 n65_4 +-100 -123456 -0.3 -40000.25 -123456789123456789.1000100000 -1024 -7000 -8 -999999.9000 -9223372036854775807.0000 +-9999999999 -9999999999 -0.9 -99999999.99 -99999999999999999999999999999999999999999999999999.9999999999 -9999999999 -9999999999 -9 -9999999999999999.9999 -9999999999999999999999999999999999999999999999999999999999999.9999 +0 0 0.0 0.00 0.0000000000 0 0 0 0.0000 0.0000 +9999999999 9999999999 0.9 99999999.99 99999999999999999999999999999999999999999999999999.9999999999 9999999999 9999999999 9 9999999999999999.9999 9999999999999999999999999999999999999999999999999999999999999.9999 +INSERT INTO t1 SELECT n65_4, n65_4, n65_4, n65_4, n65_4, n65_4, n65_4, n65_4, n65_4, n65_4 FROM t1 WHERE n65_4 = ( SELECT MAX(n65_4) FROM t1 ); +Warnings: +Warning 1264 Out of range value for column 'd' at row 1 +Warning 1264 Out of range value for column 'd0' at row 1 +Warning 1264 Out of range value for column 'd1_1' at row 1 +Warning 1264 Out of range value for column 'd10_2' at row 1 +Warning 1264 Out of range value for column 'd60_10' at row 1 +Warning 1264 Out of range value for column 'n' at row 1 +Warning 1264 Out of range value for column 'n0_0' at row 1 +Warning 1264 Out of range value for column 'n1' at row 1 +Warning 1264 Out of range value for column 'n20_4' at row 1 +SELECT * FROM t1; +d d0 d1_1 d10_2 d60_10 n n0_0 n1 n20_4 n65_4 +-100 -123456 -0.3 -40000.25 -123456789123456789.1000100000 -1024 -7000 -8 -999999.9000 -9223372036854775807.0000 +-9999999999 -9999999999 -0.9 -99999999.99 -99999999999999999999999999999999999999999999999999.9999999999 -9999999999 -9999999999 -9 -9999999999999999.9999 -9999999999999999999999999999999999999999999999999999999999999.9999 +0 0 0.0 0.00 0.0000000000 0 0 0 0.0000 0.0000 +100 123456 0.3 40000.25 123456789123456789.1000100000 1024 7000 8 999999.9000 9223372036854775807.0000 +9999999999 9999999999 0.9 99999999.99 99999999999999999999999999999999999999999999999999.9999999999 9999999999 9999999999 9 9999999999999999.9999 9999999999999999999999999999999999999999999999999999999999999.9999 +9999999999 9999999999 0.9 99999999.99 99999999999999999999999999999999999999999999999999.9999999999 9999999999 9999999999 9 9999999999999999.9999 9999999999999999999999999999999999999999999999999999999999999.9999 +INSERT INTO t1 VALUES (10000000000.0,10000000000.0,1.1,100000000.99,100000000000000000000000000000000000000000000000000.0,10000000000.0,10000000000.0,10.0,10000000000000000.9999,10000000000000000000000000000000000000000000000000000000000000.9999); +Warnings: +Warning 1264 Out of range value for column 'd' at row 1 +Warning 1264 Out of range value for column 'd0' at row 1 +Warning 1264 Out of range value for column 'd1_1' at row 1 +Warning 1264 Out of range value for column 'd10_2' at row 1 +Warning 1264 Out of range value for column 'd60_10' at row 1 +Warning 1264 Out of range value for column 'n' at row 1 +Warning 1264 Out of range value for column 'n0_0' at row 1 +Warning 1264 Out of range value for column 'n1' at row 1 +Warning 1264 Out of range value for column 'n20_4' at row 1 +Warning 1264 Out of range value for column 'n65_4' at row 1 +SELECT * FROM t1; +d d0 d1_1 d10_2 d60_10 n n0_0 n1 n20_4 n65_4 +-100 -123456 -0.3 -40000.25 -123456789123456789.1000100000 -1024 -7000 -8 -999999.9000 -9223372036854775807.0000 +-9999999999 -9999999999 -0.9 -99999999.99 -99999999999999999999999999999999999999999999999999.9999999999 -9999999999 -9999999999 -9 -9999999999999999.9999 -9999999999999999999999999999999999999999999999999999999999999.9999 +0 0 0.0 0.00 0.0000000000 0 0 0 0.0000 0.0000 +100 123456 0.3 40000.25 123456789123456789.1000100000 1024 7000 8 999999.9000 9223372036854775807.0000 +9999999999 9999999999 0.9 99999999.99 99999999999999999999999999999999999999999999999999.9999999999 9999999999 9999999999 9 9999999999999999.9999 9999999999999999999999999999999999999999999999999999999999999.9999 +9999999999 9999999999 0.9 99999999.99 99999999999999999999999999999999999999999999999999.9999999999 9999999999 9999999999 9 9999999999999999.9999 9999999999999999999999999999999999999999999999999999999999999.9999 +9999999999 9999999999 0.9 99999999.99 99999999999999999999999999999999999999999999999999.9999999999 9999999999 9999999999 9 9999999999999999.9999 9999999999999999999999999999999999999999999999999999999999999.9999 +INSERT INTO t1 VALUES (9999999999.1,9999999999.1,1.9,99999999.001,99999999999999999999999999999999999999999999999999.99999999991,9999999999.1,9999999999.1,9.1,9999999999999999.00001,9999999999999999999999999999999999999999999999999999999999999.11111); +Warnings: +Note 1265 Data truncated for column 'd' at row 1 +Note 1265 Data truncated for column 'd0' at row 1 +Warning 1264 Out of range value for column 'd1_1' at row 1 +Note 1265 Data truncated for column 'd10_2' at row 1 +Note 1265 Data truncated for column 'd60_10' at row 1 +Note 1265 Data truncated for column 'n' at row 1 +Note 1265 Data truncated for column 'n0_0' at row 1 +Note 1265 Data truncated for column 'n1' at row 1 +Note 1265 Data truncated for column 'n20_4' at row 1 +Note 1265 Data truncated for column 'n65_4' at row 1 +SELECT * FROM t1; +d d0 d1_1 d10_2 d60_10 n n0_0 n1 n20_4 n65_4 +-100 -123456 -0.3 -40000.25 -123456789123456789.1000100000 -1024 -7000 -8 -999999.9000 -9223372036854775807.0000 +-9999999999 -9999999999 -0.9 -99999999.99 -99999999999999999999999999999999999999999999999999.9999999999 -9999999999 -9999999999 -9 -9999999999999999.9999 -9999999999999999999999999999999999999999999999999999999999999.9999 +0 0 0.0 0.00 0.0000000000 0 0 0 0.0000 0.0000 +100 123456 0.3 40000.25 123456789123456789.1000100000 1024 7000 8 999999.9000 9223372036854775807.0000 +9999999999 9999999999 0.9 99999999.00 99999999999999999999999999999999999999999999999999.9999999999 9999999999 9999999999 9 9999999999999999.0000 9999999999999999999999999999999999999999999999999999999999999.1111 +9999999999 9999999999 0.9 99999999.99 99999999999999999999999999999999999999999999999999.9999999999 9999999999 9999999999 9 9999999999999999.9999 9999999999999999999999999999999999999999999999999999999999999.9999 +9999999999 9999999999 0.9 99999999.99 99999999999999999999999999999999999999999999999999.9999999999 9999999999 9999999999 9 9999999999999999.9999 9999999999999999999999999999999999999999999999999999999999999.9999 +9999999999 9999999999 0.9 99999999.99 99999999999999999999999999999999999999999999999999.9999999999 9999999999 9999999999 9 9999999999999999.9999 9999999999999999999999999999999999999999999999999999999999999.9999 +ALTER TABLE t1 ADD COLUMN n66 NUMERIC(66); +ERROR 42000: Too big precision 66 specified for 'n66'. Maximum is 65. +ALTER TABLE t1 ADD COLUMN n66_6 DECIMAL(66,6); +ERROR 42000: Too big precision 66 specified for 'n66_6'. Maximum is 65. +ALTER TABLE t1 ADD COLUMN n66_66 DECIMAL(66,66); +ERROR 42000: Too big scale 66 specified for 'n66_66'. Maximum is 30. +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c DECIMAL NOT NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c decimal(10,0) NO NULL +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +DROP TABLE t1; +CREATE TABLE t1 (c DECIMAL NOT NULL, +c2 DECIMAL NOT NULL DEFAULT 1.1 +) ENGINE= ; +Warnings: +Note 1265 Data truncated for column 'c2' at row 1 +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c decimal(10,0) NO NULL +c2 decimal(10,0) NO 1 +ALTER TABLE t1 ADD COLUMN err DECIMAL NOT NULL DEFAULT NULL; +ERROR 42000: Invalid default value for 'err' +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +SELECT HEX(c), HEX(c2) FROM t1; +HEX(c) HEX(c2) +INSERT INTO t1 (c2) VALUES (NULL); +ERROR 23000: Column 'c2' cannot be null +INSERT INTO t1 (c) VALUES (1.1); +Warnings: +Note 1265 Data truncated for column 'c' at row 1 +SELECT COUNT(c), COUNT(c2) FROM t1; +COUNT(c) COUNT(c2) +1 1 +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c NUMERIC NOT NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c decimal(10,0) NO NULL +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +DROP TABLE t1; +CREATE TABLE t1 (c NUMERIC NOT NULL, +c2 NUMERIC NOT NULL DEFAULT 0 +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c decimal(10,0) NO NULL +c2 decimal(10,0) NO 0 +ALTER TABLE t1 ADD COLUMN err NUMERIC NOT NULL DEFAULT NULL; +ERROR 42000: Invalid default value for 'err' +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +SELECT HEX(c), HEX(c2) FROM t1; +HEX(c) HEX(c2) +INSERT INTO t1 (c2) VALUES (NULL); +ERROR 23000: Column 'c2' cannot be null +INSERT INTO t1 (c) VALUES (0); +SELECT COUNT(c), COUNT(c2) FROM t1; +COUNT(c) COUNT(c2) +1 1 +DROP TABLE t1; +# +# Floating point columns (FLOAT, DOUBLE) +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (f FLOAT NOT NULL, +f0 FLOAT(0) NOT NULL, +r1_1 REAL(1,1) NOT NULL, +f23_0 FLOAT(23) NOT NULL, +f20_3 FLOAT(20,3) NOT NULL, +d DOUBLE NOT NULL, +d1_0 DOUBLE(1,0) NOT NULL, +d10_10 DOUBLE PRECISION (10,10) NOT NULL, +d53 DOUBLE(53,0) NOT NULL, +d53_10 DOUBLE(53,10) NOT NULL +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +f float # # # +f0 float # # # +r1_1 double(1,1) # # # +f23_0 float # # # +f20_3 float(20,3) # # # +d double # # # +d1_0 double(1,0) # # # +d10_10 double(10,10) # # # +d53 double(53,0) # # # +d53_10 double(53,10) # # # +INSERT INTO t1 VALUES (12345.12345,12345.12345,0.9,123456789.123,56789.987,11111111.111,8.0,0.0123456789,1234566789123456789,99999999999999999.99999999); +SELECT * FROM t1; +f 12345.1 +d 11111111.111 +d10_10 0.0123456789 +d1_0 8 +d53 1234566789123456800 +d53_10 100000000000000000.0000000000 +f0 12345.1 +f20_3 56789.988 +f23_0 123457000 +r1_1 0.9 +INSERT INTO t1 VALUES (0,0,0,0,0,0,0,0,0,0); +INSERT INTO t1 VALUES ( +99999999999999999999999999999999999999, +99999999999999999999999999999999999999.9999999999999999, +0.9, +99999999999999999999999999999999999999.9, +99999999999999999.999, +999999999999999999999999999999999999999999999999999999999999999999999999999999999, +9, +0.9999999999, +1999999999999999999999999999999999999999999999999999999, +19999999999999999999999999999999999999999999.9999999999 +); +Warnings: +Warning 1264 Out of range value for column 'd53' at row 1 +Warning 1264 Out of range value for column 'd53_10' at row 1 +SELECT * FROM t1; +f 12345.1 +d 0 +d 11111111.111 +d 1e81 +d10_10 0.0000000000 +d10_10 0.0123456789 +d10_10 0.9999999999 +d1_0 0 +d1_0 8 +d1_0 9 +d53 0 +d53 100000000000000000000000000000000000000000000000000000 +d53 1234566789123456800 +d53_10 0.0000000000 +d53_10 100000000000000000.0000000000 +d53_10 10000000000000000000000000000000000000000000.0000000000 +f 0 +f 1e38 +f0 0 +f0 12345.1 +f0 1e38 +f20_3 0.000 +f20_3 56789.988 +f20_3 99999998430674940.000 +f23_0 0 +f23_0 123457000 +f23_0 1e38 +r1_1 0.0 +r1_1 0.9 +r1_1 0.9 +INSERT INTO t1 VALUES (-999999999999999999999999,-99999999999.999999999999,-0.9,-999.99999999999999999999,-99999999999999999.999,-999999999999999999999999999999999999999999999999999999999999-0.999,-9,-.9999999999,-999999999999999999999999999999.99999999999999999999999,-9999999999999999999999999999999999999999999.9999999999); +SELECT * FROM t1; +f 12345.1 +d -1e60 +d 0 +d 11111111.111 +d 1e81 +d10_10 -0.9999999999 +d10_10 0.0000000000 +d10_10 0.0123456789 +d10_10 0.9999999999 +d1_0 -9 +d1_0 0 +d1_0 8 +d1_0 9 +d53 -1000000000000000000000000000000 +d53 0 +d53 100000000000000000000000000000000000000000000000000000 +d53 1234566789123456800 +d53_10 -10000000000000000000000000000000000000000000.0000000000 +d53_10 0.0000000000 +d53_10 100000000000000000.0000000000 +d53_10 10000000000000000000000000000000000000000000.0000000000 +f -1e24 +f 0 +f 1e38 +f0 -100000000000 +f0 0 +f0 12345.1 +f0 1e38 +f20_3 -99999998430674940.000 +f20_3 0.000 +f20_3 56789.988 +f20_3 99999998430674940.000 +f23_0 -1000 +f23_0 0 +f23_0 123457000 +f23_0 1e38 +r1_1 -0.9 +r1_1 0.0 +r1_1 0.9 +r1_1 0.9 +SELECT MAX(f), MAX(f0), MAX(r1_1), MAX(f23_0), MAX(f20_3), MAX(d), MAX(d1_0), MAX(d10_10), MAX(d53), MAX(d53_10) FROM t1; +MAX(f) 9.999999680285692e37 +MAX(d) 1e81 +MAX(d10_10) 0.9999999999 +MAX(d1_0) 9 +MAX(d53) 100000000000000000000000000000000000000000000000000000 +MAX(d53_10) 10000000000000000000000000000000000000000000.0000000000 +MAX(f0) 9.999999680285692e37 +MAX(f20_3) 99999998430674940.000 +MAX(f23_0) 9.999999680285692e37 +MAX(r1_1) 0.9 +INSERT INTO t1 SELECT d53_10, d53_10, d53_10, d53_10, d53_10, d53_10, d53_10, d53_10, d53_10, d53_10 FROM t1 ORDER BY d53_10 DESC LIMIT 1; +Warnings: +Warning 1264 Out of range value for column 'f' at row 1 +Warning 1264 Out of range value for column 'f0' at row 1 +Warning 1264 Out of range value for column 'r1_1' at row 1 +Warning 1264 Out of range value for column 'f23_0' at row 1 +Warning 1264 Out of range value for column 'f20_3' at row 1 +Warning 1264 Out of range value for column 'd1_0' at row 1 +SELECT * FROM t1; +f 12345.1 +d -1e60 +d 0 +d 11111111.111 +d 1e43 +d 1e81 +d10_10 -0.9999999999 +d10_10 0.0000000000 +d10_10 0.0123456789 +d10_10 0.9999999999 +d10_10 10000000000000000000000000000000000000000000.0000000000 +d1_0 -9 +d1_0 0 +d1_0 8 +d1_0 9 +d1_0 9 +d53 -1000000000000000000000000000000 +d53 0 +d53 10000000000000000000000000000000000000000000 +d53 100000000000000000000000000000000000000000000000000000 +d53 1234566789123456800 +d53_10 -10000000000000000000000000000000000000000000.0000000000 +d53_10 0.0000000000 +d53_10 100000000000000000.0000000000 +d53_10 10000000000000000000000000000000000000000000.0000000000 +d53_10 10000000000000000000000000000000000000000000.0000000000 +f -1e24 +f 0 +f 1e38 +f 3.40282e38 +f0 -100000000000 +f0 0 +f0 12345.1 +f0 1e38 +f0 3.40282e38 +f20_3 -99999998430674940.000 +f20_3 0.000 +f20_3 56789.988 +f20_3 99999998430674940.000 +f20_3 99999998430674940.000 +f23_0 -1000 +f23_0 0 +f23_0 123457000 +f23_0 1e38 +f23_0 3.40282e38 +r1_1 -0.9 +r1_1 0.0 +r1_1 0.9 +r1_1 0.9 +r1_1 0.9 +INSERT INTO t1 VALUES ( +999999999999999999999999999999999999999, +999999999999999999999999999999999999999.9999999999999999, +1.9, +999999999999999999999999999999999999999.9, +999999999999999999.999, +9999999999999999999999999999999999999999999999999999999999999999999999999999999999, +99, +1.9999999999, +1999999999999999999999999999999999999999999999999999999, +19999999999999999999999999999999999999999999.9999999999 +); +Warnings: +Warning 1916 Got overflow when converting '' to DECIMAL. Value truncated. +Warning 1264 Out of range value for column 'f' at row 1 +Warning 1264 Out of range value for column 'f0' at row 1 +Warning 1264 Out of range value for column 'r1_1' at row 1 +Warning 1264 Out of range value for column 'f23_0' at row 1 +Warning 1264 Out of range value for column 'f20_3' at row 1 +Warning 1264 Out of range value for column 'd1_0' at row 1 +Warning 1264 Out of range value for column 'd10_10' at row 1 +Warning 1264 Out of range value for column 'd53' at row 1 +Warning 1264 Out of range value for column 'd53_10' at row 1 +SELECT * FROM t1; +f 12345.1 +d -1e60 +d 0 +d 11111111.111 +d 1e43 +d 1e65 +d 1e81 +d10_10 -0.9999999999 +d10_10 0.0000000000 +d10_10 0.0123456789 +d10_10 0.9999999999 +d10_10 0.9999999999 +d10_10 10000000000000000000000000000000000000000000.0000000000 +d1_0 -9 +d1_0 0 +d1_0 8 +d1_0 9 +d1_0 9 +d1_0 9 +d53 -1000000000000000000000000000000 +d53 0 +d53 10000000000000000000000000000000000000000000 +d53 100000000000000000000000000000000000000000000000000000 +d53 100000000000000000000000000000000000000000000000000000 +d53 1234566789123456800 +d53_10 -10000000000000000000000000000000000000000000.0000000000 +d53_10 0.0000000000 +d53_10 100000000000000000.0000000000 +d53_10 10000000000000000000000000000000000000000000.0000000000 +d53_10 10000000000000000000000000000000000000000000.0000000000 +d53_10 10000000000000000000000000000000000000000000.0000000000 +f -1e24 +f 0 +f 1e38 +f 3.40282e38 +f 3.40282e38 +f0 -100000000000 +f0 0 +f0 12345.1 +f0 1e38 +f0 3.40282e38 +f0 3.40282e38 +f20_3 -99999998430674940.000 +f20_3 0.000 +f20_3 56789.988 +f20_3 99999998430674940.000 +f20_3 99999998430674940.000 +f20_3 99999998430674940.000 +f23_0 -1000 +f23_0 0 +f23_0 123457000 +f23_0 1e38 +f23_0 3.40282e38 +f23_0 3.40282e38 +r1_1 -0.9 +r1_1 0.0 +r1_1 0.9 +r1_1 0.9 +r1_1 0.9 +r1_1 0.9 +ALTER TABLE t1 ADD COLUMN d0_0 DOUBLE(0,0); +ERROR 42000: Display width out of range for 'd0_0' (max = 255) +ALTER TABLE t1 ADD COLUMN n66_6 DECIMAL(256,1); +ERROR 42000: Too big precision 256 specified for 'n66_6'. Maximum is 65. +ALTER TABLE t1 ADD COLUMN n66_66 DECIMAL(40,35); +ERROR 42000: Too big scale 35 specified for 'n66_66'. Maximum is 30. +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c FLOAT NOT NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c float NO NULL +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +DROP TABLE t1; +CREATE TABLE t1 (c FLOAT NOT NULL, +c2 FLOAT NOT NULL DEFAULT 1.1 +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c float NO NULL +c2 float NO 1.1 +ALTER TABLE t1 ADD COLUMN err FLOAT NOT NULL DEFAULT NULL; +ERROR 42000: Invalid default value for 'err' +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +SELECT HEX(c), HEX(c2) FROM t1; +HEX(c) HEX(c2) +INSERT INTO t1 (c2) VALUES (NULL); +ERROR 23000: Column 'c2' cannot be null +INSERT INTO t1 (c) VALUES (1.1 ); +SELECT COUNT(c), COUNT(c2) FROM t1; +COUNT(c) COUNT(c2) +1 1 +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c DOUBLE NOT NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c double NO NULL +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +DROP TABLE t1; +CREATE TABLE t1 (c DOUBLE NOT NULL, +c2 DOUBLE NOT NULL DEFAULT 0 +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c double NO NULL +c2 double NO 0 +ALTER TABLE t1 ADD COLUMN err DOUBLE NOT NULL DEFAULT NULL; +ERROR 42000: Invalid default value for 'err' +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +SELECT HEX(c), HEX(c2) FROM t1; +HEX(c) HEX(c2) +INSERT INTO t1 (c2) VALUES (NULL); +ERROR 23000: Column 'c2' cannot be null +INSERT INTO t1 (c) VALUES (0); +SELECT COUNT(c), COUNT(c2) FROM t1; +COUNT(c) COUNT(c2) +1 1 +DROP TABLE t1; +# +# INT columns +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (i INT NOT NULL, +i0 INT(0) NOT NULL, +i1 INT(1) NOT NULL, +i20 INT(20) NOT NULL, +t TINYINT NOT NULL, +t0 TINYINT(0) NOT NULL, +t1 TINYINT(1) NOT NULL, +t20 TINYINT(20) NOT NULL, +s SMALLINT NOT NULL, +s0 SMALLINT(0) NOT NULL, +s1 SMALLINT(1) NOT NULL, +s20 SMALLINT(20) NOT NULL, +m MEDIUMINT NOT NULL, +m0 MEDIUMINT(0) NOT NULL, +m1 MEDIUMINT(1) NOT NULL, +m20 MEDIUMINT(20) NOT NULL, +b BIGINT NOT NULL, +b0 BIGINT(0) NOT NULL, +b1 BIGINT(1) NOT NULL, +b20 BIGINT(20) NOT NULL +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +i int(11) # # # +i0 int(11) # # # +i1 int(1) # # # +i20 int(20) # # # +t tinyint(4) # # # +t0 tinyint(4) # # # +t1 tinyint(1) # # # +t20 tinyint(20) # # # +s smallint(6) # # # +s0 smallint(6) # # # +s1 smallint(1) # # # +s20 smallint(20) # # # +m mediumint(9) # # # +m0 mediumint(9) # # # +m1 mediumint(1) # # # +m20 mediumint(20) # # # +b bigint(20) # # # +b0 bigint(20) # # # +b1 bigint(1) # # # +b20 bigint(20) # # # +INSERT INTO t1 VALUES (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20); +INSERT INTO t1 VALUES (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); +INSERT INTO t1 VALUES (2147483647,2147483647,2147483647,2147483647,127,127,127,127,32767,32767,32767,32767,8388607,8388607,8388607,8388607,9223372036854775807,9223372036854775807,9223372036854775807,9223372036854775807); +SELECT * FROM t1; +i i0 i1 i20 t t0 t1 t20 s s0 s1 s20 m m0 m1 m20 b b0 b1 b20 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 +2147483647 2147483647 2147483647 2147483647 127 127 127 127 32767 32767 32767 32767 8388607 8388607 8388607 8388607 9223372036854775807 9223372036854775807 9223372036854775807 9223372036854775807 +INSERT INTO t1 VALUES (-2147483648,-2147483648,-2147483648,-2147483648,-128,-128,-128,-128,-32768,-32768,-32768,-32768,-8388608,-8388608,-8388608,-8388608,-9223372036854775808,-9223372036854775808,-9223372036854775808,-9223372036854775808); +INSERT INTO t1 VALUES (4294967295,4294967295,4294967295,4294967295,255,255,255,255,65535,65535,65535,65535,16777215,16777215,16777215,16777215,18446744073709551615,18446744073709551615,18446744073709551615,18446744073709551615); +Warnings: +Warning 1264 Out of range value for column 'i' at row 1 +Warning 1264 Out of range value for column 'i0' at row 1 +Warning 1264 Out of range value for column 'i1' at row 1 +Warning 1264 Out of range value for column 'i20' at row 1 +Warning 1264 Out of range value for column 't' at row 1 +Warning 1264 Out of range value for column 't0' at row 1 +Warning 1264 Out of range value for column 't1' at row 1 +Warning 1264 Out of range value for column 't20' at row 1 +Warning 1264 Out of range value for column 's' at row 1 +Warning 1264 Out of range value for column 's0' at row 1 +Warning 1264 Out of range value for column 's1' at row 1 +Warning 1264 Out of range value for column 's20' at row 1 +Warning 1264 Out of range value for column 'm' at row 1 +Warning 1264 Out of range value for column 'm0' at row 1 +Warning 1264 Out of range value for column 'm1' at row 1 +Warning 1264 Out of range value for column 'm20' at row 1 +Warning 1264 Out of range value for column 'b' at row 1 +Warning 1264 Out of range value for column 'b0' at row 1 +Warning 1264 Out of range value for column 'b1' at row 1 +Warning 1264 Out of range value for column 'b20' at row 1 +SELECT * FROM t1; +i i0 i1 i20 t t0 t1 t20 s s0 s1 s20 m m0 m1 m20 b b0 b1 b20 +-2147483648 -2147483648 -2147483648 -2147483648 -128 -128 -128 -128 -32768 -32768 -32768 -32768 -8388608 -8388608 -8388608 -8388608 -9223372036854775808 -9223372036854775808 -9223372036854775808 -9223372036854775808 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 +2147483647 2147483647 2147483647 2147483647 127 127 127 127 32767 32767 32767 32767 8388607 8388607 8388607 8388607 9223372036854775807 9223372036854775807 9223372036854775807 9223372036854775807 +2147483647 2147483647 2147483647 2147483647 127 127 127 127 32767 32767 32767 32767 8388607 8388607 8388607 8388607 9223372036854775807 9223372036854775807 9223372036854775807 9223372036854775807 +INSERT INTO t1 VALUES (-2147483649,-2147483649,-2147483649,-2147483649,-129,-129,-129,-129,-32769,-32769,-32769,-32769,-8388609,-8388609,-8388609,-8388609,-9223372036854775809,-9223372036854775809,-9223372036854775809,-9223372036854775809); +Warnings: +Warning 1264 Out of range value for column 'i' at row 1 +Warning 1264 Out of range value for column 'i0' at row 1 +Warning 1264 Out of range value for column 'i1' at row 1 +Warning 1264 Out of range value for column 'i20' at row 1 +Warning 1264 Out of range value for column 't' at row 1 +Warning 1264 Out of range value for column 't0' at row 1 +Warning 1264 Out of range value for column 't1' at row 1 +Warning 1264 Out of range value for column 't20' at row 1 +Warning 1264 Out of range value for column 's' at row 1 +Warning 1264 Out of range value for column 's0' at row 1 +Warning 1264 Out of range value for column 's1' at row 1 +Warning 1264 Out of range value for column 's20' at row 1 +Warning 1264 Out of range value for column 'm' at row 1 +Warning 1264 Out of range value for column 'm0' at row 1 +Warning 1264 Out of range value for column 'm1' at row 1 +Warning 1264 Out of range value for column 'm20' at row 1 +Warning 1264 Out of range value for column 'b' at row 1 +Warning 1264 Out of range value for column 'b0' at row 1 +Warning 1264 Out of range value for column 'b1' at row 1 +Warning 1264 Out of range value for column 'b20' at row 1 +INSERT INTO t1 VALUES (4294967296,4294967296,4294967296,4294967296,256,256,256,256,65536,65536,65536,65536,16777216,16777216,16777216,16777216,18446744073709551616,18446744073709551616,18446744073709551616,18446744073709551616); +Warnings: +Warning 1264 Out of range value for column 'i' at row 1 +Warning 1264 Out of range value for column 'i0' at row 1 +Warning 1264 Out of range value for column 'i1' at row 1 +Warning 1264 Out of range value for column 'i20' at row 1 +Warning 1264 Out of range value for column 't' at row 1 +Warning 1264 Out of range value for column 't0' at row 1 +Warning 1264 Out of range value for column 't1' at row 1 +Warning 1264 Out of range value for column 't20' at row 1 +Warning 1264 Out of range value for column 's' at row 1 +Warning 1264 Out of range value for column 's0' at row 1 +Warning 1264 Out of range value for column 's1' at row 1 +Warning 1264 Out of range value for column 's20' at row 1 +Warning 1264 Out of range value for column 'm' at row 1 +Warning 1264 Out of range value for column 'm0' at row 1 +Warning 1264 Out of range value for column 'm1' at row 1 +Warning 1264 Out of range value for column 'm20' at row 1 +Warning 1264 Out of range value for column 'b' at row 1 +Warning 1264 Out of range value for column 'b0' at row 1 +Warning 1264 Out of range value for column 'b1' at row 1 +Warning 1264 Out of range value for column 'b20' at row 1 +INSERT INTO t1 SELECT b,b,b,b,b,b,b,b,b,b,b,b,b,b,b,b,b,b,b,b FROM t1 WHERE b IN (-9223372036854775808,9223372036854775807,18446744073709551615); +Warnings: +Warning 1264 Out of range value for column 'i' at row 1 +Warning 1264 Out of range value for column 'i0' at row 1 +Warning 1264 Out of range value for column 'i1' at row 1 +Warning 1264 Out of range value for column 'i20' at row 1 +Warning 1264 Out of range value for column 't' at row 1 +Warning 1264 Out of range value for column 't0' at row 1 +Warning 1264 Out of range value for column 't1' at row 1 +Warning 1264 Out of range value for column 't20' at row 1 +Warning 1264 Out of range value for column 's' at row 1 +Warning 1264 Out of range value for column 's0' at row 1 +Warning 1264 Out of range value for column 's1' at row 1 +Warning 1264 Out of range value for column 's20' at row 1 +Warning 1264 Out of range value for column 'm' at row 1 +Warning 1264 Out of range value for column 'm0' at row 1 +Warning 1264 Out of range value for column 'm1' at row 1 +Warning 1264 Out of range value for column 'm20' at row 1 +Warning 1264 Out of range value for column 'i' at row 2 +Warning 1264 Out of range value for column 'i0' at row 2 +Warning 1264 Out of range value for column 'i1' at row 2 +Warning 1264 Out of range value for column 'i20' at row 2 +Warning 1264 Out of range value for column 't' at row 2 +Warning 1264 Out of range value for column 't0' at row 2 +Warning 1264 Out of range value for column 't1' at row 2 +Warning 1264 Out of range value for column 't20' at row 2 +Warning 1264 Out of range value for column 's' at row 2 +Warning 1264 Out of range value for column 's0' at row 2 +Warning 1264 Out of range value for column 's1' at row 2 +Warning 1264 Out of range value for column 's20' at row 2 +Warning 1264 Out of range value for column 'm' at row 2 +Warning 1264 Out of range value for column 'm0' at row 2 +Warning 1264 Out of range value for column 'm1' at row 2 +Warning 1264 Out of range value for column 'm20' at row 2 +Warning 1264 Out of range value for column 'i' at row 3 +Warning 1264 Out of range value for column 'i0' at row 3 +Warning 1264 Out of range value for column 'i1' at row 3 +Warning 1264 Out of range value for column 'i20' at row 3 +Warning 1264 Out of range value for column 't' at row 3 +Warning 1264 Out of range value for column 't0' at row 3 +Warning 1264 Out of range value for column 't1' at row 3 +Warning 1264 Out of range value for column 't20' at row 3 +Warning 1264 Out of range value for column 's' at row 3 +Warning 1264 Out of range value for column 's0' at row 3 +Warning 1264 Out of range value for column 's1' at row 3 +Warning 1264 Out of range value for column 's20' at row 3 +Warning 1264 Out of range value for column 'm' at row 3 +Warning 1264 Out of range value for column 'm0' at row 3 +Warning 1264 Out of range value for column 'm1' at row 3 +Warning 1264 Out of range value for column 'm20' at row 3 +Warning 1264 Out of range value for column 'i' at row 4 +Warning 1264 Out of range value for column 'i0' at row 4 +Warning 1264 Out of range value for column 'i1' at row 4 +Warning 1264 Out of range value for column 'i20' at row 4 +Warning 1264 Out of range value for column 't' at row 4 +Warning 1264 Out of range value for column 't0' at row 4 +Warning 1264 Out of range value for column 't1' at row 4 +Warning 1264 Out of range value for column 't20' at row 4 +Warning 1264 Out of range value for column 's' at row 4 +Warning 1264 Out of range value for column 's0' at row 4 +Warning 1264 Out of range value for column 's1' at row 4 +Warning 1264 Out of range value for column 's20' at row 4 +Warning 1264 Out of range value for column 'm' at row 4 +Warning 1264 Out of range value for column 'm0' at row 4 +Warning 1264 Out of range value for column 'm1' at row 4 +Warning 1264 Out of range value for column 'm20' at row 4 +SELECT * FROM t1; +i i0 i1 i20 t t0 t1 t20 s s0 s1 s20 m m0 m1 m20 b b0 b1 b20 +-2147483648 -2147483648 -2147483648 -2147483648 -128 -128 -128 -128 -32768 -32768 -32768 -32768 -8388608 -8388608 -8388608 -8388608 -9223372036854775808 -9223372036854775808 -9223372036854775808 -9223372036854775808 +-2147483648 -2147483648 -2147483648 -2147483648 -128 -128 -128 -128 -32768 -32768 -32768 -32768 -8388608 -8388608 -8388608 -8388608 -9223372036854775808 -9223372036854775808 -9223372036854775808 -9223372036854775808 +-2147483648 -2147483648 -2147483648 -2147483648 -128 -128 -128 -128 -32768 -32768 -32768 -32768 -8388608 -8388608 -8388608 -8388608 -9223372036854775808 -9223372036854775808 -9223372036854775808 -9223372036854775808 +-2147483648 -2147483648 -2147483648 -2147483648 -128 -128 -128 -128 -32768 -32768 -32768 -32768 -8388608 -8388608 -8388608 -8388608 -9223372036854775808 -9223372036854775808 -9223372036854775808 -9223372036854775808 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 +2147483647 2147483647 2147483647 2147483647 127 127 127 127 32767 32767 32767 32767 8388607 8388607 8388607 8388607 9223372036854775807 9223372036854775807 9223372036854775807 9223372036854775807 +2147483647 2147483647 2147483647 2147483647 127 127 127 127 32767 32767 32767 32767 8388607 8388607 8388607 8388607 9223372036854775807 9223372036854775807 9223372036854775807 9223372036854775807 +2147483647 2147483647 2147483647 2147483647 127 127 127 127 32767 32767 32767 32767 8388607 8388607 8388607 8388607 9223372036854775807 9223372036854775807 9223372036854775807 9223372036854775807 +2147483647 2147483647 2147483647 2147483647 127 127 127 127 32767 32767 32767 32767 8388607 8388607 8388607 8388607 9223372036854775807 9223372036854775807 9223372036854775807 9223372036854775807 +2147483647 2147483647 2147483647 2147483647 127 127 127 127 32767 32767 32767 32767 8388607 8388607 8388607 8388607 9223372036854775807 9223372036854775807 9223372036854775807 9223372036854775807 +2147483647 2147483647 2147483647 2147483647 127 127 127 127 32767 32767 32767 32767 8388607 8388607 8388607 8388607 9223372036854775807 9223372036854775807 9223372036854775807 9223372036854775807 +ALTER TABLE t1 ADD COLUMN i257 INT(257); +ERROR 42000: Display width out of range for 'i257' (max = 255) +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c INT NOT NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c int(11) NO NULL +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +DROP TABLE t1; +CREATE TABLE t1 (c INT NOT NULL, +c2 INT NOT NULL DEFAULT 2147483647 +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c int(11) NO NULL +c2 int(11) NO 2147483647 +ALTER TABLE t1 ADD COLUMN err INT NOT NULL DEFAULT NULL; +ERROR 42000: Invalid default value for 'err' +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +SELECT HEX(c), HEX(c2) FROM t1; +HEX(c) HEX(c2) +INSERT INTO t1 (c2) VALUES (NULL); +ERROR 23000: Column 'c2' cannot be null +INSERT INTO t1 (c) VALUES (2147483647); +SELECT COUNT(c), COUNT(c2) FROM t1; +COUNT(c) COUNT(c2) +1 1 +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c TINYINT NOT NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c tinyint(4) NO NULL +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +DROP TABLE t1; +CREATE TABLE t1 (c TINYINT NOT NULL, +c2 TINYINT NOT NULL DEFAULT 127 +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c tinyint(4) NO NULL +c2 tinyint(4) NO 127 +ALTER TABLE t1 ADD COLUMN err TINYINT NOT NULL DEFAULT NULL; +ERROR 42000: Invalid default value for 'err' +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +SELECT HEX(c), HEX(c2) FROM t1; +HEX(c) HEX(c2) +INSERT INTO t1 (c2) VALUES (NULL); +ERROR 23000: Column 'c2' cannot be null +INSERT INTO t1 (c) VALUES (127 ); +SELECT COUNT(c), COUNT(c2) FROM t1; +COUNT(c) COUNT(c2) +1 1 +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c SMALLINT NOT NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c smallint(6) NO NULL +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +DROP TABLE t1; +CREATE TABLE t1 (c SMALLINT NOT NULL, +c2 SMALLINT NOT NULL DEFAULT 0 +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c smallint(6) NO NULL +c2 smallint(6) NO 0 +ALTER TABLE t1 ADD COLUMN err SMALLINT NOT NULL DEFAULT NULL; +ERROR 42000: Invalid default value for 'err' +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +SELECT HEX(c), HEX(c2) FROM t1; +HEX(c) HEX(c2) +INSERT INTO t1 (c2) VALUES (NULL); +ERROR 23000: Column 'c2' cannot be null +INSERT INTO t1 (c) VALUES (0); +SELECT COUNT(c), COUNT(c2) FROM t1; +COUNT(c) COUNT(c2) +1 1 +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c MEDIUMINT NOT NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c mediumint(9) NO NULL +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +DROP TABLE t1; +CREATE TABLE t1 (c MEDIUMINT NOT NULL, +c2 MEDIUMINT NOT NULL DEFAULT 1 +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c mediumint(9) NO NULL +c2 mediumint(9) NO 1 +ALTER TABLE t1 ADD COLUMN err MEDIUMINT NOT NULL DEFAULT NULL; +ERROR 42000: Invalid default value for 'err' +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +SELECT HEX(c), HEX(c2) FROM t1; +HEX(c) HEX(c2) +INSERT INTO t1 (c2) VALUES (NULL); +ERROR 23000: Column 'c2' cannot be null +INSERT INTO t1 (c) VALUES (1); +SELECT COUNT(c), COUNT(c2) FROM t1; +COUNT(c) COUNT(c2) +1 1 +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c BIGINT NOT NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c bigint(20) NO NULL +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +DROP TABLE t1; +CREATE TABLE t1 (c BIGINT NOT NULL, +c2 BIGINT NOT NULL DEFAULT 9223372036854775807 +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c bigint(20) NO NULL +c2 bigint(20) NO 9223372036854775807 +ALTER TABLE t1 ADD COLUMN err BIGINT NOT NULL DEFAULT NULL; +ERROR 42000: Invalid default value for 'err' +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +SELECT HEX(c), HEX(c2) FROM t1; +HEX(c) HEX(c2) +INSERT INTO t1 (c2) VALUES (NULL); +ERROR 23000: Column 'c2' cannot be null +INSERT INTO t1 (c) VALUES (9223372036854775807); +SELECT COUNT(c), COUNT(c2) FROM t1; +COUNT(c) COUNT(c2) +1 1 +DROP TABLE t1; +# +# SET columns +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (a SET('') NOT NULL, +b SET('test1','test2','test3','test4','test5') NOT NULL, +c SET('01','02','03','04','05','06','07','08','09','10','11','12','13','14','15','16','17','18','19','20','21','22','23','24','25','26','27','28','29','30','31','32','33','34','35','36','37','38','39','40','41','42','43','44','45','46','47','48','49','50''51','52','53','54','55','56','57','58','59','60','61','62','63','64') NOT NULL +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +a set('') # # # +b set('test1','test2','test3','test4','test5') # # # +c set('01','02','03','04','05','06','07','08','09','10','11','12','13','14','15','16','17','18','19','20','21','22','23','24','25','26','27','28','29','30','31','32','33','34','35','36','37','38','39','40','41','42','43','44','45','46','47','48','49','50''51','52','53','54','55','56','57','58','59','60','61','62','63','64') # # # +INSERT INTO t1 VALUES +('','test2,test3','01,34,44,,23'), +('',5,2), +(',','test4,test2',''); +Warnings: +Warning 1265 Data truncated for column 'c' at row 1 +SELECT * FROM t1; +a b c + test1,test3 02 + test2,test3 01,23,34,44 + test2,test4 +INSERT INTO t1 VALUES (0,'test6',-1); +Warnings: +Warning 1265 Data truncated for column 'b' at row 1 +Warning 1265 Data truncated for column 'c' at row 1 +SELECT * FROM t1; +a b c + 01,02,03,04,05,06,07,08,09,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50'51,52,53,54,55,56,57,58,59,60,61,62,63,64 + test1,test3 02 + test2,test3 01,23,34,44 + test2,test4 +ALTER TABLE t1 ADD COLUMN e SET('a','A') NOT NULL; +Warnings: +Note 1291 Column 'e' has duplicated value 'a' in SET +Note 1291 Column 'e' has duplicated value 'a' in SET +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +a set('') # # # +b set('test1','test2','test3','test4','test5') # # # +c set('01','02','03','04','05','06','07','08','09','10','11','12','13','14','15','16','17','18','19','20','21','22','23','24','25','26','27','28','29','30','31','32','33','34','35','36','37','38','39','40','41','42','43','44','45','46','47','48','49','50''51','52','53','54','55','56','57','58','59','60','61','62','63','64') # # # +e set('a','A') # # # +ALTER TABLE t1 ADD COLUMN f SET('1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',' ','11','12','13','14','15','16','17','18','19','1a','1b','1c','1d','1e','1f','1g','1h','1i','1j','1k','1l','1m','1n','1o','1p','1q','1r','1s','1t','1u','1v','1w','1x','1y','1z','20','21','22','23','24','25','26','27','28','29','2a','2b','2c','2d','2e','2f','2g','2h','2i','2j','2k','2l','2m','2n','2o','2p','2q','2r','2s','2t','2u','2v','2w','2x','2y','2z','30','31','32','33','34','35','36','37','38','39','3a','3b','3c','3d','3e','3f','3g','3h','3i') NOT NULL; +ERROR HY000: Too many strings for column f and SET +SELECT * FROM t1 WHERE FIND_IN_SET('test2',b)>0 OR a != ''; +a b c e + test2,test3 01,23,34,44 + test2,test4 +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c SET('test1','test2','test3') NOT NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c set('test1','test2','test3') NO NULL +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +DROP TABLE t1; +CREATE TABLE t1 (c SET('test1','test2','test3') NOT NULL, +c2 SET('test1','test2','test3') NOT NULL DEFAULT 'test2,test3' +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c set('test1','test2','test3') NO NULL +c2 set('test1','test2','test3') NO test2,test3 +ALTER TABLE t1 ADD COLUMN err SET('test1','test2','test3') NOT NULL DEFAULT NULL; +ERROR 42000: Invalid default value for 'err' +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +SELECT HEX(c), HEX(c2) FROM t1; +HEX(c) HEX(c2) +INSERT INTO t1 (c2) VALUES (NULL); +ERROR 23000: Column 'c2' cannot be null +INSERT INTO t1 (c) VALUES ('test2,test3'); +SELECT COUNT(c), COUNT(c2) FROM t1; +COUNT(c) COUNT(c2) +1 1 +DROP TABLE t1; +# +# TEXT columns +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (t TEXT NOT NULL, +t0 TEXT(0) NOT NULL, +t1 TEXT(1) NOT NULL, +t300 TEXT(300) NOT NULL, +tm TEXT(65535) NOT NULL, +t70k TEXT(70000) NOT NULL, +t17m TEXT(17000000) NOT NULL, +tt TINYTEXT NOT NULL, +m MEDIUMTEXT NOT NULL, +l LONGTEXT NOT NULL +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +t text # # # +t0 text # # # +t1 tinytext # # # +t300 text # # # +tm text # # # +t70k mediumtext # # # +t17m longtext # # # +tt tinytext # # # +m mediumtext # # # +l longtext # # # +INSERT INTO t1 VALUES +('','','','','','','','','',''), +('a','b','c','d','e','f','g','h','i','j'), +('test1','test2','test3','test4','test5','test6','test7','test8','test9','test10'), +( REPEAT('a',65535), REPEAT('b',65535), REPEAT('c',255), REPEAT('d',65535), REPEAT('e',65535), REPEAT('f',1048576), REPEAT('g',1048576), REPEAT('h',255), REPEAT('i',1048576), REPEAT('j',1048576) ); +SELECT LENGTH(t), LENGTH(t0), LENGTH(t1), LENGTH(t300), LENGTH(tm), LENGTH(t70k), LENGTH(t17m), LENGTH(tt), LENGTH(m), LENGTH(l) FROM t1; +LENGTH(t) LENGTH(t0) LENGTH(t1) LENGTH(t300) LENGTH(tm) LENGTH(t70k) LENGTH(t17m) LENGTH(tt) LENGTH(m) LENGTH(l) +0 0 0 0 0 0 0 0 0 0 +1 1 1 1 1 1 1 1 1 1 +5 5 5 5 5 5 5 5 5 6 +65535 65535 255 65535 65535 1048576 1048576 255 1048576 1048576 +INSERT INTO t1 VALUES +( REPEAT('a',65536), REPEAT('b',65536), REPEAT('c',256), REPEAT('d',65536), REPEAT('e',65536), REPEAT('f',1048576), REPEAT('g',1048576), REPEAT('h',256), REPEAT('i',1048576), REPEAT('j',1048576) ); +Warnings: +Warning 1265 Data truncated for column 't' at row 1 +Warning 1265 Data truncated for column 't0' at row 1 +Warning 1265 Data truncated for column 't1' at row 1 +Warning 1265 Data truncated for column 't300' at row 1 +Warning 1265 Data truncated for column 'tm' at row 1 +Warning 1265 Data truncated for column 'tt' at row 1 +SELECT LENGTH(t), LENGTH(t0), LENGTH(t1), LENGTH(t300), LENGTH(tm), LENGTH(t70k), LENGTH(t17m), LENGTH(tt), LENGTH(m), LENGTH(l) FROM t1; +LENGTH(t) LENGTH(t0) LENGTH(t1) LENGTH(t300) LENGTH(tm) LENGTH(t70k) LENGTH(t17m) LENGTH(tt) LENGTH(m) LENGTH(l) +0 0 0 0 0 0 0 0 0 0 +1 1 1 1 1 1 1 1 1 1 +5 5 5 5 5 5 5 5 5 6 +65535 65535 255 65535 65535 1048576 1048576 255 1048576 1048576 +65535 65535 255 65535 65535 1048576 1048576 255 1048576 1048576 +ALTER TABLE t1 ADD COLUMN ttt TEXT(4294967296); +ERROR 42000: Display width out of range for 'ttt' (max = 4294967295) +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c TEXT NOT NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c text NO NULL +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c TINYTEXT NOT NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c tinytext NO NULL +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c MEDIUMTEXT NOT NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c mediumtext NO NULL +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c LONGTEXT NOT NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c longtext NO NULL +INSERT INTO t1 (c) VALUES (NULL); +ERROR 23000: Column 'c' cannot be null +DROP TABLE t1; diff --git a/mysql-test/suite/storage_engine/col_opt_not_null.test b/mysql-test/suite/storage_engine/col_opt_not_null.test new file mode 100644 index 00000000000..2cd0e909536 --- /dev/null +++ b/mysql-test/suite/storage_engine/col_opt_not_null.test @@ -0,0 +1,260 @@ +# +# NOT NULL column attribute +# + +let $extra_col_opts = NOT NULL; + +--source have_engine.inc + +--echo # +--echo # BINARY columns +--echo # + +--source type_binary.inc +--let $col_definition = BINARY $default_col_opts +--let $col_default = 0 +--source col_not_null.inc + +--echo # +--echo # VARBINARY columns +--echo # + +--source type_varbinary.inc +--let $col_definition = VARBINARY(64) $default_col_opts +--let $col_default = 'test' +--source col_not_null.inc + +--echo # +--echo # BIT columns +--echo # + +--source type_bit.inc +--let $col_definition = BIT $default_col_opts +--let $col_default = 1 +--source col_not_null.inc + +--echo # +--echo # BLOB columns +--echo # + +--source type_blob.inc + +--let $col_definition = BLOB $default_col_opts +--source col_not_null.inc + +--let $col_definition = TINYBLOB $default_col_opts +--source col_not_null.inc + +--let $col_definition = MEDIUMBLOB $default_col_opts +--source col_not_null.inc + +--let $col_definition = LONGBLOB $default_col_opts +--source col_not_null.inc + +--echo # +--echo # BOOL columns +--echo # + +--source type_bool.inc +--let $col_definition = BOOL $default_col_opts +--let $col_default = '0' +--source col_not_null.inc + +--echo # +--echo # CHAR columns +--echo # + +--source type_char.inc +--let $col_definition = CHAR $default_col_opts +--let $col_default = '_' +--source col_not_null.inc + +--echo # +--echo # VARCHAR columns +--echo # + +--source type_varchar.inc +--let $col_definition = VARCHAR(64) $default_col_opts +--let $col_default = 'test default' +--source col_not_null.inc + +--echo # +--echo # date and time columns +--echo # + +--source type_date_time.inc + +--let $col_definition = DATE $default_col_opts +--let $col_default = '2012-12-21' +--source col_not_null.inc + +--let $col_definition = DATETIME $default_col_opts +--let $col_default = '2012-12-21 12:21:12' +--source col_not_null.inc + +# For TIMESTAMP the behavior is non-standard + +# $col_opts already contains NOT NULL part (it's set in have_engine.inc) + +let $create_definition = + c TIMESTAMP $col_opts, + c2 TIMESTAMP $col_opts DEFAULT '2012-02-21 12:21:12' +; +--source create_table.inc +if ($mysql_errname) +{ + --let $functionality = TIMESTAMP type or NOT NULL columns or DEFAULT + --source unexpected_result.inc +} +if (!$mysql_errname) +{ + --let $error_codes = ER_INVALID_DEFAULT + --let $alter_definition = ADD COLUMN err TIMESTAMP $col_opts DEFAULT NULL + --source alter_table.inc + if ($mysql_errname!=ER_INVALID_DEFAULT) + { + --let $functionality = ALTER or DEFAULT + --source unexpected_result.inc + } + + INSERT INTO t1 (c) VALUES (NULL); + INSERT INTO t1 (c2) VALUES (NULL); + --replace_regex /2012-02-21 12:21:12// /[[:digit:]]{4}-[[:digit:]]{2}-[[:digit:]]{2} [[:digit:]]{2}:[[:digit:]]{2}:[[:digit:]]{2}// + SELECT c, c2 FROM t1; + + DROP TABLE t1; +} + +--let $create_definition = c TIMESTAMP $col_opts +--source create_table.inc +if ($mysql_errname) +{ + --let $functionality = TIMESTAMP type + --source unexpected_result.inc +} +if (!$mysql_errname) +{ + SHOW COLUMNS IN t1; + + INSERT INTO t1 (c) VALUES (NULL); + if ($mysql_errname) + { + --let $functionality = TIMESTAMP + --source unexpected_result.inc + } + + --replace_regex /[[:digit:]]{4}-[[:digit:]]{2}-[[:digit:]]{2} [[:digit:]]{2}:[[:digit:]]{2}:[[:digit:]]{2}// + SELECT * FROM t1; + DROP TABLE t1; +} + +# End of TIMESTAMP exception + + +--let $col_definition = TIME $default_col_opts +--let $col_default = '12:21:12' +--source col_not_null.inc + +--let $col_definition = YEAR $default_col_opts +--let $col_default = '2012' +--source col_not_null.inc + +--let $col_definition = YEAR(2) $default_col_opts +--let $col_default = '12' +--source col_not_null.inc + + +--echo # +--echo # ENUM columns +--echo # + +--source type_enum.inc + +--let $col_definition = ENUM('test1','test2','test3') $default_col_opts +--let $col_default = 'test2' +--source col_not_null.inc + + +--echo # +--echo # Fixed point columns (NUMERIC, DECIMAL) +--echo # + +--source type_fixed.inc + +--let $col_definition = DECIMAL $default_col_opts +--let $col_default = 1.1 +--source col_not_null.inc + +--let $col_definition = NUMERIC $default_col_opts +--let $col_default = 0 +--source col_not_null.inc + +--echo # +--echo # Floating point columns (FLOAT, DOUBLE) +--echo # + +--source type_float.inc + +--let $col_definition = FLOAT $default_col_opts +--let $col_default = 1.1 +--source col_not_null.inc + +--let $col_definition = DOUBLE $default_col_opts +--let $col_default = 0 +--source col_not_null.inc + +--echo # +--echo # INT columns +--echo # + +--source type_int.inc + +--let $col_definition = INT $default_col_opts +--let $col_default = 2147483647 +--source col_not_null.inc + +--let $col_definition = TINYINT $default_col_opts +--let $col_default = 127 +--source col_not_null.inc + +--let $col_definition = SMALLINT $default_col_opts +--let $col_default = 0 +--source col_not_null.inc + +--let $col_definition = MEDIUMINT $default_col_opts +--let $col_default = 1 +--source col_not_null.inc + +--let $col_definition = BIGINT $default_col_opts +--let $col_default = 9223372036854775807 +--source col_not_null.inc + +--echo # +--echo # SET columns +--echo # + +--source type_set.inc +--let $col_definition = SET('test1','test2','test3') $default_col_opts +--let $col_default = 'test2,test3' +--source col_not_null.inc + +--echo # +--echo # TEXT columns +--echo # + +--source type_text.inc + +--let $col_definition = TEXT $default_col_opts +--source col_not_null.inc + +--let $col_definition = TINYTEXT $default_col_opts +--source col_not_null.inc + +--let $col_definition = MEDIUMTEXT $default_col_opts +--source col_not_null.inc + +--let $col_definition = LONGTEXT $default_col_opts +--source col_not_null.inc + +--source cleanup_engine.inc + diff --git a/mysql-test/suite/storage_engine/col_opt_null.result b/mysql-test/suite/storage_engine/col_opt_null.result new file mode 100644 index 00000000000..c6a46f8c18f --- /dev/null +++ b/mysql-test/suite/storage_engine/col_opt_null.result @@ -0,0 +1,1991 @@ +# +# BINARY columns +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (b BINARY NULL, +b0 BINARY(0) NULL, +b1 BINARY(1) NULL, +b20 BINARY(20) NULL, +b255 BINARY(255) NULL +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +b binary(1) # # # # +b0 binary(0) # # # # +b1 binary(1) # # # # +b20 binary(20) # # # # +b255 binary(255) # # # # +INSERT INTO t1 VALUES ('','','','',''); +INSERT INTO t1 VALUES ('a','','b','abcdefghi klmnopqrst', 'Creating an article for the Knowledgebase is similar to asking questions. First, navigate to the category where you feel the article should be. Once there, double check that an article doesn\'t already exist which would work.'); +SELECT HEX(b), HEX(b0), HEX(b1), HEX(b20), HEX(b255) FROM t1; +HEX(b) HEX(b0) HEX(b1) HEX(b20) HEX(b255) +00 00 0000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +61 62 616263646566676869206B6C6D6E6F7071727374 4372656174696E6720616E2061727469636C6520666F7220746865204B6E6F776C65646765626173652069732073696D696C617220746F2061736B696E67207175657374696F6E732E2046697273742C206E6176696761746520746F207468652063617465676F727920776865726520796F75206665656C207468652061727469636C652073686F756C642062652E204F6E63652074686572652C20646F75626C6520636865636B207468617420616E2061727469636C6520646F65736E277420616C726561647920657869737420776869636820776F756C6420776F726B2E00000000000000000000000000000000000000000000000000000000000000 +INSERT INTO t1 VALUES ('abc', 'a', 'abc', REPEAT('a',21), REPEAT('x',256)); +Warnings: +Warning 1265 Data truncated for column 'b' at row 1 +Warning 1265 Data truncated for column 'b0' at row 1 +Warning 1265 Data truncated for column 'b1' at row 1 +Warning 1265 Data truncated for column 'b20' at row 1 +Warning 1265 Data truncated for column 'b255' at row 1 +INSERT INTO t1 SELECT b255, b255, b255, b255, CONCAT(b255,b255) FROM t1; +Warnings: +Warning 1265 Data truncated for column 'b' at row 1 +Warning 1265 Data truncated for column 'b0' at row 1 +Warning 1265 Data truncated for column 'b1' at row 1 +Warning 1265 Data truncated for column 'b20' at row 1 +Warning 1265 Data truncated for column 'b255' at row 1 +Warning 1265 Data truncated for column 'b' at row 2 +Warning 1265 Data truncated for column 'b0' at row 2 +Warning 1265 Data truncated for column 'b1' at row 2 +Warning 1265 Data truncated for column 'b20' at row 2 +Warning 1265 Data truncated for column 'b255' at row 2 +Warning 1265 Data truncated for column 'b' at row 3 +Warning 1265 Data truncated for column 'b0' at row 3 +Warning 1265 Data truncated for column 'b1' at row 3 +Warning 1265 Data truncated for column 'b20' at row 3 +Warning 1265 Data truncated for column 'b255' at row 3 +SELECT HEX(b), HEX(b0), HEX(b1), HEX(b20), HEX(b255) FROM t1; +HEX(b) HEX(b0) HEX(b1) HEX(b20) HEX(b255) +00 00 0000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00 00 0000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +43 43 4372656174696E6720616E2061727469636C6520 4372656174696E6720616E2061727469636C6520666F7220746865204B6E6F776C65646765626173652069732073696D696C617220746F2061736B696E67207175657374696F6E732E2046697273742C206E6176696761746520746F207468652063617465676F727920776865726520796F75206665656C207468652061727469636C652073686F756C642062652E204F6E63652074686572652C20646F75626C6520636865636B207468617420616E2061727469636C6520646F65736E277420616C726561647920657869737420776869636820776F756C6420776F726B2E00000000000000000000000000000000000000000000000000000000000000 +61 61 6161616161616161616161616161616161616161 787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878 +61 62 616263646566676869206B6C6D6E6F7071727374 4372656174696E6720616E2061727469636C6520666F7220746865204B6E6F776C65646765626173652069732073696D696C617220746F2061736B696E67207175657374696F6E732E2046697273742C206E6176696761746520746F207468652063617465676F727920776865726520796F75206665656C207468652061727469636C652073686F756C642062652E204F6E63652074686572652C20646F75626C6520636865636B207468617420616E2061727469636C6520646F65736E277420616C726561647920657869737420776869636820776F756C6420776F726B2E00000000000000000000000000000000000000000000000000000000000000 +78 78 7878787878787878787878787878787878787878 787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878 +ALTER TABLE t1 ADD COLUMN b257 BINARY(257) NULL; +ERROR 42000: Column length too big for column 'b257' (max = 255); use BLOB or TEXT instead +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +b binary(1) # # # # +b0 binary(0) # # # # +b1 binary(1) # # # # +b20 binary(20) # # # # +b255 binary(255) # # # # +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c BINARY NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c binary(1) YES NULL +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c), COUNT(*) FROM t1; +COUNT(c) COUNT(*) +0 1 +DROP TABLE t1; +CREATE TABLE t1 (c BINARY NULL, +c1 BINARY NULL DEFAULT NULL, +c2 BINARY NULL DEFAULT 0 +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c binary(1) YES NULL +c1 binary(1) YES NULL +c2 binary(1) YES 0 +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c2), COUNT(c1), COUNT(c), COUNT(*) FROM t1; +COUNT(c2) COUNT(c1) COUNT(c) COUNT(*) +1 0 0 1 +DROP TABLE t1; +# +# VARBINARY columns +# +DROP TABLE IF EXISTS t1, t2; +CREATE TABLE t1 (v0 VARBINARY(0) NULL, +v1 VARBINARY(1) NULL, +v64 VARBINARY(64) NULL, +v65000 VARBINARY(65000) NULL +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +v0 varbinary(0) # # # +v1 varbinary(1) # # # +v64 varbinary(64) # # # +v65000 varbinary(65000) # # # +CREATE TABLE t2 (v VARBINARY(65532) NULL) ENGINE= ; +SHOW COLUMNS IN t2; +Field Type Null Key Default Extra +v varbinary(65532) # # # +INSERT INTO t1 (v0,v1,v64,v65000) VALUES ('','','',''); +INSERT INTO t1 (v0,v1,v64,v65000) VALUES ('','y','Once there, double check that an article doesn\'t already exist','Here is a list of recommended books on MariaDB and MySQL. We\'ve provided links to Amazon.com here for convenience, but they can be found at many other bookstores, both online and off. + + If you want to have your favorite MySQL / MariaDB book listed here, please leave a comment. + For developers who want to code on MariaDB or MySQL + + * Understanding MySQL Internals by Sasha Pachev, former MySQL developer at MySQL AB. + o This is the only book we know about that describes the internals of MariaDB / MySQL. A must have for anyone who wants to understand and develop on MariaDB! + o Not all topics are covered and some parts are slightly outdated, but still the best book on this topic. + * MySQL 5.1 Plugin Development by Sergei Golubchik and Andrew Hutchings + o A must read for anyone wanting to write a plugin for MariaDB, written by the Sergei who designed the plugin interface for MySQL and MariaDB! + + For MariaDB / MySQL end users + + * MariaDB Crash Course by Ben Forta + o First MariaDB book! + o For people who want to learn SQL and the basics of MariaDB. + o Now shipping. Purchase at Amazon.com or your favorite bookseller. + + * SQL-99 Complete, Really by Peter Gulutzan & Trudy Pelzer. + o Everything you wanted to know about the SQL 99 standard. Excellent reference book! + o Free to read in the Knowledgebase! + + * MySQL (4th Edition) by Paul DuBois + o The \'default\' book to read if you wont to learn to use MySQL / MariaDB. + + * MySQL Cookbook by Paul DuBois + o A lot of examples of how to use MySQL. As with all of Paul\'s books, it\'s worth its weight in gold and even enjoyable reading for such a \'dry\' subject. + + * High Performance MySQL, Second Edition, By Baron Schwartz, Peter Zaitsev, Vadim Tkachenko, Jeremy D. Zawodny, Arjen Lentz, Derek J. Balling, et al. + o \"High Performance MySQL is the definitive guide to building fast, reliable systems with MySQL. Written by noted experts with years of real-world experience building very large systems, this book covers every aspect of MySQL performance in detail, and focuses on robustness, security, and data integrity. Learn advanced techniques in depth so you can bring out MySQL\'s full power.\" (From the book description at O\'Reilly) + + * MySQL Admin Cookbook + o A quick step-by-step guide for MySQL users and database administrators to tackle real-world challenges with MySQL configuration and administration + + * MySQL 5.0 Certification Study Guide, By Paul DuBois, Stefan Hinz, Carsten Pedersen + o This is the official guide to cover the passing of the two MySQL Certification examinations. It is valid till version 5.0 of the server, so while it misses all the features available in MySQL 5.1 and greater (including MariaDB 5.1 and greater), it provides a good basic understanding of MySQL for the end-user. '); +SELECT HEX(v0), HEX(v1), HEX(v64), HEX(v65000) FROM t1; +HEX(v0) HEX(v1) HEX(v64) HEX(v65000) + + 79 4F6E63652074686572652C20646F75626C6520636865636B207468617420616E2061727469636C6520646F65736E277420616C7265616479206578697374 486572652069732061206C697374206F66207265636F6D6D656E64656420626F6F6B73206F6E204D61726961444220616E64204D7953514C2E2057652776652070726F7669646564206C696E6B7320746F20416D617A6F6E2E636F6D206865726520666F7220636F6E76656E69656E63652C2062757420746865792063616E20626520666F756E64206174206D616E79206F7468657220626F6F6B73746F7265732C20626F7468206F6E6C696E6520616E64206F66662E0A0A2020496620796F752077616E7420746F206861766520796F7572206661766F72697465204D7953514C202F204D61726961444220626F6F6B206C697374656420686572652C20706C65617365206C65617665206120636F6D6D656E742E0A2020466F7220646576656C6F706572732077686F2077616E7420746F20636F6465206F6E204D617269614442206F72204D7953514C0A0A2020202020202A20556E6465727374616E64696E67204D7953514C20496E7465726E616C73206279205361736861205061636865762C20666F726D6572204D7953514C20646576656C6F706572206174204D7953514C2041422E0A2020202020202020202020206F205468697320697320746865206F6E6C7920626F6F6B207765206B6E6F772061626F75742074686174206465736372696265732074686520696E7465726E616C73206F66204D617269614442202F204D7953514C2E2041206D757374206861766520666F7220616E796F6E652077686F2077616E747320746F20756E6465727374616E6420616E6420646576656C6F70206F6E204D617269614442210A2020202020202020202020206F204E6F7420616C6C20746F706963732061726520636F766572656420616E6420736F6D652070617274732061726520736C696768746C79206F757464617465642C20627574207374696C6C20746865206265737420626F6F6B206F6E207468697320746F7069632E200A2020202020202A204D7953514C20352E3120506C7567696E20446576656C6F706D656E742062792053657267656920476F6C75626368696B20616E6420416E64726577204875746368696E67730A2020202020202020202020206F2041206D757374207265616420666F7220616E796F6E652077616E74696E6720746F207772697465206120706C7567696E20666F72204D6172696144422C207772697474656E20627920746865205365726765692077686F2064657369676E65642074686520706C7567696E20696E7465726661636520666F72204D7953514C20616E64204D61726961444221200A0A2020466F72204D617269614442202F204D7953514C20656E642075736572730A0A2020202020202A204D61726961444220437261736820436F757273652062792042656E20466F7274610A2020202020202020202020206F204669727374204D61726961444220626F6F6B210A2020202020202020202020206F20466F722070656F706C652077686F2077616E7420746F206C6561726E2053514C20616E642074686520626173696373206F66204D6172696144422E0A2020202020202020202020206F204E6F77207368697070696E672E20507572636861736520617420416D617A6F6E2E636F6D206F7220796F7572206661766F7269746520626F6F6B73656C6C65722E200A0A2020202020202A2053514C2D393920436F6D706C6574652C205265616C6C792062792050657465722047756C75747A616E20262054727564792050656C7A65722E0A2020202020202020202020206F2045766572797468696E6720796F752077616E74656420746F206B6E6F772061626F7574207468652053514C203939207374616E646172642E20457863656C6C656E74207265666572656E636520626F6F6B210A2020202020202020202020206F204672656520746F207265616420696E20746865204B6E6F776C656467656261736521200A0A2020202020202A204D7953514C20283474682045646974696F6E29206279205061756C204475426F69730A2020202020202020202020206F20546865202764656661756C742720626F6F6B20746F207265616420696620796F7520776F6E7420746F206C6561726E20746F20757365204D7953514C202F204D6172696144422E200A0A2020202020202A204D7953514C20436F6F6B626F6F6B206279205061756C204475426F69730A2020202020202020202020206F2041206C6F74206F66206578616D706C6573206F6620686F7720746F20757365204D7953514C2E204173207769746820616C6C206F66205061756C277320626F6F6B732C206974277320776F727468206974732077656967687420696E20676F6C6420616E64206576656E20656E6A6F7961626C652072656164696E6720666F7220737563682061202764727927207375626A6563742E200A0A2020202020202A204869676820506572666F726D616E6365204D7953514C2C205365636F6E642045646974696F6E2C204279204261726F6E20536368776172747A2C205065746572205A6169747365762C20566164696D20546B616368656E6B6F2C204A6572656D7920442E205A61776F646E792C2041726A656E204C656E747A2C20446572656B204A2E2042616C6C696E672C20657420616C2E0A2020202020202020202020206F20224869676820506572666F726D616E6365204D7953514C2069732074686520646566696E697469766520677569646520746F206275696C64696E6720666173742C2072656C6961626C652073797374656D732077697468204D7953514C2E205772697474656E206279206E6F74656420657870657274732077697468207965617273206F66207265616C2D776F726C6420657870657269656E6365206275696C64696E672076657279206C617267652073797374656D732C207468697320626F6F6B20636F7665727320657665727920617370656374206F66204D7953514C20706572666F726D616E636520696E2064657461696C2C20616E6420666F6375736573206F6E20726F627573746E6573732C2073656375726974792C20616E64206461746120696E746567726974792E204C6561726E20616476616E63656420746563686E697175657320696E20646570746820736F20796F752063616E206272696E67206F7574204D7953514C27732066756C6C20706F7765722E22202846726F6D2074686520626F6F6B206465736372697074696F6E206174204F275265696C6C7929200A0A2020202020202A204D7953514C2041646D696E20436F6F6B626F6F6B0A2020202020202020202020206F204120717569636B20737465702D62792D7374657020677569646520666F72204D7953514C20757365727320616E642064617461626173652061646D696E6973747261746F727320746F207461636B6C65207265616C2D776F726C64206368616C6C656E6765732077697468204D7953514C20636F6E66696775726174696F6E20616E642061646D696E697374726174696F6E200A0A2020202020202A204D7953514C20352E302043657274696669636174696F6E2053747564792047756964652C204279205061756C204475426F69732C2053746566616E2048696E7A2C204361727374656E20506564657273656E0A2020202020202020202020206F205468697320697320746865206F6666696369616C20677569646520746F20636F766572207468652070617373696E67206F66207468652074776F204D7953514C2043657274696669636174696F6E206578616D696E6174696F6E732E2049742069732076616C69642074696C6C2076657273696F6E20352E30206F6620746865207365727665722C20736F207768696C65206974206D697373657320616C6C2074686520666561747572657320617661696C61626C6520696E204D7953514C20352E3120616E6420677265617465722028696E636C7564696E67204D61726961444220352E3120616E642067726561746572292C2069742070726F7669646573206120676F6F6420626173696320756E6465727374616E64696E67206F66204D7953514C20666F722074686520656E642D757365722E20 +INSERT INTO t1 (v0,v1,v64,v65000) VALUES ('y', 'yy', REPEAT('c',65), REPEAT('abcdefghi ',6501)); +Warnings: +Warning 1265 Data truncated for column 'v0' at row 1 +Warning 1265 Data truncated for column 'v1' at row 1 +Warning 1265 Data truncated for column 'v64' at row 1 +Warning 1265 Data truncated for column 'v65000' at row 1 +INSERT INTO t1 (v0,v1,v64,v65000) SELECT v65000, v65000, v65000, CONCAT(v65000,v1) FROM t1; +Warnings: +Warning 1265 Data truncated for column 'v0' at row 2 +Warning 1265 Data truncated for column 'v1' at row 2 +Warning 1265 Data truncated for column 'v64' at row 2 +Warning 1265 Data truncated for column 'v0' at row 3 +Warning 1265 Data truncated for column 'v1' at row 3 +Warning 1265 Data truncated for column 'v64' at row 3 +Warning 1265 Data truncated for column 'v65000' at row 3 +SELECT HEX(v0), HEX(v1), HEX(v64), LENGTH(HEX(v65000)) FROM t1; +HEX(v0) HEX(v1) HEX(v64) LENGTH(HEX(v65000)) + 0 + 0 + 48 486572652069732061206C697374206F66207265636F6D6D656E64656420626F6F6B73206F6E204D61726961444220616E64204D7953514C2E20576527766520 5932 + 61 61626364656667686920616263646566676869206162636465666768692061626364656667686920616263646566676869206162636465666768692061626364 130000 + 79 4F6E63652074686572652C20646F75626C6520636865636B207468617420616E2061727469636C6520646F65736E277420616C7265616479206578697374 5930 + 79 63636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363 130000 +ALTER TABLE t1 ADD COLUMN v65536 VARBINARY(65536) NULL; +Warnings: +Note 1246 Converting column 'v65536' from VARBINARY to BLOB +Note 1246 Converting column 'v65536' from VARBINARY to BLOB +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +v0 varbinary(0) # # # +v1 varbinary(1) # # # +v64 varbinary(64) # # # +v65000 varbinary(65000) # # # +v65536 mediumblob # # # +DROP TABLE t1, t2; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c VARBINARY(64) NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c varbinary(64) YES NULL +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c), COUNT(*) FROM t1; +COUNT(c) COUNT(*) +0 1 +DROP TABLE t1; +CREATE TABLE t1 (c VARBINARY(64) NULL, +c1 VARBINARY(64) NULL DEFAULT NULL, +c2 VARBINARY(64) NULL DEFAULT 'test' +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c varbinary(64) YES NULL +c1 varbinary(64) YES NULL +c2 varbinary(64) YES test +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c2), COUNT(c1), COUNT(c), COUNT(*) FROM t1; +COUNT(c2) COUNT(c1) COUNT(c) COUNT(*) +1 0 0 1 +DROP TABLE t1; +# +# BIT columns +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (a BIT NULL, +b BIT(20) NULL, +c BIT(64) NULL, +d BIT(1) NULL +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +a bit(1) # # # +b bit(20) # # # +c bit(64) # # # +d bit(1) # # # +ALTER TABLE t1 DROP COLUMN d; +ALTER TABLE t1 ADD COLUMN d BIT(0) NULL; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +a bit(1) # # # +b bit(20) # # # +c bit(64) # # # +d bit(1) # # # +INSERT INTO t1 VALUES (0,POW(2,20)-1,b'1111111111111111111111111111111111111111111111111111111111111111',1); +SELECT BIN(a), HEX(b), c+0 FROM t1 WHERE d>0; +BIN(a) HEX(b) c+0 +0 FFFFF 18446744073709551615 +INSERT INTO t1 VALUES (1,0,-1,0); +SELECT a+0, b+0, c+0 FROM t1 WHERE d<100; +a+0 b+0 c+0 +0 1048575 18446744073709551615 +1 0 18446744073709551615 +INSERT INTO t1 VALUES (b'1', 'f', 0xFF, 0x0); +SELECT a+0, b+0, c+0 FROM t1 WHERE d IN (0, 2); +a+0 b+0 c+0 +1 0 18446744073709551615 +1 102 255 +INSERT INTO t1 VALUES (0x10,0,0,1); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +SELECT * FROM t1; +a b c d +INSERT INTO t1 VALUES (0x01,0,0x10000000000000000,0); +Warnings: +Warning 1264 Out of range value for column 'c' at row 1 +SELECT * FROM t1; +a b c d +DROP TABLE t1; +CREATE TABLE t1 (a BIT(65) NULL) ENGINE= ; +ERROR 42000: Display width out of range for 'a' (max = 64) +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c BIT NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c bit(1) YES NULL +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c), COUNT(*) FROM t1; +COUNT(c) COUNT(*) +0 1 +DROP TABLE t1; +CREATE TABLE t1 (c BIT NULL, +c1 BIT NULL DEFAULT NULL, +c2 BIT NULL DEFAULT 1 +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c bit(1) YES NULL +c1 bit(1) YES NULL +c2 bit(1) YES b'1' +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c2), COUNT(c1), COUNT(c), COUNT(*) FROM t1; +COUNT(c2) COUNT(c1) COUNT(c) COUNT(*) +1 0 0 1 +DROP TABLE t1; +# +# BLOB columns +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (b BLOB NULL, +b0 BLOB(0) NULL, +b1 BLOB(1) NULL, +b300 BLOB(300) NULL, +bm BLOB(65535) NULL, +b70k BLOB(70000) NULL, +b17m BLOB(17000000) NULL, +t TINYBLOB NULL, +m MEDIUMBLOB NULL, +l LONGBLOB NULL +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +b blob # # # +b0 blob # # # +b1 tinyblob # # # +b300 blob # # # +bm blob # # # +b70k mediumblob # # # +b17m longblob # # # +t tinyblob # # # +m mediumblob # # # +l longblob # # # +INSERT INTO t1 VALUES +('','','','','','','','','',''), +('a','b','c','d','e','f','g','h','i','j'), +('test1','test2','test3','test4','test5','test6','test7','test8','test9','test10'), +( REPEAT('a',65535), REPEAT('b',65535), REPEAT('c',255), REPEAT('d',65535), REPEAT('e',65535), REPEAT('f',1048576), HEX(REPEAT('g',1048576)), REPEAT('h',255), REPEAT('i',1048576), HEX(REPEAT('j',1048576)) ); +SELECT LENGTH(b), LENGTH(b0), LENGTH(b1), LENGTH(b300), LENGTH(bm), LENGTH(b70k), LENGTH(b17m), LENGTH(t), LENGTH(m), LENGTH(l) FROM t1; +LENGTH(b) LENGTH(b0) LENGTH(b1) LENGTH(b300) LENGTH(bm) LENGTH(b70k) LENGTH(b17m) LENGTH(t) LENGTH(m) LENGTH(l) +0 0 0 0 0 0 0 0 0 0 +1 1 1 1 1 1 1 1 1 1 +5 5 5 5 5 5 5 5 5 6 +65535 65535 255 65535 65535 1048576 2097152 255 1048576 2097152 +INSERT INTO t1 VALUES +( REPEAT('a',65536), REPEAT('b',65536), REPEAT('c',256), REPEAT('d',65536), REPEAT('e',65536), REPEAT('f',1048576), REPEAT('g',1048576), REPEAT('h',256), REPEAT('i',1048576), REPEAT('j',1048576) ); +Warnings: +Warning 1265 Data truncated for column 'b' at row 1 +Warning 1265 Data truncated for column 'b0' at row 1 +Warning 1265 Data truncated for column 'b1' at row 1 +Warning 1265 Data truncated for column 'b300' at row 1 +Warning 1265 Data truncated for column 'bm' at row 1 +Warning 1265 Data truncated for column 't' at row 1 +SELECT LENGTH(b), LENGTH(b0), LENGTH(b1), LENGTH(b300), LENGTH(bm), LENGTH(b70k), LENGTH(b17m), LENGTH(t), LENGTH(m), LENGTH(l) FROM t1; +LENGTH(b) LENGTH(b0) LENGTH(b1) LENGTH(b300) LENGTH(bm) LENGTH(b70k) LENGTH(b17m) LENGTH(t) LENGTH(m) LENGTH(l) +0 0 0 0 0 0 0 0 0 0 +1 1 1 1 1 1 1 1 1 1 +5 5 5 5 5 5 5 5 5 6 +65535 65535 255 65535 65535 1048576 1048576 255 1048576 1048576 +65535 65535 255 65535 65535 1048576 2097152 255 1048576 2097152 +ALTER TABLE t1 ADD COLUMN bbb BLOB(4294967296); +ERROR 42000: Display width out of range for 'bbb' (max = 4294967295) +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c BLOB NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c blob YES NULL +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c), COUNT(*) FROM t1; +COUNT(c) COUNT(*) +0 1 +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c TINYBLOB NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c tinyblob YES NULL +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c), COUNT(*) FROM t1; +COUNT(c) COUNT(*) +0 1 +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c MEDIUMBLOB NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c mediumblob YES NULL +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c), COUNT(*) FROM t1; +COUNT(c) COUNT(*) +0 1 +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c LONGBLOB NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c longblob YES NULL +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c), COUNT(*) FROM t1; +COUNT(c) COUNT(*) +0 1 +DROP TABLE t1; +# +# BOOL columns +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (b1 BOOL NULL, +b2 BOOLEAN NULL +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +b1 tinyint(1) # # # +b2 tinyint(1) # # # +INSERT INTO t1 VALUES (1,TRUE); +SELECT * FROM t1; +b1 b2 +1 1 +INSERT INTO t1 VALUES (FALSE,0); +SELECT * FROM t1; +b1 b2 +0 0 +1 1 +INSERT INTO t1 VALUES (2,3); +SELECT * FROM t1; +b1 b2 +0 0 +1 1 +2 3 +INSERT INTO t1 VALUES (-1,-2); +SELECT * FROM t1; +b1 b2 +-1 -2 +0 0 +1 1 +2 3 +SELECT IF(b1,'true','false') AS a, IF(b2,'true','false') AS b FROM t1; +a b +false false +true true +true true +true true +SELECT * FROM t1 WHERE b1 = TRUE; +b1 b2 +1 1 +SELECT * FROM t1 WHERE b2 = FALSE; +b1 b2 +0 0 +INSERT INTO t1 VALUES ('a','b'); +Warnings: +Warning 1366 Incorrect integer value: 'a' for column 'b1' at row 1 +Warning 1366 Incorrect integer value: 'b' for column 'b2' at row 1 +SELECT * FROM t1; +b1 b2 +-1 -2 +0 0 +0 0 +1 1 +2 3 +INSERT INTO t1 VALUES (128,-129); +Warnings: +Warning 1264 Out of range value for column 'b1' at row 1 +Warning 1264 Out of range value for column 'b2' at row 1 +SELECT * FROM t1; +b1 b2 +-1 -2 +0 0 +0 0 +1 1 +127 -128 +2 3 +ALTER TABLE t1 ADD COLUMN b3 BOOLEAN UNSIGNED; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'UNSIGNED' at line 1 +ALTER TABLE t1 ADD COLUMN b3 BOOL ZEROFILL; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'ZEROFILL' at line 1 +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c BOOL NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c tinyint(1) YES NULL +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c), COUNT(*) FROM t1; +COUNT(c) COUNT(*) +0 1 +DROP TABLE t1; +CREATE TABLE t1 (c BOOL NULL, +c1 BOOL NULL DEFAULT NULL, +c2 BOOL NULL DEFAULT '0' +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c tinyint(1) YES NULL +c1 tinyint(1) YES NULL +c2 tinyint(1) YES 0 +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c2), COUNT(c1), COUNT(c), COUNT(*) FROM t1; +COUNT(c2) COUNT(c1) COUNT(c) COUNT(*) +1 0 0 1 +DROP TABLE t1; +# +# CHAR columns +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c CHAR NULL, +c0 CHAR(0) NULL, +c1 CHAR(1) NULL, +c20 CHAR(20) NULL, +c255 CHAR(255) NULL +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c char(1) # # # +c0 char(0) # # # +c1 char(1) # # # +c20 char(20) # # # +c255 char(255) # # # +INSERT INTO t1 VALUES ('','','','',''); +INSERT INTO t1 VALUES ('a','','b','abcdefghi klmnopqrst', 'Creating an article for the Knowledgebase is similar to asking questions. First, navigate to the category where you feel the article should be. Once there, double check that an article doesn\'t already exist which would work.'); +SELECT * FROM t1; +c c0 c1 c20 c255 + +a b abcdefghi klmnopqrst Creating an article for the Knowledgebase is similar to asking questions. First, navigate to the category where you feel the article should be. Once there, double check that an article doesn't already exist which would work. +INSERT INTO t1 VALUES ('abc', 'a', 'abc', REPEAT('a',21), REPEAT('x',256)); +Warnings: +Warning 1265 Data truncated for column 'c' at row 1 +Warning 1265 Data truncated for column 'c0' at row 1 +Warning 1265 Data truncated for column 'c1' at row 1 +Warning 1265 Data truncated for column 'c20' at row 1 +Warning 1265 Data truncated for column 'c255' at row 1 +INSERT INTO t1 SELECT c255, c255, c255, c255, CONCAT(c255,c1) FROM t1; +Warnings: +Warning 1265 Data truncated for column 'c' at row 2 +Warning 1265 Data truncated for column 'c0' at row 2 +Warning 1265 Data truncated for column 'c1' at row 2 +Warning 1265 Data truncated for column 'c20' at row 2 +Warning 1265 Data truncated for column 'c' at row 3 +Warning 1265 Data truncated for column 'c0' at row 3 +Warning 1265 Data truncated for column 'c1' at row 3 +Warning 1265 Data truncated for column 'c20' at row 3 +Warning 1265 Data truncated for column 'c255' at row 3 +SELECT * FROM t1; +c c0 c1 c20 c255 + + +C C Creating an article Creating an article for the Knowledgebase is similar to asking questions. First, navigate to the category where you feel the article should be. Once there, double check that an article doesn't already exist which would work.b +a a aaaaaaaaaaaaaaaaaaaa xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +a b abcdefghi klmnopqrst Creating an article for the Knowledgebase is similar to asking questions. First, navigate to the category where you feel the article should be. Once there, double check that an article doesn't already exist which would work. +x x xxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +SELECT DISTINCT c20, REPEAT('a',LENGTH(c20)), COUNT(*) FROM t1 GROUP BY c1, c20; +c20 REPEAT('a',LENGTH(c20)) COUNT(*) + 2 +Creating an article aaaaaaaaaaaaaaaaaaa 1 +aaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaa 1 +abcdefghi klmnopqrst aaaaaaaaaaaaaaaaaaaa 1 +xxxxxxxxxxxxxxxxxxxx aaaaaaaaaaaaaaaaaaaa 1 +ALTER TABLE t1 ADD COLUMN c257 CHAR(257) NULL; +ERROR 42000: Column length too big for column 'c257' (max = 255); use BLOB or TEXT instead +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c CHAR NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c char(1) YES NULL +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c), COUNT(*) FROM t1; +COUNT(c) COUNT(*) +0 1 +DROP TABLE t1; +CREATE TABLE t1 (c CHAR NULL, +c1 CHAR NULL DEFAULT NULL, +c2 CHAR NULL DEFAULT '_' +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c char(1) YES NULL +c1 char(1) YES NULL +c2 char(1) YES _ +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c2), COUNT(c1), COUNT(c), COUNT(*) FROM t1; +COUNT(c2) COUNT(c1) COUNT(c) COUNT(*) +1 0 0 1 +DROP TABLE t1; +# +# VARCHAR columns +# +DROP TABLE IF EXISTS t1, t2; +CREATE TABLE t1 (v0 VARCHAR(0) NULL, +v1 VARCHAR(1) NULL, +v64 VARCHAR(64) NULL, +v65000 VARCHAR(65000) NULL +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +v0 varchar(0) # # # +v1 varchar(1) # # # +v64 varchar(64) # # # +v65000 varchar(65000) # # # +CREATE TABLE t2 (v VARCHAR(65532) NULL) ENGINE= ; +SHOW COLUMNS IN t2; +Field Type Null Key Default Extra +v varchar(65532) # # # +INSERT INTO t1 (v0,v1,v64,v65000) VALUES ('','','',''); +INSERT INTO t1 (v0,v1,v64,v65000) VALUES ('','y','Once there, double check that an article doesn\'t already exist','Here is a list of recommended books on MariaDB and MySQL. We\'ve provided links to Amazon.com here for convenience, but they can be found at many other bookstores, both online and off. + + If you want to have your favorite MySQL / MariaDB book listed here, please leave a comment. + For developers who want to code on MariaDB or MySQL + + * Understanding MySQL Internals by Sasha Pachev, former MySQL developer at MySQL AB. + o This is the only book we know about that describes the internals of MariaDB / MySQL. A must have for anyone who wants to understand and develop on MariaDB! + o Not all topics are covered and some parts are slightly outdated, but still the best book on this topic. + * MySQL 5.1 Plugin Development by Sergei Golubchik and Andrew Hutchings + o A must read for anyone wanting to write a plugin for MariaDB, written by the Sergei who designed the plugin interface for MySQL and MariaDB! + + For MariaDB / MySQL end users + + * MariaDB Crash Course by Ben Forta + o First MariaDB book! + o For people who want to learn SQL and the basics of MariaDB. + o Now shipping. Purchase at Amazon.com or your favorite bookseller. + + * SQL-99 Complete, Really by Peter Gulutzan & Trudy Pelzer. + o Everything you wanted to know about the SQL 99 standard. Excellent reference book! + o Free to read in the Knowledgebase! + + * MySQL (4th Edition) by Paul DuBois + o The \'default\' book to read if you wont to learn to use MySQL / MariaDB. + + * MySQL Cookbook by Paul DuBois + o A lot of examples of how to use MySQL. As with all of Paul\'s books, it\'s worth its weight in gold and even enjoyable reading for such a \'dry\' subject. + + * High Performance MySQL, Second Edition, By Baron Schwartz, Peter Zaitsev, Vadim Tkachenko, Jeremy D. Zawodny, Arjen Lentz, Derek J. Balling, et al. + o \"High Performance MySQL is the definitive guide to building fast, reliable systems with MySQL. Written by noted experts with years of real-world experience building very large systems, this book covers every aspect of MySQL performance in detail, and focuses on robustness, security, and data integrity. Learn advanced techniques in depth so you can bring out MySQL\'s full power.\" (From the book description at O\'Reilly) + + * MySQL Admin Cookbook + o A quick step-by-step guide for MySQL users and database administrators to tackle real-world challenges with MySQL configuration and administration + + * MySQL 5.0 Certification Study Guide, By Paul DuBois, Stefan Hinz, Carsten Pedersen + o This is the official guide to cover the passing of the two MySQL Certification examinations. It is valid till version 5.0 of the server, so while it misses all the features available in MySQL 5.1 and greater (including MariaDB 5.1 and greater), it provides a good basic understanding of MySQL for the end-user. '); +SELECT * FROM t1; +v0 v1 v64 v65000 + + + + + + + + + + + + y Once there, double check that an article doesn't already exist Here is a list of recommended books on MariaDB and MySQL. We've provided links to Amazon.com here for convenience, but they can be found at many other bookstores, both online and off. + o "High Performance MySQL is the definitive guide to building fast, reliable systems with MySQL. Written by noted experts with years of real-world experience building very large systems, this book covers every aspect of MySQL performance in detail, and focuses on robustness, security, and data integrity. Learn advanced techniques in depth so you can bring out MySQL's full power." (From the book description at O'Reilly) + o A lot of examples of how to use MySQL. As with all of Paul's books, it's worth its weight in gold and even enjoyable reading for such a 'dry' subject. + o A must read for anyone wanting to write a plugin for MariaDB, written by the Sergei who designed the plugin interface for MySQL and MariaDB! + o A quick step-by-step guide for MySQL users and database administrators to tackle real-world challenges with MySQL configuration and administration + o Everything you wanted to know about the SQL 99 standard. Excellent reference book! + o First MariaDB book! + o For people who want to learn SQL and the basics of MariaDB. + o Free to read in the Knowledgebase! + o Not all topics are covered and some parts are slightly outdated, but still the best book on this topic. + o Now shipping. Purchase at Amazon.com or your favorite bookseller. + o The 'default' book to read if you wont to learn to use MySQL / MariaDB. + o This is the official guide to cover the passing of the two MySQL Certification examinations. It is valid till version 5.0 of the server, so while it misses all the features available in MySQL 5.1 and greater (including MariaDB 5.1 and greater), it provides a good basic understanding of MySQL for the end-user. + o This is the only book we know about that describes the internals of MariaDB / MySQL. A must have for anyone who wants to understand and develop on MariaDB! + * High Performance MySQL, Second Edition, By Baron Schwartz, Peter Zaitsev, Vadim Tkachenko, Jeremy D. Zawodny, Arjen Lentz, Derek J. Balling, et al. + * MariaDB Crash Course by Ben Forta + * MySQL (4th Edition) by Paul DuBois + * MySQL 5.0 Certification Study Guide, By Paul DuBois, Stefan Hinz, Carsten Pedersen + * MySQL 5.1 Plugin Development by Sergei Golubchik and Andrew Hutchings + * MySQL Admin Cookbook + * MySQL Cookbook by Paul DuBois + * SQL-99 Complete, Really by Peter Gulutzan & Trudy Pelzer. + * Understanding MySQL Internals by Sasha Pachev, former MySQL developer at MySQL AB. + For MariaDB / MySQL end users + For developers who want to code on MariaDB or MySQL + If you want to have your favorite MySQL / MariaDB book listed here, please leave a comment. +INSERT INTO t1 (v0,v1,v64,v65000) VALUES ('y', 'yy', REPEAT('c',65), REPEAT('abcdefghi ',6501)); +Warnings: +Warning 1265 Data truncated for column 'v0' at row 1 +Warning 1265 Data truncated for column 'v1' at row 1 +Warning 1265 Data truncated for column 'v64' at row 1 +Warning 1265 Data truncated for column 'v65000' at row 1 +INSERT INTO t1 (v0,v1,v64,v65000) SELECT v65000, v65000, v65000, CONCAT(v65000,v1) FROM t1; +Warnings: +Warning 1265 Data truncated for column 'v0' at row 2 +Warning 1265 Data truncated for column 'v1' at row 2 +Warning 1265 Data truncated for column 'v64' at row 2 +Warning 1265 Data truncated for column 'v0' at row 3 +Warning 1265 Data truncated for column 'v1' at row 3 +Warning 1265 Data truncated for column 'v64' at row 3 +Warning 1265 Data truncated for column 'v65000' at row 3 +SELECT v0, v1, v64, LENGTH(v65000) FROM t1; +v0 v1 v64 LENGTH(v65000) + 0 + 0 + H Here is a list of recommended books on MariaDB and MySQL. We've 2966 + a abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcd 65000 + y Once there, double check that an article doesn't already exist 2965 + y cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc 65000 +ALTER TABLE t1 ADD COLUMN v65536 VARCHAR(65536) NULL; +Warnings: +Note 1246 Converting column 'v65536' from VARCHAR to TEXT +Note 1246 Converting column 'v65536' from VARCHAR to TEXT +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +v0 varchar(0) # # # +v1 varchar(1) # # # +v64 varchar(64) # # # +v65000 varchar(65000) # # # +v65536 mediumtext # # # +DROP TABLE t1, t2; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c VARCHAR(64) NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c varchar(64) YES NULL +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c), COUNT(*) FROM t1; +COUNT(c) COUNT(*) +0 1 +DROP TABLE t1; +CREATE TABLE t1 (c VARCHAR(64) NULL, +c1 VARCHAR(64) NULL DEFAULT NULL, +c2 VARCHAR(64) NULL DEFAULT 'test default' +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c varchar(64) YES NULL +c1 varchar(64) YES NULL +c2 varchar(64) YES test default +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c2), COUNT(c1), COUNT(c), COUNT(*) FROM t1; +COUNT(c2) COUNT(c1) COUNT(c) COUNT(*) +1 0 0 1 +DROP TABLE t1; +# +# date and time columns +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (d DATE NULL, +dt DATETIME NULL, +ts TIMESTAMP NULL, +t TIME NULL, +y YEAR NULL, +y4 YEAR(4) NULL, +y2 YEAR(2) NULL +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +d date # # # +dt datetime # # # +ts timestamp # # # +t time # # # +y year(4) # # # +y4 year(4) # # # +y2 year(2) # # # +SET @tm = '2012-04-09 05:27:00'; +INSERT INTO t1 VALUES +('1000-01-01', '1000-01-01 00:00:00', FROM_UNIXTIME(1), '-838:59:59', '1901', '1901', '00'), +('9999-12-31', '9999-12-31 23:59:59', FROM_UNIXTIME(2147483647), '838:59:59', '2155', '2155', '99'), +('0000-00-00', '0000-00-00 00:00:00', '0000-00-00 00:00:00', '00:00:00', '0', '0', '0'), +(DATE(@tm),@tm,TIMESTAMP(@tm),TIME(@tm),YEAR(@tm),YEAR(@tm),YEAR(@tm)); +SELECT * FROM t1; +d dt ts t y y4 y2 +0000-00-00 0000-00-00 00:00:00 0000-00-00 00:00:00 00:00:00 2000 2000 00 +1000-01-01 1000-01-01 00:00:00 1970-01-01 03:00:01 -838:59:59 1901 1901 00 +2012-04-09 2012-04-09 05:27:00 2012-04-09 05:27:00 05:27:00 2012 2012 12 +9999-12-31 9999-12-31 23:59:59 2038-01-19 07:14:07 838:59:59 2155 2155 99 +INSERT INTO t1 VALUES +('999-13-32', '999-11-31 00:00:00', '0', '-839:00:00', '1900', '1900', '-1' ); +Warnings: +Warning 1265 Data truncated for column 'd' at row 1 +Warning 1265 Data truncated for column 'dt' at row 1 +Warning 1265 Data truncated for column 'ts' at row 1 +Warning 1264 Out of range value for column 't' at row 1 +Warning 1264 Out of range value for column 'y' at row 1 +Warning 1264 Out of range value for column 'y4' at row 1 +Warning 1264 Out of range value for column 'y2' at row 1 +SELECT * FROM t1; +d dt ts t y y4 y2 +0000-00-00 0000-00-00 00:00:00 0000-00-00 00:00:00 -838:59:59 0000 0000 00 +0000-00-00 0000-00-00 00:00:00 0000-00-00 00:00:00 00:00:00 2000 2000 00 +1000-01-01 1000-01-01 00:00:00 1970-01-01 03:00:01 -838:59:59 1901 1901 00 +2012-04-09 2012-04-09 05:27:00 2012-04-09 05:27:00 05:27:00 2012 2012 12 +9999-12-31 9999-12-31 23:59:59 2038-01-19 07:14:07 838:59:59 2155 2155 99 +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c DATE NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c date YES NULL +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c), COUNT(*) FROM t1; +COUNT(c) COUNT(*) +0 1 +DROP TABLE t1; +CREATE TABLE t1 (c DATE NULL, +c1 DATE NULL DEFAULT NULL, +c2 DATE NULL DEFAULT '2012-12-21' +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c date YES NULL +c1 date YES NULL +c2 date YES 2012-12-21 +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c2), COUNT(c1), COUNT(c), COUNT(*) FROM t1; +COUNT(c2) COUNT(c1) COUNT(c) COUNT(*) +1 0 0 1 +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c DATETIME NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c datetime YES NULL +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c), COUNT(*) FROM t1; +COUNT(c) COUNT(*) +0 1 +DROP TABLE t1; +CREATE TABLE t1 (c DATETIME NULL, +c1 DATETIME NULL DEFAULT NULL, +c2 DATETIME NULL DEFAULT '2012-12-21 12:21:12' +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c datetime YES NULL +c1 datetime YES NULL +c2 datetime YES 2012-12-21 12:21:12 +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c2), COUNT(c1), COUNT(c), COUNT(*) FROM t1; +COUNT(c2) COUNT(c1) COUNT(c) COUNT(*) +1 0 0 1 +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c TIMESTAMP NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c timestamp YES NULL +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c), COUNT(*) FROM t1; +COUNT(c) COUNT(*) +0 1 +DROP TABLE t1; +CREATE TABLE t1 (c TIMESTAMP NULL, +c1 TIMESTAMP NULL DEFAULT NULL, +c2 TIMESTAMP NULL DEFAULT '2012-12-21 12:21:12' +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c timestamp YES NULL +c1 timestamp YES NULL +c2 timestamp YES 2012-12-21 12:21:12 +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c2), COUNT(c1), COUNT(c), COUNT(*) FROM t1; +COUNT(c2) COUNT(c1) COUNT(c) COUNT(*) +1 0 0 1 +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c TIME NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c time YES NULL +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c), COUNT(*) FROM t1; +COUNT(c) COUNT(*) +0 1 +DROP TABLE t1; +CREATE TABLE t1 (c TIME NULL, +c1 TIME NULL DEFAULT NULL, +c2 TIME NULL DEFAULT '12:21:12' +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c time YES NULL +c1 time YES NULL +c2 time YES 12:21:12 +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c2), COUNT(c1), COUNT(c), COUNT(*) FROM t1; +COUNT(c2) COUNT(c1) COUNT(c) COUNT(*) +1 0 0 1 +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c YEAR NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c year(4) YES NULL +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c), COUNT(*) FROM t1; +COUNT(c) COUNT(*) +0 1 +DROP TABLE t1; +CREATE TABLE t1 (c YEAR NULL, +c1 YEAR NULL DEFAULT NULL, +c2 YEAR NULL DEFAULT '2012' +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c year(4) YES NULL +c1 year(4) YES NULL +c2 year(4) YES 2012 +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c2), COUNT(c1), COUNT(c), COUNT(*) FROM t1; +COUNT(c2) COUNT(c1) COUNT(c) COUNT(*) +1 0 0 1 +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c YEAR(2) NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c year(2) YES NULL +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c), COUNT(*) FROM t1; +COUNT(c) COUNT(*) +0 1 +DROP TABLE t1; +CREATE TABLE t1 (c YEAR(2) NULL, +c1 YEAR(2) NULL DEFAULT NULL, +c2 YEAR(2) NULL DEFAULT '12' +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c year(2) YES NULL +c1 year(2) YES NULL +c2 year(2) YES 12 +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c2), COUNT(c1), COUNT(c), COUNT(*) FROM t1; +COUNT(c2) COUNT(c1) COUNT(c) COUNT(*) +1 0 0 1 +DROP TABLE t1; +# +# ENUM columns +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (a ENUM('') NULL, +b ENUM('test1','test2','test3','test4','test5') NULL, +c ENUM('1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',' ','11','12','13','14','15','16','17','18','19','1a','1b','1c','1d','1e','1f','1g','1h','1i','1j','1k','1l','1m','1n','1o','1p','1q','1r','1s','1t','1u','1v','1w','1x','1y','1z','20','21','22','23','24','25','26','27','28','29','2a','2b','2c','2d','2e','2f','2g','2h','2i','2j','2k','2l','2m','2n','2o','2p','2q','2r','2s','2t','2u','2v','2w','2x','2y','2z','30','31','32','33','34','35','36','37','38','39','3a','3b','3c','3d','3e','3f','3g','3h','3i','3j','3k','3l','3m','3n','3o','3p','3q','3r','3s','3t','3u','3v','3w','3x','3y','3z','40','41','42','43','44','45','46','47','48','49','4a','4b','4c','4d','4e','4f','4g','4h','4i','4j','4k','4l','4m','4n','4o','4p','4q','4r','4s','4t','4u','4v','4w','4x','4y','4z','50','51','52','53','54','55','56','57','58','59','5a','5b','5c','5d','5e','5f','5g','5h','5i','5j','5k','5l','5m','5n','5o','5p','5q','5r','5s','5t','5u','5v','5w','5x','5y','5z','60','61','62','63','64','65','66','67','68','69','6a','6b','6c','6d','6e','6f','6g','6h','6i','6j','6k','6l','6m','6n','6o','6p','6q','6r','6s','6t','6u','6v','6w','6x','6y','6z','70','71','72','73','74','75') NULL +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +a enum('') # # # +b enum('test1','test2','test3','test4','test5') # # # +c enum('1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','','11','12','13','14','15','16','17','18','19','1a','1b','1c','1d','1e','1f','1g','1h','1i','1j','1k','1l','1m','1n','1o','1p','1q','1r','1s','1t','1u','1v','1w','1x','1y','1z','20','21','22','23','24','25','26','27','28','29','2a','2b','2c','2d','2e','2f','2g','2h','2i','2j','2k','2l','2m','2n','2o','2p','2q','2r','2s','2t','2u','2v','2w','2x','2y','2z','30','31','32','33','34','35','36','37','38','39','3a','3b','3c','3d','3e','3f','3g','3h','3i','3j','3k','3l','3m','3n','3o','3p','3q','3r','3s','3t','3u','3v','3w','3x','3y','3z','40','41','42','43','44','45','46','47','48','49','4a','4b','4c','4d','4e','4f','4g','4h','4i','4j','4k','4l','4m','4n','4o','4p','4q','4r','4s','4t','4u','4v','4w','4x','4y','4z','50','51','52','53','54','55','56','57','58','59','5a','5b','5c','5d','5e','5f','5g','5h','5i','5j','5k','5l','5m','5n','5o','5p','5q','5r','5s','5t','5u','5v','5w','5x','5y','5z','60','61','62','63','64','65','66','67','68','69','6a','6b','6c','6d','6e','6f','6g','6h','6i','6j','6k','6l','6m','6n','6o','6p','6q','6r','6s','6t','6u','6v','6w','6x','6y','6z','70','71','72','73','74','75') # # # +INSERT INTO t1 VALUES ('','test2','4'),('',5,2); +SELECT * FROM t1; +a b c + test2 4 + test5 2 +INSERT INTO t1 VALUES (0,'test6',-1); +Warnings: +Warning 1265 Data truncated for column 'a' at row 1 +Warning 1265 Data truncated for column 'b' at row 1 +Warning 1265 Data truncated for column 'c' at row 1 +SELECT * FROM t1; +a b c + + test2 4 + test5 2 +ALTER TABLE t1 ADD COLUMN e ENUM('a','A') NULL; +Warnings: +Note 1291 Column 'e' has duplicated value 'a' in ENUM +Note 1291 Column 'e' has duplicated value 'a' in ENUM +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +a enum('') # # # +b enum('test1','test2','test3','test4','test5') # # # +c enum('1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','','11','12','13','14','15','16','17','18','19','1a','1b','1c','1d','1e','1f','1g','1h','1i','1j','1k','1l','1m','1n','1o','1p','1q','1r','1s','1t','1u','1v','1w','1x','1y','1z','20','21','22','23','24','25','26','27','28','29','2a','2b','2c','2d','2e','2f','2g','2h','2i','2j','2k','2l','2m','2n','2o','2p','2q','2r','2s','2t','2u','2v','2w','2x','2y','2z','30','31','32','33','34','35','36','37','38','39','3a','3b','3c','3d','3e','3f','3g','3h','3i','3j','3k','3l','3m','3n','3o','3p','3q','3r','3s','3t','3u','3v','3w','3x','3y','3z','40','41','42','43','44','45','46','47','48','49','4a','4b','4c','4d','4e','4f','4g','4h','4i','4j','4k','4l','4m','4n','4o','4p','4q','4r','4s','4t','4u','4v','4w','4x','4y','4z','50','51','52','53','54','55','56','57','58','59','5a','5b','5c','5d','5e','5f','5g','5h','5i','5j','5k','5l','5m','5n','5o','5p','5q','5r','5s','5t','5u','5v','5w','5x','5y','5z','60','61','62','63','64','65','66','67','68','69','6a','6b','6c','6d','6e','6f','6g','6h','6i','6j','6k','6l','6m','6n','6o','6p','6q','6r','6s','6t','6u','6v','6w','6x','6y','6z','70','71','72','73','74','75') # # # +e enum('a','A') # # # +INSERT INTO t1 VALUES ('','test3','75','A'); +SELECT * FROM t1; +a b c e + NULL + test2 4 NULL + test3 75 a + test5 2 NULL +SELECT * FROM t1 WHERE b='test2' OR a != ''; +a b c e + test2 4 NULL +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c ENUM('test1','test2','test3') NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c enum('test1','test2','test3') YES NULL +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c), COUNT(*) FROM t1; +COUNT(c) COUNT(*) +0 1 +DROP TABLE t1; +CREATE TABLE t1 (c ENUM('test1','test2','test3') NULL, +c1 ENUM('test1','test2','test3') NULL DEFAULT NULL, +c2 ENUM('test1','test2','test3') NULL DEFAULT 'test2' +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c enum('test1','test2','test3') YES NULL +c1 enum('test1','test2','test3') YES NULL +c2 enum('test1','test2','test3') YES test2 +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c2), COUNT(c1), COUNT(c), COUNT(*) FROM t1; +COUNT(c2) COUNT(c1) COUNT(c) COUNT(*) +1 0 0 1 +DROP TABLE t1; +# +# Fixed point columns (NUMERIC, DECIMAL) +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (d DECIMAL NULL, +d0 DECIMAL(0) NULL, +d1_1 DECIMAL(1,1) NULL, +d10_2 DECIMAL(10,2) NULL, +d60_10 DECIMAL(60,10) NULL, +n NUMERIC NULL, +n0_0 NUMERIC(0,0) NULL, +n1 NUMERIC(1) NULL, +n20_4 NUMERIC(20,4) NULL, +n65_4 NUMERIC(65,4) NULL +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +d decimal(10,0) # # # +d0 decimal(10,0) # # # +d1_1 decimal(1,1) # # # +d10_2 decimal(10,2) # # # +d60_10 decimal(60,10) # # # +n decimal(10,0) # # # +n0_0 decimal(10,0) # # # +n1 decimal(1,0) # # # +n20_4 decimal(20,4) # # # +n65_4 decimal(65,4) # # # +INSERT INTO t1 VALUES (100,123456,0.3,40000.25,123456789123456789.10001,1024,7000.0,8.0,999999.9,9223372036854775807); +INSERT INTO t1 VALUES (0,0,0,0,0,0,0,0,0,0); +INSERT INTO t1 VALUES (9999999999.0,9999999999.0,0.9,99999999.99,99999999999999999999999999999999999999999999999999.9999999999,9999999999.0,9999999999.0,9.0,9999999999999999.9999,9999999999999999999999999999999999999999999999999999999999999.9999); +SELECT * FROM t1; +d d0 d1_1 d10_2 d60_10 n n0_0 n1 n20_4 n65_4 +0 0 0.0 0.00 0.0000000000 0 0 0 0.0000 0.0000 +100 123456 0.3 40000.25 123456789123456789.1000100000 1024 7000 8 999999.9000 9223372036854775807.0000 +9999999999 9999999999 0.9 99999999.99 99999999999999999999999999999999999999999999999999.9999999999 9999999999 9999999999 9 9999999999999999.9999 9999999999999999999999999999999999999999999999999999999999999.9999 +INSERT INTO t1 VALUES (-100,-123456,-0.3,-40000.25,-123456789123456789.10001,-1024,-7000.0,-8.0,-999999.9,-9223372036854775807); +INSERT INTO t1 VALUES (-9999999999.0,-9999999999.0,-0.9,-99999999.99,-99999999999999999999999999999999999999999999999999.9999999999,-9999999999.0,-9999999999.0,-9.0,-9999999999999999.9999,-9999999999999999999999999999999999999999999999999999999999999.9999); +SELECT * FROM t1; +d d0 d1_1 d10_2 d60_10 n n0_0 n1 n20_4 n65_4 +-100 -123456 -0.3 -40000.25 -123456789123456789.1000100000 -1024 -7000 -8 -999999.9000 -9223372036854775807.0000 +-9999999999 -9999999999 -0.9 -99999999.99 -99999999999999999999999999999999999999999999999999.9999999999 -9999999999 -9999999999 -9 -9999999999999999.9999 -9999999999999999999999999999999999999999999999999999999999999.9999 +0 0 0.0 0.00 0.0000000000 0 0 0 0.0000 0.0000 +100 123456 0.3 40000.25 123456789123456789.1000100000 1024 7000 8 999999.9000 9223372036854775807.0000 +9999999999 9999999999 0.9 99999999.99 99999999999999999999999999999999999999999999999999.9999999999 9999999999 9999999999 9 9999999999999999.9999 9999999999999999999999999999999999999999999999999999999999999.9999 +SELECT * FROM t1 WHERE n20_4 = 9999999999999999.9999 OR d < 100; +d d0 d1_1 d10_2 d60_10 n n0_0 n1 n20_4 n65_4 +-100 -123456 -0.3 -40000.25 -123456789123456789.1000100000 -1024 -7000 -8 -999999.9000 -9223372036854775807.0000 +-9999999999 -9999999999 -0.9 -99999999.99 -99999999999999999999999999999999999999999999999999.9999999999 -9999999999 -9999999999 -9 -9999999999999999.9999 -9999999999999999999999999999999999999999999999999999999999999.9999 +0 0 0.0 0.00 0.0000000000 0 0 0 0.0000 0.0000 +9999999999 9999999999 0.9 99999999.99 99999999999999999999999999999999999999999999999999.9999999999 9999999999 9999999999 9 9999999999999999.9999 9999999999999999999999999999999999999999999999999999999999999.9999 +INSERT INTO t1 SELECT n65_4, n65_4, n65_4, n65_4, n65_4, n65_4, n65_4, n65_4, n65_4, n65_4 FROM t1 WHERE n65_4 = ( SELECT MAX(n65_4) FROM t1 ); +Warnings: +Warning 1264 Out of range value for column 'd' at row 1 +Warning 1264 Out of range value for column 'd0' at row 1 +Warning 1264 Out of range value for column 'd1_1' at row 1 +Warning 1264 Out of range value for column 'd10_2' at row 1 +Warning 1264 Out of range value for column 'd60_10' at row 1 +Warning 1264 Out of range value for column 'n' at row 1 +Warning 1264 Out of range value for column 'n0_0' at row 1 +Warning 1264 Out of range value for column 'n1' at row 1 +Warning 1264 Out of range value for column 'n20_4' at row 1 +SELECT * FROM t1; +d d0 d1_1 d10_2 d60_10 n n0_0 n1 n20_4 n65_4 +-100 -123456 -0.3 -40000.25 -123456789123456789.1000100000 -1024 -7000 -8 -999999.9000 -9223372036854775807.0000 +-9999999999 -9999999999 -0.9 -99999999.99 -99999999999999999999999999999999999999999999999999.9999999999 -9999999999 -9999999999 -9 -9999999999999999.9999 -9999999999999999999999999999999999999999999999999999999999999.9999 +0 0 0.0 0.00 0.0000000000 0 0 0 0.0000 0.0000 +100 123456 0.3 40000.25 123456789123456789.1000100000 1024 7000 8 999999.9000 9223372036854775807.0000 +9999999999 9999999999 0.9 99999999.99 99999999999999999999999999999999999999999999999999.9999999999 9999999999 9999999999 9 9999999999999999.9999 9999999999999999999999999999999999999999999999999999999999999.9999 +9999999999 9999999999 0.9 99999999.99 99999999999999999999999999999999999999999999999999.9999999999 9999999999 9999999999 9 9999999999999999.9999 9999999999999999999999999999999999999999999999999999999999999.9999 +INSERT INTO t1 VALUES (10000000000.0,10000000000.0,1.1,100000000.99,100000000000000000000000000000000000000000000000000.0,10000000000.0,10000000000.0,10.0,10000000000000000.9999,10000000000000000000000000000000000000000000000000000000000000.9999); +Warnings: +Warning 1264 Out of range value for column 'd' at row 1 +Warning 1264 Out of range value for column 'd0' at row 1 +Warning 1264 Out of range value for column 'd1_1' at row 1 +Warning 1264 Out of range value for column 'd10_2' at row 1 +Warning 1264 Out of range value for column 'd60_10' at row 1 +Warning 1264 Out of range value for column 'n' at row 1 +Warning 1264 Out of range value for column 'n0_0' at row 1 +Warning 1264 Out of range value for column 'n1' at row 1 +Warning 1264 Out of range value for column 'n20_4' at row 1 +Warning 1264 Out of range value for column 'n65_4' at row 1 +SELECT * FROM t1; +d d0 d1_1 d10_2 d60_10 n n0_0 n1 n20_4 n65_4 +-100 -123456 -0.3 -40000.25 -123456789123456789.1000100000 -1024 -7000 -8 -999999.9000 -9223372036854775807.0000 +-9999999999 -9999999999 -0.9 -99999999.99 -99999999999999999999999999999999999999999999999999.9999999999 -9999999999 -9999999999 -9 -9999999999999999.9999 -9999999999999999999999999999999999999999999999999999999999999.9999 +0 0 0.0 0.00 0.0000000000 0 0 0 0.0000 0.0000 +100 123456 0.3 40000.25 123456789123456789.1000100000 1024 7000 8 999999.9000 9223372036854775807.0000 +9999999999 9999999999 0.9 99999999.99 99999999999999999999999999999999999999999999999999.9999999999 9999999999 9999999999 9 9999999999999999.9999 9999999999999999999999999999999999999999999999999999999999999.9999 +9999999999 9999999999 0.9 99999999.99 99999999999999999999999999999999999999999999999999.9999999999 9999999999 9999999999 9 9999999999999999.9999 9999999999999999999999999999999999999999999999999999999999999.9999 +9999999999 9999999999 0.9 99999999.99 99999999999999999999999999999999999999999999999999.9999999999 9999999999 9999999999 9 9999999999999999.9999 9999999999999999999999999999999999999999999999999999999999999.9999 +INSERT INTO t1 VALUES (9999999999.1,9999999999.1,1.9,99999999.001,99999999999999999999999999999999999999999999999999.99999999991,9999999999.1,9999999999.1,9.1,9999999999999999.00001,9999999999999999999999999999999999999999999999999999999999999.11111); +Warnings: +Note 1265 Data truncated for column 'd' at row 1 +Note 1265 Data truncated for column 'd0' at row 1 +Warning 1264 Out of range value for column 'd1_1' at row 1 +Note 1265 Data truncated for column 'd10_2' at row 1 +Note 1265 Data truncated for column 'd60_10' at row 1 +Note 1265 Data truncated for column 'n' at row 1 +Note 1265 Data truncated for column 'n0_0' at row 1 +Note 1265 Data truncated for column 'n1' at row 1 +Note 1265 Data truncated for column 'n20_4' at row 1 +Note 1265 Data truncated for column 'n65_4' at row 1 +SELECT * FROM t1; +d d0 d1_1 d10_2 d60_10 n n0_0 n1 n20_4 n65_4 +-100 -123456 -0.3 -40000.25 -123456789123456789.1000100000 -1024 -7000 -8 -999999.9000 -9223372036854775807.0000 +-9999999999 -9999999999 -0.9 -99999999.99 -99999999999999999999999999999999999999999999999999.9999999999 -9999999999 -9999999999 -9 -9999999999999999.9999 -9999999999999999999999999999999999999999999999999999999999999.9999 +0 0 0.0 0.00 0.0000000000 0 0 0 0.0000 0.0000 +100 123456 0.3 40000.25 123456789123456789.1000100000 1024 7000 8 999999.9000 9223372036854775807.0000 +9999999999 9999999999 0.9 99999999.00 99999999999999999999999999999999999999999999999999.9999999999 9999999999 9999999999 9 9999999999999999.0000 9999999999999999999999999999999999999999999999999999999999999.1111 +9999999999 9999999999 0.9 99999999.99 99999999999999999999999999999999999999999999999999.9999999999 9999999999 9999999999 9 9999999999999999.9999 9999999999999999999999999999999999999999999999999999999999999.9999 +9999999999 9999999999 0.9 99999999.99 99999999999999999999999999999999999999999999999999.9999999999 9999999999 9999999999 9 9999999999999999.9999 9999999999999999999999999999999999999999999999999999999999999.9999 +9999999999 9999999999 0.9 99999999.99 99999999999999999999999999999999999999999999999999.9999999999 9999999999 9999999999 9 9999999999999999.9999 9999999999999999999999999999999999999999999999999999999999999.9999 +ALTER TABLE t1 ADD COLUMN n66 NUMERIC(66); +ERROR 42000: Too big precision 66 specified for 'n66'. Maximum is 65. +ALTER TABLE t1 ADD COLUMN n66_6 DECIMAL(66,6); +ERROR 42000: Too big precision 66 specified for 'n66_6'. Maximum is 65. +ALTER TABLE t1 ADD COLUMN n66_66 DECIMAL(66,66); +ERROR 42000: Too big scale 66 specified for 'n66_66'. Maximum is 30. +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c DECIMAL NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c decimal(10,0) YES NULL +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c), COUNT(*) FROM t1; +COUNT(c) COUNT(*) +0 1 +DROP TABLE t1; +CREATE TABLE t1 (c DECIMAL NULL, +c1 DECIMAL NULL DEFAULT NULL, +c2 DECIMAL NULL DEFAULT 1.1 +) ENGINE= ; +Warnings: +Note 1265 Data truncated for column 'c2' at row 1 +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c decimal(10,0) YES NULL +c1 decimal(10,0) YES NULL +c2 decimal(10,0) YES 1 +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c2), COUNT(c1), COUNT(c), COUNT(*) FROM t1; +COUNT(c2) COUNT(c1) COUNT(c) COUNT(*) +1 0 0 1 +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c NUMERIC NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c decimal(10,0) YES NULL +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c), COUNT(*) FROM t1; +COUNT(c) COUNT(*) +0 1 +DROP TABLE t1; +CREATE TABLE t1 (c NUMERIC NULL, +c1 NUMERIC NULL DEFAULT NULL, +c2 NUMERIC NULL DEFAULT 0 +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c decimal(10,0) YES NULL +c1 decimal(10,0) YES NULL +c2 decimal(10,0) YES 0 +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c2), COUNT(c1), COUNT(c), COUNT(*) FROM t1; +COUNT(c2) COUNT(c1) COUNT(c) COUNT(*) +1 0 0 1 +DROP TABLE t1; +# +# Floating point columns (FLOAT, DOUBLE) +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (f FLOAT NULL, +f0 FLOAT(0) NULL, +r1_1 REAL(1,1) NULL, +f23_0 FLOAT(23) NULL, +f20_3 FLOAT(20,3) NULL, +d DOUBLE NULL, +d1_0 DOUBLE(1,0) NULL, +d10_10 DOUBLE PRECISION (10,10) NULL, +d53 DOUBLE(53,0) NULL, +d53_10 DOUBLE(53,10) NULL +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +f float # # # +f0 float # # # +r1_1 double(1,1) # # # +f23_0 float # # # +f20_3 float(20,3) # # # +d double # # # +d1_0 double(1,0) # # # +d10_10 double(10,10) # # # +d53 double(53,0) # # # +d53_10 double(53,10) # # # +INSERT INTO t1 VALUES (12345.12345,12345.12345,0.9,123456789.123,56789.987,11111111.111,8.0,0.0123456789,1234566789123456789,99999999999999999.99999999); +SELECT * FROM t1; +f 12345.1 +d 11111111.111 +d10_10 0.0123456789 +d1_0 8 +d53 1234566789123456800 +d53_10 100000000000000000.0000000000 +f0 12345.1 +f20_3 56789.988 +f23_0 123457000 +r1_1 0.9 +INSERT INTO t1 VALUES (0,0,0,0,0,0,0,0,0,0); +INSERT INTO t1 VALUES ( +99999999999999999999999999999999999999, +99999999999999999999999999999999999999.9999999999999999, +0.9, +99999999999999999999999999999999999999.9, +99999999999999999.999, +999999999999999999999999999999999999999999999999999999999999999999999999999999999, +9, +0.9999999999, +1999999999999999999999999999999999999999999999999999999, +19999999999999999999999999999999999999999999.9999999999 +); +Warnings: +Warning 1264 Out of range value for column 'd53' at row 1 +Warning 1264 Out of range value for column 'd53_10' at row 1 +SELECT * FROM t1; +f 12345.1 +d 0 +d 11111111.111 +d 1e81 +d10_10 0.0000000000 +d10_10 0.0123456789 +d10_10 0.9999999999 +d1_0 0 +d1_0 8 +d1_0 9 +d53 0 +d53 100000000000000000000000000000000000000000000000000000 +d53 1234566789123456800 +d53_10 0.0000000000 +d53_10 100000000000000000.0000000000 +d53_10 10000000000000000000000000000000000000000000.0000000000 +f 0 +f 1e38 +f0 0 +f0 12345.1 +f0 1e38 +f20_3 0.000 +f20_3 56789.988 +f20_3 99999998430674940.000 +f23_0 0 +f23_0 123457000 +f23_0 1e38 +r1_1 0.0 +r1_1 0.9 +r1_1 0.9 +INSERT INTO t1 VALUES (-999999999999999999999999,-99999999999.999999999999,-0.9,-999.99999999999999999999,-99999999999999999.999,-999999999999999999999999999999999999999999999999999999999999-0.999,-9,-.9999999999,-999999999999999999999999999999.99999999999999999999999,-9999999999999999999999999999999999999999999.9999999999); +SELECT * FROM t1; +f 12345.1 +d -1e60 +d 0 +d 11111111.111 +d 1e81 +d10_10 -0.9999999999 +d10_10 0.0000000000 +d10_10 0.0123456789 +d10_10 0.9999999999 +d1_0 -9 +d1_0 0 +d1_0 8 +d1_0 9 +d53 -1000000000000000000000000000000 +d53 0 +d53 100000000000000000000000000000000000000000000000000000 +d53 1234566789123456800 +d53_10 -10000000000000000000000000000000000000000000.0000000000 +d53_10 0.0000000000 +d53_10 100000000000000000.0000000000 +d53_10 10000000000000000000000000000000000000000000.0000000000 +f -1e24 +f 0 +f 1e38 +f0 -100000000000 +f0 0 +f0 12345.1 +f0 1e38 +f20_3 -99999998430674940.000 +f20_3 0.000 +f20_3 56789.988 +f20_3 99999998430674940.000 +f23_0 -1000 +f23_0 0 +f23_0 123457000 +f23_0 1e38 +r1_1 -0.9 +r1_1 0.0 +r1_1 0.9 +r1_1 0.9 +SELECT MAX(f), MAX(f0), MAX(r1_1), MAX(f23_0), MAX(f20_3), MAX(d), MAX(d1_0), MAX(d10_10), MAX(d53), MAX(d53_10) FROM t1; +MAX(f) 9.999999680285692e37 +MAX(d) 1e81 +MAX(d10_10) 0.9999999999 +MAX(d1_0) 9 +MAX(d53) 100000000000000000000000000000000000000000000000000000 +MAX(d53_10) 10000000000000000000000000000000000000000000.0000000000 +MAX(f0) 9.999999680285692e37 +MAX(f20_3) 99999998430674940.000 +MAX(f23_0) 9.999999680285692e37 +MAX(r1_1) 0.9 +INSERT INTO t1 SELECT d53_10, d53_10, d53_10, d53_10, d53_10, d53_10, d53_10, d53_10, d53_10, d53_10 FROM t1 ORDER BY d53_10 DESC LIMIT 1; +Warnings: +Warning 1264 Out of range value for column 'f' at row 1 +Warning 1264 Out of range value for column 'f0' at row 1 +Warning 1264 Out of range value for column 'r1_1' at row 1 +Warning 1264 Out of range value for column 'f23_0' at row 1 +Warning 1264 Out of range value for column 'f20_3' at row 1 +Warning 1264 Out of range value for column 'd1_0' at row 1 +SELECT * FROM t1; +f 12345.1 +d -1e60 +d 0 +d 11111111.111 +d 1e43 +d 1e81 +d10_10 -0.9999999999 +d10_10 0.0000000000 +d10_10 0.0123456789 +d10_10 0.9999999999 +d10_10 10000000000000000000000000000000000000000000.0000000000 +d1_0 -9 +d1_0 0 +d1_0 8 +d1_0 9 +d1_0 9 +d53 -1000000000000000000000000000000 +d53 0 +d53 10000000000000000000000000000000000000000000 +d53 100000000000000000000000000000000000000000000000000000 +d53 1234566789123456800 +d53_10 -10000000000000000000000000000000000000000000.0000000000 +d53_10 0.0000000000 +d53_10 100000000000000000.0000000000 +d53_10 10000000000000000000000000000000000000000000.0000000000 +d53_10 10000000000000000000000000000000000000000000.0000000000 +f -1e24 +f 0 +f 1e38 +f 3.40282e38 +f0 -100000000000 +f0 0 +f0 12345.1 +f0 1e38 +f0 3.40282e38 +f20_3 -99999998430674940.000 +f20_3 0.000 +f20_3 56789.988 +f20_3 99999998430674940.000 +f20_3 99999998430674940.000 +f23_0 -1000 +f23_0 0 +f23_0 123457000 +f23_0 1e38 +f23_0 3.40282e38 +r1_1 -0.9 +r1_1 0.0 +r1_1 0.9 +r1_1 0.9 +r1_1 0.9 +INSERT INTO t1 VALUES ( +999999999999999999999999999999999999999, +999999999999999999999999999999999999999.9999999999999999, +1.9, +999999999999999999999999999999999999999.9, +999999999999999999.999, +9999999999999999999999999999999999999999999999999999999999999999999999999999999999, +99, +1.9999999999, +1999999999999999999999999999999999999999999999999999999, +19999999999999999999999999999999999999999999.9999999999 +); +Warnings: +Warning 1916 Got overflow when converting '' to DECIMAL. Value truncated. +Warning 1264 Out of range value for column 'f' at row 1 +Warning 1264 Out of range value for column 'f0' at row 1 +Warning 1264 Out of range value for column 'r1_1' at row 1 +Warning 1264 Out of range value for column 'f23_0' at row 1 +Warning 1264 Out of range value for column 'f20_3' at row 1 +Warning 1264 Out of range value for column 'd1_0' at row 1 +Warning 1264 Out of range value for column 'd10_10' at row 1 +Warning 1264 Out of range value for column 'd53' at row 1 +Warning 1264 Out of range value for column 'd53_10' at row 1 +SELECT * FROM t1; +f 12345.1 +d -1e60 +d 0 +d 11111111.111 +d 1e43 +d 1e65 +d 1e81 +d10_10 -0.9999999999 +d10_10 0.0000000000 +d10_10 0.0123456789 +d10_10 0.9999999999 +d10_10 0.9999999999 +d10_10 10000000000000000000000000000000000000000000.0000000000 +d1_0 -9 +d1_0 0 +d1_0 8 +d1_0 9 +d1_0 9 +d1_0 9 +d53 -1000000000000000000000000000000 +d53 0 +d53 10000000000000000000000000000000000000000000 +d53 100000000000000000000000000000000000000000000000000000 +d53 100000000000000000000000000000000000000000000000000000 +d53 1234566789123456800 +d53_10 -10000000000000000000000000000000000000000000.0000000000 +d53_10 0.0000000000 +d53_10 100000000000000000.0000000000 +d53_10 10000000000000000000000000000000000000000000.0000000000 +d53_10 10000000000000000000000000000000000000000000.0000000000 +d53_10 10000000000000000000000000000000000000000000.0000000000 +f -1e24 +f 0 +f 1e38 +f 3.40282e38 +f 3.40282e38 +f0 -100000000000 +f0 0 +f0 12345.1 +f0 1e38 +f0 3.40282e38 +f0 3.40282e38 +f20_3 -99999998430674940.000 +f20_3 0.000 +f20_3 56789.988 +f20_3 99999998430674940.000 +f20_3 99999998430674940.000 +f20_3 99999998430674940.000 +f23_0 -1000 +f23_0 0 +f23_0 123457000 +f23_0 1e38 +f23_0 3.40282e38 +f23_0 3.40282e38 +r1_1 -0.9 +r1_1 0.0 +r1_1 0.9 +r1_1 0.9 +r1_1 0.9 +r1_1 0.9 +ALTER TABLE t1 ADD COLUMN d0_0 DOUBLE(0,0); +ERROR 42000: Display width out of range for 'd0_0' (max = 255) +ALTER TABLE t1 ADD COLUMN n66_6 DECIMAL(256,1); +ERROR 42000: Too big precision 256 specified for 'n66_6'. Maximum is 65. +ALTER TABLE t1 ADD COLUMN n66_66 DECIMAL(40,35); +ERROR 42000: Too big scale 35 specified for 'n66_66'. Maximum is 30. +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c FLOAT NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c float YES NULL +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c), COUNT(*) FROM t1; +COUNT(c) COUNT(*) +0 1 +DROP TABLE t1; +CREATE TABLE t1 (c FLOAT NULL, +c1 FLOAT NULL DEFAULT NULL, +c2 FLOAT NULL DEFAULT 1.1 +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c float YES NULL +c1 float YES NULL +c2 float YES 1.1 +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c2), COUNT(c1), COUNT(c), COUNT(*) FROM t1; +COUNT(c2) COUNT(c1) COUNT(c) COUNT(*) +1 0 0 1 +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c DOUBLE NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c double YES NULL +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c), COUNT(*) FROM t1; +COUNT(c) COUNT(*) +0 1 +DROP TABLE t1; +CREATE TABLE t1 (c DOUBLE NULL, +c1 DOUBLE NULL DEFAULT NULL, +c2 DOUBLE NULL DEFAULT 0 +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c double YES NULL +c1 double YES NULL +c2 double YES 0 +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c2), COUNT(c1), COUNT(c), COUNT(*) FROM t1; +COUNT(c2) COUNT(c1) COUNT(c) COUNT(*) +1 0 0 1 +DROP TABLE t1; +# +# INT columns +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (i INT NULL, +i0 INT(0) NULL, +i1 INT(1) NULL, +i20 INT(20) NULL, +t TINYINT NULL, +t0 TINYINT(0) NULL, +t1 TINYINT(1) NULL, +t20 TINYINT(20) NULL, +s SMALLINT NULL, +s0 SMALLINT(0) NULL, +s1 SMALLINT(1) NULL, +s20 SMALLINT(20) NULL, +m MEDIUMINT NULL, +m0 MEDIUMINT(0) NULL, +m1 MEDIUMINT(1) NULL, +m20 MEDIUMINT(20) NULL, +b BIGINT NULL, +b0 BIGINT(0) NULL, +b1 BIGINT(1) NULL, +b20 BIGINT(20) NULL +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +i int(11) # # # +i0 int(11) # # # +i1 int(1) # # # +i20 int(20) # # # +t tinyint(4) # # # +t0 tinyint(4) # # # +t1 tinyint(1) # # # +t20 tinyint(20) # # # +s smallint(6) # # # +s0 smallint(6) # # # +s1 smallint(1) # # # +s20 smallint(20) # # # +m mediumint(9) # # # +m0 mediumint(9) # # # +m1 mediumint(1) # # # +m20 mediumint(20) # # # +b bigint(20) # # # +b0 bigint(20) # # # +b1 bigint(1) # # # +b20 bigint(20) # # # +INSERT INTO t1 VALUES (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20); +INSERT INTO t1 VALUES (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); +INSERT INTO t1 VALUES (2147483647,2147483647,2147483647,2147483647,127,127,127,127,32767,32767,32767,32767,8388607,8388607,8388607,8388607,9223372036854775807,9223372036854775807,9223372036854775807,9223372036854775807); +SELECT * FROM t1; +i i0 i1 i20 t t0 t1 t20 s s0 s1 s20 m m0 m1 m20 b b0 b1 b20 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 +2147483647 2147483647 2147483647 2147483647 127 127 127 127 32767 32767 32767 32767 8388607 8388607 8388607 8388607 9223372036854775807 9223372036854775807 9223372036854775807 9223372036854775807 +INSERT INTO t1 VALUES (-2147483648,-2147483648,-2147483648,-2147483648,-128,-128,-128,-128,-32768,-32768,-32768,-32768,-8388608,-8388608,-8388608,-8388608,-9223372036854775808,-9223372036854775808,-9223372036854775808,-9223372036854775808); +INSERT INTO t1 VALUES (4294967295,4294967295,4294967295,4294967295,255,255,255,255,65535,65535,65535,65535,16777215,16777215,16777215,16777215,18446744073709551615,18446744073709551615,18446744073709551615,18446744073709551615); +Warnings: +Warning 1264 Out of range value for column 'i' at row 1 +Warning 1264 Out of range value for column 'i0' at row 1 +Warning 1264 Out of range value for column 'i1' at row 1 +Warning 1264 Out of range value for column 'i20' at row 1 +Warning 1264 Out of range value for column 't' at row 1 +Warning 1264 Out of range value for column 't0' at row 1 +Warning 1264 Out of range value for column 't1' at row 1 +Warning 1264 Out of range value for column 't20' at row 1 +Warning 1264 Out of range value for column 's' at row 1 +Warning 1264 Out of range value for column 's0' at row 1 +Warning 1264 Out of range value for column 's1' at row 1 +Warning 1264 Out of range value for column 's20' at row 1 +Warning 1264 Out of range value for column 'm' at row 1 +Warning 1264 Out of range value for column 'm0' at row 1 +Warning 1264 Out of range value for column 'm1' at row 1 +Warning 1264 Out of range value for column 'm20' at row 1 +Warning 1264 Out of range value for column 'b' at row 1 +Warning 1264 Out of range value for column 'b0' at row 1 +Warning 1264 Out of range value for column 'b1' at row 1 +Warning 1264 Out of range value for column 'b20' at row 1 +SELECT * FROM t1; +i i0 i1 i20 t t0 t1 t20 s s0 s1 s20 m m0 m1 m20 b b0 b1 b20 +-2147483648 -2147483648 -2147483648 -2147483648 -128 -128 -128 -128 -32768 -32768 -32768 -32768 -8388608 -8388608 -8388608 -8388608 -9223372036854775808 -9223372036854775808 -9223372036854775808 -9223372036854775808 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 +2147483647 2147483647 2147483647 2147483647 127 127 127 127 32767 32767 32767 32767 8388607 8388607 8388607 8388607 9223372036854775807 9223372036854775807 9223372036854775807 9223372036854775807 +2147483647 2147483647 2147483647 2147483647 127 127 127 127 32767 32767 32767 32767 8388607 8388607 8388607 8388607 9223372036854775807 9223372036854775807 9223372036854775807 9223372036854775807 +INSERT INTO t1 VALUES (-2147483649,-2147483649,-2147483649,-2147483649,-129,-129,-129,-129,-32769,-32769,-32769,-32769,-8388609,-8388609,-8388609,-8388609,-9223372036854775809,-9223372036854775809,-9223372036854775809,-9223372036854775809); +Warnings: +Warning 1264 Out of range value for column 'i' at row 1 +Warning 1264 Out of range value for column 'i0' at row 1 +Warning 1264 Out of range value for column 'i1' at row 1 +Warning 1264 Out of range value for column 'i20' at row 1 +Warning 1264 Out of range value for column 't' at row 1 +Warning 1264 Out of range value for column 't0' at row 1 +Warning 1264 Out of range value for column 't1' at row 1 +Warning 1264 Out of range value for column 't20' at row 1 +Warning 1264 Out of range value for column 's' at row 1 +Warning 1264 Out of range value for column 's0' at row 1 +Warning 1264 Out of range value for column 's1' at row 1 +Warning 1264 Out of range value for column 's20' at row 1 +Warning 1264 Out of range value for column 'm' at row 1 +Warning 1264 Out of range value for column 'm0' at row 1 +Warning 1264 Out of range value for column 'm1' at row 1 +Warning 1264 Out of range value for column 'm20' at row 1 +Warning 1264 Out of range value for column 'b' at row 1 +Warning 1264 Out of range value for column 'b0' at row 1 +Warning 1264 Out of range value for column 'b1' at row 1 +Warning 1264 Out of range value for column 'b20' at row 1 +INSERT INTO t1 VALUES (4294967296,4294967296,4294967296,4294967296,256,256,256,256,65536,65536,65536,65536,16777216,16777216,16777216,16777216,18446744073709551616,18446744073709551616,18446744073709551616,18446744073709551616); +Warnings: +Warning 1264 Out of range value for column 'i' at row 1 +Warning 1264 Out of range value for column 'i0' at row 1 +Warning 1264 Out of range value for column 'i1' at row 1 +Warning 1264 Out of range value for column 'i20' at row 1 +Warning 1264 Out of range value for column 't' at row 1 +Warning 1264 Out of range value for column 't0' at row 1 +Warning 1264 Out of range value for column 't1' at row 1 +Warning 1264 Out of range value for column 't20' at row 1 +Warning 1264 Out of range value for column 's' at row 1 +Warning 1264 Out of range value for column 's0' at row 1 +Warning 1264 Out of range value for column 's1' at row 1 +Warning 1264 Out of range value for column 's20' at row 1 +Warning 1264 Out of range value for column 'm' at row 1 +Warning 1264 Out of range value for column 'm0' at row 1 +Warning 1264 Out of range value for column 'm1' at row 1 +Warning 1264 Out of range value for column 'm20' at row 1 +Warning 1264 Out of range value for column 'b' at row 1 +Warning 1264 Out of range value for column 'b0' at row 1 +Warning 1264 Out of range value for column 'b1' at row 1 +Warning 1264 Out of range value for column 'b20' at row 1 +INSERT INTO t1 SELECT b,b,b,b,b,b,b,b,b,b,b,b,b,b,b,b,b,b,b,b FROM t1 WHERE b IN (-9223372036854775808,9223372036854775807,18446744073709551615); +Warnings: +Warning 1264 Out of range value for column 'i' at row 1 +Warning 1264 Out of range value for column 'i0' at row 1 +Warning 1264 Out of range value for column 'i1' at row 1 +Warning 1264 Out of range value for column 'i20' at row 1 +Warning 1264 Out of range value for column 't' at row 1 +Warning 1264 Out of range value for column 't0' at row 1 +Warning 1264 Out of range value for column 't1' at row 1 +Warning 1264 Out of range value for column 't20' at row 1 +Warning 1264 Out of range value for column 's' at row 1 +Warning 1264 Out of range value for column 's0' at row 1 +Warning 1264 Out of range value for column 's1' at row 1 +Warning 1264 Out of range value for column 's20' at row 1 +Warning 1264 Out of range value for column 'm' at row 1 +Warning 1264 Out of range value for column 'm0' at row 1 +Warning 1264 Out of range value for column 'm1' at row 1 +Warning 1264 Out of range value for column 'm20' at row 1 +Warning 1264 Out of range value for column 'i' at row 2 +Warning 1264 Out of range value for column 'i0' at row 2 +Warning 1264 Out of range value for column 'i1' at row 2 +Warning 1264 Out of range value for column 'i20' at row 2 +Warning 1264 Out of range value for column 't' at row 2 +Warning 1264 Out of range value for column 't0' at row 2 +Warning 1264 Out of range value for column 't1' at row 2 +Warning 1264 Out of range value for column 't20' at row 2 +Warning 1264 Out of range value for column 's' at row 2 +Warning 1264 Out of range value for column 's0' at row 2 +Warning 1264 Out of range value for column 's1' at row 2 +Warning 1264 Out of range value for column 's20' at row 2 +Warning 1264 Out of range value for column 'm' at row 2 +Warning 1264 Out of range value for column 'm0' at row 2 +Warning 1264 Out of range value for column 'm1' at row 2 +Warning 1264 Out of range value for column 'm20' at row 2 +Warning 1264 Out of range value for column 'i' at row 3 +Warning 1264 Out of range value for column 'i0' at row 3 +Warning 1264 Out of range value for column 'i1' at row 3 +Warning 1264 Out of range value for column 'i20' at row 3 +Warning 1264 Out of range value for column 't' at row 3 +Warning 1264 Out of range value for column 't0' at row 3 +Warning 1264 Out of range value for column 't1' at row 3 +Warning 1264 Out of range value for column 't20' at row 3 +Warning 1264 Out of range value for column 's' at row 3 +Warning 1264 Out of range value for column 's0' at row 3 +Warning 1264 Out of range value for column 's1' at row 3 +Warning 1264 Out of range value for column 's20' at row 3 +Warning 1264 Out of range value for column 'm' at row 3 +Warning 1264 Out of range value for column 'm0' at row 3 +Warning 1264 Out of range value for column 'm1' at row 3 +Warning 1264 Out of range value for column 'm20' at row 3 +Warning 1264 Out of range value for column 'i' at row 4 +Warning 1264 Out of range value for column 'i0' at row 4 +Warning 1264 Out of range value for column 'i1' at row 4 +Warning 1264 Out of range value for column 'i20' at row 4 +Warning 1264 Out of range value for column 't' at row 4 +Warning 1264 Out of range value for column 't0' at row 4 +Warning 1264 Out of range value for column 't1' at row 4 +Warning 1264 Out of range value for column 't20' at row 4 +Warning 1264 Out of range value for column 's' at row 4 +Warning 1264 Out of range value for column 's0' at row 4 +Warning 1264 Out of range value for column 's1' at row 4 +Warning 1264 Out of range value for column 's20' at row 4 +Warning 1264 Out of range value for column 'm' at row 4 +Warning 1264 Out of range value for column 'm0' at row 4 +Warning 1264 Out of range value for column 'm1' at row 4 +Warning 1264 Out of range value for column 'm20' at row 4 +SELECT * FROM t1; +i i0 i1 i20 t t0 t1 t20 s s0 s1 s20 m m0 m1 m20 b b0 b1 b20 +-2147483648 -2147483648 -2147483648 -2147483648 -128 -128 -128 -128 -32768 -32768 -32768 -32768 -8388608 -8388608 -8388608 -8388608 -9223372036854775808 -9223372036854775808 -9223372036854775808 -9223372036854775808 +-2147483648 -2147483648 -2147483648 -2147483648 -128 -128 -128 -128 -32768 -32768 -32768 -32768 -8388608 -8388608 -8388608 -8388608 -9223372036854775808 -9223372036854775808 -9223372036854775808 -9223372036854775808 +-2147483648 -2147483648 -2147483648 -2147483648 -128 -128 -128 -128 -32768 -32768 -32768 -32768 -8388608 -8388608 -8388608 -8388608 -9223372036854775808 -9223372036854775808 -9223372036854775808 -9223372036854775808 +-2147483648 -2147483648 -2147483648 -2147483648 -128 -128 -128 -128 -32768 -32768 -32768 -32768 -8388608 -8388608 -8388608 -8388608 -9223372036854775808 -9223372036854775808 -9223372036854775808 -9223372036854775808 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 +2147483647 2147483647 2147483647 2147483647 127 127 127 127 32767 32767 32767 32767 8388607 8388607 8388607 8388607 9223372036854775807 9223372036854775807 9223372036854775807 9223372036854775807 +2147483647 2147483647 2147483647 2147483647 127 127 127 127 32767 32767 32767 32767 8388607 8388607 8388607 8388607 9223372036854775807 9223372036854775807 9223372036854775807 9223372036854775807 +2147483647 2147483647 2147483647 2147483647 127 127 127 127 32767 32767 32767 32767 8388607 8388607 8388607 8388607 9223372036854775807 9223372036854775807 9223372036854775807 9223372036854775807 +2147483647 2147483647 2147483647 2147483647 127 127 127 127 32767 32767 32767 32767 8388607 8388607 8388607 8388607 9223372036854775807 9223372036854775807 9223372036854775807 9223372036854775807 +2147483647 2147483647 2147483647 2147483647 127 127 127 127 32767 32767 32767 32767 8388607 8388607 8388607 8388607 9223372036854775807 9223372036854775807 9223372036854775807 9223372036854775807 +2147483647 2147483647 2147483647 2147483647 127 127 127 127 32767 32767 32767 32767 8388607 8388607 8388607 8388607 9223372036854775807 9223372036854775807 9223372036854775807 9223372036854775807 +ALTER TABLE t1 ADD COLUMN i257 INT(257); +ERROR 42000: Display width out of range for 'i257' (max = 255) +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c INT NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c int(11) YES NULL +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c), COUNT(*) FROM t1; +COUNT(c) COUNT(*) +0 1 +DROP TABLE t1; +CREATE TABLE t1 (c INT NULL, +c1 INT NULL DEFAULT NULL, +c2 INT NULL DEFAULT 2147483647 +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c int(11) YES NULL +c1 int(11) YES NULL +c2 int(11) YES 2147483647 +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c2), COUNT(c1), COUNT(c), COUNT(*) FROM t1; +COUNT(c2) COUNT(c1) COUNT(c) COUNT(*) +1 0 0 1 +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c TINYINT NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c tinyint(4) YES NULL +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c), COUNT(*) FROM t1; +COUNT(c) COUNT(*) +0 1 +DROP TABLE t1; +CREATE TABLE t1 (c TINYINT NULL, +c1 TINYINT NULL DEFAULT NULL, +c2 TINYINT NULL DEFAULT 127 +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c tinyint(4) YES NULL +c1 tinyint(4) YES NULL +c2 tinyint(4) YES 127 +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c2), COUNT(c1), COUNT(c), COUNT(*) FROM t1; +COUNT(c2) COUNT(c1) COUNT(c) COUNT(*) +1 0 0 1 +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c SMALLINT NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c smallint(6) YES NULL +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c), COUNT(*) FROM t1; +COUNT(c) COUNT(*) +0 1 +DROP TABLE t1; +CREATE TABLE t1 (c SMALLINT NULL, +c1 SMALLINT NULL DEFAULT NULL, +c2 SMALLINT NULL DEFAULT 0 +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c smallint(6) YES NULL +c1 smallint(6) YES NULL +c2 smallint(6) YES 0 +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c2), COUNT(c1), COUNT(c), COUNT(*) FROM t1; +COUNT(c2) COUNT(c1) COUNT(c) COUNT(*) +1 0 0 1 +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c MEDIUMINT NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c mediumint(9) YES NULL +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c), COUNT(*) FROM t1; +COUNT(c) COUNT(*) +0 1 +DROP TABLE t1; +CREATE TABLE t1 (c MEDIUMINT NULL, +c1 MEDIUMINT NULL DEFAULT NULL, +c2 MEDIUMINT NULL DEFAULT 1 +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c mediumint(9) YES NULL +c1 mediumint(9) YES NULL +c2 mediumint(9) YES 1 +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c2), COUNT(c1), COUNT(c), COUNT(*) FROM t1; +COUNT(c2) COUNT(c1) COUNT(c) COUNT(*) +1 0 0 1 +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c BIGINT NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c bigint(20) YES NULL +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c), COUNT(*) FROM t1; +COUNT(c) COUNT(*) +0 1 +DROP TABLE t1; +CREATE TABLE t1 (c BIGINT NULL, +c1 BIGINT NULL DEFAULT NULL, +c2 BIGINT NULL DEFAULT 9223372036854775807 +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c bigint(20) YES NULL +c1 bigint(20) YES NULL +c2 bigint(20) YES 9223372036854775807 +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c2), COUNT(c1), COUNT(c), COUNT(*) FROM t1; +COUNT(c2) COUNT(c1) COUNT(c) COUNT(*) +1 0 0 1 +DROP TABLE t1; +# +# SET columns +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (a SET('') NULL, +b SET('test1','test2','test3','test4','test5') NULL, +c SET('01','02','03','04','05','06','07','08','09','10','11','12','13','14','15','16','17','18','19','20','21','22','23','24','25','26','27','28','29','30','31','32','33','34','35','36','37','38','39','40','41','42','43','44','45','46','47','48','49','50''51','52','53','54','55','56','57','58','59','60','61','62','63','64') NULL +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +a set('') # # # +b set('test1','test2','test3','test4','test5') # # # +c set('01','02','03','04','05','06','07','08','09','10','11','12','13','14','15','16','17','18','19','20','21','22','23','24','25','26','27','28','29','30','31','32','33','34','35','36','37','38','39','40','41','42','43','44','45','46','47','48','49','50''51','52','53','54','55','56','57','58','59','60','61','62','63','64') # # # +INSERT INTO t1 VALUES +('','test2,test3','01,34,44,,23'), +('',5,2), +(',','test4,test2',''); +Warnings: +Warning 1265 Data truncated for column 'c' at row 1 +SELECT * FROM t1; +a b c + test1,test3 02 + test2,test3 01,23,34,44 + test2,test4 +INSERT INTO t1 VALUES (0,'test6',-1); +Warnings: +Warning 1265 Data truncated for column 'b' at row 1 +Warning 1265 Data truncated for column 'c' at row 1 +SELECT * FROM t1; +a b c + 01,02,03,04,05,06,07,08,09,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50'51,52,53,54,55,56,57,58,59,60,61,62,63,64 + test1,test3 02 + test2,test3 01,23,34,44 + test2,test4 +ALTER TABLE t1 ADD COLUMN e SET('a','A') NULL; +Warnings: +Note 1291 Column 'e' has duplicated value 'a' in SET +Note 1291 Column 'e' has duplicated value 'a' in SET +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +a set('') # # # +b set('test1','test2','test3','test4','test5') # # # +c set('01','02','03','04','05','06','07','08','09','10','11','12','13','14','15','16','17','18','19','20','21','22','23','24','25','26','27','28','29','30','31','32','33','34','35','36','37','38','39','40','41','42','43','44','45','46','47','48','49','50''51','52','53','54','55','56','57','58','59','60','61','62','63','64') # # # +e set('a','A') # # # +ALTER TABLE t1 ADD COLUMN f SET('1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',' ','11','12','13','14','15','16','17','18','19','1a','1b','1c','1d','1e','1f','1g','1h','1i','1j','1k','1l','1m','1n','1o','1p','1q','1r','1s','1t','1u','1v','1w','1x','1y','1z','20','21','22','23','24','25','26','27','28','29','2a','2b','2c','2d','2e','2f','2g','2h','2i','2j','2k','2l','2m','2n','2o','2p','2q','2r','2s','2t','2u','2v','2w','2x','2y','2z','30','31','32','33','34','35','36','37','38','39','3a','3b','3c','3d','3e','3f','3g','3h','3i') NULL; +ERROR HY000: Too many strings for column f and SET +SELECT * FROM t1 WHERE FIND_IN_SET('test2',b)>0 OR a != ''; +a b c e + test2,test3 01,23,34,44 NULL + test2,test4 NULL +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c SET('test1','test2','test3') NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c set('test1','test2','test3') YES NULL +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c), COUNT(*) FROM t1; +COUNT(c) COUNT(*) +0 1 +DROP TABLE t1; +CREATE TABLE t1 (c SET('test1','test2','test3') NULL, +c1 SET('test1','test2','test3') NULL DEFAULT NULL, +c2 SET('test1','test2','test3') NULL DEFAULT 'test2,test3' +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c set('test1','test2','test3') YES NULL +c1 set('test1','test2','test3') YES NULL +c2 set('test1','test2','test3') YES test2,test3 +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c2), COUNT(c1), COUNT(c), COUNT(*) FROM t1; +COUNT(c2) COUNT(c1) COUNT(c) COUNT(*) +1 0 0 1 +DROP TABLE t1; +# +# TEXT columns +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (t TEXT NULL, +t0 TEXT(0) NULL, +t1 TEXT(1) NULL, +t300 TEXT(300) NULL, +tm TEXT(65535) NULL, +t70k TEXT(70000) NULL, +t17m TEXT(17000000) NULL, +tt TINYTEXT NULL, +m MEDIUMTEXT NULL, +l LONGTEXT NULL +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +t text # # # +t0 text # # # +t1 tinytext # # # +t300 text # # # +tm text # # # +t70k mediumtext # # # +t17m longtext # # # +tt tinytext # # # +m mediumtext # # # +l longtext # # # +INSERT INTO t1 VALUES +('','','','','','','','','',''), +('a','b','c','d','e','f','g','h','i','j'), +('test1','test2','test3','test4','test5','test6','test7','test8','test9','test10'), +( REPEAT('a',65535), REPEAT('b',65535), REPEAT('c',255), REPEAT('d',65535), REPEAT('e',65535), REPEAT('f',1048576), REPEAT('g',1048576), REPEAT('h',255), REPEAT('i',1048576), REPEAT('j',1048576) ); +SELECT LENGTH(t), LENGTH(t0), LENGTH(t1), LENGTH(t300), LENGTH(tm), LENGTH(t70k), LENGTH(t17m), LENGTH(tt), LENGTH(m), LENGTH(l) FROM t1; +LENGTH(t) LENGTH(t0) LENGTH(t1) LENGTH(t300) LENGTH(tm) LENGTH(t70k) LENGTH(t17m) LENGTH(tt) LENGTH(m) LENGTH(l) +0 0 0 0 0 0 0 0 0 0 +1 1 1 1 1 1 1 1 1 1 +5 5 5 5 5 5 5 5 5 6 +65535 65535 255 65535 65535 1048576 1048576 255 1048576 1048576 +INSERT INTO t1 VALUES +( REPEAT('a',65536), REPEAT('b',65536), REPEAT('c',256), REPEAT('d',65536), REPEAT('e',65536), REPEAT('f',1048576), REPEAT('g',1048576), REPEAT('h',256), REPEAT('i',1048576), REPEAT('j',1048576) ); +Warnings: +Warning 1265 Data truncated for column 't' at row 1 +Warning 1265 Data truncated for column 't0' at row 1 +Warning 1265 Data truncated for column 't1' at row 1 +Warning 1265 Data truncated for column 't300' at row 1 +Warning 1265 Data truncated for column 'tm' at row 1 +Warning 1265 Data truncated for column 'tt' at row 1 +SELECT LENGTH(t), LENGTH(t0), LENGTH(t1), LENGTH(t300), LENGTH(tm), LENGTH(t70k), LENGTH(t17m), LENGTH(tt), LENGTH(m), LENGTH(l) FROM t1; +LENGTH(t) LENGTH(t0) LENGTH(t1) LENGTH(t300) LENGTH(tm) LENGTH(t70k) LENGTH(t17m) LENGTH(tt) LENGTH(m) LENGTH(l) +0 0 0 0 0 0 0 0 0 0 +1 1 1 1 1 1 1 1 1 1 +5 5 5 5 5 5 5 5 5 6 +65535 65535 255 65535 65535 1048576 1048576 255 1048576 1048576 +65535 65535 255 65535 65535 1048576 1048576 255 1048576 1048576 +ALTER TABLE t1 ADD COLUMN ttt TEXT(4294967296); +ERROR 42000: Display width out of range for 'ttt' (max = 4294967295) +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c TEXT NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c text YES NULL +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c), COUNT(*) FROM t1; +COUNT(c) COUNT(*) +0 1 +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c TINYTEXT NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c tinytext YES NULL +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c), COUNT(*) FROM t1; +COUNT(c) COUNT(*) +0 1 +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c MEDIUMTEXT NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c mediumtext YES NULL +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c), COUNT(*) FROM t1; +COUNT(c) COUNT(*) +0 1 +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c LONGTEXT NULL) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +c longtext YES NULL +INSERT INTO t1 (c) VALUES (NULL); +SELECT COUNT(c), COUNT(*) FROM t1; +COUNT(c) COUNT(*) +0 1 +DROP TABLE t1; diff --git a/mysql-test/suite/storage_engine/col_opt_null.test b/mysql-test/suite/storage_engine/col_opt_null.test new file mode 100644 index 00000000000..29979d29dfd --- /dev/null +++ b/mysql-test/suite/storage_engine/col_opt_null.test @@ -0,0 +1,208 @@ +# +# NULL column attribute +# + +let $extra_col_opts = NULL; + +--source have_engine.inc + +--echo # +--echo # BINARY columns +--echo # + +--source type_binary.inc +--let $col_definition = BINARY $default_col_opts +--let $col_default = 0 +--source col_null.inc + +--echo # +--echo # VARBINARY columns +--echo # + +--source type_varbinary.inc +--let $col_definition = VARBINARY(64) $default_col_opts +--let $col_default = 'test' +--source col_null.inc + +--echo # +--echo # BIT columns +--echo # + +--source type_bit.inc +--let $col_definition = BIT $default_col_opts +--let $col_default = 1 +--source col_null.inc + +--echo # +--echo # BLOB columns +--echo # + +--source type_blob.inc + +--let $col_definition = BLOB $default_col_opts +--source col_null.inc + +--let $col_definition = TINYBLOB $default_col_opts +--source col_null.inc + +--let $col_definition = MEDIUMBLOB $default_col_opts +--source col_null.inc + +--let $col_definition = LONGBLOB $default_col_opts +--source col_null.inc + +--echo # +--echo # BOOL columns +--echo # + +--source type_bool.inc +--let $col_definition = BOOL $default_col_opts +--let $col_default = '0' +--source col_null.inc + + +--echo # +--echo # CHAR columns +--echo # + +--source type_char.inc +--let $col_definition = CHAR $default_col_opts +--let $col_default = '_' +--source col_null.inc + +--echo # +--echo # VARCHAR columns +--echo # + + +--source type_varchar.inc +--let $col_definition = VARCHAR(64) $default_col_opts +--let $col_default = 'test default' +--source col_null.inc + + +--echo # +--echo # date and time columns +--echo # + +--source type_date_time.inc + +--let $col_definition = DATE $default_col_opts +--let $col_default = '2012-12-21' +--source col_null.inc + +--let $col_definition = DATETIME $default_col_opts +--let $col_default = '2012-12-21 12:21:12' +--source col_null.inc + +--let $col_definition = TIMESTAMP $default_col_opts +--let $col_default = '2012-12-21 12:21:12' +--source col_null.inc + +--let $col_definition = TIME $default_col_opts +--let $col_default = '12:21:12' +--source col_null.inc + +--let $col_definition = YEAR $default_col_opts +--let $col_default = '2012' +--source col_null.inc + +--let $col_definition = YEAR(2) $default_col_opts +--let $col_default = '12' +--source col_null.inc + + +--echo # +--echo # ENUM columns +--echo # + +--source type_enum.inc +--let $col_definition = ENUM('test1','test2','test3') $default_col_opts +--let $col_default = 'test2' +--source col_null.inc + +--echo # +--echo # Fixed point columns (NUMERIC, DECIMAL) +--echo # + +--source type_fixed.inc + +--let $col_definition = DECIMAL $default_col_opts +--let $col_default = 1.1 +--source col_null.inc + +--let $col_definition = NUMERIC $default_col_opts +--let $col_default = 0 +--source col_null.inc + +--echo # +--echo # Floating point columns (FLOAT, DOUBLE) +--echo # + +--source type_float.inc + +--let $col_definition = FLOAT $default_col_opts +--let $col_default = 1.1 +--source col_null.inc + +--let $col_definition = DOUBLE $default_col_opts +--let $col_default = 0 +--source col_null.inc + +--echo # +--echo # INT columns +--echo # + +--source type_int.inc + +--let $col_definition = INT $default_col_opts +--let $col_default = 2147483647 +--source col_null.inc + +--let $col_definition = TINYINT $default_col_opts +--let $col_default = 127 +--source col_null.inc + +--let $col_definition = SMALLINT $default_col_opts +--let $col_default = 0 +--source col_null.inc + +--let $col_definition = MEDIUMINT $default_col_opts +--let $col_default = 1 +--source col_null.inc + +--let $col_definition = BIGINT $default_col_opts +--let $col_default = 9223372036854775807 +--source col_null.inc + +--echo # +--echo # SET columns +--echo # + +--source type_set.inc +--let $col_definition = SET('test1','test2','test3') $default_col_opts +--let $col_default = 'test2,test3' +--source col_null.inc + + +--echo # +--echo # TEXT columns +--echo # + +--source type_text.inc + +--let $col_definition = TEXT $default_col_opts +--source col_null.inc + +--let $col_definition = TINYTEXT $default_col_opts +--source col_null.inc + +--let $col_definition = MEDIUMTEXT $default_col_opts +--source col_null.inc + +--let $col_definition = LONGTEXT $default_col_opts +--source col_null.inc + + +--source cleanup_engine.inc + diff --git a/mysql-test/suite/storage_engine/col_opt_unsigned.result b/mysql-test/suite/storage_engine/col_opt_unsigned.result new file mode 100644 index 00000000000..a68aa48ee79 --- /dev/null +++ b/mysql-test/suite/storage_engine/col_opt_unsigned.result @@ -0,0 +1,697 @@ +# +# Fixed point columns (NUMERIC, DECIMAL) +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (d DECIMAL UNSIGNED , +d0 DECIMAL(0) UNSIGNED , +d1_1 DECIMAL(1,1) UNSIGNED , +d10_2 DECIMAL(10,2) UNSIGNED , +d60_10 DECIMAL(60,10) UNSIGNED , +n NUMERIC UNSIGNED , +n0_0 NUMERIC(0,0) UNSIGNED , +n1 NUMERIC(1) UNSIGNED , +n20_4 NUMERIC(20,4) UNSIGNED , +n65_4 NUMERIC(65,4) UNSIGNED +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +d decimal(10,0) unsigned # # # +d0 decimal(10,0) unsigned # # # +d1_1 decimal(1,1) unsigned # # # +d10_2 decimal(10,2) unsigned # # # +d60_10 decimal(60,10) unsigned # # # +n decimal(10,0) unsigned # # # +n0_0 decimal(10,0) unsigned # # # +n1 decimal(1,0) unsigned # # # +n20_4 decimal(20,4) unsigned # # # +n65_4 decimal(65,4) unsigned # # # +INSERT INTO t1 VALUES (100,123456,0.3,40000.25,123456789123456789.10001,1024,7000.0,8.0,999999.9,9223372036854775807); +INSERT INTO t1 VALUES (0,0,0,0,0,0,0,0,0,0); +INSERT INTO t1 VALUES (9999999999.0,9999999999.0,0.9,99999999.99,99999999999999999999999999999999999999999999999999.9999999999,9999999999.0,9999999999.0,9.0,9999999999999999.9999,9999999999999999999999999999999999999999999999999999999999999.9999); +SELECT * FROM t1; +d d0 d1_1 d10_2 d60_10 n n0_0 n1 n20_4 n65_4 +0 0 0.0 0.00 0.0000000000 0 0 0 0.0000 0.0000 +100 123456 0.3 40000.25 123456789123456789.1000100000 1024 7000 8 999999.9000 9223372036854775807.0000 +9999999999 9999999999 0.9 99999999.99 99999999999999999999999999999999999999999999999999.9999999999 9999999999 9999999999 9 9999999999999999.9999 9999999999999999999999999999999999999999999999999999999999999.9999 +INSERT INTO t1 VALUES (-100,-123456,-0.3,-40000.25,-123456789123456789.10001,-1024,-7000.0,-8.0,-999999.9,-9223372036854775807); +Warnings: +Warning 1264 Out of range value for column 'd' at row 1 +Warning 1264 Out of range value for column 'd0' at row 1 +Warning 1264 Out of range value for column 'd1_1' at row 1 +Warning 1264 Out of range value for column 'd10_2' at row 1 +Warning 1264 Out of range value for column 'd60_10' at row 1 +Warning 1264 Out of range value for column 'n' at row 1 +Warning 1264 Out of range value for column 'n0_0' at row 1 +Warning 1264 Out of range value for column 'n1' at row 1 +Warning 1264 Out of range value for column 'n20_4' at row 1 +Warning 1264 Out of range value for column 'n65_4' at row 1 +INSERT INTO t1 VALUES (-9999999999.0,-9999999999.0,-0.9,-99999999.99,-99999999999999999999999999999999999999999999999999.9999999999,-9999999999.0,-9999999999.0,-9.0,-9999999999999999.9999,-9999999999999999999999999999999999999999999999999999999999999.9999); +Warnings: +Warning 1264 Out of range value for column 'd' at row 1 +Warning 1264 Out of range value for column 'd0' at row 1 +Warning 1264 Out of range value for column 'd1_1' at row 1 +Warning 1264 Out of range value for column 'd10_2' at row 1 +Warning 1264 Out of range value for column 'd60_10' at row 1 +Warning 1264 Out of range value for column 'n' at row 1 +Warning 1264 Out of range value for column 'n0_0' at row 1 +Warning 1264 Out of range value for column 'n1' at row 1 +Warning 1264 Out of range value for column 'n20_4' at row 1 +Warning 1264 Out of range value for column 'n65_4' at row 1 +SELECT * FROM t1; +d d0 d1_1 d10_2 d60_10 n n0_0 n1 n20_4 n65_4 +0 0 0.0 0.00 0.0000000000 0 0 0 0.0000 0.0000 +0 0 0.0 0.00 0.0000000000 0 0 0 0.0000 0.0000 +0 0 0.0 0.00 0.0000000000 0 0 0 0.0000 0.0000 +100 123456 0.3 40000.25 123456789123456789.1000100000 1024 7000 8 999999.9000 9223372036854775807.0000 +9999999999 9999999999 0.9 99999999.99 99999999999999999999999999999999999999999999999999.9999999999 9999999999 9999999999 9 9999999999999999.9999 9999999999999999999999999999999999999999999999999999999999999.9999 +SELECT * FROM t1 WHERE n20_4 = 9999999999999999.9999 OR d < 100; +d d0 d1_1 d10_2 d60_10 n n0_0 n1 n20_4 n65_4 +0 0 0.0 0.00 0.0000000000 0 0 0 0.0000 0.0000 +0 0 0.0 0.00 0.0000000000 0 0 0 0.0000 0.0000 +0 0 0.0 0.00 0.0000000000 0 0 0 0.0000 0.0000 +9999999999 9999999999 0.9 99999999.99 99999999999999999999999999999999999999999999999999.9999999999 9999999999 9999999999 9 9999999999999999.9999 9999999999999999999999999999999999999999999999999999999999999.9999 +INSERT INTO t1 SELECT n65_4, n65_4, n65_4, n65_4, n65_4, n65_4, n65_4, n65_4, n65_4, n65_4 FROM t1 WHERE n65_4 = ( SELECT MAX(n65_4) FROM t1 ); +Warnings: +Warning 1264 Out of range value for column 'd' at row 1 +Warning 1264 Out of range value for column 'd0' at row 1 +Warning 1264 Out of range value for column 'd1_1' at row 1 +Warning 1264 Out of range value for column 'd10_2' at row 1 +Warning 1264 Out of range value for column 'd60_10' at row 1 +Warning 1264 Out of range value for column 'n' at row 1 +Warning 1264 Out of range value for column 'n0_0' at row 1 +Warning 1264 Out of range value for column 'n1' at row 1 +Warning 1264 Out of range value for column 'n20_4' at row 1 +SELECT * FROM t1; +d d0 d1_1 d10_2 d60_10 n n0_0 n1 n20_4 n65_4 +0 0 0.0 0.00 0.0000000000 0 0 0 0.0000 0.0000 +0 0 0.0 0.00 0.0000000000 0 0 0 0.0000 0.0000 +0 0 0.0 0.00 0.0000000000 0 0 0 0.0000 0.0000 +100 123456 0.3 40000.25 123456789123456789.1000100000 1024 7000 8 999999.9000 9223372036854775807.0000 +9999999999 9999999999 0.9 99999999.99 99999999999999999999999999999999999999999999999999.9999999999 9999999999 9999999999 9 9999999999999999.9999 9999999999999999999999999999999999999999999999999999999999999.9999 +9999999999 9999999999 0.9 99999999.99 99999999999999999999999999999999999999999999999999.9999999999 9999999999 9999999999 9 9999999999999999.9999 9999999999999999999999999999999999999999999999999999999999999.9999 +INSERT INTO t1 VALUES (10000000000.0,10000000000.0,1.1,100000000.99,100000000000000000000000000000000000000000000000000.0,10000000000.0,10000000000.0,10.0,10000000000000000.9999,10000000000000000000000000000000000000000000000000000000000000.9999); +Warnings: +Warning 1264 Out of range value for column 'd' at row 1 +Warning 1264 Out of range value for column 'd0' at row 1 +Warning 1264 Out of range value for column 'd1_1' at row 1 +Warning 1264 Out of range value for column 'd10_2' at row 1 +Warning 1264 Out of range value for column 'd60_10' at row 1 +Warning 1264 Out of range value for column 'n' at row 1 +Warning 1264 Out of range value for column 'n0_0' at row 1 +Warning 1264 Out of range value for column 'n1' at row 1 +Warning 1264 Out of range value for column 'n20_4' at row 1 +Warning 1264 Out of range value for column 'n65_4' at row 1 +SELECT * FROM t1; +d d0 d1_1 d10_2 d60_10 n n0_0 n1 n20_4 n65_4 +0 0 0.0 0.00 0.0000000000 0 0 0 0.0000 0.0000 +0 0 0.0 0.00 0.0000000000 0 0 0 0.0000 0.0000 +0 0 0.0 0.00 0.0000000000 0 0 0 0.0000 0.0000 +100 123456 0.3 40000.25 123456789123456789.1000100000 1024 7000 8 999999.9000 9223372036854775807.0000 +9999999999 9999999999 0.9 99999999.99 99999999999999999999999999999999999999999999999999.9999999999 9999999999 9999999999 9 9999999999999999.9999 9999999999999999999999999999999999999999999999999999999999999.9999 +9999999999 9999999999 0.9 99999999.99 99999999999999999999999999999999999999999999999999.9999999999 9999999999 9999999999 9 9999999999999999.9999 9999999999999999999999999999999999999999999999999999999999999.9999 +9999999999 9999999999 0.9 99999999.99 99999999999999999999999999999999999999999999999999.9999999999 9999999999 9999999999 9 9999999999999999.9999 9999999999999999999999999999999999999999999999999999999999999.9999 +INSERT INTO t1 VALUES (9999999999.1,9999999999.1,1.9,99999999.001,99999999999999999999999999999999999999999999999999.99999999991,9999999999.1,9999999999.1,9.1,9999999999999999.00001,9999999999999999999999999999999999999999999999999999999999999.11111); +Warnings: +Note 1265 Data truncated for column 'd' at row 1 +Note 1265 Data truncated for column 'd0' at row 1 +Warning 1264 Out of range value for column 'd1_1' at row 1 +Note 1265 Data truncated for column 'd10_2' at row 1 +Note 1265 Data truncated for column 'd60_10' at row 1 +Note 1265 Data truncated for column 'n' at row 1 +Note 1265 Data truncated for column 'n0_0' at row 1 +Note 1265 Data truncated for column 'n1' at row 1 +Note 1265 Data truncated for column 'n20_4' at row 1 +Note 1265 Data truncated for column 'n65_4' at row 1 +SELECT * FROM t1; +d d0 d1_1 d10_2 d60_10 n n0_0 n1 n20_4 n65_4 +0 0 0.0 0.00 0.0000000000 0 0 0 0.0000 0.0000 +0 0 0.0 0.00 0.0000000000 0 0 0 0.0000 0.0000 +0 0 0.0 0.00 0.0000000000 0 0 0 0.0000 0.0000 +100 123456 0.3 40000.25 123456789123456789.1000100000 1024 7000 8 999999.9000 9223372036854775807.0000 +9999999999 9999999999 0.9 99999999.00 99999999999999999999999999999999999999999999999999.9999999999 9999999999 9999999999 9 9999999999999999.0000 9999999999999999999999999999999999999999999999999999999999999.1111 +9999999999 9999999999 0.9 99999999.99 99999999999999999999999999999999999999999999999999.9999999999 9999999999 9999999999 9 9999999999999999.9999 9999999999999999999999999999999999999999999999999999999999999.9999 +9999999999 9999999999 0.9 99999999.99 99999999999999999999999999999999999999999999999999.9999999999 9999999999 9999999999 9 9999999999999999.9999 9999999999999999999999999999999999999999999999999999999999999.9999 +9999999999 9999999999 0.9 99999999.99 99999999999999999999999999999999999999999999999999.9999999999 9999999999 9999999999 9 9999999999999999.9999 9999999999999999999999999999999999999999999999999999999999999.9999 +ALTER TABLE t1 ADD COLUMN n66 NUMERIC(66); +ERROR 42000: Too big precision 66 specified for 'n66'. Maximum is 65. +ALTER TABLE t1 ADD COLUMN n66_6 DECIMAL(66,6); +ERROR 42000: Too big precision 66 specified for 'n66_6'. Maximum is 65. +ALTER TABLE t1 ADD COLUMN n66_66 DECIMAL(66,66); +ERROR 42000: Too big scale 66 specified for 'n66_66'. Maximum is 30. +DROP TABLE t1; +CREATE TABLE t1 (a DECIMAL UNSIGNED , +b NUMERIC UNSIGNED +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +a decimal(10,0) unsigned # # # # +b decimal(10,0) unsigned # # # # +INSERT INTO t1 (a,b) VALUES (1.0,-1.0); +Warnings: +Warning 1264 Out of range value for column 'b' at row 1 +INSERT INTO t1 (a,b) VALUES (-100,100); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +SELECT * FROM t1; +a b +0 100 +1 0 +DROP TABLE t1; +# +# Floating point columns (FLOAT, DOUBLE) +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (f FLOAT UNSIGNED , +f0 FLOAT(0) UNSIGNED , +r1_1 REAL(1,1) UNSIGNED , +f23_0 FLOAT(23) UNSIGNED , +f20_3 FLOAT(20,3) UNSIGNED , +d DOUBLE UNSIGNED , +d1_0 DOUBLE(1,0) UNSIGNED , +d10_10 DOUBLE PRECISION (10,10) UNSIGNED , +d53 DOUBLE(53,0) UNSIGNED , +d53_10 DOUBLE(53,10) UNSIGNED +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +f float unsigned # # # +f0 float unsigned # # # +r1_1 double(1,1) unsigned # # # +f23_0 float unsigned # # # +f20_3 float(20,3) unsigned # # # +d double unsigned # # # +d1_0 double(1,0) unsigned # # # +d10_10 double(10,10) unsigned # # # +d53 double(53,0) unsigned # # # +d53_10 double(53,10) unsigned # # # +INSERT INTO t1 VALUES (12345.12345,12345.12345,0.9,123456789.123,56789.987,11111111.111,8.0,0.0123456789,1234566789123456789,99999999999999999.99999999); +SELECT * FROM t1; +f 12345.1 +d 11111111.111 +d10_10 0.0123456789 +d1_0 8 +d53 1234566789123456800 +d53_10 100000000000000000.0000000000 +f0 12345.1 +f20_3 56789.988 +f23_0 123457000 +r1_1 0.9 +INSERT INTO t1 VALUES (0,0,0,0,0,0,0,0,0,0); +INSERT INTO t1 VALUES ( +99999999999999999999999999999999999999, +99999999999999999999999999999999999999.9999999999999999, +0.9, +99999999999999999999999999999999999999.9, +99999999999999999.999, +999999999999999999999999999999999999999999999999999999999999999999999999999999999, +9, +0.9999999999, +1999999999999999999999999999999999999999999999999999999, +19999999999999999999999999999999999999999999.9999999999 +); +Warnings: +Warning 1264 Out of range value for column 'd53' at row 1 +Warning 1264 Out of range value for column 'd53_10' at row 1 +SELECT * FROM t1; +f 12345.1 +d 0 +d 11111111.111 +d 1e81 +d10_10 0.0000000000 +d10_10 0.0123456789 +d10_10 0.9999999999 +d1_0 0 +d1_0 8 +d1_0 9 +d53 0 +d53 100000000000000000000000000000000000000000000000000000 +d53 1234566789123456800 +d53_10 0.0000000000 +d53_10 100000000000000000.0000000000 +d53_10 10000000000000000000000000000000000000000000.0000000000 +f 0 +f 1e38 +f0 0 +f0 12345.1 +f0 1e38 +f20_3 0.000 +f20_3 56789.988 +f20_3 99999998430674940.000 +f23_0 0 +f23_0 123457000 +f23_0 1e38 +r1_1 0.0 +r1_1 0.9 +r1_1 0.9 +INSERT INTO t1 VALUES (-999999999999999999999999,-99999999999.999999999999,-0.9,-999.99999999999999999999,-99999999999999999.999,-999999999999999999999999999999999999999999999999999999999999-0.999,-9,-.9999999999,-999999999999999999999999999999.99999999999999999999999,-9999999999999999999999999999999999999999999.9999999999); +Warnings: +Warning 1264 Out of range value for column 'f' at row 1 +Warning 1264 Out of range value for column 'f0' at row 1 +Warning 1264 Out of range value for column 'r1_1' at row 1 +Warning 1264 Out of range value for column 'f23_0' at row 1 +Warning 1264 Out of range value for column 'f20_3' at row 1 +Warning 1264 Out of range value for column 'd' at row 1 +Warning 1264 Out of range value for column 'd1_0' at row 1 +Warning 1264 Out of range value for column 'd10_10' at row 1 +Warning 1264 Out of range value for column 'd53' at row 1 +Warning 1264 Out of range value for column 'd53_10' at row 1 +SELECT * FROM t1; +f 12345.1 +d 0 +d 0 +d 11111111.111 +d 1e81 +d10_10 0.0000000000 +d10_10 0.0000000000 +d10_10 0.0123456789 +d10_10 0.9999999999 +d1_0 0 +d1_0 0 +d1_0 8 +d1_0 9 +d53 0 +d53 0 +d53 100000000000000000000000000000000000000000000000000000 +d53 1234566789123456800 +d53_10 0.0000000000 +d53_10 0.0000000000 +d53_10 100000000000000000.0000000000 +d53_10 10000000000000000000000000000000000000000000.0000000000 +f 0 +f 0 +f 1e38 +f0 0 +f0 0 +f0 12345.1 +f0 1e38 +f20_3 0.000 +f20_3 0.000 +f20_3 56789.988 +f20_3 99999998430674940.000 +f23_0 0 +f23_0 0 +f23_0 123457000 +f23_0 1e38 +r1_1 0.0 +r1_1 0.0 +r1_1 0.9 +r1_1 0.9 +SELECT MAX(f), MAX(f0), MAX(r1_1), MAX(f23_0), MAX(f20_3), MAX(d), MAX(d1_0), MAX(d10_10), MAX(d53), MAX(d53_10) FROM t1; +MAX(f) 9.999999680285692e37 +MAX(d) 1e81 +MAX(d10_10) 0.9999999999 +MAX(d1_0) 9 +MAX(d53) 100000000000000000000000000000000000000000000000000000 +MAX(d53_10) 10000000000000000000000000000000000000000000.0000000000 +MAX(f0) 9.999999680285692e37 +MAX(f20_3) 99999998430674940.000 +MAX(f23_0) 9.999999680285692e37 +MAX(r1_1) 0.9 +INSERT INTO t1 SELECT d53_10, d53_10, d53_10, d53_10, d53_10, d53_10, d53_10, d53_10, d53_10, d53_10 FROM t1 ORDER BY d53_10 DESC LIMIT 1; +Warnings: +Warning 1264 Out of range value for column 'f' at row 1 +Warning 1264 Out of range value for column 'f0' at row 1 +Warning 1264 Out of range value for column 'r1_1' at row 1 +Warning 1264 Out of range value for column 'f23_0' at row 1 +Warning 1264 Out of range value for column 'f20_3' at row 1 +Warning 1264 Out of range value for column 'd1_0' at row 1 +SELECT * FROM t1; +f 12345.1 +d 0 +d 0 +d 11111111.111 +d 1e43 +d 1e81 +d10_10 0.0000000000 +d10_10 0.0000000000 +d10_10 0.0123456789 +d10_10 0.9999999999 +d10_10 10000000000000000000000000000000000000000000.0000000000 +d1_0 0 +d1_0 0 +d1_0 8 +d1_0 9 +d1_0 9 +d53 0 +d53 0 +d53 10000000000000000000000000000000000000000000 +d53 100000000000000000000000000000000000000000000000000000 +d53 1234566789123456800 +d53_10 0.0000000000 +d53_10 0.0000000000 +d53_10 100000000000000000.0000000000 +d53_10 10000000000000000000000000000000000000000000.0000000000 +d53_10 10000000000000000000000000000000000000000000.0000000000 +f 0 +f 0 +f 1e38 +f 3.40282e38 +f0 0 +f0 0 +f0 12345.1 +f0 1e38 +f0 3.40282e38 +f20_3 0.000 +f20_3 0.000 +f20_3 56789.988 +f20_3 99999998430674940.000 +f20_3 99999998430674940.000 +f23_0 0 +f23_0 0 +f23_0 123457000 +f23_0 1e38 +f23_0 3.40282e38 +r1_1 0.0 +r1_1 0.0 +r1_1 0.9 +r1_1 0.9 +r1_1 0.9 +INSERT INTO t1 VALUES ( +999999999999999999999999999999999999999, +999999999999999999999999999999999999999.9999999999999999, +1.9, +999999999999999999999999999999999999999.9, +999999999999999999.999, +9999999999999999999999999999999999999999999999999999999999999999999999999999999999, +99, +1.9999999999, +1999999999999999999999999999999999999999999999999999999, +19999999999999999999999999999999999999999999.9999999999 +); +Warnings: +Warning 1916 Got overflow when converting '' to DECIMAL. Value truncated. +Warning 1264 Out of range value for column 'f' at row 1 +Warning 1264 Out of range value for column 'f0' at row 1 +Warning 1264 Out of range value for column 'r1_1' at row 1 +Warning 1264 Out of range value for column 'f23_0' at row 1 +Warning 1264 Out of range value for column 'f20_3' at row 1 +Warning 1264 Out of range value for column 'd1_0' at row 1 +Warning 1264 Out of range value for column 'd10_10' at row 1 +Warning 1264 Out of range value for column 'd53' at row 1 +Warning 1264 Out of range value for column 'd53_10' at row 1 +SELECT * FROM t1; +f 12345.1 +d 0 +d 0 +d 11111111.111 +d 1e43 +d 1e65 +d 1e81 +d10_10 0.0000000000 +d10_10 0.0000000000 +d10_10 0.0123456789 +d10_10 0.9999999999 +d10_10 0.9999999999 +d10_10 10000000000000000000000000000000000000000000.0000000000 +d1_0 0 +d1_0 0 +d1_0 8 +d1_0 9 +d1_0 9 +d1_0 9 +d53 0 +d53 0 +d53 10000000000000000000000000000000000000000000 +d53 100000000000000000000000000000000000000000000000000000 +d53 100000000000000000000000000000000000000000000000000000 +d53 1234566789123456800 +d53_10 0.0000000000 +d53_10 0.0000000000 +d53_10 100000000000000000.0000000000 +d53_10 10000000000000000000000000000000000000000000.0000000000 +d53_10 10000000000000000000000000000000000000000000.0000000000 +d53_10 10000000000000000000000000000000000000000000.0000000000 +f 0 +f 0 +f 1e38 +f 3.40282e38 +f 3.40282e38 +f0 0 +f0 0 +f0 12345.1 +f0 1e38 +f0 3.40282e38 +f0 3.40282e38 +f20_3 0.000 +f20_3 0.000 +f20_3 56789.988 +f20_3 99999998430674940.000 +f20_3 99999998430674940.000 +f20_3 99999998430674940.000 +f23_0 0 +f23_0 0 +f23_0 123457000 +f23_0 1e38 +f23_0 3.40282e38 +f23_0 3.40282e38 +r1_1 0.0 +r1_1 0.0 +r1_1 0.9 +r1_1 0.9 +r1_1 0.9 +r1_1 0.9 +ALTER TABLE t1 ADD COLUMN d0_0 DOUBLE(0,0); +ERROR 42000: Display width out of range for 'd0_0' (max = 255) +ALTER TABLE t1 ADD COLUMN n66_6 DECIMAL(256,1); +ERROR 42000: Too big precision 256 specified for 'n66_6'. Maximum is 65. +ALTER TABLE t1 ADD COLUMN n66_66 DECIMAL(40,35); +ERROR 42000: Too big scale 35 specified for 'n66_66'. Maximum is 30. +DROP TABLE t1; +CREATE TABLE t1 (a DOUBLE UNSIGNED , +b FLOAT UNSIGNED +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +a double unsigned # # # # +b float unsigned # # # # +INSERT INTO t1 (a,b) VALUES (1.0,-1.0); +Warnings: +Warning 1264 Out of range value for column 'b' at row 1 +INSERT INTO t1 (a,b) VALUES (-100,100); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +SELECT * FROM t1; +a b +0 100 +1 0 +DROP TABLE t1; +# +# INT columns +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (i INT UNSIGNED , +i0 INT(0) UNSIGNED , +i1 INT(1) UNSIGNED , +i20 INT(20) UNSIGNED , +t TINYINT UNSIGNED , +t0 TINYINT(0) UNSIGNED , +t1 TINYINT(1) UNSIGNED , +t20 TINYINT(20) UNSIGNED , +s SMALLINT UNSIGNED , +s0 SMALLINT(0) UNSIGNED , +s1 SMALLINT(1) UNSIGNED , +s20 SMALLINT(20) UNSIGNED , +m MEDIUMINT UNSIGNED , +m0 MEDIUMINT(0) UNSIGNED , +m1 MEDIUMINT(1) UNSIGNED , +m20 MEDIUMINT(20) UNSIGNED , +b BIGINT UNSIGNED , +b0 BIGINT(0) UNSIGNED , +b1 BIGINT(1) UNSIGNED , +b20 BIGINT(20) UNSIGNED +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +i int(10) unsigned # # # +i0 int(10) unsigned # # # +i1 int(1) unsigned # # # +i20 int(20) unsigned # # # +t tinyint(3) unsigned # # # +t0 tinyint(3) unsigned # # # +t1 tinyint(1) unsigned # # # +t20 tinyint(20) unsigned # # # +s smallint(5) unsigned # # # +s0 smallint(5) unsigned # # # +s1 smallint(1) unsigned # # # +s20 smallint(20) unsigned # # # +m mediumint(8) unsigned # # # +m0 mediumint(8) unsigned # # # +m1 mediumint(1) unsigned # # # +m20 mediumint(20) unsigned # # # +b bigint(20) unsigned # # # +b0 bigint(20) unsigned # # # +b1 bigint(1) unsigned # # # +b20 bigint(20) unsigned # # # +INSERT INTO t1 VALUES (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20); +INSERT INTO t1 VALUES (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); +INSERT INTO t1 VALUES (2147483647,2147483647,2147483647,2147483647,127,127,127,127,32767,32767,32767,32767,8388607,8388607,8388607,8388607,9223372036854775807,9223372036854775807,9223372036854775807,9223372036854775807); +SELECT * FROM t1; +i i0 i1 i20 t t0 t1 t20 s s0 s1 s20 m m0 m1 m20 b b0 b1 b20 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 +2147483647 2147483647 2147483647 2147483647 127 127 127 127 32767 32767 32767 32767 8388607 8388607 8388607 8388607 9223372036854775807 9223372036854775807 9223372036854775807 9223372036854775807 +INSERT INTO t1 VALUES (-2147483648,-2147483648,-2147483648,-2147483648,-128,-128,-128,-128,-32768,-32768,-32768,-32768,-8388608,-8388608,-8388608,-8388608,-9223372036854775808,-9223372036854775808,-9223372036854775808,-9223372036854775808); +Warnings: +Warning 1264 Out of range value for column 'i' at row 1 +Warning 1264 Out of range value for column 'i0' at row 1 +Warning 1264 Out of range value for column 'i1' at row 1 +Warning 1264 Out of range value for column 'i20' at row 1 +Warning 1264 Out of range value for column 't' at row 1 +Warning 1264 Out of range value for column 't0' at row 1 +Warning 1264 Out of range value for column 't1' at row 1 +Warning 1264 Out of range value for column 't20' at row 1 +Warning 1264 Out of range value for column 's' at row 1 +Warning 1264 Out of range value for column 's0' at row 1 +Warning 1264 Out of range value for column 's1' at row 1 +Warning 1264 Out of range value for column 's20' at row 1 +Warning 1264 Out of range value for column 'm' at row 1 +Warning 1264 Out of range value for column 'm0' at row 1 +Warning 1264 Out of range value for column 'm1' at row 1 +Warning 1264 Out of range value for column 'm20' at row 1 +Warning 1264 Out of range value for column 'b' at row 1 +Warning 1264 Out of range value for column 'b0' at row 1 +Warning 1264 Out of range value for column 'b1' at row 1 +Warning 1264 Out of range value for column 'b20' at row 1 +INSERT INTO t1 VALUES (4294967295,4294967295,4294967295,4294967295,255,255,255,255,65535,65535,65535,65535,16777215,16777215,16777215,16777215,18446744073709551615,18446744073709551615,18446744073709551615,18446744073709551615); +SELECT * FROM t1; +i i0 i1 i20 t t0 t1 t20 s s0 s1 s20 m m0 m1 m20 b b0 b1 b20 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 +2147483647 2147483647 2147483647 2147483647 127 127 127 127 32767 32767 32767 32767 8388607 8388607 8388607 8388607 9223372036854775807 9223372036854775807 9223372036854775807 9223372036854775807 +4294967295 4294967295 4294967295 4294967295 255 255 255 255 65535 65535 65535 65535 16777215 16777215 16777215 16777215 18446744073709551615 18446744073709551615 18446744073709551615 18446744073709551615 +INSERT INTO t1 VALUES (-2147483649,-2147483649,-2147483649,-2147483649,-129,-129,-129,-129,-32769,-32769,-32769,-32769,-8388609,-8388609,-8388609,-8388609,-9223372036854775809,-9223372036854775809,-9223372036854775809,-9223372036854775809); +Warnings: +Warning 1264 Out of range value for column 'i' at row 1 +Warning 1264 Out of range value for column 'i0' at row 1 +Warning 1264 Out of range value for column 'i1' at row 1 +Warning 1264 Out of range value for column 'i20' at row 1 +Warning 1264 Out of range value for column 't' at row 1 +Warning 1264 Out of range value for column 't0' at row 1 +Warning 1264 Out of range value for column 't1' at row 1 +Warning 1264 Out of range value for column 't20' at row 1 +Warning 1264 Out of range value for column 's' at row 1 +Warning 1264 Out of range value for column 's0' at row 1 +Warning 1264 Out of range value for column 's1' at row 1 +Warning 1264 Out of range value for column 's20' at row 1 +Warning 1264 Out of range value for column 'm' at row 1 +Warning 1264 Out of range value for column 'm0' at row 1 +Warning 1264 Out of range value for column 'm1' at row 1 +Warning 1264 Out of range value for column 'm20' at row 1 +Warning 1264 Out of range value for column 'b' at row 1 +Warning 1264 Out of range value for column 'b0' at row 1 +Warning 1264 Out of range value for column 'b1' at row 1 +Warning 1264 Out of range value for column 'b20' at row 1 +INSERT INTO t1 VALUES (4294967296,4294967296,4294967296,4294967296,256,256,256,256,65536,65536,65536,65536,16777216,16777216,16777216,16777216,18446744073709551616,18446744073709551616,18446744073709551616,18446744073709551616); +Warnings: +Warning 1264 Out of range value for column 'i' at row 1 +Warning 1264 Out of range value for column 'i0' at row 1 +Warning 1264 Out of range value for column 'i1' at row 1 +Warning 1264 Out of range value for column 'i20' at row 1 +Warning 1264 Out of range value for column 't' at row 1 +Warning 1264 Out of range value for column 't0' at row 1 +Warning 1264 Out of range value for column 't1' at row 1 +Warning 1264 Out of range value for column 't20' at row 1 +Warning 1264 Out of range value for column 's' at row 1 +Warning 1264 Out of range value for column 's0' at row 1 +Warning 1264 Out of range value for column 's1' at row 1 +Warning 1264 Out of range value for column 's20' at row 1 +Warning 1264 Out of range value for column 'm' at row 1 +Warning 1264 Out of range value for column 'm0' at row 1 +Warning 1264 Out of range value for column 'm1' at row 1 +Warning 1264 Out of range value for column 'm20' at row 1 +Warning 1264 Out of range value for column 'b' at row 1 +Warning 1264 Out of range value for column 'b0' at row 1 +Warning 1264 Out of range value for column 'b1' at row 1 +Warning 1264 Out of range value for column 'b20' at row 1 +INSERT INTO t1 SELECT b,b,b,b,b,b,b,b,b,b,b,b,b,b,b,b,b,b,b,b FROM t1 WHERE b IN (-9223372036854775808,9223372036854775807,18446744073709551615); +Warnings: +Warning 1264 Out of range value for column 'i' at row 1 +Warning 1264 Out of range value for column 'i0' at row 1 +Warning 1264 Out of range value for column 'i1' at row 1 +Warning 1264 Out of range value for column 'i20' at row 1 +Warning 1264 Out of range value for column 't' at row 1 +Warning 1264 Out of range value for column 't0' at row 1 +Warning 1264 Out of range value for column 't1' at row 1 +Warning 1264 Out of range value for column 't20' at row 1 +Warning 1264 Out of range value for column 's' at row 1 +Warning 1264 Out of range value for column 's0' at row 1 +Warning 1264 Out of range value for column 's1' at row 1 +Warning 1264 Out of range value for column 's20' at row 1 +Warning 1264 Out of range value for column 'm' at row 1 +Warning 1264 Out of range value for column 'm0' at row 1 +Warning 1264 Out of range value for column 'm1' at row 1 +Warning 1264 Out of range value for column 'm20' at row 1 +Warning 1264 Out of range value for column 'i' at row 2 +Warning 1264 Out of range value for column 'i0' at row 2 +Warning 1264 Out of range value for column 'i1' at row 2 +Warning 1264 Out of range value for column 'i20' at row 2 +Warning 1264 Out of range value for column 't' at row 2 +Warning 1264 Out of range value for column 't0' at row 2 +Warning 1264 Out of range value for column 't1' at row 2 +Warning 1264 Out of range value for column 't20' at row 2 +Warning 1264 Out of range value for column 's' at row 2 +Warning 1264 Out of range value for column 's0' at row 2 +Warning 1264 Out of range value for column 's1' at row 2 +Warning 1264 Out of range value for column 's20' at row 2 +Warning 1264 Out of range value for column 'm' at row 2 +Warning 1264 Out of range value for column 'm0' at row 2 +Warning 1264 Out of range value for column 'm1' at row 2 +Warning 1264 Out of range value for column 'm20' at row 2 +Warning 1264 Out of range value for column 'i' at row 3 +Warning 1264 Out of range value for column 'i0' at row 3 +Warning 1264 Out of range value for column 'i1' at row 3 +Warning 1264 Out of range value for column 'i20' at row 3 +Warning 1264 Out of range value for column 't' at row 3 +Warning 1264 Out of range value for column 't0' at row 3 +Warning 1264 Out of range value for column 't1' at row 3 +Warning 1264 Out of range value for column 't20' at row 3 +Warning 1264 Out of range value for column 's' at row 3 +Warning 1264 Out of range value for column 's0' at row 3 +Warning 1264 Out of range value for column 's1' at row 3 +Warning 1264 Out of range value for column 's20' at row 3 +Warning 1264 Out of range value for column 'm' at row 3 +Warning 1264 Out of range value for column 'm0' at row 3 +Warning 1264 Out of range value for column 'm1' at row 3 +Warning 1264 Out of range value for column 'm20' at row 3 +SELECT * FROM t1; +i i0 i1 i20 t t0 t1 t20 s s0 s1 s20 m m0 m1 m20 b b0 b1 b20 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 +2147483647 2147483647 2147483647 2147483647 127 127 127 127 32767 32767 32767 32767 8388607 8388607 8388607 8388607 9223372036854775807 9223372036854775807 9223372036854775807 9223372036854775807 +4294967295 4294967295 4294967295 4294967295 255 255 255 255 65535 65535 65535 65535 16777215 16777215 16777215 16777215 18446744073709551615 18446744073709551615 18446744073709551615 18446744073709551615 +4294967295 4294967295 4294967295 4294967295 255 255 255 255 65535 65535 65535 65535 16777215 16777215 16777215 16777215 18446744073709551615 18446744073709551615 18446744073709551615 18446744073709551615 +4294967295 4294967295 4294967295 4294967295 255 255 255 255 65535 65535 65535 65535 16777215 16777215 16777215 16777215 18446744073709551615 18446744073709551615 18446744073709551615 18446744073709551615 +4294967295 4294967295 4294967295 4294967295 255 255 255 255 65535 65535 65535 65535 16777215 16777215 16777215 16777215 18446744073709551615 18446744073709551615 18446744073709551615 18446744073709551615 +4294967295 4294967295 4294967295 4294967295 255 255 255 255 65535 65535 65535 65535 16777215 16777215 16777215 16777215 9223372036854775807 9223372036854775807 9223372036854775807 9223372036854775807 +ALTER TABLE t1 ADD COLUMN i257 INT(257); +ERROR 42000: Display width out of range for 'i257' (max = 255) +DROP TABLE t1; +CREATE TABLE t1 (t TINYINT UNSIGNED , +s SMALLINT UNSIGNED , +m MEDIUMINT UNSIGNED , +i INT UNSIGNED , +b BIGINT UNSIGNED +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +t tinyint(3) unsigned # # # # +s smallint(5) unsigned # # # # +m mediumint(8) unsigned # # # # +i int(10) unsigned # # # # +b bigint(20) unsigned # # # # +INSERT INTO t1 (t,s,m,i,b) VALUES (255,65535,16777215,4294967295,18446744073709551615); +INSERT INTO t1 (t,s,m,i,b) VALUES (-1,-1,-1,-1,-1); +Warnings: +Warning 1264 Out of range value for column 't' at row 1 +Warning 1264 Out of range value for column 's' at row 1 +Warning 1264 Out of range value for column 'm' at row 1 +Warning 1264 Out of range value for column 'i' at row 1 +Warning 1264 Out of range value for column 'b' at row 1 +SELECT * FROM t1; +t s m i b +0 0 0 0 0 +255 65535 16777215 4294967295 18446744073709551615 +DROP TABLE t1; diff --git a/mysql-test/suite/storage_engine/col_opt_unsigned.test b/mysql-test/suite/storage_engine/col_opt_unsigned.test new file mode 100644 index 00000000000..e9d4566de7f --- /dev/null +++ b/mysql-test/suite/storage_engine/col_opt_unsigned.test @@ -0,0 +1,95 @@ +# +# UNSIGNED column attribute +# + +let $extra_type_opts = UNSIGNED; + +--source have_engine.inc + +--echo # +--echo # Fixed point columns (NUMERIC, DECIMAL) +--echo # + +--source type_fixed.inc +let $create_definition = + a DECIMAL $col_opts, + b NUMERIC $col_opts +; +--source create_table.inc +if ($mysql_errname) +{ + --let $functionality = Fixed point types or UNSIGNED columns + --source unexpected_result.inc +} +if (!$mysql_errname) +{ + --replace_column 3 # 4 # 5 # 6 # + SHOW COLUMNS IN t1; + + INSERT INTO t1 (a,b) VALUES (1.0,-1.0); + INSERT INTO t1 (a,b) VALUES (-100,100); + --sorted_result + SELECT * FROM t1; + DROP TABLE t1; +} + +--echo # +--echo # Floating point columns (FLOAT, DOUBLE) +--echo # + +--source type_float.inc +let $create_definition = + a DOUBLE $col_opts, + b FLOAT $col_opts +; +--source create_table.inc +if ($mysql_errname) +{ + --let $functionality = Floating point types or UNSIGNED columns + --source unexpected_result.inc +} +if (!$mysql_errname) +{ + --replace_column 3 # 4 # 5 # 6 # + SHOW COLUMNS IN t1; + + INSERT INTO t1 (a,b) VALUES (1.0,-1.0); + INSERT INTO t1 (a,b) VALUES (-100,100); + --sorted_result + SELECT * FROM t1; + DROP TABLE t1; +} + +--echo # +--echo # INT columns +--echo # + +--source type_int.inc +let $create_definition = + t TINYINT $col_opts, + s SMALLINT $col_opts, + m MEDIUMINT $col_opts, + i INT $col_opts, + b BIGINT $col_opts +; +--source create_table.inc +if ($mysql_errname) +{ + --let $functionality = INT types or UNSIGNED columns + --source unexpected_result.inc +} +if (!$mysql_errname) +{ + --replace_column 3 # 4 # 5 # 6 # + SHOW COLUMNS IN t1; + + INSERT INTO t1 (t,s,m,i,b) VALUES (255,65535,16777215,4294967295,18446744073709551615); + INSERT INTO t1 (t,s,m,i,b) VALUES (-1,-1,-1,-1,-1); + --sorted_result + SELECT * FROM t1; + DROP TABLE t1; + +} + +--source cleanup_engine.inc + diff --git a/mysql-test/suite/storage_engine/col_opt_zerofill.result b/mysql-test/suite/storage_engine/col_opt_zerofill.result new file mode 100644 index 00000000000..c2445c5bbc7 --- /dev/null +++ b/mysql-test/suite/storage_engine/col_opt_zerofill.result @@ -0,0 +1,679 @@ +# +# Fixed point columns (NUMERIC, DECIMAL) +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (d DECIMAL ZEROFILL , +d0 DECIMAL(0) ZEROFILL , +d1_1 DECIMAL(1,1) ZEROFILL , +d10_2 DECIMAL(10,2) ZEROFILL , +d60_10 DECIMAL(60,10) ZEROFILL , +n NUMERIC ZEROFILL , +n0_0 NUMERIC(0,0) ZEROFILL , +n1 NUMERIC(1) ZEROFILL , +n20_4 NUMERIC(20,4) ZEROFILL , +n65_4 NUMERIC(65,4) ZEROFILL +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +d decimal(10,0) unsigned zerofill # # # +d0 decimal(10,0) unsigned zerofill # # # +d1_1 decimal(1,1) unsigned zerofill # # # +d10_2 decimal(10,2) unsigned zerofill # # # +d60_10 decimal(60,10) unsigned zerofill # # # +n decimal(10,0) unsigned zerofill # # # +n0_0 decimal(10,0) unsigned zerofill # # # +n1 decimal(1,0) unsigned zerofill # # # +n20_4 decimal(20,4) unsigned zerofill # # # +n65_4 decimal(65,4) unsigned zerofill # # # +INSERT INTO t1 VALUES (100,123456,0.3,40000.25,123456789123456789.10001,1024,7000.0,8.0,999999.9,9223372036854775807); +INSERT INTO t1 VALUES (0,0,0,0,0,0,0,0,0,0); +INSERT INTO t1 VALUES (9999999999.0,9999999999.0,0.9,99999999.99,99999999999999999999999999999999999999999999999999.9999999999,9999999999.0,9999999999.0,9.0,9999999999999999.9999,9999999999999999999999999999999999999999999999999999999999999.9999); +SELECT * FROM t1; +d d0 d1_1 d10_2 d60_10 n n0_0 n1 n20_4 n65_4 +0000000000 0000000000 0.0 00000000.00 00000000000000000000000000000000000000000000000000.0000000000 0000000000 0000000000 0 0000000000000000.0000 0000000000000000000000000000000000000000000000000000000000000.0000 +0000000100 0000123456 0.3 00040000.25 00000000000000000000000000000000123456789123456789.1000100000 0000001024 0000007000 8 0000000000999999.9000 0000000000000000000000000000000000000000009223372036854775807.0000 +9999999999 9999999999 0.9 99999999.99 99999999999999999999999999999999999999999999999999.9999999999 9999999999 9999999999 9 9999999999999999.9999 9999999999999999999999999999999999999999999999999999999999999.9999 +INSERT INTO t1 VALUES (-100,-123456,-0.3,-40000.25,-123456789123456789.10001,-1024,-7000.0,-8.0,-999999.9,-9223372036854775807); +Warnings: +Warning 1264 Out of range value for column 'd' at row 1 +Warning 1264 Out of range value for column 'd0' at row 1 +Warning 1264 Out of range value for column 'd1_1' at row 1 +Warning 1264 Out of range value for column 'd10_2' at row 1 +Warning 1264 Out of range value for column 'd60_10' at row 1 +Warning 1264 Out of range value for column 'n' at row 1 +Warning 1264 Out of range value for column 'n0_0' at row 1 +Warning 1264 Out of range value for column 'n1' at row 1 +Warning 1264 Out of range value for column 'n20_4' at row 1 +Warning 1264 Out of range value for column 'n65_4' at row 1 +INSERT INTO t1 VALUES (-9999999999.0,-9999999999.0,-0.9,-99999999.99,-99999999999999999999999999999999999999999999999999.9999999999,-9999999999.0,-9999999999.0,-9.0,-9999999999999999.9999,-9999999999999999999999999999999999999999999999999999999999999.9999); +Warnings: +Warning 1264 Out of range value for column 'd' at row 1 +Warning 1264 Out of range value for column 'd0' at row 1 +Warning 1264 Out of range value for column 'd1_1' at row 1 +Warning 1264 Out of range value for column 'd10_2' at row 1 +Warning 1264 Out of range value for column 'd60_10' at row 1 +Warning 1264 Out of range value for column 'n' at row 1 +Warning 1264 Out of range value for column 'n0_0' at row 1 +Warning 1264 Out of range value for column 'n1' at row 1 +Warning 1264 Out of range value for column 'n20_4' at row 1 +Warning 1264 Out of range value for column 'n65_4' at row 1 +SELECT * FROM t1; +d d0 d1_1 d10_2 d60_10 n n0_0 n1 n20_4 n65_4 +0000000000 0000000000 0.0 00000000.00 00000000000000000000000000000000000000000000000000.0000000000 0000000000 0000000000 0 0000000000000000.0000 0000000000000000000000000000000000000000000000000000000000000.0000 +0000000000 0000000000 0.0 00000000.00 00000000000000000000000000000000000000000000000000.0000000000 0000000000 0000000000 0 0000000000000000.0000 0000000000000000000000000000000000000000000000000000000000000.0000 +0000000000 0000000000 0.0 00000000.00 00000000000000000000000000000000000000000000000000.0000000000 0000000000 0000000000 0 0000000000000000.0000 0000000000000000000000000000000000000000000000000000000000000.0000 +0000000100 0000123456 0.3 00040000.25 00000000000000000000000000000000123456789123456789.1000100000 0000001024 0000007000 8 0000000000999999.9000 0000000000000000000000000000000000000000009223372036854775807.0000 +9999999999 9999999999 0.9 99999999.99 99999999999999999999999999999999999999999999999999.9999999999 9999999999 9999999999 9 9999999999999999.9999 9999999999999999999999999999999999999999999999999999999999999.9999 +SELECT * FROM t1 WHERE n20_4 = 9999999999999999.9999 OR d < 100; +d d0 d1_1 d10_2 d60_10 n n0_0 n1 n20_4 n65_4 +0000000000 0000000000 0.0 00000000.00 00000000000000000000000000000000000000000000000000.0000000000 0000000000 0000000000 0 0000000000000000.0000 0000000000000000000000000000000000000000000000000000000000000.0000 +0000000000 0000000000 0.0 00000000.00 00000000000000000000000000000000000000000000000000.0000000000 0000000000 0000000000 0 0000000000000000.0000 0000000000000000000000000000000000000000000000000000000000000.0000 +0000000000 0000000000 0.0 00000000.00 00000000000000000000000000000000000000000000000000.0000000000 0000000000 0000000000 0 0000000000000000.0000 0000000000000000000000000000000000000000000000000000000000000.0000 +9999999999 9999999999 0.9 99999999.99 99999999999999999999999999999999999999999999999999.9999999999 9999999999 9999999999 9 9999999999999999.9999 9999999999999999999999999999999999999999999999999999999999999.9999 +INSERT INTO t1 SELECT n65_4, n65_4, n65_4, n65_4, n65_4, n65_4, n65_4, n65_4, n65_4, n65_4 FROM t1 WHERE n65_4 = ( SELECT MAX(n65_4) FROM t1 ); +Warnings: +Warning 1264 Out of range value for column 'd' at row 1 +Warning 1264 Out of range value for column 'd0' at row 1 +Warning 1264 Out of range value for column 'd1_1' at row 1 +Warning 1264 Out of range value for column 'd10_2' at row 1 +Warning 1264 Out of range value for column 'd60_10' at row 1 +Warning 1264 Out of range value for column 'n' at row 1 +Warning 1264 Out of range value for column 'n0_0' at row 1 +Warning 1264 Out of range value for column 'n1' at row 1 +Warning 1264 Out of range value for column 'n20_4' at row 1 +SELECT * FROM t1; +d d0 d1_1 d10_2 d60_10 n n0_0 n1 n20_4 n65_4 +0000000000 0000000000 0.0 00000000.00 00000000000000000000000000000000000000000000000000.0000000000 0000000000 0000000000 0 0000000000000000.0000 0000000000000000000000000000000000000000000000000000000000000.0000 +0000000000 0000000000 0.0 00000000.00 00000000000000000000000000000000000000000000000000.0000000000 0000000000 0000000000 0 0000000000000000.0000 0000000000000000000000000000000000000000000000000000000000000.0000 +0000000000 0000000000 0.0 00000000.00 00000000000000000000000000000000000000000000000000.0000000000 0000000000 0000000000 0 0000000000000000.0000 0000000000000000000000000000000000000000000000000000000000000.0000 +0000000100 0000123456 0.3 00040000.25 00000000000000000000000000000000123456789123456789.1000100000 0000001024 0000007000 8 0000000000999999.9000 0000000000000000000000000000000000000000009223372036854775807.0000 +9999999999 9999999999 0.9 99999999.99 99999999999999999999999999999999999999999999999999.9999999999 9999999999 9999999999 9 9999999999999999.9999 9999999999999999999999999999999999999999999999999999999999999.9999 +9999999999 9999999999 0.9 99999999.99 99999999999999999999999999999999999999999999999999.9999999999 9999999999 9999999999 9 9999999999999999.9999 9999999999999999999999999999999999999999999999999999999999999.9999 +INSERT INTO t1 VALUES (10000000000.0,10000000000.0,1.1,100000000.99,100000000000000000000000000000000000000000000000000.0,10000000000.0,10000000000.0,10.0,10000000000000000.9999,10000000000000000000000000000000000000000000000000000000000000.9999); +Warnings: +Warning 1264 Out of range value for column 'd' at row 1 +Warning 1264 Out of range value for column 'd0' at row 1 +Warning 1264 Out of range value for column 'd1_1' at row 1 +Warning 1264 Out of range value for column 'd10_2' at row 1 +Warning 1264 Out of range value for column 'd60_10' at row 1 +Warning 1264 Out of range value for column 'n' at row 1 +Warning 1264 Out of range value for column 'n0_0' at row 1 +Warning 1264 Out of range value for column 'n1' at row 1 +Warning 1264 Out of range value for column 'n20_4' at row 1 +Warning 1264 Out of range value for column 'n65_4' at row 1 +SELECT * FROM t1; +d d0 d1_1 d10_2 d60_10 n n0_0 n1 n20_4 n65_4 +0000000000 0000000000 0.0 00000000.00 00000000000000000000000000000000000000000000000000.0000000000 0000000000 0000000000 0 0000000000000000.0000 0000000000000000000000000000000000000000000000000000000000000.0000 +0000000000 0000000000 0.0 00000000.00 00000000000000000000000000000000000000000000000000.0000000000 0000000000 0000000000 0 0000000000000000.0000 0000000000000000000000000000000000000000000000000000000000000.0000 +0000000000 0000000000 0.0 00000000.00 00000000000000000000000000000000000000000000000000.0000000000 0000000000 0000000000 0 0000000000000000.0000 0000000000000000000000000000000000000000000000000000000000000.0000 +0000000100 0000123456 0.3 00040000.25 00000000000000000000000000000000123456789123456789.1000100000 0000001024 0000007000 8 0000000000999999.9000 0000000000000000000000000000000000000000009223372036854775807.0000 +9999999999 9999999999 0.9 99999999.99 99999999999999999999999999999999999999999999999999.9999999999 9999999999 9999999999 9 9999999999999999.9999 9999999999999999999999999999999999999999999999999999999999999.9999 +9999999999 9999999999 0.9 99999999.99 99999999999999999999999999999999999999999999999999.9999999999 9999999999 9999999999 9 9999999999999999.9999 9999999999999999999999999999999999999999999999999999999999999.9999 +9999999999 9999999999 0.9 99999999.99 99999999999999999999999999999999999999999999999999.9999999999 9999999999 9999999999 9 9999999999999999.9999 9999999999999999999999999999999999999999999999999999999999999.9999 +INSERT INTO t1 VALUES (9999999999.1,9999999999.1,1.9,99999999.001,99999999999999999999999999999999999999999999999999.99999999991,9999999999.1,9999999999.1,9.1,9999999999999999.00001,9999999999999999999999999999999999999999999999999999999999999.11111); +Warnings: +Note 1265 Data truncated for column 'd' at row 1 +Note 1265 Data truncated for column 'd0' at row 1 +Warning 1264 Out of range value for column 'd1_1' at row 1 +Note 1265 Data truncated for column 'd10_2' at row 1 +Note 1265 Data truncated for column 'd60_10' at row 1 +Note 1265 Data truncated for column 'n' at row 1 +Note 1265 Data truncated for column 'n0_0' at row 1 +Note 1265 Data truncated for column 'n1' at row 1 +Note 1265 Data truncated for column 'n20_4' at row 1 +Note 1265 Data truncated for column 'n65_4' at row 1 +SELECT * FROM t1; +d d0 d1_1 d10_2 d60_10 n n0_0 n1 n20_4 n65_4 +0000000000 0000000000 0.0 00000000.00 00000000000000000000000000000000000000000000000000.0000000000 0000000000 0000000000 0 0000000000000000.0000 0000000000000000000000000000000000000000000000000000000000000.0000 +0000000000 0000000000 0.0 00000000.00 00000000000000000000000000000000000000000000000000.0000000000 0000000000 0000000000 0 0000000000000000.0000 0000000000000000000000000000000000000000000000000000000000000.0000 +0000000000 0000000000 0.0 00000000.00 00000000000000000000000000000000000000000000000000.0000000000 0000000000 0000000000 0 0000000000000000.0000 0000000000000000000000000000000000000000000000000000000000000.0000 +0000000100 0000123456 0.3 00040000.25 00000000000000000000000000000000123456789123456789.1000100000 0000001024 0000007000 8 0000000000999999.9000 0000000000000000000000000000000000000000009223372036854775807.0000 +9999999999 9999999999 0.9 99999999.00 99999999999999999999999999999999999999999999999999.9999999999 9999999999 9999999999 9 9999999999999999.0000 9999999999999999999999999999999999999999999999999999999999999.1111 +9999999999 9999999999 0.9 99999999.99 99999999999999999999999999999999999999999999999999.9999999999 9999999999 9999999999 9 9999999999999999.9999 9999999999999999999999999999999999999999999999999999999999999.9999 +9999999999 9999999999 0.9 99999999.99 99999999999999999999999999999999999999999999999999.9999999999 9999999999 9999999999 9 9999999999999999.9999 9999999999999999999999999999999999999999999999999999999999999.9999 +9999999999 9999999999 0.9 99999999.99 99999999999999999999999999999999999999999999999999.9999999999 9999999999 9999999999 9 9999999999999999.9999 9999999999999999999999999999999999999999999999999999999999999.9999 +ALTER TABLE t1 ADD COLUMN n66 NUMERIC(66); +ERROR 42000: Too big precision 66 specified for 'n66'. Maximum is 65. +ALTER TABLE t1 ADD COLUMN n66_6 DECIMAL(66,6); +ERROR 42000: Too big precision 66 specified for 'n66_6'. Maximum is 65. +ALTER TABLE t1 ADD COLUMN n66_66 DECIMAL(66,66); +ERROR 42000: Too big scale 66 specified for 'n66_66'. Maximum is 30. +DROP TABLE t1; +CREATE TABLE t1 (a DECIMAL ZEROFILL , +b NUMERIC ZEROFILL +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +a decimal(10,0) unsigned zerofill # # # # +b decimal(10,0) unsigned zerofill # # # # +INSERT INTO t1 (a,b) VALUES (1.1,1234); +Warnings: +Note 1265 Data truncated for column 'a' at row 1 +SELECT * FROM t1; +a b +0000000001 0000001234 +DROP TABLE t1; +# +# Floating point columns (FLOAT, DOUBLE) +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (f FLOAT ZEROFILL , +f0 FLOAT(0) ZEROFILL , +r1_1 REAL(1,1) ZEROFILL , +f23_0 FLOAT(23) ZEROFILL , +f20_3 FLOAT(20,3) ZEROFILL , +d DOUBLE ZEROFILL , +d1_0 DOUBLE(1,0) ZEROFILL , +d10_10 DOUBLE PRECISION (10,10) ZEROFILL , +d53 DOUBLE(53,0) ZEROFILL , +d53_10 DOUBLE(53,10) ZEROFILL +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +f float unsigned zerofill # # # +f0 float unsigned zerofill # # # +r1_1 double(1,1) unsigned zerofill # # # +f23_0 float unsigned zerofill # # # +f20_3 float(20,3) unsigned zerofill # # # +d double unsigned zerofill # # # +d1_0 double(1,0) unsigned zerofill # # # +d10_10 double(10,10) unsigned zerofill # # # +d53 double(53,0) unsigned zerofill # # # +d53_10 double(53,10) unsigned zerofill # # # +INSERT INTO t1 VALUES (12345.12345,12345.12345,0.9,123456789.123,56789.987,11111111.111,8.0,0.0123456789,1234566789123456789,99999999999999999.99999999); +SELECT * FROM t1; +f 0000012345.1 +d 000000000011111111.111 +d10_10 0.0123456789 +d1_0 8 +d53 00000000000000000000000000000000001234566789123456800 +d53_10 000000000000000000000000100000000000000000.0000000000 +f0 0000012345.1 +f20_3 0000000000056789.988 +f23_0 000123457000 +r1_1 0.9 +INSERT INTO t1 VALUES (0,0,0,0,0,0,0,0,0,0); +INSERT INTO t1 VALUES ( +99999999999999999999999999999999999999, +99999999999999999999999999999999999999.9999999999999999, +0.9, +99999999999999999999999999999999999999.9, +99999999999999999.999, +999999999999999999999999999999999999999999999999999999999999999999999999999999999, +9, +0.9999999999, +1999999999999999999999999999999999999999999999999999999, +19999999999999999999999999999999999999999999.9999999999 +); +Warnings: +Warning 1264 Out of range value for column 'd53' at row 1 +Warning 1264 Out of range value for column 'd53_10' at row 1 +SELECT * FROM t1; +f 0000012345.1 +d 0000000000000000000000 +d 0000000000000000001e81 +d 000000000011111111.111 +d10_10 0.0000000000 +d10_10 0.0123456789 +d10_10 0.9999999999 +d1_0 0 +d1_0 8 +d1_0 9 +d53 00000000000000000000000000000000000000000000000000000 +d53 00000000000000000000000000000000001234566789123456800 +d53 100000000000000000000000000000000000000000000000000000 +d53_10 000000000000000000000000000000000000000000.0000000000 +d53_10 000000000000000000000000100000000000000000.0000000000 +d53_10 10000000000000000000000000000000000000000000.0000000000 +f 000000000000 +f 000000001e38 +f0 000000000000 +f0 000000001e38 +f0 0000012345.1 +f20_3 0000000000000000.000 +f20_3 0000000000056789.988 +f20_3 99999998430674940.000 +f23_0 000000000000 +f23_0 000000001e38 +f23_0 000123457000 +r1_1 0.0 +r1_1 0.9 +r1_1 0.9 +INSERT INTO t1 VALUES (-999999999999999999999999,-99999999999.999999999999,-0.9,-999.99999999999999999999,-99999999999999999.999,-999999999999999999999999999999999999999999999999999999999999-0.999,-9,-.9999999999,-999999999999999999999999999999.99999999999999999999999,-9999999999999999999999999999999999999999999.9999999999); +Warnings: +Warning 1264 Out of range value for column 'f' at row 1 +Warning 1264 Out of range value for column 'f0' at row 1 +Warning 1264 Out of range value for column 'r1_1' at row 1 +Warning 1264 Out of range value for column 'f23_0' at row 1 +Warning 1264 Out of range value for column 'f20_3' at row 1 +Warning 1264 Out of range value for column 'd' at row 1 +Warning 1264 Out of range value for column 'd1_0' at row 1 +Warning 1264 Out of range value for column 'd10_10' at row 1 +Warning 1264 Out of range value for column 'd53' at row 1 +Warning 1264 Out of range value for column 'd53_10' at row 1 +SELECT * FROM t1; +f 0000012345.1 +d 0000000000000000000000 +d 0000000000000000000000 +d 0000000000000000001e81 +d 000000000011111111.111 +d10_10 0.0000000000 +d10_10 0.0000000000 +d10_10 0.0123456789 +d10_10 0.9999999999 +d1_0 0 +d1_0 0 +d1_0 8 +d1_0 9 +d53 00000000000000000000000000000000000000000000000000000 +d53 00000000000000000000000000000000000000000000000000000 +d53 00000000000000000000000000000000001234566789123456800 +d53 100000000000000000000000000000000000000000000000000000 +d53_10 000000000000000000000000000000000000000000.0000000000 +d53_10 000000000000000000000000000000000000000000.0000000000 +d53_10 000000000000000000000000100000000000000000.0000000000 +d53_10 10000000000000000000000000000000000000000000.0000000000 +f 000000000000 +f 000000000000 +f 000000001e38 +f0 000000000000 +f0 000000000000 +f0 000000001e38 +f0 0000012345.1 +f20_3 0000000000000000.000 +f20_3 0000000000000000.000 +f20_3 0000000000056789.988 +f20_3 99999998430674940.000 +f23_0 000000000000 +f23_0 000000000000 +f23_0 000000001e38 +f23_0 000123457000 +r1_1 0.0 +r1_1 0.0 +r1_1 0.9 +r1_1 0.9 +SELECT MAX(f), MAX(f0), MAX(r1_1), MAX(f23_0), MAX(f20_3), MAX(d), MAX(d1_0), MAX(d10_10), MAX(d53), MAX(d53_10) FROM t1; +MAX(f) 9.999999680285692e37 +MAX(d) 1e81 +MAX(d10_10) 0.9999999999 +MAX(d1_0) 9 +MAX(d53) 100000000000000000000000000000000000000000000000000000 +MAX(d53_10) 10000000000000000000000000000000000000000000.0000000000 +MAX(f0) 9.999999680285692e37 +MAX(f20_3) 99999998430674940.000 +MAX(f23_0) 9.999999680285692e37 +MAX(r1_1) 0.9 +INSERT INTO t1 SELECT d53_10, d53_10, d53_10, d53_10, d53_10, d53_10, d53_10, d53_10, d53_10, d53_10 FROM t1 ORDER BY d53_10 DESC LIMIT 1; +Warnings: +Warning 1264 Out of range value for column 'f' at row 1 +Warning 1264 Out of range value for column 'f0' at row 1 +Warning 1264 Out of range value for column 'r1_1' at row 1 +Warning 1264 Out of range value for column 'f23_0' at row 1 +Warning 1264 Out of range value for column 'f20_3' at row 1 +Warning 1264 Out of range value for column 'd1_0' at row 1 +SELECT * FROM t1; +f 0000012345.1 +d 0000000000000000000000 +d 0000000000000000000000 +d 0000000000000000001e43 +d 0000000000000000001e81 +d 000000000011111111.111 +d10_10 0.0000000000 +d10_10 0.0000000000 +d10_10 0.0123456789 +d10_10 0.9999999999 +d10_10 10000000000000000000000000000000000000000000.0000000000 +d1_0 0 +d1_0 0 +d1_0 8 +d1_0 9 +d1_0 9 +d53 00000000000000000000000000000000000000000000000000000 +d53 00000000000000000000000000000000000000000000000000000 +d53 00000000000000000000000000000000001234566789123456800 +d53 00000000010000000000000000000000000000000000000000000 +d53 100000000000000000000000000000000000000000000000000000 +d53_10 000000000000000000000000000000000000000000.0000000000 +d53_10 000000000000000000000000000000000000000000.0000000000 +d53_10 000000000000000000000000100000000000000000.0000000000 +d53_10 10000000000000000000000000000000000000000000.0000000000 +d53_10 10000000000000000000000000000000000000000000.0000000000 +f 000000000000 +f 000000000000 +f 000000001e38 +f 003.40282e38 +f0 000000000000 +f0 000000000000 +f0 000000001e38 +f0 0000012345.1 +f0 003.40282e38 +f20_3 0000000000000000.000 +f20_3 0000000000000000.000 +f20_3 0000000000056789.988 +f20_3 99999998430674940.000 +f20_3 99999998430674940.000 +f23_0 000000000000 +f23_0 000000000000 +f23_0 000000001e38 +f23_0 000123457000 +f23_0 003.40282e38 +r1_1 0.0 +r1_1 0.0 +r1_1 0.9 +r1_1 0.9 +r1_1 0.9 +INSERT INTO t1 VALUES ( +999999999999999999999999999999999999999, +999999999999999999999999999999999999999.9999999999999999, +1.9, +999999999999999999999999999999999999999.9, +999999999999999999.999, +9999999999999999999999999999999999999999999999999999999999999999999999999999999999, +99, +1.9999999999, +1999999999999999999999999999999999999999999999999999999, +19999999999999999999999999999999999999999999.9999999999 +); +Warnings: +Warning 1916 Got overflow when converting '' to DECIMAL. Value truncated. +Warning 1264 Out of range value for column 'f' at row 1 +Warning 1264 Out of range value for column 'f0' at row 1 +Warning 1264 Out of range value for column 'r1_1' at row 1 +Warning 1264 Out of range value for column 'f23_0' at row 1 +Warning 1264 Out of range value for column 'f20_3' at row 1 +Warning 1264 Out of range value for column 'd1_0' at row 1 +Warning 1264 Out of range value for column 'd10_10' at row 1 +Warning 1264 Out of range value for column 'd53' at row 1 +Warning 1264 Out of range value for column 'd53_10' at row 1 +SELECT * FROM t1; +f 0000012345.1 +d 0000000000000000000000 +d 0000000000000000000000 +d 0000000000000000001e43 +d 0000000000000000001e65 +d 0000000000000000001e81 +d 000000000011111111.111 +d10_10 0.0000000000 +d10_10 0.0000000000 +d10_10 0.0123456789 +d10_10 0.9999999999 +d10_10 0.9999999999 +d10_10 10000000000000000000000000000000000000000000.0000000000 +d1_0 0 +d1_0 0 +d1_0 8 +d1_0 9 +d1_0 9 +d1_0 9 +d53 00000000000000000000000000000000000000000000000000000 +d53 00000000000000000000000000000000000000000000000000000 +d53 00000000000000000000000000000000001234566789123456800 +d53 00000000010000000000000000000000000000000000000000000 +d53 100000000000000000000000000000000000000000000000000000 +d53 100000000000000000000000000000000000000000000000000000 +d53_10 000000000000000000000000000000000000000000.0000000000 +d53_10 000000000000000000000000000000000000000000.0000000000 +d53_10 000000000000000000000000100000000000000000.0000000000 +d53_10 10000000000000000000000000000000000000000000.0000000000 +d53_10 10000000000000000000000000000000000000000000.0000000000 +d53_10 10000000000000000000000000000000000000000000.0000000000 +f 000000000000 +f 000000000000 +f 000000001e38 +f 003.40282e38 +f 003.40282e38 +f0 000000000000 +f0 000000000000 +f0 000000001e38 +f0 0000012345.1 +f0 003.40282e38 +f0 003.40282e38 +f20_3 0000000000000000.000 +f20_3 0000000000000000.000 +f20_3 0000000000056789.988 +f20_3 99999998430674940.000 +f20_3 99999998430674940.000 +f20_3 99999998430674940.000 +f23_0 000000000000 +f23_0 000000000000 +f23_0 000000001e38 +f23_0 000123457000 +f23_0 003.40282e38 +f23_0 003.40282e38 +r1_1 0.0 +r1_1 0.0 +r1_1 0.9 +r1_1 0.9 +r1_1 0.9 +r1_1 0.9 +ALTER TABLE t1 ADD COLUMN d0_0 DOUBLE(0,0); +ERROR 42000: Display width out of range for 'd0_0' (max = 255) +ALTER TABLE t1 ADD COLUMN n66_6 DECIMAL(256,1); +ERROR 42000: Too big precision 256 specified for 'n66_6'. Maximum is 65. +ALTER TABLE t1 ADD COLUMN n66_66 DECIMAL(40,35); +ERROR 42000: Too big scale 35 specified for 'n66_66'. Maximum is 30. +DROP TABLE t1; +CREATE TABLE t1 (a DOUBLE ZEROFILL , +b FLOAT ZEROFILL +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +a double unsigned zerofill # # # # +b float unsigned zerofill # # # # +INSERT INTO t1 (a,b) VALUES (1,1234.5); +SELECT * FROM t1; +a b +0000000000000000000001 0000001234.5 +DROP TABLE t1; +# +# INT columns +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (i INT ZEROFILL , +i0 INT(0) ZEROFILL , +i1 INT(1) ZEROFILL , +i20 INT(20) ZEROFILL , +t TINYINT ZEROFILL , +t0 TINYINT(0) ZEROFILL , +t1 TINYINT(1) ZEROFILL , +t20 TINYINT(20) ZEROFILL , +s SMALLINT ZEROFILL , +s0 SMALLINT(0) ZEROFILL , +s1 SMALLINT(1) ZEROFILL , +s20 SMALLINT(20) ZEROFILL , +m MEDIUMINT ZEROFILL , +m0 MEDIUMINT(0) ZEROFILL , +m1 MEDIUMINT(1) ZEROFILL , +m20 MEDIUMINT(20) ZEROFILL , +b BIGINT ZEROFILL , +b0 BIGINT(0) ZEROFILL , +b1 BIGINT(1) ZEROFILL , +b20 BIGINT(20) ZEROFILL +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +i int(10) unsigned zerofill # # # +i0 int(10) unsigned zerofill # # # +i1 int(1) unsigned zerofill # # # +i20 int(20) unsigned zerofill # # # +t tinyint(3) unsigned zerofill # # # +t0 tinyint(3) unsigned zerofill # # # +t1 tinyint(1) unsigned zerofill # # # +t20 tinyint(20) unsigned zerofill # # # +s smallint(5) unsigned zerofill # # # +s0 smallint(5) unsigned zerofill # # # +s1 smallint(1) unsigned zerofill # # # +s20 smallint(20) unsigned zerofill # # # +m mediumint(8) unsigned zerofill # # # +m0 mediumint(8) unsigned zerofill # # # +m1 mediumint(1) unsigned zerofill # # # +m20 mediumint(20) unsigned zerofill # # # +b bigint(20) unsigned zerofill # # # +b0 bigint(20) unsigned zerofill # # # +b1 bigint(1) unsigned zerofill # # # +b20 bigint(20) unsigned zerofill # # # +INSERT INTO t1 VALUES (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20); +INSERT INTO t1 VALUES (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); +INSERT INTO t1 VALUES (2147483647,2147483647,2147483647,2147483647,127,127,127,127,32767,32767,32767,32767,8388607,8388607,8388607,8388607,9223372036854775807,9223372036854775807,9223372036854775807,9223372036854775807); +SELECT * FROM t1; +i i0 i1 i20 t t0 t1 t20 s s0 s1 s20 m m0 m1 m20 b b0 b1 b20 +0000000000 0000000000 0 00000000000000000000 000 000 0 00000000000000000000 00000 00000 0 00000000000000000000 00000000 00000000 0 00000000000000000000 00000000000000000000 00000000000000000000 0 00000000000000000000 +0000000001 0000000002 3 00000000000000000004 005 006 7 00000000000000000008 00009 00010 11 00000000000000000012 00000013 00000014 15 00000000000000000016 00000000000000000017 00000000000000000018 19 00000000000000000020 +2147483647 2147483647 2147483647 00000000002147483647 127 127 127 00000000000000000127 32767 32767 32767 00000000000000032767 08388607 08388607 8388607 00000000000008388607 09223372036854775807 09223372036854775807 9223372036854775807 09223372036854775807 +INSERT INTO t1 VALUES (-2147483648,-2147483648,-2147483648,-2147483648,-128,-128,-128,-128,-32768,-32768,-32768,-32768,-8388608,-8388608,-8388608,-8388608,-9223372036854775808,-9223372036854775808,-9223372036854775808,-9223372036854775808); +Warnings: +Warning 1264 Out of range value for column 'i' at row 1 +Warning 1264 Out of range value for column 'i0' at row 1 +Warning 1264 Out of range value for column 'i1' at row 1 +Warning 1264 Out of range value for column 'i20' at row 1 +Warning 1264 Out of range value for column 't' at row 1 +Warning 1264 Out of range value for column 't0' at row 1 +Warning 1264 Out of range value for column 't1' at row 1 +Warning 1264 Out of range value for column 't20' at row 1 +Warning 1264 Out of range value for column 's' at row 1 +Warning 1264 Out of range value for column 's0' at row 1 +Warning 1264 Out of range value for column 's1' at row 1 +Warning 1264 Out of range value for column 's20' at row 1 +Warning 1264 Out of range value for column 'm' at row 1 +Warning 1264 Out of range value for column 'm0' at row 1 +Warning 1264 Out of range value for column 'm1' at row 1 +Warning 1264 Out of range value for column 'm20' at row 1 +Warning 1264 Out of range value for column 'b' at row 1 +Warning 1264 Out of range value for column 'b0' at row 1 +Warning 1264 Out of range value for column 'b1' at row 1 +Warning 1264 Out of range value for column 'b20' at row 1 +INSERT INTO t1 VALUES (4294967295,4294967295,4294967295,4294967295,255,255,255,255,65535,65535,65535,65535,16777215,16777215,16777215,16777215,18446744073709551615,18446744073709551615,18446744073709551615,18446744073709551615); +SELECT * FROM t1; +i i0 i1 i20 t t0 t1 t20 s s0 s1 s20 m m0 m1 m20 b b0 b1 b20 +0000000000 0000000000 0 00000000000000000000 000 000 0 00000000000000000000 00000 00000 0 00000000000000000000 00000000 00000000 0 00000000000000000000 00000000000000000000 00000000000000000000 0 00000000000000000000 +0000000000 0000000000 0 00000000000000000000 000 000 0 00000000000000000000 00000 00000 0 00000000000000000000 00000000 00000000 0 00000000000000000000 00000000000000000000 00000000000000000000 0 00000000000000000000 +0000000001 0000000002 3 00000000000000000004 005 006 7 00000000000000000008 00009 00010 11 00000000000000000012 00000013 00000014 15 00000000000000000016 00000000000000000017 00000000000000000018 19 00000000000000000020 +2147483647 2147483647 2147483647 00000000002147483647 127 127 127 00000000000000000127 32767 32767 32767 00000000000000032767 08388607 08388607 8388607 00000000000008388607 09223372036854775807 09223372036854775807 9223372036854775807 09223372036854775807 +4294967295 4294967295 4294967295 00000000004294967295 255 255 255 00000000000000000255 65535 65535 65535 00000000000000065535 16777215 16777215 16777215 00000000000016777215 18446744073709551615 18446744073709551615 18446744073709551615 18446744073709551615 +INSERT INTO t1 VALUES (-2147483649,-2147483649,-2147483649,-2147483649,-129,-129,-129,-129,-32769,-32769,-32769,-32769,-8388609,-8388609,-8388609,-8388609,-9223372036854775809,-9223372036854775809,-9223372036854775809,-9223372036854775809); +Warnings: +Warning 1264 Out of range value for column 'i' at row 1 +Warning 1264 Out of range value for column 'i0' at row 1 +Warning 1264 Out of range value for column 'i1' at row 1 +Warning 1264 Out of range value for column 'i20' at row 1 +Warning 1264 Out of range value for column 't' at row 1 +Warning 1264 Out of range value for column 't0' at row 1 +Warning 1264 Out of range value for column 't1' at row 1 +Warning 1264 Out of range value for column 't20' at row 1 +Warning 1264 Out of range value for column 's' at row 1 +Warning 1264 Out of range value for column 's0' at row 1 +Warning 1264 Out of range value for column 's1' at row 1 +Warning 1264 Out of range value for column 's20' at row 1 +Warning 1264 Out of range value for column 'm' at row 1 +Warning 1264 Out of range value for column 'm0' at row 1 +Warning 1264 Out of range value for column 'm1' at row 1 +Warning 1264 Out of range value for column 'm20' at row 1 +Warning 1264 Out of range value for column 'b' at row 1 +Warning 1264 Out of range value for column 'b0' at row 1 +Warning 1264 Out of range value for column 'b1' at row 1 +Warning 1264 Out of range value for column 'b20' at row 1 +INSERT INTO t1 VALUES (4294967296,4294967296,4294967296,4294967296,256,256,256,256,65536,65536,65536,65536,16777216,16777216,16777216,16777216,18446744073709551616,18446744073709551616,18446744073709551616,18446744073709551616); +Warnings: +Warning 1264 Out of range value for column 'i' at row 1 +Warning 1264 Out of range value for column 'i0' at row 1 +Warning 1264 Out of range value for column 'i1' at row 1 +Warning 1264 Out of range value for column 'i20' at row 1 +Warning 1264 Out of range value for column 't' at row 1 +Warning 1264 Out of range value for column 't0' at row 1 +Warning 1264 Out of range value for column 't1' at row 1 +Warning 1264 Out of range value for column 't20' at row 1 +Warning 1264 Out of range value for column 's' at row 1 +Warning 1264 Out of range value for column 's0' at row 1 +Warning 1264 Out of range value for column 's1' at row 1 +Warning 1264 Out of range value for column 's20' at row 1 +Warning 1264 Out of range value for column 'm' at row 1 +Warning 1264 Out of range value for column 'm0' at row 1 +Warning 1264 Out of range value for column 'm1' at row 1 +Warning 1264 Out of range value for column 'm20' at row 1 +Warning 1264 Out of range value for column 'b' at row 1 +Warning 1264 Out of range value for column 'b0' at row 1 +Warning 1264 Out of range value for column 'b1' at row 1 +Warning 1264 Out of range value for column 'b20' at row 1 +INSERT INTO t1 SELECT b,b,b,b,b,b,b,b,b,b,b,b,b,b,b,b,b,b,b,b FROM t1 WHERE b IN (-9223372036854775808,9223372036854775807,18446744073709551615); +Warnings: +Warning 1264 Out of range value for column 'i' at row 1 +Warning 1264 Out of range value for column 'i0' at row 1 +Warning 1264 Out of range value for column 'i1' at row 1 +Warning 1264 Out of range value for column 'i20' at row 1 +Warning 1264 Out of range value for column 't' at row 1 +Warning 1264 Out of range value for column 't0' at row 1 +Warning 1264 Out of range value for column 't1' at row 1 +Warning 1264 Out of range value for column 't20' at row 1 +Warning 1264 Out of range value for column 's' at row 1 +Warning 1264 Out of range value for column 's0' at row 1 +Warning 1264 Out of range value for column 's1' at row 1 +Warning 1264 Out of range value for column 's20' at row 1 +Warning 1264 Out of range value for column 'm' at row 1 +Warning 1264 Out of range value for column 'm0' at row 1 +Warning 1264 Out of range value for column 'm1' at row 1 +Warning 1264 Out of range value for column 'm20' at row 1 +Warning 1264 Out of range value for column 'i' at row 2 +Warning 1264 Out of range value for column 'i0' at row 2 +Warning 1264 Out of range value for column 'i1' at row 2 +Warning 1264 Out of range value for column 'i20' at row 2 +Warning 1264 Out of range value for column 't' at row 2 +Warning 1264 Out of range value for column 't0' at row 2 +Warning 1264 Out of range value for column 't1' at row 2 +Warning 1264 Out of range value for column 't20' at row 2 +Warning 1264 Out of range value for column 's' at row 2 +Warning 1264 Out of range value for column 's0' at row 2 +Warning 1264 Out of range value for column 's1' at row 2 +Warning 1264 Out of range value for column 's20' at row 2 +Warning 1264 Out of range value for column 'm' at row 2 +Warning 1264 Out of range value for column 'm0' at row 2 +Warning 1264 Out of range value for column 'm1' at row 2 +Warning 1264 Out of range value for column 'm20' at row 2 +Warning 1264 Out of range value for column 'i' at row 3 +Warning 1264 Out of range value for column 'i0' at row 3 +Warning 1264 Out of range value for column 'i1' at row 3 +Warning 1264 Out of range value for column 'i20' at row 3 +Warning 1264 Out of range value for column 't' at row 3 +Warning 1264 Out of range value for column 't0' at row 3 +Warning 1264 Out of range value for column 't1' at row 3 +Warning 1264 Out of range value for column 't20' at row 3 +Warning 1264 Out of range value for column 's' at row 3 +Warning 1264 Out of range value for column 's0' at row 3 +Warning 1264 Out of range value for column 's1' at row 3 +Warning 1264 Out of range value for column 's20' at row 3 +Warning 1264 Out of range value for column 'm' at row 3 +Warning 1264 Out of range value for column 'm0' at row 3 +Warning 1264 Out of range value for column 'm1' at row 3 +Warning 1264 Out of range value for column 'm20' at row 3 +SELECT * FROM t1; +i i0 i1 i20 t t0 t1 t20 s s0 s1 s20 m m0 m1 m20 b b0 b1 b20 +0000000000 0000000000 0 00000000000000000000 000 000 0 00000000000000000000 00000 00000 0 00000000000000000000 00000000 00000000 0 00000000000000000000 00000000000000000000 00000000000000000000 0 00000000000000000000 +0000000000 0000000000 0 00000000000000000000 000 000 0 00000000000000000000 00000 00000 0 00000000000000000000 00000000 00000000 0 00000000000000000000 00000000000000000000 00000000000000000000 0 00000000000000000000 +0000000000 0000000000 0 00000000000000000000 000 000 0 00000000000000000000 00000 00000 0 00000000000000000000 00000000 00000000 0 00000000000000000000 00000000000000000000 00000000000000000000 0 00000000000000000000 +0000000001 0000000002 3 00000000000000000004 005 006 7 00000000000000000008 00009 00010 11 00000000000000000012 00000013 00000014 15 00000000000000000016 00000000000000000017 00000000000000000018 19 00000000000000000020 +2147483647 2147483647 2147483647 00000000002147483647 127 127 127 00000000000000000127 32767 32767 32767 00000000000000032767 08388607 08388607 8388607 00000000000008388607 09223372036854775807 09223372036854775807 9223372036854775807 09223372036854775807 +4294967295 4294967295 4294967295 00000000004294967295 255 255 255 00000000000000000255 65535 65535 65535 00000000000000065535 16777215 16777215 16777215 00000000000016777215 09223372036854775807 09223372036854775807 9223372036854775807 09223372036854775807 +4294967295 4294967295 4294967295 00000000004294967295 255 255 255 00000000000000000255 65535 65535 65535 00000000000000065535 16777215 16777215 16777215 00000000000016777215 18446744073709551615 18446744073709551615 18446744073709551615 18446744073709551615 +4294967295 4294967295 4294967295 00000000004294967295 255 255 255 00000000000000000255 65535 65535 65535 00000000000000065535 16777215 16777215 16777215 00000000000016777215 18446744073709551615 18446744073709551615 18446744073709551615 18446744073709551615 +4294967295 4294967295 4294967295 00000000004294967295 255 255 255 00000000000000000255 65535 65535 65535 00000000000000065535 16777215 16777215 16777215 00000000000016777215 18446744073709551615 18446744073709551615 18446744073709551615 18446744073709551615 +4294967295 4294967295 4294967295 00000000004294967295 255 255 255 00000000000000000255 65535 65535 65535 00000000000000065535 16777215 16777215 16777215 00000000000016777215 18446744073709551615 18446744073709551615 18446744073709551615 18446744073709551615 +ALTER TABLE t1 ADD COLUMN i257 INT(257); +ERROR 42000: Display width out of range for 'i257' (max = 255) +DROP TABLE t1; +CREATE TABLE t1 (t TINYINT ZEROFILL , +s SMALLINT ZEROFILL , +m MEDIUMINT ZEROFILL , +i INT ZEROFILL , +b BIGINT ZEROFILL +) ENGINE= ; +SHOW COLUMNS IN t1; +Field Type Null Key Default Extra +t tinyint(3) unsigned zerofill # # # # +s smallint(5) unsigned zerofill # # # # +m mediumint(8) unsigned zerofill # # # # +i int(10) unsigned zerofill # # # # +b bigint(20) unsigned zerofill # # # # +INSERT INTO t1 (t,s,m,i,b) VALUES (1,10,100,1000,0); +SELECT * FROM t1; +t s m i b +001 00010 00000100 0000001000 00000000000000000000 +DROP TABLE t1; diff --git a/mysql-test/suite/storage_engine/col_opt_zerofill.test b/mysql-test/suite/storage_engine/col_opt_zerofill.test new file mode 100644 index 00000000000..83b7dcf28c1 --- /dev/null +++ b/mysql-test/suite/storage_engine/col_opt_zerofill.test @@ -0,0 +1,88 @@ +# +# ZEROFILL column attribute +# + +let $extra_type_opts = ZEROFILL; + +--source have_engine.inc + +--echo # +--echo # Fixed point columns (NUMERIC, DECIMAL) +--echo # + +--source type_fixed.inc +let $create_definition = + a DECIMAL $col_opts, + b NUMERIC $col_opts +; +--source create_table.inc +if ($mysql_errname) +{ + --let $functionality = Fixed point types or ZEROFILL columns + --source unexpected_result.inc +} +if (!$mysql_errname) +{ + --replace_column 3 # 4 # 5 # 6 # + SHOW COLUMNS IN t1; + + INSERT INTO t1 (a,b) VALUES (1.1,1234); + SELECT * FROM t1; + DROP TABLE t1; +} + +--echo # +--echo # Floating point columns (FLOAT, DOUBLE) +--echo # + +--source type_float.inc +let $create_definition = + a DOUBLE $col_opts, + b FLOAT $col_opts +; +--source create_table.inc +if ($mysql_errname) +{ + --let $functionality = Floating point types or ZEROFILL columns + --source unexpected_result.inc +} +if (!$mysql_errname) +{ + --replace_column 3 # 4 # 5 # 6 # + SHOW COLUMNS IN t1; + + INSERT INTO t1 (a,b) VALUES (1,1234.5); + SELECT * FROM t1; + DROP TABLE t1; +} + +--echo # +--echo # INT columns +--echo # + +--source type_int.inc +let $create_definition = + t TINYINT $col_opts, + s SMALLINT $col_opts, + m MEDIUMINT $col_opts, + i INT $col_opts, + b BIGINT $col_opts +; +--source create_table.inc +if ($mysql_errname) +{ + --let $functionality = INT types or UNSIGNED columns + --source unexpected_result.inc +} +if (!$mysql_errname) +{ + --replace_column 3 # 4 # 5 # 6 # + SHOW COLUMNS IN t1; + + INSERT INTO t1 (t,s,m,i,b) VALUES (1,10,100,1000,0); + SELECT * FROM t1; + DROP TABLE t1; +} + +--source cleanup_engine.inc + diff --git a/mysql-test/suite/storage_engine/create_table.inc b/mysql-test/suite/storage_engine/create_table.inc new file mode 100644 index 00000000000..9a1cba5100a --- /dev/null +++ b/mysql-test/suite/storage_engine/create_table.inc @@ -0,0 +1,174 @@ +################################## +# +# This include file will be used for all CREATE TABLE statements in the suite. +# If you need to add additional steps or change the logic, copy the file +# to storage//mysql-test/storage_engine/ folder and modify it there. +# +################## +# +# Parameters: +# +# --let $create_definition = # optional, default t1 +# --let $table_options =
# optional, default based on define_engine.inc +# --let $partition_options = # optional, default none +# --let $as_select =
# optional, default t1 +# --let $error_codes = # optional, default 0 +# --let $online = [0|1] # optional, default 0 (1 adds ONLINE) +# --let $rename_to = # optional, default empty. +# # If set, means we are running RENAME TO, then alter definition is ignored +# +# Usage examples: +# +# --let $alter_definition = ADD COLUMN b $char_col DEFAULT '' +# + +--let $child_alter_definition = $alter_definition + +if ($rename_to) +{ + --let $alter_definition = RENAME TO $rename_to + --let $child_alter_definition = RENAME TO mrg.$rename_to +} + +if (!$alter_definition) +{ + --die # The ALTER statement is empty +} + +--let $alter_statement = ALTER + +if ($online) +{ + --let $alter_statement = $alter_statement ONLINE +} + +if (!$table_name) +{ + --let $table_name = t1 +} + +--let $alter_statement = $alter_statement TABLE $table_name $alter_definition +# We don't want to do ONLINE on underlying tables, we are not testing MyISAM +--let $child_statement = ALTER TABLE mrg.$table_name $child_alter_definition + + + +# We now have the complete ALTER statement in $alter_statement. +# If your ALTER statement should be composed differently, +# modify the logic above. + +##################### +# Here you can add logic needed BEFORE the main statement +# (e.g. base tables need to be altered, etc.). +# Surround it by --disable_query_log/--enable_query_log +# if you don't want it to appear in the result output. +##################### + +--source obfuscate.inc + +eval $alter_statement; +--source check_errors.inc + +# Make sure you don't add any statements between the main ALTER (above) +# and saving mysql_errno and mysql_errname (below) +# They are saved in case you want to add more logic after the main ALTER, +# because we need the result code of the statement. +# Also, do not change $alter_statement after it is executed! + +--let $my_errno = $mysql_errno +--let $my_errname = $mysql_errname + +##################### +# Here you can add logic needed AFTER the main statement. +# Surround it by --disable_query_log/--enable_query_log +# if you don't want it to appear in the result output. +##################### +--disable_query_log +--disable_warnings +--disable_result_log +# We will only try to alter the underlying table if the main alter was successful +if (!$my_errno) +{ + if ($rename_to) + { + eval ALTER TABLE $rename_to UNION(mrg.$rename_to); + } + # In the same section, the manual says that FLUSH TABLES should be performed before altering + # the underlying table, and later also says that it should be done after. We'll do both + FLUSH TABLES; + eval $child_statement; + FLUSH TABLES; +} +--enable_result_log +--enable_warnings +--enable_query_log + +# Unset the parameters, we don't want them to be accidentally reused later +--let $alter_definition = +--let $table_name = +--let $error_codes = +--let $online = 0 +--let $rename_to = + +# Restore the error codes of the main statement +--let $mysql_errno = $my_errno +--let $mysql_errname = $my_errname +# Make sure you don't add any SQL statements after restoring +# mysql_errno and mysql_errname (above) + diff --git a/storage/myisammrg/mysql-test/storage_engine/alter_table.rdiff b/storage/myisammrg/mysql-test/storage_engine/alter_table.rdiff new file mode 100644 index 00000000000..447a38a5b2b --- /dev/null +++ b/storage/myisammrg/mysql-test/storage_engine/alter_table.rdiff @@ -0,0 +1,68 @@ +11c11 +< ) ENGINE= DEFAULT CHARSET=latin1 +--- +> ) ENGINE= DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`) +19c19 +< ) ENGINE= DEFAULT CHARSET=latin1 +--- +> ) ENGINE= DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`) +27c27 +< ) ENGINE= DEFAULT CHARSET=latin1 +--- +> ) ENGINE= DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`) +35c35 +< ) ENGINE= DEFAULT CHARSET=latin1 +--- +> ) ENGINE= DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`) +43c43 +< ) ENGINE= DEFAULT CHARSET=latin1 +--- +> ) ENGINE= DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`) +51c51 +< ) ENGINE= DEFAULT CHARSET=latin1 +--- +> ) ENGINE= DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`) +59c59 +< ) ENGINE= DEFAULT CHARSET=latin1 +--- +> ) ENGINE= DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`) +67c67 +< ) ENGINE= DEFAULT CHARSET=latin1 +--- +> ) ENGINE= DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`) +75c75 +< ) ENGINE= DEFAULT CHARSET=latin1 +--- +> ) ENGINE= DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`) +82c82 +< ) ENGINE= DEFAULT CHARSET=latin1 +--- +> ) ENGINE= DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`) +91c91 +< ) ENGINE= DEFAULT CHARSET=latin1 +--- +> ) ENGINE= DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t2`) +100c100 +< ) ENGINE= DEFAULT CHARSET=latin1 +--- +> ) ENGINE= DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`) +107c107 +< ) ENGINE= DEFAULT CHARSET=latin1 +--- +> ) ENGINE= DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`) +122c122 +< ) ENGINE= DEFAULT CHARSET=latin1 COLLATE=latin1_general_cs +--- +> ) ENGINE= DEFAULT CHARSET=latin1 COLLATE=latin1_general_cs INSERT_METHOD=LAST UNION=(`mrg`.`t1`) +130c130 +< ) ENGINE= DEFAULT CHARSET=utf8 +--- +> ) ENGINE= DEFAULT CHARSET=utf8 INSERT_METHOD=LAST UNION=(`mrg`.`t1`) +138c138 +< ) ENGINE= DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci +--- +> ) ENGINE= DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci INSERT_METHOD=LAST UNION=(`mrg`.`t1`) +146c146 +< ) ENGINE= DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci +--- +> ) ENGINE= DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci INSERT_METHOD=LAST UNION=(`mrg`.`t1`) diff --git a/storage/myisammrg/mysql-test/storage_engine/alter_tablespace.rdiff b/storage/myisammrg/mysql-test/storage_engine/alter_tablespace.rdiff new file mode 100644 index 00000000000..cfc821582ed --- /dev/null +++ b/storage/myisammrg/mysql-test/storage_engine/alter_tablespace.rdiff @@ -0,0 +1,27 @@ +4,18c4,13 +< DROP TABLE t1; +< CREATE TABLE t1 (a ) ENGINE= ; +< INSERT INTO t1 (a) VALUES (1),(2); +< SELECT * FROM t1; +< a +< 1 +< 2 +< ALTER TABLE t1 DISCARD TABLESPACE; +< SELECT * FROM t1; +< ERROR HY000: Got error -1 from storage engine +< ALTER TABLE t1 IMPORT TABLESPACE; +< SELECT * FROM t1; +< a +< 1 +< 2 +--- +> ERROR HY000: 'test.t1' is not BASE TABLE +> # ERROR: Statement ended with errno 1347, errname ER_WRONG_OBJECT (expected to succeed) +> # ------------ UNEXPECTED RESULT ------------ +> # [ ALTER TABLE t1 DISCARD TABLESPACE ] +> # The statement|command finished with ER_WRONG_OBJECT. +> # Tablespace operations or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors. +> # You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def. +> # Further in this test, the message might sometimes be suppressed; a part of the test might be skipped. +> # Also, this problem may cause a chain effect (more errors of different kinds in the test). +> # ------------------------------------------- diff --git a/storage/myisammrg/mysql-test/storage_engine/analyze_table.rdiff b/storage/myisammrg/mysql-test/storage_engine/analyze_table.rdiff new file mode 100644 index 00000000000..139bcc00a81 --- /dev/null +++ b/storage/myisammrg/mysql-test/storage_engine/analyze_table.rdiff @@ -0,0 +1,22 @@ +8c8 +< test.t1 analyze status OK +--- +> test.t1 analyze note The storage engine for the table doesn't support analyze +12c12 +< test.t2 analyze status OK +--- +> test.t2 analyze note The storage engine for the table doesn't support analyze +17,18c17,18 +< test.t1 analyze status OK +< test.t2 analyze status OK +--- +> test.t1 analyze note The storage engine for the table doesn't support analyze +> test.t2 analyze note The storage engine for the table doesn't support analyze +24c24 +< test.t1 analyze status OK +--- +> test.t1 analyze note The storage engine for the table doesn't support analyze +28c28 +< test.t1 analyze status OK +--- +> test.t1 analyze note The storage engine for the table doesn't support analyze diff --git a/storage/myisammrg/mysql-test/storage_engine/autoincrement.rdiff b/storage/myisammrg/mysql-test/storage_engine/autoincrement.rdiff new file mode 100644 index 00000000000..e9095aa3944 --- /dev/null +++ b/storage/myisammrg/mysql-test/storage_engine/autoincrement.rdiff @@ -0,0 +1,34 @@ +9c9 +< ) ENGINE= DEFAULT CHARSET=latin1 +--- +> ) ENGINE= DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`) +55c55 +< t1 # # # # # # # # 6 # # # # # # # +--- +> t1 # # # # # # # # 0 # # # # # # # +62c62 +< t1 # # # # # # # # # 8 # # # # # # # +--- +> t1 # # # # # # # # # 0 # # # # # # # +81c81 +< t1 # # # # # # # # # 10 # # # # # # # +--- +> t1 # # # # # # # # # 0 # # # # # # # +85c85 +< t1 # # # # # # # # # 21 # # # # # # # +--- +> t1 # # # # # # # # # 0 # # # # # # # +106c106 +< t1 # # # # # # # # # 22 # # # # # # # +--- +> t1 # # # # # # # # # 0 # # # # # # # +128,129c128,129 +< 100 a +< 101 b +--- +> 1 a +> 2 b +132c132 +< 100 +--- +> 1 diff --git a/storage/myisammrg/mysql-test/storage_engine/cache_index.rdiff b/storage/myisammrg/mysql-test/storage_engine/cache_index.rdiff new file mode 100644 index 00000000000..e10b22a8e66 --- /dev/null +++ b/storage/myisammrg/mysql-test/storage_engine/cache_index.rdiff @@ -0,0 +1,46 @@ +15,16c15,16 +< test.t1 assign_to_keycache status OK +< test.t2 assign_to_keycache status OK +--- +> test.t1 assign_to_keycache note The storage engine for the table doesn't support assign_to_keycache +> test.t2 assign_to_keycache note The storage engine for the table doesn't support assign_to_keycache +19,20c19,20 +< test.t1 preload_keys status OK +< test.t2 preload_keys status OK +--- +> test.t1 preload_keys note The storage engine for the table doesn't support preload_keys +> test.t2 preload_keys note The storage engine for the table doesn't support preload_keys +25,26c25,26 +< test.t1 preload_keys status OK +< test.t2 preload_keys status OK +--- +> test.t1 preload_keys note The storage engine for the table doesn't support preload_keys +> test.t2 preload_keys note The storage engine for the table doesn't support preload_keys +31c31 +< test.t1 preload_keys status OK +--- +> test.t1 preload_keys note The storage engine for the table doesn't support preload_keys +35c35 +< test.t1 assign_to_keycache status OK +--- +> test.t1 assign_to_keycache note The storage engine for the table doesn't support assign_to_keycache +39c39 +< test.t1 preload_keys status OK +--- +> test.t1 preload_keys note The storage engine for the table doesn't support preload_keys +50c50 +< test.t1 assign_to_keycache status OK +--- +> test.t1 assign_to_keycache note The storage engine for the table doesn't support assign_to_keycache +54c54 +< test.t1 preload_keys status OK +--- +> test.t1 preload_keys note The storage engine for the table doesn't support preload_keys +62c62 +< test.t1 assign_to_keycache status OK +--- +> test.t1 assign_to_keycache note The storage engine for the table doesn't support assign_to_keycache +66c66 +< test.t1 preload_keys status OK +--- +> test.t1 preload_keys note The storage engine for the table doesn't support preload_keys diff --git a/storage/myisammrg/mysql-test/storage_engine/char_indexes.rdiff b/storage/myisammrg/mysql-test/storage_engine/char_indexes.rdiff new file mode 100644 index 00000000000..e69de29bb2d diff --git a/storage/myisammrg/mysql-test/storage_engine/checksum_table_live.rdiff b/storage/myisammrg/mysql-test/storage_engine/checksum_table_live.rdiff new file mode 100644 index 00000000000..1710cc18fea --- /dev/null +++ b/storage/myisammrg/mysql-test/storage_engine/checksum_table_live.rdiff @@ -0,0 +1,6 @@ +14,15c14,15 +< test.t1 4272806499 +< test.t2 0 +--- +> test.t1 NULL +> test.t2 NULL diff --git a/storage/myisammrg/mysql-test/storage_engine/cleanup_engine.inc b/storage/myisammrg/mysql-test/storage_engine/cleanup_engine.inc new file mode 100644 index 00000000000..b8f84110c76 --- /dev/null +++ b/storage/myisammrg/mysql-test/storage_engine/cleanup_engine.inc @@ -0,0 +1,16 @@ +########################################### +# +# This is a stub of the include file cleanup_engine.inc which +# should be placed in storage//mysql-test/storage_engine folder. +# +################################ +# +# Here you can add whatever is needed to cleanup +# in case your define_engine.inc created any artefacts, +# e.g. an additional schema and/or tables. +--disable_query_log +--disable_warnings +DROP DATABASE IF EXISTS mrg; +--enable_warnings +--enable_query_log + diff --git a/storage/myisammrg/mysql-test/storage_engine/create_table.inc b/storage/myisammrg/mysql-test/storage_engine/create_table.inc new file mode 100644 index 00000000000..c74460d42fb --- /dev/null +++ b/storage/myisammrg/mysql-test/storage_engine/create_table.inc @@ -0,0 +1,208 @@ +################################## +# +# This include file will be used for all CREATE TABLE statements in the suite. +# If you need to add additional steps or change the logic, copy the file +# to storage//mysql-test/storage_engine/ folder and modify it there. +# +################## +# +# Parameters: +# +# --let $create_definition = # optional, default t1 +# --let $table_options =
# optional, default based on define_engine.inc +# --let $partition_options = # optional, default none +# --let $as_select = ') as upd1; +upd1 + +show status like "feature_xml"; +Variable_name Value +Feature_xml 2 diff --git a/mysql-test/r/mysqld--help.result b/mysql-test/r/mysqld--help.result index 63df79160cc..718909d1b27 100644 --- a/mysql-test/r/mysqld--help.result +++ b/mysql-test/r/mysqld--help.result @@ -923,7 +923,6 @@ key-cache-age-threshold 300 key-cache-block-size 1024 key-cache-division-limit 100 key-cache-segments 0 -language MYSQL_SHAREDIR/ large-pages FALSE lc-messages en_US lc-messages-dir MYSQL_SHAREDIR/ diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 1b35fe5a56a..5af20fd0c3c 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -4678,6 +4678,7 @@ DROP TABLE t1,t2,t3; # LP bug#1007622 Server crashes in handler::increment_statistics on # inserting into a view over a view # +flush status; CREATE TABLE t1 (a INT); CREATE ALGORITHM=MERGE VIEW v1 AS SELECT a1.* FROM t1 AS a1, t1 AS a2; CREATE ALGORITHM=MERGE VIEW v2 AS SELECT * FROM v1; @@ -4687,6 +4688,15 @@ a 1 drop view v2,v1; drop table t1; +show status like '%view%'; +Variable_name Value +Com_create_view 2 +Com_drop_view 1 +Opened_views 3 +show status like 'Opened_table%'; +Variable_name Value +Opened_table_definitions 2 +Opened_tables 3 # # MDEV-486 LP BUG#1010116 Incorrect query results in # view and derived tables diff --git a/mysql-test/suite/rpl/t/rpl_start_stop_slave.test b/mysql-test/suite/rpl/t/rpl_start_stop_slave.test index c9c8f043668..ab388f3eebc 100644 --- a/mysql-test/suite/rpl/t/rpl_start_stop_slave.test +++ b/mysql-test/suite/rpl/t/rpl_start_stop_slave.test @@ -21,6 +21,16 @@ connection slave; --let $connection_id=`SELECT id FROM information_schema.processlist where state LIKE 'Waiting for master to send event'` +if(!$connection_id) +{ + # Something went wrong (timing) + # Show process list so that we can debug. In this case we will abort with + # wrong result + -- echo "Could not find connect id. Dumping process list for debugging" + SELECT * FROM information_schema.processlist; + exit; +} + set @time_before_kill := (select CURRENT_TIMESTAMP); --echo [Time before the query] diff --git a/mysql-test/t/features.test b/mysql-test/t/features.test new file mode 100644 index 00000000000..a54b09a3fd3 --- /dev/null +++ b/mysql-test/t/features.test @@ -0,0 +1,107 @@ +# Testing of feature statistics + +-- source include/have_geometry.inc + +--disable_warnings +drop table if exists t1; +--enable_warnings + +show status like "feature%"; + +--echo # +--echo # Feature GIS +--echo # + +CREATE TABLE t1 (g POINT); +SHOW FIELDS FROM t1; +INSERT INTO t1 VALUES + (PointFromText('POINT(10 10)')), + (PointFromText('POINT(20 10)')), + (PointFromText('POINT(20 20)')), + (PointFromWKB(AsWKB(PointFromText('POINT(10 20)')))); +drop table t1; + +show status like "feature_gis"; + +--echo # +--echo # Feature dynamic columns +--echo # +set @a= COLUMN_CREATE(1, 1212 AS int); +set @b= column_add(@a, 2, 1212 as integer); +select column_get(@b, 2 as integer); + +show status like "feature_dynamic_columns"; + +--echo # +--echo # Feature fulltext +--echo # + +CREATE TABLE t1 (a VARCHAR(200), b TEXT, FULLTEXT (a,b)) engine=myisam; +INSERT INTO t1 VALUES('MySQL has now support', 'for full-text search'), + ('Full-text indexes', 'are called collections'), + ('Only MyISAM tables','support collections'), + ('Function MATCH ... AGAINST()','is used to do a search'), + ('Full-text search in MySQL', 'implements vector space model'); +select * from t1 where MATCH(a,b) AGAINST ("collections"); +select * from t1 where MATCH(a,b) AGAINST ("indexes"); +drop table t1; + +show status like "feature_fulltext"; + + +--echo # +--echo # Feature locale +--echo # + +SET lc_messages=sr_RS; +SET lc_messages=en_US; +show status like "feature_locale"; + +--echo # +--echo # Feature subquery +--echo # + +select (select 2); +SELECT (SELECT 1) UNION SELECT (SELECT 2); + +create table t1 (a int); +insert into t1 values (2); +select (select a from t1 where t1.a=t2.a), a from t1 as t2; +drop table t1; +show status like "feature_subquery"; + +--echo # +--echo # Feature timezone +--echo # + +SELECT FROM_UNIXTIME(unix_timestamp()) > "1970-01-01"; +set time_zone="+03:00"; +SELECT FROM_UNIXTIME(unix_timestamp()) > "1970-01-01"; +set time_zone= @@global.time_zone; +show status like "feature_timezone"; + +--echo # +--echo # Feature triggers +--echo # + +create table t1 (i int); +--echo # let us test some very simple trigger +create trigger trg before insert on t1 for each row set @a:=1; +set @a:=0; +select @a; +insert into t1 values (1),(2); +select @a; +SHOW TRIGGERS IN test like 't1'; +drop trigger trg; +drop table t1; + +show status like "%trigger%"; + +--echo # +--echo # Feature xml +--echo # +SET @xml='a1b1c1b2a2'; +SELECT extractValue(@xml,'/a'); +select updatexml('
12
', + '/','') as upd1; +show status like "feature_xml"; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index efb6956ae8f..4f739b524e6 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -4618,6 +4618,8 @@ DROP TABLE t1,t2,t3; --echo # inserting into a view over a view --echo # +flush status; + CREATE TABLE t1 (a INT); CREATE ALGORITHM=MERGE VIEW v1 AS SELECT a1.* FROM t1 AS a1, t1 AS a2; CREATE ALGORITHM=MERGE VIEW v2 AS SELECT * FROM v1; @@ -4625,6 +4627,8 @@ INSERT INTO v2 (a) VALUES (1) ; select * from t1; drop view v2,v1; drop table t1; +show status like '%view%'; +show status like 'Opened_table%'; --echo # --echo # MDEV-486 LP BUG#1010116 Incorrect query results in diff --git a/sql/event_scheduler.cc b/sql/event_scheduler.cc index 55a3f6b36c4..b41c9e2cda0 100644 --- a/sql/event_scheduler.cc +++ b/sql/event_scheduler.cc @@ -42,7 +42,7 @@ cond_wait(mythd, abstime, msg, SCHED_FUNC, __LINE__) extern pthread_attr_t connection_attrib; - +extern ulong event_executed; Event_db_repository *Event_worker_thread::db_repository; @@ -557,7 +557,8 @@ Event_scheduler::execute_top(Event_queue_element_for_exec *event_name) event_name))) goto error; - ++started_events; + started_events++; + executed_events++; // For SHOW STATUS DBUG_PRINT("info", ("Event is in THD: 0x%lx", (long) new_thd)); DBUG_RETURN(FALSE); diff --git a/sql/field.cc b/sql/field.cc index 1004f58c945..a3d3d951887 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -9395,9 +9395,12 @@ Field *make_field(TABLE_SHARE *share, uchar *ptr, uint32 field_length, #ifdef HAVE_SPATIAL if (f_is_geom(pack_flag)) + { + status_var_increment(current_thd->status_var.feature_gis); return new Field_geom(ptr,null_pos,null_bit, unireg_check, field_name, share, pack_length, geom_type); + } #endif if (f_is_blob(pack_flag)) return new Field_blob(ptr,null_pos,null_bit, diff --git a/sql/item_func.cc b/sql/item_func.cc index 1e891f06f0b..441eb37d701 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -6046,6 +6046,8 @@ bool Item_func_match::fix_fields(THD *thd, Item **ref) DBUG_ASSERT(fixed == 0); Item *UNINIT_VAR(item); // Safe as arg_count is > 1 + status_var_increment(thd->status_var.feature_fulltext); + maybe_null=1; join_key=0; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index c5d1edbe475..ebfca684ccb 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -3774,6 +3774,7 @@ bool Item_func_dyncol_create::fix_fields(THD *thd, Item **ref) (arg_count / 2)); nums= (uint *) alloc_root(thd->mem_root, sizeof(uint) * (arg_count / 2)); + status_var_increment(thd->status_var.feature_dynamic_columns); return res || vals == 0 || nums == 0; } diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 8bb4e7af00f..091eb178d68 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -220,6 +220,8 @@ bool Item_subselect::fix_fields(THD *thd_param, Item **ref) uint8 uncacheable; bool res; + status_var_increment(thd->status_var.feature_subquery); + DBUG_ASSERT(fixed == 0); engine->set_thd((thd= thd_param)); if (!done_first_fix_fields) diff --git a/sql/item_xmlfunc.cc b/sql/item_xmlfunc.cc index 0fa2d39aea9..ae0a74c5ba6 100644 --- a/sql/item_xmlfunc.cc +++ b/sql/item_xmlfunc.cc @@ -2601,6 +2601,8 @@ void Item_xml_str_func::fix_length_and_dec() MY_XPATH xpath; int rc; + status_var_increment(current_thd->status_var.feature_xml); + nodeset_func= 0; if (agg_arg_charsets_for_comparison(collation, args, arg_count)) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index c2a07e11f0e..e56b5123a7c 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -482,6 +482,7 @@ ulonglong binlog_stmt_cache_size=0; ulonglong max_binlog_stmt_cache_size=0; ulonglong query_cache_size=0; ulong refresh_version; /* Increments on each reload */ +ulong executed_events=0; query_id_t global_query_id; my_atomic_rwlock_t global_query_id_lock; my_atomic_rwlock_t thread_running_lock; @@ -6948,6 +6949,16 @@ SHOW_VAR status_vars[]= { {"Delayed_insert_threads", (char*) &delayed_insert_threads, SHOW_LONG_NOFLUSH}, {"Delayed_writes", (char*) &delayed_insert_writes, SHOW_LONG}, {"Empty_queries", (char*) offsetof(STATUS_VAR, empty_queries), SHOW_LONG_STATUS}, + {"Executed_events", (char*) &executed_events, SHOW_LONG_NOFLUSH }, + {"Executed_triggers", (char*) offsetof(STATUS_VAR, executed_triggers), SHOW_LONG_STATUS}, + {"Feature_dynamic_columns", (char*) offsetof(STATUS_VAR, feature_dynamic_columns), SHOW_LONG_STATUS}, + {"Feature_fulltext", (char*) offsetof(STATUS_VAR, feature_fulltext), SHOW_LONG_STATUS}, + {"Feature_gis", (char*) offsetof(STATUS_VAR, feature_gis), SHOW_LONG_STATUS}, + {"Feature_locale", (char*) offsetof(STATUS_VAR, feature_locale), SHOW_LONG_STATUS}, + {"Feature_subquery", (char*) offsetof(STATUS_VAR, feature_subquery), SHOW_LONG_STATUS}, + {"Feature_timezone", (char*) offsetof(STATUS_VAR, feature_timezone), SHOW_LONG_STATUS}, + {"Feature_trigger", (char*) offsetof(STATUS_VAR, feature_trigger), SHOW_LONG_STATUS}, + {"Feature_xml", (char*) offsetof(STATUS_VAR, feature_xml), SHOW_LONG_STATUS}, {"Flush_commands", (char*) &refresh_version, SHOW_LONG_NOFLUSH}, {"Handler_commit", (char*) offsetof(STATUS_VAR, ha_commit_count), SHOW_LONG_STATUS}, {"Handler_delete", (char*) offsetof(STATUS_VAR, ha_delete_count), SHOW_LONG_STATUS}, @@ -6987,6 +6998,7 @@ SHOW_VAR status_vars[]= { {"Opened_files", (char*) &my_file_total_opened, SHOW_LONG_NOFLUSH}, {"Opened_tables", (char*) offsetof(STATUS_VAR, opened_tables), SHOW_LONG_STATUS}, {"Opened_table_definitions", (char*) offsetof(STATUS_VAR, opened_shares), SHOW_LONG_STATUS}, + {"Opened_views", (char*) offsetof(STATUS_VAR, opened_views), SHOW_LONG_STATUS}, {"Prepared_stmt_count", (char*) &show_prepared_stmt_count, SHOW_FUNC}, {"Rows_sent", (char*) offsetof(STATUS_VAR, rows_sent), SHOW_LONGLONG_STATUS}, {"Rows_read", (char*) offsetof(STATUS_VAR, rows_read), SHOW_LONGLONG_STATUS}, @@ -7274,6 +7286,7 @@ static int mysql_init_variables(void) protocol_version= PROTOCOL_VERSION; what_to_log= ~ (1L << (uint) COM_TIME); refresh_version= 1L; /* Increments on each reload */ + executed_events= 0; global_query_id= thread_id= 1L; my_atomic_rwlock_init(&global_query_id_lock); my_atomic_rwlock_init(&thread_running_lock); diff --git a/sql/mysqld.h b/sql/mysqld.h index 56419acdcd4..619f30ce683 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -175,6 +175,7 @@ extern ulong opt_binlog_rows_event_max_size; extern ulong rpl_recovery_rank, thread_cache_size; extern ulong stored_program_cache_size; extern ulong back_log; +extern ulong executed_events; extern char language[FN_REFLEN]; extern "C" MYSQL_PLUGIN_IMPORT ulong server_id; extern ulong concurrency; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index a1e00b74a47..85e9227c154 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -9421,6 +9421,7 @@ open_new_frm(THD *thd, TABLE_SHARE *share, const char *alias, if (mysql_make_view(thd, parser, table_desc, (prgflag & OPEN_VIEW_NO_PARSE))) goto err; + status_var_increment(thd->status_var.opened_views); } else { diff --git a/sql/sql_class.h b/sql/sql_class.h index 845c2115922..344d6435ad5 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -620,25 +620,17 @@ typedef struct system_status_var ulong ha_savepoint_count; ulong ha_savepoint_rollback_count; -#if 0 - /* KEY_CACHE parts. These are copies of the original */ - ulong key_blocks_changed; - ulong key_blocks_used; - ulong key_cache_r_requests; - ulong key_cache_read; - ulong key_cache_w_requests; - ulong key_cache_write; - /* END OF KEY_CACHE parts */ -#endif - ulong net_big_packet_count; ulong opened_tables; ulong opened_shares; + ulong opened_views; /* +1 opening a view */ + ulong select_full_join_count; ulong select_full_range_join_count; ulong select_range_count; ulong select_range_check_count; ulong select_scan_count; + ulong executed_triggers; ulong long_query_count; ulong filesort_merge_passes; ulong filesort_range_count; @@ -653,6 +645,16 @@ typedef struct system_status_var ulong com_stmt_reset; ulong com_stmt_close; + /* Features used */ + ulong feature_dynamic_columns; /* +1 when creating a dynamic column */ + ulong feature_fulltext; /* +1 when MATCH is used */ + ulong feature_gis; /* +1 opening a table with GIS features */ + ulong feature_locale; /* +1 when LOCALE is set */ + ulong feature_subquery; /* +1 when subqueries are used */ + ulong feature_timezone; /* +1 when XPATH is used */ + ulong feature_trigger; /* +1 opening a table with triggers */ + ulong feature_xml; /* +1 when XPATH is used */ + ulong empty_queries; ulong access_denied_errors; ulong lost_connections; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 6f157c89ee2..dd14173e47f 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1425,6 +1425,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, (thd->open_tables == NULL || (thd->locked_tables_mode == LTM_LOCK_TABLES))); + thd_proc_info(thd, "updating status"); /* Finalize server status flags after executing a command. */ thd->update_server_status(); thd->protocol->end_statement(); diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 1b942ecc93b..aff00f9fcf4 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -1334,6 +1334,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, triggers->definitions_list.elements); table->triggers= triggers; + status_var_increment(thd->status_var.feature_trigger); /* TODO: This could be avoided if there is no triggers @@ -2116,6 +2117,8 @@ bool Table_triggers_list::process_triggers(THD *thd, if (sp_trigger == NULL) return FALSE; + status_var_increment(thd->status_var.executed_triggers); + if (old_row_is_record1) { old_field= record1_field; diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 2fdba7fda82..6de285086a2 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -3578,22 +3578,25 @@ static bool check_locale(sys_var *self, THD *thd, set_var *var) if (!locale->errmsgs->errmsgs) { + bool res; mysql_mutex_lock(&LOCK_error_messages); - if (!locale->errmsgs->errmsgs && - read_texts(ERRMSG_FILE, locale->errmsgs->language, - &locale->errmsgs->errmsgs, - ER_ERROR_LAST - ER_ERROR_FIRST + 1)) + res= (!locale->errmsgs->errmsgs && + read_texts(ERRMSG_FILE, locale->errmsgs->language, + &locale->errmsgs->errmsgs, + ER_ERROR_LAST - ER_ERROR_FIRST + 1)); + mysql_mutex_unlock(&LOCK_error_messages); + if (res) { push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR, "Can't process error message file for locale '%s'", locale->name); - mysql_mutex_unlock(&LOCK_error_messages); return true; } - mysql_mutex_unlock(&LOCK_error_messages); } + status_var_increment(thd->status_var.feature_locale); return false; } + static Sys_var_struct Sys_lc_messages( "lc_messages", "Set the language used for the error messages", SESSION_VAR(lc_messages), NO_CMD_LINE, diff --git a/sql/tztime.cc b/sql/tztime.cc index 9fae9f3fedd..ba24cab9ca7 100644 --- a/sql/tztime.cc +++ b/sql/tztime.cc @@ -2329,7 +2329,6 @@ my_tz_find(THD *thd, const String *name) if (!str_to_offset(name->ptr(), name->length(), &offset)) { - if (!(result_tz= (Time_zone_offset *)my_hash_search(&offset_tzs, (const uchar *)&offset, sizeof(long)))) @@ -2371,6 +2370,9 @@ my_tz_find(THD *thd, const String *name) mysql_mutex_unlock(&tz_LOCK); + if (result_tz && result_tz != my_tz_SYSTEM && result_tz != my_tz_UTC) + status_var_increment(thd->status_var.feature_timezone); + DBUG_RETURN(result_tz); } From 7fbd2de8b8bba2ed27bebbdba99ed4f345b83fa5 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Mon, 10 Sep 2012 13:53:19 +0300 Subject: [PATCH 260/289] Fixed compiler warning on Mac --- mysys/mf_iocache2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysys/mf_iocache2.c b/mysys/mf_iocache2.c index 72372ae6bc0..ff05b7fa485 100644 --- a/mysys/mf_iocache2.c +++ b/mysys/mf_iocache2.c @@ -440,7 +440,7 @@ process_flags: /* TODO: implement precision */ if (backtick_quoting) { - size_t total= my_b_write_backtick_quote(info, (uchar *) par, length2); + size_t total= my_b_write_backtick_quote(info, par, length2); if (total == (size_t)-1) goto err; out_length+= total; From 1539f91267a8ca11b137444a4cb87c61febfb05c Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Mon, 10 Sep 2012 16:46:33 +0300 Subject: [PATCH 261/289] Fixed Bug#1002564: Wrong result for a lookup query from a heap table mysql-test/suite/heap/heap_hash.result: Added test case mysql-test/suite/heap/heap_hash.test: Added test case storage/heap/hp_hash.c: Limit key data length to max key length --- mysql-test/suite/heap/heap_hash.result | 19 +++++++++++++++++++ mysql-test/suite/heap/heap_hash.test | 13 +++++++++++++ storage/heap/hp_hash.c | 9 +++++++++ 3 files changed, 41 insertions(+) diff --git a/mysql-test/suite/heap/heap_hash.result b/mysql-test/suite/heap/heap_hash.result index 453bfc0c165..ac62427c81c 100644 --- a/mysql-test/suite/heap/heap_hash.result +++ b/mysql-test/suite/heap/heap_hash.result @@ -427,4 +427,23 @@ INDEX(col_int_key) USING HASH) ENGINE = HEAP; INSERT INTO t1 (col_int_nokey, col_int_key) VALUES (3, 0), (4, 0), (3, 1); DELETE FROM t1 WHERE col_int_nokey = 5 ORDER BY col_int_key LIMIT 2; DROP TABLE t1; +# +# Bug #1002564: Wrong result for a lookup query from a heap table +# +CREATE TABLE t1 (c1 VARCHAR(10) NOT NULL, KEY i1 (c1(3))) ENGINE=MEMORY DEFAULT CHARSET=latin1; +INSERT INTO t1 VALUES ('foo1'), ('bar2'), ('baz3'); +explain SELECT * FROM t1 WHERE c1='bar2'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref i1 i1 5 const 2 Using where +SELECT * FROM t1 WHERE c1='bar2'; +c1 +bar2 +ALTER TABLE t1 DROP KEY i1, ADD KEY il (c1(3)) using btree; +explain SELECT * FROM t1 WHERE c1='bar2'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref il il 5 const 1 Using where +SELECT * FROM t1 WHERE c1='bar2'; +c1 +bar2 +DROP TABLE t1; End of 5.5 tests diff --git a/mysql-test/suite/heap/heap_hash.test b/mysql-test/suite/heap/heap_hash.test index 80ae01e9547..80d6ef9c8f2 100644 --- a/mysql-test/suite/heap/heap_hash.test +++ b/mysql-test/suite/heap/heap_hash.test @@ -316,4 +316,17 @@ DELETE FROM t1 WHERE col_int_nokey = 5 ORDER BY col_int_key LIMIT 2; DROP TABLE t1; +--echo # +--echo # Bug #1002564: Wrong result for a lookup query from a heap table +--echo # + +CREATE TABLE t1 (c1 VARCHAR(10) NOT NULL, KEY i1 (c1(3))) ENGINE=MEMORY DEFAULT CHARSET=latin1; +INSERT INTO t1 VALUES ('foo1'), ('bar2'), ('baz3'); +explain SELECT * FROM t1 WHERE c1='bar2'; +SELECT * FROM t1 WHERE c1='bar2'; +ALTER TABLE t1 DROP KEY i1, ADD KEY il (c1(3)) using btree; +explain SELECT * FROM t1 WHERE c1='bar2'; +SELECT * FROM t1 WHERE c1='bar2'; +DROP TABLE t1; + --echo End of 5.5 tests diff --git a/storage/heap/hp_hash.c b/storage/heap/hp_hash.c index d44726ba762..2abed55459c 100644 --- a/storage/heap/hp_hash.c +++ b/storage/heap/hp_hash.c @@ -348,6 +348,8 @@ ulong hp_rec_hashnr(register HP_KEYDEF *keydef, register const uchar *rec) seg->length/cs->mbmaxlen); set_if_smaller(length, char_length); } + else + set_if_smaller(length, seg->length); cs->coll->hash_sort(cs, pos+pack_length, length, &nr, &nr2); } else @@ -593,6 +595,11 @@ int hp_rec_key_cmp(HP_KEYDEF *keydef, const uchar *rec1, const uchar *rec2, char_length2= my_charpos(cs, pos2, pos2 + char_length2, char_length); set_if_smaller(char_length2, safe_length2); } + else + { + set_if_smaller(char_length1, seg->length); + set_if_smaller(char_length2, seg->length); + } if (cs->coll->strnncollsp(seg->charset, pos1, char_length1, @@ -689,6 +696,8 @@ int hp_key_cmp(HP_KEYDEF *keydef, const uchar *rec, const uchar *key) char_length2= my_charpos(cs, pos, pos + char_length_rec, char_length2); set_if_smaller(char_length_rec, char_length2); } + else + set_if_smaller(char_length_rec, seg->length); if (cs->coll->strnncollsp(seg->charset, (uchar*) pos, char_length_rec, From 6f94b5c76d51e655d36198d177972caa18089e31 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Mon, 10 Sep 2012 17:26:54 +0300 Subject: [PATCH 262/289] Fixed random test failure mysql-test/include/index_merge2.inc: InnoDB did report 9 or 7 rows in explain --- mysql-test/include/index_merge2.inc | 1 + mysql-test/r/index_merge_innodb.result | 2 +- mysql-test/r/index_merge_myisam.result | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/mysql-test/include/index_merge2.inc b/mysql-test/include/index_merge2.inc index 1d6b82e1787..c50a45a9923 100644 --- a/mysql-test/include/index_merge2.inc +++ b/mysql-test/include/index_merge2.inc @@ -343,6 +343,7 @@ alter table t1 add index i3(key3); update t1 set key2=key1,key3=key1; # to test the bug, the following must use "sort_union": +--replace_column 9 REF explain select * from t1 where (key3 > 30 and key3<35) or (key2 >32 and key2 < 40); select * from t1 where (key3 > 30 and key3<35) or (key2 >32 and key2 < 40); drop table t1; diff --git a/mysql-test/r/index_merge_innodb.result b/mysql-test/r/index_merge_innodb.result index 92bcb2e88f0..b93d15f7bef 100644 --- a/mysql-test/r/index_merge_innodb.result +++ b/mysql-test/r/index_merge_innodb.result @@ -313,7 +313,7 @@ alter table t1 add index i3(key3); update t1 set key2=key1,key3=key1; explain select * from t1 where (key3 > 30 and key3<35) or (key2 >32 and key2 < 40); id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge i2,i3 i3,i2 4,4 NULL 9 Using sort_union(i3,i2); Using where +1 SIMPLE t1 index_merge i2,i3 i3,i2 4,4 NULL REF Using sort_union(i3,i2); Using where select * from t1 where (key3 > 30 and key3<35) or (key2 >32 and key2 < 40); key1 key2 key3 31 31 31 diff --git a/mysql-test/r/index_merge_myisam.result b/mysql-test/r/index_merge_myisam.result index bf151a872cf..0b6959d15a9 100644 --- a/mysql-test/r/index_merge_myisam.result +++ b/mysql-test/r/index_merge_myisam.result @@ -1146,7 +1146,7 @@ alter table t1 add index i3(key3); update t1 set key2=key1,key3=key1; explain select * from t1 where (key3 > 30 and key3<35) or (key2 >32 and key2 < 40); id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge i2,i3 i3,i2 4,4 NULL 11 Using sort_union(i3,i2); Using where +1 SIMPLE t1 index_merge i2,i3 i3,i2 4,4 NULL REF Using sort_union(i3,i2); Using where select * from t1 where (key3 > 30 and key3<35) or (key2 >32 and key2 < 40); key1 key2 key3 31 31 31 From 288eeb3a31e4bfb52180f3906a4d354ac9cc457e Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 13 Sep 2012 14:31:29 +0200 Subject: [PATCH 263/289] MDEV-232: Remove one fsync() from commit phase. Introduce a new storage engine API method commit_checkpoint_request(). This is used to replace the fsync() at the end of every storage engine commit with a single fsync() when a binlog is rotated. Binlog rotation is now done during group commit instead of being delayed until unlog(), removing some server stall and avoiding an expensive lock/unlock of LOCK_log inside unlog(). --- .../extra/rpl_tests/rpl_insert_delayed.test | 2 +- mysql-test/r/mysqlbinlog.result | 1 + mysql-test/r/mysqlbinlog2.result | 12 - .../suite/binlog/r/binlog_checkpoint.result | 88 +++ .../suite/binlog/r/binlog_mdev342.result | 1 + .../suite/binlog/r/binlog_row_binlog.result | 1 + .../r/binlog_row_mysqlbinlog_options.result | 4 +- .../suite/binlog/r/binlog_stm_binlog.result | 1 + .../suite/binlog/r/binlog_xa_recover.result | 321 +++++----- .../suite/binlog/t/binlog_checkpoint.test | 108 ++++ .../binlog/t/binlog_xa_recover-master.opt | 2 +- .../suite/binlog/t/binlog_xa_recover.test | 287 +++++---- .../suite/innodb/r/binlog_consistent.result | 6 +- .../innodb/r/group_commit_binlog_pos.result | 1 + ...ommit_binlog_pos_no_optimize_thread.result | 1 + .../innodb/t/group_commit_binlog_pos.test | 13 + ..._commit_binlog_pos_no_optimize_thread.test | 13 + mysql-test/suite/rpl/r/rpl_checksum.result | 2 +- .../suite/rpl/r/rpl_insert_delayed,stmt.rdiff | 2 +- .../rpl/r/rpl_mariadb_slave_capability.result | 2 +- mysql-test/suite/rpl/r/rpl_row_log.result | 2 + .../suite/rpl/r/rpl_row_log_innodb.result | 2 + .../rpl/r/rpl_row_show_relaylog_events.result | 11 +- mysql-test/suite/rpl/r/rpl_stm_log.result | 2 + .../r/rpl_stm_mix_show_relaylog_events.result | 11 +- .../rpl/t/rpl_mariadb_slave_capability.test | 2 +- ...nnodb_flush_log_at_trx_commit_basic.result | 10 +- sql/handler.cc | 49 ++ sql/handler.h | 42 ++ sql/log.cc | 604 ++++++++++++++---- sql/log.h | 91 ++- sql/log_event.cc | 2 +- sql/log_event.h | 2 +- sql/mysqld.cc | 6 +- sql/mysqld.h | 2 +- sql/rpl_rli.cc | 2 +- sql/slave.cc | 13 +- sql/sql_class.h | 3 - storage/innobase/handler/ha_innodb.cc | 30 +- storage/innobase/trx/trx0trx.c | 11 +- storage/xtradb/handler/ha_innodb.cc | 30 +- storage/xtradb/include/trx0trx.h | 1 - storage/xtradb/trx/trx0trx.c | 11 +- 43 files changed, 1331 insertions(+), 476 deletions(-) create mode 100644 mysql-test/suite/binlog/r/binlog_checkpoint.result create mode 100644 mysql-test/suite/binlog/t/binlog_checkpoint.test diff --git a/mysql-test/extra/rpl_tests/rpl_insert_delayed.test b/mysql-test/extra/rpl_tests/rpl_insert_delayed.test index df08622b0bd..bb34f4be207 100644 --- a/mysql-test/extra/rpl_tests/rpl_insert_delayed.test +++ b/mysql-test/extra/rpl_tests/rpl_insert_delayed.test @@ -133,7 +133,7 @@ if (`SELECT @@global.binlog_format = 'STATEMENT'`) { #must show two INSERT DELAYED --let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1) - --let $binlog_limit= 1,6 + --let $binlog_limit= 2,6 --source include/show_binlog_events.inc } select * from t1; diff --git a/mysql-test/r/mysqlbinlog.result b/mysql-test/r/mysqlbinlog.result index 33904dfd9bd..255b0679244 100644 --- a/mysql-test/r/mysqlbinlog.result +++ b/mysql-test/r/mysqlbinlog.result @@ -892,6 +892,7 @@ DROP DATABASE test1; FLUSH LOGS; show binlog events in 'master-bin.000002' from ; Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000002 # Binlog_checkpoint # # master-bin.000002 master-bin.000002 # Query # # CREATE DATABASE test1 master-bin.000002 # Query # # use `test1`; CREATE TABLE t1(id int) master-bin.000002 # Query # # DROP DATABASE test1 diff --git a/mysql-test/r/mysqlbinlog2.result b/mysql-test/r/mysqlbinlog2.result index 806cf74479e..bf65bab602d 100644 --- a/mysql-test/r/mysqlbinlog2.result +++ b/mysql-test/r/mysqlbinlog2.result @@ -697,7 +697,6 @@ SET @@session.lc_time_names=0/*!*/; SET @@session.collation_database=DEFAULT/*!*/; BEGIN /*!*/; -SET INSERT_ID=6/*!*/; DELIMITER ; # End of log file ROLLBACK /* added by mysqlbinlog */; @@ -1483,17 +1482,6 @@ COMMIT /*!*/; DELIMITER ; DELIMITER /*!*/; -SET TIMESTAMP=1579609943/*!*/; -SET @@session.pseudo_thread_id=999999999/*!*/; -SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/; -SET @@session.sql_mode=0/*!*/; -SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/; -/*!\C latin1 *//*!*/; -SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8/*!*/; -SET @@session.lc_time_names=0/*!*/; -SET @@session.collation_database=DEFAULT/*!*/; -BEGIN -/*!*/; DELIMITER ; # End of log file ROLLBACK /* added by mysqlbinlog */; diff --git a/mysql-test/suite/binlog/r/binlog_checkpoint.result b/mysql-test/suite/binlog/r/binlog_checkpoint.result new file mode 100644 index 00000000000..7532e33367e --- /dev/null +++ b/mysql-test/suite/binlog/r/binlog_checkpoint.result @@ -0,0 +1,88 @@ +SET @old_max_binlog_size= @@global.max_binlog_size; +SET GLOBAL max_binlog_size= 4096; +SET @old_innodb_flush_log_at_trx_commit= @@global.innodb_flush_log_at_trx_commit; +SET GLOBAL innodb_flush_log_at_trx_commit= 1; +RESET MASTER; +CREATE TABLE t1 (a INT PRIMARY KEY, b MEDIUMTEXT) ENGINE=Innodb; +CREATE TABLE t2 (a INT PRIMARY KEY, b MEDIUMTEXT) ENGINE=Myisam; +*** Test that RESET MASTER waits for pending commit checkpoints to complete. +SET DEBUG_SYNC= "commit_after_group_release_commit_ordered SIGNAL con1_ready WAIT_FOR con1_go"; +INSERT INTO t1 VALUES (1, REPEAT("x", 4100)); +SET DEBUG_SYNC= "now WAIT_FOR con1_ready"; +INSERT INTO t2 VALUES (1, REPEAT("x", 4100)); +INSERT INTO t2 VALUES (2, REPEAT("x", 4100)); +show binary logs; +Log_name File_size +master-bin.000001 # +master-bin.000002 # +master-bin.000003 # +master-bin.000004 # +show binlog events in 'master-bin.00000' from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.00000 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +master-bin.00000 # Binlog_checkpoint # # master-bin.000001 +SET DEBUG_SYNC= "execute_command_after_close_tables SIGNAL reset_master_done"; +RESET MASTER; +This will timeout, as RESET MASTER is blocked +SET DEBUG_SYNC= "now WAIT_FOR reset_master_done TIMEOUT 1"; +Warnings: +Warning 1639 debug sync point wait timed out +SET DEBUG_SYNC= "now SIGNAL con1_go"; +show binary logs; +Log_name File_size +master-bin.000001 # +show binlog events in 'master-bin.000001' from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +master-bin.000001 # Binlog_checkpoint # # master-bin.000001 +*** Test that binlog N is active, and commit checkpoint for (N-1) is +*** done while there is still a pending commit checkpoint for (N-2). +SET DEBUG_SYNC= "commit_after_group_release_commit_ordered SIGNAL con1_ready WAIT_FOR con1_continue"; +INSERT INTO t1 VALUES (20, REPEAT("x", 4100)); +SET DEBUG_SYNC= "now WAIT_FOR con1_ready"; +SET DEBUG_SYNC= "commit_after_group_release_commit_ordered SIGNAL con2_ready WAIT_FOR con2_continue"; +INSERT INTO t1 VALUES (21, REPEAT("x", 4100)); +SET DEBUG_SYNC= "now WAIT_FOR con2_ready"; +show binary logs; +Log_name File_size +master-bin.000001 # +master-bin.000002 # +master-bin.000003 # +show binlog events in 'master-bin.000001' from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +master-bin.000001 # Binlog_checkpoint # # master-bin.000001 +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Rotate # # master-bin.000002;pos= +show binlog events in 'master-bin.000002' from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000002 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +master-bin.000002 # Binlog_checkpoint # # master-bin.000001 +master-bin.000002 # Query # # BEGIN +master-bin.000002 # Table_map # # table_id: # (test.t1) +master-bin.000002 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000002 # Xid # # COMMIT /* XID */ +master-bin.000002 # Rotate # # master-bin.000003;pos= +show binlog events in 'master-bin.000003' from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000003 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +master-bin.000003 # Binlog_checkpoint # # master-bin.000001 +SET DEBUG_SYNC= "now SIGNAL con2_continue"; +con1 is still pending, no new binlog checkpoint should have been logged. +show binlog events in 'master-bin.000003' from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000003 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +master-bin.000003 # Binlog_checkpoint # # master-bin.000001 +SET DEBUG_SYNC= "now SIGNAL con1_continue"; +No commit checkpoints are pending, a new binlog checkpoint should have been logged. +show binlog events in 'master-bin.000003' from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000003 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +master-bin.000003 # Binlog_checkpoint # # master-bin.000001 +master-bin.000003 # Binlog_checkpoint # # master-bin.000003 +DROP TABLE t1, t2; +SET GLOBAL max_binlog_size= @old_max_binlog_size; +SET GLOBAL innodb_flush_log_at_trx_commit= @old_innodb_flush_log_at_trx_commit; diff --git a/mysql-test/suite/binlog/r/binlog_mdev342.result b/mysql-test/suite/binlog/r/binlog_mdev342.result index 0e1d8f8ac78..6ec6dcd783b 100644 --- a/mysql-test/suite/binlog/r/binlog_mdev342.result +++ b/mysql-test/suite/binlog/r/binlog_mdev342.result @@ -21,6 +21,7 @@ master-bin.000002 # show binlog events in 'master-bin.000001' from ; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +master-bin.000001 # Binlog_checkpoint # # master-bin.000001 master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT PRIMARY KEY, b MEDIUMTEXT) ENGINE=Innodb master-bin.000001 # Query # # BEGIN master-bin.000001 # Table_map # # table_id: # (test.t1) diff --git a/mysql-test/suite/binlog/r/binlog_row_binlog.result b/mysql-test/suite/binlog/r/binlog_row_binlog.result index 26710178cd8..99ab1ac9ec2 100644 --- a/mysql-test/suite/binlog/r/binlog_row_binlog.result +++ b/mysql-test/suite/binlog/r/binlog_row_binlog.result @@ -234,6 +234,7 @@ master-bin.000001 # Xid # # COMMIT /* XID */ master-bin.000001 # Rotate # # master-bin.000002;pos=4 show binlog events in 'master-bin.000002' from ; Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000002 # Binlog_checkpoint # # master-bin.000002 master-bin.000002 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ set @ac = @@autocommit; set autocommit= 0; diff --git a/mysql-test/suite/binlog/r/binlog_row_mysqlbinlog_options.result b/mysql-test/suite/binlog/r/binlog_row_mysqlbinlog_options.result index ae732ffcc08..55f4154574b 100644 --- a/mysql-test/suite/binlog/r/binlog_row_mysqlbinlog_options.result +++ b/mysql-test/suite/binlog/r/binlog_row_mysqlbinlog_options.result @@ -34,8 +34,8 @@ DELIMITER /*!*/; # at # #010909 4:46:40 server id # end_log_pos # Start: binlog v 4, server v #.##.## created 010909 4:46:40 at startup ROLLBACK/*!*/; -#010909 4:46:40 server id # end_log_pos # Binlog checkpoint master-bin.000001 # at # +#010909 4:46:40 server id # end_log_pos # Binlog checkpoint master-bin.000001 # at # use `new_test1`/*!*/; #010909 4:46:40 server id # end_log_pos # Query thread_id=# exec_time=# error_code=0 @@ -230,8 +230,8 @@ DELIMITER /*!*/; # at # #010909 4:46:40 server id # end_log_pos # Start: binlog v 4, server v #.##.## created 010909 4:46:40 at startup ROLLBACK/*!*/; -#010909 4:46:40 server id # end_log_pos # Binlog checkpoint master-bin.000001 # at # +#010909 4:46:40 server id # end_log_pos # Binlog checkpoint master-bin.000001 # at # use `new_test1`/*!*/; #010909 4:46:40 server id # end_log_pos # Query thread_id=# exec_time=# error_code=0 diff --git a/mysql-test/suite/binlog/r/binlog_stm_binlog.result b/mysql-test/suite/binlog/r/binlog_stm_binlog.result index f9d9fa1d18d..d676f5184ac 100644 --- a/mysql-test/suite/binlog/r/binlog_stm_binlog.result +++ b/mysql-test/suite/binlog/r/binlog_stm_binlog.result @@ -145,6 +145,7 @@ master-bin.000001 # Xid # # COMMIT /* XID */ master-bin.000001 # Rotate # # master-bin.000002;pos=4 show binlog events in 'master-bin.000002' from ; Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000002 # Binlog_checkpoint # # master-bin.000002 master-bin.000002 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ set @ac = @@autocommit; set autocommit= 0; diff --git a/mysql-test/suite/binlog/r/binlog_xa_recover.result b/mysql-test/suite/binlog/r/binlog_xa_recover.result index 41df149a928..0ac14fd7f7d 100644 --- a/mysql-test/suite/binlog/r/binlog_xa_recover.result +++ b/mysql-test/suite/binlog/r/binlog_xa_recover.result @@ -1,175 +1,198 @@ SET GLOBAL max_binlog_size= 4096; +SET GLOBAL innodb_flush_log_at_trx_commit= 1; +RESET MASTER; CREATE TABLE t1 (a INT PRIMARY KEY, b MEDIUMTEXT) ENGINE=Innodb; -CREATE TABLE t2 (a INT PRIMARY KEY, b MEDIUMTEXT) ENGINE=Myisam; -SET @@global.debug_dbug='+d,skip_commit_ordered'; -INSERT INTO t1 VALUES (0, REPEAT("x", 4100)); -SET DEBUG_SYNC= "ha_commit_trans_after_log_and_order SIGNAL con1_ready WAIT_FOR _ever"; +INSERT INTO t1 VALUES (100, REPEAT("x", 4100)); +INSERT INTO t1 VALUES (101, REPEAT("x", 4100)); +INSERT INTO t1 VALUES (102, REPEAT("x", 4100)); +SET DEBUG_SYNC= "ha_commit_trans_before_log_and_order SIGNAL con1_wait WAIT_FOR con1_cont"; +SET DEBUG_SYNC= "commit_after_group_release_commit_ordered SIGNAL con1_ready WAIT_FOR _ever"; INSERT INTO t1 VALUES (1, REPEAT("x", 4100)); -SET DEBUG_SYNC= "now WAIT_FOR con1_ready"; -INSERT INTO t2 VALUES (1, "force binlog rotation"); -SET DEBUG_SYNC= "ha_commit_trans_after_log_and_order SIGNAL con2_ready WAIT_FOR _ever"; +SET DEBUG_SYNC= "now WAIT_FOR con1_wait"; +SET DEBUG_SYNC= "ha_commit_trans_before_log_and_order SIGNAL con2_wait WAIT_FOR con2_cont"; +SET DEBUG_SYNC= "commit_after_group_release_commit_ordered SIGNAL con2_ready WAIT_FOR _ever"; INSERT INTO t1 VALUES (2, NULL); -SET DEBUG_SYNC= "now WAIT_FOR con2_ready"; -SET DEBUG_SYNC= "ha_commit_trans_after_log_and_order SIGNAL con3_ready WAIT_FOR _ever"; +SET DEBUG_SYNC= "now WAIT_FOR con2_wait"; +SET DEBUG_SYNC= "ha_commit_trans_before_log_and_order SIGNAL con3_wait WAIT_FOR con3_cont"; +SET DEBUG_SYNC= "commit_after_group_release_commit_ordered SIGNAL con3_ready WAIT_FOR _ever"; INSERT INTO t1 VALUES (3, REPEAT("x", 4100)); +SET DEBUG_SYNC= "now WAIT_FOR con3_wait"; +SET DEBUG_SYNC= "ha_commit_trans_before_log_and_order SIGNAL con4_wait WAIT_FOR con4_cont"; +SET SESSION debug_dbug="+d,crash_commit_after_log"; +INSERT INTO t1 VALUES (4, NULL); +SET DEBUG_SYNC= "now WAIT_FOR con4_wait"; +SET DEBUG_SYNC= "now SIGNAL con1_cont"; +SET DEBUG_SYNC= "now WAIT_FOR con1_ready"; +SET DEBUG_SYNC= "now SIGNAL con2_cont"; +SET DEBUG_SYNC= "now WAIT_FOR con2_ready"; +SET DEBUG_SYNC= "now SIGNAL con3_cont"; SET DEBUG_SYNC= "now WAIT_FOR con3_ready"; -INSERT INTO t2 VALUES (2, "force binlog rotation"); -FLUSH TABLES t2; show binary logs; Log_name File_size master-bin.000001 # master-bin.000002 # master-bin.000003 # master-bin.000004 # -show binlog events in 'master-bin.000001' from ; -Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Format_desc # # SERVER_VERSION, BINLOG_VERSION -master-bin.000001 # Binlog_checkpoint # # master-bin.000001 -master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT PRIMARY KEY, b MEDIUMTEXT) ENGINE=Innodb -master-bin.000001 # Query # # use `test`; CREATE TABLE t2 (a INT PRIMARY KEY, b MEDIUMTEXT) ENGINE=Myisam -master-bin.000001 # Query # # BEGIN -master-bin.000001 # Table_map # # table_id: # (test.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Xid # # COMMIT /* XID */ -master-bin.000001 # Rotate # # master-bin.000002;pos= -show binlog events in 'master-bin.000002' from ; -Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000002 # Format_desc # # SERVER_VERSION, BINLOG_VERSION -master-bin.000002 # Binlog_checkpoint # # master-bin.000002 -master-bin.000002 # Query # # BEGIN -master-bin.000002 # Table_map # # table_id: # (test.t1) -master-bin.000002 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000002 # Xid # # COMMIT /* XID */ -master-bin.000002 # Query # # BEGIN -master-bin.000002 # Table_map # # table_id: # (test.t2) -master-bin.000002 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000002 # Query # # COMMIT -master-bin.000002 # Rotate # # master-bin.000003;pos= -show binlog events in 'master-bin.000003' from ; -Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000003 # Format_desc # # SERVER_VERSION, BINLOG_VERSION -master-bin.000003 # Binlog_checkpoint # # master-bin.000002 -master-bin.000003 # Query # # BEGIN -master-bin.000003 # Table_map # # table_id: # (test.t1) -master-bin.000003 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000003 # Xid # # COMMIT /* XID */ -master-bin.000003 # Query # # BEGIN -master-bin.000003 # Table_map # # table_id: # (test.t1) -master-bin.000003 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000003 # Xid # # COMMIT /* XID */ -master-bin.000003 # Query # # BEGIN -master-bin.000003 # Table_map # # table_id: # (test.t2) -master-bin.000003 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000003 # Query # # COMMIT -master-bin.000003 # Rotate # # master-bin.00000;pos= -show binlog events in 'master-bin.00000' from ; -Log_name Pos Event_type Server_id End_log_pos Info -master-bin.00000 # Format_desc # # SERVER_VERSION, BINLOG_VERSION -master-bin.00000 # Binlog_checkpoint # # master-bin.000002 -master-bin.00000 # Query # # use `test`; FLUSH TABLES t2 -We should see only one entry here, a=0: -SELECT a FROM t1 ORDER BY a; -a -0 -PURGE BINARY LOGS TO "master-bin.000004"; -show binary logs; -Log_name File_size -master-bin.000002 # -master-bin.000003 # -master-bin.000004 # -SET SESSION debug_dbug="+d,crash_commit_after_log"; -INSERT INTO t1 VALUES (4, NULL); -Got one of the listed errors -SELECT a FROM t1 ORDER BY a; -a -0 -1 -2 -3 -4 -*** Test that RESET MASTER waits for pending XIDs to be unlogged. -SET @old_max_binlog_size= @@global.max_binlog_size; -SET GLOBAL max_binlog_size= 4096; -SET DEBUG_SYNC= "ha_commit_trans_after_log_and_order SIGNAL con10_ready WAIT_FOR con10_go"; -INSERT INTO t1 VALUES (10, NULL); -SET DEBUG_SYNC= "now WAIT_FOR con10_ready"; -INSERT INTO t2 VALUES (10, REPEAT("x", 4100)); -INSERT INTO t2 VALUES (11, REPEAT("x", 4100)); -show binary logs; -Log_name File_size -master-bin.000002 # -master-bin.000003 # -master-bin.000004 # master-bin.000005 # master-bin.000006 # -master-bin.000007 # -SET DEBUG_SYNC= "execute_command_after_close_tables SIGNAL reset_master_done"; -RESET MASTER; -This will timeout, as RESET MASTER is blocked -SET DEBUG_SYNC= "now WAIT_FOR reset_master_done TIMEOUT 1"; -Warnings: -Warning 1639 debug sync point wait timed out -SET DEBUG_SYNC= "now SIGNAL con10_go"; +show binlog events in 'master-bin.000003' from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000003 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +master-bin.000003 # Binlog_checkpoint # # master-bin.000002 +master-bin.000003 # Binlog_checkpoint # # master-bin.000003 +master-bin.000003 # Query # # BEGIN +master-bin.000003 # Table_map # # table_id: # (test.t1) +master-bin.000003 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000003 # Xid # # COMMIT /* XID */ +master-bin.000003 # Rotate # # master-bin.00000;pos= +show binlog events in 'master-bin.00000' from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.00000 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +master-bin.00000 # Binlog_checkpoint # # master-bin.000003 +master-bin.00000 # Binlog_checkpoint # # master-bin.00000 +master-bin.00000 # Query # # BEGIN +master-bin.00000 # Table_map # # table_id: # (test.t1) +master-bin.00000 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.00000 # Xid # # COMMIT /* XID */ +master-bin.00000 # Rotate # # master-bin.000005;pos= +show binlog events in 'master-bin.000005' from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000005 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +master-bin.000005 # Binlog_checkpoint # # master-bin.00000 +master-bin.000005 # Query # # BEGIN +master-bin.000005 # Table_map # # table_id: # (test.t1) +master-bin.000005 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000005 # Xid # # COMMIT /* XID */ +master-bin.000005 # Query # # BEGIN +master-bin.000005 # Table_map # # table_id: # (test.t1) +master-bin.000005 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000005 # Xid # # COMMIT /* XID */ +master-bin.000005 # Rotate # # master-bin.000006;pos= +show binlog events in 'master-bin.000006' from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000006 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +master-bin.000006 # Binlog_checkpoint # # master-bin.00000 +PURGE BINARY LOGS TO "master-bin.000006"; show binary logs; Log_name File_size -master-bin.000001 # -*** Test that binlog N is active, and last pending trx in (N-1) is -unlogged while there is still a pending trx in (N-2). -SET DEBUG_SYNC= "ha_commit_trans_after_log_and_order SIGNAL con10_ready WAIT_FOR con10_continue"; -INSERT INTO t1 VALUES (20, REPEAT("x", 4100)); +master-bin.000004 # +master-bin.000005 # +master-bin.000006 # +SET DEBUG_SYNC= "now SIGNAL con4_cont"; +Got one of the listed errors +SELECT a FROM t1 ORDER BY a; +a +1 +2 +3 +4 +100 +101 +102 +Test that with multiple binlog checkpoints, recovery starts from the last one. +SET GLOBAL max_binlog_size= 4096; +SET GLOBAL innodb_flush_log_at_trx_commit= 1; +RESET MASTER; +SET DEBUG_SYNC= "commit_after_group_release_commit_ordered SIGNAL con10_ready WAIT_FOR con10_cont"; +INSERT INTO t1 VALUES (10, REPEAT("x", 4100)); SET DEBUG_SYNC= "now WAIT_FOR con10_ready"; -INSERT INTO t2 VALUES (3, "force binlog rotation"); -SET DEBUG_SYNC= "ha_commit_trans_after_log_and_order SIGNAL con11_ready WAIT_FOR con11_continue"; -INSERT INTO t1 VALUES (21, REPEAT("x", 4100)); +SET DEBUG_SYNC= "commit_after_group_release_commit_ordered SIGNAL con11_ready WAIT_FOR con11_cont"; +INSERT INTO t1 VALUES (11, REPEAT("x", 4100)); SET DEBUG_SYNC= "now WAIT_FOR con11_ready"; -INSERT INTO t2 VALUES (4, "force binlog rotation"); +SET DEBUG_SYNC= "commit_after_group_release_commit_ordered SIGNAL con12_ready WAIT_FOR con12_cont"; +INSERT INTO t1 VALUES (12, REPEAT("x", 4100)); +SET DEBUG_SYNC= "now WAIT_FOR con12_ready"; +INSERT INTO t1 VALUES (13, NULL); show binary logs; Log_name File_size master-bin.000001 # master-bin.000002 # master-bin.000003 # -show binlog events in 'master-bin.000001' from ; +master-bin.000004 # +show binlog events in 'master-bin.00000' from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Format_desc # # SERVER_VERSION, BINLOG_VERSION -master-bin.000001 # Binlog_checkpoint # # master-bin.000001 -master-bin.000001 # Query # # BEGIN -master-bin.000001 # Table_map # # table_id: # (test.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Xid # # COMMIT /* XID */ -master-bin.000001 # Query # # BEGIN -master-bin.000001 # Table_map # # table_id: # (test.t2) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Query # # COMMIT -master-bin.000001 # Rotate # # master-bin.000002;pos= -show binlog events in 'master-bin.000002' from ; +master-bin.00000 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +master-bin.00000 # Binlog_checkpoint # # master-bin.000001 +master-bin.00000 # Query # # BEGIN +master-bin.00000 # Table_map # # table_id: # (test.t1) +master-bin.00000 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.00000 # Xid # # COMMIT /* XID */ +SET DEBUG_SYNC= "now SIGNAL con10_cont"; +SET DEBUG_SYNC= "now SIGNAL con12_cont"; +SET DEBUG_SYNC= "now SIGNAL con11_cont"; +Checking that master-bin.000004 is the last binlog checkpoint +show binlog events in 'master-bin.00000' from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000002 # Format_desc # # SERVER_VERSION, BINLOG_VERSION -master-bin.000002 # Binlog_checkpoint # # master-bin.000001 -master-bin.000002 # Query # # BEGIN -master-bin.000002 # Table_map # # table_id: # (test.t1) -master-bin.000002 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000002 # Xid # # COMMIT /* XID */ -master-bin.000002 # Query # # BEGIN -master-bin.000002 # Table_map # # table_id: # (test.t2) -master-bin.000002 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000002 # Query # # COMMIT -master-bin.000002 # Rotate # # master-bin.000003;pos= -show binlog events in 'master-bin.000003' from ; +master-bin.00000 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +master-bin.00000 # Binlog_checkpoint # # master-bin.000001 +master-bin.00000 # Query # # BEGIN +master-bin.00000 # Table_map # # table_id: # (test.t1) +master-bin.00000 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.00000 # Xid # # COMMIT /* XID */ +master-bin.00000 # Binlog_checkpoint # # master-bin.000002 +master-bin.00000 # Binlog_checkpoint # # master-bin.00000 +Now crash the server +SET SESSION debug_dbug="+d,crash_commit_after_log"; +INSERT INTO t1 VALUES (14, NULL); +Got one of the listed errors +SELECT a FROM t1 ORDER BY a; +a +1 +2 +3 +4 +10 +11 +12 +13 +14 +100 +101 +102 +*** Check that recovery works if we crashed early during rotate, before +*** binlog checkpoint event could be written. +SET GLOBAL max_binlog_size= 4096; +SET GLOBAL innodb_flush_log_at_trx_commit= 1; +RESET MASTER; +INSERT INTO t1 VALUES (21, REPEAT("x", 4100)); +INSERT INTO t1 VALUES (22, REPEAT("x", 4100)); +INSERT INTO t1 VALUES (23, REPEAT("x", 4100)); +SET SESSION debug_dbug="+d,crash_before_write_checkpoint_event"; +INSERT INTO t1 VALUES (24, REPEAT("x", 4100)); +Got one of the listed errors +SELECT a FROM t1 ORDER BY a; +a +1 +2 +3 +4 +10 +11 +12 +13 +14 +21 +22 +23 +24 +100 +101 +102 +show binary logs; +Log_name File_size +master-bin.000001 # +master-bin.000002 # +master-bin.000003 # +master-bin.000004 # +master-bin.000005 # +show binlog events in 'master-bin.00000' from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000003 # Format_desc # # SERVER_VERSION, BINLOG_VERSION -master-bin.000003 # Binlog_checkpoint # # master-bin.000001 -SET DEBUG_SYNC= "now SIGNAL con11_continue"; -con10 is still pending, no new binlog checkpoint should have been logged. -show binlog events in 'master-bin.000003' from ; -Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000003 # Format_desc # # SERVER_VERSION, BINLOG_VERSION -master-bin.000003 # Binlog_checkpoint # # master-bin.000001 -SET DEBUG_SYNC= "now SIGNAL con10_continue"; -No XIDs are pending, a new binlog checkpoint should have been logged. -show binlog events in 'master-bin.000003' from ; -Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000003 # Format_desc # # SERVER_VERSION, BINLOG_VERSION -master-bin.000003 # Binlog_checkpoint # # master-bin.000001 -master-bin.000003 # Binlog_checkpoint # # master-bin.000003 -DROP TABLE t1, t2; -SET GLOBAL max_binlog_size= @old_max_binlog_size; +master-bin.00000 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +master-bin.00000 # Binlog_checkpoint # # master-bin.000003 +master-bin.00000 # Binlog_checkpoint # # master-bin.00000 +master-bin.00000 # Query # # BEGIN +master-bin.00000 # Table_map # # table_id: # (test.t1) +master-bin.00000 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.00000 # Xid # # COMMIT /* XID */ +master-bin.00000 # Rotate # # master-bin.000005;pos= +DROP TABLE t1; diff --git a/mysql-test/suite/binlog/t/binlog_checkpoint.test b/mysql-test/suite/binlog/t/binlog_checkpoint.test new file mode 100644 index 00000000000..557791c77e5 --- /dev/null +++ b/mysql-test/suite/binlog/t/binlog_checkpoint.test @@ -0,0 +1,108 @@ +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc +--source include/have_binlog_format_row.inc + +SET @old_max_binlog_size= @@global.max_binlog_size; +SET GLOBAL max_binlog_size= 4096; +SET @old_innodb_flush_log_at_trx_commit= @@global.innodb_flush_log_at_trx_commit; +SET GLOBAL innodb_flush_log_at_trx_commit= 1; +RESET MASTER; + +CREATE TABLE t1 (a INT PRIMARY KEY, b MEDIUMTEXT) ENGINE=Innodb; +CREATE TABLE t2 (a INT PRIMARY KEY, b MEDIUMTEXT) ENGINE=Myisam; + +--echo *** Test that RESET MASTER waits for pending commit checkpoints to complete. + +# con1 will hang before doing commit checkpoint, blocking RESET MASTER. +connect(con1,localhost,root,,); +SET DEBUG_SYNC= "commit_after_group_release_commit_ordered SIGNAL con1_ready WAIT_FOR con1_go"; +send INSERT INTO t1 VALUES (1, REPEAT("x", 4100)); + +connection default; +SET DEBUG_SYNC= "now WAIT_FOR con1_ready"; +# Let's add a few binlog rotations just for good measure. +INSERT INTO t2 VALUES (1, REPEAT("x", 4100)); +INSERT INTO t2 VALUES (2, REPEAT("x", 4100)); +--source include/show_binary_logs.inc +--let $binlog_file= master-bin.000004 +--let $binlog_start= 4 +--source include/show_binlog_events.inc +SET DEBUG_SYNC= "execute_command_after_close_tables SIGNAL reset_master_done"; +send RESET MASTER; + +connect(con2,localhost,root,,); +--echo This will timeout, as RESET MASTER is blocked +SET DEBUG_SYNC= "now WAIT_FOR reset_master_done TIMEOUT 1"; +# Wake up transaction to allow RESET MASTER to complete. +SET DEBUG_SYNC= "now SIGNAL con1_go"; + +connection con1; +reap; + +connection default; +reap; +--source include/show_binary_logs.inc +--let $binlog_file= master-bin.000001 +--let $binlog_start= 4 +--source include/show_binlog_events.inc + +--echo *** Test that binlog N is active, and commit checkpoint for (N-1) is +--echo *** done while there is still a pending commit checkpoint for (N-2). + +connection con1; +SET DEBUG_SYNC= "commit_after_group_release_commit_ordered SIGNAL con1_ready WAIT_FOR con1_continue"; +send INSERT INTO t1 VALUES (20, REPEAT("x", 4100)); + +connection default; +SET DEBUG_SYNC= "now WAIT_FOR con1_ready"; + +connection con2; +SET DEBUG_SYNC= "commit_after_group_release_commit_ordered SIGNAL con2_ready WAIT_FOR con2_continue"; +send INSERT INTO t1 VALUES (21, REPEAT("x", 4100)); + +connection default; +SET DEBUG_SYNC= "now WAIT_FOR con2_ready"; +--source include/show_binary_logs.inc +--let $binlog_file= master-bin.000001 +--source include/show_binlog_events.inc +--let $binlog_file= master-bin.000002 +--source include/show_binlog_events.inc +--let $binlog_file= master-bin.000003 +--source include/show_binlog_events.inc + +SET DEBUG_SYNC= "now SIGNAL con2_continue"; + +connection con2; +reap; + +connection default; +--echo con1 is still pending, no new binlog checkpoint should have been logged. +--let $binlog_file= master-bin.000003 +--source include/show_binlog_events.inc + +SET DEBUG_SYNC= "now SIGNAL con1_continue"; + +connection con1; +reap; + +connection default; + +--echo No commit checkpoints are pending, a new binlog checkpoint should have been logged. +--let $binlog_file= master-bin.000003 + +# Wait for the master-bin.000003 binlog checkpoint to appear. +--let $wait_for_all= 0 +--let $show_statement= SHOW BINLOG EVENTS IN "$binlog_file" +--let $field= Info +--let $condition= = "master-bin.000003" +--source include/wait_show_condition.inc + +--source include/show_binlog_events.inc + + +# Cleanup +connection default; +DROP TABLE t1, t2; +SET GLOBAL max_binlog_size= @old_max_binlog_size; +SET GLOBAL innodb_flush_log_at_trx_commit= @old_innodb_flush_log_at_trx_commit; diff --git a/mysql-test/suite/binlog/t/binlog_xa_recover-master.opt b/mysql-test/suite/binlog/t/binlog_xa_recover-master.opt index 425fda95086..3c44f9fad10 100644 --- a/mysql-test/suite/binlog/t/binlog_xa_recover-master.opt +++ b/mysql-test/suite/binlog/t/binlog_xa_recover-master.opt @@ -1 +1 @@ ---skip-stack-trace --skip-core-file +--skip-stack-trace --skip-core-file --loose-debug-dbug=+d,xa_recover_expect_master_bin_000004 diff --git a/mysql-test/suite/binlog/t/binlog_xa_recover.test b/mysql-test/suite/binlog/t/binlog_xa_recover.test index 7a4cc17112e..36b2ddecb4f 100644 --- a/mysql-test/suite/binlog/t/binlog_xa_recover.test +++ b/mysql-test/suite/binlog/t/binlog_xa_recover.test @@ -5,81 +5,191 @@ # Valgrind does not work well with test that crashes the server --source include/not_valgrind.inc +# (We do not need to restore these settings, as we crash the server). SET GLOBAL max_binlog_size= 4096; +SET GLOBAL innodb_flush_log_at_trx_commit= 1; +RESET MASTER; CREATE TABLE t1 (a INT PRIMARY KEY, b MEDIUMTEXT) ENGINE=Innodb; -CREATE TABLE t2 (a INT PRIMARY KEY, b MEDIUMTEXT) ENGINE=Myisam; - -# Transactions are not guaranteed stored durably on disk in the engine until -# they are fsync()ed, which normally happens during commit(). But there is no -# guarantee that they will _not_ be durable, in particular loosing results -# of a write(2) system call normally requires a kernel crash (as opposed to -# just mysqld crash), which is inconvenient to do in a test suite. -# So instead we do an error insert to prevent commit_ordered() from being -# called in the engine - so nothing will be written to disk at all, and crash -# recovery is sure to be needed. -SET @@global.debug_dbug='+d,skip_commit_ordered'; - -INSERT INTO t1 VALUES (0, REPEAT("x", 4100)); +# Insert some data to force a couple binlog rotations (3), so we get some +# normal binlog checkpoints before starting the test. +INSERT INTO t1 VALUES (100, REPEAT("x", 4100)); +INSERT INTO t1 VALUES (101, REPEAT("x", 4100)); +INSERT INTO t1 VALUES (102, REPEAT("x", 4100)); # Now start a bunch of transactions that span multiple binlog # files. Leave then in the state prepared-but-not-committed in the engine # and crash the server. Check that crash recovery is able to recover all # of them. +# +# We use debug_sync to get all the transactions into the prepared state before +# we commit any of them. This is because the prepare step flushes the InnoDB +# redo log - including any commits made before, so recovery would become +# unnecessary, decreasing the value of this test. +# +# We arrange to have con1 with a prepared transaction in master-bin.000004, +# con2 and con3 with a prepared transaction in master-bin.000005, and a new +# empty master-bin.000006. So the latest binlog checkpoint should be +# master-bin.000006. connect(con1,localhost,root,,); -SET DEBUG_SYNC= "ha_commit_trans_after_log_and_order SIGNAL con1_ready WAIT_FOR _ever"; +# First wait after prepare and before write to binlog. +SET DEBUG_SYNC= "ha_commit_trans_before_log_and_order SIGNAL con1_wait WAIT_FOR con1_cont"; +# Then complete InnoDB commit in memory (but not commit checkpoint / write to +# disk), and hang until crash, leaving a transaction to be XA recovered. +SET DEBUG_SYNC= "commit_after_group_release_commit_ordered SIGNAL con1_ready WAIT_FOR _ever"; send INSERT INTO t1 VALUES (1, REPEAT("x", 4100)); connection default; -SET DEBUG_SYNC= "now WAIT_FOR con1_ready"; -INSERT INTO t2 VALUES (1, "force binlog rotation"); +SET DEBUG_SYNC= "now WAIT_FOR con1_wait"; connect(con2,localhost,root,,); -SET DEBUG_SYNC= "ha_commit_trans_after_log_and_order SIGNAL con2_ready WAIT_FOR _ever"; +SET DEBUG_SYNC= "ha_commit_trans_before_log_and_order SIGNAL con2_wait WAIT_FOR con2_cont"; +SET DEBUG_SYNC= "commit_after_group_release_commit_ordered SIGNAL con2_ready WAIT_FOR _ever"; send INSERT INTO t1 VALUES (2, NULL); connection default; -SET DEBUG_SYNC= "now WAIT_FOR con2_ready"; +SET DEBUG_SYNC= "now WAIT_FOR con2_wait"; connect(con3,localhost,root,,); -SET DEBUG_SYNC= "ha_commit_trans_after_log_and_order SIGNAL con3_ready WAIT_FOR _ever"; +SET DEBUG_SYNC= "ha_commit_trans_before_log_and_order SIGNAL con3_wait WAIT_FOR con3_cont"; +SET DEBUG_SYNC= "commit_after_group_release_commit_ordered SIGNAL con3_ready WAIT_FOR _ever"; send INSERT INTO t1 VALUES (3, REPEAT("x", 4100)); + connection default; +SET DEBUG_SYNC= "now WAIT_FOR con3_wait"; + +connect(con4,localhost,root,,); +SET DEBUG_SYNC= "ha_commit_trans_before_log_and_order SIGNAL con4_wait WAIT_FOR con4_cont"; +SET SESSION debug_dbug="+d,crash_commit_after_log"; +send INSERT INTO t1 VALUES (4, NULL); + +connection default; +SET DEBUG_SYNC= "now WAIT_FOR con4_wait"; + +SET DEBUG_SYNC= "now SIGNAL con1_cont"; +SET DEBUG_SYNC= "now WAIT_FOR con1_ready"; +SET DEBUG_SYNC= "now SIGNAL con2_cont"; +SET DEBUG_SYNC= "now WAIT_FOR con2_ready"; +SET DEBUG_SYNC= "now SIGNAL con3_cont"; SET DEBUG_SYNC= "now WAIT_FOR con3_ready"; -INSERT INTO t2 VALUES (2, "force binlog rotation"); -# So we won't get warnings about t2 being crashed. -FLUSH TABLES t2; # Check that everything is committed in binary log. --source include/show_binary_logs.inc ---let $binlog_file= master-bin.000001 ---let $binlog_start= 4 ---source include/show_binlog_events.inc ---let $binlog_file= master-bin.000002 ---source include/show_binlog_events.inc --let $binlog_file= master-bin.000003 +--let $binlog_start= 4 --source include/show_binlog_events.inc --let $binlog_file= master-bin.000004 --source include/show_binlog_events.inc - -# Check that transactions really are not yet committed in engine. -# (This works because of debug_dbug='+d,skip_commit_ordered'). ---echo We should see only one entry here, a=0: -SELECT a FROM t1 ORDER BY a; +--let $binlog_file= master-bin.000005 +--source include/show_binlog_events.inc +--let $binlog_file= master-bin.000006 +--source include/show_binlog_events.inc # Check that server will not purge too much. -PURGE BINARY LOGS TO "master-bin.000004"; +PURGE BINARY LOGS TO "master-bin.000006"; --source include/show_binary_logs.inc # Now crash the server with one more transaction in prepared state. -system echo wait-binlog_xa_recover.test >> $MYSQLTEST_VARDIR/tmp/mysqld.1.expect; +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +wait-binlog_xa_recover.test +EOF +SET DEBUG_SYNC= "now SIGNAL con4_cont"; +connection con4; +--error 2006,2013 +reap; + +--remove_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +restart-group_commit_binlog_pos.test +EOF + +connection default; +--enable_reconnect +--source include/wait_until_connected_again.inc + +# Check that all transactions are recovered. +SELECT a FROM t1 ORDER BY a; + +--echo Test that with multiple binlog checkpoints, recovery starts from the last one. +SET GLOBAL max_binlog_size= 4096; +SET GLOBAL innodb_flush_log_at_trx_commit= 1; +RESET MASTER; + +# Rotate to binlog master-bin.000003 while delaying binlog checkpoints. +# So we get multiple binlog checkpoints in master-bin.000003. +# Then complete the checkpoints, crash, and check that we only scan +# the necessary binlog file (ie. that we use the _last_ checkpoint). + +connect(con10,localhost,root,,); +SET DEBUG_SYNC= "commit_after_group_release_commit_ordered SIGNAL con10_ready WAIT_FOR con10_cont"; +send INSERT INTO t1 VALUES (10, REPEAT("x", 4100)); + +connection default; +SET DEBUG_SYNC= "now WAIT_FOR con10_ready"; + +connect(con11,localhost,root,,); +SET DEBUG_SYNC= "commit_after_group_release_commit_ordered SIGNAL con11_ready WAIT_FOR con11_cont"; +send INSERT INTO t1 VALUES (11, REPEAT("x", 4100)); + +connection default; +SET DEBUG_SYNC= "now WAIT_FOR con11_ready"; + +connect(con12,localhost,root,,); +SET DEBUG_SYNC= "commit_after_group_release_commit_ordered SIGNAL con12_ready WAIT_FOR con12_cont"; +send INSERT INTO t1 VALUES (12, REPEAT("x", 4100)); + +connection default; +SET DEBUG_SYNC= "now WAIT_FOR con12_ready"; +INSERT INTO t1 VALUES (13, NULL); + +--source include/show_binary_logs.inc +--let $binlog_file= master-bin.000004 +--let $binlog_start= 4 +--source include/show_binlog_events.inc + +SET DEBUG_SYNC= "now SIGNAL con10_cont"; +connection con10; +reap; +connection default; +SET DEBUG_SYNC= "now SIGNAL con12_cont"; +connection con12; +reap; +connection default; +SET DEBUG_SYNC= "now SIGNAL con11_cont"; +connection con11; +reap; + +connection default; +# Wait for the last (master-bin.000004) binlog checkpoint to appear. +--let $wait_for_all= 0 +--let $show_statement= SHOW BINLOG EVENTS IN "master-bin.000004" +--let $field= Info +--let $condition= = "master-bin.000004" +--source include/wait_show_condition.inc + +--echo Checking that master-bin.000004 is the last binlog checkpoint +--source include/show_binlog_events.inc + +--echo Now crash the server +# It is not too easy to test XA recovery, as it runs early during server +# startup, before any connections can be made. +# What we do is set a DBUG error insert which will crash if XA recovery +# starts from any other binlog than master-bin.000004 (check the file +# binlog_xa_recover-master.opt). Then we will fail here if XA recovery +# would start from the wrong place. +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +wait-binlog_xa_recover.test +EOF SET SESSION debug_dbug="+d,crash_commit_after_log"; --error 2006,2013 -INSERT INTO t1 VALUES (4, NULL); +INSERT INTO t1 VALUES (14, NULL); -system echo restart-group_commit_binlog_pos.test >> $MYSQLTEST_VARDIR/tmp/mysqld.1.expect; +--remove_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +restart-group_commit_binlog_pos.test +EOF connection default; --enable_reconnect @@ -89,86 +199,41 @@ connection default; SELECT a FROM t1 ORDER BY a; ---echo *** Test that RESET MASTER waits for pending XIDs to be unlogged. +--echo *** Check that recovery works if we crashed early during rotate, before +--echo *** binlog checkpoint event could be written. -SET @old_max_binlog_size= @@global.max_binlog_size; SET GLOBAL max_binlog_size= 4096; -# con10 will hang with a pending XID, blocking RESET MASTER. -connect(con10,localhost,root,,); -SET DEBUG_SYNC= "ha_commit_trans_after_log_and_order SIGNAL con10_ready WAIT_FOR con10_go"; -send INSERT INTO t1 VALUES (10, NULL); +SET GLOBAL innodb_flush_log_at_trx_commit= 1; +RESET MASTER; + +# We need some initial data to reach binlog master-bin.000004. Otherwise +# crash recovery fails due to the error insert used for previous test. +INSERT INTO t1 VALUES (21, REPEAT("x", 4100)); +INSERT INTO t1 VALUES (22, REPEAT("x", 4100)); +INSERT INTO t1 VALUES (23, REPEAT("x", 4100)); +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +wait-binlog_xa_recover.test +EOF +SET SESSION debug_dbug="+d,crash_before_write_checkpoint_event"; +--error 2006,2013 +INSERT INTO t1 VALUES (24, REPEAT("x", 4100)); + +--remove_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +restart-group_commit_binlog_pos.test +EOF + +--enable_reconnect +--source include/wait_until_connected_again.inc + +# Check that all transactions are recovered. +SELECT a FROM t1 ORDER BY a; -connection default; -SET DEBUG_SYNC= "now WAIT_FOR con10_ready"; -# Let's add a few binlog rotations just for good measure. -INSERT INTO t2 VALUES (10, REPEAT("x", 4100)); -INSERT INTO t2 VALUES (11, REPEAT("x", 4100)); --source include/show_binary_logs.inc -SET DEBUG_SYNC= "execute_command_after_close_tables SIGNAL reset_master_done"; -send RESET MASTER; - -connect(con11,localhost,root,,); ---echo This will timeout, as RESET MASTER is blocked -SET DEBUG_SYNC= "now WAIT_FOR reset_master_done TIMEOUT 1"; -# Wake up transaction to allow RESET MASTER to complete. -SET DEBUG_SYNC= "now SIGNAL con10_go"; - -connection con10; -reap; - -connection default; -reap; ---source include/show_binary_logs.inc - - ---echo *** Test that binlog N is active, and last pending trx in (N-1) is ---echo unlogged while there is still a pending trx in (N-2). - -connection con10; -SET DEBUG_SYNC= "ha_commit_trans_after_log_and_order SIGNAL con10_ready WAIT_FOR con10_continue"; -send INSERT INTO t1 VALUES (20, REPEAT("x", 4100)); - -connection default; -SET DEBUG_SYNC= "now WAIT_FOR con10_ready"; -INSERT INTO t2 VALUES (3, "force binlog rotation"); - -connection con11; -SET DEBUG_SYNC= "ha_commit_trans_after_log_and_order SIGNAL con11_ready WAIT_FOR con11_continue"; -send INSERT INTO t1 VALUES (21, REPEAT("x", 4100)); - -connection default; -SET DEBUG_SYNC= "now WAIT_FOR con11_ready"; -INSERT INTO t2 VALUES (4, "force binlog rotation"); ---source include/show_binary_logs.inc ---let $binlog_file= master-bin.000001 +--let $binlog_file= master-bin.000004 +--let $binlog_start= 4 --source include/show_binlog_events.inc ---let $binlog_file= master-bin.000002 ---source include/show_binlog_events.inc ---let $binlog_file= master-bin.000003 ---source include/show_binlog_events.inc - -SET DEBUG_SYNC= "now SIGNAL con11_continue"; - -connection con11; -reap; - -connection default; ---echo con10 is still pending, no new binlog checkpoint should have been logged. ---let $binlog_file= master-bin.000003 ---source include/show_binlog_events.inc - -SET DEBUG_SYNC= "now SIGNAL con10_continue"; - -connection con10; -reap; - -connection default; ---echo No XIDs are pending, a new binlog checkpoint should have been logged. ---let $binlog_file= master-bin.000003 ---source include/show_binlog_events.inc - # Cleanup connection default; -DROP TABLE t1, t2; -SET GLOBAL max_binlog_size= @old_max_binlog_size; +DROP TABLE t1; diff --git a/mysql-test/suite/innodb/r/binlog_consistent.result b/mysql-test/suite/innodb/r/binlog_consistent.result index 68838e8d52b..f0b665b5ac9 100644 --- a/mysql-test/suite/innodb/r/binlog_consistent.result +++ b/mysql-test/suite/innodb/r/binlog_consistent.result @@ -63,15 +63,15 @@ binlog_snapshot_file master-bin.000001 binlog_snapshot_position 945 SHOW MASTER STATUS; File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000002 286 +master-bin.000002 326 COMMIT; SHOW STATUS LIKE 'binlog_snapshot_%'; Variable_name Value binlog_snapshot_file master-bin.000002 -binlog_snapshot_position 286 +binlog_snapshot_position 326 SHOW MASTER STATUS; File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000002 286 +master-bin.000002 326 SHOW BINLOG EVENTS; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 4 Format_desc 1 246 Server ver: #, Binlog ver: # diff --git a/mysql-test/suite/innodb/r/group_commit_binlog_pos.result b/mysql-test/suite/innodb/r/group_commit_binlog_pos.result index 29aa765c1b4..ccf458809d8 100644 --- a/mysql-test/suite/innodb/r/group_commit_binlog_pos.result +++ b/mysql-test/suite/innodb/r/group_commit_binlog_pos.result @@ -1,3 +1,4 @@ +SET GLOBAL innodb_flush_log_at_trx_commit=3; CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=innodb; INSERT INTO t1 VALUES (0); SET DEBUG_SYNC= "commit_after_get_LOCK_log SIGNAL con1_waiting WAIT_FOR con3_queued"; diff --git a/mysql-test/suite/innodb/r/group_commit_binlog_pos_no_optimize_thread.result b/mysql-test/suite/innodb/r/group_commit_binlog_pos_no_optimize_thread.result index 3c3b0709331..44cf2f3979d 100644 --- a/mysql-test/suite/innodb/r/group_commit_binlog_pos_no_optimize_thread.result +++ b/mysql-test/suite/innodb/r/group_commit_binlog_pos_no_optimize_thread.result @@ -1,3 +1,4 @@ +SET GLOBAL innodb_flush_log_at_trx_commit=3; CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=innodb; INSERT INTO t1 VALUES (0); SET DEBUG_SYNC= "commit_after_get_LOCK_log SIGNAL con1_waiting WAIT_FOR con3_queued"; diff --git a/mysql-test/suite/innodb/t/group_commit_binlog_pos.test b/mysql-test/suite/innodb/t/group_commit_binlog_pos.test index 72798a68a1e..213dbc9d3d8 100644 --- a/mysql-test/suite/innodb/t/group_commit_binlog_pos.test +++ b/mysql-test/suite/innodb/t/group_commit_binlog_pos.test @@ -17,6 +17,19 @@ # Test that we get the correct position when we group commit several # transactions together. +# What we really want to test here is what happens when a group of +# transactions get written only partially to disk inside InnoDB before +# the crash. But that is hard to test in mysql-test-run automated +# tests. Instead, we use debug_sync to tightly control when each +# transaction is written to the redo log. And we set +# innodb_flush_log_at_trx_commit=3 so that we can write out +# transactions individually - as with +# innodb_flush_log_at_trx_commit=1, all commits are written together, +# as part of a commit_checkpoint. +# (Note that we do not have to restore innodb_flush_log_at_trx_commit, as +# we crash the server). +SET GLOBAL innodb_flush_log_at_trx_commit=3; + CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=innodb; INSERT INTO t1 VALUES (0); diff --git a/mysql-test/suite/innodb/t/group_commit_binlog_pos_no_optimize_thread.test b/mysql-test/suite/innodb/t/group_commit_binlog_pos_no_optimize_thread.test index e9a234577e2..3ae3c50085d 100644 --- a/mysql-test/suite/innodb/t/group_commit_binlog_pos_no_optimize_thread.test +++ b/mysql-test/suite/innodb/t/group_commit_binlog_pos_no_optimize_thread.test @@ -17,6 +17,19 @@ # Test that we get the correct position when we group commit several # transactions together. +# What we really want to test here is what happens when a group of +# transactions get written only partially to disk inside InnoDB before +# the crash. But that is hard to test in mysql-test-run automated +# tests. Instead, we use debug_sync to tightly control when each +# transaction is written to the redo log. And we set +# innodb_flush_log_at_trx_commit=3 so that we can write out +# transactions individually - as with +# innodb_flush_log_at_trx_commit=1, all commits are written together, +# as part of a commit_checkpoint. +# (Note that we do not have to restore innodb_flush_log_at_trx_commit, as +# we crash the server). +SET GLOBAL innodb_flush_log_at_trx_commit=3; + CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=innodb; INSERT INTO t1 VALUES (0); diff --git a/mysql-test/suite/rpl/r/rpl_checksum.result b/mysql-test/suite/rpl/r/rpl_checksum.result index 9e561908a7b..fb61f159c80 100644 --- a/mysql-test/suite/rpl/r/rpl_checksum.result +++ b/mysql-test/suite/rpl/r/rpl_checksum.result @@ -71,7 +71,7 @@ insert into t1 values (1) /* will not be applied on slave due to simulation */; set @@global.debug_dbug='d,simulate_slave_unaware_checksum'; start slave; include/wait_for_slave_io_error.inc [errno=1236] -Last_IO_Error = 'Got fatal error 1236 from master when reading data from binary log: 'Slave can not handle replication events with the checksum that master is configured to log; the first event 'master-bin.000009' at 286, the last event read from 'master-bin.000010' at 246, the last byte read from 'master-bin.000010' at 246.'' +Last_IO_Error = 'Got fatal error 1236 from master when reading data from binary log: 'Slave can not handle replication events with the checksum that master is configured to log; the first event 'master-bin.000009' at 326, the last event read from 'master-bin.000010' at 246, the last byte read from 'master-bin.000010' at 246.'' select count(*) as zero from t1; zero 0 diff --git a/mysql-test/suite/rpl/r/rpl_insert_delayed,stmt.rdiff b/mysql-test/suite/rpl/r/rpl_insert_delayed,stmt.rdiff index 5e0e7db5b63..44d8a305f61 100644 --- a/mysql-test/suite/rpl/r/rpl_insert_delayed,stmt.rdiff +++ b/mysql-test/suite/rpl/r/rpl_insert_delayed,stmt.rdiff @@ -36,7 +36,7 @@ a 1 On slave -+show binlog events in 'slave-bin.000002' from limit 1,6; ++show binlog events in 'slave-bin.000002' from limit 2,6; +Log_name Pos Event_type Server_id End_log_pos Info +slave-bin.000002 # Query # # BEGIN +slave-bin.000002 # Query # # use `test`; INSERT IGNORE INTO t1 VALUES(1) diff --git a/mysql-test/suite/rpl/r/rpl_mariadb_slave_capability.result b/mysql-test/suite/rpl/r/rpl_mariadb_slave_capability.result index 9af3d4bbfd2..8a068ad8d72 100644 --- a/mysql-test/suite/rpl/r/rpl_mariadb_slave_capability.result +++ b/mysql-test/suite/rpl/r/rpl_mariadb_slave_capability.result @@ -54,7 +54,7 @@ master-bin.000002 # Query # # COMMIT SELECT * FROM t1; a 2 -show relaylog events in 'slave-relay-bin.000005' from limit 4,5; +show relaylog events in 'slave-relay-bin.000005' from limit 5,5; Log_name Pos Event_type Server_id End_log_pos Info slave-relay-bin.000005 # Query # # BEGIN slave-relay-bin.000005 # Query # # # Dummy ev diff --git a/mysql-test/suite/rpl/r/rpl_row_log.result b/mysql-test/suite/rpl/r/rpl_row_log.result index b9be2cd0144..13938762991 100644 --- a/mysql-test/suite/rpl/r/rpl_row_log.result +++ b/mysql-test/suite/rpl/r/rpl_row_log.result @@ -205,6 +205,7 @@ master-bin.000001 # Query # # COMMIT master-bin.000001 # Rotate # # master-bin.000002;pos=4 show binlog events in 'master-bin.000002' from ; Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000002 # Binlog_checkpoint # # master-bin.000002 master-bin.000002 # Query # # use `test`; create table t3 (a int)ENGINE=MyISAM master-bin.000002 # Query # # use `test`; create table t2 (n int)ENGINE=MyISAM master-bin.000002 # Query # # BEGIN @@ -236,6 +237,7 @@ slave-bin.000001 # Query # # use `test`; create table t3 (a int)ENGINE=MyISAM slave-bin.000001 # Rotate # # slave-bin.000002;pos=4 show binlog events in 'slave-bin.000002' from ; Log_name Pos Event_type Server_id End_log_pos Info +slave-bin.000002 # Binlog_checkpoint # # slave-bin.000002 slave-bin.000002 # Query # # use `test`; create table t2 (n int)ENGINE=MyISAM slave-bin.000002 # Query # # BEGIN slave-bin.000002 # Table_map # # table_id: # (test.t2) diff --git a/mysql-test/suite/rpl/r/rpl_row_log_innodb.result b/mysql-test/suite/rpl/r/rpl_row_log_innodb.result index 15aa8f23b55..c9489a3dc66 100644 --- a/mysql-test/suite/rpl/r/rpl_row_log_innodb.result +++ b/mysql-test/suite/rpl/r/rpl_row_log_innodb.result @@ -205,6 +205,7 @@ master-bin.000001 # Xid # # COMMIT /* XID */ master-bin.000001 # Rotate # # master-bin.000002;pos=4 show binlog events in 'master-bin.000002' from ; Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000002 # Binlog_checkpoint # # master-bin.000002 master-bin.000002 # Query # # use `test`; create table t3 (a int)ENGINE=InnoDB master-bin.000002 # Query # # use `test`; create table t2 (n int)ENGINE=InnoDB master-bin.000002 # Query # # BEGIN @@ -236,6 +237,7 @@ slave-bin.000001 # Query # # use `test`; create table t3 (a int)ENGINE=InnoDB slave-bin.000001 # Rotate # # slave-bin.000002;pos=4 show binlog events in 'slave-bin.000002' from ; Log_name Pos Event_type Server_id End_log_pos Info +slave-bin.000002 # Binlog_checkpoint # # slave-bin.000002 slave-bin.000002 # Query # # use `test`; create table t2 (n int)ENGINE=InnoDB slave-bin.000002 # Query # # BEGIN slave-bin.000002 # Table_map # # table_id: # (test.t2) diff --git a/mysql-test/suite/rpl/r/rpl_row_show_relaylog_events.result b/mysql-test/suite/rpl/r/rpl_row_show_relaylog_events.result index 8534bf00711..a6d691f420e 100644 --- a/mysql-test/suite/rpl/r/rpl_row_show_relaylog_events.result +++ b/mysql-test/suite/rpl/r/rpl_row_show_relaylog_events.result @@ -128,14 +128,16 @@ DROP TABLE t1; ******** [master] SHOW BINLOG EVENTS IN ******** show binlog events in 'master-bin.000002' from ; Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000002 # Binlog_checkpoint # # master-bin.000002 master-bin.000002 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ ******** [master] SHOW BINLOG EVENTS IN LIMIT 1 ******** show binlog events in 'master-bin.000002' from limit 1; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000002 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ +master-bin.000002 # Binlog_checkpoint # # master-bin.000002 ******** [master] SHOW BINLOG EVENTS IN LIMIT 1,3 ******** show binlog events in 'master-bin.000002' from limit 1,3; Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000002 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ ******** [master] SHOW BINLOG EVENTS ******** show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info @@ -156,14 +158,16 @@ master-bin.000001 # Rotate # # master-bin.000002;pos=4 ******** [slave] SHOW BINLOG EVENTS IN ******** show binlog events in 'slave-bin.000002' from ; Log_name Pos Event_type Server_id End_log_pos Info +slave-bin.000002 # Binlog_checkpoint # # slave-bin.000002 slave-bin.000002 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ ******** [slave] SHOW BINLOG EVENTS IN LIMIT 1 ******** show binlog events in 'slave-bin.000002' from limit 1; Log_name Pos Event_type Server_id End_log_pos Info -slave-bin.000002 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ +slave-bin.000002 # Binlog_checkpoint # # slave-bin.000002 ******** [slave] SHOW BINLOG EVENTS IN LIMIT 1,3 ******** show binlog events in 'slave-bin.000002' from limit 1,3; Log_name Pos Event_type Server_id End_log_pos Info +slave-bin.000002 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ ******** [slave] SHOW BINLOG EVENTS ******** show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info @@ -186,6 +190,7 @@ show relaylog events in 'slave-relay-bin.000006' from ; Log_name Pos Event_type Server_id End_log_pos Info slave-relay-bin.000006 # Rotate # # master-bin.000002;pos=4 slave-relay-bin.000006 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +slave-relay-bin.000006 # Binlog_checkpoint # # master-bin.000001 slave-relay-bin.000006 # Binlog_checkpoint # # master-bin.000002 slave-relay-bin.000006 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ ******** [slave] SHOW RELAYLOG EVENTS IN LIMIT 1 ******** @@ -196,8 +201,8 @@ slave-relay-bin.000006 # Rotate # # master-bin.000002;pos=4 show relaylog events in 'slave-relay-bin.000006' from limit 1,3; Log_name Pos Event_type Server_id End_log_pos Info slave-relay-bin.000006 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +slave-relay-bin.000006 # Binlog_checkpoint # # master-bin.000001 slave-relay-bin.000006 # Binlog_checkpoint # # master-bin.000002 -slave-relay-bin.000006 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ ******** [slave] SHOW RELAYLOG EVENTS ******** show relaylog events from ; Log_name Pos Event_type Server_id End_log_pos Info diff --git a/mysql-test/suite/rpl/r/rpl_stm_log.result b/mysql-test/suite/rpl/r/rpl_stm_log.result index 3bb3f347a43..ea4fc259b14 100644 --- a/mysql-test/suite/rpl/r/rpl_stm_log.result +++ b/mysql-test/suite/rpl/r/rpl_stm_log.result @@ -205,6 +205,7 @@ master-bin.000001 # Query # # COMMIT master-bin.000001 # Rotate # # master-bin.000002;pos=4 show binlog events in 'master-bin.000002' from ; Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000002 # Binlog_checkpoint # # master-bin.000002 master-bin.000002 # Query # # use `test`; create table t3 (a int)ENGINE=MyISAM master-bin.000002 # Query # # use `test`; create table t2 (n int)ENGINE=MyISAM master-bin.000002 # Query # # BEGIN @@ -235,6 +236,7 @@ slave-bin.000001 # Query # # use `test`; create table t3 (a int)ENGINE=MyISAM slave-bin.000001 # Rotate # # slave-bin.000002;pos=4 show binlog events in 'slave-bin.000002' from ; Log_name Pos Event_type Server_id End_log_pos Info +slave-bin.000002 # Binlog_checkpoint # # slave-bin.000002 slave-bin.000002 # Query # # use `test`; create table t2 (n int)ENGINE=MyISAM slave-bin.000002 # Query # # BEGIN slave-bin.000002 # Query # # use `test`; insert into t2 values (1) diff --git a/mysql-test/suite/rpl/r/rpl_stm_mix_show_relaylog_events.result b/mysql-test/suite/rpl/r/rpl_stm_mix_show_relaylog_events.result index a978c3c900c..2c93a15a7b3 100644 --- a/mysql-test/suite/rpl/r/rpl_stm_mix_show_relaylog_events.result +++ b/mysql-test/suite/rpl/r/rpl_stm_mix_show_relaylog_events.result @@ -113,14 +113,16 @@ DROP TABLE t1; ******** [master] SHOW BINLOG EVENTS IN ******** show binlog events in 'master-bin.000002' from ; Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000002 # Binlog_checkpoint # # master-bin.000002 master-bin.000002 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ ******** [master] SHOW BINLOG EVENTS IN LIMIT 1 ******** show binlog events in 'master-bin.000002' from limit 1; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000002 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ +master-bin.000002 # Binlog_checkpoint # # master-bin.000002 ******** [master] SHOW BINLOG EVENTS IN LIMIT 1,3 ******** show binlog events in 'master-bin.000002' from limit 1,3; Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000002 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ ******** [master] SHOW BINLOG EVENTS ******** show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info @@ -138,14 +140,16 @@ master-bin.000001 # Rotate # # master-bin.000002;pos=4 ******** [slave] SHOW BINLOG EVENTS IN ******** show binlog events in 'slave-bin.000002' from ; Log_name Pos Event_type Server_id End_log_pos Info +slave-bin.000002 # Binlog_checkpoint # # slave-bin.000002 slave-bin.000002 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ ******** [slave] SHOW BINLOG EVENTS IN LIMIT 1 ******** show binlog events in 'slave-bin.000002' from limit 1; Log_name Pos Event_type Server_id End_log_pos Info -slave-bin.000002 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ +slave-bin.000002 # Binlog_checkpoint # # slave-bin.000002 ******** [slave] SHOW BINLOG EVENTS IN LIMIT 1,3 ******** show binlog events in 'slave-bin.000002' from limit 1,3; Log_name Pos Event_type Server_id End_log_pos Info +slave-bin.000002 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ ******** [slave] SHOW BINLOG EVENTS ******** show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info @@ -165,6 +169,7 @@ show relaylog events in 'slave-relay-bin.000006' from ; Log_name Pos Event_type Server_id End_log_pos Info slave-relay-bin.000006 # Rotate # # master-bin.000002;pos=4 slave-relay-bin.000006 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +slave-relay-bin.000006 # Binlog_checkpoint # # master-bin.000001 slave-relay-bin.000006 # Binlog_checkpoint # # master-bin.000002 slave-relay-bin.000006 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ ******** [slave] SHOW RELAYLOG EVENTS IN LIMIT 1 ******** @@ -175,8 +180,8 @@ slave-relay-bin.000006 # Rotate # # master-bin.000002;pos=4 show relaylog events in 'slave-relay-bin.000006' from limit 1,3; Log_name Pos Event_type Server_id End_log_pos Info slave-relay-bin.000006 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +slave-relay-bin.000006 # Binlog_checkpoint # # master-bin.000001 slave-relay-bin.000006 # Binlog_checkpoint # # master-bin.000002 -slave-relay-bin.000006 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ ******** [slave] SHOW RELAYLOG EVENTS ******** show relaylog events from ; Log_name Pos Event_type Server_id End_log_pos Info diff --git a/mysql-test/suite/rpl/t/rpl_mariadb_slave_capability.test b/mysql-test/suite/rpl/t/rpl_mariadb_slave_capability.test index 36f4defa252..251136a2fe1 100644 --- a/mysql-test/suite/rpl/t/rpl_mariadb_slave_capability.test +++ b/mysql-test/suite/rpl/t/rpl_mariadb_slave_capability.test @@ -61,7 +61,7 @@ connection slave; SELECT * FROM t1; let $binlog_file= query_get_value(SHOW SLAVE STATUS, Relay_Log_File, 1); let $binlog_start= 0; -let $binlog_limit=4,5; +let $binlog_limit=5,5; --source include/show_relaylog_events.inc --echo # Test that slave which cannot tolerate holes in binlog stream but diff --git a/mysql-test/suite/sys_vars/r/innodb_flush_log_at_trx_commit_basic.result b/mysql-test/suite/sys_vars/r/innodb_flush_log_at_trx_commit_basic.result index 441fb4cd362..268d40c1be3 100644 --- a/mysql-test/suite/sys_vars/r/innodb_flush_log_at_trx_commit_basic.result +++ b/mysql-test/suite/sys_vars/r/innodb_flush_log_at_trx_commit_basic.result @@ -50,7 +50,7 @@ Warnings: Warning 1292 Truncated incorrect innodb_flush_log_at_trx_commit value: '1001' SELECT @@global.innodb_flush_log_at_trx_commit; @@global.innodb_flush_log_at_trx_commit -2 +3 '#----------------------FN_DYNVARS_046_05------------------------#' SELECT @@global.innodb_flush_log_at_trx_commit = VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES @@ -60,22 +60,22 @@ VARIABLE_VALUE 1 SELECT @@global.innodb_flush_log_at_trx_commit; @@global.innodb_flush_log_at_trx_commit -2 +3 SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME='innodb_flush_log_at_trx_commit'; VARIABLE_VALUE -2 +3 '#---------------------FN_DYNVARS_046_06-------------------------#' SET @@global.innodb_flush_log_at_trx_commit = OFF; ERROR 42000: Incorrect argument type to variable 'innodb_flush_log_at_trx_commit' SELECT @@global.innodb_flush_log_at_trx_commit; @@global.innodb_flush_log_at_trx_commit -2 +3 SET @@global.innodb_flush_log_at_trx_commit = ON; ERROR 42000: Incorrect argument type to variable 'innodb_flush_log_at_trx_commit' SELECT @@global.innodb_flush_log_at_trx_commit; @@global.innodb_flush_log_at_trx_commit -2 +3 '#---------------------FN_DYNVARS_046_07----------------------#' SET @@global.innodb_flush_log_at_trx_commit = TRUE; SELECT @@global.innodb_flush_log_at_trx_commit; diff --git a/sql/handler.cc b/sql/handler.cc index e7eddef55ed..3f201b266f0 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -644,6 +644,43 @@ void ha_checkpoint_state(bool disable) } +struct st_commit_checkpoint_request { + void *cookie; + void (*pre_hook)(void *); +}; + +static my_bool commit_checkpoint_request_handlerton(THD *unused1, plugin_ref plugin, + void *data) +{ + st_commit_checkpoint_request *st= (st_commit_checkpoint_request *)data; + handlerton *hton= plugin_data(plugin, handlerton *); + if (hton->state == SHOW_OPTION_YES && hton->commit_checkpoint_request) + { + void *cookie= st->cookie; + if (st->pre_hook) + (*st->pre_hook)(cookie); + (*hton->commit_checkpoint_request)(hton, cookie); + } + return FALSE; +} + + +/* + Invoke commit_checkpoint_request() in all storage engines that implement it. + + If pre_hook is non-NULL, the hook will be called prior to each invocation. +*/ +void +ha_commit_checkpoint_request(void *cookie, void (*pre_hook)(void *)) +{ + st_commit_checkpoint_request st; + st.cookie= cookie; + st.pre_hook= pre_hook; + plugin_foreach(NULL, commit_checkpoint_request_handlerton, + MYSQL_STORAGE_ENGINE_PLUGIN, &st); +} + + static my_bool closecon_handlerton(THD *thd, plugin_ref plugin, void *unused) @@ -1281,6 +1318,7 @@ int ha_commit_trans(THD *thd, bool all) goto done; } + DEBUG_SYNC(thd, "ha_commit_trans_before_log_and_order"); cookie= tc_log->log_and_order(thd, xid, all, need_prepare_ordered, need_commit_ordered); if (!cookie) @@ -1778,6 +1816,17 @@ bool mysql_xa_recover(THD *thd) DBUG_RETURN(0); } +/* + Called by engine to notify TC that a new commit checkpoint has been reached. + See comments on handlerton method commit_checkpoint_request() for details. +*/ +void +commit_checkpoint_notify_ha(handlerton *hton, void *cookie) +{ + tc_log->commit_checkpoint_notify(cookie); +} + + /** @details This function should be called when MySQL sends rows of a SELECT result set diff --git a/sql/handler.h b/sql/handler.h index 9c0850e157a..b6052412069 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -976,6 +976,46 @@ struct handlerton int (*recover)(handlerton *hton, XID *xid_list, uint len); int (*commit_by_xid)(handlerton *hton, XID *xid); int (*rollback_by_xid)(handlerton *hton, XID *xid); + /* + The commit_checkpoint_request() handlerton method is used to checkpoint + the XA recovery process for storage engines that support two-phase + commit. + + The method is optional - an engine that does not implemented is expected + to work the traditional way, where every commit() durably flushes the + transaction to disk in the engine before completion, so XA recovery will + no longer be needed for that transaction. + + An engine that does implement commit_checkpoint_request() is also + expected to implement commit_ordered(), so that ordering of commits is + consistent between 2pc participants. Such engine is no longer required to + durably flush to disk transactions in commit(), provided that the + transaction has been successfully prepare()d and commit_ordered(); thus + potentionally saving one fsync() call. (Engine must still durably flush + to disk in commit() when no prepare()/commit_ordered() steps took place, + at least if durable commits are wanted; this happens eg. if binlog is + disabled). + + The TC will periodically (eg. once per binlog rotation) call + commit_checkpoint_request(). When this happens, the engine must arrange + for all transaction that have completed commit_ordered() to be durably + flushed to disk (this does not include transactions that might be in the + middle of executing commit_ordered()). When such flush has completed, the + engine must call commit_checkpoint_notify_ha(), passing back the opaque + "cookie". + + The flush and call of commit_checkpoint_notify_ha() need not happen + immediately - it can be scheduled and performed asynchroneously (ie. as + part of next prepare(), or sync every second, or whatever), but should + not be postponed indefinitely. It is however also permissible to do it + immediately, before returning from commit_checkpoint_request(). + + When commit_checkpoint_notify_ha() is called, the TC will know that the + transactions are durably committed, and thus no longer require XA + recovery. It uses that to reduce the work needed for any subsequent XA + recovery process. + */ + void (*commit_checkpoint_request)(handlerton *hton, void *cookie); /* "Disable or enable checkpointing internal to the storage engine. This is used for FLUSH TABLES WITH READ LOCK AND DISABLE CHECKPOINT to ensure that @@ -2977,6 +3017,7 @@ void ha_close_connection(THD* thd); bool ha_flush_logs(handlerton *db_type); void ha_drop_database(char* path); void ha_checkpoint_state(bool disable); +void ha_commit_checkpoint_request(void *cookie, void (*pre_hook)(void *)); int ha_create_table(THD *thd, const char *path, const char *db, const char *table_name, HA_CREATE_INFO *create_info, @@ -3057,6 +3098,7 @@ int ha_binlog_end(THD *thd); const char *get_canonical_filename(handler *file, const char *path, char *tmp_path); bool mysql_xa_recover(THD *thd); +void commit_checkpoint_notify_ha(handlerton *hton, void *cookie); inline const char *table_case_name(HA_CREATE_INFO *info, const char *name) { diff --git a/sql/log.cc b/sql/log.cc index 430f0a0bf60..50c66135f24 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -479,7 +479,14 @@ public: */ bool using_xa; my_xid xa_xid; - ulong cookie; + bool need_unlog; + /* + Id of binlog that transaction was written to; only needed if need_unlog is + true. + */ + ulong binlog_id; + /* Set if we get an error during commit that must be returned from unlog(). */ + bool delayed_error; private: @@ -1678,8 +1685,7 @@ binlog_flush_cache(THD *thd, binlog_cache_mngr *cache_mngr, So there is no work to do. Therefore, we will not increment any XID count, so we must not decrement any XID count in unlog(). */ - if (cache_mngr->using_xa && cache_mngr->xa_xid) - cache_mngr->cookie= BINLOG_COOKIE_DUMMY; + cache_mngr->need_unlog= 0; } cache_mngr->reset(using_stmt, using_trx); @@ -2904,16 +2910,16 @@ const char *MYSQL_LOG::generate_name(const char *log_name, MYSQL_BIN_LOG::MYSQL_BIN_LOG(uint *sync_period) - :current_binlog_id(BINLOG_COOKIE_START), reset_master_pending(false), + :reset_master_pending(false), bytes_written(0), file_id(1), open_count(1), - need_start_event(TRUE), group_commit_queue(0), group_commit_queue_busy(FALSE), num_commits(0), num_group_commits(0), sync_period_ptr(sync_period), sync_counter(0), is_relay_log(0), signal_cnt(0), checksum_alg_reset(BINLOG_CHECKSUM_ALG_UNDEF), relay_log_checksum_alg(BINLOG_CHECKSUM_ALG_UNDEF), - description_event_for_exec(0), description_event_for_queue(0) + description_event_for_exec(0), description_event_for_queue(0), + current_binlog_id(0) { /* We don't want to initialize locks here as such initialization depends on @@ -2963,10 +2969,9 @@ void MYSQL_BIN_LOG::cleanup() /* Init binlog-specific vars */ -void MYSQL_BIN_LOG::init(bool no_auto_events_arg, ulong max_size_arg) +void MYSQL_BIN_LOG::init(ulong max_size_arg) { DBUG_ENTER("MYSQL_BIN_LOG::init"); - no_auto_events= no_auto_events_arg; max_size= max_size_arg; DBUG_PRINT("info",("max_size: %lu", max_size)); DBUG_VOID_RETURN; @@ -3070,12 +3075,12 @@ bool MYSQL_BIN_LOG::open(const char *log_name, enum_log_type log_type_arg, const char *new_name, enum cache_type io_cache_type_arg, - bool no_auto_events_arg, ulong max_size_arg, bool null_created_arg, bool need_mutex) { File file= -1; + xid_count_per_binlog *new_xid_list_entry= NULL, *b; DBUG_ENTER("MYSQL_BIN_LOG::open"); DBUG_PRINT("enter",("log_type: %d",(int) log_type_arg)); @@ -3131,7 +3136,7 @@ bool MYSQL_BIN_LOG::open(const char *log_name, DBUG_RETURN(1); /* all warnings issued */ } - init(no_auto_events_arg, max_size_arg); + init(max_size_arg); open_count++; @@ -3155,11 +3160,10 @@ bool MYSQL_BIN_LOG::open(const char *log_name, write_file_name_to_index_file= 1; } - if (need_start_event && !no_auto_events) { /* - In 4.x we set need_start_event=0 here, but in 5.0 we want a Start event - even if this is not the very first binlog. + In 4.x we put Start event only in the first binlog. But from 5.0 we + want a Start event even if this is not the very first binlog. */ Format_description_log_event s(BINLOG_VERSION); /* @@ -3191,42 +3195,51 @@ bool MYSQL_BIN_LOG::open(const char *log_name, { char buf[FN_REFLEN]; /* - Put this one into the list of active binlogs. + Construct an entry in the binlog_xid_count_list for the new binlog + file (we will not link it into the list until we know the new file + is successfully created; otherwise we would have to remove it again + if creation failed, which gets tricky since other threads may have + seen the entry in the meantime - and we do not want to hold + LOCK_xid_list for long periods of time). + Write the current binlog checkpoint into the log, so XA recovery will know from where to start recovery. */ uint off= dirname_length(log_file_name); uint len= strlen(log_file_name) - off; char *entry_mem, *name_mem; - xid_count_per_binlog *b, *b2; - if (!(b = (xid_count_per_binlog *) + if (!(new_xid_list_entry = (xid_count_per_binlog *) my_multi_malloc(MYF(MY_WME), &entry_mem, sizeof(xid_count_per_binlog), &name_mem, len, NULL))) goto err; memcpy(name_mem, log_file_name+off, len); - b->binlog_name= name_mem; - b->binlog_name_len= len; - b->xid_count= 0; - - mysql_mutex_lock(&LOCK_xid_list); - b->binlog_id= ++current_binlog_id; + new_xid_list_entry->binlog_name= name_mem; + new_xid_list_entry->binlog_name_len= len; + new_xid_list_entry->xid_count= 0; /* - Remove any initial entries with no pending XIDs. - Normally this will be done in unlog(), but if there are no - transactions with an XA-capable engine at all in a given binlog - file, unlog() will never be used and we will remove the entry here. - */ - while ((b2= binlog_xid_count_list.head()) && b2->xid_count == 0) - my_free(binlog_xid_count_list.get()); + Find the name for the Initial binlog checkpoint. - binlog_xid_count_list.push_back(b); - b2= binlog_xid_count_list.head(); - strmake(buf, b2->binlog_name, b2->binlog_name_len); + Normally this will just be the first entry, as we delete entries + when their count drops to zero. But we scan the list to handle any + corner case, eg. for the first binlog file opened after startup, the + list will be empty. + */ + mysql_mutex_lock(&LOCK_xid_list); + I_List_iterator it(binlog_xid_count_list); + while ((b= it++) && b->xid_count == 0) + ; mysql_mutex_unlock(&LOCK_xid_list); + if (!b) + b= new_xid_list_entry; + strmake(buf, b->binlog_name, b->binlog_name_len); Binlog_checkpoint_log_event ev(buf, len); + DBUG_EXECUTE_IF("crash_before_write_checkpoint_event", + flush_io_cache(&log_file); + mysql_file_sync(log_file.file, MYF(MY_WME)); + DBUG_SUICIDE();); if (ev.write(&log_file)) goto err; bytes_written+= ev.data_written; @@ -3302,6 +3315,23 @@ bool MYSQL_BIN_LOG::open(const char *log_name, #endif } } + + if (!is_relay_log) + { + /* + Now the file was created successfully, so we can link in the entry for + the new binlog file in binlog_xid_count_list. + */ + mysql_mutex_lock(&LOCK_xid_list); + ++current_binlog_id; + new_xid_list_entry->binlog_id= current_binlog_id; + /* Remove any initial entries with no pending XIDs. */ + while ((b= binlog_xid_count_list.head()) && b->xid_count == 0) + my_free(binlog_xid_count_list.get()); + binlog_xid_count_list.push_back(new_xid_list_entry); + mysql_mutex_unlock(&LOCK_xid_list); + } + log_state= LOG_OPENED; #ifdef HAVE_REPLICATION @@ -3320,6 +3350,8 @@ err: Turning logging off for the whole duration of the MySQL server process. \ To turn it on again: fix the cause, \ shutdown the MySQL server and restart it.", name, errno); + if (new_xid_list_entry) + my_free(new_xid_list_entry); if (file >= 0) mysql_file_close(file, MYF(0)); close(LOG_CLOSE_INDEX); @@ -3599,12 +3631,40 @@ bool MYSQL_BIN_LOG::reset_logs(THD* thd) if (!is_relay_log) { /* - We are going to nuke all binary log files. - So first wait until all pending binlog checkpoints have completed. + Mark that a RESET MASTER is in progress. + This ensures that a binlog checkpoint will not try to write binlog + checkpoint events, which would be useless (as we are deleting the binlog + anyway) and could deadlock, as we are holding LOCK_log. */ mysql_mutex_lock(&LOCK_xid_list); - xid_count_per_binlog *b; reset_master_pending= true; + mysql_mutex_unlock(&LOCK_xid_list); + + /* + We are going to nuke all binary log files. + Without binlog, we cannot XA recover prepared-but-not-committed + transactions in engines. So force a commit checkpoint first. + + Note that we take and immediately release LOCK_commit_ordered. This has + the effect to ensure that any on-going group commit (in + trx_group_commit_leader()) has completed before we request the checkpoint, + due to the chaining of LOCK_log and LOCK_commit_ordered in that function. + (We are holding LOCK_log, so no new group commit can start). + + Without this, it is possible (though perhaps unlikely) that the RESET + MASTER could run in-between the write to the binlog and the + commit_ordered() in the engine of some transaction, and then a crash + later would leave such transaction not recoverable. + */ + mysql_mutex_lock(&LOCK_commit_ordered); + mysql_mutex_unlock(&LOCK_commit_ordered); + + mark_xids_active(current_binlog_id, 1); + do_checkpoint_request(current_binlog_id); + + /* Now wait for all checkpoint requests and pending unlog() to complete. */ + mysql_mutex_lock(&LOCK_xid_list); + xid_count_per_binlog *b; for (;;) { I_List_iterator it(binlog_xid_count_list); @@ -3626,9 +3686,6 @@ bool MYSQL_BIN_LOG::reset_logs(THD* thd) Now all XIDs are fully flushed to disk, and we are holding LOCK_log so no new ones will be written. So we can proceed to delete the logs. */ - while ((b= binlog_xid_count_list.get())) - my_free(b); - reset_master_pending= false; mysql_mutex_unlock(&LOCK_xid_list); } @@ -3722,10 +3779,8 @@ bool MYSQL_BIN_LOG::reset_logs(THD* thd) goto err; } } - if (!thd->slave_thread) - need_start_event=1; if (!open_index_file(index_file_name, 0, FALSE)) - if ((error= open(save_name, log_type, 0, io_cache_type, no_auto_events, max_size, 0, FALSE))) + if ((error= open(save_name, log_type, 0, io_cache_type, max_size, 0, FALSE))) goto err; my_free((void *) save_name); @@ -3733,6 +3788,31 @@ err: if (error == 1) name= const_cast(save_name); mysql_mutex_unlock(&LOCK_thread_count); + + if (!is_relay_log) + { + xid_count_per_binlog *b; + /* + Remove all entries in the xid_count list except the last. + Normally we will just be deleting all the entries that we waited for to + drop to zero above. But if we fail during RESET MASTER for some reason + then we will not have created any new log file, and we may keep the last + of the old entries. + */ + mysql_mutex_lock(&LOCK_xid_list); + for (;;) + { + b= binlog_xid_count_list.head(); + DBUG_ASSERT(b /* List can never become empty. */); + if (b->binlog_id == current_binlog_id) + break; + DBUG_ASSERT(b->xid_count == 0); + my_free(binlog_xid_count_list.get()); + } + reset_master_pending= false; + mysql_mutex_unlock(&LOCK_xid_list); + } + mysql_mutex_unlock(&LOCK_index); mysql_mutex_unlock(&LOCK_log); DBUG_RETURN(error); @@ -4476,7 +4556,6 @@ int MYSQL_BIN_LOG::new_file_impl(bool need_lock) if (log_type == LOG_BIN) { - if (!no_auto_events) { /* We log the whole file name for log file as the user may decide @@ -4551,7 +4630,7 @@ int MYSQL_BIN_LOG::new_file_impl(bool need_lock) /* reopen the binary log file. */ file_to_open= new_name_ptr; error= open(old_name, log_type, new_name_ptr, io_cache_type, - no_auto_events, max_size, 1, FALSE); + max_size, 1, FALSE); } /* handle reopening errors */ @@ -5176,6 +5255,8 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info, my_bool *with_annotate) bool is_trans_cache= FALSE; bool using_trans= event_info->use_trans_cache(); bool direct= event_info->use_direct_logging(); + ulong prev_binlog_id; + LINT_INIT(prev_binlog_id); if (thd->binlog_evt_union.do_union) { @@ -5227,6 +5308,7 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info, my_bool *with_annotate) file= &log_file; my_org_b_tell= my_b_tell(file); mysql_mutex_lock(&LOCK_log); + prev_binlog_id= current_binlog_id; } else { @@ -5372,7 +5454,7 @@ err: mysql_mutex_unlock(&LOCK_log); if (check_purge) - purge(); + checkpoint_and_purge(prev_binlog_id); } if (error) @@ -5457,6 +5539,64 @@ bool general_log_write(THD *thd, enum enum_server_command command, return FALSE; } + +/* + I would like to make this function static, but this causes compiler warnings + when it is declared as friend function in log.h. +*/ +void +binlog_checkpoint_callback(void *cookie) +{ + MYSQL_BIN_LOG::xid_count_per_binlog *entry= + (MYSQL_BIN_LOG::xid_count_per_binlog *)cookie; + /* + For every supporting engine, we increment the xid_count and issue a + commit_checkpoint_request(). Then we can count when all + commit_checkpoint_notify() callbacks have occured, and then log a new + binlog checkpoint event. + */ + mysql_bin_log.mark_xids_active(entry->binlog_id, 1); +} + + +/* + Request a commit checkpoint from each supporting engine. + This must be called after each binlog rotate, and after LOCK_log has been + released. The xid_count value in the xid_count_per_binlog entry was + incremented by 1 and will be decremented in this function; this ensures + that the entry will not go away early despite LOCK_log not being held. +*/ +void +MYSQL_BIN_LOG::do_checkpoint_request(ulong binlog_id) +{ + xid_count_per_binlog *entry; + + /* + Find the binlog entry, and invoke commit_checkpoint_request() on it in + each supporting storage engine. + */ + mysql_mutex_lock(&LOCK_xid_list); + I_List_iterator it(binlog_xid_count_list); + do { + entry= it++; + DBUG_ASSERT(entry /* binlog_id is always somewhere in the list. */); + } while (entry->binlog_id != binlog_id); + mysql_mutex_unlock(&LOCK_xid_list); + + ha_commit_checkpoint_request(entry, binlog_checkpoint_callback); + /* + When we rotated the binlog, we incremented xid_count to make sure the + entry would not go away until this point, where we have done all necessary + commit_checkpoint_request() calls. + So now we can (and must) decrease the count - when it reaches zero, we + will know that both all pending unlog() and all pending + commit_checkpoint_notify() calls are done, and we can log a new binlog + checkpoint. + */ + mark_xid_done(binlog_id, true); +} + + /** The method executes rotation when LOCK_log is already acquired by the caller. @@ -5464,6 +5604,15 @@ bool general_log_write(THD *thd, enum enum_server_command command, @param force_rotate caller can request the log rotation @param check_purge is set to true if rotation took place + @note + Caller _must_ check the check_purge variable. If this is set, it means + that the binlog was rotated, and caller _must_ ensure that + do_checkpoint_request() is called later with the binlog_id of the rotated + binlog file. The call to do_checkpoint_request() must happen after + LOCK_log is released (which is why we cannot simply do it here). + Usually, checkpoint_and_purge() is appropriate, as it will both handle + the checkpointing and any needed purging of old logs. + @note If rotation fails, for instance the server was unable to create a new log file, we still try to write an @@ -5482,7 +5631,27 @@ int MYSQL_BIN_LOG::rotate(bool force_rotate, bool* check_purge) if (force_rotate || (my_b_tell(&log_file) >= (my_off_t) max_size)) { + ulong binlog_id= current_binlog_id; + /* + We rotate the binlog, so we need to start a commit checkpoint in all + supporting engines - when it finishes, we can log a new binlog checkpoint + event. + + But we cannot start the checkpoint here - there could be a group commit + still in progress which needs to be included in the checkpoint, and + besides we do not want to do the (possibly expensive) checkpoint while + LOCK_log is held. + + On the other hand, we must be sure that the xid_count entry for the + previous log does not go away until we start the checkpoint - which it + could do as it is no longer the most recent. So we increment xid_count + (to count the pending checkpoint request) - this will fix the entry in + place until we decrement again in do_checkpoint_request(). + */ + mark_xids_active(binlog_id, 1); + if ((error= new_file_without_locking())) + { /** Be conservative... There are possible lost events (eg, failing to log the Execute_load_query_log_event @@ -5495,7 +5664,14 @@ int MYSQL_BIN_LOG::rotate(bool force_rotate, bool* check_purge) if (!write_incident_already_locked(current_thd)) flush_and_sync(0); - *check_purge= true; + /* + We failed to rotate - so we have to decrement the xid_count back that + we incremented before attempting the rotate. + */ + mark_xid_done(binlog_id, false); + } + else + *check_purge= true; } DBUG_RETURN(error); } @@ -5523,6 +5699,13 @@ void MYSQL_BIN_LOG::purge() #endif } + +void MYSQL_BIN_LOG::checkpoint_and_purge(ulong binlog_id) +{ + do_checkpoint_request(binlog_id); + purge(); +} + /** The method is a shortcut of @c rotate() and @c purge(). LOCK_log is acquired prior to rotate and is released after it. @@ -5535,11 +5718,13 @@ void MYSQL_BIN_LOG::purge() int MYSQL_BIN_LOG::rotate_and_purge(bool force_rotate) { int error= 0; + ulong prev_binlog_id; DBUG_ENTER("MYSQL_BIN_LOG::rotate_and_purge"); bool check_purge= false; //todo: fix the macro def and restore safe_mutex_assert_not_owner(&LOCK_log); mysql_mutex_lock(&LOCK_log); + prev_binlog_id= current_binlog_id; if ((error= rotate(force_rotate, &check_purge))) check_purge= false; /* @@ -5549,7 +5734,7 @@ int MYSQL_BIN_LOG::rotate_and_purge(bool force_rotate) mysql_mutex_unlock(&LOCK_log); if (check_purge) - purge(); + checkpoint_and_purge(prev_binlog_id); DBUG_RETURN(error); } @@ -5880,11 +6065,13 @@ bool MYSQL_BIN_LOG::write_incident(THD *thd) uint error= 0; my_off_t offset; bool check_purge= false; + ulong prev_binlog_id; DBUG_ENTER("MYSQL_BIN_LOG::write_incident"); mysql_mutex_lock(&LOCK_log); if (likely(is_open())) { + prev_binlog_id= current_binlog_id; if (!(error= write_incident_already_locked(thd)) && !(error= flush_and_sync(0))) { @@ -5904,7 +6091,7 @@ bool MYSQL_BIN_LOG::write_incident(THD *thd) mysql_mutex_unlock(&LOCK_log); if (check_purge) - purge(); + checkpoint_and_purge(prev_binlog_id); } DBUG_RETURN(error); @@ -5914,6 +6101,7 @@ void MYSQL_BIN_LOG::write_binlog_checkpoint_event_already_locked(const char *name, uint len) { + my_off_t offset; Binlog_checkpoint_log_event ev(name, len); /* Note that we must sync the binlog checkpoint to disk. @@ -5922,22 +6110,29 @@ MYSQL_BIN_LOG::write_binlog_checkpoint_event_already_locked(const char *name, */ if (!ev.write(&log_file) && !flush_and_sync(0)) { - bool check_purge= false; signal_update(); - rotate(false, &check_purge); - if (check_purge) - purge(); - return; + } + else + { + /* + If we fail to write the checkpoint event, something is probably really + bad with the binlog. We complain in the error log. + + Note that failure to write binlog checkpoint does not compromise the + ability to do crash recovery - crash recovery will just have to scan a + bit more of the binlog than strictly necessary. + */ + sql_print_error("Failed to write binlog checkpoint event to binary log\n"); } + offset= my_b_tell(&log_file); /* - If we fail to write the checkpoint event, something is probably really - bad with the binlog. We complain in the error log. - Note that failure to write binlog checkpoint does not compromise the - ability to do crash recovery - crash recovery will just have to scan a - bit more of the binlog than strictly necessary. + Take mutex to protect against a reader seeing partial writes of 64-bit + offset on 32-bit CPUs. */ - sql_print_error("Failed to write binlog checkpoint event to binary log\n"); + mysql_mutex_lock(&LOCK_commit_ordered); + last_commit_pos_offset= offset; + mysql_mutex_unlock(&LOCK_commit_ordered); } @@ -5973,6 +6168,7 @@ MYSQL_BIN_LOG::write_transaction_to_binlog(THD *thd, bool using_trx_cache) { group_commit_entry entry; + Ha_trx_info *ha_info; DBUG_ENTER("MYSQL_BIN_LOG::write_transaction_to_binlog"); entry.thd= thd; @@ -5981,6 +6177,15 @@ MYSQL_BIN_LOG::write_transaction_to_binlog(THD *thd, entry.all= all; entry.using_stmt_cache= using_stmt_cache; entry.using_trx_cache= using_trx_cache; + entry.need_unlog= false; + ha_info= all ? thd->transaction.all.ha_list : thd->transaction.stmt.ha_list; + for (; ha_info; ha_info= ha_info->next()) + { + if (ha_info->is_started() && ha_info->ht() != binlog_hton && + !ha_info->ht()->commit_checkpoint_request) + entry.need_unlog= true; + break; + } /* Log "BEGIN" at the beginning of every transaction. Here, a transaction is @@ -6069,6 +6274,18 @@ MYSQL_BIN_LOG::write_transaction_to_binlog_events(group_commit_entry *entry) { next->thd->signal_wakeup_ready(); } + else + { + /* + If we rotated the binlog, and if we are using the unoptimized thread + scheduling where every thread runs its own commit_ordered(), then we + must do the commit checkpoint and log purge here, after all + commit_ordered() calls have finished, and locks have been released. + */ + if (entry->check_purge) + checkpoint_and_purge(entry->binlog_id); + } + } if (likely(!entry->error)) @@ -6099,8 +6316,9 @@ MYSQL_BIN_LOG::write_transaction_to_binlog_events(group_commit_entry *entry) we need to mark it as not needed for recovery (unlog() is not called for a transaction if log_xid() fails). */ - if (entry->cache_mngr->using_xa && entry->cache_mngr->xa_xid) - mark_xid_done(entry->cache_mngr->cookie); + if (entry->cache_mngr->using_xa && entry->cache_mngr->xa_xid && + entry->cache_mngr->need_unlog) + mark_xid_done(entry->cache_mngr->binlog_id, true); return 1; } @@ -6120,10 +6338,12 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader) { uint xid_count= 0; my_off_t UNINIT_VAR(commit_offset); - group_commit_entry *current; + group_commit_entry *current, *last_in_queue; group_commit_entry *queue= NULL; bool check_purge= false; + ulong binlog_id; DBUG_ENTER("MYSQL_BIN_LOG::trx_group_commit_leader"); + LINT_INIT(binlog_id); DBUG_ASSERT(is_open()); if (likely(is_open())) // Should always be true @@ -6134,6 +6354,7 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader) */ mysql_mutex_lock(&LOCK_log); DEBUG_SYNC(leader->thd, "commit_after_get_LOCK_log"); + binlog_id= current_binlog_id; mysql_mutex_lock(&LOCK_prepare_ordered); current= group_commit_queue; @@ -6141,6 +6362,7 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader) mysql_mutex_unlock(&LOCK_prepare_ordered); /* As the queue is in reverse order of entering, reverse it. */ + last_in_queue= current; while (current) { group_commit_entry *next= current->next; @@ -6180,8 +6402,22 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader) cache_mngr->last_commit_pos_offset= commit_offset; if (cache_mngr->using_xa && cache_mngr->xa_xid) { - xid_count++; - cache_mngr->cookie= current_binlog_id; + /* + If all storage engines support commit_checkpoint_request(), then we + do not need to keep track of when this XID is durably committed. + Instead we will just ask the storage engine to durably commit all its + XIDs when we rotate a binlog file. + */ + if (current->need_unlog) + { + xid_count++; + cache_mngr->need_unlog= true; + cache_mngr->binlog_id= binlog_id; + } + else + cache_mngr->need_unlog= false; + + cache_mngr->delayed_error= false; } } @@ -6232,21 +6468,27 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader) */ if (xid_count > 0) { - mark_xids_active(current_binlog_id, xid_count); + mark_xids_active(binlog_id, xid_count); } - else + + if (rotate(false, &check_purge)) { - if (rotate(false, &check_purge)) - { - /* - If we fail to rotate, which thread should get the error? - We give the error to the leader, as any my_error() thrown inside - rotate() will have been registered for the leader THD. - */ - leader->error= ER_ERROR_ON_WRITE; - leader->commit_errno= errno; - check_purge= false; - } + /* + If we fail to rotate, which thread should get the error? + We give the error to the leader, as any my_error() thrown inside + rotate() will have been registered for the leader THD. + + However we must not return error from here - that would cause + ha_commit_trans() to abort and rollback the transaction, which would + leave an inconsistent state with the transaction committed in the + binlog but rolled back in the engine. + + Instead set a flag so that we can return error later, from unlog(), + when the transaction has been safely committed in the engine. + */ + leader->cache_mngr->delayed_error= true; + my_error(ER_ERROR_ON_WRITE, MYF(ME_NOREFRESH), name, errno); + check_purge= false; } } @@ -6278,6 +6520,15 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader) mysql_cond_wait(&COND_queue_busy, &LOCK_commit_ordered); group_commit_queue_busy= TRUE; + /* + Set these so parent can run checkpoint_and_purge() in last thread. + (When using optimized thread scheduling, we run checkpoint_and_purge() + in this function, so parent does not need to and we need not set these + values). + */ + last_in_queue->check_purge= check_purge; + last_in_queue->binlog_id= binlog_id; + /* Note that we return with LOCK_commit_ordered locked! */ DBUG_VOID_RETURN; } @@ -6308,9 +6559,10 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader) } DEBUG_SYNC(leader->thd, "commit_after_group_run_commit_ordered"); mysql_mutex_unlock(&LOCK_commit_ordered); + DEBUG_SYNC(leader->thd, "commit_after_group_release_commit_ordered"); if (check_purge) - purge(); + checkpoint_and_purge(binlog_id); DBUG_VOID_RETURN; } @@ -6470,7 +6722,7 @@ void MYSQL_BIN_LOG::close(uint exiting) if (log_state == LOG_OPENED) { #ifdef HAVE_REPLICATION - if (log_type == LOG_BIN && !no_auto_events && + if (log_type == LOG_BIN && (exiting & LOG_CLOSE_STOP_EVENT)) { Stop_log_event s; @@ -7104,6 +7356,8 @@ int TC_LOG_MMAP::open(const char *opt_name) mysql_mutex_init(key_LOCK_sync, &LOCK_sync, MY_MUTEX_INIT_FAST); mysql_mutex_init(key_LOCK_active, &LOCK_active, MY_MUTEX_INIT_FAST); mysql_mutex_init(key_LOCK_pool, &LOCK_pool, MY_MUTEX_INIT_FAST); + mysql_mutex_init(key_LOCK_pending_checkpoint, &LOCK_pending_checkpoint, + MY_MUTEX_INIT_FAST); mysql_cond_init(key_COND_active, &COND_active, 0); mysql_cond_init(key_COND_pool, &COND_pool, 0); mysql_cond_init(key_TC_LOG_MMAP_COND_queue_busy, &COND_queue_busy, 0); @@ -7356,17 +7610,93 @@ int TC_LOG_MMAP::sync() return err; } +static void +mmap_do_checkpoint_callback(void *data) +{ + TC_LOG_MMAP::pending_cookies *pending= + static_cast(data); + ++pending->pending_count; +} + +int TC_LOG_MMAP::unlog(ulong cookie, my_xid xid) +{ + pending_cookies *full_buffer= NULL; + DBUG_ASSERT(*(my_xid *)(data+cookie) == xid); + + /* + Do not delete the entry immediately, as there may be participating storage + engines which implement commit_checkpoint_request(), and thus have not yet + flushed the commit durably to disk. + + Instead put it in a queue - and periodically, we will request a checkpoint + from all engines and delete a whole batch at once. + */ + mysql_mutex_lock(&LOCK_pending_checkpoint); + if (pending_checkpoint == NULL) + { + uint32 size= sizeof(*pending_checkpoint); + if (!(pending_checkpoint= + (pending_cookies *)my_malloc(size, MYF(MY_ZEROFILL)))) + { + my_error(ER_OUTOFMEMORY, MYF(0), size); + mysql_mutex_unlock(&LOCK_pending_checkpoint); + return 1; + } + } + + pending_checkpoint->cookies[pending_checkpoint->count++]= cookie; + if (pending_checkpoint->count == sizeof(pending_checkpoint->cookies) / + sizeof(pending_checkpoint->cookies[0])) + { + full_buffer= pending_checkpoint; + pending_checkpoint= NULL; + } + mysql_mutex_unlock(&LOCK_pending_checkpoint); + + if (full_buffer) + { + /* + We do an extra increment and notify here - this ensures that + things work also if there are no engines at all that support + commit_checkpoint_request. + */ + ++full_buffer->pending_count; + ha_commit_checkpoint_request(full_buffer, mmap_do_checkpoint_callback); + commit_checkpoint_notify(full_buffer); + } + return 0; +} + + +void +TC_LOG_MMAP::commit_checkpoint_notify(void *cookie) +{ + uint count; + pending_cookies *pending= static_cast(cookie); + mysql_mutex_lock(&LOCK_pending_checkpoint); + DBUG_ASSERT(pending->pending_count > 0); + count= --pending->pending_count; + mysql_mutex_unlock(&LOCK_pending_checkpoint); + if (count == 0) + { + uint i; + for (i= 0; i < sizeof(pending->cookies)/sizeof(pending->cookies[0]); ++i) + delete_entry(pending->cookies[i]); + my_free(pending); + } +} + + /** erase xid from the page, update page free space counters/pointers. cookie points directly to the memory where xid was logged. */ -int TC_LOG_MMAP::unlog(ulong cookie, my_xid xid) +int TC_LOG_MMAP::delete_entry(ulong cookie) { PAGE *p=pages+(cookie/tc_log_page_size); my_xid *x=(my_xid *)(data+cookie); - DBUG_ASSERT(*x == xid); DBUG_ASSERT(x >= p->start && x < p->end); mysql_mutex_lock(&p->lock); @@ -7390,6 +7720,7 @@ void TC_LOG_MMAP::close() mysql_mutex_destroy(&LOCK_sync); mysql_mutex_destroy(&LOCK_active); mysql_mutex_destroy(&LOCK_pool); + mysql_mutex_destroy(&LOCK_pending_checkpoint); mysql_cond_destroy(&COND_pool); mysql_cond_destroy(&COND_active); mysql_cond_destroy(&COND_queue_busy); @@ -7412,9 +7743,12 @@ void TC_LOG_MMAP::close() } if (inited>=5) // cannot do in the switch because of Windows mysql_file_delete(key_file_tclog, logname, MYF(MY_WME)); + if (pending_checkpoint) + my_free(pending_checkpoint); inited=0; } + int TC_LOG_MMAP::recover() { HASH xids; @@ -7518,7 +7852,7 @@ int TC_LOG_BINLOG::open(const char *opt_name) if (using_heuristic_recover()) { /* generate a new binlog to mask a corrupted one */ - open(opt_name, LOG_BIN, 0, WRITE_CACHE, 0, max_binlog_size, 0, TRUE); + open(opt_name, LOG_BIN, 0, WRITE_CACHE, max_binlog_size, 0, TRUE); cleanup(); return 1; } @@ -7606,9 +7940,6 @@ TC_LOG_BINLOG::log_and_order(THD *thd, my_xid xid, bool all, cache_mngr->using_xa= TRUE; cache_mngr->xa_xid= xid; -#ifndef DBUG_OFF - cache_mngr->cookie= 0; -#endif err= binlog_commit_flush_xid_caches(thd, cache_mngr, all, xid); DEBUG_SYNC(thd, "binlog_after_log_and_order"); @@ -7619,10 +7950,11 @@ TC_LOG_BINLOG::log_and_order(THD *thd, my_xid xid, bool all, If using explicit user XA, we will not have XID. We must still return a non-zero cookie (as zero cookie signals error). */ - if (!xid) - DBUG_RETURN(BINLOG_COOKIE_DUMMY); - DBUG_ASSERT(cache_mngr->cookie != 0); - DBUG_RETURN(cache_mngr->cookie); + if (!xid || !cache_mngr->need_unlog) + DBUG_RETURN(BINLOG_COOKIE_DUMMY(cache_mngr->delayed_error)); + else + DBUG_RETURN(BINLOG_COOKIE_MAKE(cache_mngr->binlog_id, + cache_mngr->delayed_error)); } /* @@ -7637,19 +7969,18 @@ TC_LOG_BINLOG::log_and_order(THD *thd, my_xid xid, bool all, binary log. */ void -TC_LOG_BINLOG::mark_xids_active(ulong cookie, uint xid_count) +TC_LOG_BINLOG::mark_xids_active(ulong binlog_id, uint xid_count) { xid_count_per_binlog *b; DBUG_ENTER("TC_LOG_BINLOG::mark_xids_active"); - DBUG_PRINT("info", ("cookie=%lu xid_count=%u", cookie, xid_count)); - DBUG_ASSERT(cookie != 0 && cookie != BINLOG_COOKIE_DUMMY); + DBUG_PRINT("info", ("binlog_id=%lu xid_count=%u", binlog_id, xid_count)); mysql_mutex_lock(&LOCK_xid_list); I_List_iterator it(binlog_xid_count_list); while ((b= it++)) { - if (b->binlog_id == cookie) + if (b->binlog_id == binlog_id) { b->xid_count += xid_count; break; @@ -7675,15 +8006,13 @@ TC_LOG_BINLOG::mark_xids_active(ulong cookie, uint xid_count) checkpoint. */ void -TC_LOG_BINLOG::mark_xid_done(ulong cookie) +TC_LOG_BINLOG::mark_xid_done(ulong binlog_id, bool write_checkpoint) { xid_count_per_binlog *b; bool first; ulong current; DBUG_ENTER("TC_LOG_BINLOG::mark_xid_done"); - if (cookie == BINLOG_COOKIE_DUMMY) - DBUG_VOID_RETURN; /* Nothing to do. */ mysql_mutex_lock(&LOCK_xid_list); current= current_binlog_id; @@ -7691,7 +8020,7 @@ TC_LOG_BINLOG::mark_xid_done(ulong cookie) first= true; while ((b= it++)) { - if (b->binlog_id == cookie) + if (b->binlog_id == binlog_id) { --b->xid_count; break; @@ -7700,8 +8029,22 @@ TC_LOG_BINLOG::mark_xid_done(ulong cookie) } /* Binlog is always found, as we do not remove until count reaches 0 */ DBUG_ASSERT(b); - if (likely(cookie == current && !reset_master_pending) || - b->xid_count != 0 || !first) + /* + If a RESET MASTER is pending, we are about to remove all log files, and + the RESET MASTER thread is waiting for all pending unlog() calls to + complete while holding LOCK_log. In this case we should not log a binlog + checkpoint event (it would be deleted immediately anyway and we would + deadlock on LOCK_log) but just signal the thread. + */ + if (unlikely(reset_master_pending)) + { + mysql_cond_signal(&COND_xid_list); + mysql_mutex_unlock(&LOCK_xid_list); + DBUG_VOID_RETURN; + } + + if (likely(binlog_id == current) || b->xid_count != 0 || !first || + !write_checkpoint) { /* No new binlog checkpoint reached yet. */ mysql_mutex_unlock(&LOCK_xid_list); @@ -7726,40 +8069,27 @@ TC_LOG_BINLOG::mark_xid_done(ulong cookie) LOCK_log, then re-aquire LOCK_xid_list. If we were to take LOCK_log while holding LOCK_xid_list, we might deadlock with other threads that take the locks in the opposite order. - - If a RESET MASTER is pending, we are about to remove all log files, and - the RESET MASTER thread is waiting for all pending unlog() calls to - complete while holding LOCK_log. In this case we should not log a binlog - checkpoint event (it would be deleted immediately anywat and we would - deadlock on LOCK_log) but just signal the thread. */ - if (!reset_master_pending) - { - mysql_mutex_unlock(&LOCK_xid_list); - mysql_mutex_lock(&LOCK_log); - mysql_mutex_lock(&LOCK_xid_list); - } + + mysql_mutex_unlock(&LOCK_xid_list); + mysql_mutex_lock(&LOCK_log); + mysql_mutex_lock(&LOCK_xid_list); + /* We need to reload current_binlog_id due to release/re-take of lock. */ + current= current_binlog_id; + for (;;) { /* Remove initial element(s) with zero count. */ b= binlog_xid_count_list.head(); /* - Normally, we must not remove all elements in the list. - Only if a RESET MASTER is in progress may we delete everything - RESET - MASTER has LOCK_log held, and will create a new initial element before - releasing the lock. + We must not remove all elements in the list - the entry for the current + binlog must be present always. */ - DBUG_ASSERT(b || reset_master_pending); - if (unlikely(!b) || b->binlog_id == current || b->xid_count > 0) + DBUG_ASSERT(b); + if (b->binlog_id == current || b->xid_count > 0) break; my_free(binlog_xid_count_list.get()); } - if (reset_master_pending) - { - mysql_cond_signal(&COND_xid_list); - mysql_mutex_unlock(&LOCK_xid_list); - DBUG_VOID_RETURN; - } mysql_mutex_unlock(&LOCK_xid_list); write_binlog_checkpoint_event_already_locked(b->binlog_name, @@ -7771,10 +8101,22 @@ TC_LOG_BINLOG::mark_xid_done(ulong cookie) int TC_LOG_BINLOG::unlog(ulong cookie, my_xid xid) { DBUG_ENTER("TC_LOG_BINLOG::unlog"); - if (xid) - mark_xid_done(cookie); - /* As ::write_transaction_to_binlog() did not rotate, do it here. */ - DBUG_RETURN(rotate_and_purge(0)); + if (!xid) + DBUG_RETURN(0); + + if (!BINLOG_COOKIE_IS_DUMMY(cookie)) + mark_xid_done(BINLOG_COOKIE_GET_ID(cookie), true); + /* + See comment in trx_group_commit_leader() - if rotate() gave a failure, + we delay the return of error code to here. + */ + DBUG_RETURN(BINLOG_COOKIE_GET_ERROR_FLAG(cookie)); +} + +void +TC_LOG_BINLOG::commit_checkpoint_notify(void *cookie) +{ + mark_xid_done(((xid_count_per_binlog *)cookie)->binlog_id, true); } int TC_LOG_BINLOG::recover(LOG_INFO *linfo, const char *last_log_name, @@ -7871,6 +8213,11 @@ int TC_LOG_BINLOG::recover(LOG_INFO *linfo, const char *last_log_name, if (!binlog_checkpoint_found) break; first_round= false; + DBUG_EXECUTE_IF("xa_recover_expect_master_bin_000004", + if (0 != strcmp("./master-bin.000004", binlog_checkpoint_name) && + 0 != strcmp(".\\master-bin.000004", binlog_checkpoint_name)) + DBUG_SUICIDE(); + ); if (find_log_pos(linfo, binlog_checkpoint_name, 1)) { sql_print_error("Binlog file '%s' not found in binlog index, needed " @@ -7983,10 +8330,13 @@ binlog_checksum_update(MYSQL_THD thd, struct st_mysql_sys_var *var, { ulong value= *((ulong *)save); bool check_purge= false; + ulong prev_binlog_id; + LINT_INIT(prev_binlog_id); mysql_mutex_lock(mysql_bin_log.get_log_lock()); if(mysql_bin_log.is_open()) { + prev_binlog_id= mysql_bin_log.current_binlog_id; if (binlog_checksum_options != value) mysql_bin_log.checksum_alg_reset= (uint8) value; if (mysql_bin_log.rotate(true, &check_purge)) @@ -8000,7 +8350,7 @@ binlog_checksum_update(MYSQL_THD thd, struct st_mysql_sys_var *var, mysql_bin_log.checksum_alg_reset= BINLOG_CHECKSUM_ALG_UNDEF; mysql_mutex_unlock(mysql_bin_log.get_log_lock()); if (check_purge) - mysql_bin_log.purge(); + mysql_bin_log.checkpoint_and_purge(prev_binlog_id); } diff --git a/sql/log.h b/sql/log.h index 179d302d2cc..cd1845908ef 100644 --- a/sql/log.h +++ b/sql/log.h @@ -49,6 +49,7 @@ class TC_LOG bool need_prepare_ordered, bool need_commit_ordered) = 0; virtual int unlog(ulong cookie, my_xid xid)=0; + virtual void commit_checkpoint_notify(void *cookie)= 0; protected: /* @@ -98,8 +99,12 @@ public: return 1; } int unlog(ulong cookie, my_xid xid) { return 0; } + void commit_checkpoint_notify(void *cookie) { DBUG_ASSERT(0); }; }; +#define TC_LOG_PAGE_SIZE 8192 +#define TC_LOG_MIN_SIZE (3*TC_LOG_PAGE_SIZE) + #ifdef HAVE_MMAP class TC_LOG_MMAP: public TC_LOG { @@ -110,6 +115,12 @@ class TC_LOG_MMAP: public TC_LOG PS_DIRTY // new xids added since last sync } PAGE_STATE; + struct pending_cookies { + uint count; + uint pending_count; + ulong cookies[TC_LOG_PAGE_SIZE]; + }; + private: typedef struct st_page { struct st_page *next; // page a linked in a fifo queue @@ -141,7 +152,7 @@ class TC_LOG_MMAP: public TC_LOG one has to use active->lock. Same for LOCK_pool and LOCK_sync */ - mysql_mutex_t LOCK_active, LOCK_pool, LOCK_sync; + mysql_mutex_t LOCK_active, LOCK_pool, LOCK_sync, LOCK_pending_checkpoint; mysql_cond_t COND_pool, COND_active; /* Queue of threads that need to call commit_ordered(). @@ -163,14 +174,16 @@ class TC_LOG_MMAP: public TC_LOG */ mysql_cond_t COND_queue_busy; my_bool commit_ordered_queue_busy; + pending_cookies* pending_checkpoint; public: - TC_LOG_MMAP(): inited(0) {} + TC_LOG_MMAP(): inited(0), pending_checkpoint(0) {} int open(const char *opt_name); void close(); int log_and_order(THD *thd, my_xid xid, bool all, bool need_prepare_ordered, bool need_commit_ordered); int unlog(ulong cookie, my_xid xid); + void commit_checkpoint_notify(void *cookie); int recover(); private: @@ -178,6 +191,7 @@ class TC_LOG_MMAP: public TC_LOG void get_active_from_pool(); int sync(); int overflow(); + int delete_entry(ulong cookie); }; #else #define TC_LOG_MMAP TC_LOG_DUMMY @@ -356,12 +370,32 @@ private: /* We assign each binlog file an internal ID, used to identify them for unlog(). - Ids start from BINLOG_COOKIE_START; the value BINLOG_COOKIE_DUMMY is special - meaning "no binlog" (we cannot use zero as that is reserved for error return - from log_and_order). -*/ -#define BINLOG_COOKIE_DUMMY 1 -#define BINLOG_COOKIE_START 2 + The IDs start from 0 and increment for each new binlog created. + + In unlog() we need to know the ID of the binlog file that the corresponding + transaction was written into. We also need a special value for a corner + case where there is no corresponding binlog id (since nothing was logged). + And we need an error flag to mark that unlog() must return failure. + + We use the following macros to pack all of this information into the single + ulong available with log_and_order() / unlog(). + + Note that we cannot use the value 0 for cookie, as that is reserved as error + return value from log_and_order(). + */ +#define BINLOG_COOKIE_ERROR_RETURN 0 +#define BINLOG_COOKIE_DUMMY_ID 1 +#define BINLOG_COOKIE_BASE 2 +#define BINLOG_COOKIE_DUMMY(error_flag) \ + ( (BINLOG_COOKIE_DUMMY_ID<<1) | ((error_flag)&1) ) +#define BINLOG_COOKIE_MAKE(id, error_flag) \ + ( (((id)+BINLOG_COOKIE_BASE)<<1) | ((error_flag)&1) ) +#define BINLOG_COOKIE_GET_ERROR_FLAG(c) ((c) & 1) +#define BINLOG_COOKIE_GET_ID(c) ( ((ulong)(c)>>1) - BINLOG_COOKIE_BASE ) +#define BINLOG_COOKIE_IS_DUMMY(c) \ + ( ((ulong)(c)>>1) == BINLOG_COOKIE_DUMMY_ID ) + +void binlog_checkpoint_callback(void *cookie); class binlog_cache_mngr; class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG @@ -401,11 +435,25 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG IO_CACHE *error_cache; /* This is the `all' parameter for ha_commit_ordered(). */ bool all; + /* + True if we need to increment xid_count in trx_group_commit_leader() and + decrement in unlog() (this is needed if there is a participating engine + that does not implement the commit_checkpoint_request() handlerton + method). + */ + bool need_unlog; + /* + Fields used to pass the necessary information to the last thread in a + group commit, only used when opt_optimize_thread_scheduling is not set. + */ + bool check_purge; + ulong binlog_id; }; /* A list of struct xid_count_per_binlog is used to keep track of how many - XIDs are in prepared, but not committed, state in each binlog. + XIDs are in prepared, but not committed, state in each binlog. And how + many commit_checkpoint_request()'s are pending. When count drops to zero in a binlog after rotation, it means that there are no more XIDs in prepared state, so that binlog is no longer needed @@ -418,10 +466,10 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG char *binlog_name; uint binlog_name_len; ulong binlog_id; + /* Total prepared XIDs and pending checkpoint requests in this binlog. */ long xid_count; xid_count_per_binlog(); /* Give link error if constructor used. */ }; - ulong current_binlog_id; I_List binlog_xid_count_list; /* When this is set, a RESET MASTER is in progress. @@ -432,6 +480,7 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG checkpoint arrives - when all have arrived, RESET MASTER will complete. */ bool reset_master_pending; + friend void binlog_checkpoint_callback(void *cookie); /* LOCK_log and LOCK_index are inited by init_pthread_objects() */ mysql_mutex_t LOCK_index; @@ -464,15 +513,6 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG uint file_id; uint open_count; // For replication int readers_count; - bool need_start_event; - /* - no_auto_events means we don't want any of these automatic events : - Start/Rotate/Stop. That is, in 4.x when we rotate a relay log, we don't - want a Rotate_log event to be written to the relay log. When we start a - relay log etc. So in 4.x this is 1 for relay logs, 0 for binlogs. - In 5.0 it's 0 for relay logs too! - */ - bool no_auto_events; /* Queue of transactions queued up to participate in group commit. */ group_commit_entry *group_commit_queue; /* @@ -508,10 +548,12 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG */ int new_file_without_locking(); int new_file_impl(bool need_lock); + void do_checkpoint_request(ulong binlog_id); + void purge(); int write_transaction_or_stmt(group_commit_entry *entry); bool write_transaction_to_binlog_events(group_commit_entry *entry); void trx_group_commit_leader(group_commit_entry *leader); - void mark_xid_done(ulong cookie); + void mark_xid_done(ulong cookie, bool write_checkpoint); void mark_xids_active(ulong cookie, uint xid_count); public: @@ -572,6 +614,7 @@ public: */ char last_commit_pos_file[FN_REFLEN]; my_off_t last_commit_pos_offset; + ulong current_binlog_id; MYSQL_BIN_LOG(uint *sync_period); /* @@ -600,6 +643,7 @@ public: int log_and_order(THD *thd, my_xid xid, bool all, bool need_prepare_ordered, bool need_commit_ordered); int unlog(ulong cookie, my_xid xid); + void commit_checkpoint_notify(void *cookie); int recover(LOG_INFO *linfo, const char *last_log_name, IO_CACHE *first_log, Format_description_log_event *fdle); #if !defined(MYSQL_CLIENT) @@ -629,15 +673,14 @@ public: void signal_update(); void wait_for_update_relay_log(THD* thd); int wait_for_update_bin_log(THD* thd, const struct timespec * timeout); - void set_need_start_event() { need_start_event = 1; } - void init(bool no_auto_events_arg, ulong max_size); + void init(ulong max_size); void init_pthread_objects(); void cleanup(); bool open(const char *log_name, enum_log_type log_type, const char *new_name, enum cache_type io_cache_type_arg, - bool no_auto_events_arg, ulong max_size, + ulong max_size, bool null_created, bool need_mutex); bool open_index_file(const char *index_file_name_arg, @@ -674,7 +717,7 @@ public: bool can_purge_log(const char *log_file_name); int update_log_index(LOG_INFO* linfo, bool need_update_threads); int rotate(bool force_rotate, bool* check_purge); - void purge(); + void checkpoint_and_purge(ulong binlog_id); int rotate_and_purge(bool force_rotate); /** Flush binlog cache and synchronize to disk. diff --git a/sql/log_event.cc b/sql/log_event.cc index 6cefdb4fa59..25ab7b7c870 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -5874,7 +5874,7 @@ Rotate_log_event::do_shall_skip(Relay_log_info *rli) **************************************************************************/ #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) -void Binlog_checkpoint_log_event::pack_info(Protocol *protocol) +void Binlog_checkpoint_log_event::pack_info(THD *thd, Protocol *protocol) { protocol->store(binlog_file_name, binlog_file_len, &my_charset_bin); } diff --git a/sql/log_event.h b/sql/log_event.h index c76e538618b..dfbefdb359e 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -2911,7 +2911,7 @@ public: Binlog_checkpoint_log_event(const char *binlog_file_name_arg, uint binlog_file_len_arg); #ifdef HAVE_REPLICATION - void pack_info(Protocol *protocol); + void pack_info(THD *thd, Protocol *protocol); #endif #else void print(FILE *file, PRINT_EVENT_INFO *print_event_info); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 3c0f209235a..fa6b085c3ad 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -715,7 +715,8 @@ char **orig_argv; #ifdef HAVE_PSI_INTERFACE #ifdef HAVE_MMAP -PSI_mutex_key key_PAGE_lock, key_LOCK_sync, key_LOCK_active, key_LOCK_pool; +PSI_mutex_key key_PAGE_lock, key_LOCK_sync, key_LOCK_active, key_LOCK_pool, + key_LOCK_pending_checkpoint; #endif /* HAVE_MMAP */ #ifdef HAVE_OPENSSL @@ -756,6 +757,7 @@ static PSI_mutex_info all_server_mutexes[]= { &key_LOCK_sync, "TC_LOG_MMAP::LOCK_sync", 0}, { &key_LOCK_active, "TC_LOG_MMAP::LOCK_active", 0}, { &key_LOCK_pool, "TC_LOG_MMAP::LOCK_pool", 0}, + { &key_LOCK_pool, "TC_LOG_MMAP::LOCK_pending_checkpoint", 0}, #endif /* HAVE_MMAP */ #ifdef HAVE_OPENSSL @@ -4418,7 +4420,7 @@ a file name for --log-bin-index option", opt_binlog_index_name); } if (opt_bin_log && mysql_bin_log.open(opt_bin_logname, LOG_BIN, 0, - WRITE_CACHE, 0, max_binlog_size, 0, TRUE)) + WRITE_CACHE, max_binlog_size, 0, TRUE)) unireg_abort(1); #ifdef HAVE_REPLICATION diff --git a/sql/mysqld.h b/sql/mysqld.h index 28c4d771a48..62d2426d692 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -218,7 +218,7 @@ extern pthread_key(MEM_ROOT**,THR_MALLOC); #ifdef HAVE_PSI_INTERFACE #ifdef HAVE_MMAP extern PSI_mutex_key key_PAGE_lock, key_LOCK_sync, key_LOCK_active, - key_LOCK_pool; + key_LOCK_pool, key_LOCK_pending_checkpoint; #endif /* HAVE_MMAP */ #ifdef HAVE_OPENSSL diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index 252b4f3f5b9..a700aff0da9 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -213,7 +213,7 @@ a file name for --relay-log-index option", opt_relaylog_index_name); but a destructor will take care of that */ if (rli->relay_log.open_index_file(opt_relaylog_index_name, ln, TRUE) || - rli->relay_log.open(ln, LOG_BIN, 0, SEQ_READ_APPEND, 0, + rli->relay_log.open(ln, LOG_BIN, 0, SEQ_READ_APPEND, (max_relay_log_size ? max_relay_log_size : max_binlog_size), 1, TRUE)) { diff --git a/sql/slave.cc b/sql/slave.cc index 8869ccb7004..7b7bddecd17 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1757,13 +1757,12 @@ past_checksum: /* Announce MariaDB slave capabilities. */ DBUG_EXECUTE_IF("simulate_slave_capability_none", goto after_set_capability;); { - const char *q= - DBUG_EVALUATE_IF("simulate_slave_capability_old_53", - "SET @mariadb_slave_capability=" - STRINGIFY_ARG(MARIA_SLAVE_CAPABILITY_ANNOTATE), - "SET @mariadb_slave_capability=" - STRINGIFY_ARG(MARIA_SLAVE_CAPABILITY_MINE)); - if (mysql_real_query(mysql, q, strlen(q))) + int rc= DBUG_EVALUATE_IF("simulate_slave_capability_old_53", + mysql_real_query(mysql, STRING_WITH_LEN("SET @mariadb_slave_capability=" + STRINGIFY_ARG(MARIA_SLAVE_CAPABILITY_ANNOTATE))), + mysql_real_query(mysql, STRING_WITH_LEN("SET @mariadb_slave_capability=" + STRINGIFY_ARG(MARIA_SLAVE_CAPABILITY_MINE)))); + if (rc) { err_code= mysql_errno(mysql); if (is_network_error(err_code)) diff --git a/sql/sql_class.h b/sql/sql_class.h index 054f267ed01..4943a39f491 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -149,9 +149,6 @@ public: }; -#define TC_LOG_PAGE_SIZE 8192 -#define TC_LOG_MIN_SIZE (3*TC_LOG_PAGE_SIZE) - #define TC_HEURISTIC_RECOVER_COMMIT 1 #define TC_HEURISTIC_RECOVER_ROLLBACK 2 extern ulong tc_heuristic_recover; diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 81bb4a1c3eb..71fcacbd0e8 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -347,6 +347,7 @@ static int innobase_rollback_to_savepoint(handlerton *hton, THD* thd, static int innobase_savepoint(handlerton *hton, THD* thd, void *savepoint); static int innobase_release_savepoint(handlerton *hton, THD* thd, void *savepoint); +static void innobase_checkpoint_request(handlerton *hton, void *cookie); static handler *innobase_create_handler(handlerton *hton, TABLE_SHARE *table, MEM_ROOT *mem_root); @@ -2250,6 +2251,7 @@ innobase_init( innobase_hton->recover=innobase_xa_recover; innobase_hton->commit_by_xid=innobase_commit_by_xid; innobase_hton->rollback_by_xid=innobase_rollback_by_xid; + innobase_hton->commit_checkpoint_request=innobase_checkpoint_request; innobase_hton->create_cursor_read_view=innobase_create_cursor_view; innobase_hton->set_cursor_read_view=innobase_set_cursor_view; innobase_hton->close_cursor_read_view=innobase_close_cursor_view; @@ -3006,6 +3008,19 @@ innobase_rollback_trx( DBUG_RETURN(convert_error_code_to_mysql(error, 0, NULL)); } +/*****************************************************************//** +Handle a commit checkpoint request from server layer. +We simply flush the redo log immediately and do the notify call.*/ +static +void +innobase_checkpoint_request( + handlerton *hton, + void *cookie) +{ + log_buffer_flush_to_disk(); + commit_checkpoint_notify_ha(hton, cookie); +} + /*****************************************************************//** Rolls back a transaction to a savepoint. @return 0 if success, HA_ERR_NO_SAVEPOINT if no savepoint with the @@ -11460,10 +11475,17 @@ static MYSQL_SYSVAR_STR(file_format_max, innobase_file_format_max, static MYSQL_SYSVAR_ULONG(flush_log_at_trx_commit, srv_flush_log_at_trx_commit, PLUGIN_VAR_OPCMDARG, - "Set to 0 (write and flush once per second)," - " 1 (write and flush at each commit)" - " or 2 (write at commit, flush once per second).", - NULL, NULL, 1, 0, 2, 0); + "Controls the durability/speed trade-off for commits." + " Set to 0 (write and flush redo log to disk only once per second)," + " 1 (flush to disk at each commit)," + " 2 (write to log at commit but flush to disk only once per second)" + " or 3 (flush to disk at prepare and at commit, slower and usually redundant)." + " 1 and 3 guarantees that after a crash, committed transactions will" + " not be lost and will be consistent with the binlog and other transactional" + " engines. 2 can get inconsistent and lose transactions if there is a" + " power failure or kernel crash but not if mysqld crashes. 0 has no" + " guarantees in case of crash. 0 and 2 can be faster than 1 or 3.", + NULL, NULL, 1, 0, 3, 0); static MYSQL_SYSVAR_STR(flush_method, innobase_file_flush_method, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, diff --git a/storage/innobase/trx/trx0trx.c b/storage/innobase/trx/trx0trx.c index 85246aa6d1f..78191c4c1b4 100644 --- a/storage/innobase/trx/trx0trx.c +++ b/storage/innobase/trx/trx0trx.c @@ -1025,7 +1025,8 @@ trx_commit_off_kernel( trx->must_flush_log_later = TRUE; } else if (srv_flush_log_at_trx_commit == 0) { /* Do nothing */ - } else if (srv_flush_log_at_trx_commit == 1) { + } else if (srv_flush_log_at_trx_commit == 1 || + srv_flush_log_at_trx_commit == 3) { if (srv_unix_file_flush_method == SRV_UNIX_NOSYNC) { /* Write the log but do not flush it to disk */ @@ -1712,7 +1713,11 @@ trx_commit_complete_for_mysql( /* Do nothing */ } else if (srv_flush_log_at_trx_commit == 0) { /* Do nothing */ - } else if (srv_flush_log_at_trx_commit == 1) { + } else if (srv_flush_log_at_trx_commit == 1 && trx->active_commit_ordered) { + /* Do nothing - we already flushed the prepare and binlog write + to disk, so transaction is durable (will be recovered from + binlog if necessary) */ + } else if (srv_flush_log_at_trx_commit == 1 || srv_flush_log_at_trx_commit == 3) { if (srv_unix_file_flush_method == SRV_UNIX_NOSYNC) { /* Write the log but do not flush it to disk */ @@ -1992,7 +1997,7 @@ trx_prepare_off_kernel( if (srv_flush_log_at_trx_commit == 0) { /* Do nothing */ - } else if (srv_flush_log_at_trx_commit == 1) { + } else if (srv_flush_log_at_trx_commit == 1 || srv_flush_log_at_trx_commit == 3) { if (srv_unix_file_flush_method == SRV_UNIX_NOSYNC) { /* Write the log but do not flush it to disk */ diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index db0bd40c9b6..e4da37286bb 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -383,6 +383,7 @@ static int innobase_rollback_to_savepoint(handlerton *hton, THD* thd, static int innobase_savepoint(handlerton *hton, THD* thd, void *savepoint); static int innobase_release_savepoint(handlerton *hton, THD* thd, void *savepoint); +static void innobase_checkpoint_request(handlerton *hton, void *cookie); static handler *innobase_create_handler(handlerton *hton, TABLE_SHARE *table, MEM_ROOT *mem_root); @@ -483,10 +484,17 @@ static MYSQL_THDVAR_ULONG(lock_wait_timeout, PLUGIN_VAR_RQCMDARG, NULL, NULL, 50, 1, 1024 * 1024 * 1024, 0); static MYSQL_THDVAR_ULONG(flush_log_at_trx_commit, PLUGIN_VAR_OPCMDARG, - "Set to 0 (write and flush once per second)," - " 1 (write and flush at each commit)" - " or 2 (write at commit, flush once per second).", - NULL, NULL, 1, 0, 2, 0); + "Controls the durability/speed trade-off for commits." + " Set to 0 (write and flush redo log to disk only once per second)," + " 1 (flush to disk at each commit)," + " 2 (write to log at commit but flush to disk only once per second)" + " or 3 (flush to disk at prepare and at commit, slower and usually redundant)." + " 1 and 3 guarantees that after a crash, committed transactions will" + " not be lost and will be consistent with the binlog and other transactional" + " engines. 2 can get inconsistent and lose transactions if there is a" + " power failure or kernel crash but not if mysqld crashes. 0 has no" + " guarantees in case of crash. 0 and 2 can be faster than 1 or 3.", + NULL, NULL, 1, 0, 3, 0); static MYSQL_THDVAR_BOOL(fake_changes, PLUGIN_VAR_OPCMDARG, "In the transaction after enabled, UPDATE, INSERT and DELETE only move the cursor to the records " @@ -2469,6 +2477,7 @@ innobase_init( innobase_hton->recover=innobase_xa_recover; innobase_hton->commit_by_xid=innobase_commit_by_xid; innobase_hton->rollback_by_xid=innobase_rollback_by_xid; + innobase_hton->commit_checkpoint_request=innobase_checkpoint_request; innobase_hton->checkpoint_state= innobase_checkpoint_state; innobase_hton->create_cursor_read_view=innobase_create_cursor_view; innobase_hton->set_cursor_read_view=innobase_set_cursor_view; @@ -3491,6 +3500,19 @@ innobase_rollback_trx( DBUG_RETURN(convert_error_code_to_mysql(error, 0, NULL)); } +/*****************************************************************//** +Handle a commit checkpoint request from server layer. +We simply flush the redo log immediately and do the notify call.*/ +static +void +innobase_checkpoint_request( + handlerton *hton, + void *cookie) +{ + log_buffer_flush_to_disk(); + commit_checkpoint_notify_ha(hton, cookie); +} + /*****************************************************************//** Rolls back a transaction to a savepoint. @return 0 if success, HA_ERR_NO_SAVEPOINT if no savepoint with the diff --git a/storage/xtradb/include/trx0trx.h b/storage/xtradb/include/trx0trx.h index eded5c303fa..a03f7aceafa 100644 --- a/storage/xtradb/include/trx0trx.h +++ b/storage/xtradb/include/trx0trx.h @@ -494,7 +494,6 @@ struct trx_struct{ this is set to 1 then registered should also be set to 1. This is used in the XA code */ - unsigned called_commit_ordered:1;/* 1 if innobase_commit_ordered has run. */ /*------------------------------*/ ulint isolation_level;/* TRX_ISO_REPEATABLE_READ, ... */ ulint check_foreigns; /* normally TRUE, but if the user diff --git a/storage/xtradb/trx/trx0trx.c b/storage/xtradb/trx/trx0trx.c index c9fccaad16b..b703a04b1b0 100644 --- a/storage/xtradb/trx/trx0trx.c +++ b/storage/xtradb/trx/trx0trx.c @@ -1099,7 +1099,8 @@ trx_commit_off_kernel( trx->must_flush_log_later = TRUE; } else if (flush_log_at_trx_commit == 0) { /* Do nothing */ - } else if (flush_log_at_trx_commit == 1) { + } else if (flush_log_at_trx_commit == 1 || + flush_log_at_trx_commit == 3) { if (srv_unix_file_flush_method == SRV_UNIX_NOSYNC) { /* Write the log but do not flush it to disk */ @@ -1809,7 +1810,11 @@ trx_commit_complete_for_mysql( /* Do nothing */ } else if (flush_log_at_trx_commit == 0) { /* Do nothing */ - } else if (flush_log_at_trx_commit == 1) { + } else if (flush_log_at_trx_commit == 1 && trx->active_commit_ordered) { + /* Do nothing - we already flushed the prepare and binlog write + to disk, so transaction is durable (will be recovered from + binlog if necessary) */ + } else if (flush_log_at_trx_commit == 1 || flush_log_at_trx_commit == 3) { if (srv_unix_file_flush_method == SRV_UNIX_NOSYNC) { /* Write the log but do not flush it to disk */ @@ -2097,7 +2102,7 @@ trx_prepare_off_kernel( if (flush_log_at_trx_commit == 0) { /* Do nothing */ - } else if (flush_log_at_trx_commit == 1) { + } else if (flush_log_at_trx_commit == 1 || flush_log_at_trx_commit == 3) { if (srv_unix_file_flush_method == SRV_UNIX_NOSYNC) { /* Write the log but do not flush it to disk */ From 32e4c7e138c9577b5dd9477dbee8b4091c5b69fe Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Thu, 13 Sep 2012 21:11:47 +0300 Subject: [PATCH 264/289] Added THD::utime_after_query to avoid calling current_utime() twice for every end-of-query Increment long_query_count also if thd->variables.log_slow_rate_limit is used Added new state "Writing to binlog" sql/sql_class.h: Added THD::utime_after_query to avoid calling current_utime() twice for every end-of-query sql/sql_parse.cc: Increment long_query_count also if thd->variables.log_slow_rate_limit is used Removed extra calls to thd_proc_info(thd, "logging slow query") and thd->current_utime(); sql/sql_table.cc: Added new state "Writing to binlog" --- sql/sql_class.h | 6 +++--- sql/sql_parse.cc | 48 ++++++++++++++++++++---------------------------- sql/sql_table.cc | 2 ++ 3 files changed, 25 insertions(+), 31 deletions(-) diff --git a/sql/sql_class.h b/sql/sql_class.h index 344d6435ad5..f50d1442a3f 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1685,7 +1685,7 @@ public: my_hrtime_t user_time; // track down slow pthread_create ulonglong prior_thr_create_utime, thr_create_utime; - ulonglong start_utime, utime_after_lock; + ulonglong start_utime, utime_after_lock, utime_after_query; // Process indicator struct { @@ -2488,8 +2488,8 @@ public: */ void update_server_status() { - ulonglong end_utime_of_query= current_utime(); - if (end_utime_of_query > utime_after_lock + variables.long_query_time) + utime_after_query= current_utime(); + if (utime_after_query > utime_after_lock + variables.long_query_time) server_status|= SERVER_QUERY_WAS_SLOW; } inline ulonglong found_rows(void) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index dd14173e47f..f5124d60f3f 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1483,38 +1483,30 @@ void log_slow_statement(THD *thd) DBUG_VOID_RETURN; // Don't set time for sub stmt /* Follow the slow log filter configuration. */ - if (!(thd->variables.log_slow_filter & thd->query_plan_flags)) + if (!thd->enable_slow_log || + !(thd->variables.log_slow_filter & thd->query_plan_flags)) DBUG_VOID_RETURN; - /* - If rate limiting of slow log writes is enabled, decide whether to log - this query to the log or not. - */ - if (thd->variables.log_slow_rate_limit > 1 && - (global_query_id % thd->variables.log_slow_rate_limit) != 0) - DBUG_VOID_RETURN; - - /* - Do not log administrative statements unless the appropriate option is - set. - */ - if (thd->enable_slow_log) + if (((thd->server_status & SERVER_QUERY_WAS_SLOW) || + ((thd->server_status & + (SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED)) && + opt_log_queries_not_using_indexes && + !(sql_command_flags[thd->lex->sql_command] & CF_STATUS_COMMAND))) && + thd->examined_row_count >= thd->variables.min_examined_row_limit) { - ulonglong end_utime_of_query= thd->current_utime(); - thd_proc_info(thd, "logging slow query"); + thd->status_var.long_query_count++; + /* + If rate limiting of slow log writes is enabled, decide whether to log + this query to the log or not. + */ + if (thd->variables.log_slow_rate_limit > 1 && + (global_query_id % thd->variables.log_slow_rate_limit) != 0) + DBUG_VOID_RETURN; - if (((thd->server_status & SERVER_QUERY_WAS_SLOW) || - ((thd->server_status & - (SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED)) && - opt_log_queries_not_using_indexes && - !(sql_command_flags[thd->lex->sql_command] & CF_STATUS_COMMAND))) && - thd->examined_row_count >= thd->variables.min_examined_row_limit) - { - thd_proc_info(thd, "logging slow query"); - thd->status_var.long_query_count++; - slow_log_print(thd, thd->query(), thd->query_length(), - end_utime_of_query); - } + thd_proc_info(thd, "logging slow query"); + slow_log_print(thd, thd->query(), thd->query_length(), + thd->utime_after_query); + thd_proc_info(thd, 0); } DBUG_VOID_RETURN; } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index f01c367fd55..4ff29b33b5b 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1828,6 +1828,7 @@ int write_bin_log(THD *thd, bool clear_error, if (mysql_bin_log.is_open()) { int errcode= 0; + thd_proc_info(thd, "Writing to binlog"); if (clear_error) thd->clear_error(); else @@ -1835,6 +1836,7 @@ int write_bin_log(THD *thd, bool clear_error, error= thd->binlog_query(THD::STMT_QUERY_TYPE, query, query_length, is_trans, FALSE, FALSE, errcode); + thd_proc_info(thd, 0); } return error; } From b917fb63a638fd117e1e52d3bc29b57a81124fea Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 14 Sep 2012 11:26:01 +0300 Subject: [PATCH 265/289] Fix bug lp:1009187, mdev-373, mysql bug#58628 Analysis: The queries in question use the [unique | index]_subquery execution methods. These methods reuse the ref keys constructed by create_ref_for_key(). The way create_ref_for_key() works is that it doesn't store in ref.key_copy[] store_key elements that represent constants. In particular it doesn't store the store_key for NULL constants. The execution of [unique | index]_subquery calls subselect_uniquesubquery_engine::copy_ref_key, which in addition to copy the left IN argument into a index lookup key, is supposed to detect if the left IN argument contains NULLs. Since the store_key for the NULL constant is not copied into the key array, the null is not detected, and execution erroneously proceeds as if it should look for a complete match. Solution: The solution (unlike MySQL) is to reuse already computed information about NULL presence. Item_in_optimizer::val_int already finds out if the left IN operand contains NULLs. The fix propagates this to the execution methods subselect_[unique | index]subquery_engine::exec so it knows if there were NULL values independent of the presence of keys. In addition the patch siplifies copy_ref_key() and the logic that hanldes the case of NULLs in the left IN operand. --- mysql-test/r/subselect4.result | 81 +++++++++++++++++++ mysql-test/t/subselect4.test | 44 +++++++++++ sql/item_subselect.cc | 139 +++++++++++++-------------------- sql/item_subselect.h | 2 +- 4 files changed, 180 insertions(+), 86 deletions(-) diff --git a/mysql-test/r/subselect4.result b/mysql-test/r/subselect4.result index 8385ee6f4c0..952717c5c37 100644 --- a/mysql-test/r/subselect4.result +++ b/mysql-test/r/subselect4.result @@ -197,5 +197,86 @@ default(a) aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa DROP TABLE t; # +# LP BUG#1009187, MDEV-373, MYSQL bug#58628 +# Wrong result for a query with [NOT] IN subquery predicate if +# the left part of the predicate is explicit NULL +# +CREATE TABLE t1 (pk INT NOT NULL, i INT NOT NULL); +INSERT INTO t1 VALUES (0,10), (1,20), (2,30), (3,40); +CREATE TABLE t2a (pk INT NOT NULL, i INT NOT NULL, PRIMARY KEY(i,pk)); +INSERT INTO t2a VALUES (0,0), (1,1), (2,2), (3,3); +CREATE TABLE t2b (pk INT, i INT); +INSERT INTO t2b VALUES (0,0), (1,1), (2,2), (3,3); +CREATE TABLE t2c (pk INT NOT NULL, i INT NOT NULL); +INSERT INTO t2c VALUES (0,0), (1,1), (2,2), (3,3); +create index it2c on t2c (i,pk); +EXPLAIN +SELECT * FROM t1 WHERE NULL NOT IN (SELECT t2a.i FROM t2a WHERE t2a.pk = t1.pk); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where +2 DEPENDENT SUBQUERY t2a unique_subquery PRIMARY PRIMARY 8 const,test.t1.pk 1 Using index; Using where; Full scan on NULL key +SELECT * FROM t1 WHERE NULL NOT IN (SELECT t2a.i FROM t2a WHERE t2a.pk = t1.pk); +pk i +SELECT * FROM t1 WHERE 1+NULL NOT IN (SELECT t2a.i FROM t2a WHERE t2a.pk = t1.pk); +pk i +SELECT * FROM t1 WHERE NULL IN (SELECT t2a.i FROM t2a WHERE t2a.pk = t1.pk) IS UNKNOWN; +pk i +0 10 +1 20 +2 30 +3 40 +SELECT t1.pk, NULL NOT IN (SELECT t2a.i FROM t2a WHERE t2a.pk = t1.pk) FROM t1; +pk NULL NOT IN (SELECT t2a.i FROM t2a WHERE t2a.pk = t1.pk) +0 NULL +1 NULL +2 NULL +3 NULL +EXPLAIN +SELECT * FROM t1 WHERE NULL NOT IN (SELECT t2b.i FROM t2b WHERE t2b.pk = t1.pk); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where +2 DEPENDENT SUBQUERY t2b ALL NULL NULL NULL NULL 4 Using where +SELECT * FROM t1 WHERE NULL NOT IN (SELECT t2b.i FROM t2b WHERE t2b.pk = t1.pk); +pk i +SELECT * FROM t1 WHERE NULL IN (SELECT t2b.i FROM t2b WHERE t2b.pk = t1.pk) IS UNKNOWN; +pk i +0 10 +1 20 +2 30 +3 40 +SELECT t1.pk, NULL NOT IN (SELECT t2b.i FROM t2b WHERE t2b.pk = t1.pk) FROM t1; +pk NULL NOT IN (SELECT t2b.i FROM t2b WHERE t2b.pk = t1.pk) +0 NULL +1 NULL +2 NULL +3 NULL +EXPLAIN +SELECT * FROM t1 WHERE NULL NOT IN (SELECT t2c.i FROM t2c WHERE t2c.pk = t1.pk); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where +2 DEPENDENT SUBQUERY t2c index_subquery it2c it2c 8 const,test.t1.pk 2 Using index; Using where; Full scan on NULL key +SELECT * FROM t1 WHERE NULL NOT IN (SELECT t2c.i FROM t2c WHERE t2c.pk = t1.pk); +pk i +SELECT * FROM t1 WHERE NULL IN (SELECT t2c.i FROM t2c WHERE t2c.pk = t1.pk) IS UNKNOWN; +pk i +0 10 +1 20 +2 30 +3 40 +SELECT t1.pk, NULL NOT IN (SELECT t2c.i FROM t2c WHERE t2c.pk = t1.pk) FROM t1; +pk NULL NOT IN (SELECT t2c.i FROM t2c WHERE t2c.pk = t1.pk) +0 NULL +1 NULL +2 NULL +3 NULL +EXPLAIN +SELECT * FROM t1 WHERE (NULL, 1) NOT IN (SELECT t2a.i, t2a.pk FROM t2a WHERE t2a.pk = t1.pk); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where +2 DEPENDENT SUBQUERY t2a eq_ref PRIMARY PRIMARY 8 const,test.t1.pk 2 Using where; Using index; Full scan on NULL key +SELECT * FROM t1 WHERE (NULL, 1) NOT IN (SELECT t2a.i, t2a.pk FROM t2a WHERE t2a.pk = t1.pk); +pk i +drop table t1, t2a, t2b, t2c; +# # End of 5.1 tests. # diff --git a/mysql-test/t/subselect4.test b/mysql-test/t/subselect4.test index bb97f246488..3de2dfc394e 100644 --- a/mysql-test/t/subselect4.test +++ b/mysql-test/t/subselect4.test @@ -170,6 +170,50 @@ INSERT INTO t VALUES (''),(''),(''),(''),(''),(''),(''),(''),(''),(''),(''); SELECT * FROM (SELECT default(a) FROM t GROUP BY a) d; DROP TABLE t; +--echo # +--echo # LP BUG#1009187, MDEV-373, MYSQL bug#58628 +--echo # Wrong result for a query with [NOT] IN subquery predicate if +--echo # the left part of the predicate is explicit NULL +--echo # + +CREATE TABLE t1 (pk INT NOT NULL, i INT NOT NULL); +INSERT INTO t1 VALUES (0,10), (1,20), (2,30), (3,40); + +CREATE TABLE t2a (pk INT NOT NULL, i INT NOT NULL, PRIMARY KEY(i,pk)); +INSERT INTO t2a VALUES (0,0), (1,1), (2,2), (3,3); + +CREATE TABLE t2b (pk INT, i INT); +INSERT INTO t2b VALUES (0,0), (1,1), (2,2), (3,3); + +CREATE TABLE t2c (pk INT NOT NULL, i INT NOT NULL); +INSERT INTO t2c VALUES (0,0), (1,1), (2,2), (3,3); +create index it2c on t2c (i,pk); + +EXPLAIN +SELECT * FROM t1 WHERE NULL NOT IN (SELECT t2a.i FROM t2a WHERE t2a.pk = t1.pk); +SELECT * FROM t1 WHERE NULL NOT IN (SELECT t2a.i FROM t2a WHERE t2a.pk = t1.pk); +SELECT * FROM t1 WHERE 1+NULL NOT IN (SELECT t2a.i FROM t2a WHERE t2a.pk = t1.pk); +SELECT * FROM t1 WHERE NULL IN (SELECT t2a.i FROM t2a WHERE t2a.pk = t1.pk) IS UNKNOWN; +SELECT t1.pk, NULL NOT IN (SELECT t2a.i FROM t2a WHERE t2a.pk = t1.pk) FROM t1; + +EXPLAIN +SELECT * FROM t1 WHERE NULL NOT IN (SELECT t2b.i FROM t2b WHERE t2b.pk = t1.pk); +SELECT * FROM t1 WHERE NULL NOT IN (SELECT t2b.i FROM t2b WHERE t2b.pk = t1.pk); +SELECT * FROM t1 WHERE NULL IN (SELECT t2b.i FROM t2b WHERE t2b.pk = t1.pk) IS UNKNOWN; +SELECT t1.pk, NULL NOT IN (SELECT t2b.i FROM t2b WHERE t2b.pk = t1.pk) FROM t1; + +EXPLAIN +SELECT * FROM t1 WHERE NULL NOT IN (SELECT t2c.i FROM t2c WHERE t2c.pk = t1.pk); +SELECT * FROM t1 WHERE NULL NOT IN (SELECT t2c.i FROM t2c WHERE t2c.pk = t1.pk); +SELECT * FROM t1 WHERE NULL IN (SELECT t2c.i FROM t2c WHERE t2c.pk = t1.pk) IS UNKNOWN; +SELECT t1.pk, NULL NOT IN (SELECT t2c.i FROM t2c WHERE t2c.pk = t1.pk) FROM t1; + +EXPLAIN +SELECT * FROM t1 WHERE (NULL, 1) NOT IN (SELECT t2a.i, t2a.pk FROM t2a WHERE t2a.pk = t1.pk); +SELECT * FROM t1 WHERE (NULL, 1) NOT IN (SELECT t2a.i, t2a.pk FROM t2a WHERE t2a.pk = t1.pk); + +drop table t1, t2a, t2b, t2c; + --echo # --echo # End of 5.1 tests. --echo # diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index fc214a584ee..888c346c199 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -1686,6 +1686,12 @@ bool Item_in_subselect::fix_fields(THD *thd_arg, Item **ref) } +inline bool Item_in_subselect::left_expr_has_null() +{ + return (*(optimizer->get_cache()))->null_value; +} + + Item_subselect::trans_res Item_allany_subselect::select_transformer(JOIN *join) { @@ -2131,39 +2137,19 @@ int subselect_uniquesubquery_engine::scan_table() subselect_uniquesubquery_engine::copy_ref_key() DESCRIPTION - Copy ref key and check for null parts in it. - Depending on the nullability and conversion problems this function - recognizes and processes the following states : - 1. Partial match on top level. This means IN has a value of FALSE - regardless of the data in the subquery table. - Detected by finding a NULL in the left IN operand of a top level - expression. - We may actually skip reading the subquery, so return TRUE to skip - the table scan in subselect_uniquesubquery_engine::exec and make - the value of the IN predicate a NULL (that is equal to FALSE on - top level). - 2. No exact match when IN is nested inside another predicate. - Detected by finding a NULL in the left IN operand when IN is not - a top level predicate. - We cannot have an exact match. But we must proceed further with a - table scan to find out if it's a partial match (and IN has a value - of NULL) or no match (and IN has a value of FALSE). - So we return FALSE to continue with the scan and see if there are - any record that would constitute a partial match (as we cannot - determine that from the index). - 3. Error converting the left IN operand to the column type of the - right IN operand. This counts as no match (and IN has the value of - FALSE). We mark the subquery table cursor as having no more rows - (to ensure that the processing that follows will not find a match) - and return FALSE, so IN is not treated as returning NULL. + Copy ref key and check for conversion problems. + If there is an error converting the left IN operand to the column type of + the right IN operand count it as no match. In this case IN has the value of + FALSE. We mark the subquery table cursor as having no more rows (to ensure + that the processing that follows will not find a match) and return FALSE, + so IN is not treated as returning NULL. RETURN FALSE - The value of the IN predicate is not known. Proceed to find the - value of the IN predicate using the determined values of - null_keypart and table->status. - TRUE - IN predicate has a value of NULL. Stop the processing right there - and return NULL to the outer predicates. + value of the IN predicate using the copied key. + TRUE - IN predicate has a value of FALSE. Stop the processing right there + and tell the outer predicate it is FALSE. */ bool subselect_uniquesubquery_engine::copy_ref_key() @@ -2176,30 +2162,6 @@ bool subselect_uniquesubquery_engine::copy_ref_key() continue; tab->ref.key_err= (*copy)->copy(); - /* - When there is a NULL part in the key we don't need to make index - lookup for such key thus we don't need to copy whole key. - If we later should do a sequential scan return OK. Fail otherwise. - - See also the comment for the subselect_uniquesubquery_engine::exec() - function. - */ - null_keypart= (*copy)->null_key; - if (null_keypart) - { - bool top_level= ((Item_in_subselect *) item)->is_top_level_item(); - if (top_level) - { - /* Partial match on top level */ - DBUG_RETURN(1); - } - else - { - /* No exact match when IN is nested inside another predicate */ - break; - } - } - /* Check if the error is equal to STORE_KEY_FATAL. This is not expressed using the store_key::store_key_result enum because ref.key_err is a @@ -2215,10 +2177,10 @@ bool subselect_uniquesubquery_engine::copy_ref_key() IN operand. */ tab->table->status= STATUS_NOT_FOUND; - break; + DBUG_RETURN(true); } } - DBUG_RETURN(0); + DBUG_RETURN(false); } @@ -2248,8 +2210,9 @@ bool subselect_uniquesubquery_engine::copy_ref_key() NOTE RETURN - FALSE - ok - TRUE - an error occured while scanning + 0 - ok + 1 - notify caller to call Item_subselect::reset(), + in most cases reset() sets the result to NULL */ int subselect_uniquesubquery_engine::exec() @@ -2259,23 +2222,27 @@ int subselect_uniquesubquery_engine::exec() TABLE *table= tab->table; empty_result_set= TRUE; table->status= 0; + Item_in_subselect *in_subs= (Item_in_subselect *) item; - /* TODO: change to use of 'full_scan' here? */ - if (copy_ref_key()) - DBUG_RETURN(1); - if (table->status) + if (in_subs->left_expr_has_null()) { - /* - We know that there will be no rows even if we scan. - Can be set in copy_ref_key. + /* + The case when all values in left_expr are NULL is handled by + Item_in_optimizer::val_int(). */ - ((Item_in_subselect *) item)->value= 0; + if (in_subs->is_top_level_item()) + DBUG_RETURN(1); /* notify caller to call reset() and set NULL value. */ + else + DBUG_RETURN(scan_table()); + } + + if (copy_ref_key()) + { + /* We know that there will be no rows even if we scan. */ + in_subs->value= 0; DBUG_RETURN(0); } - if (null_keypart) - DBUG_RETURN(scan_table()); - if (!table->file->inited) table->file->ha_index_init(tab->ref.key, 0); error= table->file->ha_index_read_map(table->record[0], @@ -2357,9 +2324,9 @@ subselect_uniquesubquery_engine::~subselect_uniquesubquery_engine() cheaper. We can use index statistics to quickly check whether "ref" scan will be cheaper than full table scan. - RETURN - 0 - 1 + 0 - ok + 1 - notify caller to call Item_subselect::reset(), + in most cases reset() sets the result to NULL */ int subselect_indexsubquery_engine::exec() @@ -2368,10 +2335,10 @@ int subselect_indexsubquery_engine::exec() int error; bool null_finding= 0; TABLE *table= tab->table; + Item_in_subselect *in_subs= (Item_in_subselect *) item; - ((Item_in_subselect *) item)->value= 0; + in_subs->value= 0; empty_result_set= TRUE; - null_keypart= 0; table->status= 0; if (check_null) @@ -2381,22 +2348,24 @@ int subselect_indexsubquery_engine::exec() ((Item_in_subselect *) item)->was_null= 0; } - /* Copy the ref key and check for nulls... */ - if (copy_ref_key()) - DBUG_RETURN(1); - - if (table->status) + if (in_subs->left_expr_has_null()) { - /* - We know that there will be no rows even if we scan. - Can be set in copy_ref_key. + /* + The case when all values in left_expr are NULL is handled by + Item_in_optimizer::val_int(). */ - ((Item_in_subselect *) item)->value= 0; - DBUG_RETURN(0); + if (in_subs->is_top_level_item()) + DBUG_RETURN(1); /* notify caller to call reset() and set NULL value. */ + else + DBUG_RETURN(scan_table()); } - if (null_keypart) - DBUG_RETURN(scan_table()); + if (copy_ref_key()) + { + /* We know that there will be no rows even if we scan. */ + in_subs->value= 0; + DBUG_RETURN(0); + } if (!table->file->inited) table->file->ha_index_init(tab->ref.key, 1); diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 7eb45e74f40..b6b9750b910 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -334,6 +334,7 @@ public: bool test_limit(st_select_lex_unit *unit); virtual void print(String *str, enum_query_type query_type); bool fix_fields(THD *thd, Item **ref); + inline bool left_expr_has_null(); friend class Item_ref_null_helper; friend class Item_is_not_null_test; @@ -513,7 +514,6 @@ protected: expression is NULL. */ bool empty_result_set; - bool null_keypart; /* TRUE <=> constructed search tuple has a NULL */ public: // constructor can assign THD because it will be called after JOIN::prepare From 0704d47007c394d07226cf1fec984fda27d9b3cf Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Tue, 18 Sep 2012 00:42:05 +0300 Subject: [PATCH 266/289] Fixed issues in test suite when running with --ps-protocol mysql-test/t/features.test: --ps-protocol counts both prepare and execute mysql-test/t/last_value.test: Disable ps-protocol for metadata tests --- mysql-test/t/features.test | 4 ++++ mysql-test/t/last_value.test | 3 +++ 2 files changed, 7 insertions(+) diff --git a/mysql-test/t/features.test b/mysql-test/t/features.test index a54b09a3fd3..cdfc9413da5 100644 --- a/mysql-test/t/features.test +++ b/mysql-test/t/features.test @@ -46,6 +46,8 @@ select * from t1 where MATCH(a,b) AGAINST ("collections"); select * from t1 where MATCH(a,b) AGAINST ("indexes"); drop table t1; +# We need the following when running with --ps-protocol +--replace_result 4 2 show status like "feature_fulltext"; @@ -68,6 +70,7 @@ create table t1 (a int); insert into t1 values (2); select (select a from t1 where t1.a=t2.a), a from t1 as t2; drop table t1; +--replace_result 8 4 show status like "feature_subquery"; --echo # @@ -104,4 +107,5 @@ SET @xml='a1b1c1b2a2'; SELECT extractValue(@xml,'/a'); select updatexml('
12
', '/','
') as upd1; +--replace_result 4 2 show status like "feature_xml"; diff --git a/mysql-test/t/last_value.test b/mysql-test/t/last_value.test index ee793f879da..41cfdb5482d 100644 --- a/mysql-test/t/last_value.test +++ b/mysql-test/t/last_value.test @@ -27,9 +27,12 @@ DROP TABLE t1; # # Test with different types # +# PS protocol gives slightly different metadata for the length --enable_metadata +--disable_ps_protocol SELECT LAST_VALUE(@last_a:=1,@last_b:=1); select @last_b; +--enable_ps_protocol SELECT LAST_VALUE(@last_a:=1,@last_b:=1.0); select @last_b; SELECT LAST_VALUE(@last_a:=1,@last_b:="hello"); From ae5bc059880c395ccf2cc51d5db1895dffc4f5f0 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Tue, 18 Sep 2012 15:14:19 +0300 Subject: [PATCH 267/289] Fix for MDEV-533: Confusing error code when doing auto-increment insert for out-of-range values create table t1 (a smallint primary key auto_increment); insert into t1 values(32767); insert into t1 values(NULL); ERROR 1062 (23000): Duplicate entry '32767' for key 'PRIMARY Now on always gets error HA_ERR_AUTOINC_RANGE=167 "Out of range value for column", independent of store engine, SQL Mode or number of inserted rows. This is an unique error that is easier to test for in replication. Another bug fix is that we now get an error when trying to insert a too big auto-generated value, even in non-strict mode. Before one get insted the max column value inserted. This patch also fixes some issues with inserting negative numbers in an auto-increment column. Fixed the ER_DUP_ENTRY and HA_ERR_AUTOINC_ERANGE are compared the same between master and slave. This ensures that replication works between an old server to a new slave for auto-increment overflow errors. Added SQLSTATE errors for handler errors Smaller bug fixes: * Added warnings for duplicate key errors when using INSERT IGNORE * Fixed bug when using --skip-log-bin followed by --log-bin, which did set log-bin to "0" * Allow one to see how cmake is called by using --just-print --just-configure BUILD/FINISH.sh: --just-print --just-configure now shows how cmake would be invoked. Good for understanding parameters to cmake. cmake/configure.pl: --just-print --just-configure now shows how cmake would be invoked. Good for understanding parameters to cmake. include/CMakeLists.txt: Added handler_state.h include/handler_state.h: SQLSTATE for handler error messages. Required for HA_ERR_AUTOINC_ERANGE, but solves also some other cases. mysql-test/extra/binlog_tests/binlog.test: Fixed old wrong behaviour Added more tests mysql-test/extra/binlog_tests/binlog_insert_delayed.test: Reset binary log to only print what's necessary in show_binlog_events mysql-test/extra/rpl_tests/rpl_auto_increment.test: Update to new error codes mysql-test/extra/rpl_tests/rpl_insert_delayed.test: Ignore warnings as this depends on how the test is run mysql-test/include/strict_autoinc.inc: On now gets an error on overflow mysql-test/r/auto_increment.result: Update results after fixing error message mysql-test/r/auto_increment_ranges_innodb.result: Test new behaviour mysql-test/r/auto_increment_ranges_myisam.result: Test new behaviour mysql-test/r/commit_1innodb.result: Added warnings for duplicate key error mysql-test/r/create.result: Added warnings for duplicate key error mysql-test/r/insert.result: Added warnings for duplicate key error mysql-test/r/insert_select.result: Added warnings for duplicate key error mysql-test/r/insert_update.result: Added warnings for duplicate key error mysql-test/r/mix2_myisam.result: Added warnings for duplicate key error mysql-test/r/myisam_mrr.result: Added warnings for duplicate key error mysql-test/r/null_key.result: Added warnings for duplicate key error mysql-test/r/replace.result: Update to new error codes mysql-test/r/strict_autoinc_1myisam.result: Update to new error codes mysql-test/r/strict_autoinc_2innodb.result: Update to new error codes mysql-test/r/strict_autoinc_3heap.result: Update to new error codes mysql-test/r/trigger.result: Added warnings for duplicate key error mysql-test/r/xtradb_mrr.result: Added warnings for duplicate key error mysql-test/suite/binlog/r/binlog_innodb_row.result: Updated result mysql-test/suite/binlog/r/binlog_row_binlog.result: Out of range data for auto-increment is not inserted anymore mysql-test/suite/binlog/r/binlog_statement_insert_delayed.result: Updated result mysql-test/suite/binlog/r/binlog_stm_binlog.result: Out of range data for auto-increment is not inserted anymore mysql-test/suite/binlog/r/binlog_unsafe.result: Updated result mysql-test/suite/innodb/r/innodb-autoinc.result: Update to new error codes mysql-test/suite/innodb/r/innodb-lock.result: Updated results mysql-test/suite/innodb/r/innodb.result: Updated results mysql-test/suite/innodb/r/innodb_bug56947.result: Updated results mysql-test/suite/innodb/r/innodb_mysql.result: Updated results mysql-test/suite/innodb/t/innodb-autoinc.test: Update to new error codes mysql-test/suite/maria/maria3.result: Updated result mysql-test/suite/maria/mrr.result: Updated result mysql-test/suite/optimizer_unfixed_bugs/r/bug43617.result: Updated result mysql-test/suite/rpl/r/rpl_auto_increment.result: Update to new error codes mysql-test/suite/rpl/r/rpl_insert_delayed,stmt.rdiff: Updated results mysql-test/suite/rpl/r/rpl_loaddatalocal.result: Updated results mysql-test/t/auto_increment.test: Update to new error codes mysql-test/t/auto_increment_ranges.inc: Test new behaviour mysql-test/t/auto_increment_ranges_innodb.test: Test new behaviour mysql-test/t/auto_increment_ranges_myisam.test: Test new behaviour mysql-test/t/replace.test: Update to new error codes mysys/my_getopt.c: Fixed bug when using --skip-log-bin followed by --log-bin, which did set log-bin to "0" sql/handler.cc: Ignore negative values for signed auto-increment columns Always give an error if we get an overflow for an auto-increment-column (instead of inserting the max value) Ensure that the row number is correct for the out-of-range-value error message. ****** Fixed wrong printing of column namn for "Out of range value" errors Fixed that INSERT_ID is correctly replicated also for out-of-range autoincrement values Fixed that print_keydup_error() can also be used to generate warnings ****** Return HA_ERR_AUTOINC_ERANGE (167) instead of ER_WARN_DATA_OUT_OF_RANGE for auto-increment overflow sql/handler.h: Allow INSERT IGNORE to continue also after out-of-range inserts. Fixed that print_keydup_error() can also be used to generate warnings sql/log_event.cc: Added DBUG_PRINT Fixed the ER_AUTOINC_READ_FAILED, ER_DUP_ENTRY and HA_ERR_AUTOINC_ERANGE are compared the same between master and slave. This ensures that replication works between an old server to a new slave for auto-increment overflow errors. sql/sql_insert.cc: Add warnings for duplicate key errors when using INSERT IGNORE sql/sql_state.c: Added handler errors sql/sql_table.cc: Update call to print_keydup_error() storage/innobase/handler/ha_innodb.cc: Fixed increment handling of auto-increment columns to be consistent with rest of MariaDB. storage/xtradb/handler/ha_innodb.cc: Fixed increment handling of auto-increment columns to be consistent with rest of MariaDB. --- BUILD/FINISH.sh | 6 + cmake/configure.pl | 7 + include/CMakeLists.txt | 1 + include/handler_state.h | 21 ++ mysql-test/extra/binlog_tests/binlog.test | 47 ++- .../binlog_tests/binlog_insert_delayed.test | 1 + .../extra/rpl_tests/rpl_auto_increment.test | 5 +- .../extra/rpl_tests/rpl_insert_delayed.test | 2 + mysql-test/include/strict_autoinc.inc | 3 +- mysql-test/r/auto_increment.result | 7 +- .../r/auto_increment_ranges_innodb.result | 266 +++++++++++++++++ .../r/auto_increment_ranges_myisam.result | 272 ++++++++++++++++++ mysql-test/r/commit_1innodb.result | 2 + mysql-test/r/create.result | 2 + mysql-test/r/insert.result | 12 +- mysql-test/r/insert_select.result | 4 + mysql-test/r/insert_update.result | 4 + mysql-test/r/mix2_myisam.result | 2 + mysql-test/r/myisam_mrr.result | 2 + mysql-test/r/null_key.result | 2 + mysql-test/r/replace.result | 4 +- mysql-test/r/strict_autoinc_1myisam.result | 4 +- mysql-test/r/strict_autoinc_2innodb.result | 4 +- mysql-test/r/strict_autoinc_3heap.result | 4 +- mysql-test/r/trigger.result | 2 + mysql-test/r/xtradb_mrr.result | 2 + .../suite/binlog/r/binlog_innodb_row.result | 2 + .../suite/binlog/r/binlog_row_binlog.result | 87 +++--- .../r/binlog_statement_insert_delayed.result | 4 +- .../suite/binlog/r/binlog_stm_binlog.result | 90 ++++-- .../suite/binlog/r/binlog_unsafe.result | 1 + .../suite/innodb/r/innodb-autoinc.result | 24 +- mysql-test/suite/innodb/r/innodb-lock.result | 4 + mysql-test/suite/innodb/r/innodb.result | 2 + .../suite/innodb/r/innodb_bug56947.result | 2 +- mysql-test/suite/innodb/r/innodb_mysql.result | 5 + mysql-test/suite/innodb/t/innodb-autoinc.test | 24 +- mysql-test/suite/maria/maria3.result | 2 + mysql-test/suite/maria/mrr.result | 2 + .../optimizer_unfixed_bugs/r/bug43617.result | 4 + .../suite/rpl/r/rpl_auto_increment.result | 19 +- .../suite/rpl/r/rpl_insert_delayed,stmt.rdiff | 4 +- .../suite/rpl/r/rpl_loaddatalocal.result | 2 + mysql-test/t/auto_increment.test | 5 +- mysql-test/t/auto_increment_ranges.inc | 240 ++++++++++++++++ .../t/auto_increment_ranges_innodb.test | 7 + .../t/auto_increment_ranges_myisam.test | 7 + mysql-test/t/replace.test | 4 +- mysys/my_getopt.c | 10 +- sql/handler.cc | 52 ++-- sql/handler.h | 5 +- sql/log_event.cc | 36 ++- sql/sql_insert.cc | 5 + sql/sql_state.c | 2 + sql/sql_table.cc | 2 +- storage/innobase/handler/ha_innodb.cc | 29 +- storage/xtradb/handler/ha_innodb.cc | 29 +- 57 files changed, 1227 insertions(+), 172 deletions(-) create mode 100644 include/handler_state.h create mode 100644 mysql-test/r/auto_increment_ranges_innodb.result create mode 100644 mysql-test/r/auto_increment_ranges_myisam.result create mode 100644 mysql-test/t/auto_increment_ranges.inc create mode 100644 mysql-test/t/auto_increment_ranges_innodb.test create mode 100644 mysql-test/t/auto_increment_ranges_myisam.test diff --git a/BUILD/FINISH.sh b/BUILD/FINISH.sh index 1bbc47341c9..7f8859dde54 100644 --- a/BUILD/FINISH.sh +++ b/BUILD/FINISH.sh @@ -21,6 +21,12 @@ extra_configs="$extra_configs $local_infile_configs $EXTRA_CONFIGS" configure="./configure $base_configs $extra_configs" +if test "$just_print" = "1" -a "$just_configure" = "1" +then + just_print="" + configure="$configure --print" +fi + commands="\ /bin/rm -rf configure; /bin/rm -rf CMakeCache.txt CMakeFiles/ diff --git a/cmake/configure.pl b/cmake/configure.pl index 69f973c41fb..3a7d187c0be 100644 --- a/cmake/configure.pl +++ b/cmake/configure.pl @@ -25,6 +25,7 @@ my $cmakeargs = ""; # Assume this script is in /cmake my $srcdir = dirname(dirname(abs_path($0))); my $cmake_install_prefix=""; +my $just_print= 0; # Sets installation directory, bindir, libdir, libexecdir etc # the equivalent CMake variables are given without prefix @@ -113,6 +114,11 @@ foreach my $option (@ARGV) system("cmake ${srcdir} -LH"); exit(0); } + if ($option =~ /print/) + { + $just_print=1; + next; + } if($option =~ /with-plugins=/) { my @plugins= split(/,/, substr($option,13)); @@ -223,6 +229,7 @@ foreach my $option (@ARGV) } print("configure.pl : calling cmake $srcdir $cmakeargs\n"); +exit(0) if ($just_print); unlink("CMakeCache.txt"); my $rc = system("cmake $srcdir $cmakeargs"); exit($rc); diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index a90238dbd42..95850da382b 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -51,6 +51,7 @@ SET(HEADERS m_ctype.h my_attribute.h my_compiler.h + handler_state.h ) INSTALL(FILES ${HEADERS} DESTINATION ${INSTALL_INCLUDEDIR} COMPONENT Development) diff --git a/include/handler_state.h b/include/handler_state.h new file mode 100644 index 00000000000..65604a672fb --- /dev/null +++ b/include/handler_state.h @@ -0,0 +1,21 @@ +/* + Map handler error message to sql states. Note that this list MUST be in + increasing order! + See sql_state.c for usage +*/ + +{ HA_ERR_KEY_NOT_FOUND, "02000", "" }, +{ HA_ERR_FOUND_DUPP_KEY, "23000", "" }, +{ HA_ERR_WRONG_COMMAND, "0A000", "" }, +{ HA_ERR_UNSUPPORTED, "0A000", "" }, +{ HA_WRONG_CREATE_OPTION, "0A000", "" }, +{ HA_ERR_FOUND_DUPP_UNIQUE, "23000", "" }, +{ HA_ERR_UNKNOWN_CHARSET, "0A000", "" }, +{ HA_ERR_READ_ONLY_TRANSACTION, "25000", "" }, +{ HA_ERR_LOCK_DEADLOCK, "40001", "" }, +{ HA_ERR_NO_REFERENCED_ROW, "23000", "" }, +{ HA_ERR_ROW_IS_REFERENCED, "23000", "" }, +{ HA_ERR_TABLE_EXIST, "42S01", "" }, +{ HA_ERR_FOREIGN_DUPLICATE_KEY, "23000", "" }, +{ HA_ERR_TABLE_READONLY, "25000", "" }, +{ HA_ERR_AUTOINC_ERANGE, "22003", "" }, diff --git a/mysql-test/extra/binlog_tests/binlog.test b/mysql-test/extra/binlog_tests/binlog.test index 3bbc693ceda..5b57eab1005 100644 --- a/mysql-test/extra/binlog_tests/binlog.test +++ b/mysql-test/extra/binlog_tests/binlog.test @@ -205,16 +205,55 @@ DROP PROCEDURE p4; --echo End of 5.0 tests -# Test of a too big SET INSERT_ID: see if the truncated value goes -# into binlog (right), or the too big value (wrong); we look at the -# binlog further down with SHOW BINLOG EVENTS. +# Test of a too big SET INSERT_ID. +# This should generate an error and should not be put in binlog +# We look at the binlog further down with SHOW BINLOG EVENTS. + reset master; create table t1 (id tinyint auto_increment primary key); +insert into t1 values(5); set insert_id=128; -insert into t1 values(null); +--error 167 +insert into t1 values(null) /* Not binlogged */; + +# The followin insert ignore will be put in binlog +set insert_id=128; +insert ignore into t1 values(null) /* Insert 128 */; + +# Insert with duplicate key error should not go into binglo +set insert_id=5; +--error ER_DUP_ENTRY +insert into t1 values(null) /* Not binlogged */; + +# Insert with autogenerated key + duplicate key error should go into binlog +set insert_id=5; +insert ignore into t1 values(null) /* Insert 5 */; select * from t1; drop table t1; +# Same tests but with 2 rows inserted at a time + +create table t1 (id tinyint auto_increment primary key) engine=myisam; +set insert_id=128; +--error 167 +insert into t1 values(5),(null) /* Insert_id 128 */; + +# The followin insert ignore will be put in binlog +set insert_id=128; +insert ignore into t1 values (4),(null) /* Insert_id 128 */; + +# Insert with duplicate key error should not go into binglo +set insert_id=5; +--error ER_DUP_ENTRY +insert into t1 values(3),(null) /* Insert_id 5 */; + +# Insert with autogenerated key + duplicate key error should go into binlog +set insert_id=5; +insert ignore into t1 values(2),(null) /* Insert_id 5 */; +select * from t1 order by id; +drop table t1; + + # bug#22027 create table t1 (a int); create table if not exists t2 select * from t1; diff --git a/mysql-test/extra/binlog_tests/binlog_insert_delayed.test b/mysql-test/extra/binlog_tests/binlog_insert_delayed.test index 7b31a3ebf17..8f669fc1152 100644 --- a/mysql-test/extra/binlog_tests/binlog_insert_delayed.test +++ b/mysql-test/extra/binlog_tests/binlog_insert_delayed.test @@ -28,6 +28,7 @@ # BUG#20627: INSERT DELAYED does not honour auto_increment_* variables # Bug in this test: BUG#38068: binlog_stm_binlog fails sporadically in pushbuild +reset master; create table t1 (a int not null auto_increment, primary key (a)) engine=myisam; diff --git a/mysql-test/extra/rpl_tests/rpl_auto_increment.test b/mysql-test/extra/rpl_tests/rpl_auto_increment.test index bd5943d46ea..8cd86de8040 100644 --- a/mysql-test/extra/rpl_tests/rpl_auto_increment.test +++ b/mysql-test/extra/rpl_tests/rpl_auto_increment.test @@ -111,7 +111,7 @@ set auto_increment_increment=11; set auto_increment_offset=4; insert into t1 values(null); insert into t1 values(null); ---error ER_DUP_ENTRY +--error 167 insert into t1 values(null); select a, mod(a-@@auto_increment_offset,@@auto_increment_increment) from t1 order by a; @@ -120,6 +120,8 @@ create table t2 (a tinyint unsigned not null auto_increment primary key) engine= set auto_increment_increment=10; set auto_increment_offset=1; set insert_id=1000; +insert into t2 values(10); +--error 167 insert into t2 values(null); select a, mod(a-@@auto_increment_offset,@@auto_increment_increment) from t2 order by a; @@ -127,6 +129,7 @@ select a, mod(a-@@auto_increment_offset,@@auto_increment_increment) from t2 orde create table t3 like t1; set auto_increment_increment=1000; set auto_increment_offset=700; +--error 167 insert into t3 values(null); select * from t3 order by a; sync_slave_with_master; diff --git a/mysql-test/extra/rpl_tests/rpl_insert_delayed.test b/mysql-test/extra/rpl_tests/rpl_insert_delayed.test index df08622b0bd..62e90b629ba 100644 --- a/mysql-test/extra/rpl_tests/rpl_insert_delayed.test +++ b/mysql-test/extra/rpl_tests/rpl_insert_delayed.test @@ -102,7 +102,9 @@ CREATE TABLE t1(a int, UNIQUE(a)); --let $_start= query_get_value(SHOW MASTER STATUS, Position, 1) INSERT DELAYED IGNORE INTO t1 VALUES(1); +--disable_warnings INSERT DELAYED IGNORE INTO t1 VALUES(1); +--enable_warnings flush table t1; # to wait for INSERT DELAYED to be done if (`SELECT @@global.binlog_format = 'STATEMENT'`) { diff --git a/mysql-test/include/strict_autoinc.inc b/mysql-test/include/strict_autoinc.inc index 823efcc2040..3298008b66f 100644 --- a/mysql-test/include/strict_autoinc.inc +++ b/mysql-test/include/strict_autoinc.inc @@ -19,11 +19,12 @@ select count(*) from t1; set auto_increment_increment=1000; set auto_increment_offset=700; ---error ER_WARN_DATA_OUT_OF_RANGE +--error 167 insert into t1 values(null); select count(*) from t1; set @@sql_mode=@org_mode; +--error 167 insert into t1 values(null); select * from t1; diff --git a/mysql-test/r/auto_increment.result b/mysql-test/r/auto_increment.result index 30b4ff11227..12cbf294b69 100644 --- a/mysql-test/r/auto_increment.result +++ b/mysql-test/r/auto_increment.result @@ -150,7 +150,7 @@ select last_insert_id(); last_insert_id() 255 insert into t1 set i = null; -ERROR 23000: Duplicate entry '255' for key 'PRIMARY' +ERROR 22003: Out of range value for column 'i' at row 1 select last_insert_id(); last_insert_id() 255 @@ -162,8 +162,7 @@ select last_insert_id(); last_insert_id() 255 insert into t1 set i = null; -Warnings: -Warning 1264 Out of range value for column 'i' at row 1 +ERROR 22003: Out of range value for column 'i' at row 1 select last_insert_id(); last_insert_id() 255 @@ -487,7 +486,7 @@ SELECT @@SESSION.AUTO_INCREMENT_OFFSET; @@SESSION.AUTO_INCREMENT_OFFSET 1 INSERT INTO t1 VALUES (NULL), (NULL), (NULL); -ERROR 22003: Out of range value for column 't1' at row 167 +ERROR 22003: Out of range value for column 'c1' at row 2 SELECT * FROM t1; c1 1 diff --git a/mysql-test/r/auto_increment_ranges_innodb.result b/mysql-test/r/auto_increment_ranges_innodb.result new file mode 100644 index 00000000000..fb936ddfd2b --- /dev/null +++ b/mysql-test/r/auto_increment_ranges_innodb.result @@ -0,0 +1,266 @@ +set default_storage_engine=innodb; +drop table if exists t1; +# +# Testing ranges with smallint +# +create table t1 (a smallint primary key auto_increment); +insert into t1 values(32767); +insert into t1 values(NULL); +ERROR 22003: Out of range value for column 'a' at row 1 +truncate table t1; +insert into t1 values(32767-1); +insert into t1 values(NULL); +insert into t1 values(NULL); +ERROR 22003: Out of range value for column 'a' at row 1 +select * from t1; +a +32766 +32767 +truncate table t1; +insert into t1 values(32767),(NULL); +ERROR 22003: Out of range value for column 'a' at row 2 +select * from t1; +a +truncate table t1; +insert into t1 values(32767-1),(NULL),(NULL); +ERROR 22003: Out of range value for column 'a' at row 3 +truncate table t1; +insert into t1 values(32767+1); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +select * from t1; +a +32767 +insert into t1 values(NULL); +ERROR 22003: Out of range value for column 'a' at row 1 +drop table t1; +# +# Testing ranges with unsigned smallint +# +create table t1 (a smallint unsigned primary key auto_increment); +insert into t1 values(65535); +insert into t1 values(NULL); +ERROR 22003: Out of range value for column 'a' at row 1 +truncate table t1; +insert into t1 values(65535-1); +insert into t1 values(NULL); +insert into t1 values(NULL); +ERROR 22003: Out of range value for column 'a' at row 1 +select * from t1; +a +65534 +65535 +truncate table t1; +insert into t1 values(65535),(NULL); +ERROR 22003: Out of range value for column 'a' at row 2 +select * from t1; +a +truncate table t1; +insert into t1 values(65535-1),(NULL),(NULL); +ERROR 22003: Out of range value for column 'a' at row 3 +truncate table t1; +insert into t1 values(65535+1); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +select * from t1; +a +65535 +insert into t1 values(NULL); +ERROR 22003: Out of range value for column 'a' at row 1 +drop table t1; +# +# Testing ranges with integer +# +create table t1 (a int primary key auto_increment); +insert into t1 values(2147483647); +insert into t1 values(NULL); +ERROR 22003: Out of range value for column 'a' at row 1 +truncate table t1; +insert into t1 values(2147483647-1); +insert into t1 values(NULL); +insert into t1 values(NULL); +ERROR 22003: Out of range value for column 'a' at row 1 +select * from t1; +a +2147483646 +2147483647 +truncate table t1; +insert into t1 values(2147483647),(NULL); +ERROR 22003: Out of range value for column 'a' at row 2 +select * from t1; +a +truncate table t1; +insert into t1 values(2147483647-1),(NULL),(NULL); +ERROR 22003: Out of range value for column 'a' at row 3 +truncate table t1; +insert into t1 values(2147483647+1); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +select * from t1; +a +2147483647 +insert into t1 values(NULL); +ERROR 22003: Out of range value for column 'a' at row 1 +drop table t1; +# +# Testing ranges with unsigned integer +# +create table t1 (a int unsigned primary key auto_increment); +insert into t1 values(4294967295); +insert into t1 values(NULL); +ERROR 22003: Out of range value for column 'a' at row 1 +truncate table t1; +insert into t1 values(4294967295-1); +insert into t1 values(NULL); +insert into t1 values(NULL); +ERROR 22003: Out of range value for column 'a' at row 1 +select * from t1; +a +4294967294 +4294967295 +truncate table t1; +insert into t1 values(4294967295),(NULL); +ERROR 22003: Out of range value for column 'a' at row 2 +select * from t1; +a +truncate table t1; +insert into t1 values(4294967295-1),(NULL),(NULL); +ERROR 22003: Out of range value for column 'a' at row 3 +truncate table t1; +insert into t1 values(4294967295+1); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +select * from t1; +a +4294967295 +insert into t1 values(NULL); +ERROR 22003: Out of range value for column 'a' at row 1 +drop table t1; +# +# Testing ranges with bigint +# +create table t1 (a bigint primary key auto_increment); +insert into t1 values(cast(9223372036854775807 as unsigned)); +insert into t1 values(NULL); +ERROR 22003: Out of range value for column 'a' at row 1 +truncate table t1; +insert into t1 values(cast(9223372036854775807 as unsigned)-1); +insert into t1 values(NULL); +insert into t1 values(NULL); +ERROR 22003: Out of range value for column 'a' at row 1 +select * from t1; +a +9223372036854775806 +9223372036854775807 +truncate table t1; +insert into t1 values(cast(9223372036854775807 as unsigned)),(NULL); +ERROR 22003: Out of range value for column 'a' at row 2 +select * from t1; +a +truncate table t1; +insert into t1 values(cast(9223372036854775807 as unsigned)-1),(NULL),(NULL); +ERROR 22003: Out of range value for column 'a' at row 3 +truncate table t1; +insert into t1 values(cast(9223372036854775807 as unsigned)+1); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +select * from t1; +a +9223372036854775807 +insert into t1 values(NULL); +ERROR 22003: Out of range value for column 'a' at row 1 +drop table t1; +# +# Testing ranges with unsigned bigint +# +create table t1 (a bigint unsigned primary key auto_increment); +insert into t1 values(18446744073709551615-1); +insert into t1 values(NULL); +ERROR HY000: Failed to read auto-increment value from storage engine +insert into t1 values(NULL); +ERROR HY000: Failed to read auto-increment value from storage engine +truncate table t1; +insert into t1 values(18446744073709551615-1); +insert into t1 values(NULL); +ERROR HY000: Failed to read auto-increment value from storage engine +insert into t1 values(NULL); +ERROR HY000: Failed to read auto-increment value from storage engine +select * from t1; +a +18446744073709551614 +truncate table t1; +insert into t1 values(18446744073709551615),(NULL); +ERROR HY000: Failed to read auto-increment value from storage engine +select * from t1; +a +truncate table t1; +insert into t1 values(18446744073709551615-1),(NULL),(NULL); +ERROR HY000: Failed to read auto-increment value from storage engine +drop table t1; +# +# Test IGNORE and strict mode +# +create table t1 (a smallint primary key auto_increment); +insert ignore into t1 values(32766),(NULL),(NULL),(1); +Warnings: +Warning 167 Out of range value for column 'a' at row 3 +select * from t1; +a +1 +32766 +32767 +truncate table t1; +set @org_mode=@@sql_mode; +set @@sql_mode='ansi,traditional'; +insert ignore into t1 values(32766),(NULL),(NULL); +Warnings: +Warning 167 Out of range value for column 'a' at row 3 +truncate table t1; +insert into t1 values(32766),(NULL),(NULL); +ERROR 22003: Out of range value for column 'a' at row 3 +set @@sql_mode=@org_mode; +drop table t1; +# +# Test auto increment with negative numbers +# +CREATE TABLE t1 (a INTEGER AUTO_INCREMENT, PRIMARY KEY (a)); +INSERT INTO t1 VALUES (NULL), (2), (-5), (NULL); +INSERT INTO t1 VALUES (NULL); +SELECT * FROM t1; +a +-5 +1 +2 +3 +5 +TRUNCATE TABLE t1; +INSERT INTO t1 VALUES (-5), (NULL); +SELECT * FROM t1; +a +-5 +1 +DROP TABLE t1; +# +# Test inserting a value out-of-range into an auto increment column +# +CREATE TABLE t1 (a smallint AUTO_INCREMENT, PRIMARY KEY (a)); +INSERT INTO t1 VALUES (2); +INSERT INTO t1 VALUES (32768); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +INSERT INTO t1 VALUES (NULL); +ERROR 22003: Out of range value for column 'a' at row 1 +SELECT * FROM t1; +a +2 +32767 +DROP TABLE t1; +# +# Test old behaviour +# +create table t1 (a smallint primary key auto_increment); +insert into t1 values(32766),(NULL); +delete from t1 where a=32767; +insert into t1 values(NULL); +ERROR 22003: Out of range value for column 'a' at row 1 +drop table t1; diff --git a/mysql-test/r/auto_increment_ranges_myisam.result b/mysql-test/r/auto_increment_ranges_myisam.result new file mode 100644 index 00000000000..5101321c864 --- /dev/null +++ b/mysql-test/r/auto_increment_ranges_myisam.result @@ -0,0 +1,272 @@ +set default_storage_engine=MYISAM; +drop table if exists t1; +# +# Testing ranges with smallint +# +create table t1 (a smallint primary key auto_increment); +insert into t1 values(32767); +insert into t1 values(NULL); +ERROR 22003: Out of range value for column 'a' at row 1 +truncate table t1; +insert into t1 values(32767-1); +insert into t1 values(NULL); +insert into t1 values(NULL); +ERROR 22003: Out of range value for column 'a' at row 1 +select * from t1; +a +32766 +32767 +truncate table t1; +insert into t1 values(32767),(NULL); +ERROR 22003: Out of range value for column 'a' at row 2 +select * from t1; +a +32767 +truncate table t1; +insert into t1 values(32767-1),(NULL),(NULL); +ERROR 22003: Out of range value for column 'a' at row 3 +truncate table t1; +insert into t1 values(32767+1); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +select * from t1; +a +32767 +insert into t1 values(NULL); +ERROR 22003: Out of range value for column 'a' at row 1 +drop table t1; +# +# Testing ranges with unsigned smallint +# +create table t1 (a smallint unsigned primary key auto_increment); +insert into t1 values(65535); +insert into t1 values(NULL); +ERROR 22003: Out of range value for column 'a' at row 1 +truncate table t1; +insert into t1 values(65535-1); +insert into t1 values(NULL); +insert into t1 values(NULL); +ERROR 22003: Out of range value for column 'a' at row 1 +select * from t1; +a +65534 +65535 +truncate table t1; +insert into t1 values(65535),(NULL); +ERROR 22003: Out of range value for column 'a' at row 2 +select * from t1; +a +65535 +truncate table t1; +insert into t1 values(65535-1),(NULL),(NULL); +ERROR 22003: Out of range value for column 'a' at row 3 +truncate table t1; +insert into t1 values(65535+1); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +select * from t1; +a +65535 +insert into t1 values(NULL); +ERROR 22003: Out of range value for column 'a' at row 1 +drop table t1; +# +# Testing ranges with integer +# +create table t1 (a int primary key auto_increment); +insert into t1 values(2147483647); +insert into t1 values(NULL); +ERROR 22003: Out of range value for column 'a' at row 1 +truncate table t1; +insert into t1 values(2147483647-1); +insert into t1 values(NULL); +insert into t1 values(NULL); +ERROR 22003: Out of range value for column 'a' at row 1 +select * from t1; +a +2147483646 +2147483647 +truncate table t1; +insert into t1 values(2147483647),(NULL); +ERROR 22003: Out of range value for column 'a' at row 2 +select * from t1; +a +2147483647 +truncate table t1; +insert into t1 values(2147483647-1),(NULL),(NULL); +ERROR 22003: Out of range value for column 'a' at row 3 +truncate table t1; +insert into t1 values(2147483647+1); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +select * from t1; +a +2147483647 +insert into t1 values(NULL); +ERROR 22003: Out of range value for column 'a' at row 1 +drop table t1; +# +# Testing ranges with unsigned integer +# +create table t1 (a int unsigned primary key auto_increment); +insert into t1 values(4294967295); +insert into t1 values(NULL); +ERROR 22003: Out of range value for column 'a' at row 1 +truncate table t1; +insert into t1 values(4294967295-1); +insert into t1 values(NULL); +insert into t1 values(NULL); +ERROR 22003: Out of range value for column 'a' at row 1 +select * from t1; +a +4294967294 +4294967295 +truncate table t1; +insert into t1 values(4294967295),(NULL); +ERROR 22003: Out of range value for column 'a' at row 2 +select * from t1; +a +4294967295 +truncate table t1; +insert into t1 values(4294967295-1),(NULL),(NULL); +ERROR 22003: Out of range value for column 'a' at row 3 +truncate table t1; +insert into t1 values(4294967295+1); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +select * from t1; +a +4294967295 +insert into t1 values(NULL); +ERROR 22003: Out of range value for column 'a' at row 1 +drop table t1; +# +# Testing ranges with bigint +# +create table t1 (a bigint primary key auto_increment); +insert into t1 values(cast(9223372036854775807 as unsigned)); +insert into t1 values(NULL); +ERROR 22003: Out of range value for column 'a' at row 1 +truncate table t1; +insert into t1 values(cast(9223372036854775807 as unsigned)-1); +insert into t1 values(NULL); +insert into t1 values(NULL); +ERROR 22003: Out of range value for column 'a' at row 1 +select * from t1; +a +9223372036854775806 +9223372036854775807 +truncate table t1; +insert into t1 values(cast(9223372036854775807 as unsigned)),(NULL); +ERROR 22003: Out of range value for column 'a' at row 2 +select * from t1; +a +9223372036854775807 +truncate table t1; +insert into t1 values(cast(9223372036854775807 as unsigned)-1),(NULL),(NULL); +ERROR 22003: Out of range value for column 'a' at row 3 +truncate table t1; +insert into t1 values(cast(9223372036854775807 as unsigned)+1); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +select * from t1; +a +9223372036854775807 +insert into t1 values(NULL); +ERROR 22003: Out of range value for column 'a' at row 1 +drop table t1; +# +# Testing ranges with unsigned bigint +# +create table t1 (a bigint unsigned primary key auto_increment); +insert into t1 values(18446744073709551615-1); +insert into t1 values(NULL); +ERROR HY000: Failed to read auto-increment value from storage engine +insert into t1 values(NULL); +ERROR HY000: Failed to read auto-increment value from storage engine +truncate table t1; +insert into t1 values(18446744073709551615-1); +insert into t1 values(NULL); +ERROR HY000: Failed to read auto-increment value from storage engine +insert into t1 values(NULL); +ERROR HY000: Failed to read auto-increment value from storage engine +select * from t1; +a +18446744073709551614 +truncate table t1; +insert into t1 values(18446744073709551615),(NULL); +ERROR HY000: Failed to read auto-increment value from storage engine +select * from t1; +a +18446744073709551615 +truncate table t1; +insert into t1 values(18446744073709551615-1),(NULL),(NULL); +ERROR HY000: Failed to read auto-increment value from storage engine +drop table t1; +# +# Test IGNORE and strict mode +# +create table t1 (a smallint primary key auto_increment); +insert ignore into t1 values(32766),(NULL),(NULL),(1); +Warnings: +Warning 167 Out of range value for column 'a' at row 3 +select * from t1; +a +1 +32766 +32767 +truncate table t1; +set @org_mode=@@sql_mode; +set @@sql_mode='ansi,traditional'; +insert ignore into t1 values(32766),(NULL),(NULL); +Warnings: +Warning 167 Out of range value for column 'a' at row 3 +truncate table t1; +insert into t1 values(32766),(NULL),(NULL); +ERROR 22003: Out of range value for column 'a' at row 3 +set @@sql_mode=@org_mode; +drop table t1; +# +# Test auto increment with negative numbers +# +CREATE TABLE t1 (a INTEGER AUTO_INCREMENT, PRIMARY KEY (a)); +INSERT INTO t1 VALUES (NULL), (2), (-5), (NULL); +INSERT INTO t1 VALUES (NULL); +SELECT * FROM t1; +a +-5 +1 +2 +3 +4 +TRUNCATE TABLE t1; +INSERT INTO t1 VALUES (-5), (NULL); +SELECT * FROM t1; +a +-5 +1 +DROP TABLE t1; +# +# Test inserting a value out-of-range into an auto increment column +# +CREATE TABLE t1 (a smallint AUTO_INCREMENT, PRIMARY KEY (a)); +INSERT INTO t1 VALUES (2); +INSERT INTO t1 VALUES (32768); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +INSERT INTO t1 VALUES (NULL); +ERROR 22003: Out of range value for column 'a' at row 1 +SELECT * FROM t1; +a +2 +32767 +DROP TABLE t1; +# +# Test old behaviour +# +create table t1 (a smallint primary key auto_increment); +insert into t1 values(32766),(NULL); +delete from t1 where a=32767; +insert into t1 values(NULL); +ERROR 22003: Out of range value for column 'a' at row 1 +drop table t1; diff --git a/mysql-test/r/commit_1innodb.result b/mysql-test/r/commit_1innodb.result index 3e3d75f66e4..af198edc4ca 100644 --- a/mysql-test/r/commit_1innodb.result +++ b/mysql-test/r/commit_1innodb.result @@ -529,6 +529,8 @@ SUCCESS # 13. Read-write statement: INSERT IGNORE, change 0 rows. # insert ignore t1 set a=2; +Warnings: +Warning 1062 Duplicate entry '2' for key 'a' call p_verify_status_increment(2, 2, 1, 0); SUCCESS diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index 0a6dff6d9a3..ba52959be84 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -2396,6 +2396,8 @@ a b drop table t1; create table if not exists t1 (a int unique, b int) ignore select 1 as a, 1 as b union select 1 as a, 2 as b; +Warnings: +Warning 1062 Duplicate entry '1' for key 'a' select * from t1; a b 1 1 diff --git a/mysql-test/r/insert.result b/mysql-test/r/insert.result index 655303be7f4..7110f541fb7 100644 --- a/mysql-test/r/insert.result +++ b/mysql-test/r/insert.result @@ -327,9 +327,11 @@ select row_count(); row_count() 3 insert ignore into t1 values (1, 1); +Warnings: +Warning 1062 Duplicate entry '1' for key 'PRIMARY' select row_count(); row_count() -0 +-1 replace into t1 values (1, 11); select row_count(); row_count() @@ -371,7 +373,15 @@ drop table t1,t2; create table t1 (id int primary key auto_increment, data int, unique(data)); insert ignore into t1 values(NULL,100),(NULL,110),(NULL,120); insert ignore into t1 values(NULL,10),(NULL,20),(NULL,110),(NULL,120),(NULL,100),(NULL,90); +Warnings: +Warning 1062 Duplicate entry '110' for key 'data' +Warning 1062 Duplicate entry '120' for key 'data' +Warning 1062 Duplicate entry '100' for key 'data' insert ignore into t1 values(NULL,130),(NULL,140),(500,110),(550,120),(450,100),(NULL,150); +Warnings: +Warning 1062 Duplicate entry '110' for key 'data' +Warning 1062 Duplicate entry '120' for key 'data' +Warning 1062 Duplicate entry '100' for key 'data' select * from t1 order by id; id data 1 100 diff --git a/mysql-test/r/insert_select.result b/mysql-test/r/insert_select.result index c952b914167..8bfc4e9215e 100644 --- a/mysql-test/r/insert_select.result +++ b/mysql-test/r/insert_select.result @@ -6,6 +6,10 @@ insert into t2 (payoutID) SELECT DISTINCT payoutID FROM t1; insert into t2 (payoutID) SELECT payoutID+10 FROM t1; ERROR 23000: Duplicate entry '16' for key 'PRIMARY' insert ignore into t2 (payoutID) SELECT payoutID+10 FROM t1; +Warnings: +Warning 1062 Duplicate entry '16' for key 'PRIMARY' +Warning 1062 Duplicate entry '16' for key 'PRIMARY' +Warning 1062 Duplicate entry '22' for key 'PRIMARY' select * from t2; payoutID 1 diff --git a/mysql-test/r/insert_update.result b/mysql-test/r/insert_update.result index c3acea5d11f..1987c5c0559 100644 --- a/mysql-test/r/insert_update.result +++ b/mysql-test/r/insert_update.result @@ -172,11 +172,15 @@ DROP TABLE t2; create table t1 (a int not null unique) engine=myisam; insert into t1 values (1),(2); insert ignore into t1 select 1 on duplicate key update a=2; +Warnings: +Warning 1062 Duplicate entry '2' for key 'a' select * from t1; a 1 2 insert ignore into t1 select a from t1 as t2 on duplicate key update a=t1.a+1 ; +Warnings: +Warning 1062 Duplicate entry '2' for key 'a' select * from t1; a 1 diff --git a/mysql-test/r/mix2_myisam.result b/mysql-test/r/mix2_myisam.result index e5f5857d2c9..6f90555325b 100644 --- a/mysql-test/r/mix2_myisam.result +++ b/mysql-test/r/mix2_myisam.result @@ -702,6 +702,8 @@ id 2 99 insert ignore into t1 values (100,1,2,'D'),(1,1,99,'D'); +Warnings: +Warning 1062 Duplicate entry '1-1' for key 'PRIMARY' commit; select id,id3 from t1; id id3 diff --git a/mysql-test/r/myisam_mrr.result b/mysql-test/r/myisam_mrr.result index 03d212dbc04..bd50df7c40e 100644 --- a/mysql-test/r/myisam_mrr.result +++ b/mysql-test/r/myisam_mrr.result @@ -278,6 +278,8 @@ bb-1 NULL cc-2 NULL-1 drop table t1, t2, t3, t4; create table t1 (a int, b int not null,unique key (a,b),index(b)); insert ignore into t1 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(null,7),(9,9),(8,8),(7,7),(null,9),(null,9),(6,6); +Warnings: +Warning 1062 Duplicate entry '6-6' for key 'a' create table t2 like t1; insert into t2 select * from t1; alter table t1 modify b blob not null, add c int not null, drop key a, add unique key (a,b(20),c), drop key b, add key (b(10)); diff --git a/mysql-test/r/null_key.result b/mysql-test/r/null_key.result index 35c6ebe1442..ba79011f53e 100644 --- a/mysql-test/r/null_key.result +++ b/mysql-test/r/null_key.result @@ -1,6 +1,8 @@ drop table if exists t1,t2; create table t1 (a int, b int not null,unique key (a,b),index(b)) engine=myisam; insert ignore into t1 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(null,7),(9,9),(8,8),(7,7),(null,9),(null,9),(6,6); +Warnings: +Warning 1062 Duplicate entry '6-6' for key 'a' explain select * from t1 where a is null; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ref a a 5 const 3 Using where; Using index diff --git a/mysql-test/r/replace.result b/mysql-test/r/replace.result index 842302c89ac..59b8565f671 100644 --- a/mysql-test/r/replace.result +++ b/mysql-test/r/replace.result @@ -13,9 +13,9 @@ drop table t1; create table t1 (a tinyint not null auto_increment primary key, b char(20) default "default_value"); insert into t1 values (126,"first"),(63, "middle"),(0,"last"); insert into t1 values (0,"error"); -ERROR 23000: Duplicate entry '127' for key 'PRIMARY' +ERROR 22003: Out of range value for column 'a' at row 1 replace into t1 values (0,"error"); -ERROR 23000: Duplicate entry '127' for key 'PRIMARY' +ERROR 22003: Out of range value for column 'a' at row 1 replace into t1 values (126,"first updated"); replace into t1 values (63,default); select * from t1; diff --git a/mysql-test/r/strict_autoinc_1myisam.result b/mysql-test/r/strict_autoinc_1myisam.result index afcccb1c40f..b22540f295b 100644 --- a/mysql-test/r/strict_autoinc_1myisam.result +++ b/mysql-test/r/strict_autoinc_1myisam.result @@ -20,9 +20,7 @@ count(*) 0 set @@sql_mode=@org_mode; insert into t1 values(null); -Warnings: -Warning 1264 Out of range value for column 'a' at row 1 +ERROR 22003: Out of range value for column 'a' at row 1 select * from t1; a -127 drop table t1; diff --git a/mysql-test/r/strict_autoinc_2innodb.result b/mysql-test/r/strict_autoinc_2innodb.result index e534286e2a2..1cf720da12a 100644 --- a/mysql-test/r/strict_autoinc_2innodb.result +++ b/mysql-test/r/strict_autoinc_2innodb.result @@ -20,9 +20,7 @@ count(*) 0 set @@sql_mode=@org_mode; insert into t1 values(null); -Warnings: -Warning 1264 Out of range value for column 'a' at row 1 +ERROR 22003: Out of range value for column 'a' at row 1 select * from t1; a -127 drop table t1; diff --git a/mysql-test/r/strict_autoinc_3heap.result b/mysql-test/r/strict_autoinc_3heap.result index 0a31da04460..21eea537af5 100644 --- a/mysql-test/r/strict_autoinc_3heap.result +++ b/mysql-test/r/strict_autoinc_3heap.result @@ -20,9 +20,7 @@ count(*) 0 set @@sql_mode=@org_mode; insert into t1 values(null); -Warnings: -Warning 1264 Out of range value for column 'a' at row 1 +ERROR 22003: Out of range value for column 'a' at row 1 select * from t1; a -127 drop table t1; diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result index ef998abafcf..6047d00c858 100644 --- a/mysql-test/r/trigger.result +++ b/mysql-test/r/trigger.result @@ -165,6 +165,8 @@ select @log; (BEFORE_INSERT: new=(id=1, data=1))(AFTER_INSERT: new=(id=1, data=1)) set @log:= ""; insert ignore t1 values (1, 2); +Warnings: +Warning 1062 Duplicate entry '1' for key 'PRIMARY' select @log; @log (BEFORE_INSERT: new=(id=1, data=2)) diff --git a/mysql-test/r/xtradb_mrr.result b/mysql-test/r/xtradb_mrr.result index 069d3c25826..15b750d2fd3 100644 --- a/mysql-test/r/xtradb_mrr.result +++ b/mysql-test/r/xtradb_mrr.result @@ -276,6 +276,8 @@ bb-1 NULL cc-2 NULL-1 drop table t1, t2, t3, t4; create table t1 (a int, b int not null,unique key (a,b),index(b)); insert ignore into t1 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(null,7),(9,9),(8,8),(7,7),(null,9),(null,9),(6,6); +Warnings: +Warning 1062 Duplicate entry '6-6' for key 'a' create table t2 like t1; insert into t2 select * from t1; alter table t1 modify b blob not null, add c int not null, drop key a, add unique key (a,b(20),c), drop key b, add key (b(10)); diff --git a/mysql-test/suite/binlog/r/binlog_innodb_row.result b/mysql-test/suite/binlog/r/binlog_innodb_row.result index 61f961f16da..043f363c9c7 100644 --- a/mysql-test/suite/binlog/r/binlog_innodb_row.result +++ b/mysql-test/suite/binlog/r/binlog_innodb_row.result @@ -69,6 +69,8 @@ INSERT INTO t1 VALUES (1); START TRANSACTION; INSERT INTO t2 VALUES (1); INSERT IGNORE INTO t1 VALUES (1); +Warnings: +Warning 1062 Duplicate entry '1' for key 'PRIMARY' COMMIT; INSERT INTO t1 VALUES (2); START TRANSACTION; diff --git a/mysql-test/suite/binlog/r/binlog_row_binlog.result b/mysql-test/suite/binlog/r/binlog_row_binlog.result index 95477d13b50..a3ee21b9957 100644 --- a/mysql-test/suite/binlog/r/binlog_row_binlog.result +++ b/mysql-test/suite/binlog/r/binlog_row_binlog.result @@ -578,13 +578,46 @@ DROP PROCEDURE p4; End of 5.0 tests reset master; create table t1 (id tinyint auto_increment primary key); +insert into t1 values(5); set insert_id=128; -insert into t1 values(null); +insert into t1 values(null) /* Not binlogged */; +ERROR 22003: Out of range value for column 'id' at row 1 +set insert_id=128; +insert ignore into t1 values(null) /* Insert 128 */; Warnings: -Warning 1264 Out of range value for column 'id' at row 1 +Warning 167 Out of range value for column 'id' at row 1 +set insert_id=5; +insert into t1 values(null) /* Not binlogged */; +ERROR 23000: Duplicate entry '5' for key 'PRIMARY' +set insert_id=5; +insert ignore into t1 values(null) /* Insert 5 */; +Warnings: +Warning 1062 Duplicate entry '5' for key 'PRIMARY' select * from t1; id -127 +5 +drop table t1; +create table t1 (id tinyint auto_increment primary key) engine=myisam; +set insert_id=128; +insert into t1 values(5),(null) /* Insert_id 128 */; +ERROR 22003: Out of range value for column 'id' at row 2 +set insert_id=128; +insert ignore into t1 values (4),(null) /* Insert_id 128 */; +Warnings: +Warning 167 Out of range value for column 'id' at row 2 +set insert_id=5; +insert into t1 values(3),(null) /* Insert_id 5 */; +ERROR 23000: Duplicate entry '5' for key 'PRIMARY' +set insert_id=5; +insert ignore into t1 values(2),(null) /* Insert_id 5 */; +Warnings: +Warning 1062 Duplicate entry '5' for key 'PRIMARY' +select * from t1 order by id; +id +2 +3 +4 +5 drop table t1; create table t1 (a int); create table if not exists t2 select * from t1; @@ -603,6 +636,24 @@ master-bin.000001 # Table_map # # table_id: # (test.t1) master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F master-bin.000001 # Query # # COMMIT master-bin.000001 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ +master-bin.000001 # Query # # use `test`; create table t1 (id tinyint auto_increment primary key) engine=myisam +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ master-bin.000001 # Query # # use `test`; create table t1 (a int) master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; CREATE TABLE IF NOT EXISTS `t2` ( @@ -625,6 +676,7 @@ master-bin.000001 # Table_map # # table_id: # (mysql.user) master-bin.000001 # Delete_rows # # table_id: # flags: STMT_END_F master-bin.000001 # Query # # COMMIT drop table t1,t2,t3,tt1; +reset master; create table t1 (a int not null auto_increment, primary key (a)) engine=myisam; insert /* before delayed */ delayed /* after delayed */ into t1 values (207); insert /*! delayed */ into t1 values (null); @@ -632,35 +684,6 @@ insert delayed into t1 values (300); FLUSH TABLES; show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Query # # use `test`; create table t1 (id tinyint auto_increment primary key) -master-bin.000001 # Query # # BEGIN -master-bin.000001 # Table_map # # table_id: # (test.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Query # # COMMIT -master-bin.000001 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ -master-bin.000001 # Query # # use `test`; create table t1 (a int) -master-bin.000001 # Query # # BEGIN -master-bin.000001 # Query # # use `test`; CREATE TABLE IF NOT EXISTS `t2` ( - `a` int(11) DEFAULT NULL -) -master-bin.000001 # Query # # COMMIT -master-bin.000001 # Query # # use `test`; CREATE TABLE IF NOT EXISTS `t3` ( - `a` int(11) DEFAULT NULL -) -master-bin.000001 # Query # # BEGIN -master-bin.000001 # Table_map # # table_id: # (mysql.user) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Query # # COMMIT -master-bin.000001 # Query # # BEGIN -master-bin.000001 # Table_map # # table_id: # (mysql.user) -master-bin.000001 # Update_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Query # # COMMIT -master-bin.000001 # Query # # BEGIN -master-bin.000001 # Table_map # # table_id: # (mysql.user) -master-bin.000001 # Delete_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Query # # COMMIT -master-bin.000001 # Query # # use `test`; DROP TEMPORARY TABLE IF EXISTS `tt1` /* generated by server */ -master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`t2`,`t3` /* generated by server */ master-bin.000001 # Query # # use `test`; create table t1 (a int not null auto_increment, primary key (a)) engine=myisam master-bin.000001 # Query # # BEGIN master-bin.000001 # Table_map # # table_id: # (test.t1) diff --git a/mysql-test/suite/binlog/r/binlog_statement_insert_delayed.result b/mysql-test/suite/binlog/r/binlog_statement_insert_delayed.result index cdcc96b94b0..15610296d5c 100644 --- a/mysql-test/suite/binlog/r/binlog_statement_insert_delayed.result +++ b/mysql-test/suite/binlog/r/binlog_statement_insert_delayed.result @@ -1,3 +1,4 @@ +reset master; create table t1 (a int not null auto_increment, primary key (a)) engine=myisam; insert /* before delayed */ delayed /* after delayed */ into t1 values (207); insert /*! delayed */ into t1 values (null); @@ -5,9 +6,6 @@ insert delayed into t1 values (300); FLUSH TABLES; show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Query # # BEGIN -master-bin.000001 # Query # # use `mtr`; INSERT INTO test_suppressions (pattern) VALUES ( NAME_CONST('pattern',_latin1'Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT' COLLATE 'latin1_swedish_ci')) -master-bin.000001 # Query # # COMMIT master-bin.000001 # Query # # use `test`; create table t1 (a int not null auto_increment, primary key (a)) engine=myisam master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; insert /* before delayed */ /* after delayed */ into t1 values (207) diff --git a/mysql-test/suite/binlog/r/binlog_stm_binlog.result b/mysql-test/suite/binlog/r/binlog_stm_binlog.result index 062f4f4e906..68e76921ff3 100644 --- a/mysql-test/suite/binlog/r/binlog_stm_binlog.result +++ b/mysql-test/suite/binlog/r/binlog_stm_binlog.result @@ -387,13 +387,46 @@ DROP PROCEDURE p4; End of 5.0 tests reset master; create table t1 (id tinyint auto_increment primary key); +insert into t1 values(5); set insert_id=128; -insert into t1 values(null); +insert into t1 values(null) /* Not binlogged */; +ERROR 22003: Out of range value for column 'id' at row 1 +set insert_id=128; +insert ignore into t1 values(null) /* Insert 128 */; Warnings: -Warning 1264 Out of range value for column 'id' at row 1 +Warning 167 Out of range value for column 'id' at row 1 +set insert_id=5; +insert into t1 values(null) /* Not binlogged */; +ERROR 23000: Duplicate entry '5' for key 'PRIMARY' +set insert_id=5; +insert ignore into t1 values(null) /* Insert 5 */; +Warnings: +Warning 1062 Duplicate entry '5' for key 'PRIMARY' select * from t1; id -127 +5 +drop table t1; +create table t1 (id tinyint auto_increment primary key) engine=myisam; +set insert_id=128; +insert into t1 values(5),(null) /* Insert_id 128 */; +ERROR 22003: Out of range value for column 'id' at row 2 +set insert_id=128; +insert ignore into t1 values (4),(null) /* Insert_id 128 */; +Warnings: +Warning 167 Out of range value for column 'id' at row 2 +set insert_id=5; +insert into t1 values(3),(null) /* Insert_id 5 */; +ERROR 23000: Duplicate entry '5' for key 'PRIMARY' +set insert_id=5; +insert ignore into t1 values(2),(null) /* Insert_id 5 */; +Warnings: +Warning 1062 Duplicate entry '5' for key 'PRIMARY' +select * from t1 order by id; +id +2 +3 +4 +5 drop table t1; create table t1 (a int); create table if not exists t2 select * from t1; @@ -408,8 +441,33 @@ show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # use `test`; create table t1 (id tinyint auto_increment primary key) master-bin.000001 # Query # # BEGIN -master-bin.000001 # Intvar # # INSERT_ID=127 -master-bin.000001 # Query # # use `test`; insert into t1 values(null) +master-bin.000001 # Query # # use `test`; insert into t1 values(5) +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Intvar # # INSERT_ID=128 +master-bin.000001 # Query # # use `test`; insert ignore into t1 values(null) /* Insert 128 */ +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Intvar # # INSERT_ID=5 +master-bin.000001 # Query # # use `test`; insert ignore into t1 values(null) /* Insert 5 */ +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ +master-bin.000001 # Query # # use `test`; create table t1 (id tinyint auto_increment primary key) engine=myisam +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Intvar # # INSERT_ID=128 +master-bin.000001 # Query # # use `test`; insert into t1 values(5),(null) /* Insert_id 128 */ +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Intvar # # INSERT_ID=128 +master-bin.000001 # Query # # use `test`; insert ignore into t1 values (4),(null) /* Insert_id 128 */ +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Intvar # # INSERT_ID=5 +master-bin.000001 # Query # # use `test`; insert into t1 values(3),(null) /* Insert_id 5 */ +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Intvar # # INSERT_ID=5 +master-bin.000001 # Query # # use `test`; insert ignore into t1 values(2),(null) /* Insert_id 5 */ master-bin.000001 # Query # # COMMIT master-bin.000001 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ master-bin.000001 # Query # # use `test`; create table t1 (a int) @@ -426,6 +484,7 @@ master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `mysql`; DELETE FROM user WHERE host='localhost' AND user='@#@' master-bin.000001 # Query # # COMMIT drop table t1,t2,t3,tt1; +reset master; create table t1 (a int not null auto_increment, primary key (a)) engine=myisam; insert /* before delayed */ delayed /* after delayed */ into t1 values (207); insert /*! delayed */ into t1 values (null); @@ -433,27 +492,6 @@ insert delayed into t1 values (300); FLUSH TABLES; show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Query # # use `test`; create table t1 (id tinyint auto_increment primary key) -master-bin.000001 # Query # # BEGIN -master-bin.000001 # Intvar # # INSERT_ID=127 -master-bin.000001 # Query # # use `test`; insert into t1 values(null) -master-bin.000001 # Query # # COMMIT -master-bin.000001 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ -master-bin.000001 # Query # # use `test`; create table t1 (a int) -master-bin.000001 # Query # # use `test`; create table if not exists t2 select * from t1 -master-bin.000001 # Query # # use `test`; create temporary table tt1 (a int) -master-bin.000001 # Query # # use `test`; create table if not exists t3 like tt1 -master-bin.000001 # Query # # BEGIN -master-bin.000001 # Query # # use `mysql`; INSERT INTO user SET host='localhost', user='@#@', password=password('Just a test') -master-bin.000001 # Query # # COMMIT -master-bin.000001 # Query # # BEGIN -master-bin.000001 # Query # # use `mysql`; UPDATE user SET password=password('Another password') WHERE host='localhost' AND user='@#@' -master-bin.000001 # Query # # COMMIT -master-bin.000001 # Query # # BEGIN -master-bin.000001 # Query # # use `mysql`; DELETE FROM user WHERE host='localhost' AND user='@#@' -master-bin.000001 # Query # # COMMIT -master-bin.000001 # Query # # use `test`; DROP TEMPORARY TABLE `tt1` /* generated by server */ -master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`t2`,`t3` /* generated by server */ master-bin.000001 # Query # # use `test`; create table t1 (a int not null auto_increment, primary key (a)) engine=myisam master-bin.000001 # Query # # BEGIN master-bin.000001 # Table_map # # table_id: # (test.t1) diff --git a/mysql-test/suite/binlog/r/binlog_unsafe.result b/mysql-test/suite/binlog/r/binlog_unsafe.result index 2cc1ebdd2d7..043b3d1e7a6 100644 --- a/mysql-test/suite/binlog/r/binlog_unsafe.result +++ b/mysql-test/suite/binlog/r/binlog_unsafe.result @@ -2682,6 +2682,7 @@ CREATE TABLE insert_2_keys (a INT UNIQUE KEY, b INT UNIQUE KEY); INSERT INTO insert_2_keys values (1, 1); INSERT IGNORE INTO insert_table SELECT * FROM filler_table; Warnings: +Warning 1062 Duplicate entry '1' for key 'PRIMARY' Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. INSERT IGNORE... SELECT is unsafe because the order in which rows are retrieved by the SELECT determines which (if any) rows are ignored. This order cannot be predicted and may differ on master and the slave. TRUNCATE TABLE insert_table; INSERT INTO insert_table SELECT * FROM filler_table ON DUPLICATE KEY UPDATE a = 1; diff --git a/mysql-test/suite/innodb/r/innodb-autoinc.result b/mysql-test/suite/innodb/r/innodb-autoinc.result index 9eb89bead74..8c4c1c20590 100644 --- a/mysql-test/suite/innodb/r/innodb-autoinc.result +++ b/mysql-test/suite/innodb/r/innodb-autoinc.result @@ -2,7 +2,7 @@ drop table if exists t1; CREATE TABLE t1 (c1 BIGINT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; INSERT INTO t1 VALUES (9223372036854775807, null); INSERT INTO t1 (c2) VALUES ('innodb'); -Got one of the listed errors +ERROR 22003: Out of range value for column 'c1' at row 1 SELECT * FROM t1; c1 c2 9223372036854775807 NULL @@ -10,7 +10,7 @@ DROP TABLE t1; CREATE TABLE t1 (c1 TINYINT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; INSERT INTO t1 VALUES (127, null); INSERT INTO t1 (c2) VALUES ('innodb'); -Got one of the listed errors +ERROR 22003: Out of range value for column 'c1' at row 1 SELECT * FROM t1; c1 c2 127 NULL @@ -18,7 +18,7 @@ DROP TABLE t1; CREATE TABLE t1 (c1 TINYINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; INSERT INTO t1 VALUES (255, null); INSERT INTO t1 (c2) VALUES ('innodb'); -Got one of the listed errors +ERROR 22003: Out of range value for column 'c1' at row 1 SELECT * FROM t1; c1 c2 255 NULL @@ -26,7 +26,7 @@ DROP TABLE t1; CREATE TABLE t1 (c1 SMALLINT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; INSERT INTO t1 VALUES (32767, null); INSERT INTO t1 (c2) VALUES ('innodb'); -Got one of the listed errors +ERROR 22003: Out of range value for column 'c1' at row 1 SELECT * FROM t1; c1 c2 32767 NULL @@ -34,7 +34,7 @@ DROP TABLE t1; CREATE TABLE t1 (c1 SMALLINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; INSERT INTO t1 VALUES (65535, null); INSERT INTO t1 (c2) VALUES ('innodb'); -Got one of the listed errors +ERROR 22003: Out of range value for column 'c1' at row 1 SELECT * FROM t1; c1 c2 65535 NULL @@ -42,7 +42,7 @@ DROP TABLE t1; CREATE TABLE t1 (c1 MEDIUMINT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; INSERT INTO t1 VALUES (8388607, null); INSERT INTO t1 (c2) VALUES ('innodb'); -Got one of the listed errors +ERROR 22003: Out of range value for column 'c1' at row 1 SELECT * FROM t1; c1 c2 8388607 NULL @@ -50,7 +50,7 @@ DROP TABLE t1; CREATE TABLE t1 (c1 MEDIUMINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; INSERT INTO t1 VALUES (16777215, null); INSERT INTO t1 (c2) VALUES ('innodb'); -Got one of the listed errors +ERROR 22003: Out of range value for column 'c1' at row 1 SELECT * FROM t1; c1 c2 16777215 NULL @@ -58,7 +58,7 @@ DROP TABLE t1; CREATE TABLE t1 (c1 INT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; INSERT INTO t1 VALUES (2147483647, null); INSERT INTO t1 (c2) VALUES ('innodb'); -Got one of the listed errors +ERROR 22003: Out of range value for column 'c1' at row 1 SELECT * FROM t1; c1 c2 2147483647 NULL @@ -66,7 +66,7 @@ DROP TABLE t1; CREATE TABLE t1 (c1 INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; INSERT INTO t1 VALUES (4294967295, null); INSERT INTO t1 (c2) VALUES ('innodb'); -Got one of the listed errors +ERROR 22003: Out of range value for column 'c1' at row 1 SELECT * FROM t1; c1 c2 4294967295 NULL @@ -74,7 +74,7 @@ DROP TABLE t1; CREATE TABLE t1 (c1 BIGINT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; INSERT INTO t1 VALUES (9223372036854775807, null); INSERT INTO t1 (c2) VALUES ('innodb'); -Got one of the listed errors +ERROR 22003: Out of range value for column 'c1' at row 1 SELECT * FROM t1; c1 c2 9223372036854775807 NULL @@ -567,7 +567,7 @@ Variable_name Value auto_increment_increment 65535 auto_increment_offset 65535 INSERT INTO t1 VALUES (NULL),(NULL); -ERROR 22003: Out of range value for column 't1' at row 167 +ERROR 22003: Out of range value for column 'c1' at row 1 SELECT * FROM t1; c1 1 @@ -858,7 +858,7 @@ PRIMARY KEY) ENGINE=InnoDB; INSERT INTO t2 SELECT c1 FROM t1; Got one of the listed errors INSERT INTO t2 SELECT NULL FROM t1; -Got one of the listed errors +ERROR 22003: Out of range value for column 'c1' at row 1 DROP TABLE t1; DROP TABLE t2; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; diff --git a/mysql-test/suite/innodb/r/innodb-lock.result b/mysql-test/suite/innodb/r/innodb-lock.result index 439a8d6513c..7191bcd238a 100644 --- a/mysql-test/suite/innodb/r/innodb-lock.result +++ b/mysql-test/suite/innodb/r/innodb-lock.result @@ -98,8 +98,12 @@ CREATE TABLE t1 (a INT PRIMARY KEY, b INT NOT NULL) ENGINE=InnoDB; INSERT INTO t1 VALUES(3,1); BEGIN; INSERT IGNORE INTO t1 VALUES(3,14); +Warnings: +Warning 1062 Duplicate entry '3' for key 'PRIMARY' BEGIN; INSERT IGNORE INTO t1 VALUES(3,23); +Warnings: +Warning 1062 Duplicate entry '3' for key 'PRIMARY' SELECT * FROM t1 FOR UPDATE; COMMIT; a b diff --git a/mysql-test/suite/innodb/r/innodb.result b/mysql-test/suite/innodb/r/innodb.result index bb4d783ccf4..f3f1b1ed045 100644 --- a/mysql-test/suite/innodb/r/innodb.result +++ b/mysql-test/suite/innodb/r/innodb.result @@ -816,6 +816,8 @@ id 1 2 insert ignore into t1 values (100,1,2,'D'),(1,1,99,'D'); +Warnings: +Warning 1062 Duplicate entry '1-1' for key 'PRIMARY' commit; select id,id3 from t1; id id3 diff --git a/mysql-test/suite/innodb/r/innodb_bug56947.result b/mysql-test/suite/innodb/r/innodb_bug56947.result index b279069d834..8b864b62e81 100644 --- a/mysql-test/suite/innodb/r/innodb_bug56947.result +++ b/mysql-test/suite/innodb/r/innodb_bug56947.result @@ -3,6 +3,6 @@ SET GLOBAL innodb_file_per_table=0; create table bug56947(a int not null) engine = innodb; CREATE TABLE `bug56947#1`(a int) ENGINE=InnoDB; alter table bug56947 add unique index (a); -ERROR HY000: Table 'test.bug56947#1' already exists +ERROR 42S01: Table 'test.bug56947#1' already exists drop table `bug56947#1`; drop table bug56947; diff --git a/mysql-test/suite/innodb/r/innodb_mysql.result b/mysql-test/suite/innodb/r/innodb_mysql.result index 2b3d24551c7..be2b4b28f6a 100644 --- a/mysql-test/suite/innodb/r/innodb_mysql.result +++ b/mysql-test/suite/innodb/r/innodb_mysql.result @@ -1480,10 +1480,15 @@ k a c 1 6 2 2 7 NULL insert ignore into t2 values (null,6,1),(10,8,1); +Warnings: +Warning 1062 Duplicate entry '6' for key 'idx_1' select last_insert_id(); last_insert_id() 0 insert ignore into t2 values (null,6,1),(null,8,1),(null,15,1),(null,20,1); +Warnings: +Warning 1062 Duplicate entry '6' for key 'idx_1' +Warning 1062 Duplicate entry '8' for key 'idx_1' select last_insert_id(); last_insert_id() 11 diff --git a/mysql-test/suite/innodb/t/innodb-autoinc.test b/mysql-test/suite/innodb/t/innodb-autoinc.test index 4f54a8ff957..888c73bacdf 100644 --- a/mysql-test/suite/innodb/t/innodb-autoinc.test +++ b/mysql-test/suite/innodb/t/innodb-autoinc.test @@ -11,7 +11,7 @@ drop table if exists t1; # CREATE TABLE t1 (c1 BIGINT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; INSERT INTO t1 VALUES (9223372036854775807, null); --- error ER_DUP_ENTRY,1062 +-- error 167 INSERT INTO t1 (c2) VALUES ('innodb'); SELECT * FROM t1; DROP TABLE t1; @@ -22,14 +22,14 @@ DROP TABLE t1; # TINYINT CREATE TABLE t1 (c1 TINYINT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; INSERT INTO t1 VALUES (127, null); --- error ER_DUP_ENTRY,1062 +-- error 167 INSERT INTO t1 (c2) VALUES ('innodb'); SELECT * FROM t1; DROP TABLE t1; CREATE TABLE t1 (c1 TINYINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; INSERT INTO t1 VALUES (255, null); --- error ER_DUP_ENTRY,1062 +-- error 167 INSERT INTO t1 (c2) VALUES ('innodb'); SELECT * FROM t1; DROP TABLE t1; @@ -38,14 +38,14 @@ DROP TABLE t1; # CREATE TABLE t1 (c1 SMALLINT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; INSERT INTO t1 VALUES (32767, null); --- error ER_DUP_ENTRY,1062 +-- error 167 INSERT INTO t1 (c2) VALUES ('innodb'); SELECT * FROM t1; DROP TABLE t1; CREATE TABLE t1 (c1 SMALLINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; INSERT INTO t1 VALUES (65535, null); --- error ER_DUP_ENTRY,1062 +-- error 167 INSERT INTO t1 (c2) VALUES ('innodb'); SELECT * FROM t1; DROP TABLE t1; @@ -54,14 +54,14 @@ DROP TABLE t1; # CREATE TABLE t1 (c1 MEDIUMINT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; INSERT INTO t1 VALUES (8388607, null); --- error ER_DUP_ENTRY,1062 +-- error 167 INSERT INTO t1 (c2) VALUES ('innodb'); SELECT * FROM t1; DROP TABLE t1; CREATE TABLE t1 (c1 MEDIUMINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; INSERT INTO t1 VALUES (16777215, null); --- error ER_DUP_ENTRY,1062 +-- error 167 INSERT INTO t1 (c2) VALUES ('innodb'); SELECT * FROM t1; DROP TABLE t1; @@ -70,14 +70,14 @@ DROP TABLE t1; # CREATE TABLE t1 (c1 INT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; INSERT INTO t1 VALUES (2147483647, null); --- error ER_DUP_ENTRY,1062 +-- error 167 INSERT INTO t1 (c2) VALUES ('innodb'); SELECT * FROM t1; DROP TABLE t1; CREATE TABLE t1 (c1 INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; INSERT INTO t1 VALUES (4294967295, null); --- error ER_DUP_ENTRY,1062 +-- error 167 INSERT INTO t1 (c2) VALUES ('innodb'); SELECT * FROM t1; DROP TABLE t1; @@ -86,7 +86,7 @@ DROP TABLE t1; # CREATE TABLE t1 (c1 BIGINT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; INSERT INTO t1 VALUES (9223372036854775807, null); --- error ER_DUP_ENTRY,1062 +-- error 167 INSERT INTO t1 (c2) VALUES ('innodb'); SELECT * FROM t1; DROP TABLE t1; @@ -349,7 +349,7 @@ INSERT INTO t1 VALUES (18446744073709551610); #-- 2^64 - 2 SELECT * FROM t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1152921504606846976, @@SESSION.AUTO_INCREMENT_OFFSET=1152921504606846976; SHOW VARIABLES LIKE "%auto_inc%"; ---error ER_WARN_DATA_OUT_OF_RANGE +--error 167 INSERT INTO t1 VALUES (NULL),(NULL); SELECT * FROM t1; DROP TABLE t1; @@ -437,7 +437,7 @@ CREATE TABLE t2( PRIMARY KEY) ENGINE=InnoDB; -- error ER_DUP_ENTRY,1062 INSERT INTO t2 SELECT c1 FROM t1; --- error ER_DUP_ENTRY,1467 +-- error 167 INSERT INTO t2 SELECT NULL FROM t1; DROP TABLE t1; DROP TABLE t2; diff --git a/mysql-test/suite/maria/maria3.result b/mysql-test/suite/maria/maria3.result index 37613875f38..27d72b75930 100644 --- a/mysql-test/suite/maria/maria3.result +++ b/mysql-test/suite/maria/maria3.result @@ -452,6 +452,8 @@ SET SQL_MODE='NO_AUTO_VALUE_ON_ZERO'; CREATE TABLE t1 (id int(11) PRIMARY KEY auto_increment,f1 varchar(10) NOT NULL UNIQUE); INSERT IGNORE INTO t1 (f1) VALUES ("test1"); INSERT IGNORE INTO t1 (f1) VALUES ("test1"); +Warnings: +Warning 1062 Duplicate entry 'test1' for key 'f1' INSERT IGNORE INTO t1 (f1) VALUES ("test2"); SELECT * FROM t1; id f1 diff --git a/mysql-test/suite/maria/mrr.result b/mysql-test/suite/maria/mrr.result index af7789eebff..06be64566e5 100644 --- a/mysql-test/suite/maria/mrr.result +++ b/mysql-test/suite/maria/mrr.result @@ -277,6 +277,8 @@ bb-1 NULL cc-2 NULL-1 drop table t1, t2, t3, t4; create table t1 (a int, b int not null,unique key (a,b),index(b)); insert ignore into t1 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(null,7),(9,9),(8,8),(7,7),(null,9),(null,9),(6,6); +Warnings: +Warning 1062 Duplicate entry '6-6' for key 'a' create table t2 like t1; insert into t2 select * from t1; alter table t1 modify b blob not null, add c int not null, drop key a, add unique key (a,b(20),c), drop key b, add key (b(10)); diff --git a/mysql-test/suite/optimizer_unfixed_bugs/r/bug43617.result b/mysql-test/suite/optimizer_unfixed_bugs/r/bug43617.result index 3c19a37c95d..505dd587d0b 100644 --- a/mysql-test/suite/optimizer_unfixed_bugs/r/bug43617.result +++ b/mysql-test/suite/optimizer_unfixed_bugs/r/bug43617.result @@ -38,7 +38,11 @@ c1 c2 c3 c4 2008-01-01 00:00:00 NULL 2008-01-02 2008-01-03 00:00:00 2009-01-29 11:11:27 2009-01-29 00:00:00 2009-01-29 2009-01-29 00:00:00 INSERT IGNORE INTO t1(c1,c2) VALUES('20070525','20070527') /* doesnt throw error */; +Warnings: +Warning 1062 Duplicate entry '2007-05-25 00:00:00' for key 'PRIMARY' INSERT IGNORE INTO t1(c1,c2) VALUES(19840905,830907) /* doesnt throw error */; +Warnings: +Warning 1062 Duplicate entry '1983-09-07 00:00:00' for key 'c2' SELECT * FROM t1 WHERE c1='20070527' /* Returns no rows */; c1 c2 c3 c4 INSERT INTO t1(c1) VALUES('20070525') ON DUPLICATE KEY UPDATE c1='20070527'; diff --git a/mysql-test/suite/rpl/r/rpl_auto_increment.result b/mysql-test/suite/rpl/r/rpl_auto_increment.result index 8b41a01cb6e..41bacd78f52 100644 --- a/mysql-test/suite/rpl/r/rpl_auto_increment.result +++ b/mysql-test/suite/rpl/r/rpl_auto_increment.result @@ -125,6 +125,10 @@ insert into t1 values(600),(NULL),(NULL); ERROR 23000: Duplicate entry '600' for key 'PRIMARY' set @@insert_id=600; insert ignore into t1 values(600),(NULL),(NULL),(610),(NULL); +Warnings: +Warning 1062 Duplicate entry '600' for key 'PRIMARY' +Warning 1062 Duplicate entry '600' for key 'PRIMARY' +Warning 1062 Duplicate entry '600' for key 'PRIMARY' select * from t1; a 1 @@ -186,7 +190,7 @@ set auto_increment_offset=4; insert into t1 values(null); insert into t1 values(null); insert into t1 values(null); -ERROR 23000: Duplicate entry '125' for key 'PRIMARY' +ERROR 22003: Out of range value for column 'a' at row 1 select a, mod(a-@@auto_increment_offset,@@auto_increment_increment) from t1 order by a; a mod(a-@@auto_increment_offset,@@auto_increment_increment) 103 0 @@ -196,21 +200,19 @@ create table t2 (a tinyint unsigned not null auto_increment primary key) engine= set auto_increment_increment=10; set auto_increment_offset=1; set insert_id=1000; +insert into t2 values(10); insert into t2 values(null); -Warnings: -Warning 1264 Out of range value for column 'a' at row 1 +ERROR 22003: Out of range value for column 'a' at row 1 select a, mod(a-@@auto_increment_offset,@@auto_increment_increment) from t2 order by a; a mod(a-@@auto_increment_offset,@@auto_increment_increment) -251 0 +10 9 create table t3 like t1; set auto_increment_increment=1000; set auto_increment_offset=700; insert into t3 values(null); -Warnings: -Warning 1264 Out of range value for column 'a' at row 1 +ERROR 22003: Out of range value for column 'a' at row 1 select * from t3 order by a; a -127 select * from t1 order by a; a 103 @@ -218,10 +220,9 @@ a 125 select * from t2 order by a; a -251 +10 select * from t3 order by a; a -127 drop table t1,t2,t3; set auto_increment_increment=1; set auto_increment_offset=1; diff --git a/mysql-test/suite/rpl/r/rpl_insert_delayed,stmt.rdiff b/mysql-test/suite/rpl/r/rpl_insert_delayed,stmt.rdiff index 5e0e7db5b63..ddb10d604c6 100644 --- a/mysql-test/suite/rpl/r/rpl_insert_delayed,stmt.rdiff +++ b/mysql-test/suite/rpl/r/rpl_insert_delayed,stmt.rdiff @@ -1,5 +1,5 @@ ---- suite/rpl/r/rpl_insert_delayed.result 2012-02-06 21:37:21.000000000 +0100 -+++ suite/rpl/r/rpl_insert_delayed,stmt.reject 2012-02-06 23:12:55.000000000 +0100 +--- suite/rpl/r/rpl_insert_delayed.result 2012-09-18 01:37:45.317521958 +0300 ++++ suite/rpl/r/rpl_insert_delayed,stmt.reject 2012-09-18 01:36:16.637514667 +0300 @@ -15,17 +15,17 @@ insert delayed into t1 values(10, "my name"); flush table t1; diff --git a/mysql-test/suite/rpl/r/rpl_loaddatalocal.result b/mysql-test/suite/rpl/r/rpl_loaddatalocal.result index 902bc1cda00..ae91e000c37 100644 --- a/mysql-test/suite/rpl/r/rpl_loaddatalocal.result +++ b/mysql-test/suite/rpl/r/rpl_loaddatalocal.result @@ -14,6 +14,8 @@ select * into outfile 'MYSQLD_DATADIR/rpl_loaddatalocal.select_outfile' from t1; drop table t1; create table t1(a int primary key); load data local infile 'MYSQLD_DATADIR/rpl_loaddatalocal.select_outfile' into table t1; +Warnings: +Warning 1062 Duplicate entry '2' for key 'PRIMARY' SELECT * FROM t1 ORDER BY a; a 1 diff --git a/mysql-test/t/auto_increment.test b/mysql-test/t/auto_increment.test index 884e0fabb5e..15156b89d8e 100644 --- a/mysql-test/t/auto_increment.test +++ b/mysql-test/t/auto_increment.test @@ -104,7 +104,7 @@ explain extended select last_insert_id(); --error ER_DUP_ENTRY insert into t1 set i = 254; select last_insert_id(); ---error ER_DUP_ENTRY +--error 167 insert into t1 set i = null; select last_insert_id(); drop table t1; @@ -113,6 +113,7 @@ create table t1 (i tinyint unsigned not null auto_increment, key (i)); insert into t1 set i = 254; insert into t1 set i = null; select last_insert_id(); +--error 167 insert into t1 set i = null; select last_insert_id(); drop table t1; @@ -353,7 +354,7 @@ INSERT INTO t1 VALUES (18446744073709551601); SET @@SESSION.AUTO_INCREMENT_INCREMENT=10; SELECT @@SESSION.AUTO_INCREMENT_OFFSET; ---error ER_WARN_DATA_OUT_OF_RANGE +--error 167 INSERT INTO t1 VALUES (NULL), (NULL), (NULL); SELECT * FROM t1; diff --git a/mysql-test/t/auto_increment_ranges.inc b/mysql-test/t/auto_increment_ranges.inc new file mode 100644 index 00000000000..a94aa46d38e --- /dev/null +++ b/mysql-test/t/auto_increment_ranges.inc @@ -0,0 +1,240 @@ +# +# Test of auto_increment at end of range +# +--disable_warnings +drop table if exists t1; +--enable_warnings + +--echo # +--echo # Testing ranges with smallint +--echo # +let $type=smallint; +let $range_max=32767; + +eval create table t1 (a $type primary key auto_increment); +eval insert into t1 values($range_max); +--error 167 +insert into t1 values(NULL); +truncate table t1; +eval insert into t1 values($range_max-1); +insert into t1 values(NULL); +--error 167 +insert into t1 values(NULL); +select * from t1; +truncate table t1; +--error 167 +eval insert into t1 values($range_max),(NULL); +select * from t1; +truncate table t1; +--error 167 +eval insert into t1 values($range_max-1),(NULL),(NULL); +truncate table t1; +eval insert into t1 values($range_max+1); +select * from t1; +--error 167 +eval insert into t1 values(NULL); +drop table t1; + +--echo # +--echo # Testing ranges with unsigned smallint +--echo # + +let $type=smallint unsigned; +let $range_max=65535; + +eval create table t1 (a $type primary key auto_increment); +eval insert into t1 values($range_max); +--error 167 +insert into t1 values(NULL); +truncate table t1; +eval insert into t1 values($range_max-1); +insert into t1 values(NULL); +--error 167 +insert into t1 values(NULL); +select * from t1; +truncate table t1; +--error 167 +eval insert into t1 values($range_max),(NULL); +select * from t1; +truncate table t1; +--error 167 +eval insert into t1 values($range_max-1),(NULL),(NULL); +truncate table t1; +eval insert into t1 values($range_max+1); +select * from t1; +--error 167 +eval insert into t1 values(NULL); +drop table t1; + +--echo # +--echo # Testing ranges with integer +--echo # + +let $type=int; +let $range_max=2147483647; + +eval create table t1 (a $type primary key auto_increment); +eval insert into t1 values($range_max); +--error 167 +insert into t1 values(NULL); +truncate table t1; +eval insert into t1 values($range_max-1); +insert into t1 values(NULL); +--error 167 +insert into t1 values(NULL); +select * from t1; +truncate table t1; +--error 167 +eval insert into t1 values($range_max),(NULL); +select * from t1; +truncate table t1; +--error 167 +eval insert into t1 values($range_max-1),(NULL),(NULL); +truncate table t1; +eval insert into t1 values($range_max+1); +select * from t1; +--error 167 +eval insert into t1 values(NULL); +drop table t1; + +--echo # +--echo # Testing ranges with unsigned integer +--echo # + +let $type=int unsigned; +let $range_max=4294967295; + +eval create table t1 (a $type primary key auto_increment); +eval insert into t1 values($range_max); +--error 167 +insert into t1 values(NULL); +truncate table t1; +eval insert into t1 values($range_max-1); +insert into t1 values(NULL); +--error 167 +insert into t1 values(NULL); +select * from t1; +truncate table t1; +--error 167 +eval insert into t1 values($range_max),(NULL); +select * from t1; +truncate table t1; +--error 167 +eval insert into t1 values($range_max-1),(NULL),(NULL); +truncate table t1; +eval insert into t1 values($range_max+1); +select * from t1; +--error 167 +eval insert into t1 values(NULL); +drop table t1; + +--echo # +--echo # Testing ranges with bigint +--echo # + +let $type=bigint; +let $range_max=cast(9223372036854775807 as unsigned); + +eval create table t1 (a $type primary key auto_increment); +eval insert into t1 values($range_max); +--error 167 +insert into t1 values(NULL); +truncate table t1; +eval insert into t1 values($range_max-1); +insert into t1 values(NULL); +--error 167 +insert into t1 values(NULL); +select * from t1; +truncate table t1; +--error 167 +eval insert into t1 values($range_max),(NULL); +select * from t1; +truncate table t1; +--error 167 +eval insert into t1 values($range_max-1),(NULL),(NULL); +truncate table t1; +eval insert into t1 values($range_max+1); +select * from t1; +--error 167 +eval insert into t1 values(NULL); +drop table t1; + +--echo # +--echo # Testing ranges with unsigned bigint +--echo # + +let $type=bigint unsigned; +let $range_max=18446744073709551615; + +eval create table t1 (a $type primary key auto_increment); +eval insert into t1 values($range_max-1); +--error ER_AUTOINC_READ_FAILED +insert into t1 values(NULL); +--error ER_AUTOINC_READ_FAILED +insert into t1 values(NULL); +truncate table t1; +eval insert into t1 values($range_max-1); +--error ER_AUTOINC_READ_FAILED +insert into t1 values(NULL); +--error ER_AUTOINC_READ_FAILED +insert into t1 values(NULL); +select * from t1; +truncate table t1; +--error ER_AUTOINC_READ_FAILED +eval insert into t1 values($range_max),(NULL); +select * from t1; +truncate table t1; +--error ER_AUTOINC_READ_FAILED +eval insert into t1 values($range_max-1),(NULL),(NULL); +drop table t1; + +--echo # +--echo # Test IGNORE and strict mode +--echo # +create table t1 (a smallint primary key auto_increment); +insert ignore into t1 values(32766),(NULL),(NULL),(1); +select * from t1; +truncate table t1; + +set @org_mode=@@sql_mode; +set @@sql_mode='ansi,traditional'; +insert ignore into t1 values(32766),(NULL),(NULL); +truncate table t1; +--error 167 +insert into t1 values(32766),(NULL),(NULL); +set @@sql_mode=@org_mode; +drop table t1; + +--echo # +--echo # Test auto increment with negative numbers +--echo # +CREATE TABLE t1 (a INTEGER AUTO_INCREMENT, PRIMARY KEY (a)); +INSERT INTO t1 VALUES (NULL), (2), (-5), (NULL); +INSERT INTO t1 VALUES (NULL); +SELECT * FROM t1; +TRUNCATE TABLE t1; +INSERT INTO t1 VALUES (-5), (NULL); +SELECT * FROM t1; +DROP TABLE t1; + +--echo # +--echo # Test inserting a value out-of-range into an auto increment column +--echo # +CREATE TABLE t1 (a smallint AUTO_INCREMENT, PRIMARY KEY (a)); +INSERT INTO t1 VALUES (2); +INSERT INTO t1 VALUES (32768); +--error 167 +INSERT INTO t1 VALUES (NULL); +SELECT * FROM t1; +DROP TABLE t1; + + +--echo # +--echo # Test old behaviour +--echo # +create table t1 (a smallint primary key auto_increment); +insert into t1 values(32766),(NULL); +delete from t1 where a=32767; +--error 167 +insert into t1 values(NULL); +drop table t1; diff --git a/mysql-test/t/auto_increment_ranges_innodb.test b/mysql-test/t/auto_increment_ranges_innodb.test new file mode 100644 index 00000000000..c2afee7ac66 --- /dev/null +++ b/mysql-test/t/auto_increment_ranges_innodb.test @@ -0,0 +1,7 @@ +# +# Test of auto_increment at end of range +# + +--source include/have_innodb.inc +set default_storage_engine=innodb; +--source auto_increment_ranges.inc diff --git a/mysql-test/t/auto_increment_ranges_myisam.test b/mysql-test/t/auto_increment_ranges_myisam.test new file mode 100644 index 00000000000..90e84377540 --- /dev/null +++ b/mysql-test/t/auto_increment_ranges_myisam.test @@ -0,0 +1,7 @@ +# +# Test of auto_increment at end of range +# + +set default_storage_engine=MYISAM; +--source auto_increment_ranges.inc + diff --git a/mysql-test/t/replace.test b/mysql-test/t/replace.test index ff910bdf5cf..3d32a8c0da6 100644 --- a/mysql-test/t/replace.test +++ b/mysql-test/t/replace.test @@ -25,9 +25,9 @@ drop table t1; create table t1 (a tinyint not null auto_increment primary key, b char(20) default "default_value"); insert into t1 values (126,"first"),(63, "middle"),(0,"last"); ---error ER_DUP_ENTRY +--error 167 insert into t1 values (0,"error"); ---error ER_DUP_ENTRY +--error 167 replace into t1 values (0,"error"); replace into t1 values (126,"first updated"); replace into t1 values (63,default); diff --git a/mysys/my_getopt.c b/mysys/my_getopt.c index facc1569943..c1b0a129a30 100644 --- a/mysys/my_getopt.c +++ b/mysys/my_getopt.c @@ -691,15 +691,13 @@ static int setval(const struct my_option *opts, void *value, char *argument, *((double*) value)= getopt_double(argument, opts, &err); break; case GET_STR: - if (argument == enabled_my_option) - break; /* string options don't use this default of "1" */ - *((char**) value)= argument; + /* If no argument or --enable-string-option, set string to "" */ + *((char**) value)= argument == enabled_my_option ? (char*) "" : argument; break; case GET_STR_ALLOC: - if (argument == enabled_my_option) - break; /* string options don't use this default of "1" */ my_free(*((char**) value)); - if (!(*((char**) value)= my_strdup(argument, MYF(MY_WME)))) + if (!(*((char**) value)= my_strdup(argument == enabled_my_option ? "" : + argument, MYF(MY_WME)))) { res= EXIT_OUT_OF_MEMORY; goto ret; diff --git a/sql/handler.cc b/sql/handler.cc index 58d37532796..b06aa4255fd 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -2502,6 +2502,8 @@ int handler::update_auto_increment() bool append= FALSE; THD *thd= table->in_use; struct system_variables *variables= &thd->variables; + int result=0, tmp; + enum enum_check_fields save_count_cuted_fields; DBUG_ENTER("handler::update_auto_increment"); /* @@ -2519,8 +2521,10 @@ int handler::update_auto_increment() statement (case of INSERT VALUES(null),(3763),(null): the last NULL needs to insert 3764, not the value of the first NULL plus 1). + Ignore negative values. */ - adjust_next_insert_id_after_explicit_value(nr); + if ((longlong) nr > 0 || (table->next_number_field->flags & UNSIGNED_FLAG)) + adjust_next_insert_id_after_explicit_value(nr); insert_id_for_cur_row= 0; // didn't generate anything DBUG_RETURN(0); } @@ -2579,7 +2583,6 @@ int handler::update_auto_increment() else nb_desired_values= AUTO_INC_DEFAULT_NB_MAX; } - /* This call ignores all its parameters but nr, currently */ get_auto_increment(variables->auto_increment_offset, variables->auto_increment_increment, nb_desired_values, &nr, @@ -2616,29 +2619,23 @@ int handler::update_auto_increment() } if (unlikely(nr == ULONGLONG_MAX)) - DBUG_RETURN(HA_ERR_AUTOINC_ERANGE); + DBUG_RETURN(HA_ERR_AUTOINC_ERANGE); DBUG_PRINT("info",("auto_increment: %lu", (ulong) nr)); - if (unlikely(table->next_number_field->store((longlong) nr, TRUE))) + /* Store field without warning (Warning will be printed by insert) */ + save_count_cuted_fields= thd->count_cuted_fields; + thd->count_cuted_fields= CHECK_FIELD_IGNORE; + tmp= table->next_number_field->store((longlong) nr, TRUE); + thd->count_cuted_fields= save_count_cuted_fields; + + if (unlikely(tmp)) // Out of range value in store { /* - first test if the query was aborted due to strict mode constraints + It's better to return an error here than getting a confusing + 'duplicate key error' later. */ - if (killed_mask_hard(thd->killed) == KILL_BAD_DATA) - DBUG_RETURN(HA_ERR_AUTOINC_ERANGE); - - /* - field refused this value (overflow) and truncated it, use the result of - the truncation (which is going to be inserted); however we try to - decrease it to honour auto_increment_* variables. - That will shift the left bound of the reserved interval, we don't - bother shifting the right bound (anyway any other value from this - interval will cause a duplicate key). - */ - nr= prev_insert_id(table->next_number_field->val_int(), variables); - if (unlikely(table->next_number_field->store((longlong) nr, TRUE))) - nr= table->next_number_field->val_int(); + result= HA_ERR_AUTOINC_ERANGE; } if (append) { @@ -2660,6 +2657,10 @@ int handler::update_auto_increment() already set. */ insert_id_for_cur_row= nr; + + if (result) // overflow + DBUG_RETURN(result); + /* Set next insert id to point to next auto-increment value to be able to handle multi-row statements. @@ -2783,7 +2784,7 @@ void handler::ha_release_auto_increment() } -void handler::print_keydup_error(uint key_nr, const char *msg) +void handler::print_keydup_error(uint key_nr, const char *msg, myf errflag) { /* Write the duplicated key in the error message */ char key[MAX_KEY_LENGTH]; @@ -2793,7 +2794,7 @@ void handler::print_keydup_error(uint key_nr, const char *msg) { /* Key is unknown */ str.copy("", 0, system_charset_info); - my_printf_error(ER_DUP_ENTRY, msg, MYF(0), str.c_ptr(), "*UNKNOWN*"); + my_printf_error(ER_DUP_ENTRY, msg, errflag, str.c_ptr(), "*UNKNOWN*"); } else { @@ -2806,7 +2807,7 @@ void handler::print_keydup_error(uint key_nr, const char *msg) str.append(STRING_WITH_LEN("...")); } my_printf_error(ER_DUP_ENTRY, msg, - MYF(0), str.c_ptr_safe(), table->key_info[key_nr].name); + errflag, str.c_ptr_safe(), table->key_info[key_nr].name); } } @@ -2874,7 +2875,7 @@ void handler::print_error(int error, myf errflag) uint key_nr=get_dup_key(error); if ((int) key_nr >= 0) { - print_keydup_error(key_nr, ER(ER_DUP_ENTRY_WITH_KEY_NAME)); + print_keydup_error(key_nr, ER(ER_DUP_ENTRY_WITH_KEY_NAME), errflag); DBUG_VOID_RETURN; } } @@ -3037,7 +3038,10 @@ void handler::print_error(int error, myf errflag) textno= ER_AUTOINC_READ_FAILED; break; case HA_ERR_AUTOINC_ERANGE: - textno= ER_WARN_DATA_OUT_OF_RANGE; + textno= error; + my_error(textno, errflag, table->next_number_field->field_name, + table->in_use->warning_info->current_row_for_warning()); + DBUG_VOID_RETURN; break; case HA_ERR_TOO_MANY_CONCURRENT_TRXS: textno= ER_TOO_MANY_CONCURRENT_TRXS; diff --git a/sql/handler.h b/sql/handler.h index 9c0850e157a..4a6fc2f1bd5 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1957,7 +1957,7 @@ public: void adjust_next_insert_id_after_explicit_value(ulonglong nr); int update_auto_increment(); - void print_keydup_error(uint key_nr, const char *msg); + void print_keydup_error(uint key_nr, const char *msg, myf errflag); virtual void print_error(int error, myf errflag); virtual bool get_error_message(int error, String *buf); uint get_dup_key(int error); @@ -2006,7 +2006,8 @@ public: if (!error || ((flags & HA_CHECK_DUP_KEY) && (error == HA_ERR_FOUND_DUPP_KEY || - error == HA_ERR_FOUND_DUPP_UNIQUE))) + error == HA_ERR_FOUND_DUPP_UNIQUE)) || + error == HA_ERR_AUTOINC_ERANGE) return FALSE; return TRUE; } diff --git a/sql/log_event.cc b/sql/log_event.cc index dca9091e03d..6fc116d2b92 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1086,6 +1086,9 @@ bool Log_event::write_header(IO_CACHE* file, ulong event_data_length) ulong now; bool ret; DBUG_ENTER("Log_event::write_header"); + DBUG_PRINT("enter", ("filepos: %lld length: %lu type: %d", + (longlong) my_b_tell(file), event_data_length, + (int) get_type_code())); /* Store number of bytes that will be written by this event */ data_written= event_data_length + sizeof(header); @@ -3512,6 +3515,34 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli) return do_apply_event(rli, query, q_len); } +/** + Compare if two errors should be regarded as equal. + This is to handle the case when you can get slightly different errors + on master and slave for the same thing. + @param + expected_error Error we got on master + actual_error Error we got on slave + + @return + 1 Errors are equal + 0 Errors are different +*/ + +bool test_if_equal_repl_errors(int expected_error, int actual_error) +{ + if (expected_error == actual_error) + return 1; + switch (expected_error) { + case ER_DUP_ENTRY: + case ER_AUTOINC_READ_FAILED: + return (actual_error == ER_AUTOINC_READ_FAILED || + actual_error == HA_ERR_AUTOINC_ERANGE); + default: + break; + } + return 0; +} + /** @todo @@ -3824,7 +3855,8 @@ compare_errors: DBUG_PRINT("info",("expected_error: %d sql_errno: %d", expected_error, actual_error)); - if ((expected_error && expected_error != actual_error && + if ((expected_error && + !test_if_equal_repl_errors(expected_error, actual_error) && !concurrency_error_code(expected_error)) && !ignored_error_code(actual_error) && !ignored_error_code(expected_error)) @@ -3846,7 +3878,7 @@ Default database: '%s'. Query: '%s'", If we get the same error code as expected and it is not a concurrency issue, or should be ignored. */ - else if ((expected_error == actual_error && + else if ((test_if_equal_repl_errors(expected_error, actual_error) && !concurrency_error_code(expected_error)) || ignored_error_code(actual_error)) { diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index e0d0d4c4223..42704862c16 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1598,7 +1598,10 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) report error as usual. We will not do any duplicate key processing. */ if (info->ignore) + { + table->file->print_error(error, MYF(ME_JUST_WARNING)); goto ok_or_after_trg_err; /* Ignoring a not fatal error, return 0 */ + } goto err; } if ((int) (key_nr = table->file->get_dup_key(error)) < 0) @@ -1688,6 +1691,7 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) if (info->ignore && !table->file->is_fatal_error(error, HA_CHECK_DUP_KEY)) { + table->file->print_error(error, MYF(ME_JUST_WARNING)); goto ok_or_after_trg_err; } goto err; @@ -1803,6 +1807,7 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) if (!info->ignore || table->file->is_fatal_error(error, HA_CHECK_DUP)) goto err; + table->file->print_error(error, MYF(ME_JUST_WARNING)); table->file->restore_auto_increment(prev_insert_id); goto ok_or_after_trg_err; } diff --git a/sql/sql_state.c b/sql/sql_state.c index 511dc65917b..5acf97f16cc 100644 --- a/sql/sql_state.c +++ b/sql/sql_state.c @@ -17,6 +17,7 @@ #include #include +#include struct st_map_errno_to_sqlstate { @@ -27,6 +28,7 @@ struct st_map_errno_to_sqlstate struct st_map_errno_to_sqlstate sqlstate_map[]= { +#include #include }; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 4ff29b33b5b..5724fb8f184 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -7476,7 +7476,7 @@ copy_data_between_tables(THD *thd, TABLE *from,TABLE *to, (to->key_info[0].key_part[0].field->flags & AUTO_INCREMENT_FLAG)) err_msg= ER(ER_DUP_ENTRY_AUTOINCREMENT_CASE); - to->file->print_keydup_error(key_nr, err_msg); + to->file->print_keydup_error(key_nr, err_msg, MYF(0)); break; } } diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index f0bc262327a..3185403c2ac 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -1474,6 +1474,15 @@ innobase_next_autoinc( ut_a(block > 0); ut_a(max_value > 0); + /* + Allow auto_increment to go over max_value up to max ulonglong. + This allows us to detect that all values are exhausted. + If we don't do this, we will return max_value several times + and get duplicate key errors instead of auto increment value + out of range. + */ + max_value= (~(ulonglong) 0); + /* Current value should never be greater than the maximum. */ ut_a(current <= max_value); @@ -5236,7 +5245,10 @@ no_commit: goto report_error; } - /* MySQL errors are passed straight back. */ + /* MySQL errors are passed straight back. except for + HA_ERR_AUTO_INC_READ_FAILED. This can only happen + for values out of range. + */ error_result = (int) error; goto func_exit; } @@ -10264,13 +10276,16 @@ ha_innobase::get_auto_increment( /* Not in the middle of a mult-row INSERT. */ } else if (prebuilt->autoinc_last_value == 0) { set_if_bigger(*first_value, autoinc); - /* Check for -ve values. */ - } else if (*first_value > col_max_value && trx->n_autoinc_rows > 0) { - /* Set to next logical value. */ - ut_a(autoinc > trx->n_autoinc_rows); - *first_value = (autoinc - trx->n_autoinc_rows) - 1; } + if (*first_value > col_max_value) + { + /* Out of range number. Let handler::update_auto_increment() + take care of this */ + prebuilt->autoinc_last_value = 0; + dict_table_autoinc_unlock(prebuilt->table); + return; + } *nb_reserved_values = trx->n_autoinc_rows; /* With old style AUTOINC locking we only update the table's @@ -10279,7 +10294,7 @@ ha_innobase::get_auto_increment( ulonglong current; ulonglong next_value; - current = *first_value > col_max_value ? autoinc : *first_value; + current = *first_value; /* Compute the last value in the interval */ next_value = innobase_next_autoinc( diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index fe48c472e8b..f4072082b33 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -1664,6 +1664,15 @@ innobase_next_autoinc( ut_a(block > 0); ut_a(max_value > 0); + /* + Allow auto_increment to go over max_value up to max ulonglong. + This allows us to detect that all values are exhausted. + If we don't do this, we will return max_value several times + and get duplicate key errors instead of auto increment value + out of range. + */ + max_value= (~(ulonglong) 0); + /* Current value should never be greater than the maximum. */ ut_a(current <= max_value); @@ -5999,7 +6008,10 @@ no_commit: goto report_error; } - /* MySQL errors are passed straight back. */ + /* MySQL errors are passed straight back. except for + HA_ERR_AUTO_INC_READ_FAILED. This can only happen + for values out of range. + */ error_result = (int) error; goto func_exit; } @@ -11205,13 +11217,16 @@ ha_innobase::get_auto_increment( /* Not in the middle of a mult-row INSERT. */ } else if (prebuilt->autoinc_last_value == 0) { set_if_bigger(*first_value, autoinc); - /* Check for -ve values. */ - } else if (*first_value > col_max_value && trx->n_autoinc_rows > 0) { - /* Set to next logical value. */ - ut_a(autoinc > trx->n_autoinc_rows); - *first_value = (autoinc - trx->n_autoinc_rows) - 1; } + if (*first_value > col_max_value) + { + /* Out of range number. Let handler::update_auto_increment() + take care of this */ + prebuilt->autoinc_last_value = 0; + dict_table_autoinc_unlock(prebuilt->table); + return; + } *nb_reserved_values = trx->n_autoinc_rows; /* With old style AUTOINC locking we only update the table's @@ -11220,7 +11235,7 @@ ha_innobase::get_auto_increment( ulonglong current; ulonglong next_value; - current = *first_value > col_max_value ? autoinc : *first_value; + current = *first_value; /* Compute the last value in the interval */ next_value = innobase_next_autoinc( From f30342365b05a72d477d61d199587bdf2b0e1d2d Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Tue, 18 Sep 2012 15:31:21 +0300 Subject: [PATCH 268/289] Fixed test for ps-protocol --- mysql-test/t/view.test | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 4f739b524e6..c4881f7df3f 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -4619,7 +4619,7 @@ DROP TABLE t1,t2,t3; --echo # flush status; - +--disable_ps_protocol CREATE TABLE t1 (a INT); CREATE ALGORITHM=MERGE VIEW v1 AS SELECT a1.* FROM t1 AS a1, t1 AS a2; CREATE ALGORITHM=MERGE VIEW v2 AS SELECT * FROM v1; @@ -4629,6 +4629,7 @@ drop view v2,v1; drop table t1; show status like '%view%'; show status like 'Opened_table%'; +--enable_ps_protocol --echo # --echo # MDEV-486 LP BUG#1010116 Incorrect query results in From af4eeaf548c523934d335d18d390c30ef8f2bf23 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Tue, 18 Sep 2012 23:34:16 +0300 Subject: [PATCH 269/289] This fix+comments was originally made by Alexey Kopytov LP bug #1035225 / MySQL bug #66301: INSERT ... ON DUPLICATE KEY UPDATE + innodb_autoinc_lock_mode=1 is broken The problem was that when certain INSERT ... ON DUPLICATE KEY UPDATE were executed concurrently on a table containing an AUTO_INCREMENT column as a primary key, InnoDB would correctly reserve non-overlapping AUTO_INCREMENT intervals for each statement, but when the server encountered the first duplicate key error on the secondary key in one of the statements and performed an UPDATE, it also updated the internal AUTO_INCREMENT value to the one from the existing row that caused a duplicate key error, even though the AUTO_INCREMENT value was not specified explicitly in the UPDATE clause. It would then proceed with using AUTO_INCREMENT values the range reserved previously by another statement, causing duplicate key errors on the AUTO_INCREMENT column. Fixed by changing write_record() to ensure that in case of a duplicate key error the internal AUTO_INCREMENT counter is only updated when the AUTO_INCREMENT value was explicitly updated by the UPDATE clause. Otherwise it is restored to what it was before the duplicate key error, as that value is unused and can be reused for subsequent successfully inserted rows. sql/sql_insert.cc: Don't update next_insert_id to the value of a row found during ON DUPLICATE KEY UPDATE. sql/sql_parse.cc: Added DBUG_SYNC sql/table.h: Added next_number_field_updated flag to detect changing of auto increment fields. Moved fields a bit to get bool fields after each other (better alignment) --- .../suite/innodb/r/auto_increment_dup.result | 33 ++++++++++++ .../suite/innodb/t/auto_increment_dup.test | 51 ++++++++++++++++++ sql/sql_insert.cc | 53 +++++++++++++++++-- sql/sql_parse.cc | 1 + sql/table.h | 11 ++-- 5 files changed, 142 insertions(+), 7 deletions(-) create mode 100644 mysql-test/suite/innodb/r/auto_increment_dup.result create mode 100644 mysql-test/suite/innodb/t/auto_increment_dup.test diff --git a/mysql-test/suite/innodb/r/auto_increment_dup.result b/mysql-test/suite/innodb/r/auto_increment_dup.result new file mode 100644 index 00000000000..5bf901cb212 --- /dev/null +++ b/mysql-test/suite/innodb/r/auto_increment_dup.result @@ -0,0 +1,33 @@ +drop table if exists t1; +CREATE TABLE t1( +id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, +k INT, +c CHAR(1), +UNIQUE KEY(k)) ENGINE=InnoDB; +# +# Connection 1 +# +SET DEBUG_SYNC='ha_write_row_end SIGNAL continue2 WAIT_FOR continue1'; +affected rows: 0 +INSERT INTO t1(k) VALUES (1), (2), (3) ON DUPLICATE KEY UPDATE c='1'; +# +# Connection 2 +# +SET DEBUG_SYNC='start_ha_write_row WAIT_FOR continue2'; +affected rows: 0 +SET DEBUG_SYNC='after_mysql_insert SIGNAL continue1'; +affected rows: 0 +INSERT INTO t1(k) VALUES (2), (4), (5) ON DUPLICATE KEY UPDATE c='2'; +affected rows: 3 +info: Records: 3 Duplicates: 0 Warnings: 0 +affected rows: 4 +info: Records: 3 Duplicates: 1 Warnings: 0 +SET DEBUG_SYNC='RESET'; +SELECT * FROM t1 ORDER BY k; +id k c +1 1 NULL +4 2 1 +2 3 NULL +5 4 NULL +6 5 NULL +DROP TABLE t1; diff --git a/mysql-test/suite/innodb/t/auto_increment_dup.test b/mysql-test/suite/innodb/t/auto_increment_dup.test new file mode 100644 index 00000000000..ad439024f65 --- /dev/null +++ b/mysql-test/suite/innodb/t/auto_increment_dup.test @@ -0,0 +1,51 @@ +########################################################################## +# LP bug #1035225 / MySQL bug #66301: INSERT ... ON DUPLICATE KEY UPDATE + +# innodb_autoinc_lock_mode=1 is broken +########################################################################## + +--source include/have_innodb.inc +--source include/have_debug_sync.inc + +--disable_warnings +drop table if exists t1; +--enable_warnings + +CREATE TABLE t1( + id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + k INT, + c CHAR(1), + UNIQUE KEY(k)) ENGINE=InnoDB; + +--enable_info + +--connect(con1, localhost, root) +--connect(con2, localhost, root) + +--connection con1 + +--echo # +--echo # Connection 1 +--echo # +SET DEBUG_SYNC='ha_write_row_end SIGNAL continue2 WAIT_FOR continue1'; +--send INSERT INTO t1(k) VALUES (1), (2), (3) ON DUPLICATE KEY UPDATE c='1' + +--connection con2 +--echo # +--echo # Connection 2 +--echo # +SET DEBUG_SYNC='start_ha_write_row WAIT_FOR continue2'; +SET DEBUG_SYNC='after_mysql_insert SIGNAL continue1'; +INSERT INTO t1(k) VALUES (2), (4), (5) ON DUPLICATE KEY UPDATE c='2'; + +--connection con1 +--reap +--disable_info +SET DEBUG_SYNC='RESET'; +SELECT * FROM t1 ORDER BY k; + +--disconnect con1 +--disconnect con2 + +--connection default + +DROP TABLE t1; diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 42704862c16..3c3b9f85727 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -329,7 +329,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, /* - Check update fields for the timestamp field. + Check update fields for the timestamp and auto_increment fields. SYNOPSIS check_update_fields() @@ -342,6 +342,9 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, If the update fields include the timestamp field, remove TIMESTAMP_AUTO_SET_ON_UPDATE from table->timestamp_field_type. + If the update fields include an autoinc field, set the + table->next_number_field_updated flag. + RETURN 0 OK -1 Error @@ -353,7 +356,9 @@ static int check_update_fields(THD *thd, TABLE_LIST *insert_table_list, { TABLE *table= insert_table_list->table; my_bool timestamp_mark; + my_bool autoinc_mark; LINT_INIT(timestamp_mark); + LINT_INIT(autoinc_mark); if (table->timestamp_field) { @@ -365,6 +370,19 @@ static int check_update_fields(THD *thd, TABLE_LIST *insert_table_list, table->timestamp_field->field_index); } + table->next_number_field_updated= FALSE; + + if (table->found_next_number_field) + { + /* + Unmark the auto_increment field so that we can check if this is modified + by update_fields + */ + autoinc_mark= bitmap_test_and_clear(table->write_set, + table->found_next_number_field-> + field_index); + } + /* Check the fields we are going to modify */ if (setup_fields(thd, 0, update_fields, MARK_COLUMNS_WRITE, 0, 0)) return -1; @@ -386,6 +404,18 @@ static int check_update_fields(THD *thd, TABLE_LIST *insert_table_list, bitmap_set_bit(table->write_set, table->timestamp_field->field_index); } + + if (table->found_next_number_field) + { + if (bitmap_is_set(table->write_set, + table->found_next_number_field->field_index)) + table->next_number_field_updated= TRUE; + + if (autoinc_mark) + bitmap_set_bit(table->write_set, + table->found_next_number_field->field_index); + } + return 0; } @@ -1563,6 +1593,7 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) MY_BITMAP *save_read_set, *save_write_set; ulonglong prev_insert_id= table->file->next_insert_id; ulonglong insert_id_for_cur_row= 0; + ulonglong prev_insert_id_for_cur_row= 0; DBUG_ENTER("write_record"); info->records++; @@ -1709,6 +1740,7 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) INSERT query, which is handled separately by THD::arg_of_last_insert_id_function. */ + prev_insert_id_for_cur_row= table->file->insert_id_for_cur_row; insert_id_for_cur_row= table->file->insert_id_for_cur_row= 0; trg_error= (table->triggers && table->triggers->process_triggers(thd, TRG_EVENT_UPDATE, @@ -1716,9 +1748,22 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) info->copied++; } - if (table->next_number_field) - table->file->adjust_next_insert_id_after_explicit_value( - table->next_number_field->val_int()); + /* + Only update next_insert_id if the AUTO_INCREMENT value was explicitly + updated, so we don't update next_insert_id with the value from the + row being updated. Otherwise reset next_insert_id to what it was + before the duplicate key error, since that value is unused. + */ + if (table->next_number_field_updated) + { + DBUG_ASSERT(table->next_number_field != NULL); + + table->file->adjust_next_insert_id_after_explicit_value(table->next_number_field->val_int()); + } + else + { + table->file->restore_auto_increment(prev_insert_id_for_cur_row); + } goto ok_or_after_trg_err; } else /* DUP_REPLACE */ diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index f5124d60f3f..d2eb6ae8d1f 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2938,6 +2938,7 @@ end_with_restore_list: DBUG_ASSERT(!debug_sync_set_action(thd, STRING_WITH_LEN(act2))); };); + DEBUG_SYNC(thd, "after_mysql_insert"); break; } case SQLCOM_REPLACE_SELECT: diff --git a/sql/table.h b/sql/table.h index f5ae3bcebb3..0259e063748 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1053,15 +1053,20 @@ public: uint db_stat; /* mode of file as in handler.h */ /* number of select if it is derived table */ uint derived_select_number; - int current_lock; /* Type of lock on table */ - bool copy_blobs; /* copy_blobs when storing */ - /* 0 or JOIN_TYPE_{LEFT|RIGHT}. Currently this is only compared to 0. If maybe_null !=0, this table is inner w.r.t. some outer join operation, and null_row may be true. */ uint maybe_null; + int current_lock; /* Type of lock on table */ + bool copy_blobs; /* copy_blobs when storing */ + /* + Set if next_number_field is in the UPDATE fields of INSERT ... ON DUPLICATE + KEY UPDATE. + */ + bool next_number_field_updated; + /* If true, the current table row is considered to have all columns set to NULL, including columns declared as "not null" (see maybe_null). From 5b2ec4efc268b65ae2146684c7809a87f80841a6 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 21 Sep 2012 15:03:38 +0200 Subject: [PATCH 270/289] Fix test failure on --embedded-server --- mysql-test/suite/plugins/t/feedback_plugin_send.test | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mysql-test/suite/plugins/t/feedback_plugin_send.test b/mysql-test/suite/plugins/t/feedback_plugin_send.test index 3324ef469fe..45b507f8e78 100644 --- a/mysql-test/suite/plugins/t/feedback_plugin_send.test +++ b/mysql-test/suite/plugins/t/feedback_plugin_send.test @@ -1,3 +1,6 @@ +# Restart of server does not work for embedded. +--source include/not_embedded.inc + source feedback_plugin_load.test; if (!$MTR_FEEDBACK_PLUGIN) { From 79feec77ed4a7121e68be1dc16f79dcad6c5d25e Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Sat, 22 Sep 2012 14:19:02 +0300 Subject: [PATCH 271/289] Updated mytop to version 1.91 Fixed that 'Handler:' output gives correct result with MariaDB (not including temporary tables) --- scripts/mytop.sh | 147 +++++++++++++++++++++++++---------------------- 1 file changed, 78 insertions(+), 69 deletions(-) diff --git a/scripts/mytop.sh b/scripts/mytop.sh index a36fddf7368..f0456498da7 100755 --- a/scripts/mytop.sh +++ b/scripts/mytop.sh @@ -1,6 +1,6 @@ #!/usr/bin/perl -w # -# $Id: mytop,v 1.90 2010/05/23 10:51:21 mark Exp $ +# $Id: mytop,v 1.91 2012/01/18 16:49:12 mgrennan Exp $ =pod @@ -15,12 +15,13 @@ mytop - display MySQL server performance info like `top' use 5.005; use strict; use DBI; +use DBD::mysql; use Getopt::Long; use Socket; use List::Util qw(min max); use File::Basename; -$main::VERSION = "1.9a"; +$main::VERSION = "1.91a"; my $path_for_script= dirname($0); $|=1; @@ -96,7 +97,7 @@ my %config = ( resolve => 0, slow => 10, # slow query time socket => '', - sort => 0, # default or reverse sort ("s") + sort => 1, # default or reverse sort ("s") user => 'root', fullqueries => 0 ); @@ -378,12 +379,11 @@ while (1) ## keystroke command processing (if we get this far) ## - # ! - Force past a replication error - - if ($key eq 'r') + if ($key eq '!') { - Execute("STOP SLAVE; SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1; START SLAVE;"); - next; + Execute("stop slave"); + Execute("set global sql_slave_skip_counter=1"); + Execute("start slave"); } # t - top @@ -415,7 +415,7 @@ while (1) next; } - ## m - mode swtich to qps + ## m - mode switch to qps if ($key eq 'm') { @@ -425,17 +425,7 @@ while (1) next; } - ## M - mode swtich to qps - - if ($key eq 'M') - { - $config{mode} = 'status'; - Clear() unless $config{batchmode}; - print "Queries Per Second [hit q to exit this mode]\n"; - next; - } - - ## c - mode swtich to command summary + ## c - mode switch to command summary if ($key eq 'c') { @@ -467,8 +457,6 @@ while (1) next; } - # Change the SLOW query value - if ($key eq 'S') { cmd_S(); @@ -755,7 +743,9 @@ while (1) ReadKey(0); } - if ($key eq 'S') + # Switch to show status mode + + if ($key eq 'M') { $config{mode} = 'status'; } @@ -931,6 +921,11 @@ sub GetData() } } + open L, "; + close L; + chomp $l; + $last_time = $now_time; ## Server Uptime in meaningful terms... @@ -962,6 +957,7 @@ sub GetData() printf "%-.${host_width}s %${up_width}s\n", "$server on $config{host} ($db_version)", "up $uptime $current_time"; +# "load $l up $uptime $current_time"; $lines_left--; @@ -1055,19 +1051,29 @@ sub GetData() if ($t_delta) { + my $rows_read; + if (defined($STATUS{Rows_read})) + { + $rows_read= $STATUS{Rows_read} - $OLD_STATUS{Rows_read}; + } + else + { + $rows_read= + ($STATUS{Handler_read_first}+$STATUS{Handler_read_key}+ + $STATUS{Handler_read_next}+$STATUS{Handler_read_prev}+ + $STATUS{Handler_read_rnd}+$STATUS{Handler_read_rnd_next} - + $OLD_STATUS{Handler_read_first}-$OLD_STATUS{Handler_read_key}- + $OLD_STATUS{Handler_read_next}-$OLD_STATUS{Handler_read_prev}- + $OLD_STATUS{Handler_read_rnd}- + $OLD_STATUS{Handler_read_rnd_next}); + } printf(" Handler: (R/W/U/D) %5d/%5d/%5d/%5d Tmp: R/W/U: %5d/%5d/%5d\n", - ($STATUS{Handler_read_first}+$STATUS{Handler_read_key}+ - $STATUS{Handler_read_next}+$STATUS{Handler_read_prev}+ - $STATUS{Handler_read_rnd}+$STATUS{Handler_read_rnd_next} - - $OLD_STATUS{Handler_read_first}-$OLD_STATUS{Handler_read_key}- - $OLD_STATUS{Handler_read_next}-$OLD_STATUS{Handler_read_prev}- - $OLD_STATUS{Handler_read_rnd}- - $OLD_STATUS{Handler_read_rnd_next})/$t_delta, + $rows_read/$t_delta, ($STATUS{Handler_write} - $OLD_STATUS{Handler_write}) / $t_delta, ($STATUS{Handler_update} - $OLD_STATUS{Handler_update}) / $t_delta, - ($STATUS{Handler_delete} - $OLD_STATUS{Handler_delete}) / + ($STATUS{Handler_delete} - $OLD_STATUS{Handler_delete}) / $t_delta, ($STATUS{Rows_tmp_read} - $OLD_STATUS{Rows_tmp_read}) / $t_delta, @@ -1083,7 +1089,7 @@ sub GetData() $lines_left--; - printf(" MyISAM Key Efficiency: %2.1f%% Bps in/out: %5s/%5s ", + printf(" ISAM Key Efficiency: %2.1f%% Bps in/out: %5s/%5s ", $cache_hits_percent, make_short($STATUS{Bytes_received} / $STATUS{Uptime} ), make_short($STATUS{Bytes_sent} / $STATUS{Uptime})); @@ -1095,35 +1101,40 @@ sub GetData() $lines_left--; - my($data) = Hashes('SHOW SLAVE STATUS'); + my($data) = Hashes('show global variables like "read_only"'); + if ($data->{Value} ne "OFF") + { + print RED() if ($HAS_COLOR) ; + print " ReadOnly"; + RESET() if ($HAS_COLOR); + } + + ($data) = Hashes('SHOW SLAVE STATUS'); if (defined($data->{Master_Host})) { + if (defined($data->{Seconds_Behind_Master})) + { + if ($HAS_COLOR) { + print GREEN(); + print YELLOW() if ($data->{Seconds_Behind_Master} > 60); + print MAGENTA() if ($data->{Seconds_Behind_Master} > 360); + } + } print " Replication "; - if ($HAS_COLOR) { - print GREEN(); - print RED() if ($data->{Slave_IO_Running} ne "Yes") ; - } print "IO:$data->{Slave_IO_Running} "; - RESET() if ($HAS_COLOR); - - if ($HAS_COLOR) { - print GREEN(); - print RED() if ($data->{Slave_SQL_Running} ne "Yes") ; - } print "SQL:$data->{Slave_SQL_Running} "; print RESET() if ($HAS_COLOR); - my $SlaveDelay = $data->{Seconds_Behind_Master}; - if ($SlaveDelay) + if (defined($data->{Seconds_Behind_Master})) { if ($HAS_COLOR) { print GREEN(); - print YELLOW() if ($SlaveDelay > 10); - print MAGENTA() if ($SlaveDelay > 120); + print YELLOW() if ($data->{Seconds_Behind_Master} > 60); + print MAGENTA() if ($data->{Seconds_Behind_Master} > 360); } - print "Delay: $SlaveDelay sec."; + print "Delay: $data->{Seconds_Behind_Master} sec."; } else { - my $free = $width - 35; + my $free = $width - 45; my $Err = substr $data->{Last_Error},0 ,$free; printf(" ERR: %-${free}s", $Err) if ( $Err ne "" ); } @@ -1198,6 +1209,7 @@ sub GetData() if ($is_ip and $config{resolve}) { $thread->{Host} =~ s/:\d+$//; +# my $host = $thread->{Host}; my $host = gethostbyaddr(inet_aton($thread->{Host}), AF_INET); # $host =~ s/^([^.]+).*/$1/; $thread->{Host} = $host; @@ -1483,7 +1495,7 @@ sub GetShowStatus() Clear() unless $config{batchmode}; my @rows = Hashes("SHOW STATUS"); - printf "%32s %10s %10s\n", 'Counter', 'Total', 'Change'; + printf "%32s %10s %10s Toggle idle with 'i'\n", 'Counter', 'Total', 'Change'; printf "%32s %10s %10s\n", '-------', '-----', '------'; for my $row (@rows) @@ -1519,9 +1531,7 @@ sub GetShowStatus() } } - if ($delta != 0) { - printf "%32s: %10s %10s\n", $name, $value, $delta; - } + printf "%32s: %10s %10s\n", $name, $value, $delta; print RESET() if $HAS_COLOR; $statcache{$name} = $value; @@ -1703,12 +1713,11 @@ sub trim($) sub PrintHelp() { my $help = qq[ -Help for mytop version $main::VERSION by Mark Grennan <${YELLOW}Mark\@Grennan.com${RESET}> -Origional work by Jeremy D. Zawodny <${YELLOW}Jeremy\@Zawodny.com${RESET}> +Help for mytop version $main::VERSION by Jeremy D. Zawodny <${YELLOW}Jeremy\@Zawodny.com${RESET}> + with updates by Mark Grennan <${YELLOW}mark\@grennan.com${RESET}> ? - display this screen # - toggle short/long numbers (not yet implemented) - ! - force past replication error c - command summary view (based on Com_* counters) C - turn color on and off d - show only a specific database @@ -1733,8 +1742,9 @@ Origional work by Jeremy D. Zawodny <${YELLOW}Jeremy\@Zawodny.com${RESET}> S - change slow quiery hightlighting t - switch to thread view (default) u - show only a specific user - V - show variablesi + V - show variables : - enter a command (not yet implemented) + ! - Skip an error that has stopped replications (at your own risk) L - show full queries (do not strip to terminal width) Base version from ${GREEN}http://www.mysqlfanboy.com/mytop${RESET} @@ -2317,11 +2327,8 @@ having the User column appear, for example. mytop was developed and is maintained by Jeremy D. Zawodny (Jeremy@Zawodny.com). -(Mark Grennan) After weeks and months of trying to get Jeremy's -attention I desided to release my own update to mytop. I use it -every day as a part of my job. Thanks Jeremy for creating mytop. -I hope you find my updates as helpful as I have. I can be -reached at (Mark@Grennan.com). +If you wish to e-mail me regarding this software, B subscribe +to the B mailing list. See the B homepage for details. =head1 DISCLAIMER @@ -2330,12 +2337,6 @@ for it. Yahoo! does not necessarily support this software in any way. It is merely a personal idea which happened to be very useful in my job. -=head1 RECRUITING - -If you hack Perl and grok MySQL, come work at Yahoo! Contact me for -details. Or just send me your resume. Er, unless we just had layoffs, -in which case we're not hiring. :-( - =head1 SEE ALSO Please check the MySQL manual if you're not sure where some of the @@ -2344,7 +2345,6 @@ output of B is coming from. =head1 COPYRIGHT Copyright (C) 2000-2010, Jeremy D. Zawodny. -Copyright (C) 2010, Mark T. Grennan. =head1 CREDITS @@ -2358,6 +2358,15 @@ Many thanks go to these fine folks: Added --fullqueries and reading of .my.cnf +=item Mark Grennan (mark@grennan.com) www.linuxfangoy.com + +Added updates for MySQL 5.x. Added 'S' (slow) highlighting. +Added 'C' to turn on and off Color. Added 'l' command to change +color for long running queries. Fixed a few documentation issues. +Monitors Slave status. Added color to Queue hit ratio. +Added number of rows sorted per second. +Created release 1.7. + =item Sami Ahlroos (sami@avis-net.de) Suggested the idle/noidle stuff. From b8ca6c2e68a7875ec585af516bbc6331d2c2b940 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Tue, 25 Sep 2012 00:46:54 +0200 Subject: [PATCH 272/289] MDEV-546 : error when compiling client library - incorrect client_settings.h Remove sql directory from the include path to workaround the problem. This removes the ambiguity , since then only one client_settings.h will be in the include paths --- libmysql/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/libmysql/CMakeLists.txt b/libmysql/CMakeLists.txt index 182c8748934..f67b3962c1a 100644 --- a/libmysql/CMakeLists.txt +++ b/libmysql/CMakeLists.txt @@ -17,7 +17,6 @@ INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/libmysql ${CMAKE_SOURCE_DIR}/regex - ${CMAKE_SOURCE_DIR}/sql ${CMAKE_SOURCE_DIR}/strings ${SSL_INCLUDE_DIRS} ${SSL_INTERNAL_INCLUDE_DIRS} From 2f7d7c9f7f7b8da68de4bed21f167e316c600a0e Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 25 Sep 2012 13:45:11 +0300 Subject: [PATCH 273/289] makes mi_test_all.sh & ma_test_all.sh working (MDEV-285) --- storage/maria/CMakeLists.txt | 2 +- storage/maria/ma_test_all.sh | 13 +++++++++++-- storage/myisam/CMakeLists.txt | 2 +- storage/myisam/mi_test_all.sh | 2 +- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/storage/maria/CMakeLists.txt b/storage/maria/CMakeLists.txt index 2817e11681c..9ca198873d1 100644 --- a/storage/maria/CMakeLists.txt +++ b/storage/maria/CMakeLists.txt @@ -68,7 +68,7 @@ SET_TARGET_PROPERTIES(aria_dump_log PROPERTIES COMPILE_FLAGS "-DMARIA_DUMP_LOG") MYSQL_ADD_EXECUTABLE(aria_pack maria_pack.c COMPONENT Server) TARGET_LINK_LIBRARIES(aria_pack aria) -IF(WITH_UNIT_TESTS AND FALSE) +IF(WITH_UNIT_TESTS) ADD_EXECUTABLE(ma_test1 ma_test1.c) TARGET_LINK_LIBRARIES(ma_test1 aria) diff --git a/storage/maria/ma_test_all.sh b/storage/maria/ma_test_all.sh index 041fbf3abe6..4e9be4a5beb 100755 --- a/storage/maria/ma_test_all.sh +++ b/storage/maria/ma_test_all.sh @@ -7,13 +7,22 @@ # # +PRG='unittest/ma_test_all-t' +UTST='../../unittest/unit.pl' + +if [ ! -x $PRG ] ; then + DIR=`dirname $0` + PRG="$DIR/unittest/ma_test_all-t" + UTST="$DIR/../../unittest/unit.pl" +fi + if test -n "$1"; then # unit.pl can't pass options to ma_test_all-t, so if anything # was passed as an argument, assume the purpose was to pass # them to ma_test_all-t and call it directly - unittest/ma_test_all-t $@ + $PRG $@ else - perl ../../unittest/unit.pl run unittest/ma_test_all-t + perl $UTST run $PRG fi diff --git a/storage/myisam/CMakeLists.txt b/storage/myisam/CMakeLists.txt index 97c1bc78d95..f58c942b4d7 100644 --- a/storage/myisam/CMakeLists.txt +++ b/storage/myisam/CMakeLists.txt @@ -46,7 +46,7 @@ TARGET_LINK_LIBRARIES(myisamlog myisam) MYSQL_ADD_EXECUTABLE(myisampack myisampack.c COMPONENT Server) TARGET_LINK_LIBRARIES(myisampack myisam) -IF(WITH_UNIT_TESTS AND FALSE) +IF(WITH_UNIT_TESTS) ADD_EXECUTABLE(mi_test1 mi_test1.c) TARGET_LINK_LIBRARIES(mi_test1 myisam) diff --git a/storage/myisam/mi_test_all.sh b/storage/myisam/mi_test_all.sh index 641f1cc0a35..c9c89a9ecac 100755 --- a/storage/myisam/mi_test_all.sh +++ b/storage/myisam/mi_test_all.sh @@ -99,7 +99,7 @@ if test -f mi_test1$MACH ; then suffix=$MACH ; else suffix=""; fi # check of myisampack / myisamchk ./myisampack$suffix --force -s test1 # Ignore error for index file -./myisamchk$suffix -es test1 2>&1 >& /dev/null +./myisamchk$suffix -es test1 2>&1 > /dev/null ./myisamchk$suffix -rqs test1 ./myisamchk$suffix -es test1 ./myisamchk$suffix -rs test1 From 1864d9596d9531427f1d63f86ada9e0cb21b51db Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Fri, 28 Sep 2012 02:06:56 +0300 Subject: [PATCH 274/289] Implementation of Multi-source replication (MDEV:253) Documentation of the feature can be found at: http://kb.askmonty.org/en/multi-source-replication/ This code is based on code from Taobao, developed by Plinux BUILD/SETUP.sh: Added -Wno-invalid-offsetof to get rid of warning of offsetof() on C++ class (safe in the contex we use it) client/mysqltest.cc: Added support for error names starting with 'W' Added connection_name support to --sync_with_master cmake/maintainer.cmake: Added -Wno-invalid-offsetof to get rid of warning of offsetof() on C++ class (safe in the contex we use it) mysql-test/r/mysqltest.result: Updated results mysql-test/r/parser.result: Updated results mysql-test/suite/multi_source/my.cnf: Setup of multi-master tests mysql-test/suite/multi_source/simple.result: Simple basic test of multi-source functionality mysql-test/suite/multi_source/simple.test: Simple basic test of multi-source functionality mysql-test/suite/multi_source/syntax.result: Test of multi-source syntax mysql-test/suite/multi_source/syntax.test: Test of multi-source syntax mysql-test/suite/rpl/r/rpl_rotate_logs.result: Updated results because of new error messages mysql-test/t/parser.test: Updated test as master_pos_wait() now takes more arguments than before sql/event_scheduler.cc: No reason to initialize slave_thread (it's guaranteed to be zero here) sql/item_create.cc: Added connection_name argument to master_pos_wait() Simplified code sql/item_func.cc: Added connection_name argument to master_pos_wait() sql/item_func.h: Added connection_name argument to master_pos_wait() sql/log.cc: Added tag "Master 'connection_name'" to slave errors that has a connection name. sql/mysqld.cc: Added variable mysqld_server_initialized so that other functions can test if server is fully initialized. Free all slave data in one place (fewer ifdef's) Removed not needed call to close_active_mi() Initialize slaves() later in startup to ensure that everthing is really initialized when slaves start. Made status variable slave_running multi-source safe sql/mysqld.h: Added mysqld_server_initialized sql/rpl_mi.cc: Store connection name and cmp_connection_name (only used for show full slave status) in Master_info Added code for Master_info_index, which handles storage of multi-master information Don't write the empty "" connection_name to multi-master.info file. This is handled by the original code. sql/rpl_mi.h: Added connection_name and Master_info_index sql/rpl_rli.cc: Added connection_name to relay log files. sql/rpl_rli.h: Fixed type of slave_skip_counter as we now access it directly in sys_vars.cc, so it must be uint sql/share/errmsg-utf8.txt: Added new error messages needed for multi-source Added multi-source name to error ER_MASTER_INFO and WARN_NO_MASTER_INFO sql/slave.cc: Moved things a bit around to make it easier to handle error conditions. Create a global master_info_index and add the "" connection to it Ensure that new Master_info doesn't fail. Don't call terminate_slave_threads(active_mi..) on end_slave() as this is now done automaticly when deleting master_info_index. Delete not needed function close_active_mi(). One can achive same thing by calling end_slave(). Added support for SHOW FULL SLAVE STATUS (show status for all master connections with connection_name as first column) sql/slave.h: Added new prototypes sql/sql_base.cc: More DBUG_PRINT sql/sql_class.cc: Reset thd->connection_name and thd-->default_master_connection sql/sql_class.h: Added thd->connection_name and thd-->default_master_connection Added slave_skip_count to variables to make changing the @@sql_slave_skip_count variable thread safe sql/sql_const.h: Added MAX_CONNECTION_NAME sql/sql_lex.cc: Reset 'lex->verbose' (to simplify some sql_yacc.yy code) sql/sql_lex.h: Added connection_name sql/sql_parse.cc: Added support for connection_name to all SLAVE commands. - Instead of using active_mi, we now get the current Master_info from master_info_index. - Create new replication threads with CHANGE MASTER - Added support for show_all_master_info() sql/sql_reload.cc: Made reset/full slave use master_info_index->get_master_info() instead of active_mi. If one uses 'RESET SLAVE "connection_name" all' the connection is removed from master_info_index. sql/sql_repl.cc: sql_slave_skip_counter is moved to thd->variables to make it thread safe and fix some bugs with it Add connection name to relay log files. Added connection name to errors. Added some logging for multi-master if log_warnings > 1 stop_slave(): - Don't check if thd is set. It's guaranteed to always be set. change_master(): - Check for duplicate connection names in change_master() - Check for wrong arguments first in file (to simplify error handling) - Register new connections in master_info_index sql/sql_yacc.yy: Added optional connection_name to a all relevant master/slave commands sql/strfunc.cc: my_global.h shoud always be included first. sql/sys_vars.cc: Added variable default_master_connection Made variable sql_slave_skip_counter multi-source safe sql/sys_vars.h: Added Sys_var_session_lexstring (needed for default_master_connection) Added Sys_var_multi_source_uint (needed for sql_slave_skip_counter). --- BUILD/SETUP.sh | 2 +- client/mysqltest.cc | 42 +- cmake/maintainer.cmake | 2 +- mysql-test/r/mysqltest.result | 2 +- mysql-test/r/parser.result | 2 +- mysql-test/suite/multi_source/my.cnf | 22 + mysql-test/suite/multi_source/simple.result | 64 +++ mysql-test/suite/multi_source/simple.test | 38 ++ .../suite/multi_source/skip_counter.result | 81 +++ .../suite/multi_source/skip_counter.test | 126 +++++ mysql-test/suite/multi_source/syntax.result | 89 ++++ mysql-test/suite/multi_source/syntax.test | 77 +++ mysql-test/suite/rpl/r/rpl_rotate_logs.result | 4 +- mysql-test/t/parser.test | 2 +- sql/event_scheduler.cc | 1 - sql/item_create.cc | 23 +- sql/item_func.cc | 34 +- sql/item_func.h | 3 + sql/log.cc | 21 +- sql/mysqld.cc | 68 +-- sql/mysqld.h | 2 +- sql/rpl_mi.cc | 472 +++++++++++++++++- sql/rpl_mi.h | 51 +- sql/rpl_rli.cc | 22 +- sql/rpl_rli.h | 3 +- sql/share/errmsg-utf8.txt | 19 +- sql/slave.cc | 199 ++++++-- sql/slave.h | 9 +- sql/sql_base.cc | 5 + sql/sql_class.cc | 10 + sql/sql_class.h | 10 + sql/sql_const.h | 1 + sql/sql_lex.cc | 1 + sql/sql_lex.h | 1 + sql/sql_parse.cc | 107 ++-- sql/sql_reload.cc | 17 +- sql/sql_repl.cc | 127 +++-- sql/sql_yacc.yy | 53 +- sql/strfunc.cc | 1 + sql/sys_vars.cc | 112 +++-- sql/sys_vars.h | 142 ++++++ 41 files changed, 1833 insertions(+), 234 deletions(-) create mode 100644 mysql-test/suite/multi_source/my.cnf create mode 100644 mysql-test/suite/multi_source/simple.result create mode 100644 mysql-test/suite/multi_source/simple.test create mode 100644 mysql-test/suite/multi_source/skip_counter.result create mode 100644 mysql-test/suite/multi_source/skip_counter.test create mode 100644 mysql-test/suite/multi_source/syntax.result create mode 100644 mysql-test/suite/multi_source/syntax.test diff --git a/BUILD/SETUP.sh b/BUILD/SETUP.sh index de3cb4890a9..5154f64b98f 100755 --- a/BUILD/SETUP.sh +++ b/BUILD/SETUP.sh @@ -139,7 +139,7 @@ else # C warnings c_warnings="$warnings" # C++ warnings - cxx_warnings="$warnings -Wno-unused-parameter" + cxx_warnings="$warnings -Wno-unused-parameter -Wno-invalid-offsetof" # cxx_warnings="$cxx_warnings -Woverloaded-virtual -Wsign-promo" cxx_warnings="$cxx_warnings -Wnon-virtual-dtor" debug_extra_cflags="-O0 -g3 -gdwarf-2" diff --git a/client/mysqltest.cc b/client/mysqltest.cc index bb89db4b231..f824d53ed1b 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -253,6 +253,8 @@ static void init_re(void); static int match_re(my_regex_t *, char *); static void free_re(void); +static char *get_string(char **to_ptr, char **from_ptr, + struct st_command *command); static int replace(DYNAMIC_STRING *ds_str, const char *search_str, ulong search_len, const char *replace_str, ulong replace_len); @@ -4580,7 +4582,8 @@ void do_wait_for_slave_to_stop(struct st_command *c __attribute__((unused))) } -void do_sync_with_master2(struct st_command *command, long offset) +void do_sync_with_master2(struct st_command *command, long offset, + const char *connection_name) { MYSQL_RES *res; MYSQL_ROW row; @@ -4591,8 +4594,9 @@ void do_sync_with_master2(struct st_command *command, long offset) if (!master_pos.file[0]) die("Calling 'sync_with_master' without calling 'save_master_pos'"); - sprintf(query_buf, "select master_pos_wait('%s', %ld, %d)", - master_pos.file, master_pos.pos + offset, timeout); + sprintf(query_buf, "select master_pos_wait('%s', %ld, %d, '%s')", + master_pos.file, master_pos.pos + offset, timeout, + connection_name); if (mysql_query(mysql, query_buf)) die("failed in '%s': %d: %s", query_buf, mysql_errno(mysql), @@ -4652,16 +4656,32 @@ void do_sync_with_master(struct st_command *command) long offset= 0; char *p= command->first_argument; const char *offset_start= p; + char *start, *buff= 0; + start= (char*) ""; + if (*offset_start) { for (; my_isdigit(charset_info, *p); p++) offset = offset * 10 + *p - '0'; - if(*p && !my_isspace(charset_info, *p)) + if (*p && !my_isspace(charset_info, *p) && *p != ',') die("Invalid integer argument \"%s\"", offset_start); + + while (*p && my_isspace(charset_info, *p)) + p++; + if (*p == ',') + { + p++; + while (*p && my_isspace(charset_info, *p)) + p++; + start= buff= (char*)my_malloc(strlen(p)+1,MYF(MY_WME | MY_FAE)); + get_string(&buff, &p, command); + } command->last_argument= p; } - do_sync_with_master2(command, offset); + do_sync_with_master2(command, offset, start); + if (buff) + my_free(start); return; } @@ -5286,7 +5306,7 @@ void do_get_errcodes(struct st_command *command) { die("The sqlstate definition must start with an uppercase S"); } - else if (*p == 'E') + else if (*p == 'E' || *p == 'W') { /* Error name string */ @@ -5295,9 +5315,9 @@ void do_get_errcodes(struct st_command *command) to->type= ERR_ERRNO; DBUG_PRINT("info", ("ERR_ERRNO: %d", to->code.errnum)); } - else if (*p == 'e') + else if (*p == 'e' || *p == 'w') { - die("The error name definition must start with an uppercase E"); + die("The error name definition must start with an uppercase E or W"); } else { @@ -5360,8 +5380,8 @@ void do_get_errcodes(struct st_command *command) If string is a '$variable', return the value of the variable. */ -char *get_string(char **to_ptr, char **from_ptr, - struct st_command *command) +static char *get_string(char **to_ptr, char **from_ptr, + struct st_command *command) { char c, sep; char *to= *to_ptr, *from= *from_ptr, *start=to; @@ -9288,7 +9308,7 @@ int main(int argc, char **argv) select_connection(command); else select_connection_name("slave"); - do_sync_with_master2(command, 0); + do_sync_with_master2(command, 0, ""); break; } case Q_COMMENT: diff --git a/cmake/maintainer.cmake b/cmake/maintainer.cmake index a70226e2b6e..d52405e8bcc 100644 --- a/cmake/maintainer.cmake +++ b/cmake/maintainer.cmake @@ -18,7 +18,7 @@ INCLUDE(CheckCCompilerFlag) # Setup GCC (GNU C compiler) warning options. MACRO(SET_MYSQL_MAINTAINER_GNU_C_OPTIONS) SET(MY_MAINTAINER_WARNINGS - "-Wall -Wextra -Wunused -Wwrite-strings -Wno-strict-aliasing -DFORCE_INIT_OF_VARS") + "-Wall -Wextra -Wunused -Wwrite-strings -Wno-strict-aliasing -Wno-invalid-offsetof -DFORCE_INIT_OF_VARS") CHECK_C_COMPILER_FLAG("-Wno-missing-field-initializers" HAVE_NO_MISSING_FIELD_INITIALIZERS) diff --git a/mysql-test/r/mysqltest.result b/mysql-test/r/mysqltest.result index fdb3029059f..d08ffd96a04 100644 --- a/mysql-test/r/mysqltest.result +++ b/mysql-test/r/mysqltest.result @@ -232,7 +232,7 @@ mysqltest: At line 2: Spurious text after `query` expression mysqltest: At line 1: Missing argument(s) to 'error' mysqltest: At line 1: Missing argument(s) to 'error' mysqltest: At line 1: The sqlstate definition must start with an uppercase S -mysqltest: At line 1: The error name definition must start with an uppercase E +mysqltest: At line 1: The error name definition must start with an uppercase E or W mysqltest: At line 1: Invalid argument to error: '9eeeee' - the errno may only consist of digits[0-9] mysqltest: At line 1: Invalid argument to error: '1sssss' - the errno may only consist of digits[0-9] mysqltest: At line 1: The sqlstate must be exactly 5 chars long diff --git a/mysql-test/r/parser.result b/mysql-test/r/parser.result index 10700d0ba73..54378f16d49 100644 --- a/mysql-test/r/parser.result +++ b/mysql-test/r/parser.result @@ -441,7 +441,7 @@ select master_pos_wait(); ERROR 42000: Incorrect parameter count in the call to native function 'master_pos_wait' select master_pos_wait(1); ERROR 42000: Incorrect parameter count in the call to native function 'master_pos_wait' -select master_pos_wait(1, 2, 3, 4); +select master_pos_wait(1, 2, 3, 4, 5); ERROR 42000: Incorrect parameter count in the call to native function 'master_pos_wait' select rand(1, 2, 3); ERROR 42000: Incorrect parameter count in the call to native function 'rand' diff --git a/mysql-test/suite/multi_source/my.cnf b/mysql-test/suite/multi_source/my.cnf new file mode 100644 index 00000000000..dd57fd2199f --- /dev/null +++ b/mysql-test/suite/multi_source/my.cnf @@ -0,0 +1,22 @@ +# cat t/multisource1.cnf +!include include/default_mysqld.cnf +!include include/default_client.cnf + +[mysqld.1] +server-id=1 +log-bin=master-bin + +[mysqld.2] +server-id=2 +log-bin=master-bin + +[mysqld.3] +server-id=3 + +[ENV] +SERVER_MYPORT_1= @mysqld.1.port +SERVER_MYSOCK_1= @mysqld.1.socket +SERVER_MYPORT_2= @mysqld.2.port +SERVER_MYSOCK_2= @mysqld.2.socket +SERVER_MYPORT_3= @mysqld.3.port +SERVER_MYSOCK_3= @mysqld.3.socket diff --git a/mysql-test/suite/multi_source/simple.result b/mysql-test/suite/multi_source/simple.result new file mode 100644 index 00000000000..7448e0a0113 --- /dev/null +++ b/mysql-test/suite/multi_source/simple.result @@ -0,0 +1,64 @@ +change master 'slave1' to master_port=MYPORT_1, master_host='127.0.0.1', master_user='root'; +change master 'slave2' to master_port=MYPORT_2, master_host='127.0.0.1', master_user='root'; +start slave 'slave1'; +start slave 'slave2'; +show full slave status; +Connection_name 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 Replicate_Ignore_Server_Ids Master_Server_Id +slave1 Waiting for master to send event 127.0.0.1 root MYPORT_1 60 master-bin.000001 286 mysqld-relay-bin-slave1.000002 572 master-bin.000001 Yes Yes 0 0 286 875 None 0 No 0 No 0 0 1 +slave2 Waiting for master to send event 127.0.0.1 root MYPORT_2 60 master-bin.000001 286 mysqld-relay-bin-slave2.000002 572 master-bin.000001 Yes Yes 0 0 286 875 None 0 No 0 No 0 0 2 +stop slave 'slave1'; +show slave 'slave1' status; +Slave_IO_State +Master_Host 127.0.0.1 +Master_User root +Master_Port MYPORT_1 +Connect_Retry 60 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos 286 +Relay_Log_File mysqld-relay-bin-slave1.000002 +Relay_Log_Pos 572 +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running No +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 0 +Last_Error +Skip_Counter 0 +Exec_Master_Log_Pos 286 +Relay_Log_Space 875 +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 NULL +Master_SSL_Verify_Server_Cert No +Last_IO_Errno 0 +Last_IO_Error +Last_SQL_Errno 0 +Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 +reset slave 'slave1'; +show full slave status; +Connection_name 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 Replicate_Ignore_Server_Ids Master_Server_Id +slave1 127.0.0.1 root MYPORT_1 60 4 mysqld-relay-bin-slave1.000001 4 No No 0 0 0 265 None 0 No NULL No 0 0 1 +slave2 Waiting for master to send event 127.0.0.1 root MYPORT_2 60 master-bin.000001 286 mysqld-relay-bin-slave2.000002 572 master-bin.000001 Yes Yes 0 0 286 875 None 0 No 0 No 0 0 2 +reset slave 'slave1' all; +show full slave status; +Connection_name 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 Replicate_Ignore_Server_Ids Master_Server_Id +slave2 Waiting for master to send event 127.0.0.1 root MYPORT_2 60 master-bin.000001 286 mysqld-relay-bin-slave2.000002 572 master-bin.000001 Yes Yes 0 0 286 875 None 0 No 0 No 0 0 2 +stop slave 'slave2'; +show full slave status; +Connection_name 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 Replicate_Ignore_Server_Ids Master_Server_Id +slave2 127.0.0.1 root MYPORT_2 60 master-bin.000001 286 mysqld-relay-bin-slave2.000002 572 master-bin.000001 No No 0 0 286 875 None 0 No NULL No 0 0 2 +reset slave 'slave2' all; diff --git a/mysql-test/suite/multi_source/simple.test b/mysql-test/suite/multi_source/simple.test new file mode 100644 index 00000000000..97696c6e75f --- /dev/null +++ b/mysql-test/suite/multi_source/simple.test @@ -0,0 +1,38 @@ +# +# Simple multi-master test +# + +--connect (slave,127.0.0.1,root,,,$SERVER_MYPORT_3) + +--replace_result $SERVER_MYPORT_1 MYPORT_1 +eval change master 'slave1' to master_port=$SERVER_MYPORT_1, master_host='127.0.0.1', master_user='root'; +--replace_result $SERVER_MYPORT_2 MYPORT_2 +eval change master 'slave2' to master_port=$SERVER_MYPORT_2, master_host='127.0.0.1', master_user='root'; +start slave 'slave1'; +start slave 'slave2'; +--sleep 5 + +--replace_result $SERVER_MYPORT_1 MYPORT_1 $SERVER_MYPORT_2 MYPORT_2 +show full slave status; + +stop slave 'slave1'; + +--replace_result $SERVER_MYPORT_1 MYPORT_1 $SERVER_MYPORT_2 MYPORT_2 +query_vertical show slave 'slave1' status; + +reset slave 'slave1'; +--replace_result $SERVER_MYPORT_1 MYPORT_1 $SERVER_MYPORT_2 MYPORT_2 +show full slave status; + +reset slave 'slave1' all; +--replace_result $SERVER_MYPORT_1 MYPORT_1 $SERVER_MYPORT_2 MYPORT_2 +show full slave status; + +stop slave 'slave2'; +--replace_result $SERVER_MYPORT_1 MYPORT_1 $SERVER_MYPORT_2 MYPORT_2 +show full slave status; + +# +# clean up +# +reset slave 'slave2' all; diff --git a/mysql-test/suite/multi_source/skip_counter.result b/mysql-test/suite/multi_source/skip_counter.result new file mode 100644 index 00000000000..1fb1c255d80 --- /dev/null +++ b/mysql-test/suite/multi_source/skip_counter.result @@ -0,0 +1,81 @@ +connect master1,127.0.0.1,root,,,$SERVER_MYPORT_1; +drop database if exists db; +create database db; +create table db.t1 (i int) engine=MyISAM; +connect master2,127.0.0.1,root,,,$SERVER_MYPORT_2; +drop database if exists db; +create database db; +create table db.t2 (i int) engine=MyISAM; +connect slave,127.0.0.1,root,,,$SERVER_MYPORT_3; +change master 'master1' to +master_port=MYPORT_1, +master_host='127.0.0.1', +master_user='root'; +start slave 'master1'; +set default_master_connection = 'master1'; +include/wait_for_slave_to_start.inc +set default_master_connection = 'master2'; +change master 'master2' to +master_port=MYPORT_2, +master_host='127.0.0.1', +master_user='root'; +set global sql_slave_skip_counter = 2; +select @@global.sql_slave_skip_counter; +@@global.sql_slave_skip_counter +2 +select @@session.sql_slave_skip_counter; +@@session.sql_slave_skip_counter +2 +set session sql_slave_skip_counter = 3; +select @@global.sql_slave_skip_counter; +@@global.sql_slave_skip_counter +3 +select @@session.sql_slave_skip_counter; +@@session.sql_slave_skip_counter +3 +set global sql_slave_skip_counter= default; +select @@global.sql_slave_skip_counter; +@@global.sql_slave_skip_counter +0 +select @@session.sql_slave_skip_counter; +@@session.sql_slave_skip_counter +0 +set global sql_slave_skip_counter= 3; +set default_master_connection = 'master1'; +select @@session.sql_slave_skip_counter; +@@session.sql_slave_skip_counter +0 +set default_master_connection = 'qqq'; +select @@session.sql_slave_skip_counter; +@@session.sql_slave_skip_counter +0 +Warnings: +Warning 1617 There is no master connection 'qqq' +set default_master_connection = 'master2'; +select @@session.sql_slave_skip_counter; +@@session.sql_slave_skip_counter +3 +start slave 'master2'; +include/wait_for_slave_to_start.inc +set default_master_connection = ''; +connection master2; +connection slave; +show tables in db; +Tables_in_db +t1 +t2 +drop database db; +set default_master_connection = 'master1'; +stop slave; +include/wait_for_slave_to_stop.inc +set default_master_connection = 'master2'; +stop slave; +include/wait_for_slave_to_stop.inc +set global sql_slave_skip_counter = 0; +disconnect slave; +connection master1; +drop database db; +disconnect master1; +connection master2; +drop database db; +disconnect master2; diff --git a/mysql-test/suite/multi_source/skip_counter.test b/mysql-test/suite/multi_source/skip_counter.test new file mode 100644 index 00000000000..fe5df69097a --- /dev/null +++ b/mysql-test/suite/multi_source/skip_counter.test @@ -0,0 +1,126 @@ +# +# Test of sql_slave_skip_counter +# + +--enable_connect_log + +# Create a schema and a table i +# on the 1st master + +--connect (master1,127.0.0.1,root,,,$SERVER_MYPORT_1) + +--disable_warnings +drop database if exists db; +--enable_warnings +create database db; +create table db.t1 (i int) engine=MyISAM; +--save_master_pos + + +# Create the same schema and another table +# on the 2nd master + +--connect (master2,127.0.0.1,root,,,$SERVER_MYPORT_2) + +--disable_warnings +drop database if exists db; +--enable_warnings +create database db; +create table db.t2 (i int) engine=MyISAM; + +--connect (slave,127.0.0.1,root,,,$SERVER_MYPORT_3) +--disable_connect_log + +# Start replication from the first master + +--replace_result $SERVER_MYPORT_1 MYPORT_1 +eval change master 'master1' to +master_port=$SERVER_MYPORT_1, +master_host='127.0.0.1', +master_user='root'; + +start slave 'master1'; +set default_master_connection = 'master1'; +--source include/wait_for_slave_to_start.inc +--sync_with_master 0,'master1' + +# Start replication from the second master + +set default_master_connection = 'master2'; + +--replace_result $SERVER_MYPORT_2 MYPORT_2 +eval change master 'master2' to +master_port=$SERVER_MYPORT_2, +master_host='127.0.0.1', +master_user='root'; + +# the schema creation will be replicated from the 1st master, +# so we want to skip it in the second replication connection. + +# Normally it should have been 2 events, but +# currently Binlog_checkpoint also counts. Maybe we'll need +# to modify the test later + +--let $skip_counter_saved = `select @@global.sql_slave_skip_counter` +set global sql_slave_skip_counter = 2; +select @@global.sql_slave_skip_counter; +select @@session.sql_slave_skip_counter; +set session sql_slave_skip_counter = 3; +select @@global.sql_slave_skip_counter; +select @@session.sql_slave_skip_counter; +set global sql_slave_skip_counter= default; +select @@global.sql_slave_skip_counter; +select @@session.sql_slave_skip_counter; +set global sql_slave_skip_counter= 3; +set default_master_connection = 'master1'; +select @@session.sql_slave_skip_counter; +set default_master_connection = 'qqq'; +select @@session.sql_slave_skip_counter; +set default_master_connection = 'master2'; +select @@session.sql_slave_skip_counter; + +start slave 'master2'; +--source include/wait_for_slave_to_start.inc +set default_master_connection = ''; + +--enable_connect_log + +--connection master2 +--save_master_pos + +--connection slave + +--disable_connect_log +--sync_with_master 0,'master2' + +# If the skip_counter worked as expected, we should +# get here (replication shouldn't have broken) +# and should see both tables here +# (drop database which came from master2 shoudn't have been executed +# so t1 should still exist) + +show tables in db; + +# Cleanup + +drop database db; +set default_master_connection = 'master1'; +stop slave; + +--source include/wait_for_slave_to_stop.inc +set default_master_connection = 'master2'; +stop slave; + +--source include/wait_for_slave_to_stop.inc +--eval set global sql_slave_skip_counter = $skip_counter_saved + +--enable_connect_log +--disconnect slave + +--connection master1 +drop database db; +--disconnect master1 + +--connection master2 +drop database db; +--disconnect master2 diff --git a/mysql-test/suite/multi_source/syntax.result b/mysql-test/suite/multi_source/syntax.result new file mode 100644 index 00000000000..23ea4d9fd3d --- /dev/null +++ b/mysql-test/suite/multi_source/syntax.result @@ -0,0 +1,89 @@ +include/master-slave.inc +[connection master] +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 Replicate_Ignore_Server_Ids Master_Server_Id +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 Replicate_Ignore_Server_Ids Master_Server_Id +show full slave status; +Connection_name 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 Replicate_Ignore_Server_Ids Master_Server_Id +# +# Check error handling +# +show slave 'qqq' status; +ERROR HY000: There is no master connection 'qqq' +show slave 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc' status; +ERROR HY000: There is no master connection 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc' +show slave 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc' status; +ERROR HY000: Incorrect arguments to MASTER_CONNECTION_NAME +change master 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc' to master_host='dummy'; +ERROR HY000: Incorrect arguments to MASTER_CONNECTION_NAME +start slave 'qqq'; +ERROR HY000: There is no master connection 'qqq' +stop slave 'qqq'; +ERROR HY000: There is no master connection 'qqq' +slave 'qqq' start; +ERROR HY000: There is no master connection 'qqq' +slave 'qqq' stop; +ERROR HY000: There is no master connection 'qqq' +flush slave 'qqq'; +ERROR HY000: There is no master connection 'qqq' +reset slave 'qqq'; +ERROR HY000: There is no master connection 'qqq' +select master_pos_wait('master-bin.999999',0,2,'qqq'); +master_pos_wait('master-bin.999999',0,2,'qqq') +NULL +Warnings: +Warning 1617 There is no master connection 'qqq' +select master_pos_wait('master-bin.999999',0,2,'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc'); +master_pos_wait('master-bin.999999',0,2,'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc') +NULL +Warnings: +Warning 1210 Incorrect arguments to MASTER_CONNECTION_NAME +# +# checking usage of default_master_connection; +# +select @@default_master_connection; +@@default_master_connection + +select @@global.default_master_connection; +ERROR HY000: Variable 'default_master_connection' is a SESSION variable +set @@global.default_master_connection='qqq'; +ERROR HY000: Variable 'default_master_connection' is a SESSION variable and can't be used with SET GLOBAL +set @@default_master_connection='aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc'; +ERROR 42000: Variable 'default_master_connection' can't be set to the value of 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc' +select @@default_master_connection; +@@default_master_connection + +set @@default_master_connection='qqq'; +select @@default_master_connection; +@@default_master_connection +qqq +show variables like "default_master_connection"; +Variable_name Value +default_master_connection qqq +show slave status; +ERROR HY000: There is no master connection 'qqq' +select master_pos_wait('master-bin.999999',0,2); +master_pos_wait('master-bin.999999',0,2) +NULL +Warnings: +Warning 1617 There is no master connection 'qqq' +set @@default_master_connection=''; +select master_pos_wait('master-bin.999999',0,2); +master_pos_wait('master-bin.999999',0,2) +-1 +set @@default_master_connection=''; +# +# checking variables +# +show status like "Slave_running"; +Variable_name Value +Slave_running ON +set @@default_master_connection='qqq'; +show status like "Slave_running"; +Variable_name Value +Slave_running OFF +Warnings: +Warning 1617 There is no master connection 'qqq' +set @@default_master_connection=''; +include/rpl_end.inc diff --git a/mysql-test/suite/multi_source/syntax.test b/mysql-test/suite/multi_source/syntax.test new file mode 100644 index 00000000000..af793fe6100 --- /dev/null +++ b/mysql-test/suite/multi_source/syntax.test @@ -0,0 +1,77 @@ +# Test multi master syntax +source include/master-slave.inc; + +# Check syntax of multi source replication + +show slave status; +show slave '' status; +show full slave status; + +--echo # +--echo # Check error handling +--echo # + +--error WARN_NO_MASTER_INFO +show slave 'qqq' status; +--error WARN_NO_MASTER_INFO +show slave 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc' status; +--error ER_WRONG_ARGUMENTS +show slave 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc' status; +--error ER_WRONG_ARGUMENTS +change master 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc' to master_host='dummy'; + +--error WARN_NO_MASTER_INFO +start slave 'qqq'; +--error WARN_NO_MASTER_INFO +stop slave 'qqq'; +--error WARN_NO_MASTER_INFO +slave 'qqq' start; +--error WARN_NO_MASTER_INFO +slave 'qqq' stop; +--error WARN_NO_MASTER_INFO +flush slave 'qqq'; +--error WARN_NO_MASTER_INFO +reset slave 'qqq'; + +select master_pos_wait('master-bin.999999',0,2,'qqq'); +select master_pos_wait('master-bin.999999',0,2,'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc'); + +save_master_pos; +connection slave; +sync_with_master 0,''; +sync_with_master 0 ,''; +sync_with_master 0, ''; + +--echo # +--echo # checking usage of default_master_connection; +--echo # +select @@default_master_connection; + +--error 1238 +select @@global.default_master_connection; +--error 1228 +set @@global.default_master_connection='qqq'; +--error 1231 +set @@default_master_connection='aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc'; +select @@default_master_connection; +set @@default_master_connection='qqq'; +select @@default_master_connection; +show variables like "default_master_connection"; + +--error WARN_NO_MASTER_INFO +show slave status; +select master_pos_wait('master-bin.999999',0,2); +set @@default_master_connection=''; +select master_pos_wait('master-bin.999999',0,2); + +set @@default_master_connection=''; + +--echo # +--echo # checking variables +--echo # +show status like "Slave_running"; +set @@default_master_connection='qqq'; +show status like "Slave_running"; +set @@default_master_connection=''; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/r/rpl_rotate_logs.result b/mysql-test/suite/rpl/r/rpl_rotate_logs.result index f10e30c698d..783c02b961c 100644 --- a/mysql-test/suite/rpl/r/rpl_rotate_logs.result +++ b/mysql-test/suite/rpl/r/rpl_rotate_logs.result @@ -2,9 +2,9 @@ CALL mtr.add_suppression("Unsafe statement written to the binary log using state start slave; Got one of the listed errors start slave; -ERROR HY000: Could not initialize master info structure; more error messages can be found in the MariaDB error log +ERROR HY000: Could not initialize master info structure for ''; more error messages can be found in the MariaDB error log change master to master_host='127.0.0.1',master_port=MASTER_PORT, master_user='root'; -ERROR HY000: Could not initialize master info structure; more error messages can be found in the MariaDB error log +ERROR HY000: Could not initialize master info structure for ''; more error messages can be found in the MariaDB error log reset slave; change master to master_host='127.0.0.1',master_port=MASTER_PORT, master_user='root'; reset master; diff --git a/mysql-test/t/parser.test b/mysql-test/t/parser.test index d477843b22b..2c8cfafb90a 100644 --- a/mysql-test/t/parser.test +++ b/mysql-test/t/parser.test @@ -553,7 +553,7 @@ select master_pos_wait(); -- error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT select master_pos_wait(1); -- error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT -select master_pos_wait(1, 2, 3, 4); +select master_pos_wait(1, 2, 3, 4, 5); -- error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT select rand(1, 2, 3); diff --git a/sql/event_scheduler.cc b/sql/event_scheduler.cc index b41c9e2cda0..f107914f738 100644 --- a/sql/event_scheduler.cc +++ b/sql/event_scheduler.cc @@ -190,7 +190,6 @@ pre_init_event_thread(THD* thd) my_net_init(&thd->net, NULL); thd->security_ctx->set_user((char*)"event_scheduler"); thd->net.read_timeout= slave_net_timeout; - thd->slave_thread= 0; thd->variables.option_bits|= OPTION_AUTO_IS_NULL; thd->client_capabilities|= CLIENT_MULTI_RESULTS; mysql_mutex_lock(&LOCK_thread_count); diff --git a/sql/item_create.cc b/sql/item_create.cc index 96837a8f262..87e90ed4f8b 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -4393,27 +4393,36 @@ Create_func_master_pos_wait::create_native(THD *thd, LEX_STRING name, if (item_list != NULL) arg_count= item_list->elements; + if (arg_count < 2 || arg_count >4) + { + my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name.str); + return func; + } + + thd->lex->safe_to_cache_query= 0; + + Item *param_1= item_list->pop(); + Item *param_2= item_list->pop(); switch (arg_count) { case 2: { - Item *param_1= item_list->pop(); - Item *param_2= item_list->pop(); func= new (thd->mem_root) Item_master_pos_wait(param_1, param_2); - thd->lex->safe_to_cache_query= 0; break; } case 3: { - Item *param_1= item_list->pop(); - Item *param_2= item_list->pop(); Item *param_3= item_list->pop(); func= new (thd->mem_root) Item_master_pos_wait(param_1, param_2, param_3); thd->lex->safe_to_cache_query= 0; break; } - default: + case 4: { - my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name.str); + Item *param_3= item_list->pop(); + Item *param_4= item_list->pop(); + func= new (thd->mem_root) Item_master_pos_wait(param_1, param_2, param_3, + param_4); + thd->lex->safe_to_cache_query= 0; break; } } diff --git a/sql/item_func.cc b/sql/item_func.cc index 441eb37d701..5db91cd4231 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -3866,13 +3866,45 @@ longlong Item_master_pos_wait::val_int() #ifdef HAVE_REPLICATION longlong pos = (ulong)args[1]->val_int(); longlong timeout = (arg_count==3) ? args[2]->val_int() : 0 ; - if ((event_count = active_mi->rli.wait_for_pos(thd, log_name, pos, timeout)) == -2) + String connection_name_buff; + LEX_STRING connection_name; + Master_info *mi; + if (arg_count == 4) + { + String *con; + if (!(con= args[3]->val_str(&connection_name_buff))) + goto err; + + connection_name.str= (char*) con->ptr(); + connection_name.length= con->length(); + if (check_master_connection_name(&connection_name)) + { + my_error(ER_WRONG_ARGUMENTS, MYF(ME_JUST_WARNING), + "MASTER_CONNECTION_NAME"); + goto err; + } + } + else + connection_name= thd->variables.default_master_connection; + + if (!(mi= master_info_index->get_master_info(&connection_name, + MYSQL_ERROR::WARN_LEVEL_WARN))) + goto err; + if ((event_count = mi->rli.wait_for_pos(thd, log_name, pos, timeout)) == -2) { null_value = 1; event_count=0; } #endif return event_count; + +#ifdef HAVE_REPLICATION +err: + { + null_value = 1; + return 0; + } +#endif } diff --git a/sql/item_func.h b/sql/item_func.h index 586444e0e4e..07b246b3ccd 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -496,6 +496,8 @@ public: { collation.set_numeric(); fix_char_length(21); } Item_int_func(Item *a,Item *b,Item *c) :Item_func(a,b,c) { collation.set_numeric(); fix_char_length(21); } + Item_int_func(Item *a,Item *b,Item *c, Item *d) :Item_func(a,b,c,d) + { collation.set_numeric(); fix_char_length(21); } Item_int_func(List &list) :Item_func(list) { collation.set_numeric(); fix_char_length(21); } Item_int_func(THD *thd, Item_int_func *item) :Item_func(thd, item) @@ -1522,6 +1524,7 @@ class Item_master_pos_wait :public Item_int_func public: Item_master_pos_wait(Item *a,Item *b) :Item_int_func(a,b) {} Item_master_pos_wait(Item *a,Item *b,Item *c) :Item_int_func(a,b,c) {} + Item_master_pos_wait(Item *a,Item *b, Item *c, Item *d) :Item_int_func(a,b,c,d) {} longlong val_int(); const char *func_name() const { return "master_pos_wait"; } void fix_length_and_dec() { max_length=21; maybe_null=1;} diff --git a/sql/log.cc b/sql/log.cc index e4db7b2eb0f..54340f94679 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -40,6 +40,7 @@ #include "rpl_rli.h" #include "sql_audit.h" #include "log_slow.h" +#include "mysqld.h" #include #include @@ -6980,16 +6981,33 @@ static void print_buffer_to_file(enum loglevel level, const char *buffer, time_t skr; struct tm tm_tmp; struct tm *start; + THD *thd; + int tag_length= 0; + char tag[NAME_LEN]; DBUG_ENTER("print_buffer_to_file"); DBUG_PRINT("enter",("buffer: %s", buffer)); + if (mysqld_server_initialized && (thd= current_thd)) + { + if (thd->connection_name.length) + { + /* + Add tag for slaves so that the user can see from which connection + the error originates. + */ + tag_length= my_snprintf(tag, sizeof(tag), ER(ER_MASTER_LOG_PREFIX), + (int) thd->connection_name.length, + thd->connection_name.str); + } + } + mysql_mutex_lock(&LOCK_error_log); skr= my_time(0); localtime_r(&skr, &tm_tmp); start=&tm_tmp; - fprintf(stderr, "%02d%02d%02d %2d:%02d:%02d [%s] %.*s\n", + fprintf(stderr, "%02d%02d%02d %2d:%02d:%02d [%s] %.*s%.*s\n", start->tm_year % 100, start->tm_mon+1, start->tm_mday, @@ -6998,6 +7016,7 @@ static void print_buffer_to_file(enum loglevel level, const char *buffer, start->tm_sec, (level == ERROR_LEVEL ? "ERROR" : level == WARNING_LEVEL ? "Warning" : "Note"), + tag_length, tag, (int) length, buffer); fflush(stderr); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 96ea789edd7..defd3a71b93 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -673,8 +673,7 @@ pthread_attr_t connection_attrib; mysql_mutex_t LOCK_server_started; mysql_cond_t COND_server_started; -int mysqld_server_started= 0; - +int mysqld_server_started=0, mysqld_server_initialized= 0; File_parser_dummy_hook file_parser_dummy_hook; /* replication parameters, if master_host is not NULL, we are a slave */ @@ -1761,7 +1760,12 @@ void clean_up(bool print_message) if (cleanup_done++) return; /* purecov: inspected */ - close_active_mi(); +#ifdef HAVE_REPLICATION + // We must call end_slave() as clean_up may have been called during startup + end_slave(); + if (use_slave_mask) + bitmap_free(&slave_error_mask); +#endif stop_handle_manager(); release_ddl_log(); @@ -1776,10 +1780,6 @@ void clean_up(bool print_message) injector::free_instance(); mysql_bin_log.cleanup(); -#ifdef HAVE_REPLICATION - if (use_slave_mask) - bitmap_free(&slave_error_mask); -#endif my_tz_free(); my_dboptions_cache_free(); #ifndef NO_EMBEDDED_ACCESS_CHECKS @@ -4626,6 +4626,7 @@ int mysqld_main(int argc, char **argv) } #endif + mysqld_server_started= mysqld_server_initialized= 0; orig_argc= argc; orig_argv= argv; my_getopt_use_args_separator= TRUE; @@ -4890,16 +4891,6 @@ int mysqld_main(int argc, char **argv) opt_skip_slave_start= 1; binlog_unsafe_map_init(); - /* - init_slave() must be called after the thread keys are created. - Some parts of the code (e.g. SHOW STATUS LIKE 'slave_running' and other - places) assume that active_mi != 0, so let's fail if it's 0 (out of - memory); a message has already been printed. - */ - if (init_slave() && !active_mi) - { - unireg_abort(1); - } #ifdef WITH_PERFSCHEMA_STORAGE_ENGINE initialize_performance_schema_acl(opt_bootstrap); @@ -4917,9 +4908,17 @@ int mysqld_main(int argc, char **argv) execute_ddl_log_recovery(); + /* + We must have LOCK_open before LOCK_global_system_variables because + LOCK_open is hold while sql_plugin.c::intern_sys_var_ptr() is called. + */ + mysql_mutex_record_order(&LOCK_open, &LOCK_global_system_variables); + if (Events::init(opt_noacl || opt_bootstrap)) unireg_abort(1); + mysqld_server_initialized= 1; + if (opt_bootstrap) { select_thread_in_use= 0; // Allow 'kill' to work @@ -4932,21 +4931,27 @@ int mysqld_main(int argc, char **argv) exit(0); } } + + create_shutdown_thread(); + start_handle_manager(); + + /* + init_slave() must be called after the thread keys are created. + Some parts of the code (e.g. SHOW STATUS LIKE 'slave_running' and other + places) assume that active_mi != 0, so let's fail if it's 0 (out of + memory); a message has already been printed. + */ + if (init_slave() && !active_mi) + { + unireg_abort(1); + } + if (opt_init_file && *opt_init_file) { if (read_init_file(opt_init_file)) unireg_abort(1); } - /* - We must have LOCK_open before LOCK_global_system_variables because - LOCK_open is hold while sql_plugin.c::intern_sys_var_ptr() is called. - */ - mysql_mutex_record_order(&LOCK_open, &LOCK_global_system_variables); - - create_shutdown_thread(); - start_handle_manager(); - sql_print_information(ER_DEFAULT(ER_STARTUP),my_progname,server_version, ((unix_sock == INVALID_SOCKET) ? (char*) "" : mysqld_unix_port), @@ -6524,12 +6529,17 @@ static int show_rpl_status(THD *thd, SHOW_VAR *var, char *buff) static int show_slave_running(THD *thd, SHOW_VAR *var, char *buff) { + Master_info *mi; var->type= SHOW_MY_BOOL; mysql_mutex_lock(&LOCK_active_mi); var->value= buff; - *((my_bool *)buff)= (my_bool) (active_mi && - active_mi->slave_running == MYSQL_SLAVE_RUN_CONNECT && - active_mi->rli.slave_running); + mi= master_info_index-> + get_master_info(&thd->variables.default_master_connection, + MYSQL_ERROR::WARN_LEVEL_WARN); + *((my_bool *)buff)= (my_bool) (mi && + mi->slave_running == + MYSQL_SLAVE_RUN_CONNECT && + mi->rli.slave_running); mysql_mutex_unlock(&LOCK_active_mi); return 0; } diff --git a/sql/mysqld.h b/sql/mysqld.h index 7a24b56dcb7..fd33ca0cf85 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -198,7 +198,7 @@ extern handlerton *myisam_hton; extern handlerton *heap_hton; extern const char *load_default_groups[]; extern struct my_option my_long_options[]; -extern int mysqld_server_started; +extern int mysqld_server_started, mysqld_server_initialized; extern "C" MYSQL_PLUGIN_IMPORT int orig_argc; extern "C" MYSQL_PLUGIN_IMPORT char **orig_argv; extern pthread_attr_t connection_attrib; diff --git a/sql/rpl_mi.cc b/sql/rpl_mi.cc index 3c5a99121fa..3dc3e38f419 100644 --- a/sql/rpl_mi.cc +++ b/sql/rpl_mi.cc @@ -20,6 +20,7 @@ #include "unireg.h" // REQUIRED by other includes #include "rpl_mi.h" #include "slave.h" // SLAVE_MAX_HEARTBEAT_PERIOD +#include "strfunc.h" #ifdef HAVE_REPLICATION @@ -27,7 +28,8 @@ static void init_master_log_pos(Master_info* mi); -Master_info::Master_info(bool is_slave_recovery) +Master_info::Master_info(LEX_STRING *connection_name_arg, + bool is_slave_recovery) :Slave_reporting_capability("I/O"), ssl(0), ssl_verify_server_cert(1), fd(-1), io_thd(0), rli(is_slave_recovery), port(MYSQL_PORT), @@ -40,6 +42,21 @@ Master_info::Master_info(bool is_slave_recovery) ssl_ca[0]= 0; ssl_capath[0]= 0; ssl_cert[0]= 0; ssl_cipher[0]= 0; ssl_key[0]= 0; + /* Store connection name and lower case connection name */ + connection_name.length= cmp_connection_name.length= + connection_name_arg->length; + if ((connection_name.str= (char*) my_malloc(connection_name_arg->length*2+2, + MYF(MY_WME)))) + { + cmp_connection_name.str= (connection_name.str + + connection_name_arg->length+1); + strmake(connection_name.str, connection_name_arg->str, + connection_name.length); + memcpy(cmp_connection_name.str, connection_name_arg->str, + connection_name.length+1); + my_casedn_str(system_charset_info, cmp_connection_name.str); + } + my_init_dynamic_array(&ignore_server_ids, sizeof(::server_id), 16, 16); bzero((char*) &file, sizeof(file)); mysql_mutex_init(key_master_info_run_lock, &run_lock, MY_MUTEX_INIT_FAST); @@ -55,6 +72,7 @@ Master_info::Master_info(bool is_slave_recovery) Master_info::~Master_info() { + my_free(connection_name.str); delete_dynamic(&ignore_server_ids); mysql_mutex_destroy(&run_lock); mysql_mutex_destroy(&data_lock); @@ -407,7 +425,7 @@ file '%s')", fname); mi->master_log_name, (ulong) mi->master_log_pos)); - mi->rli.mi = mi; + mi->rli.mi= mi; if (init_relay_log_info(&mi->rli, slave_info_fname)) goto err; @@ -560,5 +578,455 @@ void end_master_info(Master_info* mi) DBUG_VOID_RETURN; } +/* Multi-Master By P.Linux */ +uchar *get_key_master_info(Master_info *mi, size_t *length, + my_bool not_used __attribute__((unused))) +{ + /* Return lower case name */ + *length= mi->cmp_connection_name.length; + return (uchar*) mi->cmp_connection_name.str; +} + +void free_key_master_info(Master_info *mi) +{ + DBUG_ENTER("free_key_master_info"); + terminate_slave_threads(mi,SLAVE_FORCE_ALL); + end_master_info(mi); + delete mi; + DBUG_VOID_RETURN; +} + +/** + Check if connection name for master_info is valid. + + It's valid if it's a valid system name, is less than + MAX_CONNECTION_NAME. + + @return + 0 ok + 1 error +*/ + +bool check_master_connection_name(LEX_STRING *name) +{ + if (name->length >= MAX_CONNECTION_NAME) + return 1; + return 0; +} + + +/** + Create a log file with a signed suffix. + + @param + res_file_name Store result here + length Length of res_file_name buffer + info_file Original file name (prefix) + separator Separator character + suffix Suffix + + @note + If suffix is an empty string, then we don't add any suffix. + This is to allow one to use this function also to generate old + file names without a prefix. +*/ + +void create_signed_file_name(char *res_file_name, uint length, + const char *info_file, + char separator, LEX_STRING *suffix) +{ + char buff[MAX_CONNECTION_NAME+1], res[MAX_CONNECTION_NAME+1], *p; + p= strmake(res_file_name, info_file, length); + if (suffix->length != 0 && p != info_file + length) + { + uint errors; + size_t res_length; + + *p++= separator; + /* Create null terminated string */ + strmake(buff, suffix->str, suffix->length); + /* Convert to lower case */ + my_casedn_str(system_charset_info, buff); + /* Convert to characters usable in a file name */ + res_length= strconvert(system_charset_info, buff, + &my_charset_filename, res, sizeof(res), &errors); + strmake(p, res, min(length - (p - res_file_name), res_length)); + } +} + + +Master_info_index::Master_info_index() +{ + index_file_name[0] = 0; + bzero((char*) &index_file, sizeof(index_file)); +} + +Master_info_index::~Master_info_index() +{ + /* This will close connection for all objects in the cache */ + my_hash_free(&master_info_hash); + end_io_cache(&index_file); + if (index_file.file > 0) + my_close(index_file.file, MYF(MY_WME)); +} + + +/* Load All Master_info from master.info.index File + * RETURN: + * 0 - All Success + * 1 - All Fail + * 2 - Some Success, Some Fail + */ + +bool Master_info_index::init_all_master_info() +{ + int thread_mask; + int err_num= 0, succ_num= 0; // The number of success read Master_info + char sign[MAX_CONNECTION_NAME]; + File index_file_nr; + size_t filename_length, dir_length; + DBUG_ENTER("init_all_master_info"); + + /* + Create the Master_info index file by prepending 'multi-' before + the master_info_file file name. + */ + fn_format(index_file_name, master_info_file, mysql_data_home, + "", MY_UNPACK_FILENAME); + filename_length= strlen(index_file_name) + 1; /* Count 0 byte */ + dir_length= dirname_length(index_file_name); + bmove_upp((uchar*) index_file_name + filename_length + 6, + (uchar*) index_file_name + filename_length, + filename_length - dir_length); + memcpy(index_file_name + dir_length, "multi-", 6); + + if ((index_file_nr= my_open(index_file_name, + O_RDWR | O_CREAT | O_BINARY , + MYF(MY_WME | ME_NOREFRESH))) < 0 || + my_sync(index_file_nr, MYF(MY_WME)) || + init_io_cache(&index_file, index_file_nr, + IO_SIZE, READ_CACHE, + my_seek(index_file_nr,0L,MY_SEEK_END,MYF(0)), + 0, MYF(MY_WME | MY_WAIT_IF_FULL))) + { + if (index_file_nr >= 0) + my_close(index_file_nr,MYF(0)); + + sql_print_error("Creation of Master_info index file '%s' failed", + index_file_name); + DBUG_RETURN(1); + } + + /* Initialize Master_info Hash Table */ + if (my_hash_init(&master_info_hash, system_charset_info, + MAX_REPLICATION_THREAD, 0, 0, + (my_hash_get_key) get_key_master_info, + (my_hash_free_key)free_key_master_info, HASH_UNIQUE)) + { + sql_print_error("Initializing Master_info hash table failed"); + DBUG_RETURN(1); + } + + reinit_io_cache(&index_file, READ_CACHE, 0L,0,0); + while (!init_strvar_from_file(sign, sizeof(sign), + &index_file, NULL)) + { + LEX_STRING connection_name; + Master_info *mi; + char buf_master_info_file[FN_REFLEN]; + char buf_relay_log_info_file[FN_REFLEN]; + + connection_name.str= sign; + connection_name.length= strlen(sign); + if (!(mi= new Master_info(&connection_name, relay_log_recovery)) || + mi->error()) + { + delete mi; + DBUG_RETURN(1); + } + + lock_slave_threads(mi); + init_thread_mask(&thread_mask,mi,0 /*not inverse*/); + + create_signed_file_name(buf_master_info_file, sizeof(buf_master_info_file), + master_info_file, '.', &connection_name); + create_signed_file_name(buf_relay_log_info_file, + sizeof(buf_relay_log_info_file), + relay_log_info_file, '.', &connection_name); + if (global_system_variables.log_warnings > 1) + sql_print_information("Reading Master_info: '%s' Relay_info:'%s'", + buf_master_info_file, buf_relay_log_info_file); + + if (init_master_info(mi, buf_master_info_file, buf_relay_log_info_file, + 0, thread_mask)) + { + err_num++; + sql_print_error("Initialized Master_info from '%s' failed", + buf_master_info_file); + if (!master_info_index->get_master_info(&connection_name, + MYSQL_ERROR::WARN_LEVEL_NOTE)) + { + /* Master_info is not in HASH; Add it */ + if (master_info_index->add_master_info(mi, FALSE)) + return 1; + succ_num++; + unlock_slave_threads(mi); + } + else + { + /* Master_info already in HASH */ + sql_print_error(ER(ER_CONNECTION_ALREADY_EXISTS), + (int) connection_name.length, connection_name.str); + unlock_slave_threads(mi); + delete mi; + } + continue; + } + else + { + /* Initialization of Master_info succeded. Add it to HASH */ + if (global_system_variables.log_warnings > 1) + sql_print_information("Initialized Master_info from '%s'", + buf_master_info_file); + if (master_info_index->get_master_info(&connection_name, + MYSQL_ERROR::WARN_LEVEL_NOTE)) + { + /* Master_info was already registered */ + sql_print_error(ER(ER_CONNECTION_ALREADY_EXISTS), + (int) connection_name.length, connection_name.str); + unlock_slave_threads(mi); + delete mi; + continue; + } + + /* Master_info was not registered; add it */ + if (master_info_index->add_master_info(mi, FALSE)) + return 1; + succ_num++; + unlock_slave_threads(mi); + + if (!opt_skip_slave_start) + { + if (start_slave_threads(1 /* need mutex */, + 0 /* no wait for start*/, + mi, + buf_master_info_file, + buf_relay_log_info_file, + SLAVE_IO | SLAVE_SQL)) + { + sql_print_error("Failed to create slave threads for connection %.*s", + (int) connection_name.length, + connection_name.str); + continue; + } + if (global_system_variables.log_warnings) + sql_print_information("Started replication for '%.*s'", + (int) connection_name.length, + connection_name.str); + } + } + } + + if (!err_num) // No Error on read Master_info + { + if (global_system_variables.log_warnings > 1) + sql_print_information("Reading of all Master_info entries succeded"); + DBUG_RETURN(0); + } + else if (succ_num) // Have some Error and some Success + { + sql_print_warning("Reading of some Master_info entries failed"); + DBUG_RETURN(2); + } + else // All failed + { + sql_print_error("Reading of all Master_info entries failed!"); + DBUG_RETURN(1); + } +} + + +/* Write new master.info to master.info.index File */ +bool Master_info_index::write_master_name_to_index_file(LEX_STRING *name, + bool do_sync) +{ + DBUG_ASSERT(my_b_inited(&index_file) != 0); + DBUG_ENTER("write_master_name_to_index_file"); + + /* Don't write default slave to master_info.index */ + if (name->length == 0) + DBUG_RETURN(0); + + reinit_io_cache(&index_file, WRITE_CACHE, + my_b_filelength(&index_file), 0, 0); + + if (my_b_write(&index_file, (uchar*) name->str, name->length) || + my_b_write(&index_file, (uchar*) "\n", 1) || + flush_io_cache(&index_file) || + (do_sync && my_sync(index_file.file, MYF(MY_WME)))) + { + sql_print_error("Write of new Master_info for '%.*s' to index file failed", + (int) name->length, name->str); + DBUG_RETURN(1); + } + + DBUG_RETURN(0); +} + + +/** + Get Master_info for a connection + + @param + connection_name Connection name + warning WARN_LEVEL_NOTE -> Don't print anything + WARN_LEVEL_WARN -> Issue warning if not exists + WARN_LEVEL_ERROR-> Issue error if not exists +*/ + +Master_info * +Master_info_index::get_master_info(LEX_STRING *connection_name, + MYSQL_ERROR::enum_warning_level warning) +{ + Master_info *mi; + char buff[MAX_CONNECTION_NAME+1], *res; + uint buff_length; + + /* Make name lower case for comparison */ + res= strmake(buff, connection_name->str, connection_name->length); + my_casedn_str(system_charset_info, buff); + buff_length= (size_t) (res-buff); + + mi= (Master_info*) my_hash_search(&master_info_hash, + (uchar*) buff, buff_length); + if (!mi && warning != MYSQL_ERROR::WARN_LEVEL_NOTE) + { + my_error(WARN_NO_MASTER_INFO, + MYF(warning == MYSQL_ERROR::WARN_LEVEL_WARN ? ME_JUST_WARNING : + 0), + (int) connection_name->length, + connection_name->str); + } + return mi; +} + + +/* Check Master_host & Master_port is duplicated or not */ +bool Master_info_index::check_duplicate_master_info(LEX_STRING *name_arg, + const char *host, + uint port) +{ + Master_info *mi; + + /* Get full host and port name */ + if ((mi= master_info_index->get_master_info(name_arg, + MYSQL_ERROR::WARN_LEVEL_NOTE))) + { + if (!host) + host= mi->host; + if (!port) + port= mi->port; + } + if (!host || !port) + return FALSE; // Not comparable yet + + for (uint i= 0; i < master_info_hash.records; ++i) + { + Master_info *tmp_mi; + tmp_mi= (Master_info *) my_hash_element(&master_info_hash, i); + if (tmp_mi == mi) + continue; // Current connection + if (!strcasecmp(host, tmp_mi->host) && port == tmp_mi->port) + { + sql_print_error(ER(ER_CONNECTION_ALREADY_EXISTS), + (int) tmp_mi->connection_name.length, + tmp_mi->connection_name.str); + return TRUE; + } + } + return FALSE; +} + + +/* Add a Master_info class to Hash Table */ +bool Master_info_index::add_master_info(Master_info *mi, bool write_to_file) +{ + if (!my_hash_insert(&master_info_hash, (uchar*) mi)) + { + if (global_system_variables.log_warnings > 1) + sql_print_information("Added new Master_info '%.*s' to hash table", + (int) mi->connection_name.length, + mi->connection_name.str); + if (write_to_file) + return write_master_name_to_index_file(&mi->connection_name, 1); + return FALSE; + } + + /* Impossible error (EOM) ? */ + sql_print_error("Adding new entry '%.*s' to master_info failed", + (int) mi->connection_name.length, + mi->connection_name.str); + return TRUE; +} + + +/** + Remove a Master_info class From Hash Table + + TODO: Change this to use my_rename() to make the file name creation + atomic +*/ + +bool Master_info_index::remove_master_info(LEX_STRING *name) +{ + Master_info* mi; + DBUG_ENTER("remove_master_info"); + + if ((mi= get_master_info(name, MYSQL_ERROR::WARN_LEVEL_WARN))) + { + // Delete Master_info and rewrite others to file + if (!my_hash_delete(&master_info_hash, (uchar*) mi)) + { + File index_file_nr; + + // Close IO_CACHE and FILE handler fisrt + end_io_cache(&index_file); + my_close(index_file.file, MYF(MY_WME)); + + // Reopen File and truncate it + fn_format(index_file_name, master_info_file, mysql_data_home, + ".index", MY_UNPACK_FILENAME | MY_APPEND_EXT); + + if ((index_file_nr= my_open(index_file_name, + O_RDWR | O_CREAT | O_TRUNC | O_BINARY , + MYF(MY_WME))) < 0 || + init_io_cache(&index_file, index_file_nr, + IO_SIZE, WRITE_CACHE, + my_seek(index_file_nr,0L,MY_SEEK_END,MYF(0)), + 0, MYF(MY_WME | MY_WAIT_IF_FULL))) + { + int error= my_errno; + if (index_file_nr >= 0) + my_close(index_file_nr,MYF(0)); + + sql_print_error("Create of Master Info Index file '%s' failed with " + "error: %M", + index_file_name, error); + DBUG_RETURN(TRUE); + } + + // Rewrite Master_info.index + uint i; + for (i= 0; i< master_info_hash.records; ++i) + { + Master_info *tmp_mi; + tmp_mi= (Master_info *) my_hash_element(&master_info_hash, i); + write_master_name_to_index_file(&tmp_mi->connection_name, 0); + } + my_sync(index_file_nr, MYF(MY_WME)); + } + } + DBUG_RETURN(FALSE); +} #endif /* HAVE_REPLICATION */ diff --git a/sql/rpl_mi.h b/sql/rpl_mi.h index a885576ef1c..6892ecdb9d1 100644 --- a/sql/rpl_mi.h +++ b/sql/rpl_mi.h @@ -59,16 +59,23 @@ typedef struct st_mysql MYSQL; class Master_info : public Slave_reporting_capability { public: - Master_info(bool is_slave_recovery); + Master_info(LEX_STRING *connection_name, bool is_slave_recovery); ~Master_info(); bool shall_ignore_server_id(ulong s_id); void clear_in_memory_info(bool all); + bool error() + { + /* If malloc() in initialization failed */ + return connection_name.str == 0; + } /* the variables below are needed because we can change masters on the fly */ - char master_log_name[FN_REFLEN]; + char master_log_name[FN_REFLEN+6]; /* Place for multi-*/ char host[HOSTNAME_LENGTH+1]; char user[USERNAME_LENGTH+1]; char password[MAX_PASSWORD_LENGTH+1]; + LEX_STRING connection_name; /* User supplied connection name */ + LEX_STRING cmp_connection_name; /* Connection name in lower case */ bool ssl; // enables use of SSL connection if true char ssl_ca[FN_REFLEN], ssl_capath[FN_REFLEN], ssl_cert[FN_REFLEN]; char ssl_cipher[FN_REFLEN], ssl_key[FN_REFLEN]; @@ -130,5 +137,45 @@ int flush_master_info(Master_info* mi, bool need_lock_relay_log); int change_master_server_id_cmp(ulong *id1, ulong *id2); +/* + Multi master are handled trough this struct. + Changes to this needs to be protected by LOCK_active_mi; +*/ + +class Master_info_index +{ +private: + IO_CACHE index_file; + char index_file_name[FN_REFLEN]; + +public: + Master_info_index(); + ~Master_info_index(); + + HASH master_info_hash; + + bool init_all_master_info(); + bool write_master_name_to_index_file(LEX_STRING *connection_name, + bool do_sync); + + bool check_duplicate_master_info(LEX_STRING *connection_name, + const char *host, uint port); + bool add_master_info(Master_info *mi, bool write_to_file); + bool remove_master_info(LEX_STRING *connection_name); + Master_info *get_master_info(LEX_STRING *connection_name, + MYSQL_ERROR::enum_warning_level warning); +}; + +bool check_master_connection_name(LEX_STRING *name); +void create_signed_file_name(char *res_file_name, uint length, + const char *info_file, + char separator, + LEX_STRING *suffix); + +uchar *get_key_master_info(Master_info *mi, size_t *length, + my_bool not_used __attribute__((unused))); +void free_key_master_info(Master_info *mi); + + #endif /* HAVE_REPLICATION */ #endif /* RPL_MI_H */ diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index a700aff0da9..442a9895f6b 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -206,19 +206,37 @@ a file name for --relay-log-index option", opt_relaylog_index_name); name_warning_sent= 1; } + /* For multimaster, add connection name to relay log filenames */ + Master_info* mi= rli->mi; + char buf_relay_logname[FN_REFLEN], buf_relaylog_index_name_buff[FN_REFLEN]; + char *buf_relaylog_index_name= opt_relaylog_index_name; + + create_signed_file_name(buf_relay_logname, sizeof(buf_relay_logname), + ln, '-', &mi->connection_name); + ln= buf_relay_logname; + + if (opt_relaylog_index_name) + { + buf_relaylog_index_name= buf_relaylog_index_name_buff; + create_signed_file_name(buf_relaylog_index_name_buff, + sizeof(buf_relaylog_index_name_buff), + opt_relaylog_index_name, '-', + &mi->connection_name); + } + rli->relay_log.is_relay_log= TRUE; /* note, that if open() fails, we'll still have index file open but a destructor will take care of that */ - if (rli->relay_log.open_index_file(opt_relaylog_index_name, ln, TRUE) || + if (rli->relay_log.open_index_file(buf_relaylog_index_name, ln, TRUE) || rli->relay_log.open(ln, LOG_BIN, 0, SEQ_READ_APPEND, (max_relay_log_size ? max_relay_log_size : max_binlog_size), 1, TRUE)) { mysql_mutex_unlock(&rli->data_lock); - sql_print_error("Failed in open_log() called from init_relay_log_info()"); + sql_print_error("Failed when trying to open logs for '%s' in init_relay_log_info(). Error: %M", ln, my_errno); DBUG_RETURN(1); } } diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h index b989283deb4..eb808351a34 100644 --- a/sql/rpl_rli.h +++ b/sql/rpl_rli.h @@ -25,7 +25,6 @@ struct RPL_TABLE_LIST; class Master_info; -extern uint sql_slave_skip_counter; /**************************************************************************** @@ -230,7 +229,7 @@ public: skipping one or more events in the master log that have caused errors, and have been manually applied by DBA already. */ - volatile uint32 slave_skip_counter; + volatile uint slave_skip_counter; /* Must be uint */ volatile ulong abort_pos_wait; /* Incremented on change master */ volatile ulong slave_run_id; /* Incremented on slave start */ mysql_mutex_t log_space_lock; diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index 2e8b2231948..bb5506756e1 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -4310,11 +4310,11 @@ ER_BAD_SLAVE swe "Servern är inte konfigurerade som en replikationsslav. Ändra konfigurationsfilen eller gör CHANGE MASTER TO" ukr "Сервер не зконфігуровано Ñк підлеглий, виправте це у файлі конфігурації або з CHANGE MASTER TO" ER_MASTER_INFO - eng "Could not initialize master info structure; more error messages can be found in the MariaDB error log" - fre "Impossible d'initialiser les structures d'information de maître, vous trouverez des messages d'erreur supplémentaires dans le journal des erreurs de MariaDB" - ger "Konnte Master-Info-Struktur nicht initialisieren. Weitere Fehlermeldungen können im MariaDB-Error-Log eingesehen werden" - serbian "Nisam mogao da inicijalizujem informacionu strukturu glavnog servera, proverite da li imam privilegije potrebne za pristup file-u 'master.info'" - swe "Kunde inte initialisera replikationsstrukturerna. See MariaDB fel fil för mera information" + eng "Could not initialize master info structure for '%.*s'; more error messages can be found in the MariaDB error log" + fre "Impossible d'initialiser les structures d'information de maître '%.*s', vous trouverez des messages d'erreur supplémentaires dans le journal des erreurs de MariaDB" + ger "Konnte Master-Info-Struktur '%.*s' nicht initialisieren. Weitere Fehlermeldungen können im MariaDB-Error-Log eingesehen werden" + serbian "Nisam mogao da inicijalizujem informacionu strukturu glavnog servera, proverite da li imam privilegije potrebne za pristup file-u 'master.info' '%.*s'" + swe "Kunde inte initialisera replikationsstrukturerna för '%.*s'. See MariaDB fel fil för mera information" ER_SLAVE_THREAD dan "Kunne ikke danne en slave-trÃ¥d; check systemressourcerne" nla "Kon slave thread niet aanmaken, controleer systeem resources" @@ -6156,8 +6156,8 @@ ER_DELAYED_NOT_SUPPORTED eng "DELAYED option not supported for table '%-.192s'" ger "Die DELAYED-Option wird für Tabelle '%-.192s' nicht unterstützt" WARN_NO_MASTER_INFO - eng "The master info structure does not exist" - ger "Die Master-Info-Struktur existiert nicht" + eng "There is no master connection '%.*s'" + ger "Die Master-Info-Struktur existiert nicht '%.*s'" WARN_OPTION_IGNORED eng "<%-.64s> option ignored" ger "Option <%-.64s> ignoriert" @@ -6588,3 +6588,8 @@ ER_QUERY_EXCEEDED_ROWS_EXAMINED_LIMIT ER_NO_SUCH_TABLE_IN_ENGINE 42S02 eng "Table '%-.192s.%-.192s' doesn't exist in engine" swe "Det finns ingen tabell som heter '%-.192s.%-.192s' i handlern" +ER_CONNECTION_ALREADY_EXISTS + eng "Connection '%.*s' already exists" +ER_MASTER_LOG_PREFIX + eng "Master '%.*s': " + diff --git a/sql/slave.cc b/sql/slave.cc index 7b7bddecd17..8254e90b369 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -71,8 +71,10 @@ char slave_skip_error_names[SHOW_VAR_FUNC_BUFF_SIZE]; char* slave_load_tmpdir = 0; Master_info *active_mi= 0; +Master_info_index *master_info_index; my_bool replicate_same_server_id; ulonglong relay_log_space_limit = 0; +LEX_STRING default_master_connection_name= { (char*) "", 0 }; /* When slave thread exits, we need to remember the temporary tables so we @@ -144,7 +146,8 @@ static int process_io_create_file(Master_info* mi, Create_file_log_event* cev); static bool wait_for_relay_log_space(Relay_log_info* rli); static inline bool io_slave_killed(THD* thd,Master_info* mi); static inline bool sql_slave_killed(THD* thd,Relay_log_info* rli); -static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type); +static int init_slave_thread(THD* thd, Master_info *mi, + SLAVE_THD_TYPE thd_type); static void print_slave_skip_errors(void); static int safe_connect(THD* thd, MYSQL* mysql, Master_info* mi); static int safe_reconnect(THD* thd, MYSQL* mysql, Master_info* mi, @@ -159,6 +162,8 @@ static int terminate_slave_thread(THD *thd, volatile uint *slave_running, bool skip_lock); static bool check_io_slave_killed(THD *thd, Master_info *mi, const char *info); +static bool send_show_master_info_header(THD *thd, Master_info *mi, bool full); +static bool send_show_master_info_data(THD *thd, Master_info *mi, bool full); /* Find out which replications threads are running @@ -263,15 +268,33 @@ int init_slave() So it's safer to take the lock. */ mysql_mutex_lock(&LOCK_active_mi); - /* - TODO: re-write this to interate through the list of files - for multi-master - */ - active_mi= new Master_info(relay_log_recovery); if (pthread_key_create(&RPL_MASTER_INFO, NULL)) goto err; + master_info_index= new Master_info_index; + if (!master_info_index || master_info_index->init_all_master_info()) + { + sql_print_error("Failed to initialize multi master structures"); + mysql_mutex_unlock(&LOCK_active_mi); + DBUG_RETURN(1); + } + if (!(active_mi= new Master_info(&default_master_connection_name, + relay_log_recovery)) || + active_mi->error()) + { + delete active_mi; + active_mi= 0; + goto err; + } + + if (master_info_index->add_master_info(active_mi, FALSE)) + { + delete active_mi; + active_mi= 0; + goto err; + } + /* If --slave-skip-errors=... was not used, the string value for the system variable has not been set up yet. Do it now. @@ -286,18 +309,11 @@ int init_slave() If master_host is specified, create the master_info file if it doesn't exists. */ - if (!active_mi) - { - sql_print_error("Failed to allocate memory for the master info structure"); - error= 1; - goto err; - } if (init_master_info(active_mi,master_info_file,relay_log_info_file, 1, (SLAVE_IO | SLAVE_SQL))) { sql_print_error("Failed to initialize the master info structure"); - error= 1; goto err; } @@ -313,14 +329,18 @@ int init_slave() SLAVE_IO | SLAVE_SQL)) { sql_print_error("Failed to create slave threads"); - error= 1; goto err; } } -err: +end: mysql_mutex_unlock(&LOCK_active_mi); DBUG_RETURN(error); + +err: + sql_print_error("Failed to allocate memory for the Master Info structure"); + error= 1; + goto end; } /* @@ -820,42 +840,19 @@ void end_slave() running presently. If a START SLAVE was in progress, the mutex lock below will make us wait until slave threads have started, and START SLAVE returns, then we terminate them here. + + We can also be called by cleanup(), which only happens if some + startup parameter to the server was wrong. */ mysql_mutex_lock(&LOCK_active_mi); - if (active_mi) - { - /* - TODO: replace the line below with - list_walk(&master_list, (list_walk_action)end_slave_on_walk,0); - once multi-master code is ready. - */ - terminate_slave_threads(active_mi,SLAVE_FORCE_ALL); - } + /* This will call terminate_slave_threads() on all connections */ + delete master_info_index; + master_info_index= 0; + active_mi= 0; mysql_mutex_unlock(&LOCK_active_mi); DBUG_VOID_RETURN; } -/** - Free all resources used by slave threads at time of executing shutdown. - The routine must be called after all possible users of @c active_mi - have left. - - SYNOPSIS - close_active_mi() - -*/ -void close_active_mi() -{ - mysql_mutex_lock(&LOCK_active_mi); - if (active_mi) - { - end_master_info(active_mi); - delete active_mi; - active_mi= 0; - } - mysql_mutex_unlock(&LOCK_active_mi); -} - static bool io_slave_killed(THD* thd, Master_info* mi) { DBUG_ENTER("io_slave_killed"); @@ -2022,12 +2019,28 @@ int register_slave_on_master(MYSQL* mysql, Master_info *mi, @retval FALSE success @retval TRUE failure */ -bool show_master_info(THD* thd, Master_info* mi) + +bool show_master_info(THD *thd, Master_info *mi, bool full) +{ + DBUG_ENTER("show_master_info"); + + if (send_show_master_info_header(thd, mi, full)) + DBUG_RETURN(TRUE); + if (send_show_master_info_data(thd, mi, full)) + DBUG_RETURN(TRUE); + my_eof(thd); + DBUG_RETURN(FALSE); +} + +static bool send_show_master_info_header(THD *thd, Master_info *mi, bool full) { - // TODO: fix this for multi-master List field_list; Protocol *protocol= thd->protocol; - DBUG_ENTER("show_master_info"); + DBUG_ENTER("show_master_info_header"); + + if (full) + field_list.push_back(new Item_empty_string("Connection_name", + MAX_CONNECTION_NAME)); field_list.push_back(new Item_empty_string("Slave_IO_State", 14)); @@ -2097,17 +2110,29 @@ bool show_master_info(THD* thd, Master_info* mi) if (protocol->send_result_set_metadata(&field_list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) DBUG_RETURN(TRUE); + DBUG_RETURN(FALSE); +} + + +static bool send_show_master_info_data(THD *thd, Master_info *mi, bool full) +{ + DBUG_ENTER("send_show_master_info_data"); if (mi->host[0]) { DBUG_PRINT("info",("host is set: '%s'", mi->host)); String *packet= &thd->packet; + Protocol *protocol= thd->protocol; + protocol->prepare_for_resend(); /* slave_running can be accessed without run_lock but not other non-volotile members like mi->io_thd, which is guarded by the mutex. */ + if (full) + protocol->store(mi->connection_name.str, mi->connection_name.length, + &my_charset_bin); mysql_mutex_lock(&mi->run_lock); protocol->store(mi->io_thd ? mi->io_thd->proc_info : "", &my_charset_bin); mysql_mutex_unlock(&mi->run_lock); @@ -2250,6 +2275,65 @@ bool show_master_info(THD* thd, Master_info* mi) if (my_net_write(&thd->net, (uchar*) thd->packet.ptr(), packet->length())) DBUG_RETURN(TRUE); } + DBUG_RETURN(FALSE); +} + + +/* Used to sort connections by name */ + +static int cmp_mi_by_name(const Master_info **arg1, + const Master_info **arg2) +{ + return my_strcasecmp(system_charset_info, (*arg1)->connection_name.str, + (*arg2)->connection_name.str); +} + + +/** + Execute a SHOW FULL SLAVE STATUS statement. + + @param thd Pointer to THD object for the client thread executing the + statement. + + Elements are sorted according to the original connection_name. + + @retval FALSE success + @retval TRUE failure +*/ + +bool show_all_master_info(THD* thd) +{ + uint i, elements; + Master_info **tmp; + DBUG_ENTER("show_master_info"); + + if (send_show_master_info_header(thd, active_mi, 1)) + DBUG_RETURN(TRUE); + + if (!(elements= master_info_index->master_info_hash.records)) + goto end; + + /* + Sort lines to get them into a predicted order + (needed for test cases and to not confuse users) + */ + if (!(tmp= (Master_info**) thd->alloc(sizeof(Master_info*) * elements))) + DBUG_RETURN(TRUE); + + for (i= 0; i < elements; i++) + { + tmp[i]= (Master_info *) my_hash_element(&master_info_index-> + master_info_hash, i); + } + my_qsort(tmp, elements, sizeof(Master_info*), (qsort_cmp) cmp_mi_by_name); + + for (i= 0; i < elements; i++) + { + if (send_show_master_info_data(thd, tmp[i], 1)) + DBUG_RETURN(TRUE); + } + +end: my_eof(thd); DBUG_RETURN(FALSE); } @@ -2303,7 +2387,8 @@ void set_slave_thread_default_charset(THD* thd, Relay_log_info const *rli) init_slave_thread() */ -static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type) +static int init_slave_thread(THD* thd, Master_info *mi, + SLAVE_THD_TYPE thd_type) { DBUG_ENTER("init_slave_thread"); #if !defined(DBUG_OFF) @@ -2319,7 +2404,8 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type) than the corresponding packet (query) sent from client to master. */ thd->variables.max_allowed_packet= slave_max_allowed_packet; - thd->slave_thread = 1; + thd->slave_thread= 1; + thd->connection_name= mi->connection_name; thd->enable_slow_log= opt_log_slow_slave_statements; thd->variables.log_slow_filter= global_system_variables.log_slow_filter; set_slave_thread_options(thd); @@ -2635,7 +2721,10 @@ int apply_event_and_update_pos(Log_event* ev, THD* thd, Relay_log_info* rli) int reason= ev->shall_skip(rli); if (reason == Log_event::EVENT_SKIP_COUNT) - sql_slave_skip_counter= --rli->slave_skip_counter; + { + DBUG_ASSERT(rli->slave_skip_counter > 0); + rli->slave_skip_counter--; + } mysql_mutex_unlock(&rli->data_lock); if (reason == Log_event::EVENT_SKIP_NOT) exec_res= ev->apply_event(rli); @@ -3058,7 +3147,7 @@ pthread_handler_t handle_slave_io(void *arg) pthread_detach_this_thread(); thd->thread_stack= (char*) &thd; // remember where our stack is mi->clear_error(); - if (init_slave_thread(thd, SLAVE_THD_IO)) + if (init_slave_thread(thd, mi, SLAVE_THD_IO)) { mysql_cond_broadcast(&mi->start_cond); sql_print_error("Failed during slave I/O thread initialization"); @@ -3457,7 +3546,8 @@ pthread_handler_t handle_slave_sql(void *arg) my_off_t UNINIT_VAR(saved_log_pos); my_off_t UNINIT_VAR(saved_master_log_pos); my_off_t saved_skip= 0; - Relay_log_info* rli = &((Master_info*)arg)->rli; + Master_info *mi= ((Master_info*)arg); + Relay_log_info* rli = &mi->rli; const char *errmsg; // needs to call my_thread_init(), otherwise we get a coredump in DBUG_ stuff @@ -3471,6 +3561,7 @@ pthread_handler_t handle_slave_sql(void *arg) thd->thread_stack = (char*)&thd; // remember where our stack is DBUG_ASSERT(rli->inited); + DBUG_ASSERT(rli->mi == mi); mysql_mutex_lock(&rli->run_lock); DBUG_ASSERT(!rli->slave_running); errmsg= 0; @@ -3485,7 +3576,7 @@ pthread_handler_t handle_slave_sql(void *arg) rli->slave_running = 1; pthread_detach_this_thread(); - if (init_slave_thread(thd, SLAVE_THD_SQL)) + if (init_slave_thread(thd, mi, SLAVE_THD_SQL)) { /* TODO: this is currently broken - slave start and change master diff --git a/sql/slave.h b/sql/slave.h index 6b4bcffe109..565f40b7236 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -45,9 +45,12 @@ #define MAX_SLAVE_ERROR 2000 +#define MAX_REPLICATION_THREAD 64 + // Forward declarations class Relay_log_info; class Master_info; +class Master_info_index; int init_intvar_from_file(int* var, IO_CACHE* f, int default_val); int init_strvar_from_file(char *var, int max_size, IO_CACHE *f, @@ -197,7 +200,8 @@ int mysql_table_dump(THD* thd, const char* db, int fetch_master_table(THD* thd, const char* db_name, const char* table_name, Master_info* mi, MYSQL* mysql, bool overwrite); -bool show_master_info(THD* thd, Master_info* mi); +bool show_master_info(THD* thd, Master_info* mi, bool full); +bool show_all_master_info(THD* thd); bool show_binlog_info(THD* thd); bool rpl_master_has_bug(const Relay_log_info *rli, uint bug_id, bool report, bool (*pred)(const void *), const void *param); @@ -231,6 +235,9 @@ bool net_request_file(NET* net, const char* fname); extern bool volatile abort_loop; extern Master_info main_mi, *active_mi; /* active_mi for multi-master */ +extern Master_info *default_master_info; /* To replace active_mi */ +extern Master_info_index *master_info_index; +extern LEX_STRING default_master_connection_name; extern LIST master_list; extern my_bool replicate_same_server_id; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 85e9227c154..c098ba5be7c 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -396,6 +396,7 @@ bool table_def_init(void) void table_def_start_shutdown(void) { + DBUG_ENTER("table_def_start_shutdown"); if (table_def_inited) { mysql_mutex_lock(&LOCK_open); @@ -410,6 +411,7 @@ void table_def_start_shutdown(void) /* Free all cached but unused TABLEs and TABLE_SHAREs. */ close_cached_tables(NULL, NULL, FALSE, LONG_TIMEOUT); } + DBUG_VOID_RETURN; } @@ -1086,6 +1088,9 @@ bool close_cached_tables(THD *thd, TABLE_LIST *tables, mysql_mutex_unlock(&LOCK_open); + DBUG_PRINT("info", ("open table definitions: %d", + (int) table_def_cache.records)); + if (!wait_for_refresh) DBUG_RETURN(result); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index f77ef114d2d..b0d262f7b6a 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -799,6 +799,9 @@ THD::THD() progress.max_counter= 0; current_linfo = 0; slave_thread = 0; + connection_name.str= 0; + connection_name.length= 0; + bzero(&variables, sizeof(variables)); thread_id= 0; one_shot_set= 0; @@ -1166,7 +1169,14 @@ void THD::init(void) avoid temporary tables replication failure. */ variables.pseudo_thread_id= thread_id; + + variables.default_master_connection.str= default_master_connection_buff; + ::strmake(variables.default_master_connection.str, + global_system_variables.default_master_connection.str, + variables.default_master_connection.length); + mysql_mutex_unlock(&LOCK_global_system_variables); + server_status= SERVER_STATUS_AUTOCOMMIT; if (variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES) server_status|= SERVER_STATUS_NO_BACKSLASH_ESCAPES; diff --git a/sql/sql_class.h b/sql/sql_class.h index 3aa0c5ae9c7..7f44a4b468a 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -533,6 +533,11 @@ typedef struct system_variables thread the query is being run to replicate temp tables properly */ my_thread_id pseudo_thread_id; + /** + Place holder to store sql_slave_skip_counter in sys_var.cc during + update and show of variables. + */ + uint slave_skip_counter; my_bool low_priority_updates; my_bool query_cache_wlock_invalidate; @@ -557,6 +562,9 @@ typedef struct system_variables CHARSET_INFO *collation_database; CHARSET_INFO *collation_connection; + /* Names. These will be allocated in buffers in thd */ + LEX_STRING default_master_connection; + /* Error messages */ MY_LOCALE *lc_messages; /* Locale Support */ @@ -2192,6 +2200,8 @@ public: /* scramble - random string sent to client on handshake */ char scramble[SCRAMBLE_LENGTH+1]; + LEX_STRING connection_name; /* If slave */ + char default_master_connection_buff[MAX_CONNECTION_NAME+1]; bool slave_thread, one_shot_set; bool extra_port; /* If extra connection */ diff --git a/sql/sql_const.h b/sql/sql_const.h index cfbf077bd91..255a0162e93 100644 --- a/sql/sql_const.h +++ b/sql/sql_const.h @@ -38,6 +38,7 @@ #define MAX_REFLENGTH 4 /* Max length for record ref */ #endif #define MAX_HOSTNAME 61 /* len+1 in mysql.user */ +#define MAX_CONNECTION_NAME NAME_LEN #define MAX_MBWIDTH 3 /* Max multibyte sequence */ #define MAX_FIELD_CHARLENGTH 255 diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 240aeb223d4..0b8265e7028 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -503,6 +503,7 @@ void lex_start(THD *thd) lex->expr_allows_subselect= TRUE; lex->use_only_table_context= FALSE; lex->parse_vcol_expr= FALSE; + lex->verbose= 0; lex->name.str= 0; lex->name.length= 0; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 2f3214646de..7e92fe12dc3 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -286,6 +286,7 @@ struct LEX_MASTER_INFO char *host, *user, *password, *log_file_name; char *ssl_key, *ssl_cert, *ssl_ca, *ssl_capath, *ssl_cipher; char *relay_log_name; + LEX_STRING connection_name; ulonglong pos; ulong relay_log_pos; ulong server_id; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 175c2c1d672..114035bc16d 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -82,6 +82,7 @@ #include #include #include "rpl_handler.h" +#include "rpl_mi.h" #include "sp_head.h" #include "sp.h" @@ -2343,10 +2344,41 @@ case SQLCOM_PREPARE: #ifdef HAVE_REPLICATION case SQLCOM_CHANGE_MASTER: { + LEX_MASTER_INFO *lex_mi= &thd->lex->mi; + Master_info *mi; + bool new_master= 0; + if (check_global_access(thd, SUPER_ACL)) goto error; mysql_mutex_lock(&LOCK_active_mi); - res = change_master(thd,active_mi); + + mi= master_info_index->get_master_info(&lex_mi->connection_name, + MYSQL_ERROR::WARN_LEVEL_NOTE); + + if (mi == NULL) + { + /* New replication created */ + mi= new Master_info(&lex_mi->connection_name, relay_log_recovery); + if (!mi || mi->error()) + { + delete mi; + res= 1; + mysql_mutex_unlock(&LOCK_active_mi); + break; + } + new_master= 1; + } + + res= change_master(thd, mi); + if (res && new_master) + { + /* + The new master was added by change_master(). Remove it as it didn't + work. + */ + master_info_index->remove_master_info(&lex_mi->connection_name); + } + mysql_mutex_unlock(&LOCK_active_mi); break; } @@ -2356,15 +2388,19 @@ case SQLCOM_PREPARE: if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL)) goto error; mysql_mutex_lock(&LOCK_active_mi); - if (active_mi != NULL) - { - res = show_master_info(thd, active_mi); - } + + if (lex->verbose) + res= show_all_master_info(thd); else { - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - WARN_NO_MASTER_INFO, ER(WARN_NO_MASTER_INFO)); - my_ok(thd); + LEX_MASTER_INFO *lex_mi= &thd->lex->mi; + Master_info *mi; + mi= master_info_index->get_master_info(&lex_mi->connection_name, + MYSQL_ERROR::WARN_LEVEL_ERROR); + if (mi != NULL) + { + res= show_master_info(thd, mi, 0); + } } mysql_mutex_unlock(&LOCK_active_mi); break; @@ -2664,40 +2700,53 @@ end_with_restore_list: #ifdef HAVE_REPLICATION case SQLCOM_SLAVE_START: { + LEX_MASTER_INFO* lex_mi= &thd->lex->mi; + Master_info *mi; mysql_mutex_lock(&LOCK_active_mi); - start_slave(thd,active_mi,1 /* net report*/); + + if ((mi= (master_info_index-> + get_master_info(&lex_mi->connection_name, + MYSQL_ERROR::WARN_LEVEL_ERROR)))) + start_slave(thd, mi, 1 /* net report*/); mysql_mutex_unlock(&LOCK_active_mi); break; } case SQLCOM_SLAVE_STOP: - /* - If the client thread has locked tables, a deadlock is possible. - Assume that - - the client thread does LOCK TABLE t READ. - - then the master updates t. - - then the SQL slave thread wants to update t, - so it waits for the client thread because t is locked by it. + { + LEX_MASTER_INFO *lex_mi; + Master_info *mi; + /* + If the client thread has locked tables, a deadlock is possible. + Assume that + - the client thread does LOCK TABLE t READ. + - then the master updates t. + - then the SQL slave thread wants to update t, + so it waits for the client thread because t is locked by it. - then the client thread does SLAVE STOP. SLAVE STOP waits for the SQL slave thread to terminate its update t, which waits for the client thread because t is locked by it. - To prevent that, refuse SLAVE STOP if the - client thread has locked tables - */ - if (thd->locked_tables_mode || - thd->in_active_multi_stmt_transaction() || thd->global_read_lock.is_acquired()) - { - my_message(ER_LOCK_OR_ACTIVE_TRANSACTION, - ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0)); - goto error; - } - { + To prevent that, refuse SLAVE STOP if the + client thread has locked tables + */ + if (thd->locked_tables_mode || + thd->in_active_multi_stmt_transaction() || + thd->global_read_lock.is_acquired()) + { + my_message(ER_LOCK_OR_ACTIVE_TRANSACTION, + ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0)); + goto error; + } + + lex_mi= &thd->lex->mi; mysql_mutex_lock(&LOCK_active_mi); - stop_slave(thd,active_mi,1/* net report*/); + if ((mi= (master_info_index-> + get_master_info(&lex_mi->connection_name, + MYSQL_ERROR::WARN_LEVEL_ERROR)))) + stop_slave(thd, mi, 1/* net report*/); mysql_mutex_unlock(&LOCK_active_mi); break; } #endif /* HAVE_REPLICATION */ - case SQLCOM_RENAME_TABLE: { if (execute_rename_table(thd, first_table, all_tables)) diff --git a/sql/sql_reload.cc b/sql/sql_reload.cc index 914b9026014..fcb7d15f5ba 100644 --- a/sql/sql_reload.cc +++ b/sql/sql_reload.cc @@ -26,6 +26,7 @@ #include "sql_repl.h" // reset_master, reset_slave #include "rpl_mi.h" // Master_info::data_lock #include "debug_sync.h" +#include "rpl_mi.h" static void disable_checkpoints(THD *thd); @@ -314,13 +315,27 @@ bool reload_acl_and_cache(THD *thd, unsigned long options, #ifdef HAVE_REPLICATION if (options & REFRESH_SLAVE) { + LEX_MASTER_INFO* lex_mi= &thd->lex->mi; + Master_info *mi; tmp_write_to_binlog= 0; mysql_mutex_lock(&LOCK_active_mi); - if (reset_slave(thd, active_mi)) + + if (!(mi= (master_info_index-> + get_master_info(&lex_mi->connection_name, + MYSQL_ERROR::WARN_LEVEL_ERROR)))) + { + result= 1; + } + else if (reset_slave(thd, mi)) { /* NOTE: my_error() has been already called by reset_slave(). */ result= 1; } + else if (mi->connection_name.length && thd->lex->reset_slave_info.all) + { + /* If not default connection and 'all' is used */ + master_info_index->remove_master_info(&mi->connection_name); + } mysql_mutex_unlock(&LOCK_active_mi); } #endif diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 079aab27101..99395738c66 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -34,14 +34,6 @@ my_bool opt_sporadic_binlog_dump_fail = 0; static int binlog_dump_count = 0; #endif -/** - a copy of active_mi->rli->slave_skip_counter, for showing in SHOW VARIABLES, - INFORMATION_SCHEMA.GLOBAL_VARIABLES and @@sql_slave_skip_counter without - taking all the mutexes needed to access active_mi->rli->slave_skip_counter - properly. -*/ -uint sql_slave_skip_counter; - extern TYPELIB binlog_checksum_typelib; /* @@ -1310,8 +1302,17 @@ int start_slave(THD* thd , Master_info* mi, bool net_report) { int slave_errno= 0; int thread_mask; + char master_info_file_tmp[FN_REFLEN]; + char relay_log_info_file_tmp[FN_REFLEN]; DBUG_ENTER("start_slave"); + create_signed_file_name(master_info_file_tmp, + sizeof(master_info_file_tmp), + master_info_file, '.', &mi->connection_name); + create_signed_file_name(relay_log_info_file_tmp, + sizeof(relay_log_info_file_tmp), + relay_log_info_file, '.', &mi->connection_name); + if (check_access(thd, SUPER_ACL, any_db, NULL, NULL, 0, 0)) DBUG_RETURN(1); lock_slave_threads(mi); // this allows us to cleanly read slave_running @@ -1327,7 +1328,7 @@ int start_slave(THD* thd , Master_info* mi, bool net_report) thread_mask&= thd->lex->slave_thd_opt; if (thread_mask) //some threads are stopped, start them { - if (init_master_info(mi,master_info_file,relay_log_info_file, 0, + if (init_master_info(mi,master_info_file_tmp,relay_log_info_file_tmp, 0, thread_mask)) slave_errno=ER_MASTER_INFO; else if (server_id_supplied && *mi->host) @@ -1401,10 +1402,11 @@ int start_slave(THD* thd , Master_info* mi, bool net_report) if (!slave_errno) slave_errno = start_slave_threads(0 /*no mutex */, - 1 /* wait for start */, - mi, - master_info_file,relay_log_info_file, - thread_mask); + 1 /* wait for start */, + mi, + master_info_file_tmp, + relay_log_info_file_tmp, + thread_mask); } else slave_errno = ER_BAD_SLAVE; @@ -1421,7 +1423,9 @@ int start_slave(THD* thd , Master_info* mi, bool net_report) if (slave_errno) { if (net_report) - my_message(slave_errno, ER(slave_errno), MYF(0)); + my_error(slave_errno, MYF(0), + (int) mi->connection_name.length, + mi->connection_name.str); DBUG_RETURN(1); } else if (net_report) @@ -1446,11 +1450,9 @@ int start_slave(THD* thd , Master_info* mi, bool net_report) */ int stop_slave(THD* thd, Master_info* mi, bool net_report ) { - DBUG_ENTER("stop_slave"); - int slave_errno; - if (!thd) - thd = current_thd; + DBUG_ENTER("stop_slave"); + DBUG_PRINT("enter",("Connection: %s", mi->connection_name.str)); if (check_access(thd, SUPER_ACL, any_db, NULL, NULL, 0, 0)) DBUG_RETURN(1); @@ -1514,6 +1516,8 @@ int reset_slave(THD *thd, Master_info* mi) int thread_mask= 0, error= 0; uint sql_errno=ER_UNKNOWN_ERROR; const char* errmsg= "Unknown error occured while reseting slave"; + char master_info_file_tmp[FN_REFLEN]; + char relay_log_info_file_tmp[FN_REFLEN]; DBUG_ENTER("reset_slave"); lock_slave_threads(mi); @@ -1549,22 +1553,35 @@ int reset_slave(THD *thd, Master_info* mi) // close master_info_file, relay_log_info_file, set mi->inited=rli->inited=0 end_master_info(mi); + // and delete these two files - fn_format(fname, master_info_file, mysql_data_home, "", 4+32); + create_signed_file_name(master_info_file_tmp, + sizeof(master_info_file_tmp), + master_info_file, '.', &mi->connection_name); + create_signed_file_name(relay_log_info_file_tmp, + sizeof(relay_log_info_file_tmp), + relay_log_info_file, '.', &mi->connection_name); + + fn_format(fname, master_info_file_tmp, mysql_data_home, "", 4+32); if (mysql_file_stat(key_file_master_info, fname, &stat_area, MYF(0)) && mysql_file_delete(key_file_master_info, fname, MYF(MY_WME))) { error=1; goto err; } + else if (global_system_variables.log_warnings > 1) + sql_print_information("Deleted Master_info file '%s'.", fname); + // delete relay_log_info_file - fn_format(fname, relay_log_info_file, mysql_data_home, "", 4+32); + fn_format(fname, relay_log_info_file_tmp, mysql_data_home, "", 4+32); if (mysql_file_stat(key_file_relay_log_info, fname, &stat_area, MYF(0)) && mysql_file_delete(key_file_relay_log_info, fname, MYF(MY_WME))) { error=1; goto err; } + else if (global_system_variables.log_warnings > 1) + sql_print_information("Deleted Master_info file '%s'.", fname); RUN_HOOK(binlog_relay_io, after_reset_slave, (thd, mi)); err: @@ -1644,12 +1661,36 @@ bool change_master(THD* thd, Master_info* mi) char saved_host[HOSTNAME_LENGTH + 1]; uint saved_port; char saved_log_name[FN_REFLEN]; + char master_info_file_tmp[FN_REFLEN]; + char relay_log_info_file_tmp[FN_REFLEN]; my_off_t saved_log_pos; + LEX_MASTER_INFO* lex_mi= &thd->lex->mi; DBUG_ENTER("change_master"); + /* + We need to check if there is an empty master_host. Otherwise + change master succeeds, a master.info file is created containing + empty master_host string and when issuing: start slave; an error + is thrown stating that the server is not configured as slave. + (See BUG#28796). + */ + if (lex_mi->host && !*lex_mi->host) + { + my_error(ER_WRONG_ARGUMENTS, MYF(0), "MASTER_HOST"); + DBUG_RETURN(TRUE); + } + if (master_info_index->check_duplicate_master_info(&lex_mi->connection_name, + lex_mi->host, + lex_mi->port)) + { + my_error(ER_MASTER_INFO, MYF(0), + (int) lex_mi->connection_name.length, + lex_mi->connection_name.str); + DBUG_RETURN(TRUE); + } + lock_slave_threads(mi); init_thread_mask(&thread_mask,mi,0 /*not inverse*/); - LEX_MASTER_INFO* lex_mi= &thd->lex->mi; if (thread_mask) // We refuse if any slave thread is running { my_message(ER_SLAVE_MUST_STOP, ER(ER_SLAVE_MUST_STOP), MYF(0)); @@ -1658,24 +1699,40 @@ bool change_master(THD* thd, Master_info* mi) } thd_proc_info(thd, "Changing master"); - /* - We need to check if there is an empty master_host. Otherwise - change master succeeds, a master.info file is created containing - empty master_host string and when issuing: start slave; an error - is thrown stating that the server is not configured as slave. - (See BUG#28796). - */ - if(lex_mi->host && !*lex_mi->host) + + create_signed_file_name(master_info_file_tmp, + sizeof(master_info_file_tmp), + master_info_file, '.', &mi->connection_name); + create_signed_file_name(relay_log_info_file_tmp, + sizeof(relay_log_info_file_tmp), + relay_log_info_file, '.', &mi->connection_name); + + /* if new Master_info doesn't exists, add it */ + if (!master_info_index->get_master_info(&mi->connection_name, + MYSQL_ERROR::WARN_LEVEL_NOTE)) { - my_error(ER_WRONG_ARGUMENTS, MYF(0), "MASTER_HOST"); - unlock_slave_threads(mi); - DBUG_RETURN(TRUE); + if (master_info_index->add_master_info(mi, TRUE)) + { + my_error(ER_MASTER_INFO, MYF(0), + (int) lex_mi->connection_name.length, + lex_mi->connection_name.str); + ret= TRUE; + goto err; + } } - // TODO: see if needs re-write - if (init_master_info(mi, master_info_file, relay_log_info_file, 0, + if (global_system_variables.log_warnings > 1) + sql_print_information("Master: '%.*s' Master_info_file: '%s' " + "Relay_info_file: '%s'", + (int) mi->connection_name.length, + mi->connection_name.str, + master_info_file_tmp, relay_log_info_file_tmp); + + if (init_master_info(mi, master_info_file_tmp, relay_log_info_file_tmp, 0, thread_mask)) { - my_message(ER_MASTER_INFO, ER(ER_MASTER_INFO), MYF(0)); + my_error(ER_MASTER_INFO, MYF(0), + (int) lex_mi->connection_name.length, + lex_mi->connection_name.str); ret= TRUE; goto err; } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 555efaf366d..e1bcb48e541 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -65,6 +65,7 @@ #include #include "keycaches.h" #include "set_var.h" +#include "rpl_mi.h" /* this is to get the bison compilation windows warnings out */ #ifdef _MSC_VER @@ -1904,7 +1905,7 @@ help: /* change master */ change: - CHANGE MASTER_SYM TO_SYM + CHANGE MASTER_SYM optional_connection_name TO_SYM { Lex->sql_command = SQLCOM_CHANGE_MASTER; } @@ -2053,6 +2054,29 @@ master_file_def: } ; +optional_connection_name: + /* empty */ + { + THD *thd= YYTHD; + LEX *lex= thd->lex; + lex->mi.connection_name= thd->variables.default_master_connection; + } + | connection_name; + ; + +connection_name: + TEXT_STRING_sys + { + Lex->mi.connection_name= $1; +#ifdef HAVE_REPLICATION + if (check_master_connection_name(&$1)) + { + my_error(ER_WRONG_ARGUMENTS, MYF(0), "MASTER_CONNECTION_NAME"); + MYSQL_YYABORT; + } +#endif + } + /* create a table */ create: @@ -7074,7 +7098,7 @@ opt_to: */ slave: - START_SYM SLAVE slave_thread_opts + START_SYM SLAVE optional_connection_name slave_thread_opts { LEX *lex=Lex; lex->sql_command = SQLCOM_SLAVE_START; @@ -7083,14 +7107,14 @@ slave: } slave_until {} - | STOP_SYM SLAVE slave_thread_opts + | STOP_SYM SLAVE optional_connection_name slave_thread_opts { LEX *lex=Lex; lex->sql_command = SQLCOM_SLAVE_STOP; lex->type = 0; /* If you change this code don't forget to update SLAVE STOP too */ } - | SLAVE START_SYM slave_thread_opts + | SLAVE optional_connection_name START_SYM slave_thread_opts { LEX *lex=Lex; lex->sql_command = SQLCOM_SLAVE_START; @@ -7098,7 +7122,7 @@ slave: } slave_until {} - | SLAVE STOP_SYM slave_thread_opts + | SLAVE optional_connection_name STOP_SYM slave_thread_opts { LEX *lex=Lex; lex->sql_command = SQLCOM_SLAVE_STOP; @@ -11558,9 +11582,23 @@ show_param: { Lex->sql_command = SQLCOM_SHOW_MASTER_STAT; } - | SLAVE STATUS_SYM + | FULL SLAVE STATUS_SYM { Lex->sql_command = SQLCOM_SHOW_SLAVE_STAT; + Lex->verbose= 1; + } + | SLAVE STATUS_SYM + { + THD *thd= YYTHD; + LEX *lex= thd->lex; + lex->mi.connection_name= thd->variables.default_master_connection; + lex->sql_command = SQLCOM_SHOW_SLAVE_STAT; + lex->verbose= 0; + } + | SLAVE connection_name STATUS_SYM + { + Lex->sql_command = SQLCOM_SHOW_SLAVE_STAT; + Lex->verbose= 0; } | CLIENT_STATS_SYM { @@ -11824,7 +11862,7 @@ flush_option: { Lex->type|= REFRESH_LOG; } | STATUS_SYM { Lex->type|= REFRESH_STATUS; } - | SLAVE + | SLAVE optional_connection_name { Lex->type|= REFRESH_SLAVE; Lex->reset_slave_info.all= false; @@ -11871,6 +11909,7 @@ reset_options: reset_option: SLAVE { Lex->type|= REFRESH_SLAVE; } + optional_connection_name slave_reset_options { } | MASTER_SYM { Lex->type|= REFRESH_MASTER; } | QUERY_SYM CACHE_SYM { Lex->type|= REFRESH_QUERY_CACHE;} diff --git a/sql/strfunc.cc b/sql/strfunc.cc index 0c0742b3805..9603ca30cfa 100644 --- a/sql/strfunc.cc +++ b/sql/strfunc.cc @@ -15,6 +15,7 @@ /* Some useful string utility functions used by the MySQL server */ +#include #include "sql_priv.h" #include "unireg.h" #include "strfunc.h" diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 4a003a89a7e..30cfe1a5680 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -796,6 +796,30 @@ static Sys_var_lexstring Sys_init_connect( DEFAULT(""), &PLock_sys_init_connect, NOT_IN_BINLOG, ON_CHECK(check_init_string)); +#ifdef HAVE_REPLICATION +static bool check_master_connection(sys_var *self, THD *thd, set_var *var) +{ + LEX_STRING tmp; + tmp.str= var->save_result.string_value.str; + tmp.length= var->save_result.string_value.length; + if (check_master_connection_name(&tmp)) + { + my_error(ER_WRONG_ARGUMENTS, MYF(ME_JUST_WARNING), + "DEFAULT_MASTER_CONNECTION"); + return true; + } + return false; +} + +static Sys_var_session_lexstring Sys_default_master_connection( + "default_master_connection", + "Master connection to use for all slave variables and slave commands", + SESSION_ONLY(default_master_connection), + NO_CMD_LINE, IN_SYSTEM_CHARSET, + DEFAULT(""), MAX_CONNECTION_NAME, ON_CHECK(check_master_connection), + ON_UPDATE(0)); +#endif + static Sys_var_charptr Sys_init_file( "init_file", "Read SQL commands from this file at startup", READ_ONLY GLOBAL_VAR(opt_init_file), @@ -3454,47 +3478,67 @@ static Sys_var_uint Sys_slave_net_timeout( NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), ON_UPDATE(fix_slave_net_timeout)); -static bool check_slave_skip_counter(sys_var *self, THD *thd, set_var *var) + +/* + Access a multi_source variable + Return 0 + warning if it doesn't exist +*/ + +uint Sys_var_multi_source_uint:: +get_master_info_uint_value(THD *thd, ptrdiff_t offset) { - bool result= false; + Master_info *mi; + uint res= 0; // Default value mysql_mutex_lock(&LOCK_active_mi); - mysql_mutex_lock(&active_mi->rli.run_lock); - if (active_mi->rli.slave_running) + mi= master_info_index-> + get_master_info(&thd->variables.default_master_connection, + MYSQL_ERROR::WARN_LEVEL_WARN); + if (mi) { - my_message(ER_SLAVE_MUST_STOP, ER(ER_SLAVE_MUST_STOP), MYF(0)); - result= true; + mysql_mutex_lock(&mi->rli.data_lock); + res= *((uint*) (((uchar*) mi) + master_info_offset)); + mysql_mutex_unlock(&mi->rli.data_lock); + } + mysql_mutex_unlock(&LOCK_active_mi); + return res; +} + + +static bool update_slave_skip_counter(sys_var *self, THD *thd, + enum_var_type type) +{ + bool result= true; + Master_info *mi; + mysql_mutex_lock(&LOCK_active_mi); + mi= master_info_index-> + get_master_info(&thd->variables.default_master_connection, + MYSQL_ERROR::WARN_LEVEL_ERROR); + if (mi) + { + mysql_mutex_lock(&mi->rli.run_lock); + if (mi->rli.slave_running) + my_message(ER_SLAVE_MUST_STOP, ER(ER_SLAVE_MUST_STOP), MYF(0)); + else + { + result= false; // ok + mysql_mutex_lock(&mi->rli.data_lock); + /* The value was stored temporarly in thd */ + mi->rli.slave_skip_counter= thd->variables.slave_skip_counter; + mysql_mutex_unlock(&mi->rli.data_lock); + } + mysql_mutex_unlock(&mi->rli.run_lock); } - mysql_mutex_unlock(&active_mi->rli.run_lock); mysql_mutex_unlock(&LOCK_active_mi); return result; } -static bool fix_slave_skip_counter(sys_var *self, THD *thd, enum_var_type type) -{ - mysql_mutex_unlock(&LOCK_global_system_variables); - mysql_mutex_lock(&LOCK_active_mi); - mysql_mutex_lock(&active_mi->rli.run_lock); - /* - The following test should normally never be true as we test this - in the check function; To be safe against multiple - SQL_SLAVE_SKIP_COUNTER request, we do the check anyway - */ - if (!active_mi->rli.slave_running) - { - mysql_mutex_lock(&active_mi->rli.data_lock); - active_mi->rli.slave_skip_counter= sql_slave_skip_counter; - mysql_mutex_unlock(&active_mi->rli.data_lock); - } - mysql_mutex_unlock(&active_mi->rli.run_lock); - mysql_mutex_unlock(&LOCK_active_mi); - mysql_mutex_lock(&LOCK_global_system_variables); - return 0; -} -static Sys_var_uint Sys_slave_skip_counter( - "sql_slave_skip_counter", "sql_slave_skip_counter", - GLOBAL_VAR(sql_slave_skip_counter), NO_CMD_LINE, - VALID_RANGE(0, UINT_MAX), DEFAULT(0), BLOCK_SIZE(1), - NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_slave_skip_counter), - ON_UPDATE(fix_slave_skip_counter)); + +static Sys_var_multi_source_uint +Sys_slave_skip_counter("sql_slave_skip_counter", + "Skip the next N events from the master log", + SESSION_VAR(slave_skip_counter), + offsetof(Master_info, rli.slave_skip_counter), + VALID_RANGE(0, UINT_MAX), DEFAULT(0), BLOCK_SIZE(1), + ON_UPDATE(update_slave_skip_counter)); static Sys_var_charptr Sys_slave_skip_errors( "slave_skip_errors", "Tells the slave thread to continue " diff --git a/sql/sys_vars.h b/sql/sys_vars.h index 21bebcd762c..6509ba6a5f4 100644 --- a/sql/sys_vars.h +++ b/sql/sys_vars.h @@ -633,6 +633,88 @@ public: } }; + +/* + A LEX_STRING stored only in thd->variables + Only to be used for small buffers +*/ + +class Sys_var_session_lexstring: public sys_var +{ + size_t max_length; +public: + Sys_var_session_lexstring(const char *name_arg, + const char *comment, int flag_args, + ptrdiff_t off, size_t size, CMD_LINE getopt, + enum charset_enum is_os_charset_arg, + const char *def_val, size_t max_length_arg, + on_check_function on_check_func=0, + on_update_function on_update_func=0) + : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id, + getopt.arg_type, SHOW_CHAR, (intptr)def_val, + 0, VARIABLE_NOT_IN_BINLOG, on_check_func, on_update_func, + 0, 0),max_length(max_length_arg) + { + option.var_type= GET_NO_ARG; + SYSVAR_ASSERT(scope() == ONLY_SESSION) + *const_cast(&show_val_type)= SHOW_LEX_STRING; + } + bool do_check(THD *thd, set_var *var) + { + char buff[STRING_BUFFER_USUAL_SIZE]; + String str(buff, sizeof(buff), system_charset_info), *res; + + if (!(res=var->value->val_str(&str))) + var->save_result.string_value.str= const_cast(""); + else + { + if (res->length() > max_length) + { + my_error(ER_WRONG_STRING_LENGTH, MYF(0), + res->ptr(), name.str, (int) max_length); + return true; + } + var->save_result.string_value.str= thd->strmake(res->ptr(), + res->length()); + var->save_result.string_value.length= res->length(); + } + return false; + } + bool session_update(THD *thd, set_var *var) + { + LEX_STRING *tmp= &session_var(thd, LEX_STRING); + tmp->length= var->save_result.string_value.length; + /* Store as \0 terminated string (just to be safe) */ + strmake(tmp->str, var->save_result.string_value.str, tmp->length); + return false; + } + bool global_update(THD *thd, set_var *var) + { + DBUG_ASSERT(FALSE); + return false; + } + void session_save_default(THD *thd, set_var *var) + { + char *ptr= (char*)(intptr)option.def_value; + var->save_result.string_value.str= ptr; + } + void global_save_default(THD *thd, set_var *var) + { + DBUG_ASSERT(FALSE); + } + uchar *session_value_ptr(THD *thd, LEX_STRING *base) + { + return (uchar*) &session_var(thd, LEX_STRING); + } + uchar *global_value_ptr(THD *thd, LEX_STRING *base) + { + DBUG_ASSERT(FALSE); + } + bool check_update_type(Item_result type) + { return type != STRING_RESULT; } +}; + + #ifndef DBUG_OFF /** @@session.dbug and @@global.dbug variables. @@ -1389,6 +1471,7 @@ public: }; #endif /* defined(ENABLED_DEBUG_SYNC) */ + /** The class for bit variables - a variant of boolean that stores the value in a bit. @@ -1862,6 +1945,65 @@ public: bool global_update(THD *thd, set_var *var); }; +/* + Class for handing multi-source replication variables + Variable values are store in Master_info, but to make it possible to + access variable without locks we also store it thd->variables. + These can be used as GLOBAL or SESSION, but both points to the same + variable. This is to make things compatible with MySQL 5.5 where variables + like sql_slave_skip_counter are GLOBAL. +*/ + +class Sys_var_multi_source_uint :public Sys_var_uint +{ + ptrdiff_t master_info_offset; +public: + Sys_var_multi_source_uint(const char *name_arg, + const char *comment, int flag_args, + ptrdiff_t off, size_t size, + ptrdiff_t master_info_offset_arg, + uint min_val, uint max_val, uint def_val, + uint block_size, + on_update_function on_update_func) + :Sys_var_uint(name_arg, comment, flag_args, off, size, + NO_CMD_LINE, min_val, max_val, def_val, block_size, + 0, VARIABLE_NOT_IN_BINLOG, 0, on_update_func), + master_info_offset(master_info_offset_arg) + { + /* No global storage of variables. Cause a crash if we try an update */ + option.value= (uchar**)1; + } + bool session_update(THD *thd, set_var *var) + { + session_var(thd, uint)= (uint) (var->save_result.ulonglong_value); + /* Value should be moved to multi_master in on_update_func */ + return false; + } + bool global_update(THD *thd, set_var *var) + { + return session_update(thd, var); + } + void session_save_default(THD *thd, set_var *var) + { + /* Use value given in variable declaration */ + global_save_default(thd, var); + } + uchar *session_value_ptr(THD *thd,LEX_STRING *base) + { + uint *tmp, res; + tmp= (uint*) (((uchar*)&(thd->variables)) + offset); + res= get_master_info_uint_value(thd, master_info_offset); + *tmp= res; + return (uchar*) tmp; + } + uchar *global_value_ptr(THD *thd, LEX_STRING *base) + { + return session_value_ptr(thd, base); + } + uint get_master_info_uint_value(THD *thd, ptrdiff_t offset); +}; + + /**************************************************************************** Used templates ****************************************************************************/ From 222883b0d66a3e4987b2f3d98023f677ea23642f Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Fri, 28 Sep 2012 03:45:05 +0300 Subject: [PATCH 275/289] Added multi-source support to show relaylog events --- sql/sql_repl.cc | 22 +++++++++++++++++++--- sql/sql_yacc.yy | 2 +- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 99395738c66..036afb45a19 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -2022,6 +2022,7 @@ bool mysql_show_binlog_events(THD* thd) File file = -1; MYSQL_BIN_LOG *binary_log= NULL; int old_max_allowed_packet= thd->variables.max_allowed_packet; + Master_info *mi= 0; LOG_INFO linfo; DBUG_ENTER("mysql_show_binlog_events"); @@ -2051,10 +2052,15 @@ bool mysql_show_binlog_events(THD* thd) } else /* showing relay log contents */ { - if (!active_mi) + mysql_mutex_lock(&LOCK_active_mi); + if (!(mi= master_info_index-> + get_master_info(&thd->variables.default_master_connection, + MYSQL_ERROR::WARN_LEVEL_ERROR))) + { + mysql_mutex_unlock(&LOCK_active_mi); DBUG_RETURN(TRUE); - - binary_log= &(active_mi->rli.relay_log); + } + binary_log= &(mi->rli.relay_log); } if (binary_log->is_open()) @@ -2068,6 +2074,13 @@ bool mysql_show_binlog_events(THD* thd) mysql_mutex_t *log_lock = binary_log->get_log_lock(); Log_event* ev; + if (mi) + { + /* We can unlock the mutex as we have a lock on the file */ + mysql_mutex_unlock(&LOCK_active_mi); + mi= 0; + } + unit->set_limit(thd->lex->current_select); limit_start= unit->offset_limit_cnt; limit_end= unit->select_limit_cnt; @@ -2162,6 +2175,9 @@ bool mysql_show_binlog_events(THD* thd) mysql_mutex_unlock(log_lock); } + else if (mi) + mysql_mutex_unlock(&LOCK_active_mi); + // Check that linfo is still on the function scope. DEBUG_SYNC(thd, "after_show_binlog_events"); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index e1bcb48e541..ab07a2010f0 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -11453,7 +11453,7 @@ show_param: LEX *lex= Lex; lex->sql_command= SQLCOM_SHOW_BINLOG_EVENTS; } opt_limit_clause_init - | RELAYLOG_SYM EVENTS_SYM binlog_in binlog_from + | RELAYLOG_SYM optional_connection_name EVENTS_SYM binlog_in binlog_from { LEX *lex= Lex; lex->sql_command= SQLCOM_SHOW_RELAYLOG_EVENTS; From 9b03041b27547e926145d8cc5c39bea659c45015 Mon Sep 17 00:00:00 2001 From: Elena Stepanova Date: Fri, 28 Sep 2012 09:28:40 +0400 Subject: [PATCH 276/289] Tests for Multi-source replication (MDEV-253) --- .../suite/multi_source/relaylog_events.result | 27 ++++++++ .../suite/multi_source/relaylog_events.test | 50 +++++++++++++++ .../suite/multi_source/reset_slave.result | 31 ++++++++++ .../suite/multi_source/reset_slave.test | 62 +++++++++++++++++++ mysql-test/suite/multi_source/simple.result | 5 ++ mysql-test/suite/multi_source/simple.test | 6 +- 6 files changed, 180 insertions(+), 1 deletion(-) create mode 100644 mysql-test/suite/multi_source/relaylog_events.result create mode 100644 mysql-test/suite/multi_source/relaylog_events.test create mode 100644 mysql-test/suite/multi_source/reset_slave.result create mode 100644 mysql-test/suite/multi_source/reset_slave.test diff --git a/mysql-test/suite/multi_source/relaylog_events.result b/mysql-test/suite/multi_source/relaylog_events.result new file mode 100644 index 00000000000..f93dff97718 --- /dev/null +++ b/mysql-test/suite/multi_source/relaylog_events.result @@ -0,0 +1,27 @@ +change master 'master1' to +master_port=MYPORT_1, +master_host='127.0.0.1', +master_user='root'; +start slave 'master1'; +set default_master_connection = 'master1'; +include/wait_for_slave_to_start.inc +drop table if exists t1; +create table t1 (i int) engine=MyISAM; +mysqld-relay-bin-master1.000001 +mysqld-relay-bin-master1.000002 +show relaylog events in 'mysqld-relay-bin-master1.000002'; +Log_name Pos Event_type Server_id End_log_pos Info +mysqld-relay-bin-master1.000002 4 Format_desc 3 246 Server version +mysqld-relay-bin-master1.000002 246 Rotate 1 0 master-bin.000001;pos=4 +mysqld-relay-bin-master1.000002 290 Format_desc 1 246 Server version +mysqld-relay-bin-master1.000002 532 Binlog_checkpoint 1 286 master-bin.000001 +mysqld-relay-bin-master1.000002 572 Query 1 400 use `test`; DROP TABLE IF EXISTS `t1` /* generated by server */ +mysqld-relay-bin-master1.000002 686 Query 1 500 use `test`; create table t1 (i int) engine=MyISAM +show relaylog events; +Log_name Pos Event_type Server_id End_log_pos Info +mysqld-relay-bin-master1.000001 4 Format_desc 3 246 Server version +mysqld-relay-bin-master1.000001 246 Rotate 3 304 mysqld-relay-bin-master1.000002;pos=4 +drop table t1; +stop slave; +include/wait_for_slave_to_stop.inc +reset master; diff --git a/mysql-test/suite/multi_source/relaylog_events.test b/mysql-test/suite/multi_source/relaylog_events.test new file mode 100644 index 00000000000..a9488d1373c --- /dev/null +++ b/mysql-test/suite/multi_source/relaylog_events.test @@ -0,0 +1,50 @@ +# +# Check that SHOW RELAYLOG EVENTS can be used +# for a named master connection +# + +--connect (slave,127.0.0.1,root,,,$SERVER_MYPORT_3) + +--replace_result $SERVER_MYPORT_1 MYPORT_1 +eval change master 'master1' to +master_port=$SERVER_MYPORT_1, +master_host='127.0.0.1', +master_user='root'; + +start slave 'master1'; +set default_master_connection = 'master1'; +--source include/wait_for_slave_to_start.inc + +--connect (master1,127.0.0.1,root,,,$SERVER_MYPORT_1) +--disable_warnings +drop table if exists t1; +--enable_warnings +create table t1 (i int) engine=MyISAM; +--save_master_pos + +--connection slave +--sync_with_master 0,'master1' + +--let $datadir = `SELECT @@datadir` +--list_files $datadir mysqld-relay-bin-master1.* + +--replace_regex /Server ver:.*/Server version/ +show relaylog events in 'mysqld-relay-bin-master1.000002'; +--replace_regex /Server ver:.*/Server version/ +show relaylog events; + +--connection master1 +drop table t1; +--save_master_pos + +--connection slave +--sync_with_master 0,'master1' +stop slave; +--source include/wait_for_slave_to_stop.inc + +--disconnect slave + +--connection master1 +reset master; +--disconnect master1 + diff --git a/mysql-test/suite/multi_source/reset_slave.result b/mysql-test/suite/multi_source/reset_slave.result new file mode 100644 index 00000000000..0ae32e94166 --- /dev/null +++ b/mysql-test/suite/multi_source/reset_slave.result @@ -0,0 +1,31 @@ +change master 'master1' to +master_port=MYPORT_1, +master_host='127.0.0.1', +master_user='root'; +start slave 'master1'; +set default_master_connection = 'master1'; +include/wait_for_slave_to_start.inc +drop table if exists t1; +create table t1 (i int) engine=MyISAM; +insert into t1 values (1),(2); +stop slave 'master1'; +show slave 'master1' 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 Replicate_Ignore_Server_Ids Master_Server_Id + 127.0.0.1 root MYPORT_1 60 master-bin.000001 729 mysqld-relay-bin-master1.000002 1015 master-bin.000001 No No 0 0 729 1319 None 0 No NULL No 0 0 1 +mysqld-relay-bin-master1.000001 +mysqld-relay-bin-master1.000002 +mysqld-relay-bin.index-master1 +reset slave 'master1'; +show slave 'master1' 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 Replicate_Ignore_Server_Ids Master_Server_Id + 127.0.0.1 root MYPORT_1 60 4 mysqld-relay-bin-master1.000001 4 No No 0 0 0 265 None 0 No NULL No 0 0 1 +mysqld-relay-bin-master1.000001 +mysqld-relay-bin.index-master1 +reset slave 'master1' all; +show slave 'master1' status; +ERROR HY000: There is no master connection 'master1' +mysqld-relay-bin-master1.000001 +mysqld-relay-bin.index-master1 +drop table t1; +drop table t1; +reset master; diff --git a/mysql-test/suite/multi_source/reset_slave.test b/mysql-test/suite/multi_source/reset_slave.test new file mode 100644 index 00000000000..d3b9abb91ca --- /dev/null +++ b/mysql-test/suite/multi_source/reset_slave.test @@ -0,0 +1,62 @@ +#--enable_connect_log +--connect (slave,127.0.0.1,root,,,$SERVER_MYPORT_3) + +--replace_result $SERVER_MYPORT_1 MYPORT_1 +eval change master 'master1' to +master_port=$SERVER_MYPORT_1, +master_host='127.0.0.1', +master_user='root'; + +start slave 'master1'; + +set default_master_connection = 'master1'; +--source include/wait_for_slave_to_start.inc + +--connect (master1,127.0.0.1,root,,,$SERVER_MYPORT_1) + +--disable_warnings +drop table if exists t1; +--enable_warnings + +create table t1 (i int) engine=MyISAM; +insert into t1 values (1),(2); + +--save_master_pos + +--connection slave + +--sync_with_master 0,'master1' +stop slave 'master1'; + +--wait_for_slave_to_stop + +--let $datadir = `SELECT @@datadir` + +--replace_result $SERVER_MYPORT_1 MYPORT_1 +show slave 'master1' status; +--list_files $datadir mysqld* + +reset slave 'master1'; + +--replace_result $SERVER_MYPORT_1 MYPORT_1 +show slave 'master1' status; +--list_files $datadir mysqld* + +reset slave 'master1' all; + +--error WARN_NO_MASTER_INFO +show slave 'master1' status; +--list_files $datadir mysqld* + +# Cleanup + +drop table t1; +--disconnect slave + +--connection master1 +drop table t1; +reset master; +--disconnect master1 + + + diff --git a/mysql-test/suite/multi_source/simple.result b/mysql-test/suite/multi_source/simple.result index 7448e0a0113..aeb52d06bad 100644 --- a/mysql-test/suite/multi_source/simple.result +++ b/mysql-test/suite/multi_source/simple.result @@ -1,7 +1,12 @@ change master 'slave1' to master_port=MYPORT_1, master_host='127.0.0.1', master_user='root'; change master 'slave2' to master_port=MYPORT_2, master_host='127.0.0.1', master_user='root'; start slave 'slave1'; +set default_master_connection = 'slave1'; +include/wait_for_slave_to_start.inc +set default_master_connection = 'slave2'; start slave 'slave2'; +include/wait_for_slave_to_start.inc +set default_master_connection = ''; show full slave status; Connection_name 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 Replicate_Ignore_Server_Ids Master_Server_Id slave1 Waiting for master to send event 127.0.0.1 root MYPORT_1 60 master-bin.000001 286 mysqld-relay-bin-slave1.000002 572 master-bin.000001 Yes Yes 0 0 286 875 None 0 No 0 No 0 0 1 diff --git a/mysql-test/suite/multi_source/simple.test b/mysql-test/suite/multi_source/simple.test index 97696c6e75f..8ebc1e9f0a6 100644 --- a/mysql-test/suite/multi_source/simple.test +++ b/mysql-test/suite/multi_source/simple.test @@ -9,8 +9,12 @@ eval change master 'slave1' to master_port=$SERVER_MYPORT_1, master_host='127.0. --replace_result $SERVER_MYPORT_2 MYPORT_2 eval change master 'slave2' to master_port=$SERVER_MYPORT_2, master_host='127.0.0.1', master_user='root'; start slave 'slave1'; +set default_master_connection = 'slave1'; +--source include/wait_for_slave_to_start.inc +set default_master_connection = 'slave2'; start slave 'slave2'; ---sleep 5 +--source include/wait_for_slave_to_start.inc +set default_master_connection = ''; --replace_result $SERVER_MYPORT_1 MYPORT_1 $SERVER_MYPORT_2 MYPORT_2 show full slave status; From 5a4b5869a039bd50ce5a040114ede77bbae58c80 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Fri, 28 Sep 2012 21:22:24 +0300 Subject: [PATCH 277/289] Fixed issues found by QA (Elena) - Added parameter to reset_logs() so that one can specify if new logs should be created. mysql-test/include/setup_fake_relay_log.inc: There is no orphan relay log files anymore mysql-test/mysql-test-run.pl: Added multi_source to test suite mysql-test/suite/multi_source/info_logs.result: New test mysql-test/suite/multi_source/info_logs.test: New test mysql-test/suite/multi_source/my.cnf: Added log-warnings to get more information to the log files mysql-test/suite/multi_source/relaylog_events.result: Added cleanup mysql-test/suite/multi_source/relaylog_events.test: Added cleanup mysql-test/suite/multi_source/reset_slave.result: Updated results after improved RESET SLAVE mysql-test/suite/multi_source/simple.result: Updated results after improved RESET SLAVE mysql-test/suite/multi_source/simple.test: Syncronize positions before show full slave status mysql-test/suite/rpl/r/rpl_row_show_relaylog_events.result: Updated results after improved RESET SLAVE (we now use less relay log files) mysql-test/suite/rpl/r/rpl_stm_mix_show_relaylog_events.result: Updated results after improved RESET SLAVE (we now use less relay log files) sql/log.cc: Added parameter to reset_logs() so that one can specify if new logs should be created. sql/log.h: Added parameter to reset_logs() sql/rpl_mi.cc: Create Master_info_index::index_file_names once at init More DBUG_PRINT Give error if Master_info_index::check_duplicate_master_info fails sql/rpl_rli.cc: If we do a full reset, don't create any new relay log files. sql/share/errmsg-utf8.txt: Improved error message if connection exists sql/sql_parse.cc: Fixed memory leak sql/sql_repl.cc: check_duplicate_master_info() now generates an error Added parameter to reset_logs() --- mysql-test/include/setup_fake_relay_log.inc | 4 - mysql-test/mysql-test-run.pl | 1 + .../suite/multi_source/info_logs.result | 115 +++++++++++++ mysql-test/suite/multi_source/info_logs.test | 160 ++++++++++++++++++ mysql-test/suite/multi_source/my.cnf | 3 + .../suite/multi_source/relaylog_events.result | 1 + .../suite/multi_source/relaylog_events.test | 2 + .../suite/multi_source/reset_slave.result | 6 +- mysql-test/suite/multi_source/simple.result | 2 +- mysql-test/suite/multi_source/simple.test | 13 ++ .../rpl/r/rpl_row_show_relaylog_events.result | 76 ++++----- .../r/rpl_stm_mix_show_relaylog_events.result | 70 ++++---- sql/log.cc | 8 +- sql/log.h | 2 +- sql/rpl_mi.cc | 53 +++--- sql/rpl_rli.cc | 35 ++-- sql/share/errmsg-utf8.txt | 3 +- sql/sql_parse.cc | 1 + sql/sql_repl.cc | 7 +- 19 files changed, 428 insertions(+), 134 deletions(-) create mode 100644 mysql-test/suite/multi_source/info_logs.result create mode 100644 mysql-test/suite/multi_source/info_logs.test diff --git a/mysql-test/include/setup_fake_relay_log.inc b/mysql-test/include/setup_fake_relay_log.inc index 4f1d4f6f162..a1964572427 100644 --- a/mysql-test/include/setup_fake_relay_log.inc +++ b/mysql-test/include/setup_fake_relay_log.inc @@ -74,7 +74,6 @@ let $_fake_relay_index= $_fake_datadir/$_fake_filename.index; let $_fake_relay_log_purge= `SELECT @@global.relay_log_purge`; RESET SLAVE; -let $_orphan_relay_file= query_get_value(SHOW SLAVE STATUS, Relay_Log_File, 1); # Create relay log file. --copy_file $fake_relay_log $_fake_relay_log @@ -103,8 +102,5 @@ let $_orphan_relay_file= query_get_value(SHOW SLAVE STATUS, Relay_Log_File, 1); # Setup replication from existing relay log. eval CHANGE MASTER TO MASTER_HOST='dummy.localdomain', RELAY_LOG_FILE='$_fake_filename-fake.000001', RELAY_LOG_POS=4; -# remove the orphan log file (became spurious) --- remove_file $_fake_datadir/$_orphan_relay_file - --let $include_filename= setup_fake_relay_log.inc --source include/end_include_file.inc diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 8c4013e1c24..768016d94aa 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -174,6 +174,7 @@ my $DEFAULT_SUITES= join(',', map { "$_-" } qw( heap innodb maria + multi_source optimizer_unfixed_bugs oqgraph parts diff --git a/mysql-test/suite/multi_source/info_logs.result b/mysql-test/suite/multi_source/info_logs.result new file mode 100644 index 00000000000..4947244068a --- /dev/null +++ b/mysql-test/suite/multi_source/info_logs.result @@ -0,0 +1,115 @@ +# +# List of files matching '*info*' pattern before starting any slaves +multi-master.info +# End of list +# +# Contents of multi-master.info +# EOF +# +change master 'master1' to +master_port=MYPORT_1, +master_host='127.0.0.1', +master_user='root'; +start slave 'master1'; +set default_master_connection = 'master1'; +include/wait_for_slave_to_start.inc +# +# List of files matching '*info*' pattern while 'master1' is running +master.info.master1 +multi-master.info +relay-log.info.master1 +# End of list +# +# Contents of multi-master.info +master1 +# EOF +# +change master 'master2' to +master_port=MYPORT_2, +master_host='127.0.0.1', +master_user='root'; +start slave 'master2'; +set default_master_connection = 'master2'; +include/wait_for_slave_to_start.inc +# +# List of files matching '*info*' pattern +# while 'master1' and 'master2' are running +master.info.master1 +master.info.master2 +multi-master.info +relay-log.info.master1 +relay-log.info.master2 +# End of list +# +# Contents of multi-master.info +master1 +master2 +# EOF +# +stop slave 'master1'; +set default_master_connection = 'master1'; +include/wait_for_slave_to_stop.inc +reset slave 'master1' all; +# +# List of files matching '*info*' pattern +# after 'master1' was completely reset, 'master2' still running +master.info.master2 +multi-master.info +relay-log.info.master2 +# End of list +# +# Contents of multi-master.info +master2 +# EOF +# +set default_master_connection = ''; +change master to +master_port=MYPORT_1, +master_host='127.0.0.1', +master_user='root'; +start slave; +include/wait_for_slave_to_start.inc +# +# List of files matching '*info*' pattern +# while 'master2' and '' are running +master.info +master.info.master2 +multi-master.info +relay-log.info +relay-log.info.master2 +# End of list +# +# Contents of multi-master.info +master2 +# EOF +# +show full slave status; +Connection_name 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 Replicate_Ignore_Server_Ids Master_Server_Id + Waiting for master to send event 127.0.0.1 root MYPORT_1 60 master-bin.000001 286 mysqld-relay-bin.000002 572 master-bin.000001 Yes Yes 0 0 286 868 None 0 No 0 No 0 0 1 +master2 Waiting for master to send event 127.0.0.1 root MYPORT_2 60 master-bin.000001 286 mysqld-relay-bin-master2.000002 572 master-bin.000001 Yes Yes 0 0 286 876 None 0 No 0 No 0 0 2 +show full slave status; +Connection_name 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 Replicate_Ignore_Server_Ids Master_Server_Id + Waiting for master to send event 127.0.0.1 root MYPORT_1 60 master-bin.000001 286 mysqld-relay-bin.000004 532 master-bin.000001 Yes Yes 0 0 286 828 None 0 No 0 No 0 0 1 +master2 Waiting for master to send event 127.0.0.1 root MYPORT_2 60 master-bin.000001 286 mysqld-relay-bin-master2.000004 532 master-bin.000001 Yes Yes 0 0 286 836 None 0 No 0 No 0 0 2 +# +# List of files matching '*info*' pattern +# after slave server restart +# while 'master2' and '' are running +master.info +master.info.master2 +multi-master.info +relay-log.info +relay-log.info.master2 +# End of list +# +# Contents of multi-master.info +master2 +# EOF +# +stop slave; +include/wait_for_slave_to_stop.inc +set default_master_connection = 'master2'; +stop slave; +include/wait_for_slave_to_stop.inc +reset slave all; +reset slave '' all; diff --git a/mysql-test/suite/multi_source/info_logs.test b/mysql-test/suite/multi_source/info_logs.test new file mode 100644 index 00000000000..40e1b481d2c --- /dev/null +++ b/mysql-test/suite/multi_source/info_logs.test @@ -0,0 +1,160 @@ +# +# Check log files with multi-source +# + +--connect (slave,127.0.0.1,root,,,$SERVER_MYPORT_3) + +--let $datadir = `SELECT @@datadir` + +# +# Check creation and updating of multi-source *info* logs +# + +--echo # +--echo # List of files matching '*info*' pattern before starting any slaves +--list_files $datadir *info* +--echo # End of list +--echo # +--echo # Contents of multi-master.info +--cat_file $datadir/multi-master.info +--echo # EOF +--echo # + +# Start replication from the first master + +--replace_result $SERVER_MYPORT_1 MYPORT_1 +eval change master 'master1' to +master_port=$SERVER_MYPORT_1, +master_host='127.0.0.1', +master_user='root'; + +start slave 'master1'; +set default_master_connection = 'master1'; +--source include/wait_for_slave_to_start.inc + +# Check the files + +--echo # +--echo # List of files matching '*info*' pattern while 'master1' is running +--list_files $datadir *info* +--echo # End of list +--echo # +--echo # Contents of multi-master.info +--cat_file $datadir/multi-master.info +--echo # EOF +--echo # + +# Start replication from the second master + +--replace_result $SERVER_MYPORT_2 MYPORT_2 +eval change master 'master2' to +master_port=$SERVER_MYPORT_2, +master_host='127.0.0.1', +master_user='root'; + +start slave 'master2'; +set default_master_connection = 'master2'; +--source include/wait_for_slave_to_start.inc + +# Check the files + +--echo # +--echo # List of files matching '*info*' pattern +--echo # while 'master1' and 'master2' are running +--list_files $datadir *info* +--echo # End of list +--echo # +--echo # Contents of multi-master.info +--cat_file $datadir/multi-master.info +--echo # EOF +--echo # + +# Remove master1 configuration + +stop slave 'master1'; +set default_master_connection = 'master1'; +--source include/wait_for_slave_to_stop.inc +reset slave 'master1' all; + +# Check the files + +--echo # +--echo # List of files matching '*info*' pattern +--echo # after 'master1' was completely reset, 'master2' still running +--list_files $datadir *info* +--echo # End of list +--echo # +--echo # Contents of multi-master.info +--cat_file $datadir/multi-master.info +--echo # EOF +--echo # + +# Start replication from the first master, +# now with the default empty name + +set default_master_connection = ''; +--replace_result $SERVER_MYPORT_1 MYPORT_1 +eval change master to +master_port=$SERVER_MYPORT_1, +master_host='127.0.0.1', +master_user='root'; + +start slave; +--source include/wait_for_slave_to_start.inc + +# Check the files + +--echo # +--echo # List of files matching '*info*' pattern +--echo # while 'master2' and '' are running +--list_files $datadir *info* +--echo # End of list +--echo # +--echo # Contents of multi-master.info +--cat_file $datadir/multi-master.info +--echo # EOF +--echo # + +--sleep 5 +--replace_result $SERVER_MYPORT_1 MYPORT_1 $SERVER_MYPORT_2 MYPORT_2 +show full slave status; + +# Restart the slave server + +--enable_reconnect +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.3.expect +restart +EOF +--shutdown_server 60 +--source include/wait_until_connected_again.inc + +--replace_result $SERVER_MYPORT_1 MYPORT_1 $SERVER_MYPORT_2 MYPORT_2 +show full slave status; + +# Check the files + +--echo # +--echo # List of files matching '*info*' pattern +--echo # after slave server restart +--echo # while 'master2' and '' are running +--list_files $datadir *info* +--echo # End of list +--echo # +--echo # Contents of multi-master.info +--cat_file $datadir/multi-master.info +--echo # EOF +--echo # + + +# Cleanup + +stop slave; +--source include/wait_for_slave_to_stop.inc + +set default_master_connection = 'master2'; +stop slave; +--source include/wait_for_slave_to_stop.inc +reset slave all; +reset slave '' all; + +--disconnect slave diff --git a/mysql-test/suite/multi_source/my.cnf b/mysql-test/suite/multi_source/my.cnf index dd57fd2199f..826967b52f9 100644 --- a/mysql-test/suite/multi_source/my.cnf +++ b/mysql-test/suite/multi_source/my.cnf @@ -5,13 +5,16 @@ [mysqld.1] server-id=1 log-bin=master-bin +log-warnings=2 [mysqld.2] server-id=2 log-bin=master-bin +log-warnings=2 [mysqld.3] server-id=3 +log-warnings=2 [ENV] SERVER_MYPORT_1= @mysqld.1.port diff --git a/mysql-test/suite/multi_source/relaylog_events.result b/mysql-test/suite/multi_source/relaylog_events.result index f93dff97718..a91ae82970b 100644 --- a/mysql-test/suite/multi_source/relaylog_events.result +++ b/mysql-test/suite/multi_source/relaylog_events.result @@ -24,4 +24,5 @@ mysqld-relay-bin-master1.000001 246 Rotate 3 304 mysqld-relay-bin-master1.000002 drop table t1; stop slave; include/wait_for_slave_to_stop.inc +reset slave 'master1' all; reset master; diff --git a/mysql-test/suite/multi_source/relaylog_events.test b/mysql-test/suite/multi_source/relaylog_events.test index a9488d1373c..b5bbf726316 100644 --- a/mysql-test/suite/multi_source/relaylog_events.test +++ b/mysql-test/suite/multi_source/relaylog_events.test @@ -42,6 +42,8 @@ drop table t1; stop slave; --source include/wait_for_slave_to_stop.inc +reset slave 'master1' all; + --disconnect slave --connection master1 diff --git a/mysql-test/suite/multi_source/reset_slave.result b/mysql-test/suite/multi_source/reset_slave.result index 0ae32e94166..a1256988bbf 100644 --- a/mysql-test/suite/multi_source/reset_slave.result +++ b/mysql-test/suite/multi_source/reset_slave.result @@ -18,14 +18,10 @@ mysqld-relay-bin.index-master1 reset slave 'master1'; show slave 'master1' 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 Replicate_Ignore_Server_Ids Master_Server_Id - 127.0.0.1 root MYPORT_1 60 4 mysqld-relay-bin-master1.000001 4 No No 0 0 0 265 None 0 No NULL No 0 0 1 -mysqld-relay-bin-master1.000001 -mysqld-relay-bin.index-master1 + 127.0.0.1 root MYPORT_1 60 4 1015 No No 0 0 0 1319 None 0 No NULL No 0 0 1 reset slave 'master1' all; show slave 'master1' status; ERROR HY000: There is no master connection 'master1' -mysqld-relay-bin-master1.000001 -mysqld-relay-bin.index-master1 drop table t1; drop table t1; reset master; diff --git a/mysql-test/suite/multi_source/simple.result b/mysql-test/suite/multi_source/simple.result index aeb52d06bad..003622a1b46 100644 --- a/mysql-test/suite/multi_source/simple.result +++ b/mysql-test/suite/multi_source/simple.result @@ -56,7 +56,7 @@ Master_Server_Id 1 reset slave 'slave1'; show full slave status; Connection_name 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 Replicate_Ignore_Server_Ids Master_Server_Id -slave1 127.0.0.1 root MYPORT_1 60 4 mysqld-relay-bin-slave1.000001 4 No No 0 0 0 265 None 0 No NULL No 0 0 1 +slave1 127.0.0.1 root MYPORT_1 60 4 572 No No 0 0 0 875 None 0 No NULL No 0 0 1 slave2 Waiting for master to send event 127.0.0.1 root MYPORT_2 60 master-bin.000001 286 mysqld-relay-bin-slave2.000002 572 master-bin.000001 Yes Yes 0 0 286 875 None 0 No 0 No 0 0 2 reset slave 'slave1' all; show full slave status; diff --git a/mysql-test/suite/multi_source/simple.test b/mysql-test/suite/multi_source/simple.test index 8ebc1e9f0a6..2b4f06aa1fe 100644 --- a/mysql-test/suite/multi_source/simple.test +++ b/mysql-test/suite/multi_source/simple.test @@ -3,6 +3,9 @@ # --connect (slave,127.0.0.1,root,,,$SERVER_MYPORT_3) +--connect (master1,127.0.0.1,root,,,$SERVER_MYPORT_1) +--connect (master2,127.0.0.1,root,,,$SERVER_MYPORT_2) +--connection slave --replace_result $SERVER_MYPORT_1 MYPORT_1 eval change master 'slave1' to master_port=$SERVER_MYPORT_1, master_host='127.0.0.1', master_user='root'; @@ -16,6 +19,16 @@ start slave 'slave2'; --source include/wait_for_slave_to_start.inc set default_master_connection = ''; +# Ensure that all data is in the relay log +--connection master1 +--save_master_pos +--connection slave +--sync_with_master 0,'slave1' +--connection master2 +--save_master_pos +--connection slave +--sync_with_master 0,'slave2' + --replace_result $SERVER_MYPORT_1 MYPORT_1 $SERVER_MYPORT_2 MYPORT_2 show full slave status; diff --git a/mysql-test/suite/rpl/r/rpl_row_show_relaylog_events.result b/mysql-test/suite/rpl/r/rpl_row_show_relaylog_events.result index a6d691f420e..cd72b489e1a 100644 --- a/mysql-test/suite/rpl/r/rpl_row_show_relaylog_events.result +++ b/mysql-test/suite/rpl/r/rpl_row_show_relaylog_events.result @@ -90,38 +90,38 @@ slave-bin.000001 # Table_map # # table_id: # (test.t1) slave-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F slave-bin.000001 # Query # # COMMIT ******** [slave] SHOW RELAYLOG EVENTS IN ******** -show relaylog events in 'slave-relay-bin.000003' from ; +show relaylog events in 'slave-relay-bin.000002' from ; Log_name Pos Event_type Server_id End_log_pos Info -slave-relay-bin.000003 # Rotate # # master-bin.000001;pos=4 -slave-relay-bin.000003 # Format_desc # # SERVER_VERSION, BINLOG_VERSION -slave-relay-bin.000003 # Binlog_checkpoint # # master-bin.000001 -slave-relay-bin.000003 # Query # # use `test`; CREATE TABLE t1 (a INT) -slave-relay-bin.000003 # Query # # BEGIN -slave-relay-bin.000003 # Table_map # # table_id: # (test.t1) -slave-relay-bin.000003 # Write_rows # # table_id: # flags: STMT_END_F -slave-relay-bin.000003 # Query # # COMMIT -slave-relay-bin.000003 # Query # # BEGIN -slave-relay-bin.000003 # Table_map # # table_id: # (test.t1) -slave-relay-bin.000003 # Write_rows # # table_id: # flags: STMT_END_F -slave-relay-bin.000003 # Query # # COMMIT -slave-relay-bin.000003 # Query # # BEGIN -slave-relay-bin.000003 # Table_map # # table_id: # (test.t1) -slave-relay-bin.000003 # Write_rows # # table_id: # flags: STMT_END_F -slave-relay-bin.000003 # Query # # COMMIT +slave-relay-bin.000002 # Rotate # # master-bin.000001;pos=4 +slave-relay-bin.000002 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +slave-relay-bin.000002 # Binlog_checkpoint # # master-bin.000001 +slave-relay-bin.000002 # Query # # use `test`; CREATE TABLE t1 (a INT) +slave-relay-bin.000002 # Query # # BEGIN +slave-relay-bin.000002 # Table_map # # table_id: # (test.t1) +slave-relay-bin.000002 # Write_rows # # table_id: # flags: STMT_END_F +slave-relay-bin.000002 # Query # # COMMIT +slave-relay-bin.000002 # Query # # BEGIN +slave-relay-bin.000002 # Table_map # # table_id: # (test.t1) +slave-relay-bin.000002 # Write_rows # # table_id: # flags: STMT_END_F +slave-relay-bin.000002 # Query # # COMMIT +slave-relay-bin.000002 # Query # # BEGIN +slave-relay-bin.000002 # Table_map # # table_id: # (test.t1) +slave-relay-bin.000002 # Write_rows # # table_id: # flags: STMT_END_F +slave-relay-bin.000002 # Query # # COMMIT ******** [slave] SHOW RELAYLOG EVENTS IN LIMIT 1 ******** -show relaylog events in 'slave-relay-bin.000003' from limit 1; +show relaylog events in 'slave-relay-bin.000002' from limit 1; Log_name Pos Event_type Server_id End_log_pos Info -slave-relay-bin.000003 # Rotate # # master-bin.000001;pos=4 +slave-relay-bin.000002 # Rotate # # master-bin.000001;pos=4 ******** [slave] SHOW RELAYLOG EVENTS IN LIMIT 1,3 ******** -show relaylog events in 'slave-relay-bin.000003' from limit 1,3; +show relaylog events in 'slave-relay-bin.000002' from limit 1,3; Log_name Pos Event_type Server_id End_log_pos Info -slave-relay-bin.000003 # Format_desc # # SERVER_VERSION, BINLOG_VERSION -slave-relay-bin.000003 # Binlog_checkpoint # # master-bin.000001 -slave-relay-bin.000003 # Query # # use `test`; CREATE TABLE t1 (a INT) +slave-relay-bin.000002 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +slave-relay-bin.000002 # Binlog_checkpoint # # master-bin.000001 +slave-relay-bin.000002 # Query # # use `test`; CREATE TABLE t1 (a INT) ******** [slave] SHOW RELAYLOG EVENTS ******** show relaylog events from ; Log_name Pos Event_type Server_id End_log_pos Info -slave-relay-bin.000002 # Rotate # # slave-relay-bin.000003;pos=4 +slave-relay-bin.000001 # Rotate # # slave-relay-bin.000002;pos=4 FLUSH LOGS; FLUSH LOGS; DROP TABLE t1; @@ -186,26 +186,26 @@ slave-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F slave-bin.000001 # Query # # COMMIT slave-bin.000001 # Rotate # # slave-bin.000002;pos=4 ******** [slave] SHOW RELAYLOG EVENTS IN ******** -show relaylog events in 'slave-relay-bin.000006' from ; +show relaylog events in 'slave-relay-bin.000005' from ; Log_name Pos Event_type Server_id End_log_pos Info -slave-relay-bin.000006 # Rotate # # master-bin.000002;pos=4 -slave-relay-bin.000006 # Format_desc # # SERVER_VERSION, BINLOG_VERSION -slave-relay-bin.000006 # Binlog_checkpoint # # master-bin.000001 -slave-relay-bin.000006 # Binlog_checkpoint # # master-bin.000002 -slave-relay-bin.000006 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ +slave-relay-bin.000005 # Rotate # # master-bin.000002;pos=4 +slave-relay-bin.000005 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +slave-relay-bin.000005 # Binlog_checkpoint # # master-bin.000001 +slave-relay-bin.000005 # Binlog_checkpoint # # master-bin.000002 +slave-relay-bin.000005 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ ******** [slave] SHOW RELAYLOG EVENTS IN LIMIT 1 ******** -show relaylog events in 'slave-relay-bin.000006' from limit 1; +show relaylog events in 'slave-relay-bin.000005' from limit 1; Log_name Pos Event_type Server_id End_log_pos Info -slave-relay-bin.000006 # Rotate # # master-bin.000002;pos=4 +slave-relay-bin.000005 # Rotate # # master-bin.000002;pos=4 ******** [slave] SHOW RELAYLOG EVENTS IN LIMIT 1,3 ******** -show relaylog events in 'slave-relay-bin.000006' from limit 1,3; +show relaylog events in 'slave-relay-bin.000005' from limit 1,3; Log_name Pos Event_type Server_id End_log_pos Info -slave-relay-bin.000006 # Format_desc # # SERVER_VERSION, BINLOG_VERSION -slave-relay-bin.000006 # Binlog_checkpoint # # master-bin.000001 -slave-relay-bin.000006 # Binlog_checkpoint # # master-bin.000002 +slave-relay-bin.000005 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +slave-relay-bin.000005 # Binlog_checkpoint # # master-bin.000001 +slave-relay-bin.000005 # Binlog_checkpoint # # master-bin.000002 ******** [slave] SHOW RELAYLOG EVENTS ******** show relaylog events from ; Log_name Pos Event_type Server_id End_log_pos Info -slave-relay-bin.000005 # Rotate # # master-bin.000002;pos=4 -slave-relay-bin.000005 # Rotate # # slave-relay-bin.000006;pos=4 +slave-relay-bin.000004 # Rotate # # master-bin.000002;pos=4 +slave-relay-bin.000004 # Rotate # # slave-relay-bin.000005;pos=4 include/rpl_end.inc diff --git a/mysql-test/suite/rpl/r/rpl_stm_mix_show_relaylog_events.result b/mysql-test/suite/rpl/r/rpl_stm_mix_show_relaylog_events.result index 2c93a15a7b3..490c4998b5d 100644 --- a/mysql-test/suite/rpl/r/rpl_stm_mix_show_relaylog_events.result +++ b/mysql-test/suite/rpl/r/rpl_stm_mix_show_relaylog_events.result @@ -78,35 +78,35 @@ slave-bin.000001 # Query # # BEGIN slave-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (3) slave-bin.000001 # Query # # COMMIT ******** [slave] SHOW RELAYLOG EVENTS IN ******** -show relaylog events in 'slave-relay-bin.000003' from ; +show relaylog events in 'slave-relay-bin.000002' from ; Log_name Pos Event_type Server_id End_log_pos Info -slave-relay-bin.000003 # Rotate # # master-bin.000001;pos=4 -slave-relay-bin.000003 # Format_desc # # SERVER_VERSION, BINLOG_VERSION -slave-relay-bin.000003 # Binlog_checkpoint # # master-bin.000001 -slave-relay-bin.000003 # Query # # use `test`; CREATE TABLE t1 (a INT) -slave-relay-bin.000003 # Query # # BEGIN -slave-relay-bin.000003 # Query # # use `test`; INSERT INTO t1 VALUES (1) -slave-relay-bin.000003 # Query # # COMMIT -slave-relay-bin.000003 # Query # # BEGIN -slave-relay-bin.000003 # Query # # use `test`; INSERT INTO t1 VALUES (2) -slave-relay-bin.000003 # Query # # COMMIT -slave-relay-bin.000003 # Query # # BEGIN -slave-relay-bin.000003 # Query # # use `test`; INSERT INTO t1 VALUES (3) -slave-relay-bin.000003 # Query # # COMMIT +slave-relay-bin.000002 # Rotate # # master-bin.000001;pos=4 +slave-relay-bin.000002 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +slave-relay-bin.000002 # Binlog_checkpoint # # master-bin.000001 +slave-relay-bin.000002 # Query # # use `test`; CREATE TABLE t1 (a INT) +slave-relay-bin.000002 # Query # # BEGIN +slave-relay-bin.000002 # Query # # use `test`; INSERT INTO t1 VALUES (1) +slave-relay-bin.000002 # Query # # COMMIT +slave-relay-bin.000002 # Query # # BEGIN +slave-relay-bin.000002 # Query # # use `test`; INSERT INTO t1 VALUES (2) +slave-relay-bin.000002 # Query # # COMMIT +slave-relay-bin.000002 # Query # # BEGIN +slave-relay-bin.000002 # Query # # use `test`; INSERT INTO t1 VALUES (3) +slave-relay-bin.000002 # Query # # COMMIT ******** [slave] SHOW RELAYLOG EVENTS IN LIMIT 1 ******** -show relaylog events in 'slave-relay-bin.000003' from limit 1; +show relaylog events in 'slave-relay-bin.000002' from limit 1; Log_name Pos Event_type Server_id End_log_pos Info -slave-relay-bin.000003 # Rotate # # master-bin.000001;pos=4 +slave-relay-bin.000002 # Rotate # # master-bin.000001;pos=4 ******** [slave] SHOW RELAYLOG EVENTS IN LIMIT 1,3 ******** -show relaylog events in 'slave-relay-bin.000003' from limit 1,3; +show relaylog events in 'slave-relay-bin.000002' from limit 1,3; Log_name Pos Event_type Server_id End_log_pos Info -slave-relay-bin.000003 # Format_desc # # SERVER_VERSION, BINLOG_VERSION -slave-relay-bin.000003 # Binlog_checkpoint # # master-bin.000001 -slave-relay-bin.000003 # Query # # use `test`; CREATE TABLE t1 (a INT) +slave-relay-bin.000002 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +slave-relay-bin.000002 # Binlog_checkpoint # # master-bin.000001 +slave-relay-bin.000002 # Query # # use `test`; CREATE TABLE t1 (a INT) ******** [slave] SHOW RELAYLOG EVENTS ******** show relaylog events from ; Log_name Pos Event_type Server_id End_log_pos Info -slave-relay-bin.000002 # Rotate # # slave-relay-bin.000003;pos=4 +slave-relay-bin.000001 # Rotate # # slave-relay-bin.000002;pos=4 FLUSH LOGS; FLUSH LOGS; DROP TABLE t1; @@ -165,26 +165,26 @@ slave-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (3) slave-bin.000001 # Query # # COMMIT slave-bin.000001 # Rotate # # slave-bin.000002;pos=4 ******** [slave] SHOW RELAYLOG EVENTS IN ******** -show relaylog events in 'slave-relay-bin.000006' from ; +show relaylog events in 'slave-relay-bin.000005' from ; Log_name Pos Event_type Server_id End_log_pos Info -slave-relay-bin.000006 # Rotate # # master-bin.000002;pos=4 -slave-relay-bin.000006 # Format_desc # # SERVER_VERSION, BINLOG_VERSION -slave-relay-bin.000006 # Binlog_checkpoint # # master-bin.000001 -slave-relay-bin.000006 # Binlog_checkpoint # # master-bin.000002 -slave-relay-bin.000006 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ +slave-relay-bin.000005 # Rotate # # master-bin.000002;pos=4 +slave-relay-bin.000005 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +slave-relay-bin.000005 # Binlog_checkpoint # # master-bin.000001 +slave-relay-bin.000005 # Binlog_checkpoint # # master-bin.000002 +slave-relay-bin.000005 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ ******** [slave] SHOW RELAYLOG EVENTS IN LIMIT 1 ******** -show relaylog events in 'slave-relay-bin.000006' from limit 1; +show relaylog events in 'slave-relay-bin.000005' from limit 1; Log_name Pos Event_type Server_id End_log_pos Info -slave-relay-bin.000006 # Rotate # # master-bin.000002;pos=4 +slave-relay-bin.000005 # Rotate # # master-bin.000002;pos=4 ******** [slave] SHOW RELAYLOG EVENTS IN LIMIT 1,3 ******** -show relaylog events in 'slave-relay-bin.000006' from limit 1,3; +show relaylog events in 'slave-relay-bin.000005' from limit 1,3; Log_name Pos Event_type Server_id End_log_pos Info -slave-relay-bin.000006 # Format_desc # # SERVER_VERSION, BINLOG_VERSION -slave-relay-bin.000006 # Binlog_checkpoint # # master-bin.000001 -slave-relay-bin.000006 # Binlog_checkpoint # # master-bin.000002 +slave-relay-bin.000005 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +slave-relay-bin.000005 # Binlog_checkpoint # # master-bin.000001 +slave-relay-bin.000005 # Binlog_checkpoint # # master-bin.000002 ******** [slave] SHOW RELAYLOG EVENTS ******** show relaylog events from ; Log_name Pos Event_type Server_id End_log_pos Info -slave-relay-bin.000005 # Rotate # # master-bin.000002;pos=4 -slave-relay-bin.000005 # Rotate # # slave-relay-bin.000006;pos=4 +slave-relay-bin.000004 # Rotate # # master-bin.000002;pos=4 +slave-relay-bin.000004 # Rotate # # slave-relay-bin.000005;pos=4 include/rpl_end.inc diff --git a/sql/log.cc b/sql/log.cc index 54340f94679..1f3c529f491 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -3598,11 +3598,11 @@ 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. - @param thd Thread + @param thd Thread + @param create_new_log 1 if we should start writing to a new log file @note If not called from slave thread, write start event to new log @@ -3613,7 +3613,7 @@ err: 1 error */ -bool MYSQL_BIN_LOG::reset_logs(THD* thd) +bool MYSQL_BIN_LOG::reset_logs(THD* thd, bool create_new_log) { LOG_INFO linfo; bool error=0; @@ -3780,7 +3780,7 @@ bool MYSQL_BIN_LOG::reset_logs(THD* thd) goto err; } } - if (!open_index_file(index_file_name, 0, FALSE)) + if (create_new_log && !open_index_file(index_file_name, 0, FALSE)) if ((error= open(save_name, log_type, 0, io_cache_type, max_size, 0, FALSE))) goto err; my_free((void *) save_name); diff --git a/sql/log.h b/sql/log.h index cd1845908ef..0ade3618fd7 100644 --- a/sql/log.h +++ b/sql/log.h @@ -748,7 +748,7 @@ public: int register_create_index_entry(const char* entry); int purge_index_entry(THD *thd, ulonglong *decrease_log_space, bool need_mutex); - bool reset_logs(THD* thd); + bool reset_logs(THD* thd, bool create_new_log); void close(uint exiting); void clear_inuse_flag_when_closing(File file); diff --git a/sql/rpl_mi.cc b/sql/rpl_mi.cc index 3dc3e38f419..366b271851a 100644 --- a/sql/rpl_mi.cc +++ b/sql/rpl_mi.cc @@ -657,7 +657,20 @@ void create_signed_file_name(char *res_file_name, uint length, Master_info_index::Master_info_index() { - index_file_name[0] = 0; + size_t filename_length, dir_length; + /* + Create the Master_info index file by prepending 'multi-' before + the master_info_file file name. + */ + fn_format(index_file_name, master_info_file, mysql_data_home, + "", MY_UNPACK_FILENAME); + filename_length= strlen(index_file_name) + 1; /* Count 0 byte */ + dir_length= dirname_length(index_file_name); + bmove_upp((uchar*) index_file_name + filename_length + 6, + (uchar*) index_file_name + filename_length, + filename_length - dir_length); + memcpy(index_file_name + dir_length, "multi-", 6); + bzero((char*) &index_file, sizeof(index_file)); } @@ -684,22 +697,8 @@ bool Master_info_index::init_all_master_info() int err_num= 0, succ_num= 0; // The number of success read Master_info char sign[MAX_CONNECTION_NAME]; File index_file_nr; - size_t filename_length, dir_length; DBUG_ENTER("init_all_master_info"); - /* - Create the Master_info index file by prepending 'multi-' before - the master_info_file file name. - */ - fn_format(index_file_name, master_info_file, mysql_data_home, - "", MY_UNPACK_FILENAME); - filename_length= strlen(index_file_name) + 1; /* Count 0 byte */ - dir_length= dirname_length(index_file_name); - bmove_upp((uchar*) index_file_name + filename_length + 6, - (uchar*) index_file_name + filename_length, - filename_length - dir_length); - memcpy(index_file_name + dir_length, "multi-", 6); - if ((index_file_nr= my_open(index_file_name, O_RDWR | O_CREAT | O_BINARY , MYF(MY_WME | ME_NOREFRESH))) < 0 || @@ -891,6 +890,10 @@ Master_info_index::get_master_info(LEX_STRING *connection_name, Master_info *mi; char buff[MAX_CONNECTION_NAME+1], *res; uint buff_length; + DBUG_ENTER("get_master_info"); + DBUG_PRINT("enter", + ("connection_name: '%.*s'", (int) connection_name->length, + connection_name->str)); /* Make name lower case for comparison */ res= strmake(buff, connection_name->str, connection_name->length); @@ -907,7 +910,7 @@ Master_info_index::get_master_info(LEX_STRING *connection_name, (int) connection_name->length, connection_name->str); } - return mi; + DBUG_RETURN(mi); } @@ -917,6 +920,7 @@ bool Master_info_index::check_duplicate_master_info(LEX_STRING *name_arg, uint port) { Master_info *mi; + DBUG_ENTER("check_duplicate_master_info"); /* Get full host and port name */ if ((mi= master_info_index->get_master_info(name_arg, @@ -928,7 +932,7 @@ bool Master_info_index::check_duplicate_master_info(LEX_STRING *name_arg, port= mi->port; } if (!host || !port) - return FALSE; // Not comparable yet + DBUG_RETURN(FALSE); // Not comparable yet for (uint i= 0; i < master_info_hash.records; ++i) { @@ -938,13 +942,15 @@ bool Master_info_index::check_duplicate_master_info(LEX_STRING *name_arg, continue; // Current connection if (!strcasecmp(host, tmp_mi->host) && port == tmp_mi->port) { - sql_print_error(ER(ER_CONNECTION_ALREADY_EXISTS), - (int) tmp_mi->connection_name.length, - tmp_mi->connection_name.str); - return TRUE; + my_error(ER_CONNECTION_ALREADY_EXISTS, MYF(0), + (int) name_arg->length, + name_arg->str, + (int) tmp_mi->connection_name.length, + tmp_mi->connection_name.str); + DBUG_RETURN(TRUE); } } - return FALSE; + DBUG_RETURN(FALSE); } @@ -994,9 +1000,6 @@ bool Master_info_index::remove_master_info(LEX_STRING *name) my_close(index_file.file, MYF(MY_WME)); // Reopen File and truncate it - fn_format(index_file_name, master_info_file, mysql_data_home, - ".index", MY_UNPACK_FILENAME | MY_APPEND_EXT); - if ((index_file_nr= my_open(index_file_name, O_RDWR | O_CREAT | O_TRUNC | O_BINARY , MYF(MY_WME))) < 0 || diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index 442a9895f6b..49c8390ff9b 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -1015,28 +1015,37 @@ int purge_relay_logs(Relay_log_info* rli, THD *thd, bool just_reset, rli->cur_log_fd= -1; } - if (rli->relay_log.reset_logs(thd)) + if (rli->relay_log.reset_logs(thd, !just_reset)) { *errmsg = "Failed during log reset"; error=1; goto err; } - /* Save name of used relay log file */ - strmake(rli->group_relay_log_name, rli->relay_log.get_log_fname(), - sizeof(rli->group_relay_log_name)-1); - strmake(rli->event_relay_log_name, rli->relay_log.get_log_fname(), - sizeof(rli->event_relay_log_name)-1); - rli->group_relay_log_pos= rli->event_relay_log_pos= BIN_LOG_HEADER_SIZE; - if (count_relay_log_space(rli)) - { - *errmsg= "Error counting relay log space"; - error=1; - goto err; - } if (!just_reset) + { + /* Save name of used relay log file */ + strmake(rli->group_relay_log_name, rli->relay_log.get_log_fname(), + sizeof(rli->group_relay_log_name)-1); + strmake(rli->event_relay_log_name, rli->relay_log.get_log_fname(), + sizeof(rli->event_relay_log_name)-1); + rli->group_relay_log_pos= rli->event_relay_log_pos= BIN_LOG_HEADER_SIZE; + rli->log_space_total= 0; + + if (count_relay_log_space(rli)) + { + *errmsg= "Error counting relay log space"; + error=1; + goto err; + } error= init_relay_log_pos(rli, rli->group_relay_log_name, rli->group_relay_log_pos, 0 /* do not need data lock */, errmsg, 0); + } + else + { + /* Ensure relay log names are not used */ + rli->group_relay_log_name[0]= rli->event_relay_log_name[0]= 0; + } err: #ifndef DBUG_OFF diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index bb5506756e1..803575b7ba0 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -6589,7 +6589,6 @@ ER_NO_SUCH_TABLE_IN_ENGINE 42S02 eng "Table '%-.192s.%-.192s' doesn't exist in engine" swe "Det finns ingen tabell som heter '%-.192s.%-.192s' i handlern" ER_CONNECTION_ALREADY_EXISTS - eng "Connection '%.*s' already exists" + eng "Connection '%.*s' conflicts with existing connection '%.*s'" ER_MASTER_LOG_PREFIX eng "Master '%.*s': " - diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 114035bc16d..831931e1ef2 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2377,6 +2377,7 @@ case SQLCOM_PREPARE: work. */ master_info_index->remove_master_info(&lex_mi->connection_name); + delete mi; } mysql_mutex_unlock(&LOCK_active_mi); diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 036afb45a19..ed00fcaaddf 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -1682,12 +1682,7 @@ bool change_master(THD* thd, Master_info* mi) if (master_info_index->check_duplicate_master_info(&lex_mi->connection_name, lex_mi->host, lex_mi->port)) - { - my_error(ER_MASTER_INFO, MYF(0), - (int) lex_mi->connection_name.length, - lex_mi->connection_name.str); DBUG_RETURN(TRUE); - } lock_slave_threads(mi); init_thread_mask(&thread_mask,mi,0 /*not inverse*/); @@ -1996,7 +1991,7 @@ int reset_master(THD* thd) return 1; } - if (mysql_bin_log.reset_logs(thd)) + if (mysql_bin_log.reset_logs(thd, 1)) return 1; RUN_HOOK(binlog_transmit, after_reset_master, (thd, 0 /* flags */)); return 0; From 8ac1b41cf358029b8e08e977f45bb6197a1c1c19 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Mon, 1 Oct 2012 02:30:44 +0300 Subject: [PATCH 278/289] Made max_relay_log_size depending on master connection. Changed names of multi-source log files so that original suffixes are kept. include/my_sys.h: Added fn_ext2(), which returns pointer to last '.' in file name mysql-test/extra/rpl_tests/rpl_max_relay_size.test: Updated test mysql-test/suite/multi_source/info_logs-master.opt: Test with strange file names mysql-test/suite/multi_source/info_logs.result: Updated results mysql-test/suite/multi_source/info_logs.test: Changed to test with complex names to be able to verify the filename generator code mysql-test/suite/multi_source/relaylog_events.result: Updated results mysql-test/suite/multi_source/reset_slave.result: Updated results mysql-test/suite/multi_source/skip_counter.result: Updated results mysql-test/suite/multi_source/skip_counter.test: Added testing of max_relay_log_size mysql-test/suite/rpl/r/rpl_row_max_relay_size.result: Updated results mysql-test/suite/rpl/r/rpl_stm_max_relay_size.result: Updated results mysql-test/suite/sys_vars/r/max_relay_log_size_basic.result: Updated results mysql-test/suite/sys_vars/t/max_relay_log_size_basic.test: Updated results mysys/mf_fn_ext.c: Added fn_ext2(), which returns pointer to last '.' in file name sql/log.cc: Removed some wrong casts sql/log.h: Updated comment to reflect new code sql/log_event.cc: Updated DBUG_PRINT sql/mysqld.cc: Added that max_relay_log_size copies it's values from max_binlog_size sql/mysqld.h: Removed max_relay_log_size sql/rpl_mi.cc: Changed names of multi-source log files so that original suffixes are kept. sql/rpl_mi.h: Updated prototype sql/rpl_rli.cc: Updated comment to reflect new code Made max_relay_log_size depending on master connection. sql/rpl_rli.h: Made max_relay_log_size depending on master connection. sql/set_var.h: Made option global so that one can check and change min & max values (sorry Sergei) sql/sql_class.h: Made max_relay_log_size depending on master connection. sql/sql_repl.cc: Updated calls to create_signed_file_name() sql/sys_vars.cc: Made max_relay_log_size depending on master connection. Made old code more reusable sql/sys_vars.h: Changed Sys_var_multi_source_uint to ulong to be able to handle max_relay_log_size Made old code more reusable --- include/my_sys.h | 1 + .../extra/rpl_tests/rpl_max_relay_size.test | 3 +- .../suite/multi_source/info_logs-master.opt | 1 + .../suite/multi_source/info_logs.result | 60 +++++++------- mysql-test/suite/multi_source/info_logs.test | 16 ++-- .../suite/multi_source/relaylog_events.result | 1 + .../suite/multi_source/reset_slave.result | 2 +- .../suite/multi_source/skip_counter.result | 45 ++++++++++ .../suite/multi_source/skip_counter.test | 29 ++++++- .../suite/rpl/r/rpl_row_max_relay_size.result | 7 +- .../suite/rpl/r/rpl_stm_max_relay_size.result | 7 +- .../r/max_relay_log_size_basic.result | 29 ++++--- .../sys_vars/t/max_relay_log_size_basic.test | 3 - mysys/mf_fn_ext.c | 37 +++++++++ sql/log.cc | 4 +- sql/log.h | 5 +- sql/log_event.cc | 6 +- sql/mysqld.cc | 24 +++++- sql/mysqld.h | 2 +- sql/rpl_mi.cc | 38 ++++++--- sql/rpl_mi.h | 2 +- sql/rpl_rli.cc | 17 +--- sql/rpl_rli.h | 3 +- sql/set_var.h | 3 +- sql/sql_class.h | 5 +- sql/sql_repl.cc | 12 +-- sql/sys_vars.cc | 83 ++++++++++--------- sql/sys_vars.h | 42 ++++++---- 28 files changed, 326 insertions(+), 161 deletions(-) create mode 100644 mysql-test/suite/multi_source/info_logs-master.opt diff --git a/include/my_sys.h b/include/my_sys.h index 1d666cb4a60..336b5635dd8 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -679,6 +679,7 @@ extern my_bool has_path(const char *name); extern char *convert_dirname(char *to, const char *from, const char *from_end); extern void to_unix_path(char * name); extern char * fn_ext(const char *name); +extern char * fn_ext2(const char *name); extern char * fn_same(char * toname,const char *name,int flag); extern char * fn_format(char * to,const char *name,const char *dir, const char *form, uint flag); diff --git a/mysql-test/extra/rpl_tests/rpl_max_relay_size.test b/mysql-test/extra/rpl_tests/rpl_max_relay_size.test index d8cd4f2d284..0fcff5ebe6c 100644 --- a/mysql-test/extra/rpl_tests/rpl_max_relay_size.test +++ b/mysql-test/extra/rpl_tests/rpl_max_relay_size.test @@ -34,7 +34,7 @@ reset slave; --echo # Test 1 --echo # -set @my_max_binlog_size= @@global.max_binlog_size; +set @my_max_binlog_size= @@global.max_binlog_size, @my_max_relay_log_size=@@global.max_relay_log_size; set global max_binlog_size=8192; set global max_relay_log_size=8192-1; # mapped to 4096 select @@global.max_relay_log_size; @@ -110,6 +110,7 @@ source include/show_master_status.inc; # Restore max_binlog_size connection slave; set global max_binlog_size= @my_max_binlog_size; +set global max_relay_log_size= @my_max_relay_log_size; --echo # --echo # End of 4.1 tests diff --git a/mysql-test/suite/multi_source/info_logs-master.opt b/mysql-test/suite/multi_source/info_logs-master.opt new file mode 100644 index 00000000000..da4e6d3c455 --- /dev/null +++ b/mysql-test/suite/multi_source/info_logs-master.opt @@ -0,0 +1 @@ +--relay-log=relay.bin --relay-log-info=relay.bin.info diff --git a/mysql-test/suite/multi_source/info_logs.result b/mysql-test/suite/multi_source/info_logs.result index 4947244068a..1da44992ec6 100644 --- a/mysql-test/suite/multi_source/info_logs.result +++ b/mysql-test/suite/multi_source/info_logs.result @@ -15,35 +15,35 @@ set default_master_connection = 'master1'; include/wait_for_slave_to_start.inc # # List of files matching '*info*' pattern while 'master1' is running -master.info.master1 +master-master1.info multi-master.info -relay-log.info.master1 +relay.bin-master1.info # End of list # # Contents of multi-master.info master1 # EOF # -change master 'master2' to +change master 'MASTER 2.2' to master_port=MYPORT_2, master_host='127.0.0.1', master_user='root'; -start slave 'master2'; -set default_master_connection = 'master2'; +start slave 'MASTER 2.2'; +set default_master_connection = 'MASTER 2.2'; include/wait_for_slave_to_start.inc # # List of files matching '*info*' pattern -# while 'master1' and 'master2' are running -master.info.master1 -master.info.master2 +# while 'master1' and 'MASTER 2.2' are running +master-master1.info +master-master@00202@002e2.info multi-master.info -relay-log.info.master1 -relay-log.info.master2 +relay.bin-master1.info +relay.bin-master@00202@002e2.info # End of list # # Contents of multi-master.info master1 -master2 +MASTER 2.2 # EOF # stop slave 'master1'; @@ -52,14 +52,14 @@ include/wait_for_slave_to_stop.inc reset slave 'master1' all; # # List of files matching '*info*' pattern -# after 'master1' was completely reset, 'master2' still running -master.info.master2 +# after 'master1' was completely reset, 'MASTER 2.2' still running +master-master@00202@002e2.info multi-master.info -relay-log.info.master2 +relay.bin-master@00202@002e2.info # End of list # # Contents of multi-master.info -master2 +MASTER 2.2 # EOF # set default_master_connection = ''; @@ -71,44 +71,44 @@ start slave; include/wait_for_slave_to_start.inc # # List of files matching '*info*' pattern -# while 'master2' and '' are running +# while 'MASTER 2.2' and '' are running +master-master@00202@002e2.info master.info -master.info.master2 multi-master.info -relay-log.info -relay-log.info.master2 +relay.bin-master@00202@002e2.info +relay.bin.info # End of list # # Contents of multi-master.info -master2 +MASTER 2.2 # EOF # show full slave status; Connection_name 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 Replicate_Ignore_Server_Ids Master_Server_Id - Waiting for master to send event 127.0.0.1 root MYPORT_1 60 master-bin.000001 286 mysqld-relay-bin.000002 572 master-bin.000001 Yes Yes 0 0 286 868 None 0 No 0 No 0 0 1 -master2 Waiting for master to send event 127.0.0.1 root MYPORT_2 60 master-bin.000001 286 mysqld-relay-bin-master2.000002 572 master-bin.000001 Yes Yes 0 0 286 876 None 0 No 0 No 0 0 2 + Waiting for master to send event 127.0.0.1 root MYPORT_1 60 master-bin.000001 286 relay.000002 572 master-bin.000001 Yes Yes 0 0 286 857 None 0 No 0 No 0 0 1 +MASTER 2.2 Waiting for master to send event 127.0.0.1 root MYPORT_2 60 master-bin.000001 286 relay-master@00202@002e2.000002 572 master-bin.000001 Yes Yes 0 0 286 876 None 0 No 0 No 0 0 2 show full slave status; Connection_name 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 Replicate_Ignore_Server_Ids Master_Server_Id - Waiting for master to send event 127.0.0.1 root MYPORT_1 60 master-bin.000001 286 mysqld-relay-bin.000004 532 master-bin.000001 Yes Yes 0 0 286 828 None 0 No 0 No 0 0 1 -master2 Waiting for master to send event 127.0.0.1 root MYPORT_2 60 master-bin.000001 286 mysqld-relay-bin-master2.000004 532 master-bin.000001 Yes Yes 0 0 286 836 None 0 No 0 No 0 0 2 + Waiting for master to send event 127.0.0.1 root MYPORT_1 60 master-bin.000001 286 relay.000004 532 master-bin.000001 Yes Yes 0 0 286 817 None 0 No 0 No 0 0 1 +MASTER 2.2 Waiting for master to send event 127.0.0.1 root MYPORT_2 60 master-bin.000001 286 relay-master@00202@002e2.000004 532 master-bin.000001 Yes Yes 0 0 286 836 None 0 No 0 No 0 0 2 # # List of files matching '*info*' pattern # after slave server restart -# while 'master2' and '' are running +# while 'MASTER 2.2' and '' are running +master-master@00202@002e2.info master.info -master.info.master2 multi-master.info -relay-log.info -relay-log.info.master2 +relay.bin-master@00202@002e2.info +relay.bin.info # End of list # # Contents of multi-master.info -master2 +MASTER 2.2 # EOF # stop slave; include/wait_for_slave_to_stop.inc -set default_master_connection = 'master2'; +set default_master_connection = 'MASTER 2.2'; stop slave; include/wait_for_slave_to_stop.inc reset slave all; diff --git a/mysql-test/suite/multi_source/info_logs.test b/mysql-test/suite/multi_source/info_logs.test index 40e1b481d2c..f06880faca6 100644 --- a/mysql-test/suite/multi_source/info_logs.test +++ b/mysql-test/suite/multi_source/info_logs.test @@ -47,20 +47,20 @@ set default_master_connection = 'master1'; # Start replication from the second master --replace_result $SERVER_MYPORT_2 MYPORT_2 -eval change master 'master2' to +eval change master 'MASTER 2.2' to master_port=$SERVER_MYPORT_2, master_host='127.0.0.1', master_user='root'; -start slave 'master2'; -set default_master_connection = 'master2'; +start slave 'MASTER 2.2'; +set default_master_connection = 'MASTER 2.2'; --source include/wait_for_slave_to_start.inc # Check the files --echo # --echo # List of files matching '*info*' pattern ---echo # while 'master1' and 'master2' are running +--echo # while 'master1' and 'MASTER 2.2' are running --list_files $datadir *info* --echo # End of list --echo # @@ -80,7 +80,7 @@ reset slave 'master1' all; --echo # --echo # List of files matching '*info*' pattern ---echo # after 'master1' was completely reset, 'master2' still running +--echo # after 'master1' was completely reset, 'MASTER 2.2' still running --list_files $datadir *info* --echo # End of list --echo # @@ -106,7 +106,7 @@ start slave; --echo # --echo # List of files matching '*info*' pattern ---echo # while 'master2' and '' are running +--echo # while 'MASTER 2.2' and '' are running --list_files $datadir *info* --echo # End of list --echo # @@ -136,7 +136,7 @@ show full slave status; --echo # --echo # List of files matching '*info*' pattern --echo # after slave server restart ---echo # while 'master2' and '' are running +--echo # while 'MASTER 2.2' and '' are running --list_files $datadir *info* --echo # End of list --echo # @@ -151,7 +151,7 @@ show full slave status; stop slave; --source include/wait_for_slave_to_stop.inc -set default_master_connection = 'master2'; +set default_master_connection = 'MASTER 2.2'; stop slave; --source include/wait_for_slave_to_stop.inc reset slave all; diff --git a/mysql-test/suite/multi_source/relaylog_events.result b/mysql-test/suite/multi_source/relaylog_events.result index a91ae82970b..437dc87788a 100644 --- a/mysql-test/suite/multi_source/relaylog_events.result +++ b/mysql-test/suite/multi_source/relaylog_events.result @@ -9,6 +9,7 @@ drop table if exists t1; create table t1 (i int) engine=MyISAM; mysqld-relay-bin-master1.000001 mysqld-relay-bin-master1.000002 +mysqld-relay-bin-master1.index show relaylog events in 'mysqld-relay-bin-master1.000002'; Log_name Pos Event_type Server_id End_log_pos Info mysqld-relay-bin-master1.000002 4 Format_desc 3 246 Server version diff --git a/mysql-test/suite/multi_source/reset_slave.result b/mysql-test/suite/multi_source/reset_slave.result index a1256988bbf..ab59f54315a 100644 --- a/mysql-test/suite/multi_source/reset_slave.result +++ b/mysql-test/suite/multi_source/reset_slave.result @@ -14,7 +14,7 @@ Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File 127.0.0.1 root MYPORT_1 60 master-bin.000001 729 mysqld-relay-bin-master1.000002 1015 master-bin.000001 No No 0 0 729 1319 None 0 No NULL No 0 0 1 mysqld-relay-bin-master1.000001 mysqld-relay-bin-master1.000002 -mysqld-relay-bin.index-master1 +mysqld-relay-bin-master1.index reset slave 'master1'; show slave 'master1' 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 Replicate_Ignore_Server_Ids Master_Server_Id diff --git a/mysql-test/suite/multi_source/skip_counter.result b/mysql-test/suite/multi_source/skip_counter.result index 1fb1c255d80..51ad36c4ee8 100644 --- a/mysql-test/suite/multi_source/skip_counter.result +++ b/mysql-test/suite/multi_source/skip_counter.result @@ -55,6 +55,49 @@ set default_master_connection = 'master2'; select @@session.sql_slave_skip_counter; @@session.sql_slave_skip_counter 3 +select @@global.max_relay_log_size; +@@global.max_relay_log_size +1073741824 +set global max_relay_log_size = 1*1024*1024; +select @@global.max_relay_log_size; +@@global.max_relay_log_size +1048576 +select @@session.max_relay_log_size; +@@session.max_relay_log_size +1048576 +set session max_relay_log_size = 3*1024*1024; +select @@global.max_relay_log_size; +@@global.max_relay_log_size +3145728 +select @@session.max_relay_log_size; +@@session.max_relay_log_size +3145728 +set global max_relay_log_size= default; +select @@global.max_relay_log_size; +@@global.max_relay_log_size +1073741824 +select @@session.max_relay_log_size; +@@session.max_relay_log_size +1073741824 +set global max_relay_log_size= 3*1024*1024; +set default_master_connection = 'master1'; +select @@session.max_relay_log_size; +@@session.max_relay_log_size +1073741824 +set default_master_connection = 'qqq'; +select @@session.max_relay_log_size; +@@session.max_relay_log_size +0 +Warnings: +Warning 1617 There is no master connection 'qqq' +set default_master_connection = 'master2'; +select @@session.max_relay_log_size; +@@session.max_relay_log_size +3145728 +set global max_binlog_size= 4*1024*1024; +select @@global.max_relay_log_size; +@@global.max_relay_log_size +3145728 start slave 'master2'; include/wait_for_slave_to_start.inc set default_master_connection = ''; @@ -72,6 +115,8 @@ set default_master_connection = 'master2'; stop slave; include/wait_for_slave_to_stop.inc set global sql_slave_skip_counter = 0; +set global max_relay_log_size = 1073741824; +set global max_binlog_size = 1073741824; disconnect slave; connection master1; drop database db; diff --git a/mysql-test/suite/multi_source/skip_counter.test b/mysql-test/suite/multi_source/skip_counter.test index fe5df69097a..ceb7eb93f0f 100644 --- a/mysql-test/suite/multi_source/skip_counter.test +++ b/mysql-test/suite/multi_source/skip_counter.test @@ -1,5 +1,5 @@ # -# Test of sql_slave_skip_counter +# Test of sql_slave_skip_counter and rpl_max_size # --enable_connect_log @@ -16,7 +16,6 @@ create database db; create table db.t1 (i int) engine=MyISAM; --save_master_pos - # Create the same schema and another table # on the 2nd master @@ -62,6 +61,8 @@ master_user='root'; # to modify the test later --let $skip_counter_saved = `select @@global.sql_slave_skip_counter` +--let $max_relay_log_size_saved= `select @@global.max_relay_log_size` +--let $max_binlog_size_saved= `select @@global.max_binlog_size` set global sql_slave_skip_counter = 2; select @@global.sql_slave_skip_counter; select @@session.sql_slave_skip_counter; @@ -79,6 +80,28 @@ select @@session.sql_slave_skip_counter; set default_master_connection = 'master2'; select @@session.sql_slave_skip_counter; +# Test of setting max_relay_log_size +select @@global.max_relay_log_size; +set global max_relay_log_size = 1*1024*1024; +select @@global.max_relay_log_size; +select @@session.max_relay_log_size; +set session max_relay_log_size = 3*1024*1024; +select @@global.max_relay_log_size; +select @@session.max_relay_log_size; +set global max_relay_log_size= default; +select @@global.max_relay_log_size; +select @@session.max_relay_log_size; +set global max_relay_log_size= 3*1024*1024; +set default_master_connection = 'master1'; +select @@session.max_relay_log_size; +set default_master_connection = 'qqq'; +select @@session.max_relay_log_size; +set default_master_connection = 'master2'; +select @@session.max_relay_log_size; +set global max_binlog_size= 4*1024*1024; +select @@global.max_relay_log_size; + + start slave 'master2'; --source include/wait_for_slave_to_start.inc set default_master_connection = ''; @@ -113,6 +136,8 @@ stop slave; --source include/wait_for_slave_to_stop.inc --eval set global sql_slave_skip_counter = $skip_counter_saved +--eval set global max_relay_log_size = $max_relay_log_size_saved +--eval set global max_binlog_size = $max_binlog_size_saved --enable_connect_log --disconnect slave diff --git a/mysql-test/suite/rpl/r/rpl_row_max_relay_size.result b/mysql-test/suite/rpl/r/rpl_row_max_relay_size.result index 379cea4d3fc..88d68bb50ee 100644 --- a/mysql-test/suite/rpl/r/rpl_row_max_relay_size.result +++ b/mysql-test/suite/rpl/r/rpl_row_max_relay_size.result @@ -10,7 +10,7 @@ reset slave; # # Test 1 # -set @my_max_binlog_size= @@global.max_binlog_size; +set @my_max_binlog_size= @@global.max_binlog_size, @my_max_relay_log_size=@@global.max_relay_log_size; set global max_binlog_size=8192; set global max_relay_log_size=8192-1; Warnings: @@ -36,8 +36,10 @@ include/check_slave_is_running.inc stop slave; reset slave; set global max_relay_log_size=0; +Warnings: +Warning 1292 Truncated incorrect max_relay_log_size value: '0' select @@global.max_relay_log_size; -@@global.max_relay_log_size 0 +@@global.max_relay_log_size 4096 start slave; include/check_slave_is_running.inc # @@ -65,6 +67,7 @@ show master status; File Position Binlog_Do_DB Binlog_Ignore_DB master-bin.000002 # set global max_binlog_size= @my_max_binlog_size; +set global max_relay_log_size= @my_max_relay_log_size; # # End of 4.1 tests # diff --git a/mysql-test/suite/rpl/r/rpl_stm_max_relay_size.result b/mysql-test/suite/rpl/r/rpl_stm_max_relay_size.result index 379cea4d3fc..88d68bb50ee 100644 --- a/mysql-test/suite/rpl/r/rpl_stm_max_relay_size.result +++ b/mysql-test/suite/rpl/r/rpl_stm_max_relay_size.result @@ -10,7 +10,7 @@ reset slave; # # Test 1 # -set @my_max_binlog_size= @@global.max_binlog_size; +set @my_max_binlog_size= @@global.max_binlog_size, @my_max_relay_log_size=@@global.max_relay_log_size; set global max_binlog_size=8192; set global max_relay_log_size=8192-1; Warnings: @@ -36,8 +36,10 @@ include/check_slave_is_running.inc stop slave; reset slave; set global max_relay_log_size=0; +Warnings: +Warning 1292 Truncated incorrect max_relay_log_size value: '0' select @@global.max_relay_log_size; -@@global.max_relay_log_size 0 +@@global.max_relay_log_size 4096 start slave; include/check_slave_is_running.inc # @@ -65,6 +67,7 @@ show master status; File Position Binlog_Do_DB Binlog_Ignore_DB master-bin.000002 # set global max_binlog_size= @my_max_binlog_size; +set global max_relay_log_size= @my_max_relay_log_size; # # End of 4.1 tests # diff --git a/mysql-test/suite/sys_vars/r/max_relay_log_size_basic.result b/mysql-test/suite/sys_vars/r/max_relay_log_size_basic.result index d61e9dd20b0..6025e28ccaa 100644 --- a/mysql-test/suite/sys_vars/r/max_relay_log_size_basic.result +++ b/mysql-test/suite/sys_vars/r/max_relay_log_size_basic.result @@ -1,7 +1,7 @@ SET @start_value = @@global.max_relay_log_size; SELECT @start_value; @start_value -0 +1073741824 '#--------------------FN_DYNVARS_082_01------------------------#' SET @@global.max_relay_log_size = 5000; Warnings: @@ -9,7 +9,7 @@ Warning 1292 Truncated incorrect max_relay_log_size value: '5000' SET @@global.max_relay_log_size = DEFAULT; SELECT @@global.max_relay_log_size; @@global.max_relay_log_size -0 +1073741824 '#---------------------FN_DYNVARS_082_02-------------------------#' SET @@global.max_relay_log_size = @start_value; SELECT @@global.max_relay_log_size = 1024; @@ -17,15 +17,17 @@ SELECT @@global.max_relay_log_size = 1024; 0 '#--------------------FN_DYNVARS_082_03------------------------#' SET @@global.max_relay_log_size = 0; +Warnings: +Warning 1292 Truncated incorrect max_relay_log_size value: '0' SELECT @@global.max_relay_log_size; @@global.max_relay_log_size -0 +4096 SET @@global.max_relay_log_size = 1; Warnings: Warning 1292 Truncated incorrect max_relay_log_size value: '1' SELECT @@global.max_relay_log_size; @@global.max_relay_log_size -0 +4096 SET @@global.max_relay_log_size = 1073741824; SELECT @@global.max_relay_log_size; @@global.max_relay_log_size @@ -48,7 +50,7 @@ Warnings: Warning 1292 Truncated incorrect max_relay_log_size value: '-1' SELECT @@global.max_relay_log_size; @@global.max_relay_log_size -0 +4096 SET @@global.max_relay_log_size = 100000000000; Warnings: Warning 1292 Truncated incorrect max_relay_log_size value: '100000000000' @@ -65,7 +67,7 @@ Warnings: Warning 1292 Truncated incorrect max_relay_log_size value: '-1024' SELECT @@global.max_relay_log_size; @@global.max_relay_log_size -0 +4096 SET @@global.max_relay_log_size = 1073741825; Warnings: Warning 1292 Truncated incorrect max_relay_log_size value: '1073741825' @@ -90,9 +92,9 @@ SELECT @@global.max_relay_log_size; 1073741824 '#-------------------FN_DYNVARS_082_05----------------------------#' SET @@session.max_relay_log_size = 4096; -ERROR HY000: Variable 'max_relay_log_size' is a GLOBAL variable and should be set with SET GLOBAL SELECT @@session.max_relay_log_size; -ERROR HY000: Variable 'max_relay_log_size' is a GLOBAL variable +@@session.max_relay_log_size +4096 '#----------------------FN_DYNVARS_082_06------------------------#' SELECT @@global.max_relay_log_size = VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES @@ -110,11 +112,13 @@ Warnings: Warning 1292 Truncated incorrect max_relay_log_size value: '1' SELECT @@global.max_relay_log_size; @@global.max_relay_log_size -0 +4096 SET @@global.max_relay_log_size = FALSE; +Warnings: +Warning 1292 Truncated incorrect max_relay_log_size value: '0' SELECT @@global.max_relay_log_size; @@global.max_relay_log_size -0 +4096 '#---------------------FN_DYNVARS_082_08----------------------#' SET @@global.max_relay_log_size = 5000; Warnings: @@ -124,7 +128,8 @@ SELECT @@max_relay_log_size = @@global.max_relay_log_size; 1 '#---------------------FN_DYNVARS_082_09----------------------#' SET max_relay_log_size = 6000; -ERROR HY000: Variable 'max_relay_log_size' is a GLOBAL variable and should be set with SET GLOBAL +Warnings: +Warning 1292 Truncated incorrect max_relay_log_size value: '6000' SELECT @@max_relay_log_size; @@max_relay_log_size 4096 @@ -141,4 +146,4 @@ ERROR 42S22: Unknown column 'max_relay_log_size' in 'field list' SET @@global.max_relay_log_size = @start_value; SELECT @@global.max_relay_log_size; @@global.max_relay_log_size -0 +1073741824 diff --git a/mysql-test/suite/sys_vars/t/max_relay_log_size_basic.test b/mysql-test/suite/sys_vars/t/max_relay_log_size_basic.test index e39778baca8..2e8983f5f01 100644 --- a/mysql-test/suite/sys_vars/t/max_relay_log_size_basic.test +++ b/mysql-test/suite/sys_vars/t/max_relay_log_size_basic.test @@ -105,9 +105,7 @@ SELECT @@global.max_relay_log_size; # Test if accessing session max_relay_log_size gives error # ######################################################################## ---Error ER_GLOBAL_VARIABLE SET @@session.max_relay_log_size = 4096; ---Error ER_INCORRECT_GLOBAL_LOCAL_VAR SELECT @@session.max_relay_log_size; @@ -150,7 +148,6 @@ SELECT @@max_relay_log_size = @@global.max_relay_log_size; # Check if max_relay_log_size can be accessed with and without @@ sign # ############################################################################# ---Error ER_GLOBAL_VARIABLE SET max_relay_log_size = 6000; SELECT @@max_relay_log_size; --Error ER_PARSE_ERROR diff --git a/mysys/mf_fn_ext.c b/mysys/mf_fn_ext.c index 47fc67cabbd..cbf0d5dd9e4 100644 --- a/mysys/mf_fn_ext.c +++ b/mysys/mf_fn_ext.c @@ -52,3 +52,40 @@ char *fn_ext(const char *name) pos=strchr(gpos,FN_EXTCHAR); DBUG_RETURN((char*) (pos ? pos : strend(gpos))); } /* fn_ext */ + + +/* + Return a pointer to the extension of the filename. + + SYNOPSIS + fn_ext() + name Name of file + + DESCRIPTION + The extension is defined as everything after the last extension character + (normally '.') after the directory name. + + RETURN VALUES + Pointer to to the extension character. If there isn't any extension, + points at the end ASCII(0) of the filename. +*/ + +char *fn_ext2(const char *name) +{ + register const char *pos, *gpos; + DBUG_ENTER("fn_ext"); + DBUG_PRINT("mfunkt",("name: '%s'",name)); + +#if defined(FN_DEVCHAR) || defined(BASKSLASH_MBTAIL) + { + char buff[FN_REFLEN]; + size_t res_length; + gpos= name+ dirname_part(buff,(char*) name, &res_length); + } +#else + if (!(gpos= strrchr(name, FN_LIBCHAR))) + gpos= name; +#endif + pos=strrchr(gpos,FN_EXTCHAR); + DBUG_RETURN((char*) (pos ? pos : strend(gpos))); +} /* fn_ext */ diff --git a/sql/log.cc b/sql/log.cc index 1f3c529f491..6b0507943c3 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -4703,7 +4703,7 @@ bool MYSQL_BIN_LOG::append(Log_event* ev) DBUG_PRINT("info",("max_size: %lu",max_size)); if (flush_and_sync(0)) goto err; - if ((uint) my_b_append_tell(&log_file) > max_size) + if (my_b_append_tell(&log_file) > max_size) error= new_file_without_locking(); err: mysql_mutex_unlock(&LOCK_log); @@ -4734,7 +4734,7 @@ bool MYSQL_BIN_LOG::appendv(const char* buf, uint len,...) DBUG_PRINT("info",("max_size: %lu",max_size)); if (flush_and_sync(0)) goto err; - if ((uint) my_b_append_tell(&log_file) > max_size) + if (my_b_append_tell(&log_file) > max_size) error= new_file_without_locking(); err: if (!error) diff --git a/sql/log.h b/sql/log.h index 0ade3618fd7..0e887b48462 100644 --- a/sql/log.h +++ b/sql/log.h @@ -502,11 +502,8 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG The max size before rotation (usable only if log_type == LOG_BIN: binary logs and relay logs). For a binlog, max_size should be max_binlog_size. - For a relay log, it should be max_relay_log_size if this is non-zero, - max_binlog_size otherwise. max_size is set in init(), and dynamically changed (when one does SET - GLOBAL MAX_BINLOG_SIZE|MAX_RELAY_LOG_SIZE) by fix_max_binlog_size and - fix_max_relay_log_size). + GLOBAL MAX_BINLOG_SIZE|MAX_RELAY_LOG_SIZE) from sys_vars.cc */ ulong max_size; // current file sequence number for load data infile binary logging diff --git a/sql/log_event.cc b/sql/log_event.cc index 132f778ee08..1d525aa94d8 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -906,9 +906,9 @@ int Log_event::do_update_pos(Relay_log_info *rli) Log_event::enum_skip_reason Log_event::do_shall_skip(Relay_log_info *rli) { - DBUG_PRINT("info", ("ev->server_id=%lu, ::server_id=%lu," - " rli->replicate_same_server_id=%d," - " rli->slave_skip_counter=%d", + DBUG_PRINT("info", ("ev->server_id: %lu, ::server_id: %lu," + " rli->replicate_same_server_id: %d," + " rli->slave_skip_counter: %lu", (ulong) server_id, (ulong) ::server_id, rli->replicate_same_server_id, rli->slave_skip_counter)); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index defd3a71b93..3a89de32b8a 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -52,6 +52,7 @@ #include "des_key_file.h" // load_des_key_file #include "sql_manager.h" // stop_handle_manager, start_handle_manager #include "sql_expression_cache.h" // subquery_cache_miss, subquery_cache_hit +#include "sys_vars_shared.h" #include #include @@ -469,7 +470,7 @@ ulong back_log, connect_timeout, concurrency, server_id; ulong table_cache_size, table_def_size; ulong what_to_log; ulong slow_launch_time, slave_open_temp_tables; -ulong open_files_limit, max_binlog_size, max_relay_log_size; +ulong open_files_limit, max_binlog_size; ulong slave_trans_retries; uint slave_net_timeout; ulong slave_exec_mode_options; @@ -8017,8 +8018,27 @@ static int get_options(int *argc_ptr, char ***argv_ptr) if (!max_long_data_size_used) max_long_data_size= global_system_variables.max_allowed_packet; - /* Rember if max_user_connections was 0 at startup */ + /* Remember if max_user_connections was 0 at startup */ max_user_connections_checking= global_system_variables.max_user_connections != 0; + + { + sys_var *max_relay_log_size_var, *max_binlog_size_var; + /* If max_relay_log_size is 0, then set it to max_binlog_size */ + if (!global_system_variables.max_relay_log_size) + global_system_variables.max_relay_log_size= max_binlog_size; + + /* + Fix so that DEFAULT and limit checking works with max_relay_log_size + (Yes, this is a hack, but it's required as the definition of + max_relay_log_size allows it to be set to 0). + */ + max_relay_log_size_var= intern_find_sys_var("max_relay_log_size", 0); + max_binlog_size_var= intern_find_sys_var("max_binlog_size", 0); + max_relay_log_size_var->option.min_value= + max_binlog_size_var->option.min_value; + max_relay_log_size_var->option.def_value= + max_binlog_size_var->option.def_value; + } return 0; } diff --git a/sql/mysqld.h b/sql/mysqld.h index fd33ca0cf85..4250898cc5b 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -169,7 +169,7 @@ extern ulong max_prepared_stmt_count, prepared_stmt_count; extern ulong open_files_limit; extern ulonglong binlog_cache_size, binlog_stmt_cache_size; extern ulonglong max_binlog_cache_size, max_binlog_stmt_cache_size; -extern ulong max_binlog_size, max_relay_log_size; +extern ulong max_binlog_size; extern ulong slave_max_allowed_packet; extern ulong opt_binlog_rows_event_max_size; extern ulong rpl_recovery_rank, thread_cache_size; diff --git a/sql/rpl_mi.cc b/sql/rpl_mi.cc index 366b271851a..1491d970472 100644 --- a/sql/rpl_mi.cc +++ b/sql/rpl_mi.cc @@ -622,27 +622,34 @@ bool check_master_connection_name(LEX_STRING *name) res_file_name Store result here length Length of res_file_name buffer info_file Original file name (prefix) - separator Separator character + append 1 if we should add suffix last (not before ext) suffix Suffix @note + The suffix is added before the extension of the file name prefixed with '-'. + The suffix is also converted to lower case and we transform + all not safe character, as we do with MySQL table names. + If suffix is an empty string, then we don't add any suffix. This is to allow one to use this function also to generate old file names without a prefix. */ void create_signed_file_name(char *res_file_name, uint length, - const char *info_file, - char separator, LEX_STRING *suffix) + const char *info_file, bool append, + LEX_STRING *suffix) { char buff[MAX_CONNECTION_NAME+1], res[MAX_CONNECTION_NAME+1], *p; - p= strmake(res_file_name, info_file, length); - if (suffix->length != 0 && p != info_file + length) - { - uint errors; - size_t res_length; - *p++= separator; + p= strmake(res_file_name, info_file, length); + /* If not empty suffix and there is place left for some part of the suffix */ + if (suffix->length != 0 && p <= res_file_name + length -1) + { + const char *info_file_end= info_file + (p - res_file_name); + const char *ext= append ? info_file_end : fn_ext2(info_file); + size_t res_length, ext_pos; + uint errors; + /* Create null terminated string */ strmake(buff, suffix->str, suffix->length); /* Convert to lower case */ @@ -650,7 +657,14 @@ void create_signed_file_name(char *res_file_name, uint length, /* Convert to characters usable in a file name */ res_length= strconvert(system_charset_info, buff, &my_charset_filename, res, sizeof(res), &errors); - strmake(p, res, min(length - (p - res_file_name), res_length)); + + ext_pos= (size_t) (ext - info_file); + length-= (suffix->length - ext_pos); /* Leave place for extension */ + p= res_file_name + ext_pos; + *p++= '-'; /* Add separator */ + p= strmake(p, res, min(length - (p - res_file_name), res_length)); + /* Add back extension. We have checked above that there is space for it */ + strmov(p, ext); } } @@ -748,10 +762,10 @@ bool Master_info_index::init_all_master_info() init_thread_mask(&thread_mask,mi,0 /*not inverse*/); create_signed_file_name(buf_master_info_file, sizeof(buf_master_info_file), - master_info_file, '.', &connection_name); + master_info_file, 0, &connection_name); create_signed_file_name(buf_relay_log_info_file, sizeof(buf_relay_log_info_file), - relay_log_info_file, '.', &connection_name); + relay_log_info_file, 0, &connection_name); if (global_system_variables.log_warnings > 1) sql_print_information("Reading Master_info: '%s' Relay_info:'%s'", buf_master_info_file, buf_relay_log_info_file); diff --git a/sql/rpl_mi.h b/sql/rpl_mi.h index 6892ecdb9d1..6c7bd3a5d28 100644 --- a/sql/rpl_mi.h +++ b/sql/rpl_mi.h @@ -169,7 +169,7 @@ public: bool check_master_connection_name(LEX_STRING *name); void create_signed_file_name(char *res_file_name, uint length, const char *info_file, - char separator, + bool append, LEX_STRING *suffix); uchar *get_key_master_info(Master_info *mi, size_t *length, diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index 49c8390ff9b..362ebab9fa0 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -69,6 +69,7 @@ Relay_log_info::Relay_log_info(bool is_slave_recovery) group_relay_log_name[0]= event_relay_log_name[0]= group_master_log_name[0]= 0; until_log_name[0]= ign_master_log_name_end[0]= 0; + max_relay_log_size= global_system_variables.max_relay_log_size; bzero((char*) &info_file, sizeof(info_file)); bzero((char*) &cache_buf, sizeof(cache_buf)); cached_charset_invalidate(); @@ -149,15 +150,6 @@ int init_relay_log_info(Relay_log_info* rli, event, in flush_master_info(mi, 1, ?). */ - /* - For the maximum log size, we choose max_relay_log_size if it is - non-zero, max_binlog_size otherwise. If later the user does SET - GLOBAL on one of these variables, fix_max_binlog_size and - fix_max_relay_log_size will reconsider the choice (for example - if the user changes max_relay_log_size to zero, we have to - switch to using max_binlog_size for the relay log) and update - rli->relay_log.max_size (and mysql_bin_log.max_size). - */ { /* Reports an error and returns, if the --relay-log's path is a directory.*/ @@ -212,7 +204,7 @@ a file name for --relay-log-index option", opt_relaylog_index_name); char *buf_relaylog_index_name= opt_relaylog_index_name; create_signed_file_name(buf_relay_logname, sizeof(buf_relay_logname), - ln, '-', &mi->connection_name); + ln, 1, &mi->connection_name); ln= buf_relay_logname; if (opt_relaylog_index_name) @@ -220,7 +212,7 @@ a file name for --relay-log-index option", opt_relaylog_index_name); buf_relaylog_index_name= buf_relaylog_index_name_buff; create_signed_file_name(buf_relaylog_index_name_buff, sizeof(buf_relaylog_index_name_buff), - opt_relaylog_index_name, '-', + opt_relaylog_index_name, 0, &mi->connection_name); } @@ -232,8 +224,7 @@ a file name for --relay-log-index option", opt_relaylog_index_name); */ if (rli->relay_log.open_index_file(buf_relaylog_index_name, ln, TRUE) || rli->relay_log.open(ln, LOG_BIN, 0, SEQ_READ_APPEND, - (max_relay_log_size ? max_relay_log_size : - max_binlog_size), 1, TRUE)) + mi->rli.max_relay_log_size, 1, TRUE)) { mysql_mutex_unlock(&rli->data_lock); sql_print_error("Failed when trying to open logs for '%s' in init_relay_log_info(). Error: %M", ln, my_errno); diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h index eb808351a34..c543b4d3198 100644 --- a/sql/rpl_rli.h +++ b/sql/rpl_rli.h @@ -229,9 +229,10 @@ public: skipping one or more events in the master log that have caused errors, and have been manually applied by DBA already. */ - volatile uint slave_skip_counter; /* Must be uint */ + volatile ulong slave_skip_counter; /* Must be ulong */ volatile ulong abort_pos_wait; /* Incremented on change master */ volatile ulong slave_run_id; /* Incremented on slave start */ + ulong max_relay_log_size; mysql_mutex_t log_space_lock; mysql_cond_t log_space_cond; THD * sql_thd; diff --git a/sql/set_var.h b/sql/set_var.h index 6edfd6adb39..fea947aa1da 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -68,13 +68,14 @@ public: enum binlog_status_enum { VARIABLE_NOT_IN_BINLOG, SESSION_VARIABLE_IN_BINLOG } binlog_status; + my_option option; ///< min, max, default values are stored here + protected: typedef bool (*on_check_function)(sys_var *self, THD *thd, set_var *var); typedef bool (*on_update_function)(sys_var *self, THD *thd, enum_var_type type); int flags; ///< or'ed flag_enum values const SHOW_TYPE show_val_type; ///< what value_ptr() returns for sql_show.cc - my_option option; ///< min, max, default values are stored here PolyLock *guard; ///< *second* lock that protects the variable ptrdiff_t offset; ///< offset to the value from global_system_variables on_check_function on_check; diff --git a/sql/sql_class.h b/sql/sql_class.h index 7f44a4b468a..50c99af29d1 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -534,10 +534,11 @@ typedef struct system_variables */ my_thread_id pseudo_thread_id; /** - Place holder to store sql_slave_skip_counter in sys_var.cc during + Place holders to store Multi-source variables in sys_var.cc during update and show of variables. */ - uint slave_skip_counter; + ulong slave_skip_counter; + ulong max_relay_log_size; my_bool low_priority_updates; my_bool query_cache_wlock_invalidate; diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index ed00fcaaddf..0238a98f5d0 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -1308,10 +1308,10 @@ int start_slave(THD* thd , Master_info* mi, bool net_report) create_signed_file_name(master_info_file_tmp, sizeof(master_info_file_tmp), - master_info_file, '.', &mi->connection_name); + master_info_file, 0, &mi->connection_name); create_signed_file_name(relay_log_info_file_tmp, sizeof(relay_log_info_file_tmp), - relay_log_info_file, '.', &mi->connection_name); + relay_log_info_file, 0, &mi->connection_name); if (check_access(thd, SUPER_ACL, any_db, NULL, NULL, 0, 0)) DBUG_RETURN(1); @@ -1557,10 +1557,10 @@ int reset_slave(THD *thd, Master_info* mi) // and delete these two files create_signed_file_name(master_info_file_tmp, sizeof(master_info_file_tmp), - master_info_file, '.', &mi->connection_name); + master_info_file, 0, &mi->connection_name); create_signed_file_name(relay_log_info_file_tmp, sizeof(relay_log_info_file_tmp), - relay_log_info_file, '.', &mi->connection_name); + relay_log_info_file, 0, &mi->connection_name); fn_format(fname, master_info_file_tmp, mysql_data_home, "", 4+32); if (mysql_file_stat(key_file_master_info, fname, &stat_area, MYF(0)) && @@ -1697,10 +1697,10 @@ bool change_master(THD* thd, Master_info* mi) create_signed_file_name(master_info_file_tmp, sizeof(master_info_file_tmp), - master_info_file, '.', &mi->connection_name); + master_info_file, 0, &mi->connection_name); create_signed_file_name(relay_log_info_file_tmp, sizeof(relay_log_info_file_tmp), - relay_log_info_file, '.', &mi->connection_name); + relay_log_info_file, 0, &mi->connection_name); /* if new Master_info doesn't exists, add it */ if (!master_info_index->get_master_info(&mi->connection_name, diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 30cfe1a5680..9421dca5c05 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -1105,16 +1105,12 @@ static Sys_var_ulonglong Sys_max_binlog_stmt_cache_size( static bool fix_max_binlog_size(sys_var *self, THD *thd, enum_var_type type) { mysql_bin_log.set_max_size(max_binlog_size); -#ifdef HAVE_REPLICATION - if (!max_relay_log_size) - active_mi->rli.relay_log.set_max_size(max_binlog_size); -#endif return false; } static Sys_var_ulong Sys_max_binlog_size( "max_binlog_size", "Binary log will be rotated automatically when the size exceeds this " - "value. Will also apply to relay logs if max_relay_log_size is 0", + "value.", GLOBAL_VAR(max_binlog_size), CMD_LINE(REQUIRED_ARG), VALID_RANGE(IO_SIZE, 1024*1024L*1024L), DEFAULT(1024*1024L*1024L), BLOCK_SIZE(IO_SIZE), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), @@ -1259,24 +1255,6 @@ static Sys_var_ulong Sys_max_prepared_stmt_count( VALID_RANGE(0, 1024*1024), DEFAULT(16382), BLOCK_SIZE(1), &PLock_prepared_stmt_count); -static bool fix_max_relay_log_size(sys_var *self, THD *thd, enum_var_type type) -{ -#ifdef HAVE_REPLICATION - active_mi->rli.relay_log.set_max_size(max_relay_log_size ? - max_relay_log_size: max_binlog_size); -#endif - return false; -} -static Sys_var_ulong Sys_max_relay_log_size( - "max_relay_log_size", - "If non-zero: relay log will be rotated automatically when the " - "size exceeds this value; if zero: when the size " - "exceeds max_binlog_size", - GLOBAL_VAR(max_relay_log_size), CMD_LINE(REQUIRED_ARG), - VALID_RANGE(0, 1024L*1024*1024), DEFAULT(0), BLOCK_SIZE(IO_SIZE), - NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), - ON_UPDATE(fix_max_relay_log_size)); - static Sys_var_ulong Sys_max_sort_length( "max_sort_length", "The number of bytes to use when sorting BLOB or TEXT values (only " @@ -3459,7 +3437,7 @@ static bool fix_slave_net_timeout(sys_var *self, THD *thd, enum_var_type type) mysql_mutex_unlock(&LOCK_global_system_variables); mysql_mutex_lock(&LOCK_active_mi); - DBUG_PRINT("info", ("slave_net_timeout=%u mi->heartbeat_period=%.3f", + DBUG_PRINT("info", ("slave_net_timeout: %u mi->heartbeat_period: %.3f", slave_net_timeout, (active_mi? active_mi->heartbeat_period : 0.0))); if (active_mi && slave_net_timeout < active_mi->heartbeat_period) @@ -3484,7 +3462,7 @@ static Sys_var_uint Sys_slave_net_timeout( Return 0 + warning if it doesn't exist */ -uint Sys_var_multi_source_uint:: +uint Sys_var_multi_source_ulong:: get_master_info_uint_value(THD *thd, ptrdiff_t offset) { Master_info *mi; @@ -3504,11 +3482,13 @@ get_master_info_uint_value(THD *thd, ptrdiff_t offset) } -static bool update_slave_skip_counter(sys_var *self, THD *thd, - enum_var_type type) +bool update_multi_source_variable(sys_var *self_var, THD *thd, + enum_var_type type) { + Sys_var_multi_source_ulong *self= (Sys_var_multi_source_ulong*) self_var; bool result= true; Master_info *mi; + mysql_mutex_lock(&LOCK_active_mi); mi= master_info_index-> get_master_info(&thd->variables.default_master_connection, @@ -3516,30 +3496,57 @@ static bool update_slave_skip_counter(sys_var *self, THD *thd, if (mi) { mysql_mutex_lock(&mi->rli.run_lock); - if (mi->rli.slave_running) - my_message(ER_SLAVE_MUST_STOP, ER(ER_SLAVE_MUST_STOP), MYF(0)); - else - { - result= false; // ok - mysql_mutex_lock(&mi->rli.data_lock); - /* The value was stored temporarly in thd */ - mi->rli.slave_skip_counter= thd->variables.slave_skip_counter; - mysql_mutex_unlock(&mi->rli.data_lock); - } + mysql_mutex_lock(&mi->rli.data_lock); + result= self->update_variable(thd, mi); + mysql_mutex_unlock(&mi->rli.data_lock); mysql_mutex_unlock(&mi->rli.run_lock); } mysql_mutex_unlock(&LOCK_active_mi); return result; } -static Sys_var_multi_source_uint +static bool update_slave_skip_counter(sys_var *self, THD *thd, Master_info *mi) +{ + if (mi->rli.slave_running) + { + my_message(ER_SLAVE_MUST_STOP, ER(ER_SLAVE_MUST_STOP), MYF(0)); + return true; + } + /* The value was stored temporarly in thd */ + mi->rli.slave_skip_counter= thd->variables.slave_skip_counter; + return false; +} + + +static Sys_var_multi_source_ulong Sys_slave_skip_counter("sql_slave_skip_counter", "Skip the next N events from the master log", SESSION_VAR(slave_skip_counter), + NO_CMD_LINE, offsetof(Master_info, rli.slave_skip_counter), VALID_RANGE(0, UINT_MAX), DEFAULT(0), BLOCK_SIZE(1), ON_UPDATE(update_slave_skip_counter)); + +static bool update_max_relay_log_size(sys_var *self, THD *thd, Master_info *mi) +{ + mi->rli.max_relay_log_size= thd->variables.max_relay_log_size; + mi->rli.relay_log.set_max_size(mi->rli.max_relay_log_size); + return false; +} + +static Sys_var_multi_source_ulong +Sys_max_relay_log_size( "max_relay_log_size", + "relay log will be rotated automatically when the " + "size exceeds this value. If 0 are startup, it's " + "set to max_binlog_size", + SESSION_VAR(max_relay_log_size), + CMD_LINE(REQUIRED_ARG), + offsetof(Master_info, rli.max_relay_log_size), + VALID_RANGE(0, 1024L*1024*1024), DEFAULT(0), + BLOCK_SIZE(IO_SIZE), + ON_UPDATE(update_max_relay_log_size)); + static Sys_var_charptr Sys_slave_skip_errors( "slave_skip_errors", "Tells the slave thread to continue " "replication when a query event returns an error from the " diff --git a/sql/sys_vars.h b/sql/sys_vars.h index 6509ba6a5f4..8e832e57630 100644 --- a/sql/sys_vars.h +++ b/sql/sys_vars.h @@ -1954,24 +1954,34 @@ public: like sql_slave_skip_counter are GLOBAL. */ -class Sys_var_multi_source_uint :public Sys_var_uint +class Sys_var_multi_source_ulong; +class Master_info; + +typedef bool (*on_multi_source_update_function)(sys_var *self, THD *thd, + Master_info *mi); +bool update_multi_source_variable(sys_var *self, + THD *thd, enum_var_type type); + + +class Sys_var_multi_source_ulong :public Sys_var_ulong { ptrdiff_t master_info_offset; + on_multi_source_update_function update_multi_source_variable_func; public: - Sys_var_multi_source_uint(const char *name_arg, - const char *comment, int flag_args, - ptrdiff_t off, size_t size, - ptrdiff_t master_info_offset_arg, - uint min_val, uint max_val, uint def_val, - uint block_size, - on_update_function on_update_func) - :Sys_var_uint(name_arg, comment, flag_args, off, size, - NO_CMD_LINE, min_val, max_val, def_val, block_size, - 0, VARIABLE_NOT_IN_BINLOG, 0, on_update_func), - master_info_offset(master_info_offset_arg) + Sys_var_multi_source_ulong(const char *name_arg, + const char *comment, int flag_args, + ptrdiff_t off, size_t size, + CMD_LINE getopt, + ptrdiff_t master_info_offset_arg, + uint min_val, uint max_val, uint def_val, + uint block_size, + on_multi_source_update_function on_update_func) + :Sys_var_ulong(name_arg, comment, flag_args, off, size, + getopt, min_val, max_val, def_val, block_size, + 0, VARIABLE_NOT_IN_BINLOG, 0, update_multi_source_variable), + master_info_offset(master_info_offset_arg), + update_multi_source_variable_func(on_update_func) { - /* No global storage of variables. Cause a crash if we try an update */ - option.value= (uchar**)1; } bool session_update(THD *thd, set_var *var) { @@ -2001,6 +2011,10 @@ public: return session_value_ptr(thd, base); } uint get_master_info_uint_value(THD *thd, ptrdiff_t offset); + bool update_variable(THD *thd, Master_info *mi) + { + return update_multi_source_variable_func(this, thd, mi); + } }; From b722aebdf4cd73be88e2ae6768dce05276f52076 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Tue, 2 Oct 2012 16:26:22 +0300 Subject: [PATCH 279/289] Fixed installation issues on debian: - Don't abort if plugin table exists - Use longer timeout for start/stop of mysqld debian/dist/Debian/mariadb-server-5.5.postinst: Don't abort if plugin table exists debian/mariadb-server-5.5.mysql.init: Use longer timeout for start/stop of mysqld --- debian/dist/Debian/mariadb-server-5.5.postinst | 2 +- debian/mariadb-server-5.5.mysql.init | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/debian/dist/Debian/mariadb-server-5.5.postinst b/debian/dist/Debian/mariadb-server-5.5.postinst index 2e15b121db9..4da8979fd03 100644 --- a/debian/dist/Debian/mariadb-server-5.5.postinst +++ b/debian/dist/Debian/mariadb-server-5.5.postinst @@ -212,7 +212,7 @@ EOF # admin might already have chosen to remove one or more plugins. Newlines are necessary. install_plugins=`/bin/echo -e \ "USE mysql;\n" \ - "CREATE TABLE plugin (name char(64) COLLATE utf8_bin NOT NULL DEFAULT '', " \ + "CREATE TABLE IF NOT EXISTS plugin (name char(64) COLLATE utf8_bin NOT NULL DEFAULT '', " \ " dl char(128) COLLATE utf8_bin NOT NULL DEFAULT '', " \ " PRIMARY KEY (name)) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='MySQL plugins';" ` diff --git a/debian/mariadb-server-5.5.mysql.init b/debian/mariadb-server-5.5.mysql.init index b83316aedea..01e1288525e 100644 --- a/debian/mariadb-server-5.5.mysql.init +++ b/debian/mariadb-server-5.5.mysql.init @@ -109,7 +109,7 @@ case "${1:-''}" in /usr/bin/mysqld_safe > /dev/null 2>&1 & # 6s was reported in #352070 to be too few when using ndbcluster - for i in $(seq 1 "${MYSQLD_STARTUP_TIMEOUT:-14}"); do + for i in $(seq 1 "${MYSQLD_STARTUP_TIMEOUT:-30}"); do sleep 1 if mysqld_status check_alive nowarn ; then break; fi log_progress_msg "." @@ -142,7 +142,7 @@ case "${1:-''}" in log_daemon_msg "Killing MariaDB database server by signal" "mysqld" killall -15 mysqld server_down= - for i in 1 2 3 4 5 6 7 8 9 10; do + for i in 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10; do sleep 1 if mysqld_status check_dead nowarn; then server_down=1; break; fi done From 572560f38c248d5020f0e63aeb3f8905cd568208 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Wed, 3 Oct 2012 01:44:54 +0300 Subject: [PATCH 280/289] Changed SHOW_FUNC variabels that don't return SHOW_ARRAY to SHOW_SIMPLE_FUNC. This allows us to avoid calculating variables (including those involving mutex) that doesn't match the given wildcard in SHOW STATUS LIKE '...' Removed all references to active_mi that could cause problems for multi-source replication. Added START|STOP ALL SLAVES Added SHOW ALL SLAVES STATUS include/mysql/plugin.h: Added SHOW_SIMPLE_FUNC include/mysql/plugin_audit.h.pp: Updated .pp file include/mysql/plugin_auth.h.pp: Updated .pp file include/mysql/plugin_ftparser.h.pp: Updated .pp file mysql-test/suite/multi_source/info_logs.result: New columns in SHOW ALL SLAVES STATUS mysql-test/suite/multi_source/info_logs.test: Test new syntax mysql-test/suite/multi_source/simple.result: New columns in SHOW ALL SLAVES STATUS mysql-test/suite/multi_source/simple.test: test new syntax mysql-test/suite/multi_source/syntax.result: Updated result mysql-test/suite/multi_source/syntax.test: Test new syntax mysql-test/suite/rpl/r/rpl_skip_replication.result: Updated result plugin/semisync/semisync_master_plugin.cc: SHOW_FUNC -> SHOW_SIMPLE_FUNC sql/item_create.cc: Simplify code sql/lex.h: Added SLAVES keyword sql/log.cc: Constant -> define sql/log_event.cc: Added comment sql/mysqld.cc: SHOW_FUNC -> SHOW_SIMPLE_FUNC Made slave_retried_trans, slave_received_heartbeats and heartbeat_period multi-source safe Clear variable denied_connections and slave_retried_transactions on startup sql/mysqld.h: Added slave_retried_transactions sql/rpl_mi.cc: create_signed_file_name -> create_logfile_name_with_suffix Added start_all_slaves() and stop_all_slaves() sql/rpl_mi.h: Added prototypes sql/rpl_rli.cc: create_signed_file_name -> create_logfile_name_with_suffix added executed_entries sql/rpl_rli.h: Added executed_entries sql/share/errmsg-utf8.txt: More and better error messages sql/slave.cc: Added more fields to SHOW ALL SLAVES STATUS Added slave_retried_transactions Changed constants -> defines sql/sql_class.h: Added comment sql/sql_insert.cc: active_mi.rli -> thd->rli_slave sql/sql_lex.h: Added SQLCOM_SLAVE_ALL_START & SQLCOM_SLAVE_ALL_STOP sql/sql_load.cc: active_mi.rli -> thd->rli_slave sql/sql_parse.cc: Added START|STOP ALL SLAVES sql/sql_prepare.cc: Added SQLCOM_SLAVE_ALL_START & SQLCOM_SLAVE_ALL_STOP sql/sql_reload.cc: Made REFRESH RELAY LOG multi-source safe sql/sql_repl.cc: create_signed_file_name -> create_logfile_name_with_suffix Don't send my_ok() from start_slave() or stop_slave() so that we can call it for all master connections sql/sql_show.cc: Compare wild cards early for all variables sql/sql_yacc.yy: Added START|STOP ALL SLAVES Added SHOW ALL SLAVES STATUS sql/sys_vars.cc: Made replicate_events_marked_for_skip,slave_net_timeout and rpl_filter multi-source safe. sql/sys_vars.h: Simplify Sys_var_rpl_filter --- include/mysql/plugin.h | 2 +- include/mysql/plugin_audit.h.pp | 2 +- include/mysql/plugin_auth.h.pp | 2 +- include/mysql/plugin_ftparser.h.pp | 2 +- .../suite/multi_source/info_logs.result | 16 +- mysql-test/suite/multi_source/info_logs.test | 4 +- mysql-test/suite/multi_source/simple.result | 38 +++-- mysql-test/suite/multi_source/simple.test | 19 ++- mysql-test/suite/multi_source/syntax.result | 8 +- mysql-test/suite/multi_source/syntax.test | 2 +- .../suite/rpl/r/rpl_deadlock_innodb.result | 2 + .../suite/rpl/r/rpl_filter_dbs_dynamic.result | 4 +- .../rpl/r/rpl_filter_tables_dynamic.result | 4 +- .../r/rpl_filter_wild_tables_dynamic.result | 4 +- mysql-test/suite/rpl/r/rpl_flush_logs.result | 10 +- mysql-test/suite/rpl/r/rpl_heartbeat.result | 2 - .../suite/rpl/r/rpl_heartbeat_basic.result | 2 - .../suite/rpl/r/rpl_skip_replication.result | 2 +- .../rpl_start_slave_deadlock_sys_vars.result | 31 ---- mysql-test/suite/rpl/t/rpl_flush_logs.test | 24 +-- .../t/rpl_start_slave_deadlock_sys_vars.test | 57 ------- plugin/semisync/semisync_master_plugin.cc | 18 +-- sql/item_create.cc | 4 +- sql/lex.h | 1 + sql/log.cc | 2 +- sql/log_event.cc | 3 + sql/mysqld.cc | 146 ++++++++---------- sql/mysqld.h | 1 + sql/rpl_mi.cc | 144 +++++++++++++++-- sql/rpl_mi.h | 7 +- sql/rpl_rli.cc | 6 +- sql/rpl_rli.h | 4 +- sql/share/errmsg-utf8.txt | 30 ++-- sql/slave.cc | 59 +++++-- sql/sql_class.h | 6 +- sql/sql_insert.cc | 8 +- sql/sql_lex.h | 3 +- sql/sql_load.cc | 6 +- sql/sql_parse.cc | 30 +++- sql/sql_prepare.cc | 2 + sql/sql_reload.cc | 18 ++- sql/sql_repl.cc | 48 +++--- sql/sql_show.cc | 26 +++- sql/sql_yacc.yy | 20 ++- sql/sys_vars.cc | 138 +++-------------- sql/sys_vars.h | 13 +- storage/example/ha_example.cc | 5 +- storage/sphinx/ha_sphinx.cc | 12 +- storage/xtradb/handler/ha_innodb.cc | 4 +- 49 files changed, 532 insertions(+), 469 deletions(-) delete mode 100644 mysql-test/suite/rpl/r/rpl_start_slave_deadlock_sys_vars.result delete mode 100644 mysql-test/suite/rpl/t/rpl_start_slave_deadlock_sys_vars.test diff --git a/include/mysql/plugin.h b/include/mysql/plugin.h index b73f2d75193..b8e90f764bd 100644 --- a/include/mysql/plugin.h +++ b/include/mysql/plugin.h @@ -167,7 +167,7 @@ enum enum_mysql_show_type SHOW_UNDEF, SHOW_BOOL, SHOW_UINT, SHOW_ULONG, SHOW_ULONGLONG, SHOW_CHAR, SHOW_CHAR_PTR, SHOW_ARRAY, SHOW_FUNC, SHOW_DOUBLE, - SHOW_SINT, SHOW_SLONG, SHOW_SLONGLONG, + SHOW_SINT, SHOW_SLONG, SHOW_SLONGLONG, SHOW_SIMPLE_FUNC, SHOW_always_last }; diff --git a/include/mysql/plugin_audit.h.pp b/include/mysql/plugin_audit.h.pp index b987f690592..dea2446ac9c 100644 --- a/include/mysql/plugin_audit.h.pp +++ b/include/mysql/plugin_audit.h.pp @@ -94,7 +94,7 @@ enum enum_mysql_show_type SHOW_UNDEF, SHOW_BOOL, SHOW_UINT, SHOW_ULONG, SHOW_ULONGLONG, SHOW_CHAR, SHOW_CHAR_PTR, SHOW_ARRAY, SHOW_FUNC, SHOW_DOUBLE, - SHOW_SINT, SHOW_SLONG, SHOW_SLONGLONG, + SHOW_SINT, SHOW_SLONG, SHOW_SLONGLONG, SHOW_SIMPLE_FUNC, SHOW_always_last }; struct st_mysql_show_var { diff --git a/include/mysql/plugin_auth.h.pp b/include/mysql/plugin_auth.h.pp index 113aaf62d19..f1213a73bc6 100644 --- a/include/mysql/plugin_auth.h.pp +++ b/include/mysql/plugin_auth.h.pp @@ -94,7 +94,7 @@ enum enum_mysql_show_type SHOW_UNDEF, SHOW_BOOL, SHOW_UINT, SHOW_ULONG, SHOW_ULONGLONG, SHOW_CHAR, SHOW_CHAR_PTR, SHOW_ARRAY, SHOW_FUNC, SHOW_DOUBLE, - SHOW_SINT, SHOW_SLONG, SHOW_SLONGLONG, + SHOW_SINT, SHOW_SLONG, SHOW_SLONGLONG, SHOW_SIMPLE_FUNC, SHOW_always_last }; struct st_mysql_show_var { diff --git a/include/mysql/plugin_ftparser.h.pp b/include/mysql/plugin_ftparser.h.pp index 6011e7f7519..74b298098dd 100644 --- a/include/mysql/plugin_ftparser.h.pp +++ b/include/mysql/plugin_ftparser.h.pp @@ -94,7 +94,7 @@ enum enum_mysql_show_type SHOW_UNDEF, SHOW_BOOL, SHOW_UINT, SHOW_ULONG, SHOW_ULONGLONG, SHOW_CHAR, SHOW_CHAR_PTR, SHOW_ARRAY, SHOW_FUNC, SHOW_DOUBLE, - SHOW_SINT, SHOW_SLONG, SHOW_SLONGLONG, + SHOW_SINT, SHOW_SLONG, SHOW_SLONGLONG, SHOW_SIMPLE_FUNC, SHOW_always_last }; struct st_mysql_show_var { diff --git a/mysql-test/suite/multi_source/info_logs.result b/mysql-test/suite/multi_source/info_logs.result index 1da44992ec6..2d4c52b936d 100644 --- a/mysql-test/suite/multi_source/info_logs.result +++ b/mysql-test/suite/multi_source/info_logs.result @@ -83,14 +83,14 @@ relay.bin.info MASTER 2.2 # EOF # -show full slave status; -Connection_name 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 Replicate_Ignore_Server_Ids Master_Server_Id - Waiting for master to send event 127.0.0.1 root MYPORT_1 60 master-bin.000001 286 relay.000002 572 master-bin.000001 Yes Yes 0 0 286 857 None 0 No 0 No 0 0 1 -MASTER 2.2 Waiting for master to send event 127.0.0.1 root MYPORT_2 60 master-bin.000001 286 relay-master@00202@002e2.000002 572 master-bin.000001 Yes Yes 0 0 286 876 None 0 No 0 No 0 0 2 -show full slave status; -Connection_name 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 Replicate_Ignore_Server_Ids Master_Server_Id - Waiting for master to send event 127.0.0.1 root MYPORT_1 60 master-bin.000001 286 relay.000004 532 master-bin.000001 Yes Yes 0 0 286 817 None 0 No 0 No 0 0 1 -MASTER 2.2 Waiting for master to send event 127.0.0.1 root MYPORT_2 60 master-bin.000001 286 relay-master@00202@002e2.000004 532 master-bin.000001 Yes Yes 0 0 286 836 None 0 No 0 No 0 0 2 +show all slaves status; +Connection_name Slave_SQL_State 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 Replicate_Ignore_Server_Ids Master_Server_Id Retried_transactions Max_relay_log_size Executed_log_entries + Slave has read all relay log; waiting for the slave I/O thread to update it Waiting for master to send event 127.0.0.1 root MYPORT_1 60 master-bin.000001 286 relay.000002 572 master-bin.000001 Yes Yes 0 0 286 857 None 0 No 0 No 0 0 1 0 1073741824 6 +MASTER 2.2 Slave has read all relay log; waiting for the slave I/O thread to update it Waiting for master to send event 127.0.0.1 root MYPORT_2 60 master-bin.000001 286 relay-master@00202@002e2.000002 572 master-bin.000001 Yes Yes 0 0 286 876 None 0 No 0 No 0 0 2 0 1073741824 6 +show all slaves status; +Connection_name Slave_SQL_State 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 Replicate_Ignore_Server_Ids Master_Server_Id Retried_transactions Max_relay_log_size Executed_log_entries + Slave has read all relay log; waiting for the slave I/O thread to update it Waiting for master to send event 127.0.0.1 root MYPORT_1 60 master-bin.000001 286 relay.000004 532 master-bin.000001 Yes Yes 0 0 286 817 None 0 No 0 No 0 0 1 0 1073741824 6 +MASTER 2.2 Slave has read all relay log; waiting for the slave I/O thread to update it Waiting for master to send event 127.0.0.1 root MYPORT_2 60 master-bin.000001 286 relay-master@00202@002e2.000004 532 master-bin.000001 Yes Yes 0 0 286 836 None 0 No 0 No 0 0 2 0 1073741824 6 # # List of files matching '*info*' pattern # after slave server restart diff --git a/mysql-test/suite/multi_source/info_logs.test b/mysql-test/suite/multi_source/info_logs.test index f06880faca6..6314a94434c 100644 --- a/mysql-test/suite/multi_source/info_logs.test +++ b/mysql-test/suite/multi_source/info_logs.test @@ -117,7 +117,7 @@ start slave; --sleep 5 --replace_result $SERVER_MYPORT_1 MYPORT_1 $SERVER_MYPORT_2 MYPORT_2 -show full slave status; +show all slaves status; # Restart the slave server @@ -129,7 +129,7 @@ EOF --source include/wait_until_connected_again.inc --replace_result $SERVER_MYPORT_1 MYPORT_1 $SERVER_MYPORT_2 MYPORT_2 -show full slave status; +show all slaves status; # Check the files diff --git a/mysql-test/suite/multi_source/simple.result b/mysql-test/suite/multi_source/simple.result index 003622a1b46..302db59c4e4 100644 --- a/mysql-test/suite/multi_source/simple.result +++ b/mysql-test/suite/multi_source/simple.result @@ -4,13 +4,16 @@ start slave 'slave1'; set default_master_connection = 'slave1'; include/wait_for_slave_to_start.inc set default_master_connection = 'slave2'; -start slave 'slave2'; +start all slaves; +Warnings: +Note 1936 SLAVE 'slave2' started include/wait_for_slave_to_start.inc set default_master_connection = ''; -show full slave status; -Connection_name 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 Replicate_Ignore_Server_Ids Master_Server_Id -slave1 Waiting for master to send event 127.0.0.1 root MYPORT_1 60 master-bin.000001 286 mysqld-relay-bin-slave1.000002 572 master-bin.000001 Yes Yes 0 0 286 875 None 0 No 0 No 0 0 1 -slave2 Waiting for master to send event 127.0.0.1 root MYPORT_2 60 master-bin.000001 286 mysqld-relay-bin-slave2.000002 572 master-bin.000001 Yes Yes 0 0 286 875 None 0 No 0 No 0 0 2 +show all slaves status; +Connection_name Slave_SQL_State 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 Replicate_Ignore_Server_Ids Master_Server_Id Retried_transactions Max_relay_log_size Executed_log_entries +slave1 Slave has read all relay log; waiting for the slave I/O thread to update it Waiting for master to send event 127.0.0.1 root MYPORT_1 60 master-bin.000001 286 mysqld-relay-bin-slave1.000002 572 master-bin.000001 Yes Yes 0 0 286 875 None 0 No 0 No 0 0 1 0 1073741824 6 +slave2 Slave has read all relay log; waiting for the slave I/O thread to update it Waiting for master to send event 127.0.0.1 root MYPORT_2 60 master-bin.000001 286 mysqld-relay-bin-slave2.000002 572 master-bin.000001 Yes Yes 0 0 286 875 None 0 No 0 No 0 0 2 0 1073741824 6 +start all slaves; stop slave 'slave1'; show slave 'slave1' status; Slave_IO_State @@ -54,16 +57,19 @@ Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id 1 reset slave 'slave1'; -show full slave status; -Connection_name 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 Replicate_Ignore_Server_Ids Master_Server_Id -slave1 127.0.0.1 root MYPORT_1 60 4 572 No No 0 0 0 875 None 0 No NULL No 0 0 1 -slave2 Waiting for master to send event 127.0.0.1 root MYPORT_2 60 master-bin.000001 286 mysqld-relay-bin-slave2.000002 572 master-bin.000001 Yes Yes 0 0 286 875 None 0 No 0 No 0 0 2 +show all slaves status; +Connection_name Slave_SQL_State 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 Replicate_Ignore_Server_Ids Master_Server_Id Retried_transactions Max_relay_log_size Executed_log_entries +slave1 127.0.0.1 root MYPORT_1 60 4 572 No No 0 0 0 875 None 0 No NULL No 0 0 1 0 1073741824 6 +slave2 Slave has read all relay log; waiting for the slave I/O thread to update it Waiting for master to send event 127.0.0.1 root MYPORT_2 60 master-bin.000001 286 mysqld-relay-bin-slave2.000002 572 master-bin.000001 Yes Yes 0 0 286 875 None 0 No 0 No 0 0 2 0 1073741824 6 reset slave 'slave1' all; -show full slave status; -Connection_name 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 Replicate_Ignore_Server_Ids Master_Server_Id -slave2 Waiting for master to send event 127.0.0.1 root MYPORT_2 60 master-bin.000001 286 mysqld-relay-bin-slave2.000002 572 master-bin.000001 Yes Yes 0 0 286 875 None 0 No 0 No 0 0 2 -stop slave 'slave2'; -show full slave status; -Connection_name 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 Replicate_Ignore_Server_Ids Master_Server_Id -slave2 127.0.0.1 root MYPORT_2 60 master-bin.000001 286 mysqld-relay-bin-slave2.000002 572 master-bin.000001 No No 0 0 286 875 None 0 No NULL No 0 0 2 +show all slaves status; +Connection_name Slave_SQL_State 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 Replicate_Ignore_Server_Ids Master_Server_Id Retried_transactions Max_relay_log_size Executed_log_entries +slave2 Slave has read all relay log; waiting for the slave I/O thread to update it Waiting for master to send event 127.0.0.1 root MYPORT_2 60 master-bin.000001 286 mysqld-relay-bin-slave2.000002 572 master-bin.000001 Yes Yes 0 0 286 875 None 0 No 0 No 0 0 2 0 1073741824 6 +stop all slaves; +Warnings: +Note 1937 SLAVE 'slave2' stopped +show all slaves status; +Connection_name Slave_SQL_State 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 Replicate_Ignore_Server_Ids Master_Server_Id Retried_transactions Max_relay_log_size Executed_log_entries +slave2 127.0.0.1 root MYPORT_2 60 master-bin.000001 286 mysqld-relay-bin-slave2.000002 572 master-bin.000001 No No 0 0 286 875 None 0 No NULL No 0 0 2 0 1073741824 6 +stop all slaves; reset slave 'slave2' all; diff --git a/mysql-test/suite/multi_source/simple.test b/mysql-test/suite/multi_source/simple.test index 2b4f06aa1fe..4b13623785a 100644 --- a/mysql-test/suite/multi_source/simple.test +++ b/mysql-test/suite/multi_source/simple.test @@ -15,7 +15,8 @@ start slave 'slave1'; set default_master_connection = 'slave1'; --source include/wait_for_slave_to_start.inc set default_master_connection = 'slave2'; -start slave 'slave2'; +start all slaves; + --source include/wait_for_slave_to_start.inc set default_master_connection = ''; @@ -30,7 +31,10 @@ set default_master_connection = ''; --sync_with_master 0,'slave2' --replace_result $SERVER_MYPORT_1 MYPORT_1 $SERVER_MYPORT_2 MYPORT_2 -show full slave status; +show all slaves status; + +# Ensure that start all slaves doesn't do anything as all slaves are started +start all slaves; stop slave 'slave1'; @@ -39,15 +43,18 @@ query_vertical show slave 'slave1' status; reset slave 'slave1'; --replace_result $SERVER_MYPORT_1 MYPORT_1 $SERVER_MYPORT_2 MYPORT_2 -show full slave status; +show all slaves status; reset slave 'slave1' all; --replace_result $SERVER_MYPORT_1 MYPORT_1 $SERVER_MYPORT_2 MYPORT_2 -show full slave status; +show all slaves status; -stop slave 'slave2'; +stop all slaves; --replace_result $SERVER_MYPORT_1 MYPORT_1 $SERVER_MYPORT_2 MYPORT_2 -show full slave status; +show all slaves status; + +# Ensure that start all slaves doesn't do anything as all slaves are stopped +stop all slaves; # # clean up diff --git a/mysql-test/suite/multi_source/syntax.result b/mysql-test/suite/multi_source/syntax.result index 23ea4d9fd3d..28003c99040 100644 --- a/mysql-test/suite/multi_source/syntax.result +++ b/mysql-test/suite/multi_source/syntax.result @@ -4,8 +4,8 @@ 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 Replicate_Ignore_Server_Ids Master_Server_Id 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 Replicate_Ignore_Server_Ids Master_Server_Id -show full slave status; -Connection_name 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 Replicate_Ignore_Server_Ids Master_Server_Id +show all slaves status; +Connection_name Slave_SQL_State 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 Replicate_Ignore_Server_Ids Master_Server_Id Retried_transactions Max_relay_log_size Executed_log_entries # # Check error handling # @@ -82,8 +82,6 @@ Slave_running ON set @@default_master_connection='qqq'; show status like "Slave_running"; Variable_name Value -Slave_running OFF -Warnings: -Warning 1617 There is no master connection 'qqq' +Slave_running set @@default_master_connection=''; include/rpl_end.inc diff --git a/mysql-test/suite/multi_source/syntax.test b/mysql-test/suite/multi_source/syntax.test index af793fe6100..15e862ab607 100644 --- a/mysql-test/suite/multi_source/syntax.test +++ b/mysql-test/suite/multi_source/syntax.test @@ -5,7 +5,7 @@ source include/master-slave.inc; show slave status; show slave '' status; -show full slave status; +show all slaves status; --echo # --echo # Check error handling diff --git a/mysql-test/suite/rpl/r/rpl_deadlock_innodb.result b/mysql-test/suite/rpl/r/rpl_deadlock_innodb.result index 37d209bbcf6..f2128f8d855 100644 --- a/mysql-test/suite/rpl/r/rpl_deadlock_innodb.result +++ b/mysql-test/suite/rpl/r/rpl_deadlock_innodb.result @@ -76,6 +76,8 @@ include/check_slave_is_running.inc *** Test lock wait timeout and purged relay logs *** SET @my_max_relay_log_size= @@global.max_relay_log_size; SET global max_relay_log_size=0; +Warnings: +Warning 1292 Truncated incorrect max_relay_log_size value: '0' include/stop_slave.inc DELETE FROM t2; CHANGE MASTER TO MASTER_LOG_POS=; diff --git a/mysql-test/suite/rpl/r/rpl_filter_dbs_dynamic.result b/mysql-test/suite/rpl/r/rpl_filter_dbs_dynamic.result index 321b8d912e6..eaa2ed9a61d 100644 --- a/mysql-test/suite/rpl/r/rpl_filter_dbs_dynamic.result +++ b/mysql-test/suite/rpl/r/rpl_filter_dbs_dynamic.result @@ -1,9 +1,9 @@ include/master-slave.inc [connection master] SET @@GLOBAL.replicate_do_db="db1"; -ERROR HY000: This operation cannot be performed with a running slave; run STOP SLAVE first +ERROR HY000: This operation cannot be performed as you have a running slave ''; run STOP SLAVE '' first SET @@GLOBAL.replicate_ignore_db="db2"; -ERROR HY000: This operation cannot be performed with a running slave; run STOP SLAVE first +ERROR HY000: This operation cannot be performed as you have a running slave ''; run STOP SLAVE '' first include/stop_slave.inc SET @@GLOBAL.replicate_do_db="db1"; SET @@GLOBAL.replicate_ignore_db="db2"; diff --git a/mysql-test/suite/rpl/r/rpl_filter_tables_dynamic.result b/mysql-test/suite/rpl/r/rpl_filter_tables_dynamic.result index 9eb803d17ea..3d03d36828a 100644 --- a/mysql-test/suite/rpl/r/rpl_filter_tables_dynamic.result +++ b/mysql-test/suite/rpl/r/rpl_filter_tables_dynamic.result @@ -1,9 +1,9 @@ include/master-slave.inc [connection master] SET @@GLOBAL.replicate_do_table="test.t1,test.t2,test.t3"; -ERROR HY000: This operation cannot be performed with a running slave; run STOP SLAVE first +ERROR HY000: This operation cannot be performed as you have a running slave ''; run STOP SLAVE '' first SET @@GLOBAL.replicate_ignore_table="test.t4,test.t5,test.t6"; -ERROR HY000: This operation cannot be performed with a running slave; run STOP SLAVE first +ERROR HY000: This operation cannot be performed as you have a running slave ''; run STOP SLAVE '' first include/stop_slave.inc SET @@GLOBAL.replicate_do_table="test.t1,test.t2,test.t3"; SET @@GLOBAL.replicate_ignore_table="test.t4,test.t5,test.t6"; diff --git a/mysql-test/suite/rpl/r/rpl_filter_wild_tables_dynamic.result b/mysql-test/suite/rpl/r/rpl_filter_wild_tables_dynamic.result index 6858181234e..19d8e513e6f 100644 --- a/mysql-test/suite/rpl/r/rpl_filter_wild_tables_dynamic.result +++ b/mysql-test/suite/rpl/r/rpl_filter_wild_tables_dynamic.result @@ -1,9 +1,9 @@ include/master-slave.inc [connection master] SET @@GLOBAL.replicate_wild_do_table="test.a%"; -ERROR HY000: This operation cannot be performed with a running slave; run STOP SLAVE first +ERROR HY000: This operation cannot be performed as you have a running slave ''; run STOP SLAVE '' first SET @@GLOBAL.replicate_wild_ignore_table="test.b%"; -ERROR HY000: This operation cannot be performed with a running slave; run STOP SLAVE first +ERROR HY000: This operation cannot be performed as you have a running slave ''; run STOP SLAVE '' first include/stop_slave.inc SET @@GLOBAL.replicate_wild_do_table="test.a%"; SET @@GLOBAL.replicate_wild_ignore_table="test.b%"; diff --git a/mysql-test/suite/rpl/r/rpl_flush_logs.result b/mysql-test/suite/rpl/r/rpl_flush_logs.result index 4fce91a7234..1f543cd9f43 100644 --- a/mysql-test/suite/rpl/r/rpl_flush_logs.result +++ b/mysql-test/suite/rpl/r/rpl_flush_logs.result @@ -8,7 +8,7 @@ flush error logs; # after execute 'flush error logs' statement. # Test if support 'flush relay logs' statement. flush relay logs; -# Check the 'slave-relay-bin.000003' file is created +# Check the 'slave-relay-bin.000003' file is not created # after executed 'flush relay logs' statement. # Make sure binary logs was not be flushed # after execute 'flush relay logs' statement. @@ -30,21 +30,21 @@ flush engine logs; flush binary logs; # Check the 'master-bin.000002' file is created # after executed 'flush binary logs' statement. -# Make sure the 'slave-relay-bin.000006' file does not exist +# Make sure the 'slave-relay-bin.000005' file does not exist # exist before execute 'flush error logs, relay logs' statement. # Test if support to combine all kinds of logs into one statement. flush error logs, relay logs; # Make sure binary logs was not be flushed # after execute 'flush error logs, relay logs' statement. -# Check the 'slave-relay-bin.000006' file is created after +# Check the 'slave-relay-bin.000004' file is created after # execute 'flush error logs, relay logs' statement. -# Make sure the 'slave-relay-bin.000007' and 'slave-relay-bin.000008' +# Make sure the 'slave-relay-bin.000005' and 'slave-relay-bin.000006' # files do not exist before execute 'flush error logs, relay logs' # statement. # Test if 'flush logs' statement works fine and flush all the logs. flush logs; # Check 'master-bin.000003' is created # after execute 'flush logs' statement. -# Check the 'slave-relay-bin.000007' and 'slave-relay-bin.000008' +# Check the 'slave-relay-bin.000005' and 'slave-relay-bin.000006' # files are created after execute 'flush logs' statement. include/rpl_end.inc diff --git a/mysql-test/suite/rpl/r/rpl_heartbeat.result b/mysql-test/suite/rpl/r/rpl_heartbeat.result index d4bdb77ef0b..b0f36558d10 100644 --- a/mysql-test/suite/rpl/r/rpl_heartbeat.result +++ b/mysql-test/suite/rpl/r/rpl_heartbeat.result @@ -41,8 +41,6 @@ show status like 'Slave_heartbeat_period';; Variable_name Slave_heartbeat_period Value 4.000 set @@global.slave_net_timeout= 3 /* must be a warning */; -Warnings: -Warning 1704 The requested value for the heartbeat period exceeds the value of `slave_net_timeout' seconds. A sensible value for the period should be less than the timeout. reset slave; drop table if exists t1; set @@global.slave_net_timeout= 10; diff --git a/mysql-test/suite/rpl/r/rpl_heartbeat_basic.result b/mysql-test/suite/rpl/r/rpl_heartbeat_basic.result index cc9d1f99f7c..0c274165e1e 100644 --- a/mysql-test/suite/rpl/r/rpl_heartbeat_basic.result +++ b/mysql-test/suite/rpl/r/rpl_heartbeat_basic.result @@ -33,8 +33,6 @@ RESET SLAVE; *** Warning if updated slave_net_timeout < slave_heartbeat_timeout *** SET @@global.slave_net_timeout=FLOOR(SLAVE_HEARTBEAT_TIMEOUT)-1; -Warnings: -Warning 1704 The requested value for the heartbeat period exceeds the value of `slave_net_timeout' seconds. A sensible value for the period should be less than the timeout. SET @@global.slave_net_timeout=@restore_slave_net_timeout; RESET SLAVE; diff --git a/mysql-test/suite/rpl/r/rpl_skip_replication.result b/mysql-test/suite/rpl/r/rpl_skip_replication.result index c19f9009021..92b5fa5f629 100644 --- a/mysql-test/suite/rpl/r/rpl_skip_replication.result +++ b/mysql-test/suite/rpl/r/rpl_skip_replication.result @@ -10,7 +10,7 @@ SELECT @@global.replicate_events_marked_for_skip; @@global.replicate_events_marked_for_skip replicate SET GLOBAL replicate_events_marked_for_skip=FILTER_ON_SLAVE; -ERROR HY000: This operation cannot be performed with a running slave; run STOP SLAVE first +ERROR HY000: This operation cannot be performed as you have a running slave ''; run STOP SLAVE '' first SELECT @@global.replicate_events_marked_for_skip; @@global.replicate_events_marked_for_skip replicate diff --git a/mysql-test/suite/rpl/r/rpl_start_slave_deadlock_sys_vars.result b/mysql-test/suite/rpl/r/rpl_start_slave_deadlock_sys_vars.result deleted file mode 100644 index f69a323f980..00000000000 --- a/mysql-test/suite/rpl/r/rpl_start_slave_deadlock_sys_vars.result +++ /dev/null @@ -1,31 +0,0 @@ -include/master-slave.inc -[connection master] -# connection: slave -SET @save_slave_net_timeout = @@GLOBAL.slave_net_timeout; -STOP SLAVE; -include/wait_for_slave_to_stop.inc -# open an extra connection to the slave -# connection: slave2 -# set debug synchronization point -SET DEBUG_SYNC='fix_slave_net_timeout SIGNAL parked WAIT_FOR go'; -# attempt to set slave_net_timeout, will wait on sync point -SET @@GLOBAL.slave_net_timeout = 100; -# connection: slave -SET DEBUG_SYNC='now WAIT_FOR parked'; -# connection: slave1 -# attempt to start the SQL thread -START SLAVE SQL_THREAD; -# connection: slave -# wait until SQL thread has been started -# sleep a bit so that the SQL thread THD handle is initialized -# signal the set slave_net_timeout to continue -SET DEBUG_SYNC='now SIGNAL go'; -# connection: slave2 -# reap result of set slave_net_timeout -# connection: slave1 -# reap result of starting the SQL thread -# disconnect: slave2 -# connection: slave -# cleanup -SET @@GLOBAL.slave_net_timeout = @save_slave_net_timeout; -include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_flush_logs.test b/mysql-test/suite/rpl/t/rpl_flush_logs.test index 6e9de634157..1d19576d47c 100644 --- a/mysql-test/suite/rpl/t/rpl_flush_logs.test +++ b/mysql-test/suite/rpl/t/rpl_flush_logs.test @@ -31,8 +31,9 @@ connection master; flush relay logs; sync_slave_with_master; ---echo # Check the 'slave-relay-bin.000003' file is created +--echo # Check the 'slave-relay-bin.000003' file is not created --echo # after executed 'flush relay logs' statement. +--error 1 file_exists $MYSQLTEST_VARDIR/mysqld.2/data/slave-relay-bin.000003; connection master; @@ -89,10 +90,10 @@ file_exists $MYSQLTEST_VARDIR/mysqld.1/data/master-bin.000001; # Test 'flush error logs, relay logs' statement sync_slave_with_master; ---echo # Make sure the 'slave-relay-bin.000006' file does not exist +--echo # Make sure the 'slave-relay-bin.000005' file does not exist --echo # exist before execute 'flush error logs, relay logs' statement. --error 1 -file_exists $MYSQLTEST_VARDIR/mysqld.2/data/slave-relay-bin.000006; +file_exists $MYSQLTEST_VARDIR/mysqld.2/data/slave-relay-bin.000005; connection master; @@ -107,19 +108,18 @@ file_exists $MYSQLTEST_VARDIR/tmp/master_log.err; file_exists $MYSQLTEST_VARDIR/mysqld.1/data/master-bin.000003; sync_slave_with_master; ---echo # Check the 'slave-relay-bin.000006' file is created after +--echo # Check the 'slave-relay-bin.000004' file is created after --echo # execute 'flush error logs, relay logs' statement. -file_exists $MYSQLTEST_VARDIR/mysqld.2/data/slave-relay-bin.000006; - +file_exists $MYSQLTEST_VARDIR/mysqld.2/data/slave-relay-bin.000004; # Test 'flush logs' statement ---echo # Make sure the 'slave-relay-bin.000007' and 'slave-relay-bin.000008' +--echo # Make sure the 'slave-relay-bin.000005' and 'slave-relay-bin.000006' --echo # files do not exist before execute 'flush error logs, relay logs' --echo # statement. --error 1 -file_exists $MYSQLTEST_VARDIR/mysqld.2/data/slave-relay-bin.000007; +file_exists $MYSQLTEST_VARDIR/mysqld.2/data/slave-relay-bin.000005; --error 1 -file_exists $MYSQLTEST_VARDIR/mysqld.2/data/slave-relay-bin.000008; +file_exists $MYSQLTEST_VARDIR/mysqld.2/data/slave-relay-bin.000006; connection master; @@ -133,9 +133,9 @@ file_exists $MYSQLTEST_VARDIR/tmp/master_log.err; file_exists $MYSQLTEST_VARDIR/mysqld.1/data/master-bin.000003; sync_slave_with_master; ---echo # Check the 'slave-relay-bin.000007' and 'slave-relay-bin.000008' +--echo # Check the 'slave-relay-bin.000005' and 'slave-relay-bin.000006' --echo # files are created after execute 'flush logs' statement. -file_exists $MYSQLTEST_VARDIR/mysqld.2/data/slave-relay-bin.000007; -file_exists $MYSQLTEST_VARDIR/mysqld.2/data/slave-relay-bin.000008; +file_exists $MYSQLTEST_VARDIR/mysqld.2/data/slave-relay-bin.000005; +file_exists $MYSQLTEST_VARDIR/mysqld.2/data/slave-relay-bin.000006; --source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_start_slave_deadlock_sys_vars.test b/mysql-test/suite/rpl/t/rpl_start_slave_deadlock_sys_vars.test deleted file mode 100644 index 3eaff761108..00000000000 --- a/mysql-test/suite/rpl/t/rpl_start_slave_deadlock_sys_vars.test +++ /dev/null @@ -1,57 +0,0 @@ -source include/have_debug_sync.inc; -source include/master-slave.inc; - ---echo # connection: slave -connection slave; -SET @save_slave_net_timeout = @@GLOBAL.slave_net_timeout; -STOP SLAVE; -source include/wait_for_slave_to_stop.inc; - ---echo # open an extra connection to the slave -connect(slave2,127.0.0.1,root,,test,$SLAVE_MYPORT,); ---echo # connection: slave2 ---echo # set debug synchronization point -SET DEBUG_SYNC='fix_slave_net_timeout SIGNAL parked WAIT_FOR go'; ---echo # attempt to set slave_net_timeout, will wait on sync point ---send SET @@GLOBAL.slave_net_timeout = 100 - ---echo # connection: slave -connection slave; -SET DEBUG_SYNC='now WAIT_FOR parked'; - ---echo # connection: slave1 -connection slave1; ---echo # attempt to start the SQL thread ---send START SLAVE SQL_THREAD - ---echo # connection: slave -connection slave; ---echo # wait until SQL thread has been started -let $wait_condition= - select count(*) = 1 from information_schema.processlist - where state = "Waiting for slave thread to start" and info = "START SLAVE SQL_THREAD"; ---source include/wait_condition.inc ---echo # sleep a bit so that the SQL thread THD handle is initialized -sleep 2; ---echo # signal the set slave_net_timeout to continue -SET DEBUG_SYNC='now SIGNAL go'; - ---echo # connection: slave2 -connection slave2; ---echo # reap result of set slave_net_timeout ---reap - ---echo # connection: slave1 -connection slave1; ---echo # reap result of starting the SQL thread ---reap - ---echo # disconnect: slave2 -disconnect slave2; - ---echo # connection: slave -connection slave; ---echo # cleanup -SET @@GLOBAL.slave_net_timeout = @save_slave_net_timeout; - -source include/rpl_end.inc; diff --git a/plugin/semisync/semisync_master_plugin.cc b/plugin/semisync/semisync_master_plugin.cc index b6ff23cd1ad..c811cb1cc9e 100644 --- a/plugin/semisync/semisync_master_plugin.cc +++ b/plugin/semisync/semisync_master_plugin.cc @@ -297,10 +297,10 @@ DEF_SHOW_FUNC(avg_trx_wait_time, SHOW_LONG) static SHOW_VAR semi_sync_master_status_vars[]= { {"Rpl_semi_sync_master_status", (char*) &SHOW_FNAME(status), - SHOW_FUNC}, + SHOW_SIMPLE_FUNC}, {"Rpl_semi_sync_master_clients", (char*) &SHOW_FNAME(clients), - SHOW_FUNC}, + SHOW_SIMPLE_FUNC}, {"Rpl_semi_sync_master_yes_tx", (char*) &rpl_semi_sync_master_yes_transactions, SHOW_LONG}, @@ -309,7 +309,7 @@ static SHOW_VAR semi_sync_master_status_vars[]= { SHOW_LONG}, {"Rpl_semi_sync_master_wait_sessions", (char*) &SHOW_FNAME(wait_sessions), - SHOW_FUNC}, + SHOW_SIMPLE_FUNC}, {"Rpl_semi_sync_master_no_times", (char*) &rpl_semi_sync_master_off_times, SHOW_LONG}, @@ -321,22 +321,22 @@ static SHOW_VAR semi_sync_master_status_vars[]= { SHOW_LONG}, {"Rpl_semi_sync_master_tx_wait_time", (char*) &SHOW_FNAME(trx_wait_time), - SHOW_FUNC}, + SHOW_SIMPLE_FUNC}, {"Rpl_semi_sync_master_tx_waits", (char*) &SHOW_FNAME(trx_wait_num), - SHOW_FUNC}, + SHOW_SIMPLE_FUNC}, {"Rpl_semi_sync_master_tx_avg_wait_time", (char*) &SHOW_FNAME(avg_trx_wait_time), - SHOW_FUNC}, + SHOW_SIMPLE_FUNC}, {"Rpl_semi_sync_master_net_wait_time", (char*) &SHOW_FNAME(net_wait_time), - SHOW_FUNC}, + SHOW_SIMPLE_FUNC}, {"Rpl_semi_sync_master_net_waits", (char*) &SHOW_FNAME(net_wait_num), - SHOW_FUNC}, + SHOW_SIMPLE_FUNC}, {"Rpl_semi_sync_master_net_avg_wait_time", (char*) &SHOW_FNAME(avg_net_wait_time), - SHOW_FUNC}, + SHOW_SIMPLE_FUNC}, {NULL, NULL, SHOW_LONG}, }; diff --git a/sql/item_create.cc b/sql/item_create.cc index 87e90ed4f8b..07e7f7b7ff9 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -4393,7 +4393,7 @@ Create_func_master_pos_wait::create_native(THD *thd, LEX_STRING name, if (item_list != NULL) arg_count= item_list->elements; - if (arg_count < 2 || arg_count >4) + if (arg_count < 2 || arg_count > 4) { my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name.str); return func; @@ -4413,7 +4413,6 @@ Create_func_master_pos_wait::create_native(THD *thd, LEX_STRING name, { Item *param_3= item_list->pop(); func= new (thd->mem_root) Item_master_pos_wait(param_1, param_2, param_3); - thd->lex->safe_to_cache_query= 0; break; } case 4: @@ -4422,7 +4421,6 @@ Create_func_master_pos_wait::create_native(THD *thd, LEX_STRING name, Item *param_4= item_list->pop(); func= new (thd->mem_root) Item_master_pos_wait(param_1, param_2, param_3, param_4); - thd->lex->safe_to_cache_query= 0; break; } } diff --git a/sql/lex.h b/sql/lex.h index 9bf4c439cb6..dab9e2adbc4 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -514,6 +514,7 @@ static SYMBOL symbols[] = { { "SIGNED", SYM(SIGNED_SYM)}, { "SIMPLE", SYM(SIMPLE_SYM)}, { "SLAVE", SYM(SLAVE)}, + { "SLAVES", SYM(SLAVES)}, { "SLOW", SYM(SLOW)}, { "SNAPSHOT", SYM(SNAPSHOT_SYM)}, { "SMALLINT", SYM(SMALLINT)}, diff --git a/sql/log.cc b/sql/log.cc index 6b0507943c3..e664540f0d6 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -3866,7 +3866,7 @@ int MYSQL_BIN_LOG::purge_first_log(Relay_log_info* rli, bool included) DBUG_ENTER("purge_first_log"); DBUG_ASSERT(is_open()); - DBUG_ASSERT(rli->slave_running == 1); + DBUG_ASSERT(rli->slave_running == MYSQL_SLAVE_RUN_NOT_CONNECT); DBUG_ASSERT(!strcmp(rli->linfo.log_file_name,rli->event_relay_log_name)); mysql_mutex_lock(&LOCK_index); diff --git a/sql/log_event.cc b/sql/log_event.cc index 1d525aa94d8..e802c7db16e 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -11247,6 +11247,9 @@ Heartbeat_log_event::Heartbeat_log_event(const char* buf, uint event_len, There is a dummy replacement for this in the embedded library that returns FALSE; this is used by XtraDB to allow it to access replication stuff while still being able to use the same plugin in both stand-alone and embedded. + + In this function it's ok to use active_mi, as this is only called for + the main replication server. */ bool rpl_get_position_info(const char **log_file_name, ulonglong *log_pos, const char **group_relay_log_name, diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 3a89de32b8a..24408849eed 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -496,6 +496,7 @@ ulong binlog_cache_use= 0, binlog_cache_disk_use= 0; ulong binlog_stmt_cache_use= 0, binlog_stmt_cache_disk_use= 0; ulong max_connections, max_connect_errors; ulong extra_max_connections; +ulong slave_retried_transactions; ulonglong denied_connections; my_decimal decimal_zero; @@ -3379,8 +3380,8 @@ SHOW_VAR com_status_vars[]= { {"show_user_statistics", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_USER_STATS]), SHOW_LONG_STATUS}, {"show_variables", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_VARIABLES]), SHOW_LONG_STATUS}, {"show_warnings", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_WARNS]), SHOW_LONG_STATUS}, - {"slave_start", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SLAVE_START]), SHOW_LONG_STATUS}, - {"slave_stop", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SLAVE_STOP]), SHOW_LONG_STATUS}, + {"start_all_slaves", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SLAVE_ALL_START]), SHOW_LONG_STATUS}, + {"start_slave", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SLAVE_START]), SHOW_LONG_STATUS}, {"stmt_close", (char*) offsetof(STATUS_VAR, com_stmt_close), SHOW_LONG_STATUS}, {"stmt_execute", (char*) offsetof(STATUS_VAR, com_stmt_execute), SHOW_LONG_STATUS}, {"stmt_fetch", (char*) offsetof(STATUS_VAR, com_stmt_fetch), SHOW_LONG_STATUS}, @@ -3388,6 +3389,8 @@ SHOW_VAR com_status_vars[]= { {"stmt_reprepare", (char*) offsetof(STATUS_VAR, com_stmt_reprepare), SHOW_LONG_STATUS}, {"stmt_reset", (char*) offsetof(STATUS_VAR, com_stmt_reset), SHOW_LONG_STATUS}, {"stmt_send_long_data", (char*) offsetof(STATUS_VAR, com_stmt_send_long_data), SHOW_LONG_STATUS}, + {"stop_all_slaves", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SLAVE_ALL_STOP]), SHOW_LONG_STATUS}, + {"stop_slave", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SLAVE_STOP]), SHOW_LONG_STATUS}, {"truncate", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_TRUNCATE]), SHOW_LONG_STATUS}, {"uninstall_plugin", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_UNINSTALL_PLUGIN]), SHOW_LONG_STATUS}, {"unlock_tables", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_UNLOCK_TABLES]), SHOW_LONG_STATUS}, @@ -4911,7 +4914,7 @@ int mysqld_main(int argc, char **argv) /* We must have LOCK_open before LOCK_global_system_variables because - LOCK_open is hold while sql_plugin.c::intern_sys_var_ptr() is called. + LOCK_open is held while sql_plugin.c::intern_sys_var_ptr() is called. */ mysql_mutex_record_order(&LOCK_open, &LOCK_global_system_variables); @@ -6532,66 +6535,51 @@ static int show_slave_running(THD *thd, SHOW_VAR *var, char *buff) { Master_info *mi; var->type= SHOW_MY_BOOL; - mysql_mutex_lock(&LOCK_active_mi); var->value= buff; + mysql_mutex_lock(&LOCK_active_mi); mi= master_info_index-> get_master_info(&thd->variables.default_master_connection, - MYSQL_ERROR::WARN_LEVEL_WARN); - *((my_bool *)buff)= (my_bool) (mi && - mi->slave_running == - MYSQL_SLAVE_RUN_CONNECT && - mi->rli.slave_running); - mysql_mutex_unlock(&LOCK_active_mi); - return 0; -} - -static int show_slave_retried_trans(THD *thd, SHOW_VAR *var, char *buff) -{ - /* - TODO: with multimaster, have one such counter per line in - SHOW SLAVE STATUS, and have the sum over all lines here. - */ - mysql_mutex_lock(&LOCK_active_mi); - if (active_mi) - { - var->type= SHOW_LONG; - var->value= buff; - mysql_mutex_lock(&active_mi->rli.data_lock); - *((long *)buff)= (long)active_mi->rli.retried_trans; - mysql_mutex_unlock(&active_mi->rli.data_lock); - } + MYSQL_ERROR::WARN_LEVEL_NOTE); + if (mi) + *((my_bool *)buff)= (my_bool) (mi->slave_running == + MYSQL_SLAVE_RUN_CONNECT && + mi->rli.slave_running); else var->type= SHOW_UNDEF; mysql_mutex_unlock(&LOCK_active_mi); return 0; } + static int show_slave_received_heartbeats(THD *thd, SHOW_VAR *var, char *buff) { + Master_info *mi; + var->type= SHOW_LONGLONG; + var->value= buff; mysql_mutex_lock(&LOCK_active_mi); - if (active_mi) - { - var->type= SHOW_LONGLONG; - var->value= buff; - mysql_mutex_lock(&active_mi->rli.data_lock); - *((longlong *)buff)= active_mi->received_heartbeats; - mysql_mutex_unlock(&active_mi->rli.data_lock); - } + mi= master_info_index-> + get_master_info(&thd->variables.default_master_connection, + MYSQL_ERROR::WARN_LEVEL_NOTE); + if (mi) + *((longlong *)buff)= mi->received_heartbeats; else var->type= SHOW_UNDEF; mysql_mutex_unlock(&LOCK_active_mi); return 0; } + static int show_heartbeat_period(THD *thd, SHOW_VAR *var, char *buff) { + Master_info *mi; + var->type= SHOW_CHAR; + var->value= buff; mysql_mutex_lock(&LOCK_active_mi); - if (active_mi) - { - var->type= SHOW_CHAR; - var->value= buff; - sprintf(buff, "%.3f", active_mi->heartbeat_period); - } + mi= master_info_index-> + get_master_info(&thd->variables.default_master_connection, + MYSQL_ERROR::WARN_LEVEL_NOTE); + if (mi) + sprintf(buff, "%.3f", mi->heartbeat_period); else var->type= SHOW_UNDEF; mysql_mutex_unlock(&LOCK_active_mi); @@ -6952,7 +6940,7 @@ SHOW_VAR status_vars[]= { {"Bytes_sent", (char*) offsetof(STATUS_VAR, bytes_sent), SHOW_LONGLONG_STATUS}, {"Binlog_bytes_written", (char*) offsetof(STATUS_VAR, binlog_bytes_written), SHOW_LONGLONG_STATUS}, {"Com", (char*) com_status_vars, SHOW_ARRAY}, - {"Compression", (char*) &show_net_compression, SHOW_FUNC}, + {"Compression", (char*) &show_net_compression, SHOW_SIMPLE_FUNC}, {"Connections", (char*) &thread_id, SHOW_LONG_NOFLUSH}, {"Cpu_time", (char*) offsetof(STATUS_VAR, cpu_time), SHOW_DOUBLE_STATUS}, {"Created_tmp_disk_tables", (char*) offsetof(STATUS_VAR, created_tmp_disk_tables), SHOW_LONG_STATUS}, @@ -7006,13 +6994,13 @@ SHOW_VAR status_vars[]= { {"Not_flushed_delayed_rows", (char*) &delayed_rows_in_use, SHOW_LONG_NOFLUSH}, {"Open_files", (char*) &my_file_opened, SHOW_LONG_NOFLUSH}, {"Open_streams", (char*) &my_stream_opened, SHOW_LONG_NOFLUSH}, - {"Open_table_definitions", (char*) &show_table_definitions, SHOW_FUNC}, - {"Open_tables", (char*) &show_open_tables, SHOW_FUNC}, + {"Open_table_definitions", (char*) &show_table_definitions, SHOW_SIMPLE_FUNC}, + {"Open_tables", (char*) &show_open_tables, SHOW_SIMPLE_FUNC}, {"Opened_files", (char*) &my_file_total_opened, SHOW_LONG_NOFLUSH}, {"Opened_tables", (char*) offsetof(STATUS_VAR, opened_tables), SHOW_LONG_STATUS}, {"Opened_table_definitions", (char*) offsetof(STATUS_VAR, opened_shares), SHOW_LONG_STATUS}, {"Opened_views", (char*) offsetof(STATUS_VAR, opened_views), SHOW_LONG_STATUS}, - {"Prepared_stmt_count", (char*) &show_prepared_stmt_count, SHOW_FUNC}, + {"Prepared_stmt_count", (char*) &show_prepared_stmt_count, SHOW_SIMPLE_FUNC}, {"Rows_sent", (char*) offsetof(STATUS_VAR, rows_sent), SHOW_LONGLONG_STATUS}, {"Rows_read", (char*) offsetof(STATUS_VAR, rows_read), SHOW_LONGLONG_STATUS}, {"Rows_tmp_read", (char*) offsetof(STATUS_VAR, rows_tmp_read), SHOW_LONGLONG_STATUS}, @@ -7026,10 +7014,10 @@ SHOW_VAR status_vars[]= { {"Qcache_queries_in_cache", (char*) &query_cache.queries_in_cache, SHOW_LONG_NOFLUSH}, {"Qcache_total_blocks", (char*) &query_cache.total_blocks, SHOW_LONG_NOFLUSH}, #endif /*HAVE_QUERY_CACHE*/ - {"Queries", (char*) &show_queries, SHOW_FUNC}, + {"Queries", (char*) &show_queries, SHOW_SIMPLE_FUNC}, {"Questions", (char*) offsetof(STATUS_VAR, questions), SHOW_LONG_STATUS}, #ifdef HAVE_REPLICATION - {"Rpl_status", (char*) &show_rpl_status, SHOW_FUNC}, + {"Rpl_status", (char*) &show_rpl_status, SHOW_SIMPLE_FUNC}, #endif {"Select_full_join", (char*) offsetof(STATUS_VAR, select_full_join_count), SHOW_LONG_STATUS}, {"Select_full_range_join", (char*) offsetof(STATUS_VAR, select_full_range_join_count), SHOW_LONG_STATUS}, @@ -7038,10 +7026,10 @@ SHOW_VAR status_vars[]= { {"Select_scan", (char*) offsetof(STATUS_VAR, select_scan_count), SHOW_LONG_STATUS}, {"Slave_open_temp_tables", (char*) &slave_open_temp_tables, SHOW_LONG}, #ifdef HAVE_REPLICATION - {"Slave_retried_transactions",(char*) &show_slave_retried_trans, SHOW_FUNC}, - {"Slave_heartbeat_period", (char*) &show_heartbeat_period, SHOW_FUNC}, - {"Slave_received_heartbeats",(char*) &show_slave_received_heartbeats, SHOW_FUNC}, - {"Slave_running", (char*) &show_slave_running, SHOW_FUNC}, + {"Slave_retried_transactions",(char*)&slave_retried_transactions, SHOW_LONG}, + {"Slave_heartbeat_period", (char*) &show_heartbeat_period, SHOW_SIMPLE_FUNC}, + {"Slave_received_heartbeats",(char*) &show_slave_received_heartbeats, SHOW_SIMPLE_FUNC}, + {"Slave_running", (char*) &show_slave_running, SHOW_SIMPLE_FUNC}, #endif {"Slow_launch_threads", (char*) &slow_launch_threads, SHOW_LONG}, {"Slow_queries", (char*) offsetof(STATUS_VAR, long_query_count), SHOW_LONG_STATUS}, @@ -7051,29 +7039,29 @@ SHOW_VAR status_vars[]= { {"Sort_scan", (char*) offsetof(STATUS_VAR, filesort_scan_count), SHOW_LONG_STATUS}, #ifdef HAVE_OPENSSL #ifndef EMBEDDED_LIBRARY - {"Ssl_accept_renegotiates", (char*) &show_ssl_ctx_sess_accept_renegotiate, SHOW_FUNC}, - {"Ssl_accepts", (char*) &show_ssl_ctx_sess_accept, SHOW_FUNC}, - {"Ssl_callback_cache_hits", (char*) &show_ssl_ctx_sess_cb_hits, SHOW_FUNC}, - {"Ssl_cipher", (char*) &show_ssl_get_cipher, SHOW_FUNC}, - {"Ssl_cipher_list", (char*) &show_ssl_get_cipher_list, SHOW_FUNC}, - {"Ssl_client_connects", (char*) &show_ssl_ctx_sess_connect, SHOW_FUNC}, - {"Ssl_connect_renegotiates", (char*) &show_ssl_ctx_sess_connect_renegotiate, SHOW_FUNC}, - {"Ssl_ctx_verify_depth", (char*) &show_ssl_ctx_get_verify_depth, SHOW_FUNC}, - {"Ssl_ctx_verify_mode", (char*) &show_ssl_ctx_get_verify_mode, SHOW_FUNC}, - {"Ssl_default_timeout", (char*) &show_ssl_get_default_timeout, SHOW_FUNC}, - {"Ssl_finished_accepts", (char*) &show_ssl_ctx_sess_accept_good, SHOW_FUNC}, - {"Ssl_finished_connects", (char*) &show_ssl_ctx_sess_connect_good, SHOW_FUNC}, - {"Ssl_session_cache_hits", (char*) &show_ssl_ctx_sess_hits, SHOW_FUNC}, - {"Ssl_session_cache_misses", (char*) &show_ssl_ctx_sess_misses, SHOW_FUNC}, - {"Ssl_session_cache_mode", (char*) &show_ssl_ctx_get_session_cache_mode, SHOW_FUNC}, - {"Ssl_session_cache_overflows", (char*) &show_ssl_ctx_sess_cache_full, SHOW_FUNC}, - {"Ssl_session_cache_size", (char*) &show_ssl_ctx_sess_get_cache_size, SHOW_FUNC}, - {"Ssl_session_cache_timeouts", (char*) &show_ssl_ctx_sess_timeouts, SHOW_FUNC}, - {"Ssl_sessions_reused", (char*) &show_ssl_session_reused, SHOW_FUNC}, - {"Ssl_used_session_cache_entries",(char*) &show_ssl_ctx_sess_number, SHOW_FUNC}, - {"Ssl_verify_depth", (char*) &show_ssl_get_verify_depth, SHOW_FUNC}, - {"Ssl_verify_mode", (char*) &show_ssl_get_verify_mode, SHOW_FUNC}, - {"Ssl_version", (char*) &show_ssl_get_version, SHOW_FUNC}, + {"Ssl_accept_renegotiates", (char*) &show_ssl_ctx_sess_accept_renegotiate, SHOW_SIMPLE_FUNC}, + {"Ssl_accepts", (char*) &show_ssl_ctx_sess_accept, SHOW_SIMPLE_FUNC}, + {"Ssl_callback_cache_hits", (char*) &show_ssl_ctx_sess_cb_hits, SHOW_SIMPLE_FUNC}, + {"Ssl_cipher", (char*) &show_ssl_get_cipher, SHOW_SIMPLE_FUNC}, + {"Ssl_cipher_list", (char*) &show_ssl_get_cipher_list, SHOW_SIMPLE_FUNC}, + {"Ssl_client_connects", (char*) &show_ssl_ctx_sess_connect, SHOW_SIMPLE_FUNC}, + {"Ssl_connect_renegotiates", (char*) &show_ssl_ctx_sess_connect_renegotiate, SHOW_SIMPLE_FUNC}, + {"Ssl_ctx_verify_depth", (char*) &show_ssl_ctx_get_verify_depth, SHOW_SIMPLE_FUNC}, + {"Ssl_ctx_verify_mode", (char*) &show_ssl_ctx_get_verify_mode, SHOW_SIMPLE_FUNC}, + {"Ssl_default_timeout", (char*) &show_ssl_get_default_timeout, SHOW_SIMPLE_FUNC}, + {"Ssl_finished_accepts", (char*) &show_ssl_ctx_sess_accept_good, SHOW_SIMPLE_FUNC}, + {"Ssl_finished_connects", (char*) &show_ssl_ctx_sess_connect_good, SHOW_SIMPLE_FUNC}, + {"Ssl_session_cache_hits", (char*) &show_ssl_ctx_sess_hits, SHOW_SIMPLE_FUNC}, + {"Ssl_session_cache_misses", (char*) &show_ssl_ctx_sess_misses, SHOW_SIMPLE_FUNC}, + {"Ssl_session_cache_mode", (char*) &show_ssl_ctx_get_session_cache_mode, SHOW_SIMPLE_FUNC}, + {"Ssl_session_cache_overflows", (char*) &show_ssl_ctx_sess_cache_full, SHOW_SIMPLE_FUNC}, + {"Ssl_session_cache_size", (char*) &show_ssl_ctx_sess_get_cache_size, SHOW_SIMPLE_FUNC}, + {"Ssl_session_cache_timeouts", (char*) &show_ssl_ctx_sess_timeouts, SHOW_SIMPLE_FUNC}, + {"Ssl_sessions_reused", (char*) &show_ssl_session_reused, SHOW_SIMPLE_FUNC}, + {"Ssl_used_session_cache_entries",(char*) &show_ssl_ctx_sess_number, SHOW_SIMPLE_FUNC}, + {"Ssl_verify_depth", (char*) &show_ssl_get_verify_depth, SHOW_SIMPLE_FUNC}, + {"Ssl_verify_mode", (char*) &show_ssl_get_verify_mode, SHOW_SIMPLE_FUNC}, + {"Ssl_version", (char*) &show_ssl_get_version, SHOW_SIMPLE_FUNC}, #endif #endif /* HAVE_OPENSSL */ {"Syncs", (char*) &my_sync_count, SHOW_LONG_NOFLUSH}, @@ -7091,16 +7079,16 @@ SHOW_VAR status_vars[]= { {"Tc_log_page_waits", (char*) &tc_log_page_waits, SHOW_LONG}, #endif #ifdef HAVE_POOL_OF_THREADS - {"Threadpool_idle_threads", (char *) &show_threadpool_idle_threads, SHOW_FUNC}, + {"Threadpool_idle_threads", (char *) &show_threadpool_idle_threads, SHOW_SIMPLE_FUNC}, {"Threadpool_threads", (char *) &tp_stats.num_worker_threads, SHOW_INT}, #endif {"Threads_cached", (char*) &cached_thread_count, SHOW_LONG_NOFLUSH}, {"Threads_connected", (char*) &connection_count, SHOW_INT}, {"Threads_created", (char*) &thread_created, SHOW_LONG_NOFLUSH}, {"Threads_running", (char*) &thread_running, SHOW_INT}, - {"Uptime", (char*) &show_starttime, SHOW_FUNC}, + {"Uptime", (char*) &show_starttime, SHOW_SIMPLE_FUNC}, #ifdef ENABLED_PROFILING - {"Uptime_since_flush_status",(char*) &show_flushstatustime, SHOW_FUNC}, + {"Uptime_since_flush_status",(char*) &show_flushstatustime, SHOW_SIMPLE_FUNC}, #endif {NullS, NullS, SHOW_LONG} }; @@ -7299,6 +7287,7 @@ static int mysql_init_variables(void) protocol_version= PROTOCOL_VERSION; what_to_log= ~ (1L << (uint) COM_TIME); refresh_version= 1L; /* Increments on each reload */ + denied_connections= 0; executed_events= 0; global_query_id= thread_id= 1L; my_atomic_rwlock_init(&global_query_id_lock); @@ -7326,6 +7315,7 @@ static int mysql_init_variables(void) relay_log_info_file= (char*) "relay-log.info"; report_user= report_password = report_host= 0; /* TO BE DELETED */ opt_relay_logname= opt_relaylog_index_name= 0; + slave_retried_transactions= 0; /* Variables in libraries */ charsets_dir= 0; diff --git a/sql/mysqld.h b/sql/mysqld.h index 4250898cc5b..430811a956c 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -95,6 +95,7 @@ extern my_bool opt_safe_user_create; extern my_bool opt_safe_show_db, opt_local_infile, opt_myisam_use_mmap; extern my_bool opt_slave_compressed_protocol, use_temp_pool; extern ulong slave_exec_mode_options; +extern ulong slave_retried_transactions; extern ulonglong slave_type_conversions_options; extern my_bool read_only, opt_readonly; extern my_bool lower_case_file_system; diff --git a/sql/rpl_mi.cc b/sql/rpl_mi.cc index 1491d970472..e004e3495c7 100644 --- a/sql/rpl_mi.cc +++ b/sql/rpl_mi.cc @@ -21,6 +21,7 @@ #include "rpl_mi.h" #include "slave.h" // SLAVE_MAX_HEARTBEAT_PERIOD #include "strfunc.h" +#include "sql_repl.h" #ifdef HAVE_REPLICATION @@ -42,7 +43,10 @@ Master_info::Master_info(LEX_STRING *connection_name_arg, ssl_ca[0]= 0; ssl_capath[0]= 0; ssl_cert[0]= 0; ssl_cipher[0]= 0; ssl_key[0]= 0; - /* Store connection name and lower case connection name */ + /* + Store connection name and lower case connection name + It's safe to ignore any OMM errors as this is checked by error() + */ connection_name.length= cmp_connection_name.length= connection_name_arg->length; if ((connection_name.str= (char*) my_malloc(connection_name_arg->length*2+2, @@ -599,7 +603,7 @@ void free_key_master_info(Master_info *mi) /** Check if connection name for master_info is valid. - It's valid if it's a valid system name, is less than + It's valid if it's a valid system name of length less than MAX_CONNECTION_NAME. @return @@ -616,7 +620,7 @@ bool check_master_connection_name(LEX_STRING *name) /** - Create a log file with a signed suffix. + Create a log file with a given suffix. @param res_file_name Store result here @@ -635,7 +639,7 @@ bool check_master_connection_name(LEX_STRING *name) file names without a prefix. */ -void create_signed_file_name(char *res_file_name, uint length, +void create_logfile_name_with_suffix(char *res_file_name, uint length, const char *info_file, bool append, LEX_STRING *suffix) { @@ -761,9 +765,9 @@ bool Master_info_index::init_all_master_info() lock_slave_threads(mi); init_thread_mask(&thread_mask,mi,0 /*not inverse*/); - create_signed_file_name(buf_master_info_file, sizeof(buf_master_info_file), + create_logfile_name_with_suffix(buf_master_info_file, sizeof(buf_master_info_file), master_info_file, 0, &connection_name); - create_signed_file_name(buf_relay_log_info_file, + create_logfile_name_with_suffix(buf_relay_log_info_file, sizeof(buf_relay_log_info_file), relay_log_info_file, 0, &connection_name); if (global_system_variables.log_warnings > 1) @@ -827,7 +831,7 @@ bool Master_info_index::init_all_master_info() buf_relay_log_info_file, SLAVE_IO | SLAVE_SQL)) { - sql_print_error("Failed to create slave threads for connection %.*s", + sql_print_error("Failed to create slave threads for connection '%.*s'", (int) connection_name.length, connection_name.str); continue; @@ -1033,8 +1037,7 @@ bool Master_info_index::remove_master_info(LEX_STRING *name) } // Rewrite Master_info.index - uint i; - for (i= 0; i< master_info_hash.records; ++i) + for (uint i= 0; i< master_info_hash.records; ++i) { Master_info *tmp_mi; tmp_mi= (Master_info *) my_hash_element(&master_info_hash, i); @@ -1046,4 +1049,127 @@ bool Master_info_index::remove_master_info(LEX_STRING *name) DBUG_RETURN(FALSE); } + +/** + Master_info_index::give_error_if_slave_running() + + @return + TRUE If some slave is running. An error is printed + FALSE No slave is running +*/ + +bool Master_info_index::give_error_if_slave_running() +{ + DBUG_ENTER("warn_if_slave_running"); + mysql_mutex_assert_owner(&LOCK_active_mi); + + for (uint i= 0; i< master_info_hash.records; ++i) + { + Master_info *mi; + mi= (Master_info *) my_hash_element(&master_info_hash, i); + if (mi->rli.slave_running != MYSQL_SLAVE_NOT_RUN) + { + my_error(ER_SLAVE_MUST_STOP, MYF(0), (int) mi->connection_name.length, + mi->connection_name.str); + DBUG_RETURN(TRUE); + } + } + DBUG_RETURN(FALSE); +} + + +/** + Master_info_index::start_all_slaves() + + Start all slaves that was not running. + + @return + TRUE Error + FALSE Everything ok. +*/ + +bool Master_info_index::start_all_slaves(THD *thd) +{ + bool result= FALSE; + DBUG_ENTER("warn_if_slave_running"); + mysql_mutex_assert_owner(&LOCK_active_mi); + + for (uint i= 0; i< master_info_hash.records; ++i) + { + int error; + Master_info *mi; + mi= (Master_info *) my_hash_element(&master_info_hash, i); + + /* + Try to start all slaves that are configured (host is defined) + and are not already running + */ + if ((mi->slave_running != MYSQL_SLAVE_RUN_CONNECT || + !mi->rli.slave_running) && *mi->host) + { + if ((error= start_slave(thd, mi, 1))) + { + my_error(ER_CANT_START_STOP_SLAVE, MYF(0), + "START", + (int) mi->connection_name.length, + mi->connection_name.str); + result= 1; + if (error < 0) // fatal error + break; + } + else + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, + ER_SLAVE_STARTED, ER(ER_SLAVE_STARTED), + (int) mi->connection_name.length, + mi->connection_name.str); + } + } + DBUG_RETURN(result); +} + + +/** + Master_info_index::stop_all_slaves() + + Start all slaves that was not running. + + @return + TRUE Error + FALSE Everything ok. +*/ + +bool Master_info_index::stop_all_slaves(THD *thd) +{ + bool result= FALSE; + DBUG_ENTER("warn_if_slave_running"); + mysql_mutex_assert_owner(&LOCK_active_mi); + + for (uint i= 0; i< master_info_hash.records; ++i) + { + int error; + Master_info *mi; + mi= (Master_info *) my_hash_element(&master_info_hash, i); + if ((mi->slave_running != MYSQL_SLAVE_NOT_RUN || + mi->rli.slave_running)) + { + if ((error= stop_slave(thd, mi, 1))) + { + my_error(ER_CANT_START_STOP_SLAVE, MYF(0), + "STOP", + (int) mi->connection_name.length, + mi->connection_name.str); + result= 1; + if (error < 0) // Fatal error + break; + } + else + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, + ER_SLAVE_STOPPED, ER(ER_SLAVE_STOPPED), + (int) mi->connection_name.length, + mi->connection_name.str); + } + } + DBUG_RETURN(result); +} + #endif /* HAVE_REPLICATION */ diff --git a/sql/rpl_mi.h b/sql/rpl_mi.h index 6c7bd3a5d28..48fdd3937c5 100644 --- a/sql/rpl_mi.h +++ b/sql/rpl_mi.h @@ -70,7 +70,7 @@ class Master_info : public Slave_reporting_capability } /* the variables below are needed because we can change masters on the fly */ - char master_log_name[FN_REFLEN+6]; /* Place for multi-*/ + char master_log_name[FN_REFLEN+6]; /* Room for multi-*/ char host[HOSTNAME_LENGTH+1]; char user[USERNAME_LENGTH+1]; char password[MAX_PASSWORD_LENGTH+1]; @@ -164,10 +164,13 @@ public: bool remove_master_info(LEX_STRING *connection_name); Master_info *get_master_info(LEX_STRING *connection_name, MYSQL_ERROR::enum_warning_level warning); + bool give_error_if_slave_running(); + bool start_all_slaves(THD *thd); + bool stop_all_slaves(THD *thd); }; bool check_master_connection_name(LEX_STRING *name); -void create_signed_file_name(char *res_file_name, uint length, +void create_logfile_name_with_suffix(char *res_file_name, uint length, const char *info_file, bool append, LEX_STRING *suffix); diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index 362ebab9fa0..e74831464fa 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -50,7 +50,7 @@ Relay_log_info::Relay_log_info(bool is_slave_recovery) last_master_timestamp(0), slave_skip_counter(0), abort_pos_wait(0), slave_run_id(0), sql_thd(0), inited(0), abort_slave(0), slave_running(0), until_condition(UNTIL_NONE), - until_log_pos(0), retried_trans(0), + until_log_pos(0), retried_trans(0), executed_entries(0), tables_to_lock(0), tables_to_lock_count(0), last_event_start_time(0), deferred_events(NULL),m_flags(0), row_stmt_start_timestamp(0), long_find_row_note_printed(false), @@ -203,14 +203,14 @@ a file name for --relay-log-index option", opt_relaylog_index_name); char buf_relay_logname[FN_REFLEN], buf_relaylog_index_name_buff[FN_REFLEN]; char *buf_relaylog_index_name= opt_relaylog_index_name; - create_signed_file_name(buf_relay_logname, sizeof(buf_relay_logname), + create_logfile_name_with_suffix(buf_relay_logname, sizeof(buf_relay_logname), ln, 1, &mi->connection_name); ln= buf_relay_logname; if (opt_relaylog_index_name) { buf_relaylog_index_name= buf_relaylog_index_name_buff; - create_signed_file_name(buf_relaylog_index_name_buff, + create_logfile_name_with_suffix(buf_relaylog_index_name_buff, sizeof(buf_relaylog_index_name_buff), opt_relaylog_index_name, 0, &mi->connection_name); diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h index c543b4d3198..6144d37026b 100644 --- a/sql/rpl_rli.h +++ b/sql/rpl_rli.h @@ -228,8 +228,9 @@ public: Needed for problems when slave stops and we want to restart it skipping one or more events in the master log that have caused errors, and have been manually applied by DBA already. + Must be ulong as it's refered to from set_var.cc */ - volatile ulong slave_skip_counter; /* Must be ulong */ + volatile ulong slave_skip_counter; volatile ulong abort_pos_wait; /* Incremented on change master */ volatile ulong slave_run_id; /* Incremented on slave start */ ulong max_relay_log_size; @@ -286,6 +287,7 @@ public: slave started. */ ulong trans_retries, retried_trans; + ulong executed_entries; /* For SLAVE STATUS */ /* If the end of the hot relay log is made of master's events ignored by the diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index 803575b7ba0..3832ee150e3 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -4271,18 +4271,18 @@ ER_TRANS_CACHE_FULL swe "Transaktionen krävde mera än 'max_binlog_cache_size' minne. Öka denna mysqld-variabel och försök pÃ¥ nytt" ukr "Ð¢Ñ€Ð°Ð½Ð·Ð°ÐºÑ†Ñ–Ñ Ð· багатьма виразами вимагає більше ніж 'max_binlog_cache_size' байтів Ð´Ð»Ñ Ð·Ð±ÐµÑ€Ñ–Ð³Ð°Ð½Ð½Ñ. Збільште цю змінну mysqld та Ñпробуйте знову" ER_SLAVE_MUST_STOP - dan "Denne handling kunne ikke udføres med kørende slave, brug først kommandoen STOP SLAVE" - nla "Deze operatie kan niet worden uitgevoerd met een actieve slave, doe eerst STOP SLAVE" - eng "This operation cannot be performed with a running slave; run STOP SLAVE first" - fre "Cette opération ne peut être réalisée avec un esclave actif, faites STOP SLAVE d'abord" - ger "Diese Operation kann bei einem aktiven Slave nicht durchgeführt werden. Bitte zuerst STOP SLAVE ausführen" - ita "Questa operazione non puo' essere eseguita con un database 'slave' che gira, lanciare prima STOP SLAVE" - por "Esta operação não pode ser realizada com um 'slave' em execução. Execute STOP SLAVE primeiro" - rus "Эту операцию невозможно выполнить при работающем потоке подчиненного Ñервера. Сначала выполните STOP SLAVE" - serbian "Ova operacija ne može biti izvrÅ¡ena dok je aktivan podreÄ‘eni server. Zadajte prvo komandu 'STOP SLAVE' da zaustavite podreÄ‘eni server." - spa "Esta operación no puede ser hecha con el esclavo funcionando, primero use STOP SLAVE" - swe "Denna operation kan inte göras under replikering; Gör STOP SLAVE först" - ukr "ÐžÐ¿ÐµÑ€Ð°Ñ†Ñ–Ñ Ð½Ðµ може бути виконана з запущеним підлеглим, Ñпочатку виконайте STOP SLAVE" + dan "Denne handling kunne ikke udføres med kørende slave '%2$*1$s', brug først kommandoen STOP SLAVE '%2$*1$s'" + nla "Deze operatie kan niet worden uitgevoerd met een actieve slave '%2$*1$s', doe eerst STOP SLAVE '%2$*1$s'" + eng "This operation cannot be performed as you have a running slave '%2$*1$s'; run STOP SLAVE '%2$*1$s' first" + fre "Cette opération ne peut être réalisée avec un esclave '%2$*1$s' actif, faites STOP SLAVE '%2$*1$s' d'abord" + ger "Diese Operation kann bei einem aktiven Slave '%2$*1$s' nicht durchgeführt werden. Bitte zuerst STOP SLAVE '%2$*1$s' ausführen" + ita "Questa operazione non puo' essere eseguita con un database 'slave' '%2$*1$s' che gira, lanciare prima STOP SLAVE '%2$*1$s'" + por "Esta operação não pode ser realizada com um 'slave' '%2$*1$s' em execução. Execute STOP SLAVE '%2$*1$s' primeiro" + rus "Эту операцию невозможно выполнить при работающем потоке подчиненного Ñервера %2$*1$s. Сначала выполните STOP SLAVE '%2$*1$s'" + serbian "Ova operacija ne može biti izvrÅ¡ena dok je aktivan podreÄ‘eni '%2$*1$s' server. Zadajte prvo komandu 'STOP SLAVE '%2$*1$s'' da zaustavite podreÄ‘eni server." + spa "Esta operación no puede ser hecha con el esclavo '%2$*1$s' funcionando, primero use STOP SLAVE '%2$*1$s'" + swe "Denna operation kan inte göras under replikering; Du har en aktiv förbindelse till '%2$*1$s'. Gör STOP SLAVE '%2$*1$s' först" + ukr "ÐžÐ¿ÐµÑ€Ð°Ñ†Ñ–Ñ Ð½Ðµ може бути виконана з запущеним підлеглим '%2$*1$s', Ñпочатку виконайте STOP SLAVE '%2$*1$s'" ER_SLAVE_NOT_RUNNING dan "Denne handling kræver en kørende slave. Konfigurer en slave og brug kommandoen START SLAVE" nla "Deze operatie vereist een actieve slave, configureer slave en doe dan START SLAVE" @@ -6592,3 +6592,9 @@ ER_CONNECTION_ALREADY_EXISTS eng "Connection '%.*s' conflicts with existing connection '%.*s'" ER_MASTER_LOG_PREFIX eng "Master '%.*s': " +ER_CANT_START_STOP_SLAVE + eng "Can't %s SLAVE '%.*s'" +ER_SLAVE_STARTED + eng "SLAVE '%.*s' started" +ER_SLAVE_STOPPED + eng "SLAVE '%.*s' stopped" diff --git a/sql/slave.cc b/sql/slave.cc index 8254e90b369..efaf25b3456 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -162,7 +162,7 @@ static int terminate_slave_thread(THD *thd, volatile uint *slave_running, bool skip_lock); static bool check_io_slave_killed(THD *thd, Master_info *mi, const char *info); -static bool send_show_master_info_header(THD *thd, Master_info *mi, bool full); +static bool send_show_master_info_header(THD *thd, bool full); static bool send_show_master_info_data(THD *thd, Master_info *mi, bool full); /* @@ -1863,9 +1863,9 @@ Waiting for the slave SQL thread to free enough relay log space"); #endif if (rli->sql_force_rotate_relay) { - mysql_mutex_lock(&active_mi->data_lock); + mysql_mutex_lock(&mi->data_lock); rotate_relay_log(rli->mi); - mysql_mutex_unlock(&active_mi->data_lock); + mysql_mutex_unlock(&mi->data_lock); rli->sql_force_rotate_relay= false; } @@ -2024,7 +2024,7 @@ bool show_master_info(THD *thd, Master_info *mi, bool full) { DBUG_ENTER("show_master_info"); - if (send_show_master_info_header(thd, mi, full)) + if (send_show_master_info_header(thd, full)) DBUG_RETURN(TRUE); if (send_show_master_info_data(thd, mi, full)) DBUG_RETURN(TRUE); @@ -2032,18 +2032,23 @@ bool show_master_info(THD *thd, Master_info *mi, bool full) DBUG_RETURN(FALSE); } -static bool send_show_master_info_header(THD *thd, Master_info *mi, bool full) +static bool send_show_master_info_header(THD *thd, bool full) { List field_list; Protocol *protocol= thd->protocol; + Master_info *mi; DBUG_ENTER("show_master_info_header"); if (full) + { field_list.push_back(new Item_empty_string("Connection_name", MAX_CONNECTION_NAME)); + field_list.push_back(new Item_empty_string("Slave_SQL_State", + 30)); + } field_list.push_back(new Item_empty_string("Slave_IO_State", - 14)); + 30)); field_list.push_back(new Item_empty_string("Master_Host", sizeof(mi->host))); field_list.push_back(new Item_empty_string("Master_User", @@ -2106,7 +2111,15 @@ static bool send_show_master_info_header(THD *thd, Master_info *mi, bool full) FN_REFLEN)); field_list.push_back(new Item_return_int("Master_Server_Id", sizeof(ulong), MYSQL_TYPE_LONG)); - + if (full) + { + field_list.push_back(new Item_return_int("Retried_transactions", + 10, MYSQL_TYPE_LONG)); + field_list.push_back(new Item_return_int("Max_relay_log_size", + 10, MYSQL_TYPE_LONGLONG)); + field_list.push_back(new Item_return_int("Executed_log_entries", + 10, MYSQL_TYPE_LONG)); + } if (protocol->send_result_set_metadata(&field_list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) DBUG_RETURN(TRUE); @@ -2134,6 +2147,9 @@ static bool send_show_master_info_data(THD *thd, Master_info *mi, bool full) protocol->store(mi->connection_name.str, mi->connection_name.length, &my_charset_bin); mysql_mutex_lock(&mi->run_lock); + if (full) + protocol->store(mi->rli.sql_thd ? mi->rli.sql_thd->proc_info : "", + &my_charset_bin); protocol->store(mi->io_thd ? mi->io_thd->proc_info : "", &my_charset_bin); mysql_mutex_unlock(&mi->run_lock); @@ -2266,6 +2282,12 @@ static bool send_show_master_info_data(THD *thd, Master_info *mi, bool full) } // Master_Server_id protocol->store((uint32) mi->master_id); + if (full) + { + protocol->store((uint32) mi->rli.retried_trans); + protocol->store((ulonglong) mi->rli.max_relay_log_size); + protocol->store((uint32) mi->rli.executed_entries); + } mysql_mutex_unlock(&mi->rli.err_lock); mysql_mutex_unlock(&mi->err_lock); @@ -2299,6 +2321,9 @@ static int cmp_mi_by_name(const Master_info **arg1, @retval FALSE success @retval TRUE failure + + @note + master_info_index is protected by LOCK_active_mi. */ bool show_all_master_info(THD* thd) @@ -2306,8 +2331,9 @@ bool show_all_master_info(THD* thd) uint i, elements; Master_info **tmp; DBUG_ENTER("show_master_info"); + mysql_mutex_assert_owner(&LOCK_active_mi); - if (send_show_master_info_header(thd, active_mi, 1)) + if (send_show_master_info_header(thd, 1)) DBUG_RETURN(TRUE); if (!(elements= master_info_index->master_info_hash.records)) @@ -2973,6 +2999,7 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli) mysql_mutex_lock(&rli->data_lock); // because of SHOW STATUS rli->trans_retries++; rli->retried_trans++; + statistic_increment(slave_retried_transactions, LOCK_status); mysql_mutex_unlock(&rli->data_lock); DBUG_PRINT("info", ("Slave retries transaction " "rli->trans_retries: %lu", rli->trans_retries)); @@ -3156,7 +3183,7 @@ pthread_handler_t handle_slave_io(void *arg) mysql_mutex_lock(&LOCK_thread_count); threads.append(thd); mysql_mutex_unlock(&LOCK_thread_count); - mi->slave_running = 1; + mi->slave_running = MYSQL_SLAVE_RUN_NOT_CONNECT; mi->abort_slave = 0; mysql_mutex_unlock(&mi->run_lock); mysql_cond_broadcast(&mi->start_cond); @@ -3468,7 +3495,7 @@ err_during_init: delete thd; mysql_mutex_unlock(&LOCK_thread_count); mi->abort_slave= 0; - mi->slave_running= 0; + mi->slave_running= MYSQL_SLAVE_NOT_RUN; mi->io_thd= 0; /* Note: the order of the two following calls (first broadcast, then unlock) @@ -3573,7 +3600,7 @@ pthread_handler_t handle_slave_sql(void *arg) /* Inform waiting threads that slave has started */ rli->slave_run_id++; - rli->slave_running = 1; + rli->slave_running= MYSQL_SLAVE_RUN_NOT_CONNECT; pthread_detach_this_thread(); if (init_slave_thread(thd, mi, SLAVE_THD_SQL)) @@ -3817,6 +3844,7 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \ } goto err; } + rli->executed_entries++; } /* Thread stopped. Print the current replication position to the log */ @@ -3847,9 +3875,9 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \ err_during_init: /* We need data_lock, at least to wake up any waiting master_pos_wait() */ mysql_mutex_lock(&rli->data_lock); - DBUG_ASSERT(rli->slave_running == 1); // tracking buffer overrun + DBUG_ASSERT(rli->slave_running == MYSQL_SLAVE_RUN_NOT_CONNECT); // tracking buffer overrun /* When master_pos_wait() wakes up it will check this and terminate */ - rli->slave_running= 0; + rli->slave_running= MYSQL_SLAVE_NOT_RUN; /* Forget the relay log's format */ delete rli->relay_log.description_event_for_exec; rli->relay_log.description_event_for_exec= 0; @@ -5635,11 +5663,10 @@ bool rpl_master_has_bug(const Relay_log_info *rli, uint bug_id, bool report, */ bool rpl_master_erroneous_autoinc(THD *thd) { - if (active_mi && active_mi->rli.sql_thd == thd) + if (thd->rli_slave) { - Relay_log_info *rli= &active_mi->rli; DBUG_EXECUTE_IF("simulate_bug33029", return TRUE;); - return rpl_master_has_bug(rli, 33029, FALSE, NULL, NULL); + return rpl_master_has_bug(thd->rli_slave, 33029, FALSE, NULL, NULL); } return FALSE; } diff --git a/sql/sql_class.h b/sql/sql_class.h index 50c99af29d1..dd203af2a1b 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -2201,7 +2201,11 @@ public: /* scramble - random string sent to client on handshake */ char scramble[SCRAMBLE_LENGTH+1]; - LEX_STRING connection_name; /* If slave */ + /* + If this is a slave, the name of the connection stored here. + This is used for taging error messages in the log files. + */ + LEX_STRING connection_name; char default_master_connection_buff[MAX_CONNECTION_NAME+1]; bool slave_thread, one_shot_set; bool extra_port; /* If extra connection */ diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 3c3b9f85727..4372f6dfbfe 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -850,10 +850,10 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, table->next_number_field=table->found_next_number_field; #ifdef HAVE_REPLICATION - if (thd->slave_thread && + if (thd->rli_slave && (info.handle_duplicates == DUP_UPDATE) && (table->next_number_field != NULL) && - rpl_master_has_bug(&active_mi->rli, 24432, TRUE, NULL, NULL)) + rpl_master_has_bug(thd->rli_slave, 24432, TRUE, NULL, NULL)) goto abort; #endif @@ -3436,10 +3436,10 @@ select_insert::prepare(List &values, SELECT_LEX_UNIT *u) table->next_number_field=table->found_next_number_field; #ifdef HAVE_REPLICATION - if (thd->slave_thread && + if (thd->rli_slave && (info.handle_duplicates == DUP_UPDATE) && (table->next_number_field != NULL) && - rpl_master_has_bug(&active_mi->rli, 24432, TRUE, NULL, NULL)) + rpl_master_has_bug(thd->rli_slave, 24432, TRUE, NULL, NULL)) DBUG_RETURN(1); #endif diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 7e92fe12dc3..be0c3d8a0df 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -156,7 +156,8 @@ enum enum_sql_command { SQLCOM_FLUSH, SQLCOM_KILL, SQLCOM_ANALYZE, SQLCOM_ROLLBACK, SQLCOM_ROLLBACK_TO_SAVEPOINT, SQLCOM_COMMIT, SQLCOM_SAVEPOINT, SQLCOM_RELEASE_SAVEPOINT, - SQLCOM_SLAVE_START, SQLCOM_SLAVE_STOP, + SQLCOM_SLAVE_START, SQLCOM_SLAVE_ALL_START, + SQLCOM_SLAVE_STOP, SQLCOM_SLAVE_ALL_STOP, SQLCOM_BEGIN, SQLCOM_CHANGE_MASTER, SQLCOM_RENAME_TABLE, SQLCOM_RESET, SQLCOM_PURGE, SQLCOM_PURGE_BEFORE, SQLCOM_SHOW_BINLOGS, diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 98031c96225..e2c744401b9 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -375,11 +375,11 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, MY_RETURN_REAL_PATH); } - if (thd->slave_thread) + if (thd->rli_slave) { #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) - if (strncmp(active_mi->rli.slave_patternload_file, name, - active_mi->rli.slave_patternload_file_size)) + if (strncmp(thd->rli_slave->slave_patternload_file, name, + thd->rli_slave->slave_patternload_file_size)) { /* LOAD DATA INFILE in the slave SQL Thread can only read from diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 831931e1ef2..60698dde421 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2708,7 +2708,8 @@ end_with_restore_list: if ((mi= (master_info_index-> get_master_info(&lex_mi->connection_name, MYSQL_ERROR::WARN_LEVEL_ERROR)))) - start_slave(thd, mi, 1 /* net report*/); + if (!start_slave(thd, mi, 1 /* net report*/)) + my_ok(thd); mysql_mutex_unlock(&LOCK_active_mi); break; } @@ -2743,7 +2744,32 @@ end_with_restore_list: if ((mi= (master_info_index-> get_master_info(&lex_mi->connection_name, MYSQL_ERROR::WARN_LEVEL_ERROR)))) - stop_slave(thd, mi, 1/* net report*/); + if (!stop_slave(thd, mi, 1/* net report*/)) + my_ok(thd); + mysql_mutex_unlock(&LOCK_active_mi); + break; + } + case SQLCOM_SLAVE_ALL_START: + { + mysql_mutex_lock(&LOCK_active_mi); + if (!master_info_index->start_all_slaves(thd)) + my_ok(thd); + mysql_mutex_unlock(&LOCK_active_mi); + break; + } + case SQLCOM_SLAVE_ALL_STOP: + { + if (thd->locked_tables_mode || + thd->in_active_multi_stmt_transaction() || + thd->global_read_lock.is_acquired()) + { + my_message(ER_LOCK_OR_ACTIVE_TRANSACTION, + ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0)); + goto error; + } + mysql_mutex_lock(&LOCK_active_mi); + if (!master_info_index->stop_all_slaves(thd)) + my_ok(thd); mysql_mutex_unlock(&LOCK_active_mi); break; } diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index ed437c498e6..2954e9e1016 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2151,6 +2151,8 @@ static bool check_prepared_statement(Prepared_statement *stmt) case SQLCOM_FLUSH: case SQLCOM_SLAVE_START: case SQLCOM_SLAVE_STOP: + case SQLCOM_SLAVE_ALL_START: + case SQLCOM_SLAVE_ALL_STOP: case SQLCOM_INSTALL_PLUGIN: case SQLCOM_UNINSTALL_PLUGIN: case SQLCOM_CREATE_DB: diff --git a/sql/sql_reload.cc b/sql/sql_reload.cc index fcb7d15f5ba..21a07a51e49 100644 --- a/sql/sql_reload.cc +++ b/sql/sql_reload.cc @@ -158,10 +158,26 @@ bool reload_acl_and_cache(THD *thd, unsigned long options, if (options & REFRESH_RELAY_LOG) { #ifdef HAVE_REPLICATION + LEX_MASTER_INFO* lex_mi= &thd->lex->mi; + Master_info *mi; + + /* + Writing this command to the binlog may cause problems as the + slave is not likely to have the same connection names. + */ + tmp_write_to_binlog= 0; + mysql_mutex_lock(&LOCK_active_mi); mysql_mutex_lock(&active_mi->data_lock); - if (rotate_relay_log(active_mi)) + if (!(mi= (master_info_index-> + get_master_info(&lex_mi->connection_name, + MYSQL_ERROR::WARN_LEVEL_ERROR)))) + { + result= 1; + } + else if (rotate_relay_log(mi)) *write_to_binlog= -1; mysql_mutex_unlock(&active_mi->data_lock); + mysql_mutex_unlock(&LOCK_active_mi); #endif } #ifdef HAVE_QUERY_CACHE diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 0238a98f5d0..e18b0cd04c0 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -1297,7 +1297,9 @@ err: @retval 0 success @retval 1 error + @retval -1 fatal error */ + int start_slave(THD* thd , Master_info* mi, bool net_report) { int slave_errno= 0; @@ -1306,15 +1308,17 @@ int start_slave(THD* thd , Master_info* mi, bool net_report) char relay_log_info_file_tmp[FN_REFLEN]; DBUG_ENTER("start_slave"); - create_signed_file_name(master_info_file_tmp, - sizeof(master_info_file_tmp), - master_info_file, 0, &mi->connection_name); - create_signed_file_name(relay_log_info_file_tmp, - sizeof(relay_log_info_file_tmp), - relay_log_info_file, 0, &mi->connection_name); - if (check_access(thd, SUPER_ACL, any_db, NULL, NULL, 0, 0)) - DBUG_RETURN(1); + DBUG_RETURN(-1); + + create_logfile_name_with_suffix(master_info_file_tmp, + sizeof(master_info_file_tmp), + master_info_file, 0, &mi->connection_name); + create_logfile_name_with_suffix(relay_log_info_file_tmp, + sizeof(relay_log_info_file_tmp), + relay_log_info_file, 0, + &mi->connection_name); + lock_slave_threads(mi); // this allows us to cleanly read slave_running // Get a mask of _stopped_ threads init_thread_mask(&thread_mask,mi,1 /* inverse */); @@ -1426,10 +1430,8 @@ int start_slave(THD* thd , Master_info* mi, bool net_report) my_error(slave_errno, MYF(0), (int) mi->connection_name.length, mi->connection_name.str); - DBUG_RETURN(1); + DBUG_RETURN(slave_errno == ER_BAD_SLAVE ? -1 : 1); } - else if (net_report) - my_ok(thd); DBUG_RETURN(0); } @@ -1447,7 +1449,9 @@ int start_slave(THD* thd , Master_info* mi, bool net_report) @retval 0 success @retval 1 error + @retval -1 error */ + int stop_slave(THD* thd, Master_info* mi, bool net_report ) { int slave_errno; @@ -1455,7 +1459,7 @@ int stop_slave(THD* thd, Master_info* mi, bool net_report ) DBUG_PRINT("enter",("Connection: %s", mi->connection_name.str)); if (check_access(thd, SUPER_ACL, any_db, NULL, NULL, 0, 0)) - DBUG_RETURN(1); + DBUG_RETURN(-1); thd_proc_info(thd, "Killing slave"); int thread_mask; lock_slave_threads(mi); @@ -1491,8 +1495,6 @@ int stop_slave(THD* thd, Master_info* mi, bool net_report ) my_message(slave_errno, ER(slave_errno), MYF(0)); DBUG_RETURN(1); } - else if (net_report) - my_ok(thd); DBUG_RETURN(0); } @@ -1524,9 +1526,10 @@ int reset_slave(THD *thd, Master_info* mi) init_thread_mask(&thread_mask,mi,0 /* not inverse */); if (thread_mask) // We refuse if any slave thread is running { - sql_errno= ER_SLAVE_MUST_STOP; - error=1; - goto err; + unlock_slave_threads(mi); + my_error(ER_SLAVE_MUST_STOP, MYF(0), (int) mi->connection_name.length, + mi->connection_name.str); + DBUG_RETURN(ER_SLAVE_MUST_STOP); } ha_reset_slave(thd); @@ -1555,10 +1558,10 @@ int reset_slave(THD *thd, Master_info* mi) end_master_info(mi); // and delete these two files - create_signed_file_name(master_info_file_tmp, + create_logfile_name_with_suffix(master_info_file_tmp, sizeof(master_info_file_tmp), master_info_file, 0, &mi->connection_name); - create_signed_file_name(relay_log_info_file_tmp, + create_logfile_name_with_suffix(relay_log_info_file_tmp, sizeof(relay_log_info_file_tmp), relay_log_info_file, 0, &mi->connection_name); @@ -1688,17 +1691,18 @@ bool change_master(THD* thd, Master_info* mi) init_thread_mask(&thread_mask,mi,0 /*not inverse*/); if (thread_mask) // We refuse if any slave thread is running { - my_message(ER_SLAVE_MUST_STOP, ER(ER_SLAVE_MUST_STOP), MYF(0)); + my_error(ER_SLAVE_MUST_STOP, MYF(0), (int) mi->connection_name.length, + mi->connection_name.str); ret= TRUE; goto err; } thd_proc_info(thd, "Changing master"); - create_signed_file_name(master_info_file_tmp, + create_logfile_name_with_suffix(master_info_file_tmp, sizeof(master_info_file_tmp), master_info_file, 0, &mi->connection_name); - create_signed_file_name(relay_log_info_file_tmp, + create_logfile_name_with_suffix(relay_log_info_file_tmp, sizeof(relay_log_info_file_tmp), relay_log_info_file, 0, &mi->connection_name); diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 8a106b8ec6f..c87538681a2 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2335,6 +2335,7 @@ static bool show_status_array(THD *thd, const char *wild, for (; variables->name; variables++) { + bool wild_checked; strnmov(prefix_end, variables->name, len); name_buffer[sizeof(name_buffer)-1]=0; /* Safety */ if (ucase_names) @@ -2343,11 +2344,25 @@ static bool show_status_array(THD *thd, const char *wild, restore_record(table, s->default_values); table->field[0]->store(name_buffer, strlen(name_buffer), system_charset_info); + /* - if var->type is SHOW_FUNC, call the function. - Repeat as necessary, if new var is again SHOW_FUNC + Compare name for types that can't return arrays. We do this to not + calculate the value for function variables that we will not access */ - for (var=variables; var->type == SHOW_FUNC; var= &tmp) + if ((variables->type != SHOW_FUNC && variables->type != SHOW_ARRAY)) + { + if (wild && wild[0] && wild_case_compare(system_charset_info, + name_buffer, wild)) + continue; + wild_checked= 1; // Avoid checking it again + } + + /* + if var->type is SHOW_FUNC or SHOW_SIMPLE_FUNC, call the function. + Repeat as necessary, if new var is again one of the above + */ + for (var=variables; var->type == SHOW_FUNC || + var->type == SHOW_SIMPLE_FUNC; var= &tmp) ((mysql_show_var_func)(var->value))(thd, &tmp, buff); SHOW_TYPE show_type=var->type; @@ -2358,8 +2373,9 @@ static bool show_status_array(THD *thd, const char *wild, } else { - if (!(wild && wild[0] && wild_case_compare(system_charset_info, - name_buffer, wild)) && + if ((wild_checked || + (wild && wild[0] && wild_case_compare(system_charset_info, + name_buffer, wild))) && (!partial_cond || partial_cond->val_int())) { char *value=var->value; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index ab07a2010f0..d7e7695207a 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1292,6 +1292,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token SIGNED_SYM %token SIMPLE_SYM /* SQL-2003-N */ %token SLAVE +%token SLAVES %token SLOW %token SMALLINT /* SQL-2003-R */ %token SNAPSHOT_SYM @@ -7107,6 +7108,13 @@ slave: } slave_until {} + | START_SYM ALL SLAVES slave_thread_opts + { + LEX *lex=Lex; + lex->sql_command = SQLCOM_SLAVE_ALL_START; + lex->type = 0; + } + {} | STOP_SYM SLAVE optional_connection_name slave_thread_opts { LEX *lex=Lex; @@ -7114,6 +7122,13 @@ slave: lex->type = 0; /* If you change this code don't forget to update SLAVE STOP too */ } + | STOP_SYM ALL SLAVES slave_thread_opts + { + LEX *lex=Lex; + lex->sql_command = SQLCOM_SLAVE_ALL_STOP; + lex->type = 0; + /* If you change this code don't forget to update SLAVE STOP too */ + } | SLAVE optional_connection_name START_SYM slave_thread_opts { LEX *lex=Lex; @@ -11582,7 +11597,7 @@ show_param: { Lex->sql_command = SQLCOM_SHOW_MASTER_STAT; } - | FULL SLAVE STATUS_SYM + | ALL SLAVES STATUS_SYM { Lex->sql_command = SQLCOM_SHOW_SLAVE_STAT; Lex->verbose= 1; @@ -11850,7 +11865,7 @@ flush_option: { Lex->type|= REFRESH_SLOW_LOG; } | BINARY LOGS_SYM { Lex->type|= REFRESH_BINARY_LOG; } - | RELAY LOGS_SYM + | RELAY LOGS_SYM optional_connection_name { Lex->type|= REFRESH_RELAY_LOG; } | QUERY_SYM CACHE_SYM { Lex->type|= REFRESH_QUERY_CACHE_FREE; } @@ -13008,6 +13023,7 @@ keyword: | SIGNED_SYM {} | SOCKET_SYM {} | SLAVE {} + | SLAVES {} | SONAME_SYM {} | START_SYM {} | STOP_SYM {} diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 9421dca5c05..9eacc1c8392 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -2025,50 +2025,22 @@ static Sys_var_mybool Sys_master_verify_checksum( static const char *replicate_events_marked_for_skip_names[]= { "replicate", "filter_on_slave", "filter_on_master", 0 }; -static bool -replicate_events_marked_for_skip_check(sys_var *self, THD *thd, - set_var *var) -{ - int thread_mask; - DBUG_ENTER("sys_var_replicate_events_marked_for_skip_check"); - /* Slave threads must be stopped to change the variable. */ - mysql_mutex_lock(&LOCK_active_mi); - lock_slave_threads(active_mi); - init_thread_mask(&thread_mask, active_mi, 0 /*not inverse*/); - unlock_slave_threads(active_mi); - mysql_mutex_unlock(&LOCK_active_mi); - - if (thread_mask) // We refuse if any slave thread is running - { - my_error(ER_SLAVE_MUST_STOP, MYF(0)); - DBUG_RETURN(true); - } - DBUG_RETURN(false); -} bool Sys_var_replicate_events_marked_for_skip::global_update(THD *thd, set_var *var) { - bool result; - int thread_mask; + bool result= true; // Assume error DBUG_ENTER("Sys_var_replicate_events_marked_for_skip::global_update"); - /* Slave threads must be stopped to change the variable. */ + mysql_mutex_unlock(&LOCK_global_system_variables); mysql_mutex_lock(&LOCK_active_mi); - lock_slave_threads(active_mi); - init_thread_mask(&thread_mask, active_mi, 0 /*not inverse*/); - if (thread_mask) // We refuse if any slave thread is running - { - my_error(ER_SLAVE_MUST_STOP, MYF(0)); - result= true; - } - else + if (!master_info_index->give_error_if_slave_running()) result= Sys_var_enum::global_update(thd, var); - - unlock_slave_threads(active_mi); mysql_mutex_unlock(&LOCK_active_mi); + mysql_mutex_lock(&LOCK_global_system_variables); DBUG_RETURN(result); } + static Sys_var_replicate_events_marked_for_skip Replicate_events_marked_for_skip ("replicate_events_marked_for_skip", "Whether the slave should replicate events that were created with " @@ -2079,8 +2051,7 @@ static Sys_var_replicate_events_marked_for_skip Replicate_events_marked_for_skip "the slave).", GLOBAL_VAR(opt_replicate_events_marked_for_skip), CMD_LINE(REQUIRED_ARG), replicate_events_marked_for_skip_names, DEFAULT(RPL_SKIP_REPLICATE), - NO_MUTEX_GUARD, NOT_IN_BINLOG, - ON_CHECK(replicate_events_marked_for_skip_check)); + NO_MUTEX_GUARD, NOT_IN_BINLOG); #endif @@ -3255,71 +3226,18 @@ static Sys_var_mybool Sys_relay_log_recovery( "processed", GLOBAL_VAR(relay_log_recovery), CMD_LINE(OPT_ARG), DEFAULT(FALSE)); -bool Sys_var_rpl_filter::do_check(THD *thd, set_var *var) -{ - bool status; - - /* - We must not be holding LOCK_global_system_variables here, otherwise we can - deadlock with THD::init() which is invoked from within the slave threads - with opposite locking order. - */ - mysql_mutex_assert_not_owner(&LOCK_global_system_variables); - - mysql_mutex_lock(&LOCK_active_mi); - mysql_mutex_lock(&active_mi->rli.run_lock); - - status= active_mi->rli.slave_running; - - mysql_mutex_unlock(&active_mi->rli.run_lock); - mysql_mutex_unlock(&LOCK_active_mi); - - if (status) - my_error(ER_SLAVE_MUST_STOP, MYF(0)); - else - status= Sys_var_charptr::do_string_check(thd, var, charset(thd)); - - return status; -} - -void Sys_var_rpl_filter::lock(void) -{ - /* - Starting a slave thread causes the new thread to attempt to - acquire LOCK_global_system_variables (in THD::init) while - LOCK_active_mi is being held by the thread that initiated - the process. In order to not violate the lock order, unlock - LOCK_global_system_variables before grabbing LOCK_active_mi. - */ - mysql_mutex_unlock(&LOCK_global_system_variables); - - mysql_mutex_lock(&LOCK_active_mi); - mysql_mutex_lock(&active_mi->rli.run_lock); -} - -void Sys_var_rpl_filter::unlock(void) -{ - mysql_mutex_unlock(&active_mi->rli.run_lock); - mysql_mutex_unlock(&LOCK_active_mi); - - mysql_mutex_lock(&LOCK_global_system_variables); -} bool Sys_var_rpl_filter::global_update(THD *thd, set_var *var) { - bool slave_running, status= false; + bool result= true; // Assume error - lock(); - - if (! (slave_running= active_mi->rli.slave_running)) - status= set_filter_value(var->save_result.string_value.str); - - if (slave_running) - my_error(ER_SLAVE_MUST_STOP, MYF(0)); - - unlock(); - - return slave_running || status; + mysql_mutex_unlock(&LOCK_global_system_variables); + mysql_mutex_lock(&LOCK_active_mi); + if (!master_info_index->give_error_if_slave_running()) + result= set_filter_value(var->save_result.string_value.str); + mysql_mutex_unlock(&LOCK_active_mi); + mysql_mutex_lock(&LOCK_global_system_variables); + return result; } bool Sys_var_rpl_filter::set_filter_value(const char *value) @@ -3357,8 +3275,6 @@ uchar *Sys_var_rpl_filter::global_value_ptr(THD *thd, LEX_STRING *base) tmp.length(0); - lock(); - switch (opt_id) { case OPT_REPLICATE_DO_DB: rpl_filter->get_do_db(&tmp); @@ -3380,8 +3296,6 @@ uchar *Sys_var_rpl_filter::global_value_ptr(THD *thd, LEX_STRING *base) break; } - unlock(); - return (uchar *) thd->strmake(tmp.ptr(), tmp.length()); } @@ -3431,30 +3345,13 @@ static Sys_var_charptr Sys_slave_load_tmpdir( READ_ONLY GLOBAL_VAR(slave_load_tmpdir), CMD_LINE(REQUIRED_ARG), IN_FS_CHARSET, DEFAULT(0)); -static bool fix_slave_net_timeout(sys_var *self, THD *thd, enum_var_type type) -{ - DEBUG_SYNC(thd, "fix_slave_net_timeout"); - - mysql_mutex_unlock(&LOCK_global_system_variables); - mysql_mutex_lock(&LOCK_active_mi); - DBUG_PRINT("info", ("slave_net_timeout: %u mi->heartbeat_period: %.3f", - slave_net_timeout, - (active_mi? active_mi->heartbeat_period : 0.0))); - if (active_mi && slave_net_timeout < active_mi->heartbeat_period) - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MAX, - ER(ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MAX)); - mysql_mutex_unlock(&LOCK_active_mi); - mysql_mutex_lock(&LOCK_global_system_variables); - return false; -} static Sys_var_uint Sys_slave_net_timeout( "slave_net_timeout", "Number of seconds to wait for more data " - "from a master/slave connection before aborting the read", + "from any master/slave connection before aborting the read", GLOBAL_VAR(slave_net_timeout), CMD_LINE(REQUIRED_ARG), VALID_RANGE(1, LONG_TIMEOUT), DEFAULT(SLAVE_NET_TIMEOUT), BLOCK_SIZE(1), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), - ON_UPDATE(fix_slave_net_timeout)); + ON_UPDATE(0)); /* @@ -3509,7 +3406,8 @@ static bool update_slave_skip_counter(sys_var *self, THD *thd, Master_info *mi) { if (mi->rli.slave_running) { - my_message(ER_SLAVE_MUST_STOP, ER(ER_SLAVE_MUST_STOP), MYF(0)); + my_error(ER_SLAVE_MUST_STOP, MYF(0), mi->connection_name.length, + mi->connection_name.str); return true; } /* The value was stored temporarly in thd */ diff --git a/sql/sys_vars.h b/sql/sys_vars.h index 8e832e57630..6c46c816105 100644 --- a/sql/sys_vars.h +++ b/sql/sys_vars.h @@ -566,11 +566,13 @@ public: option.var_type= GET_STR; } + bool do_check(THD *thd, set_var *var) + { + return Sys_var_charptr::do_string_check(thd, var, charset(thd)); + } bool check_update_type(Item_result type) { return type != STRING_RESULT; } - bool do_check(THD *thd, set_var *var); - void session_save_default(THD *thd, set_var *var) { DBUG_ASSERT(FALSE); } @@ -588,8 +590,6 @@ public: protected: uchar *global_value_ptr(THD *thd, LEX_STRING *base); bool set_filter_value(const char *value); - void lock(void); - void unlock(void); }; /** @@ -1937,10 +1937,9 @@ public: const char *comment, int flag_args, ptrdiff_t off, size_t size, CMD_LINE getopt, const char *values[], uint def_val, PolyLock *lock, - enum binlog_status_enum binlog_status_arg, - on_check_function on_check_func) + enum binlog_status_enum binlog_status_arg) :Sys_var_enum(name_arg, comment, flag_args, off, size, getopt, - values, def_val, lock, binlog_status_arg, on_check_func) + values, def_val, lock, binlog_status_arg) {} bool global_update(THD *thd, set_var *var); }; diff --git a/storage/example/ha_example.cc b/storage/example/ha_example.cc index 2c65fd657a9..81f6cbe707f 100644 --- a/storage/example/ha_example.cc +++ b/storage/example/ha_example.cc @@ -1097,7 +1097,8 @@ static struct st_mysql_sys_var* example_system_variables[]= { NULL }; -// this is an example of SHOW_FUNC and of my_snprintf() service +// this is an example of SHOW_SIMPLE_FUNC and of my_snprintf() service +// If this function would return an array, one should use SHOW_FUNC static int show_func_example(MYSQL_THD thd, struct st_mysql_show_var *var, char *buf) { @@ -1111,7 +1112,7 @@ static int show_func_example(MYSQL_THD thd, struct st_mysql_show_var *var, static struct st_mysql_show_var func_status[]= { - {"example_func_example", (char *)show_func_example, SHOW_FUNC}, + {"example_func_example", (char *)show_func_example, SHOW_SIMPLE_FUNC}, {0,0,SHOW_UNDEF} }; diff --git a/storage/sphinx/ha_sphinx.cc b/storage/sphinx/ha_sphinx.cc index 27a463bf61f..97e83cd9221 100644 --- a/storage/sphinx/ha_sphinx.cc +++ b/storage/sphinx/ha_sphinx.cc @@ -3591,12 +3591,12 @@ struct st_mysql_storage_engine sphinx_storage_engine = struct st_mysql_show_var sphinx_status_vars[] = { - {"sphinx_total", (char *)sphinx_showfunc_total, SHOW_FUNC}, - {"sphinx_total_found", (char *)sphinx_showfunc_total_found, SHOW_FUNC}, - {"sphinx_time", (char *)sphinx_showfunc_time, SHOW_FUNC}, - {"sphinx_word_count", (char *)sphinx_showfunc_word_count, SHOW_FUNC}, - {"sphinx_words", (char *)sphinx_showfunc_words, SHOW_FUNC}, - {"sphinx_error", (char *)sphinx_showfunc_error, SHOW_FUNC}, + {"sphinx_total", (char *)sphinx_showfunc_total, SHOW_SIMPLE_FUNC}, + {"sphinx_total_found", (char *)sphinx_showfunc_total_found, SHOW_SIMPLE_FUNC}, + {"sphinx_time", (char *)sphinx_showfunc_time, SHOW_SIMPLE_FUNC}, + {"sphinx_word_count", (char *)sphinx_showfunc_word_count, SHOW_SIMPLE_FUNC}, + {"sphinx_words", (char *)sphinx_showfunc_words, SHOW_SIMPLE_FUNC}, + {"sphinx_error", (char *)sphinx_showfunc_error, SHOW_SIMPLE_FUNC}, {0, 0, (enum_mysql_show_type)0} }; diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index 97a30a81d12..9acda7ed13e 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -3190,7 +3190,9 @@ innobase_commit_low( #ifdef MYSQL_SERVER THD *thd=current_thd; - if (thd && thd_is_replication_slave_thread(thd)) { + if (innobase_overwrite_relay_log_info && + thd && thd_is_replication_slave_thread(thd) && + thd->connection_name.length) { /* Update the replication position info inside InnoDB. In embedded server, does nothing. */ const char *log_file_name, *group_relay_log_name; From d491302fb550f63550cfed8ab54410ef080768dc Mon Sep 17 00:00:00 2001 From: Elena Stepanova Date: Thu, 4 Oct 2012 08:02:13 +0400 Subject: [PATCH 281/289] More tests and test cleanup for MDEV-253 (Multi-source replication) --- .../suite/multi_source/info_logs.result | 14 +- mysql-test/suite/multi_source/info_logs.test | 36 ++- .../suite/multi_source/multisource.result | 140 ++++++++++++ .../suite/multi_source/multisource.test | 211 ++++++++++++++++++ .../suite/multi_source/relaylog_events.result | 6 +- .../suite/multi_source/relaylog_events.test | 7 +- .../suite/multi_source/reset_master_slave.inc | 29 +++ .../suite/multi_source/reset_slave.result | 3 +- .../suite/multi_source/reset_slave.test | 3 +- mysql-test/suite/multi_source/simple.result | 4 +- mysql-test/suite/multi_source/simple.test | 11 +- .../suite/multi_source/skip_counter.result | 19 +- .../suite/multi_source/skip_counter.test | 18 +- .../suite/multi_source/status_vars.result | 97 ++++++++ .../suite/multi_source/status_vars.test | 132 +++++++++++ 15 files changed, 670 insertions(+), 60 deletions(-) create mode 100644 mysql-test/suite/multi_source/multisource.result create mode 100644 mysql-test/suite/multi_source/multisource.test create mode 100644 mysql-test/suite/multi_source/reset_master_slave.inc create mode 100644 mysql-test/suite/multi_source/status_vars.result create mode 100644 mysql-test/suite/multi_source/status_vars.test diff --git a/mysql-test/suite/multi_source/info_logs.result b/mysql-test/suite/multi_source/info_logs.result index f192cf17fbb..b72e934ba57 100644 --- a/mysql-test/suite/multi_source/info_logs.result +++ b/mysql-test/suite/multi_source/info_logs.result @@ -87,6 +87,10 @@ show all slaves status; Connection_name Slave_SQL_State 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 Replicate_Ignore_Server_Ids Master_Server_Id Retried_transactions Max_relay_log_size Executed_log_entries Slave_received_heartbeats Slave_heartbeat_period Slave has read all relay log; waiting for the slave I/O thread to update it Waiting for master to send event 127.0.0.1 root MYPORT_1 60 master-bin.000001 286 relay.000002 572 master-bin.000001 Yes Yes 0 0 286 857 None 0 No 0 No 0 0 1 0 1073741824 6 0 60.000 MASTER 2.2 Slave has read all relay log; waiting for the slave I/O thread to update it Waiting for master to send event 127.0.0.1 root MYPORT_2 60 master-bin.000001 286 relay-master@00202@002e2.000002 572 master-bin.000001 Yes Yes 0 0 286 876 None 0 No 0 No 0 0 2 0 1073741824 6 0 60.000 +include/wait_for_slave_to_start.inc +set default_master_connection = 'MASTER 2.2'; +include/wait_for_slave_to_start.inc +set default_master_connection = ''; show all slaves status; Connection_name Slave_SQL_State 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 Replicate_Ignore_Server_Ids Master_Server_Id Retried_transactions Max_relay_log_size Executed_log_entries Slave_received_heartbeats Slave_heartbeat_period Slave has read all relay log; waiting for the slave I/O thread to update it Waiting for master to send event 127.0.0.1 root MYPORT_1 60 master-bin.000001 286 relay.000004 532 master-bin.000001 Yes Yes 0 0 286 817 None 0 No 0 No 0 0 1 0 1073741824 6 0 60.000 @@ -106,10 +110,6 @@ relay.bin.info MASTER 2.2 # EOF # -stop slave; -include/wait_for_slave_to_stop.inc -set default_master_connection = 'MASTER 2.2'; -stop slave; -include/wait_for_slave_to_stop.inc -reset slave all; -reset slave '' all; +include/reset_master_slave.inc +include/reset_master_slave.inc +include/reset_master_slave.inc diff --git a/mysql-test/suite/multi_source/info_logs.test b/mysql-test/suite/multi_source/info_logs.test index 6314a94434c..b4bbe7af385 100644 --- a/mysql-test/suite/multi_source/info_logs.test +++ b/mysql-test/suite/multi_source/info_logs.test @@ -56,6 +56,12 @@ start slave 'MASTER 2.2'; set default_master_connection = 'MASTER 2.2'; --source include/wait_for_slave_to_start.inc +--connect (master2,127.0.0.1,root,,,$SERVER_MYPORT_2) +--save_master_pos + +--connection slave +--sync_with_master 0,'MASTER 2.2' + # Check the files --echo # @@ -102,6 +108,12 @@ master_user='root'; start slave; --source include/wait_for_slave_to_start.inc +--connect (master1,127.0.0.1,root,,,$SERVER_MYPORT_1) +--save_master_pos + +--connection slave +--sync_with_master + # Check the files --echo # @@ -115,7 +127,6 @@ start slave; --echo # EOF --echo # ---sleep 5 --replace_result $SERVER_MYPORT_1 MYPORT_1 $SERVER_MYPORT_2 MYPORT_2 show all slaves status; @@ -127,6 +138,10 @@ restart EOF --shutdown_server 60 --source include/wait_until_connected_again.inc +--source include/wait_for_slave_to_start.inc +set default_master_connection = 'MASTER 2.2'; +--source include/wait_for_slave_to_start.inc +set default_master_connection = ''; --replace_result $SERVER_MYPORT_1 MYPORT_1 $SERVER_MYPORT_2 MYPORT_2 show all slaves status; @@ -148,13 +163,14 @@ show all slaves status; # Cleanup -stop slave; ---source include/wait_for_slave_to_stop.inc - -set default_master_connection = 'MASTER 2.2'; -stop slave; ---source include/wait_for_slave_to_stop.inc -reset slave all; -reset slave '' all; - +--source reset_master_slave.inc --disconnect slave + +--connection master1 +--source reset_master_slave.inc +--disconnect master1 + +--connection master2 +--source reset_master_slave.inc +--disconnect master2 + diff --git a/mysql-test/suite/multi_source/multisource.result b/mysql-test/suite/multi_source/multisource.result new file mode 100644 index 00000000000..4507b9c5676 --- /dev/null +++ b/mysql-test/suite/multi_source/multisource.result @@ -0,0 +1,140 @@ +change master 'master1' to +master_port=MYPORT_1, +master_host='127.0.0.1', +master_user='root'; +start slave 'master1'; +set default_master_connection = 'master1'; +include/wait_for_slave_to_start.inc +show slave 'master1' 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 Replicate_Ignore_Server_Ids Master_Server_Id +Waiting for master to send event 127.0.0.1 root MYPORT_1 60 master-bin.000001 286 mysqld-relay-bin-master1.000002 572 master-bin.000001 Yes Yes 0 0 286 876 None 0 No 0 No 0 0 1 +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 Replicate_Ignore_Server_Ids Master_Server_Id +Waiting for master to send event 127.0.0.1 root MYPORT_1 60 master-bin.000001 286 mysqld-relay-bin-master1.000002 572 master-bin.000001 Yes Yes 0 0 286 876 None 0 No 0 No 0 0 1 +show all slaves status; +Connection_name Slave_SQL_State 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 Replicate_Ignore_Server_Ids Master_Server_Id Retried_transactions Max_relay_log_size Executed_log_entries Slave_received_heartbeats Slave_heartbeat_period +master1 Slave has read all relay log; waiting for the slave I/O thread to update it Waiting for master to send event 127.0.0.1 root MYPORT_1 60 master-bin.000001 286 mysqld-relay-bin-master1.000002 572 master-bin.000001 Yes Yes 0 0 286 876 None 0 No 0 No 0 0 1 0 1073741824 6 0 60.000 +drop database if exists db1; +create database db1; +use db1; +create table t1 (i int auto_increment, f1 varchar(16), primary key pk (i,f1)) engine=MyISAM; +insert into t1 (f1) values ('one'),('two'); +select * from db1.t1; +i f1 +1 one +2 two +# List of relay log files in the datadir +mysqld-relay-bin-master1.000001 +mysqld-relay-bin-master1.000002 +mysqld-relay-bin-master1.index +show relaylog events; +Log_name Pos Event_type Server_id End_log_pos Info +mysqld-relay-bin-master1.000001 4 Format_desc 3 246 Server ver: 10.0.0-MariaDB-debug-log, Binlog ver: 4 +mysqld-relay-bin-master1.000001 246 Rotate 3 304 mysqld-relay-bin-master1.000002;pos=4 +show relaylog events in 'mysqld-relay-bin-master1.000002'; +Log_name Pos Event_type Server_id End_log_pos Info +mysqld-relay-bin-master1.000002 4 Format_desc 3 246 Server ver: 10.0.0-MariaDB-debug-log, Binlog ver: 4 +mysqld-relay-bin-master1.000002 246 Rotate 1 0 master-bin.000001;pos=4 +mysqld-relay-bin-master1.000002 290 Format_desc 1 246 Server ver: 10.0.0-MariaDB-debug-log, Binlog ver: 4 +mysqld-relay-bin-master1.000002 532 Binlog_checkpoint 1 286 master-bin.000001 +mysqld-relay-bin-master1.000002 572 Query 1 375 drop database if exists db1 +mysqld-relay-bin-master1.000002 661 Query 1 456 create database db1 +mysqld-relay-bin-master1.000002 742 Query 1 609 use `db1`; create table t1 (i int auto_increment, f1 varchar(16), primary key pk (i,f1)) engine=MyISAM +mysqld-relay-bin-master1.000002 895 Query 1 676 BEGIN +mysqld-relay-bin-master1.000002 962 Intvar 1 704 INSERT_ID=1 +mysqld-relay-bin-master1.000002 990 Query 1 808 use `db1`; insert into t1 (f1) values ('one'),('two') +mysqld-relay-bin-master1.000002 1094 Query 1 876 COMMIT +change master 'master1' to +master_port=MYPORT_2, +master_host='127.0.0.1', +master_user='root'; +ERROR HY000: This operation cannot be performed as you have a running slave 'master1'; run STOP SLAVE 'master1' first +change master to +master_port=MYPORT_2, +master_host='127.0.0.1', +master_user='root'; +ERROR HY000: This operation cannot be performed as you have a running slave 'master1'; run STOP SLAVE 'master1' first +change master 'master2' to +master_port=MYPORT_1, +master_host='127.0.0.1', +master_user='root'; +ERROR HY000: Connection 'master2' conflicts with existing connection 'master1' +set default_master_connection = ''; +change master to +master_port=MYPORT_2, +master_host='127.0.0.1', +master_user='root'; +start slave; +include/wait_for_slave_to_start.inc +show all slaves status; +Connection_name Slave_SQL_State 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 Replicate_Ignore_Server_Ids Master_Server_Id Retried_transactions Max_relay_log_size Executed_log_entries Slave_received_heartbeats Slave_heartbeat_period + Slave has read all relay log; waiting for the slave I/O thread to update it Waiting for master to send event 127.0.0.1 root MYPORT_2 60 master-bin.000001 286 mysqld-relay-bin.000002 572 master-bin.000001 Yes Yes 0 0 286 868 None 0 No 0 No 0 0 2 0 1073741824 6 0 60.000 +master1 Slave has read all relay log; waiting for the slave I/O thread to update it Waiting for master to send event 127.0.0.1 root MYPORT_1 60 master-bin.000001 876 mysqld-relay-bin-master1.000002 1162 master-bin.000001 Yes Yes 0 0 876 1466 None 0 No 0 No 0 0 1 0 1073741824 13 0 60.000 +insert into t1 (f1) values ('three'); +drop database if exists db2; +create database db2; +use db2; +create table t1 (pk int auto_increment primary key, f1 int) engine=InnoDB; +begin; +insert into t1 (f1) values (1),(2); +select * from db1.t1; +i f1 +1 one +2 two +3 three +select * from db2.t1; +pk f1 +commit; +select * from db2.t1; +pk f1 +1 1 +2 2 +flush logs; +purge binary logs to 'master-bin.000002'; +show binary logs; +Log_name File_size +master-bin.000002 326 +insert into t1 (f1) values ('four'); +create table db1.t3 (f1 int) engine=InnoDB; +show all slaves status; +Connection_name Slave_SQL_State 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 Replicate_Ignore_Server_Ids Master_Server_Id Retried_transactions Max_relay_log_size Executed_log_entries Slave_received_heartbeats Slave_heartbeat_period + Slave has read all relay log; waiting for the slave I/O thread to update it Waiting for master to send event 127.0.0.1 root MYPORT_2 60 master-bin.000001 809 mysqld-relay-bin.000002 1095 master-bin.000001 Yes Yes 0 0 809 1391 None 0 No 0 No 0 0 2 0 1073741824 13 0 60.000 +master1 Slave has read all relay log; waiting for the slave I/O thread to update it Waiting for master to send event 127.0.0.1 root MYPORT_1 60 master-bin.000002 690 mysqld-relay-bin-master1.000004 976 master-bin.000002 Yes Yes 0 0 690 1324 None 0 No 0 No 0 0 1 0 1073741824 31 0 60.000 +select * from db1.t1; +i f1 +1 one +2 two +3 three +4 four +show relaylog events; +Log_name Pos Event_type Server_id End_log_pos Info +mysqld-relay-bin.000001 4 Format_desc 3 246 Server ver: 10.0.0-MariaDB-debug-log, Binlog ver: 4 +mysqld-relay-bin.000001 246 Rotate 3 296 mysqld-relay-bin.000002;pos=4 +show relaylog events in 'mysqld-relay-bin.000002'; +Log_name Pos Event_type Server_id End_log_pos Info +mysqld-relay-bin.000002 4 Format_desc 3 246 Server ver: 10.0.0-MariaDB-debug-log, Binlog ver: 4 +mysqld-relay-bin.000002 246 Rotate 2 0 master-bin.000001;pos=4 +mysqld-relay-bin.000002 290 Format_desc 2 246 Server ver: 10.0.0-MariaDB-debug-log, Binlog ver: 4 +mysqld-relay-bin.000002 532 Binlog_checkpoint 2 286 master-bin.000001 +mysqld-relay-bin.000002 572 Query 2 375 drop database if exists db2 +mysqld-relay-bin.000002 661 Query 2 456 create database db2 +mysqld-relay-bin.000002 742 Query 2 591 use `db2`; create table t1 (pk int auto_increment primary key, f1 int) engine=InnoDB +mysqld-relay-bin.000002 877 Query 2 658 BEGIN +mysqld-relay-bin.000002 944 Intvar 2 686 INSERT_ID=1 +mysqld-relay-bin.000002 972 Query 2 782 use `db2`; insert into t1 (f1) values (1),(2) +mysqld-relay-bin.000002 1068 Xid 2 809 COMMIT /* xid=25 */ +stop slave io_thread; +show status like 'Slave_running'; +Variable_name Value +Slave_running OFF +set default_master_connection = 'master1'; +show status like 'Slave_running'; +Variable_name Value +Slave_running ON +drop database db1; +drop database db2; +include/reset_master_slave.inc +drop database db1; +include/reset_master_slave.inc +drop database db2; +include/reset_master_slave.inc diff --git a/mysql-test/suite/multi_source/multisource.test b/mysql-test/suite/multi_source/multisource.test new file mode 100644 index 00000000000..b1e05051f59 --- /dev/null +++ b/mysql-test/suite/multi_source/multisource.test @@ -0,0 +1,211 @@ +--source include/have_innodb.inc + +--connect (slave,127.0.0.1,root,,,$SERVER_MYPORT_3) + +# Start replication from the first master + +--replace_result $SERVER_MYPORT_1 MYPORT_1 +eval change master 'master1' to +master_port=$SERVER_MYPORT_1, +master_host='127.0.0.1', +master_user='root'; + +start slave 'master1'; +set default_master_connection = 'master1'; +--source include/wait_for_slave_to_start.inc + +--connect (master1,127.0.0.1,root,,,$SERVER_MYPORT_1) +--save_master_pos + +--connection slave +--sync_with_master 0,'master1' + +# each of the 3 commands should produce +# 'master1' status + +--replace_result $SERVER_MYPORT_1 MYPORT_1 +show slave 'master1' status; +--replace_result $SERVER_MYPORT_1 MYPORT_1 +show slave status; +--replace_result $SERVER_MYPORT_1 MYPORT_1 +show all slaves status; + + +# Check that replication actually works + +--connection master1 + +--disable_warnings +drop database if exists db1; +--enable_warnings +create database db1; +use db1; +create table t1 (i int auto_increment, f1 varchar(16), primary key pk (i,f1)) engine=MyISAM; +insert into t1 (f1) values ('one'),('two'); +--save_master_pos + +--connection slave +--sync_with_master 0,'master1' + +--sorted_result +select * from db1.t1; + +--let $datadir = `SELECT @@datadir` + +--echo # List of relay log files in the datadir +--list_files $datadir mysqld-relay-bin-master1.* + +# Check that relay logs are recognizable + +show relaylog events; +show relaylog events in 'mysqld-relay-bin-master1.000002'; + + +# Try to configure connection with the same name again, +# should get an error because the slave is running + +--replace_result $SERVER_MYPORT_2 MYPORT_2 +--error ER_SLAVE_MUST_STOP +eval change master 'master1' to +master_port=$SERVER_MYPORT_2, +master_host='127.0.0.1', +master_user='root'; + +# Try to configure using the default connection name +# (which is 'master1' at the moment), +# again, should get an error + +--replace_result $SERVER_MYPORT_2 MYPORT_2 +--error ER_SLAVE_MUST_STOP +eval change master to +master_port=$SERVER_MYPORT_2, +master_host='127.0.0.1', +master_user='root'; + +# Try to configure a connection with the same master +# using a different name, should get a conflict + +--replace_result $SERVER_MYPORT_1 MYPORT_1 +--error ER_CONNECTION_ALREADY_EXISTS +eval change master 'master2' to +master_port=$SERVER_MYPORT_1, +master_host='127.0.0.1', +master_user='root'; + + +# Set up a proper 'default' connection to master2 + +set default_master_connection = ''; + +--replace_result $SERVER_MYPORT_2 MYPORT_2 +eval change master to +master_port=$SERVER_MYPORT_2, +master_host='127.0.0.1', +master_user='root'; + +start slave; +--source include/wait_for_slave_to_start.inc + +# See both connections in the same status output + +--replace_result $SERVER_MYPORT_1 MYPORT_1 $SERVER_MYPORT_2 MYPORT_2 +show all slaves status; + +# Check that replication from two servers actually works + +--connection master1 + +insert into t1 (f1) values ('three'); +--save_master_pos + +--connect (master2,127.0.0.1,root,,,$SERVER_MYPORT_2) + +--disable_warnings +drop database if exists db2; +--enable_warnings +create database db2; +use db2; +create table t1 (pk int auto_increment primary key, f1 int) engine=InnoDB; +begin; +insert into t1 (f1) values (1),(2); + +--connection slave +--sync_with_master 0,'master1' + +--connection master2 +--save_master_pos + +--connection slave +--sync_with_master 0 +--sorted_result +select * from db1.t1; +select * from db2.t1; + +--connection master2 +commit; +--save_master_pos + +--connection slave +--sync_with_master 0 +--sorted_result +select * from db2.t1; + +# Flush and purge logs on one master, +# make sure slaves don't get confused + +--connection master1 +flush logs; +--save_master_pos +--connection slave +--sync_with_master 0, 'master1' + +--connection master1 +purge binary logs to 'master-bin.000002'; +show binary logs; +insert into t1 (f1) values ('four'); +create table db1.t3 (f1 int) engine=InnoDB; +--save_master_pos + +--connection slave +--sync_with_master 0,'master1' + +--replace_result $SERVER_MYPORT_1 MYPORT_1 $SERVER_MYPORT_2 MYPORT_2 +show all slaves status; + +--sorted_result +select * from db1.t1; + +# This should show relay log events for the default master +# (the one with the empty name) +show relaylog events; +show relaylog events in 'mysqld-relay-bin.000002'; + +# Make sure we don't lose control over replication connections +# after reconnecting to the slave + +--disconnect slave +--connect (slave,127.0.0.1,root,,,$SERVER_MYPORT_3) + +stop slave io_thread; +show status like 'Slave_running'; +set default_master_connection = 'master1'; +show status like 'Slave_running'; + +# Cleanup + +drop database db1; +drop database db2; + +--source reset_master_slave.inc +--disconnect slave + +--connection master1 +drop database db1; +--source reset_master_slave.inc +--disconnect master1 + +--connection master2 +drop database db2; +--source reset_master_slave.inc +--disconnect master2 + diff --git a/mysql-test/suite/multi_source/relaylog_events.result b/mysql-test/suite/multi_source/relaylog_events.result index 437dc87788a..1f3b57b045d 100644 --- a/mysql-test/suite/multi_source/relaylog_events.result +++ b/mysql-test/suite/multi_source/relaylog_events.result @@ -23,7 +23,5 @@ Log_name Pos Event_type Server_id End_log_pos Info mysqld-relay-bin-master1.000001 4 Format_desc 3 246 Server version mysqld-relay-bin-master1.000001 246 Rotate 3 304 mysqld-relay-bin-master1.000002;pos=4 drop table t1; -stop slave; -include/wait_for_slave_to_stop.inc -reset slave 'master1' all; -reset master; +include/reset_master_slave.inc +include/reset_master_slave.inc diff --git a/mysql-test/suite/multi_source/relaylog_events.test b/mysql-test/suite/multi_source/relaylog_events.test index b5bbf726316..67048749f67 100644 --- a/mysql-test/suite/multi_source/relaylog_events.test +++ b/mysql-test/suite/multi_source/relaylog_events.test @@ -39,14 +39,11 @@ drop table t1; --connection slave --sync_with_master 0,'master1' -stop slave; ---source include/wait_for_slave_to_stop.inc - -reset slave 'master1' all; +--source reset_master_slave.inc --disconnect slave --connection master1 -reset master; +--source reset_master_slave.inc --disconnect master1 diff --git a/mysql-test/suite/multi_source/reset_master_slave.inc b/mysql-test/suite/multi_source/reset_master_slave.inc new file mode 100644 index 00000000000..63ba3ee00af --- /dev/null +++ b/mysql-test/suite/multi_source/reset_master_slave.inc @@ -0,0 +1,29 @@ +# +# The include file runs RESET ALL for every replication connection +# currently present in SHOW FULL SLAVE STATUS output on the server, +# and also runs RESET MASTER on the same server. +# + +--let $include_filename= reset_master_slave.inc +--source include/begin_include_file.inc + +--disable_query_log +--disable_result_log +--disable_warnings +--let $default_master = `SELECT @@default_master_connection` +--let $con_name = query_get_value(show all slaves status, Connection_name, 1) +while ($con_name != 'No such row') +{ + eval set default_master_connection = '$con_name'; + stop slave; + --source include/wait_for_slave_to_stop.inc + reset slave all; + --let $con_name = query_get_value(show all slaves status, Connection_name, 1) +} + +--error 0,ER_FLUSH_MASTER_BINLOG_CLOSED +reset master; +eval set default_master_connection = '$default_master'; + +--source include/end_include_file.inc + diff --git a/mysql-test/suite/multi_source/reset_slave.result b/mysql-test/suite/multi_source/reset_slave.result index ab59f54315a..0c2777f7958 100644 --- a/mysql-test/suite/multi_source/reset_slave.result +++ b/mysql-test/suite/multi_source/reset_slave.result @@ -23,5 +23,6 @@ reset slave 'master1' all; show slave 'master1' status; ERROR HY000: There is no master connection 'master1' drop table t1; +include/reset_master_slave.inc drop table t1; -reset master; +include/reset_master_slave.inc diff --git a/mysql-test/suite/multi_source/reset_slave.test b/mysql-test/suite/multi_source/reset_slave.test index d3b9abb91ca..e63cf1d949a 100644 --- a/mysql-test/suite/multi_source/reset_slave.test +++ b/mysql-test/suite/multi_source/reset_slave.test @@ -51,11 +51,12 @@ show slave 'master1' status; # Cleanup drop table t1; +--source reset_master_slave.inc --disconnect slave --connection master1 drop table t1; -reset master; +--source reset_master_slave.inc --disconnect master1 diff --git a/mysql-test/suite/multi_source/simple.result b/mysql-test/suite/multi_source/simple.result index 8465c4a5c52..59f23179243 100644 --- a/mysql-test/suite/multi_source/simple.result +++ b/mysql-test/suite/multi_source/simple.result @@ -72,4 +72,6 @@ show all slaves status; Connection_name Slave_SQL_State 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 Replicate_Ignore_Server_Ids Master_Server_Id Retried_transactions Max_relay_log_size Executed_log_entries Slave_received_heartbeats Slave_heartbeat_period slave2 127.0.0.1 root MYPORT_2 60 master-bin.000001 286 mysqld-relay-bin-slave2.000002 572 master-bin.000001 No No 0 0 286 875 None 0 No NULL No 0 0 2 0 1073741824 6 0 60.000 stop all slaves; -reset slave 'slave2' all; +include/reset_master_slave.inc +include/reset_master_slave.inc +include/reset_master_slave.inc diff --git a/mysql-test/suite/multi_source/simple.test b/mysql-test/suite/multi_source/simple.test index 4b13623785a..8f501b777ad 100644 --- a/mysql-test/suite/multi_source/simple.test +++ b/mysql-test/suite/multi_source/simple.test @@ -59,4 +59,13 @@ stop all slaves; # # clean up # -reset slave 'slave2' all; + +--source reset_master_slave.inc +--disconnect slave +--connection master1 +--source reset_master_slave.inc +--disconnect master1 +--connection master2 +--source reset_master_slave.inc +--disconnect master2 + diff --git a/mysql-test/suite/multi_source/skip_counter.result b/mysql-test/suite/multi_source/skip_counter.result index 51ad36c4ee8..42ad961d6dd 100644 --- a/mysql-test/suite/multi_source/skip_counter.result +++ b/mysql-test/suite/multi_source/skip_counter.result @@ -1,12 +1,9 @@ -connect master1,127.0.0.1,root,,,$SERVER_MYPORT_1; drop database if exists db; create database db; create table db.t1 (i int) engine=MyISAM; -connect master2,127.0.0.1,root,,,$SERVER_MYPORT_2; drop database if exists db; create database db; create table db.t2 (i int) engine=MyISAM; -connect slave,127.0.0.1,root,,,$SERVER_MYPORT_3; change master 'master1' to master_port=MYPORT_1, master_host='127.0.0.1', @@ -101,26 +98,16 @@ select @@global.max_relay_log_size; start slave 'master2'; include/wait_for_slave_to_start.inc set default_master_connection = ''; -connection master2; -connection slave; show tables in db; Tables_in_db t1 t2 drop database db; -set default_master_connection = 'master1'; -stop slave; -include/wait_for_slave_to_stop.inc -set default_master_connection = 'master2'; -stop slave; -include/wait_for_slave_to_stop.inc set global sql_slave_skip_counter = 0; set global max_relay_log_size = 1073741824; set global max_binlog_size = 1073741824; -disconnect slave; -connection master1; +include/reset_master_slave.inc drop database db; -disconnect master1; -connection master2; +include/reset_master_slave.inc drop database db; -disconnect master2; +include/reset_master_slave.inc diff --git a/mysql-test/suite/multi_source/skip_counter.test b/mysql-test/suite/multi_source/skip_counter.test index ceb7eb93f0f..04a9102a312 100644 --- a/mysql-test/suite/multi_source/skip_counter.test +++ b/mysql-test/suite/multi_source/skip_counter.test @@ -2,8 +2,6 @@ # Test of sql_slave_skip_counter and rpl_max_size # ---enable_connect_log - # Create a schema and a table i # on the 1st master @@ -28,7 +26,6 @@ create database db; create table db.t2 (i int) engine=MyISAM; --connect (slave,127.0.0.1,root,,,$SERVER_MYPORT_3) ---disable_connect_log # Start replication from the first master @@ -106,14 +103,11 @@ start slave 'master2'; --source include/wait_for_slave_to_start.inc set default_master_connection = ''; ---enable_connect_log - --connection master2 --save_master_pos --connection slave ---disable_connect_log --sync_with_master 0,'master2' # If the skip_counter worked as expected, we should @@ -127,25 +121,21 @@ show tables in db; # Cleanup drop database db; -set default_master_connection = 'master1'; -stop slave; ---source include/wait_for_slave_to_stop.inc -set default_master_connection = 'master2'; -stop slave; - ---source include/wait_for_slave_to_stop.inc --eval set global sql_slave_skip_counter = $skip_counter_saved --eval set global max_relay_log_size = $max_relay_log_size_saved --eval set global max_binlog_size = $max_binlog_size_saved ---enable_connect_log +--source reset_master_slave.inc --disconnect slave --connection master1 drop database db; +--source reset_master_slave.inc --disconnect master1 --connection master2 drop database db; +--source reset_master_slave.inc --disconnect master2 + diff --git a/mysql-test/suite/multi_source/status_vars.result b/mysql-test/suite/multi_source/status_vars.result new file mode 100644 index 00000000000..12917f94140 --- /dev/null +++ b/mysql-test/suite/multi_source/status_vars.result @@ -0,0 +1,97 @@ +call mtr.add_suppression("Connection 'master1' already exists"); +change master 'master1' to +master_port=MYPORT_1, +master_host='127.0.0.1', +master_user='root', +master_heartbeat_period = 25; +start slave 'master1'; +set default_master_connection = 'master1'; +include/wait_for_slave_to_start.inc +set default_master_connection = ''; +change master to +master_port=MYPORT_2, +master_host='127.0.0.1', +master_user='root', +master_heartbeat_period=35; +start slave; +include/wait_for_slave_to_start.inc +# +# Check how status works for the default connection, anonymous or named +# +# Slave_running and Slave_heartbeat_period should be local for a connection +# +set default_master_connection = ''; +show status like 'Slave_running'; +Variable_name Value +Slave_running ON +show status like 'Slave_heartbeat_period'; +Variable_name Value +Slave_heartbeat_period 35.000 +stop slave io_thread; +include/wait_for_slave_io_to_stop.inc +show status like 'Slave_running'; +Variable_name Value +Slave_running OFF +set default_master_connection = 'master1'; +show status like 'Slave_running'; +Variable_name Value +Slave_running ON +show status like 'Slave_heartbeat_period'; +Variable_name Value +Slave_heartbeat_period 25.000 +# +# Slave_received_heartbeats should also be local +# +set default_master_connection = ''; +stop slave sql_thread; +include/wait_for_slave_sql_to_stop.inc +change master to master_heartbeat_period=1; +show status like 'Slave_received_heartbeats'; +Variable_name Value +Slave_received_heartbeats 0 +start slave; +include/wait_for_slave_to_start.inc +show status like 'Slave_received_heartbeats'; +Variable_name Value +Slave_received_heartbeats 2 +stop slave; +include/wait_for_slave_to_stop.inc +set default_master_connection = 'master1'; +show status like 'Slave_received_heartbeats'; +Variable_name Value +Slave_received_heartbeats 0 +stop slave; +include/wait_for_slave_to_stop.inc +change master to master_heartbeat_period=2; +start slave; +include/wait_for_slave_to_start.inc +show status like 'Slave_received_heartbeats'; +Variable_name Value +Slave_received_heartbeats 1 +# +# Slave_open_temp_tables should be global +# +set default_master_connection = ''; +start slave; +include/wait_for_slave_to_start.inc +set binlog_format = statement; +create temporary table tmp1 (i int) engine=MyISAM; +show status like 'Slave_open_temp_tables'; +Variable_name Value +Slave_open_temp_tables 1 +set default_master_connection = 'master1'; +show status like 'Slave_open_temp_tables'; +Variable_name Value +Slave_open_temp_tables 1 +set binlog_format = statement; +create temporary table tmp1 (i int) engine=MyISAM; +show status like 'Slave_open_temp_tables'; +Variable_name Value +Slave_open_temp_tables 2 +set default_master_connection = ''; +show status like 'Slave_open_temp_tables'; +Variable_name Value +Slave_open_temp_tables 2 +include/reset_master_slave.inc +include/reset_master_slave.inc +include/reset_master_slave.inc diff --git a/mysql-test/suite/multi_source/status_vars.test b/mysql-test/suite/multi_source/status_vars.test new file mode 100644 index 00000000000..8ecb9c17074 --- /dev/null +++ b/mysql-test/suite/multi_source/status_vars.test @@ -0,0 +1,132 @@ +--connect (slave,127.0.0.1,root,,,$SERVER_MYPORT_3) + +call mtr.add_suppression("Connection 'master1' already exists"); + +# Start replication from the first master + +--replace_result $SERVER_MYPORT_1 MYPORT_1 +eval change master 'master1' to +master_port=$SERVER_MYPORT_1, +master_host='127.0.0.1', +master_user='root', +master_heartbeat_period = 25; + +start slave 'master1'; +set default_master_connection = 'master1'; +--source include/wait_for_slave_to_start.inc + + +# Set up a proper 'default' connection to master2 + +set default_master_connection = ''; + +--replace_result $SERVER_MYPORT_2 MYPORT_2 +eval change master to +master_port=$SERVER_MYPORT_2, +master_host='127.0.0.1', +master_user='root', +master_heartbeat_period=35; + +start slave; +--source include/wait_for_slave_to_start.inc + +--echo # +--echo # Check how status works for the default connection, anonymous or named +--echo # + +--echo # Slave_running and Slave_heartbeat_period should be local for a connection +--echo # + +set default_master_connection = ''; +show status like 'Slave_running'; +show status like 'Slave_heartbeat_period'; +stop slave io_thread; +--source include/wait_for_slave_io_to_stop.inc +show status like 'Slave_running'; + +set default_master_connection = 'master1'; +show status like 'Slave_running'; +show status like 'Slave_heartbeat_period'; + +--echo # +--echo # Slave_received_heartbeats should also be local +--echo # + +set default_master_connection = ''; +stop slave sql_thread; +--source include/wait_for_slave_sql_to_stop.inc +change master to master_heartbeat_period=1; +show status like 'Slave_received_heartbeats'; +start slave; +--source include/wait_for_slave_to_start.inc + +--let $status_var = Slave_received_heartbeats +--let $status_var_value = 2 +# The units are tens of seconds +--let $status_timeout = 30 +--source include/wait_for_status_var.inc +show status like 'Slave_received_heartbeats'; +stop slave; +--source include/wait_for_slave_to_stop.inc + +set default_master_connection = 'master1'; +show status like 'Slave_received_heartbeats'; + +stop slave; +--source include/wait_for_slave_to_stop.inc +change master to master_heartbeat_period=2; +start slave; +--source include/wait_for_slave_to_start.inc + +--let $status_var = Slave_received_heartbeats +--let $status_var_value = 1 +--let $status_timeout = 30 +--source include/wait_for_status_var.inc +show status like 'Slave_received_heartbeats'; + + +--echo # +--echo # Slave_open_temp_tables should be global +--echo # + +set default_master_connection = ''; +start slave; +--source include/wait_for_slave_to_start.inc + +--connect (master1,127.0.0.1,root,,,$SERVER_MYPORT_1) +set binlog_format = statement; +create temporary table tmp1 (i int) engine=MyISAM; +--save_master_pos + +--connection slave +--sync_with_master 0,'master1' +show status like 'Slave_open_temp_tables'; + +set default_master_connection = 'master1'; +show status like 'Slave_open_temp_tables'; + +--connect (master2,127.0.0.1,root,,,$SERVER_MYPORT_2) +set binlog_format = statement; +create temporary table tmp1 (i int) engine=MyISAM; +--save_master_pos + +--connection slave +--sync_with_master 0,'' +show status like 'Slave_open_temp_tables'; + +set default_master_connection = ''; +show status like 'Slave_open_temp_tables'; + + +# Cleanup + +--source reset_master_slave.inc +--disconnect slave +--connection master1 +--source reset_master_slave.inc +--disconnect master1 +--connection master2 +--source reset_master_slave.inc +--disconnect master2 + + From 0ae6ee55a971218c61a6a05b730cb88776ea193d Mon Sep 17 00:00:00 2001 From: Elena Stepanova Date: Thu, 4 Oct 2012 13:59:54 +0400 Subject: [PATCH 282/289] Test fix: Mask server version in relaylog events output --- mysql-test/suite/multi_source/multisource.result | 6 +++--- mysql-test/suite/multi_source/multisource.test | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/mysql-test/suite/multi_source/multisource.result b/mysql-test/suite/multi_source/multisource.result index 4507b9c5676..61495e2fce2 100644 --- a/mysql-test/suite/multi_source/multisource.result +++ b/mysql-test/suite/multi_source/multisource.result @@ -29,13 +29,13 @@ mysqld-relay-bin-master1.000002 mysqld-relay-bin-master1.index show relaylog events; Log_name Pos Event_type Server_id End_log_pos Info -mysqld-relay-bin-master1.000001 4 Format_desc 3 246 Server ver: 10.0.0-MariaDB-debug-log, Binlog ver: 4 +mysqld-relay-bin-master1.000001 4 Format_desc 3 246 Server version mysqld-relay-bin-master1.000001 246 Rotate 3 304 mysqld-relay-bin-master1.000002;pos=4 show relaylog events in 'mysqld-relay-bin-master1.000002'; Log_name Pos Event_type Server_id End_log_pos Info -mysqld-relay-bin-master1.000002 4 Format_desc 3 246 Server ver: 10.0.0-MariaDB-debug-log, Binlog ver: 4 +mysqld-relay-bin-master1.000002 4 Format_desc 3 246 Server version mysqld-relay-bin-master1.000002 246 Rotate 1 0 master-bin.000001;pos=4 -mysqld-relay-bin-master1.000002 290 Format_desc 1 246 Server ver: 10.0.0-MariaDB-debug-log, Binlog ver: 4 +mysqld-relay-bin-master1.000002 290 Format_desc 1 246 Server version mysqld-relay-bin-master1.000002 532 Binlog_checkpoint 1 286 master-bin.000001 mysqld-relay-bin-master1.000002 572 Query 1 375 drop database if exists db1 mysqld-relay-bin-master1.000002 661 Query 1 456 create database db1 diff --git a/mysql-test/suite/multi_source/multisource.test b/mysql-test/suite/multi_source/multisource.test index b1e05051f59..df5309624bd 100644 --- a/mysql-test/suite/multi_source/multisource.test +++ b/mysql-test/suite/multi_source/multisource.test @@ -57,7 +57,9 @@ select * from db1.t1; # Check that relay logs are recognizable +--replace_regex /Server ver:.*/Server version/ show relaylog events; +--replace_regex /Server ver:.*/Server version/ show relaylog events in 'mysqld-relay-bin-master1.000002'; From 1ab7dfe5196a75fefb78ebc58d5fbf12c8f5444d Mon Sep 17 00:00:00 2001 From: Elena Stepanova Date: Thu, 4 Oct 2012 20:55:22 +0400 Subject: [PATCH 283/289] Fix multi-source replication tests for ps-protocol (different xid values), and disable for embedded --- mysql-test/suite/multi_source/info_logs.test | 2 ++ mysql-test/suite/multi_source/multisource.result | 8 ++++---- mysql-test/suite/multi_source/multisource.test | 12 ++++++++++-- mysql-test/suite/multi_source/relaylog_events.test | 2 ++ mysql-test/suite/multi_source/reset_slave.test | 7 ++++++- mysql-test/suite/multi_source/simple.test | 2 ++ mysql-test/suite/multi_source/skip_counter.test | 2 ++ mysql-test/suite/multi_source/status_vars.test | 6 ++++++ mysql-test/suite/multi_source/syntax.test | 4 +++- 9 files changed, 37 insertions(+), 8 deletions(-) diff --git a/mysql-test/suite/multi_source/info_logs.test b/mysql-test/suite/multi_source/info_logs.test index b4bbe7af385..73e6ee73722 100644 --- a/mysql-test/suite/multi_source/info_logs.test +++ b/mysql-test/suite/multi_source/info_logs.test @@ -2,6 +2,8 @@ # Check log files with multi-source # +--source include/not_embedded.inc + --connect (slave,127.0.0.1,root,,,$SERVER_MYPORT_3) --let $datadir = `SELECT @@datadir` diff --git a/mysql-test/suite/multi_source/multisource.result b/mysql-test/suite/multi_source/multisource.result index 61495e2fce2..c4fb7123e81 100644 --- a/mysql-test/suite/multi_source/multisource.result +++ b/mysql-test/suite/multi_source/multisource.result @@ -108,13 +108,13 @@ i f1 4 four show relaylog events; Log_name Pos Event_type Server_id End_log_pos Info -mysqld-relay-bin.000001 4 Format_desc 3 246 Server ver: 10.0.0-MariaDB-debug-log, Binlog ver: 4 +mysqld-relay-bin.000001 4 Format_desc 3 246 Server version mysqld-relay-bin.000001 246 Rotate 3 296 mysqld-relay-bin.000002;pos=4 show relaylog events in 'mysqld-relay-bin.000002'; Log_name Pos Event_type Server_id End_log_pos Info -mysqld-relay-bin.000002 4 Format_desc 3 246 Server ver: 10.0.0-MariaDB-debug-log, Binlog ver: 4 +mysqld-relay-bin.000002 4 Format_desc 3 246 Server version mysqld-relay-bin.000002 246 Rotate 2 0 master-bin.000001;pos=4 -mysqld-relay-bin.000002 290 Format_desc 2 246 Server ver: 10.0.0-MariaDB-debug-log, Binlog ver: 4 +mysqld-relay-bin.000002 290 Format_desc 2 246 Server version mysqld-relay-bin.000002 532 Binlog_checkpoint 2 286 master-bin.000001 mysqld-relay-bin.000002 572 Query 2 375 drop database if exists db2 mysqld-relay-bin.000002 661 Query 2 456 create database db2 @@ -122,7 +122,7 @@ mysqld-relay-bin.000002 742 Query 2 591 use `db2`; create table t1 (pk int auto_ mysqld-relay-bin.000002 877 Query 2 658 BEGIN mysqld-relay-bin.000002 944 Intvar 2 686 INSERT_ID=1 mysqld-relay-bin.000002 972 Query 2 782 use `db2`; insert into t1 (f1) values (1),(2) -mysqld-relay-bin.000002 1068 Xid 2 809 COMMIT /* xid=25 */ +mysqld-relay-bin.000002 1068 Xid 2 809 COMMIT /* xid= */ stop slave io_thread; show status like 'Slave_running'; Variable_name Value diff --git a/mysql-test/suite/multi_source/multisource.test b/mysql-test/suite/multi_source/multisource.test index df5309624bd..b9d26478282 100644 --- a/mysql-test/suite/multi_source/multisource.test +++ b/mysql-test/suite/multi_source/multisource.test @@ -1,3 +1,9 @@ +# +# Test basic replication functionality +# in multi-source setup +# + +--source include/not_embedded.inc --source include/have_innodb.inc --connect (slave,127.0.0.1,root,,,$SERVER_MYPORT_3) @@ -57,9 +63,9 @@ select * from db1.t1; # Check that relay logs are recognizable ---replace_regex /Server ver:.*/Server version/ +--replace_regex /Server ver:.*/Server version/ /xid=[0-9]+/xid=/ show relaylog events; ---replace_regex /Server ver:.*/Server version/ +--replace_regex /Server ver:.*/Server version/ /xid=[0-9]+/xid=/ show relaylog events in 'mysqld-relay-bin-master1.000002'; @@ -179,7 +185,9 @@ select * from db1.t1; # This should show relay log events for the default master # (the one with the empty name) +--replace_regex /Server ver:.*/Server version/ /xid=[0-9]+/xid=/ show relaylog events; +--replace_regex /Server ver:.*/Server version/ /xid=[0-9]+/xid=/ show relaylog events in 'mysqld-relay-bin.000002'; # Make sure we don't lose control over replication connections diff --git a/mysql-test/suite/multi_source/relaylog_events.test b/mysql-test/suite/multi_source/relaylog_events.test index 67048749f67..ba13a4dd7e9 100644 --- a/mysql-test/suite/multi_source/relaylog_events.test +++ b/mysql-test/suite/multi_source/relaylog_events.test @@ -3,6 +3,8 @@ # for a named master connection # +--source include/not_embedded.inc + --connect (slave,127.0.0.1,root,,,$SERVER_MYPORT_3) --replace_result $SERVER_MYPORT_1 MYPORT_1 diff --git a/mysql-test/suite/multi_source/reset_slave.test b/mysql-test/suite/multi_source/reset_slave.test index e63cf1d949a..bcc0560fe5b 100644 --- a/mysql-test/suite/multi_source/reset_slave.test +++ b/mysql-test/suite/multi_source/reset_slave.test @@ -1,4 +1,9 @@ -#--enable_connect_log +# +# Check RESET SLAVE [name] [ALL] for multi-source replication +# + +--source include/not_embedded.inc + --connect (slave,127.0.0.1,root,,,$SERVER_MYPORT_3) --replace_result $SERVER_MYPORT_1 MYPORT_1 diff --git a/mysql-test/suite/multi_source/simple.test b/mysql-test/suite/multi_source/simple.test index 8f501b777ad..915cbd73941 100644 --- a/mysql-test/suite/multi_source/simple.test +++ b/mysql-test/suite/multi_source/simple.test @@ -2,6 +2,8 @@ # Simple multi-master test # +--source include/not_embedded.inc + --connect (slave,127.0.0.1,root,,,$SERVER_MYPORT_3) --connect (master1,127.0.0.1,root,,,$SERVER_MYPORT_1) --connect (master2,127.0.0.1,root,,,$SERVER_MYPORT_2) diff --git a/mysql-test/suite/multi_source/skip_counter.test b/mysql-test/suite/multi_source/skip_counter.test index 04a9102a312..d158f382a97 100644 --- a/mysql-test/suite/multi_source/skip_counter.test +++ b/mysql-test/suite/multi_source/skip_counter.test @@ -5,6 +5,8 @@ # Create a schema and a table i # on the 1st master +--source include/not_embedded.inc + --connect (master1,127.0.0.1,root,,,$SERVER_MYPORT_1) --disable_warnings diff --git a/mysql-test/suite/multi_source/status_vars.test b/mysql-test/suite/multi_source/status_vars.test index 8ecb9c17074..eec89ee4e81 100644 --- a/mysql-test/suite/multi_source/status_vars.test +++ b/mysql-test/suite/multi_source/status_vars.test @@ -1,3 +1,9 @@ +# +# Status variables related to a replication connection +# + +--source include/not_embedded.inc + --connect (slave,127.0.0.1,root,,,$SERVER_MYPORT_3) call mtr.add_suppression("Connection 'master1' already exists"); diff --git a/mysql-test/suite/multi_source/syntax.test b/mysql-test/suite/multi_source/syntax.test index 15e862ab607..ae493200bf1 100644 --- a/mysql-test/suite/multi_source/syntax.test +++ b/mysql-test/suite/multi_source/syntax.test @@ -1,5 +1,7 @@ # Test multi master syntax -source include/master-slave.inc; + +--source include/not_embedded.inc +--source include/master-slave.inc # Check syntax of multi source replication From ac891c616c683d36aaf2bf002d91fa01ae484b6e Mon Sep 17 00:00:00 2001 From: Elena Stepanova Date: Fri, 5 Oct 2012 00:36:17 +0400 Subject: [PATCH 284/289] Extra check for synchronization in the multi-source replication test --- mysql-test/suite/multi_source/multisource.test | 8 ++++++++ .../suite/multi_source/wait_for_sql_thread_read_all.inc | 6 ++++++ 2 files changed, 14 insertions(+) create mode 100644 mysql-test/suite/multi_source/wait_for_sql_thread_read_all.inc diff --git a/mysql-test/suite/multi_source/multisource.test b/mysql-test/suite/multi_source/multisource.test index b9d26478282..e9d672a9ae3 100644 --- a/mysql-test/suite/multi_source/multisource.test +++ b/mysql-test/suite/multi_source/multisource.test @@ -26,6 +26,10 @@ set default_master_connection = 'master1'; --connection slave --sync_with_master 0,'master1' +# Here and further: add an extra check on SQL thread status +# as the normal sync is not always enough +--source wait_for_sql_thread_read_all.inc + # each of the 3 commands should produce # 'master1' status @@ -114,6 +118,8 @@ master_user='root'; start slave; --source include/wait_for_slave_to_start.inc +--source wait_for_sql_thread_read_all.inc + # See both connections in the same status output --replace_result $SERVER_MYPORT_1 MYPORT_1 $SERVER_MYPORT_2 MYPORT_2 @@ -177,6 +183,8 @@ create table db1.t3 (f1 int) engine=InnoDB; --connection slave --sync_with_master 0,'master1' +--source wait_for_sql_thread_read_all.inc + --replace_result $SERVER_MYPORT_1 MYPORT_1 $SERVER_MYPORT_2 MYPORT_2 show all slaves status; diff --git a/mysql-test/suite/multi_source/wait_for_sql_thread_read_all.inc b/mysql-test/suite/multi_source/wait_for_sql_thread_read_all.inc new file mode 100644 index 00000000000..ec5ecd0cb17 --- /dev/null +++ b/mysql-test/suite/multi_source/wait_for_sql_thread_read_all.inc @@ -0,0 +1,6 @@ +--let $show_statement = show all slaves status +--let $field = Slave_SQL_State +--let $condition = = 'Slave has read all relay log; waiting for the slave I/O thread to update it' +--let $wait_for_all = 1 +--source include/wait_show_condition.inc + From ea6a4eef3a43d916d43bef24165e16906b98a8de Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Thu, 4 Oct 2012 23:52:11 +0300 Subject: [PATCH 285/289] Fixed issues found by buildbot & valgrind: - Wrong thd uses in Item_subselect, could lead to crash - Inititalize uninitialized variable in new autoincrement handling code sql/handler.cc: More DBUG_PRINT sql/item_subselect.cc: Wrong thd uses in Item_subselect, could lead to crash storage/innobase/handler/ha_innodb.cc: Initialize variable needed by upper level. This only happens when auto-increment value wraps over. storage/xtradb/handler/ha_innodb.cc: Initialize variable needed by upper level. This only happens when auto-increment value wraps over. --- sql/handler.cc | 3 ++- sql/item_subselect.cc | 2 +- storage/innobase/handler/ha_innodb.cc | 1 + storage/xtradb/handler/ha_innodb.cc | 3 ++- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/sql/handler.cc b/sql/handler.cc index b06aa4255fd..8891b29138c 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -2621,7 +2621,8 @@ int handler::update_auto_increment() if (unlikely(nr == ULONGLONG_MAX)) DBUG_RETURN(HA_ERR_AUTOINC_ERANGE); - DBUG_PRINT("info",("auto_increment: %lu", (ulong) nr)); + DBUG_PRINT("info",("auto_increment: %llu nb_reserved_values: %llu", + nr, nb_reserved_values)); /* Store field without warning (Warning will be printed by insert) */ save_count_cuted_fields= thd->count_cuted_fields; diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 2f6b4549d8d..d79c6ccfe64 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -220,7 +220,7 @@ bool Item_subselect::fix_fields(THD *thd_param, Item **ref) uint8 uncacheable; bool res; - status_var_increment(thd->status_var.feature_subquery); + status_var_increment(thd_param->status_var.feature_subquery); DBUG_ASSERT(fixed == 0); engine->set_thd((thd= thd_param)); diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 3185403c2ac..3baa02b1228 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -10284,6 +10284,7 @@ ha_innobase::get_auto_increment( take care of this */ prebuilt->autoinc_last_value = 0; dict_table_autoinc_unlock(prebuilt->table); + *nb_reserved_values= 0; return; } *nb_reserved_values = trx->n_autoinc_rows; diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index f4072082b33..a9995a5bdf8 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -11225,6 +11225,7 @@ ha_innobase::get_auto_increment( take care of this */ prebuilt->autoinc_last_value = 0; dict_table_autoinc_unlock(prebuilt->table); + *nb_reserved_values = 0; return; } *nb_reserved_values = trx->n_autoinc_rows; @@ -13019,7 +13020,7 @@ static MYSQL_SYSVAR_ENUM(corrupt_table_action, srv_pass_corrupt_table, "Warn corruptions of user tables as 'corrupt table' instead of not crashing itself, " "when used with file_per_table. " "All file io for the datafile after detected as corrupt are disabled, " - "except for the deletion.", + "except for the deletion. Possible options are 'assert', 'warn' & 'salvage'", NULL, NULL, 0, &corrupt_table_action_typelib); static MYSQL_SYSVAR_ULINT(lazy_drop_table, srv_lazy_drop_table, From be4cea7ef22e4d5108479b2e76972803e4c6a92e Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Thu, 4 Oct 2012 23:58:59 +0300 Subject: [PATCH 286/289] Fixed compiler warnings sql/rpl_mi.cc: Fixed compiler warning support-files/compiler_warnings.supp: Supress warning about offsetof macro. (ok in this case) --- sql/rpl_mi.cc | 3 ++- support-files/compiler_warnings.supp | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/sql/rpl_mi.cc b/sql/rpl_mi.cc index e004e3495c7..fc13fb2c762 100644 --- a/sql/rpl_mi.cc +++ b/sql/rpl_mi.cc @@ -666,7 +666,8 @@ void create_logfile_name_with_suffix(char *res_file_name, uint length, length-= (suffix->length - ext_pos); /* Leave place for extension */ p= res_file_name + ext_pos; *p++= '-'; /* Add separator */ - p= strmake(p, res, min(length - (p - res_file_name), res_length)); + p= strmake(p, res, min((size_t) (length - (p - res_file_name)), + res_length)); /* Add back extension. We have checked above that there is space for it */ strmov(p, ext); } diff --git a/support-files/compiler_warnings.supp b/support-files/compiler_warnings.supp index e18c44bf5ed..107c306421a 100644 --- a/support-files/compiler_warnings.supp +++ b/support-files/compiler_warnings.supp @@ -193,6 +193,8 @@ ma_packrec\.c : .*result of 32-bit shift implicitly converted to 64 bits.* : 550 # .* : .*no matching operator delete found; memory will not be freed if initialization throws an exception.* ctype-simple\.c : .*unary minus operator applied to unsigned type, result still unsigned.* +sql/sys_vars\.cc : invalid access to non-static data member +sql/sys_vars\.cc : perhaps the 'offsetof' macro was used incorrectly # Wrong warning due to GCC bug: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=29478 regexec\.c : passing argument 3 of.*matcher.* discards qualifiers from pointer target type From b988331b71efbb75b58d10ee3c10b08d0f670394 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Sat, 6 Oct 2012 11:09:18 +0400 Subject: [PATCH 287/289] MDEV-462: SHOW EXPLAIN: Assertion `table_list->table' fails in find_field_in_table_ref ... - Only allow basic constants as SHOW EXPLAIN arguments. --- mysql-test/r/show_explain.result | 7 ++++++- mysql-test/t/show_explain.test | 8 +++++++- sql/sql_parse.cc | 3 ++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/show_explain.result b/mysql-test/r/show_explain.result index b5eda0b30c8..bf96ad88f23 100644 --- a/mysql-test/r/show_explain.result +++ b/mysql-test/r/show_explain.result @@ -7,7 +7,7 @@ insert into t1 select A.a + 10*B.a + 100*C.a from t0 A, t0 B, t0 C; alter table t1 add b int, add c int, add filler char(32); update t1 set b=a, c=a, filler='fooo'; alter table t1 add key(a), add key(b); -show explain for 2*1000*1000*1000; +show explain for 2000000000; ERROR HY000: Unknown thread id: 2000000000 show explain for (select max(a) from t0); ERROR HY000: You may only use constant expressions in this statement @@ -1069,5 +1069,10 @@ a 2 set debug_dbug=''; set names default; +# +# MDEV-462: SHOW EXPLAIN: Assertion `table_list->table' fails in find_field_in_table_ref if FOR contains a non-numeric value +# +show explain for foo; +ERROR HY000: You may only use constant expressions in this statement # End drop table t0; diff --git a/mysql-test/t/show_explain.test b/mysql-test/t/show_explain.test index 8bfeae7e7e5..c2429b82d0c 100644 --- a/mysql-test/t/show_explain.test +++ b/mysql-test/t/show_explain.test @@ -43,7 +43,7 @@ alter table t1 add key(a), add key(b); # Try killing a non-existent thread # --error ER_NO_SUCH_THREAD -show explain for 2*1000*1000*1000; +show explain for 2000000000; --error ER_SET_CONSTANTS_ONLY show explain for (select max(a) from t0); @@ -1105,5 +1105,11 @@ reap; set debug_dbug=''; set names default; +--echo # +--echo # MDEV-462: SHOW EXPLAIN: Assertion `table_list->table' fails in find_field_in_table_ref if FOR contains a non-numeric value +--echo # +--error ER_SET_CONSTANTS_ONLY +show explain for foo; + --echo # End drop table t0; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 3c697cb43af..217b60faa57 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2159,7 +2159,8 @@ mysql_execute_command(THD *thd) } Item **it= lex->value_list.head_ref(); - if ((!(*it)->fixed && (*it)->fix_fields(lex->thd, it)) || + if (!(*it)->basic_const_item() || + (!(*it)->fixed && (*it)->fix_fields(lex->thd, it)) || (*it)->check_cols(1)) { my_message(ER_SET_CONSTANTS_ONLY, ER(ER_SET_CONSTANTS_ONLY), From 850fb901770d8a40a2a8d0cee7737089153e5cc4 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Sat, 6 Oct 2012 11:10:59 +0400 Subject: [PATCH 288/289] Remove unneeded comments --- sql/sql_select.cc | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 7a23a71e040..c46d7cdb30c 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -19038,14 +19038,6 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order, /* Currently ORDER BY ... LIMIT is not supported in subqueries. */ DBUG_ASSERT(join->group_list || !join->is_in_subquery()); - /* - If we have a select->quick object that is created outside of - create_sort_index() and this is part of a subquery that - potentially can be executed multiple times then we should not - delete the quick object on exit from this function. - */ - //bool keep_quick= select && select->quick && join->join_tab_save; - /* When there is SQL_BIG_RESULT do not sort using index for GROUP BY, and thus force sorting on disk unless a group min-max optimization @@ -19097,7 +19089,6 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order, get_quick_select_for_ref(thd, table, &tab->ref, tab->found_records)))) goto err; - //DBUG_ASSERT(!keep_quick);//psergey-post-merge-check quick_created= TRUE; } } @@ -19145,6 +19136,7 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order, /*TODO: here, close the index scan, cancel index-only read. */ tab->records= table->sort.found_records; // For SQL_CALC_ROWS #if 0 + /* MariaDB doesn't need the following: */ if (select) { /* From 807fef40fffbbb8e92564a52b902b504ba8cfcdc Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Thu, 11 Oct 2012 07:01:44 +0400 Subject: [PATCH 289/289] Update test results after SHOW EXPLAIN merge-in. --- mysql-test/suite/multi_source/simple.result | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/multi_source/simple.result b/mysql-test/suite/multi_source/simple.result index 59f23179243..4018573d074 100644 --- a/mysql-test/suite/multi_source/simple.result +++ b/mysql-test/suite/multi_source/simple.result @@ -6,7 +6,7 @@ include/wait_for_slave_to_start.inc set default_master_connection = 'slave2'; start all slaves; Warnings: -Note 1936 SLAVE 'slave2' started +Note 1937 SLAVE 'slave2' started include/wait_for_slave_to_start.inc set default_master_connection = ''; show all slaves status; @@ -67,7 +67,7 @@ Connection_name Slave_SQL_State Slave_IO_State Master_Host Master_User Master_Po slave2 Slave has read all relay log; waiting for the slave I/O thread to update it Waiting for master to send event 127.0.0.1 root MYPORT_2 60 master-bin.000001 286 mysqld-relay-bin-slave2.000002 572 master-bin.000001 Yes Yes 0 0 286 875 None 0 No 0 No 0 0 2 0 1073741824 6 0 60.000 stop all slaves; Warnings: -Note 1937 SLAVE 'slave2' stopped +Note 1938 SLAVE 'slave2' stopped show all slaves status; Connection_name Slave_SQL_State 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 Replicate_Ignore_Server_Ids Master_Server_Id Retried_transactions Max_relay_log_size Executed_log_entries Slave_received_heartbeats Slave_heartbeat_period slave2 127.0.0.1 root MYPORT_2 60 master-bin.000001 286 mysqld-relay-bin-slave2.000002 572 master-bin.000001 No No 0 0 286 875 None 0 No NULL No 0 0 2 0 1073741824 6 0 60.000
12
12
12
12