diff --git a/.bzrignore b/.bzrignore index bacfe2ff975..27ee8321289 100644 --- a/.bzrignore +++ b/.bzrignore @@ -513,3 +513,6 @@ innobase/stamp-h1 myisam/rt_test.MYD myisam/rt_test.MYI stamp-h1 +libmysqld/sql_help.cc +scripts/fill_func_tables +scripts/fill_func_tables.sql diff --git a/include/thr_lock.h b/include/thr_lock.h index 7459849cb04..cf5b0cce4bc 100644 --- a/include/thr_lock.h +++ b/include/thr_lock.h @@ -74,6 +74,7 @@ typedef struct st_thr_lock_data { enum thr_lock_type type; ulong thread_id; void *status_param; /* Param to status functions */ + void *debug_print_param; } THR_LOCK_DATA; struct st_lock_list { @@ -97,6 +98,9 @@ typedef struct st_thr_lock { } THR_LOCK; +extern LIST *thr_lock_thread_list; +extern pthread_mutex_t THR_LOCK_lock; + my_bool init_thr_lock(void); /* Must be called once/thread */ void thr_lock_init(THR_LOCK *lock); void thr_lock_delete(THR_LOCK *lock); diff --git a/mysql-test/r/derived.result b/mysql-test/r/derived.result index e05be96c6b7..d3fbd557156 100644 --- a/mysql-test/r/derived.result +++ b/mysql-test/r/derived.result @@ -18,3 +18,9 @@ a y 3 3 3 3 drop table if exists t1.t2,t3; +select * from (select 1); +1 +1 +select a from (select 1 as a); +a +1 diff --git a/mysql-test/t/derived.test b/mysql-test/t/derived.test index 76ef5fba351..87910c29706 100644 --- a/mysql-test/t/derived.test +++ b/mysql-test/t/derived.test @@ -9,3 +9,5 @@ CREATE TABLE t3 (a int not null, b char (10) not null); insert into t3 values (3,'f'),(4,'y'),(5,'z'),(6,'c'); select t1.a,t4.y from t1,(select t2.a as y from t2,(select t3.b from t3 where t3.a>3) as t5 where t2.b=t5.b) as t4 where t1.a = t4.y; drop table if exists t1.t2,t3; +select * from (select 1); +select a from (select 1 as a); diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c index 0288c7c1cbe..c796bd1956a 100644 --- a/mysys/thr_lock.c +++ b/mysys/thr_lock.c @@ -91,7 +91,7 @@ enum thr_lock_type thr_upgraded_concurrent_insert_lock = TL_WRITE; #define MAX_LOCKS 100 -static LIST *thread_list; /* List of threads in use */ +LIST *thr_lock_thread_list; /* List of threads in use */ ulong max_write_lock_count= ~(ulong) 0L; static inline pthread_cond_t *get_cond(void) @@ -307,7 +307,7 @@ void thr_lock_init(THR_LOCK *lock) pthread_mutex_lock(&THR_LOCK_lock); /* Add to locks in use */ lock->list.data=(void*) lock; - thread_list=list_add(thread_list,&lock->list); + thr_lock_thread_list=list_add(thr_lock_thread_list,&lock->list); pthread_mutex_unlock(&THR_LOCK_lock); DBUG_VOID_RETURN; } @@ -318,7 +318,7 @@ void thr_lock_delete(THR_LOCK *lock) DBUG_ENTER("thr_lock_delete"); VOID(pthread_mutex_destroy(&lock->mutex)); pthread_mutex_lock(&THR_LOCK_lock); - thread_list=list_delete(thread_list,&lock->list); + thr_lock_thread_list=list_delete(thr_lock_thread_list,&lock->list); pthread_mutex_unlock(&THR_LOCK_lock); DBUG_VOID_RETURN; } @@ -1061,7 +1061,7 @@ void thr_print_locks(void) pthread_mutex_lock(&THR_LOCK_lock); puts("Current locks:"); - for (list=thread_list ; list && count++ < MAX_THREADS ; list=rest(list)) + for (list=thr_lock_thread_list ; list && count++ < MAX_THREADS ; list=rest(list)) { THR_LOCK *lock=(THR_LOCK*) list->data; VOID(pthread_mutex_lock(&lock->mutex)); diff --git a/sql/lock.cc b/sql/lock.cc index aed0e1988ea..3b2444c8e9d 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -69,6 +69,12 @@ TODO: #include "mysql_priv.h" #include #include +#include +#ifndef MASTER +#include "../srclib/myisammrg/myrg_def.h" +#else +#include "../myisammrg/myrg_def.h" +#endif extern HASH open_cache; @@ -154,6 +160,7 @@ retry: sql_lock=0; } } + thd->lock_time(); DBUG_RETURN (sql_lock); } @@ -410,8 +417,12 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, return 0; } } + THR_LOCK_DATA **org_locks = locks; locks=table->file->store_lock(thd, locks, get_old_locks ? TL_IGNORE : lock_type); + if (locks) + for ( ; org_locks != locks ; org_locks++) + (*org_locks)->debug_print_param= (void *) table; } return sql_lock; } diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 81eade6edb7..9cc83a3835a 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -70,7 +70,7 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t, if (tables_is_opened || !(res=open_and_lock_tables(thd,tables))) { - if (tables && setup_fields(thd,tables,item_list,0,0,1)) + if (setup_fields(thd,tables,item_list,0,0,1)) { res=-1; goto exit; @@ -113,6 +113,7 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t, t->table=table; table->derived_select_number= sl->select_number; sl->exclude(); + t->db= (tables && tables->db && tables->db[0]) ? t->db : thd->db; t->derived=(SELECT_LEX *)0; // just in case ... } } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 69f1eae9ac8..97714da0e8d 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1388,10 +1388,14 @@ mysql_execute_command(THD *thd) for (TABLE_LIST *cursor= tables; cursor; cursor= cursor->next) - if (cursor->derived && mysql_derived(thd, lex, + if (cursor->derived && (res=mysql_derived(thd, lex, (SELECT_LEX_UNIT *)cursor->derived, - cursor, 0)) + cursor, 0))) + { + if (res < 0) + send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0); DBUG_VOID_RETURN; + } } if ((lex->select_lex.next_select_in_list() && lex->unit.create_total_list(thd, lex, &tables)) || @@ -2781,7 +2785,7 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables, found=1; } } - else if (check_access(thd,want_access,tables->db,&tables->grant.privilege, + else if (tables->db && check_access(thd,want_access,tables->db,&tables->grant.privilege, 0, no_errors)) return TRUE; } diff --git a/sql/sql_test.cc b/sql/sql_test.cc index 6ae07417e7d..b3bf47e7fd2 100644 --- a/sql/sql_test.cc +++ b/sql/sql_test.cc @@ -26,6 +26,23 @@ /* Intern key cache variables */ extern "C" pthread_mutex_t THR_LOCK_keycache; +static const char *lock_descriptions[] = +{ + "No lock", + "Low priority read lock", + "Shared Read lock", + "High priority read lock", + "Read lock without concurrent inserts", + "Write lock that allows other writers", + "Write lock, but allow reading", + "Concurrent insert lock", + "Lock Used by delayed insert", + "Low priority write lock", + "High priority write lock", + "Highest priority write lock" +}; + + #ifndef DBUG_OFF void @@ -45,29 +62,11 @@ print_where(COND *cond,const char *info) DBUG_UNLOCK_FILE; } } - /* This is for debugging purposes */ extern HASH open_cache; extern TABLE *unused_tables; -static const char *lock_descriptions[] = -{ - "No lock", - "Low priority read lock", - "Shared Read lock", - "High priority read lock", - "Read lock without concurrent inserts", - "Write lock that allows other writers", - "Write lock, but allow reading", - "Concurrent insert lock", - "Lock Used by delayed insert", - "Low priority write lock", - "High priority write lock", - "Highest priority write lock" -}; - - void print_cached_tables(void) { uint idx,count,unused; @@ -203,6 +202,99 @@ TEST_join(JOIN *join) #endif +typedef struct st_debug_lock +{ + ulong thread_id; + char table_name[FN_REFLEN]; + bool waiting; + const char *lock_text; + enum thr_lock_type type; +} TABLE_LOCK_INFO; + +static int dl_compare(TABLE_LOCK_INFO *a,TABLE_LOCK_INFO *b) +{ + if (a->thread_id > b->thread_id) + return 1; + if (a->thread_id < b->thread_id) + return -1; + if (a->waiting == b->waiting) + return 0; + else if (a->waiting) + return -1; + return 1; +} + +static void push_locks_into_array(DYNAMIC_ARRAY *ar, THR_LOCK_DATA *data, bool wait, const char *text) +{ + if (data) + { + TABLE *table=(TABLE *)data->debug_print_param; + if (table && table->tmp_table == NO_TMP_TABLE) + { + TABLE_LOCK_INFO table_lock_info; + table_lock_info.thread_id=table->in_use->thread_id; + memcpy(table_lock_info.table_name, table->table_cache_key, table->key_length); + table_lock_info.table_name[strlen(table_lock_info.table_name)]='.'; + table_lock_info.waiting=wait; + table_lock_info.lock_text=text; + table_lock_info.type=table->reginfo.lock_type; // obtainable also from THR_LOCK_DATA + VOID(push_dynamic(ar,(gptr) &table_lock_info)); + } + } +} +/* + Regarding MERGE tables: + +For now, the best option is to use the common TABLE *pointer for all +cases; The drawback is that for MERGE tables we will see many locks +for the merge tables even if some of them are for individual tables. + +The way to solve this is to add to 'THR_LOCK' structure a pointer to +the filename and use this when printing the data. +(We can for now ignore this and just print the same name for all merge +table parts; Please add the above as a comment to the display_lock +function so that we can easily add this if we ever need this. + +*/ + +static void display_table_locks (void) +{ + LIST *list; + DYNAMIC_ARRAY saved_table_locks; + + VOID(my_init_dynamic_array(&saved_table_locks,sizeof(TABLE_LOCK_INFO),open_cache.records + 20,50)); + VOID(pthread_mutex_lock(&THR_LOCK_lock)); + for (list=thr_lock_thread_list ; list ; list=rest(list)) + { + THR_LOCK *lock=(THR_LOCK*) list->data; + + VOID(pthread_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, "Waiting - write"); + push_locks_into_array(&saved_table_locks, lock->read.data, false, "Locked - read"); + push_locks_into_array(&saved_table_locks, lock->read_wait.data, true, "Waiting - read"); + VOID(pthread_mutex_unlock(&lock->mutex)); + } + VOID(pthread_mutex_unlock(&THR_LOCK_lock)); + if (!saved_table_locks.elements) goto end; + + qsort((gptr) dynamic_element(&saved_table_locks,0,TABLE_LOCK_INFO *),saved_table_locks.elements,sizeof(TABLE_LOCK_INFO),(qsort_cmp) dl_compare); + freeze_size(&saved_table_locks); + + puts("\nThread database.table_name Locked/Waiting Lock_type\n"); + + for (uint i=0 ; i < saved_table_locks.elements ; i++) + { + TABLE_LOCK_INFO *dl_ptr=dynamic_element(&saved_table_locks,i,TABLE_LOCK_INFO*); + printf("%-8ld%-28.28s%-22s%s\n", + dl_ptr->thread_id,dl_ptr->table_name,dl_ptr->lock_text,lock_descriptions[(int)dl_ptr->type]); + } + puts("\n\n"); +end: + delete_dynamic(&saved_table_locks); +} + + void mysql_print_status(THD *thd) { char current_dir[FN_REFLEN]; @@ -268,6 +360,7 @@ Next alarm time: %lu\n", alarm_info.max_used_alarms, alarm_info.next_alarm_time); #endif + display_table_locks(); fflush(stdout); if (thd) thd->proc_info="malloc";