diff options
author | unknown <kostja@bodhi.local> | 2006-11-29 11:44:37 +0300 |
---|---|---|
committer | unknown <kostja@bodhi.local> | 2006-11-29 11:44:37 +0300 |
commit | 0e978328ae3055a55f9e21cc7b395cf2581925b9 (patch) | |
tree | f6410b9231112e66043c0eb7edc1b33fbff6e760 /sql | |
parent | 0534b679b70d34db1a9ff3d5ae0c6dd39560636f (diff) | |
parent | fe99bda872fd51b07e1ebb0dc506e26d195edec7 (diff) | |
download | mariadb-git-0e978328ae3055a55f9e21cc7b395cf2581925b9.tar.gz |
Merge bk-internal.mysql.com:/home/bk/mysql-5.1
into bodhi.local:/opt/local/work/mysql-5.1-runtime-merge
libmysql/libmysql.c:
Auto merged
mysql-test/r/ps.result:
Auto merged
mysql-test/t/func_str.test:
Auto merged
mysql-test/t/ps.test:
Auto merged
sql/item_cmpfunc.cc:
Auto merged
sql/item_func.cc:
Auto merged
sql/item_strfunc.cc:
Auto merged
sql/item_sum.cc:
Auto merged
sql/mysqld.cc:
Auto merged
sql/set_var.cc:
Auto merged
sql/sql_lex.cc:
Auto merged
sql/sql_lex.h:
Auto merged
sql/sql_yacc.yy:
Auto merged
server-tools/instance-manager/mysql_connection.cc:
Rollback Monty's removals of explicit casts
tests/mysql_client_test.c:
SCCS merged
Diffstat (limited to 'sql')
80 files changed, 3523 insertions, 2696 deletions
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 1c2944de530..4cdc4c01c4e 100644 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -54,6 +54,7 @@ ADD_EXECUTABLE(mysqld ../sql-common/client.c derror.cc des_key_file.cc event_queue.cc event_db_repository.cc sql_tablespace.cc events.cc ../sql-common/my_user.c partition_info.cc rpl_utility.cc rpl_injector.cc sql_locale.cc + rpl_rli.cc rpl_mi.cc ${PROJECT_SOURCE_DIR}/sql/sql_yacc.cc ${PROJECT_SOURCE_DIR}/sql/sql_yacc.h ${PROJECT_SOURCE_DIR}/include/mysqld_error.h diff --git a/sql/Makefile.am b/sql/Makefile.am index 9a0303a433f..ac2f4836c15 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -54,7 +54,7 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \ ha_ndbcluster.h ha_ndbcluster_binlog.h \ ha_ndbcluster_tables.h \ opt_range.h protocol.h rpl_tblmap.h rpl_utility.h \ - log.h sql_show.h rpl_rli.h \ + log.h sql_show.h rpl_rli.h rpl_mi.h \ sql_select.h structs.h table.h sql_udf.h hash_filo.h \ lex.h lex_symbol.h sql_acl.h sql_crypt.h \ log_event.h sql_repl.h slave.h rpl_filter.h \ @@ -94,7 +94,7 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \ sql_load.cc mf_iocache.cc field_conv.cc sql_show.cc \ sql_udf.cc sql_analyse.cc sql_analyse.h sql_cache.cc \ slave.cc sql_repl.cc rpl_filter.cc rpl_tblmap.cc \ - rpl_utility.cc rpl_injector.cc \ + rpl_utility.cc rpl_injector.cc rpl_rli.cc rpl_mi.cc \ sql_union.cc sql_derived.cc \ client.c sql_client.cc mini_client_errors.c pack.c\ stacktrace.c repl_failsafe.h repl_failsafe.cc \ diff --git a/sql/event_data_objects.cc b/sql/event_data_objects.cc index afd10350bb5..0de90e4145b 100644 --- a/sql/event_data_objects.cc +++ b/sql/event_data_objects.cc @@ -124,8 +124,8 @@ void Event_parse_data::init_body(THD *thd) { DBUG_ENTER("Event_parse_data::init_body"); - DBUG_PRINT("info", ("body=[%s] body_begin=0x%lx end=0x%lx", body_begin, - body_begin, thd->lex->ptr)); + DBUG_PRINT("info", ("body: '%s' body_begin: 0x%lx end: 0x%lx", body_begin, + (long) body_begin, (long) thd->lex->ptr)); body.length= thd->lex->ptr - body_begin; const uchar *body_end= body_begin + body.length - 1; @@ -399,8 +399,9 @@ Event_parse_data::init_starts(THD *thd) thd->variables.time_zone->gmt_sec_to_TIME(&time_tmp, (my_time_t) thd->query_start()); - DBUG_PRINT("info",("now =%lld", TIME_to_ulonglong_datetime(&time_tmp))); - DBUG_PRINT("info",("starts=%lld", TIME_to_ulonglong_datetime(<ime))); + DBUG_PRINT("info",("now: %ld starts: %ld", + (long) TIME_to_ulonglong_datetime(&time_tmp), + (long) TIME_to_ulonglong_datetime(<ime))); if (TIME_to_ulonglong_datetime(<ime) < TIME_to_ulonglong_datetime(&time_tmp)) goto wrong_value; @@ -536,8 +537,9 @@ Event_parse_data::check_parse_data(THD *thd) { bool ret; DBUG_ENTER("Event_parse_data::check_parse_data"); - DBUG_PRINT("info", ("execute_at=0x%lx expr=0x%lx starts=0x%lx ends=0x%lx", - item_execute_at, item_expression, item_starts, item_ends)); + DBUG_PRINT("info", ("execute_at: 0x%lx expr=0x%lx starts=0x%lx ends=0x%lx", + (long) item_execute_at, (long) item_expression, + (long) item_starts, (long) item_ends)); init_name(thd, identifier); @@ -564,9 +566,9 @@ Event_parse_data::init_definer(THD *thd) int definer_host_len; DBUG_ENTER("Event_parse_data::init_definer"); - DBUG_PRINT("info",("init definer_user thd->mem_root=0x%lx " - "thd->sec_ctx->priv_user=0x%lx", thd->mem_root, - thd->security_ctx->priv_user)); + DBUG_PRINT("info",("init definer_user thd->mem_root: 0x%lx " + "thd->sec_ctx->priv_user: 0x%lx", (long) thd->mem_root, + (long) thd->security_ctx->priv_user)); definer_user_len= strlen(thd->security_ctx->priv_user); definer_host_len= strlen(thd->security_ctx->priv_host); @@ -1032,8 +1034,9 @@ bool get_next_time(TIME *next, TIME *start, TIME *time_now, TIME *last_exec, TIME tmp; longlong months=0, seconds=0; DBUG_ENTER("get_next_time"); - DBUG_PRINT("enter", ("start=%llu now=%llu", TIME_to_ulonglong_datetime(start), - TIME_to_ulonglong_datetime(time_now))); + DBUG_PRINT("enter", ("start: %lu now: %lu", + (long) TIME_to_ulonglong_datetime(start), + (long) TIME_to_ulonglong_datetime(time_now))); bzero(&interval, sizeof(interval)); @@ -1081,7 +1084,7 @@ bool get_next_time(TIME *next, TIME *start, TIME *time_now, TIME *last_exec, case INTERVAL_LAST: DBUG_ASSERT(0); } - DBUG_PRINT("info", ("seconds=%ld months=%ld", seconds, months)); + DBUG_PRINT("info", ("seconds: %ld months: %ld", (long) seconds, (long) months)); if (seconds) { longlong seconds_diff; @@ -1099,14 +1102,14 @@ bool get_next_time(TIME *next, TIME *start, TIME *time_now, TIME *last_exec, event two times for the same time get the next exec if the modulus is not */ - DBUG_PRINT("info", ("multiplier=%d", multiplier)); + DBUG_PRINT("info", ("multiplier: %d", multiplier)); if (seconds_diff % seconds || (!seconds_diff && last_exec->year) || TIME_to_ulonglong_datetime(time_now) == TIME_to_ulonglong_datetime(last_exec)) ++multiplier; interval.second= seconds * multiplier; - DBUG_PRINT("info", ("multiplier=%u interval.second=%u", multiplier, - interval.second)); + DBUG_PRINT("info", ("multiplier: %lu interval.second: %lu", (ulong) multiplier, + (ulong) interval.second)); tmp= *start; if (!(ret= date_add_interval(&tmp, INTERVAL_SECOND, interval))) *next= tmp; @@ -1158,7 +1161,7 @@ bool get_next_time(TIME *next, TIME *start, TIME *time_now, TIME *last_exec, } done: - DBUG_PRINT("info", ("next=%llu", TIME_to_ulonglong_datetime(next))); + DBUG_PRINT("info", ("next: %lu", (long) TIME_to_ulonglong_datetime(next))); DBUG_RETURN(ret); } @@ -1183,17 +1186,17 @@ Event_queue_element::compute_next_execution_time() { TIME time_now; int tmp; - DBUG_ENTER("Event_queue_element::compute_next_execution_time"); - DBUG_PRINT("enter", ("starts=%llu ends=%llu last_executed=%llu this=0x%lx", - TIME_to_ulonglong_datetime(&starts), - TIME_to_ulonglong_datetime(&ends), - TIME_to_ulonglong_datetime(&last_executed), this)); + DBUG_PRINT("enter", ("starts: %lu ends: %lu last_executed: %lu this: 0x%lx", + (long) TIME_to_ulonglong_datetime(&starts), + (long) TIME_to_ulonglong_datetime(&ends), + (long) TIME_to_ulonglong_datetime(&last_executed), + (long) this)); if (status == Event_queue_element::DISABLED) { DBUG_PRINT("compute_next_execution_time", - ("Event %s is DISABLED", name.str)); + ("Event %s is DISABLED", name.str)); goto ret; } /* If one-time, no need to do computation */ @@ -1203,9 +1206,9 @@ Event_queue_element::compute_next_execution_time() if (last_executed.year) { DBUG_PRINT("info",("One-time event %s.%s of was already executed", - dbname.str, name.str, definer.str)); + dbname.str, name.str)); dropped= (on_completion == Event_queue_element::ON_COMPLETION_DROP); - DBUG_PRINT("info",("One-time event will be dropped=%d.", dropped)); + DBUG_PRINT("info",("One-time event will be dropped: %d.", dropped)); status= Event_queue_element::DISABLED; status_changed= TRUE; @@ -1215,7 +1218,8 @@ Event_queue_element::compute_next_execution_time() my_tz_UTC->gmt_sec_to_TIME(&time_now, current_thd->query_start()); - DBUG_PRINT("info",("NOW=[%llu]", TIME_to_ulonglong_datetime(&time_now))); + DBUG_PRINT("info",("NOW: [%lu]", + (ulong) TIME_to_ulonglong_datetime(&time_now))); /* if time_now is after ends don't execute anymore */ if (!ends_null && (tmp= my_time_compare(&ends, &time_now)) == -1) @@ -1226,7 +1230,7 @@ Event_queue_element::compute_next_execution_time() execute_at_null= TRUE; if (on_completion == Event_queue_element::ON_COMPLETION_DROP) dropped= TRUE; - DBUG_PRINT("info", ("Dropped=%d", dropped)); + DBUG_PRINT("info", ("Dropped: %d", dropped)); status= Event_queue_element::DISABLED; status_changed= TRUE; @@ -1297,7 +1301,8 @@ Event_queue_element::compute_next_execution_time() } else { - DBUG_PRINT("info",("Next[%llu]",TIME_to_ulonglong_datetime(&next_exec))); + DBUG_PRINT("info",("Next[%lu]", + (ulong) TIME_to_ulonglong_datetime(&next_exec))); execute_at= next_exec; execute_at_null= FALSE; } @@ -1319,7 +1324,8 @@ Event_queue_element::compute_next_execution_time() expression, interval)) goto err; execute_at= next_exec; - DBUG_PRINT("info",("Next[%llu]",TIME_to_ulonglong_datetime(&next_exec))); + DBUG_PRINT("info",("Next[%lu]", + (ulong) TIME_to_ulonglong_datetime(&next_exec))); } else { @@ -1353,7 +1359,8 @@ Event_queue_element::compute_next_execution_time() expression, interval)) goto err; execute_at= next_exec; - DBUG_PRINT("info",("Next[%llu]",TIME_to_ulonglong_datetime(&next_exec))); + DBUG_PRINT("info",("Next[%lu]", + (ulong) TIME_to_ulonglong_datetime(&next_exec))); } execute_at_null= FALSE; } @@ -1390,8 +1397,8 @@ Event_queue_element::compute_next_execution_time() } else { - DBUG_PRINT("info", ("Next[%llu]", - TIME_to_ulonglong_datetime(&next_exec))); + DBUG_PRINT("info", ("Next[%lu]", + (ulong) TIME_to_ulonglong_datetime(&next_exec))); execute_at= next_exec; execute_at_null= FALSE; } @@ -1400,8 +1407,8 @@ Event_queue_element::compute_next_execution_time() goto ret; } ret: - DBUG_PRINT("info", ("ret=0 execute_at=%llu", - TIME_to_ulonglong_datetime(&execute_at))); + DBUG_PRINT("info", ("ret: 0 execute_at: %lu", + (long) TIME_to_ulonglong_datetime(&execute_at))); DBUG_RETURN(FALSE); err: DBUG_PRINT("info", ("ret=1")); @@ -1688,7 +1695,7 @@ done: thd->end_statement(); thd->cleanup_after_query(); - DBUG_PRINT("info", ("EXECUTED %s.%s ret=%d", dbname.str, name.str, ret)); + DBUG_PRINT("info", ("EXECUTED %s.%s ret: %d", dbname.str, name.str, ret)); DBUG_RETURN(ret); } @@ -1752,7 +1759,7 @@ Event_job_data::compile(THD *thd, MEM_ROOT *mem_root) thd->update_charset(); - DBUG_PRINT("info",("old_sql_mode=%d new_sql_mode=%d",old_sql_mode, sql_mode)); + DBUG_PRINT("info",("old_sql_mode: %lu new_sql_mode: %lu",old_sql_mode, sql_mode)); thd->variables.sql_mode= this->sql_mode; /* Change the memory root for the execution time */ if (mem_root) @@ -1769,7 +1776,7 @@ Event_job_data::compile(THD *thd, MEM_ROOT *mem_root) thd->query= show_create.c_ptr_safe(); thd->query_length= show_create.length(); - DBUG_PRINT("info", ("query:%s",thd->query)); + DBUG_PRINT("info", ("query: %s",thd->query)); event_change_security_context(thd, definer_user, definer_host, dbname, &save_ctx); @@ -1777,14 +1784,14 @@ Event_job_data::compile(THD *thd, MEM_ROOT *mem_root) mysql_init_query(thd, (uchar*) thd->query, thd->query_length); if (MYSQLparse((void *)thd) || thd->is_fatal_error) { - DBUG_PRINT("error", ("error during compile or thd->is_fatal_error=%d", + DBUG_PRINT("error", ("error during compile or thd->is_fatal_error: %d", thd->is_fatal_error)); /* Free lex associated resources QQ: Do we really need all this stuff here? */ sql_print_error("SCHEDULER: Error during compilation of %s.%s or " - "thd->is_fatal_error=%d", + "thd->is_fatal_error: %d", dbname.str, name.str, thd->is_fatal_error); lex.unit.cleanup(); diff --git a/sql/event_data_objects.h b/sql/event_data_objects.h index e7e96d299fb..2da39c2158b 100644 --- a/sql/event_data_objects.h +++ b/sql/event_data_objects.h @@ -111,14 +111,14 @@ public: void *p; DBUG_ENTER("Event_queue_element::new(size)"); p= my_malloc(size, MYF(0)); - DBUG_PRINT("info", ("alloc_ptr=0x%lx", p)); + DBUG_PRINT("info", ("alloc_ptr: 0x%lx", (long) p)); DBUG_RETURN(p); } static void operator delete(void *ptr, size_t size) { DBUG_ENTER("Event_queue_element::delete(ptr,size)"); - DBUG_PRINT("enter", ("free_ptr=0x%lx", ptr)); + DBUG_PRINT("enter", ("free_ptr: 0x%lx", (long) ptr)); TRASH(ptr, size); my_free((gptr) ptr, MYF(0)); DBUG_VOID_RETURN; diff --git a/sql/event_db_repository.cc b/sql/event_db_repository.cc index 3d30aff669b..367c5bae579 100644 --- a/sql/event_db_repository.cc +++ b/sql/event_db_repository.cc @@ -958,7 +958,7 @@ Event_db_repository::load_named_event(THD *thd, LEX_STRING dbname, Open_tables_state backup; DBUG_ENTER("Event_db_repository::load_named_event"); - DBUG_PRINT("enter",("thd=0x%lx name:%*s",thd, name.length, name.str)); + DBUG_PRINT("enter",("thd: 0x%lx name: %*s", (long) thd, name.length, name.str)); thd->reset_n_backup_open_tables_state(&backup); diff --git a/sql/event_queue.cc b/sql/event_queue.cc index 527a59018a8..7ec665fcd5f 100644 --- a/sql/event_queue.cc +++ b/sql/event_queue.cc @@ -143,7 +143,7 @@ Event_queue::init_queue(THD *thd, Event_db_repository *db_repo) struct event_queue_param *event_queue_param_value= NULL; DBUG_ENTER("Event_queue::init_queue"); - DBUG_PRINT("enter", ("this=0x%lx", this)); + DBUG_PRINT("enter", ("this: 0x%lx", (long) this)); LOCK_QUEUE_DATA(); db_repository= db_repo; @@ -218,7 +218,7 @@ Event_queue::create_event(THD *thd, LEX_STRING dbname, LEX_STRING name) int res; Event_queue_element *new_element; DBUG_ENTER("Event_queue::create_event"); - DBUG_PRINT("enter", ("thd=0x%lx et=%s.%s",thd, dbname.str, name.str)); + DBUG_PRINT("enter", ("thd: 0x%lx et=%s.%s", (long) thd, dbname.str, name.str)); new_element= new Event_queue_element(); res= db_repository->load_named_event(thd, dbname, name, new_element); @@ -229,7 +229,7 @@ Event_queue::create_event(THD *thd, LEX_STRING dbname, LEX_STRING name) new_element->compute_next_execution_time(); LOCK_QUEUE_DATA(); - DBUG_PRINT("info", ("new event in the queue 0x%lx", new_element)); + DBUG_PRINT("info", ("new event in the queue: 0x%lx", (long) new_element)); queue_insert_safe(&queue, (byte *) new_element); dbug_dump_queue(thd->query_start()); pthread_cond_broadcast(&COND_queue_state); @@ -264,7 +264,7 @@ Event_queue::update_event(THD *thd, LEX_STRING dbname, LEX_STRING name, Event_queue_element *new_element; DBUG_ENTER("Event_queue::update_event"); - DBUG_PRINT("enter", ("thd=0x%lx et=[%s.%s]", thd, dbname.str, name.str)); + DBUG_PRINT("enter", ("thd: 0x%lx et=[%s.%s]", (long) thd, dbname.str, name.str)); new_element= new Event_queue_element(); @@ -294,7 +294,7 @@ Event_queue::update_event(THD *thd, LEX_STRING dbname, LEX_STRING name, /* If not disabled event */ if (new_element) { - DBUG_PRINT("info", ("new event in the Q 0x%lx", new_element)); + DBUG_PRINT("info", ("new event in the queue: 0x%lx", (long) new_element)); queue_insert_safe(&queue, (byte *) new_element); pthread_cond_broadcast(&COND_queue_state); } @@ -322,7 +322,8 @@ void Event_queue::drop_event(THD *thd, LEX_STRING dbname, LEX_STRING name) { DBUG_ENTER("Event_queue::drop_event"); - DBUG_PRINT("enter", ("thd=0x%lx db=%s name=%s", thd, dbname.str, name.str)); + DBUG_PRINT("enter", ("thd: 0x%lx db :%s name: %s", (long) thd, + dbname.str, name.str)); LOCK_QUEUE_DATA(); find_n_remove_event(dbname, name); @@ -484,7 +485,7 @@ Event_queue::load_events_from_db(THD *thd) bool clean_the_queue= TRUE; DBUG_ENTER("Event_queue::load_events_from_db"); - DBUG_PRINT("enter", ("thd=0x%lx", thd)); + DBUG_PRINT("enter", ("thd: 0x%lx", (long) thd)); if ((ret= db_repository->open_event_table(thd, TL_READ, &table))) { @@ -555,7 +556,6 @@ Event_queue::load_events_from_db(THD *thd) goto end; } - DBUG_PRINT("load_events_from_db", ("Adding 0x%lx to the exec list.")); queue_insert_safe(&queue, (byte *) et); count++; } @@ -663,16 +663,20 @@ Event_queue::dbug_dump_queue(time_t now) for (i = 0; i < queue.elements; i++) { et= ((Event_queue_element*)queue_element(&queue, i)); - DBUG_PRINT("info",("et=0x%lx db=%s name=%s",et, et->dbname.str, et->name.str)); - DBUG_PRINT("info", ("exec_at=%llu starts=%llu ends=%llu execs_so_far=%u" - " expr=%lld et.exec_at=%d now=%d (et.exec_at - now)=%d if=%d", - TIME_to_ulonglong_datetime(&et->execute_at), - TIME_to_ulonglong_datetime(&et->starts), - TIME_to_ulonglong_datetime(&et->ends), - et->execution_count, - et->expression, sec_since_epoch_TIME(&et->execute_at), now, - (int)(sec_since_epoch_TIME(&et->execute_at) - now), - sec_since_epoch_TIME(&et->execute_at) <= now)); + DBUG_PRINT("info", ("et: 0x%lx name: %s.%s", (long) et, + et->dbname.str, et->name.str)); + DBUG_PRINT("info", ("exec_at: %lu starts: %lu ends: %lu execs_so_far: %u " + "expr: %ld et.exec_at: %ld now: %ld " + "(et.exec_at - now): %d if: %d", + (long) TIME_to_ulonglong_datetime(&et->execute_at), + (long) TIME_to_ulonglong_datetime(&et->starts), + (long) TIME_to_ulonglong_datetime(&et->ends), + et->execution_count, + (long) et->expression, + (long) (sec_since_epoch_TIME(&et->execute_at)), + (long) now, + (int) (sec_since_epoch_TIME(&et->execute_at) - now), + sec_since_epoch_TIME(&et->execute_at) <= now)); } DBUG_VOID_RETURN; #endif @@ -812,11 +816,11 @@ end: if (to_free) delete top; - DBUG_PRINT("info", ("returning %d. et_new=0x%lx abstime.tv_sec=%d ", - ret, *job_data, abstime? abstime->tv_sec:0)); + DBUG_PRINT("info", ("returning %d et_new: 0x%lx abstime.tv_sec: %ld ", + ret, (long) *job_data, abstime ? abstime->tv_sec : 0)); if (*job_data) - DBUG_PRINT("info", ("db=%s name=%s definer=%s", (*job_data)->dbname.str, + DBUG_PRINT("info", ("db: %s name: %s definer=%s", (*job_data)->dbname.str, (*job_data)->name.str, (*job_data)->definer.str)); DBUG_RETURN(ret); diff --git a/sql/event_scheduler.cc b/sql/event_scheduler.cc index 6f9f6887c12..9be2f2d1125 100644 --- a/sql/event_scheduler.cc +++ b/sql/event_scheduler.cc @@ -264,8 +264,9 @@ event_worker_thread(void *arg) if (!post_init_event_thread(thd)) { - DBUG_PRINT("info", ("Baikonur, time is %d, BURAN reporting and operational." - "THD=0x%lx", time(NULL), thd)); + DBUG_PRINT("info", ("Baikonur, time is %ld, BURAN reporting and operational." + "THD: 0x%lx", + (long) time(NULL), (long) thd)); sql_print_information("SCHEDULER: [%s.%s of %s] executing in thread %lu. " "Execution %u", @@ -378,7 +379,7 @@ Event_scheduler::start() DBUG_ENTER("Event_scheduler::start"); LOCK_DATA(); - DBUG_PRINT("info", ("state before action %s", scheduler_states_names[state])); + DBUG_PRINT("info", ("state before action %s", scheduler_states_names[state].str)); if (state > INITIALIZED) goto end; @@ -400,7 +401,7 @@ Event_scheduler::start() scheduler_thd= new_thd; DBUG_PRINT("info", ("Setting state go RUNNING")); state= RUNNING; - DBUG_PRINT("info", ("Forking new thread for scheduduler. THD=0x%lx", new_thd)); + DBUG_PRINT("info", ("Forking new thread for scheduduler. THD: 0x%lx", (long) new_thd)); if (pthread_create(&th, &connection_attrib, event_scheduler_thread, (void*)scheduler_param_value)) { @@ -463,7 +464,7 @@ Event_scheduler::run(THD *thd) break; } - DBUG_PRINT("info", ("get_top returned job_data=0x%lx", job_data)); + DBUG_PRINT("info", ("get_top returned job_data: 0x%lx", (long) job_data)); if (job_data) { if ((res= execute_top(thd, job_data))) @@ -522,11 +523,11 @@ Event_scheduler::execute_top(THD *thd, Event_job_data *job_data) ++started_events; - DBUG_PRINT("info", ("Launch succeeded. BURAN is in THD=0x%lx", new_thd)); + DBUG_PRINT("info", ("Launch succeeded. BURAN is in THD: 0x%lx", (long) new_thd)); DBUG_RETURN(FALSE); error: - DBUG_PRINT("error", ("Baikonur, we have a problem! res=%d", res)); + DBUG_PRINT("error", ("Baikonur, we have a problem! res: %d", res)); if (new_thd) { new_thd->proc_info= "Clearing"; @@ -581,10 +582,10 @@ Event_scheduler::stop() { THD *thd= current_thd; DBUG_ENTER("Event_scheduler::stop"); - DBUG_PRINT("enter", ("thd=0x%lx", current_thd)); + DBUG_PRINT("enter", ("thd: 0x%lx", (long) thd)); LOCK_DATA(); - DBUG_PRINT("info", ("state before action %s", scheduler_states_names[state])); + DBUG_PRINT("info", ("state before action %s", scheduler_states_names[state].str)); if (state != RUNNING) goto end; @@ -605,7 +606,7 @@ Event_scheduler::stop() */ state= STOPPING; - DBUG_PRINT("info", ("Manager thread has id %d", scheduler_thd->thread_id)); + DBUG_PRINT("info", ("Manager thread has id %lu", scheduler_thd->thread_id)); /* Lock from delete */ pthread_mutex_lock(&scheduler_thd->LOCK_delete); /* This will wake up the thread if it waits on Queue's conditional */ @@ -775,7 +776,7 @@ Event_scheduler::dump_internal_status() mutex_last_unlocked_at_line); printf("WOC : %s\n", waiting_on_cond? "YES":"NO"); printf("Workers : %u\n", workers_count()); - printf("Executed : %llu\n", started_events); + printf("Executed : %lu\n", (ulong) started_events); printf("Data locked: %s\n", mutex_scheduler_data_locked ? "YES":"NO"); DBUG_VOID_RETURN; diff --git a/sql/events.cc b/sql/events.cc index 10a8be948ef..3dbc6fd27e1 100644 --- a/sql/events.cc +++ b/sql/events.cc @@ -858,7 +858,7 @@ Events::check_system_tables(THD *thd) bool ret= FALSE; DBUG_ENTER("Events::check_system_tables"); - DBUG_PRINT("enter", ("thd=0x%lx", thd)); + DBUG_PRINT("enter", ("thd: 0x%lx", (long) thd)); thd->reset_n_backup_open_tables_state(&backup); diff --git a/sql/field.cc b/sql/field.cc index 122a44305f2..1551b78bd72 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1237,12 +1237,6 @@ Field::Field(char *ptr_arg,uint32 length_arg,uchar *null_ptr_arg, } -uint Field::offset() -{ - return (uint) (ptr - (char*) table->record[0]); -} - - void Field::hash(ulong *nr, ulong *nr2) { if (is_null()) @@ -1427,6 +1421,7 @@ Field_str::Field_str(char *ptr_arg,uint32 len_arg, uchar *null_ptr_arg, field_charset=charset; if (charset->state & MY_CS_BINSORT) flags|=BINARY_FLAG; + field_derivation= DERIVATION_IMPLICIT; } @@ -5921,38 +5916,149 @@ void Field_datetime::sql_type(String &res) const ** A string may be varchar or binary ****************************************************************************/ +/* + Report "not well formed" or "cannot convert" error + after storing a character string info a field. + + SYNOPSIS + check_string_copy_error() + field - Field + well_formed_error_pos - where not well formed data was first met + cannot_convert_error_pos - where a not-convertable character was first met + end - end of the string + + NOTES + As of version 5.0 both cases return the same error: + + "Invalid string value: 'xxx' for column 't' at row 1" + + Future versions will possibly introduce a new error message: + + "Cannot convert character string: 'xxx' for column 't' at row 1" + + RETURN + FALSE - If errors didn't happen + TRUE - If an error happened +*/ + +static bool +check_string_copy_error(Field_str *field, + const char *well_formed_error_pos, + const char *cannot_convert_error_pos, + const char *end) +{ + const char *pos, *end_orig; + char tmp[64], *t; + + if (!(pos= well_formed_error_pos) && + !(pos= cannot_convert_error_pos)) + return FALSE; + + end_orig= end; + set_if_smaller(end, pos + 6); + + for (t= tmp; pos < end; pos++) + { + if (((unsigned char) *pos) >= 0x20 && + ((unsigned char) *pos) <= 0x7F) + { + *t++= *pos; + } + else + { + *t++= '\\'; + *t++= 'x'; + *t++= _dig_vec_upper[((unsigned char) *pos) >> 4]; + *t++= _dig_vec_upper[((unsigned char) *pos) & 15]; + } + } + if (end_orig > end) + { + *t++= '.'; + *t++= '.'; + *t++= '.'; + } + *t= '\0'; + push_warning_printf(field->table->in_use, + field->table->in_use->abort_on_warning ? + MYSQL_ERROR::WARN_LEVEL_ERROR : + MYSQL_ERROR::WARN_LEVEL_WARN, + ER_TRUNCATED_WRONG_VALUE_FOR_FIELD, + ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD), + "string", tmp, field->field_name, + (ulong) field->table->in_use->row_count); + return TRUE; +} + + + +/* + Send a truncation warning or a truncation error + after storing a too long character string info a field. + + SYNOPSIS + report_data_too_long() + field - Field + + RETURN + N/A +*/ + +inline void +report_data_too_long(Field_str *field) +{ + if (field->table->in_use->abort_on_warning) + field->set_warning(MYSQL_ERROR::WARN_LEVEL_ERROR, ER_DATA_TOO_LONG, 1); + else + field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1); +} + + +/* + Test if the given string contains important data: + not spaces for character string, + or any data for binary string. + + SYNOPSIS + test_if_important_data() + cs Character set + str String to test + strend String end + + RETURN + FALSE - If string does not have important data + TRUE - If string has some important data +*/ + +static bool +test_if_important_data(CHARSET_INFO *cs, const char *str, const char *strend) +{ + if (cs != &my_charset_bin) + str+= cs->cset->scan(cs, str, strend, MY_SEQ_SPACES); + return (str < strend); +} + + /* Copy a string and fill with space */ int Field_string::store(const char *from,uint length,CHARSET_INFO *cs) { ASSERT_COLUMN_MARKED_FOR_WRITE; - int error= 0, well_formed_error; - uint32 not_used; - char buff[STRING_BUFFER_USUAL_SIZE]; - String tmpstr(buff,sizeof(buff), &my_charset_bin); uint copy_length; + const char *well_formed_error_pos; + const char *cannot_convert_error_pos; + const char *from_end_pos; /* See the comment for Field_long::store(long long) */ DBUG_ASSERT(table->in_use == current_thd); - /* Convert character set if necessary */ - if (String::needs_conversion(length, cs, field_charset, ¬_used)) - { - uint conv_errors; - tmpstr.copy(from, length, cs, field_charset, &conv_errors); - from= tmpstr.ptr(); - length= tmpstr.length(); - if (conv_errors) - error= 2; - } - - /* Make sure we don't break a multibyte sequence or copy malformed data. */ - copy_length= field_charset->cset->well_formed_len(field_charset, - from,from+length, - field_length/ - field_charset->mbmaxlen, - &well_formed_error); - memmove(ptr, from, copy_length); + copy_length= well_formed_copy_nchars(field_charset, + ptr, field_length, + cs, from, length, + field_length / field_charset->mbmaxlen, + &well_formed_error_pos, + &cannot_convert_error_pos, + &from_end_pos); /* Append spaces if the string was shorter than the field. */ if (copy_length < field_length) @@ -5960,32 +6066,23 @@ int Field_string::store(const char *from,uint length,CHARSET_INFO *cs) field_length-copy_length, field_charset->pad_char); + if (check_string_copy_error(this, well_formed_error_pos, + cannot_convert_error_pos, from + length)) + return 2; + /* Check if we lost any important data (anything in a binary string, or any non-space in others). */ - if ((copy_length < length) && table->in_use->count_cuted_fields) + if ((from_end_pos < from + length) && table->in_use->count_cuted_fields) { - if (binary()) - error= 2; - else + if (test_if_important_data(field_charset, from_end_pos, from + length)) { - const char *end=from+length; - from+= copy_length; - from+= field_charset->cset->scan(field_charset, from, end, - MY_SEQ_SPACES); - if (from != end) - error= 2; + report_data_too_long(this); + return 2; } } - if (error) - { - if (table->in_use->abort_on_warning) - set_warning(MYSQL_ERROR::WARN_LEVEL_ERROR, ER_DATA_TOO_LONG, 1); - else - set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1); - } - return error; + return 0; } @@ -6343,58 +6440,35 @@ Field *Field_string::new_field(MEM_ROOT *root, struct st_table *new_table, int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs) { ASSERT_COLUMN_MARKED_FOR_WRITE; - uint32 not_used, copy_length; - char buff[STRING_BUFFER_USUAL_SIZE]; - String tmpstr(buff,sizeof(buff), &my_charset_bin); - int error_code= 0, well_formed_error; - enum MYSQL_ERROR::enum_warning_level level= MYSQL_ERROR::WARN_LEVEL_WARN; + uint copy_length; + const char *well_formed_error_pos; + const char *cannot_convert_error_pos; + const char *from_end_pos; + + copy_length= well_formed_copy_nchars(field_charset, + ptr + length_bytes, field_length, + cs, from, length, + field_length / field_charset->mbmaxlen, + &well_formed_error_pos, + &cannot_convert_error_pos, + &from_end_pos); - /* Convert character set if necessary */ - if (String::needs_conversion(length, cs, field_charset, ¬_used)) - { - uint conv_errors; - tmpstr.copy(from, length, cs, field_charset, &conv_errors); - from= tmpstr.ptr(); - length= tmpstr.length(); - if (conv_errors) - error_code= WARN_DATA_TRUNCATED; - } - /* - Make sure we don't break a multibyte sequence - as well as don't copy a malformed data. - */ - copy_length= field_charset->cset->well_formed_len(field_charset, - from,from+length, - field_length/ - field_charset->mbmaxlen, - &well_formed_error); - memmove(ptr + length_bytes, from, copy_length); if (length_bytes == 1) *ptr= (uchar) copy_length; else int2store(ptr, copy_length); + if (check_string_copy_error(this, well_formed_error_pos, + cannot_convert_error_pos, from + length)) + return 2; + // Check if we lost something other than just trailing spaces - if ((copy_length < length) && table->in_use->count_cuted_fields && - !error_code) - { - if (!binary()) - { - const char *end= from + length; - from+= copy_length; - from+= field_charset->cset->scan(field_charset, from, end, MY_SEQ_SPACES); - /* If we lost only spaces then produce a NOTE, not a WARNING */ - if (from == end) - level= MYSQL_ERROR::WARN_LEVEL_NOTE; - } - error_code= WARN_DATA_TRUNCATED; - } - if (error_code) + if ((from_end_pos < from + length) && table->in_use->count_cuted_fields) { - if (level == MYSQL_ERROR::WARN_LEVEL_WARN && - table->in_use->abort_on_warning) - error_code= ER_DATA_TOO_LONG; - set_warning(level, error_code, 1); + if (test_if_important_data(field_charset, from_end_pos, from + length)) + report_data_too_long(this); + else /* If we lost only spaces then produce a NOTE, not a WARNING */ + set_warning(MYSQL_ERROR::WARN_LEVEL_NOTE, WARN_DATA_TRUNCATED, 1); return 2; } return 0; @@ -7012,68 +7086,70 @@ void Field_blob::put_length(char *pos, uint32 length) int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs) { ASSERT_COLUMN_MARKED_FOR_WRITE; - int error= 0, well_formed_error; + uint copy_length, new_length; + const char *well_formed_error_pos; + const char *cannot_convert_error_pos; + const char *from_end_pos, *tmp; + char buff[STRING_BUFFER_USUAL_SIZE]; + String tmpstr(buff,sizeof(buff), &my_charset_bin); + if (!length) { bzero(ptr,Field_blob::pack_length()); + return 0; } - else - { - bool was_conversion; - char buff[STRING_BUFFER_USUAL_SIZE]; - String tmpstr(buff,sizeof(buff), &my_charset_bin); - uint copy_length; - uint32 not_used; - /* Convert character set if necessary */ - if ((was_conversion= String::needs_conversion(length, cs, field_charset, - ¬_used))) - { - uint conv_errors; - if (tmpstr.copy(from, length, cs, field_charset, &conv_errors)) - { - /* Fatal OOM error */ - bzero(ptr,Field_blob::pack_length()); - return -1; - } - from= tmpstr.ptr(); - length= tmpstr.length(); - if (conv_errors) - error= 2; - } - - copy_length= max_data_length(); - /* - copy_length is OK as last argument to well_formed_len as this is never - used to limit the length of the data. The cut of long data is done with - the 'min()' call below. - */ - copy_length= field_charset->cset->well_formed_len(field_charset, - from,from + - min(length, copy_length), - copy_length, - &well_formed_error); - if (copy_length < length) - error= 2; - Field_blob::store_length(copy_length); - if (was_conversion || table->copy_blobs || copy_length <= MAX_FIELD_WIDTH) - { // Must make a copy - if (from != value.ptr()) // For valgrind - { - value.copy(from,copy_length,charset()); - from=value.ptr(); - } + if (from == value.ptr()) + { + uint32 dummy_offset; + if (!String::needs_conversion(length, cs, field_charset, &dummy_offset)) + { + Field_blob::store_length(length); + bmove(ptr+packlength,(char*) &from,sizeof(char*)); + return 0; } - bmove(ptr+packlength,(char*) &from,sizeof(char*)); + if (tmpstr.copy(from, length, cs)) + goto oom_error; + from= tmpstr.ptr(); } - if (error) + + new_length= min(max_data_length(), field_charset->mbmaxlen * length); + if (value.alloc(new_length)) + goto oom_error; + + /* + "length" is OK as "nchars" argument to well_formed_copy_nchars as this + is never used to limit the length of the data. The cut of long data + is done with the new_length value. + */ + copy_length= well_formed_copy_nchars(field_charset, + (char*) value.ptr(), new_length, + cs, from, length, + length, + &well_formed_error_pos, + &cannot_convert_error_pos, + &from_end_pos); + + Field_blob::store_length(copy_length); + tmp= value.ptr(); + bmove(ptr+packlength,(char*) &tmp,sizeof(char*)); + + if (check_string_copy_error(this, well_formed_error_pos, + cannot_convert_error_pos, from + length)) + return 2; + + if (copy_length < length) { - if (table->in_use->abort_on_warning) - set_warning(MYSQL_ERROR::WARN_LEVEL_ERROR, ER_DATA_TOO_LONG, 1); - else - set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1); + report_data_too_long(this); + return 2; } + return 0; + +oom_error: + /* Fatal OOM error */ + bzero(ptr,Field_blob::pack_length()); + return -1; } @@ -8104,8 +8180,8 @@ Field_bit::do_last_null_byte() const bits. On systems with CHAR_BIT > 8 (not very common), the storage will lose the extra bits. */ - DBUG_PRINT("debug", ("bit_ofs=%d, bit_len=%d, bit_ptr=%p", - bit_ofs, bit_len, bit_ptr)); + DBUG_PRINT("test", ("bit_ofs: %d, bit_len: %d bit_ptr: 0x%lx", + bit_ofs, bit_len, (long) bit_ptr)); uchar *result; if (bit_len == 0) result= null_ptr; diff --git a/sql/field.h b/sql/field.h index 9b81931d416..433f5c6bfbf 100644 --- a/sql/field.h +++ b/sql/field.h @@ -239,7 +239,7 @@ public: */ my_size_t last_null_byte() const { my_size_t bytes= do_last_null_byte(); - DBUG_PRINT("debug", ("last_null_byte() ==> %d", bytes)); + DBUG_PRINT("debug", ("last_null_byte() ==> %ld", (long) bytes)); DBUG_ASSERT(bytes <= table->s->null_bytes); return bytes; } @@ -342,7 +342,10 @@ public: virtual int pack_cmp(const char *b, uint key_length_arg, my_bool insert_or_update) { return cmp(ptr,b); } - uint offset(); // Should be inline ... + uint offset(byte *record) + { + return (uint) (ptr - (char*) record); + } void copy_from_tmp(int offset); uint fill_cache_field(struct st_cache_field *copy); virtual bool get_date(TIME *ltime,uint fuzzydate); @@ -351,6 +354,9 @@ public: virtual CHARSET_INFO *sort_charset(void) const { return charset(); } virtual bool has_charset(void) const { return FALSE; } virtual void set_charset(CHARSET_INFO *charset) { } + virtual enum Derivation derivation(void) const + { return DERIVATION_IMPLICIT; } + virtual void set_derivation(enum Derivation derivation) { } bool set_warning(MYSQL_ERROR::enum_warning_level, unsigned int code, int cuted_increment); bool check_int(const char *str, int length, const char *int_end, @@ -446,6 +452,7 @@ public: class Field_str :public Field { protected: CHARSET_INFO *field_charset; + enum Derivation field_derivation; public: Field_str(char *ptr_arg,uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, utype unireg_check_arg, @@ -459,6 +466,9 @@ public: uint size_of() const { return sizeof(*this); } CHARSET_INFO *charset(void) const { return field_charset; } void set_charset(CHARSET_INFO *charset) { field_charset=charset; } + enum Derivation derivation(void) const { return field_derivation; } + virtual void set_derivation(enum Derivation derivation_arg) + { field_derivation= derivation_arg; } bool binary() const { return field_charset == &my_charset_bin; } uint32 max_length() { return field_length; } friend class create_field; diff --git a/sql/field_conv.cc b/sql/field_conv.cc index 7bc6c432d1c..01b5306f5a4 100644 --- a/sql/field_conv.cc +++ b/sql/field_conv.cc @@ -119,12 +119,12 @@ set_field_to_null(Field *field) return 0; } field->reset(); - if (current_thd->count_cuted_fields == CHECK_FIELD_WARN) + if (field->table->in_use->count_cuted_fields == CHECK_FIELD_WARN) { field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1); return 0; } - if (!current_thd->no_errors) + if (!field->table->in_use->no_errors) my_error(ER_BAD_NULL_ERROR, MYF(0), field->field_name); return -1; } @@ -176,12 +176,12 @@ set_field_to_null_with_conversions(Field *field, bool no_conversions) field->table->auto_increment_field_not_null= FALSE; return 0; // field is set in handler.cc } - if (current_thd->count_cuted_fields == CHECK_FIELD_WARN) + if (field->table->in_use->count_cuted_fields == CHECK_FIELD_WARN) { field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_BAD_NULL_ERROR, 1); return 0; } - if (!current_thd->no_errors) + if (!field->table->in_use->no_errors) my_error(ER_BAD_NULL_ERROR, MYF(0), field->field_name); return -1; } @@ -403,7 +403,7 @@ static void do_varstring1(Copy_field *copy) if (length > copy->to_length- 1) { length=copy->to_length - 1; - if (current_thd->count_cuted_fields) + if (copy->from_field->table->in_use->count_cuted_fields) copy->to_field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1); } @@ -418,7 +418,7 @@ static void do_varstring2(Copy_field *copy) if (length > copy->to_length- HA_KEY_BLOB_LENGTH) { length=copy->to_length-HA_KEY_BLOB_LENGTH; - if (current_thd->count_cuted_fields) + if (copy->from_field->table->in_use->count_cuted_fields) copy->to_field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1); } diff --git a/sql/filesort.cc b/sql/filesort.cc index 01f3bb97557..2cba2b733da 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -302,7 +302,7 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length, DBUG_POP(); /* Ok to DBUG */ #endif memcpy(&table->sort, &table_sort, sizeof(FILESORT_INFO)); - DBUG_PRINT("exit",("records: %ld",records)); + DBUG_PRINT("exit",("records: %ld", (long) records)); DBUG_RETURN(error ? HA_POS_ERROR : records); } /* filesort */ diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 9df2171d85c..0703e18b5f7 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -413,7 +413,8 @@ Thd_ndb::get_open_table(THD *thd, const void *key) thd_ndb_share->stat.no_uncommitted_rows_count= 0; thd_ndb_share->stat.records= ~(ha_rows)0; } - DBUG_PRINT("exit", ("thd_ndb_share: 0x%x key: 0x%x", thd_ndb_share, key)); + DBUG_PRINT("exit", ("thd_ndb_share: 0x%lx key: 0x%lx", + (long) thd_ndb_share, (long) key)); DBUG_RETURN(thd_ndb_share); } @@ -761,8 +762,8 @@ int ha_ndbcluster::set_ndb_value(NdbOperation *ndb_op, Field *field, blob_ptr= (char*)""; } - DBUG_PRINT("value", ("set blob ptr=%p len=%u", - blob_ptr, blob_len)); + DBUG_PRINT("value", ("set blob ptr: 0x%lx len: %u", + (long) blob_ptr, blob_len)); DBUG_DUMP("value", (char*)blob_ptr, min(blob_len, 26)); if (set_blob_value) @@ -847,8 +848,8 @@ int get_ndb_blobs_value(TABLE* table, NdbValue* value_array, uint32 len= 0xffffffff; // Max uint32 if (ndb_blob->readData(buf, len) != 0) ERR_RETURN(ndb_blob->getNdbError()); - DBUG_PRINT("info", ("[%u] offset=%u buf=%p len=%u [ptrdiff=%d]", - i, offset, buf, len, (int)ptrdiff)); + DBUG_PRINT("info", ("[%u] offset: %u buf: 0x%lx len=%u [ptrdiff=%d]", + i, offset, (long) buf, len, (int)ptrdiff)); DBUG_ASSERT(len == len64); // Ugly hack assumes only ptr needs to be changed field_blob->ptr+= ptrdiff; @@ -1171,8 +1172,8 @@ int ha_ndbcluster::add_index_handle(THD *thd, NDBDICT *dict, KEY *key_info, index= dict->getIndexGlobal(index_name, *m_table); if (!index) ERR_RETURN(dict->getNdbError()); - DBUG_PRINT("info", ("index: 0x%x id: %d version: %d.%d status: %d", - index, + DBUG_PRINT("info", ("index: 0x%lx id: %d version: %d.%d status: %d", + (long) index, index->getObjectId(), index->getObjectVersion() & 0xFFFFFF, index->getObjectVersion() >> 24, @@ -1215,8 +1216,8 @@ int ha_ndbcluster::add_index_handle(THD *thd, NDBDICT *dict, KEY *key_info, index= dict->getIndexGlobal(unique_index_name, *m_table); if (!index) ERR_RETURN(dict->getNdbError()); - DBUG_PRINT("info", ("index: 0x%x id: %d version: %d.%d status: %d", - index, + DBUG_PRINT("info", ("index: 0x%lx id: %d version: %d.%d status: %d", + (long) index, index->getObjectId(), index->getObjectVersion() & 0xFFFFFF, index->getObjectVersion() >> 24, @@ -2072,7 +2073,7 @@ inline int ha_ndbcluster::fetch_next(NdbScanOperation* cursor) all pending update or delete operations should be sent to NDB */ - DBUG_PRINT("info", ("ops_pending: %d", m_ops_pending)); + DBUG_PRINT("info", ("ops_pending: %ld", (long) m_ops_pending)); if (m_ops_pending) { if (m_transaction_on) @@ -2305,7 +2306,7 @@ int ha_ndbcluster::set_bounds(NdbIndexScanOperation *op, // Set bound if not done with this key if (p.key != NULL) { - DBUG_PRINT("info", ("key %d:%d offset=%d length=%d last=%d bound=%d", + DBUG_PRINT("info", ("key %d:%d offset: %d length: %d last: %d bound: %d", j, i, tot_len, part_len, p.part_last, p.bound_type)); DBUG_DUMP("info", (const char*)p.part_ptr, part_store_len); @@ -2462,7 +2463,7 @@ int ha_ndbcluster::full_table_scan(byte *buf) part_spec.start_part= 0; part_spec.end_part= m_part_info->get_tot_partitions() - 1; prune_partition_set(table, &part_spec); - DBUG_PRINT("info", ("part_spec.start_part = %u, part_spec.end_part = %u", + DBUG_PRINT("info", ("part_spec.start_part: %u part_spec.end_part: %u", part_spec.start_part, part_spec.end_part)); /* If partition pruning has found no partition in set @@ -2658,7 +2659,7 @@ int ha_ndbcluster::write_row(byte *record) { // Send rows to NDB DBUG_PRINT("info", ("Sending inserts to NDB, "\ - "rows_inserted:%d, bulk_insert_rows: %d", + "rows_inserted: %d bulk_insert_rows: %d", (int)m_rows_inserted, (int)m_bulk_insert_rows)); m_bulk_insert_not_flushed= FALSE; @@ -3108,7 +3109,8 @@ void ndb_unpack_record(TABLE *table, NdbValue *value, char* ptr; field_blob->get_ptr(&ptr, row_offset); uint32 len= field_blob->get_length(row_offset); - DBUG_PRINT("info",("[%u] SET ptr=%p len=%u", col_no, ptr, len)); + DBUG_PRINT("info",("[%u] SET ptr: 0x%lx len: %u", + col_no, (long) ptr, len)); #endif } } @@ -3350,7 +3352,7 @@ int ha_ndbcluster::read_range_first_to_buf(const key_range *start_key, if (m_use_partition_function) { get_partition_set(table, buf, active_index, start_key, &part_spec); - DBUG_PRINT("info", ("part_spec.start_part = %u, part_spec.end_part = %u", + DBUG_PRINT("info", ("part_spec.start_part: %u part_spec.end_part: %u", part_spec.start_part, part_spec.end_part)); /* If partition pruning has found no partition in set @@ -3480,7 +3482,7 @@ int ha_ndbcluster::close_scan() Take over any pending transactions to the deleteing/updating transaction before closing the scan */ - DBUG_PRINT("info", ("ops_pending: %d", m_ops_pending)); + DBUG_PRINT("info", ("ops_pending: %ld", (long) m_ops_pending)); if (execute_no_commit(this,trans,false) != 0) { no_uncommitted_rows_execute_failure(); DBUG_RETURN(ndb_err(trans)); @@ -3876,7 +3878,7 @@ int ha_ndbcluster::end_bulk_insert() NdbTransaction *trans= m_active_trans; // Send rows to NDB DBUG_PRINT("info", ("Sending inserts to NDB, "\ - "rows_inserted:%d, bulk_insert_rows: %d", + "rows_inserted: %d bulk_insert_rows: %d", (int) m_rows_inserted, (int) m_bulk_insert_rows)); m_bulk_insert_not_flushed= FALSE; if (m_transaction_on) @@ -4286,8 +4288,8 @@ static int ndbcluster_commit(handlerton *hton, THD *thd, bool all) while ((share= it++)) { pthread_mutex_lock(&share->mutex); - DBUG_PRINT("info", ("Invalidate commit_count for %s, share->commit_count: %d ", - share->key, share->commit_count)); + DBUG_PRINT("info", ("Invalidate commit_count for %s, share->commit_count: %lu", + share->table_name, (ulong) share->commit_count)); share->commit_count= 0; share->commit_count_lock++; pthread_mutex_unlock(&share->mutex); @@ -4690,8 +4692,7 @@ int ha_ndbcluster::create(const char *name, my_free((char*)data, MYF(0)); DBUG_RETURN(2); } - - DBUG_PRINT("info", ("setFrm data=%lx len=%d", pack_data, pack_length)); + DBUG_PRINT("info", ("setFrm data: 0x%lx len: %d", (long) pack_data, pack_length)); tab.setFrm(pack_data, pack_length); my_free((char*)data, MYF(0)); my_free((char*)pack_data, MYF(0)); @@ -5102,13 +5103,12 @@ void ha_ndbcluster::prepare_for_alter() int ha_ndbcluster::add_index(TABLE *table_arg, KEY *key_info, uint num_of_keys) { - DBUG_ENTER("ha_ndbcluster::add_index"); - DBUG_PRINT("info", ("ha_ndbcluster::add_index to table %s", - table_arg->s->table_name)); int error= 0; uint idx; - + DBUG_ENTER("ha_ndbcluster::add_index"); + DBUG_PRINT("enter", ("table %s", table_arg->s->table_name.str)); DBUG_ASSERT(m_share->state == NSS_ALTERED); + for (idx= 0; idx < num_of_keys; idx++) { KEY *key= key_info + idx; @@ -6663,7 +6663,7 @@ static int ndbcluster_end(handlerton *hton, ha_panic_function type) void ha_ndbcluster::print_error(int error, myf errflag) { DBUG_ENTER("ha_ndbcluster::print_error"); - DBUG_PRINT("enter", ("error = %d", error)); + DBUG_PRINT("enter", ("error: %d", error)); if (error == HA_ERR_NO_PARTITION_FOUND) m_part_info->print_no_partition_found(table); @@ -7169,16 +7169,16 @@ static void dbug_print_open_tables() for (uint i= 0; i < ndbcluster_open_tables.records; i++) { NDB_SHARE *share= (NDB_SHARE*) hash_element(&ndbcluster_open_tables, i); - DBUG_PRINT("share", - ("[%d] 0x%lx key: %s key_length: %d", - i, share, share->key, share->key_length)); - DBUG_PRINT("share", - ("db.tablename: %s.%s use_count: %d commit_count: %d", + DBUG_PRINT("loop", + ("[%d] 0x%lx key: %s key_length: %d", + i, (long) share, share->key, share->key_length)); + DBUG_PRINT("loop", + ("db.tablename: %s.%s use_count: %d commit_count: %lu", share->db, share->table_name, - share->use_count, share->commit_count)); + share->use_count, (ulong) share->commit_count)); #ifdef HAVE_NDB_BINLOG if (share->table) - DBUG_PRINT("share", + DBUG_PRINT("loop", ("table->s->db.table_name: %s.%s", share->table->s->db.str, share->table->s->table_name.str)); #endif @@ -7331,13 +7331,13 @@ static int rename_share(NDB_SHARE *share, const char *new_key) share->table_name= share->db + strlen(share->db) + 1; ha_ndbcluster::set_tabname(new_key, share->table_name); - DBUG_PRINT("rename_share", - ("0x%lx key: %s key_length: %d", - share, share->key, share->key_length)); - DBUG_PRINT("rename_share", - ("db.tablename: %s.%s use_count: %d commit_count: %d", + DBUG_PRINT("info", + ("share: 0x%lx key: %s key_length: %d", + (long) share, share->key, share->key_length)); + DBUG_PRINT("info", + ("db.tablename: %s.%s use_count: %d commit_count: %lu", share->db, share->table_name, - share->use_count, share->commit_count)); + share->use_count, (ulong) share->commit_count)); if (share->table) { DBUG_PRINT("rename_share", @@ -7372,13 +7372,13 @@ NDB_SHARE *ndbcluster_get_share(NDB_SHARE *share) dbug_print_open_tables(); - DBUG_PRINT("get_share", - ("0x%lx key: %s key_length: %d", - share, share->key, share->key_length)); - DBUG_PRINT("get_share", - ("db.tablename: %s.%s use_count: %d commit_count: %d", + DBUG_PRINT("info", + ("share: 0x%lx key: %s key_length: %d", + (long) share, share->key, share->key_length)); + DBUG_PRINT("info", + ("db.tablename: %s.%s use_count: %d commit_count: %lu", share->db, share->table_name, - share->use_count, share->commit_count)); + share->use_count, (ulong) share->commit_count)); pthread_mutex_unlock(&ndbcluster_mutex); return share; } @@ -7472,11 +7472,11 @@ NDB_SHARE *ndbcluster_get_share(const char *key, TABLE *table, DBUG_PRINT("info", ("0x%lx key: %s key_length: %d key: %s", - share, share->key, share->key_length, key)); + (long) share, share->key, share->key_length, key)); DBUG_PRINT("info", - ("db.tablename: %s.%s use_count: %d commit_count: %d", + ("db.tablename: %s.%s use_count: %d commit_count: %lu", share->db, share->table_name, - share->use_count, share->commit_count)); + share->use_count, (ulong) share->commit_count)); if (!have_lock) pthread_mutex_unlock(&ndbcluster_mutex); DBUG_RETURN(share); @@ -7486,13 +7486,12 @@ NDB_SHARE *ndbcluster_get_share(const char *key, TABLE *table, void ndbcluster_real_free_share(NDB_SHARE **share) { DBUG_ENTER("ndbcluster_real_free_share"); - DBUG_PRINT("real_free_share", - ("0x%lx key: %s key_length: %d", - (*share), (*share)->key, (*share)->key_length)); - DBUG_PRINT("real_free_share", - ("db.tablename: %s.%s use_count: %d commit_count: %d", + DBUG_PRINT("enter", + ("share: 0x%lx key: %s key_length: %d " + "db.tablename: %s.%s use_count: %d commit_count: %lu", + (long) (*share), (*share)->key, (*share)->key_length, (*share)->db, (*share)->table_name, - (*share)->use_count, (*share)->commit_count)); + (*share)->use_count, (ulong) (*share)->commit_count)); hash_delete(&ndbcluster_open_tables, (byte*) *share); thr_lock_delete(&(*share)->lock); @@ -7540,13 +7539,13 @@ void ndbcluster_free_share(NDB_SHARE **share, bool have_lock) else { dbug_print_open_tables(); - DBUG_PRINT("free_share", - ("0x%lx key: %s key_length: %d", - *share, (*share)->key, (*share)->key_length)); - DBUG_PRINT("free_share", - ("db.tablename: %s.%s use_count: %d commit_count: %d", + DBUG_PRINT("info", + ("share: 0x%lx key: %s key_length: %d", + (long) *share, (*share)->key, (*share)->key_length)); + DBUG_PRINT("info", + ("db.tablename: %s.%s use_count: %d commit_count: %lu", (*share)->db, (*share)->table_name, - (*share)->use_count, (*share)->commit_count)); + (*share)->use_count, (ulong) (*share)->commit_count)); } if (!have_lock) pthread_mutex_unlock(&ndbcluster_mutex); @@ -7816,7 +7815,7 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p, get_partition_set(table, curr, active_index, &multi_range_curr->start_key, &part_spec); - DBUG_PRINT("info", ("part_spec.start_part = %u, part_spec.end_part = %u", + DBUG_PRINT("info", ("part_spec.start_part: %u part_spec.end_part: %u", part_spec.start_part, part_spec.end_part)); /* If partition pruning has found no partition in set @@ -8182,7 +8181,7 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused))) my_thread_init(); DBUG_ENTER("ndb_util_thread"); - DBUG_PRINT("enter", ("ndb_cache_check_time: %d", ndb_cache_check_time)); + DBUG_PRINT("enter", ("ndb_cache_check_time: %lu", ndb_cache_check_time)); thd= new THD; /* note that contructor of THD uses DBUG_ */ THD_CHECK_SENTRY(thd); @@ -8270,7 +8269,7 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused))) &abstime); pthread_mutex_unlock(&LOCK_ndb_util_thread); #ifdef NDB_EXTRA_DEBUG_UTIL_THREAD - DBUG_PRINT("ndb_util_thread", ("Started, ndb_cache_check_time: %d", + DBUG_PRINT("ndb_util_thread", ("Started, ndb_cache_check_time: %lu", ndb_cache_check_time)); #endif if (abort_loop) @@ -8348,8 +8347,8 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused))) ndb_get_table_statistics(NULL, false, ndb, ndbtab_g.get_table(), &stat) == 0) { char buff[22], buff2[22]; - DBUG_PRINT("ndb_util_thread", - ("Table: %s, commit_count: %llu, rows: %llu", + DBUG_PRINT("info", + ("Table: %s commit_count: %s rows: %s", share->key, llstr(stat.commit_count, buff), llstr(stat.row_count, buff2))); @@ -9191,7 +9190,7 @@ void ndb_serialize_cond(const Item *item, void *arg) if (context->expecting(Item::INT_ITEM)) { Item_int *int_item= (Item_int *) item; - DBUG_PRINT("info", ("value %d", int_item->value)); + DBUG_PRINT("info", ("value %ld", (long) int_item->value)); NDB_ITEM_QUALIFICATION q; q.value_type= Item::INT_ITEM; curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item); @@ -9214,7 +9213,7 @@ void ndb_serialize_cond(const Item *item, void *arg) context->supported= FALSE; break; case Item::REAL_ITEM: - DBUG_PRINT("info", ("REAL_ITEM %s")); + DBUG_PRINT("info", ("REAL_ITEM")); if (context->expecting(Item::REAL_ITEM)) { Item_float *float_item= (Item_float *) item; @@ -9262,7 +9261,7 @@ void ndb_serialize_cond(const Item *item, void *arg) context->supported= FALSE; break; case Item::DECIMAL_ITEM: - DBUG_PRINT("info", ("DECIMAL_ITEM %s")); + DBUG_PRINT("info", ("DECIMAL_ITEM")); if (context->expecting(Item::DECIMAL_ITEM)) { Item_decimal *decimal_item= (Item_decimal *) item; diff --git a/sql/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc index 3dfca5d1bb2..865fa0bde94 100644 --- a/sql/ha_ndbcluster_binlog.cc +++ b/sql/ha_ndbcluster_binlog.cc @@ -161,16 +161,16 @@ static void dbug_print_table(const char *info, TABLE *table) } DBUG_PRINT("info", ("%s: %s.%s s->fields: %d " - "reclength: %d rec_buff_length: %d record[0]: %lx " - "record[1]: %lx", + "reclength: %lu rec_buff_length: %u record[0]: 0x%lx " + "record[1]: 0x%lx", info, table->s->db.str, table->s->table_name.str, table->s->fields, table->s->reclength, table->s->rec_buff_length, - table->record[0], - table->record[1])); + (long) table->record[0], + (long) table->record[1])); for (unsigned int i= 0; i < table->s->fields; i++) { @@ -180,7 +180,7 @@ static void dbug_print_table(const char *info, TABLE *table) "ptr: 0x%lx[+%d] null_bit: %u null_ptr: 0x%lx[+%d]", i, f->field_name, - f->flags, + (long) f->flags, (f->flags & PRI_KEY_FLAG) ? "pri" : "attr", (f->flags & NOT_NULL_FLAG) ? "" : ",nullable", (f->flags & UNSIGNED_FLAG) ? ",unsigned" : ",signed", @@ -189,16 +189,18 @@ static void dbug_print_table(const char *info, TABLE *table) (f->flags & BINARY_FLAG) ? ",binary" : "", f->real_type(), f->pack_length(), - f->ptr, f->ptr - table->record[0], + (long) f->ptr, (int) (f->ptr - table->record[0]), f->null_bit, - f->null_ptr, (byte*) f->null_ptr - table->record[0])); + (long) f->null_ptr, + (int) ((byte*) f->null_ptr - table->record[0]))); if (f->type() == MYSQL_TYPE_BIT) { Field_bit *g= (Field_bit*) f; DBUG_PRINT("MYSQL_TYPE_BIT",("field_length: %d bit_ptr: 0x%lx[+%d] " - "bit_ofs: %u bit_len: %u", - g->field_length, g->bit_ptr, - (byte*) g->bit_ptr-table->record[0], + "bit_ofs: %d bit_len: %u", + g->field_length, (long) g->bit_ptr, + (int) ((byte*) g->bit_ptr - + table->record[0]), g->bit_ofs, g->bit_len)); } } @@ -605,11 +607,11 @@ static int ndbcluster_binlog_end(THD *thd) { DBUG_PRINT("share", ("[%d] 0x%lx key: %s key_length: %d", - i, share, share->key, share->key_length)); + i, (long) share, share->key, share->key_length)); DBUG_PRINT("share", - ("db.tablename: %s.%s use_count: %d commit_count: %d", + ("db.tablename: %s.%s use_count: %d commit_count: %lu", share->db, share->table_name, - share->use_count, share->commit_count)); + share->use_count, (long) share->commit_count)); } } pthread_mutex_unlock(&ndbcluster_mutex); @@ -685,8 +687,8 @@ static NDB_SHARE *ndbcluster_check_apply_status_share() void *share= hash_search(&ndbcluster_open_tables, NDB_APPLY_TABLE_FILE, sizeof(NDB_APPLY_TABLE_FILE) - 1); - DBUG_PRINT("info",("ndbcluster_check_apply_status_share %s %p", - NDB_APPLY_TABLE_FILE, share)); + DBUG_PRINT("info",("ndbcluster_check_apply_status_share %s 0x%lx", + NDB_APPLY_TABLE_FILE, (long) share)); pthread_mutex_unlock(&ndbcluster_mutex); return (NDB_SHARE*) share; } @@ -703,8 +705,8 @@ static NDB_SHARE *ndbcluster_check_schema_share() void *share= hash_search(&ndbcluster_open_tables, NDB_SCHEMA_TABLE_FILE, sizeof(NDB_SCHEMA_TABLE_FILE) - 1); - DBUG_PRINT("info",("ndbcluster_check_schema_share %s %p", - NDB_SCHEMA_TABLE_FILE, share)); + DBUG_PRINT("info",("ndbcluster_check_schema_share %s 0x%lx", + NDB_SCHEMA_TABLE_FILE, (long) share)); pthread_mutex_unlock(&ndbcluster_mutex); return (NDB_SHARE*) share; } @@ -2721,10 +2723,9 @@ ndbcluster_create_event_ops(NDB_SHARE *share, const NDBTAB *ndbtab, if (share->flags & NSF_BLOB_FLAG) op->mergeEvents(TRUE); // currently not inherited from event - DBUG_PRINT("info", ("share->ndb_value[0]: 0x%x", - share->ndb_value[0])); - DBUG_PRINT("info", ("share->ndb_value[1]: 0x%x", - share->ndb_value[1])); + DBUG_PRINT("info", ("share->ndb_value[0]: 0x%lx share->ndb_value[1]: 0x%lx", + (long) share->ndb_value[0], + (long) share->ndb_value[1])); int n_columns= ndbtab->getNoOfColumns(); int n_fields= table ? table->s->fields : 0; // XXX ??? for (int j= 0; j < n_columns; j++) @@ -2778,12 +2779,14 @@ ndbcluster_create_event_ops(NDB_SHARE *share, const NDBTAB *ndbtab, } share->ndb_value[0][j].ptr= attr0.ptr; share->ndb_value[1][j].ptr= attr1.ptr; - DBUG_PRINT("info", ("&share->ndb_value[0][%d]: 0x%x " - "share->ndb_value[0][%d]: 0x%x", - j, &share->ndb_value[0][j], j, attr0.ptr)); - DBUG_PRINT("info", ("&share->ndb_value[1][%d]: 0x%x " - "share->ndb_value[1][%d]: 0x%x", - j, &share->ndb_value[0][j], j, attr1.ptr)); + DBUG_PRINT("info", ("&share->ndb_value[0][%d]: 0x%lx " + "share->ndb_value[0][%d]: 0x%lx", + j, (long) &share->ndb_value[0][j], + j, (long) attr0.ptr)); + DBUG_PRINT("info", ("&share->ndb_value[1][%d]: 0x%lx " + "share->ndb_value[1][%d]: 0x%lx", + j, (long) &share->ndb_value[0][j], + j, (long) attr1.ptr)); } op->setCustomData((void *) share); // set before execute share->op= op; // assign op in NDB_SHARE @@ -2826,8 +2829,8 @@ ndbcluster_create_event_ops(NDB_SHARE *share, const NDBTAB *ndbtab, (void) pthread_cond_signal(&injector_cond); } - DBUG_PRINT("info",("%s share->op: 0x%lx, share->use_count: %u", - share->key, share->op, share->use_count)); + DBUG_PRINT("info",("%s share->op: 0x%lx share->use_count: %u", + share->key, (long) share->op, share->use_count)); if (ndb_extra_logging) sql_print_information("NDB Binlog: logging %s", share->key); @@ -3012,10 +3015,11 @@ ndb_binlog_thread_handle_non_data_event(THD *thd, Ndb *ndb, free_share(&apply_status_share); apply_status_share= 0; } - DBUG_PRINT("info", ("CLUSTER FAILURE EVENT: " - "%s received share: 0x%lx op: %lx share op: %lx " - "op_old: %lx", - share->key, share, pOp, share->op, share->op_old)); + DBUG_PRINT("error", ("CLUSTER FAILURE EVENT: " + "%s received share: 0x%lx op: 0x%lx share op: 0x%lx " + "op_old: 0x%lx", + share->key, (long) share, (long) pOp, + (long) share->op, (long) share->op_old)); break; case NDBEVENT::TE_DROP: if (apply_status_share == share) @@ -3033,10 +3037,11 @@ ndb_binlog_thread_handle_non_data_event(THD *thd, Ndb *ndb, // fall through case NDBEVENT::TE_ALTER: row.n_schemaops++; - DBUG_PRINT("info", ("TABLE %s EVENT: %s received share: 0x%lx op: %lx " - "share op: %lx op_old: %lx", - type == NDBEVENT::TE_DROP ? "DROP" : "ALTER", - share->key, share, pOp, share->op, share->op_old)); + DBUG_PRINT("info", ("TABLE %s EVENT: %s received share: 0x%lx op: 0x%lx " + "share op: 0x%lx op_old: 0x%lx", + type == NDBEVENT::TE_DROP ? "DROP" : "ALTER", + share->key, (long) share, (long) pOp, + (long) share->op, (long) share->op_old)); break; case NDBEVENT::TE_NODE_FAILURE: /* fall through */ @@ -3436,7 +3441,6 @@ pthread_handler_t ndb_binlog_thread_func(void *arg) global_system_variables.binlog_format == BINLOG_FORMAT_MIXED) { ndb_binlog_running= TRUE; - thd->current_stmt_binlog_row_based= TRUE; // If in mixed mode } else { @@ -3514,7 +3518,8 @@ restart: } } // now check that we have epochs consistant with what we had before the restart - DBUG_PRINT("info", ("schema_res: %d schema_gci: %d", schema_res, schema_gci)); + DBUG_PRINT("info", ("schema_res: %d schema_gci: %lu", schema_res, + (long) schema_gci)); { i_ndb->flushIncompleteEvents(schema_gci); s_ndb->flushIncompleteEvents(schema_gci); @@ -3558,9 +3563,11 @@ restart: if (do_ndbcluster_binlog_close_connection) { DBUG_PRINT("info", ("do_ndbcluster_binlog_close_connection: %d, " - "ndb_latest_handled_binlog_epoch: %llu, " - "*p_latest_trans_gci: %llu", do_ndbcluster_binlog_close_connection, - ndb_latest_handled_binlog_epoch, *p_latest_trans_gci)); + "ndb_latest_handled_binlog_epoch: %lu, " + "*p_latest_trans_gci: %lu", + do_ndbcluster_binlog_close_connection, + (ulong) ndb_latest_handled_binlog_epoch, + (ulong) *p_latest_trans_gci)); } #endif #ifdef RUN_NDB_BINLOG_TIMER @@ -3648,9 +3655,10 @@ restart: do_ndbcluster_binlog_close_connection= BCCC_restart; if (ndb_latest_received_binlog_epoch < *p_latest_trans_gci && ndb_binlog_running) { - sql_print_error("NDB Binlog: latest transaction in epoch %lld not in binlog " - "as latest received epoch is %lld", - *p_latest_trans_gci, ndb_latest_received_binlog_epoch); + sql_print_error("NDB Binlog: latest transaction in epoch %lu not in binlog " + "as latest received epoch is %lu", + (ulong) *p_latest_trans_gci, + (ulong) ndb_latest_received_binlog_epoch); } } } @@ -3698,8 +3706,8 @@ restart: != NULL) { NDB_SHARE *share= (NDB_SHARE*)gci_op->getCustomData(); - DBUG_PRINT("info", ("per gci_op: %p share: %p event_types: 0x%x", - gci_op, share, event_types)); + DBUG_PRINT("info", ("per gci_op: 0x%lx share: 0x%lx event_types: 0x%x", + (long) gci_op, (long) share, event_types)); // workaround for interface returning TE_STOP events // which are normally filtered out below in the nextEvent loop if ((event_types & ~NdbDictionary::Event::TE_STOP) == 0) @@ -3785,11 +3793,13 @@ restart: { NDB_SHARE *share= (NDB_SHARE*) pOp->getCustomData(); DBUG_PRINT("info", - ("EVENT TYPE: %d GCI: %lld last applied: %lld " - "share: 0x%lx (%s.%s)", pOp->getEventType(), gci, - ndb_latest_applied_binlog_epoch, share, - share ? share->db : "share == NULL", - share ? share->table_name : "")); + ("EVENT TYPE: %d GCI: %ld last applied: %ld " + "share: 0x%lx (%s.%s)", pOp->getEventType(), + (long) gci, + (long) ndb_latest_applied_binlog_epoch, + (long) share, + share ? share->db : "'NULL'", + share ? share->table_name : "'NULL'")); DBUG_ASSERT(share != 0); } // assert that there is consistancy between gci op list @@ -3834,9 +3844,10 @@ restart: do_ndbcluster_binlog_close_connection= BCCC_restart; if (ndb_latest_received_binlog_epoch < *p_latest_trans_gci && ndb_binlog_running) { - sql_print_error("NDB Binlog: latest transaction in epoch %lld not in binlog " - "as latest received epoch is %lld", - *p_latest_trans_gci, ndb_latest_received_binlog_epoch); + sql_print_error("NDB Binlog: latest transaction in epoch %lu not in binlog " + "as latest received epoch is %lu", + (ulong) *p_latest_trans_gci, + (ulong) ndb_latest_received_binlog_epoch); } } } @@ -3868,7 +3879,7 @@ restart: row.master_log_file= start.file_name(); row.master_log_pos= start.file_pos(); - DBUG_PRINT("info", ("COMMIT gci: %lld", gci)); + DBUG_PRINT("info", ("COMMIT gci: %lu", (ulong) gci)); if (ndb_update_binlog_index) ndb_add_binlog_index(thd, &row); ndb_latest_applied_binlog_epoch= gci; diff --git a/sql/ha_ndbcluster_tables.h b/sql/ha_ndbcluster_tables.h index 12124cd8820..9d7fda33102 100644 --- a/sql/ha_ndbcluster_tables.h +++ b/sql/ha_ndbcluster_tables.h @@ -15,7 +15,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#define NDB_REP_DB "cluster" +#define NDB_REP_DB "mysql" #define NDB_REP_TABLE "binlog_index" #define NDB_APPLY_TABLE "apply_status" #define NDB_SCHEMA_TABLE "schema" diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 3edd3923779..7cd33dd5726 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -2027,7 +2027,7 @@ bool ha_partition::create_handlers(MEM_ROOT *mem_root) if (!(m_file[i]= get_new_handler(table_share, mem_root, m_engine_array[i]))) DBUG_RETURN(TRUE); - DBUG_PRINT("info", ("engine_type: %u", m_engine_array[i])); + DBUG_PRINT("info", ("engine_type: %u", m_engine_array[i]->db_type)); } /* For the moment we only support partition over the same table engine */ if (m_engine_array[0] == myisam_hton) @@ -2427,7 +2427,7 @@ repeat: do { DBUG_PRINT("info", ("external_lock(thd, %d) iteration %d", - lock_type, (file - m_file))); + lock_type, (int) (file - m_file))); if ((error= (*file)->external_lock(thd, lock_type))) { if (F_UNLCK != lock_type) @@ -2508,7 +2508,7 @@ THR_LOCK_DATA **ha_partition::store_lock(THD *thd, file= m_file; do { - DBUG_PRINT("info", ("store lock %d iteration", (file - m_file))); + DBUG_PRINT("info", ("store lock %d iteration", (int) (file - m_file))); to= (*file)->store_lock(thd, to, lock_type); } while (*(++file)); DBUG_RETURN(to); @@ -2939,8 +2939,8 @@ int ha_partition::rnd_init(bool scan) include_partition_fields_in_used_fields(); /* Now we see what the index of our first important partition is */ - DBUG_PRINT("info", ("m_part_info->used_partitions 0x%x", - m_part_info->used_partitions.bitmap)); + DBUG_PRINT("info", ("m_part_info->used_partitions: 0x%lx", + (long) m_part_info->used_partitions.bitmap)); part_id= bitmap_get_first_set(&(m_part_info->used_partitions)); DBUG_PRINT("info", ("m_part_spec.start_part %d", part_id)); diff --git a/sql/handler.cc b/sql/handler.cc index 451f974a066..f874100e634 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1513,7 +1513,7 @@ int handler::ha_open(TABLE *table_arg, const char *name, int mode, DBUG_ENTER("handler::ha_open"); DBUG_PRINT("enter", ("name: %s db_type: %d db_stat: %d mode: %d lock_test: %d", - name, table_share->db_type, table_arg->db_stat, mode, + name, ht->db_type, table_arg->db_stat, mode, test_if_locked)); table= table_arg; @@ -1654,7 +1654,7 @@ prev_insert_id(ulonglong nr, struct system_variables *variables) */ DBUG_PRINT("info",("auto_increment: nr: %lu cannot honour " "auto_increment_offset: %lu", - nr, variables->auto_increment_offset)); + (ulong) nr, variables->auto_increment_offset)); return nr; } if (variables->auto_increment_increment == 1) @@ -1927,8 +1927,8 @@ int handler::update_auto_increment() void handler::column_bitmaps_signal() { DBUG_ENTER("column_bitmaps_signal"); - DBUG_PRINT("info", ("read_set: 0x%lx write_set: 0x%lx", table->read_set, - table->write_set)); + DBUG_PRINT("info", ("read_set: 0x%lx write_set: 0x%lx", (long) table->read_set, + (long) table->write_set)); DBUG_VOID_RETURN; } @@ -3460,38 +3460,15 @@ bool ha_show_status(THD *thd, handlerton *db_type, enum ha_stat_type stat) declared static, but it works by putting it into an anonymous namespace. */ namespace { - struct st_table_data { - char const *db; - char const *name; - }; - - static int table_name_compare(void const *a, void const *b) - { - st_table_data const *x = (st_table_data const*) a; - st_table_data const *y = (st_table_data const*) b; - - /* Doing lexical compare in order (db,name) */ - int const res= strcmp(x->db, y->db); - return res != 0 ? res : strcmp(x->name, y->name); - } - bool check_table_binlog_row_based(THD *thd, TABLE *table) { - static st_table_data const ignore[] = { - { "mysql", "event" }, - { "mysql", "general_log" }, - { "mysql", "slow_log" } - }; - - my_size_t const ignore_size = sizeof(ignore)/sizeof(*ignore); - st_table_data const item = { table->s->db.str, table->s->table_name.str }; - if (table->s->cached_row_logging_check == -1) - table->s->cached_row_logging_check= - (table->s->tmp_table == NO_TMP_TABLE) && - binlog_filter->db_ok(table->s->db.str) && - bsearch(&item, ignore, ignore_size, - sizeof(st_table_data), table_name_compare) == NULL; + { + int const check(table->s->tmp_table == NO_TMP_TABLE && + binlog_filter->db_ok(table->s->db.str) && + strcmp("mysql", table->s->db.str) != 0); + table->s->cached_row_logging_check= check; + } DBUG_ASSERT(table->s->cached_row_logging_check == 0 || table->s->cached_row_logging_check == 1); @@ -3530,8 +3507,10 @@ namespace int write_locked_table_maps(THD *thd) { DBUG_ENTER("write_locked_table_maps"); - DBUG_PRINT("enter", ("thd=%p, thd->lock=%p, thd->locked_tables=%p, thd->extra_lock", - thd, thd->lock, thd->locked_tables, thd->extra_lock)); + DBUG_PRINT("enter", ("thd: 0x%lx thd->lock: 0x%lx thd->locked_tables: 0x%lx " + "thd->extra_lock: 0x%lx", + (long) thd, (long) thd->lock, + (long) thd->locked_tables, (long) thd->extra_lock)); if (thd->get_binlog_table_maps() == 0) { @@ -3551,7 +3530,7 @@ namespace ++table_ptr) { TABLE *const table= *table_ptr; - DBUG_PRINT("info", ("Checking table %s", table->s->table_name)); + DBUG_PRINT("info", ("Checking table %s", table->s->table_name.str)); if (table->current_lock == F_WRLCK && check_table_binlog_row_based(thd, table)) { diff --git a/sql/item.cc b/sql/item.cc index f8a8b4a6272..6ab9a90ffe3 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1655,7 +1655,7 @@ void Item_field::set_field(Field *field_par) db_name= field_par->table->s->db.str; alias_name_used= field_par->table->alias_name_used; unsigned_flag=test(field_par->flags & UNSIGNED_FLAG); - collation.set(field_par->charset(), DERIVATION_IMPLICIT); + collation.set(field_par->charset(), field_par->derivation()); fixed= 1; } diff --git a/sql/item.h b/sql/item.h index 8799fa07eb7..2c26e1c4a07 100644 --- a/sql/item.h +++ b/sql/item.h @@ -27,19 +27,7 @@ class Item_field; /* "Declared Type Collation" A combination of collation and its derivation. -*/ -enum Derivation -{ - DERIVATION_IGNORABLE= 5, - DERIVATION_COERCIBLE= 4, - DERIVATION_SYSCONST= 3, - DERIVATION_IMPLICIT= 2, - DERIVATION_NONE= 1, - DERIVATION_EXPLICIT= 0 -}; - -/* Flags for collation aggregation modes: MY_COLL_ALLOW_SUPERSET_CONV - allow conversion to a superset MY_COLL_ALLOW_COERCIBLE_CONV - allow conversion of a coercible value diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 79d37c50030..cfd367944e6 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -2229,7 +2229,7 @@ cmp_item* cmp_item_row::make_same() cmp_item_row::~cmp_item_row() { DBUG_ENTER("~cmp_item_row"); - DBUG_PRINT("enter",("this: 0x%lx", this)); + DBUG_PRINT("enter",("this: 0x%lx", (long) this)); if (comparators) { for (uint i= 0; i < n; i++) @@ -3060,7 +3060,7 @@ longlong Item_is_not_null_test::val_int() if (!used_tables_cache) { owner->was_null|= (!cached_value); - DBUG_PRINT("info", ("cached :%d", cached_value)); + DBUG_PRINT("info", ("cached: %ld", (long) cached_value)); DBUG_RETURN(cached_value); } if (args[0]->is_null()) diff --git a/sql/item_func.cc b/sql/item_func.cc index d1c346ac43e..76bec5c4967 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -5051,7 +5051,7 @@ Item_func_sp::result_type() const { Field *field; DBUG_ENTER("Item_func_sp::result_type"); - DBUG_PRINT("info", ("m_sp = %p", m_sp)); + DBUG_PRINT("info", ("m_sp: 0x%lx", (long) m_sp)); if (result_field) DBUG_RETURN(result_field->result_type()); diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 5b602314a55..32b283fca57 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -992,8 +992,8 @@ String *Item_func_insert::val_str(String *str) if (length > res->length() - start) length= res->length() - start; - if (res->length() - length + res2->length() > - current_thd->variables.max_allowed_packet) + if ((ulonglong) (res->length() - length + res2->length()) > + (ulonglong) current_thd->variables.max_allowed_packet) { push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_ALLOWED_PACKET_OVERFLOWED, @@ -2485,7 +2485,7 @@ String *Item_func_lpad::val_str(String *str) pad_char_length= pad->numchars(); byte_count= count * collation.collation->mbmaxlen; - if (byte_count > current_thd->variables.max_allowed_packet) + if ((ulonglong) byte_count > current_thd->variables.max_allowed_packet) { push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_ALLOWED_PACKET_OVERFLOWED, diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 4e6c67cba60..fcf34240189 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -54,7 +54,7 @@ void Item_subselect::init(st_select_lex *select_lex, { DBUG_ENTER("Item_subselect::init"); - DBUG_PRINT("enter", ("select_lex: 0x%x", (ulong) select_lex)); + DBUG_PRINT("enter", ("select_lex: 0x%lx", (long) select_lex)); unit= select_lex->master_unit(); if (unit->item) diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 0d18cf1d424..bb629129667 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -2933,13 +2933,14 @@ int group_concat_key_cmp_with_distinct(void* arg, byte* key1, */ Field *field= (*field_item)->get_tmp_table_field(); /* - If field_item is a const item then either get_tp_table_field returns 0 + If field_item is a const item then either get_tmp_table_field returns 0 or it is an item over a const table. */ if (field && !(*field_item)->const_item()) { int res; - uint offset= field->offset() - table->s->null_bytes; + uint offset= (field->offset(field->table->record[0]) - + table->s->null_bytes); if ((res= field->cmp((char *) key1 + offset, (char *) key2 + offset))) return res; } @@ -2977,7 +2978,8 @@ int group_concat_key_cmp_with_order(void* arg, byte* key1, byte* key2) if (field && !item->const_item()) { int res; - uint offset= field->offset() - table->s->null_bytes; + uint offset= (field->offset(field->table->record[0]) - + table->s->null_bytes); if ((res= field->cmp((char *) key1 + offset, (char *) key2 + offset))) return (*order_item)->asc ? res : -res; } @@ -3023,6 +3025,7 @@ int dump_leaf_key(byte* key, element_count count __attribute__((unused)), String tmp2; String *result= &item->result; Item **arg= item->args, **arg_end= item->args + item->arg_count_field; + uint old_length= result->length(); if (item->no_appended) item->no_appended= FALSE; @@ -3044,7 +3047,8 @@ int dump_leaf_key(byte* key, element_count count __attribute__((unused)), because it contains both order and arg list fields. */ Field *field= (*arg)->get_tmp_table_field(); - uint offset= field->offset() - table->s->null_bytes; + uint offset= (field->offset(field->table->record[0]) - + table->s->null_bytes); DBUG_ASSERT(offset < table->s->reclength); res= field->val_str(&tmp, (char *) key + offset); } @@ -3057,8 +3061,22 @@ int dump_leaf_key(byte* key, element_count count __attribute__((unused)), /* stop if length of result more than max_length */ if (result->length() > item->max_length) { + int well_formed_error; + CHARSET_INFO *cs= item->collation.collation; + const char *ptr= result->ptr(); + uint add_length; + /* + It's ok to use item->result.length() as the fourth argument + as this is never used to limit the length of the data. + Cut is done with the third argument. + */ + add_length= cs->cset->well_formed_len(cs, + ptr + old_length, + ptr + item->max_length, + result->length(), + &well_formed_error); + result->length(old_length + add_length); item->count_cut_values++; - result->length(item->max_length); item->warning_for_row= TRUE; return 1; } @@ -3248,8 +3266,7 @@ bool Item_func_group_concat::add() we can dump the row here in case of GROUP_CONCAT(DISTINCT...) instead of doing tree traverse later. */ - if (result.length() <= max_length && - !warning_for_row && + if (!warning_for_row && (!tree || (el->count == 1 && distinct && !arg_count_order))) dump_leaf_key(table->record[0] + table->s->null_bytes, 1, this); @@ -3318,7 +3335,8 @@ bool Item_func_group_concat::setup(THD *thd) DBUG_RETURN(TRUE); /* We'll convert all blobs to varchar fields in the temporary table */ - tmp_table_param->convert_blob_length= max_length; + tmp_table_param->convert_blob_length= max_length * + collation.collation->mbmaxlen; /* Push all not constant fields to the list and create a temp table */ always_null= 0; for (uint i= 0; i < arg_count_field; i++) diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 3d49305cfd3..d14feb2ba68 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -1368,11 +1368,9 @@ bool get_interval_value(Item *args,interval_type int_type, interval->second= array[0]; interval->second_part= array[1]; break; - /* purecov: begin deadcode */ - case INTERVAL_LAST: - DBUG_ASSERT(0); - break; - /* purecov: end */ + case INTERVAL_LAST: /* purecov: begin deadcode */ + DBUG_ASSERT(0); + break; /* purecov: end */ } return 0; } @@ -2199,7 +2197,7 @@ void Item_extract::fix_length_and_dec() case INTERVAL_HOUR_MICROSECOND: max_length=13; date_value=0; break; case INTERVAL_MINUTE_MICROSECOND: max_length=11; date_value=0; break; case INTERVAL_SECOND_MICROSECOND: max_length=9; date_value=0; break; - case INTERVAL_LAST: DBUG_ASSERT(0); break; /* purecov: deadcode */ + case INTERVAL_LAST: DBUG_ASSERT(0); break; /* purecov: deadcode */ } } @@ -2269,8 +2267,7 @@ longlong Item_extract::val_int() ltime.second_part)*neg; case INTERVAL_SECOND_MICROSECOND: return ((longlong)ltime.second*1000000L+ ltime.second_part)*neg; - case INTERVAL_LAST: DBUG_ASSERT(0); return(0); /* purecov: deadcode */ - /* purecov: end */ + case INTERVAL_LAST: DBUG_ASSERT(0); break; /* purecov: deadcode */ } return 0; // Impossible } @@ -2385,7 +2382,8 @@ String *Item_char_typecast::val_str(String *str) { // Safe even if const arg char char_type[40]; my_snprintf(char_type, sizeof(char_type), "%s(%lu)", - cast_cs == &my_charset_bin ? "BINARY" : "CHAR", (ulong) length); + cast_cs == &my_charset_bin ? "BINARY" : "CHAR", + (ulong) length); if (!res->alloced_length()) { // Don't change const str diff --git a/sql/item_xmlfunc.cc b/sql/item_xmlfunc.cc index 44a2b690bac..21239a13735 100644 --- a/sql/item_xmlfunc.cc +++ b/sql/item_xmlfunc.cc @@ -532,7 +532,7 @@ public: longlong val_int() { Item_func *comp= (Item_func*)args[1]; - Item_string *fake= (Item_string*)(comp->arguments()[1]); + Item_string *fake= (Item_string*)(comp->arguments()[0]); String *res= args[0]->val_nodeset(&tmp_nodeset); MY_XPATH_FLT *fltbeg= (MY_XPATH_FLT*) res->ptr(); MY_XPATH_FLT *fltend= (MY_XPATH_FLT*) (res->ptr() + res->length()); @@ -884,7 +884,7 @@ static Item *eq_func(int oper, Item *a, Item *b) Create a comparator function for scalar arguments, for the given arguments and reverse operation, e.g. - A >= B is converted into A < B + A > B is converted into B < A RETURN The newly created item. @@ -895,10 +895,10 @@ static Item *eq_func_reverse(int oper, Item *a, Item *b) { case '=': return new Item_func_eq(a, b); case '!': return new Item_func_ne(a, b); - case MY_XPATH_LEX_GE: return new Item_func_lt(a, b); - case MY_XPATH_LEX_LE: return new Item_func_gt(a, b); - case MY_XPATH_LEX_GREATER: return new Item_func_le(a, b); - case MY_XPATH_LEX_LESS: return new Item_func_ge(a, b); + case MY_XPATH_LEX_GE: return new Item_func_le(a, b); + case MY_XPATH_LEX_LE: return new Item_func_ge(a, b); + case MY_XPATH_LEX_GREATER: return new Item_func_lt(a, b); + case MY_XPATH_LEX_LESS: return new Item_func_gt(a, b); } return 0; } @@ -951,13 +951,13 @@ static Item *create_comparator(MY_XPATH *xpath, { nodeset= (Item_nodeset_func*) a; scalar= b; - comp= eq_func(oper, scalar, fake); + comp= eq_func(oper, fake, scalar); } else { nodeset= (Item_nodeset_func*) b; scalar= a; - comp= eq_func_reverse(oper, scalar, fake); + comp= eq_func_reverse(oper, fake, scalar); } return new Item_nodeset_to_const_comparator(nodeset, comp, xpath->pxml); } diff --git a/sql/key.cc b/sql/key.cc index be21bf11c3c..dceeab1c011 100644 --- a/sql/key.cc +++ b/sql/key.cc @@ -19,37 +19,54 @@ #include "mysql_priv.h" - /* - ** Search after with key field is. If no key starts with field test - ** if field is part of some key. - ** - ** returns number of key. keylength is set to length of key before - ** (not including) field - ** Used when calculating key for NEXT_NUMBER - */ - -int find_ref_key(KEY *key, uint key_count, Field *field, uint *key_length) +/* + Search after a key that starts with 'field' + + SYNOPSIS + find_ref_key() + key First key to check + key_count How many keys to check + record Start of record + field Field to search after + key_length On partial match, contains length of fields before + field + + NOTES + Used when calculating key for NEXT_NUMBER + + IMPLEMENTATION + If no key starts with field test if field is part of some key. If we find + one, then return first key and set key_length to the number of bytes + preceding 'field'. + + RETURN + -1 field is not part of the key + # Key part for key matching key. + key_length is set to length of key before (not including) field +*/ + +int find_ref_key(KEY *key, uint key_count, byte *record, Field *field, + uint *key_length) { reg2 int i; reg3 KEY *key_info; uint fieldpos; - fieldpos= field->offset(); - - /* Test if some key starts as fieldpos */ + fieldpos= field->offset(record); + /* Test if some key starts as fieldpos */ for (i= 0, key_info= key ; i < (int) key_count ; i++, key_info++) { if (key_info->key_part[0].offset == fieldpos) - { /* Found key. Calc keylength */ + { /* Found key. Calc keylength */ *key_length=0; - return(i); /* Use this key */ + return(i); /* Use this key */ } } - /* Test if some key contains fieldpos */ + /* Test if some key contains fieldpos */ for (i= 0, key_info= key; i < (int) key_count ; i++, key_info++) @@ -62,7 +79,7 @@ int find_ref_key(KEY *key, uint key_count, Field *field, uint *key_length) j++, key_part++) { if (key_part->offset == fieldpos) - return(i); /* Use this key */ + return(i); /* Use this key */ *key_length+=key_part->store_length; } } diff --git a/sql/log.cc b/sql/log.cc index 83e190a5c01..b12eca9bb07 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -424,6 +424,18 @@ bool Log_to_csv_event_handler:: { TABLE *table= general_log.table; + /* + "INSERT INTO general_log" can generate warning sometimes. + Let's reset warnings from previous queries, + otherwise warning list can grow too much, + so thd->query gets spoiled as some point in time, + and mysql_parse() receives a broken query. + QQ: this problem needs to be studied in more details. + Probably it's better to suppress warnings in logging INSERTs at all. + Comment this line and run "cast.test" to see what's happening: + */ + mysql_reset_errors(table->in_use, 1); + /* below should never happen */ if (unlikely(!logger.is_log_tables_initialized)) return FALSE; @@ -1332,7 +1344,7 @@ binlog_trans_log_savepos(THD *thd, my_off_t *pos) (binlog_trx_data*) thd->ha_data[binlog_hton->slot]; DBUG_ASSERT(mysql_bin_log.is_open()); *pos= trx_data->position(); - DBUG_PRINT("return", ("*pos=%u", *pos)); + DBUG_PRINT("return", ("*pos: %lu", (ulong) *pos)); DBUG_VOID_RETURN; } @@ -1356,7 +1368,7 @@ static void binlog_trans_log_truncate(THD *thd, my_off_t pos) { DBUG_ENTER("binlog_trans_log_truncate"); - DBUG_PRINT("enter", ("pos=%u", pos)); + DBUG_PRINT("enter", ("pos: %lu", (ulong) pos)); DBUG_ASSERT(thd->ha_data[binlog_hton->slot] != NULL); /* Only true if binlog_trans_log_savepos() wasn't called before */ @@ -1432,8 +1444,8 @@ binlog_end_trans(THD *thd, binlog_trx_data *trx_data, DBUG_ENTER("binlog_end_trans"); int error=0; IO_CACHE *trans_log= &trx_data->trans_log; - DBUG_PRINT("enter", ("transaction: %s, end_ev=%p", - all ? "all" : "stmt", end_ev)); + DBUG_PRINT("enter", ("transaction: %s end_ev: 0x%lx", + all ? "all" : "stmt", (long) end_ev)); DBUG_PRINT("info", ("thd->options={ %s%s}", FLAGSTR(thd->options, OPTION_NOT_AUTOCOMMIT), FLAGSTR(thd->options, OPTION_BEGIN))); @@ -3405,12 +3417,13 @@ int THD::binlog_setup_trx_data() void THD::binlog_start_trans_and_stmt() { - DBUG_ENTER("binlog_start_trans_and_stmt"); binlog_trx_data *trx_data= (binlog_trx_data*) ha_data[binlog_hton->slot]; - DBUG_PRINT("enter", ("trx_data=0x%lu", trx_data)); - if (trx_data) - DBUG_PRINT("enter", ("trx_data->before_stmt_pos=%u", - trx_data->before_stmt_pos)); + DBUG_ENTER("binlog_start_trans_and_stmt"); + DBUG_PRINT("enter", ("trx_data: 0x%lx trx_data->before_stmt_pos: %lu", + (long) trx_data, + (trx_data ? (ulong) trx_data->before_stmt_pos : + (ulong) 0))); + if (trx_data == NULL || trx_data->before_stmt_pos == MY_OFF_T_UNDEF) { @@ -3441,8 +3454,8 @@ int THD::binlog_write_table_map(TABLE *table, bool is_trans) { int error; DBUG_ENTER("THD::binlog_write_table_map"); - DBUG_PRINT("enter", ("table: %0xlx (%s: #%u)", - (long) table, table->s->table_name, + DBUG_PRINT("enter", ("table: 0x%lx (%s: #%lu)", + (long) table, table->s->table_name.str, table->s->table_map_id)); /* Pre-conditions */ @@ -3505,7 +3518,7 @@ MYSQL_BIN_LOG::flush_and_set_pending_rows_event(THD *thd, { DBUG_ENTER("MYSQL_BIN_LOG::flush_and_set_pending_rows_event(event)"); DBUG_ASSERT(mysql_bin_log.is_open()); - DBUG_PRINT("enter", ("event=%p", event)); + DBUG_PRINT("enter", ("event: 0x%lx", (long) event)); int error= 0; @@ -3514,7 +3527,7 @@ MYSQL_BIN_LOG::flush_and_set_pending_rows_event(THD *thd, DBUG_ASSERT(trx_data); - DBUG_PRINT("info", ("trx_data->pending()=%p", trx_data->pending())); + DBUG_PRINT("info", ("trx_data->pending(): 0x%lx", (long) trx_data->pending())); if (Rows_log_event* pending= trx_data->pending()) { @@ -3669,9 +3682,9 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info) my_off_t trans_log_pos= my_b_tell(trans_log); if (event_info->get_cache_stmt() || trans_log_pos != 0) { - DBUG_PRINT("info", ("Using trans_log: cache=%d, trans_log_pos=%u", + DBUG_PRINT("info", ("Using trans_log: cache: %d, trans_log_pos: %lu", event_info->get_cache_stmt(), - trans_log_pos)); + (ulong) trans_log_pos)); if (trans_log_pos == 0) thd->binlog_start_trans_and_stmt(); file= trans_log; @@ -3713,15 +3726,17 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info) } if (thd->auto_inc_intervals_in_cur_stmt_for_binlog.nb_elements() > 0) { - DBUG_PRINT("info",("number of auto_inc intervals: %lu", - thd->auto_inc_intervals_in_cur_stmt_for_binlog.nb_elements())); + DBUG_PRINT("info",("number of auto_inc intervals: %u", + thd->auto_inc_intervals_in_cur_stmt_for_binlog. + nb_elements())); /* If the auto_increment was second in a table's index (possible with MyISAM or BDB) (table->next_number_key_offset != 0), such event is in fact not necessary. We could avoid logging it. */ - Intvar_log_event e(thd,(uchar) INSERT_ID_EVENT, - thd->auto_inc_intervals_in_cur_stmt_for_binlog.minimum()); + Intvar_log_event e(thd, (uchar) INSERT_ID_EVENT, + thd->auto_inc_intervals_in_cur_stmt_for_binlog. + minimum()); if (e.write(file)) goto err; } diff --git a/sql/log_event.cc b/sql/log_event.cc index d99fb9da8f8..112f4aee135 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -140,6 +140,21 @@ static void pretty_print_str(IO_CACHE* cache, char* str, int len) } #endif /* MYSQL_CLIENT */ +#ifdef HAVE_purify +static void +valgrind_check_mem(void *ptr, size_t len) +{ + static volatile uchar dummy; + for (volatile uchar *p= (uchar*) ptr ; p != (uchar*) ptr + len ; ++p) + { + int const c = *p; + if (c < 128) + dummy= c + 1; + else + dummy = c - 1; + } +} +#endif #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) @@ -831,7 +846,7 @@ Log_event* Log_event::read_log_event(IO_CACHE* file, LOG_EVENT_MINIMAL_HEADER_LEN); LOCK_MUTEX; - DBUG_PRINT("info", ("my_b_tell=%lu", my_b_tell(file))); + DBUG_PRINT("info", ("my_b_tell: %lu", (ulong) my_b_tell(file))); if (my_b_read(file, (byte *) head, header_size)) { DBUG_PRINT("info", ("Log_event::read_log_event(IO_CACHE*,Format_desc*) \ @@ -1398,6 +1413,7 @@ bool Query_log_event::write(IO_CACHE* file) /* Store length of status variables */ status_vars_len= (uint) (start-start_of_status); + DBUG_ASSERT(status_vars_len <= MAX_SIZE_LOG_EVENT_STATUS); int2store(buf + Q_STATUS_VARS_LEN_OFFSET, status_vars_len); /* @@ -1483,7 +1499,8 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, } else time_zone_len= 0; - DBUG_PRINT("info",("Query_log_event has flags2=%lu sql_mode=%lu",flags2,sql_mode)); + DBUG_PRINT("info",("Query_log_event has flags2: %lu sql_mode: %lu", + (ulong) flags2, sql_mode)); } #endif /* MYSQL_CLIENT */ @@ -1531,7 +1548,7 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, common_header_len= description_event->common_header_len; post_header_len= description_event->post_header_len[event_type-1]; - DBUG_PRINT("info",("event_len=%ld, common_header_len=%d, post_header_len=%d", + DBUG_PRINT("info",("event_len: %u common_header_len: %d post_header_len: %d", event_len, common_header_len, post_header_len)); /* @@ -1579,7 +1596,7 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, case Q_FLAGS2_CODE: flags2_inited= 1; flags2= uint4korr(pos); - DBUG_PRINT("info",("In Query_log_event, read flags2: %lu", flags2)); + DBUG_PRINT("info",("In Query_log_event, read flags2: %lu", (ulong) flags2)); pos+= 4; break; case Q_SQL_MODE_CODE: @@ -3354,8 +3371,8 @@ Rotate_log_event::Rotate_log_event(const char* new_log_ident_arg, #ifndef DBUG_OFF char buff[22]; DBUG_ENTER("Rotate_log_event::Rotate_log_event(...,flags)"); - DBUG_PRINT("enter",("new_log_ident %s pos %s flags %lu", new_log_ident_arg, - llstr(pos_arg, buff), flags)); + DBUG_PRINT("enter",("new_log_ident: %s pos: %s flags: %lu", new_log_ident_arg, + llstr(pos_arg, buff), (ulong) flags)); #endif if (flags & DUP_NAME) new_log_ident= my_strndup(new_log_ident_arg, ident_len, MYF(MY_WME)); @@ -4136,7 +4153,7 @@ Slave_log_event::Slave_log_event(THD* thd_arg, memcpy(master_log, rli->group_master_log_name, master_log_len + 1); master_port = mi->port; master_pos = rli->group_master_log_pos; - DBUG_PRINT("info", ("master_log: %s pos: %d", master_log, + DBUG_PRINT("info", ("master_log: %s pos: %lu", master_log, (ulong) master_pos)); } else @@ -5328,8 +5345,8 @@ Rows_log_event::Rows_log_event(const char *buf, uint event_len, uint8 const common_header_len= description_event->common_header_len; uint8 const post_header_len= description_event->post_header_len[event_type-1]; - DBUG_PRINT("enter",("event_len=%ld, common_header_len=%d, " - "post_header_len=%d", + DBUG_PRINT("enter",("event_len: %u common_header_len: %d " + "post_header_len: %d", event_len, common_header_len, post_header_len)); @@ -5359,7 +5376,7 @@ Rows_log_event::Rows_log_event(const char *buf, uint event_len, const byte* const ptr_rows_data= var_start + byte_count + 1; my_size_t const data_size= event_len - (ptr_rows_data - (const byte *) buf); - DBUG_PRINT("info",("m_table_id=%lu, m_flags=%d, m_width=%u, data_size=%lu", + DBUG_PRINT("info",("m_table_id: %lu m_flags: %d m_width: %lu data_size: %lu", m_table_id, m_flags, m_width, data_size)); m_rows_buf= (byte*)my_malloc(data_size, MYF(MY_WME)); @@ -5400,8 +5417,14 @@ int Rows_log_event::do_add_row_data(byte *const row_data, */ DBUG_ENTER("Rows_log_event::do_add_row_data"); DBUG_PRINT("enter", ("row_data: 0x%lx length: %lu", (ulong) row_data, - length)); + (ulong) length)); + /* + Don't print debug messages when running valgrind since they can + trigger false warnings. + */ +#ifndef HAVE_purify DBUG_DUMP("row_data", (const char*)row_data, min(length, 32)); +#endif DBUG_ASSERT(m_rows_buf <= m_rows_cur); DBUG_ASSERT(!m_rows_buf || m_rows_end && m_rows_buf < m_rows_end); @@ -5445,14 +5468,13 @@ int Rows_log_event::do_add_row_data(byte *const row_data, #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) /* - Unpack a row into a record. + Unpack a row into table->record[0]. SYNOPSIS unpack_row() rli Relay log info table Table to unpack into colcnt Number of columns to read from record - record Record where the data should be unpacked row Packed row data cols Pointer to columns data to fill in row_end Pointer to variable that will hold the value of the @@ -5465,6 +5487,11 @@ int Rows_log_event::do_add_row_data(byte *const row_data, DESCRIPTION + The function will always unpack into the table->record[0] + record. This is because there are too many dependencies on + where the various member functions of Field and subclasses + expect to write. + The row is assumed to only consist of the fields for which the bitset represented by 'arr' and 'bits'; the other parts of the record are left alone. @@ -5483,13 +5510,15 @@ int Rows_log_event::do_add_row_data(byte *const row_data, */ static int unpack_row(RELAY_LOG_INFO *rli, - TABLE *table, uint const colcnt, byte *record, + TABLE *table, uint const colcnt, char const *row, MY_BITMAP const *cols, char const **row_end, ulong *master_reclength, MY_BITMAP* const rw_set, Log_event_type const event_type) { + byte *const record= table->record[0]; + DBUG_ENTER("unpack_row"); DBUG_ASSERT(record && row); - my_ptrdiff_t const offset= record - (byte*) table->record[0]; + DBUG_PRINT("enter", ("row: 0x%lx table->record[0]: 0x%lx", (long) row, (long) record)); my_size_t master_null_bytes= table->s->null_bytes; if (colcnt != table->s->fields) @@ -5529,9 +5558,13 @@ unpack_row(RELAY_LOG_INFO *rli, if (bitmap_is_set(cols, field_ptr - begin_ptr)) { - f->move_field_offset(offset); + DBUG_ASSERT(table->record[0] <= f->ptr); + DBUG_ASSERT(f->ptr < (table->record[0] + table->s->reclength + + (f->pack_length_in_rec() == 0))); + + DBUG_PRINT("info", ("unpacking column '%s' to 0x%lx", f->field_name, + (long) f->ptr)); ptr= f->unpack(f->ptr, ptr); - f->move_field_offset(-offset); /* Field...::unpack() cannot return 0 */ DBUG_ASSERT(ptr != NULL); } @@ -5562,13 +5595,11 @@ unpack_row(RELAY_LOG_INFO *rli, for ( ; *field_ptr ; ++field_ptr) { uint32 const mask= NOT_NULL_FLAG | NO_DEFAULT_VALUE_FLAG; + Field *const f= *field_ptr; - DBUG_PRINT("debug", ("flags = 0x%x, mask = 0x%x, flags & mask = 0x%x", - (*field_ptr)->flags, mask, - (*field_ptr)->flags & mask)); - - if (event_type == WRITE_ROWS_EVENT && - ((*field_ptr)->flags & mask) == mask) + DBUG_PRINT("info", ("processing column '%s' @ 0x%lx", f->field_name, + (long) f->ptr)); + if (event_type == WRITE_ROWS_EVENT && (f->flags & mask) == mask) { slave_print_msg(ERROR_LEVEL, rli, ER_NO_DEFAULT_FOR_FIELD, "Field `%s` of table `%s`.`%s` " @@ -5578,10 +5609,10 @@ unpack_row(RELAY_LOG_INFO *rli, error = ER_NO_DEFAULT_FOR_FIELD; } else - (*field_ptr)->set_default(); + f->set_default(); } - return error; + DBUG_RETURN(error); } int Rows_log_event::exec_event(st_relay_log_info *rli) @@ -5689,12 +5720,10 @@ int Rows_log_event::exec_event(st_relay_log_info *rli) We also invalidate the query cache for all the tables, since they will now be changed. */ - TABLE_LIST *ptr; for (ptr= rli->tables_to_lock ; ptr ; ptr= ptr->next_global) { rli->m_table_map.set_table(ptr->table_id, ptr->table); - rli->touching_table(ptr->db, ptr->table_name, ptr->table_id); } #ifdef HAVE_QUERY_CACHE query_cache.invalidate_locked_for_write(rli->tables_to_lock); @@ -5747,7 +5776,7 @@ int Rows_log_event::exec_event(st_relay_log_info *rli) if ((error= do_prepare_row(thd, rli, table, row_start, &row_end))) break; // We should perform the after-row operation even in // the case of error - + DBUG_ASSERT(row_end != NULL); // cannot happen DBUG_ASSERT(row_end <= (const char*)m_rows_end); @@ -5803,9 +5832,10 @@ int Rows_log_event::exec_event(st_relay_log_info *rli) STMT_END_F. For now we code, knowing that error is not skippable and so slave SQL thread is certainly going to stop. + rollback at the caller along with sbr. */ thd->reset_current_stmt_binlog_row_based(); - rli->cleanup_context(thd, 1); + rli->cleanup_context(thd, 0); /* rollback at caller in step with sbr */ thd->query_error= 1; DBUG_RETURN(error); } @@ -6044,10 +6074,16 @@ Table_map_log_event::Table_map_log_event(const char *buf, uint event_len, uint8 common_header_len= description_event->common_header_len; uint8 post_header_len= description_event->post_header_len[TABLE_MAP_EVENT-1]; - DBUG_PRINT("info",("event_len=%ld, common_header_len=%d, post_header_len=%d", + DBUG_PRINT("info",("event_len: %u common_header_len: %d post_header_len: %d", event_len, common_header_len, post_header_len)); + /* + Don't print debug messages when running valgrind since they can + trigger false warnings. + */ +#ifndef HAVE_purify DBUG_DUMP("event buffer", buf, event_len); +#endif /* Read the post-header */ const char *post_start= buf + common_header_len; @@ -6086,10 +6122,10 @@ Table_map_log_event::Table_map_log_event(const char *buf, uint event_len, uchar *ptr_after_colcnt= (uchar*) ptr_colcnt; m_colcnt= net_field_length(&ptr_after_colcnt); - DBUG_PRINT("info",("m_dblen=%d off=%d m_tbllen=%d off=%d m_colcnt=%d off=%d", - m_dblen, ptr_dblen-(const byte*)vpart, - m_tbllen, ptr_tbllen-(const byte*)vpart, - m_colcnt, ptr_colcnt-(const byte*)vpart)); + DBUG_PRINT("info",("m_dblen: %lu off: %ld m_tbllen: %lu off: %ld m_colcnt: %lu off: %ld", + m_dblen, (long) (ptr_dblen-(const byte*)vpart), + m_tbllen, (long) (ptr_tbllen-(const byte*)vpart), + m_colcnt, (long) (ptr_colcnt-(const byte*)vpart))); /* Allocate mem for all fields in one go. If fails, catched in is_valid() */ m_memory= my_multi_malloc(MYF(MY_WME), @@ -6230,8 +6266,7 @@ int Table_map_log_event::exec_event(st_relay_log_info *rli) /* We record in the slave's information that the table should be - locked by linking the table into the list of tables to lock, and - tell the RLI that we are touching a table. + locked by linking the table into the list of tables to lock. */ table_list->next_global= table_list->next_local= rli->tables_to_lock; rli->tables_to_lock= table_list; @@ -6423,17 +6458,15 @@ int Write_rows_log_event::do_after_row_operations(TABLE *table, int error) int Write_rows_log_event::do_prepare_row(THD *thd, RELAY_LOG_INFO *rli, TABLE *table, - char const *row_start, - char const **row_end) + char const *const row_start, + char const **const row_end) { DBUG_ASSERT(table != NULL); DBUG_ASSERT(row_start && row_end); int error; - error= unpack_row(rli, - table, m_width, table->record[0], - row_start, &m_cols, row_end, &m_master_reclength, - table->write_set, WRITE_ROWS_EVENT); + error= unpack_row(rli, table, m_width, row_start, &m_cols, row_end, + &m_master_reclength, table->write_set, WRITE_ROWS_EVENT); bitmap_copy(table->read_set, table->write_set); return error; } @@ -6494,11 +6527,11 @@ copy_extra_record_fields(TABLE *table, my_size_t master_reclength, my_ptrdiff_t master_fields) { - DBUG_PRINT("info", ("Copying to %p " - "from field %d at offset %u " - "to field %d at offset %u", - table->record[0], - master_fields, master_reclength, + DBUG_PRINT("info", ("Copying to 0x%lx " + "from field %lu at offset %lu " + "to field %d at offset %lu", + (long) table->record[0], + (ulong) master_fields, (ulong) master_reclength, table->s->fields, table->s->reclength)); /* Copying the extra fields of the slave that does not exist on @@ -6595,6 +6628,11 @@ replace_record(THD *thd, TABLE *table, while ((error= table->file->ha_write_row(table->record[0]))) { + if (error == HA_ERR_LOCK_DEADLOCK || error == HA_ERR_LOCK_WAIT_TIMEOUT) + { + table->file->print_error(error, MYF(0)); /* to check at exec_relay_log_event */ + DBUG_RETURN(error); + } if ((keynum= table->file->get_dup_key(error)) < 0) { /* We failed to retrieve the duplicate key */ @@ -6649,7 +6687,7 @@ replace_record(THD *thd, TABLE *table, present on the master from table->record[1], if there are any. */ copy_extra_record_fields(table, master_reclength, master_fields); - + /* REPLACE is defined as either INSERT or DELETE + INSERT. If possible, we can replace it with an UPDATE, but that will not @@ -6728,8 +6766,26 @@ static bool record_compare(TABLE *table) /* Find the row given by 'key', if the table has keys, or else use a table scan - to find (and fetch) the row. If the engine allows random access of the - records, a combination of position() and rnd_pos() will be used. + to find (and fetch) the row. + + If the engine allows random access of the records, a combination of + position() and rnd_pos() will be used. + + @param table Pointer to table to search + @param key Pointer to key to use for search, if table has key + + @pre <code>table->record[0]</code> shall contain the row to locate + and <code>key</code> shall contain a key to use for searching, if + the engine has a key. + + @post If the return value is zero, <code>table->record[1]</code> + will contain the fetched row and the internal "cursor" will refer to + the row. If the return value is non-zero, + <code>table->record[1]</code> is undefined. In either case, + <code>table->record[0]</code> is undefined. + + @return Zero if the row was successfully fetched into + <code>table->record[1]</code>, error code otherwise. */ static int find_and_fetch_row(TABLE *table, byte *key) @@ -6749,13 +6805,28 @@ static int find_and_fetch_row(TABLE *table, byte *key) row reference using the position() member function (it will be stored in table->file->ref) and the use rnd_pos() to position the "cursor" (i.e., record[0] in this case) at the correct row. + + TODO: Add a check that the correct record has been fetched by + comparing with the original record. Take into account that the + record on the master and slave can be of different + length. Something along these lines should work: + + ADD>>> store_record(table,record[1]); + int error= table->file->rnd_pos(table->record[0], table->file->ref); + ADD>>> DBUG_ASSERT(memcmp(table->record[1], table->record[0], + table->s->reclength) == 0); + */ table->file->position(table->record[0]); - DBUG_RETURN(table->file->rnd_pos(table->record[0], table->file->ref)); + int error= table->file->rnd_pos(table->record[0], table->file->ref); + /* + rnd_pos() returns the record in table->record[0], so we have to + move it to table->record[1]. + */ + bmove_align(table->record[1], table->record[0], table->s->reclength); + DBUG_RETURN(error); } - DBUG_ASSERT(table->record[1]); - /* We need to retrieve all fields */ /* TODO: Move this out from this function to main loop */ table->use_all_columns(); @@ -6765,7 +6836,16 @@ static int find_and_fetch_row(TABLE *table, byte *key) int error; /* We have a key: search the table using the index */ if (!table->file->inited && (error= table->file->ha_index_init(0, FALSE))) - return error; + DBUG_RETURN(error); + + /* + Don't print debug messages when running valgrind since they can + trigger false warnings. + */ +#ifndef HAVE_purify + DBUG_DUMP("table->record[0]", table->record[0], table->s->reclength); + DBUG_DUMP("table->record[1]", table->record[1], table->s->reclength); +#endif /* We need to set the null bytes to ensure that the filler bit are @@ -6785,6 +6865,14 @@ static int find_and_fetch_row(TABLE *table, byte *key) DBUG_RETURN(error); } + /* + Don't print debug messages when running valgrind since they can + trigger false warnings. + */ +#ifndef HAVE_purify + DBUG_DUMP("table->record[0]", table->record[0], table->s->reclength); + DBUG_DUMP("table->record[1]", table->record[1], table->s->reclength); +#endif /* Below is a minor "optimization". If the key (i.e., key number 0) has the HA_NOSAME flag set, we know that we have found the @@ -6969,8 +7057,8 @@ int Delete_rows_log_event::do_after_row_operations(TABLE *table, int error) int Delete_rows_log_event::do_prepare_row(THD *thd, RELAY_LOG_INFO *rli, TABLE *table, - char const *row_start, - char const **row_end) + char const *const row_start, + char const **const row_end) { int error; DBUG_ASSERT(row_start && row_end); @@ -6980,10 +7068,8 @@ int Delete_rows_log_event::do_prepare_row(THD *thd, RELAY_LOG_INFO *rli, */ DBUG_ASSERT(table->s->fields >= m_width); - error= unpack_row(rli, - table, m_width, table->record[0], - row_start, &m_cols, row_end, &m_master_reclength, - table->read_set, DELETE_ROWS_EVENT); + error= unpack_row(rli, table, m_width, row_start, &m_cols, row_end, + &m_master_reclength, table->read_set, DELETE_ROWS_EVENT); /* If we will access rows using the random access method, m_key will be set to NULL, so we do not need to make a key copy in that case. @@ -7106,8 +7192,8 @@ int Update_rows_log_event::do_after_row_operations(TABLE *table, int error) int Update_rows_log_event::do_prepare_row(THD *thd, RELAY_LOG_INFO *rli, TABLE *table, - char const *row_start, - char const **row_end) + char const *const row_start, + char const **const row_end) { int error; DBUG_ASSERT(row_start && row_end); @@ -7117,21 +7203,31 @@ int Update_rows_log_event::do_prepare_row(THD *thd, RELAY_LOG_INFO *rli, */ DBUG_ASSERT(table->s->fields >= m_width); + /* + We need to perform some juggling below since unpack_row() always + unpacks into table->record[0]. For more information, see the + comments for unpack_row(). + */ + /* record[0] is the before image for the update */ - error= unpack_row(rli, - table, m_width, table->record[0], - row_start, &m_cols, row_end, &m_master_reclength, - table->read_set, UPDATE_ROWS_EVENT); - row_start = *row_end; + error= unpack_row(rli, table, m_width, row_start, &m_cols, row_end, + &m_master_reclength, table->read_set, UPDATE_ROWS_EVENT); + store_record(table, record[1]); + char const *next_start = *row_end; /* m_after_image is the after image for the update */ - error= unpack_row(rli, - table, m_width, m_after_image, - row_start, &m_cols, row_end, &m_master_reclength, - table->write_set, UPDATE_ROWS_EVENT); + error= unpack_row(rli, table, m_width, next_start, &m_cols, row_end, + &m_master_reclength, table->write_set, UPDATE_ROWS_EVENT); + bmove_align(m_after_image, table->record[0], table->s->reclength); + restore_record(table, record[1]); + /* + Don't print debug messages when running valgrind since they can + trigger false warnings. + */ +#ifndef HAVE_purify DBUG_DUMP("record[0]", (const char *)table->record[0], table->s->reclength); DBUG_DUMP("m_after_image", (const char *)m_after_image, table->s->reclength); - +#endif /* If we will access rows using the random access method, m_key will diff --git a/sql/log_event.h b/sql/log_event.h index 81ce2f18b4d..c3f015e723c 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -200,8 +200,26 @@ struct sql_ex_info #define EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN (4 + 4 + 4 + 1) #define EXECUTE_LOAD_QUERY_HEADER_LEN (QUERY_HEADER_LEN + EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN) -/* - Event header offsets; +/* + Max number of possible extra bytes in a replication event compared to a + packet (i.e. a query) sent from client to master; + First, an auxiliary log_event status vars estimation: +*/ +#define MAX_SIZE_LOG_EVENT_STATUS (4 /* flags2 */ + \ + 8 /* sql mode */ + \ + 1 + 1 + 255 /* catalog */ + \ + 4 /* autoinc */ + \ + 6 /* charset */ + \ + MAX_TIME_ZONE_NAME_LENGTH) +#define MAX_LOG_EVENT_HEADER ( /* in order of Query_log_event::write */ \ + LOG_EVENT_HEADER_LEN + /* write_header */ \ + QUERY_HEADER_LEN + /* write_data */ \ + EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN + /*write_post_header_for_derived */ \ + MAX_SIZE_LOG_EVENT_STATUS + /* status */ \ + NAME_LEN + 1) + +/* + Event header offsets; these point to places inside the fixed header. */ diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index b0947249439..2a596a673f7 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -105,6 +105,17 @@ extern CHARSET_INFO *system_charset_info, *files_charset_info ; extern CHARSET_INFO *national_charset_info, *table_alias_charset; +enum Derivation +{ + DERIVATION_IGNORABLE= 5, + DERIVATION_COERCIBLE= 4, + DERIVATION_SYSCONST= 3, + DERIVATION_IMPLICIT= 2, + DERIVATION_NONE= 1, + DERIVATION_EXPLICIT= 0 +}; + + typedef struct my_locale_st { const char *name; @@ -1423,7 +1434,8 @@ void print_plan(JOIN* join,uint idx, double record_count, double read_time, #endif void mysql_print_status(); /* key.cc */ -int find_ref_key(KEY *key, uint key_count, Field *field, uint *key_length); +int find_ref_key(KEY *key, uint key_count, byte *record, Field *field, + uint *key_length); void key_copy(byte *to_key, byte *from_record, KEY *key_info, uint key_length); void key_restore(byte *to_record, byte *from_key, KEY *key_info, uint key_length); @@ -1812,7 +1824,7 @@ int create_frm(THD *thd, const char *name, const char *db, const char *table, HA_CREATE_INFO *create_info, uint keys); void update_create_info_from_table(HA_CREATE_INFO *info, TABLE *form); int rename_file_ext(const char * from,const char * to,const char * ext); -bool check_db_name(char *db); +bool check_db_name(LEX_STRING *db); bool check_column_name(const char *name); bool check_table_name(const char *name, uint length); char *get_field(MEM_ROOT *mem, Field *field); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 5d28d0663e7..83ac6425f2b 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1610,7 +1610,7 @@ static void network_init(void) if (strlen(mysqld_unix_port) > (sizeof(UNIXaddr.sun_path) - 1)) { sql_print_error("The socket file path is too long (> %u): %s", - sizeof(UNIXaddr.sun_path) - 1, mysqld_unix_port); + (uint) sizeof(UNIXaddr.sun_path) - 1, mysqld_unix_port); unireg_abort(1); } if ((unix_sock= socket(AF_UNIX, SOCK_STREAM, 0)) < 0) @@ -2121,7 +2121,7 @@ the thread stack. Please read http://www.mysql.com/doc/en/Linux.html\n\n", #ifdef HAVE_STACKTRACE if (!(test_flags & TEST_NO_STACKTRACE)) { - fprintf(stderr,"thd=%p\n",thd); + fprintf(stderr,"thd: 0x%lx\n",(long) thd); print_stacktrace(thd ? (gptr) thd->thread_stack : (gptr) 0, thread_stack); } @@ -3149,11 +3149,6 @@ with --log-bin instead."); } if (global_system_variables.binlog_format == BINLOG_FORMAT_UNSPEC) { -#if defined(HAVE_NDB_BINLOG) && defined(HAVE_ROW_BASED_REPLICATION) - if (opt_bin_log && have_ndbcluster == SHOW_OPTION_YES) - global_system_variables.binlog_format= BINLOG_FORMAT_ROW; - else -#endif #if defined(HAVE_ROW_BASED_REPLICATION) global_system_variables.binlog_format= BINLOG_FORMAT_MIXED; #else @@ -3213,7 +3208,7 @@ server."); using_update_log=1; } - if (plugin_init(0)) + if (plugin_init(opt_bootstrap)) { sql_print_error("Failed to init plugins."); return 1; @@ -3531,7 +3526,7 @@ int main(int argc, char **argv) if (stack_size && stack_size < thread_stack) { if (global_system_variables.log_warnings) - sql_print_warning("Asked for %ld thread stack, but got %ld", + sql_print_warning("Asked for %lu thread stack, but got %ld", thread_stack, (long) stack_size); #if defined(__ia64__) || defined(__ia64) thread_stack= stack_size*2; @@ -4077,7 +4072,7 @@ static void create_new_thread(THD *thd) int error; thread_created++; threads.append(thd); - DBUG_PRINT("info",(("creating thread %d"), thd->thread_id)); + DBUG_PRINT("info",(("creating thread %lu"), thd->thread_id)); thd->connect_time = time(NULL); if ((error=pthread_create(&thd->real_id,&connection_attrib, handle_one_connection, @@ -5341,7 +5336,8 @@ master-ssl", (gptr*) &locked_in_memory, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"merge", OPT_MERGE, "Enable Merge storage engine. Disable with \ --skip-merge.", - (gptr*) &opt_merge, (gptr*) &opt_merge, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, + (gptr*) &opt_merge, (gptr*) &opt_merge, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, + 0}, {"myisam-recover", OPT_MYISAM_RECOVER, "Syntax: myisam-recover[=option[,option...]], where option can be DEFAULT, BACKUP, FORCE or QUICK.", (gptr*) &myisam_recover_options_str, (gptr*) &myisam_recover_options_str, 0, diff --git a/sql/mysqld.cc.rej b/sql/mysqld.cc.rej new file mode 100644 index 00000000000..62f0357622d --- /dev/null +++ b/sql/mysqld.cc.rej @@ -0,0 +1,17 @@ +*************** +*** 5316,5322 **** + (gptr*) &locked_in_memory, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"merge", OPT_MERGE, "Enable Merge storage engine. Disable with \ + --skip-merge.", +! (gptr*) &opt_merge, (gptr*) &opt_merge, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0}, + {"myisam-recover", OPT_MYISAM_RECOVER, + "Syntax: myisam-recover[=option[,option...]], where option can be DEFAULT, BACKUP, FORCE or QUICK.", + (gptr*) &myisam_recover_options_str, (gptr*) &myisam_recover_options_str, 0, +--- 5336,5342 ---- + (gptr*) &locked_in_memory, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"merge", OPT_MERGE, "Enable Merge storage engine. Disable with \ + --skip-merge.", +! (gptr*) &opt_merge, (gptr*) &opt_merge, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, + {"myisam-recover", OPT_MYISAM_RECOVER, + "Syntax: myisam-recover[=option[,option...]], where option can be DEFAULT, BACKUP, FORCE or QUICK.", + (gptr*) &myisam_recover_options_str, (gptr*) &myisam_recover_options_str, 0, diff --git a/sql/net_serv.cc b/sql/net_serv.cc index a55fef5555c..ec4c4675e76 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -809,7 +809,7 @@ my_real_read(NET *net, ulong *complen) { my_bool interrupted = vio_should_retry(net->vio); - DBUG_PRINT("info",("vio_read returned %d, errno: %d", + DBUG_PRINT("info",("vio_read returned %ld, errno: %d", length, vio_errno(net->vio))); #if !defined(__WIN__) || defined(MYSQL_SERVER) /* diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 79b3e023a5f..1d6b384df35 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -1003,7 +1003,7 @@ QUICK_RANGE_SELECT::~QUICK_RANGE_SELECT() range_end(); if (free_file) { - DBUG_PRINT("info", ("Freeing separate handler %p (free=%d)", file, + DBUG_PRINT("info", ("Freeing separate handler 0x%lx (free: %d)", (long) file, free_file)); file->ha_external_lock(current_thd, F_UNLCK); file->close(); @@ -2011,7 +2011,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, double scan_time; DBUG_ENTER("SQL_SELECT::test_quick_select"); DBUG_PRINT("enter",("keys_to_use: %lu prev_tables: %lu const_tables: %lu", - keys_to_use.to_ulonglong(), (ulong) prev_tables, + (ulong) keys_to_use.to_ulonglong(), (ulong) prev_tables, (ulong) const_tables)); DBUG_PRINT("info", ("records: %lu", (ulong) head->file->stats.records)); delete quick; @@ -3396,7 +3396,7 @@ double get_sweep_read_cost(const PARAM *param, ha_rows records) n_blocks * (1.0 - pow(1.0 - 1.0/n_blocks, rows2double(records))); if (busy_blocks < 1.0) busy_blocks= 1.0; - DBUG_PRINT("info",("sweep: nblocks=%g, busy_blocks=%g", n_blocks, + DBUG_PRINT("info",("sweep: nblocks: %g, busy_blocks: %g", n_blocks, busy_blocks)); /* Disabled: Bail out if # of blocks to read is bigger than # of blocks in @@ -3420,7 +3420,7 @@ double get_sweep_read_cost(const PARAM *param, ha_rows records) result= busy_blocks; } } - DBUG_PRINT("info",("returning cost=%g", result)); + DBUG_PRINT("return",("cost: %g", result)); DBUG_RETURN(result); } @@ -3514,7 +3514,7 @@ TABLE_READ_PLAN *get_best_disjunct_quick(PARAM *param, SEL_IMERGE *imerge, ha_rows roru_total_records; double roru_intersect_part= 1.0; DBUG_ENTER("get_best_disjunct_quick"); - DBUG_PRINT("info", ("Full table scan cost =%g", read_time)); + DBUG_PRINT("info", ("Full table scan cost: %g", read_time)); if (!(range_scans= (TRP_RANGE**)alloc_root(param->mem_root, sizeof(TRP_RANGE*)* @@ -3558,7 +3558,7 @@ TABLE_READ_PLAN *get_best_disjunct_quick(PARAM *param, SEL_IMERGE *imerge, non_cpk_scan_records += (*cur_child)->records; } - DBUG_PRINT("info", ("index_merge scans cost=%g", imerge_cost)); + DBUG_PRINT("info", ("index_merge scans cost %g", imerge_cost)); if (imerge_too_expensive || (imerge_cost > read_time) || (non_cpk_scan_records+cpk_scan_records >= param->table->file->stats.records) && read_time != DBL_MAX) @@ -4172,7 +4172,7 @@ static bool ror_intersect_add(ROR_INTERSECT_INFO *info, DBUG_PRINT("info", ("Current out_rows= %g", info->out_rows)); DBUG_PRINT("info", ("Adding scan on %s", info->param->table->key_info[ror_scan->keynr].name)); - DBUG_PRINT("info", ("is_cpk_scan=%d",is_cpk_scan)); + DBUG_PRINT("info", ("is_cpk_scan: %d",is_cpk_scan)); selectivity_mult = ror_scan_selectivity(info, ror_scan); if (selectivity_mult == 1.0) @@ -9700,8 +9700,8 @@ void cost_group_min_max(TABLE* table, KEY *index_info, uint used_key_parts, *records= num_groups; DBUG_PRINT("info", - ("table rows=%u, keys/block=%u, keys/group=%u, result rows=%u, blocks=%u", - table_records, keys_per_block, keys_per_group, *records, + ("table rows: %u keys/block: %u keys/group: %u result rows: %lu blocks: %u", + table_records, keys_per_block, keys_per_group, (ulong) *records, num_blocks)); DBUG_VOID_RETURN; } @@ -10814,7 +10814,7 @@ static void print_sel_tree(PARAM *param, SEL_TREE *tree, key_map *tree_map, if (!tmp.length()) tmp.append(STRING_WITH_LEN("(empty)")); - DBUG_PRINT("info", ("SEL_TREE %p (%s) scans:%s", tree, msg, tmp.ptr())); + DBUG_PRINT("info", ("SEL_TREE: 0x%lx (%s) scans: %s", (long) tree, msg, tmp.ptr())); DBUG_VOID_RETURN; } diff --git a/sql/parse_file.cc b/sql/parse_file.cc index 0071d59242e..0a2d4012af4 100644 --- a/sql/parse_file.cc +++ b/sql/parse_file.cc @@ -368,32 +368,33 @@ my_bool rename_in_schema_file(const char *schema, const char *old_name, { char old_path[FN_REFLEN], new_path[FN_REFLEN], arc_path[FN_REFLEN]; - strxnmov(old_path, FN_REFLEN-1, mysql_data_home, "/", schema, "/", - old_name, reg_ext, NullS); - (void) unpack_filename(old_path, old_path); - - strxnmov(new_path, FN_REFLEN-1, mysql_data_home, "/", schema, "/", - new_name, reg_ext, NullS); - (void) unpack_filename(new_path, new_path); + build_table_filename(old_path, sizeof(old_path) - 1, + schema, old_name, reg_ext, 0); + build_table_filename(new_path, sizeof(new_path) - 1, + schema, new_name, reg_ext, 0); if (my_rename(old_path, new_path, MYF(MY_WME))) return 1; /* check if arc_dir exists */ - strxnmov(arc_path, FN_REFLEN-1, mysql_data_home, "/", schema, "/arc", NullS); - (void) unpack_filename(arc_path, arc_path); + build_table_filename(arc_path, sizeof(arc_path) - 1, schema, "arc", "", 0); if (revision > 0 && !access(arc_path, F_OK)) { + char old_name_buf[FN_REFLEN], new_name_buf[FN_REFLEN]; ulonglong limit= ((revision > num_view_backups) ? revision - num_view_backups : 0); + + VOID(tablename_to_filename(old_name, old_name_buf, sizeof(old_name_buf))); + VOID(tablename_to_filename(new_name, new_name_buf, sizeof(new_name_buf))); + for (; revision > limit ; revision--) { my_snprintf(old_path, FN_REFLEN, "%s/%s%s-%04lu", - arc_path, old_name, reg_ext, (ulong)revision); + arc_path, old_name_buf, reg_ext, (ulong) revision); (void) unpack_filename(old_path, old_path); my_snprintf(new_path, FN_REFLEN, "%s/%s%s-%04lu", - arc_path, new_name, reg_ext, (ulong)revision); + arc_path, new_name_buf, reg_ext, (ulong) revision); (void) unpack_filename(new_path, new_path); my_rename(old_path, new_path, MYF(0)); } diff --git a/sql/parse_file.h b/sql/parse_file.h index 5fb65b4c7ec..0a02bf7eb75 100644 --- a/sql/parse_file.h +++ b/sql/parse_file.h @@ -106,21 +106,4 @@ public: MEM_ROOT *mem_root, bool bad_format_errors); }; - - -/* - Custom version of standard offsetof() macro which can be used to get - offsets of members in class for non-POD types (according to the current - version of C++ standard offsetof() macro can't be used in such cases and - attempt to do so causes warnings to be emitted, OTOH in many cases it is - still OK to assume that all instances of the class has the same offsets - for the same members). - - This is temporary solution which should be removed once File_parser class - and related routines are refactored. -*/ - -#define my_offsetof(TYPE, MEMBER) \ - ((size_t)((char *)&(((TYPE *)0x10)->MEMBER) - (char*)0x10)) - #endif /* _PARSE_FILE_H_ */ diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index 66e2aa1c31c..762fcfb7a6a 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -564,8 +564,8 @@ err: mysql_free_result(res); if (error) { - sql_print_error("While trying to obtain the list of slaves from the master \ -'%s:%d', user '%s' got the following error: '%s'", + sql_print_error("While trying to obtain the list of slaves from the master " + "'%s:%d', user '%s' got the following error: '%s'", mi->host, mi->port, mi->user, error); DBUG_RETURN(1); } @@ -962,7 +962,7 @@ bool load_master_data(THD* thd) Cancel the previous START SLAVE UNTIL, as the fact to download a new copy logically makes UNTIL irrelevant. */ - clear_until_condition(&active_mi->rli); + active_mi->rli.clear_until_condition(); /* No need to update rli.event* coordinates, they will be when the slave diff --git a/sql/rpl_injector.cc b/sql/rpl_injector.cc index 5a74fd58755..3a0fca4dfa5 100644 --- a/sql/rpl_injector.cc +++ b/sql/rpl_injector.cc @@ -39,6 +39,8 @@ injector::transaction::transaction(MYSQL_BIN_LOG *log, THD *thd) m_start_pos.m_file_pos= log_info.pos; begin_trans(m_thd); + + thd->set_current_stmt_binlog_row_based(); } injector::transaction::~transaction() diff --git a/sql/rpl_mi.cc b/sql/rpl_mi.cc new file mode 100644 index 00000000000..c89c8aa131e --- /dev/null +++ b/sql/rpl_mi.cc @@ -0,0 +1,386 @@ +/* Copyright (C) 2000-2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + 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 <my_global.h> // For HAVE_REPLICATION +#include "mysql_priv.h" +#include <my_dir.h> + +#include "rpl_mi.h" + +#ifdef HAVE_REPLICATION + + +// Defined in slave.cc +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, + const char *default_val); + +MASTER_INFO::MASTER_INFO() + :ssl(0), fd(-1), io_thd(0), inited(0), + abort_slave(0),slave_running(0), slave_run_id(0) +{ + host[0] = 0; user[0] = 0; password[0] = 0; + ssl_ca[0]= 0; ssl_capath[0]= 0; ssl_cert[0]= 0; + ssl_cipher[0]= 0; ssl_key[0]= 0; + + bzero((char*) &file, sizeof(file)); + pthread_mutex_init(&run_lock, MY_MUTEX_INIT_FAST); + pthread_mutex_init(&data_lock, MY_MUTEX_INIT_FAST); + pthread_cond_init(&data_cond, NULL); + pthread_cond_init(&start_cond, NULL); + pthread_cond_init(&stop_cond, NULL); +} + +MASTER_INFO::~MASTER_INFO() +{ + pthread_mutex_destroy(&run_lock); + pthread_mutex_destroy(&data_lock); + pthread_cond_destroy(&data_cond); + pthread_cond_destroy(&start_cond); + pthread_cond_destroy(&stop_cond); +} + + +void init_master_info_with_options(MASTER_INFO* mi) +{ + DBUG_ENTER("init_master_info_with_options"); + + mi->master_log_name[0] = 0; + mi->master_log_pos = BIN_LOG_HEADER_SIZE; // skip magic number + + if (master_host) + strmake(mi->host, master_host, sizeof(mi->host) - 1); + if (master_user) + strmake(mi->user, master_user, sizeof(mi->user) - 1); + if (master_password) + strmake(mi->password, master_password, MAX_PASSWORD_LENGTH); + mi->port = master_port; + mi->connect_retry = master_connect_retry; + + mi->ssl= master_ssl; + if (master_ssl_ca) + strmake(mi->ssl_ca, master_ssl_ca, sizeof(mi->ssl_ca)-1); + if (master_ssl_capath) + strmake(mi->ssl_capath, master_ssl_capath, sizeof(mi->ssl_capath)-1); + if (master_ssl_cert) + strmake(mi->ssl_cert, master_ssl_cert, sizeof(mi->ssl_cert)-1); + if (master_ssl_cipher) + strmake(mi->ssl_cipher, master_ssl_cipher, sizeof(mi->ssl_cipher)-1); + if (master_ssl_key) + strmake(mi->ssl_key, master_ssl_key, sizeof(mi->ssl_key)-1); + DBUG_VOID_RETURN; +} + + +#define LINES_IN_MASTER_INFO_WITH_SSL 14 + + +int init_master_info(MASTER_INFO* mi, const char* master_info_fname, + const char* slave_info_fname, + bool abort_if_no_master_info_file, + int thread_mask) +{ + int fd,error; + char fname[FN_REFLEN+128]; + DBUG_ENTER("init_master_info"); + + if (mi->inited) + { + /* + We have to reset read position of relay-log-bin as we may have + already been reading from 'hotlog' when the slave was stopped + last time. If this case pos_in_file would be set and we would + get a crash when trying to read the signature for the binary + relay log. + + We only rewind the read position if we are starting the SQL + thread. The handle_slave_sql thread assumes that the read + position is at the beginning of the file, and will read the + "signature" and then fast-forward to the last position read. + */ + if (thread_mask & SLAVE_SQL) + { + my_b_seek(mi->rli.cur_log, (my_off_t) 0); + } + DBUG_RETURN(0); + } + + mi->mysql=0; + mi->file_id=1; + fn_format(fname, master_info_fname, mysql_data_home, "", 4+32); + + /* + We need a mutex while we are changing master info parameters to + keep other threads from reading bogus info + */ + + pthread_mutex_lock(&mi->data_lock); + fd = mi->fd; + + /* does master.info exist ? */ + + if (access(fname,F_OK)) + { + if (abort_if_no_master_info_file) + { + pthread_mutex_unlock(&mi->data_lock); + DBUG_RETURN(0); + } + /* + if someone removed the file from underneath our feet, just close + the old descriptor and re-create the old file + */ + if (fd >= 0) + my_close(fd, MYF(MY_WME)); + if ((fd = my_open(fname, O_CREAT|O_RDWR|O_BINARY, MYF(MY_WME))) < 0 ) + { + sql_print_error("Failed to create a new master info file (\ +file '%s', errno %d)", fname, my_errno); + goto err; + } + if (init_io_cache(&mi->file, fd, IO_SIZE*2, READ_CACHE, 0L,0, + MYF(MY_WME))) + { + sql_print_error("Failed to create a cache on master info file (\ +file '%s')", fname); + goto err; + } + + mi->fd = fd; + init_master_info_with_options(mi); + + } + else // file exists + { + if (fd >= 0) + reinit_io_cache(&mi->file, READ_CACHE, 0L,0,0); + else + { + if ((fd = my_open(fname, O_RDWR|O_BINARY, MYF(MY_WME))) < 0 ) + { + sql_print_error("Failed to open the existing master info file (\ +file '%s', errno %d)", fname, my_errno); + goto err; + } + if (init_io_cache(&mi->file, fd, IO_SIZE*2, READ_CACHE, 0L, + 0, MYF(MY_WME))) + { + sql_print_error("Failed to create a cache on master info file (\ +file '%s')", fname); + goto err; + } + } + + mi->fd = fd; + int port, connect_retry, master_log_pos, ssl= 0, lines; + char *first_non_digit; + + /* + Starting from 4.1.x master.info has new format. Now its + first line contains number of lines in file. By reading this + number we will be always distinguish to which version our + master.info corresponds to. We can't simply count lines in + file since versions before 4.1.x could generate files with more + lines than needed. + If first line doesn't contain a number or contain number less than + 14 then such file is treated like file from pre 4.1.1 version. + There is no ambiguity when reading an old master.info, as before + 4.1.1, the first line contained the binlog's name, which is either + empty or has an extension (contains a '.'), so can't be confused + with an integer. + + So we're just reading first line and trying to figure which version + is this. + */ + + /* + The first row is temporarily stored in mi->master_log_name, + if it is line count and not binlog name (new format) it will be + overwritten by the second row later. + */ + if (init_strvar_from_file(mi->master_log_name, + sizeof(mi->master_log_name), &mi->file, + "")) + goto errwithmsg; + + lines= strtoul(mi->master_log_name, &first_non_digit, 10); + + if (mi->master_log_name[0]!='\0' && + *first_non_digit=='\0' && lines >= LINES_IN_MASTER_INFO_WITH_SSL) + { // Seems to be new format + if (init_strvar_from_file(mi->master_log_name, + sizeof(mi->master_log_name), &mi->file, "")) + goto errwithmsg; + } + else + lines= 7; + + if (init_intvar_from_file(&master_log_pos, &mi->file, 4) || + init_strvar_from_file(mi->host, sizeof(mi->host), &mi->file, + master_host) || + init_strvar_from_file(mi->user, sizeof(mi->user), &mi->file, + master_user) || + init_strvar_from_file(mi->password, SCRAMBLED_PASSWORD_CHAR_LENGTH+1, + &mi->file, master_password) || + init_intvar_from_file(&port, &mi->file, master_port) || + init_intvar_from_file(&connect_retry, &mi->file, + master_connect_retry)) + goto errwithmsg; + + /* + If file has ssl part use it even if we have server without + SSL support. But these option will be ignored later when + slave will try connect to master, so in this case warning + is printed. + */ + if (lines >= LINES_IN_MASTER_INFO_WITH_SSL && + (init_intvar_from_file(&ssl, &mi->file, master_ssl) || + init_strvar_from_file(mi->ssl_ca, sizeof(mi->ssl_ca), + &mi->file, master_ssl_ca) || + init_strvar_from_file(mi->ssl_capath, sizeof(mi->ssl_capath), + &mi->file, master_ssl_capath) || + init_strvar_from_file(mi->ssl_cert, sizeof(mi->ssl_cert), + &mi->file, master_ssl_cert) || + init_strvar_from_file(mi->ssl_cipher, sizeof(mi->ssl_cipher), + &mi->file, master_ssl_cipher) || + init_strvar_from_file(mi->ssl_key, sizeof(mi->ssl_key), + &mi->file, master_ssl_key))) + goto errwithmsg; +#ifndef HAVE_OPENSSL + if (ssl) + sql_print_warning("SSL information in the master info file " + "('%s') are ignored because this MySQL slave was compiled " + "without SSL support.", fname); +#endif /* HAVE_OPENSSL */ + + /* + This has to be handled here as init_intvar_from_file can't handle + my_off_t types + */ + mi->master_log_pos= (my_off_t) master_log_pos; + mi->port= (uint) port; + mi->connect_retry= (uint) connect_retry; + mi->ssl= (my_bool) ssl; + } + DBUG_PRINT("master_info",("log_file_name: %s position: %ld", + mi->master_log_name, + (ulong) mi->master_log_pos)); + + mi->rli.mi = mi; + if (init_relay_log_info(&mi->rli, slave_info_fname)) + goto err; + + mi->inited = 1; + // now change cache READ -> WRITE - must do this before flush_master_info + reinit_io_cache(&mi->file, WRITE_CACHE, 0L, 0, 1); + if ((error=test(flush_master_info(mi, 1)))) + sql_print_error("Failed to flush master info file"); + pthread_mutex_unlock(&mi->data_lock); + DBUG_RETURN(error); + +errwithmsg: + sql_print_error("Error reading master configuration"); + +err: + if (fd >= 0) + { + my_close(fd, MYF(0)); + end_io_cache(&mi->file); + } + mi->fd= -1; + pthread_mutex_unlock(&mi->data_lock); + DBUG_RETURN(1); +} + + +/* + RETURN + 2 - flush relay log failed + 1 - flush master info failed + 0 - all ok +*/ +int flush_master_info(MASTER_INFO* mi, bool flush_relay_log_cache) +{ + IO_CACHE* file = &mi->file; + char lbuf[22]; + DBUG_ENTER("flush_master_info"); + DBUG_PRINT("enter",("master_pos: %ld", (long) mi->master_log_pos)); + + /* + Flush the relay log to disk. If we don't do it, then the relay log while + have some part (its last kilobytes) in memory only, so if the slave server + dies now, with, say, from master's position 100 to 150 in memory only (not + on disk), and with position 150 in master.info, then when the slave + restarts, the I/O thread will fetch binlogs from 150, so in the relay log + we will have "[0, 100] U [150, infinity[" and nobody will notice it, so the + SQL thread will jump from 100 to 150, and replication will silently break. + + When we come to this place in code, relay log may or not be initialized; + the caller is responsible for setting 'flush_relay_log_cache' accordingly. + */ + if (flush_relay_log_cache && + flush_io_cache(mi->rli.relay_log.get_log_file())) + DBUG_RETURN(2); + + /* + We flushed the relay log BEFORE the master.info file, because if we crash + now, we will get a duplicate event in the relay log at restart. If we + flushed in the other order, we would get a hole in the relay log. + And duplicate is better than hole (with a duplicate, in later versions we + can add detection and scrap one event; with a hole there's nothing we can + do). + */ + + /* + In certain cases this code may create master.info files that seems + corrupted, because of extra lines filled with garbage in the end + file (this happens if new contents take less space than previous + contents of file). But because of number of lines in the first line + of file we don't care about this garbage. + */ + + my_b_seek(file, 0L); + my_b_printf(file, "%u\n%s\n%s\n%s\n%s\n%s\n%d\n%d\n%d\n%s\n%s\n%s\n%s\n%s\n", + LINES_IN_MASTER_INFO_WITH_SSL, + mi->master_log_name, llstr(mi->master_log_pos, lbuf), + mi->host, mi->user, + mi->password, mi->port, mi->connect_retry, + (int)(mi->ssl), mi->ssl_ca, mi->ssl_capath, mi->ssl_cert, + mi->ssl_cipher, mi->ssl_key); + DBUG_RETURN(-flush_io_cache(file)); +} + + +void end_master_info(MASTER_INFO* mi) +{ + DBUG_ENTER("end_master_info"); + + if (!mi->inited) + DBUG_VOID_RETURN; + end_relay_log_info(&mi->rli); + if (mi->fd >= 0) + { + end_io_cache(&mi->file); + (void)my_close(mi->fd, MYF(MY_WME)); + mi->fd = -1; + } + mi->inited = 0; + + DBUG_VOID_RETURN; +} + + +#endif /* HAVE_REPLICATION */ diff --git a/sql/rpl_mi.h b/sql/rpl_mi.h new file mode 100644 index 00000000000..f0a7d6681fe --- /dev/null +++ b/sql/rpl_mi.h @@ -0,0 +1,110 @@ +/* Copyright (C) 2000-2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + 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 */ + +#ifndef RPL_MI_H +#define RPL_MI_H + +#ifdef HAVE_REPLICATION + +/***************************************************************************** + + Replication IO Thread + + MASTER_INFO contains: + - information about how to connect to a master + - current master log name + - current master log offset + - misc control variables + + MASTER_INFO is initialized once from the master.info file if such + exists. Otherwise, data members corresponding to master.info fields + are initialized with defaults specified by master-* options. The + initialization is done through init_master_info() call. + + The format of master.info file: + + log_name + log_pos + master_host + master_user + master_pass + master_port + master_connect_retry + + To write out the contents of master.info file to disk ( needed every + time we read and queue data from the master ), a call to + flush_master_info() is required. + + To clean up, call end_master_info() + +*****************************************************************************/ + +class MASTER_INFO +{ + public: + MASTER_INFO(); + ~MASTER_INFO(); + + /* the variables below are needed because we can change masters on the fly */ + char master_log_name[FN_REFLEN]; + char host[HOSTNAME_LENGTH+1]; + char user[USERNAME_LENGTH+1]; + char password[MAX_PASSWORD_LENGTH+1]; + my_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]; + + my_off_t master_log_pos; + File fd; // we keep the file open, so we need to remember the file pointer + IO_CACHE file; + + pthread_mutex_t data_lock,run_lock; + pthread_cond_t data_cond,start_cond,stop_cond; + THD *io_thd; + MYSQL* mysql; + uint32 file_id; /* for 3.23 load data infile */ + RELAY_LOG_INFO rli; + uint port; + uint connect_retry; +#ifndef DBUG_OFF + int events_till_disconnect; +#endif + bool inited; + volatile bool abort_slave; + volatile uint slave_running; + volatile ulong slave_run_id; + /* + The difference in seconds between the clock of the master and the clock of + the slave (second - first). It must be signed as it may be <0 or >0. + clock_diff_with_master is computed when the I/O thread starts; for this the + I/O thread does a SELECT UNIX_TIMESTAMP() on the master. + "how late the slave is compared to the master" is computed like this: + clock_of_slave - last_timestamp_executed_by_SQL_thread - clock_diff_with_master + + */ + long clock_diff_with_master; +}; + +void init_master_info_with_options(MASTER_INFO* mi); +int init_master_info(MASTER_INFO* mi, const char* master_info_fname, + const char* slave_info_fname, + bool abort_if_no_master_info_file, + int thread_mask); +void end_master_info(MASTER_INFO* mi); +int flush_master_info(MASTER_INFO* mi, bool flush_relay_log_cache); + +#endif /* HAVE_REPLICATION */ +#endif /* RPL_MI_H */ diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc new file mode 100644 index 00000000000..a2edb9dc8a8 --- /dev/null +++ b/sql/rpl_rli.cc @@ -0,0 +1,1112 @@ +/* Copyright (C) 2000-2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + 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 "mysql_priv.h" + +#include "rpl_rli.h" +#include <my_dir.h> // For MY_STAT +#include "sql_repl.h" // For check_binlog_magic + +static int count_relay_log_space(RELAY_LOG_INFO* rli); + +// Defined in slave.cc +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, + const char *default_val); + + +st_relay_log_info::st_relay_log_info() + :no_storage(FALSE), info_fd(-1), cur_log_fd(-1), save_temporary_tables(0), + cur_log_old_open_count(0), group_master_log_pos(0), log_space_total(0), + ignore_log_space_limit(0), last_master_timestamp(0), slave_skip_counter(0), + abort_pos_wait(0), slave_run_id(0), sql_thd(0), last_slave_errno(0), + inited(0), abort_slave(0), slave_running(0), until_condition(UNTIL_NONE), + until_log_pos(0), retried_trans(0), + tables_to_lock(0), tables_to_lock_count(0), + unsafe_to_stop_at(0) +{ + DBUG_ENTER("st_relay_log_info::st_relay_log_info"); + + group_relay_log_name[0]= event_relay_log_name[0]= + group_master_log_name[0]= 0; + last_slave_error[0]= until_log_name[0]= ign_master_log_name_end[0]= 0; + bzero((char*) &info_file, sizeof(info_file)); + bzero((char*) &cache_buf, sizeof(cache_buf)); + cached_charset_invalidate(); + pthread_mutex_init(&run_lock, MY_MUTEX_INIT_FAST); + pthread_mutex_init(&data_lock, MY_MUTEX_INIT_FAST); + pthread_mutex_init(&log_space_lock, MY_MUTEX_INIT_FAST); + pthread_cond_init(&data_cond, NULL); + pthread_cond_init(&start_cond, NULL); + pthread_cond_init(&stop_cond, NULL); + pthread_cond_init(&log_space_cond, NULL); + relay_log.init_pthread_objects(); + DBUG_VOID_RETURN; +} + + +st_relay_log_info::~st_relay_log_info() +{ + DBUG_ENTER("st_relay_log_info::~st_relay_log_info"); + + pthread_mutex_destroy(&run_lock); + pthread_mutex_destroy(&data_lock); + pthread_mutex_destroy(&log_space_lock); + pthread_cond_destroy(&data_cond); + pthread_cond_destroy(&start_cond); + pthread_cond_destroy(&stop_cond); + pthread_cond_destroy(&log_space_cond); + relay_log.cleanup(); + DBUG_VOID_RETURN; +} + + +int init_relay_log_info(RELAY_LOG_INFO* rli, + const char* info_fname) +{ + char fname[FN_REFLEN+128]; + int info_fd; + const char* msg = 0; + int error = 0; + DBUG_ENTER("init_relay_log_info"); + DBUG_ASSERT(!rli->no_storage); // Don't init if there is no storage + + if (rli->inited) // Set if this function called + DBUG_RETURN(0); + fn_format(fname, info_fname, mysql_data_home, "", 4+32); + pthread_mutex_lock(&rli->data_lock); + info_fd = rli->info_fd; + rli->cur_log_fd = -1; + rli->slave_skip_counter=0; + rli->abort_pos_wait=0; + rli->log_space_limit= relay_log_space_limit; + rli->log_space_total= 0; + rli->tables_to_lock= 0; + rli->tables_to_lock_count= 0; + + /* + The relay log will now be opened, as a SEQ_READ_APPEND IO_CACHE. + Note that the I/O thread flushes it to disk after writing every + 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). + */ + { + char buf[FN_REFLEN]; + const char *ln; + static bool name_warning_sent= 0; + ln= rli->relay_log.generate_name(opt_relay_logname, "-relay-bin", + 1, buf); + /* We send the warning only at startup, not after every RESET SLAVE */ + if (!opt_relay_logname && !opt_relaylog_index_name && !name_warning_sent) + { + /* + User didn't give us info to name the relay log index file. + Picking `hostname`-relay-bin.index like we do, causes replication to + fail if this slave's hostname is changed later. So, we would like to + instead require a name. But as we don't want to break many existing + setups, we only give warning, not error. + */ + sql_print_warning("Neither --relay-log nor --relay-log-index were used;" + " so replication " + "may break when this MySQL server acts as a " + "slave and has his hostname changed!! Please " + "use '--relay-log=%s' to avoid this problem.", ln); + name_warning_sent= 1; + } + /* + 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) || + rli->relay_log.open(ln, LOG_BIN, 0, SEQ_READ_APPEND, 0, + (max_relay_log_size ? max_relay_log_size : + max_binlog_size), 1)) + { + pthread_mutex_unlock(&rli->data_lock); + sql_print_error("Failed in open_log() called from init_relay_log_info()"); + DBUG_RETURN(1); + } + } + + /* if file does not exist */ + if (access(fname,F_OK)) + { + /* + If someone removed the file from underneath our feet, just close + the old descriptor and re-create the old file + */ + if (info_fd >= 0) + my_close(info_fd, MYF(MY_WME)); + if ((info_fd = my_open(fname, O_CREAT|O_RDWR|O_BINARY, MYF(MY_WME))) < 0) + { + sql_print_error("Failed to create a new relay log info file (\ +file '%s', errno %d)", fname, my_errno); + msg= current_thd->net.last_error; + goto err; + } + if (init_io_cache(&rli->info_file, info_fd, IO_SIZE*2, READ_CACHE, 0L,0, + MYF(MY_WME))) + { + sql_print_error("Failed to create a cache on relay log info file '%s'", + fname); + msg= current_thd->net.last_error; + goto err; + } + + /* Init relay log with first entry in the relay index file */ + if (init_relay_log_pos(rli,NullS,BIN_LOG_HEADER_SIZE,0 /* no data lock */, + &msg, 0)) + { + sql_print_error("Failed to open the relay log 'FIRST' (relay_log_pos 4)"); + goto err; + } + rli->group_master_log_name[0]= 0; + rli->group_master_log_pos= 0; + rli->info_fd= info_fd; + } + else // file exists + { + if (info_fd >= 0) + reinit_io_cache(&rli->info_file, READ_CACHE, 0L,0,0); + else + { + int error=0; + if ((info_fd = my_open(fname, O_RDWR|O_BINARY, MYF(MY_WME))) < 0) + { + sql_print_error("\ +Failed to open the existing relay log info file '%s' (errno %d)", + fname, my_errno); + error= 1; + } + else if (init_io_cache(&rli->info_file, info_fd, + IO_SIZE*2, READ_CACHE, 0L, 0, MYF(MY_WME))) + { + sql_print_error("Failed to create a cache on relay log info file '%s'", + fname); + error= 1; + } + if (error) + { + if (info_fd >= 0) + my_close(info_fd, MYF(0)); + rli->info_fd= -1; + rli->relay_log.close(LOG_CLOSE_INDEX | LOG_CLOSE_STOP_EVENT); + pthread_mutex_unlock(&rli->data_lock); + DBUG_RETURN(1); + } + } + + rli->info_fd = info_fd; + int relay_log_pos, master_log_pos; + if (init_strvar_from_file(rli->group_relay_log_name, + sizeof(rli->group_relay_log_name), + &rli->info_file, "") || + init_intvar_from_file(&relay_log_pos, + &rli->info_file, BIN_LOG_HEADER_SIZE) || + init_strvar_from_file(rli->group_master_log_name, + sizeof(rli->group_master_log_name), + &rli->info_file, "") || + init_intvar_from_file(&master_log_pos, &rli->info_file, 0)) + { + msg="Error reading slave log configuration"; + goto err; + } + strmake(rli->event_relay_log_name,rli->group_relay_log_name, + sizeof(rli->event_relay_log_name)-1); + rli->group_relay_log_pos= rli->event_relay_log_pos= relay_log_pos; + rli->group_master_log_pos= master_log_pos; + + if (init_relay_log_pos(rli, + rli->group_relay_log_name, + rli->group_relay_log_pos, + 0 /* no data lock*/, + &msg, 0)) + { + char llbuf[22]; + sql_print_error("Failed to open the relay log '%s' (relay_log_pos %s)", + rli->group_relay_log_name, + llstr(rli->group_relay_log_pos, llbuf)); + goto err; + } + } + +#ifndef DBUG_OFF + { + char llbuf1[22], llbuf2[22]; + DBUG_PRINT("info", ("my_b_tell(rli->cur_log)=%s rli->event_relay_log_pos=%s", + llstr(my_b_tell(rli->cur_log),llbuf1), + llstr(rli->event_relay_log_pos,llbuf2))); + DBUG_ASSERT(rli->event_relay_log_pos >= BIN_LOG_HEADER_SIZE); + DBUG_ASSERT(my_b_tell(rli->cur_log) == rli->event_relay_log_pos); + } +#endif + + /* + Now change the cache from READ to WRITE - must do this + before flush_relay_log_info + */ + reinit_io_cache(&rli->info_file, WRITE_CACHE,0L,0,1); + if ((error= flush_relay_log_info(rli))) + sql_print_error("Failed to flush relay log info file"); + if (count_relay_log_space(rli)) + { + msg="Error counting relay log space"; + goto err; + } + rli->inited= 1; + pthread_mutex_unlock(&rli->data_lock); + DBUG_RETURN(error); + +err: + sql_print_error(msg); + end_io_cache(&rli->info_file); + if (info_fd >= 0) + my_close(info_fd, MYF(0)); + rli->info_fd= -1; + rli->relay_log.close(LOG_CLOSE_INDEX | LOG_CLOSE_STOP_EVENT); + pthread_mutex_unlock(&rli->data_lock); + DBUG_RETURN(1); +} + + +static inline int add_relay_log(RELAY_LOG_INFO* rli,LOG_INFO* linfo) +{ + MY_STAT s; + DBUG_ENTER("add_relay_log"); + if (!my_stat(linfo->log_file_name,&s,MYF(0))) + { + sql_print_error("log %s listed in the index, but failed to stat", + linfo->log_file_name); + DBUG_RETURN(1); + } + rli->log_space_total += s.st_size; +#ifndef DBUG_OFF + char buf[22]; + DBUG_PRINT("info",("log_space_total: %s", llstr(rli->log_space_total,buf))); +#endif + DBUG_RETURN(0); +} + + +static int count_relay_log_space(RELAY_LOG_INFO* rli) +{ + LOG_INFO linfo; + DBUG_ENTER("count_relay_log_space"); + rli->log_space_total= 0; + if (rli->relay_log.find_log_pos(&linfo, NullS, 1)) + { + sql_print_error("Could not find first log while counting relay log space"); + DBUG_RETURN(1); + } + do + { + if (add_relay_log(rli,&linfo)) + DBUG_RETURN(1); + } while (!rli->relay_log.find_next_log(&linfo, 1)); + /* + As we have counted everything, including what may have written in a + preceding write, we must reset bytes_written, or we may count some space + twice. + */ + rli->relay_log.reset_bytes_written(); + DBUG_RETURN(0); +} + + +void st_relay_log_info::clear_slave_error() +{ + DBUG_ENTER("clear_slave_error"); + + /* Clear the errors displayed by SHOW SLAVE STATUS */ + last_slave_error[0]= 0; + last_slave_errno= 0; + DBUG_VOID_RETURN; +} + +/* + Reset UNTIL condition for RELAY_LOG_INFO + + SYNOPSYS + clear_until_condition() + rli - RELAY_LOG_INFO structure where UNTIL condition should be reset + */ + +void st_relay_log_info::clear_until_condition() +{ + DBUG_ENTER("clear_until_condition"); + + until_condition= RELAY_LOG_INFO::UNTIL_NONE; + until_log_name[0]= 0; + until_log_pos= 0; + DBUG_VOID_RETURN; +} + + +/* + Open the given relay log + + SYNOPSIS + init_relay_log_pos() + rli Relay information (will be initialized) + log Name of relay log file to read from. NULL = First log + pos Position in relay log file + need_data_lock Set to 1 if this functions should do mutex locks + errmsg Store pointer to error message here + look_for_description_event + 1 if we should look for such an event. We only need + this when the SQL thread starts and opens an existing + relay log and has to execute it (possibly from an + offset >4); then we need to read the first event of + the relay log to be able to parse the events we have + to execute. + + DESCRIPTION + - Close old open relay log files. + - If we are using the same relay log as the running IO-thread, then set + rli->cur_log to point to the same IO_CACHE entry. + - If not, open the 'log' binary file. + + TODO + - check proper initialization of group_master_log_name/group_master_log_pos + + RETURN VALUES + 0 ok + 1 error. errmsg is set to point to the error message +*/ + +int init_relay_log_pos(RELAY_LOG_INFO* rli,const char* log, + ulonglong pos, bool need_data_lock, + const char** errmsg, + bool look_for_description_event) +{ + DBUG_ENTER("init_relay_log_pos"); + DBUG_PRINT("info", ("pos: %lu", (ulong) pos)); + + *errmsg=0; + pthread_mutex_t *log_lock=rli->relay_log.get_log_lock(); + + if (need_data_lock) + pthread_mutex_lock(&rli->data_lock); + + /* + Slave threads are not the only users of init_relay_log_pos(). CHANGE MASTER + is, too, and init_slave() too; these 2 functions allocate a description + event in init_relay_log_pos, which is not freed by the terminating SQL slave + thread as that thread is not started by these functions. So we have to free + the description_event here, in case, so that there is no memory leak in + running, say, CHANGE MASTER. + */ + delete rli->relay_log.description_event_for_exec; + /* + By default the relay log is in binlog format 3 (4.0). + Even if format is 4, this will work enough to read the first event + (Format_desc) (remember that format 4 is just lenghtened compared to format + 3; format 3 is a prefix of format 4). + */ + rli->relay_log.description_event_for_exec= new + Format_description_log_event(3); + + pthread_mutex_lock(log_lock); + + /* Close log file and free buffers if it's already open */ + if (rli->cur_log_fd >= 0) + { + end_io_cache(&rli->cache_buf); + my_close(rli->cur_log_fd, MYF(MY_WME)); + rli->cur_log_fd = -1; + } + + rli->group_relay_log_pos = rli->event_relay_log_pos = pos; + + /* + Test to see if the previous run was with the skip of purging + If yes, we do not purge when we restart + */ + if (rli->relay_log.find_log_pos(&rli->linfo, NullS, 1)) + { + *errmsg="Could not find first log during relay log initialization"; + goto err; + } + + if (log && rli->relay_log.find_log_pos(&rli->linfo, log, 1)) + { + *errmsg="Could not find target log during relay log initialization"; + goto err; + } + strmake(rli->group_relay_log_name,rli->linfo.log_file_name, + sizeof(rli->group_relay_log_name)-1); + strmake(rli->event_relay_log_name,rli->linfo.log_file_name, + sizeof(rli->event_relay_log_name)-1); + if (rli->relay_log.is_active(rli->linfo.log_file_name)) + { + /* + The IO thread is using this log file. + In this case, we will use the same IO_CACHE pointer to + read data as the IO thread is using to write data. + */ + my_b_seek((rli->cur_log=rli->relay_log.get_log_file()), (off_t)0); + if (check_binlog_magic(rli->cur_log,errmsg)) + goto err; + rli->cur_log_old_open_count=rli->relay_log.get_open_count(); + } + else + { + /* + Open the relay log and set rli->cur_log to point at this one + */ + if ((rli->cur_log_fd=open_binlog(&rli->cache_buf, + rli->linfo.log_file_name,errmsg)) < 0) + goto err; + rli->cur_log = &rli->cache_buf; + } + /* + In all cases, check_binlog_magic() has been called so we're at offset 4 for + sure. + */ + if (pos > BIN_LOG_HEADER_SIZE) /* If pos<=4, we stay at 4 */ + { + Log_event* ev; + while (look_for_description_event) + { + /* + Read the possible Format_description_log_event; if position + was 4, no need, it will be read naturally. + */ + DBUG_PRINT("info",("looking for a Format_description_log_event")); + + if (my_b_tell(rli->cur_log) >= pos) + break; + + /* + Because of we have rli->data_lock and log_lock, we can safely read an + event + */ + if (!(ev=Log_event::read_log_event(rli->cur_log,0, + rli->relay_log.description_event_for_exec))) + { + DBUG_PRINT("info",("could not read event, rli->cur_log->error=%d", + rli->cur_log->error)); + if (rli->cur_log->error) /* not EOF */ + { + *errmsg= "I/O error reading event at position 4"; + goto err; + } + break; + } + else if (ev->get_type_code() == FORMAT_DESCRIPTION_EVENT) + { + DBUG_PRINT("info",("found Format_description_log_event")); + delete rli->relay_log.description_event_for_exec; + rli->relay_log.description_event_for_exec= (Format_description_log_event*) ev; + /* + As ev was returned by read_log_event, it has passed is_valid(), so + my_malloc() in ctor worked, no need to check again. + */ + /* + Ok, we found a Format_description event. But it is not sure that this + describes the whole relay log; indeed, one can have this sequence + (starting from position 4): + Format_desc (of slave) + Rotate (of master) + Format_desc (of master) + So the Format_desc which really describes the rest of the relay log + is the 3rd event (it can't be further than that, because we rotate + the relay log when we queue a Rotate event from the master). + But what describes the Rotate is the first Format_desc. + So what we do is: + go on searching for Format_description events, until you exceed the + position (argument 'pos') or until you find another event than Rotate + or Format_desc. + */ + } + else + { + DBUG_PRINT("info",("found event of another type=%d", + ev->get_type_code())); + look_for_description_event= (ev->get_type_code() == ROTATE_EVENT); + delete ev; + } + } + my_b_seek(rli->cur_log,(off_t)pos); +#ifndef DBUG_OFF + { + char llbuf1[22], llbuf2[22]; + DBUG_PRINT("info", ("my_b_tell(rli->cur_log)=%s rli->event_relay_log_pos=%s", + llstr(my_b_tell(rli->cur_log),llbuf1), + llstr(rli->event_relay_log_pos,llbuf2))); + } +#endif + + } + +err: + /* + If we don't purge, we can't honour relay_log_space_limit ; + silently discard it + */ + if (!relay_log_purge) + rli->log_space_limit= 0; + pthread_cond_broadcast(&rli->data_cond); + + pthread_mutex_unlock(log_lock); + + if (need_data_lock) + pthread_mutex_unlock(&rli->data_lock); + if (!rli->relay_log.description_event_for_exec->is_valid() && !*errmsg) + *errmsg= "Invalid Format_description log event; could be out of memory"; + + DBUG_RETURN ((*errmsg) ? 1 : 0); +} + + +/* + Waits until the SQL thread reaches (has executed up to) the + log/position or timed out. + + SYNOPSIS + wait_for_pos() + thd client thread that sent SELECT MASTER_POS_WAIT + log_name log name to wait for + log_pos position to wait for + timeout timeout in seconds before giving up waiting + + NOTES + timeout is longlong whereas it should be ulong ; but this is + to catch if the user submitted a negative timeout. + + RETURN VALUES + -2 improper arguments (log_pos<0) + or slave not running, or master info changed + during the function's execution, + or client thread killed. -2 is translated to NULL by caller + -1 timed out + >=0 number of log events the function had to wait + before reaching the desired log/position + */ + +int st_relay_log_info::wait_for_pos(THD* thd, String* log_name, + longlong log_pos, + longlong timeout) +{ + int event_count = 0; + ulong init_abort_pos_wait; + int error=0; + struct timespec abstime; // for timeout checking + const char *msg; + DBUG_ENTER("st_relay_log_info::wait_for_pos"); + + if (!inited) + DBUG_RETURN(-1); + + DBUG_PRINT("enter",("log_name: '%s' log_pos: %lu timeout: %lu", + log_name->c_ptr(), (ulong) log_pos, (ulong) timeout)); + + set_timespec(abstime,timeout); + pthread_mutex_lock(&data_lock); + msg= thd->enter_cond(&data_cond, &data_lock, + "Waiting for the slave SQL thread to " + "advance position"); + /* + This function will abort when it notices that some CHANGE MASTER or + RESET MASTER has changed the master info. + To catch this, these commands modify abort_pos_wait ; We just monitor + abort_pos_wait and see if it has changed. + Why do we have this mechanism instead of simply monitoring slave_running + in the loop (we do this too), as CHANGE MASTER/RESET SLAVE require that + the SQL thread be stopped? + This is becasue if someones does: + STOP SLAVE;CHANGE MASTER/RESET SLAVE; START SLAVE; + the change may happen very quickly and we may not notice that + slave_running briefly switches between 1/0/1. + */ + init_abort_pos_wait= abort_pos_wait; + + /* + We'll need to + handle all possible log names comparisons (e.g. 999 vs 1000). + We use ulong for string->number conversion ; this is no + stronger limitation than in find_uniq_filename in sql/log.cc + */ + ulong log_name_extension; + char log_name_tmp[FN_REFLEN]; //make a char[] from String + + strmake(log_name_tmp, log_name->ptr(), min(log_name->length(), FN_REFLEN-1)); + + char *p= fn_ext(log_name_tmp); + char *p_end; + if (!*p || log_pos<0) + { + error= -2; //means improper arguments + goto err; + } + // Convert 0-3 to 4 + log_pos= max(log_pos, BIN_LOG_HEADER_SIZE); + /* p points to '.' */ + log_name_extension= strtoul(++p, &p_end, 10); + /* + p_end points to the first invalid character. + If it equals to p, no digits were found, error. + If it contains '\0' it means conversion went ok. + */ + if (p_end==p || *p_end) + { + error= -2; + goto err; + } + + /* The "compare and wait" main loop */ + while (!thd->killed && + init_abort_pos_wait == abort_pos_wait && + slave_running) + { + bool pos_reached; + int cmp_result= 0; + + DBUG_PRINT("info", + ("init_abort_pos_wait: %ld abort_pos_wait: %ld", + init_abort_pos_wait, abort_pos_wait)); + DBUG_PRINT("info",("group_master_log_name: '%s' pos: %lu", + group_master_log_name, (ulong) group_master_log_pos)); + + /* + group_master_log_name can be "", if we are just after a fresh + replication start or after a CHANGE MASTER TO MASTER_HOST/PORT + (before we have executed one Rotate event from the master) or + (rare) if the user is doing a weird slave setup (see next + paragraph). If group_master_log_name is "", we assume we don't + have enough info to do the comparison yet, so we just wait until + more data. In this case master_log_pos is always 0 except if + somebody (wrongly) sets this slave to be a slave of itself + without using --replicate-same-server-id (an unsupported + configuration which does nothing), then group_master_log_pos + will grow and group_master_log_name will stay "". + */ + if (*group_master_log_name) + { + char *basename= (group_master_log_name + + dirname_length(group_master_log_name)); + /* + First compare the parts before the extension. + Find the dot in the master's log basename, + and protect against user's input error : + if the names do not match up to '.' included, return error + */ + char *q= (char*)(fn_ext(basename)+1); + if (strncmp(basename, log_name_tmp, (int)(q-basename))) + { + error= -2; + break; + } + // Now compare extensions. + char *q_end; + ulong group_master_log_name_extension= strtoul(q, &q_end, 10); + if (group_master_log_name_extension < log_name_extension) + cmp_result= -1 ; + else + cmp_result= (group_master_log_name_extension > log_name_extension) ? 1 : 0 ; + + pos_reached= ((!cmp_result && group_master_log_pos >= (ulonglong)log_pos) || + cmp_result > 0); + if (pos_reached || thd->killed) + break; + } + + //wait for master update, with optional timeout. + + DBUG_PRINT("info",("Waiting for master update")); + /* + We are going to pthread_cond_(timed)wait(); if the SQL thread stops it + will wake us up. + */ + if (timeout > 0) + { + /* + Note that pthread_cond_timedwait checks for the timeout + before for the condition ; i.e. it returns ETIMEDOUT + if the system time equals or exceeds the time specified by abstime + before the condition variable is signaled or broadcast, _or_ if + the absolute time specified by abstime has already passed at the time + of the call. + For that reason, pthread_cond_timedwait will do the "timeoutting" job + even if its condition is always immediately signaled (case of a loaded + master). + */ + error=pthread_cond_timedwait(&data_cond, &data_lock, &abstime); + } + else + pthread_cond_wait(&data_cond, &data_lock); + DBUG_PRINT("info",("Got signal of master update or timed out")); + if (error == ETIMEDOUT || error == ETIME) + { + error= -1; + break; + } + error=0; + event_count++; + DBUG_PRINT("info",("Testing if killed or SQL thread not running")); + } + +err: + thd->exit_cond(msg); + DBUG_PRINT("exit",("killed: %d abort: %d slave_running: %d \ +improper_arguments: %d timed_out: %d", + thd->killed_errno(), + (int) (init_abort_pos_wait != abort_pos_wait), + (int) slave_running, + (int) (error == -2), + (int) (error == -1))); + if (thd->killed || init_abort_pos_wait != abort_pos_wait || + !slave_running) + { + error= -2; + } + DBUG_RETURN( error ? error : event_count ); +} + + +void st_relay_log_info::inc_group_relay_log_pos(ulonglong log_pos, + bool skip_lock) +{ + DBUG_ENTER("st_relay_log_info::inc_group_relay_log_pos"); + + if (!skip_lock) + pthread_mutex_lock(&data_lock); + inc_event_relay_log_pos(); + group_relay_log_pos= event_relay_log_pos; + strmake(group_relay_log_name,event_relay_log_name, + sizeof(group_relay_log_name)-1); + + notify_group_relay_log_name_update(); + + /* + If the slave does not support transactions and replicates a transaction, + users should not trust group_master_log_pos (which they can display with + SHOW SLAVE STATUS or read from relay-log.info), because to compute + group_master_log_pos the slave relies on log_pos stored in the master's + binlog, but if we are in a master's transaction these positions are always + the BEGIN's one (excepted for the COMMIT), so group_master_log_pos does + not advance as it should on the non-transactional slave (it advances by + big leaps, whereas it should advance by small leaps). + */ + /* + In 4.x we used the event's len to compute the positions here. This is + wrong if the event was 3.23/4.0 and has been converted to 5.0, because + then the event's len is not what is was in the master's binlog, so this + will make a wrong group_master_log_pos (yes it's a bug in 3.23->4.0 + replication: Exec_master_log_pos is wrong). Only way to solve this is to + have the original offset of the end of the event the relay log. This is + what we do in 5.0: log_pos has become "end_log_pos" (because the real use + of log_pos in 4.0 was to compute the end_log_pos; so better to store + end_log_pos instead of begin_log_pos. + If we had not done this fix here, the problem would also have appeared + when the slave and master are 5.0 but with different event length (for + example the slave is more recent than the master and features the event + UID). It would give false MASTER_POS_WAIT, false Exec_master_log_pos in + SHOW SLAVE STATUS, and so the user would do some CHANGE MASTER using this + value which would lead to badly broken replication. + Even the relay_log_pos will be corrupted in this case, because the len is + the relay log is not "val". + With the end_log_pos solution, we avoid computations involving lengthes. + */ + DBUG_PRINT("info", ("log_pos: %lu group_master_log_pos: %lu", + (long) log_pos, (long) group_master_log_pos)); + if (log_pos) // 3.23 binlogs don't have log_posx + { + group_master_log_pos= log_pos; + } + pthread_cond_broadcast(&data_cond); + if (!skip_lock) + pthread_mutex_unlock(&data_lock); + DBUG_VOID_RETURN; +} + + +void st_relay_log_info::close_temporary_tables() +{ + TABLE *table,*next; + DBUG_ENTER("st_relay_log_info::close_temporary_tables"); + + for (table=save_temporary_tables ; table ; table=next) + { + next=table->next; + /* + Don't ask for disk deletion. For now, anyway they will be deleted when + slave restarts, but it is a better intention to not delete them. + */ + DBUG_PRINT("info", ("table: 0x%lx", (long) table)); + close_temporary(table, 1, 0); + } + save_temporary_tables= 0; + slave_open_temp_tables= 0; + DBUG_VOID_RETURN; +} + +/* + purge_relay_logs() + + NOTES + Assumes to have a run lock on rli and that no slave thread are running. +*/ + +int purge_relay_logs(RELAY_LOG_INFO* rli, THD *thd, bool just_reset, + const char** errmsg) +{ + int error=0; + DBUG_ENTER("purge_relay_logs"); + + /* + Even if rli->inited==0, we still try to empty rli->master_log_* variables. + Indeed, rli->inited==0 does not imply that they already are empty. + It could be that slave's info initialization partly succeeded : + for example if relay-log.info existed but *relay-bin*.* + have been manually removed, init_relay_log_info reads the old + relay-log.info and fills rli->master_log_*, then init_relay_log_info + checks for the existence of the relay log, this fails and + init_relay_log_info leaves rli->inited to 0. + In that pathological case, rli->master_log_pos* will be properly reinited + at the next START SLAVE (as RESET SLAVE or CHANGE + MASTER, the callers of purge_relay_logs, will delete bogus *.info files + or replace them with correct files), however if the user does SHOW SLAVE + STATUS before START SLAVE, he will see old, confusing rli->master_log_*. + In other words, we reinit rli->master_log_* for SHOW SLAVE STATUS + to display fine in any case. + */ + + rli->group_master_log_name[0]= 0; + rli->group_master_log_pos= 0; + + if (!rli->inited) + { + DBUG_PRINT("info", ("rli->inited == 0")); + DBUG_RETURN(0); + } + + DBUG_ASSERT(rli->slave_running == 0); + DBUG_ASSERT(rli->mi->slave_running == 0); + + rli->slave_skip_counter=0; + pthread_mutex_lock(&rli->data_lock); + + /* + we close the relay log fd possibly left open by the slave SQL thread, + to be able to delete it; the relay log fd possibly left open by the slave + I/O thread will be closed naturally in reset_logs() by the + close(LOG_CLOSE_TO_BE_OPENED) call + */ + if (rli->cur_log_fd >= 0) + { + end_io_cache(&rli->cache_buf); + my_close(rli->cur_log_fd, MYF(MY_WME)); + rli->cur_log_fd= -1; + } + + if (rli->relay_log.reset_logs(thd)) + { + *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"; + goto err; + } + if (!just_reset) + error= init_relay_log_pos(rli, rli->group_relay_log_name, + rli->group_relay_log_pos, + 0 /* do not need data lock */, errmsg, 0); + +err: +#ifndef DBUG_OFF + char buf[22]; +#endif + DBUG_PRINT("info",("log_space_total: %s",llstr(rli->log_space_total,buf))); + pthread_mutex_unlock(&rli->data_lock); + DBUG_RETURN(error); +} + + +/* + Check if condition stated in UNTIL clause of START SLAVE is reached. + SYNOPSYS + st_relay_log_info::is_until_satisfied() + DESCRIPTION + Checks if UNTIL condition is reached. Uses caching result of last + comparison of current log file name and target log file name. So cached + value should be invalidated if current log file name changes + (see st_relay_log_info::notify_... functions). + + This caching is needed to avoid of expensive string comparisons and + strtol() conversions needed for log names comparison. We don't need to + compare them each time this function is called, we only need to do this + when current log name changes. If we have UNTIL_MASTER_POS condition we + need to do this only after Rotate_log_event::exec_event() (which is + rare, so caching gives real benifit), and if we have UNTIL_RELAY_POS + condition then we should invalidate cached comarison value after + inc_group_relay_log_pos() which called for each group of events (so we + have some benefit if we have something like queries that use + autoincrement or if we have transactions). + + Should be called ONLY if until_condition != UNTIL_NONE ! + RETURN VALUE + true - condition met or error happened (condition seems to have + bad log file name) + false - condition not met +*/ + +bool st_relay_log_info::is_until_satisfied() +{ + const char *log_name; + ulonglong log_pos; + DBUG_ENTER("st_relay_log_info::is_until_satisfied"); + + DBUG_ASSERT(until_condition != UNTIL_NONE); + + if (until_condition == UNTIL_MASTER_POS) + { + log_name= group_master_log_name; + log_pos= group_master_log_pos; + } + else + { /* until_condition == UNTIL_RELAY_POS */ + log_name= group_relay_log_name; + log_pos= group_relay_log_pos; + } + + if (until_log_names_cmp_result == UNTIL_LOG_NAMES_CMP_UNKNOWN) + { + /* + We have no cached comparison results so we should compare log names + and cache result. + If we are after RESET SLAVE, and the SQL slave thread has not processed + any event yet, it could be that group_master_log_name is "". In that case, + just wait for more events (as there is no sensible comparison to do). + */ + + if (*log_name) + { + const char *basename= log_name + dirname_length(log_name); + + const char *q= (const char*)(fn_ext(basename)+1); + if (strncmp(basename, until_log_name, (int)(q-basename)) == 0) + { + /* Now compare extensions. */ + char *q_end; + ulong log_name_extension= strtoul(q, &q_end, 10); + if (log_name_extension < until_log_name_extension) + until_log_names_cmp_result= UNTIL_LOG_NAMES_CMP_LESS; + else + until_log_names_cmp_result= + (log_name_extension > until_log_name_extension) ? + UNTIL_LOG_NAMES_CMP_GREATER : UNTIL_LOG_NAMES_CMP_EQUAL ; + } + else + { + /* Probably error so we aborting */ + sql_print_error("Slave SQL thread is stopped because UNTIL " + "condition is bad."); + DBUG_RETURN(TRUE); + } + } + else + DBUG_RETURN(until_log_pos == 0); + } + + DBUG_RETURN(((until_log_names_cmp_result == UNTIL_LOG_NAMES_CMP_EQUAL && + log_pos >= until_log_pos) || + until_log_names_cmp_result == UNTIL_LOG_NAMES_CMP_GREATER)); +} + + +void st_relay_log_info::cached_charset_invalidate() +{ + DBUG_ENTER("st_relay_log_info::cached_charset_invalidate"); + + /* Full of zeroes means uninitialized. */ + bzero(cached_charset, sizeof(cached_charset)); + DBUG_VOID_RETURN; +} + + +bool st_relay_log_info::cached_charset_compare(char *charset) +{ + DBUG_ENTER("st_relay_log_info::cached_charset_compare"); + + if (bcmp(cached_charset, charset, sizeof(cached_charset))) + { + memcpy(cached_charset, charset, sizeof(cached_charset)); + DBUG_RETURN(1); + } + DBUG_RETURN(0); +} + + +void st_relay_log_info::transaction_end(THD* thd) +{ + DBUG_ENTER("st_relay_log_info::transaction_end"); + + /* + Nothing to do here right now. + */ + + DBUG_VOID_RETURN; +} + +#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) +void st_relay_log_info::cleanup_context(THD *thd, bool error) +{ + DBUG_ENTER("st_relay_log_info::cleanup_context"); + + DBUG_ASSERT(sql_thd == thd); + /* + 1) Instances of Table_map_log_event, if ::exec_event() was called on them, + may have opened tables, which we cannot be sure have been closed (because + maybe the Rows_log_event have not been found or will not be, because slave + SQL thread is stopping, or relay log has a missing tail etc). So we close + all thread's tables. And so the table mappings have to be cancelled. + 2) Rows_log_event::exec_event() may even have started statements or + transactions on them, which we need to rollback in case of error. + 3) If finding a Format_description_log_event after a BEGIN, we also need + to rollback before continuing with the next events. + 4) so we need this "context cleanup" function. + */ + if (error) + { + ha_autocommit_or_rollback(thd, 1); // if a "statement transaction" + end_trans(thd, ROLLBACK); // if a "real transaction" + } + m_table_map.clear_tables(); + close_thread_tables(thd); + clear_tables_to_lock(); + unsafe_to_stop_at= 0; + DBUG_VOID_RETURN; +} +#endif diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h index 392f12c2a71..d737055baf2 100644 --- a/sql/rpl_rli.h +++ b/sql/rpl_rli.h @@ -21,6 +21,7 @@ #include "rpl_tblmap.h" + /**************************************************************************** Replication SQL Thread @@ -98,8 +99,8 @@ typedef struct st_relay_log_info */ pthread_cond_t start_cond, stop_cond, data_cond; - /* parent master info structure */ - struct st_master_info *mi; + /* parent MASTER_INFO structure */ + class MASTER_INFO *mi; /* Needed to deal properly with cur_log getting closed and re-opened with @@ -164,6 +165,9 @@ typedef struct st_relay_log_info time_t last_master_timestamp; + void clear_slave_error(); + void clear_until_condition(); + /* Needed for problems when slave stops and we want to restart it skipping one or more events in the master log that have caused @@ -289,22 +293,6 @@ typedef struct st_relay_log_info void cached_charset_invalidate(); bool cached_charset_compare(char *charset); - /* - To reload special tables when they are changes, we introduce a set - of functions that will mark whenever special functions need to be - called after modifying tables. Right now, the tables are either - ACL tables or grants tables. - */ - enum enum_reload_flag - { - RELOAD_NONE_F = 0UL, - RELOAD_GRANT_F = (1UL << 0), - RELOAD_ACCESS_F = (1UL << 1) - }; - - ulong m_reload_flags; - - void touching_table(char const* db, char const* table, ulong table_id); void transaction_end(THD*); void cleanup_context(THD *, bool); @@ -322,4 +310,9 @@ typedef struct st_relay_log_info time_t unsafe_to_stop_at; } RELAY_LOG_INFO; + +// Defined in rpl_rli.cc +int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname); + + #endif /* RPL_RLI_H */ diff --git a/sql/rpl_tblmap.cc b/sql/rpl_tblmap.cc index a0272b23ee8..97f0066233c 100644 --- a/sql/rpl_tblmap.cc +++ b/sql/rpl_tblmap.cc @@ -50,17 +50,17 @@ table_mapping::~table_mapping() st_table* table_mapping::get_table(ulong table_id) { DBUG_ENTER("table_mapping::get_table(ulong)"); - DBUG_PRINT("enter", ("table_id=%d", table_id)); + DBUG_PRINT("enter", ("table_id: %lu", table_id)); entry *e= find_entry(table_id); if (e) { - DBUG_PRINT("info", ("tid %d -> table %p (%s)", - table_id, e->table, + DBUG_PRINT("info", ("tid %lu -> table 0x%lx (%s)", + table_id, (long) e->table, MAYBE_TABLE_NAME(e->table))); DBUG_RETURN(e->table); } - DBUG_PRINT("info", ("tid %d is not mapped!", table_id)); + DBUG_PRINT("info", ("tid %lu is not mapped!", table_id)); DBUG_RETURN(NULL); } @@ -93,9 +93,9 @@ int table_mapping::expand() int table_mapping::set_table(ulong table_id, TABLE* table) { DBUG_ENTER("table_mapping::set_table(ulong,TABLE*)"); - DBUG_PRINT("enter", ("table_id=%d, table=%p (%s)", + DBUG_PRINT("enter", ("table_id: %lu table: 0x%lx (%s)", table_id, - table, MAYBE_TABLE_NAME(table))); + (long) table, MAYBE_TABLE_NAME(table))); entry *e= find_entry(table_id); if (e == 0) { @@ -111,8 +111,8 @@ int table_mapping::set_table(ulong table_id, TABLE* table) e->table= table; my_hash_insert(&m_table_ids,(byte *)e); - DBUG_PRINT("info", ("tid %d -> table %p (%s)", - table_id, e->table, + DBUG_PRINT("info", ("tid %lu -> table 0x%lx (%s)", + table_id, (long) e->table, MAYBE_TABLE_NAME(e->table))); DBUG_RETURN(0); // All OK } diff --git a/sql/rpl_utility.cc b/sql/rpl_utility.cc index c80b6dc3f69..4bed1343e55 100644 --- a/sql/rpl_utility.cc +++ b/sql/rpl_utility.cc @@ -25,7 +25,7 @@ field_length_from_packed(enum_field_types const field_type, switch (field_type) { case MYSQL_TYPE_DECIMAL: case MYSQL_TYPE_NEWDECIMAL: - length= ~0UL; + length= ~(uint32) 0; break; case MYSQL_TYPE_YEAR: case MYSQL_TYPE_TINY: @@ -71,7 +71,7 @@ field_length_from_packed(enum_field_types const field_type, break; break; case MYSQL_TYPE_BIT: - length= ~0UL; + length= ~(uint32) 0; break; default: /* This case should never be chosen */ @@ -85,7 +85,7 @@ field_length_from_packed(enum_field_types const field_type, case MYSQL_TYPE_SET: case MYSQL_TYPE_VAR_STRING: case MYSQL_TYPE_VARCHAR: - length= ~0UL; // NYI + length= ~(uint32) 0; // NYI break; case MYSQL_TYPE_TINY_BLOB: @@ -93,7 +93,7 @@ field_length_from_packed(enum_field_types const field_type, case MYSQL_TYPE_LONG_BLOB: case MYSQL_TYPE_BLOB: case MYSQL_TYPE_GEOMETRY: - length= ~0UL; // NYI + length= ~(uint32) 0; // NYI break; } @@ -131,7 +131,8 @@ table_def::compatible_with(RELAY_LOG_INFO *rli, TABLE *table) slave_print_msg(ERROR_LEVEL, rli, ER_BINLOG_ROW_WRONG_TABLE_DEF, "Table width mismatch - " "received %u columns, %s.%s has %u columns", - size(), tsh->db.str, tsh->table_name.str, tsh->fields); + (uint) size(), tsh->db.str, tsh->table_name.str, + tsh->fields); } for (uint col= 0 ; col < cols_to_check ; ++col) diff --git a/sql/set_var.cc b/sql/set_var.cc index 78916e50bc1..9f6499c7af1 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -3930,7 +3930,7 @@ sys_var_event_scheduler::update(THD *thd, set_var *var) DBUG_RETURN(TRUE); } - DBUG_PRINT("new_value", ("%lu", (bool)var->save_result.ulong_value)); + DBUG_PRINT("info", ("new_value: %d", (int) var->save_result.ulong_value)); Item_result var_type= var->value->result_type(); diff --git a/sql/slave.cc b/sql/slave.cc index 00d6d168fb8..4c5f0fc4764 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -31,13 +31,15 @@ #include "rpl_tblmap.h" +int queue_event(MASTER_INFO* mi,const char* buf,ulong event_len); + + #define MAX_SLAVE_RETRY_PAUSE 5 bool use_slave_mask = 0; MY_BITMAP slave_error_mask; typedef bool (*CHECK_KILLED_FUNC)(THD*,void*); -volatile bool slave_sql_running = 0, slave_io_running = 0; char* slave_load_tmpdir = 0; MASTER_INFO *active_mi= 0; my_bool replicate_same_server_id; @@ -59,7 +61,6 @@ 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 count_relay_log_space(RELAY_LOG_INFO* rli); static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type); static int safe_connect(THD* thd, MYSQL* mysql, MASTER_INFO* mi); static int safe_reconnect(THD* thd, MYSQL* mysql, MASTER_INFO* mi, @@ -202,223 +203,6 @@ err: /* - Open the given relay log - - SYNOPSIS - init_relay_log_pos() - rli Relay information (will be initialized) - log Name of relay log file to read from. NULL = First log - pos Position in relay log file - need_data_lock Set to 1 if this functions should do mutex locks - errmsg Store pointer to error message here - look_for_description_event - 1 if we should look for such an event. We only need - this when the SQL thread starts and opens an existing - relay log and has to execute it (possibly from an - offset >4); then we need to read the first event of - the relay log to be able to parse the events we have - to execute. - - DESCRIPTION - - Close old open relay log files. - - If we are using the same relay log as the running IO-thread, then set - rli->cur_log to point to the same IO_CACHE entry. - - If not, open the 'log' binary file. - - TODO - - check proper initialization of group_master_log_name/group_master_log_pos - - RETURN VALUES - 0 ok - 1 error. errmsg is set to point to the error message -*/ - -int init_relay_log_pos(RELAY_LOG_INFO* rli,const char* log, - ulonglong pos, bool need_data_lock, - const char** errmsg, - bool look_for_description_event) -{ - DBUG_ENTER("init_relay_log_pos"); - DBUG_PRINT("info", ("pos=%lu", pos)); - - *errmsg=0; - pthread_mutex_t *log_lock=rli->relay_log.get_log_lock(); - - if (need_data_lock) - pthread_mutex_lock(&rli->data_lock); - - /* - Slave threads are not the only users of init_relay_log_pos(). CHANGE MASTER - is, too, and init_slave() too; these 2 functions allocate a description - event in init_relay_log_pos, which is not freed by the terminating SQL slave - thread as that thread is not started by these functions. So we have to free - the description_event here, in case, so that there is no memory leak in - running, say, CHANGE MASTER. - */ - delete rli->relay_log.description_event_for_exec; - /* - By default the relay log is in binlog format 3 (4.0). - Even if format is 4, this will work enough to read the first event - (Format_desc) (remember that format 4 is just lenghtened compared to format - 3; format 3 is a prefix of format 4). - */ - rli->relay_log.description_event_for_exec= new - Format_description_log_event(3); - - pthread_mutex_lock(log_lock); - - /* Close log file and free buffers if it's already open */ - if (rli->cur_log_fd >= 0) - { - end_io_cache(&rli->cache_buf); - my_close(rli->cur_log_fd, MYF(MY_WME)); - rli->cur_log_fd = -1; - } - - rli->group_relay_log_pos = rli->event_relay_log_pos = pos; - - /* - Test to see if the previous run was with the skip of purging - If yes, we do not purge when we restart - */ - if (rli->relay_log.find_log_pos(&rli->linfo, NullS, 1)) - { - *errmsg="Could not find first log during relay log initialization"; - goto err; - } - - if (log && rli->relay_log.find_log_pos(&rli->linfo, log, 1)) - { - *errmsg="Could not find target log during relay log initialization"; - goto err; - } - strmake(rli->group_relay_log_name,rli->linfo.log_file_name, - sizeof(rli->group_relay_log_name)-1); - strmake(rli->event_relay_log_name,rli->linfo.log_file_name, - sizeof(rli->event_relay_log_name)-1); - if (rli->relay_log.is_active(rli->linfo.log_file_name)) - { - /* - The IO thread is using this log file. - In this case, we will use the same IO_CACHE pointer to - read data as the IO thread is using to write data. - */ - my_b_seek((rli->cur_log=rli->relay_log.get_log_file()), (off_t)0); - if (check_binlog_magic(rli->cur_log,errmsg)) - goto err; - rli->cur_log_old_open_count=rli->relay_log.get_open_count(); - } - else - { - /* - Open the relay log and set rli->cur_log to point at this one - */ - if ((rli->cur_log_fd=open_binlog(&rli->cache_buf, - rli->linfo.log_file_name,errmsg)) < 0) - goto err; - rli->cur_log = &rli->cache_buf; - } - /* - In all cases, check_binlog_magic() has been called so we're at offset 4 for - sure. - */ - if (pos > BIN_LOG_HEADER_SIZE) /* If pos<=4, we stay at 4 */ - { - Log_event* ev; - while (look_for_description_event) - { - /* - Read the possible Format_description_log_event; if position - was 4, no need, it will be read naturally. - */ - DBUG_PRINT("info",("looking for a Format_description_log_event")); - - if (my_b_tell(rli->cur_log) >= pos) - break; - - /* - Because of we have rli->data_lock and log_lock, we can safely read an - event - */ - if (!(ev=Log_event::read_log_event(rli->cur_log,0, - rli->relay_log.description_event_for_exec))) - { - DBUG_PRINT("info",("could not read event, rli->cur_log->error=%d", - rli->cur_log->error)); - if (rli->cur_log->error) /* not EOF */ - { - *errmsg= "I/O error reading event at position 4"; - goto err; - } - break; - } - else if (ev->get_type_code() == FORMAT_DESCRIPTION_EVENT) - { - DBUG_PRINT("info",("found Format_description_log_event")); - delete rli->relay_log.description_event_for_exec; - rli->relay_log.description_event_for_exec= (Format_description_log_event*) ev; - /* - As ev was returned by read_log_event, it has passed is_valid(), so - my_malloc() in ctor worked, no need to check again. - */ - /* - Ok, we found a Format_description event. But it is not sure that this - describes the whole relay log; indeed, one can have this sequence - (starting from position 4): - Format_desc (of slave) - Rotate (of master) - Format_desc (of master) - So the Format_desc which really describes the rest of the relay log - is the 3rd event (it can't be further than that, because we rotate - the relay log when we queue a Rotate event from the master). - But what describes the Rotate is the first Format_desc. - So what we do is: - go on searching for Format_description events, until you exceed the - position (argument 'pos') or until you find another event than Rotate - or Format_desc. - */ - } - else - { - DBUG_PRINT("info",("found event of another type=%d", - ev->get_type_code())); - look_for_description_event= (ev->get_type_code() == ROTATE_EVENT); - delete ev; - } - } - my_b_seek(rli->cur_log,(off_t)pos); -#ifndef DBUG_OFF - { - char llbuf1[22], llbuf2[22]; - DBUG_PRINT("info", ("my_b_tell(rli->cur_log)=%s rli->event_relay_log_pos=%s", - llstr(my_b_tell(rli->cur_log),llbuf1), - llstr(rli->event_relay_log_pos,llbuf2))); - } -#endif - - } - -err: - /* - If we don't purge, we can't honour relay_log_space_limit ; - silently discard it - */ - if (!relay_log_purge) - rli->log_space_limit= 0; - pthread_cond_broadcast(&rli->data_cond); - - pthread_mutex_unlock(log_lock); - - if (need_data_lock) - pthread_mutex_unlock(&rli->data_lock); - if (!rli->relay_log.description_event_for_exec->is_valid() && !*errmsg) - *errmsg= "Invalid Format_description log event; could be out of memory"; - - DBUG_RETURN ((*errmsg) ? 1 : 0); -} - - -/* Init function to set up array for errors that should be skipped for slave SYNOPSIS @@ -461,174 +245,6 @@ void init_slave_skip_errors(const char* arg) } -void st_relay_log_info::inc_group_relay_log_pos(ulonglong log_pos, - bool skip_lock) -{ - DBUG_ENTER("st_relay_log_info::inc_group_relay_log_pos"); - - if (!skip_lock) - pthread_mutex_lock(&data_lock); - inc_event_relay_log_pos(); - group_relay_log_pos= event_relay_log_pos; - strmake(group_relay_log_name,event_relay_log_name, - sizeof(group_relay_log_name)-1); - - notify_group_relay_log_name_update(); - - /* - If the slave does not support transactions and replicates a transaction, - users should not trust group_master_log_pos (which they can display with - SHOW SLAVE STATUS or read from relay-log.info), because to compute - group_master_log_pos the slave relies on log_pos stored in the master's - binlog, but if we are in a master's transaction these positions are always - the BEGIN's one (excepted for the COMMIT), so group_master_log_pos does - not advance as it should on the non-transactional slave (it advances by - big leaps, whereas it should advance by small leaps). - */ - /* - In 4.x we used the event's len to compute the positions here. This is - wrong if the event was 3.23/4.0 and has been converted to 5.0, because - then the event's len is not what is was in the master's binlog, so this - will make a wrong group_master_log_pos (yes it's a bug in 3.23->4.0 - replication: Exec_master_log_pos is wrong). Only way to solve this is to - have the original offset of the end of the event the relay log. This is - what we do in 5.0: log_pos has become "end_log_pos" (because the real use - of log_pos in 4.0 was to compute the end_log_pos; so better to store - end_log_pos instead of begin_log_pos. - If we had not done this fix here, the problem would also have appeared - when the slave and master are 5.0 but with different event length (for - example the slave is more recent than the master and features the event - UID). It would give false MASTER_POS_WAIT, false Exec_master_log_pos in - SHOW SLAVE STATUS, and so the user would do some CHANGE MASTER using this - value which would lead to badly broken replication. - Even the relay_log_pos will be corrupted in this case, because the len is - the relay log is not "val". - With the end_log_pos solution, we avoid computations involving lengthes. - */ - DBUG_PRINT("info", ("log_pos: %lu group_master_log_pos: %lu", - (long) log_pos, (long) group_master_log_pos)); - if (log_pos) // 3.23 binlogs don't have log_posx - { - group_master_log_pos= log_pos; - } - pthread_cond_broadcast(&data_cond); - if (!skip_lock) - pthread_mutex_unlock(&data_lock); - DBUG_VOID_RETURN; -} - - -void st_relay_log_info::close_temporary_tables() -{ - TABLE *table,*next; - DBUG_ENTER("st_relay_log_info::close_temporary_tables"); - - for (table=save_temporary_tables ; table ; table=next) - { - next=table->next; - /* - Don't ask for disk deletion. For now, anyway they will be deleted when - slave restarts, but it is a better intention to not delete them. - */ - DBUG_PRINT("info", ("table: %p", table)); - close_temporary(table, 1, 0); - } - save_temporary_tables= 0; - slave_open_temp_tables= 0; - DBUG_VOID_RETURN; -} - -/* - purge_relay_logs() - - NOTES - Assumes to have a run lock on rli and that no slave thread are running. -*/ - -int purge_relay_logs(RELAY_LOG_INFO* rli, THD *thd, bool just_reset, - const char** errmsg) -{ - int error=0; - DBUG_ENTER("purge_relay_logs"); - - /* - Even if rli->inited==0, we still try to empty rli->master_log_* variables. - Indeed, rli->inited==0 does not imply that they already are empty. - It could be that slave's info initialization partly succeeded : - for example if relay-log.info existed but *relay-bin*.* - have been manually removed, init_relay_log_info reads the old - relay-log.info and fills rli->master_log_*, then init_relay_log_info - checks for the existence of the relay log, this fails and - init_relay_log_info leaves rli->inited to 0. - In that pathological case, rli->master_log_pos* will be properly reinited - at the next START SLAVE (as RESET SLAVE or CHANGE - MASTER, the callers of purge_relay_logs, will delete bogus *.info files - or replace them with correct files), however if the user does SHOW SLAVE - STATUS before START SLAVE, he will see old, confusing rli->master_log_*. - In other words, we reinit rli->master_log_* for SHOW SLAVE STATUS - to display fine in any case. - */ - - rli->group_master_log_name[0]= 0; - rli->group_master_log_pos= 0; - - if (!rli->inited) - { - DBUG_PRINT("info", ("rli->inited == 0")); - DBUG_RETURN(0); - } - - DBUG_ASSERT(rli->slave_running == 0); - DBUG_ASSERT(rli->mi->slave_running == 0); - - rli->slave_skip_counter=0; - pthread_mutex_lock(&rli->data_lock); - - /* - we close the relay log fd possibly left open by the slave SQL thread, - to be able to delete it; the relay log fd possibly left open by the slave - I/O thread will be closed naturally in reset_logs() by the - close(LOG_CLOSE_TO_BE_OPENED) call - */ - if (rli->cur_log_fd >= 0) - { - end_io_cache(&rli->cache_buf); - my_close(rli->cur_log_fd, MYF(MY_WME)); - rli->cur_log_fd= -1; - } - - if (rli->relay_log.reset_logs(thd)) - { - *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"; - goto err; - } - if (!just_reset) - error= init_relay_log_pos(rli, rli->group_relay_log_name, - rli->group_relay_log_pos, - 0 /* do not need data lock */, errmsg, 0); - -err: -#ifndef DBUG_OFF - char buf[22]; -#endif - DBUG_PRINT("info",("log_space_total: %s",llstr(rli->log_space_total,buf))); - pthread_mutex_unlock(&rli->data_lock); - DBUG_RETURN(error); -} - - int terminate_slave_threads(MASTER_INFO* mi,int thread_mask,bool skip_lock) { DBUG_ENTER("terminate_slave_threads"); @@ -1023,7 +639,7 @@ const char *print_slave_db_safe(const char* db) DBUG_RETURN((db ? db : "")); } -static int init_strvar_from_file(char *var, int max_size, IO_CACHE *f, +int init_strvar_from_file(char *var, int max_size, IO_CACHE *f, const char *default_val) { uint length; @@ -1054,7 +670,7 @@ static int init_strvar_from_file(char *var, int max_size, IO_CACHE *f, } -static int init_intvar_from_file(int* var, IO_CACHE* f, int default_val) +int init_intvar_from_file(int* var, IO_CACHE* f, int default_val) { char buf[32]; DBUG_ENTER("init_intvar_from_file"); @@ -1456,261 +1072,6 @@ int fetch_master_table(THD *thd, const char *db_name, const char *table_name, } -void end_master_info(MASTER_INFO* mi) -{ - DBUG_ENTER("end_master_info"); - - if (!mi->inited) - DBUG_VOID_RETURN; - end_relay_log_info(&mi->rli); - if (mi->fd >= 0) - { - end_io_cache(&mi->file); - (void)my_close(mi->fd, MYF(MY_WME)); - mi->fd = -1; - } - mi->inited = 0; - - DBUG_VOID_RETURN; -} - - -static int init_relay_log_info(RELAY_LOG_INFO* rli, - const char* info_fname) -{ - char fname[FN_REFLEN+128]; - int info_fd; - const char* msg = 0; - int error = 0; - DBUG_ENTER("init_relay_log_info"); - DBUG_ASSERT(!rli->no_storage); // Don't init if there is no storage - - if (rli->inited) // Set if this function called - DBUG_RETURN(0); - fn_format(fname, info_fname, mysql_data_home, "", 4+32); - pthread_mutex_lock(&rli->data_lock); - info_fd = rli->info_fd; - rli->cur_log_fd = -1; - rli->slave_skip_counter=0; - rli->abort_pos_wait=0; - rli->log_space_limit= relay_log_space_limit; - rli->log_space_total= 0; - rli->tables_to_lock= 0; - rli->tables_to_lock_count= 0; - - /* - The relay log will now be opened, as a SEQ_READ_APPEND IO_CACHE. - Note that the I/O thread flushes it to disk after writing every - 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). - */ - { - char buf[FN_REFLEN]; - const char *ln; - static bool name_warning_sent= 0; - ln= rli->relay_log.generate_name(opt_relay_logname, "-relay-bin", - 1, buf); - /* We send the warning only at startup, not after every RESET SLAVE */ - if (!opt_relay_logname && !opt_relaylog_index_name && !name_warning_sent) - { - /* - User didn't give us info to name the relay log index file. - Picking `hostname`-relay-bin.index like we do, causes replication to - fail if this slave's hostname is changed later. So, we would like to - instead require a name. But as we don't want to break many existing - setups, we only give warning, not error. - */ - sql_print_warning("Neither --relay-log nor --relay-log-index were used;" - " so replication " - "may break when this MySQL server acts as a " - "slave and has his hostname changed!! Please " - "use '--relay-log=%s' to avoid this problem.", ln); - name_warning_sent= 1; - } - /* - 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) || - rli->relay_log.open(ln, LOG_BIN, 0, SEQ_READ_APPEND, 0, - (max_relay_log_size ? max_relay_log_size : - max_binlog_size), 1)) - { - pthread_mutex_unlock(&rli->data_lock); - sql_print_error("Failed in open_log() called from init_relay_log_info()"); - DBUG_RETURN(1); - } - } - - /* if file does not exist */ - if (access(fname,F_OK)) - { - /* - If someone removed the file from underneath our feet, just close - the old descriptor and re-create the old file - */ - if (info_fd >= 0) - my_close(info_fd, MYF(MY_WME)); - if ((info_fd = my_open(fname, O_CREAT|O_RDWR|O_BINARY, MYF(MY_WME))) < 0) - { - sql_print_error("Failed to create a new relay log info file (\ -file '%s', errno %d)", fname, my_errno); - msg= current_thd->net.last_error; - goto err; - } - if (init_io_cache(&rli->info_file, info_fd, IO_SIZE*2, READ_CACHE, 0L,0, - MYF(MY_WME))) - { - sql_print_error("Failed to create a cache on relay log info file '%s'", - fname); - msg= current_thd->net.last_error; - goto err; - } - - /* Init relay log with first entry in the relay index file */ - if (init_relay_log_pos(rli,NullS,BIN_LOG_HEADER_SIZE,0 /* no data lock */, - &msg, 0)) - { - sql_print_error("Failed to open the relay log 'FIRST' (relay_log_pos 4)"); - goto err; - } - rli->group_master_log_name[0]= 0; - rli->group_master_log_pos= 0; - rli->info_fd= info_fd; - } - else // file exists - { - if (info_fd >= 0) - reinit_io_cache(&rli->info_file, READ_CACHE, 0L,0,0); - else - { - int error=0; - if ((info_fd = my_open(fname, O_RDWR|O_BINARY, MYF(MY_WME))) < 0) - { - sql_print_error("\ -Failed to open the existing relay log info file '%s' (errno %d)", - fname, my_errno); - error= 1; - } - else if (init_io_cache(&rli->info_file, info_fd, - IO_SIZE*2, READ_CACHE, 0L, 0, MYF(MY_WME))) - { - sql_print_error("Failed to create a cache on relay log info file '%s'", - fname); - error= 1; - } - if (error) - { - if (info_fd >= 0) - my_close(info_fd, MYF(0)); - rli->info_fd= -1; - rli->relay_log.close(LOG_CLOSE_INDEX | LOG_CLOSE_STOP_EVENT); - pthread_mutex_unlock(&rli->data_lock); - DBUG_RETURN(1); - } - } - - rli->info_fd = info_fd; - int relay_log_pos, master_log_pos; - if (init_strvar_from_file(rli->group_relay_log_name, - sizeof(rli->group_relay_log_name), - &rli->info_file, "") || - init_intvar_from_file(&relay_log_pos, - &rli->info_file, BIN_LOG_HEADER_SIZE) || - init_strvar_from_file(rli->group_master_log_name, - sizeof(rli->group_master_log_name), - &rli->info_file, "") || - init_intvar_from_file(&master_log_pos, &rli->info_file, 0)) - { - msg="Error reading slave log configuration"; - goto err; - } - strmake(rli->event_relay_log_name,rli->group_relay_log_name, - sizeof(rli->event_relay_log_name)-1); - rli->group_relay_log_pos= rli->event_relay_log_pos= relay_log_pos; - rli->group_master_log_pos= master_log_pos; - - if (init_relay_log_pos(rli, - rli->group_relay_log_name, - rli->group_relay_log_pos, - 0 /* no data lock*/, - &msg, 0)) - { - char llbuf[22]; - sql_print_error("Failed to open the relay log '%s' (relay_log_pos %s)", - rli->group_relay_log_name, - llstr(rli->group_relay_log_pos, llbuf)); - goto err; - } - } - -#ifndef DBUG_OFF - { - char llbuf1[22], llbuf2[22]; - DBUG_PRINT("info", ("my_b_tell(rli->cur_log)=%s rli->event_relay_log_pos=%s", - llstr(my_b_tell(rli->cur_log),llbuf1), - llstr(rli->event_relay_log_pos,llbuf2))); - DBUG_ASSERT(rli->event_relay_log_pos >= BIN_LOG_HEADER_SIZE); - DBUG_ASSERT(my_b_tell(rli->cur_log) == rli->event_relay_log_pos); - } -#endif - - /* - Now change the cache from READ to WRITE - must do this - before flush_relay_log_info - */ - reinit_io_cache(&rli->info_file, WRITE_CACHE,0L,0,1); - if ((error= flush_relay_log_info(rli))) - sql_print_error("Failed to flush relay log info file"); - if (count_relay_log_space(rli)) - { - msg="Error counting relay log space"; - goto err; - } - rli->inited= 1; - pthread_mutex_unlock(&rli->data_lock); - DBUG_RETURN(error); - -err: - sql_print_error(msg); - end_io_cache(&rli->info_file); - if (info_fd >= 0) - my_close(info_fd, MYF(0)); - rli->info_fd= -1; - rli->relay_log.close(LOG_CLOSE_INDEX | LOG_CLOSE_STOP_EVENT); - pthread_mutex_unlock(&rli->data_lock); - DBUG_RETURN(1); -} - - -static inline int add_relay_log(RELAY_LOG_INFO* rli,LOG_INFO* linfo) -{ - MY_STAT s; - DBUG_ENTER("add_relay_log"); - if (!my_stat(linfo->log_file_name,&s,MYF(0))) - { - sql_print_error("log %s listed in the index, but failed to stat", - linfo->log_file_name); - DBUG_RETURN(1); - } - rli->log_space_total += s.st_size; -#ifndef DBUG_OFF - char buf[22]; - DBUG_PRINT("info",("log_space_total: %s", llstr(rli->log_space_total,buf))); -#endif - DBUG_RETURN(0); -} - - static bool wait_for_relay_log_space(RELAY_LOG_INFO* rli) { bool slave_killed=0; @@ -1733,31 +1094,6 @@ Waiting for the slave SQL thread to free enough relay log space"); } -static int count_relay_log_space(RELAY_LOG_INFO* rli) -{ - LOG_INFO linfo; - DBUG_ENTER("count_relay_log_space"); - rli->log_space_total= 0; - if (rli->relay_log.find_log_pos(&linfo, NullS, 1)) - { - sql_print_error("Could not find first log while counting relay log space"); - DBUG_RETURN(1); - } - do - { - if (add_relay_log(rli,&linfo)) - DBUG_RETURN(1); - } while (!rli->relay_log.find_next_log(&linfo, 1)); - /* - As we have counted everything, including what may have written in a - preceding write, we must reset bytes_written, or we may count some space - twice. - */ - rli->relay_log.reset_bytes_written(); - DBUG_RETURN(0); -} - - /* Builds a Rotate from the ignored events' info and writes it to relay log. @@ -1811,284 +1147,6 @@ static void write_ignored_events_info_to_relay_log(THD *thd, MASTER_INFO *mi) } -void init_master_info_with_options(MASTER_INFO* mi) -{ - DBUG_ENTER("init_master_info_with_options"); - - mi->master_log_name[0] = 0; - mi->master_log_pos = BIN_LOG_HEADER_SIZE; // skip magic number - - if (master_host) - strmake(mi->host, master_host, sizeof(mi->host) - 1); - if (master_user) - strmake(mi->user, master_user, sizeof(mi->user) - 1); - if (master_password) - strmake(mi->password, master_password, MAX_PASSWORD_LENGTH); - mi->port = master_port; - mi->connect_retry = master_connect_retry; - - mi->ssl= master_ssl; - if (master_ssl_ca) - strmake(mi->ssl_ca, master_ssl_ca, sizeof(mi->ssl_ca)-1); - if (master_ssl_capath) - strmake(mi->ssl_capath, master_ssl_capath, sizeof(mi->ssl_capath)-1); - if (master_ssl_cert) - strmake(mi->ssl_cert, master_ssl_cert, sizeof(mi->ssl_cert)-1); - if (master_ssl_cipher) - strmake(mi->ssl_cipher, master_ssl_cipher, sizeof(mi->ssl_cipher)-1); - if (master_ssl_key) - strmake(mi->ssl_key, master_ssl_key, sizeof(mi->ssl_key)-1); - DBUG_VOID_RETURN; -} - -void clear_slave_error(RELAY_LOG_INFO* rli) -{ - DBUG_ENTER("clear_slave_error"); - - /* Clear the errors displayed by SHOW SLAVE STATUS */ - rli->last_slave_error[0]= 0; - rli->last_slave_errno= 0; - DBUG_VOID_RETURN; -} - -/* - Reset UNTIL condition for RELAY_LOG_INFO - SYNOPSYS - clear_until_condition() - rli - RELAY_LOG_INFO structure where UNTIL condition should be reset - */ -void clear_until_condition(RELAY_LOG_INFO* rli) -{ - DBUG_ENTER("clear_until_condition"); - - rli->until_condition= RELAY_LOG_INFO::UNTIL_NONE; - rli->until_log_name[0]= 0; - rli->until_log_pos= 0; - DBUG_VOID_RETURN; -} - - -#define LINES_IN_MASTER_INFO_WITH_SSL 14 - - -int init_master_info(MASTER_INFO* mi, const char* master_info_fname, - const char* slave_info_fname, - bool abort_if_no_master_info_file, - int thread_mask) -{ - int fd,error; - char fname[FN_REFLEN+128]; - DBUG_ENTER("init_master_info"); - - if (mi->inited) - { - /* - We have to reset read position of relay-log-bin as we may have - already been reading from 'hotlog' when the slave was stopped - last time. If this case pos_in_file would be set and we would - get a crash when trying to read the signature for the binary - relay log. - - We only rewind the read position if we are starting the SQL - thread. The handle_slave_sql thread assumes that the read - position is at the beginning of the file, and will read the - "signature" and then fast-forward to the last position read. - */ - if (thread_mask & SLAVE_SQL) - { - my_b_seek(mi->rli.cur_log, (my_off_t) 0); - } - DBUG_RETURN(0); - } - - mi->mysql=0; - mi->file_id=1; - fn_format(fname, master_info_fname, mysql_data_home, "", 4+32); - - /* - We need a mutex while we are changing master info parameters to - keep other threads from reading bogus info - */ - - pthread_mutex_lock(&mi->data_lock); - fd = mi->fd; - - /* does master.info exist ? */ - - if (access(fname,F_OK)) - { - if (abort_if_no_master_info_file) - { - pthread_mutex_unlock(&mi->data_lock); - DBUG_RETURN(0); - } - /* - if someone removed the file from underneath our feet, just close - the old descriptor and re-create the old file - */ - if (fd >= 0) - my_close(fd, MYF(MY_WME)); - if ((fd = my_open(fname, O_CREAT|O_RDWR|O_BINARY, MYF(MY_WME))) < 0 ) - { - sql_print_error("Failed to create a new master info file (\ -file '%s', errno %d)", fname, my_errno); - goto err; - } - if (init_io_cache(&mi->file, fd, IO_SIZE*2, READ_CACHE, 0L,0, - MYF(MY_WME))) - { - sql_print_error("Failed to create a cache on master info file (\ -file '%s')", fname); - goto err; - } - - mi->fd = fd; - init_master_info_with_options(mi); - - } - else // file exists - { - if (fd >= 0) - reinit_io_cache(&mi->file, READ_CACHE, 0L,0,0); - else - { - if ((fd = my_open(fname, O_RDWR|O_BINARY, MYF(MY_WME))) < 0 ) - { - sql_print_error("Failed to open the existing master info file (\ -file '%s', errno %d)", fname, my_errno); - goto err; - } - if (init_io_cache(&mi->file, fd, IO_SIZE*2, READ_CACHE, 0L, - 0, MYF(MY_WME))) - { - sql_print_error("Failed to create a cache on master info file (\ -file '%s')", fname); - goto err; - } - } - - mi->fd = fd; - int port, connect_retry, master_log_pos, ssl= 0, lines; - char *first_non_digit; - - /* - Starting from 4.1.x master.info has new format. Now its - first line contains number of lines in file. By reading this - number we will be always distinguish to which version our - master.info corresponds to. We can't simply count lines in - file since versions before 4.1.x could generate files with more - lines than needed. - If first line doesn't contain a number or contain number less than - 14 then such file is treated like file from pre 4.1.1 version. - There is no ambiguity when reading an old master.info, as before - 4.1.1, the first line contained the binlog's name, which is either - empty or has an extension (contains a '.'), so can't be confused - with an integer. - - So we're just reading first line and trying to figure which version - is this. - */ - - /* - The first row is temporarily stored in mi->master_log_name, - if it is line count and not binlog name (new format) it will be - overwritten by the second row later. - */ - if (init_strvar_from_file(mi->master_log_name, - sizeof(mi->master_log_name), &mi->file, - "")) - goto errwithmsg; - - lines= strtoul(mi->master_log_name, &first_non_digit, 10); - - if (mi->master_log_name[0]!='\0' && - *first_non_digit=='\0' && lines >= LINES_IN_MASTER_INFO_WITH_SSL) - { // Seems to be new format - if (init_strvar_from_file(mi->master_log_name, - sizeof(mi->master_log_name), &mi->file, "")) - goto errwithmsg; - } - else - lines= 7; - - if (init_intvar_from_file(&master_log_pos, &mi->file, 4) || - init_strvar_from_file(mi->host, sizeof(mi->host), &mi->file, - master_host) || - init_strvar_from_file(mi->user, sizeof(mi->user), &mi->file, - master_user) || - init_strvar_from_file(mi->password, SCRAMBLED_PASSWORD_CHAR_LENGTH+1, - &mi->file, master_password) || - init_intvar_from_file(&port, &mi->file, master_port) || - init_intvar_from_file(&connect_retry, &mi->file, - master_connect_retry)) - goto errwithmsg; - - /* - If file has ssl part use it even if we have server without - SSL support. But these option will be ignored later when - slave will try connect to master, so in this case warning - is printed. - */ - if (lines >= LINES_IN_MASTER_INFO_WITH_SSL && - (init_intvar_from_file(&ssl, &mi->file, master_ssl) || - init_strvar_from_file(mi->ssl_ca, sizeof(mi->ssl_ca), - &mi->file, master_ssl_ca) || - init_strvar_from_file(mi->ssl_capath, sizeof(mi->ssl_capath), - &mi->file, master_ssl_capath) || - init_strvar_from_file(mi->ssl_cert, sizeof(mi->ssl_cert), - &mi->file, master_ssl_cert) || - init_strvar_from_file(mi->ssl_cipher, sizeof(mi->ssl_cipher), - &mi->file, master_ssl_cipher) || - init_strvar_from_file(mi->ssl_key, sizeof(mi->ssl_key), - &mi->file, master_ssl_key))) - goto errwithmsg; -#ifndef HAVE_OPENSSL - if (ssl) - sql_print_warning("SSL information in the master info file " - "('%s') are ignored because this MySQL slave was compiled " - "without SSL support.", fname); -#endif /* HAVE_OPENSSL */ - - /* - This has to be handled here as init_intvar_from_file can't handle - my_off_t types - */ - mi->master_log_pos= (my_off_t) master_log_pos; - mi->port= (uint) port; - mi->connect_retry= (uint) connect_retry; - mi->ssl= (my_bool) ssl; - } - DBUG_PRINT("master_info",("log_file_name: %s position: %ld", - mi->master_log_name, - (ulong) mi->master_log_pos)); - - mi->rli.mi = mi; - if (init_relay_log_info(&mi->rli, slave_info_fname)) - goto err; - - mi->inited = 1; - // now change cache READ -> WRITE - must do this before flush_master_info - reinit_io_cache(&mi->file, WRITE_CACHE, 0L, 0, 1); - if ((error=test(flush_master_info(mi, 1)))) - sql_print_error("Failed to flush master info file"); - pthread_mutex_unlock(&mi->data_lock); - DBUG_RETURN(error); - -errwithmsg: - sql_print_error("Error reading master configuration"); - -err: - if (fd >= 0) - { - my_close(fd, MYF(0)); - end_io_cache(&mi->file); - } - mi->fd= -1; - pthread_mutex_unlock(&mi->data_lock); - DBUG_RETURN(1); -} - - int register_slave_on_master(MYSQL* mysql) { char buf[1024], *pos= buf; @@ -2307,313 +1365,6 @@ bool show_master_info(THD* thd, MASTER_INFO* mi) DBUG_RETURN(FALSE); } -/* - RETURN - 2 - flush relay log failed - 1 - flush master info failed - 0 - all ok -*/ -int flush_master_info(MASTER_INFO* mi, bool flush_relay_log_cache) -{ - IO_CACHE* file = &mi->file; - char lbuf[22]; - DBUG_ENTER("flush_master_info"); - DBUG_PRINT("enter",("master_pos: %ld", (long) mi->master_log_pos)); - - /* - Flush the relay log to disk. If we don't do it, then the relay log while - have some part (its last kilobytes) in memory only, so if the slave server - dies now, with, say, from master's position 100 to 150 in memory only (not - on disk), and with position 150 in master.info, then when the slave - restarts, the I/O thread will fetch binlogs from 150, so in the relay log - we will have "[0, 100] U [150, infinity[" and nobody will notice it, so the - SQL thread will jump from 100 to 150, and replication will silently break. - - When we come to this place in code, relay log may or not be initialized; - the caller is responsible for setting 'flush_relay_log_cache' accordingly. - */ - if (flush_relay_log_cache && - flush_io_cache(mi->rli.relay_log.get_log_file())) - DBUG_RETURN(2); - - /* - We flushed the relay log BEFORE the master.info file, because if we crash - now, we will get a duplicate event in the relay log at restart. If we - flushed in the other order, we would get a hole in the relay log. - And duplicate is better than hole (with a duplicate, in later versions we - can add detection and scrap one event; with a hole there's nothing we can - do). - */ - - /* - In certain cases this code may create master.info files that seems - corrupted, because of extra lines filled with garbage in the end - file (this happens if new contents take less space than previous - contents of file). But because of number of lines in the first line - of file we don't care about this garbage. - */ - - my_b_seek(file, 0L); - my_b_printf(file, "%u\n%s\n%s\n%s\n%s\n%s\n%d\n%d\n%d\n%s\n%s\n%s\n%s\n%s\n", - LINES_IN_MASTER_INFO_WITH_SSL, - mi->master_log_name, llstr(mi->master_log_pos, lbuf), - mi->host, mi->user, - mi->password, mi->port, mi->connect_retry, - (int)(mi->ssl), mi->ssl_ca, mi->ssl_capath, mi->ssl_cert, - mi->ssl_cipher, mi->ssl_key); - DBUG_RETURN(-flush_io_cache(file)); -} - - -st_relay_log_info::st_relay_log_info() - :no_storage(FALSE), info_fd(-1), cur_log_fd(-1), save_temporary_tables(0), - cur_log_old_open_count(0), group_master_log_pos(0), log_space_total(0), - ignore_log_space_limit(0), last_master_timestamp(0), slave_skip_counter(0), - abort_pos_wait(0), slave_run_id(0), sql_thd(0), last_slave_errno(0), - inited(0), abort_slave(0), slave_running(0), until_condition(UNTIL_NONE), - until_log_pos(0), retried_trans(0), - tables_to_lock(0), tables_to_lock_count(0), - m_reload_flags(RELOAD_NONE_F), - unsafe_to_stop_at(0) -{ - DBUG_ENTER("st_relay_log_info::st_relay_log_info"); - - group_relay_log_name[0]= event_relay_log_name[0]= - group_master_log_name[0]= 0; - last_slave_error[0]= until_log_name[0]= ign_master_log_name_end[0]= 0; - bzero((char*) &info_file, sizeof(info_file)); - bzero((char*) &cache_buf, sizeof(cache_buf)); - cached_charset_invalidate(); - pthread_mutex_init(&run_lock, MY_MUTEX_INIT_FAST); - pthread_mutex_init(&data_lock, MY_MUTEX_INIT_FAST); - pthread_mutex_init(&log_space_lock, MY_MUTEX_INIT_FAST); - pthread_cond_init(&data_cond, NULL); - pthread_cond_init(&start_cond, NULL); - pthread_cond_init(&stop_cond, NULL); - pthread_cond_init(&log_space_cond, NULL); - relay_log.init_pthread_objects(); - DBUG_VOID_RETURN; -} - - -st_relay_log_info::~st_relay_log_info() -{ - DBUG_ENTER("st_relay_log_info::~st_relay_log_info"); - - pthread_mutex_destroy(&run_lock); - pthread_mutex_destroy(&data_lock); - pthread_mutex_destroy(&log_space_lock); - pthread_cond_destroy(&data_cond); - pthread_cond_destroy(&start_cond); - pthread_cond_destroy(&stop_cond); - pthread_cond_destroy(&log_space_cond); - relay_log.cleanup(); - DBUG_VOID_RETURN; -} - -/* - Waits until the SQL thread reaches (has executed up to) the - log/position or timed out. - - SYNOPSIS - wait_for_pos() - thd client thread that sent SELECT MASTER_POS_WAIT - log_name log name to wait for - log_pos position to wait for - timeout timeout in seconds before giving up waiting - - NOTES - timeout is longlong whereas it should be ulong ; but this is - to catch if the user submitted a negative timeout. - - RETURN VALUES - -2 improper arguments (log_pos<0) - or slave not running, or master info changed - during the function's execution, - or client thread killed. -2 is translated to NULL by caller - -1 timed out - >=0 number of log events the function had to wait - before reaching the desired log/position - */ - -int st_relay_log_info::wait_for_pos(THD* thd, String* log_name, - longlong log_pos, - longlong timeout) -{ - int event_count = 0; - ulong init_abort_pos_wait; - int error=0; - struct timespec abstime; // for timeout checking - const char *msg; - DBUG_ENTER("st_relay_log_info::wait_for_pos"); - - if (!inited) - DBUG_RETURN(-1); - - DBUG_PRINT("enter",("log_name: '%s' log_pos: %lu timeout: %lu", - log_name->c_ptr(), (ulong) log_pos, (ulong) timeout)); - - set_timespec(abstime,timeout); - pthread_mutex_lock(&data_lock); - msg= thd->enter_cond(&data_cond, &data_lock, - "Waiting for the slave SQL thread to " - "advance position"); - /* - This function will abort when it notices that some CHANGE MASTER or - RESET MASTER has changed the master info. - To catch this, these commands modify abort_pos_wait ; We just monitor - abort_pos_wait and see if it has changed. - Why do we have this mechanism instead of simply monitoring slave_running - in the loop (we do this too), as CHANGE MASTER/RESET SLAVE require that - the SQL thread be stopped? - This is becasue if someones does: - STOP SLAVE;CHANGE MASTER/RESET SLAVE; START SLAVE; - the change may happen very quickly and we may not notice that - slave_running briefly switches between 1/0/1. - */ - init_abort_pos_wait= abort_pos_wait; - - /* - We'll need to - handle all possible log names comparisons (e.g. 999 vs 1000). - We use ulong for string->number conversion ; this is no - stronger limitation than in find_uniq_filename in sql/log.cc - */ - ulong log_name_extension; - char log_name_tmp[FN_REFLEN]; //make a char[] from String - - strmake(log_name_tmp, log_name->ptr(), min(log_name->length(), FN_REFLEN-1)); - - char *p= fn_ext(log_name_tmp); - char *p_end; - if (!*p || log_pos<0) - { - error= -2; //means improper arguments - goto err; - } - // Convert 0-3 to 4 - log_pos= max(log_pos, BIN_LOG_HEADER_SIZE); - /* p points to '.' */ - log_name_extension= strtoul(++p, &p_end, 10); - /* - p_end points to the first invalid character. - If it equals to p, no digits were found, error. - If it contains '\0' it means conversion went ok. - */ - if (p_end==p || *p_end) - { - error= -2; - goto err; - } - - /* The "compare and wait" main loop */ - while (!thd->killed && - init_abort_pos_wait == abort_pos_wait && - slave_running) - { - bool pos_reached; - int cmp_result= 0; - - DBUG_PRINT("info", - ("init_abort_pos_wait: %ld abort_pos_wait: %ld", - init_abort_pos_wait, abort_pos_wait)); - DBUG_PRINT("info",("group_master_log_name: '%s' pos: %lu", - group_master_log_name, (ulong) group_master_log_pos)); - - /* - group_master_log_name can be "", if we are just after a fresh - replication start or after a CHANGE MASTER TO MASTER_HOST/PORT - (before we have executed one Rotate event from the master) or - (rare) if the user is doing a weird slave setup (see next - paragraph). If group_master_log_name is "", we assume we don't - have enough info to do the comparison yet, so we just wait until - more data. In this case master_log_pos is always 0 except if - somebody (wrongly) sets this slave to be a slave of itself - without using --replicate-same-server-id (an unsupported - configuration which does nothing), then group_master_log_pos - will grow and group_master_log_name will stay "". - */ - if (*group_master_log_name) - { - char *basename= (group_master_log_name + - dirname_length(group_master_log_name)); - /* - First compare the parts before the extension. - Find the dot in the master's log basename, - and protect against user's input error : - if the names do not match up to '.' included, return error - */ - char *q= (char*)(fn_ext(basename)+1); - if (strncmp(basename, log_name_tmp, (int)(q-basename))) - { - error= -2; - break; - } - // Now compare extensions. - char *q_end; - ulong group_master_log_name_extension= strtoul(q, &q_end, 10); - if (group_master_log_name_extension < log_name_extension) - cmp_result= -1 ; - else - cmp_result= (group_master_log_name_extension > log_name_extension) ? 1 : 0 ; - - pos_reached= ((!cmp_result && group_master_log_pos >= (ulonglong)log_pos) || - cmp_result > 0); - if (pos_reached || thd->killed) - break; - } - - //wait for master update, with optional timeout. - - DBUG_PRINT("info",("Waiting for master update")); - /* - We are going to pthread_cond_(timed)wait(); if the SQL thread stops it - will wake us up. - */ - if (timeout > 0) - { - /* - Note that pthread_cond_timedwait checks for the timeout - before for the condition ; i.e. it returns ETIMEDOUT - if the system time equals or exceeds the time specified by abstime - before the condition variable is signaled or broadcast, _or_ if - the absolute time specified by abstime has already passed at the time - of the call. - For that reason, pthread_cond_timedwait will do the "timeoutting" job - even if its condition is always immediately signaled (case of a loaded - master). - */ - error=pthread_cond_timedwait(&data_cond, &data_lock, &abstime); - } - else - pthread_cond_wait(&data_cond, &data_lock); - DBUG_PRINT("info",("Got signal of master update or timed out")); - if (error == ETIMEDOUT || error == ETIME) - { - error= -1; - break; - } - error=0; - event_count++; - DBUG_PRINT("info",("Testing if killed or SQL thread not running")); - } - -err: - thd->exit_cond(msg); - DBUG_PRINT("exit",("killed: %d abort: %d slave_running: %d \ -improper_arguments: %d timed_out: %d", - thd->killed_errno(), - (int) (init_abort_pos_wait != abort_pos_wait), - (int) slave_running, - (int) (error == -2), - (int) (error == -1))); - if (thd->killed || init_abort_pos_wait != abort_pos_wait || - !slave_running) - { - error= -2; - } - DBUG_RETURN( error ? error : event_count ); -} void set_slave_thread_options(THD* thd) { @@ -2663,6 +1414,13 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type) SYSTEM_THREAD_SLAVE_SQL : SYSTEM_THREAD_SLAVE_IO; thd->security_ctx->skip_grants(); my_net_init(&thd->net, 0); +/* + Adding MAX_LOG_EVENT_HEADER_LEN to the max_allowed_packet on all + 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->net.read_timeout = slave_net_timeout; thd->slave_thread = 1; set_slave_thread_options(thd); @@ -2851,7 +1609,7 @@ static ulong read_event(MYSQL* mysql, MASTER_INFO *mi, bool* suppress_warnings) DBUG_RETURN(packet_error); } - DBUG_PRINT("info",( "len=%u, net->read_pos[4] = %d\n", + DBUG_PRINT("exit", ("len: %lu net->read_pos[4]: %d", len, mysql->net.read_pos[4])); DBUG_RETURN(len - 1); } @@ -2872,119 +1630,6 @@ int check_expected_error(THD* thd, RELAY_LOG_INFO* rli, int expected_error) } } -/* - Check if condition stated in UNTIL clause of START SLAVE is reached. - SYNOPSYS - st_relay_log_info::is_until_satisfied() - DESCRIPTION - Checks if UNTIL condition is reached. Uses caching result of last - comparison of current log file name and target log file name. So cached - value should be invalidated if current log file name changes - (see st_relay_log_info::notify_... functions). - - This caching is needed to avoid of expensive string comparisons and - strtol() conversions needed for log names comparison. We don't need to - compare them each time this function is called, we only need to do this - when current log name changes. If we have UNTIL_MASTER_POS condition we - need to do this only after Rotate_log_event::exec_event() (which is - rare, so caching gives real benifit), and if we have UNTIL_RELAY_POS - condition then we should invalidate cached comarison value after - inc_group_relay_log_pos() which called for each group of events (so we - have some benefit if we have something like queries that use - autoincrement or if we have transactions). - - Should be called ONLY if until_condition != UNTIL_NONE ! - RETURN VALUE - true - condition met or error happened (condition seems to have - bad log file name) - false - condition not met -*/ - -bool st_relay_log_info::is_until_satisfied() -{ - const char *log_name; - ulonglong log_pos; - DBUG_ENTER("st_relay_log_info::is_until_satisfied"); - - DBUG_ASSERT(until_condition != UNTIL_NONE); - - if (until_condition == UNTIL_MASTER_POS) - { - log_name= group_master_log_name; - log_pos= group_master_log_pos; - } - else - { /* until_condition == UNTIL_RELAY_POS */ - log_name= group_relay_log_name; - log_pos= group_relay_log_pos; - } - - if (until_log_names_cmp_result == UNTIL_LOG_NAMES_CMP_UNKNOWN) - { - /* - We have no cached comparison results so we should compare log names - and cache result. - If we are after RESET SLAVE, and the SQL slave thread has not processed - any event yet, it could be that group_master_log_name is "". In that case, - just wait for more events (as there is no sensible comparison to do). - */ - - if (*log_name) - { - const char *basename= log_name + dirname_length(log_name); - - const char *q= (const char*)(fn_ext(basename)+1); - if (strncmp(basename, until_log_name, (int)(q-basename)) == 0) - { - /* Now compare extensions. */ - char *q_end; - ulong log_name_extension= strtoul(q, &q_end, 10); - if (log_name_extension < until_log_name_extension) - until_log_names_cmp_result= UNTIL_LOG_NAMES_CMP_LESS; - else - until_log_names_cmp_result= - (log_name_extension > until_log_name_extension) ? - UNTIL_LOG_NAMES_CMP_GREATER : UNTIL_LOG_NAMES_CMP_EQUAL ; - } - else - { - /* Probably error so we aborting */ - sql_print_error("Slave SQL thread is stopped because UNTIL " - "condition is bad."); - DBUG_RETURN(TRUE); - } - } - else - DBUG_RETURN(until_log_pos == 0); - } - - DBUG_RETURN(((until_log_names_cmp_result == UNTIL_LOG_NAMES_CMP_EQUAL && - log_pos >= until_log_pos) || - until_log_names_cmp_result == UNTIL_LOG_NAMES_CMP_GREATER)); -} - - -void st_relay_log_info::cached_charset_invalidate() -{ - DBUG_ENTER("st_relay_log_info::cached_charset_invalidate"); - - /* Full of zeroes means uninitialized. */ - bzero(cached_charset, sizeof(cached_charset)); - DBUG_VOID_RETURN; -} - - -bool st_relay_log_info::cached_charset_compare(char *charset) -{ - DBUG_ENTER("st_relay_log_info::cached_charset_compare"); - - if (bcmp(cached_charset, charset, sizeof(cached_charset))) - { - memcpy(cached_charset, charset, sizeof(cached_charset)); - DBUG_RETURN(1); - } - DBUG_RETURN(0); -} /* Check if the current error is of temporary nature of not. @@ -3155,7 +1800,7 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli) ev->when = time(NULL); ev->thd = thd; // because up to this point, ev->thd == 0 exec_res = ev->exec_event(rli); - DBUG_PRINT("info", ("exec_event result = %d", exec_res)); + DBUG_PRINT("info", ("exec_event result: %d", exec_res)); DBUG_ASSERT(rli->sql_thd==thd); /* Format_description_log_event should not be deleted because it will be @@ -3176,6 +1821,8 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli) We were in a transaction which has been rolled back because of a temporary error; let's seek back to BEGIN log event and retry it all again. + Note, if lock wait timeout (innodb_lock_wait_timeout exceeded) + there is no rollback since 5.0.13 (ref: manual). We have to not only seek but also a) init_master_info(), to seek back to hot relay log's start for later (for when we will come back to this hot log after re-processing the @@ -3303,11 +1950,19 @@ pthread_handler_t handle_slave_io(void *arg) thd->proc_info = "Connecting to master"; // we can get killed during safe_connect if (!safe_connect(thd, mysql, mi)) - sql_print_information("Slave I/O thread: connected to master '%s@%s:%d',\ - replication started in log '%s' at position %s", mi->user, - mi->host, mi->port, - IO_RPL_LOG_NAME, - llstr(mi->master_log_pos,llbuff)); + { + sql_print_information("Slave I/O thread: connected to master '%s@%s:%d'," + "replication started in log '%s' at position %s", + mi->user, mi->host, mi->port, + IO_RPL_LOG_NAME, + llstr(mi->master_log_pos,llbuff)); + /* + Adding MAX_LOG_EVENT_HEADER_LEN to the max_packet_size on the I/O + thread, since a replication event can become this much larger than + the corresponding packet (query) sent from client to master. + */ + mysql->net.max_packet_size= thd->net.max_packet_size+= MAX_LOG_EVENT_HEADER; + } else { sql_print_information("Slave I/O thread killed while connecting to master"); @@ -3632,7 +2287,7 @@ pthread_handler_t handle_slave_sql(void *arg) now. But the master timestamp is reset by RESET SLAVE & CHANGE MASTER. */ - clear_slave_error(rli); + rli->clear_slave_error(); //tell the I/O thread to take relay_log_space_limit into account from now on pthread_mutex_lock(&rli->log_space_lock); @@ -3949,7 +2604,7 @@ static int process_io_rotate(MASTER_INFO *mi, Rotate_log_event *rev) /* Safe copy as 'rev' has been "sanitized" in Rotate_log_event's ctor */ memcpy(mi->master_log_name, rev->new_log_ident, rev->ident_len+1); mi->master_log_pos= rev->pos; - DBUG_PRINT("info", ("master_log_pos: '%s' %d", + DBUG_PRINT("info", ("master_log_pos: '%s' %lu", mi->master_log_name, (ulong) mi->master_log_pos)); #ifndef DBUG_OFF /* @@ -4066,7 +2721,7 @@ static int queue_binlog_ver_1_event(MASTER_INFO *mi, const char *buf, int error = process_io_create_file(mi,(Create_file_log_event*)ev); delete ev; mi->master_log_pos += inc_pos; - DBUG_PRINT("info", ("master_log_pos: %d", (ulong) mi->master_log_pos)); + DBUG_PRINT("info", ("master_log_pos: %lu", (ulong) mi->master_log_pos)); pthread_mutex_unlock(&mi->data_lock); my_free((char*)tmp_buf, MYF(0)); DBUG_RETURN(error); @@ -4093,7 +2748,7 @@ static int queue_binlog_ver_1_event(MASTER_INFO *mi, const char *buf, } delete ev; mi->master_log_pos+= inc_pos; - DBUG_PRINT("info", ("master_log_pos: %d", (ulong) mi->master_log_pos)); + DBUG_PRINT("info", ("master_log_pos: %lu", (ulong) mi->master_log_pos)); pthread_mutex_unlock(&mi->data_lock); DBUG_RETURN(0); } @@ -4149,7 +2804,7 @@ static int queue_binlog_ver_3_event(MASTER_INFO *mi, const char *buf, delete ev; mi->master_log_pos+= inc_pos; err: - DBUG_PRINT("info", ("master_log_pos: %d", (ulong) mi->master_log_pos)); + DBUG_PRINT("info", ("master_log_pos: %lu", (ulong) mi->master_log_pos)); pthread_mutex_unlock(&mi->data_lock); DBUG_RETURN(0); } @@ -4322,7 +2977,8 @@ int queue_event(MASTER_INFO* mi,const char* buf, ulong event_len) rli->ign_master_log_pos_end= mi->master_log_pos; } rli->relay_log.signal_update(); // the slave SQL thread needs to re-check - DBUG_PRINT("info", ("master_log_pos: %d, event originating from the same server, ignored", (ulong) mi->master_log_pos)); + DBUG_PRINT("info", ("master_log_pos: %lu, event originating from the same server, ignored", + (ulong) mi->master_log_pos)); } else { @@ -4330,7 +2986,7 @@ int queue_event(MASTER_INFO* mi,const char* buf, ulong event_len) if (likely(!(rli->relay_log.appendv(buf,event_len,0)))) { mi->master_log_pos+= inc_pos; - DBUG_PRINT("info", ("master_log_pos: %d", (ulong) mi->master_log_pos)); + DBUG_PRINT("info", ("master_log_pos: %lu", (ulong) mi->master_log_pos)); rli->relay_log.harvest_bytes_written(&rli->log_space_total); } else @@ -4451,11 +3107,11 @@ static int connect_to_master(THD* thd, MYSQL* mysql, MASTER_INFO* mi, { last_errno=mysql_errno(mysql); suppress_warnings= 0; - sql_print_error("Slave I/O thread: error %s to master \ -'%s@%s:%d': \ + sql_print_error("Slave I/O thread: error %s to master " + "'%s@%s:%d': \ Error: '%s' errno: %d retry-time: %d retries: %lu", (reconnect ? "reconnecting" : "connecting"), - mi->user,mi->host,mi->port, + mi->user, mi->host, mi->port, mysql_error(mysql), last_errno, mi->connect_retry, master_retry_count); @@ -4990,121 +3646,6 @@ end: DBUG_VOID_RETURN; } -/* - Some system tables needed to be re-read by the MySQL server after it has - updated them; in statement-based replication, the GRANT and other commands - are sent verbatim to the slave which then reloads; in row-based replication, - changes to these tables are done through ordinary Rows binlog events, so - master must add some flag for the slave to know it has to reload the tables. -*/ -struct st_reload_entry -{ - char const *table; - st_relay_log_info::enum_reload_flag flag; -}; - -/* - Sorted array of table names, please keep it sorted since we are - using bsearch() on it below. - */ -static st_reload_entry s_mysql_tables[] = -{ - { "columns_priv", st_relay_log_info::RELOAD_GRANT_F }, - { "db", st_relay_log_info::RELOAD_ACCESS_F }, - { "host", st_relay_log_info::RELOAD_ACCESS_F }, - { "procs_priv", st_relay_log_info::RELOAD_GRANT_F }, - { "tables_priv", st_relay_log_info::RELOAD_GRANT_F }, - { "user", st_relay_log_info::RELOAD_ACCESS_F } -}; - -static const my_size_t s_mysql_tables_size = - sizeof(s_mysql_tables)/sizeof(*s_mysql_tables); - -static int reload_entry_compare(const void *lhs, const void *rhs) -{ - const char *lstr = static_cast<const char *>(lhs); - const char *rstr = static_cast<const st_reload_entry*>(rhs)->table; - DBUG_ENTER("reload_entry_compare"); - - DBUG_RETURN(strcmp(lstr, rstr)); -} - -void st_relay_log_info::touching_table(char const* db, char const* table, - ulong table_id) -{ - DBUG_ENTER("st_relay_log_info::touching_table"); - - if (strcmp(db,"mysql") == 0) - { -#if defined(HAVE_BSEARCH) && defined(HAVE_SIZE_T) - void *const ptr= bsearch(table, s_mysql_tables, - s_mysql_tables_size, - sizeof(*s_mysql_tables), reload_entry_compare); - st_reload_entry const *const entry= static_cast<st_reload_entry*>(ptr); -#else - /* - Fall back to full scan, there are few rows anyway and updating the - "mysql" database is rare. - */ - st_reload_entry const *entry= s_mysql_tables; - for ( ; entry < s_mysql_tables + s_mysql_tables_size ; entry++) - if (reload_entry_compare(table, entry) == 0) - break; -#endif - if (entry) - m_reload_flags|= entry->flag; - } - DBUG_VOID_RETURN; -} - -void st_relay_log_info::transaction_end(THD* thd) -{ - DBUG_ENTER("st_relay_log_info::transaction_end"); - - if (m_reload_flags != RELOAD_NONE_F) - { - if (m_reload_flags & RELOAD_ACCESS_F) - acl_reload(thd); - - if (m_reload_flags & RELOAD_GRANT_F) - grant_reload(thd); - - m_reload_flags= RELOAD_NONE_F; - } - DBUG_VOID_RETURN; -} - -#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) -void st_relay_log_info::cleanup_context(THD *thd, bool error) -{ - DBUG_ENTER("st_relay_log_info::cleanup_context"); - - DBUG_ASSERT(sql_thd == thd); - /* - 1) Instances of Table_map_log_event, if ::exec_event() was called on them, - may have opened tables, which we cannot be sure have been closed (because - maybe the Rows_log_event have not been found or will not be, because slave - SQL thread is stopping, or relay log has a missing tail etc). So we close - all thread's tables. And so the table mappings have to be cancelled. - 2) Rows_log_event::exec_event() may even have started statements or - transactions on them, which we need to rollback in case of error. - 3) If finding a Format_description_log_event after a BEGIN, we also need - to rollback before continuing with the next events. - 4) so we need this "context cleanup" function. - */ - if (error) - { - ha_autocommit_or_rollback(thd, 1); // if a "statement transaction" - end_trans(thd, ROLLBACK); // if a "real transaction" - } - m_table_map.clear_tables(); - close_thread_tables(thd); - clear_tables_to_lock(); - unsafe_to_stop_at= 0; - DBUG_VOID_RETURN; -} -#endif - #ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION template class I_List_iterator<i_string>; diff --git a/sql/slave.h b/sql/slave.h index e70b2e4b326..24ba09d78d3 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -24,6 +24,7 @@ #include "rpl_filter.h" #include "rpl_tblmap.h" #include "rpl_rli.h" +#include "rpl_mi.h" #define SLAVE_NET_TIMEOUT 3600 @@ -38,11 +39,11 @@ I/O Thread - One of these threads is started for each master server. They maintain a connection to their master server, read log events from the master as they arrive, and queues them into - a single, shared relay log file. A MASTER_INFO struct + a single, shared relay log file. A MASTER_INFO represents each of these threads. SQL Thread - One of these threads is started and reads from the relay log - file, executing each event. A RELAY_LOG_INFO struct + file, executing each event. A RELAY_LOG_INFO represents this thread. Buffering in the relay log file makes it unnecessary to reread events from @@ -95,7 +96,6 @@ extern my_string opt_relay_logname, opt_relaylog_index_name; extern my_bool opt_skip_slave_start, opt_reckless_slave; extern my_bool opt_log_slave_updates; extern ulonglong relay_log_space_limit; -struct st_master_info; /* 3 possible values for MASTER_INFO::slave_running and @@ -114,110 +114,6 @@ struct st_master_info; static Log_event* next_event(RELAY_LOG_INFO* rli); -/***************************************************************************** - - Replication IO Thread - - st_master_info contains: - - information about how to connect to a master - - current master log name - - current master log offset - - misc control variables - - st_master_info is initialized once from the master.info file if such - exists. Otherwise, data members corresponding to master.info fields - are initialized with defaults specified by master-* options. The - initialization is done through init_master_info() call. - - The format of master.info file: - - log_name - log_pos - master_host - master_user - master_pass - master_port - master_connect_retry - - To write out the contents of master.info file to disk ( needed every - time we read and queue data from the master ), a call to - flush_master_info() is required. - - To clean up, call end_master_info() - -*****************************************************************************/ - -typedef struct st_master_info -{ - /* the variables below are needed because we can change masters on the fly */ - char master_log_name[FN_REFLEN]; - char host[HOSTNAME_LENGTH+1]; - char user[USERNAME_LENGTH+1]; - char password[MAX_PASSWORD_LENGTH+1]; - my_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]; - - my_off_t master_log_pos; - File fd; // we keep the file open, so we need to remember the file pointer - IO_CACHE file; - - pthread_mutex_t data_lock,run_lock; - pthread_cond_t data_cond,start_cond,stop_cond; - THD *io_thd; - MYSQL* mysql; - uint32 file_id; /* for 3.23 load data infile */ - RELAY_LOG_INFO rli; - uint port; - uint connect_retry; -#ifndef DBUG_OFF - int events_till_disconnect; -#endif - bool inited; - volatile bool abort_slave; - volatile uint slave_running; - volatile ulong slave_run_id; - /* - The difference in seconds between the clock of the master and the clock of - the slave (second - first). It must be signed as it may be <0 or >0. - clock_diff_with_master is computed when the I/O thread starts; for this the - I/O thread does a SELECT UNIX_TIMESTAMP() on the master. - "how late the slave is compared to the master" is computed like this: - clock_of_slave - last_timestamp_executed_by_SQL_thread - clock_diff_with_master - - */ - long clock_diff_with_master; - - st_master_info() - :ssl(0), fd(-1), io_thd(0), inited(0), - abort_slave(0),slave_running(0), slave_run_id(0) - { - host[0] = 0; user[0] = 0; password[0] = 0; - ssl_ca[0]= 0; ssl_capath[0]= 0; ssl_cert[0]= 0; - ssl_cipher[0]= 0; ssl_key[0]= 0; - - bzero((char*) &file, sizeof(file)); - pthread_mutex_init(&run_lock, MY_MUTEX_INIT_FAST); - pthread_mutex_init(&data_lock, MY_MUTEX_INIT_FAST); - pthread_cond_init(&data_cond, NULL); - pthread_cond_init(&start_cond, NULL); - pthread_cond_init(&stop_cond, NULL); - } - - ~st_master_info() - { - pthread_mutex_destroy(&run_lock); - pthread_mutex_destroy(&data_lock); - pthread_cond_destroy(&data_cond); - pthread_cond_destroy(&start_cond); - pthread_cond_destroy(&stop_cond); - } - -} MASTER_INFO; - - -int queue_event(MASTER_INFO* mi,const char* buf,ulong event_len); - #define RPL_LOG_NAME (rli->group_master_log_name[0] ? rli->group_master_log_name :\ "FIRST") #define IO_RPL_LOG_NAME (mi->master_log_name[0] ? mi->master_log_name :\ @@ -231,7 +127,6 @@ int queue_event(MASTER_INFO* mi,const char* buf,ulong event_len); int init_slave(); void init_slave_skip_errors(const char* arg); -int flush_master_info(MASTER_INFO* mi, bool flush_relay_log_cache); bool flush_relay_log_info(RELAY_LOG_INFO* rli); int register_slave_on_master(MYSQL* mysql); int terminate_slave_threads(MASTER_INFO* mi, int thread_mask, @@ -276,14 +171,8 @@ void slave_print_msg(enum loglevel level, RELAY_LOG_INFO* rli, ATTRIBUTE_FORMAT(printf, 4, 5); void end_slave(); /* clean up */ -void init_master_info_with_options(MASTER_INFO* mi); void clear_until_condition(RELAY_LOG_INFO* rli); void clear_slave_error(RELAY_LOG_INFO* rli); -int init_master_info(MASTER_INFO* mi, const char* master_info_fname, - const char* slave_info_fname, - bool abort_if_no_master_info_file, - int thread_mask); -void end_master_info(MASTER_INFO* mi); void end_relay_log_info(RELAY_LOG_INFO* rli); void lock_slave_threads(MASTER_INFO* mi); void unlock_slave_threads(MASTER_INFO* mi); diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 47a623ec749..622d9efdde0 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -899,7 +899,7 @@ subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str) break; val= (*splocal)->this_item(); - DBUG_PRINT("info", ("print %p", val)); + DBUG_PRINT("info", ("print 0x%lx", (long) val)); str_value= sp_get_item_value(val, &str_value_holder); if (str_value) res|= qbuf.append(*str_value); diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index aa13c2f08f4..721b6b5a003 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -3871,7 +3871,7 @@ bool check_grant_column(THD *thd, GRANT_INFO *grant, GRANT_COLUMN *grant_column; ulong want_access= grant->want_privilege & ~grant->privilege; DBUG_ENTER("check_grant_column"); - DBUG_PRINT("enter", ("table: %s want_access: %u", table_name, want_access)); + DBUG_PRINT("enter", ("table: %s want_access: %lu", table_name, want_access)); if (!want_access) DBUG_RETURN(0); // Already checked diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 28bc1e9dcbf..f1a685778f9 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1087,7 +1087,7 @@ void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived) if (!lock_in_use) VOID(pthread_mutex_lock(&LOCK_open)); - DBUG_PRINT("info", ("thd->open_tables: %p", thd->open_tables)); + DBUG_PRINT("info", ("thd->open_tables: 0x%lx", (long) thd->open_tables)); found_old_table= 0; while (thd->open_tables) @@ -1177,6 +1177,16 @@ static inline uint tmpkeyval(THD *thd, TABLE *table) void close_temporary_tables(THD *thd) { TABLE *table; + TABLE *next; + /* + TODO: 5.1 maintains prev link in temporary_tables + double-linked list so we could fix it. But it is not necessary + at this time when the list is being destroyed + */ + TABLE *prev_table; + /* Assume thd->options has OPTION_QUOTE_SHOW_CREATE */ + bool was_quote_show= TRUE; + if (!thd->temporary_tables) return; @@ -1192,12 +1202,7 @@ void close_temporary_tables(THD *thd) return; } - TABLE *next, - *prev_table /* TODO: 5.1 maintaines prev link in temporary_tables - double-linked list so we could fix it. But it is not necessary - at this time when the list is being destroyed */; - bool was_quote_show= true; /* to assume thd->options has OPTION_QUOTE_SHOW_CREATE */ - // Better add "if exists", in case a RESET MASTER has been done + /* Better add "if exists", in case a RESET MASTER has been done */ const char stub[]= "DROP /*!40005 TEMPORARY */ TABLE IF EXISTS "; uint stub_len= sizeof(stub) - 1; char buf[256]; @@ -1303,7 +1308,7 @@ void close_temporary_tables(THD *thd) } } if (!was_quote_show) - thd->options &= ~OPTION_QUOTE_SHOW_CREATE; /* restore option */ + thd->options&= ~OPTION_QUOTE_SHOW_CREATE; /* restore option */ thd->temporary_tables=0; } @@ -2069,7 +2074,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, VOID(pthread_mutex_unlock(&LOCK_open)); DBUG_RETURN(0); // VIEW } - DBUG_PRINT("info", ("inserting table %p into the cache", table)); + DBUG_PRINT("info", ("inserting table 0x%lx into the cache", (long) table)); VOID(my_hash_insert(&open_cache,(byte*) table)); } @@ -2399,7 +2404,7 @@ bool table_is_used(TABLE *table, bool wait_for_name_lock) { DBUG_PRINT("info", ("share: 0x%lx locked_by_logger: %d " "locked_by_flush: %d locked_by_name: %d " - "db_stat: %u version: %u", + "db_stat: %u version: %lu", (ulong) search->s, search->locked_by_logger, search->locked_by_flush, search->locked_by_name, search->db_stat, diff --git a/sql/sql_binlog.cc b/sql/sql_binlog.cc index 23ca5330053..37094b992e5 100644 --- a/sql/sql_binlog.cc +++ b/sql/sql_binlog.cc @@ -79,9 +79,16 @@ void mysql_client_binlog_statement(THD* thd) char const *endptr= 0; int bytes_decoded= base64_decode(strptr, coded_len, buf, &endptr); +#ifndef HAVE_purify + /* + This debug printout should not be used for valgrind builds + since it will read from unassigned memory. + */ DBUG_PRINT("info", - ("bytes_decoded=%d; strptr=0x%lu; endptr=0x%lu ('%c':%d)", - bytes_decoded, strptr, endptr, *endptr, *endptr)); + ("bytes_decoded: %d strptr: 0x%lx endptr: 0x%lx ('%c':%d)", + bytes_decoded, (long) strptr, (long) endptr, *endptr, + *endptr)); +#endif if (bytes_decoded < 0) { @@ -107,8 +114,8 @@ void mysql_client_binlog_statement(THD* thd) order to be able to read exactly what is necessary. */ - DBUG_PRINT("info",("binlog base64 decoded_len=%d, bytes_decoded=%d", - decoded_len, bytes_decoded)); + DBUG_PRINT("info",("binlog base64 decoded_len: %lu bytes_decoded: %d", + (ulong) decoded_len, bytes_decoded)); /* Now we start to read events of the buffer, until there are no @@ -145,14 +152,21 @@ void mysql_client_binlog_statement(THD* thd) bufptr += event_len; DBUG_PRINT("info",("ev->get_type_code()=%d", ev->get_type_code())); - DBUG_PRINT("info",("bufptr+EVENT_TYPE_OFFSET=0x%lx", - bufptr+EVENT_TYPE_OFFSET)); - DBUG_PRINT("info", ("bytes_decoded=%d; bufptr=0x%lx; buf[EVENT_LEN_OFFSET]=%u", - bytes_decoded, bufptr, uint4korr(bufptr+EVENT_LEN_OFFSET))); +#ifndef HAVE_purify + /* + This debug printout should not be used for valgrind builds + since it will read from unassigned memory. + */ + DBUG_PRINT("info",("bufptr+EVENT_TYPE_OFFSET: 0x%lx", + (long) (bufptr+EVENT_TYPE_OFFSET))); + DBUG_PRINT("info", ("bytes_decoded: %d bufptr: 0x%lx buf[EVENT_LEN_OFFSET]: %lu", + bytes_decoded, (long) bufptr, + (ulong) uint4korr(bufptr+EVENT_LEN_OFFSET))); +#endif ev->thd= thd; if (int err= ev->exec_event(thd->rli_fake)) { - DBUG_PRINT("info", ("exec_event() - error=%d", error)); + DBUG_PRINT("error", ("exec_event() returned: %d", err)); /* TODO: Maybe a better error message since the BINLOG statement now contains several events. diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index ee3b8aa79fe..3362ec76fc2 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -523,7 +523,8 @@ void Query_cache_query::init_n_lock() my_rwlock_init(&lock, NULL); lock_writing(); DBUG_PRINT("qcache", ("inited & locked query for block 0x%lx", - ((byte*) this)-ALIGN_SIZE(sizeof(Query_cache_block)))); + (long) (((byte*) this) - + ALIGN_SIZE(sizeof(Query_cache_block))))); DBUG_VOID_RETURN; } @@ -532,7 +533,8 @@ void Query_cache_query::unlock_n_destroy() { DBUG_ENTER("Query_cache_query::unlock_n_destroy"); DBUG_PRINT("qcache", ("destroyed & unlocked query for block 0x%lx", - ((byte*)this)-ALIGN_SIZE(sizeof(Query_cache_block)))); + (long) (((byte*) this) - + ALIGN_SIZE(sizeof(Query_cache_block))))); /* The following call is not needed on system where one can destroy an active semaphore @@ -698,6 +700,7 @@ void query_cache_abort(NET *net) void query_cache_end_of_result(THD *thd) { + Query_cache_block *query_block; DBUG_ENTER("query_cache_end_of_result"); /* See the comment on double-check locking usage above. */ @@ -713,13 +716,9 @@ void query_cache_end_of_result(THD *thd) if (unlikely(query_cache.query_cache_size == 0 || query_cache.flush_in_progress)) - { - STRUCT_UNLOCK(&query_cache.structure_guard_mutex); - DBUG_VOID_RETURN; - } + goto end; - Query_cache_block *query_block= ((Query_cache_block*) - thd->net.query_cache_query); + query_block= ((Query_cache_block*) thd->net.query_cache_query); if (query_block) { DUMP(&query_cache); @@ -738,27 +737,21 @@ void query_cache_end_of_result(THD *thd) header->query())); query_cache.wreck(__LINE__, ""); - STRUCT_UNLOCK(&query_cache.structure_guard_mutex); - - DBUG_VOID_RETURN; + BLOCK_UNLOCK_WR(query_block); + goto end; } #endif header->found_rows(current_thd->limit_found_rows); header->result()->type= Query_cache_block::RESULT; header->writer(0); thd->net.query_cache_query= 0; + BLOCK_UNLOCK_WR(query_block); DBUG_EXECUTE("check_querycache",query_cache.check_integrity(1);); - STRUCT_UNLOCK(&query_cache.structure_guard_mutex); - - BLOCK_UNLOCK_WR(query_block); - } - else - { - // Cache was flushed or resized and query was deleted => do nothing - STRUCT_UNLOCK(&query_cache.structure_guard_mutex); } +end: + STRUCT_UNLOCK(&query_cache.structure_guard_mutex); DBUG_VOID_RETURN; } @@ -875,8 +868,8 @@ sql mode: 0x%lx, sort len: %lu, conncat len: %lu", flags.character_set_client_num, flags.character_set_results_num, flags.collation_connection_num, - flags.limit, - (ulong)flags.time_zone, + (ulong) flags.limit, + (ulong) flags.time_zone, flags.sql_mode, flags.max_sort_length, flags.group_concat_max_len)); @@ -1119,8 +1112,8 @@ sql mode: 0x%lx, sort len: %lu, conncat len: %lu", flags.character_set_client_num, flags.character_set_results_num, flags.collation_connection_num, - flags.limit, - (ulong)flags.time_zone, + (ulong) flags.limit, + (ulong) flags.time_zone, flags.sql_mode, flags.max_sort_length, flags.group_concat_max_len)); @@ -1234,9 +1227,9 @@ sql mode: 0x%lx, sort len: %lu, conncat len: %lu", if (engine_data != table->engine_data()) { DBUG_PRINT("qcache", - ("Handler require invalidation queries of %s.%s %lld-%lld", - table_list.db, table_list.alias, - engine_data, table->engine_data())); + ("Handler require invalidation queries of %s.%s %lu-%lu", + table_list.db, table_list.alias, + (ulong) engine_data, (ulong) table->engine_data())); invalidate_table((byte *) table->db(), table->key_length()); } else @@ -1257,10 +1250,10 @@ sql mode: 0x%lx, sort len: %lu, conncat len: %lu", #ifndef EMBEDDED_LIBRARY do { - DBUG_PRINT("qcache", ("Results (len %lu, used %lu, headers %lu)", + DBUG_PRINT("qcache", ("Results (len: %lu used: %lu headers: %lu)", result_block->length, result_block->used, - result_block->headers_len()+ - ALIGN_SIZE(sizeof(Query_cache_result)))); + (ulong) (result_block->headers_len()+ + ALIGN_SIZE(sizeof(Query_cache_result))))); Query_cache_result *result = result_block->result(); if (net_real_write(&thd->net, result->data(), @@ -2034,7 +2027,7 @@ Query_cache::append_result_data(Query_cache_block **current_block, { DBUG_ENTER("Query_cache::append_result_data"); DBUG_PRINT("qcache", ("append %lu bytes to 0x%lx query", - data_len, query_block)); + data_len, (long) query_block)); if (query_block->query()->add(data_len) > query_cache_limit) { @@ -2476,11 +2469,11 @@ Query_cache::insert_table(uint key_len, char *key, table_block->table()->engine_data() != engine_data) { DBUG_PRINT("qcache", - ("Handler require invalidation queries of %s.%s %lld-%lld", + ("Handler require invalidation queries of %s.%s %lu-%lu", table_block->table()->db(), table_block->table()->table(), - engine_data, - table_block->table()->engine_data())); + (ulong) engine_data, + (ulong) table_block->table()->engine_data())); /* as far as we delete all queries with this table, table block will be deleted, too @@ -2988,7 +2981,7 @@ static TABLE_COUNTER_TYPE process_and_count_tables(TABLE_LIST *tables_used, DBUG_PRINT("qcache", ("table: %s db: %s type: %u", tables_used->table->s->table_name.str, tables_used->table->s->db.str, - tables_used->table->s->db_type)); + tables_used->table->s->db_type->db_type)); if (tables_used->derived) { table_count--; @@ -3043,10 +3036,10 @@ Query_cache::is_cacheable(THD *thd, uint32 query_len, char *query, LEX *lex, OPTION_TO_QUERY_CACHE))) && lex->safe_to_cache_query) { - DBUG_PRINT("qcache", ("options %lx %lx, type %u", - OPTION_TO_QUERY_CACHE, - lex->select_lex.options, - (int) thd->variables.query_cache_type)); + DBUG_PRINT("qcache", ("options: %lx %lx type: %u", + (long) OPTION_TO_QUERY_CACHE, + (long) lex->select_lex.options, + (int) thd->variables.query_cache_type)); if (!(table_count= process_and_count_tables(tables_used, tables_type))) DBUG_RETURN(0); @@ -3062,10 +3055,10 @@ Query_cache::is_cacheable(THD *thd, uint32 query_len, char *query, LEX *lex, } DBUG_PRINT("qcache", - ("not interesting query: %d or not cacheable, options %lx %lx, type %u", + ("not interesting query: %d or not cacheable, options %lx %lx type: %u", (int) lex->sql_command, - OPTION_TO_QUERY_CACHE, - lex->select_lex.options, + (long) OPTION_TO_QUERY_CACHE, + (long) lex->select_lex.options, (int) thd->variables.query_cache_type)); DBUG_RETURN(0); } @@ -3656,7 +3649,8 @@ void Query_cache::queries_dump() DBUG_PRINT("qcache", ("F:%u C:%u L:%lu T:'%s' (%u) '%s' '%s'", flags.client_long_flag, flags.character_set_client_num, - (ulong)flags.limit, flags.time_zone->get_name(), + (ulong)flags.limit, + flags.time_zone->get_name()->ptr(), len, str, strend(str)+1)); DBUG_PRINT("qcache", ("-b- 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx", (ulong) block, (ulong) block->next, (ulong) block->prev, @@ -3765,7 +3759,7 @@ my_bool Query_cache::check_integrity(bool locked) { DBUG_PRINT("error", ("block 0x%lx do not aligned by %d", (ulong) block, - ALIGN_SIZE(1))); + (int) ALIGN_SIZE(1))); result = 1; } // Check memory allocation @@ -3876,9 +3870,8 @@ my_bool Query_cache::check_integrity(bool locked) break; } default: - DBUG_PRINT("error", - ("block 0x%lx have incorrect type %u", - block, block->type)); + DBUG_PRINT("error", ("block 0x%lx have incorrect type %u", + (long) block, block->type)); result = 1; } @@ -3976,8 +3969,8 @@ my_bool Query_cache::check_integrity(bool locked) } while (block != bins[i].free_blocks); if (count != bins[i].number) { - DBUG_PRINT("error", ("bin[%d].number is %d, but bin have %d blocks", - bins[i].number, count)); + DBUG_PRINT("error", ("bins[%d].number = %d, but bin have %d blocks", + i, bins[i].number, count)); result = 1; } } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 776ba4dabea..07510c1fbb0 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -551,7 +551,7 @@ 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", this)); + DBUG_PRINT("enter", ("this: 0x%lx", (long) this)); THD_CHECK_SENTRY(this); safe_mutex_assert_owner(&LOCK_delete); @@ -799,7 +799,7 @@ void THD::add_changed_table(const char *key, long key_length) { list_include(prev_changed, curr, changed_table_dup(key, key_length)); DBUG_PRINT("info", - ("key_length %u %u", key_length, (*prev_changed)->key_length)); + ("key_length %ld %u", key_length, (*prev_changed)->key_length)); DBUG_VOID_RETURN; } else if (cmp == 0) @@ -809,7 +809,7 @@ void THD::add_changed_table(const char *key, long key_length) { list_include(prev_changed, curr, changed_table_dup(key, key_length)); DBUG_PRINT("info", - ("key_length %u %u", key_length, + ("key_length %ld %u", key_length, (*prev_changed)->key_length)); DBUG_VOID_RETURN; } @@ -821,7 +821,7 @@ void THD::add_changed_table(const char *key, long key_length) } } *prev_changed = changed_table_dup(key, key_length); - DBUG_PRINT("info", ("key_length %u %u", key_length, + DBUG_PRINT("info", ("key_length %ld %u", key_length, (*prev_changed)->key_length)); DBUG_VOID_RETURN; } @@ -2518,7 +2518,9 @@ my_size_t THD::max_row_length_blob(TABLE *table, const byte *data) const for (uint *ptr= beg ; ptr != end ; ++ptr) { Field_blob* const blob= (Field_blob*) table->field[*ptr]; - length+= blob->get_length((const char *) (data + blob->offset())) + 2; + length+= blob->get_length((const char*) (data + + blob->offset(table->record[0]))) + + HA_KEY_BLOB_LENGTH; } return length; @@ -2552,6 +2554,128 @@ my_size_t THD::pack_row(TABLE *table, MY_BITMAP const* cols, byte *row_data, } +namespace { + /** + Class to handle temporary allocation of memory for row data. + + The responsibilities of the class is to provide memory for + packing one or two rows of packed data (depending on what + constructor is called). + + In order to make the allocation more efficient for "simple" rows, + i.e., rows that do not contain any blobs, a pointer to the + allocated memory is of memory is stored in the table structure + for simple rows. If memory for a table containing a blob field + is requested, only memory for that is allocated, and subsequently + released when the object is destroyed. + + */ + class Row_data_memory { + public: + /** + Build an object to keep track of a block-local piece of memory + for storing a row of data. + + @param table + Table where the pre-allocated memory is stored. + + @param length + Length of data that is needed, if the record contain blobs. + */ + Row_data_memory(TABLE *table, my_size_t const len1) + : m_memory(0) + { +#ifndef DBUG_OFF + m_alloc_checked= false; +#endif + allocate_memory(table, len1); + m_ptr[0]= has_memory() ? m_memory : 0; + m_ptr[1]= 0; + } + + Row_data_memory(TABLE *table, my_size_t const len1, my_size_t const len2) + : m_memory(0) + { +#ifndef DBUG_OFF + m_alloc_checked= false; +#endif + allocate_memory(table, len1 + len2); + m_ptr[0]= has_memory() ? m_memory : 0; + m_ptr[1]= has_memory() ? m_memory + len1 : 0; + } + + ~Row_data_memory() + { + if (m_memory != 0 && m_release_memory_on_destruction) + my_free((gptr) m_memory, MYF(MY_WME)); + } + + /** + Is there memory allocated? + + @retval true There is memory allocated + @retval false Memory allocation failed + */ + bool has_memory() const { +#ifndef DBUG_OFF + m_alloc_checked= true; +#endif + return m_memory != 0; + } + + byte *slot(uint s) + { + DBUG_ASSERT(s < sizeof(m_ptr)/sizeof(*m_ptr)); + DBUG_ASSERT(m_ptr[s] != 0); + DBUG_ASSERT(m_alloc_checked == true); + return m_ptr[s]; + } + + private: + void allocate_memory(TABLE *const table, my_size_t const total_length) + { + if (table->s->blob_fields == 0) + { + /* + The maximum length of a packed record is less than this + length. We use this value instead of the supplied length + when allocating memory for records, since we don't know how + the memory will be used in future allocations. + + Since table->s->reclength is for unpacked records, we have + to add two bytes for each field, which can potentially be + added to hold the length of a packed field. + */ + my_size_t const maxlen= table->s->reclength + 2 * table->s->fields; + + /* + Allocate memory for two records if memory hasn't been + allocated. We allocate memory for two records so that it can + be used when processing update rows as well. + */ + if (table->write_row_record == 0) + table->write_row_record= + (byte *) alloc_root(&table->mem_root, 2 * maxlen); + m_memory= table->write_row_record; + m_release_memory_on_destruction= false; + } + else + { + m_memory= (byte *) my_malloc(total_length, MYF(MY_WME)); + m_release_memory_on_destruction= true; + } + } + +#ifndef DBUG_OFF + mutable bool m_alloc_checked; +#endif + bool m_release_memory_on_destruction; + byte *m_memory; + byte *m_ptr[2]; + }; +} + + int THD::binlog_write_row(TABLE* table, bool is_trans, MY_BITMAP const* cols, my_size_t colcnt, byte const *record) @@ -2562,40 +2686,25 @@ int THD::binlog_write_row(TABLE* table, bool is_trans, Pack records into format for transfer. We are allocating more memory than needed, but that doesn't matter. */ - bool error= 0; - byte *row_data= table->write_row_record; - my_size_t const max_len= max_row_length(table, record); - my_size_t len; - Rows_log_event *ev; - - /* Allocate room for a row (if needed) */ - if (!row_data) - { - if (!table->s->blob_fields) - { - /* multiply max_len by 2 so it can be used for update_row as well */ - table->write_row_record= (byte *) alloc_root(&table->mem_root, - 2*max_len); - if (!table->write_row_record) - return HA_ERR_OUT_OF_MEM; - row_data= table->write_row_record; - } - else if (unlikely(!(row_data= (byte *) my_malloc(max_len, MYF(MY_WME))))) - return HA_ERR_OUT_OF_MEM; - } - len= pack_row(table, cols, row_data, record); + int error= 0; - ev= binlog_prepare_pending_rows_event(table, server_id, cols, colcnt, - len, is_trans, - static_cast<Write_rows_log_event*>(0)); + Row_data_memory memory(table, max_row_length(table, record)); + if (!memory.has_memory()) + return HA_ERR_OUT_OF_MEM; - /* add_row_data copies row_data to internal buffer */ - error= likely(ev != 0) ? ev->add_row_data(row_data,len) : HA_ERR_OUT_OF_MEM ; + byte *row_data= memory.slot(0); - if (table->write_row_record == 0) - my_free((gptr) row_data, MYF(MY_WME)); + my_size_t const len= pack_row(table, cols, row_data, record); - return error; + Rows_log_event* const ev= + binlog_prepare_pending_rows_event(table, server_id, cols, colcnt, + len, is_trans, + static_cast<Write_rows_log_event*>(0)); + + if (unlikely(ev == 0)) + return HA_ERR_OUT_OF_MEM; + + return ev->add_row_data(row_data, len); } int THD::binlog_update_row(TABLE* table, bool is_trans, @@ -2605,53 +2714,44 @@ int THD::binlog_update_row(TABLE* table, bool is_trans, { DBUG_ASSERT(current_stmt_binlog_row_based && mysql_bin_log.is_open()); - bool error= 0; + int error= 0; my_size_t const before_maxlen = max_row_length(table, before_record); my_size_t const after_maxlen = max_row_length(table, after_record); - byte *row_data= table->write_row_record; - byte *before_row, *after_row; - if (row_data != 0) - { - before_row= row_data; - after_row= before_row + before_maxlen; - } - else - { - if (unlikely(!(row_data= (byte*)my_multi_malloc(MYF(MY_WME), - &before_row, before_maxlen, - &after_row, after_maxlen, - NULL)))) - return HA_ERR_OUT_OF_MEM; - } + Row_data_memory row_data(table, before_maxlen, after_maxlen); + if (!row_data.has_memory()) + return HA_ERR_OUT_OF_MEM; + + byte *before_row= row_data.slot(0); + byte *after_row= row_data.slot(1); my_size_t const before_size= pack_row(table, cols, before_row, before_record); my_size_t const after_size= pack_row(table, cols, after_row, after_record); - + + /* + Don't print debug messages when running valgrind since they can + trigger false warnings. + */ +#ifndef HAVE_purify DBUG_DUMP("before_record", (const char *)before_record, table->s->reclength); DBUG_DUMP("after_record", (const char *)after_record, table->s->reclength); DBUG_DUMP("before_row", (const char *)before_row, before_size); DBUG_DUMP("after_row", (const char *)after_row, after_size); +#endif Rows_log_event* const ev= binlog_prepare_pending_rows_event(table, server_id, cols, colcnt, before_size + after_size, is_trans, static_cast<Update_rows_log_event*>(0)); - error= - unlikely(!ev) || + if (unlikely(ev == 0)) + return HA_ERR_OUT_OF_MEM; + + return ev->add_row_data(before_row, before_size) || ev->add_row_data(after_row, after_size); - - if (!table->write_row_record) - { - /* add_row_data copies row_data to internal buffer */ - my_free((gptr)row_data, MYF(MY_WME)); - } - - return error; } int THD::binlog_delete_row(TABLE* table, bool is_trans, @@ -2664,11 +2764,14 @@ int THD::binlog_delete_row(TABLE* table, bool is_trans, Pack records into format for transfer. We are allocating more memory than needed, but that doesn't matter. */ - bool error= 0; - my_size_t const max_len= max_row_length(table, record); - byte *row_data= table->write_row_record; - if (!row_data && unlikely(!(row_data= (byte*)my_malloc(max_len, MYF(MY_WME))))) + int error= 0; + + Row_data_memory memory(table, max_row_length(table, record)); + if (unlikely(!memory.has_memory())) return HA_ERR_OUT_OF_MEM; + + byte *row_data= memory.slot(0); + my_size_t const len= pack_row(table, cols, row_data, record); Rows_log_event* const ev= @@ -2676,13 +2779,10 @@ int THD::binlog_delete_row(TABLE* table, bool is_trans, len, is_trans, static_cast<Delete_rows_log_event*>(0)); - error= (unlikely(!ev)) || ev->add_row_data(row_data, len); - - /* add_row_data copies row_data */ - if (table->write_row_record == 0) - my_free((gptr)row_data, MYF(MY_WME)); + if (unlikely(ev == 0)) + return HA_ERR_OUT_OF_MEM; - return error; + return ev->add_row_data(row_data, len); } @@ -2776,6 +2876,12 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, #endif /*HAVE_ROW_BASED_REPLICATION*/ switch (qtype) { + case THD::ROW_QUERY_TYPE: +#ifdef HAVE_ROW_BASED_REPLICATION + if (current_stmt_binlog_row_based) + DBUG_RETURN(0); +#endif + /* Otherwise, we fall through */ case THD::MYSQL_QUERY_TYPE: /* Using this query type is a conveniece hack, since we have been @@ -2785,12 +2891,6 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, Make sure to change in check_table_binlog_row_based() according to how you treat this. */ - case THD::ROW_QUERY_TYPE: -#ifdef HAVE_ROW_BASED_REPLICATION - if (current_stmt_binlog_row_based) - DBUG_RETURN(0); -#endif - /* Otherwise, we fall through */ case THD::STMT_QUERY_TYPE: /* The MYSQL_LOG::write() function will set the STMT_END_F flag and diff --git a/sql/sql_class.h b/sql/sql_class.h index 2cf7de5ee9e..e6f2ec7b041 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -425,6 +425,12 @@ public: { return strdup_root(mem_root,str); } inline char *strmake(const char *str, uint size) { return strmake_root(mem_root,str,size); } + inline bool LEX_STRING_make(LEX_STRING *lex_str, const char *str, uint size) + { + return ((lex_str->str= + strmake_root(mem_root, str, (lex_str->length= size)))) == 0; + } + inline char *memdup(const char *str, uint size) { return memdup_root(mem_root,str,size); } inline char *memdup_w_gap(const char *str, uint size, uint gap) @@ -1628,8 +1634,7 @@ public: return TRUE; } *p_db= strmake(db, db_length); - if (p_db_length) - *p_db_length= db_length; + *p_db_length= db_length; return FALSE; } }; @@ -2065,7 +2070,7 @@ public: inline bool unique_add(void *ptr) { DBUG_ENTER("unique_add"); - DBUG_PRINT("info", ("tree %u - %u", tree.elements_in_tree, max_elements)); + DBUG_PRINT("info", ("tree %u - %lu", tree.elements_in_tree, max_elements)); if (tree.elements_in_tree > max_elements && flush()) DBUG_RETURN(1); DBUG_RETURN(!tree_insert(&tree, ptr, 0, tree.custom_arg)); diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 37096fd897e..0c154069bd6 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -1302,8 +1302,8 @@ err: bool mysql_change_db(THD *thd, const char *name, bool no_access_check) { - int path_length, db_length; - char *db_name; + int path_length; + LEX_STRING db_name; bool system_db= 0; #ifndef NO_EMBEDDED_ACCESS_CHECKS ulong db_access; @@ -1323,25 +1323,26 @@ bool mysql_change_db(THD *thd, const char *name, bool no_access_check) /* Called from SP to restore the original database, which was NULL */ DBUG_ASSERT(no_access_check); system_db= 1; - db_name= NULL; - db_length= 0; + db_name.str= NULL; + db_name.length= 0; goto end; } /* Now we need to make a copy because check_db_name requires a non-constant argument. TODO: fix check_db_name. */ - if ((db_name= my_strdup(name, MYF(MY_WME))) == NULL) + if ((db_name.str= my_strdup(name, MYF(MY_WME))) == NULL) DBUG_RETURN(1); /* the error is set */ - db_length= strlen(db_name); - if (check_db_name(db_name)) + db_name.length= strlen(db_name.str); + if (check_db_name(&db_name)) { - my_error(ER_WRONG_DB_NAME, MYF(0), db_name); - my_free(db_name, MYF(0)); + my_error(ER_WRONG_DB_NAME, MYF(0), db_name.str); + my_free(db_name.str, MYF(0)); DBUG_RETURN(1); } - DBUG_PRINT("info",("Use database: %s", db_name)); - if (!my_strcasecmp(system_charset_info, db_name, information_schema_name.str)) + DBUG_PRINT("info",("Use database: %s", db_name.str)); + if (!my_strcasecmp(system_charset_info, db_name.str, + information_schema_name.str)) { system_db= 1; #ifndef NO_EMBEDDED_ACCESS_CHECKS @@ -1356,34 +1357,35 @@ bool mysql_change_db(THD *thd, const char *name, bool no_access_check) if (test_all_bits(sctx->master_access, DB_ACLS)) db_access=DB_ACLS; else - db_access= (acl_get(sctx->host, sctx->ip, sctx->priv_user, db_name, 0) | + db_access= (acl_get(sctx->host, sctx->ip, sctx->priv_user, + db_name.str, 0) | sctx->master_access); if (!(db_access & DB_ACLS) && (!grant_option || - check_grant_db(thd,db_name))) + check_grant_db(thd, db_name.str))) { my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), sctx->priv_user, sctx->priv_host, - db_name); + db_name.str); general_log_print(thd, COM_INIT_DB, ER(ER_DBACCESS_DENIED_ERROR), - sctx->priv_user, sctx->priv_host, db_name); - my_free(db_name,MYF(0)); + sctx->priv_user, sctx->priv_host, db_name.str); + my_free(db_name.str, MYF(0)); DBUG_RETURN(1); } } #endif - if (check_db_dir_existence(db_name)) + if (check_db_dir_existence(db_name.str)) { - my_error(ER_BAD_DB_ERROR, MYF(0), db_name); - my_free(db_name, MYF(0)); + my_error(ER_BAD_DB_ERROR, MYF(0), db_name.str); + my_free(db_name.str, MYF(0)); DBUG_RETURN(1); } end: x_free(thd->db); - DBUG_ASSERT(db_name == NULL || db_name[0] != '\0'); - thd->reset_db(db_name, db_length); // THD::~THD will free this + DBUG_ASSERT(db_name.str == NULL || db_name.str[0] != '\0'); + thd->reset_db(db_name.str, db_name.length); // THD::~THD will free this #ifndef NO_EMBEDDED_ACCESS_CHECKS if (!no_access_check) sctx->db_access= db_access; @@ -1397,7 +1399,7 @@ end: { HA_CREATE_INFO create; - load_db_opt_by_name(thd, db_name, &create); + load_db_opt_by_name(thd, db_name.str, &create); thd->db_charset= create.default_table_charset ? create.default_table_charset : diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index a0cd419e6c6..5da2a7660a4 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -354,7 +354,7 @@ cleanup: { thd->row_count_func= deleted; send_ok(thd,deleted); - DBUG_PRINT("info",("%d records deleted",deleted)); + DBUG_PRINT("info",("%ld records deleted",(long) deleted)); } DBUG_RETURN(error >= 0 || thd->net.report_error); } diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 0d893a6c9be..c448be04ac5 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -367,9 +367,9 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, strlen(tables->alias) + 1))) { table= hash_tables->table; - DBUG_PRINT("info-in-hash",("'%s'.'%s' as '%s' tab %p", + DBUG_PRINT("info-in-hash",("'%s'.'%s' as '%s' table: 0x%lx", hash_tables->db, hash_tables->table_name, - hash_tables->alias, table)); + hash_tables->alias, (long) table)); if (!table) { /* @@ -633,7 +633,8 @@ int mysql_ha_flush(THD *thd, TABLE_LIST *tables, uint mode_flags, TABLE **table_ptr; bool did_lock= FALSE; DBUG_ENTER("mysql_ha_flush"); - DBUG_PRINT("enter", ("tables: %p mode_flags: 0x%02x", tables, mode_flags)); + DBUG_PRINT("enter", ("tables: 0x%lx mode_flags: 0x%02x", + (long) tables, mode_flags)); if (tables) { diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 1c2d2cc1100..cfdc2954688 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -176,7 +176,8 @@ void lex_start(THD *thd, const uchar *buf, uint length) lex->reset_query_tables_list(FALSE); lex->expr_allows_subselect= TRUE; - lex->name= 0; + lex->name.str= 0; + lex->name.length= 0; lex->event_parse_data= NULL; lex->nest_level=0 ; @@ -1449,7 +1450,7 @@ bool st_select_lex::add_order_to_list(THD *thd, Item *item, bool asc) bool st_select_lex::add_item_to_list(THD *thd, Item *item) { DBUG_ENTER("st_select_lex::add_item_to_list"); - DBUG_PRINT("info", ("Item: %p", item)); + DBUG_PRINT("info", ("Item: 0x%lx", (long) item)); DBUG_RETURN(item_list.push_back(item)); } diff --git a/sql/sql_lex.h b/sql/sql_lex.h index e8f275d5caf..be508032c35 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -908,7 +908,8 @@ typedef struct st_lex : public Query_tables_list /* The values of tok_start/tok_end as they were one call of MYSQLlex before */ const uchar *tok_start_prev, *tok_end_prev; - char *length,*dec,*change,*name; + char *length,*dec,*change; + LEX_STRING name; Table_ident *like_name; char *help_arg; char *backup_dir; /* For RESTORE/BACKUP */ diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index d88478b9702..9f981fb6bc6 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -394,9 +394,9 @@ int check_user(THD *thd, enum enum_server_command command, NO_ACCESS)) // authentication is OK { DBUG_PRINT("info", - ("Capabilities: %lx packet_length: %ld Host: '%s' " + ("Capabilities: %lu packet_length: %ld Host: '%s' " "Login user: '%s' Priv_user: '%s' Using password: %s " - "Access: %u db: '%s'", + "Access: %lu db: '%s'", thd->client_capabilities, thd->max_client_packet_length, thd->main_security_ctx.host_or_ip, @@ -1002,7 +1002,7 @@ static int check_connection(THD *thd) if (thd->client_capabilities & CLIENT_IGNORE_SPACE) thd->variables.sql_mode|= MODE_IGNORE_SPACE; #ifdef HAVE_OPENSSL - DBUG_PRINT("info", ("client capabilities: %d", thd->client_capabilities)); + DBUG_PRINT("info", ("client capabilities: %lu", thd->client_capabilities)); if (thd->client_capabilities & CLIENT_SSL) { /* Do the SSL layering. */ @@ -1055,11 +1055,14 @@ static int check_connection(THD *thd) Old clients send null-terminated string as password; new clients send the size (1 byte) + string (not null-terminated). Hence in case of empty password both send '\0'. + + This strlen() can't be easily deleted without changing protocol. */ uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ? *passwd++ : strlen(passwd); db= thd->client_capabilities & CLIENT_CONNECT_WITH_DB ? db + passwd_len + 1 : 0; + /* strlen() can't be easily deleted without changing protocol */ uint db_len= db ? strlen(db) : 0; if (passwd + passwd_len + db_len > (char *)net->read_pos + pkt_len) @@ -1158,7 +1161,7 @@ pthread_handler_t handle_one_connection(void *arg) of handle_one_connection, which is thd. We need to know the start of the stack so that we could check for stack overruns. */ - DBUG_PRINT("info", ("handle_one_connection called by thread %d\n", + DBUG_PRINT("info", ("handle_one_connection called by thread %lu\n", thd->thread_id)); /* now that we've called my_thread_init(), it is safe to call DBUG_* */ @@ -1321,28 +1324,31 @@ pthread_handler_t handle_bootstrap(void *arg) thd->init_for_queries(); while (fgets(buff, thd->net.max_packet, file)) { - ulong length= (ulong) strlen(buff); - while (buff[length-1] != '\n' && !feof(file)) - { - /* - We got only a part of the current string. Will try to increase - net buffer then read the rest of the current string. - */ - if (net_realloc(&(thd->net), 2 * thd->net.max_packet)) - { - net_send_error(thd, ER_NET_PACKET_TOO_LARGE, NullS); - thd->fatal_error(); - break; - } - buff= (char*) thd->net.buff; - fgets(buff + length, thd->net.max_packet - length, file); - length+= (ulong) strlen(buff + length); - } - if (thd->is_fatal_error) - break; + /* strlen() can't be deleted because fgets() doesn't return length */ + ulong length= (ulong) strlen(buff); + while (buff[length-1] != '\n' && !feof(file)) + { + /* + We got only a part of the current string. Will try to increase + net buffer then read the rest of the current string. + */ + /* purecov: begin tested */ + if (net_realloc(&(thd->net), 2 * thd->net.max_packet)) + { + net_send_error(thd, ER_NET_PACKET_TOO_LARGE, NullS); + thd->fatal_error(); + break; + } + buff= (char*) thd->net.buff; + fgets(buff + length, thd->net.max_packet - length, file); + length+= (ulong) strlen(buff + length); + /* purecov: end */ + } + if (thd->is_fatal_error) + break; /* purecov: inspected */ while (length && (my_isspace(thd->charset(), buff[length-1]) || - buff[length-1] == ';')) + buff[length-1] == ';')) length--; buff[length]=0; thd->query_length=length; @@ -1427,24 +1433,30 @@ void cleanup_items(Item *item) */ static -int mysql_table_dump(THD* thd, char* db, char* tbl_name) +int mysql_table_dump(THD *thd, LEX_STRING *db, char *tbl_name) { TABLE* table; TABLE_LIST* table_list; int error = 0; DBUG_ENTER("mysql_table_dump"); - db = (db && db[0]) ? db : thd->db; + if (db->length == 0) + { + db->str= thd->db; /* purecov: inspected */ + db->length= thd->db_length; /* purecov: inspected */ + } if (!(table_list = (TABLE_LIST*) thd->calloc(sizeof(TABLE_LIST)))) DBUG_RETURN(1); // out of memory - table_list->db= db; + table_list->db= db->str; table_list->table_name= table_list->alias= tbl_name; table_list->lock_type= TL_READ_NO_INSERT; table_list->prev_global= &table_list; // can be removed after merge with 4.1 - if (!db || check_db_name(db)) + if (check_db_name(db)) { - my_error(ER_WRONG_DB_NAME ,MYF(0), db ? db : "NULL"); + /* purecov: begin inspected */ + my_error(ER_WRONG_DB_NAME ,MYF(0), db->str ? db->str : "NULL"); goto err; + /* purecov: end */ } if (lower_case_table_names) my_casedn_str(files_charset_info, tbl_name); @@ -1604,7 +1616,7 @@ bool do_command(THD *thd) command= COM_END; // Wrong command DBUG_PRINT("info",("Command on %s = %d (%s)", vio_description(net->vio), command, - command_name[command])); + command_name[command].str)); } net->read_timeout=old_timeout; // restore it /* @@ -1673,7 +1685,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, statistic_increment(thd->status_var.com_stat[SQLCOM_CHANGE_DB], &LOCK_status); thd->convert_string(&tmp, system_charset_info, - packet, strlen(packet), thd->charset()); + packet, packet_length-1, thd->charset()); if (!mysql_change_db(thd, tmp.str, FALSE)) { general_log_print(thd, command, "%s",thd->db); @@ -1691,7 +1703,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd, #endif case COM_TABLE_DUMP: { - char *db, *tbl_name; + char *tbl_name; + LEX_STRING db; uint db_len= *(uchar*) packet; if (db_len >= packet_length || db_len > NAME_LEN) { @@ -1707,34 +1720,41 @@ bool dispatch_command(enum enum_server_command command, THD *thd, statistic_increment(thd->status_var.com_other, &LOCK_status); thd->enable_slow_log= opt_log_slow_admin_statements; - db= thd->alloc(db_len + tbl_len + 2); - if (!db) + db.str= thd->alloc(db_len + tbl_len + 2); + db.length= db_len; + if (!db.str) { my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); break; } - tbl_name= strmake(db, packet + 1, db_len)+1; + tbl_name= strmake(db.str, packet + 1, db_len)+1; strmake(tbl_name, packet + db_len + 2, tbl_len); - mysql_table_dump(thd, db, tbl_name); + mysql_table_dump(thd, &db, tbl_name); break; } case COM_CHANGE_USER: { + statistic_increment(thd->status_var.com_other, &LOCK_status); + char *user= (char*) packet, *packet_end= packet+ packet_length; + char *passwd= strend(user)+1; + thd->change_user(); thd->clear_error(); // if errors from rollback - statistic_increment(thd->status_var.com_other, &LOCK_status); - char *user= (char*) packet; - char *passwd= strend(user)+1; /* Old clients send null-terminated string ('\0' for empty string) for password. New clients send the size (1 byte) + string (not null terminated, so also '\0' for empty string). */ - char db_buff[NAME_LEN+1]; // buffer to store db in utf8 + char db_buff[NAME_LEN+1]; // buffer to store db in utf8 char *db= passwd; - uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ? - *passwd++ : strlen(passwd); + char *save_db; + uint passwd_len= (thd->client_capabilities & CLIENT_SECURE_CONNECTION ? + *passwd++ : strlen(passwd)); + uint dummy_errors, save_db_length, db_length, res; + Security_context save_security_ctx= *thd->security_ctx; + USER_CONN *save_user_connect; + db+= passwd_len + 1; #ifndef EMBEDDED_LIBRARY /* Small check for incoming packet */ @@ -1745,17 +1765,22 @@ bool dispatch_command(enum enum_server_command command, THD *thd, } #endif /* Convert database name to utf8 */ - uint dummy_errors; + /* + Handle problem with old bug in client protocol where db had an extra + \0 + */ + db_length= (packet_end - db); + if (db_length > 0 && db[db_length-1] == 0) + db_length--; db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1, - system_charset_info, db, strlen(db), + system_charset_info, db, db_length, thd->charset(), &dummy_errors)]= 0; db= db_buff; /* Save user and privileges */ - uint save_db_length= thd->db_length; - char *save_db= thd->db; - Security_context save_security_ctx= *thd->security_ctx; - USER_CONN *save_user_connect= thd->user_connect; + save_db_length= thd->db_length; + save_db= thd->db; + save_user_connect= thd->user_connect; if (!(thd->security_ctx->user= my_strdup(user, MYF(0)))) { @@ -1766,7 +1791,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, /* Clear variables that are allocated */ thd->user_connect= 0; - int res= check_user(thd, COM_CHANGE_USER, passwd, passwd_len, db, FALSE); + res= check_user(thd, COM_CHANGE_USER, passwd, passwd_len, db, FALSE); if (res) { @@ -1826,7 +1851,9 @@ bool dispatch_command(enum enum_server_command command, THD *thd, if (alloc_query(thd, packet, packet_length)) break; // fatal error is set char *packet_end= thd->query + thd->query_length; - general_log_print(thd, command, "%.*b", thd->query_length, thd->query); + /* 'b' stands for 'buffer' parameter', special for 'my_snprintf' */ + const char *format= "%.*b"; + general_log_print(thd, command, format, thd->query_length, thd->query); DBUG_PRINT("query",("%-.4096s",thd->query)); if (!(specialflag & SPECIAL_NO_PRIOR)) @@ -1876,29 +1903,31 @@ bool dispatch_command(enum enum_server_command command, THD *thd, break; #else { - char *fields, *pend; + char *fields, *packet_end= packet + packet_length - 1, *arg_end; /* Locked closure of all tables */ TABLE_LIST *locked_tables= NULL; TABLE_LIST table_list; LEX_STRING conv_name; /* Saved variable value */ my_bool old_innodb_table_locks= thd->variables.innodb_table_locks; - + uint dummy; /* used as fields initializator */ lex_start(thd, 0, 0); - statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_FIELDS], &LOCK_status); bzero((char*) &table_list,sizeof(table_list)); - if (thd->copy_db_to(&table_list.db, 0)) + if (thd->copy_db_to(&table_list.db, &dummy)) break; - pend= strend(packet); + /* + We have name + wildcard in packet, separated by endzero + */ + arg_end= strend(packet); thd->convert_string(&conv_name, system_charset_info, - packet, (uint) (pend-packet), thd->charset()); + packet, (uint) (arg_end - packet), thd->charset()); table_list.alias= table_list.table_name= conv_name.str; - packet= pend+1; + packet= arg_end + 1; if (!my_strcasecmp(system_charset_info, table_list.db, information_schema_name.str)) @@ -1908,7 +1937,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, table_list.schema_table= schema_table; } - thd->query_length= strlen(packet); // for simplicity: don't optimize + thd->query_length= (uint) (packet_end - packet); // Don't count end \0 if (!(thd->query=fields=thd->memdup(packet,thd->query_length+1))) break; general_log_print(thd, command, "%s %s", table_list.table_name, fields); @@ -1944,24 +1973,27 @@ bool dispatch_command(enum enum_server_command command, THD *thd, error=TRUE; // End server break; +#ifdef REMOVED case COM_CREATE_DB: // QQ: To be removed { - char *db=thd->strdup(packet), *alias; + LEX_STRING db, alias; HA_CREATE_INFO create_info; statistic_increment(thd->status_var.com_stat[SQLCOM_CREATE_DB], &LOCK_status); - // null test to handle EOM - if (!db || !(alias= thd->strdup(db)) || check_db_name(db)) + if (thd->LEX_STRING_make(&db, packet, packet_length -1) || + thd->LEX_STRING_make(&alias, db.str, db.length) || + check_db_name(&db)) { - my_error(ER_WRONG_DB_NAME, MYF(0), db ? db : "NULL"); + my_error(ER_WRONG_DB_NAME, MYF(0), db.str ? db.str : "NULL"); break; } - if (check_access(thd,CREATE_ACL,db,0,1,0,is_schema_db(db))) + if (check_access(thd, CREATE_ACL, db.str , 0, 1, 0, + is_schema_db(db.str))) break; general_log_print(thd, command, packet); bzero(&create_info, sizeof(create_info)); - mysql_create_db(thd, (lower_case_table_names == 2 ? alias : db), + mysql_create_db(thd, (lower_case_table_names == 2 ? alias.str : db.str), &create_info, 0); break; } @@ -1969,14 +2001,15 @@ bool dispatch_command(enum enum_server_command command, THD *thd, { statistic_increment(thd->status_var.com_stat[SQLCOM_DROP_DB], &LOCK_status); - char *db=thd->strdup(packet); - /* null test to handle EOM */ - if (!db || check_db_name(db)) + LEX_STRING db; + + if (thd->LEX_STRING_make(&db, packet, packet_length - 1) || + check_db_name(&db)) { - my_error(ER_WRONG_DB_NAME, MYF(0), db ? db : "NULL"); + my_error(ER_WRONG_DB_NAME, MYF(0), db.str ? db.str : "NULL"); break; } - if (check_access(thd,DROP_ACL,db,0,1,0,is_schema_db(db))) + if (check_access(thd, DROP_ACL, db.str, 0, 1, 0, is_schema_db(db.str))) break; if (thd->locked_tables || thd->active_transaction()) { @@ -1984,10 +2017,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd, ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0)); break; } - general_log_print(thd, command, db); - mysql_rm_db(thd, db, 0, 0); + general_log_print(thd, command, db.str); + mysql_rm_db(thd, db.str, 0, 0); break; } +#endif #ifndef EMBEDDED_LIBRARY case COM_BINLOG_DUMP: { @@ -2069,37 +2103,47 @@ bool dispatch_command(enum enum_server_command command, THD *thd, #endif case COM_STATISTICS: { - general_log_print(thd, command, NullS); - statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_STATUS], - &LOCK_status); + STATUS_VAR current_global_status_var; + ulong uptime; + uint length; #ifndef EMBEDDED_LIBRARY - char buff[200]; + char buff[250]; + uint buff_len= sizeof(buff); #else char *buff= thd->net.last_error; + uint buff_len= sizeof(thd->net.last_error); #endif - STATUS_VAR current_global_status_var; + general_log_print(thd, command, NullS); + statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_STATUS], + &LOCK_status); calc_sum_of_all_status(¤t_global_status_var); - - ulong uptime = (ulong) (thd->start_time - start_time); - sprintf((char*) buff, - "Uptime: %lu Threads: %d Questions: %lu Slow queries: %lu Opens: %lu Flush tables: %lu Open tables: %u Queries per second avg: %.3f", - uptime, - (int) thread_count, (ulong) thd->query_id, - current_global_status_var.long_query_count, - current_global_status_var.opened_tables, refresh_version, - cached_open_tables(), - (uptime ? (ulonglong2double(thd->query_id) / (double) uptime) : - (double) 0)); + uptime= (ulong) (thd->start_time - start_time); + length= my_snprintf((char*) buff, buff_len - 1, + "Uptime: %lu Threads: %d Questions: %lu " + "Slow queries: %lu Opens: %lu Flush tables: %lu " + "Open tables: %u Queries per second avg: %.3f", + uptime, + (int) thread_count, (ulong) thd->query_id, + current_global_status_var.long_query_count, + current_global_status_var.opened_tables, + refresh_version, + cached_open_tables(), + (uptime ? (ulonglong2double(thd->query_id) / + (double) uptime) : (double) 0)); #ifdef SAFEMALLOC if (sf_malloc_cur_memory) // Using SAFEMALLOC - sprintf(strend(buff), " Memory in use: %ldK Max memory used: %ldK", - (sf_malloc_cur_memory+1023L)/1024L, - (sf_malloc_max_memory+1023L)/1024L); + { + char *end= buff + length; + length+= my_snprintf(end, buff_len - length - 1, + end," Memory in use: %ldK Max memory used: %ldK", + (sf_malloc_cur_memory+1023L)/1024L, + (sf_malloc_max_memory+1023L)/1024L); + } #endif #ifndef EMBEDDED_LIBRARY - VOID(my_net_write(net, buff,(uint) strlen(buff))); - VOID(net_flush(net)); + VOID(my_net_write(net, buff, length)); + VOID(net_flush(net)); #endif break; } @@ -2296,26 +2340,28 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident, DBUG_RETURN(1); #else { - char *db; + LEX_STRING db; + uint dummy; if (lex->select_lex.db == NULL && - thd->copy_db_to(&lex->select_lex.db, 0)) + thd->copy_db_to(&lex->select_lex.db, &dummy)) { DBUG_RETURN(1); } - db= lex->select_lex.db; - if (check_db_name(db)) + db.str= lex->select_lex.db; + db.length= strlen(db.str); + if (check_db_name(&db)) { - my_error(ER_WRONG_DB_NAME, MYF(0), db); + my_error(ER_WRONG_DB_NAME, MYF(0), db.str); DBUG_RETURN(1); } - if (check_access(thd, SELECT_ACL, db, &thd->col_access, 0, 0, - is_schema_db(db))) + if (check_access(thd, SELECT_ACL, db.str, &thd->col_access, 0, 0, + is_schema_db(db.str))) DBUG_RETURN(1); /* purecov: inspected */ - if (!thd->col_access && check_grant_db(thd,db)) + if (!thd->col_access && check_grant_db(thd, db.str)) { my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), thd->security_ctx->priv_user, thd->security_ctx->priv_host, - db); + db.str); DBUG_RETURN(1); } break; @@ -2550,7 +2596,23 @@ mysql_execute_command(THD *thd) { /* we warn the slave SQL thread */ my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0)); - reset_one_shot_variables(thd); + if (thd->one_shot_set) + { + /* + It's ok to check thd->one_shot_set here: + + The charsets in a MySQL 5.0 slave can change by both a binlogged + SET ONE_SHOT statement and the event-internal charset setting, + and these two ways to change charsets do not seems to work + together. + + At least there seems to be problems in the rli cache for + charsets if we are using ONE_SHOT. Note that this is normally no + problem because either the >= 5.0 slave reads a 4.1 binlog (with + ONE_SHOT) *or* or 5.0 binlog (without ONE_SHOT) but never both." + */ + reset_one_shot_variables(thd); + } DBUG_RETURN(0); } } @@ -2855,11 +2917,6 @@ mysql_execute_command(THD *thd) if (check_grant(thd, CREATE_ACL, all_tables, 0, 1, 0)) goto error; } - if (strlen(first_table->table_name) > NAME_LEN) - { - my_error(ER_WRONG_TABLE_NAME, MYF(0), first_table->table_name); - break; - } pthread_mutex_lock(&LOCK_active_mi); /* fetch_master_table will send the error to the client on failure. @@ -3089,11 +3146,6 @@ end_with_restore_list: if (lex->alter_info.flags & ALTER_DROP_PARTITION) priv_needed|= DROP_ACL; - if (lex->name && (!lex->name[0] || strlen(lex->name) > NAME_LEN)) - { - my_error(ER_WRONG_TABLE_NAME, MYF(0), lex->name); - goto error; - } /* Must be set in the parser */ DBUG_ASSERT(select_lex->db); if (check_access(thd, priv_needed, first_table->db, @@ -3109,11 +3161,11 @@ end_with_restore_list: { if (check_grant(thd, priv_needed, all_tables, 0, UINT_MAX, 0)) goto error; - if (lex->name && !test_all_bits(priv,INSERT_ACL | CREATE_ACL)) + if (lex->name.str && !test_all_bits(priv,INSERT_ACL | CREATE_ACL)) { // Rename of table TABLE_LIST tmp_table; bzero((char*) &tmp_table,sizeof(tmp_table)); - tmp_table.table_name=lex->name; + tmp_table.table_name= lex->name.str; tmp_table.db=select_lex->db; tmp_table.grant.privilege=priv; if (check_grant(thd, INSERT_ACL | CREATE_ACL, &tmp_table, 0, @@ -3141,7 +3193,7 @@ end_with_restore_list: } thd->enable_slow_log= opt_log_slow_admin_statements; - res= mysql_alter_table(thd, select_lex->db, lex->name, + res= mysql_alter_table(thd, select_lex->db, lex->name.str, &lex->create_info, first_table, lex->create_list, lex->key_list, @@ -3753,9 +3805,10 @@ end_with_restore_list: break; } char *alias; - if (!(alias=thd->strdup(lex->name)) || check_db_name(lex->name)) + if (!(alias=thd->strmake(lex->name.str, lex->name.length)) || + check_db_name(&lex->name)) { - my_error(ER_WRONG_DB_NAME, MYF(0), lex->name); + my_error(ER_WRONG_DB_NAME, MYF(0), lex->name.str); break; } /* @@ -3767,17 +3820,18 @@ end_with_restore_list: */ #ifdef HAVE_REPLICATION if (thd->slave_thread && - (!rpl_filter->db_ok(lex->name) || - !rpl_filter->db_ok_with_wild_table(lex->name))) + (!rpl_filter->db_ok(lex->name.str) || + !rpl_filter->db_ok_with_wild_table(lex->name.str))) { my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0)); break; } #endif - if (check_access(thd,CREATE_ACL,lex->name,0,1,0,is_schema_db(lex->name))) + if (check_access(thd,CREATE_ACL,lex->name.str, 0, 1, 0, + is_schema_db(lex->name.str))) break; - res= mysql_create_db(thd,(lower_case_table_names == 2 ? alias : lex->name), - &lex->create_info, 0); + res= mysql_create_db(thd,(lower_case_table_names == 2 ? alias : + lex->name.str), &lex->create_info, 0); break; } case SQLCOM_DROP_DB: @@ -3787,9 +3841,9 @@ end_with_restore_list: res= -1; break; } - if (check_db_name(lex->name)) + if (check_db_name(&lex->name)) { - my_error(ER_WRONG_DB_NAME, MYF(0), lex->name); + my_error(ER_WRONG_DB_NAME, MYF(0), lex->name.str); break; } /* @@ -3801,14 +3855,15 @@ end_with_restore_list: */ #ifdef HAVE_REPLICATION if (thd->slave_thread && - (!rpl_filter->db_ok(lex->name) || - !rpl_filter->db_ok_with_wild_table(lex->name))) + (!rpl_filter->db_ok(lex->name.str) || + !rpl_filter->db_ok_with_wild_table(lex->name.str))) { my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0)); break; } #endif - if (check_access(thd,DROP_ACL,lex->name,0,1,0,is_schema_db(lex->name))) + if (check_access(thd,DROP_ACL,lex->name.str,0,1,0, + is_schema_db(lex->name.str))) break; if (thd->locked_tables || thd->active_transaction()) { @@ -3816,7 +3871,7 @@ end_with_restore_list: ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0)); goto error; } - res= mysql_rm_db(thd, lex->name, lex->drop_if_exists, 0); + res= mysql_rm_db(thd, lex->name.str, lex->drop_if_exists, 0); break; } case SQLCOM_RENAME_DB: @@ -3842,6 +3897,11 @@ end_with_restore_list: break; } #endif + if (check_db_name(newdb)) + { + my_error(ER_WRONG_DB_NAME, MYF(0), newdb->str); + break; + } if (check_access(thd,ALTER_ACL,olddb->str,0,1,0,is_schema_db(olddb->str)) || check_access(thd,DROP_ACL,olddb->str,0,1,0,is_schema_db(olddb->str)) || check_access(thd,CREATE_ACL,newdb->str,0,1,0,is_schema_db(newdb->str))) @@ -3863,11 +3923,10 @@ end_with_restore_list: } case SQLCOM_ALTER_DB: { - char *db= lex->name; - DBUG_ASSERT(db); /* Must be set in the parser */ - if (!strip_sp(db) || check_db_name(db)) + LEX_STRING *db= &lex->name; + if (check_db_name(db)) { - my_error(ER_WRONG_DB_NAME, MYF(0), db); + my_error(ER_WRONG_DB_NAME, MYF(0), db->str); break; } /* @@ -3879,14 +3938,14 @@ end_with_restore_list: */ #ifdef HAVE_REPLICATION if (thd->slave_thread && - (!rpl_filter->db_ok(db) || - !rpl_filter->db_ok_with_wild_table(db))) + (!rpl_filter->db_ok(db->str) || + !rpl_filter->db_ok_with_wild_table(db->str))) { my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0)); break; } #endif - if (check_access(thd, ALTER_ACL, db, 0, 1, 0, is_schema_db(db))) + if (check_access(thd, ALTER_ACL, db->str, 0, 1, 0, is_schema_db(db->str))) break; if (thd->locked_tables || thd->active_transaction()) { @@ -3894,21 +3953,22 @@ end_with_restore_list: ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0)); goto error; } - res= mysql_alter_db(thd, db, &lex->create_info); + res= mysql_alter_db(thd, db->str, &lex->create_info); break; } case SQLCOM_SHOW_CREATE_DB: { - if (!strip_sp(lex->name) || check_db_name(lex->name)) + if (check_db_name(&lex->name)) { - my_error(ER_WRONG_DB_NAME, MYF(0), lex->name); + my_error(ER_WRONG_DB_NAME, MYF(0), lex->name.str); break; } - res=mysqld_show_create_db(thd,lex->name,&lex->create_info); + res= mysqld_show_create_db(thd, lex->name.str, &lex->create_info); break; } case SQLCOM_CREATE_EVENT: case SQLCOM_ALTER_EVENT: + do { DBUG_ASSERT(lex->event_parse_data); if (lex->table_or_sp_used()) @@ -3934,16 +3994,15 @@ end_with_restore_list: if (!res) send_ok(thd); - /* Don't do it, if we are inside a SP */ - if (!thd->spcont) - { - delete lex->sphead; - lex->sphead= NULL; - } - - /* lex->unit.cleanup() is called outside, no need to call it here */ - break; + } while (0); + /* Don't do it, if we are inside a SP */ + if (!thd->spcont) + { + delete lex->sphead; + lex->sphead= NULL; } + /* lex->unit.cleanup() is called outside, no need to call it here */ + break; case SQLCOM_DROP_EVENT: case SQLCOM_SHOW_CREATE_EVENT: { @@ -6290,7 +6349,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, } if (table->is_derived_table() == FALSE && table->db.str && - check_db_name(table->db.str)) + check_db_name(&table->db)) { my_error(ER_WRONG_DB_NAME, MYF(0), table->db.str); DBUG_RETURN(0); @@ -6319,7 +6378,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, ptr->alias= alias_str; if (lower_case_table_names && table->table.length) - my_casedn_str(files_charset_info, table->table.str); + table->table.length= my_casedn_str(files_charset_info, table->table.str); ptr->table_name=table->table.str; ptr->table_name_length=table->table.length; ptr->lock_type= lock_type; @@ -7574,7 +7633,7 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables, #ifdef NOT_NECESSARY_TO_CHECK_CREATE_TABLE_EXIST_WHEN_PREPARING_STATEMENT /* This code throws an ill error for CREATE TABLE t1 SELECT * FROM t1 */ /* - Only do the check for PS, becasue we on execute we have to check that + Only do the check for PS, because we on execute we have to check that against the opened tables to ensure we don't use a table that is part of the view (which can only be done after the table has been opened). */ diff --git a/sql/sql_parse.cc.rej b/sql/sql_parse.cc.rej new file mode 100644 index 00000000000..6e2bd03867d --- /dev/null +++ b/sql/sql_parse.cc.rej @@ -0,0 +1,166 @@ +*************** +*** 67,109 **** + static void decrease_user_connections(USER_CONN *uc); + #endif /* NO_EMBEDDED_ACCESS_CHECKS */ + static bool check_multi_update_lock(THD *thd); +- static void remove_escape(char *name); + static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables); + + const char *any_db="*any*"; // Special symbol for check_access + +! LEX_STRING command_name[]={ +! (char *)STRING_WITH_LEN("Sleep"), +! (char *)STRING_WITH_LEN("Quit"), +! (char *)STRING_WITH_LEN("Init DB"), +! (char *)STRING_WITH_LEN("Query"), +! (char *)STRING_WITH_LEN("Field List"), +! (char *)STRING_WITH_LEN("Create DB"), +! (char *)STRING_WITH_LEN("Drop DB"), +! (char *)STRING_WITH_LEN("Refresh"), +! (char *)STRING_WITH_LEN("Shutdown"), +! (char *)STRING_WITH_LEN("Statistics"), +! (char *)STRING_WITH_LEN("Processlist"), +! (char *)STRING_WITH_LEN("Connect"), +! (char *)STRING_WITH_LEN("Kill"), +! (char *)STRING_WITH_LEN("Debug"), +! (char *)STRING_WITH_LEN("Ping"), +! (char *)STRING_WITH_LEN("Time"), +! (char *)STRING_WITH_LEN("Delayed insert"), +! (char *)STRING_WITH_LEN("Change user"), +! (char *)STRING_WITH_LEN("Binlog Dump"), +! (char *)STRING_WITH_LEN("Table Dump"), +! (char *)STRING_WITH_LEN("Connect Out"), +! (char *)STRING_WITH_LEN("Register Slave"), +! (char *)STRING_WITH_LEN("Prepare"), +! (char *)STRING_WITH_LEN("Execute"), +! (char *)STRING_WITH_LEN("Long Data"), +! (char *)STRING_WITH_LEN("Close stmt"), +! (char *)STRING_WITH_LEN("Reset stmt"), +! (char *)STRING_WITH_LEN("Set option"), +! (char *)STRING_WITH_LEN("Fetch"), +! (char *)STRING_WITH_LEN("Daemon"), +! (char *)STRING_WITH_LEN("Error") // Last command number + }; + + const char *xa_state_names[]={ +--- 67,108 ---- + static void decrease_user_connections(USER_CONN *uc); + #endif /* NO_EMBEDDED_ACCESS_CHECKS */ + static bool check_multi_update_lock(THD *thd); + static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables); + + const char *any_db="*any*"; // Special symbol for check_access + +! const LEX_STRING command_name[]={ +! C_STRING_WITH_LEN("Sleep"), +! C_STRING_WITH_LEN("Quit"), +! C_STRING_WITH_LEN("Init DB"), +! C_STRING_WITH_LEN("Query"), +! C_STRING_WITH_LEN("Field List"), +! C_STRING_WITH_LEN("Create DB"), +! C_STRING_WITH_LEN("Drop DB"), +! C_STRING_WITH_LEN("Refresh"), +! C_STRING_WITH_LEN("Shutdown"), +! C_STRING_WITH_LEN("Statistics"), +! C_STRING_WITH_LEN("Processlist"), +! C_STRING_WITH_LEN("Connect"), +! C_STRING_WITH_LEN("Kill"), +! C_STRING_WITH_LEN("Debug"), +! C_STRING_WITH_LEN("Ping"), +! C_STRING_WITH_LEN("Time"), +! C_STRING_WITH_LEN("Delayed insert"), +! C_STRING_WITH_LEN("Change user"), +! C_STRING_WITH_LEN("Binlog Dump"), +! C_STRING_WITH_LEN("Table Dump"), +! C_STRING_WITH_LEN("Connect Out"), +! C_STRING_WITH_LEN("Register Slave"), +! C_STRING_WITH_LEN("Prepare"), +! C_STRING_WITH_LEN("Execute"), +! C_STRING_WITH_LEN("Long Data"), +! C_STRING_WITH_LEN("Close stmt"), +! C_STRING_WITH_LEN("Reset stmt"), +! C_STRING_WITH_LEN("Set option"), +! C_STRING_WITH_LEN("Fetch"), +! C_STRING_WITH_LEN("Daemon"), +! C_STRING_WITH_LEN("Error") // Last command number + }; + + const char *xa_state_names[]={ +*************** +*** 1738,1744 **** + password. New clients send the size (1 byte) + string (not null + terminated, so also '\0' for empty string). + */ +! char db_buff[NAME_LEN+1]; // buffer to store db in utf8 + char *db= passwd; + uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ? + *passwd++ : strlen(passwd); +--- 1736,1742 ---- + password. New clients send the size (1 byte) + string (not null + terminated, so also '\0' for empty string). + */ +! char db_buff[NAME_LEN+1]; // buffer to store db in utf8 + char *db= passwd; + uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ? + *passwd++ : strlen(passwd); +*************** +*** 2315,2321 **** + DBUG_RETURN(1); + } + db= lex->select_lex.db; +- remove_escape(db); // Fix escaped '_' + if (check_db_name(db)) + { + my_error(ER_WRONG_DB_NAME, MYF(0), db); +--- 2312,2317 ---- + DBUG_RETURN(1); + } + db= lex->select_lex.db; + if (check_db_name(db)) + { + my_error(ER_WRONG_DB_NAME, MYF(0), db); +*************** +*** 6310,6345 **** + } + + +- /* Fix escaping of _, % and \ in database and table names (for ODBC) */ +- +- static void remove_escape(char *name) +- { +- if (!*name) // For empty DB names +- return; +- char *to; +- #ifdef USE_MB +- char *strend=name+(uint) strlen(name); +- #endif +- for (to=name; *name ; name++) +- { +- #ifdef USE_MB +- int l; +- if (use_mb(system_charset_info) && +- (l = my_ismbchar(system_charset_info, name, strend))) +- { +- while (l--) +- *to++ = *name++; +- name--; +- continue; +- } +- #endif +- if (*name == '\\' && name[1]) +- name++; // Skip '\\' +- *to++= *name; +- } +- *to=0; +- } +- + /**************************************************************************** + ** save order by and tables in own lists + ****************************************************************************/ +--- 6296,6301 ---- + } + + + /**************************************************************************** + ** save order by and tables in own lists + ****************************************************************************/ diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 8df527fd25b..266a5bad34d 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -4480,7 +4480,7 @@ that are reorganised. { if (!alt_part_info->use_default_partitions) { - DBUG_PRINT("info", ("part_info= %x", tab_part_info)); + DBUG_PRINT("info", ("part_info: 0x%lx", (long) tab_part_info)); tab_part_info->use_default_partitions= FALSE; } tab_part_info->use_default_no_partitions= FALSE; diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 013c3a17fd6..0c6a5fe5846 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -1665,7 +1665,7 @@ static bool check_prepared_statement(Prepared_statement *stmt, enum enum_sql_command sql_command= lex->sql_command; int res= 0; DBUG_ENTER("check_prepared_statement"); - DBUG_PRINT("enter",("command: %d, param_count: %ld", + DBUG_PRINT("enter",("command: %d, param_count: %u", sql_command, stmt->param_count)); lex->first_lists_tables_same(); @@ -1916,9 +1916,12 @@ void mysql_stmt_prepare(THD *thd, const char *packet, uint packet_length) thd->stmt_map.erase(stmt); } else - general_log_print(thd, COM_STMT_PREPARE, "[%lu] %.*b", stmt->id, + { + const char *format= "[%lu] %.*b"; + general_log_print(thd, COM_STMT_PREPARE, format, stmt->id, stmt->query_length, stmt->query); + } /* check_prepared_statemnt sends the metadata packet in case of success */ DBUG_VOID_RETURN; } @@ -2262,7 +2265,7 @@ void mysql_stmt_execute(THD *thd, char *packet_arg, uint packet_length) DBUG_VOID_RETURN; DBUG_PRINT("exec_query", ("%s", stmt->query)); - DBUG_PRINT("info",("stmt: %p", stmt)); + DBUG_PRINT("info",("stmt: 0x%lx", (long) stmt)); sp_cache_flush_obsolete(&thd->sp_proc_cache); sp_cache_flush_obsolete(&thd->sp_func_cache); @@ -2300,9 +2303,11 @@ void mysql_stmt_execute(THD *thd, char *packet_arg, uint packet_length) if (!(specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(), WAIT_PRIOR); if (error == 0) - general_log_print(thd, COM_STMT_EXECUTE, "[%lu] %.*b", stmt->id, + { + const char *format= "[%lu] %.*b"; + general_log_print(thd, COM_STMT_EXECUTE, format, stmt->id, thd->query_length, thd->query); - + } DBUG_VOID_RETURN; set_params_data_err: @@ -2355,7 +2360,7 @@ void mysql_sql_stmt_execute(THD *thd) DBUG_VOID_RETURN; } - DBUG_PRINT("info",("stmt: %p", stmt)); + DBUG_PRINT("info",("stmt: 0x%lx", (long) stmt)); /* If the free_list is not empty, we'll wrongly free some externally @@ -2719,7 +2724,8 @@ void Prepared_statement::setup_set_params() Prepared_statement::~Prepared_statement() { DBUG_ENTER("Prepared_statement::~Prepared_statement"); - DBUG_PRINT("enter",("stmt: %p cursor: %p", this, cursor)); + DBUG_PRINT("enter",("stmt: 0x%lx cursor: 0x%lx", + (long) this, (long) cursor)); delete cursor; /* We have to call free on the items even if cleanup is called as some items, @@ -2740,7 +2746,7 @@ Query_arena::Type Prepared_statement::type() const void Prepared_statement::cleanup_stmt() { DBUG_ENTER("Prepared_statement::cleanup_stmt"); - DBUG_PRINT("enter",("stmt: %p", this)); + DBUG_PRINT("enter",("stmt: 0x%lx", (long) this)); /* The order is important */ lex->unit.cleanup(); diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 52489087b02..d4f6288c298 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -431,6 +431,12 @@ impossible position"; goto err; } packet->set("\0", 1, &my_charset_bin); + /* + Adding MAX_LOG_EVENT_HEADER_LEN, since a binlog event can become + this larger than the corresponding packet (query) sent + from client to master. + */ + thd->variables.max_allowed_packet+= MAX_LOG_EVENT_HEADER; /* We can set log_lock now, it does not move (it's a member of @@ -805,7 +811,7 @@ int start_slave(THD* thd , MASTER_INFO* mi, bool net_report) sizeof(mi->rli.until_log_name)-1); } else - clear_until_condition(&mi->rli); + mi->rli.clear_until_condition(); if (mi->rli.until_condition != RELAY_LOG_INFO::UNTIL_NONE) { @@ -978,8 +984,8 @@ int reset_slave(THD *thd, MASTER_INFO* mi) Reset errors (the idea is that we forget about the old master). */ - clear_slave_error(&mi->rli); - clear_until_condition(&mi->rli); + mi->rli.clear_slave_error(); + mi->rli.clear_until_condition(); // close master_info_file, relay_log_info_file, set mi->inited=rli->inited=0 end_master_info(mi); @@ -1105,7 +1111,7 @@ bool change_master(THD* thd, MASTER_INFO* mi) { mi->master_log_pos= lex_mi->pos; } - DBUG_PRINT("info", ("master_log_pos: %d", (ulong) mi->master_log_pos)); + DBUG_PRINT("info", ("master_log_pos: %lu", (ulong) mi->master_log_pos)); if (lex_mi->host) strmake(mi->host, lex_mi->host, sizeof(mi->host)-1); @@ -1222,7 +1228,7 @@ bool change_master(THD* thd, MASTER_INFO* mi) } } mi->rli.group_master_log_pos = mi->master_log_pos; - DBUG_PRINT("info", ("master_log_pos: %d", (ulong) mi->master_log_pos)); + DBUG_PRINT("info", ("master_log_pos: %lu", (ulong) mi->master_log_pos)); /* Coordinates in rli were spoilt by the 'if (need_relay_log_purge)' block, @@ -1244,8 +1250,8 @@ bool change_master(THD* thd, MASTER_INFO* mi) pthread_mutex_lock(&mi->rli.data_lock); mi->rli.abort_pos_wait++; /* for MASTER_POS_WAIT() to abort */ /* Clear the errors, for a clean start */ - clear_slave_error(&mi->rli); - clear_until_condition(&mi->rli); + mi->rli.clear_slave_error(); + mi->rli.clear_until_condition(); /* If we don't write new coordinates to disk now, then old will remain in relay-log.info until START SLAVE is issued; but if mysqld is shutdown diff --git a/sql/sql_select.cc b/sql/sql_select.cc index d40d9f16bb5..7ea8c6f4dfa 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -8723,6 +8723,7 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table, item->collation.collation); else new_field= item->make_string_field(table); + new_field->set_derivation(item->collation.derivation); break; case DECIMAL_RESULT: new_field= new Field_new_decimal(item->max_length, maybe_null, item->name, @@ -8908,7 +8909,9 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, (make_copy_field ? 0 : copy_func), modify_item, convert_blob_length); case Item::TYPE_HOLDER: - return ((Item_type_holder *)item)->make_field_by_type(table); + result= ((Item_type_holder *)item)->make_field_by_type(table); + result->set_derivation(item->collation.derivation); + return result; default: // Dosen't have to be stored return 0; } @@ -9488,7 +9491,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, bool maybe_null=(*cur_group->item)->maybe_null; key_part_info->null_bit=0; key_part_info->field= field; - key_part_info->offset= field->offset(); + key_part_info->offset= field->offset(table->record[0]); key_part_info->length= (uint16) field->key_length(); key_part_info->type= (uint8) field->key_type(); key_part_info->key_type = @@ -9585,7 +9588,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, { key_part_info->null_bit=0; key_part_info->field= *reg_field; - key_part_info->offset= (*reg_field)->offset(); + key_part_info->offset= (*reg_field)->offset(table->record[0]); key_part_info->length= (uint16) (*reg_field)->pack_length(); key_part_info->type= (uint8) (*reg_field)->key_type(); key_part_info->key_type = @@ -10177,7 +10180,7 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure) if (join->result->send_eof()) rc= 1; // Don't send error } - DBUG_PRINT("info",("%ld records output",join->send_records)); + DBUG_PRINT("info",("%ld records output", (long) join->send_records)); } else rc= -1; @@ -12557,8 +12560,9 @@ remove_duplicates(JOIN *join, TABLE *entry,List<Item> &fields, Item *having) DBUG_RETURN(0); } Field **first_field=entry->field+entry->s->fields - field_count; - offset= field_count ? - entry->field[entry->s->fields - field_count]->offset() : 0; + offset= (field_count ? + entry->field[entry->s->fields - field_count]-> + offset(entry->record[0]) : 0); reclength=entry->s->reclength-offset; free_io_cache(entry); // Safety diff --git a/sql/sql_show.cc b/sql/sql_show.cc index f6e39fb7913..dc8946df876 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1058,6 +1058,9 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet, packet->append(STRING_WITH_LEN("CREATE TEMPORARY TABLE ")); else packet->append(STRING_WITH_LEN("CREATE TABLE ")); + if (create_info_arg && + (create_info_arg->options & HA_LEX_CREATE_IF_NOT_EXISTS)) + packet->append(STRING_WITH_LEN("IF NOT EXISTS ")); if (table_list->schema_table) alias= table_list->schema_table->table_name; else diff --git a/sql/sql_string.cc b/sql/sql_string.cc index 6e4d3f2ed0a..29b53560067 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -844,6 +844,162 @@ outp: } +/* + copy a string, + with optional character set conversion, + with optional left padding (for binary -> UCS2 conversion) + + SYNOPSIS + well_formed_copy_nhars() + to Store result here + to_length Maxinum length of "to" string + to_cs Character set of "to" string + from Copy from here + from_length Length of from string + from_cs From character set + nchars Copy not more that nchars characters + well_formed_error_pos Return position when "from" is not well formed + or NULL otherwise. + cannot_convert_error_pos Return position where a not convertable + character met, or NULL otherwise. + from_end_pos Return position where scanning of "from" + string stopped. + NOTES + + RETURN + length of bytes copied to 'to' +*/ + + +uint32 +well_formed_copy_nchars(CHARSET_INFO *to_cs, + char *to, uint to_length, + CHARSET_INFO *from_cs, + const char *from, uint from_length, + uint nchars, + const char **well_formed_error_pos, + const char **cannot_convert_error_pos, + const char **from_end_pos) +{ + uint res; + + if ((to_cs == &my_charset_bin) || + (from_cs == &my_charset_bin) || + (to_cs == from_cs) || + my_charset_same(from_cs, to_cs)) + { + if (to_length < to_cs->mbminlen || !nchars) + { + *from_end_pos= from; + *cannot_convert_error_pos= NULL; + *well_formed_error_pos= NULL; + return 0; + } + + if (to_cs == &my_charset_bin) + { + res= min(min(nchars, to_length), from_length); + memmove(to, from, res); + *from_end_pos= from + res; + *well_formed_error_pos= NULL; + *cannot_convert_error_pos= NULL; + } + else + { + int well_formed_error; + uint from_offset; + + if ((from_offset= (from_length % to_cs->mbminlen)) && + (from_cs == &my_charset_bin)) + { + /* + Copying from BINARY to UCS2 needs to prepend zeros sometimes: + INSERT INTO t1 (ucs2_column) VALUES (0x01); + 0x01 -> 0x0001 + */ + uint pad_length= to_cs->mbminlen - from_offset; + bzero(to, pad_length); + memmove(to + pad_length, from, from_offset); + nchars--; + from+= from_offset; + from_length-= from_offset; + to+= to_cs->mbminlen; + to_length-= to_cs->mbminlen; + } + + set_if_smaller(from_length, to_length); + res= to_cs->cset->well_formed_len(to_cs, from, from + from_length, + nchars, &well_formed_error); + memmove(to, from, res); + *from_end_pos= from + res; + *well_formed_error_pos= well_formed_error ? from + res : NULL; + *cannot_convert_error_pos= NULL; + if (from_offset) + res+= to_cs->mbminlen; + } + } + else + { + int cnvres; + my_wc_t wc; + int (*mb_wc)(struct charset_info_st *, my_wc_t *, + const uchar *, const uchar *)= from_cs->cset->mb_wc; + int (*wc_mb)(struct charset_info_st *, my_wc_t, + uchar *s, uchar *e)= to_cs->cset->wc_mb; + const uchar *from_end= (const uchar*) from + from_length; + uchar *to_end= (uchar*) to + to_length; + char *to_start= to; + *well_formed_error_pos= NULL; + *cannot_convert_error_pos= NULL; + + for ( ; nchars; nchars--) + { + const char *from_prev= from; + if ((cnvres= (*mb_wc)(from_cs, &wc, (uchar*) from, from_end)) > 0) + from+= cnvres; + else if (cnvres == MY_CS_ILSEQ) + { + if (!*well_formed_error_pos) + *well_formed_error_pos= from; + from++; + wc= '?'; + } + else if (cnvres > MY_CS_TOOSMALL) + { + /* + A correct multibyte sequence detected + But it doesn't have Unicode mapping. + */ + if (!*cannot_convert_error_pos) + *cannot_convert_error_pos= from; + from+= (-cnvres); + wc= '?'; + } + else + break; // Not enough characters + +outp: + if ((cnvres= (*wc_mb)(to_cs, wc, (uchar*) to, to_end)) > 0) + to+= cnvres; + else if (cnvres == MY_CS_ILUNI && wc != '?') + { + if (!*cannot_convert_error_pos) + *cannot_convert_error_pos= from_prev; + wc= '?'; + goto outp; + } + else + break; + } + *from_end_pos= from; + res= to - to_start; + } + return (uint32) res; +} + + + + void String::print(String *str) { char *st= (char*)Ptr, *end= st+str_length; diff --git a/sql/sql_string.h b/sql/sql_string.h index b1d417be2c2..a72b24ae9d0 100644 --- a/sql/sql_string.h +++ b/sql/sql_string.h @@ -30,6 +30,14 @@ String *copy_if_not_alloced(String *a,String *b,uint32 arg_length); uint32 copy_and_convert(char *to, uint32 to_length, CHARSET_INFO *to_cs, const char *from, uint32 from_length, CHARSET_INFO *from_cs, uint *errors); +uint32 well_formed_copy_nchars(CHARSET_INFO *to_cs, + char *to, uint to_length, + CHARSET_INFO *from_cs, + const char *from, uint from_length, + uint nchars, + const char **well_formed_error_pos, + const char **cannot_convert_error_pos, + const char **from_end_pos); class String { diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 511d9fa6677..1f00275621a 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3743,7 +3743,7 @@ static void wait_while_table_is_used(THD *thd,TABLE *table, enum ha_extra_function function) { DBUG_ENTER("wait_while_table_is_used"); - DBUG_PRINT("enter", ("table: '%s' share: 0x%lx db_stat: %u version: %u", + DBUG_PRINT("enter", ("table: '%s' share: 0x%lx db_stat: %u version: %lu", table->s->table_name.str, (ulong) table->s, table->db_stat, table->s->version)); @@ -4631,7 +4631,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, my_error(ER_WRONG_TABLE_NAME, MYF(0), src_table); DBUG_RETURN(TRUE); } - if (!src_db || check_db_name(src_db)) + if (!src_db || check_db_name(&table_ident->db)) { my_error(ER_WRONG_DB_NAME, MYF(0), src_db ? src_db : "NULL"); DBUG_RETURN(-1); diff --git a/sql/sql_test.cc b/sql/sql_test.cc index c4c40ea63c8..219ca8260ed 100644 --- a/sql/sql_test.cc +++ b/sql/sql_test.cc @@ -248,14 +248,15 @@ print_plan(JOIN* join, uint idx, double record_count, double read_time, if (join->best_read == DBL_MAX) { fprintf(DBUG_FILE, - "%s; idx:%u, best: DBL_MAX, atime: %g, itime: %g, count: %g\n", - info, idx, current_read_time, read_time, record_count); + "%s; idx: %u best: DBL_MAX atime: %g itime: %g count: %g\n", + info, idx, current_read_time, read_time, record_count); } else { fprintf(DBUG_FILE, - "%s; idx:%u, best: %g, accumulated: %g, increment: %g, count: %g\n", - info, idx, join->best_read, current_read_time, read_time, record_count); + "%s; idx :%u best: %g accumulated: %g increment: %g count: %g\n", + info, idx, join->best_read, current_read_time, read_time, + record_count); } /* Print the tables in JOIN->positions */ diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index fb56b7ae3b0..8baf84585b2 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -1612,7 +1612,7 @@ Handle_old_incorrect_sql_modes_hook::process_unknown_string(char *&unknown_key, char *end) { DBUG_ENTER("Handle_old_incorrect_sql_modes_hook::process_unknown_string"); - DBUG_PRINT("info", ("unknown key:%60s", unknown_key)); + DBUG_PRINT("info", ("unknown key: %60s", unknown_key)); if (unknown_key + INVALID_SQL_MODES_LENGTH + 1 < end && unknown_key[INVALID_SQL_MODES_LENGTH] == '=' && @@ -1654,7 +1654,7 @@ process_unknown_string(char *&unknown_key, gptr base, MEM_ROOT *mem_root, char *end) { DBUG_ENTER("Handle_old_incorrect_trigger_table_hook::process_unknown_string"); - DBUG_PRINT("info", ("unknown key:%60s", unknown_key)); + DBUG_PRINT("info", ("unknown key: %60s", unknown_key)); if (unknown_key + INVALID_TRIGGER_TABLE_LENGTH + 1 < end && unknown_key[INVALID_TRIGGER_TABLE_LENGTH] == '=' && diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 1d119b99df0..2575f17d256 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -691,7 +691,7 @@ int mysql_update(THD *thd, thd->row_count_func= (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated; send_ok(thd, (ulong) thd->row_count_func, id, buff); - DBUG_PRINT("info",("%d records updated",updated)); + DBUG_PRINT("info",("%ld records updated", (long) updated)); } thd->count_cuted_fields= CHECK_FIELD_IGNORE; /* calc cuted fields */ thd->abort_on_warning= 0; @@ -788,7 +788,7 @@ static table_map get_table_map(List<Item> *items) while ((item= (Item_field *) item_it++)) map|= item->used_tables(); - DBUG_PRINT("info",("table_map: 0x%08x", map)); + DBUG_PRINT("info", ("table_map: 0x%08lx", (long) map)); return map; } diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 5bf67af9271..98226c1651b 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -1695,24 +1695,23 @@ mysql_rename_view(THD *thd, const char *new_name, TABLE_LIST *view) { - LEX_STRING pathstr, file; + LEX_STRING pathstr; File_parser *parser; - char view_path[FN_REFLEN]; + char path_buff[FN_REFLEN]; bool error= TRUE; DBUG_ENTER("mysql_rename_view"); - strxnmov(view_path, FN_REFLEN-1, mysql_data_home, "/", view->db, "/", - view->table_name, reg_ext, NullS); - (void) unpack_filename(view_path, view_path); - - pathstr.str= (char *)view_path; - pathstr.length= strlen(view_path); + pathstr.str= (char *) path_buff; + pathstr.length= build_table_filename(path_buff, sizeof(path_buff) - 1, + view->db, view->table_name, + reg_ext, 0); if ((parser= sql_parse_prepare(&pathstr, thd->mem_root, 1)) && is_equal(&view_type, parser->type())) { TABLE_LIST view_def; - char dir_buff[FN_REFLEN], file_buff[FN_REFLEN]; + char dir_buff[FN_REFLEN]; + LEX_STRING dir, file; /* To be PS-friendly we should either to restore state of @@ -1735,18 +1734,18 @@ mysql_rename_view(THD *thd, view_def.revision - 1, num_view_backups)) goto err; - strxnmov(dir_buff, FN_REFLEN-1, mysql_data_home, "/", view->db, "/", - NullS); - (void) unpack_filename(dir_buff, dir_buff); + dir.str= dir_buff; + dir.length= build_table_filename(dir_buff, sizeof(dir_buff) - 1, + view->db, "", "", 0); - pathstr.str= (char*)dir_buff; - pathstr.length= strlen(dir_buff); + pathstr.str= path_buff; + pathstr.length= build_table_filename(path_buff, sizeof(path_buff) - 1, + view->db, new_name, reg_ext, 0); - file.str= file_buff; - file.length= (strxnmov(file_buff, FN_REFLEN, new_name, reg_ext, NullS) - - file_buff); + file.str= pathstr.str + dir.length; + file.length= pathstr.length - dir.length; - if (sql_create_definition_file(&pathstr, &file, view_file_type, + if (sql_create_definition_file(&dir, &file, view_file_type, (gptr)&view_def, view_parameters, num_view_backups)) { diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index a439c859a6b..97881502686 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -746,7 +746,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); LEX_HOSTNAME ULONGLONG_NUM field_ident select_alias ident ident_or_text UNDERSCORE_CHARSET IDENT_sys TEXT_STRING_sys TEXT_STRING_literal NCHAR_STRING opt_component key_cache_name - sp_opt_label BIN_NUM label_ident TEXT_STRING_filesystem + sp_opt_label BIN_NUM label_ident TEXT_STRING_filesystem ident_or_empty %type <lex_str_ptr> opt_table_alias @@ -756,7 +756,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %type <simple_string> remember_name remember_end opt_ident opt_db text_or_password - opt_constraint constraint ident_or_empty + opt_constraint constraint %type <string> text_string opt_gconcat_separator @@ -1240,7 +1240,8 @@ create: lex->create_info.options=$2 | $4; lex->create_info.db_type= lex->thd->variables.table_type; lex->create_info.default_table_charset= NULL; - lex->name= 0; + lex->name.str= 0; + lex->name.length= 0; lex->like_name= 0; } create2 @@ -1280,7 +1281,7 @@ create: { LEX *lex=Lex; lex->sql_command=SQLCOM_CREATE_DB; - lex->name=$4.str; + lex->name= $4; lex->create_info.options=$3; } | CREATE @@ -1515,7 +1516,7 @@ clear_privileges: sp_name: ident '.' ident { - if (!$1.str || check_db_name($1.str)) + if (!$1.str || check_db_name(&$1)) { my_error(ER_WRONG_DB_NAME, MYF(0), $1.str); YYABORT; @@ -3148,7 +3149,7 @@ size_number: uint text_shift_number= 0; longlong prefix_number; char *start_ptr= $1.str; - uint str_len= strlen(start_ptr); + uint str_len= $1.length; char *end_ptr= start_ptr + str_len; int error; prefix_number= my_strtoll10(start_ptr, &end_ptr, &error); @@ -4672,7 +4673,8 @@ alter: { THD *thd= YYTHD; LEX *lex= thd->lex; - lex->name= 0; + lex->name.str= 0; + lex->name.length= 0; lex->sql_command= SQLCOM_ALTER_TABLE; lex->duplicates= DUP_ERROR; if (!lex->select_lex.add_table_to_list(thd, $4, NULL, @@ -4682,7 +4684,6 @@ alter: lex->key_list.empty(); lex->col_list.empty(); lex->select_lex.init_order(); - lex->name= 0; lex->like_name= 0; lex->select_lex.db= ((TABLE_LIST*) lex->select_lex.table_list.first)->db; @@ -4707,7 +4708,8 @@ alter: THD *thd= Lex->thd; lex->sql_command=SQLCOM_ALTER_DB; lex->name= $3; - if (lex->name == NULL && thd->copy_db_to(&lex->name, NULL)) + if (lex->name.str == NULL && + thd->copy_db_to(&lex->name.str, &lex->name.length)) YYABORT; } | ALTER PROCEDURE sp_name @@ -4857,8 +4859,8 @@ opt_ev_sql_stmt: /* empty*/ { $$= 0;} ident_or_empty: - /* empty */ { $$= 0; } - | ident { $$= $1.str; }; + /* empty */ { $$.str= 0; $$.length= 0; } + | ident { $$= $1; }; alter_commands: | DISCARD TABLESPACE { Lex->alter_info.tablespace_op= DISCARD_TABLESPACE; } @@ -5136,19 +5138,20 @@ alter_list_item: { LEX *lex=Lex; THD *thd= lex->thd; + uint dummy; lex->select_lex.db=$3->db.str; if (lex->select_lex.db == NULL && - thd->copy_db_to(&lex->select_lex.db, NULL)) + thd->copy_db_to(&lex->select_lex.db, &dummy)) { YYABORT; } if (check_table_name($3->table.str,$3->table.length) || - $3->db.str && check_db_name($3->db.str)) + $3->db.str && check_db_name(&$3->db)) { my_error(ER_WRONG_TABLE_NAME, MYF(0), $3->table.str); YYABORT; } - lex->name= $3->table.str; + lex->name= $3->table; lex->alter_info.flags|= ALTER_RENAME; } | CONVERT_SYM TO_SYM charset charset_name_or_default opt_collate @@ -7681,7 +7684,7 @@ drop: LEX *lex=Lex; lex->sql_command= SQLCOM_DROP_DB; lex->drop_if_exists=$3; - lex->name=$4.str; + lex->name= $4; } | DROP FUNCTION_SYM if_exists sp_name { @@ -8328,7 +8331,7 @@ show_param: { Lex->sql_command=SQLCOM_SHOW_CREATE_DB; Lex->create_info.options=$3; - Lex->name=$4.str; + Lex->name= $4; } | CREATE TABLE_SYM table_ident { @@ -10333,7 +10336,8 @@ grant_ident: { LEX *lex= Lex; THD *thd= lex->thd; - if (thd->copy_db_to(&lex->current_select->db, NULL)) + uint dummy; + if (thd->copy_db_to(&lex->current_select->db, &dummy)) YYABORT; if (lex->grant == GLOBAL_ACLS) lex->grant = DB_ACLS & ~GRANT_ACL; diff --git a/sql/strfunc.cc b/sql/strfunc.cc index ef769a5b16e..2d2530eb876 100644 --- a/sql/strfunc.cc +++ b/sql/strfunc.cc @@ -150,7 +150,7 @@ uint find_type2(TYPELIB *typelib, const char *x, uint length, CHARSET_INFO *cs) int pos; const char *j; DBUG_ENTER("find_type2"); - DBUG_PRINT("enter",("x: '%.*s' lib: 0x%lx", length, x, typelib)); + DBUG_PRINT("enter",("x: '%.*s' lib: 0x%lx", length, x, (long) typelib)); if (!typelib->count) { diff --git a/sql/table.cc b/sql/table.cc index 7f80b95c954..762206c7eb8 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -30,7 +30,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, File file); static void fix_type_pointers(const char ***array, TYPELIB *point_to_type, uint types, char **names); -static uint find_field(Field **fields, uint start, uint length); +static uint find_field(Field **fields, byte *record, uint start, uint length); /* Get column name from column hash */ @@ -1069,6 +1069,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, Field *field; if (new_field_pack_flag <= 1) key_part->fieldnr= (uint16) find_field(share->field, + share->default_values, (uint) key_part->offset, (uint) key_part->length); if (!key_part->fieldnr) @@ -1232,24 +1233,19 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, if (share->found_next_number_field) { - /* - We must have a table object for find_ref_key to calculate field offset - */ - TABLE tmp_table; - tmp_table.record[0]= share->default_values; - reg_field= *share->found_next_number_field; - reg_field->table= &tmp_table; if ((int) (share->next_number_index= (uint) - find_ref_key(share->key_info, share->keys, reg_field, + find_ref_key(share->key_info, share->keys, + share->default_values, reg_field, &share->next_number_key_offset)) < 0) { + /* Wrong field definition */ + DBUG_ASSERT(0); reg_field->unireg_check= Field::NONE; /* purecov: inspected */ share->found_next_number_field= 0; } else reg_field->flags |= AUTO_INCREMENT_FLAG; - reg_field->table= 0; } if (share->blob_fields) @@ -1343,7 +1339,7 @@ int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias, Field **field_ptr; DBUG_ENTER("open_table_from_share"); DBUG_PRINT("enter",("name: '%s.%s' form: 0x%lx", share->db.str, - share->table_name.str, outparam)); + share->table_name.str, (long) outparam)); error= 1; bzero((char*) outparam, sizeof(*outparam)); @@ -1969,7 +1965,7 @@ TYPELIB *typelib(MEM_ROOT *mem_root, List<String> &strings) # field number +1 */ -static uint find_field(Field **fields, uint start, uint length) +static uint find_field(Field **fields, byte *record, uint start, uint length) { Field **field; uint i, pos; @@ -1977,7 +1973,7 @@ static uint find_field(Field **fields, uint start, uint length) pos= 0; for (field= fields, i=1 ; *field ; i++,field++) { - if ((*field)->offset() == start) + if ((*field)->offset(record) == start) { if ((*field)->key_length() == length) return (i); @@ -2258,7 +2254,7 @@ char *get_field(MEM_ROOT *mem, Field *field) SYNPOSIS check_db_name() - name Name of database + org_name Name of database and length NOTES If lower_case_table_names is set then database is converted to lower case @@ -2268,35 +2264,35 @@ char *get_field(MEM_ROOT *mem, Field *field) 1 error */ -bool check_db_name(char *name) +bool check_db_name(LEX_STRING *org_name) { - char *start= name; - /* Used to catch empty names and names with end space */ - bool last_char_is_space= TRUE; + char *name= org_name->str; + + if (!org_name->length || org_name->length > NAME_LEN) + return 1; if (lower_case_table_names && name != any_db) my_casedn_str(files_charset_info, name); - while (*name) - { #if defined(USE_MB) && defined(USE_MB_IDENT) - last_char_is_space= my_isspace(system_charset_info, *name); - if (use_mb(system_charset_info)) + if (use_mb(system_charset_info)) + { + bool last_char_is_space= TRUE; + char *end= name + org_name->length; + while (name < end) { - int len=my_ismbchar(system_charset_info, name, - name+system_charset_info->mbmaxlen); - if (len) - { - name += len; - continue; - } + int len; + last_char_is_space= my_isspace(system_charset_info, *name); + len= my_ismbchar(system_charset_info, name, end); + if (!len) + len= 1; + name+= len; } -#else - last_char_is_space= *name==' '; -#endif - name++; + return last_char_is_space; } - return last_char_is_space || (uint) (name - start) > NAME_LEN; + else +#endif + return org_name->str[org_name->length - 1] != ' '; /* purecov: inspected */ } @@ -2405,8 +2401,8 @@ table_check_intact(TABLE *table, const uint table_f_count, my_bool error= FALSE; my_bool fields_diff_count; DBUG_ENTER("table_check_intact"); - DBUG_PRINT("info",("table=%s expected_count=%d",table->alias, table_f_count)); - DBUG_PRINT("info",("last_create_time=%d", *last_create_time)); + DBUG_PRINT("info",("table: %s expected_count: %d last_create_time: %ld", + table->alias, table_f_count, *last_create_time)); if ((fields_diff_count= (table->s->fields != table_f_count)) || (*last_create_time != table->file->stats.create_time)) diff --git a/sql/table.cc.rej b/sql/table.cc.rej new file mode 100644 index 00000000000..fd728ba9965 --- /dev/null +++ b/sql/table.cc.rej @@ -0,0 +1,17 @@ +*************** +*** 2246,2252 **** + + bool check_db_name(char *name) + { +! char *start=name; + /* Used to catch empty names and names with end space */ + bool last_char_is_space= TRUE; + +--- 2257,2263 ---- + + bool check_db_name(char *name) + { +! char *start= name; + /* Used to catch empty names and names with end space */ + bool last_char_is_space= TRUE; + diff --git a/sql/tztime.cc b/sql/tztime.cc index 3d9f278b3f7..6acf17520d9 100644 --- a/sql/tztime.cc +++ b/sql/tztime.cc @@ -961,13 +961,12 @@ TIME_to_gmt_sec(const TIME *t, const TIME_ZONE_INFO *sp, */ if (shift) { - if (local_t > (TIMESTAMP_MAX_VALUE - shift*86400L + - sp->revtis[i].rt_offset - saved_seconds)) + if (local_t > (my_time_t) (TIMESTAMP_MAX_VALUE - shift*86400L + + sp->revtis[i].rt_offset - saved_seconds)) { DBUG_RETURN(0); /* my_time_t overflow */ } - else - local_t+= shift*86400L; + local_t+= shift*86400L; } if (sp->revtis[i].rt_type) @@ -1744,8 +1743,8 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap) tz_leapcnt++; DBUG_PRINT("info", - ("time_zone_leap_second table: tz_leapcnt=%u tt_time=%lld offset=%ld", - tz_leapcnt, (longlong)tz_lsis[tz_leapcnt-1].ls_trans, + ("time_zone_leap_second table: tz_leapcnt:%u tt_time: %lu offset: %ld", + tz_leapcnt, (ulong) tz_lsis[tz_leapcnt-1].ls_trans, tz_lsis[tz_leapcnt-1].ls_corr)); res= table->file->index_next(table->record[0]); @@ -2058,8 +2057,8 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables) tz_info->timecnt++; DBUG_PRINT("info", - ("time_zone_transition table: tz_id=%u tt_time=%lld tt_id=%u", - tzid, (longlong)ttime, ttid)); + ("time_zone_transition table: tz_id: %u tt_time:%lu tt_id: %u", + tzid, (ulong) ttime, ttid)); res= table->file->index_next_same(table->record[0], (byte*)table->field[0]->ptr, 4); diff --git a/sql/unireg.cc b/sql/unireg.cc index a20c59fd796..4514f969913 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -469,16 +469,16 @@ static uint pack_keys(uchar *keybuff, uint key_count, KEY *keyinfo, int2store(pos+6, key->block_size); pos+=8; key_parts+=key->key_parts; - DBUG_PRINT("loop",("flags: %d key_parts: %d at 0x%lx", - key->flags,key->key_parts, - key->key_part)); + DBUG_PRINT("loop", ("flags: %d key_parts: %d at 0x%lx", + key->flags, key->key_parts, + (long) key->key_part)); for (key_part=key->key_part,key_part_end=key_part+key->key_parts ; key_part != key_part_end ; key_part++) { uint offset; - DBUG_PRINT("loop",("field: %d startpos: %lu length: %ld", + DBUG_PRINT("loop",("field: %d startpos: %lu length: %d", key_part->fieldnr, key_part->offset + data_offset, key_part->length)); int2store(pos,key_part->fieldnr+1+FIELD_NAME_USED); |