From 5fbd7b63c5852ceff5558981b56f3b16334223d5 Mon Sep 17 00:00:00 2001
From: "Sinisa@sinisa.nasamreza.org" <>
Date: Wed, 30 Oct 2002 16:52:12 +0200
Subject: [PATCH] changes for mysqladmin debug and a bug fix for derived tables

---
 include/thr_lock.h |  4 ++
 mysys/thr_lock.c   |  8 ++--
 sql/lock.cc        | 11 ++++++
 sql/sql_derived.cc |  3 +-
 sql/sql_parse.cc   | 10 +++--
 sql/sql_test.cc    | 94 ++++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 122 insertions(+), 8 deletions(-)

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/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 @@
 #include "mysql_priv.h"
 #include <hash.h>
 #include <assert.h>
+#include <ha_myisammrg.h>
+#ifndef MASTER
+#include "../srclib/myisammrg/myrg_def.h"
+#else
+#include "../myisammrg/myrg_def.h"
+#endif
 
 extern HASH open_cache;
 
@@ -154,6 +160,7 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd,TABLE **tables,uint count)
       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 ae32cd078f7..0eb7acde9f1 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)) ||
@@ -2777,7 +2781,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..5aac972e0bb 100644
--- a/sql/sql_test.cc
+++ b/sql/sql_test.cc
@@ -203,6 +203,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 +361,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";
-- 
2.30.9