diff --git a/mysql-test/r/show_check.result b/mysql-test/r/show_check.result
index 4d3b1b66e950474faff6e31fabea6ab04a6240de..a8be3f04249acaeb4d42f4544ab56d1614e5b7b3 100644
--- a/mysql-test/r/show_check.result
+++ b/mysql-test/r/show_check.result
@@ -90,6 +90,6 @@ t1	CREATE TABLE `t1` (
   `a` int(11) NOT NULL default '0',
   PRIMARY KEY  (`a`)
 ) TYPE=MyISAM
-Open_tables_in_test	Comment
-Open_tables_in_test	Comment
-t1	cached=1, in_use=0
+Database	Table	In_use	Name_locked
+Database	Table	In_use	Name_locked
+test	t1	0	0
diff --git a/sql/ha_myisam.h b/sql/ha_myisam.h
index ca5007228d89964e3f4f56caac24dea2fcb05765..d870331e7502b4ded6067e55d81cc1fba8d49362 100644
--- a/sql/ha_myisam.h
+++ b/sql/ha_myisam.h
@@ -37,17 +37,19 @@ extern ulong myisam_recover_options;
 class ha_myisam: public handler
 {
   MI_INFO *file;
-  uint    int_option_flag,enable_activate_all_index;
+  uint    int_option_flag;
   char    *data_file_name, *index_file_name;
+  bool enable_activate_all_index;
   int repair(THD *thd, MI_CHECK &param, bool optimize);
 
  public:
-  ha_myisam(TABLE *table): handler(table), file(0),enable_activate_all_index(1),
+  ha_myisam(TABLE *table): handler(table), file(0),
     int_option_flag(HA_READ_NEXT | HA_READ_PREV | HA_READ_RND_SAME |
 		    HA_KEYPOS_TO_RNDPOS | HA_READ_ORDER |  HA_LASTKEY_ORDER |
 		    HA_HAVE_KEY_READ_ONLY | HA_READ_NOT_EXACT_KEY |
 		    HA_LONGLONG_KEYS |  HA_NULL_KEY |
-		    HA_DUPP_POS | HA_BLOB_KEY | HA_AUTO_PART_KEY)
+		    HA_DUPP_POS | HA_BLOB_KEY | HA_AUTO_PART_KEY),
+    enable_activate_all_index(1)
   {}
   ~ha_myisam() {}
   const char *table_type() const { return "MyISAM"; }
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 11caa3b5463bb16e8c01d08cc9a9409061e1b009..676118c1fbec9c3a5eb8162660edcd67ef1f1e30 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -374,7 +374,7 @@ Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length,
 
 /* sql_list.c */
 int mysqld_show_dbs(THD *thd,const char *wild);
-int mysqld_show_open_tables(THD *thd,const char *db,const char *wild);
+int mysqld_show_open_tables(THD *thd,const char *wild);
 int mysqld_show_tables(THD *thd,const char *db,const char *wild);
 int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild);
 int mysqld_show_fields(THD *thd,TABLE_LIST *table, const char *wild,
@@ -451,8 +451,7 @@ bool close_cached_tables(THD *thd, bool wait_for_refresh, TABLE_LIST *tables);
 void copy_field_from_tmp_record(Field *field,int offset);
 int fill_record(List<Item> &fields,List<Item> &values);
 int fill_record(Field **field,List<Item> &values);
-int list_open_tables(THD *thd,List<char> *tables, const char *db,
-		     const char *wild);
+OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *wild);
 
 /* sql_calc.cc */
 bool eval_const_cond(COND *cond);
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 6587c4609edc45c1cb162bc0dfdbded2a5d7a4d4..ea3d77c5158ea84582712c10ea900eafced156db 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -109,75 +109,71 @@ static void check_unused(void)
 #define check_unused()
 #endif
 
-int list_open_tables(THD *thd,List<char> *tables, const char *db,
-		     const char *wild)
+OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *wild)
 {
   int result = 0;
   uint col_access=thd->col_access;
+  OPEN_TABLE_LIST **start_list, *open_list;
   TABLE_LIST table_list;
+  char name[NAME_LEN*2];
   DBUG_ENTER("list_open_tables");
+
   VOID(pthread_mutex_lock(&LOCK_open));
   bzero((char*) &table_list,sizeof(table_list));
+  start_list= &open_list;
+  open_list=0;
 
-  for (uint idx=0 ; idx < open_cache.records; idx++)
+  for (uint idx=0 ; result == 0 && idx < open_cache.records; idx++)
   {
+    OPEN_TABLE_LIST *table;
     TABLE *entry=(TABLE*) hash_element(&open_cache,idx);
-    if ((!entry->real_name) || strcmp(entry->table_cache_key,db))
-      continue;
-    if (wild && wild[0] && wild_compare(entry->real_name,wild))
-      continue;
-    if (db && !(col_access & TABLE_ACLS))
+
+    if ((!entry->real_name))
+      continue;					// Shouldn't happen
+    if (wild)
     {
-      table_list.db= (char*) db;
-      table_list.real_name= entry->real_name;/*real name*/
-      table_list.grant.privilege=col_access;
-      if (check_grant(thd,TABLE_ACLS,&table_list,1))
-        continue;
+      strxmov(name,entry->table_cache_key,".",entry->real_name,NullS);
+      if (wild_compare(name,wild))
+	continue;
     }
-    /* need to check if he have't already listed it */
 
-    List_iterator<char> it(*tables);
-    char *table_name; 
-    int check = 0;
-    while (check == 0 && (table_name=it++))
+    /* Check if user has SELECT privilege for any column in the table */
+    table_list.db= (char*) entry->table_cache_key;
+    table_list.real_name= entry->real_name;
+    table_list.grant.privilege=0;
+    if (check_table_access(thd,SELECT_ACL | EXTRA_ACL,&table_list))
+      continue;
+
+    /* need to check if we haven't already listed it */
+    for (table= open_list  ; table ; table=table->next)
     {
-      if (!strcmp(table_name,entry->real_name))
-        check++;
+      if (!strcmp(table->table,entry->real_name) &&
+	  !strcmp(table->db,entry->table_cache_key))
+      {
+	if (entry->in_use)
+	  table->in_use++;
+	if (entry->locked_by_name)
+	  table->locked++;
+	break;
+      }
     }
-    if (check)
+    if (table)
       continue;
-    
-    if (tables->push_back(thd->strdup(entry->real_name)))
+    if (!(*start_list = (OPEN_TABLE_LIST *)
+	  sql_alloc(sizeof(OPEN_TABLE_LIST)+entry->key_length)))
     {
-      result = -1;
+      open_list=0;				// Out of memory
       break;
     }
+    (*start_list)->table=(strmov((*start_list)->db=(char*) ((*start_list)+1),
+				 entry->table_cache_key)+1,
+			  entry->real_name);
+    (*start_list)->in_use= entry->in_use ? 1 : 0;
+    (*start_list)->locked= entry->locked_by_name ? 1 : 0;
+    start_list= &(*start_list)->next;
   }
-  
   VOID(pthread_mutex_unlock(&LOCK_open));
-  DBUG_RETURN(result);  
-}
-
-char*
-query_table_status(THD *thd,const char *db,const char *table_name)
-{
-  int cached = 0, in_use = 0;
-  char info[256];
-
-  for (uint idx=0 ; idx < open_cache.records; idx++)
-  {
-    TABLE *entry=(TABLE*) hash_element(&open_cache,idx);
-    if (strcmp(entry->table_cache_key,db) ||
-        strcmp(entry->real_name,table_name))
-      continue;
-
-    cached++;
-    if (entry->in_use)
-      in_use++;
-  }
-
-  sprintf(info, "cached=%d, in_use=%d", cached, in_use);
-  return thd->strdup(info);
+  DBUG_RETURN(open_list);
 }
 
 
@@ -257,7 +253,7 @@ send_fields(THD *thd,List<Item> &list,uint flag)
     if (my_net_write(&thd->net, (char*) packet->ptr(),packet->length()))
       break;					/* purecov: inspected */
   }
-  send_eof(&thd->net,(test_flags & TEST_MIT_THREAD) ? 0: 1);
+  send_eof(&thd->net);
   return 0;
  err:
   send_error(&thd->net,ER_OUT_OF_RESOURCES);	/* purecov: inspected */
@@ -405,47 +401,6 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh,
   DBUG_RETURN(result);
 }
 
-/* move one table to free list */
- 
-bool close_thread_table(THD *thd, TABLE **table_ptr)
-{
-  DBUG_ENTER("close_thread_table");
- 
-  bool found_old_table=0;
-  TABLE *table=*table_ptr;
- 
-  *table_ptr=table->next;
-  if (table->version != refresh_version ||
-      thd->version != refresh_version || !table->db_stat)
-  {
-    VOID(hash_delete(&open_cache,(byte*) table));
-    found_old_table=1;
-  }
-  else
-  {
-    if (table->flush_version != flush_version)
-    {
-      table->flush_version=flush_version;
-      table->file->extra(HA_EXTRA_FLUSH);
-    }
-    else
-    {
-      // Free memory and reset for next loop
-      table->file->extra(HA_EXTRA_RESET);
-    }
-    table->in_use=0;
-    if (unused_tables)
-    {
-      table->next=unused_tables;                /* Link in last */
-      table->prev=unused_tables->prev;
-      unused_tables->prev=table;
-      table->prev->next=table;
-    }
-    else
-      unused_tables=table->next=table->prev=table;
-  }
-  DBUG_RETURN(found_old_table);
-}
 
 /* Put all tables used by thread in free list */
 
@@ -469,40 +424,9 @@ void close_thread_tables(THD *thd, bool locked)
 
   DBUG_PRINT("info", ("thd->open_tables=%p", thd->open_tables));
 
-  for (table=thd->open_tables ; table ; table=next)
-  {
-    next=table->next;
-    if (table->version != refresh_version ||
-	thd->version != refresh_version || !table->db_stat)
-    {
-      VOID(hash_delete(&open_cache,(byte*) table));
-      found_old_table=1;
-    }
-    else
-    {
-      if (table->flush_version != flush_version)
-      {
-	table->flush_version=flush_version;
-	table->file->extra(HA_EXTRA_FLUSH);
-      }
-      else
-      {
-	// Free memory and reset for next loop
-	table->file->extra(HA_EXTRA_RESET);
-      }
-      table->in_use=0;
-      if (unused_tables)
-      {
-	table->next=unused_tables;		/* Link in last */
-	table->prev=unused_tables->prev;
-	unused_tables->prev=table;
-	table->prev->next=table;
-      }
-      else
-	unused_tables=table->next=table->prev=table;
-    }
-  }
-  thd->open_tables=0;
+  while (thd->open_tables)
+    found_old_table|=close_thread_table(thd, &thd->open_tables);
+
   /* Free tables to hold down open files */
   while (open_cache.records > table_cache_size && unused_tables)
     VOID(hash_delete(&open_cache,(byte*) unused_tables)); /* purecov: tested */
@@ -518,6 +442,48 @@ void close_thread_tables(THD *thd, bool locked)
   DBUG_VOID_RETURN;
 }
 
+/* move one table to free list */
+
+bool close_thread_table(THD *thd, TABLE **table_ptr)
+{
+  DBUG_ENTER("close_thread_table");
+
+  bool found_old_table=0;
+  TABLE *table=*table_ptr;
+
+  *table_ptr=table->next;
+  if (table->version != refresh_version ||
+      thd->version != refresh_version || !table->db_stat)
+  {
+    VOID(hash_delete(&open_cache,(byte*) table));
+    found_old_table=1;
+  }
+  else
+  {
+    if (table->flush_version != flush_version)
+    {
+      table->flush_version=flush_version;
+      table->file->extra(HA_EXTRA_FLUSH);
+    }
+    else
+    {
+      // Free memory and reset for next loop
+      table->file->extra(HA_EXTRA_RESET);
+    }
+    table->in_use=0;
+    if (unused_tables)
+    {
+      table->next=unused_tables;		/* Link in last */
+      table->prev=unused_tables->prev;
+      unused_tables->prev=table;
+      table->prev->next=table;
+    }
+    else
+      unused_tables=table->next=table->prev=table;
+  }
+  DBUG_RETURN(found_old_table);
+}
+
 	/* Close and delete temporary tables */
 
 void close_temporary(TABLE *table,bool delete_table)
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index bfc6e8185bdb46ad5de4726e803042d8605ecd95..9ec9a5265833496ad04ff392c61f93bd8fd23df4 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -47,7 +47,7 @@ static void mysql_init_query(THD *thd);
 static void remove_escape(char *name);
 static void refresh_status(void);
 static bool append_file_to_dir(char **filename_ptr, char *table_name);
-static  int link_in_large_list_and_check_acl(THD *thd,LEX *lex,SQL_LIST *tables);
+static int link_in_large_list_and_check_acl(THD *thd,LEX *lex,SQL_LIST *tables);
 
 const char *any_db="*any*";	// Special symbol for check_access
 
@@ -663,7 +663,7 @@ int mysql_table_dump(THD* thd, char* db, char* tbl_name, int fd)
   int error = 0;
   DBUG_ENTER("mysql_table_dump");
   db = (db && db[0]) ? db : thd->db;
-  if (!(table_list = (TABLE_LIST*) sql_calloc(sizeof(TABLE_LIST))))
+  if (!(table_list = (TABLE_LIST*) thd->calloc(sizeof(TABLE_LIST))))
     DBUG_RETURN(1); // out of memory
   table_list->db = db;
   table_list->real_name = table_list->name = tbl_name;
@@ -780,7 +780,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
       slow_command = TRUE;
       uint db_len = *(uchar*)packet;
       uint tbl_len = *(uchar*)(packet + db_len + 1);
-      char* db = sql_alloc(db_len + tbl_len + 2);
+      char* db = thd->alloc(db_len + tbl_len + 2);
       memcpy(db, packet + 1, db_len);
       char* tbl_name = db + db_len;
       *tbl_name++ = 0;
@@ -973,7 +973,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
     char buff[200];
     ulong uptime = (ulong) (thd->start_time - start_time);
     sprintf((char*) buff,
-	    "Uptime: %ld  Threads: %d  Questions: %lu  Slow queries: %ld  Opens: %ld  Flush tables: %ld  Open tables: %d Queries per second avg: %.3f",
+	    "Uptime: %ld  Threads: %d  Questions: %lu  Slow queries: %ld  Opens: %ld  Flush tables: %ld  Open tables: %u  Queries per second avg: %.3f",
 	    uptime,
 	    (int) thread_count,thd->query_id,long_query_count,
 	    opened_tables,refresh_version, cached_tables(),
@@ -1819,7 +1819,6 @@ mysql_execute_command(void)
     }
 #endif
   case SQLCOM_SHOW_TABLES:
-  case SQLCOM_SHOW_OPEN_TABLES:
     /* FALL THROUGH */
 #ifdef DONT_ALLOW_SHOW_COMMANDS
     send_error(&thd->net,ER_NOT_ALLOWED_COMMAND);	/* purecov: inspected */
@@ -1841,10 +1840,7 @@ mysql_execute_command(void)
       if (check_access(thd,SELECT_ACL,db,&thd->col_access))
 	goto error;				/* purecov: inspected */
       /* grant is checked in mysqld_show_tables */
-       if (lex->sql_command == SQLCOM_SHOW_OPEN_TABLES) 
-         res= mysqld_show_open_tables(thd, db,
-				 (lex->wild ? lex->wild->ptr() : NullS));
-      else if (select_lex->options & SELECT_DESCRIBE)
+      if (select_lex->options & SELECT_DESCRIBE)
         res= mysqld_extend_show_tables(thd,db,
 				       (lex->wild ? lex->wild->ptr() : NullS));
       else
@@ -1853,6 +1849,9 @@ mysql_execute_command(void)
       break;
     }
 #endif
+  case SQLCOM_SHOW_OPEN_TABLES:
+    res= mysqld_show_open_tables(thd,(lex->wild ? lex->wild->ptr() : NullS));
+    break;
   case SQLCOM_SHOW_FIELDS:
 #ifdef DONT_ALLOW_SHOW_COMMANDS
     send_error(&thd->net,ER_NOT_ALLOWED_COMMAND);	/* purecov: inspected */
@@ -2451,7 +2450,7 @@ void
 mysql_new_select(LEX *lex)
 {
   uint select_no=lex->select->select_number;
-  SELECT_LEX *select_lex = (SELECT_LEX *)sql_calloc(sizeof(SELECT_LEX));
+  SELECT_LEX *select_lex = (SELECT_LEX *) lex->thd->calloc(sizeof(SELECT_LEX));
   lex->select->next=select_lex; 
   lex->select=select_lex; lex->select->select_number = ++select_no;
   lex->select->item_list = lex->select_lex.item_list; 
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 8a4443f8a473a2b01ef87bd80f2bfedefe357d32..4ed59f7d1b0c62f8e6c037cb5690359fc0d6046c 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -95,21 +95,17 @@ mysqld_show_dbs(THD *thd,const char *wild)
 ** List all open tables in a database
 ***************************************************************************/
 
-int mysqld_show_open_tables(THD *thd,const char *db,const char *wild)
+int mysqld_show_open_tables(THD *thd,const char *wild)
 {
-  Item_string *field=new Item_string("",0);
   List<Item> field_list;
-  char *end,*table_name;
-  List<char> tables;
+  OPEN_TABLE_LIST *open_list;
+  CONVERT *convert=thd->convert_set;
   DBUG_ENTER("mysqld_show_open_tables");
 
-  field->name=(char*) thd->alloc(20+(uint) strlen(db)+(wild ? (uint) strlen(wild)+4:0));
-  end=strxmov(field->name,"Open_tables_in_",db,NullS);
-  if (wild && wild[0])
-    strxmov(end," (",wild,")",NullS);
-  field->max_length=NAME_LEN;
-  field_list.push_back(field);
-  field_list.push_back(new Item_empty_string("Comment",80));
+  field_list.push_back(new Item_empty_string("Database",NAME_LEN));
+  field_list.push_back(new Item_empty_string("Table",NAME_LEN));
+  field_list.push_back(new Item_int("In_use",0, 4));
+  field_list.push_back(new Item_int("Name_locked",0, 4));
 
   if (send_fields(thd,field_list,1))
     DBUG_RETURN(1);
@@ -117,12 +113,13 @@ int mysqld_show_open_tables(THD *thd,const char *db,const char *wild)
   if (!(open_list=list_open_tables(thd,wild)) && thd->fatal_error)
     DBUG_RETURN(-1);
 
-  List_iterator<char> it(tables);
-  while ((table_name=it++))
+  for ( ; open_list ; open_list=open_list->next)
   {
     thd->packet.length(0);
-    net_store_data(&thd->packet,table_name);
-    net_store_data(&thd->packet,query_table_status(thd,db,table_name));
+    net_store_data(&thd->packet,convert, open_list->db);
+    net_store_data(&thd->packet,convert, open_list->table);
+    net_store_data(&thd->packet,open_list->in_use);
+    net_store_data(&thd->packet,open_list->locked);
     if (my_net_write(&thd->net,(char*) thd->packet.ptr(),thd->packet.length()))
       DBUG_RETURN(-1);
   }