diff options
author | Konstantin Osipov <kostja@sun.com> | 2010-02-02 02:22:16 +0300 |
---|---|---|
committer | Konstantin Osipov <kostja@sun.com> | 2010-02-02 02:22:16 +0300 |
commit | 2c6015e8dc962bef8f353af920581d9b6bd7fd82 (patch) | |
tree | a19075577cf795c631e5ac514d6dac52880f9b86 /sql | |
parent | ca2b08e437d4c5538b40aa61fa44f68ddd74bc42 (diff) | |
parent | 92630be0ee81604ec47cb8c7e9ab016e5449dc4d (diff) | |
download | mariadb-git-2c6015e8dc962bef8f353af920581d9b6bd7fd82.tar.gz |
Merge next-mr -> next-4284.
Diffstat (limited to 'sql')
67 files changed, 2135 insertions, 1357 deletions
diff --git a/sql/.cvsignore b/sql/.cvsignore deleted file mode 100644 index 3e2f44f5a10..00000000000 --- a/sql/.cvsignore +++ /dev/null @@ -1,12 +0,0 @@ -.deps -.libs -Makefile -Makefile.in -deadlock_test.c -gen_lex_hash -lex_hash.h -mysqlbinlog -mysqlbinlog -mysqld -sql_yacc.cc -sql_yacc.h diff --git a/sql/debug_sync.cc b/sql/debug_sync.cc index 81870e6b7a3..3c8e24f6901 100644 --- a/sql/debug_sync.cc +++ b/sql/debug_sync.cc @@ -221,14 +221,14 @@ There are quite a few places in MySQL, where we use a synchronization pattern like this: - pthread_mutex_lock(&mutex); + mysql_mutex_lock(&mutex); thd->enter_cond(&condition_variable, &mutex, new_message); #if defined(ENABLE_DEBUG_SYNC) if (!thd->killed && !end_of_wait_condition) DEBUG_SYNC(thd, "sync_point_name"); #endif while (!thd->killed && !end_of_wait_condition) - pthread_cond_wait(&condition_variable, &mutex); + mysql_cond_wait(&condition_variable, &mutex); thd->exit_cond(old_message); Here some explanations: @@ -264,12 +264,12 @@ while (!thd->killed && !end_of_wait_condition) { - pthread_mutex_lock(&mutex); + mysql_mutex_lock(&mutex); thd->enter_cond(&condition_variable, &mutex, new_message); if (!thd->killed [&& !end_of_wait_condition]) { [DEBUG_SYNC(thd, "sync_point_name");] - pthread_cond_wait(&condition_variable, &mutex); + mysql_cond_wait(&condition_variable, &mutex); } thd->exit_cond(old_message); } @@ -285,7 +285,7 @@ before sleeping, we hold the mutex, which is registered in mysys_var. The killing thread would try to acquire the mutex before signaling the condition variable. Since the mutex is only released implicitly in - pthread_cond_wait(), the signaling happens at the right place. We + mysql_cond_wait(), the signaling happens at the right place. We have a safe synchronization. === Co-work with the DBUG facility === @@ -373,8 +373,8 @@ struct st_debug_sync_control struct st_debug_sync_globals { String ds_signal; /* signal variable */ - pthread_cond_t ds_cond; /* condition variable */ - pthread_mutex_t ds_mutex; /* mutex variable */ + mysql_cond_t ds_cond; /* condition variable */ + mysql_mutex_t ds_mutex; /* mutex variable */ ulonglong dsp_hits; /* statistics */ ulonglong dsp_executed; /* statistics */ ulonglong dsp_max_active; /* statistics */ @@ -425,6 +425,37 @@ static void debug_sync_C_callback(const char *sync_point_name, debug_sync(current_thd, sync_point_name, name_len); } +#ifdef HAVE_PSI_INTERFACE +static PSI_mutex_key key_debug_sync_globals_ds_mutex; + +static PSI_mutex_info all_debug_sync_mutexes[]= +{ + { &key_debug_sync_globals_ds_mutex, "DEBUG_SYNC::mutex", PSI_FLAG_GLOBAL} +}; + +static PSI_cond_key key_debug_sync_globals_ds_cond; + +static PSI_cond_info all_debug_sync_conds[]= +{ + { &key_debug_sync_globals_ds_cond, "DEBUG_SYNC::cond", PSI_FLAG_GLOBAL} +}; + +static void init_debug_sync_psi_keys(void) +{ + const char* category= "sql"; + int count; + + if (PSI_server == NULL) + return; + + count= array_elements(all_debug_sync_mutexes); + PSI_server->register_mutex(category, all_debug_sync_mutexes, count); + + count= array_elements(all_debug_sync_conds); + PSI_server->register_cond(category, all_debug_sync_conds, count); +} +#endif /* HAVE_PSI_INTERFACE */ + /** Initialize the debug sync facility at server start. @@ -438,15 +469,21 @@ int debug_sync_init(void) { DBUG_ENTER("debug_sync_init"); +#ifdef HAVE_PSI_INTERFACE + init_debug_sync_psi_keys(); +#endif + if (opt_debug_sync_timeout) { int rc; /* Initialize the global variables. */ debug_sync_global.ds_signal.length(0); - if ((rc= pthread_cond_init(&debug_sync_global.ds_cond, NULL)) || - (rc= pthread_mutex_init(&debug_sync_global.ds_mutex, - MY_MUTEX_INIT_FAST))) + if ((rc= mysql_cond_init(key_debug_sync_globals_ds_cond, + &debug_sync_global.ds_cond, NULL)) || + (rc= mysql_mutex_init(key_debug_sync_globals_ds_mutex, + &debug_sync_global.ds_mutex, + MY_MUTEX_INIT_FAST))) DBUG_RETURN(rc); /* purecov: inspected */ /* Set the call back pointer in C files. */ @@ -476,8 +513,8 @@ void debug_sync_end(void) /* Destroy the global variables. */ debug_sync_global.ds_signal.free(); - (void) pthread_cond_destroy(&debug_sync_global.ds_cond); - (void) pthread_mutex_destroy(&debug_sync_global.ds_mutex); + mysql_cond_destroy(&debug_sync_global.ds_cond); + mysql_mutex_destroy(&debug_sync_global.ds_mutex); /* Print statistics. */ { @@ -585,12 +622,12 @@ void debug_sync_end_thread(THD *thd) } /* Statistics. */ - pthread_mutex_lock(&debug_sync_global.ds_mutex); + mysql_mutex_lock(&debug_sync_global.ds_mutex); debug_sync_global.dsp_hits+= ds_control->dsp_hits; debug_sync_global.dsp_executed+= ds_control->dsp_executed; if (debug_sync_global.dsp_max_active < ds_control->dsp_max_active) debug_sync_global.dsp_max_active= ds_control->dsp_max_active; - pthread_mutex_unlock(&debug_sync_global.ds_mutex); + mysql_mutex_unlock(&debug_sync_global.ds_mutex); my_free(ds_control, MYF(0)); thd->debug_sync_control= NULL; @@ -824,9 +861,9 @@ static void debug_sync_reset(THD *thd) ds_control->ds_active= 0; /* Clear the global signal. */ - pthread_mutex_lock(&debug_sync_global.ds_mutex); + mysql_mutex_lock(&debug_sync_global.ds_mutex); debug_sync_global.ds_signal.length(0); - pthread_mutex_unlock(&debug_sync_global.ds_mutex); + mysql_mutex_unlock(&debug_sync_global.ds_mutex); DBUG_VOID_RETURN; } @@ -1659,7 +1696,7 @@ uchar *sys_var_debug_sync::value_ptr(THD *thd, static char on[]= "ON - current signal: '"; // Ensure exclusive access to debug_sync_global.ds_signal - pthread_mutex_lock(&debug_sync_global.ds_mutex); + mysql_mutex_lock(&debug_sync_global.ds_mutex); size_t lgt= (sizeof(on) /* includes '\0' */ + debug_sync_global.ds_signal.length() + 1 /* for '\'' */); @@ -1676,7 +1713,7 @@ uchar *sys_var_debug_sync::value_ptr(THD *thd, *(vptr++)= '\''; *vptr= '\0'; /* We have one byte reserved for the worst case. */ } - pthread_mutex_unlock(&debug_sync_global.ds_mutex); + mysql_mutex_unlock(&debug_sync_global.ds_mutex); } else { @@ -1744,7 +1781,7 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action) read access too, to create a memory barrier in order to avoid that threads just reads an old cached version of the signal. */ - pthread_mutex_lock(&debug_sync_global.ds_mutex); + mysql_mutex_lock(&debug_sync_global.ds_mutex); if (action->signal.length()) { @@ -1758,15 +1795,15 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action) debug_sync_emergency_disable(); /* purecov: tested */ } /* Wake threads waiting in a sync point. */ - pthread_cond_broadcast(&debug_sync_global.ds_cond); + mysql_cond_broadcast(&debug_sync_global.ds_cond); DBUG_PRINT("debug_sync_exec", ("signal '%s' at: '%s'", sig_emit, dsp_name)); } /* end if (action->signal.length()) */ if (action->wait_for.length()) { - pthread_mutex_t *old_mutex; - pthread_cond_t *old_cond; + mysql_mutex_t *old_mutex; + mysql_cond_t *old_cond; int error= 0; struct timespec abstime; @@ -1797,9 +1834,9 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action) while (stringcmp(&debug_sync_global.ds_signal, &action->wait_for) && !thd->killed && opt_debug_sync_timeout) { - error= pthread_cond_timedwait(&debug_sync_global.ds_cond, - &debug_sync_global.ds_mutex, - &abstime); + error= mysql_cond_timedwait(&debug_sync_global.ds_cond, + &debug_sync_global.ds_mutex, + &abstime); DBUG_EXECUTE("debug_sync", { /* Functions as DBUG_PRINT args can change keyword and line nr. */ const char *sig_glob= debug_sync_global.ds_signal.c_ptr(); @@ -1832,18 +1869,17 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action) protected mutex must always unlocked _before_ mysys_var->mutex is locked. (See comment in THD::exit_cond().) */ - pthread_mutex_unlock(&debug_sync_global.ds_mutex); - pthread_mutex_lock(&thd->mysys_var->mutex); + mysql_mutex_unlock(&debug_sync_global.ds_mutex); + mysql_mutex_lock(&thd->mysys_var->mutex); thd->mysys_var->current_mutex= old_mutex; thd->mysys_var->current_cond= old_cond; thd_proc_info(thd, old_proc_info); - pthread_mutex_unlock(&thd->mysys_var->mutex); - + mysql_mutex_unlock(&thd->mysys_var->mutex); } else { /* In case we don't wait, we just release the mutex. */ - pthread_mutex_unlock(&debug_sync_global.ds_mutex); + mysql_mutex_unlock(&debug_sync_global.ds_mutex); } /* end if (action->wait_for.length()) */ } /* end if (action->execute) */ diff --git a/sql/event_db_repository.cc b/sql/event_db_repository.cc index 9f53a73a594..432a4a4a555 100644 --- a/sql/event_db_repository.cc +++ b/sql/event_db_repository.cc @@ -26,7 +26,7 @@ */ static -const TABLE_FIELD_W_TYPE event_table_fields[ET_FIELD_COUNT] = +const TABLE_FIELD_TYPE event_table_fields[ET_FIELD_COUNT] = { { { C_STRING_WITH_LEN("db") }, @@ -151,6 +151,24 @@ const TABLE_FIELD_W_TYPE event_table_fields[ET_FIELD_COUNT] = } }; +static const TABLE_FIELD_DEF + event_table_def= {ET_FIELD_COUNT, event_table_fields}; + +class Event_db_intact : public Table_check_intact +{ +protected: + void report_error(uint, const char *fmt, ...) + { + va_list args; + va_start(args, fmt); + error_log_print(ERROR_LEVEL, fmt, args); + va_end(args); + } +}; + +/** In case of an error, a message is printed to the error log. */ +static Event_db_intact table_intact; + /** Puts some data common to CREATE and ALTER EVENT into a row. @@ -1117,10 +1135,8 @@ Event_db_repository::check_system_tables(THD *thd) } else { - if (table_check_intact(tables.table, MYSQL_DB_FIELD_COUNT, - mysql_db_table_fields)) + if (table_intact.check(tables.table, &mysql_db_table_def)) ret= 1; - /* in case of an error, the message is printed inside table_check_intact */ close_thread_tables(thd); } @@ -1154,9 +1170,8 @@ Event_db_repository::check_system_tables(THD *thd) } else { - if (table_check_intact(tables.table, ET_FIELD_COUNT, event_table_fields)) + if (table_intact.check(tables.table, &event_table_def)) ret= 1; - /* in case of an error, the message is printed inside table_check_intact */ close_thread_tables(thd); } diff --git a/sql/event_scheduler.cc b/sql/event_scheduler.cc index d9ca161f260..31bb3d39b85 100644 --- a/sql/event_scheduler.cc +++ b/sql/event_scheduler.cc @@ -132,9 +132,8 @@ post_init_event_thread(THD *thd) pthread_mutex_lock(&LOCK_thread_count); threads.append(thd); thread_count++; - thread_running++; + inc_thread_running(); pthread_mutex_unlock(&LOCK_thread_count); - return FALSE; } @@ -156,7 +155,7 @@ deinit_event_thread(THD *thd) DBUG_PRINT("exit", ("Event thread finishing")); pthread_mutex_lock(&LOCK_thread_count); thread_count--; - thread_running--; + dec_thread_running(); delete thd; pthread_cond_broadcast(&COND_thread_count); pthread_mutex_unlock(&LOCK_thread_count); @@ -417,7 +416,7 @@ Event_scheduler::start() net_end(&new_thd->net); pthread_mutex_lock(&LOCK_thread_count); thread_count--; - thread_running--; + dec_thread_running(); delete new_thd; pthread_cond_broadcast(&COND_thread_count); pthread_mutex_unlock(&LOCK_thread_count); @@ -550,7 +549,7 @@ error: net_end(&new_thd->net); pthread_mutex_lock(&LOCK_thread_count); thread_count--; - thread_running--; + dec_thread_running(); delete new_thd; pthread_cond_broadcast(&COND_thread_count); pthread_mutex_unlock(&LOCK_thread_count); diff --git a/sql/field.cc b/sql/field.cc index 8077336583e..0934bb04ccd 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -2519,6 +2519,50 @@ Field_new_decimal::Field_new_decimal(uint32 len_arg, } +Field *Field_new_decimal::create_from_item (Item *item) +{ + uint8 dec= item->decimals; + uint8 intg= item->decimal_precision() - dec; + uint32 len= item->max_length; + + DBUG_ASSERT (item->result_type() == DECIMAL_RESULT); + + /* + Trying to put too many digits overall in a DECIMAL(prec,dec) + will always throw a warning. We must limit dec to + DECIMAL_MAX_SCALE however to prevent an assert() later. + */ + + if (dec > 0) + { + signed int overflow; + + dec= min(dec, DECIMAL_MAX_SCALE); + + /* + If the value still overflows the field with the corrected dec, + we'll throw out decimals rather than integers. This is still + bad and of course throws a truncation warning. + +1: for decimal point + */ + + const int required_length= + my_decimal_precision_to_length(intg + dec, dec, + item->unsigned_flag); + + overflow= required_length - len; + + if (overflow > 0) + dec= max(0, dec - overflow); // too long, discard fract + else + /* Corrected value fits. */ + len= required_length; + } + return new Field_new_decimal(len, item->maybe_null, item->name, + dec, item->unsigned_flag); +} + + int Field_new_decimal::reset(void) { store_value(&decimal_zero); diff --git a/sql/field.h b/sql/field.h index 3dd18b4ffaa..b091431de29 100644 --- a/sql/field.h +++ b/sql/field.h @@ -787,6 +787,7 @@ public: uint is_equal(Create_field *new_field); virtual const uchar *unpack(uchar* to, const uchar *from, uint param_data, bool low_byte_first); + static Field *create_from_item (Item *); }; diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 220e5c460db..5253456ae6a 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2000-2003 MySQL AB +/* Copyright (C) 2000-2003 MySQL AB, 2008-2009 Sun Microsystems, Inc 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 @@ -6908,7 +6908,7 @@ int ndbcluster_drop_database_impl(const char *path) while ((tabname=it++)) { tablename_to_filename(tabname, tmp, FN_REFLEN - (tmp - full_path)-1); - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); if (ha_ndbcluster::delete_table(0, ndb, full_path, dbname, tabname)) { const NdbError err= dict->getNdbError(); @@ -6918,7 +6918,7 @@ int ndbcluster_drop_database_impl(const char *path) ret= ndb_to_mysql_error(&err); } } - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); } DBUG_RETURN(ret); } @@ -7070,7 +7070,7 @@ int ndbcluster_find_all_files(THD *thd) my_free((char*) data, MYF(MY_ALLOW_ZERO_PTR)); my_free((char*) pack_data, MYF(MY_ALLOW_ZERO_PTR)); - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); if (discover) { /* ToDo 4.1 database needs to be created if missing */ @@ -7088,7 +7088,7 @@ int ndbcluster_find_all_files(THD *thd) TRUE); } #endif - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); } } while (unhandled && retries); @@ -7181,19 +7181,19 @@ int ndbcluster_find_files(handlerton *hton, THD *thd, file_name->str, reg_ext, 0); if (my_access(name, F_OK)) { - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); DBUG_PRINT("info", ("Table %s listed and need discovery", file_name->str)); if (ndb_create_table_from_engine(thd, db, file_name->str)) { - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_TABLE_EXISTS_ERROR, "Discover of table %s.%s failed", db, file_name->str); continue; } - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); } DBUG_PRINT("info", ("%s existed in NDB _and_ on disk ", file_name->str)); file_on_disk= TRUE; @@ -7250,10 +7250,10 @@ int ndbcluster_find_files(handlerton *hton, THD *thd, file_name_str= (char*)my_hash_element(&ok_tables, i); end= end1 + tablename_to_filename(file_name_str, end1, sizeof(name) - (end1 - name)); - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); ndbcluster_create_binlog_setup(ndb, name, end-name, db, file_name_str, TRUE); - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); } } #endif @@ -7313,7 +7313,7 @@ int ndbcluster_find_files(handlerton *hton, THD *thd, } /* Lock mutex before creating .FRM files. */ - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); /* Create new files. */ List_iterator_fast<char> it2(create_list); while ((file_name_str=it2++)) @@ -7328,7 +7328,7 @@ int ndbcluster_find_files(handlerton *hton, THD *thd, } } - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); my_hash_free(&ok_tables); my_hash_free(&ndb_tables); @@ -8252,7 +8252,7 @@ int handle_trailing_share(NDB_SHARE *share) bzero((char*) &table_list,sizeof(table_list)); table_list.db= share->db; table_list.alias= table_list.table_name= share->table_name; - safe_mutex_assert_owner(&LOCK_open); + mysql_mutex_assert_owner(&LOCK_open); close_cached_tables(thd, &table_list, TRUE, FALSE); pthread_mutex_lock(&ndbcluster_mutex); diff --git a/sql/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc index d178b16520c..5184a34ad6e 100644 --- a/sql/ha_ndbcluster_binlog.cc +++ b/sql/ha_ndbcluster_binlog.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2000-2003 MySQL AB +/* Copyright (C) 2000-2003 MySQL AB, 2008-2009 Sun Microsystems, Inc 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 @@ -349,7 +349,7 @@ ndbcluster_binlog_open_table(THD *thd, NDB_SHARE *share, int error; DBUG_ENTER("ndbcluster_binlog_open_table"); - safe_mutex_assert_owner(&LOCK_open); + mysql_mutex_assert_owner(&LOCK_open); init_tmp_table_share(thd, table_share, share->db, 0, share->table_name, share->key); if ((error= open_table_def(thd, table_share, 0))) @@ -897,9 +897,9 @@ int ndbcluster_setup_binlog_table_shares(THD *thd) if (!ndb_schema_share && ndbcluster_check_ndb_schema_share() == 0) { - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); ndb_create_table_from_engine(thd, NDB_REP_DB, NDB_SCHEMA_TABLE); - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); if (!ndb_schema_share) { ndbcluster_create_schema_table(thd); @@ -911,9 +911,9 @@ int ndbcluster_setup_binlog_table_shares(THD *thd) if (!ndb_apply_status_share && ndbcluster_check_ndb_apply_status_share() == 0) { - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); ndb_create_table_from_engine(thd, NDB_REP_DB, NDB_APPLY_TABLE); - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); if (!ndb_apply_status_share) { ndbcluster_create_ndb_apply_status_table(thd); @@ -923,12 +923,12 @@ int ndbcluster_setup_binlog_table_shares(THD *thd) } if (!ndbcluster_find_all_files(thd)) { - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); ndb_binlog_tables_inited= TRUE; if (ndb_extra_logging) sql_print_information("NDB Binlog: ndb tables writable"); close_cached_tables(NULL, NULL, TRUE, FALSE); - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); /* Signal injector thread that all is setup */ pthread_cond_signal(&injector_cond); } @@ -1571,8 +1571,8 @@ end: (void) pthread_mutex_lock(&ndb_schema_object->mutex); if (have_lock_open) { - safe_mutex_assert_owner(&LOCK_open); - (void) pthread_mutex_unlock(&LOCK_open); + mysql_mutex_assert_owner(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); } while (1) { @@ -1631,7 +1631,7 @@ end: } if (have_lock_open) { - (void) pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); } (void) pthread_mutex_unlock(&ndb_schema_object->mutex); } @@ -1715,7 +1715,7 @@ ndb_handle_schema_change(THD *thd, Ndb *ndb, NdbEventOperation *pOp, { DBUG_DUMP("frm", (uchar*) altered_table->getFrmData(), altered_table->getFrmLength()); - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); Ndb_table_guard ndbtab_g(dict, tabname); const NDBTAB *old= ndbtab_g.get_table(); if (!old && @@ -1753,7 +1753,7 @@ ndb_handle_schema_change(THD *thd, Ndb *ndb, NdbEventOperation *pOp, dbname= table_share->db.str; tabname= table_share->table_name.str; - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); } my_free((char*)data, MYF(MY_ALLOW_ZERO_PTR)); my_free((char*)pack_data, MYF(MY_ALLOW_ZERO_PTR)); @@ -1980,7 +1980,7 @@ ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb, } // fall through case SOT_CREATE_TABLE: - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); if (ndbcluster_check_if_local_table(schema->db, schema->name)) { DBUG_PRINT("info", ("NDB Binlog: Skipping locally defined table '%s.%s'", @@ -1994,7 +1994,7 @@ ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb, { print_could_not_discover_error(thd, schema); } - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); log_query= 1; break; case SOT_DROP_DB: @@ -2263,7 +2263,7 @@ ndb_binlog_thread_handle_schema_event_post_epoch(THD *thd, free_share(&share); share= 0; } - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); if (ndbcluster_check_if_local_table(schema->db, schema->name)) { DBUG_PRINT("info", ("NDB Binlog: Skipping locally defined table '%s.%s'", @@ -2277,7 +2277,7 @@ ndb_binlog_thread_handle_schema_event_post_epoch(THD *thd, { print_could_not_discover_error(thd, schema); } - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); } break; default: @@ -3140,8 +3140,8 @@ ndbcluster_handle_drop_table(Ndb *ndb, const char *event_name, #ifdef SYNC_DROP_ thd->proc_info= "Syncing ndb table schema operation and binlog"; (void) pthread_mutex_lock(&share->mutex); - safe_mutex_assert_owner(&LOCK_open); - (void) pthread_mutex_unlock(&LOCK_open); + mysql_mutex_assert_owner(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); int max_timeout= opt_ndb_sync_timeout; while (share->op) { @@ -3167,7 +3167,7 @@ ndbcluster_handle_drop_table(Ndb *ndb, const char *event_name, type_str, share->key); } } - (void) pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); (void) pthread_mutex_unlock(&share->mutex); #else (void) pthread_mutex_lock(&share->mutex); diff --git a/sql/item.cc b/sql/item.cc index 7de32423927..f4b2e549667 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -5063,9 +5063,7 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table, bool fixed_length) switch (field_type()) { case MYSQL_TYPE_DECIMAL: case MYSQL_TYPE_NEWDECIMAL: - field= new Field_new_decimal((uchar*) 0, max_length, null_ptr, 0, - Field::NONE, name, decimals, 0, - unsigned_flag); + field= Field_new_decimal::create_from_item(this); break; case MYSQL_TYPE_TINY: field= new Field_tiny((uchar*) 0, max_length, null_ptr, 0, Field::NONE, @@ -7182,7 +7180,7 @@ Item_cache* Item_cache::get_cache(const Item *item, const Item_result type) { switch (type) { case INT_RESULT: - return new Item_cache_int(); + return new Item_cache_int(item->field_type()); case REAL_RESULT: return new Item_cache_real(); case DECIMAL_RESULT: @@ -7204,8 +7202,9 @@ Item_cache* Item_cache::get_cache(const Item *item, const Item_result type) void Item_cache::store(Item *item) { - if (item) - example= item; + example= item; + if (!item) + null_value= TRUE; value_cached= FALSE; } @@ -7219,12 +7218,15 @@ void Item_cache::print(String *str, enum_query_type query_type) str->append(')'); } -void Item_cache_int::cache_value() +bool Item_cache_int::cache_value() { + if (!example) + return FALSE; value_cached= TRUE; value= example->val_int_result(); null_value= example->null_value; unsigned_flag= example->unsigned_flag; + return TRUE; } @@ -7241,8 +7243,8 @@ void Item_cache_int::store(Item *item, longlong val_arg) String *Item_cache_int::val_str(String *str) { DBUG_ASSERT(fixed == 1); - if (!value_cached) - cache_value(); + if (!value_cached && !cache_value()) + return NULL; str->set(value, default_charset()); return str; } @@ -7251,8 +7253,8 @@ String *Item_cache_int::val_str(String *str) my_decimal *Item_cache_int::val_decimal(my_decimal *decimal_val) { DBUG_ASSERT(fixed == 1); - if (!value_cached) - cache_value(); + if (!value_cached && !cache_value()) + return NULL; int2my_decimal(E_DEC_FATAL_ERROR, value, unsigned_flag, decimal_val); return decimal_val; } @@ -7260,31 +7262,37 @@ my_decimal *Item_cache_int::val_decimal(my_decimal *decimal_val) double Item_cache_int::val_real() { DBUG_ASSERT(fixed == 1); - if (!value_cached) - cache_value(); + if (!value_cached && !cache_value()) + return 0.0; return (double) value; } longlong Item_cache_int::val_int() { DBUG_ASSERT(fixed == 1); - if (!value_cached) - cache_value(); + if (!value_cached && !cache_value()) + return 0; return value; } -void Item_cache_datetime::cache_value_int() +bool Item_cache_datetime::cache_value_int() { + if (!example) + return FALSE; + value_cached= TRUE; /* Assume here that the underlying item will do correct conversion.*/ int_value= example->val_int_result(); null_value= example->null_value; unsigned_flag= example->unsigned_flag; + return TRUE; } -void Item_cache_datetime::cache_value() +bool Item_cache_datetime::cache_value() { + if (!example) + return FALSE; str_value_cached= TRUE; /* Assume here that the underlying item will do correct conversion.*/ String *res= example->str_result(&str_value); @@ -7292,6 +7300,7 @@ void Item_cache_datetime::cache_value() str_value.copy(*res); null_value= example->null_value; unsigned_flag= example->unsigned_flag; + return TRUE; } @@ -7308,8 +7317,8 @@ void Item_cache_datetime::store(Item *item, longlong val_arg) String *Item_cache_datetime::val_str(String *str) { DBUG_ASSERT(fixed == 1); - if (!str_value_cached) - cache_value(); + if (!str_value_cached && !cache_value()) + return NULL; return &str_value; } @@ -7317,8 +7326,8 @@ String *Item_cache_datetime::val_str(String *str) my_decimal *Item_cache_datetime::val_decimal(my_decimal *decimal_val) { DBUG_ASSERT(fixed == 1); - if (!value_cached) - cache_value_int(); + if (!value_cached && !cache_value_int()) + return NULL; int2my_decimal(E_DEC_FATAL_ERROR, int_value, unsigned_flag, decimal_val); return decimal_val; } @@ -7326,40 +7335,43 @@ my_decimal *Item_cache_datetime::val_decimal(my_decimal *decimal_val) double Item_cache_datetime::val_real() { DBUG_ASSERT(fixed == 1); - if (!value_cached) - cache_value_int(); + if (!value_cached && !cache_value_int()) + return 0.0; return (double) int_value; } longlong Item_cache_datetime::val_int() { DBUG_ASSERT(fixed == 1); - if (!value_cached) - cache_value_int(); + if (!value_cached && !cache_value_int()) + return 0; return int_value; } -void Item_cache_real::cache_value() +bool Item_cache_real::cache_value() { + if (!example) + return FALSE; value_cached= TRUE; value= example->val_result(); null_value= example->null_value; + return TRUE; } double Item_cache_real::val_real() { DBUG_ASSERT(fixed == 1); - if (!value_cached) - cache_value(); + if (!value_cached && !cache_value()) + return 0.0; return value; } longlong Item_cache_real::val_int() { DBUG_ASSERT(fixed == 1); - if (!value_cached) - cache_value(); + if (!value_cached && !cache_value()) + return 0; return (longlong) rint(value); } @@ -7367,8 +7379,8 @@ longlong Item_cache_real::val_int() String* Item_cache_real::val_str(String *str) { DBUG_ASSERT(fixed == 1); - if (!value_cached) - cache_value(); + if (!value_cached && !cache_value()) + return NULL; str->set_real(value, decimals, default_charset()); return str; } @@ -7377,27 +7389,30 @@ String* Item_cache_real::val_str(String *str) my_decimal *Item_cache_real::val_decimal(my_decimal *decimal_val) { DBUG_ASSERT(fixed == 1); - if (!value_cached) - cache_value(); + if (!value_cached && !cache_value()) + return NULL; double2my_decimal(E_DEC_FATAL_ERROR, value, decimal_val); return decimal_val; } -void Item_cache_decimal::cache_value() +bool Item_cache_decimal::cache_value() { + if (!example) + return FALSE; value_cached= TRUE; my_decimal *val= example->val_decimal_result(&decimal_value); if (!(null_value= example->null_value) && val != &decimal_value) my_decimal2decimal(val, &decimal_value); + return TRUE; } double Item_cache_decimal::val_real() { DBUG_ASSERT(fixed); double res; - if (!value_cached) - cache_value(); + if (!value_cached && !cache_value()) + return NULL; my_decimal2double(E_DEC_FATAL_ERROR, &decimal_value, &res); return res; } @@ -7406,8 +7421,8 @@ longlong Item_cache_decimal::val_int() { DBUG_ASSERT(fixed); longlong res; - if (!value_cached) - cache_value(); + if (!value_cached && !cache_value()) + return 0; my_decimal2int(E_DEC_FATAL_ERROR, &decimal_value, unsigned_flag, &res); return res; } @@ -7415,8 +7430,8 @@ longlong Item_cache_decimal::val_int() String* Item_cache_decimal::val_str(String *str) { DBUG_ASSERT(fixed); - if (!value_cached) - cache_value(); + if (!value_cached && !cache_value()) + return NULL; my_decimal_round(E_DEC_FATAL_ERROR, &decimal_value, decimals, FALSE, &decimal_value); my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value, 0, 0, 0, str); @@ -7426,14 +7441,16 @@ String* Item_cache_decimal::val_str(String *str) my_decimal *Item_cache_decimal::val_decimal(my_decimal *val) { DBUG_ASSERT(fixed); - if (!value_cached) - cache_value(); + if (!value_cached && !cache_value()) + return NULL; return &decimal_value; } -void Item_cache_str::cache_value() +bool Item_cache_str::cache_value() { + if (!example) + return FALSE; value_cached= TRUE; value_buff.set(buffer, sizeof(buffer), example->collation.collation); value= example->str_result(&value_buff); @@ -7452,6 +7469,7 @@ void Item_cache_str::cache_value() value_buff.copy(*value); value= &value_buff; } + return TRUE; } double Item_cache_str::val_real() @@ -7459,8 +7477,8 @@ double Item_cache_str::val_real() DBUG_ASSERT(fixed == 1); int err_not_used; char *end_not_used; - if (!value_cached) - cache_value(); + if (!value_cached && !cache_value()) + return 0.0; if (value) return my_strntod(value->charset(), (char*) value->ptr(), value->length(), &end_not_used, &err_not_used); @@ -7472,8 +7490,8 @@ longlong Item_cache_str::val_int() { DBUG_ASSERT(fixed == 1); int err; - if (!value_cached) - cache_value(); + if (!value_cached && !cache_value()) + return 0; if (value) return my_strntoll(value->charset(), value->ptr(), value->length(), 10, (char**) 0, &err); @@ -7485,8 +7503,8 @@ longlong Item_cache_str::val_int() String* Item_cache_str::val_str(String *str) { DBUG_ASSERT(fixed == 1); - if (!value_cached) - cache_value(); + if (!value_cached && !cache_value()) + return 0; return value; } @@ -7494,8 +7512,8 @@ String* Item_cache_str::val_str(String *str) my_decimal *Item_cache_str::val_decimal(my_decimal *decimal_val) { DBUG_ASSERT(fixed == 1); - if (!value_cached) - cache_value(); + if (!value_cached && !cache_value()) + return NULL; if (value) string2my_decimal(E_DEC_FATAL_ERROR, value, decimal_val); else @@ -7506,8 +7524,8 @@ my_decimal *Item_cache_str::val_decimal(my_decimal *decimal_val) int Item_cache_str::save_in_field(Field *field, bool no_conversions) { - if (!value_cached) - cache_value(); + if (!value_cached && !cache_value()) + return 0; int res= Item_cache::save_in_field(field, no_conversions); return (is_varbinary && field->type() == MYSQL_TYPE_STRING && value->length() < field->field_length) ? 1 : res; @@ -7542,13 +7560,21 @@ bool Item_cache_row::setup(Item * item) void Item_cache_row::store(Item * item) { + example= item; + if (!item) + { + null_value= TRUE; + return; + } for (uint i= 0; i < item_count; i++) values[i]->store(item->element_index(i)); } -void Item_cache_row::cache_value() +bool Item_cache_row::cache_value() { + if (!example) + return FALSE; value_cached= TRUE; null_value= 0; example->bring_value(); @@ -7557,6 +7583,7 @@ void Item_cache_row::cache_value() values[i]->cache_value(); null_value|= values[i]->null_value; } + return TRUE; } diff --git a/sql/item.h b/sql/item.h index a963206a2dc..c6ef5bd349a 100644 --- a/sql/item.h +++ b/sql/item.h @@ -2170,6 +2170,23 @@ public: save_in_field(result_field, no_conversions); } void cleanup(); + /* + This method is used for debug purposes to print the name of an + item to the debug log. The second use of this method is as + a helper function of print() and error messages, where it is + applicable. To suit both goals it should return a meaningful, + distinguishable and sintactically correct string. This method + should not be used for runtime type identification, use enum + {Sum}Functype and Item_func::functype()/Item_sum::sum_func() + instead. + Added here, to the parent class of both Item_func and Item_sum_func. + + NOTE: for Items inherited from Item_sum, func_name() return part of + function name till first argument (including '(') to make difference in + names for functions with 'distinct' clause and without 'distinct' and + also to make printing of items inherited from Item_sum uniform. + */ + virtual const char *func_name() const= 0; }; @@ -2980,7 +2997,7 @@ public: return this == item; } virtual void store(Item *item); - virtual void cache_value()= 0; + virtual bool cache_value()= 0; bool basic_const_item() const { return test(example && example->basic_const_item());} }; @@ -3003,7 +3020,7 @@ public: my_decimal *val_decimal(my_decimal *); enum Item_result result_type() const { return INT_RESULT; } bool result_as_longlong() { return TRUE; } - void cache_value(); + bool cache_value(); }; @@ -3019,7 +3036,7 @@ public: String* val_str(String *str); my_decimal *val_decimal(my_decimal *); enum Item_result result_type() const { return REAL_RESULT; } - void cache_value(); + bool cache_value(); }; @@ -3035,7 +3052,7 @@ public: String* val_str(String *str); my_decimal *val_decimal(my_decimal *); enum Item_result result_type() const { return DECIMAL_RESULT; } - void cache_value(); + bool cache_value(); }; @@ -3060,7 +3077,7 @@ public: enum Item_result result_type() const { return STRING_RESULT; } CHARSET_INFO *charset() const { return value->charset(); }; int save_in_field(Field *field, bool no_conversions); - void cache_value(); + bool cache_value(); }; class Item_cache_row: public Item_cache @@ -3129,7 +3146,7 @@ public: values= 0; DBUG_VOID_RETURN; } - void cache_value(); + bool cache_value(); }; @@ -3160,8 +3177,8 @@ public: completely relies on the ability of the underlying item to do the correct conversion. */ - void cache_value_int(); - void cache_value(); + bool cache_value_int(); + bool cache_value(); }; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index fabb9a64b0d..4a1077179a9 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -30,6 +30,9 @@ #include "sql_select.h" static bool convert_constant_item(THD *, Item_field *, Item **); +static longlong +get_year_value(THD *thd, Item ***item_arg, Item **cache_arg, + Item *warn_item, bool *is_null); static Item_result item_store_type(Item_result a, Item *item, my_bool unsigned_flag) @@ -533,11 +536,12 @@ void Item_bool_func2::fix_length_and_dec() } -int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type) +int Arg_comparator::set_compare_func(Item_result_field *item, Item_result type) { owner= item; func= comparator_matrix[type] - [test(owner->functype() == Item_func::EQUAL_FUNC)]; + [is_owner_equal_func()]; + switch (type) { case ROW_RESULT: { @@ -557,7 +561,8 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type) my_error(ER_OPERAND_COLUMNS, MYF(0), (*a)->element_index(i)->cols()); return 1; } - if (comparators[i].set_cmp_func(owner, (*a)->addr(i), (*b)->addr(i))) + if (comparators[i].set_cmp_func(owner, (*a)->addr(i), (*b)->addr(i), + set_null)) return 1; } break; @@ -571,7 +576,8 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type) if (cmp_collation.set((*a)->collation, (*b)->collation) || cmp_collation.derivation == DERIVATION_NONE) { - my_coll_agg_error((*a)->collation, (*b)->collation, owner->func_name()); + my_coll_agg_error((*a)->collation, (*b)->collation, + owner->func_name()); return 1; } if (cmp_collation.collation == &my_charset_bin) @@ -785,15 +791,21 @@ Arg_comparator::can_compare_as_dates(Item *a, Item *b, ulonglong *const_value) if (cmp_type != CMP_DATE_DFLT) { + THD *thd= current_thd; /* Do not cache GET_USER_VAR() function as its const_item() may return TRUE for the current thread but it still may change during the execution. + Don't use cache while in the context analysis mode only (i.e. for + EXPLAIN/CREATE VIEW and similar queries). Cache is useless in such + cases and can cause problems. For example evaluating subqueries can + confuse storage engines since in context analysis mode tables + aren't locked. */ - if (cmp_type != CMP_DATE_WITH_DATE && str_arg->const_item() && + if (!thd->is_context_analysis_only() && + cmp_type != CMP_DATE_WITH_DATE && str_arg->const_item() && (str_arg->type() != Item::FUNC_ITEM || ((Item_func*)str_arg)->functype() != Item_func::GUSERVAR_FUNC)) { - THD *thd= current_thd; ulonglong value; bool error; String tmp, *str_val= 0; @@ -876,7 +888,7 @@ get_time_value(THD *thd, Item ***item_arg, Item **cache_arg, } -int Arg_comparator::set_cmp_func(Item_bool_func2 *owner_arg, +int Arg_comparator::set_cmp_func(Item_result_field *owner_arg, Item **a1, Item **a2, Item_result type) { @@ -886,6 +898,8 @@ int Arg_comparator::set_cmp_func(Item_bool_func2 *owner_arg, owner= owner_arg; a= a1; b= a2; + owner= owner_arg; + thd= current_thd; if ((cmp_type= can_compare_as_dates(*a, *b, &const_value))) { @@ -916,9 +930,10 @@ int Arg_comparator::set_cmp_func(Item_bool_func2 *owner_arg, b= (Item **)&b_cache; } } - is_nulls_eq= test(owner && owner->functype() == Item_func::EQUAL_FUNC); + is_nulls_eq= is_owner_equal_func(); func= &Arg_comparator::compare_datetime; - get_value_func= &get_datetime_value; + get_value_a_func= &get_datetime_value; + get_value_b_func= &get_datetime_value; return 0; } else if (type == STRING_RESULT && (*a)->field_type() == MYSQL_TYPE_TIME && @@ -927,9 +942,10 @@ int Arg_comparator::set_cmp_func(Item_bool_func2 *owner_arg, /* Compare TIME values as integers. */ a_cache= 0; b_cache= 0; - is_nulls_eq= test(owner && owner->functype() == Item_func::EQUAL_FUNC); + is_nulls_eq= is_owner_equal_func(); func= &Arg_comparator::compare_datetime; - get_value_func= &get_time_value; + get_value_a_func= &get_time_value; + get_value_b_func= &get_time_value; return 0; } else if (type == STRING_RESULT && @@ -938,9 +954,42 @@ int Arg_comparator::set_cmp_func(Item_bool_func2 *owner_arg, { DTCollation coll; coll.set((*a)->collation.collation); - if (agg_item_set_converter(coll, owner_arg->func_name(), + if (agg_item_set_converter(coll, owner->func_name(), b, 1, MY_COLL_CMP_CONV, 1)) return 1; + } else if (type != ROW_RESULT && ((*a)->field_type() == MYSQL_TYPE_YEAR || + (*b)->field_type() == MYSQL_TYPE_YEAR)) + { + is_nulls_eq= is_owner_equal_func(); + year_as_datetime= FALSE; + + if ((*a)->is_datetime()) + { + year_as_datetime= TRUE; + get_value_a_func= &get_datetime_value; + } else if ((*a)->field_type() == MYSQL_TYPE_YEAR) + get_value_a_func= &get_year_value; + else + { + /* + Because convert_constant_item is called only for EXECUTE in PS mode + the value of get_value_x_func set in PREPARE might be not + valid for EXECUTE. + */ + get_value_a_func= NULL; + } + + if ((*b)->is_datetime()) + { + year_as_datetime= TRUE; + get_value_b_func= &get_datetime_value; + } else if ((*b)->field_type() == MYSQL_TYPE_YEAR) + get_value_b_func= &get_year_value; + else + get_value_b_func= NULL; + + func= &Arg_comparator::compare_year; + return 0; } a= cache_converted_constant(thd, a, &a_cache, type); @@ -983,11 +1032,11 @@ Item** Arg_comparator::cache_converted_constant(THD *thd, Item **value, } -void Arg_comparator::set_datetime_cmp_func(Item **a1, Item **b1) +void Arg_comparator::set_datetime_cmp_func(Item_result_field *owner_arg, + Item **a1, Item **b1) { thd= current_thd; - /* A caller will handle null values by itself. */ - owner= NULL; + owner= owner_arg; a= a1; b= b1; a_type= (*a)->field_type(); @@ -996,7 +1045,8 @@ void Arg_comparator::set_datetime_cmp_func(Item **a1, Item **b1) b_cache= 0; is_nulls_eq= FALSE; func= &Arg_comparator::compare_datetime; - get_value_func= &get_datetime_value; + get_value_a_func= &get_datetime_value; + get_value_b_func= &get_datetime_value; } @@ -1096,6 +1146,51 @@ get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg, return value; } + +/* + Retrieves YEAR value of 19XX form from given item. + + SYNOPSIS + get_year_value() + thd thread handle + item_arg [in/out] item to retrieve YEAR value from + cache_arg [in/out] pointer to place to store the caching item to + warn_item [in] item for issuing the conversion warning + is_null [out] TRUE <=> the item_arg is null + + DESCRIPTION + Retrieves the YEAR value of 19XX form from given item for comparison by the + compare_year() function. + + RETURN + obtained value +*/ + +static longlong +get_year_value(THD *thd, Item ***item_arg, Item **cache_arg, + Item *warn_item, bool *is_null) +{ + longlong value= 0; + Item *item= **item_arg; + + value= item->val_int(); + *is_null= item->null_value; + if (*is_null) + return ~(ulonglong) 0; + + /* + Coerce value to the 19XX form in order to correctly compare + YEAR(2) & YEAR(4) types. + */ + if (value < 70) + value+= 100; + if (value <= 1900) + value+= 1900; + + return value; +} + + /* Compare items values as dates. @@ -1128,25 +1223,25 @@ int Arg_comparator::compare_datetime() longlong a_value, b_value; /* Get DATE/DATETIME/TIME value of the 'a' item. */ - a_value= (*get_value_func)(thd, &a, &a_cache, *b, &a_is_null); + a_value= (*get_value_a_func)(thd, &a, &a_cache, *b, &a_is_null); if (!is_nulls_eq && a_is_null) { - if (owner) + if (set_null) owner->null_value= 1; return -1; } /* Get DATE/DATETIME/TIME value of the 'b' item. */ - b_value= (*get_value_func)(thd, &b, &b_cache, *a, &b_is_null); + b_value= (*get_value_b_func)(thd, &b, &b_cache, *a, &b_is_null); if (a_is_null || b_is_null) { - if (owner) + if (set_null) owner->null_value= is_nulls_eq ? 0 : 1; return is_nulls_eq ? (a_is_null == b_is_null) : -1; } /* Here we have two not-NULL values. */ - if (owner) + if (set_null) owner->null_value= 0; /* Compare values. */ @@ -1159,15 +1254,17 @@ int Arg_comparator::compare_datetime() int Arg_comparator::compare_string() { String *res1,*res2; - if ((res1= (*a)->val_str(&owner->tmp_value1))) + if ((res1= (*a)->val_str(&value1))) { - if ((res2= (*b)->val_str(&owner->tmp_value2))) + if ((res2= (*b)->val_str(&value2))) { - owner->null_value= 0; + if (set_null) + owner->null_value= 0; return sortcmp(res1,res2,cmp_collation.collation); } } - owner->null_value= 1; + if (set_null) + owner->null_value= 1; return -1; } @@ -1186,18 +1283,20 @@ int Arg_comparator::compare_string() int Arg_comparator::compare_binary_string() { String *res1,*res2; - if ((res1= (*a)->val_str(&owner->tmp_value1))) + if ((res1= (*a)->val_str(&value1))) { - if ((res2= (*b)->val_str(&owner->tmp_value2))) + if ((res2= (*b)->val_str(&value2))) { - owner->null_value= 0; + if (set_null) + owner->null_value= 0; uint res1_length= res1->length(); uint res2_length= res2->length(); int cmp= memcmp(res1->ptr(), res2->ptr(), min(res1_length,res2_length)); return cmp ? cmp : (int) (res1_length - res2_length); } } - owner->null_value= 1; + if (set_null) + owner->null_value= 1; return -1; } @@ -1210,8 +1309,8 @@ int Arg_comparator::compare_binary_string() int Arg_comparator::compare_e_string() { String *res1,*res2; - res1= (*a)->val_str(&owner->tmp_value1); - res2= (*b)->val_str(&owner->tmp_value2); + res1= (*a)->val_str(&value1); + res2= (*b)->val_str(&value2); if (!res1 || !res2) return test(res1 == res2); return test(sortcmp(res1, res2, cmp_collation.collation) == 0); @@ -1221,8 +1320,8 @@ int Arg_comparator::compare_e_string() int Arg_comparator::compare_e_binary_string() { String *res1,*res2; - res1= (*a)->val_str(&owner->tmp_value1); - res2= (*b)->val_str(&owner->tmp_value2); + res1= (*a)->val_str(&value1); + res2= (*b)->val_str(&value2); if (!res1 || !res2) return test(res1 == res2); return test(stringcmp(res1, res2) == 0); @@ -1243,13 +1342,15 @@ int Arg_comparator::compare_real() val2= (*b)->val_real(); if (!(*b)->null_value) { - owner->null_value= 0; + if (set_null) + owner->null_value= 0; if (val1 < val2) return -1; if (val1 == val2) return 0; return 1; } } - owner->null_value= 1; + if (set_null) + owner->null_value= 1; return -1; } @@ -1263,11 +1364,13 @@ int Arg_comparator::compare_decimal() my_decimal *val2= (*b)->val_decimal(&value2); if (!(*b)->null_value) { - owner->null_value= 0; + if (set_null) + owner->null_value= 0; return my_decimal_cmp(val1, val2); } } - owner->null_value= 1; + if (set_null) + owner->null_value= 1; return -1; } @@ -1305,7 +1408,8 @@ int Arg_comparator::compare_real_fixed() val2= (*b)->val_real(); if (!(*b)->null_value) { - owner->null_value= 0; + if (set_null) + owner->null_value= 0; if (val1 == val2 || fabs(val1 - val2) < precision) return 0; if (val1 < val2) @@ -1313,7 +1417,8 @@ int Arg_comparator::compare_real_fixed() return 1; } } - owner->null_value= 1; + if (set_null) + owner->null_value= 1; return -1; } @@ -1336,13 +1441,15 @@ int Arg_comparator::compare_int_signed() longlong val2= (*b)->val_int(); if (!(*b)->null_value) { - owner->null_value= 0; + if (set_null) + owner->null_value= 0; if (val1 < val2) return -1; if (val1 == val2) return 0; return 1; } } - owner->null_value= 1; + if (set_null) + owner->null_value= 1; return -1; } @@ -1359,13 +1466,15 @@ int Arg_comparator::compare_int_unsigned() ulonglong val2= (*b)->val_int(); if (!(*b)->null_value) { - owner->null_value= 0; + if (set_null) + owner->null_value= 0; if (val1 < val2) return -1; if (val1 == val2) return 0; return 1; } } - owner->null_value= 1; + if (set_null) + owner->null_value= 1; return -1; } @@ -1382,7 +1491,8 @@ int Arg_comparator::compare_int_signed_unsigned() ulonglong uval2= (ulonglong)(*b)->val_int(); if (!(*b)->null_value) { - owner->null_value= 0; + if (set_null) + owner->null_value= 0; if (sval1 < 0 || (ulonglong)sval1 < uval2) return -1; if ((ulonglong)sval1 == uval2) @@ -1390,7 +1500,8 @@ int Arg_comparator::compare_int_signed_unsigned() return 1; } } - owner->null_value= 1; + if (set_null) + owner->null_value= 1; return -1; } @@ -1407,7 +1518,8 @@ int Arg_comparator::compare_int_unsigned_signed() longlong sval2= (*b)->val_int(); if (!(*b)->null_value) { - owner->null_value= 0; + if (set_null) + owner->null_value= 0; if (sval2 < 0) return 1; if (uval1 < (ulonglong)sval2) @@ -1417,7 +1529,8 @@ int Arg_comparator::compare_int_unsigned_signed() return 1; } } - owner->null_value= 1; + if (set_null) + owner->null_value= 1; return -1; } @@ -1453,10 +1566,11 @@ int Arg_comparator::compare_row() for (uint i= 0; i<n; i++) { res= comparators[i].compare(); - if (owner->null_value) + /* Aggregate functions don't need special null handling. */ + if (owner->null_value && owner->type() == Item::FUNC_ITEM) { // NULL was compared - switch (owner->functype()) { + switch (((Item_func*)owner)->functype()) { case Item_func::NE_FUNC: break; // NE never aborts on NULL even if abort_on_null is set case Item_func::LT_FUNC: @@ -1465,7 +1579,7 @@ int Arg_comparator::compare_row() case Item_func::GE_FUNC: return -1; // <, <=, > and >= always fail on NULL default: // EQ_FUNC - if (owner->abort_on_null) + if (((Item_bool_func2*)owner)->abort_on_null) return -1; // We do not need correct NULL returning } was_null= 1; @@ -1502,6 +1616,67 @@ int Arg_comparator::compare_e_row() } +/** + Compare values as YEAR. + + @details + Compare items as YEAR for EQUAL_FUNC and for other comparison functions. + The YEAR values of form 19XX are obtained with help of the get_year_value() + function. + If one of arguments is of DATE/DATETIME type its value is obtained + with help of the get_datetime_value function. In this case YEAR values + prior to comparison are converted to the ulonglong YYYY-00-00 00:00:00 + DATETIME form. + If an argument type neither YEAR nor DATE/DATEIME then val_int function + is used to obtain value for comparison. + + RETURN + If is_nulls_eq is TRUE: + 1 if items are equal or both are null + 0 otherwise + If is_nulls_eq is FALSE: + -1 a < b + 0 a == b or at least one of items is null + 1 a > b + See the table: + is_nulls_eq | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | + a_is_null | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | + b_is_null | 1 | 1 | 0 | 0 | 1 | 1 | 0 | 0 | + result | 1 | 0 | 0 |0/1| 0 | 0 | 0 |-1/0/1| +*/ + +int Arg_comparator::compare_year() +{ + bool a_is_null, b_is_null; + ulonglong val1= get_value_a_func ? + (*get_value_a_func)(thd, &a, &a_cache, *b, &a_is_null) : + (*a)->val_int(); + ulonglong val2= get_value_b_func ? + (*get_value_b_func)(thd, &b, &b_cache, *a, &b_is_null) : + (*b)->val_int(); + if (!(*a)->null_value) + { + if (!(*b)->null_value) + { + if (set_null) + owner->null_value= 0; + /* Convert year to DATETIME of form YYYY-00-00 00:00:00 when necessary. */ + if((*a)->field_type() == MYSQL_TYPE_YEAR && year_as_datetime) + val1*= 10000000000LL; + if((*b)->field_type() == MYSQL_TYPE_YEAR && year_as_datetime) + val2*= 10000000000LL; + + if (val1 < val2) return is_nulls_eq ? 0 : -1; + if (val1 == val2) return is_nulls_eq ? 1 : 0; + return is_nulls_eq ? 0 : 1; + } + } + if (set_null) + owner->null_value= is_nulls_eq ? 0 : 1; + return (is_nulls_eq && (*a)->null_value == (*b)->null_value) ? 1 : 0; +} + + void Item_func_truth::fix_length_and_dec() { maybe_null= 0; @@ -1789,8 +1964,8 @@ longlong Item_func_lt::val_int() longlong Item_func_strcmp::val_int() { DBUG_ASSERT(fixed == 1); - String *a=args[0]->val_str(&tmp_value1); - String *b=args[1]->val_str(&tmp_value2); + String *a=args[0]->val_str(&cmp.value1); + String *b=args[1]->val_str(&cmp.value2); if (!a || !b) { null_value=1; @@ -2073,8 +2248,8 @@ void Item_func_between::fix_length_and_dec() if (compare_as_dates) { - ge_cmp.set_datetime_cmp_func(args, args + 1); - le_cmp.set_datetime_cmp_func(args, args + 2); + ge_cmp.set_datetime_cmp_func(this, args, args + 1); + le_cmp.set_datetime_cmp_func(this, args, args + 2); } else if (time_items_found == 3) { @@ -4402,13 +4577,13 @@ void Item_func_isnotnull::print(String *str, enum_query_type query_type) longlong Item_func_like::val_int() { DBUG_ASSERT(fixed == 1); - String* res = args[0]->val_str(&tmp_value1); + String* res = args[0]->val_str(&cmp.value1); if (args[0]->null_value) { null_value=1; return 0; } - String* res2 = args[1]->val_str(&tmp_value2); + String* res2 = args[1]->val_str(&cmp.value2); if (args[1]->null_value) { null_value=1; @@ -4432,7 +4607,7 @@ Item_func::optimize_type Item_func_like::select_optimize() const { if (args[1]->const_item()) { - String* res2= args[1]->val_str((String *)&tmp_value2); + String* res2= args[1]->val_str((String *)&cmp.value2); if (!res2) return OPTIMIZE_NONE; @@ -4463,7 +4638,7 @@ bool Item_func_like::fix_fields(THD *thd, Item **ref) if (escape_item->const_item()) { /* If we are on execution stage */ - String *escape_str= escape_item->val_str(&tmp_value1); + String *escape_str= escape_item->val_str(&cmp.value1); if (escape_str) { if (escape_used_in_parsing && ( @@ -4518,7 +4693,7 @@ bool Item_func_like::fix_fields(THD *thd, Item **ref) if (args[1]->const_item() && !use_strnxfrm(collation.collation) && !(specialflag & SPECIAL_NO_NEW_FUNC)) { - String* res2 = args[1]->val_str(&tmp_value2); + String* res2 = args[1]->val_str(&cmp.value2); if (!res2) return FALSE; // Null argument diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 488909ae761..7805411dfa2 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -35,7 +35,7 @@ class Arg_comparator: public Sql_alloc { Item **a, **b; arg_cmp_func func; - Item_bool_func2 *owner; + Item_result_field *owner; Arg_comparator *comparators; // used only for compare_row() double precision; /* Fields used in DATE/DATETIME comparison. */ @@ -43,30 +43,42 @@ class Arg_comparator: public Sql_alloc enum_field_types a_type, b_type; // Types of a and b items Item *a_cache, *b_cache; // Cached values of a and b items bool is_nulls_eq; // TRUE <=> compare for the EQUAL_FUNC + bool set_null; // TRUE <=> set owner->null_value + // when one of arguments is NULL. + bool year_as_datetime; // TRUE <=> convert YEAR value to + // the YYYY-00-00 00:00:00 DATETIME + // format. See compare_year. enum enum_date_cmp_type { CMP_DATE_DFLT= 0, CMP_DATE_WITH_DATE, CMP_DATE_WITH_STR, CMP_STR_WITH_DATE }; - longlong (*get_value_func)(THD *thd, Item ***item_arg, Item **cache_arg, - Item *warn_item, bool *is_null); + longlong (*get_value_a_func)(THD *thd, Item ***item_arg, Item **cache_arg, + Item *warn_item, bool *is_null); + longlong (*get_value_b_func)(THD *thd, Item ***item_arg, Item **cache_arg, + Item *warn_item, bool *is_null); public: DTCollation cmp_collation; + /* Allow owner function to use string buffers. */ + String value1, value2; - Arg_comparator(): thd(0), a_cache(0), b_cache(0) {}; + Arg_comparator(): thd(0), a_cache(0), b_cache(0), set_null(0), + year_as_datetime(0), get_value_a_func(0), get_value_b_func(0) {}; Arg_comparator(Item **a1, Item **a2): a(a1), b(a2), thd(0), - a_cache(0), b_cache(0) {}; + a_cache(0), b_cache(0), set_null(0), year_as_datetime(0), + get_value_a_func(0), get_value_b_func(0) {}; - int set_compare_func(Item_bool_func2 *owner, Item_result type); - inline int set_compare_func(Item_bool_func2 *owner_arg) + int set_compare_func(Item_result_field *owner, Item_result type); + inline int set_compare_func(Item_result_field *owner_arg) { return set_compare_func(owner_arg, item_cmp_type((*a)->result_type(), (*b)->result_type())); } - int set_cmp_func(Item_bool_func2 *owner_arg, + int set_cmp_func(Item_result_field *owner_arg, Item **a1, Item **a2, Item_result type); - inline int set_cmp_func(Item_bool_func2 *owner_arg, - Item **a1, Item **a2) + inline int set_cmp_func(Item_result_field *owner_arg, + Item **a1, Item **a2, bool set_null_arg) { + set_null= set_null_arg; return set_cmp_func(owner_arg, a1, a2, item_cmp_type((*a1)->result_type(), (*a2)->result_type())); @@ -92,14 +104,20 @@ public: int compare_real_fixed(); int compare_e_real_fixed(); int compare_datetime(); // compare args[0] & args[1] as DATETIMEs + int compare_year(); static enum enum_date_cmp_type can_compare_as_dates(Item *a, Item *b, ulonglong *const_val_arg); - void set_datetime_cmp_func(Item **a1, Item **b1); Item** cache_converted_constant(THD *thd, Item **value, Item **cache, Item_result type); + void set_datetime_cmp_func(Item_result_field *owner_arg, Item **a1, Item **b1); static arg_cmp_func comparator_matrix [5][2]; + inline bool is_owner_equal_func() + { + return (owner->type() == Item::FUNC_ITEM && + ((Item_func*)owner)->functype() == Item_func::EQUAL_FUNC); + } friend class Item_func; }; @@ -329,7 +347,6 @@ class Item_bool_func2 :public Item_int_func { /* Bool with 2 string args */ protected: Arg_comparator cmp; - String tmp_value1,tmp_value2; bool abort_on_null; public: @@ -338,7 +355,7 @@ public: void fix_length_and_dec(); void set_cmp_func() { - cmp.set_cmp_func(this, tmp_arg, tmp_arg+1); + cmp.set_cmp_func(this, tmp_arg, tmp_arg+1, TRUE); } optimize_type select_optimize() const { return OPTIMIZE_OP; } virtual enum Functype rev_functype() const { return UNKNOWN_FUNC; } diff --git a/sql/item_create.cc b/sql/item_create.cc index 070ab5263dd..c00b5ec1701 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -3561,6 +3561,7 @@ Create_func_get_lock Create_func_get_lock::s_singleton; Item* Create_func_get_lock::create(THD *thd, Item *arg1, Item *arg2) { + thd->lex->set_stmt_unsafe(); thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT); return new (thd->mem_root) Item_func_get_lock(arg1, arg2); } @@ -3672,6 +3673,7 @@ Create_func_is_free_lock Create_func_is_free_lock::s_singleton; Item* Create_func_is_free_lock::create(THD *thd, Item *arg1) { + thd->lex->set_stmt_unsafe(); thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT); return new (thd->mem_root) Item_func_is_free_lock(arg1); } @@ -3682,6 +3684,7 @@ Create_func_is_used_lock Create_func_is_used_lock::s_singleton; Item* Create_func_is_used_lock::create(THD *thd, Item *arg1) { + thd->lex->set_stmt_unsafe(); thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT); return new (thd->mem_root) Item_func_is_used_lock(arg1); } @@ -3998,6 +4001,8 @@ Create_func_master_pos_wait::create_native(THD *thd, LEX_STRING name, Item *func= NULL; int arg_count= 0; + thd->lex->set_stmt_unsafe(); + if (item_list != NULL) arg_count= item_list->elements; @@ -4240,6 +4245,7 @@ Create_func_release_lock Create_func_release_lock::s_singleton; Item* Create_func_release_lock::create(THD *thd, Item *arg1) { + thd->lex->set_stmt_unsafe(); thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT); return new (thd->mem_root) Item_func_release_lock(arg1); } @@ -4362,6 +4368,7 @@ Create_func_sleep Create_func_sleep::s_singleton; Item* Create_func_sleep::create(THD *thd, Item *arg1) { + thd->lex->set_stmt_unsafe(); thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT); return new (thd->mem_root) Item_func_sleep(arg1); } @@ -4637,6 +4644,7 @@ Create_func_version Create_func_version::s_singleton; Item* Create_func_version::create(THD *thd) { + thd->lex->set_stmt_unsafe(); return new (thd->mem_root) Item_static_string_func("version()", server_version, (uint) strlen(server_version), diff --git a/sql/item_func.cc b/sql/item_func.cc index 883476369f2..6f14e69e101 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -1,4 +1,4 @@ -/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc. +/* Copyright 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. 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 @@ -451,45 +451,8 @@ Field *Item_func::tmp_table_field(TABLE *table) return make_string_field(table); break; case DECIMAL_RESULT: - { - uint8 dec= decimals; - uint8 intg= decimal_precision() - dec; - uint32 len= max_length; - - /* - Trying to put too many digits overall in a DECIMAL(prec,dec) - will always throw a warning. We must limit dec to - DECIMAL_MAX_SCALE however to prevent an assert() later. - */ - - if (dec > 0) - { - int overflow; - - dec= min(dec, DECIMAL_MAX_SCALE); - - /* - If the value still overflows the field with the corrected dec, - we'll throw out decimals rather than integers. This is still - bad and of course throws a truncation warning. - */ - - const int required_length= - my_decimal_precision_to_length(intg + dec, dec, - unsigned_flag); - - overflow= required_length - len; - - if (overflow > 0) - dec= max(0, dec - overflow); // too long, discard fract - else - /* Corrected value fits. */ - len= required_length; - } - - field= new Field_new_decimal(len, maybe_null, name, dec, unsigned_flag); + field= Field_new_decimal::create_from_item(this); break; - } case ROW_RESULT: default: // This case should never be chosen @@ -3319,7 +3282,7 @@ bool udf_handler::get_arguments() { return 0; } ** User level locks */ -pthread_mutex_t LOCK_user_locks; +mysql_mutex_t LOCK_user_locks; static HASH hash_user_locks; class User_level_lock @@ -3330,7 +3293,7 @@ class User_level_lock public: int count; bool locked; - pthread_cond_t cond; + mysql_cond_t cond; my_thread_id thread_id; void set_thread(THD *thd) { thread_id= thd->thread_id; } @@ -3338,7 +3301,7 @@ public: :key_length(length),count(1),locked(1), thread_id(id) { key= (uchar*) my_memdup(key_arg,length,MYF(0)); - pthread_cond_init(&cond,NULL); + mysql_cond_init(key_user_level_lock_cond, &cond, NULL); if (key) { if (my_hash_insert(&hash_user_locks,(uchar*) this)) @@ -3355,7 +3318,7 @@ public: my_hash_delete(&hash_user_locks,(uchar*) this); my_free(key, MYF(0)); } - pthread_cond_destroy(&cond); + mysql_cond_destroy(&cond); } inline bool initialized() { return key != 0; } friend void item_user_lock_release(User_level_lock *ull); @@ -3370,12 +3333,36 @@ uchar *ull_get_key(const User_level_lock *ull, size_t *length, return ull->key; } +#ifdef HAVE_PSI_INTERFACE +static PSI_mutex_key key_LOCK_user_locks; + +static PSI_mutex_info all_user_mutexes[]= +{ + { &key_LOCK_user_locks, "LOCK_user_locks", PSI_FLAG_GLOBAL} +}; + +static void init_user_lock_psi_keys(void) +{ + const char* category= "sql"; + int count; + + if (PSI_server == NULL) + return; + + count= array_elements(all_user_mutexes); + PSI_server->register_mutex(category, all_user_mutexes, count); +} +#endif static bool item_user_lock_inited= 0; void item_user_lock_init(void) { - pthread_mutex_init(&LOCK_user_locks,MY_MUTEX_INIT_SLOW); +#ifdef HAVE_PSI_INTERFACE + init_user_lock_psi_keys(); +#endif + + mysql_mutex_init(key_LOCK_user_locks, &LOCK_user_locks, MY_MUTEX_INIT_SLOW); my_hash_init(&hash_user_locks,system_charset_info, 16,0,0,(my_hash_get_key) ull_get_key,NULL,0); item_user_lock_inited= 1; @@ -3387,7 +3374,7 @@ void item_user_lock_free(void) { item_user_lock_inited= 0; my_hash_free(&hash_user_locks); - pthread_mutex_destroy(&LOCK_user_locks); + mysql_mutex_destroy(&LOCK_user_locks); } } @@ -3396,7 +3383,7 @@ void item_user_lock_release(User_level_lock *ull) ull->locked=0; ull->thread_id= 0; if (--ull->count) - pthread_cond_signal(&ull->cond); + mysql_cond_signal(&ull->cond); else delete ull; } @@ -3439,7 +3426,7 @@ void debug_sync_point(const char* lock_name, uint lock_timeout) struct timespec abstime; size_t lock_name_len; lock_name_len= strlen(lock_name); - pthread_mutex_lock(&LOCK_user_locks); + mysql_mutex_lock(&LOCK_user_locks); if (thd->ull) { @@ -3457,7 +3444,7 @@ void debug_sync_point(const char* lock_name, uint lock_timeout) (uchar*) lock_name, lock_name_len)))) { - pthread_mutex_unlock(&LOCK_user_locks); + mysql_mutex_unlock(&LOCK_user_locks); return; } ull->count++; @@ -3473,7 +3460,7 @@ void debug_sync_point(const char* lock_name, uint lock_timeout) set_timespec(abstime,lock_timeout); while (ull->locked && !thd->killed) { - int error= pthread_cond_timedwait(&ull->cond, &LOCK_user_locks, &abstime); + int error= mysql_cond_timedwait(&ull->cond, &LOCK_user_locks, &abstime); if (error == ETIMEDOUT || error == ETIME) break; } @@ -3489,19 +3476,19 @@ void debug_sync_point(const char* lock_name, uint lock_timeout) ull->set_thread(thd); thd->ull=ull; } - pthread_mutex_unlock(&LOCK_user_locks); - pthread_mutex_lock(&thd->mysys_var->mutex); + mysql_mutex_unlock(&LOCK_user_locks); + mysql_mutex_lock(&thd->mysys_var->mutex); thd_proc_info(thd, 0); thd->mysys_var->current_mutex= 0; thd->mysys_var->current_cond= 0; - pthread_mutex_unlock(&thd->mysys_var->mutex); - pthread_mutex_lock(&LOCK_user_locks); + mysql_mutex_unlock(&thd->mysys_var->mutex); + mysql_mutex_lock(&LOCK_user_locks); if (thd->ull) { item_user_lock_release(thd->ull); thd->ull=0; } - pthread_mutex_unlock(&LOCK_user_locks); + mysql_mutex_unlock(&LOCK_user_locks); } #endif @@ -3519,8 +3506,8 @@ void debug_sync_point(const char* lock_name, uint lock_timeout) #define INTERRUPT_INTERVAL (5 * ULL(1000000000)) -static int interruptible_wait(THD *thd, pthread_cond_t *cond, - pthread_mutex_t *lock, double time) +static int interruptible_wait(THD *thd, mysql_cond_t *cond, + mysql_mutex_t *lock, double time) { int error; struct timespec abstime; @@ -3536,7 +3523,7 @@ static int interruptible_wait(THD *thd, pthread_cond_t *cond, timeout-= slice; set_timespec_nsec(abstime, slice); - error= pthread_cond_timedwait(cond, lock, &abstime); + error= mysql_cond_timedwait(cond, lock, &abstime); if (error == ETIMEDOUT || error == ETIME) { /* Return error if timed out or connection is broken. */ @@ -3579,11 +3566,11 @@ longlong Item_func_get_lock::val_int() if (thd->slave_thread) DBUG_RETURN(1); - pthread_mutex_lock(&LOCK_user_locks); + mysql_mutex_lock(&LOCK_user_locks); if (!res || !res->length()) { - pthread_mutex_unlock(&LOCK_user_locks); + mysql_mutex_unlock(&LOCK_user_locks); null_value=1; DBUG_RETURN(0); } @@ -3606,13 +3593,13 @@ longlong Item_func_get_lock::val_int() if (!ull || !ull->initialized()) { delete ull; - pthread_mutex_unlock(&LOCK_user_locks); + mysql_mutex_unlock(&LOCK_user_locks); null_value=1; // Probably out of memory DBUG_RETURN(0); } ull->set_thread(thd); thd->ull=ull; - pthread_mutex_unlock(&LOCK_user_locks); + mysql_mutex_unlock(&LOCK_user_locks); DBUG_PRINT("info", ("made new lock")); DBUG_RETURN(1); // Got new lock } @@ -3662,13 +3649,13 @@ longlong Item_func_get_lock::val_int() error=0; DBUG_PRINT("info", ("got the lock")); } - pthread_mutex_unlock(&LOCK_user_locks); + mysql_mutex_unlock(&LOCK_user_locks); - pthread_mutex_lock(&thd->mysys_var->mutex); + mysql_mutex_lock(&thd->mysys_var->mutex); thd_proc_info(thd, 0); thd->mysys_var->current_mutex= 0; thd->mysys_var->current_cond= 0; - pthread_mutex_unlock(&thd->mysys_var->mutex); + mysql_mutex_unlock(&thd->mysys_var->mutex); DBUG_RETURN(!error ? 1 : 0); } @@ -3699,7 +3686,7 @@ longlong Item_func_release_lock::val_int() null_value=0; result=0; - pthread_mutex_lock(&LOCK_user_locks); + mysql_mutex_lock(&LOCK_user_locks); if (!(ull= ((User_level_lock*) my_hash_search(&hash_user_locks, (const uchar*) res->ptr(), (size_t) res->length())))) @@ -3720,7 +3707,7 @@ longlong Item_func_release_lock::val_int() thd->ull=0; } } - pthread_mutex_unlock(&LOCK_user_locks); + mysql_mutex_unlock(&LOCK_user_locks); DBUG_RETURN(result); } @@ -3826,7 +3813,7 @@ void Item_func_benchmark::print(String *str, enum_query_type query_type) longlong Item_func_sleep::val_int() { THD *thd= current_thd; - pthread_cond_t cond; + mysql_cond_t cond; double timeout; int error; @@ -3840,13 +3827,13 @@ longlong Item_func_sleep::val_int() When given a very short timeout (< 10 mcs) just return immediately. We assume that the lines between this test and the call - to pthread_cond_timedwait() will be executed in less than 0.00001 sec. + to mysql_cond_timedwait() will be executed in less than 0.00001 sec. */ if (timeout < 0.00001) return 0; - pthread_cond_init(&cond, NULL); - pthread_mutex_lock(&LOCK_user_locks); + mysql_cond_init(key_item_func_sleep_cond, &cond, NULL); + mysql_mutex_lock(&LOCK_user_locks); thd_proc_info(thd, "User sleep"); thd->mysys_var->current_mutex= &LOCK_user_locks; @@ -3861,13 +3848,13 @@ longlong Item_func_sleep::val_int() error= 0; } thd_proc_info(thd, 0); - pthread_mutex_unlock(&LOCK_user_locks); - pthread_mutex_lock(&thd->mysys_var->mutex); + mysql_mutex_unlock(&LOCK_user_locks); + mysql_mutex_lock(&thd->mysys_var->mutex); thd->mysys_var->current_mutex= 0; thd->mysys_var->current_cond= 0; - pthread_mutex_unlock(&thd->mysys_var->mutex); + mysql_mutex_unlock(&thd->mysys_var->mutex); - pthread_cond_destroy(&cond); + mysql_cond_destroy(&cond); return test(!error); // Return 1 killed } @@ -5795,10 +5782,10 @@ longlong Item_func_is_free_lock::val_int() return 0; } - pthread_mutex_lock(&LOCK_user_locks); + mysql_mutex_lock(&LOCK_user_locks); ull= (User_level_lock *) my_hash_search(&hash_user_locks, (uchar*) res->ptr(), (size_t) res->length()); - pthread_mutex_unlock(&LOCK_user_locks); + mysql_mutex_unlock(&LOCK_user_locks); if (!ull || !ull->locked) return 1; return 0; @@ -5814,10 +5801,10 @@ longlong Item_func_is_used_lock::val_int() if (!res || !res->length()) return 0; - pthread_mutex_lock(&LOCK_user_locks); + mysql_mutex_lock(&LOCK_user_locks); ull= (User_level_lock *) my_hash_search(&hash_user_locks, (uchar*) res->ptr(), (size_t) res->length()); - pthread_mutex_unlock(&LOCK_user_locks); + mysql_mutex_unlock(&LOCK_user_locks); if (!ull || !ull->locked) return 0; diff --git a/sql/item_func.h b/sql/item_func.h index 6f2b3f0bfc2..f22bc0c301c 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -127,17 +127,6 @@ public: virtual optimize_type select_optimize() const { return OPTIMIZE_NONE; } virtual bool have_rev_func() const { return 0; } virtual Item *key_item() const { return args[0]; } - /* - This method is used for debug purposes to print the name of an - item to the debug log. The second use of this method is as - a helper function of print(), where it is applicable. - To suit both goals it should return a meaningful, - distinguishable and sintactically correct string. This method - should not be used for runtime type identification, use enum - {Sum}Functype and Item_func::functype()/Item_sum::sum_func() - instead. - */ - virtual const char *func_name() const= 0; virtual bool const_item() const { return const_item_cache; } inline Item **arguments() const { return args; } void set_arguments(List<Item> &list); diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index 3c5990eb359..8c38cb2a859 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -511,8 +511,8 @@ err: longlong Item_func_spatial_rel::val_int() { DBUG_ASSERT(fixed == 1); - String *res1= args[0]->val_str(&tmp_value1); - String *res2= args[1]->val_str(&tmp_value2); + String *res1= args[0]->val_str(&cmp.value1); + String *res2= args[1]->val_str(&cmp.value2); Geometry_buffer buffer1, buffer2; Geometry *g1, *g2; MBR mbr1, mbr2; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 923b943c950..95e28e791ec 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1827,8 +1827,9 @@ String *Item_func_database::val_str(String *str) /** - @todo - make USER() replicate properly (currently it is replicated to "") + @note USER() is replicated correctly if binlog_format=ROW or (as of + BUG#28086) binlog_format=MIXED, but is incorrectly replicated to '' + if binlog_format=STATEMENT. */ bool Item_func_user::init(const char *user, const char *host) { diff --git a/sql/item_subselect.h b/sql/item_subselect.h index ea59521aab1..3503d42edc0 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -135,6 +135,7 @@ public: @return the SELECT_LEX structure associated with this Item */ st_select_lex* get_select_lex(); + const char *func_name() const { DBUG_ASSERT(0); return "subselect"; } friend class select_subselect; friend class Item_in_optimizer; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index f72b64fc66e..831f0287266 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -534,8 +534,7 @@ Field *Item_sum::create_tmp_field(bool group, TABLE *table, name, table->s, collation.collation); break; case DECIMAL_RESULT: - field= new Field_new_decimal(max_length, maybe_null, name, - decimals, unsigned_flag); + field= Field_new_decimal::create_from_item(this); break; case ROW_RESULT: default: @@ -1137,35 +1136,6 @@ Item_sum_num::fix_fields(THD *thd, Item **ref) } -Item_sum_hybrid::Item_sum_hybrid(THD *thd, Item_sum_hybrid *item) - :Item_sum(thd, item), value(item->value), hybrid_type(item->hybrid_type), - hybrid_field_type(item->hybrid_field_type), cmp_sign(item->cmp_sign), - was_values(item->was_values) -{ - /* copy results from old value */ - switch (hybrid_type) { - case INT_RESULT: - sum_int= item->sum_int; - break; - case DECIMAL_RESULT: - my_decimal2decimal(&item->sum_dec, &sum_dec); - break; - case REAL_RESULT: - sum= item->sum; - break; - case STRING_RESULT: - /* - This can happen with ROLLUP. Note that the value is already - copied at function call. - */ - break; - case ROW_RESULT: - default: - DBUG_ASSERT(0); - } - collation.set(item->collation); -} - bool Item_sum_hybrid::fix_fields(THD *thd, Item **ref) { @@ -1185,15 +1155,12 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref) switch (hybrid_type= item->result_type()) { case INT_RESULT: max_length= 20; - sum_int= 0; break; case DECIMAL_RESULT: max_length= item->max_length; - my_decimal_set_zero(&sum_dec); break; case REAL_RESULT: max_length= float_length(decimals); - sum= 0.0; break; case STRING_RESULT: max_length= item->max_length; @@ -1202,10 +1169,10 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref) default: DBUG_ASSERT(0); }; + setup(args[0], NULL); /* MIN/MAX can return NULL for empty set indepedent of the used column */ maybe_null= 1; unsigned_flag=item->unsigned_flag; - collation.set(item->collation); result_field=0; null_value=1; fix_length_and_dec(); @@ -1223,6 +1190,31 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref) return FALSE; } + +/** + MIN/MAX function setup. + + @param item argument of MIN/MAX function + @param value_arg calculated value of MIN/MAX function + + @details + Setup cache/comparator of MIN/MAX functions. When called by the + copy_or_same function value_arg parameter contains calculated value + of the original MIN/MAX object and it is saved in this object's cache. +*/ + +void Item_sum_hybrid::setup(Item *item, Item *value_arg) +{ + value= Item_cache::get_cache(item); + value->setup(item); + if (value_arg) + value->store(value_arg); + cmp= new Arg_comparator(); + cmp->set_cmp_func(this, args, (Item**)&value, FALSE); + collation.set(item->collation); +} + + Field *Item_sum_hybrid::create_tmp_field(bool group, TABLE *table, uint convert_blob_length) { @@ -1577,8 +1569,7 @@ Field *Item_sum_avg::create_tmp_field(bool group, TABLE *table, 0, name, &my_charset_bin); } else if (hybrid_type == DECIMAL_RESULT) - field= new Field_new_decimal(max_length, maybe_null, name, - decimals, unsigned_flag); + field= Field_new_decimal::create_from_item(this); else field= new Field_double(max_length, maybe_null, name, decimals, TRUE); if (field) @@ -1905,19 +1896,7 @@ void Item_sum_variance::update_field() void Item_sum_hybrid::clear() { - switch (hybrid_type) { - case INT_RESULT: - sum_int= 0; - break; - case DECIMAL_RESULT: - my_decimal_set_zero(&sum_dec); - break; - case REAL_RESULT: - sum= 0.0; - break; - default: - value.length(0); - } + value->null_value= 1; null_value= 1; } @@ -1926,30 +1905,7 @@ double Item_sum_hybrid::val_real() DBUG_ASSERT(fixed == 1); if (null_value) return 0.0; - switch (hybrid_type) { - case STRING_RESULT: - { - char *end_not_used; - int err_not_used; - String *res; res=val_str(&str_value); - return (res ? my_strntod(res->charset(), (char*) res->ptr(), res->length(), - &end_not_used, &err_not_used) : 0.0); - } - case INT_RESULT: - if (unsigned_flag) - return ulonglong2double(sum_int); - return (double) sum_int; - case DECIMAL_RESULT: - my_decimal2double(E_DEC_FATAL_ERROR, &sum_dec, &sum); - return sum; - case REAL_RESULT: - return sum; - case ROW_RESULT: - default: - // This case should never be choosen - DBUG_ASSERT(0); - return 0; - } + return value->val_real(); } longlong Item_sum_hybrid::val_int() @@ -1957,18 +1913,7 @@ longlong Item_sum_hybrid::val_int() DBUG_ASSERT(fixed == 1); if (null_value) return 0; - switch (hybrid_type) { - case INT_RESULT: - return sum_int; - case DECIMAL_RESULT: - { - longlong result; - my_decimal2int(E_DEC_FATAL_ERROR, &sum_dec, unsigned_flag, &result); - return sum_int; - } - default: - return (longlong) rint(Item_sum_hybrid::val_real()); - } + return value->val_int(); } @@ -1977,26 +1922,7 @@ my_decimal *Item_sum_hybrid::val_decimal(my_decimal *val) DBUG_ASSERT(fixed == 1); if (null_value) return 0; - switch (hybrid_type) { - case STRING_RESULT: - string2my_decimal(E_DEC_FATAL_ERROR, &value, val); - break; - case REAL_RESULT: - double2my_decimal(E_DEC_FATAL_ERROR, sum, val); - break; - case DECIMAL_RESULT: - val= &sum_dec; - break; - case INT_RESULT: - int2my_decimal(E_DEC_FATAL_ERROR, sum_int, unsigned_flag, val); - break; - case ROW_RESULT: - default: - // This case should never be choosen - DBUG_ASSERT(0); - break; - } - return val; // Keep compiler happy + return value->val_decimal(val); } @@ -2006,25 +1932,7 @@ Item_sum_hybrid::val_str(String *str) DBUG_ASSERT(fixed == 1); if (null_value) return 0; - switch (hybrid_type) { - case STRING_RESULT: - return &value; - case REAL_RESULT: - str->set_real(sum,decimals, &my_charset_bin); - break; - case DECIMAL_RESULT: - my_decimal2string(E_DEC_FATAL_ERROR, &sum_dec, 0, 0, 0, str); - return str; - case INT_RESULT: - str->set_int(sum_int, unsigned_flag, &my_charset_bin); - break; - case ROW_RESULT: - default: - // This case should never be choosen - DBUG_ASSERT(0); - break; - } - return str; // Keep compiler happy + return value->val_str(str); } @@ -2033,7 +1941,9 @@ void Item_sum_hybrid::cleanup() DBUG_ENTER("Item_sum_hybrid::cleanup"); Item_sum::cleanup(); forced_const= FALSE; - + if (cmp) + delete cmp; + cmp= 0; /* by default it is TRUE to avoid TRUE reporting by Item_func_not_all/Item_func_nop_all if this item was never called. @@ -2054,63 +1964,22 @@ void Item_sum_hybrid::no_rows_in_result() Item *Item_sum_min::copy_or_same(THD* thd) { - return new (thd->mem_root) Item_sum_min(thd, this); + Item_sum_min *item= new (thd->mem_root) Item_sum_min(thd, this); + item->setup(args[0], value); + return item; } bool Item_sum_min::add() { - switch (hybrid_type) { - case STRING_RESULT: - { - String *result=args[0]->val_str(&tmp_value); - if (!args[0]->null_value && - (null_value || sortcmp(&value,result,collation.collation) > 0)) - { - value.copy(*result); - null_value=0; - } - } - break; - case INT_RESULT: - { - longlong nr=args[0]->val_int(); - if (!args[0]->null_value && (null_value || - (unsigned_flag && - (ulonglong) nr < (ulonglong) sum_int) || - (!unsigned_flag && nr < sum_int))) - { - sum_int=nr; - null_value=0; - } - } - break; - case DECIMAL_RESULT: - { - my_decimal value_buff, *val= args[0]->val_decimal(&value_buff); - if (!args[0]->null_value && - (null_value || (my_decimal_cmp(&sum_dec, val) > 0))) - { - my_decimal2decimal(val, &sum_dec); - null_value= 0; - } - } - break; - case REAL_RESULT: + /* args[0] < value */ + int res= cmp->compare(); + if (!args[0]->null_value && + (null_value || res < 0)) { - double nr= args[0]->val_real(); - if (!args[0]->null_value && (null_value || nr < sum)) - { - sum=nr; - null_value=0; - } - } - break; - case ROW_RESULT: - default: - // This case should never be choosen - DBUG_ASSERT(0); - break; + value->store(args[0]); + value->cache_value(); + null_value= 0; } return 0; } @@ -2118,63 +1987,22 @@ bool Item_sum_min::add() Item *Item_sum_max::copy_or_same(THD* thd) { - return new (thd->mem_root) Item_sum_max(thd, this); + Item_sum_max *item= new (thd->mem_root) Item_sum_max(thd, this); + item->setup(args[0], value); + return item; } bool Item_sum_max::add() { - switch (hybrid_type) { - case STRING_RESULT: + /* args[0] > value */ + int res= cmp->compare(); + if (!args[0]->null_value && + (null_value || res > 0)) { - String *result=args[0]->val_str(&tmp_value); - if (!args[0]->null_value && - (null_value || sortcmp(&value,result,collation.collation) < 0)) - { - value.copy(*result); - null_value=0; - } - } - break; - case INT_RESULT: - { - longlong nr=args[0]->val_int(); - if (!args[0]->null_value && (null_value || - (unsigned_flag && - (ulonglong) nr > (ulonglong) sum_int) || - (!unsigned_flag && nr > sum_int))) - { - sum_int=nr; - null_value=0; - } - } - break; - case DECIMAL_RESULT: - { - my_decimal value_buff, *val= args[0]->val_decimal(&value_buff); - if (!args[0]->null_value && - (null_value || (my_decimal_cmp(val, &sum_dec) > 0))) - { - my_decimal2decimal(val, &sum_dec); - null_value= 0; - } - } - break; - case REAL_RESULT: - { - double nr= args[0]->val_real(); - if (!args[0]->null_value && (null_value || nr > sum)) - { - sum=nr; - null_value=0; - } - } - break; - case ROW_RESULT: - default: - // This case should never be choosen - DBUG_ASSERT(0); - break; + value->store(args[0]); + value->cache_value(); + null_value= 0; } return 0; } @@ -2546,14 +2374,15 @@ void Item_sum_hybrid::update_field() void Item_sum_hybrid::min_max_update_str_field() { - String *res_str=args[0]->val_str(&value); + DBUG_ASSERT(cmp); + String *res_str=args[0]->val_str(&cmp->value1); if (!args[0]->null_value) { - result_field->val_str(&tmp_value); + result_field->val_str(&cmp->value2); if (result_field->is_null() || - (cmp_sign * sortcmp(res_str,&tmp_value,collation.collation)) < 0) + (cmp_sign * sortcmp(res_str,&cmp->value2,collation.collation)) < 0) result_field->store(res_str->ptr(),res_str->length(),res_str->charset()); result_field->set_notnull(); } diff --git a/sql/item_sum.h b/sql/item_sum.h index 9e062ce1d16..26f0a08096e 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -413,22 +413,6 @@ public: virtual void update_field()=0; virtual bool keep_field_type(void) const { return 0; } virtual void fix_length_and_dec() { maybe_null=1; null_value=1; } - /* - This method is used for debug purposes to print the name of an - item to the debug log. The second use of this method is as - a helper function of print(), where it is applicable. - To suit both goals it should return a meaningful, - distinguishable and sintactically correct string. This method - should not be used for runtime type identification, use enum - {Sum}Functype and Item_func::functype()/Item_sum::sum_func() - instead. - - NOTE: for Items inherited from Item_sum, func_name() return part of - function name till first argument (including '(') to make difference in - names for functions with 'distinct' clause and without 'distinct' and - also to make printing of items inherited from Item_sum uniform. - */ - virtual const char *func_name() const= 0; virtual Item *result_item(Field *field) { return new Item_field(field); } table_map used_tables() const { return used_tables_cache; } @@ -800,6 +784,7 @@ public: } void fix_length_and_dec() {} enum Item_result result_type () const { return hybrid_type; } + const char *func_name() const { DBUG_ASSERT(0); return "avg_field"; } }; @@ -876,6 +861,7 @@ public: } void fix_length_and_dec() {} enum Item_result result_type () const { return hybrid_type; } + const char *func_name() const { DBUG_ASSERT(0); return "variance_field"; } }; @@ -951,6 +937,7 @@ public: my_decimal *val_decimal(my_decimal *); enum Item_result result_type () const { return REAL_RESULT; } enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE;} + const char *func_name() const { DBUG_ASSERT(0); return "std_field"; } }; /* @@ -976,14 +963,13 @@ class Item_sum_std :public Item_sum_variance }; // This class is a string or number function depending on num_func - +class Arg_comparator; +class Item_cache; class Item_sum_hybrid :public Item_sum { protected: - String value,tmp_value; - double sum; - longlong sum_int; - my_decimal sum_dec; + Item_cache *value; + Arg_comparator *cmp; Item_result hybrid_type; enum_field_types hybrid_field_type; int cmp_sign; @@ -991,12 +977,17 @@ protected: public: Item_sum_hybrid(Item *item_par,int sign) - :Item_sum(item_par), sum(0.0), sum_int(0), + :Item_sum(item_par), value(0), cmp(0), hybrid_type(INT_RESULT), hybrid_field_type(MYSQL_TYPE_LONGLONG), cmp_sign(sign), was_values(TRUE) { collation.set(&my_charset_bin); } - Item_sum_hybrid(THD *thd, Item_sum_hybrid *item); + Item_sum_hybrid(THD *thd, Item_sum_hybrid *item) + :Item_sum(thd, item), value(item->value), hybrid_type(item->hybrid_type), + hybrid_field_type(item->hybrid_field_type), cmp_sign(item->cmp_sign), + was_values(item->was_values) + { } bool fix_fields(THD *, Item **); + void setup(Item *item, Item *value_arg); void clear(); double val_real(); longlong val_int(); diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 3009c48cac7..56c46efb1a8 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -386,7 +386,7 @@ static bool extract_date_time(DATE_TIME_FORMAT *format, if (tmp - val > 6) tmp= (char*) val + 6; l_time->second_part= (int) my_strtoll10(val, &tmp, &error); - frac_part= 6 - (uint) (tmp - val); + frac_part= 6 - (int) (tmp - val); if (frac_part > 0) l_time->second_part*= (ulong) log_10_int[frac_part]; val= tmp; diff --git a/sql/lock.cc b/sql/lock.cc index bd4068046ca..f82cc4e7d7b 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -1,4 +1,4 @@ -/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc. +/* Copyright 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. 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 @@ -1352,7 +1352,7 @@ wait_if_global_read_lock(THD *thd, bool abort_on_refresh, threads could not close their tables. This would make a pretty deadlock. */ - safe_mutex_assert_not_owner(&LOCK_open); + mysql_mutex_assert_not_owner(&LOCK_open); (void) pthread_mutex_lock(&LOCK_global_read_lock); if ((need_exit_cond= must_wait)) @@ -1507,7 +1507,7 @@ bool Global_read_lock::make_global_read_lock_block_commit(THD *thd) void broadcast_refresh(void) { - pthread_cond_broadcast(&COND_refresh); + mysql_cond_broadcast(&COND_refresh); pthread_cond_broadcast(&COND_global_read_lock); } diff --git a/sql/log.cc b/sql/log.cc index e1f98ffa1bf..31276f30868 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -5789,9 +5789,8 @@ int TC_LOG_BINLOG::recover(IO_CACHE *log, Format_description_log_event *fdle) Xid_log_event *xev=(Xid_log_event *)ev; uchar *x= (uchar *) memdup_root(&mem_root, (uchar*) &xev->xid, sizeof(xev->xid)); - if (! x) + if (!x || my_hash_insert(&xids, x)) goto err2; - my_hash_insert(&xids, x); } delete ev; } diff --git a/sql/log_event.cc b/sql/log_event.cc index 8afd243da63..85647acfbe4 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -3056,10 +3056,7 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli, rpl_filter->db_ok(thd->db)) { thd->set_time((time_t)when); - thd->set_query((char*)query_arg, q_len_arg); - pthread_mutex_lock(&LOCK_thread_count); - thd->query_id = next_query_id(); - pthread_mutex_unlock(&LOCK_thread_count); + thd->set_query_and_id((char*)query_arg, q_len_arg, next_query_id()); thd->variables.pseudo_thread_id= thread_id; // for temp tables DBUG_PRINT("query",("%s", thd->query())); @@ -4582,9 +4579,7 @@ int Load_log_event::do_apply_event(NET* net, Relay_log_info const *rli, if (rpl_filter->db_ok(thd->db)) { thd->set_time((time_t)when); - pthread_mutex_lock(&LOCK_thread_count); - thd->query_id = next_query_id(); - pthread_mutex_unlock(&LOCK_thread_count); + thd->set_query_id(next_query_id()); thd->warning_info->opt_clear_warning_info(thd->query_id); TABLE_LIST tables; @@ -8072,9 +8067,7 @@ int Table_map_log_event::do_apply_event(Relay_log_info const *rli) DBUG_ASSERT(rli->sql_thd == thd); /* Step the query id to mark what columns that are actually used. */ - pthread_mutex_lock(&LOCK_thread_count); - thd->query_id= next_query_id(); - pthread_mutex_unlock(&LOCK_thread_count); + thd->set_query_id(next_query_id()); if (!(memory= my_multi_malloc(MYF(MY_WME), &table_list, (uint) sizeof(RPL_TABLE_LIST), diff --git a/sql/mdl.cc b/sql/mdl.cc index fe9f4053e67..5744467f576 100644 --- a/sql/mdl.cc +++ b/sql/mdl.cc @@ -729,8 +729,8 @@ static inline const char *mdl_enter_cond(THD *thd, { safe_mutex_assert_owner(mutex); - mysys_var->current_mutex= mutex; - mysys_var->current_cond= cond; + mysys_var->current_mutex= (mysql_mutex_t*) mutex; + mysys_var->current_cond= (mysql_cond_t*) cond; DEBUG_SYNC(thd, "mdl_enter_cond"); @@ -749,13 +749,13 @@ static inline void mdl_exit_cond(THD *thd, const char *calling_file, const unsigned int calling_line) { - DBUG_ASSERT(mutex == mysys_var->current_mutex); + DBUG_ASSERT(mutex == (pthread_mutex_t*) mysys_var->current_mutex); pthread_mutex_unlock(mutex); - pthread_mutex_lock(&mysys_var->mutex); + mysql_mutex_lock(&mysys_var->mutex); mysys_var->current_mutex= 0; mysys_var->current_cond= 0; - pthread_mutex_unlock(&mysys_var->mutex); + mysql_mutex_unlock(&mysys_var->mutex); DEBUG_SYNC(thd, "mdl_exit_cond"); @@ -1099,7 +1099,7 @@ bool MDL_lock::has_pending_conflicting_lock(enum_mdl_type type) { bool result; - safe_mutex_assert_not_owner(&LOCK_open); + mysql_mutex_assert_not_owner(&LOCK_open); rw_rdlock(&m_rwlock); result= (m_waiting.bitmap() & incompatible_granted_types_bitmap()[type]); @@ -1274,7 +1274,7 @@ MDL_context::try_acquire_lock(MDL_request *mdl_request) /* Don't take chances in production. */ mdl_request->ticket= NULL; - safe_mutex_assert_not_owner(&LOCK_open); + mysql_mutex_assert_not_owner(&LOCK_open); /* Check whether the context already holds a shared lock on the object, @@ -1361,7 +1361,7 @@ MDL_context::clone_ticket(MDL_request *mdl_request) { MDL_ticket *ticket; - safe_mutex_assert_not_owner(&LOCK_open); + mysql_mutex_assert_not_owner(&LOCK_open); /* By submitting mdl_request->type to MDL_ticket::create() we effectively downgrade the cloned lock to the level of @@ -1436,7 +1436,7 @@ bool MDL_context::acquire_lock_impl(MDL_request *mdl_request) st_my_thread_var *mysys_var= my_thread_var; MDL_key *key= &mdl_request->key; - safe_mutex_assert_not_owner(&LOCK_open); + mysql_mutex_assert_not_owner(&LOCK_open); DBUG_ASSERT(mdl_request->ticket == NULL); /* Don't take chances in production. */ @@ -1830,7 +1830,7 @@ MDL_context::wait_for_lock(MDL_request *mdl_request) MDL_lock *lock; st_my_thread_var *mysys_var= my_thread_var; - safe_mutex_assert_not_owner(&LOCK_open); + mysql_mutex_assert_not_owner(&LOCK_open); DBUG_ASSERT(mdl_request->ticket == NULL); @@ -1907,7 +1907,7 @@ void MDL_context::release_lock(MDL_ticket *ticket) lock->key.name())); DBUG_ASSERT(this == ticket->get_ctx()); - safe_mutex_assert_not_owner(&LOCK_open); + mysql_mutex_assert_not_owner(&LOCK_open); if (ticket == m_trans_sentinel) m_trans_sentinel= ++Ticket_list::Iterator(m_tickets, ticket); @@ -2001,7 +2001,7 @@ void MDL_context::release_all_locks_for_name(MDL_ticket *name) void MDL_ticket::downgrade_exclusive_lock(enum_mdl_type type) { - safe_mutex_assert_not_owner(&LOCK_open); + mysql_mutex_assert_not_owner(&LOCK_open); /* Do nothing if already downgraded. Used when we FLUSH TABLE under diff --git a/sql/mdl.h b/sql/mdl.h index d560f38ce0a..5eb86d2488b 100644 --- a/sql/mdl.h +++ b/sql/mdl.h @@ -716,7 +716,7 @@ extern "C" const char *set_thd_proc_info(THD *thd, const char *info, const char *calling_file, const unsigned int calling_line); #ifndef DBUG_OFF -extern pthread_mutex_t LOCK_open; +extern mysql_mutex_t LOCK_open; #endif #endif diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 2316eae4cdb..a926af0370c 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -53,6 +53,7 @@ #include "sql_array.h" #include "sql_plugin.h" #include "scheduler.h" +#include <my_atomic.h> #include <mysql/psi/mysql_file.h> #ifndef __WIN__ #include <netdb.h> @@ -89,11 +90,60 @@ typedef ulong nesting_map; /* Used for flags of nesting constructs */ typedef ulonglong nested_join_map; /* query_id */ -typedef ulonglong query_id_t; +typedef int64 query_id_t; extern query_id_t global_query_id; +extern int32 thread_running; +extern my_atomic_rwlock_t global_query_id_lock; +extern my_atomic_rwlock_t thread_running_lock; /* increment query_id and return it. */ -inline query_id_t next_query_id() { return global_query_id++; } +inline query_id_t next_query_id() +{ + query_id_t id; + my_atomic_rwlock_wrlock(&global_query_id_lock); + id= my_atomic_add64(&global_query_id, 1); + my_atomic_rwlock_wrunlock(&global_query_id_lock); + return (id+1); +} + +inline query_id_t get_query_id() +{ + query_id_t id; + my_atomic_rwlock_wrlock(&global_query_id_lock); + id= my_atomic_load64(&global_query_id); + my_atomic_rwlock_wrunlock(&global_query_id_lock); + return id; +} + +inline int32 +inc_thread_running() +{ + int32 num_thread_running; + my_atomic_rwlock_wrlock(&thread_running_lock); + num_thread_running= my_atomic_add32(&thread_running, 1); + my_atomic_rwlock_wrunlock(&thread_running_lock); + return (num_thread_running+1); +} + +inline int32 +dec_thread_running() +{ + int32 num_thread_running; + my_atomic_rwlock_wrlock(&thread_running_lock); + num_thread_running= my_atomic_add32(&thread_running, -1); + my_atomic_rwlock_wrunlock(&thread_running_lock); + return (num_thread_running-1); +} + +inline int32 +get_thread_running() +{ + int32 num_thread_running; + my_atomic_rwlock_wrlock(&thread_running_lock); + num_thread_running= my_atomic_load32(&thread_running); + my_atomic_rwlock_wrunlock(&thread_running_lock); + return num_thread_running; +} /* useful constants */ extern MYSQL_PLUGIN_IMPORT const key_map key_map_empty; @@ -1476,8 +1526,8 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds); int setup_ftfuncs(SELECT_LEX* select); int init_ftfuncs(THD *thd, SELECT_LEX* select, bool no_order); -void wait_for_condition(THD *thd, pthread_mutex_t *mutex, - pthread_cond_t *cond); +void wait_for_condition(THD *thd, mysql_mutex_t *mutex, + mysql_cond_t *cond); bool open_tables(THD *thd, TABLE_LIST **tables, uint *counter, uint flags, Prelocking_strategy *prelocking_strategy); inline bool @@ -1948,7 +1998,7 @@ extern bool opt_ignore_builtin_innodb; extern my_bool opt_character_set_client_handshake; extern bool volatile abort_loop, shutdown_in_progress; extern bool in_bootstrap; -extern uint volatile thread_count, thread_running, global_read_lock; +extern uint volatile thread_count, global_read_lock; extern uint connection_count; extern my_bool opt_sql_bin_update, opt_safe_user_create, opt_no_mix_types; extern my_bool opt_safe_show_db, opt_local_infile, opt_myisam_use_mmap; @@ -1981,13 +2031,15 @@ extern FILE *bootstrap_file; extern int bootstrap_error; extern FILE *stderror_file; extern pthread_key(MEM_ROOT**,THR_MALLOC); -extern pthread_mutex_t LOCK_mysql_create_db, LOCK_open, LOCK_lock_db, - LOCK_mapped_file,LOCK_user_locks, LOCK_status, - LOCK_error_log, LOCK_delayed_insert, LOCK_uuid_generator, - LOCK_delayed_status, LOCK_delayed_create, LOCK_crypt, LOCK_timezone, +extern pthread_mutex_t LOCK_mapped_file, + LOCK_error_log, LOCK_uuid_generator, + LOCK_crypt, LOCK_timezone, LOCK_slave_list, LOCK_active_mi, LOCK_manager, LOCK_global_read_lock, LOCK_global_system_variables, LOCK_user_conn, LOCK_prepared_stmt_count, LOCK_error_messages, LOCK_connection_count; +extern mysql_mutex_t LOCK_mysql_create_db, LOCK_lock_db, LOCK_open, + LOCK_user_locks, LOCK_status, LOCK_delayed_status, LOCK_delayed_insert, + LOCK_delayed_create; extern MYSQL_PLUGIN_IMPORT pthread_mutex_t LOCK_thread_count; #ifdef HAVE_OPENSSL extern pthread_mutex_t LOCK_des_key_file; @@ -1997,7 +2049,8 @@ extern pthread_cond_t COND_server_started; extern int mysqld_server_started; extern rw_lock_t LOCK_grant, LOCK_sys_init_connect, LOCK_sys_init_slave; extern rw_lock_t LOCK_system_variables_hash; -extern pthread_cond_t COND_refresh, COND_thread_count, COND_manager; +extern mysql_cond_t COND_refresh; +extern pthread_cond_t COND_thread_count, COND_manager; extern pthread_cond_t COND_global_read_lock; extern pthread_attr_t connection_attrib; extern I_List<THD> threads; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 71fcef2479a..fa28a175c66 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1,4 +1,4 @@ -/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc. +/* Copyright 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. 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 @@ -524,7 +524,8 @@ uint mysqld_port_timeout; uint delay_key_write_options, protocol_version; uint lower_case_table_names; uint tc_heuristic_recover= 0; -uint volatile thread_count, thread_running; +uint volatile thread_count; +int32 thread_running; ulonglong thd_startup_options; ulong back_log, connect_timeout, concurrency, server_id; ulong table_cache_size, table_def_size; @@ -540,6 +541,8 @@ ulonglong max_binlog_cache_size=0; ulong query_cache_size=0; ulong refresh_version; /* Increments on each reload */ query_id_t global_query_id; +my_atomic_rwlock_t global_query_id_lock; +my_atomic_rwlock_t thread_running_lock; ulong aborted_threads, aborted_connects; ulong delayed_insert_timeout, delayed_insert_limit, delayed_queue_size; ulong delayed_insert_threads, delayed_insert_writes, delayed_rows_in_use; @@ -647,14 +650,16 @@ SHOW_COMP_OPTION have_profiling; pthread_key(MEM_ROOT**,THR_MALLOC); pthread_key(THD*, THR_THD); -pthread_mutex_t LOCK_mysql_create_db, LOCK_open, LOCK_thread_count, - LOCK_mapped_file, LOCK_status, LOCK_global_read_lock, +pthread_mutex_t LOCK_thread_count, + LOCK_mapped_file, LOCK_global_read_lock, LOCK_error_log, LOCK_uuid_generator, - LOCK_delayed_insert, LOCK_delayed_status, LOCK_delayed_create, LOCK_crypt, LOCK_global_system_variables, LOCK_user_conn, LOCK_slave_list, LOCK_active_mi, LOCK_connection_count, LOCK_error_messages; +mysql_mutex_t LOCK_open, LOCK_mysql_create_db, LOCK_status, LOCK_delayed_status, + LOCK_delayed_insert, LOCK_delayed_create; + /** The below lock protects access to two global server variables: max_prepared_stmt_count and prepared_stmt_count. These variables @@ -668,7 +673,8 @@ pthread_mutex_t LOCK_des_key_file; #endif rw_lock_t LOCK_grant, LOCK_sys_init_connect, LOCK_sys_init_slave; rw_lock_t LOCK_system_variables_hash; -pthread_cond_t COND_refresh, COND_thread_count, COND_global_read_lock; +mysql_cond_t COND_refresh; +pthread_cond_t COND_thread_count, COND_global_read_lock; pthread_t signal_thread; pthread_attr_t connection_attrib; pthread_mutex_t LOCK_server_started; @@ -958,14 +964,14 @@ static void close_connections(void) if (tmp->mysys_var) { tmp->mysys_var->abort=1; - pthread_mutex_lock(&tmp->mysys_var->mutex); + mysql_mutex_lock(&tmp->mysys_var->mutex); if (tmp->mysys_var->current_cond) { - pthread_mutex_lock(tmp->mysys_var->current_mutex); - pthread_cond_broadcast(tmp->mysys_var->current_cond); - pthread_mutex_unlock(tmp->mysys_var->current_mutex); + mysql_mutex_lock(tmp->mysys_var->current_mutex); + mysql_cond_broadcast(tmp->mysys_var->current_cond); + mysql_mutex_unlock(tmp->mysys_var->current_mutex); } - pthread_mutex_unlock(&tmp->mysys_var->mutex); + mysql_mutex_unlock(&tmp->mysys_var->mutex); } } (void) pthread_mutex_unlock(&LOCK_thread_count); // For unlink from list @@ -1370,6 +1376,8 @@ void clean_up(bool print_message) DBUG_PRINT("quit", ("Error messages freed")); /* Tell main we are ready */ logger.cleanup_end(); + my_atomic_rwlock_destroy(&global_query_id_lock); + my_atomic_rwlock_destroy(&thread_running_lock); (void) pthread_mutex_lock(&LOCK_thread_count); DBUG_PRINT("quit", ("got thread count lock")); ready_to_exit=1; @@ -1411,17 +1419,17 @@ static void wait_for_signal_thread_to_end() static void clean_up_mutexes() { - (void) pthread_mutex_destroy(&LOCK_mysql_create_db); - (void) pthread_mutex_destroy(&LOCK_lock_db); + mysql_mutex_destroy(&LOCK_mysql_create_db); + mysql_mutex_destroy(&LOCK_lock_db); (void) rwlock_destroy(&LOCK_grant); - (void) pthread_mutex_destroy(&LOCK_open); + mysql_mutex_destroy(&LOCK_open); (void) pthread_mutex_destroy(&LOCK_thread_count); (void) pthread_mutex_destroy(&LOCK_mapped_file); - (void) pthread_mutex_destroy(&LOCK_status); + mysql_mutex_destroy(&LOCK_status); (void) pthread_mutex_destroy(&LOCK_error_log); - (void) pthread_mutex_destroy(&LOCK_delayed_insert); - (void) pthread_mutex_destroy(&LOCK_delayed_status); - (void) pthread_mutex_destroy(&LOCK_delayed_create); + mysql_mutex_destroy(&LOCK_delayed_insert); + mysql_mutex_destroy(&LOCK_delayed_status); + mysql_mutex_destroy(&LOCK_delayed_create); (void) pthread_mutex_destroy(&LOCK_manager); (void) pthread_mutex_destroy(&LOCK_crypt); (void) pthread_mutex_destroy(&LOCK_user_conn); @@ -1449,7 +1457,7 @@ static void clean_up_mutexes() (void) pthread_mutex_destroy(&LOCK_prepared_stmt_count); (void) pthread_mutex_destroy(&LOCK_error_messages); (void) pthread_cond_destroy(&COND_thread_count); - (void) pthread_cond_destroy(&COND_refresh); + mysql_cond_destroy(&COND_refresh); (void) pthread_cond_destroy(&COND_global_read_lock); (void) pthread_cond_destroy(&COND_thread_cache); (void) pthread_cond_destroy(&COND_flush_thread_cache); @@ -3593,16 +3601,20 @@ You should consider changing lower_case_table_names to 1 or 2", static int init_thread_environment() { - (void) pthread_mutex_init(&LOCK_mysql_create_db,MY_MUTEX_INIT_SLOW); - (void) pthread_mutex_init(&LOCK_lock_db,MY_MUTEX_INIT_SLOW); - (void) pthread_mutex_init(&LOCK_open, MY_MUTEX_INIT_FAST); + mysql_mutex_init(key_LOCK_mysql_create_db, + &LOCK_mysql_create_db, MY_MUTEX_INIT_SLOW); + mysql_mutex_init(key_LOCK_lock_db, &LOCK_lock_db, MY_MUTEX_INIT_SLOW); + mysql_mutex_init(key_LOCK_open, &LOCK_open, MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_thread_count,MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_mapped_file,MY_MUTEX_INIT_SLOW); - (void) pthread_mutex_init(&LOCK_status,MY_MUTEX_INIT_FAST); + mysql_mutex_init(key_LOCK_status, &LOCK_status, MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_error_log,MY_MUTEX_INIT_FAST); - (void) pthread_mutex_init(&LOCK_delayed_insert,MY_MUTEX_INIT_FAST); - (void) pthread_mutex_init(&LOCK_delayed_status,MY_MUTEX_INIT_FAST); - (void) pthread_mutex_init(&LOCK_delayed_create,MY_MUTEX_INIT_SLOW); + mysql_mutex_init(key_LOCK_deleyed_insert, + &LOCK_delayed_insert, MY_MUTEX_INIT_FAST); + mysql_mutex_init(key_LOCK_delayed_status, + &LOCK_delayed_status, MY_MUTEX_INIT_FAST); + mysql_mutex_init(key_LOCK_delayed_create, + &LOCK_delayed_create, MY_MUTEX_INIT_SLOW); (void) pthread_mutex_init(&LOCK_manager,MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_crypt,MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_user_conn, MY_MUTEX_INIT_FAST); @@ -3632,7 +3644,7 @@ static int init_thread_environment() (void) my_rwlock_init(&LOCK_sys_init_slave, NULL); (void) my_rwlock_init(&LOCK_grant, NULL); (void) pthread_cond_init(&COND_thread_count,NULL); - (void) pthread_cond_init(&COND_refresh,NULL); + mysql_cond_init(key_COND_refresh, &COND_refresh, NULL); (void) pthread_cond_init(&COND_global_read_lock,NULL); (void) pthread_cond_init(&COND_thread_cache,NULL); (void) pthread_cond_init(&COND_flush_thread_cache,NULL); @@ -3953,6 +3965,27 @@ will be ignored as the --log-bin option is not defined."); if (opt_bin_log) { + /* Reports an error and aborts, if the --log-bin's path + is a directory.*/ + if (opt_bin_logname && + opt_bin_logname[strlen(opt_bin_logname) - 1] == FN_LIBCHAR) + { + sql_print_error("Path '%s' is a directory name, please specify \ +a file name for --log-bin option", opt_bin_logname); + unireg_abort(1); + } + + /* Reports an error and aborts, if the --log-bin-index's path + is a directory.*/ + if (opt_binlog_index_name && + opt_binlog_index_name[strlen(opt_binlog_index_name) - 1] + == FN_LIBCHAR) + { + sql_print_error("Path '%s' is a directory name, please specify \ +a file name for --log-bin-index option", opt_binlog_index_name); + unireg_abort(1); + } + char buf[FN_REFLEN]; const char *ln; ln= mysql_bin_log.generate_name(opt_bin_logname, "-bin", 1, buf); @@ -5248,12 +5281,16 @@ pthread_handler_t handle_connections_sockets_thread(void *arg) pthread_handler_t handle_connections_namedpipes(void *arg) { HANDLE hConnectedPipe; - OVERLAPPED connectOverlapped = {0}; + OVERLAPPED connectOverlapped= {0}; THD *thd; my_thread_init(); DBUG_ENTER("handle_connections_namedpipes"); - connectOverlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - + connectOverlapped.hEvent= CreateEvent(NULL, TRUE, FALSE, NULL); + if (!connectOverlapped.hEvent) + { + sql_print_error("Can't create event, last error=%u", GetLastError()); + unireg_abort(1); + } DBUG_PRINT("general",("Waiting for named pipe connections.")); while (!abort_loop) { @@ -5276,7 +5313,8 @@ pthread_handler_t handle_connections_namedpipes(void *arg) { CloseHandle(hPipe); if ((hPipe= CreateNamedPipe(pipe_name, - PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED, + PIPE_ACCESS_DUPLEX | + FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, @@ -5296,7 +5334,8 @@ pthread_handler_t handle_connections_namedpipes(void *arg) hConnectedPipe = hPipe; /* create new pipe for new connection */ if ((hPipe = CreateNamedPipe(pipe_name, - PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED, + PIPE_ACCESS_DUPLEX | + FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, @@ -7761,6 +7800,8 @@ static int mysql_init_variables(void) what_to_log= ~ (1L << (uint) COM_TIME); refresh_version= 1L; /* Increments on each reload */ global_query_id= thread_id= 1L; + my_atomic_rwlock_init(&global_query_id_lock); + my_atomic_rwlock_init(&thread_running_lock); strmov(server_version, MYSQL_SERVER_VERSION); myisam_recover_options_str= sql_mode_str= "OFF"; myisam_stats_method_str= "nulls_unequal"; @@ -8685,14 +8726,8 @@ static int fix_paths(void) pos[0]= FN_LIBCHAR; pos[1]= 0; } - convert_dirname(mysql_real_data_home,mysql_real_data_home,NullS); - my_realpath(mysql_unpacked_real_data_home, mysql_real_data_home, MYF(0)); - mysql_unpacked_real_data_home_len= strlen(mysql_unpacked_real_data_home); - if (mysql_unpacked_real_data_home[mysql_unpacked_real_data_home_len-1] == FN_LIBCHAR) - --mysql_unpacked_real_data_home_len; - - convert_dirname(lc_messages_dir, lc_messages_dir, NullS); + convert_dirname(mysql_real_data_home,mysql_real_data_home,NullS); (void) my_load_path(mysql_home,mysql_home,""); // Resolve current dir (void) my_load_path(mysql_real_data_home,mysql_real_data_home,mysql_home); (void) my_load_path(pidfile_name,pidfile_name,mysql_real_data_home); @@ -8700,6 +8735,12 @@ static int fix_paths(void) get_relative_path(PLUGINDIR), mysql_home); opt_plugin_dir_ptr= opt_plugin_dir; + my_realpath(mysql_unpacked_real_data_home, mysql_real_data_home, MYF(0)); + mysql_unpacked_real_data_home_len= + (int) strlen(mysql_unpacked_real_data_home); + if (mysql_unpacked_real_data_home[mysql_unpacked_real_data_home_len-1] == FN_LIBCHAR) + --mysql_unpacked_real_data_home_len; + char *sharedir=get_relative_path(SHAREDIR); if (test_if_hard_path(sharedir)) strmake(buff,sharedir,sizeof(buff)-1); /* purecov: tested */ @@ -8903,7 +8944,7 @@ static void create_pid_file() /** Clear most status variables. */ void refresh_status(THD *thd) { - pthread_mutex_lock(&LOCK_status); + mysql_mutex_lock(&LOCK_status); /* Add thread's status variabes to global status */ add_to_status(&global_status_var, &thd->status_var); @@ -8917,7 +8958,7 @@ void refresh_status(THD *thd) /* Reset the counters of all key caches (default and named). */ process_key_caches(reset_key_cache_counters); flush_status_time= time((time_t*) 0); - pthread_mutex_unlock(&LOCK_status); + mysql_mutex_unlock(&LOCK_status); /* Set max_used_connections to the number of currently open diff --git a/sql/net_serv.cc b/sql/net_serv.cc index 5cf3597c638..d54ff1d2779 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -71,8 +71,10 @@ #if defined(__WIN__) || !defined(MYSQL_SERVER) /* The following is because alarms doesn't work on windows. */ +#ifndef NO_ALARM #define NO_ALARM #endif +#endif #ifndef NO_ALARM #include "my_pthread.h" diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 731e9872aa5..ac5b1f575de 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -457,10 +457,10 @@ public: range_key, *range_key_flag); *range_key_flag|= key_tree->min_flag; if (key_tree->next_key_part && + key_tree->next_key_part->type == SEL_ARG::KEY_RANGE && key_tree->part != last_part && key_tree->next_key_part->part == key_tree->part+1 && - !(*range_key_flag & (NO_MIN_RANGE | NEAR_MIN)) && - key_tree->next_key_part->type == SEL_ARG::KEY_RANGE) + !(*range_key_flag & (NO_MIN_RANGE | NEAR_MIN))) res+= key_tree->next_key_part->store_min_key(key, range_key, range_key_flag, @@ -479,10 +479,10 @@ public: range_key, *range_key_flag); (*range_key_flag)|= key_tree->max_flag; if (key_tree->next_key_part && + key_tree->next_key_part->type == SEL_ARG::KEY_RANGE && key_tree->part != last_part && - key_tree->next_key_part->part == key_tree->part+1 && - !(*range_key_flag & (NO_MAX_RANGE | NEAR_MAX)) && - key_tree->next_key_part->type == SEL_ARG::KEY_RANGE) + key_tree->next_key_part->part == key_tree->part+1 && + !(*range_key_flag & (NO_MAX_RANGE | NEAR_MAX))) res+= key_tree->next_key_part->store_max_key(key, range_key, range_key_flag, @@ -1727,6 +1727,7 @@ SEL_ARG *SEL_ARG::clone(RANGE_OPT_PARAM *param, SEL_ARG *new_parent, tmp->prev= *next_arg; // Link into next/prev chain (*next_arg)->next=tmp; (*next_arg)= tmp; + tmp->part= this->part; } else { @@ -6848,6 +6849,7 @@ key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1,SEL_ARG *key2) else if ((cmp=tmp->cmp_max_to_min(key2)) < 0) { // Found tmp.max < key2.min SEL_ARG *next=tmp->next; + /* key1 on the left of key2 non-overlapping */ if (cmp == -2 && eq_tree(tmp->next_key_part,key2->next_key_part)) { // Join near ranges like tmp.max < 0 and key2.min >= 0 @@ -6876,6 +6878,7 @@ key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1,SEL_ARG *key2) int tmp_cmp; if ((tmp_cmp=tmp->cmp_min_to_max(key2)) > 0) // if tmp.min > key2.max { + /* tmp is on the right of key2 non-overlapping */ if (tmp_cmp == 2 && eq_tree(tmp->next_key_part,key2->next_key_part)) { // ranges are connected tmp->copy_min_to_min(key2); @@ -6910,25 +6913,52 @@ key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1,SEL_ARG *key2) } } - // tmp.max >= key2.min && tmp.min <= key.max (overlapping ranges) + /* + tmp.min >= key2.min && tmp.min <= key.max (overlapping ranges) + key2.min <= tmp.min <= key2.max + */ if (eq_tree(tmp->next_key_part,key2->next_key_part)) { if (tmp->is_same(key2)) { + /* + Found exact match of key2 inside key1. + Use the relevant range in key1. + */ tmp->merge_flags(key2); // Copy maybe flags key2->increment_use_count(-1); // Free not used tree } else { SEL_ARG *last=tmp; + SEL_ARG *first=tmp; + /* + Find the last range in tmp that overlaps key2 and has the same + condition on the rest of the keyparts. + */ while (last->next && last->next->cmp_min_to_max(key2) <= 0 && eq_tree(last->next->next_key_part,key2->next_key_part)) { + /* + We've found the last overlapping key1 range in last. + This means that the ranges between (and including) the + first overlapping range (tmp) and the last overlapping range + (last) are fully nested into the current range of key2 + and can safely be discarded. We just need the minimum endpoint + of the first overlapping range (tmp) so we can compare it with + the minimum endpoint of the enclosing key2 range. + */ SEL_ARG *save=last; last=last->next; key1=key1->tree_delete(save); } - last->copy_min(tmp); + /* + The tmp range (the first overlapping range) could have been discarded + by the previous loop. We should re-direct tmp to the new united range + that's taking its place. + */ + tmp= last; + last->copy_min(first); bool full_range= last->copy_min(key2); if (!full_range) { @@ -7438,27 +7468,25 @@ int test_rb_tree(SEL_ARG *element,SEL_ARG *parent) } -/* - Count how many times SEL_ARG graph "root" refers to its part "key" +/** + Count how many times SEL_ARG graph "root" refers to its part "key" via + transitive closure. - SYNOPSIS - count_key_part_usage() - root An RB-Root node in a SEL_ARG graph. - key Another RB-Root node in that SEL_ARG graph. - - DESCRIPTION - The passed "root" node may refer to "key" node via root->next_key_part, - root->next->n - - This function counts how many times the node "key" is referred (via - SEL_ARG::next_key_part) by - - intervals of RB-tree pointed by "root", - - intervals of RB-trees that are pointed by SEL_ARG::next_key_part from - intervals of RB-tree pointed by "root", - - and so on. + @param root An RB-Root node in a SEL_ARG graph. + @param key Another RB-Root node in that SEL_ARG graph. + + The passed "root" node may refer to "key" node via root->next_key_part, + root->next->n + + This function counts how many times the node "key" is referred (via + SEL_ARG::next_key_part) by + - intervals of RB-tree pointed by "root", + - intervals of RB-trees that are pointed by SEL_ARG::next_key_part from + intervals of RB-tree pointed by "root", + - and so on. - Here is an example (horizontal links represent next_key_part pointers, - vertical links - next/prev prev pointers): + Here is an example (horizontal links represent next_key_part pointers, + vertical links - next/prev prev pointers): +----+ $ |root|-----------------+ @@ -7478,8 +7506,8 @@ int test_rb_tree(SEL_ARG *element,SEL_ARG *parent) ... +---+ $ | | |------------+ +---+ $ - RETURN - Number of links to "key" from nodes reachable from "root". + @return + Number of links to "key" from nodes reachable from "root". */ static ulong count_key_part_usage(SEL_ARG *root, SEL_ARG *key) @@ -7734,8 +7762,8 @@ check_quick_keys(PARAM *param, uint idx, SEL_ARG *key_tree, param->first_null_comp= key_tree->part+1; if (key_tree->next_key_part && - key_tree->next_key_part->part == key_tree->part+1 && - key_tree->next_key_part->type == SEL_ARG::KEY_RANGE) + key_tree->next_key_part->type == SEL_ARG::KEY_RANGE && + key_tree->next_key_part->part == key_tree->part+1) { // const key as prefix if (min_key_length == max_key_length && !memcmp(min_key, max_key, (uint) (tmp_max_key - max_key)) && @@ -8020,8 +8048,8 @@ get_quick_keys(PARAM *param,QUICK_RANGE_SELECT *quick,KEY_PART *key, &tmp_max_key,max_key_flag); if (key_tree->next_key_part && - key_tree->next_key_part->part == key_tree->part+1 && - key_tree->next_key_part->type == SEL_ARG::KEY_RANGE) + key_tree->next_key_part->type == SEL_ARG::KEY_RANGE && + key_tree->next_key_part->part == key_tree->part+1) { // const key as prefix if ((tmp_min_key - min_key) == (tmp_max_key - max_key) && memcmp(min_key, max_key, (uint)(tmp_max_key - max_key))==0 && @@ -10032,7 +10060,11 @@ check_group_min_max_predicates(COND *cond, Item_field *min_max_arg_item, } else if (cur_arg->const_item()) { - DBUG_RETURN(TRUE); + /* + For predicates of the form "const OP expr" we also have to check 'expr' + to make a decision. + */ + continue; } else DBUG_RETURN(FALSE); diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index e3893ce2500..8392b2c1c3d 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -559,7 +559,12 @@ HOSTS"; goto err; } si->server_id = log_server_id; - my_hash_insert(&slave_list, (uchar*)si); + if (my_hash_insert(&slave_list, (uchar*)si)) + { + error= "the slave is out of memory"; + pthread_mutex_unlock(&LOCK_slave_list); + goto err; + } } strmake(si->host, row[1], sizeof(si->host)-1); si->port = atoi(row[port_ind]); diff --git a/sql/replication.h b/sql/replication.h index eea77ef9f8e..5e9c09adf31 100644 --- a/sql/replication.h +++ b/sql/replication.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2008 MySQL AB +/* Copyright (C) 2008 MySQL AB, 2008-2009 Sun Microsystems, Inc 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 @@ -470,8 +470,8 @@ MYSQL *rpl_connect_master(MYSQL *mysql); held before call this function @param msg The new process message for the thread */ -const char* thd_enter_cond(MYSQL_THD thd, pthread_cond_t *cond, - pthread_mutex_t *mutex, const char *msg); +const char* thd_enter_cond(MYSQL_THD thd, mysql_cond_t *cond, + mysql_mutex_t *mutex, const char *msg); /** Set thread leaving a condition diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index bd03afb8dd8..2d7c6c61cd5 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -107,7 +107,8 @@ int init_relay_log_info(Relay_log_info* rli, rli->tables_to_lock_count= 0; char pattern[FN_REFLEN]; - if (fn_format(pattern, PREFIX_SQL_LOAD, slave_load_tmpdir, "", + (void) my_realpath(pattern, slave_load_tmpdir, 0); + if (fn_format(pattern, PREFIX_SQL_LOAD, pattern, "", MY_SAFE_PATH | MY_RETURN_REAL_PATH) == NullS) { pthread_mutex_unlock(&rli->data_lock); @@ -134,6 +135,29 @@ int init_relay_log_info(Relay_log_info* rli, rli->relay_log.max_size (and mysql_bin_log.max_size). */ { + /* Reports an error and returns, if the --relay-log's path + is a directory.*/ + if (opt_relay_logname && + opt_relay_logname[strlen(opt_relay_logname) - 1] == FN_LIBCHAR) + { + pthread_mutex_unlock(&rli->data_lock); + sql_print_error("Path '%s' is a directory name, please specify \ +a file name for --relay-log option", opt_relay_logname); + DBUG_RETURN(1); + } + + /* Reports an error and returns, if the --relay-log-index's path + is a directory.*/ + if (opt_relaylog_index_name && + opt_relaylog_index_name[strlen(opt_relaylog_index_name) - 1] + == FN_LIBCHAR) + { + pthread_mutex_unlock(&rli->data_lock); + sql_print_error("Path '%s' is a directory name, please specify \ +a file name for --relay-log-index option", opt_relaylog_index_name); + DBUG_RETURN(1); + } + char buf[FN_REFLEN]; const char *ln; static bool name_warning_sent= 0; diff --git a/sql/rpl_tblmap.cc b/sql/rpl_tblmap.cc index 8b7fea3b40e..b04a3120a86 100644 --- a/sql/rpl_tblmap.cc +++ b/sql/rpl_tblmap.cc @@ -119,7 +119,13 @@ int table_mapping::set_table(ulong table_id, TABLE* table) } e->table_id= table_id; e->table= table; - my_hash_insert(&m_table_ids,(uchar *)e); + if (my_hash_insert(&m_table_ids,(uchar *)e)) + { + /* we add this entry to the chain of free (free for use) entries */ + e->next= m_free; + m_free= e; + DBUG_RETURN(ERR_MEMORY_ALLOCATION); + } DBUG_PRINT("info", ("tid %lu -> table 0x%lx (%s)", table_id, (long) e->table, diff --git a/sql/share/.cvsignore b/sql/share/.cvsignore deleted file mode 100644 index 282522db034..00000000000 --- a/sql/share/.cvsignore +++ /dev/null @@ -1,2 +0,0 @@ -Makefile -Makefile.in diff --git a/sql/slave.cc b/sql/slave.cc index ca72aaea69a..884692cc98d 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1207,6 +1207,8 @@ static int get_master_version_and_clock(MYSQL* mysql, Master_info* mi) mi->clock_diff_with_master= (long) (time((time_t*) 0) - strtoul(master_row[0], 0, 10)); } + else if (check_io_slave_killed(mi->io_thd, mi, NULL)) + goto slave_killed_err; else if (is_network_error(mysql_errno(mysql))) { mi->report(WARNING_LEVEL, mysql_errno(mysql), @@ -1259,7 +1261,9 @@ not always make sense; please check the manual before using it)."; } else if (mysql_errno(mysql)) { - if (is_network_error(mysql_errno(mysql))) + if (check_io_slave_killed(mi->io_thd, mi, NULL)) + goto slave_killed_err; + else if (is_network_error(mysql_errno(mysql))) { mi->report(WARNING_LEVEL, mysql_errno(mysql), "Get master SERVER_ID failed with error: %s", mysql_error(mysql)); @@ -1330,6 +1334,8 @@ be equal for the Statement-format replication to work"; goto err; } } + else if (check_io_slave_killed(mi->io_thd, mi, NULL)) + goto slave_killed_err; else if (is_network_error(mysql_errno(mysql))) { mi->report(WARNING_LEVEL, mysql_errno(mysql), @@ -1391,6 +1397,8 @@ be equal for the Statement-format replication to work"; goto err; } } + else if (check_io_slave_killed(mi->io_thd, mi, NULL)) + goto slave_killed_err; else if (is_network_error(mysql_errno(mysql))) { mi->report(WARNING_LEVEL, mysql_errno(mysql), @@ -1454,6 +1462,11 @@ network_err: if (master_res) mysql_free_result(master_res); DBUG_RETURN(2); + +slave_killed_err: + if (master_res) + mysql_free_result(master_res); + DBUG_RETURN(2); } static bool wait_for_relay_log_space(Relay_log_info* rli) @@ -2681,7 +2694,7 @@ connected: if (ret == 1) /* Fatal error */ goto err; - + if (ret == 2) { if (check_io_slave_killed(mi->io_thd, mi, "Slave I/O thread killed" diff --git a/sql/sp.cc b/sql/sp.cc index 4cbb0f28b59..8a9f130b8f7 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -69,6 +69,122 @@ enum MYSQL_PROC_FIELD_COUNT }; +static const +TABLE_FIELD_TYPE proc_table_fields[MYSQL_PROC_FIELD_COUNT] = +{ + { + { C_STRING_WITH_LEN("db") }, + { C_STRING_WITH_LEN("char(64)") }, + { C_STRING_WITH_LEN("utf8") } + }, + { + { C_STRING_WITH_LEN("name") }, + { C_STRING_WITH_LEN("char(64)") }, + { C_STRING_WITH_LEN("utf8") } + }, + { + { C_STRING_WITH_LEN("type") }, + { C_STRING_WITH_LEN("enum('FUNCTION','PROCEDURE')") }, + { NULL, 0 } + }, + { + { C_STRING_WITH_LEN("specific_name") }, + { C_STRING_WITH_LEN("char(64)") }, + { C_STRING_WITH_LEN("utf8") } + }, + { + { C_STRING_WITH_LEN("language") }, + { C_STRING_WITH_LEN("enum('SQL')") }, + { NULL, 0 } + }, + { + { C_STRING_WITH_LEN("sql_data_access") }, + { C_STRING_WITH_LEN("enum('CONTAINS_SQL','NO_SQL','READS_SQL_DATA','MODIFIES_SQL_DATA')") }, + { NULL, 0 } + }, + { + { C_STRING_WITH_LEN("is_deterministic") }, + { C_STRING_WITH_LEN("enum('YES','NO')") }, + { NULL, 0 } + }, + { + { C_STRING_WITH_LEN("security_type") }, + { C_STRING_WITH_LEN("enum('INVOKER','DEFINER')") }, + { NULL, 0 } + }, + { + { C_STRING_WITH_LEN("param_list") }, + { C_STRING_WITH_LEN("blob") }, + { NULL, 0 } + }, + + { + { C_STRING_WITH_LEN("returns") }, + { C_STRING_WITH_LEN("longblob") }, + { NULL, 0 } + }, + { + { C_STRING_WITH_LEN("body") }, + { C_STRING_WITH_LEN("longblob") }, + { NULL, 0 } + }, + { + { C_STRING_WITH_LEN("definer") }, + { C_STRING_WITH_LEN("char(77)") }, + { C_STRING_WITH_LEN("utf8") } + }, + { + { C_STRING_WITH_LEN("created") }, + { C_STRING_WITH_LEN("timestamp") }, + { NULL, 0 } + }, + { + { C_STRING_WITH_LEN("modified") }, + { C_STRING_WITH_LEN("timestamp") }, + { NULL, 0 } + }, + { + { C_STRING_WITH_LEN("sql_mode") }, + { C_STRING_WITH_LEN("set('REAL_AS_FLOAT','PIPES_AS_CONCAT','ANSI_QUOTES'," + "'IGNORE_SPACE','NOT_USED','ONLY_FULL_GROUP_BY','NO_UNSIGNED_SUBTRACTION'," + "'NO_DIR_IN_CREATE','POSTGRESQL','ORACLE','MSSQL','DB2','MAXDB'," + "'NO_KEY_OPTIONS','NO_TABLE_OPTIONS','NO_FIELD_OPTIONS','MYSQL323','MYSQL40'," + "'ANSI','NO_AUTO_VALUE_ON_ZERO','NO_BACKSLASH_ESCAPES','STRICT_TRANS_TABLES'," + "'STRICT_ALL_TABLES','NO_ZERO_IN_DATE','NO_ZERO_DATE','INVALID_DATES'," + "'ERROR_FOR_DIVISION_BY_ZERO','TRADITIONAL','NO_AUTO_CREATE_USER'," + "'HIGH_NOT_PRECEDENCE','NO_ENGINE_SUBSTITUTION','PAD_CHAR_TO_FULL_LENGTH')") }, + { NULL, 0 } + }, + { + { C_STRING_WITH_LEN("comment") }, + { C_STRING_WITH_LEN("text") }, + { C_STRING_WITH_LEN("utf8") } + }, + { + { C_STRING_WITH_LEN("character_set_client") }, + { C_STRING_WITH_LEN("char(32)") }, + { C_STRING_WITH_LEN("utf8") } + }, + { + { C_STRING_WITH_LEN("collation_connection") }, + { C_STRING_WITH_LEN("char(32)") }, + { C_STRING_WITH_LEN("utf8") } + }, + { + { C_STRING_WITH_LEN("db_collation") }, + { C_STRING_WITH_LEN("char(32)") }, + { C_STRING_WITH_LEN("utf8") } + }, + { + { C_STRING_WITH_LEN("body_utf8") }, + { C_STRING_WITH_LEN("longblob") }, + { NULL, 0 } + } +}; + +static const TABLE_FIELD_DEF + proc_table_def= {MYSQL_PROC_FIELD_COUNT, proc_table_fields}; + /*************************************************************************/ /** @@ -246,6 +362,50 @@ Stored_routine_creation_ctx::load_from_db(THD *thd, /*************************************************************************/ +class Proc_table_intact : public Table_check_intact +{ +private: + bool m_print_once; + +public: + Proc_table_intact() : m_print_once(TRUE) {} + +protected: + void report_error(uint code, const char *fmt, ...); +}; + + +/** + Report failure to validate the mysql.proc table definition. + Print a message to the error log only once. +*/ + +void Proc_table_intact::report_error(uint code, const char *fmt, ...) +{ + va_list args; + char buf[512]; + + va_start(args, fmt); + my_vsnprintf(buf, sizeof(buf), fmt, args); + va_end(args); + + if (code) + my_message(code, buf, MYF(0)); + else + my_error(ER_CANNOT_LOAD_FROM_TABLE, MYF(0), "proc"); + + if (m_print_once) + { + m_print_once= FALSE; + sql_print_error("%s", buf); + } +}; + + +/** Single instance used to control printing to the error log. */ +static Proc_table_intact proc_table_intact; + + /** Open the mysql.proc table for read. @@ -268,10 +428,15 @@ TABLE *open_proc_table_for_read(THD *thd, Open_tables_backup *backup) table.init_one_table("mysql", 5, "proc", 4, "proc", TL_READ); - if (!open_system_tables_for_read(thd, &table, backup)) + if (open_system_tables_for_read(thd, &table, backup)) + DBUG_RETURN(NULL); + + if (!proc_table_intact.check(table.table, &proc_table_def)) DBUG_RETURN(table.table); - else - DBUG_RETURN(0); + + close_system_tables(thd, backup); + + DBUG_RETURN(NULL); } @@ -291,12 +456,22 @@ TABLE *open_proc_table_for_read(THD *thd, Open_tables_backup *backup) static TABLE *open_proc_table_for_update(THD *thd) { - TABLE_LIST table; + TABLE_LIST table_list; + TABLE *table; DBUG_ENTER("open_proc_table_for_update"); - table.init_one_table("mysql", 5, "proc", 4, "proc", TL_WRITE); + table_list.init_one_table("mysql", 5, "proc", 4, "proc", TL_WRITE); + + if (!(table= open_system_table_for_update(thd, &table_list))) + DBUG_RETURN(NULL); + + if (!proc_table_intact.check(table, &proc_table_def)) + DBUG_RETURN(table); + + close_thread_tables(thd); + + DBUG_RETURN(NULL); - DBUG_RETURN(open_system_table_for_update(thd, &table)); } @@ -1502,7 +1677,8 @@ bool sp_add_used_routine(Query_tables_list *prelocking_ctx, Query_arena *arena, if (!rn) // OOM. Error will be reported using fatal_error(). return FALSE; rn->mdl_request.init(key, MDL_SHARED); - my_hash_insert(&prelocking_ctx->sroutines, (uchar *)rn); + if (my_hash_insert(&prelocking_ctx->sroutines, (uchar *)rn)) + return FALSE; prelocking_ctx->sroutines_list.link_in_list((uchar *)rn, (uchar **)&rn->next); rn->belong_to_view= belong_to_view; rn->m_sp_cache_version= 0; @@ -1586,17 +1762,25 @@ void sp_remove_not_own_routines(Query_tables_list *prelocking_ctx) dependant on time of life of elements from source hash. It also won't touch lists linking elements in source and destination hashes. + + @returns + @return TRUE Failure + @return FALSE Success */ -void sp_update_sp_used_routines(HASH *dst, HASH *src) +bool sp_update_sp_used_routines(HASH *dst, HASH *src) { for (uint i=0 ; i < src->records ; i++) { Sroutine_hash_entry *rt= (Sroutine_hash_entry *)my_hash_element(src, i); if (!my_hash_search(dst, (uchar *)rt->mdl_request.key.ptr(), rt->mdl_request.key.length())) - my_hash_insert(dst, (uchar *)rt); + { + if (my_hash_insert(dst, (uchar *)rt)) + return TRUE; + } } + return FALSE; } @@ -115,7 +115,7 @@ void sp_add_used_routine(Query_tables_list *prelocking_ctx, Query_arena *arena, bool sp_add_used_routine(Query_tables_list *prelocking_ctx, Query_arena *arena, const MDL_key *key, TABLE_LIST *belong_to_view); void sp_remove_not_own_routines(Query_tables_list *prelocking_ctx); -void sp_update_sp_used_routines(HASH *dst, HASH *src); +bool sp_update_sp_used_routines(HASH *dst, HASH *src); void sp_update_stmt_used_routines(THD *thd, Query_tables_list *prelocking_ctx, HASH *src, TABLE_LIST *belong_to_view); void sp_update_stmt_used_routines(THD *thd, Query_tables_list *prelocking_ctx, diff --git a/sql/sp_cache.cc b/sql/sp_cache.cc index bb962ad0300..a585004b1e8 100644 --- a/sql/sp_cache.cc +++ b/sql/sp_cache.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2002 MySQL AB +/* Copyright (C) 2002 MySQL AB, 2008-2009 Sun Microsystems, Inc 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 @@ -20,7 +20,7 @@ #include "sp_cache.h" #include "sp_head.h" -static pthread_mutex_t Cversion_lock; +static mysql_mutex_t Cversion_lock; static ulong volatile Cversion= 0; @@ -34,10 +34,16 @@ public: sp_cache(); ~sp_cache(); - inline void insert(sp_head *sp) + /** + Inserts a sp_head object into a hash table. + + @returns Success status + @return TRUE Failure + @return FALSE Success + */ + inline bool insert(sp_head *sp) { - /* TODO: why don't we check return value? */ - my_hash_insert(&m_hashtable, (const uchar *)sp); + return my_hash_insert(&m_hashtable, (const uchar *)sp); } inline sp_head *lookup(char *name, uint namelen) @@ -58,12 +64,36 @@ private: HASH m_hashtable; }; // class sp_cache +#ifdef HAVE_PSI_INTERFACE +static PSI_mutex_key key_Cversion_lock; + +static PSI_mutex_info all_sp_cache_mutexes[]= +{ + { &key_Cversion_lock, "Cversion_lock", PSI_FLAG_GLOBAL} +}; + +static void init_sp_cache_psi_keys(void) +{ + const char* category= "sql"; + int count; + + if (PSI_server == NULL) + return; + + count= array_elements(all_sp_cache_mutexes); + PSI_server->register_mutex(category, all_sp_cache_mutexes, count); +} +#endif /* Initialize the SP caching once at startup */ void sp_cache_init() { - pthread_mutex_init(&Cversion_lock, MY_MUTEX_INIT_FAST); +#ifdef HAVE_PSI_INTERFACE + init_sp_cache_psi_keys(); +#endif + + mysql_mutex_init(key_Cversion_lock, &Cversion_lock, MY_MUTEX_INIT_FAST); } diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 83c928eb88f..ea47e416b92 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1319,7 +1319,7 @@ sp_head::execute(THD *thd) DBUG_ASSERT(thd->change_list.is_empty()); old_change_list.move_elements_to(&thd->change_list); thd->lex= old_lex; - thd->query_id= old_query_id; + thd->set_query_id(old_query_id); DBUG_ASSERT(!thd->derived_tables); thd->derived_tables= old_derived_tables; thd->variables.sql_mode= save_sql_mode; @@ -2101,8 +2101,18 @@ sp_head::reset_lex(THD *thd) DBUG_RETURN(FALSE); } -/// Restore lex during parsing, after we have parsed a sub statement. -void + +/** + Restore lex during parsing, after we have parsed a sub statement. + + @param thd Thread handle + + @return + @retval TRUE failure + @retval FALSE success +*/ + +bool sp_head::restore_lex(THD *thd) { DBUG_ENTER("sp_head::restore_lex"); @@ -2113,7 +2123,7 @@ sp_head::restore_lex(THD *thd) oldlex= (LEX *)m_lex.pop(); if (! oldlex) - return; // Nothing to restore + DBUG_RETURN(FALSE); // Nothing to restore oldlex->trg_table_fields.push_back(&sublex->trg_table_fields); @@ -2129,7 +2139,8 @@ sp_head::restore_lex(THD *thd) Add routines which are used by statement to respective set for this routine. */ - sp_update_sp_used_routines(&m_sroutines, &sublex->sroutines); + if (sp_update_sp_used_routines(&m_sroutines, &sublex->sroutines)) + DBUG_RETURN(TRUE); /* Merge tables used by this statement (but not by its functions or procedures) to multiset of tables used by this routine. @@ -2141,7 +2152,7 @@ sp_head::restore_lex(THD *thd) delete sublex; } thd->lex= oldlex; - DBUG_VOID_RETURN; + DBUG_RETURN(FALSE); } /** @@ -2717,9 +2728,7 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp, */ thd->lex= m_lex; - pthread_mutex_lock(&LOCK_thread_count); - thd->query_id= next_query_id(); - pthread_mutex_unlock(&LOCK_thread_count); + thd->set_query_id(next_query_id()); if (thd->locked_tables_mode <= LTM_LOCK_TABLES) { @@ -3888,7 +3897,8 @@ sp_head::merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check) tab->lock_type= table->lock_type; tab->lock_count= tab->query_lock_count= 1; tab->trg_event_map= table->trg_event_map; - my_hash_insert(&m_sptabs, (uchar *)tab); + if (my_hash_insert(&m_sptabs, (uchar *)tab)) + return FALSE; } } return TRUE; diff --git a/sql/sp_head.h b/sql/sp_head.h index bac97a1fd77..02269cf53a7 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -343,7 +343,7 @@ public: @todo Conflicting comment in sp_head.cc */ - void + bool restore_lex(THD *thd); /// Put the instruction on the backpatch list, associated with the label. diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 451b2293109..573bdd2ab3b 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -32,9 +32,8 @@ #include "sp.h" #include "transaction.h" -time_t mysql_db_table_last_check= 0L; - -TABLE_FIELD_W_TYPE mysql_db_table_fields[MYSQL_DB_FIELD_COUNT] = { +static const +TABLE_FIELD_TYPE mysql_db_table_fields[MYSQL_DB_FIELD_COUNT] = { { { C_STRING_WITH_LEN("Host") }, { C_STRING_WITH_LEN("char(60)") }, @@ -147,6 +146,8 @@ TABLE_FIELD_W_TYPE mysql_db_table_fields[MYSQL_DB_FIELD_COUNT] = { } }; +const TABLE_FIELD_DEF + mysql_db_table_def= {MYSQL_DB_FIELD_COUNT, mysql_db_table_fields}; #ifndef NO_EMBEDDED_ACCESS_CHECKS @@ -2458,7 +2459,12 @@ GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs) privs = cols = 0; /* purecov: deadcode */ return; /* purecov: deadcode */ } - my_hash_insert(&hash_columns, (uchar *) mem_check); + if (my_hash_insert(&hash_columns, (uchar *) mem_check)) + { + /* Invalidate this entry */ + privs= cols= 0; + return; + } } while (!col_privs->file->index_next(col_privs->record[0]) && !key_cmp_if_same(col_privs,key,0,key_prefix_len)); col_privs->file->ha_index_end(); @@ -2492,14 +2498,17 @@ static GRANT_NAME *name_hash_search(HASH *name_hash, const char *host,const char* ip, const char *db, const char *user, const char *tname, - bool exact) + bool exact, bool name_tolower) { - char helping [NAME_LEN*2+USERNAME_LENGTH+3]; + char helping [NAME_LEN*2+USERNAME_LENGTH+3], *name_ptr; uint len; GRANT_NAME *grant_name,*found=0; HASH_SEARCH_STATE state; - len = (uint) (strmov(strmov(strmov(helping,user)+1,db)+1,tname)-helping)+ 1; + name_ptr= strmov(strmov(helping, user) + 1, db) + 1; + len = (uint) (strmov(name_ptr, tname) - helping) + 1; + if (name_tolower) + my_casedn_str(files_charset_info, name_ptr); for (grant_name= (GRANT_NAME*) my_hash_first(name_hash, (uchar*) helping, len, &state); grant_name ; @@ -2532,7 +2541,7 @@ routine_hash_search(const char *host, const char *ip, const char *db, { return (GRANT_TABLE*) name_hash_search(proc ? &proc_priv_hash : &func_priv_hash, - host, ip, db, user, tname, exact); + host, ip, db, user, tname, exact, TRUE); } @@ -2541,7 +2550,7 @@ table_hash_search(const char *host, const char *ip, const char *db, const char *user, const char *tname, bool exact) { return (GRANT_TABLE*) name_hash_search(&column_priv_hash, host, ip, db, - user, tname, exact); + user, tname, exact, FALSE); } @@ -2664,7 +2673,11 @@ static int replace_column_table(GRANT_TABLE *g_t, goto end; /* purecov: inspected */ } grant_column= new GRANT_COLUMN(column->column,privileges); - my_hash_insert(&g_t->hash_columns,(uchar*) grant_column); + if (my_hash_insert(&g_t->hash_columns,(uchar*) grant_column)) + { + result= -1; + goto end; + } } } @@ -3191,12 +3204,12 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, Str->user.str, table_name, rights, column_priv); - if (!grant_table) // end of memory + if (!grant_table || + my_hash_insert(&column_priv_hash,(uchar*) grant_table)) { result= TRUE; /* purecov: deadcode */ continue; /* purecov: deadcode */ } - my_hash_insert(&column_priv_hash,(uchar*) grant_table); } /* If revoke_grant, calculate the new column privilege for tables_priv */ @@ -3401,12 +3414,13 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc, grant_name= new GRANT_NAME(Str->host.str, db_name, Str->user.str, table_name, rights, TRUE); - if (!grant_name) + if (!grant_name || + my_hash_insert(is_proc ? + &proc_priv_hash : &func_priv_hash,(uchar*) grant_name)) { result= TRUE; continue; } - my_hash_insert(is_proc ? &proc_priv_hash : &func_priv_hash,(uchar*) grant_name); } if (replace_routine_table(thd, grant_name, tables[1].table, *Str, @@ -3510,6 +3524,13 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list, result= TRUE; continue; } + /* + No User, but a password? + They did GRANT ... TO CURRENT_USER() IDENTIFIED BY ... ! + Get the current user, and shallow-copy the new password to them! + */ + if (!tmp_Str->user.str && tmp_Str->password.str) + Str->password= tmp_Str->password; if (replace_user_table(thd, tables[0].table, *Str, (!db ? rights : 0), revoke_grant, create_new_users, test(thd->variables.sql_mode & diff --git a/sql/sql_acl.h b/sql/sql_acl.h index 5c1f34b0b34..25a4766e58c 100644 --- a/sql/sql_acl.h +++ b/sql/sql_acl.h @@ -168,8 +168,7 @@ enum mysql_db_table_field MYSQL_DB_FIELD_COUNT }; -extern TABLE_FIELD_W_TYPE mysql_db_table_fields[]; -extern time_t mysql_db_table_last_check; +extern const TABLE_FIELD_DEF mysql_db_table_def; /* Classes */ diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 8dced67dd44..097c08e5979 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1,4 +1,4 @@ -/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc. +/* Copyright 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. 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 @@ -258,7 +258,7 @@ extern "C" uchar *table_def_key(const uchar *record, size_t *length, static void table_def_free_entry(TABLE_SHARE *share) { DBUG_ENTER("table_def_free_entry"); - safe_mutex_assert_owner(&LOCK_open); + mysql_mutex_assert_owner(&LOCK_open); if (share->prev) { /* remove from old_unused_share list */ @@ -292,7 +292,7 @@ void table_def_start_shutdown(void) { if (table_def_inited) { - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); /* Free all cached but unused TABLEs and TABLE_SHAREs first. */ close_cached_tables(NULL, NULL, TRUE, FALSE); /* @@ -302,7 +302,7 @@ void table_def_start_shutdown(void) plugins minimal and allows shutdown to proceed smoothly. */ table_def_shutdown_in_progress= TRUE; - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); } } @@ -669,7 +669,7 @@ void release_table_share(TABLE_SHARE *share) (ulong) share, share->db.str, share->table_name.str, share->ref_count, share->version)); - safe_mutex_assert_owner(&LOCK_open); + mysql_mutex_assert_owner(&LOCK_open); DBUG_ASSERT(share->ref_count); if (!--share->ref_count) @@ -719,7 +719,7 @@ TABLE_SHARE *get_cached_table_share(const char *db, const char *table_name) char key[NAME_LEN*2+2]; TABLE_LIST table_list; uint key_length; - safe_mutex_assert_owner(&LOCK_open); + mysql_mutex_assert_owner(&LOCK_open); table_list.db= (char*) db; table_list.table_name= (char*) table_name; @@ -740,7 +740,7 @@ static void reference_table_share(TABLE_SHARE *share) { DBUG_ENTER("reference_table_share"); DBUG_ASSERT(share->ref_count); - safe_mutex_assert_owner(&LOCK_open); + mysql_mutex_assert_owner(&LOCK_open); share->ref_count++; DBUG_PRINT("exit", ("share: 0x%lx ref_count: %u", (ulong) share, share->ref_count)); @@ -773,7 +773,7 @@ OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *db, const char *wild) TABLE_LIST table_list; DBUG_ENTER("list_open_tables"); - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); bzero((char*) &table_list,sizeof(table_list)); start_list= &open_list; open_list=0; @@ -813,7 +813,7 @@ OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *db, const char *wild) start_list= &(*start_list)->next; *start_list=0; } - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); DBUG_RETURN(open_list); } @@ -890,7 +890,7 @@ static void kill_delayed_threads_for_table(TABLE_SHARE *share) I_P_List_iterator<TABLE, TABLE_share> it(share->used_tables); TABLE *tab; - safe_mutex_assert_owner(&LOCK_open); + mysql_mutex_assert_owner(&LOCK_open); while ((tab= it++)) { @@ -900,14 +900,14 @@ static void kill_delayed_threads_for_table(TABLE_SHARE *share) ! in_use->killed) { in_use->killed= THD::KILL_CONNECTION; - pthread_mutex_lock(&in_use->mysys_var->mutex); + mysql_mutex_lock(&in_use->mysys_var->mutex); if (in_use->mysys_var->current_cond) { - pthread_mutex_lock(in_use->mysys_var->current_mutex); - pthread_cond_broadcast(in_use->mysys_var->current_cond); - pthread_mutex_unlock(in_use->mysys_var->current_mutex); + mysql_mutex_lock(in_use->mysys_var->current_mutex); + mysql_cond_broadcast(in_use->mysys_var->current_cond); + mysql_mutex_unlock(in_use->mysys_var->current_mutex); } - pthread_mutex_unlock(&in_use->mysys_var->mutex); + mysql_mutex_unlock(&in_use->mysys_var->mutex); } } } @@ -941,7 +941,7 @@ bool close_cached_tables(THD *thd, TABLE_LIST *tables, bool have_lock, DBUG_ASSERT(thd || (!wait_for_refresh && !tables)); if (!have_lock) - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); if (!tables) { refresh_version++; // Force close of open tables @@ -979,7 +979,7 @@ bool close_cached_tables(THD *thd, TABLE_LIST *tables, bool have_lock, } if (!have_lock) - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); if (!wait_for_refresh) DBUG_RETURN(result); @@ -1030,7 +1030,7 @@ bool close_cached_tables(THD *thd, TABLE_LIST *tables, bool have_lock, mysql_ha_flush(thd); DEBUG_SYNC(thd, "after_flush_unlock"); - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); thd->enter_cond(&COND_refresh, &LOCK_open, "Flushing tables"); @@ -1063,7 +1063,7 @@ bool close_cached_tables(THD *thd, TABLE_LIST *tables, bool have_lock, if (found) { DBUG_PRINT("signal", ("Waiting for COND_refresh")); - pthread_cond_wait(&COND_refresh,&LOCK_open); + mysql_cond_wait(&COND_refresh, &LOCK_open); } thd->exit_cond(NULL); @@ -1107,7 +1107,7 @@ bool close_cached_connection_tables(THD *thd, bool if_wait_for_refresh, bzero(&tmp, sizeof(TABLE_LIST)); if (!have_lock) - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); for (idx= 0; idx < table_def_cache.records; idx++) { @@ -1140,15 +1140,15 @@ bool close_cached_connection_tables(THD *thd, bool if_wait_for_refresh, result= close_cached_tables(thd, tables, TRUE, FALSE); if (!have_lock) - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); if (if_wait_for_refresh) { - pthread_mutex_lock(&thd->mysys_var->mutex); + mysql_mutex_lock(&thd->mysys_var->mutex); thd->mysys_var->current_mutex= 0; thd->mysys_var->current_cond= 0; thd->proc_info=0; - pthread_mutex_unlock(&thd->mysys_var->mutex); + mysql_mutex_unlock(&thd->mysys_var->mutex); } DBUG_RETURN(result); @@ -1268,9 +1268,9 @@ static void close_open_tables(THD *thd) { bool found_old_table= 0; - safe_mutex_assert_not_owner(&LOCK_open); + mysql_mutex_assert_not_owner(&LOCK_open); - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); DBUG_PRINT("info", ("thd->open_tables: 0x%lx", (long) thd->open_tables)); @@ -1286,7 +1286,7 @@ static void close_open_tables(THD *thd) broadcast_refresh(); } - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); } @@ -1317,13 +1317,13 @@ close_all_tables_for_name(THD *thd, TABLE_SHARE *share, memcpy(key, share->table_cache_key.str, key_length); - safe_mutex_assert_not_owner(&LOCK_open); + mysql_mutex_assert_not_owner(&LOCK_open); /* We need to hold LOCK_open while changing the open_tables list, since another thread may work on it. @sa mysql_notify_thread_having_shared_lock() */ - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); for (TABLE **prev= &thd->open_tables; *prev; ) { @@ -1359,7 +1359,7 @@ close_all_tables_for_name(THD *thd, TABLE_SHARE *share, } /* We have been removing tables from the table cache. */ broadcast_refresh(); - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); } @@ -1552,7 +1552,7 @@ bool close_thread_table(THD *thd, TABLE **table_ptr) DBUG_ENTER("close_thread_table"); DBUG_ASSERT(table->key_read == 0); DBUG_ASSERT(!table->file || table->file->inited == handler::NONE); - safe_mutex_assert_owner(&LOCK_open); + mysql_mutex_assert_owner(&LOCK_open); *table_ptr=table->next; @@ -2148,10 +2148,10 @@ bool wait_while_table_is_used(THD *thd, TABLE *table, if (thd->mdl_context.upgrade_shared_lock_to_exclusive(table->mdl_ticket)) DBUG_RETURN(TRUE); - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); tdc_remove_table(thd, TDC_RT_REMOVE_NOT_OWN, table->s->db.str, table->s->table_name.str); - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); /* extra() call must come only after all instances above are closed */ (void) table->file->extra(function); DBUG_RETURN(FALSE); @@ -2191,11 +2191,11 @@ void drop_open_table(THD *thd, TABLE *table, const char *db_name, /* Ensure the table is removed from the cache. */ table->s->version= 0; - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); table->file->extra(HA_EXTRA_PREPARE_FOR_DROP); close_thread_table(thd, &thd->open_tables); quick_rm_table(table_type, db_name, table_name, 0); - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); } DBUG_VOID_RETURN; } @@ -2212,7 +2212,7 @@ void drop_open_table(THD *thd, TABLE *table, const char *db_name, cond Condition to wait for */ -void wait_for_condition(THD *thd, pthread_mutex_t *mutex, pthread_cond_t *cond) +void wait_for_condition(THD *thd, mysql_mutex_t *mutex, mysql_cond_t *cond) { /* Wait until the current table is up to date */ const char *proc_info; @@ -2222,7 +2222,7 @@ void wait_for_condition(THD *thd, pthread_mutex_t *mutex, pthread_cond_t *cond) thd_proc_info(thd, "Waiting for table"); DBUG_ENTER("wait_for_condition"); if (!thd->killed) - (void) pthread_cond_wait(cond, mutex); + mysql_cond_wait(cond, mutex); /* We must unlock mutex first to avoid deadlock becasue conditions are @@ -2235,12 +2235,12 @@ void wait_for_condition(THD *thd, pthread_mutex_t *mutex, pthread_cond_t *cond) mutex is unlocked */ - pthread_mutex_unlock(mutex); - pthread_mutex_lock(&thd->mysys_var->mutex); + mysql_mutex_unlock(mutex); + mysql_mutex_lock(&thd->mysys_var->mutex); thd->mysys_var->current_mutex= 0; thd->mysys_var->current_cond= 0; thd_proc_info(thd, proc_info); - pthread_mutex_unlock(&thd->mysys_var->mutex); + mysql_mutex_unlock(&thd->mysys_var->mutex); DBUG_VOID_RETURN; } @@ -2272,7 +2272,7 @@ bool check_if_table_exists(THD *thd, TABLE_LIST *table, bool *exists) int rc; DBUG_ENTER("check_if_table_exists"); - safe_mutex_assert_owner(&LOCK_open); + mysql_mutex_assert_owner(&LOCK_open); *exists= TRUE; @@ -2316,10 +2316,10 @@ bool check_if_table_exists(THD *thd, TABLE_LIST *table, bool *exists) void table_share_release_hook(void *share) { - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); release_table_share((TABLE_SHARE*) share); broadcast_refresh(); - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); } @@ -2676,7 +2676,7 @@ bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, */ mdl_ticket= mdl_request->ticket; - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); /* If it's the first table from a list of tables used in a query, @@ -2692,7 +2692,7 @@ bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, ! (flags & MYSQL_LOCK_IGNORE_FLUSH)) { /* Someone did a refresh while thread was opening tables */ - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); (void) ot_ctx->request_backoff_action(Open_table_context::OT_WAIT_TDC); DBUG_RETURN(TRUE); } @@ -2706,14 +2706,14 @@ bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, if (!exists) { - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); DBUG_RETURN(FALSE); } /* Table exists. Let us try to open it. */ } else if (table_list->open_strategy == TABLE_LIST::OPEN_STUB) { - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); DBUG_RETURN(FALSE); } @@ -2772,7 +2772,7 @@ bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, DBUG_ASSERT(table_list->view); } - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); DBUG_RETURN(FALSE); } /* @@ -2832,7 +2832,7 @@ bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, (see tdc_wait_for_old_versions()). */ release_table_share(share); - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); (void) ot_ctx->request_backoff_action(Open_table_context::OT_WAIT_TDC); DBUG_RETURN(TRUE); } @@ -2895,7 +2895,7 @@ bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, table_def_add_used_table(thd, table); } - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); /* In CREATE TABLE .. If NOT EXISTS .. SELECT we have found that @@ -2955,7 +2955,7 @@ bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, err_unlock: release_table_share(share); err_unlock2: - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); DBUG_RETURN(TRUE); } @@ -3249,7 +3249,7 @@ unlink_all_closed_tables(THD *thd, MYSQL_LOCK *lock, size_t reopen_count) */ if (reopen_count) { - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); while (reopen_count--) { /* @@ -3266,7 +3266,7 @@ unlink_all_closed_tables(THD *thd, MYSQL_LOCK *lock, size_t reopen_count) close_thread_table(thd, &thd->open_tables); } broadcast_refresh(); - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); } /* Exclude all closed tables from the LOCK TABLES list. */ for (TABLE_LIST *table_list= m_locked_tables; table_list; table_list= @@ -3395,7 +3395,7 @@ void assign_new_table_id(TABLE_SHARE *share) /* Preconditions */ DBUG_ASSERT(share != NULL); - safe_mutex_assert_owner(&LOCK_open); + mysql_mutex_assert_owner(&LOCK_open); ulong tid= ++last_table_id; /* get next id */ /* @@ -3570,7 +3570,7 @@ bool tdc_open_view(THD *thd, TABLE_LIST *table_list, const char *alias, int error; TABLE_SHARE *share; - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); if (!(share= get_table_share_with_create(thd, table_list, cache_key, cache_key_length, @@ -3586,14 +3586,14 @@ bool tdc_open_view(THD *thd, TABLE_LIST *table_list, const char *alias, mem_root)) { release_table_share(share); - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); return FALSE; } my_error(ER_WRONG_OBJECT, MYF(0), share->db.str, share->table_name.str, "VIEW"); release_table_share(share); err: - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); return TRUE; } @@ -3605,7 +3605,6 @@ err: static bool open_table_entry_fini(THD *thd, TABLE_SHARE *share, TABLE *entry) { - if (Table_triggers_list::check_n_load(thd, share->db.str, share->table_name.str, entry, 0)) return TRUE; @@ -3668,13 +3667,13 @@ static bool auto_repair_table(THD *thd, TABLE_LIST *table_list) thd->clear_error(); - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); if (!(share= get_table_share_with_create(thd, table_list, cache_key, cache_key_length, OPEN_VIEW, ¬_used))) { - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); return TRUE; } @@ -3687,7 +3686,7 @@ static bool auto_repair_table(THD *thd, TABLE_LIST *table_list) goto end_with_lock_open; } share->version= 0; - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); if (open_table_from_share(thd, share, table_list->alias, (uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE | @@ -3714,11 +3713,11 @@ static bool auto_repair_table(THD *thd, TABLE_LIST *table_list) } my_free(entry, MYF(0)); - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); end_with_lock_open: release_table_share(share); - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); return result; } @@ -3849,14 +3848,14 @@ recover_from_failed_open(THD *thd, MDL_request *mdl_request, break; DBUG_ASSERT(mdl_request->key.mdl_namespace() == MDL_key::TABLE); - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); tdc_remove_table(thd, TDC_RT_REMOVE_ALL, mdl_request->key.db_name(), mdl_request->key.name()); ha_create_table_from_engine(thd, mdl_request->key.db_name(), mdl_request->key.name()); - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); thd->warning_info->clear_warning_info(thd->query_id); thd->clear_error(); // Clear error message @@ -3880,11 +3879,11 @@ recover_from_failed_open(THD *thd, MDL_request *mdl_request, break; DBUG_ASSERT(mdl_request->key.mdl_namespace() == MDL_key::TABLE); - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); tdc_remove_table(thd, TDC_RT_REMOVE_ALL, mdl_request->key.db_name(), mdl_request->key.name()); - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); result= auto_repair_table(thd, table); thd->mdl_context.release_transactional_locks(); @@ -8494,10 +8493,10 @@ my_bool mysql_rm_tmp_tables(void) void flush_tables() { - (void) pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); while (unused_tables) free_cache_entry(unused_tables); - (void) pthread_mutex_unlock(&LOCK_open); + (void) mysql_mutex_unlock(&LOCK_open); } @@ -8537,13 +8536,13 @@ bool mysql_notify_thread_having_shared_lock(THD *thd, THD *in_use, !in_use->killed) { in_use->killed= THD::KILL_CONNECTION; - pthread_mutex_lock(&in_use->mysys_var->mutex); + mysql_mutex_lock(&in_use->mysys_var->mutex); if (in_use->mysys_var->current_cond) - pthread_cond_broadcast(in_use->mysys_var->current_cond); - pthread_mutex_unlock(&in_use->mysys_var->mutex); + mysql_cond_broadcast(in_use->mysys_var->current_cond); + mysql_mutex_unlock(&in_use->mysys_var->mutex); signalled= TRUE; } - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); if (needs_thr_lock_abort) { @@ -8573,7 +8572,7 @@ bool mysql_notify_thread_having_shared_lock(THD *thd, THD *in_use, a multi-statement transaction. */ broadcast_refresh(); - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); return signalled; } @@ -8616,7 +8615,7 @@ void tdc_remove_table(THD *thd, enum_tdc_remove_table_type remove_type, TABLE *table; TABLE_SHARE *share; - safe_mutex_assert_owner(&LOCK_open); + mysql_mutex_assert_owner(&LOCK_open); DBUG_ASSERT(remove_type == TDC_RT_REMOVE_UNUSED || thd->mdl_context.is_lock_owner(MDL_key::TABLE, db, table_name, @@ -8684,7 +8683,7 @@ tdc_wait_for_old_versions(THD *thd, MDL_request_list *mdl_requests) */ mysql_ha_flush(thd); - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); MDL_request_list::Iterator it(*mdl_requests); while ((mdl_request= it++)) @@ -8700,11 +8699,11 @@ tdc_wait_for_old_versions(THD *thd, MDL_request_list *mdl_requests) } if (!mdl_request) { - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); break; } old_msg= thd->enter_cond(&COND_refresh, &LOCK_open, "Waiting for table"); - pthread_cond_wait(&COND_refresh, &LOCK_open); + mysql_cond_wait(&COND_refresh, &LOCK_open); /* LOCK_open mutex is unlocked by THD::exit_cond() as side-effect. */ thd->exit_cond(old_msg); } diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 9d2a55f0f3a..7e20cca16d6 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -423,12 +423,16 @@ TYPELIB query_cache_type_typelib= effect by another thread. This enables a quick path in execution to skip waits when the outcome is known. + @param use_timeout TRUE if the lock can abort because of a timeout. + + @note use_timeout is optional and default value is FALSE. + @return @retval FALSE An exclusive lock was taken @retval TRUE The locking attempt failed */ -bool Query_cache::try_lock(void) +bool Query_cache::try_lock(bool use_timeout) { bool interrupt= FALSE; DBUG_ENTER("Query_cache::try_lock"); @@ -458,7 +462,26 @@ bool Query_cache::try_lock(void) else { DBUG_ASSERT(m_cache_lock_status == Query_cache::LOCKED); - pthread_cond_wait(&COND_cache_status_changed, &structure_guard_mutex); + /* + To prevent send_result_to_client() and query_cache_insert() from + blocking execution for too long a timeout is put on the lock. + */ + if (use_timeout) + { + struct timespec waittime; + set_timespec_nsec(waittime,(ulong)(50000000L)); /* Wait for 50 msec */ + int res= pthread_cond_timedwait(&COND_cache_status_changed, + &structure_guard_mutex,&waittime); + if (res == ETIMEDOUT) + { + interrupt= TRUE; + break; + } + } + else + { + pthread_cond_wait(&COND_cache_status_changed, &structure_guard_mutex); + } } } pthread_mutex_unlock(&structure_guard_mutex); @@ -1213,8 +1236,14 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d", A table- or a full flush operation can potentially take a long time to finish. We choose not to wait for them and skip caching statements instead. + + In case the wait time can't be determined there is an upper limit which + causes try_lock() to abort with a time out. + + The 'TRUE' parameter indicate that the lock is allowed to timeout + */ - if (try_lock()) + if (try_lock(TRUE)) DBUG_VOID_RETURN; if (query_cache_size == 0) { @@ -1415,8 +1444,10 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) Try to obtain an exclusive lock on the query cache. If the cache is disabled or if a full cache flush is in progress, the attempt to get the lock is aborted. + + The 'TRUE' parameter indicate that the lock is allowed to timeout */ - if (try_lock()) + if (try_lock(TRUE)) goto err; if (query_cache_size == 0) diff --git a/sql/sql_cache.h b/sql/sql_cache.h index 6b187ebd6c2..695d6fb4db3 100644 --- a/sql/sql_cache.h +++ b/sql/sql_cache.h @@ -496,7 +496,7 @@ protected: const char *name); my_bool in_blocks(Query_cache_block * point); - bool try_lock(void); + bool try_lock(bool use_timeout= FALSE); void lock(void); void lock_and_suspend(void); void unlock(void); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 8affe88d01d..e73de250051 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -383,6 +383,8 @@ char *thd_security_context(THD *thd, char *buffer, unsigned int length, str.append(proc_info); } + pthread_mutex_lock(&thd->LOCK_thd_data); + if (thd->query()) { if (max_query_len < 1) @@ -392,6 +394,9 @@ char *thd_security_context(THD *thd, char *buffer, unsigned int length, str.append('\n'); str.append(thd->query(), len); } + + pthread_mutex_unlock(&thd->LOCK_thd_data); + if (str.c_ptr_safe() == buffer) return buffer; @@ -958,9 +963,9 @@ void THD::init_for_queries() void THD::change_user(void) { - pthread_mutex_lock(&LOCK_status); + mysql_mutex_lock(&LOCK_status); add_to_status(&global_status_var, &status_var); - pthread_mutex_unlock(&LOCK_status); + mysql_mutex_unlock(&LOCK_status); cleanup(); killed= NOT_KILLED; @@ -1031,9 +1036,9 @@ void THD::cleanup(void) if (ull) { - pthread_mutex_lock(&LOCK_user_locks); + mysql_mutex_lock(&LOCK_user_locks); item_user_lock_release(ull); - pthread_mutex_unlock(&LOCK_user_locks); + mysql_mutex_unlock(&LOCK_user_locks); ull= NULL; } @@ -1173,7 +1178,7 @@ void THD::awake(THD::killed_state state_to_set) } if (mysys_var) { - pthread_mutex_lock(&mysys_var->mutex); + mysql_mutex_lock(&mysys_var->mutex); if (!system_thread) // Don't abort locks mysys_var->abort=1; /* @@ -1197,11 +1202,11 @@ void THD::awake(THD::killed_state state_to_set) */ if (mysys_var->current_cond && mysys_var->current_mutex) { - pthread_mutex_lock(mysys_var->current_mutex); - pthread_cond_broadcast(mysys_var->current_cond); - pthread_mutex_unlock(mysys_var->current_mutex); + mysql_mutex_lock(mysys_var->current_mutex); + mysql_cond_broadcast(mysys_var->current_cond); + mysql_mutex_unlock(mysys_var->current_mutex); } - pthread_mutex_unlock(&mysys_var->mutex); + mysql_mutex_unlock(&mysys_var->mutex); } DBUG_VOID_RETURN; } @@ -3284,6 +3289,26 @@ void THD::set_query(char *query_arg, uint32 query_length_arg) pthread_mutex_unlock(&LOCK_thd_data); } +/** Assign a new value to thd->query and thd->query_id. */ + +void THD::set_query_and_id(char *query_arg, uint32 query_length_arg, + query_id_t new_query_id) +{ + pthread_mutex_lock(&LOCK_thd_data); + set_query_inner(query_arg, query_length_arg); + query_id= new_query_id; + pthread_mutex_unlock(&LOCK_thd_data); +} + +/** Assign a new value to thd->query_id. */ + +void THD::set_query_id(query_id_t new_query_id) +{ + pthread_mutex_lock(&LOCK_thd_data); + query_id= new_query_id; + pthread_mutex_unlock(&LOCK_thd_data); +} + /** Mark transaction to rollback and mark error as fatal to a sub-statement. diff --git a/sql/sql_class.h b/sql/sql_class.h index 2ca67133fe5..4fd4c0a1671 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -2158,21 +2158,21 @@ public: enter_cond(); this mutex is then released by exit_cond(). Usage must be: lock mutex; enter_cond(); your code; exit_cond(). */ - inline const char* enter_cond(pthread_cond_t *cond, pthread_mutex_t* mutex, - const char* msg) + inline const char* enter_cond(mysql_cond_t *cond, mysql_mutex_t* mutex, + const char* msg) { const char* old_msg = proc_info; - safe_mutex_assert_owner(mutex); + mysql_mutex_assert_owner(mutex); mysys_var->current_mutex = mutex; mysys_var->current_cond = cond; proc_info = msg; return old_msg; } - inline const char* enter_cond(mysql_cond_t *cond, mysql_mutex_t *mutex, + inline const char* enter_cond(pthread_cond_t *cond, pthread_mutex_t *mutex, const char *msg) { /* TO BE REMOVED: temporary helper, to help with merges */ - return enter_cond(&cond->m_cond, &mutex->m_mutex, msg); + return enter_cond((mysql_cond_t*) cond, (mysql_mutex_t*) mutex, msg); } inline void exit_cond(const char* old_msg) { @@ -2182,12 +2182,12 @@ public: locked (if that would not be the case, you'll get a deadlock if someone does a THD::awake() on you). */ - pthread_mutex_unlock(mysys_var->current_mutex); - pthread_mutex_lock(&mysys_var->mutex); + mysql_mutex_unlock(mysys_var->current_mutex); + mysql_mutex_lock(&mysys_var->mutex); mysys_var->current_mutex = 0; mysys_var->current_cond = 0; proc_info = old_msg; - pthread_mutex_unlock(&mysys_var->mutex); + mysql_mutex_unlock(&mysys_var->mutex); return; } inline time_t query_start() { query_start_used=1; return start_time; } @@ -2618,10 +2618,13 @@ public: virtual void set_statement(Statement *stmt); /** - Assign a new value to thd->query. + Assign a new value to thd->query and thd->query_id. Protected with LOCK_thd_data mutex. */ void set_query(char *query_arg, uint32 query_length_arg); + void set_query_and_id(char *query_arg, uint32 query_length_arg, + query_id_t new_query_id); + void set_query_id(query_id_t new_query_id); void enter_locked_tables_mode(enum_locked_tables_mode mode_arg) { DBUG_ASSERT(locked_tables_mode == LTM_NONE); diff --git a/sql/sql_cursor.cc b/sql/sql_cursor.cc index 31aa3e7ea52..6c7a9fb64ce 100644 --- a/sql/sql_cursor.cc +++ b/sql/sql_cursor.cc @@ -436,7 +436,7 @@ Sensitive_cursor::fetch(ulong num_rows) thd->derived_tables= derived_tables; thd->open_tables= open_tables; thd->lock= lock; - thd->query_id= query_id; + thd->set_query_id(query_id); change_list.move_elements_to(&thd->change_list); /* save references to memory allocated during fetch */ thd->set_n_backup_active_arena(this, &backup_arena); diff --git a/sql/sql_db.cc b/sql/sql_db.cc index e7a36f664dd..a7f08ebfe19 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2000-2003 MySQL AB +/* Copyright (C) 2000-2003 MySQL AB, 2008-2009 Sun Microsystems, Inc 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 @@ -47,7 +47,7 @@ static void mysql_change_db_impl(THD *thd, /* Database lock hash */ HASH lock_db_cache; -pthread_mutex_t LOCK_lock_db; +mysql_mutex_t LOCK_lock_db; int creating_database= 0; // how many database locks are made @@ -103,7 +103,7 @@ static my_bool lock_db_insert(const char *dbname, uint length) my_bool error= 0; DBUG_ENTER("lock_db_insert"); - safe_mutex_assert_owner(&LOCK_lock_db); + mysql_mutex_assert_owner(&LOCK_lock_db); if (!(opt= (my_dblock_t*) my_hash_search(&lock_db_cache, (uchar*) dbname, length))) @@ -138,7 +138,7 @@ end: void lock_db_delete(const char *name, uint length) { my_dblock_t *opt; - safe_mutex_assert_owner(&LOCK_lock_db); + mysql_mutex_assert_owner(&LOCK_lock_db); if ((opt= (my_dblock_t *)my_hash_search(&lock_db_cache, (const uchar*) name, length))) my_hash_delete(&lock_db_cache, (uchar*) opt); @@ -148,7 +148,7 @@ void lock_db_delete(const char *name, uint length) /* Database options hash */ static HASH dboptions; static my_bool dboptions_init= 0; -static rw_lock_t LOCK_dboptions; +static mysql_rwlock_t LOCK_dboptions; /* Structure for database options */ typedef struct my_dbopt_st @@ -199,6 +199,26 @@ void free_dbopt(void *dbopt) my_free((uchar*) dbopt, MYF(0)); } +#ifdef HAVE_PSI_INTERFACE +static PSI_rwlock_key key_rwlock_LOCK_dboptions; + +static PSI_rwlock_info all_database_names_rwlocks[]= +{ + { &key_rwlock_LOCK_dboptions, "LOCK_dboptions", PSI_FLAG_GLOBAL} +}; + +static void init_database_names_psi_keys(void) +{ + const char* category= "sql"; + int count; + + if (PSI_server == NULL) + return; + + count= array_elements(all_database_names_rwlocks); + PSI_server->register_rwlock(category, all_database_names_rwlocks, count); +} +#endif /* Initialize database option hash and locked database hash. @@ -216,8 +236,12 @@ void free_dbopt(void *dbopt) bool my_database_names_init(void) { +#ifdef HAVE_PSI_INTERFACE + init_database_names_psi_keys(); +#endif + bool error= 0; - (void) my_rwlock_init(&LOCK_dboptions, NULL); + mysql_rwlock_init(key_rwlock_LOCK_dboptions, &LOCK_dboptions); if (!dboptions_init) { dboptions_init= 1; @@ -246,7 +270,7 @@ void my_database_names_free(void) { dboptions_init= 0; my_hash_free(&dboptions); - (void) rwlock_destroy(&LOCK_dboptions); + mysql_rwlock_destroy(&LOCK_dboptions); my_hash_free(&lock_db_cache); } } @@ -258,13 +282,13 @@ void my_database_names_free(void) void my_dbopt_cleanup(void) { - rw_wrlock(&LOCK_dboptions); + mysql_rwlock_wrlock(&LOCK_dboptions); my_hash_free(&dboptions); my_hash_init(&dboptions, lower_case_table_names ? &my_charset_bin : system_charset_info, 32, 0, 0, (my_hash_get_key) dboptions_get_key, free_dbopt,0); - rw_unlock(&LOCK_dboptions); + mysql_rwlock_unlock(&LOCK_dboptions); } @@ -288,13 +312,13 @@ static my_bool get_dbopt(const char *dbname, HA_CREATE_INFO *create) length= (uint) strlen(dbname); - rw_rdlock(&LOCK_dboptions); + mysql_rwlock_rdlock(&LOCK_dboptions); if ((opt= (my_dbopt_t*) my_hash_search(&dboptions, (uchar*) dbname, length))) { create->default_table_charset= opt->charset; error= 0; } - rw_unlock(&LOCK_dboptions); + mysql_rwlock_unlock(&LOCK_dboptions); return error; } @@ -320,7 +344,7 @@ static my_bool put_dbopt(const char *dbname, HA_CREATE_INFO *create) length= (uint) strlen(dbname); - rw_wrlock(&LOCK_dboptions); + mysql_rwlock_wrlock(&LOCK_dboptions); if (!(opt= (my_dbopt_t*) my_hash_search(&dboptions, (uchar*) dbname, length))) { @@ -349,7 +373,7 @@ static my_bool put_dbopt(const char *dbname, HA_CREATE_INFO *create) opt->charset= create->default_table_charset; end: - rw_unlock(&LOCK_dboptions); + mysql_rwlock_unlock(&LOCK_dboptions); DBUG_RETURN(error); } @@ -361,11 +385,11 @@ end: void del_dbopt(const char *path) { my_dbopt_t *opt; - rw_wrlock(&LOCK_dboptions); + mysql_rwlock_wrlock(&LOCK_dboptions); if ((opt= (my_dbopt_t *)my_hash_search(&dboptions, (const uchar*) path, strlen(path)))) my_hash_delete(&dboptions, (uchar*) opt); - rw_unlock(&LOCK_dboptions); + mysql_rwlock_unlock(&LOCK_dboptions); } @@ -392,7 +416,8 @@ static bool write_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create) if (put_dbopt(path, create)) return 1; - if ((file=my_create(path, CREATE_MODE,O_RDWR | O_TRUNC,MYF(MY_WME))) >= 0) + if ((file= mysql_file_create(key_file_dbopt, path, CREATE_MODE, + O_RDWR | O_TRUNC, MYF(MY_WME))) >= 0) { ulong length; length= (ulong) (strxnmov(buf, sizeof(buf)-1, "default-character-set=", @@ -401,10 +426,10 @@ static bool write_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create) create->default_table_charset->name, "\n", NullS) - buf); - /* Error is written by my_write */ - if (!my_write(file,(uchar*) buf, length, MYF(MY_NABP+MY_WME))) + /* Error is written by mysql_file_write */ + if (!mysql_file_write(file, (uchar*) buf, length, MYF(MY_NABP+MY_WME))) error=0; - my_close(file,MYF(0)); + mysql_file_close(file, MYF(0)); } return error; } @@ -441,7 +466,8 @@ bool load_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create) DBUG_RETURN(0); /* Otherwise, load options from the .opt file */ - if ((file=my_open(path, O_RDONLY | O_SHARE, MYF(0))) < 0) + if ((file= mysql_file_open(key_file_dbopt, + path, O_RDONLY | O_SHARE, MYF(0))) < 0) goto err1; IO_CACHE cache; @@ -499,7 +525,7 @@ bool load_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create) end_io_cache(&cache); err2: - my_close(file,MYF(0)); + mysql_file_close(file, MYF(0)); err1: DBUG_RETURN(error); } @@ -643,13 +669,13 @@ int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info, goto exit2; } - pthread_mutex_lock(&LOCK_mysql_create_db); + mysql_mutex_lock(&LOCK_mysql_create_db); /* Check directory */ path_len= build_table_filename(path, sizeof(path) - 1, db, "", "", 0); path[path_len-1]= 0; // Remove last '/' from path - if (my_stat(path,&stat_info,MYF(0))) + if (mysql_file_stat(key_file_misc, path, &stat_info, MYF(0))) { if (!(create_options & HA_LEX_CREATE_IF_NOT_EXISTS)) { @@ -753,7 +779,7 @@ not_silent: } exit: - pthread_mutex_unlock(&LOCK_mysql_create_db); + mysql_mutex_unlock(&LOCK_mysql_create_db); thd->global_read_lock.start_waiting_global_read_lock(thd); exit2: DBUG_RETURN(error); @@ -784,7 +810,7 @@ bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info) if ((error= thd->global_read_lock.wait_if_global_read_lock(thd, FALSE, TRUE))) goto exit2; - pthread_mutex_lock(&LOCK_mysql_create_db); + mysql_mutex_lock(&LOCK_mysql_create_db); /* Recreate db options file: /dbpath/.db.opt @@ -830,7 +856,7 @@ bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info) my_ok(thd, result); exit: - pthread_mutex_unlock(&LOCK_mysql_create_db); + mysql_mutex_unlock(&LOCK_mysql_create_db); thd->global_read_lock.start_waiting_global_read_lock(thd); exit2: DBUG_RETURN(error); @@ -882,7 +908,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) goto exit2; } - pthread_mutex_lock(&LOCK_mysql_create_db); + mysql_mutex_lock(&LOCK_mysql_create_db); length= build_table_filename(path, sizeof(path) - 1, db, "", "", 0); strmov(path+length, MY_DB_OPT_FILE); // Append db option file name @@ -1026,7 +1052,7 @@ exit: */ if (thd->db && !strcmp(thd->db, db) && error == 0) mysql_change_db_impl(thd, NULL, 0, thd->variables.collation_server); - pthread_mutex_unlock(&LOCK_mysql_create_db); + mysql_mutex_unlock(&LOCK_mysql_create_db); thd->global_read_lock.start_waiting_global_read_lock(thd); exit2: DBUG_RETURN(error); @@ -1157,7 +1183,7 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db, else { strxmov(filePath, org_path, "/", file->name, NullS); - if (my_delete_with_symlink(filePath,MYF(MY_WME))) + if (mysql_file_delete_with_symlink(key_file_misc, filePath, MYF(MY_WME))) { goto err; } @@ -1235,7 +1261,7 @@ static my_bool rm_dir_w_symlink(const char *org_path, my_bool send_error) DBUG_RETURN(1); if (!error) { - if (my_delete(path, MYF(send_error ? MY_WME : 0))) + if (mysql_file_delete(key_file_misc, path, MYF(send_error ? MY_WME : 0))) { DBUG_RETURN(send_error); } @@ -1312,7 +1338,7 @@ long mysql_rm_arc_files(THD *thd, MY_DIR *dirp, const char *org_path) continue; } strxmov(filePath, org_path, "/", file->name, NullS); - if (my_delete_with_symlink(filePath,MYF(MY_WME))) + if (mysql_file_delete_with_symlink(key_file_misc, filePath, MYF(MY_WME))) { goto err; } @@ -1719,18 +1745,18 @@ static int lock_databases(THD *thd, const char *db1, uint length1, const char *db2, uint length2) { - pthread_mutex_lock(&LOCK_lock_db); + mysql_mutex_lock(&LOCK_lock_db); while (!thd->killed && (my_hash_search(&lock_db_cache,(uchar*) db1, length1) || my_hash_search(&lock_db_cache,(uchar*) db2, length2))) { wait_for_condition(thd, &LOCK_lock_db, &COND_refresh); - pthread_mutex_lock(&LOCK_lock_db); + mysql_mutex_lock(&LOCK_lock_db); } if (thd->killed) { - pthread_mutex_unlock(&LOCK_lock_db); + mysql_mutex_unlock(&LOCK_lock_db); return 1; } @@ -1747,7 +1773,7 @@ lock_databases(THD *thd, const char *db1, uint length1, while (!thd->killed && creating_table) { wait_for_condition(thd, &LOCK_lock_db, &COND_refresh); - pthread_mutex_lock(&LOCK_lock_db); + mysql_mutex_lock(&LOCK_lock_db); } if (thd->killed) @@ -1755,8 +1781,8 @@ lock_databases(THD *thd, const char *db1, uint length1, lock_db_delete(db1, length1); lock_db_delete(db2, length2); creating_database--; - pthread_mutex_unlock(&LOCK_lock_db); - pthread_cond_signal(&COND_refresh); + mysql_mutex_unlock(&LOCK_lock_db); + mysql_cond_signal(&COND_refresh); return(1); } @@ -1764,7 +1790,7 @@ lock_databases(THD *thd, const char *db1, uint length1, We can unlock now as the hash will protect against anyone creating a table in the databases we are using */ - pthread_mutex_unlock(&LOCK_lock_db); + mysql_mutex_unlock(&LOCK_lock_db); return 0; } @@ -1893,7 +1919,7 @@ bool mysql_upgrade_db(THD *thd, LEX_STRING *old_db) */ build_table_filename(path, sizeof(path)-1, new_db.str,"",MY_DB_OPT_FILE, 0); - my_delete(path, MYF(MY_WME)); + mysql_file_delete(key_file_dbopt, path, MYF(MY_WME)); length= build_table_filename(path, sizeof(path)-1, new_db.str, "", "", 0); if (length && path[length-1] == FN_LIBCHAR) path[length-1]=0; // remove ending '\' @@ -1949,7 +1975,7 @@ bool mysql_upgrade_db(THD *thd, LEX_STRING *old_db) old_db->str, "", file->name, 0); build_table_filename(newname, sizeof(newname)-1, new_db.str, "", file->name, 0); - my_rename(oldname, newname, MYF(MY_WME)); + mysql_file_rename(key_file_misc, oldname, newname, MYF(MY_WME)); } my_dirend(dirp); } @@ -1977,14 +2003,14 @@ bool mysql_upgrade_db(THD *thd, LEX_STRING *old_db) error|= mysql_change_db(thd, & new_db, FALSE); exit: - pthread_mutex_lock(&LOCK_lock_db); + mysql_mutex_lock(&LOCK_lock_db); /* Remove the databases from db lock cache */ lock_db_delete(old_db->str, old_db->length); lock_db_delete(new_db.str, new_db.length); creating_database--; /* Signal waiting CREATE TABLE's to continue */ - pthread_cond_signal(&COND_refresh); - pthread_mutex_unlock(&LOCK_lock_db); + mysql_cond_signal(&COND_refresh); + mysql_mutex_unlock(&LOCK_lock_db); DBUG_RETURN(error); } diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 87e59c0ac65..f9f3a586dc6 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB +/* Copyright (C) 2000 MySQL AB, 2008-2009 Sun Microsystems, Inc 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 @@ -427,7 +427,8 @@ cleanup: } DBUG_ASSERT(transactional_table || !deleted || thd->transaction.stmt.modified_non_trans_table); free_underlaid_joins(thd, select_lex); - if (error < 0 || (thd->lex->ignore && !thd->is_fatal_error)) + if (error < 0 || + (thd->lex->ignore && !thd->is_error() && !thd->is_fatal_error)) { /* If a TRUNCATE TABLE was issued, the number of rows should be reported as @@ -1219,10 +1220,10 @@ bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok) DBUG_RETURN(TRUE); has_mdl_lock= TRUE; - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table_list->db, table_list->table_name); - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); } } @@ -1232,10 +1233,10 @@ bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok) '\0'; */ path[path_length - reg_ext_length] = 0; - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); error= ha_create_table(thd, path, table_list->db, table_list->table_name, &create_info, 1); - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); query_cache_invalidate3(thd, table_list, 0); end: diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 5f800ea8642..4b22d5e8eec 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -1,4 +1,5 @@ -/* Copyright (C) 2000-2004 MySQL AB +/* Copyright (C) 2000-2004 MySQL AB, 2008-2009 Sun Microsystems, Inc + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. @@ -123,13 +124,13 @@ static void mysql_ha_close_table(THD *thd, TABLE_LIST *tables) { /* Non temporary table. */ tables->table->file->ha_index_or_rnd_end(); - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); if (close_thread_table(thd, &tables->table)) { /* Tell threads waiting for refresh that something has happened */ broadcast_refresh(); } - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); thd->mdl_context.release_lock(tables->mdl_request.ticket); } else if (tables->table) @@ -774,7 +775,7 @@ void mysql_ha_flush(THD *thd) TABLE_LIST *hash_tables; DBUG_ENTER("mysql_ha_flush"); - safe_mutex_assert_not_owner(&LOCK_open); + mysql_mutex_assert_not_owner(&LOCK_open); /* Don't try to flush open HANDLERs when we're working with diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index f2478213bbe..4b17826444a 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1,4 +1,4 @@ -/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc. +/* Copyright 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. 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 @@ -519,6 +519,22 @@ bool open_and_lock_for_insert_delayed(THD *thd, TABLE_LIST *table_list) DBUG_ENTER("open_and_lock_for_insert_delayed"); #ifndef EMBEDDED_LIBRARY + if (thd->locked_tables_mode && thd->global_read_lock.is_acquired()) + { + /* + If this connection has the global read lock, the handler thread + will not be able to lock the table. It will wait for the global + read lock to go away, but this will never happen since the + connection thread will be stuck waiting for the handler thread + to open and lock the table. + If we are not in locked tables mode, INSERT will seek protection + against the global read lock (and fail), thus we will only get + to this point in locked tables mode. + */ + my_error(ER_CANT_UPDATE_WITH_READLOCK, MYF(0)); + DBUG_RETURN(TRUE); + } + if (delayed_get_table(thd, table_list)) DBUG_RETURN(TRUE); @@ -899,7 +915,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, thd->net.last_error/errno. For example if there has been a disk full error when writing the row, and it was MyISAM, then thd->net.last_error/errno will be set to - "disk full"... and the my_pwrite() will wait until free + "disk full"... and the mysql_file_pwrite() will wait until free space appears, and so when it finishes then the write_row() was entirely successful */ @@ -1758,8 +1774,8 @@ class Delayed_insert :public ilink { public: THD thd; TABLE *table; - pthread_mutex_t mutex; - pthread_cond_t cond,cond_client; + mysql_mutex_t mutex; + mysql_cond_t cond, cond_client; volatile uint tables_in_use,stacked_inserts; volatile bool status; COPY_INFO info; @@ -1790,9 +1806,9 @@ public: thd.system_thread= SYSTEM_THREAD_DELAYED_INSERT; thd.security_ctx->host_or_ip= ""; bzero((char*) &info,sizeof(info)); - pthread_mutex_init(&mutex,MY_MUTEX_INIT_FAST); - pthread_cond_init(&cond,NULL); - pthread_cond_init(&cond_client,NULL); + mysql_mutex_init(key_delayed_insert_mutex, &mutex, MY_MUTEX_INIT_FAST); + mysql_cond_init(key_delayed_insert_cond, &cond, NULL); + mysql_cond_init(key_delayed_insert_cond_client, &cond_client, NULL); pthread_mutex_lock(&LOCK_thread_count); delayed_insert_threads++; delayed_lock= global_system_variables.low_priority_updates ? @@ -1808,9 +1824,9 @@ public: if (table) close_thread_tables(&thd); pthread_mutex_lock(&LOCK_thread_count); - pthread_mutex_destroy(&mutex); - pthread_cond_destroy(&cond); - pthread_cond_destroy(&cond_client); + mysql_mutex_destroy(&mutex); + mysql_cond_destroy(&cond); + mysql_cond_destroy(&cond_client); thd.unlink(); // Must be unlinked under lock x_free(thd.query()); thd.security_ctx->user= thd.security_ctx->host=0; @@ -1827,18 +1843,18 @@ public: } void unlock() { - pthread_mutex_lock(&LOCK_delayed_insert); + mysql_mutex_lock(&LOCK_delayed_insert); if (!--locks_in_memory) { - pthread_mutex_lock(&mutex); + mysql_mutex_lock(&mutex); if (thd.killed && ! stacked_inserts && ! tables_in_use) { - pthread_cond_signal(&cond); + mysql_cond_signal(&cond); status=1; } - pthread_mutex_unlock(&mutex); + mysql_mutex_unlock(&mutex); } - pthread_mutex_unlock(&LOCK_delayed_insert); + mysql_mutex_unlock(&LOCK_delayed_insert); } inline uint lock_count() { return locks_in_memory; } @@ -1860,7 +1876,7 @@ static Delayed_insert *find_handler(THD *thd, TABLE_LIST *table_list) { thd_proc_info(thd, "waiting for delay_list"); - pthread_mutex_lock(&LOCK_delayed_insert); // Protect master list + mysql_mutex_lock(&LOCK_delayed_insert); // Protect master list I_List_iterator<Delayed_insert> it(delayed_threads); Delayed_insert *di; while ((di= it++)) @@ -1872,7 +1888,7 @@ Delayed_insert *find_handler(THD *thd, TABLE_LIST *table_list) break; } } - pthread_mutex_unlock(&LOCK_delayed_insert); // For unlink from list + mysql_mutex_unlock(&LOCK_delayed_insert); // For unlink from list return di; } @@ -1941,7 +1957,7 @@ bool delayed_get_table(THD *thd, TABLE_LIST *table_list) if (delayed_insert_threads >= thd->variables.max_insert_delayed_threads) DBUG_RETURN(0); thd_proc_info(thd, "Creating delayed handler"); - pthread_mutex_lock(&LOCK_delayed_create); + mysql_mutex_lock(&LOCK_delayed_create); /* The first search above was done without LOCK_delayed_create. Another thread might have created the handler in between. Search again. @@ -1967,14 +1983,15 @@ bool delayed_get_table(THD *thd, TABLE_LIST *table_list) di->table_list.alias= di->table_list.table_name= di->thd.query(); di->table_list.db= di->thd.db; di->lock(); - pthread_mutex_lock(&di->mutex); - if ((error= pthread_create(&di->thd.real_id, &connection_attrib, - handle_delayed_insert, (void*) di))) + mysql_mutex_lock(&di->mutex); + if ((error= mysql_thread_create(key_thread_delayed_insert, + &di->thd.real_id, &connection_attrib, + handle_delayed_insert, (void*) di))) { DBUG_PRINT("error", ("Can't create thread to handle delayed insert (error %d)", error)); - pthread_mutex_unlock(&di->mutex); + mysql_mutex_unlock(&di->mutex); di->unlock(); delete di; my_error(ER_CANT_CREATE_THREAD, MYF(ME_FATALERROR), error); @@ -1985,9 +2002,9 @@ bool delayed_get_table(THD *thd, TABLE_LIST *table_list) thd_proc_info(thd, "waiting for handler open"); while (!di->thd.killed && !di->table && !thd->killed) { - pthread_cond_wait(&di->cond_client, &di->mutex); + mysql_cond_wait(&di->cond_client, &di->mutex); } - pthread_mutex_unlock(&di->mutex); + mysql_mutex_unlock(&di->mutex); thd_proc_info(thd, "got old table"); if (thd->killed) { @@ -2014,16 +2031,16 @@ bool delayed_get_table(THD *thd, TABLE_LIST *table_list) di->unlock(); goto end_create; } - pthread_mutex_lock(&LOCK_delayed_insert); + mysql_mutex_lock(&LOCK_delayed_insert); delayed_threads.append(di); - pthread_mutex_unlock(&LOCK_delayed_insert); + mysql_mutex_unlock(&LOCK_delayed_insert); } - pthread_mutex_unlock(&LOCK_delayed_create); + mysql_mutex_unlock(&LOCK_delayed_create); } - pthread_mutex_lock(&di->mutex); + mysql_mutex_lock(&di->mutex); table_list->table= di->get_local_table(thd); - pthread_mutex_unlock(&di->mutex); + mysql_mutex_unlock(&di->mutex); if (table_list->table) { DBUG_ASSERT(! thd->is_error()); @@ -2034,7 +2051,7 @@ bool delayed_get_table(THD *thd, TABLE_LIST *table_list) DBUG_RETURN((table_list->table == NULL)); end_create: - pthread_mutex_unlock(&LOCK_delayed_create); + mysql_mutex_unlock(&LOCK_delayed_create); DBUG_RETURN(thd->is_error()); } @@ -2070,10 +2087,10 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd) if (!thd.lock) // Table is not locked { thd_proc_info(client_thd, "waiting for handler lock"); - pthread_cond_signal(&cond); // Tell handler to lock table + mysql_cond_signal(&cond); // Tell handler to lock table while (!thd.killed && !thd.lock && ! client_thd->killed) { - pthread_cond_wait(&cond_client,&mutex); + mysql_cond_wait(&cond_client, &mutex); } thd_proc_info(client_thd, "got handler lock"); if (client_thd->killed) @@ -2176,7 +2193,7 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd) error: tables_in_use--; status=1; - pthread_cond_signal(&cond); // Inform thread about abort + mysql_cond_signal(&cond); // Inform thread about abort DBUG_RETURN(0); } @@ -2195,9 +2212,9 @@ int write_delayed(THD *thd, TABLE *table, enum_duplicates duplic, (ulong) query.length)); thd_proc_info(thd, "waiting for handler insert"); - pthread_mutex_lock(&di->mutex); + mysql_mutex_lock(&di->mutex); while (di->stacked_inserts >= delayed_queue_size && !thd->killed) - pthread_cond_wait(&di->cond_client,&di->mutex); + mysql_cond_wait(&di->cond_client, &di->mutex); thd_proc_info(thd, "storing row into queue"); if (thd->killed) @@ -2272,15 +2289,15 @@ int write_delayed(THD *thd, TABLE *table, enum_duplicates duplic, di->status=1; if (table->s->blob_fields) unlink_blobs(table); - pthread_cond_signal(&di->cond); + mysql_cond_signal(&di->cond); thread_safe_increment(delayed_rows_in_use,&LOCK_delayed_status); - pthread_mutex_unlock(&di->mutex); + mysql_mutex_unlock(&di->mutex); DBUG_RETURN(0); err: delete row; - pthread_mutex_unlock(&di->mutex); + mysql_mutex_unlock(&di->mutex); DBUG_RETURN(1); } @@ -2293,14 +2310,14 @@ static void end_delayed_insert(THD *thd) { DBUG_ENTER("end_delayed_insert"); Delayed_insert *di=thd->di; - pthread_mutex_lock(&di->mutex); + mysql_mutex_lock(&di->mutex); DBUG_PRINT("info",("tables in use: %d",di->tables_in_use)); if (!--di->tables_in_use || di->thd.killed) { // Unlock table di->status=1; - pthread_cond_signal(&di->cond); + mysql_cond_signal(&di->cond); } - pthread_mutex_unlock(&di->mutex); + mysql_mutex_unlock(&di->mutex); DBUG_VOID_RETURN; } @@ -2309,7 +2326,7 @@ static void end_delayed_insert(THD *thd) void kill_delayed_threads(void) { - pthread_mutex_lock(&LOCK_delayed_insert); // For unlink from list + mysql_mutex_lock(&LOCK_delayed_insert); // For unlink from list I_List_iterator<Delayed_insert> it(delayed_threads); Delayed_insert *di; @@ -2318,7 +2335,7 @@ void kill_delayed_threads(void) di->thd.killed= THD::KILL_CONNECTION; if (di->thd.mysys_var) { - pthread_mutex_lock(&di->thd.mysys_var->mutex); + mysql_mutex_lock(&di->thd.mysys_var->mutex); if (di->thd.mysys_var->current_cond) { /* @@ -2326,15 +2343,15 @@ void kill_delayed_threads(void) in handle_delayed_insert() */ if (&di->mutex != di->thd.mysys_var->current_mutex) - pthread_mutex_lock(di->thd.mysys_var->current_mutex); - pthread_cond_broadcast(di->thd.mysys_var->current_cond); + mysql_mutex_lock(di->thd.mysys_var->current_mutex); + mysql_cond_broadcast(di->thd.mysys_var->current_cond); if (&di->mutex != di->thd.mysys_var->current_mutex) - pthread_mutex_unlock(di->thd.mysys_var->current_mutex); + mysql_mutex_unlock(di->thd.mysys_var->current_mutex); } - pthread_mutex_unlock(&di->thd.mysys_var->mutex); + mysql_mutex_unlock(&di->thd.mysys_var->mutex); } } - pthread_mutex_unlock(&LOCK_delayed_insert); // For unlink from list + mysql_mutex_unlock(&LOCK_delayed_insert); // For unlink from list } @@ -2392,15 +2409,17 @@ pthread_handler_t handle_delayed_insert(void *arg) thd->killed=abort_loop ? THD::KILL_CONNECTION : THD::NOT_KILLED; pthread_mutex_unlock(&LOCK_thread_count); + mysql_thread_set_psi_id(thd->thread_id); + /* - Wait until the client runs into pthread_cond_wait(), + Wait until the client runs into mysql_cond_wait(), where we free it after the table is opened and di linked in the list. If we did not wait here, the client might detect the opened table before it is linked to the list. It would release LOCK_delayed_create and allow another thread to create another handler for the same table, since it does not find one in the list. */ - pthread_mutex_lock(&di->mutex); + mysql_mutex_lock(&di->mutex); if (my_thread_init()) { /* Can't use my_error since store_globals has not yet been called */ @@ -2440,7 +2459,7 @@ pthread_handler_t handle_delayed_insert(void *arg) goto err; /* Tell client that the thread is initialized */ - pthread_cond_signal(&di->cond_client); + mysql_cond_signal(&di->cond_client); /* Now wait until we get an insert or lock to handle */ /* We will not abort as long as a client thread uses this thread */ @@ -2454,12 +2473,12 @@ pthread_handler_t handle_delayed_insert(void *arg) Remove this from delay insert list so that no one can request a table from this */ - pthread_mutex_unlock(&di->mutex); - pthread_mutex_lock(&LOCK_delayed_insert); + mysql_mutex_unlock(&di->mutex); + mysql_mutex_lock(&LOCK_delayed_insert); di->unlink(); lock_count=di->lock_count(); - pthread_mutex_unlock(&LOCK_delayed_insert); - pthread_mutex_lock(&di->mutex); + mysql_mutex_unlock(&LOCK_delayed_insert); + mysql_mutex_lock(&di->mutex); if (!lock_count && !di->tables_in_use && !di->stacked_inserts) break; // Time to die } @@ -2480,15 +2499,15 @@ pthread_handler_t handle_delayed_insert(void *arg) { int error; #if defined(HAVE_BROKEN_COND_TIMEDWAIT) - error=pthread_cond_wait(&di->cond,&di->mutex); + error= mysql_cond_wait(&di->cond, &di->mutex); #else - error=pthread_cond_timedwait(&di->cond,&di->mutex,&abstime); + error= mysql_cond_timedwait(&di->cond, &di->mutex, &abstime); #ifdef EXTRA_DEBUG if (error && error != EINTR && error != ETIMEDOUT) { - fprintf(stderr, "Got error %d from pthread_cond_timedwait\n",error); - DBUG_PRINT("error",("Got error %d from pthread_cond_timedwait", - error)); + fprintf(stderr, "Got error %d from mysql_cond_timedwait\n", error); + DBUG_PRINT("error", ("Got error %d from mysql_cond_timedwait", + error)); } #endif #endif @@ -2496,12 +2515,12 @@ pthread_handler_t handle_delayed_insert(void *arg) thd->killed= THD::KILL_CONNECTION; } /* We can't lock di->mutex and mysys_var->mutex at the same time */ - pthread_mutex_unlock(&di->mutex); - pthread_mutex_lock(&di->thd.mysys_var->mutex); + mysql_mutex_unlock(&di->mutex); + mysql_mutex_lock(&di->thd.mysys_var->mutex); di->thd.mysys_var->current_mutex= 0; di->thd.mysys_var->current_cond= 0; - pthread_mutex_unlock(&di->thd.mysys_var->mutex); - pthread_mutex_lock(&di->mutex); + mysql_mutex_unlock(&di->thd.mysys_var->mutex); + mysql_mutex_lock(&di->mutex); } thd_proc_info(&(di->thd), 0); @@ -2543,7 +2562,7 @@ pthread_handler_t handle_delayed_insert(void *arg) thd->killed= THD::KILL_CONNECTION; } } - pthread_cond_broadcast(&di->cond_client); + mysql_cond_broadcast(&di->cond_client); } if (di->stacked_inserts) { @@ -2562,7 +2581,7 @@ pthread_handler_t handle_delayed_insert(void *arg) */ MYSQL_LOCK *lock=thd->lock; thd->lock=0; - pthread_mutex_unlock(&di->mutex); + mysql_mutex_unlock(&di->mutex); /* We need to release next_insert_id before unlocking. This is enforced by handler::ha_external_lock(). @@ -2571,10 +2590,10 @@ pthread_handler_t handle_delayed_insert(void *arg) mysql_unlock_tables(thd, lock); trans_commit_stmt(thd); di->group_count=0; - pthread_mutex_lock(&di->mutex); + mysql_mutex_lock(&di->mutex); } if (di->tables_in_use) - pthread_cond_broadcast(&di->cond_client); // If waiting clients + mysql_cond_broadcast(&di->cond_client); // If waiting clients } err: @@ -2602,14 +2621,14 @@ pthread_handler_t handle_delayed_insert(void *arg) close_thread_tables(thd); // Free the table di->table=0; thd->killed= THD::KILL_CONNECTION; // If error - pthread_cond_broadcast(&di->cond_client); // Safety - pthread_mutex_unlock(&di->mutex); + mysql_cond_broadcast(&di->cond_client); // Safety + mysql_mutex_unlock(&di->mutex); - pthread_mutex_lock(&LOCK_delayed_create); // Because of delayed_get_table - pthread_mutex_lock(&LOCK_delayed_insert); + mysql_mutex_lock(&LOCK_delayed_create); // Because of delayed_get_table + mysql_mutex_lock(&LOCK_delayed_insert); delete di; - pthread_mutex_unlock(&LOCK_delayed_insert); - pthread_mutex_unlock(&LOCK_delayed_create); + mysql_mutex_unlock(&LOCK_delayed_insert); + mysql_mutex_unlock(&LOCK_delayed_create); my_thread_end(); pthread_exit(0); @@ -2656,7 +2675,7 @@ bool Delayed_insert::handle_inserts(void) DBUG_ENTER("handle_inserts"); /* Allow client to insert new rows */ - pthread_mutex_unlock(&mutex); + mysql_mutex_unlock(&mutex); table->next_number_field=table->found_next_number_field; table->use_all_columns(); @@ -2689,12 +2708,12 @@ bool Delayed_insert::handle_inserts(void) */ if (!using_bin_log) table->file->extra(HA_EXTRA_WRITE_CACHE); - pthread_mutex_lock(&mutex); + mysql_mutex_lock(&mutex); while ((row=rows.get())) { stacked_inserts--; - pthread_mutex_unlock(&mutex); + mysql_mutex_unlock(&mutex); memcpy(table->record[0],row->record,table->s->reclength); thd.start_time=row->start_time; @@ -2812,7 +2831,7 @@ bool Delayed_insert::handle_inserts(void) free_delayed_insert_blobs(table); thread_safe_decrement(delayed_rows_in_use,&LOCK_delayed_status); thread_safe_increment(delayed_insert_writes,&LOCK_delayed_status); - pthread_mutex_lock(&mutex); + mysql_mutex_lock(&mutex); /* Reset the table->auto_increment_field_not_null as it is valid for @@ -2834,9 +2853,9 @@ bool Delayed_insert::handle_inserts(void) if (stacked_inserts || tables_in_use) // Let these wait a while { if (tables_in_use) - pthread_cond_broadcast(&cond_client); // If waiting clients + mysql_cond_broadcast(&cond_client); // If waiting clients thd_proc_info(&thd, "reschedule"); - pthread_mutex_unlock(&mutex); + mysql_mutex_unlock(&mutex); if ((error=table->file->extra(HA_EXTRA_NO_CACHE))) { /* This should never happen */ @@ -2855,15 +2874,15 @@ bool Delayed_insert::handle_inserts(void) } if (!using_bin_log) table->file->extra(HA_EXTRA_WRITE_CACHE); - pthread_mutex_lock(&mutex); + mysql_mutex_lock(&mutex); thd_proc_info(&thd, "insert"); } if (tables_in_use) - pthread_cond_broadcast(&cond_client); // If waiting clients + mysql_cond_broadcast(&cond_client); // If waiting clients } } thd_proc_info(&thd, 0); - pthread_mutex_unlock(&mutex); + mysql_mutex_unlock(&mutex); /* We need to flush the pending event when using row-based @@ -2888,7 +2907,7 @@ bool Delayed_insert::handle_inserts(void) goto err; } query_cache_invalidate3(&thd, table, 1); - pthread_mutex_lock(&mutex); + mysql_mutex_lock(&mutex); DBUG_RETURN(0); err: @@ -2912,7 +2931,7 @@ bool Delayed_insert::handle_inserts(void) } DBUG_PRINT("error", ("dropped %lu rows after an error", max_rows)); thread_safe_increment(delayed_insert_errors, &LOCK_delayed_status); - pthread_mutex_lock(&mutex); + mysql_mutex_lock(&mutex); DBUG_RETURN(1); } #endif /* EMBEDDED_LIBRARY */ @@ -3573,11 +3592,11 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, if (open_table(thd, create_table, thd->mem_root, &ot_ctx_unused, MYSQL_OPEN_REOPEN)) { - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); quick_rm_table(create_info->db_type, create_table->db, table_case_name(create_info, create_table->table_name), 0); - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); } else table= create_table->table; diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 8f4fe4e8885..cbd7b3cc232 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -337,8 +337,8 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, else { (void) fn_format(name, ex->file_name, mysql_real_data_home, "", - MY_RELATIVE_PATH | MY_UNPACK_FILENAME); - + MY_RELATIVE_PATH | MY_UNPACK_FILENAME | + MY_RETURN_REAL_PATH); #if !defined(__WIN__) && ! defined(__NETWARE__) MY_STAT stat_info; if (!my_stat(name,&stat_info,MYF(MY_WME))) @@ -381,12 +381,16 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, DBUG_ASSERT(FALSE); #endif } - else if (opt_secure_file_priv && - strncmp(opt_secure_file_priv, name, strlen(opt_secure_file_priv))) + else if (opt_secure_file_priv) { - /* Read only allowed from within dir specified by secure_file_priv */ - my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--secure-file-priv"); - DBUG_RETURN(TRUE); + char secure_file_real_path[FN_REFLEN]; + (void) my_realpath(secure_file_real_path, opt_secure_file_priv, 0); + if (strncmp(secure_file_real_path, name, strlen(secure_file_real_path))) + { + /* Read only allowed from within dir specified by secure_file_priv */ + my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--secure-file-priv"); + DBUG_RETURN(TRUE); + } } } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 0c3ccf0af85..c2199ce6ec7 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1,4 +1,4 @@ -/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc. +/* Copyright 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. 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 @@ -452,7 +452,7 @@ static void handle_bootstrap_impl(THD *thd) query= (char *) thd->memdup_w_gap(buff, length + 1, thd->db_length + 1 + QUERY_CACHE_FLAGS_SIZE); - thd->set_query(query, length); + thd->set_query_and_id(query, length, next_query_id()); DBUG_PRINT("query",("%-.4096s",thd->query())); #if defined(ENABLED_PROFILING) thd->profiling.start_new_query(); @@ -463,7 +463,6 @@ static void handle_bootstrap_impl(THD *thd) We don't need to obtain LOCK_thread_count here because in bootstrap mode we have only one thread. */ - thd->query_id=next_query_id(); thd->set_time(); mysql_parse(thd, thd->query(), length, & found_semicolon); close_thread_tables(thd); // Free tables @@ -811,12 +810,10 @@ bool dispatch_command(enum enum_server_command command, THD *thd, thd->enable_slow_log= TRUE; thd->lex->sql_command= SQLCOM_END; /* to avoid confusing VIEW detectors */ thd->set_time(); - pthread_mutex_lock(&LOCK_thread_count); - thd->query_id= global_query_id; + thd->set_query_id(get_query_id()); if (!(server_command_flags[command] & CF_SKIP_QUERY_ID)) next_query_id(); - thread_running++; - pthread_mutex_unlock(&LOCK_thread_count); + inc_thread_running(); if (!(server_command_flags[command] & CF_SKIP_QUESTIONS)) statistic_increment(thd->status_var.questions, &LOCK_status); @@ -1047,16 +1044,13 @@ bool dispatch_command(enum enum_server_command command, THD *thd, thd->security_ctx->priv_user, (char *) thd->security_ctx->host_or_ip); - thd->set_query(beginning_of_next_stmt, length); - pthread_mutex_lock(&LOCK_thread_count); + thd->set_query_and_id(beginning_of_next_stmt, length, next_query_id()); /* Count each statement from the client. */ statistic_increment(thd->status_var.questions, &LOCK_status); - thd->query_id= next_query_id(); thd->set_time(); /* Reset the query start time. */ /* TODO: set thd->lex->sql_command to SQLCOM_END here */ - pthread_mutex_unlock(&LOCK_thread_count); mysql_parse(thd, beginning_of_next_stmt, length, &end_of_stmt); } @@ -1380,9 +1374,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, thd_proc_info(thd, "cleaning up"); thd->set_query(NULL, 0); thd->command=COM_SLEEP; - pthread_mutex_lock(&LOCK_thread_count); // For process list - thread_running--; - pthread_mutex_unlock(&LOCK_thread_count); + dec_thread_running(); thd_proc_info(thd, 0); thd->packet.shrink(thd->variables.net_buffer_length); // Reclaim some memory free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC)); @@ -2003,11 +1995,11 @@ mysql_execute_command(THD *thd) restore status variables, as we don't want 'show status' to cause changes */ - pthread_mutex_lock(&LOCK_status); + mysql_mutex_lock(&LOCK_status); add_diff_to_status(&global_status_var, &thd->status_var, &old_status_var); thd->status_var= old_status_var; - pthread_mutex_unlock(&LOCK_status); + mysql_mutex_unlock(&LOCK_status); break; } case SQLCOM_SHOW_DATABASES: @@ -7293,6 +7285,9 @@ void get_default_definer(THD *thd, LEX_USER *definer) definer->host.str= (char *) sctx->priv_host; definer->host.length= strlen(definer->host.str); + + definer->password.str= NULL; + definer->password.length= 0; } @@ -7344,6 +7339,8 @@ LEX_USER *create_definer(THD *thd, LEX_STRING *user_name, LEX_STRING *host_name) definer->user= *user_name; definer->host= *host_name; + definer->password.str= NULL; + definer->password.length= 0; return definer; } diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 90fdbb45024..e75a9389f9f 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -239,26 +239,27 @@ bool partition_default_handling(TABLE *table, partition_info *part_info, { DBUG_ENTER("partition_default_handling"); - if (part_info->use_default_num_partitions) + if (!is_create_table_ind) { - if (!is_create_table_ind && - table->file->get_no_parts(normalized_path, &part_info->num_parts)) + if (part_info->use_default_num_partitions) { - DBUG_RETURN(TRUE); + if (table->file->get_no_parts(normalized_path, &part_info->num_parts)) + { + DBUG_RETURN(TRUE); + } } - } - else if (part_info->is_sub_partitioned() && - part_info->use_default_num_subpartitions) - { - uint num_parts; - if (!is_create_table_ind && - (table->file->get_no_parts(normalized_path, &num_parts))) + else if (part_info->is_sub_partitioned() && + part_info->use_default_num_subpartitions) { - DBUG_RETURN(TRUE); + uint num_parts; + if (table->file->get_no_parts(normalized_path, &num_parts)) + { + DBUG_RETURN(TRUE); + } + DBUG_ASSERT(part_info->num_parts > 0); + DBUG_ASSERT((num_parts % part_info->num_parts) == 0); + part_info->num_subparts= num_parts / part_info->num_parts; } - DBUG_ASSERT(part_info->num_parts > 0); - part_info->num_subparts= num_parts / part_info->num_parts; - DBUG_ASSERT((num_parts % part_info->num_parts) == 0); } part_info->set_up_defaults_for_partitioning(table->file, (ulonglong)0, (uint)0); @@ -1057,6 +1058,8 @@ static bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table, const char *save_where; LEX *old_lex= thd->lex; LEX lex; + uint8 saved_full_group_by_flag; + nesting_map saved_allow_sum_func; DBUG_ENTER("fix_fields_part_func"); if (init_lex_with_single_table(thd, table, &lex)) @@ -1082,8 +1085,19 @@ static bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table, This is a tricky call to prepare for since it can have a large number of interesting side effects, both desirable and undesirable. */ + saved_full_group_by_flag= thd->lex->current_select->full_group_by_flag; + saved_allow_sum_func= thd->lex->allow_sum_func; + thd->lex->allow_sum_func= 0; + error= func_expr->fix_fields(thd, (Item**)&func_expr); + /* + Restore full_group_by_flag and allow_sum_func, + fix_fields should not affect mysql_select later, see Bug#46923. + */ + thd->lex->current_select->full_group_by_flag= saved_full_group_by_flag; + thd->lex->allow_sum_func= saved_allow_sum_func; + if (unlikely(error)) { DBUG_PRINT("info", ("Field in partition function not part of table")); @@ -1794,8 +1808,8 @@ bool fix_partition_func(THD *thd, TABLE *table, if (((part_info->part_type != HASH_PARTITION || part_info->list_of_part_fields == FALSE) && (!part_info->column_list && - check_part_func_fields(part_info->part_field_array, TRUE))) || - (part_info->list_of_part_fields == FALSE && + check_part_func_fields(part_info->part_field_array, TRUE))) || + (part_info->list_of_subpart_fields == FALSE && part_info->is_sub_partitioned() && check_part_func_fields(part_info->subpart_field_array, TRUE))) { @@ -6241,7 +6255,7 @@ static int alter_close_tables(ALTER_PARTITION_PARAM_TYPE *lpt) We must keep LOCK_open while manipulating with thd->open_tables. Another thread may be working on it. */ - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); /* We can safely remove locks for all tables with the same name: later they will all be closed anyway in @@ -6266,7 +6280,7 @@ static int alter_close_tables(ALTER_PARTITION_PARAM_TYPE *lpt) table->s->table_name.str); } } - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); DBUG_RETURN(0); } diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index c5449a1dde4..28fd3581829 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -1368,10 +1368,10 @@ static void plugin_load(MEM_ROOT *tmp_root, int *argc, char **argv) When building an embedded library, if the mysql.plugin table does not exist, we silently ignore the missing table */ - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); if (check_if_table_exists(new_thd, &tables, &table_exists)) table_exists= FALSE; - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); if (!table_exists) goto end; #endif /* EMBEDDED_LIBRARY */ diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc index 50cd361b174..cf6ab684ead 100644 --- a/sql/sql_rename.cc +++ b/sql/sql_rename.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2000-2006 MySQL AB +/* Copyright (C) 2000-2006 MySQL AB, 2008-2009 Sun Microsystems, Inc 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 @@ -136,7 +136,7 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent) if (lock_table_names(thd, table_list)) goto err; - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); for (ren_table= table_list; ren_table; ren_table= ren_table->next_local) tdc_remove_table(thd, TDC_RT_REMOVE_ALL, ren_table->db, @@ -174,7 +174,7 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent) higher concurrency - query_cache_invalidate can take minutes to complete. */ - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); /* Lets hope this doesn't fail as the result will be messy */ if (!silent && !error) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index d51f72da9bf..3201dde9f1f 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -986,14 +986,20 @@ JOIN::optimize() DBUG_RETURN(1); } - if (select_lex->olap == ROLLUP_TYPE && rollup_process_const_fields()) + if (rollup.state != ROLLUP::STATE_NONE) { - DBUG_PRINT("error", ("Error: rollup_process_fields() failed")); - DBUG_RETURN(1); + if (rollup_process_const_fields()) + { + DBUG_PRINT("error", ("Error: rollup_process_fields() failed")); + DBUG_RETURN(1); + } + } + else + { + /* Remove distinct if only const tables */ + select_distinct= select_distinct && (const_tables != tables); } - /* Remove distinct if only const tables */ - select_distinct= select_distinct && (const_tables != tables); thd_proc_info(thd, "preparing"); if (result->initialize_tables(this)) { @@ -1300,11 +1306,14 @@ JOIN::optimize() - We are using an ORDER BY or GROUP BY on fields not in the first table - We are using different ORDER BY and GROUP BY orders - The user wants us to buffer the result. + When the WITH ROLLUP modifier is present, we cannot skip temporary table + creation for the DISTINCT clause just because there are only const tables. */ - need_tmp= (const_tables != tables && + need_tmp= ((const_tables != tables && ((select_distinct || !simple_order || !simple_group) || (group_list && order) || - test(select_options & OPTION_BUFFER_RESULT))); + test(select_options & OPTION_BUFFER_RESULT))) || + (rollup.state != ROLLUP::STATE_NONE && select_distinct)); // No cache for MATCH make_join_readinfo(this, @@ -2150,17 +2159,13 @@ JOIN::exec() DBUG_VOID_RETURN; if (!curr_table->select->cond) curr_table->select->cond= sort_table_cond; - else // This should never happen + else { if (!(curr_table->select->cond= new Item_cond_and(curr_table->select->cond, sort_table_cond))) DBUG_VOID_RETURN; - /* - Item_cond_and do not need fix_fields for execution, its parameters - are fixed or do not need fix_fields, too - */ - curr_table->select->cond->quick_fix_field(); + curr_table->select->cond->fix_fields(thd, 0); } curr_table->select_cond= curr_table->select->cond; curr_table->select_cond->top_level_item(); @@ -6590,6 +6595,56 @@ void rr_unlock_row(st_join_table *tab) +/** + Pick the appropriate access method functions + + Sets the functions for the selected table access method + + @param tab Table reference to put access method +*/ + +static void +pick_table_access_method(JOIN_TAB *tab) +{ + switch (tab->type) + { + case JT_REF: + tab->read_first_record= join_read_always_key; + tab->read_record.read_record= join_read_next_same; + break; + + case JT_REF_OR_NULL: + tab->read_first_record= join_read_always_key_or_null; + tab->read_record.read_record= join_read_next_same_or_null; + break; + + case JT_CONST: + tab->read_first_record= join_read_const; + tab->read_record.read_record= join_no_more_records; + break; + + case JT_EQ_REF: + tab->read_first_record= join_read_key; + tab->read_record.read_record= join_no_more_records; + break; + + case JT_FT: + tab->read_first_record= join_ft_read_first; + tab->read_record.read_record= join_ft_read_next; + break; + + case JT_SYSTEM: + tab->read_first_record= join_read_system; + tab->read_record.read_record= join_no_more_records; + break; + + /* keep gcc happy */ + default: + break; + } +} + + static void make_join_readinfo(JOIN *join, ulonglong options) { @@ -6624,45 +6679,15 @@ make_join_readinfo(JOIN *join, ulonglong options) tab->sorted= sorted; sorted= 0; // only first must be sorted + table->status=STATUS_NO_RECORD; + pick_table_access_method (tab); + switch (tab->type) { - case JT_SYSTEM: // Only happens with left join - table->status=STATUS_NO_RECORD; - tab->read_first_record= join_read_system; - tab->read_record.read_record= join_no_more_records; - break; - case JT_CONST: // Only happens with left join - table->status=STATUS_NO_RECORD; - tab->read_first_record= join_read_const; - tab->read_record.read_record= join_no_more_records; - if (table->covering_keys.is_set(tab->ref.key) && - !table->no_keyread) - { - table->key_read=1; - table->file->extra(HA_EXTRA_KEYREAD); - } - break; case JT_EQ_REF: - table->status=STATUS_NO_RECORD; - if (tab->select) - { - delete tab->select->quick; - tab->select->quick=0; - } - delete tab->quick; - tab->quick=0; - tab->read_first_record= join_read_key; tab->read_record.unlock_row= join_read_key_unlock_row; - tab->read_record.read_record= join_no_more_records; - if (table->covering_keys.is_set(tab->ref.key) && - !table->no_keyread) - { - table->key_read=1; - table->file->extra(HA_EXTRA_KEYREAD); - } - break; + /* fall through */ case JT_REF_OR_NULL: case JT_REF: - table->status=STATUS_NO_RECORD; if (tab->select) { delete tab->select->quick; @@ -6670,34 +6695,20 @@ make_join_readinfo(JOIN *join, ulonglong options) } delete tab->quick; tab->quick=0; + /* fall through */ + case JT_CONST: // Only happens with left join if (table->covering_keys.is_set(tab->ref.key) && !table->no_keyread) { table->key_read=1; table->file->extra(HA_EXTRA_KEYREAD); } - if (tab->type == JT_REF) - { - tab->read_first_record= join_read_always_key; - tab->read_record.read_record= join_read_next_same; - } - else - { - tab->read_first_record= join_read_always_key_or_null; - tab->read_record.read_record= join_read_next_same_or_null; - } - break; - case JT_FT: - table->status=STATUS_NO_RECORD; - tab->read_first_record= join_ft_read_first; - tab->read_record.read_record= join_ft_read_next; break; case JT_ALL: /* If previous table use cache If the incoming data set is already sorted don't use cache. */ - table->status=STATUS_NO_RECORD; if (i != join->const_tables && !(options & SELECT_NO_JOIN_CACHE) && tab->use_quick != 2 && !tab->first_inner && !ordered_set) { @@ -6777,6 +6788,9 @@ make_join_readinfo(JOIN *join, ulonglong options) } } break; + case JT_FT: + case JT_SYSTEM: + break; default: DBUG_PRINT("error",("Table type %d found",tab->type)); /* purecov: deadcode */ break; /* purecov: deadcode */ @@ -7927,12 +7941,12 @@ static COND *build_equal_items_for_cond(THD *thd, COND *cond, { item_equal->fix_length_and_dec(); item_equal->update_used_tables(); + set_if_bigger(thd->lex->current_select->max_equal_elems, + item_equal->members()); + return item_equal; } - else - item_equal= (Item_equal *) eq_list.pop(); - set_if_bigger(thd->lex->current_select->max_equal_elems, - item_equal->members()); - return item_equal; + + return eq_list.pop(); } else { @@ -9615,47 +9629,8 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table, new_field->set_derivation(item->collation.derivation); break; case DECIMAL_RESULT: - { - uint8 dec= item->decimals; - uint8 intg= ((Item_decimal *) item)->decimal_precision() - dec; - uint32 len= item->max_length; - - /* - Trying to put too many digits overall in a DECIMAL(prec,dec) - will always throw a warning. We must limit dec to - DECIMAL_MAX_SCALE however to prevent an assert() later. - */ - - if (dec > 0) - { - signed int overflow; - - dec= min(dec, DECIMAL_MAX_SCALE); - - /* - If the value still overflows the field with the corrected dec, - we'll throw out decimals rather than integers. This is still - bad and of course throws a truncation warning. - +1: for decimal point - */ - - const int required_length= - my_decimal_precision_to_length(intg + dec, dec, - item->unsigned_flag); - - overflow= required_length - len; - - if (overflow > 0) - dec= max(0, dec - overflow); // too long, discard fract - else - /* Corrected value fits. */ - len= required_length; - } - - new_field= new Field_new_decimal(len, maybe_null, item->name, - dec, item->unsigned_flag); + new_field= Field_new_decimal::create_from_item(item); break; - } case ROW_RESULT: default: // This case should never be choosen @@ -13362,6 +13337,8 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, if (create_ref_for_key(tab->join, tab, keyuse, tab->join->const_table_map)) DBUG_RETURN(0); + + pick_table_access_method(tab); } else { @@ -14167,7 +14144,10 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table, goto err; } else - (void) my_hash_insert(&hash, org_key_pos); + { + if (my_hash_insert(&hash, org_key_pos)) + goto err; + } key_pos+=extra_length; } my_free((char*) key_buffer,MYF(0)); diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 9a4ce112ffe..349e9948eb8 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1,4 +1,4 @@ -/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc. +/* Copyright 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. 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 @@ -1759,11 +1759,11 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) thd_info->db=thd->strdup(thd_info->db); thd_info->command=(int) tmp->command; if ((mysys_var= tmp->mysys_var)) - pthread_mutex_lock(&mysys_var->mutex); + mysql_mutex_lock(&mysys_var->mutex); thd_info->proc_info= (char*) (tmp->killed == THD::KILL_CONNECTION? "Killed" : 0); thd_info->state_info= thread_state_info(tmp); if (mysys_var) - pthread_mutex_unlock(&mysys_var->mutex); + mysql_mutex_unlock(&mysys_var->mutex); thd_info->start_time= tmp->start_time; thd_info->query=0; @@ -1862,7 +1862,7 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond) } if ((mysys_var= tmp->mysys_var)) - pthread_mutex_lock(&mysys_var->mutex); + mysql_mutex_lock(&mysys_var->mutex); /* COMMAND */ if ((val= (char *) (tmp->killed == THD::KILL_CONNECTION? "Killed" : 0))) table->field[4]->store(val, strlen(val), cs); @@ -1880,7 +1880,7 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond) } if (mysys_var) - pthread_mutex_unlock(&mysys_var->mutex); + mysql_mutex_unlock(&mysys_var->mutex); /* INFO */ if (tmp->query()) @@ -1958,7 +1958,7 @@ int add_status_vars(SHOW_VAR *list) { int res= 0; if (status_vars_inited) - pthread_mutex_lock(&LOCK_status); + mysql_mutex_lock(&LOCK_status); if (!all_status_vars.buffer && // array is not allocated yet - do it now my_init_dynamic_array(&all_status_vars, sizeof(SHOW_VAR), 200, 20)) { @@ -1973,7 +1973,7 @@ int add_status_vars(SHOW_VAR *list) sort_dynamic(&all_status_vars, show_var_cmp); err: if (status_vars_inited) - pthread_mutex_unlock(&LOCK_status); + mysql_mutex_unlock(&LOCK_status); return res; } @@ -2035,7 +2035,7 @@ void remove_status_vars(SHOW_VAR *list) { if (status_vars_inited) { - pthread_mutex_lock(&LOCK_status); + mysql_mutex_lock(&LOCK_status); SHOW_VAR *all= dynamic_element(&all_status_vars, 0, SHOW_VAR *); int a= 0, b= all_status_vars.elements, c= (a+b)/2; @@ -2056,7 +2056,7 @@ void remove_status_vars(SHOW_VAR *list) all[c].type= SHOW_UNDEF; } shrink_var_array(&all_status_vars); - pthread_mutex_unlock(&LOCK_status); + mysql_mutex_unlock(&LOCK_status); } else { @@ -3187,7 +3187,7 @@ static int fill_schema_table_from_frm(THD *thd,TABLE *table, } key_length= create_table_def_key(thd, key, &table_list, 0); - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); share= get_table_share(thd, &table_list, key, key_length, OPEN_VIEW, ¬_used); if (!share) @@ -3234,7 +3234,7 @@ end_share: release_table_share(share); end_unlock: - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); /* Don't release the MDL lock, it can be part of a transaction. If it is not, it will be released by the call to @@ -5632,14 +5632,14 @@ int fill_status(THD *thd, TABLE_LIST *tables, COND *cond) tmp1= &thd->status_var; } - pthread_mutex_lock(&LOCK_status); + mysql_mutex_lock(&LOCK_status); if (option_type == OPT_GLOBAL) calc_sum_of_all_status(&tmp); res= show_status_array(thd, wild, (SHOW_VAR *)all_status_vars.buffer, option_type, tmp1, "", tables->table, upper_case_names, cond); - pthread_mutex_unlock(&LOCK_status); + mysql_mutex_unlock(&LOCK_status); DBUG_RETURN(res); } @@ -7321,7 +7321,7 @@ TABLE_LIST *get_trigger_table(THD *thd, const sp_name *trg_name) { /* Acquire LOCK_open (stop the server). */ - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); /* Load base table name from the TRN-file and create TABLE_LIST object. @@ -7331,7 +7331,7 @@ TABLE_LIST *get_trigger_table(THD *thd, const sp_name *trg_name) /* Release LOCK_open (continue the server). */ - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); /* That's it. */ diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 971a1d79363..7f369507237 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1,4 +1,4 @@ -/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc. +/* Copyright 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. 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 @@ -1656,7 +1656,7 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) completing this we write a new phase to the log entry that will deactivate it. */ - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); if (my_delete(frm_name, MYF(MY_WME)) || #ifdef WITH_PARTITION_STORAGE_ENGINE lpt->table->file->ha_create_handler_files(path, shadow_path, @@ -1709,7 +1709,7 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) #endif err: - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); #ifdef WITH_PARTITION_STORAGE_ENGINE deactivate_ddl_log_entry(part_info->frm_log_entry->entry_pos); part_info->frm_log_entry= NULL; @@ -1872,7 +1872,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, .frm file to find if the table is a normal table (not view) and what engine to use. */ - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); for (table= tables; table; table= table->next_local) { TABLE_SHARE *share; @@ -1885,12 +1885,12 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, check_if_log_table(table->db_length, table->db, table->table_name_length, table->table_name, 1)) { - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); my_error(ER_BAD_LOG_STATEMENT, MYF(0), "DROP"); DBUG_RETURN(1); } } - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); if (!drop_temporary) { @@ -1898,10 +1898,10 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, { if (lock_table_names(thd, tables)) DBUG_RETURN(1); - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); for (table= tables; table; table= table->next_local) tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table->db, table->table_name); - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); } else { @@ -2043,7 +2043,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, TODO: Investigate what should be done to remove this lock completely. Is exclusive meta-data lock enough ? */ - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); if (drop_temporary || ((table_type == NULL && access(path, F_OK) && @@ -2096,7 +2096,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, error|= new_error; } } - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); if (error) { if (wrong_tables.length()) @@ -3948,7 +3948,7 @@ bool mysql_create_table_no_lock(THD *thd, goto err; } - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); if (!internal_tmp_table && !(create_info->options & HA_LEX_CREATE_TMP_TABLE)) { if (!access(path,F_OK)) @@ -4092,7 +4092,7 @@ bool mysql_create_table_no_lock(THD *thd, error= FALSE; unlock_and_end: - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); err: thd_proc_info(thd, "After create"); @@ -4122,22 +4122,22 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table, DBUG_ENTER("mysql_create_table"); /* Wait for any database locks */ - pthread_mutex_lock(&LOCK_lock_db); + mysql_mutex_lock(&LOCK_lock_db); while (!thd->killed && my_hash_search(&lock_db_cache, (uchar*)create_table->db, create_table->db_length)) { wait_for_condition(thd, &LOCK_lock_db, &COND_refresh); - pthread_mutex_lock(&LOCK_lock_db); + mysql_mutex_lock(&LOCK_lock_db); } if (thd->killed) { - pthread_mutex_unlock(&LOCK_lock_db); + mysql_mutex_unlock(&LOCK_lock_db); DBUG_RETURN(TRUE); } creating_table++; - pthread_mutex_unlock(&LOCK_lock_db); + mysql_mutex_unlock(&LOCK_lock_db); /* Open or obtain an exclusive metadata lock on table being created. @@ -4180,10 +4180,10 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table, } unlock: - pthread_mutex_lock(&LOCK_lock_db); + mysql_mutex_lock(&LOCK_lock_db); if (!--creating_table && creating_database) - pthread_cond_signal(&COND_refresh); - pthread_mutex_unlock(&LOCK_lock_db); + mysql_cond_signal(&COND_refresh); + mysql_mutex_unlock(&LOCK_lock_db); DBUG_RETURN(result); } @@ -4384,21 +4384,21 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list, DBUG_RETURN(0); has_mdl_lock= TRUE; - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); if (!(share= (get_table_share(thd, table_list, key, key_length, 0, &error)))) { - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); DBUG_RETURN(0); // Can't open frm file } if (open_table_from_share(thd, share, "", 0, 0, 0, &tmp_table, FALSE)) { release_table_share(share); - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); DBUG_RETURN(0); // Out of memory } - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); table= &tmp_table; } @@ -4505,9 +4505,9 @@ end: thd->locked_tables_list.unlink_all_closed_tables(thd, NULL, 0); if (table == &tmp_table) { - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); closefrm(table, 1); // Free allocated memory - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); } /* In case of a temporary table there will be no metadata lock. */ if (error && has_mdl_lock) @@ -5324,14 +5324,14 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table, write_bin_log(thd, TRUE, query.ptr(), query.length()); DBUG_ASSERT(thd->open_tables == table->table); - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); /* When opening the table, we ignored the locked tables (MYSQL_OPEN_GET_NEW_TABLE). Now we can close the table without risking to close some locked table. */ close_thread_table(thd, &thd->open_tables); - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); } else // Case 1 write_bin_log(thd, TRUE, thd->query(), thd->query_length()); @@ -6467,7 +6467,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, goto view_err; } - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); if (!do_rename(thd, table_list, new_db, new_name, new_name, 1)) { @@ -6480,7 +6480,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, } my_ok(thd); } - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); unlock_table_names(thd); @@ -6727,7 +6727,7 @@ view_err: else { *fn_ext(new_name)=0; - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); if (mysql_rename_table(old_db_type,db,table_name,new_db,new_alias, 0)) error= -1; else if (Table_triggers_list::change_table_name(thd, db, table_name, @@ -6737,7 +6737,7 @@ view_err: table_name, 0); error= -1; } - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); } } @@ -7330,7 +7330,7 @@ view_err: /* This type cannot happen in regular ALTER. */ new_db_type= old_db_type= NULL; } - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); if (mysql_rename_table(old_db_type, db, table_name, db, old_name, FN_TO_IS_TMP)) { @@ -7357,7 +7357,7 @@ view_err: if (! error) (void) quick_rm_table(old_db_type, db, old_name, FN_IS_TMP); - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); if (error) { @@ -7404,9 +7404,9 @@ view_err: create_info); DBUG_ASSERT(thd->open_tables == t_table); - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); close_thread_table(thd, &thd->open_tables); - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); table_list->table= 0; if (error) diff --git a/sql/sql_test.cc b/sql/sql_test.cc index 72b6e483d35..2d9d2cfae4d 100644 --- a/sql/sql_test.cc +++ b/sql/sql_test.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2000-2006 MySQL AB +/* Copyright (C) 2000-2006 MySQL AB, 2008-2009 Sun Microsystems, Inc 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 @@ -80,7 +80,7 @@ void print_cached_tables(void) compile_time_assert(TL_WRITE_ONLY+1 == array_elements(lock_descriptions)); /* purecov: begin tested */ - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); puts("DB Table Version Thread Open Lock"); for (idx=unused=0 ; idx < table_def_cache.records ; idx++) @@ -127,7 +127,7 @@ void print_cached_tables(void) if (my_hash_check(&table_def_cache)) printf("Error: Table definition hash table is corrupted\n"); fflush(stdout); - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); /* purecov: end */ return; } @@ -392,12 +392,12 @@ static void display_table_locks(void) DYNAMIC_ARRAY saved_table_locks; (void) my_init_dynamic_array(&saved_table_locks,sizeof(TABLE_LOCK_INFO), table_cache_count + 20,50); - pthread_mutex_lock(&THR_LOCK_lock); + mysql_mutex_lock(&THR_LOCK_lock); for (list= thr_lock_thread_list; list; list= list_rest(list)) { THR_LOCK *lock=(THR_LOCK*) list->data; - pthread_mutex_lock(&lock->mutex); + mysql_mutex_lock(&lock->mutex); push_locks_into_array(&saved_table_locks, lock->write.data, FALSE, "Locked - write"); push_locks_into_array(&saved_table_locks, lock->write_wait.data, TRUE, @@ -406,9 +406,9 @@ static void display_table_locks(void) "Locked - read"); push_locks_into_array(&saved_table_locks, lock->read_wait.data, TRUE, "Waiting - read"); - pthread_mutex_unlock(&lock->mutex); + mysql_mutex_unlock(&lock->mutex); } - pthread_mutex_unlock(&THR_LOCK_lock); + mysql_mutex_unlock(&THR_LOCK_lock); if (!saved_table_locks.elements) goto end; qsort((uchar*) dynamic_element(&saved_table_locks,0,TABLE_LOCK_INFO *),saved_table_locks.elements,sizeof(TABLE_LOCK_INFO),(qsort_cmp) dl_compare); @@ -484,7 +484,7 @@ void mysql_print_status() /* Print key cache status */ puts("\nKey caches:"); process_key_caches(print_key_cache_status); - pthread_mutex_lock(&LOCK_status); + mysql_mutex_lock(&LOCK_status); printf("\nhandler status:\n\ read_key: %10lu\n\ read_next: %10lu\n\ @@ -500,7 +500,7 @@ update: %10lu\n", tmp.ha_write_count, tmp.ha_delete_count, tmp.ha_update_count); - pthread_mutex_unlock(&LOCK_status); + mysql_mutex_unlock(&LOCK_status); printf("\nTable status:\n\ Opened tables: %10lu\n\ Open tables: %10lu\n\ diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 12180d9447c..936265e6753 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2004-2005 MySQL AB +/* Copyright (C) 2004-2005 MySQL AB, 2008-2009 Sun Microsystems, Inc 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 @@ -491,11 +491,11 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) goto end; } - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); result= (create ? table->triggers->create_trigger(thd, tables, &stmt_query): table->triggers->drop_trigger(thd, tables, &stmt_query)); - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); if (result) goto end; @@ -1891,7 +1891,7 @@ bool Table_triggers_list::change_table_name(THD *thd, const char *db, #ifndef DBUG_OFF if (thd->mdl_context.is_lock_owner(MDL_key::TABLE, db, old_table, MDL_EXCLUSIVE)) - safe_mutex_assert_owner(&LOCK_open); + mysql_mutex_assert_owner(&LOCK_open); #endif DBUG_ASSERT(my_strcasecmp(table_alias_charset, db, new_db) || diff --git a/sql/sql_view.cc b/sql/sql_view.cc index c9b6a926649..bb2cde1f81c 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2004 MySQL AB +/* Copyright (C) 2004 MySQL AB, 2008-2009 Sun Microsystems, Inc This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -620,7 +620,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, goto err; } - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); res= mysql_register_view(thd, view, mode); if (mysql_bin_log.is_open()) @@ -666,7 +666,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, buff.ptr(), buff.length(), FALSE, FALSE, errcode); } - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); if (mode != VIEW_CREATE_NEW) query_cache_invalidate3(thd, view, 0); thd->global_read_lock.start_waiting_global_read_lock(thd); @@ -1609,7 +1609,7 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode) if (lock_table_names(thd, views)) DBUG_RETURN(TRUE); - pthread_mutex_lock(&LOCK_open); + mysql_mutex_lock(&LOCK_open); for (view= views; view; view= view->next_local) { TABLE_SHARE *share; @@ -1684,7 +1684,7 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode) write_bin_log(thd, !something_wrong, thd->query(), thd->query_length()); } - pthread_mutex_unlock(&LOCK_open); + mysql_mutex_unlock(&LOCK_open); if (something_wrong) { diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 886f961a515..6d946e42262 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -391,6 +391,138 @@ void case_stmt_action_end_case(LEX *lex, bool simple) lex->sphead->do_cont_backpatch(); } + +static bool +find_sys_var_null_base(THD *thd, struct sys_var_with_base *tmp) +{ + tmp->var= find_sys_var(thd, tmp->base_name.str, tmp->base_name.length); + + if (tmp->var == NULL) + my_error(ER_UNKNOWN_SYSTEM_VARIABLE, MYF(0), tmp->base_name.str); + else + tmp->base_name= null_lex_str; + + return thd->is_error(); +} + + +/** + Helper action for a SET statement. + Used to push a system variable into the assignment list. + + @param thd the current thread + @param tmp the system variable with base name + @param var_type the scope of the variable + @param val the value being assigned to the variable + + @return TRUE if error, FALSE otherwise. +*/ + +static bool +set_system_variable(THD *thd, struct sys_var_with_base *tmp, + enum enum_var_type var_type, Item *val) +{ + set_var *var; + LEX *lex= thd->lex; + + /* No AUTOCOMMIT from a stored function or trigger. */ + if (lex->spcont && tmp->var == &sys_autocommit) + lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT; + + if (! (var= new set_var(var_type, tmp->var, &tmp->base_name, val))) + return TRUE; + + return lex->var_list.push_back(var); +} + + +/** + Helper action for a SET statement. + Used to push a SP local variable into the assignment list. + + @param thd the current thread + @param var_type the SP local variable + @param val the value being assigned to the variable + + @return TRUE if error, FALSE otherwise. +*/ + +static bool +set_local_variable(THD *thd, sp_variable_t *spv, Item *val) +{ + Item *it; + LEX *lex= thd->lex; + sp_instr_set *sp_set; + + if (val) + it= val; + else if (spv->dflt) + it= spv->dflt; + else + { + it= new (thd->mem_root) Item_null(); + if (it == NULL) + return TRUE; + } + + sp_set= new sp_instr_set(lex->sphead->instructions(), lex->spcont, + spv->offset, it, spv->type, lex, TRUE); + + return (sp_set == NULL || lex->sphead->add_instr(sp_set)); +} + + +/** + Helper action for a SET statement. + Used to SET a field of NEW row. + + @param thd the current thread + @param name the field name + @param val the value being assigned to the row + + @return TRUE if error, FALSE otherwise. +*/ + +static bool +set_trigger_new_row(THD *thd, LEX_STRING *name, Item *val) +{ + LEX *lex= thd->lex; + Item_trigger_field *trg_fld; + sp_instr_set_trigger_field *sp_fld; + + /* QQ: Shouldn't this be field's default value ? */ + if (! val) + val= new Item_null(); + + DBUG_ASSERT(lex->trg_chistics.action_time == TRG_ACTION_BEFORE && + (lex->trg_chistics.event == TRG_EVENT_INSERT || + lex->trg_chistics.event == TRG_EVENT_UPDATE)); + + trg_fld= new (thd->mem_root) + Item_trigger_field(lex->current_context(), + Item_trigger_field::NEW_ROW, + name->str, UPDATE_ACL, FALSE); + + if (trg_fld == NULL) + return TRUE; + + sp_fld= new sp_instr_set_trigger_field(lex->sphead->instructions(), + lex->spcont, trg_fld, val, lex); + + if (sp_fld == NULL) + return TRUE; + + /* + Let us add this item to list of all Item_trigger_field + objects in trigger. + */ + lex->trg_table_fields.link_in_list((uchar *) trg_fld, + (uchar **) &trg_fld->next_trg_field); + + return lex->sphead->add_instr(sp_fld); +} + + /** Helper to resolve the SQL:2003 Syntax exception 1) in <in predicate>. See SQL:2003, Part 2, section 8.4 <in predicate>, Note 184, page 383. @@ -2511,8 +2643,8 @@ sp_decl: } pctx->declare_var_boundary(0); - lex->sphead->restore_lex(YYTHD); - + if (lex->sphead->restore_lex(YYTHD)) + MYSQL_YYABORT; $$.vars= $2; $$.conds= $$.hndlrs= $$.curs= 0; } @@ -2622,7 +2754,8 @@ sp_cursor_stmt: } lex->sp_lex_in_use= TRUE; $$= lex; - lex->sphead->restore_lex(YYTHD); + if (lex->sphead->restore_lex(YYTHD)) + MYSQL_YYABORT; } ; @@ -3004,7 +3137,8 @@ sp_proc_stmt_statement: sp->add_instr(i)) MYSQL_YYABORT; } - sp->restore_lex(thd); + if (sp->restore_lex(thd)) + MYSQL_YYABORT; } ; @@ -3032,7 +3166,8 @@ sp_proc_stmt_return: MYSQL_YYABORT; sp->m_flags|= sp_head::HAS_RETURN; } - sp->restore_lex(YYTHD); + if (sp->restore_lex(YYTHD)) + MYSQL_YYABORT; } ; @@ -3272,7 +3407,8 @@ sp_if: sp->add_cont_backpatch(i) || sp->add_instr(i)) MYSQL_YYABORT; - sp->restore_lex(YYTHD); + if (sp->restore_lex(YYTHD)) + MYSQL_YYABORT; } sp_proc_stmts1 { @@ -3318,7 +3454,9 @@ simple_case_stmt: if (case_stmt_action_expr(lex, $3)) MYSQL_YYABORT; - lex->sphead->restore_lex(YYTHD); /* For expr $3 */ + /* For expr $3 */ + if (lex->sphead->restore_lex(YYTHD)) + MYSQL_YYABORT; } simple_when_clause_list else_clause_opt @@ -3368,7 +3506,9 @@ simple_when_clause: LEX *lex= Lex; if (case_stmt_action_when(lex, $3, true)) MYSQL_YYABORT; - lex->sphead->restore_lex(YYTHD); /* For expr $3 */ + /* For expr $3 */ + if (lex->sphead->restore_lex(YYTHD)) + MYSQL_YYABORT; } THEN_SYM sp_proc_stmts1 @@ -3389,7 +3529,9 @@ searched_when_clause: LEX *lex= Lex; if (case_stmt_action_when(lex, $3, false)) MYSQL_YYABORT; - lex->sphead->restore_lex(YYTHD); /* For expr $3 */ + /* For expr $3 */ + if (lex->sphead->restore_lex(YYTHD)) + MYSQL_YYABORT; } THEN_SYM sp_proc_stmts1 @@ -3566,7 +3708,8 @@ sp_unlabeled_control: sp->new_cont_backpatch(i) || sp->add_instr(i)) MYSQL_YYABORT; - sp->restore_lex(YYTHD); + if (sp->restore_lex(YYTHD)) + MYSQL_YYABORT; } sp_proc_stmts1 END WHILE_SYM { @@ -3592,7 +3735,8 @@ sp_unlabeled_control: if (i == NULL || lex->sphead->add_instr(i)) MYSQL_YYABORT; - lex->sphead->restore_lex(YYTHD); + if (lex->sphead->restore_lex(YYTHD)) + MYSQL_YYABORT; /* We can shortcut the cont_backpatch here */ i->m_cont_dest= ip+1; } @@ -8027,6 +8171,14 @@ function_call_nonkeyword: } | SYSDATE optional_braces { + /* + Unlike other time-related functions, SYSDATE() is + replication-unsafe because it is not affected by the + TIMESTAMP variable. It is unsafe even if + sysdate_is_now=1, because the slave may have + sysdate_is_now=0. + */ + Lex->set_stmt_unsafe(); if (global_system_variables.sysdate_is_now == 0) $$= new (YYTHD->mem_root) Item_func_sysdate_local(); else @@ -12327,7 +12479,8 @@ option_type_value: if (sp->add_instr(i)) MYSQL_YYABORT; } - lex->sphead->restore_lex(thd); + if (lex->sphead->restore_lex(thd)) + MYSQL_YYABORT; } } ; @@ -12367,98 +12520,42 @@ sys_option_value: option_type internal_variable_name equal set_expr_or_default { THD *thd= YYTHD; - LEX *lex=Lex; + LEX *lex= Lex; + LEX_STRING *name= &$2.base_name; if ($2.var == trg_new_row_fake_var) { /* We are in trigger and assigning value to field of new row */ - Item *it; - Item_trigger_field *trg_fld; - sp_instr_set_trigger_field *sp_fld; - LINT_INIT(sp_fld); if ($1) { my_parse_error(ER(ER_SYNTAX_ERROR)); MYSQL_YYABORT; } - if ($4) - it= $4; - else - { - /* QQ: Shouldn't this be field's default value ? */ - it= new Item_null(); - } - - DBUG_ASSERT(lex->trg_chistics.action_time == TRG_ACTION_BEFORE && - (lex->trg_chistics.event == TRG_EVENT_INSERT || - lex->trg_chistics.event == TRG_EVENT_UPDATE)); - - trg_fld= new (thd->mem_root) - Item_trigger_field(Lex->current_context(), - Item_trigger_field::NEW_ROW, - $2.base_name.str, - UPDATE_ACL, FALSE); - if (trg_fld == NULL) - MYSQL_YYABORT; - - sp_fld= new sp_instr_set_trigger_field(lex->sphead-> - instructions(), - lex->spcont, - trg_fld, - it, lex); - if (sp_fld == NULL) - MYSQL_YYABORT; - - /* - Let us add this item to list of all Item_trigger_field - objects in trigger. - */ - lex->trg_table_fields.link_in_list((uchar *)trg_fld, - (uchar **) &trg_fld-> - next_trg_field); - - if (lex->sphead->add_instr(sp_fld)) + if (set_trigger_new_row(YYTHD, name, $4)) MYSQL_YYABORT; } else if ($2.var) - { /* System variable */ + { if ($1) lex->option_type= $1; - set_var *var= new set_var(lex->option_type, $2.var, - &$2.base_name, $4); - if (var == NULL) + + /* It is a system variable. */ + if (set_system_variable(thd, &$2, lex->option_type, $4)) MYSQL_YYABORT; - lex->var_list.push_back(var); } else { - /* An SP local variable */ - sp_pcontext *ctx= lex->spcont; - sp_variable_t *spv; - sp_instr_set *sp_set; - Item *it; + sp_pcontext *spc= lex->spcont; + sp_variable_t *spv= spc->find_variable(name); + if ($1) { my_parse_error(ER(ER_SYNTAX_ERROR)); MYSQL_YYABORT; } - spv= ctx->find_variable(&$2.base_name); - - if ($4) - it= $4; - else if (spv->dflt) - it= spv->dflt; - else - { - it= new (thd->mem_root) Item_null(); - if (it == NULL) - MYSQL_YYABORT; - } - sp_set= new sp_instr_set(lex->sphead->instructions(), ctx, - spv->offset, it, spv->type, lex, TRUE); - if (sp_set == NULL || - lex->sphead->add_instr(sp_set)) + /* It is a local variable. */ + if (set_local_variable(thd, spv, $4)) MYSQL_YYABORT; } } @@ -12494,11 +12591,16 @@ option_value: } | '@' '@' opt_var_ident_type internal_variable_name equal set_expr_or_default { - LEX *lex=Lex; - set_var *var= new set_var($3, $4.var, &$4.base_name, $6); - if (var == NULL) + THD *thd= YYTHD; + struct sys_var_with_base tmp= $4; + /* Lookup if necessary: must be a system variable. */ + if (tmp.var == NULL) + { + if (find_sys_var_null_base(thd, &tmp)) + MYSQL_YYABORT; + } + if (set_system_variable(thd, &tmp, $3, $6)) MYSQL_YYABORT; - lex->var_list.push_back(var); } | charset old_or_new_charset_name_or_default { @@ -12591,31 +12693,26 @@ internal_variable_name: ident { THD *thd= YYTHD; - LEX *lex= thd->lex; - sp_pcontext *spc= lex->spcont; + sp_pcontext *spc= thd->lex->spcont; sp_variable_t *spv; - /* We have to lookup here since local vars can shadow sysvars */ + /* Best effort lookup for system variable. */ if (!spc || !(spv = spc->find_variable(&$1))) { + struct sys_var_with_base tmp= {NULL, $1}; + /* Not an SP local variable */ - sys_var *tmp=find_sys_var(thd, $1.str, $1.length); - if (!tmp) + if (find_sys_var_null_base(thd, &tmp)) MYSQL_YYABORT; - $$.var= tmp; - $$.base_name= null_lex_str; - if (spc && tmp == &sys_autocommit) - { - /* - We don't allow setting AUTOCOMMIT from a stored function - or trigger. - */ - lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT; - } + + $$= tmp; } else { - /* An SP local variable */ + /* + Possibly an SP local variable (or a shadowed sysvar). + Will depend on the context of the SET statement. + */ $$.var= NULL; $$.base_name= $1; } diff --git a/sql/table.cc b/sql/table.cc index 2bd7a8cc7ec..18814a594ee 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -1309,8 +1309,16 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, share->timestamp_field_offset= i; if (use_hash) - (void) my_hash_insert(&share->name_hash, - (uchar*) field_ptr); // never fail + if (my_hash_insert(&share->name_hash, (uchar*) field_ptr) ) + { + /* + Set return code 8 here to indicate that an error has + occurred but that the error message already has been + sent (OOM). + */ + error= 8; + goto err; + } } *field_ptr=0; // End marker @@ -2796,34 +2804,38 @@ bool check_column_name(const char *name) and such errors never reach the user. */ -my_bool -table_check_intact(TABLE *table, const uint table_f_count, - const TABLE_FIELD_W_TYPE *table_def) +bool +Table_check_intact::check(TABLE *table, const TABLE_FIELD_DEF *table_def) { uint i; my_bool error= FALSE; - my_bool fields_diff_count; + const TABLE_FIELD_TYPE *field_def= table_def->field; DBUG_ENTER("table_check_intact"); DBUG_PRINT("info",("table: %s expected_count: %d", - table->alias, table_f_count)); + table->alias, table_def->count)); + + /* Whether the table definition has already been validated. */ + if (table->s->table_field_def_cache == table_def) + DBUG_RETURN(FALSE); - fields_diff_count= (table->s->fields != table_f_count); - if (fields_diff_count) + if (table->s->fields != table_def->count) { DBUG_PRINT("info", ("Column count has changed, checking the definition")); /* previous MySQL version */ if (MYSQL_VERSION_ID > table->s->mysql_version) { - sql_print_error(ER(ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE), - table->alias, table_f_count, table->s->fields, - table->s->mysql_version, MYSQL_VERSION_ID); + report_error(ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE, + ER(ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE), + table->alias, table_def->count, table->s->fields, + table->s->mysql_version, MYSQL_VERSION_ID); DBUG_RETURN(TRUE); } else if (MYSQL_VERSION_ID == table->s->mysql_version) { - sql_print_error(ER(ER_COL_COUNT_DOESNT_MATCH_CORRUPTED), table->alias, - table_f_count, table->s->fields); + report_error(ER_COL_COUNT_DOESNT_MATCH_CORRUPTED, + ER(ER_COL_COUNT_DOESNT_MATCH_CORRUPTED), table->alias, + table_def->count, table->s->fields); DBUG_RETURN(TRUE); } /* @@ -2835,7 +2847,7 @@ table_check_intact(TABLE *table, const uint table_f_count, */ } char buffer[STRING_BUFFER_USUAL_SIZE]; - for (i=0 ; i < table_f_count; i++, table_def++) + for (i=0 ; i < table_def->count; i++, field_def++) { String sql_type(buffer, sizeof(buffer), system_charset_info); sql_type.length(0); @@ -2843,18 +2855,18 @@ table_check_intact(TABLE *table, const uint table_f_count, { Field *field= table->field[i]; - if (strncmp(field->field_name, table_def->name.str, - table_def->name.length)) + if (strncmp(field->field_name, field_def->name.str, + field_def->name.length)) { /* Name changes are not fatal, we use ordinal numbers to access columns. Still this can be a sign of a tampered table, output an error to the error log. */ - sql_print_error("Incorrect definition of table %s.%s: " - "expected column '%s' at position %d, found '%s'.", - table->s->db.str, table->alias, table_def->name.str, i, - field->field_name); + report_error(0, "Incorrect definition of table %s.%s: " + "expected column '%s' at position %d, found '%s'.", + table->s->db.str, table->alias, field_def->name.str, i, + field->field_name); } field->sql_type(sql_type); /* @@ -2874,47 +2886,51 @@ table_check_intact(TABLE *table, const uint table_f_count, the new table definition is backward compatible with the original one. */ - if (strncmp(sql_type.c_ptr_safe(), table_def->type.str, - table_def->type.length - 1)) + if (strncmp(sql_type.c_ptr_safe(), field_def->type.str, + field_def->type.length - 1)) { - sql_print_error("Incorrect definition of table %s.%s: " - "expected column '%s' at position %d to have type " - "%s, found type %s.", table->s->db.str, table->alias, - table_def->name.str, i, table_def->type.str, - sql_type.c_ptr_safe()); + report_error(0, "Incorrect definition of table %s.%s: " + "expected column '%s' at position %d to have type " + "%s, found type %s.", table->s->db.str, table->alias, + field_def->name.str, i, field_def->type.str, + sql_type.c_ptr_safe()); error= TRUE; } - else if (table_def->cset.str && !field->has_charset()) + else if (field_def->cset.str && !field->has_charset()) { - sql_print_error("Incorrect definition of table %s.%s: " - "expected the type of column '%s' at position %d " - "to have character set '%s' but the type has no " - "character set.", table->s->db.str, table->alias, - table_def->name.str, i, table_def->cset.str); + report_error(0, "Incorrect definition of table %s.%s: " + "expected the type of column '%s' at position %d " + "to have character set '%s' but the type has no " + "character set.", table->s->db.str, table->alias, + field_def->name.str, i, field_def->cset.str); error= TRUE; } - else if (table_def->cset.str && - strcmp(field->charset()->csname, table_def->cset.str)) + else if (field_def->cset.str && + strcmp(field->charset()->csname, field_def->cset.str)) { - sql_print_error("Incorrect definition of table %s.%s: " - "expected the type of column '%s' at position %d " - "to have character set '%s' but found " - "character set '%s'.", table->s->db.str, table->alias, - table_def->name.str, i, table_def->cset.str, - field->charset()->csname); + report_error(0, "Incorrect definition of table %s.%s: " + "expected the type of column '%s' at position %d " + "to have character set '%s' but found " + "character set '%s'.", table->s->db.str, table->alias, + field_def->name.str, i, field_def->cset.str, + field->charset()->csname); error= TRUE; } } else { - sql_print_error("Incorrect definition of table %s.%s: " - "expected column '%s' at position %d to have type %s " - " but the column is not found.", - table->s->db.str, table->alias, - table_def->name.str, i, table_def->type.str); + report_error(0, "Incorrect definition of table %s.%s: " + "expected column '%s' at position %d to have type %s " + " but the column is not found.", + table->s->db.str, table->alias, + field_def->name.str, i, field_def->type.str); error= TRUE; } } + + if (! error) + table->s->table_field_def_cache= table_def; + DBUG_RETURN(error); } diff --git a/sql/table.h b/sql/table.h index 6f75e693021..e7cb769c5a7 100644 --- a/sql/table.h +++ b/sql/table.h @@ -296,6 +296,35 @@ struct TABLE_share; extern ulong refresh_version; +typedef struct st_table_field_type +{ + LEX_STRING name; + LEX_STRING type; + LEX_STRING cset; +} TABLE_FIELD_TYPE; + + +typedef struct st_table_field_def +{ + uint count; + const TABLE_FIELD_TYPE *field; +} TABLE_FIELD_DEF; + + +class Table_check_intact +{ +protected: + virtual void report_error(uint code, const char *fmt, ...)= 0; + +public: + Table_check_intact() {} + virtual ~Table_check_intact() {} + + /** Checks whether a table is intact. */ + bool check(TABLE *table, const TABLE_FIELD_DEF *table_def); +}; + + /* This structure is shared between different table objects. There is one instance of table share per one table in the database. @@ -432,6 +461,18 @@ struct TABLE_SHARE handlerton *default_part_db_type; #endif + /** + Cache the checked structure of this table. + + The pointer data is used to describe the structure that + a instance of the table must have. Each element of the + array specifies a field that must exist on the table. + + The pointer is cached in order to perform the check only + once -- when the table is loaded from the disk. + */ + const TABLE_FIELD_DEF *table_field_def_cache; + /** place to store storage engine specific data */ void *ha_data; void (*ha_data_destroy)(void *); /* An optional destructor for ha_data */ @@ -1686,17 +1727,6 @@ typedef struct st_open_table_list{ uint32 in_use,locked; } OPEN_TABLE_LIST; -typedef struct st_table_field_w_type -{ - LEX_STRING name; - LEX_STRING type; - LEX_STRING cset; -} TABLE_FIELD_W_TYPE; - - -my_bool -table_check_intact(TABLE *table, const uint table_f_count, - const TABLE_FIELD_W_TYPE *table_def); static inline my_bitmap_map *tmp_use_all_columns(TABLE *table, MY_BITMAP *bitmap) |