MySQL Lists are EOL. Please join:

List:Commits« Previous MessageNext Message »
From:Mattias Jonsson Date:February 17 2009 3:45pm
Subject:bzr commit into mysql-5.1 branch (mattias.jonsson:2797) WL#3513
View as plain text  
#At file:///Users/mattiasj/clones/bzrroot/wl3513-51-pv_to_commit/ based on revid:mattias.jonsson@stripped

 2797 Mattias Jonsson	2009-02-17
      WL#3513: Open only the required partitions
      
      This is part 1 where the calls for index_init, rnd_init
      and some special extra is delayed for each partition is
      actually used. Also the reset call is only called
      for used partitions.
modified:
  include/my_bitmap.h
  mysys/my_bitmap.c
  sql/ha_partition.cc
  sql/ha_partition.h

per-file messages:
  include/my_bitmap.h
    WL#3513: Open only the required partitions
    
    Added bitmap_get_last for fast access to the last
    bit (like get_first)
  mysys/my_bitmap.c
    WL#3513: Open only the required partitions
    
    Added bitmap_get_last for fast access to the last
    bit (like get_first)
  sql/ha_partition.cc
    WL#3513: Open only the required partitions
    
    Added prepare_use_partition for doing the init functions
    for a partition before use. prepare_close_partition is
    also added, but not yet used.
    
    Fixed a bug for reorg partition where it could use the
    wrong partition when calling extra(HA_EXTRA_CACHE)
    
    Added the fix for bug-37433
  sql/ha_partition.h
    WL#3513: Open only the required partitions
    
    Fix for bug-37433 (added a mutex in ha_data to avoid
    using the table_share->mutex)
    
    Added bitmaps and variables to store the calls that
    are delayed until the real use of the partitions
=== modified file 'include/my_bitmap.h'
--- a/include/my_bitmap.h	2007-12-12 10:14:59 +0000
+++ b/include/my_bitmap.h	2009-02-17 15:44:59 +0000
@@ -56,6 +56,8 @@ extern my_bool bitmap_fast_test_and_set(
 extern uint bitmap_set_next(MY_BITMAP *map);
 extern uint bitmap_get_first(const MY_BITMAP *map);
 extern uint bitmap_get_first_set(const MY_BITMAP *map);
+extern uint bitmap_get_last(const MY_BITMAP *map);
+extern uint bitmap_get_last_set(const MY_BITMAP *map);
 extern uint bitmap_bits_set(const MY_BITMAP *map);
 extern void bitmap_free(MY_BITMAP *map);
 extern void bitmap_set_above(MY_BITMAP *map, uint from_byte, uint use_bit);
@@ -74,6 +76,8 @@ extern uint bitmap_lock_bits_set(const M
 extern my_bool bitmap_lock_is_set_all(const MY_BITMAP *map);
 extern uint bitmap_lock_get_first(const MY_BITMAP *map);
 extern uint bitmap_lock_get_first_set(const MY_BITMAP *map);
+extern uint bitmap_lock_get_last(const MY_BITMAP *map);
+extern uint bitmap_lock_get_last_set(const MY_BITMAP *map);
 extern my_bool bitmap_lock_is_subset(const MY_BITMAP *map1,
                                      const MY_BITMAP *map2);
 extern my_bool bitmap_lock_is_prefix(const MY_BITMAP *map, uint prefix_size);

=== modified file 'mysys/my_bitmap.c'
--- a/mysys/my_bitmap.c	2007-10-11 15:07:40 +0000
+++ b/mysys/my_bitmap.c	2009-02-17 15:44:59 +0000
@@ -518,6 +518,41 @@ uint bitmap_get_first_set(const MY_BITMA
 }
 
 
+uint bitmap_get_last_set(const MY_BITMAP *map)
+{
+  uchar *byte_ptr;
+  uint i,j,k;
+  my_bitmap_map *start, *data_ptr= map->last_word_ptr;
+
+  DBUG_ASSERT(map->bitmap);
+  start= map->bitmap;
+  *map->last_word_ptr &= ~map->last_word_mask;
+
+  for (i= no_words_in_map(map) - 1; start <= data_ptr; data_ptr--, i--)
+  {
+    if (*data_ptr)
+    {
+      byte_ptr= (uchar*)data_ptr;
+      byte_ptr+= 3;                          /* last byte in the word */
+      for (j=3; ; j--, byte_ptr--)
+      {
+        if (*byte_ptr)
+        {
+          for (k=7; ; k--)
+          {
+            if (*byte_ptr & (1 << k))
+              return (i*32) + (j*8) + k;
+          }
+          DBUG_ASSERT(0);
+        }
+      }
+      DBUG_ASSERT(0);
+    }
+  }
+  return MY_BIT_NONE;
+}
+
+
 uint bitmap_get_first(const MY_BITMAP *map)
 {
   uchar *byte_ptr;
@@ -552,6 +587,41 @@ uint bitmap_get_first(const MY_BITMAP *m
 }
 
 
+uint bitmap_get_last(const MY_BITMAP *map)
+{
+  uchar *byte_ptr;
+  uint i,j,k;
+  my_bitmap_map *start, *data_ptr= map->last_word_ptr;
+
+  DBUG_ASSERT(map->bitmap);
+  start= map->bitmap;
+  *map->last_word_ptr|= map->last_word_mask;
+
+  for (i= no_words_in_map(map) - 1; start <= data_ptr; data_ptr--, i--)
+  {
+    if (*data_ptr != 0xFFFFFFFF)
+    {
+      byte_ptr= (uchar*)data_ptr;
+      byte_ptr+= 3;                          /* last byte in the word */
+      for (j=3; ; j--, byte_ptr--)
+      { 
+        if (*byte_ptr != 0xFF)
+        {
+          for (k=7; ; k--)
+          {
+            if (!(*byte_ptr & (1 << k)))
+              return (i*32) + (j*8) + k;
+          }
+          DBUG_ASSERT(0);
+        }
+      }
+      DBUG_ASSERT(0);
+    }
+  }
+  return MY_BIT_NONE;
+}
+
+
 uint bitmap_lock_set_next(MY_BITMAP *map)
 {
   uint bit_found;
@@ -729,6 +799,16 @@ uint bitmap_lock_get_first(const MY_BITM
 }
 
 
+uint bitmap_lock_get_last(const MY_BITMAP *map)
+{
+  uint res;
+  bitmap_lock((MY_BITMAP*)map);
+  res= bitmap_get_last(map);
+  bitmap_unlock((MY_BITMAP*)map);
+  return res;
+}
+
+
 uint bitmap_lock_get_first_set(const MY_BITMAP *map)
 {
   uint res;
@@ -739,6 +819,16 @@ uint bitmap_lock_get_first_set(const MY_
 }
 
 
+uint bitmap_lock_get_last_set(const MY_BITMAP *map)
+{
+  uint res;
+  bitmap_lock((MY_BITMAP*)map);
+  res= bitmap_get_last_set(map);
+  bitmap_unlock((MY_BITMAP*)map);
+  return res;
+}
+
+
 void bitmap_lock_set_bit(MY_BITMAP *map, uint bitmap_bit)
 {
   DBUG_ASSERT(map->bitmap && bitmap_bit < map->n_bits);
@@ -1014,6 +1104,31 @@ error2:
   return TRUE;
 }
 
+bool test_get_last_bit(MY_BITMAP *map, uint bitsize)
+{
+  uint i, test_bit;
+  uint no_loops= bitsize > 128 ? 128 : bitsize;
+  for (i=0; i < no_loops; i++)
+  {
+    test_bit=get_rand_bit(bitsize);
+    bitmap_set_bit(map, test_bit);
+    if (bitmap_get_last_set(map) != test_bit)
+      goto error1;
+    bitmap_set_all(map);
+    bitmap_clear_bit(map, test_bit);
+    if (bitmap_get_last(map) != test_bit)
+      goto error2;
+    bitmap_clear_all(map);
+  }
+  return false;
+error1:
+  printf("get_last_set error bitsize=%u,prefix_size=%u",bitsize,test_bit);
+  return true;
+error2:
+  printf("get_last error bitsize= %u, prefix_size= %u",bitsize,test_bit);
+  return true;
+}
+
 bool test_get_next_bit(MY_BITMAP *map, uint bitsize)
 {
   uint i, j, test_bit;
@@ -1097,6 +1212,8 @@ bool do_test(uint bitsize)
   bitmap_clear_all(&map);
   if (test_get_first_bit(&map,bitsize))
     goto error;
+  if (test_get_last_bit(&map,bitsize))
+    goto error;
   bitmap_clear_all(&map);
   if (test_get_next_bit(&map,bitsize))
     goto error;

=== modified file 'sql/ha_partition.cc'
--- a/sql/ha_partition.cc	2009-02-17 14:36:54 +0000
+++ b/sql/ha_partition.cc	2009-02-17 15:44:59 +0000
@@ -202,6 +202,7 @@ ha_partition::ha_partition(handlerton *h
 
 void ha_partition::init_handler_variables()
 {
+  DBUG_ENTER("ha_partition::init_handler_variables");
   active_index= MAX_KEY;
   m_mode= 0;
   m_open_test_lock= 0;
@@ -246,11 +247,13 @@ void ha_partition::init_handler_variable
     this allows blackhole to work properly
   */
   m_no_locks= 0;
+  m_index_inited= MAX_KEY;
 
 #ifdef DONT_HAVE_TO_BE_INITALIZED
   m_start_key.flag= 0;
   m_ordered= TRUE;
 #endif
+  DBUG_VOID_RETURN;
 }
 
 
@@ -1089,7 +1092,8 @@ int ha_partition::handle_opt_partitions(
                           sub_elem->partition_name))
             DBUG_RETURN(HA_ADMIN_INTERNAL_ERROR);
 #endif
-          if ((error= handle_opt_part(thd, check_opt, m_file[part], flag)))
+          if ((error= prepare_use_partition(part, FALSE)) ||
+              (error= handle_opt_part(thd, check_opt, m_file[part], flag)))
           {
             /* print a line which partition the error belongs to */
             if (error != HA_ADMIN_NOT_IMPLEMENTED &&
@@ -1116,7 +1120,8 @@ int ha_partition::handle_opt_partitions(
                         part_elem->partition_name))
           DBUG_RETURN(HA_ADMIN_INTERNAL_ERROR);
 #endif
-        if ((error= handle_opt_part(thd, check_opt, m_file[i], flag)))
+        if ((error= prepare_use_partition(i, FALSE)) ||
+            (error= handle_opt_part(thd, check_opt, m_file[i], flag)))
         {
           /* print a line which partition the error belongs to */
           if (error != HA_ADMIN_NOT_IMPLEMENTED &&
@@ -1152,7 +1157,8 @@ bool ha_partition::check_and_repair(THD 
 
   do
   {
-    if ((*file)->ha_check_and_repair(thd))
+    if (prepare_use_partition(file - m_file, FALSE) ||
+        (*file)->ha_check_and_repair(thd))
       DBUG_RETURN(TRUE);
   } while (*(++file));
   DBUG_RETURN(FALSE);
@@ -1623,6 +1629,7 @@ int ha_partition::copy_partitions(ulongl
   uint reorg_part= 0;
   int result= 0;
   longlong func_value;
+  THD *thd= ha_thd();
   DBUG_ENTER("ha_partition::copy_partitions");
 
   if (m_part_info->linear_hash_ind)
@@ -1637,10 +1644,19 @@ int ha_partition::copy_partitions(ulongl
   {
     handler *file= m_reorged_file[reorg_part];
     uint32 new_part;
+    uint from_part_id;
 
-    late_extra_cache(reorg_part);
+    /*
+      Find the correct partition id in m_file, which is used in
+      late_extra[_no]_cache.
+    */
+    for (from_part_id= 0; file != m_file[from_part_id]; from_part_id++)
+      ;
+    if ((result= prepare_use_partition(from_part_id, FALSE)))
+      goto error;
     if ((result= file->ha_rnd_init(1)))
       goto error;
+    late_extra_cache(from_part_id);
     while (TRUE)
     {
       if ((result= file->rnd_next(m_rec0)))
@@ -1668,7 +1684,6 @@ int ha_partition::copy_partitions(ulongl
       }
       else
       {
-        THD *thd= ha_thd();
         /* Copy record to new handler */
         (*copied)++;
         tmp_disable_binlog(thd); /* Do not replicate the low-level changes. */
@@ -1678,7 +1693,7 @@ int ha_partition::copy_partitions(ulongl
           goto error;
       }
     }
-    late_extra_no_cache(reorg_part);
+    late_extra_no_cache(from_part_id);
     file->ha_rnd_end();
     reorg_part++;
   }
@@ -2145,12 +2160,14 @@ bool ha_partition::create_handler_file(c
 
 void ha_partition::clear_handler_file()
 {
+  DBUG_ENTER("ha_partition::clear_handler_file");
   if (m_engine_array)
     plugin_unlock_list(NULL, m_engine_array, m_tot_parts);
   my_free((char*) m_file_buffer, MYF(MY_ALLOW_ZERO_PTR));
   my_free((char*) m_engine_array, MYF(MY_ALLOW_ZERO_PTR));
   m_file_buffer= NULL;
   m_engine_array= NULL;
+  DBUG_VOID_RETURN;
 }
 
 /*
@@ -2392,7 +2409,7 @@ err1:
 int ha_partition::open(const char *name, int mode, uint test_if_locked)
 {
   char *name_buffer_ptr= m_name_buffer_ptr;
-  int error;
+  int error= HA_ERR_INITIALIZATION;
   uint alloc_len;
   handler **file;
   char name_buff[FN_REFLEN];
@@ -2410,10 +2427,10 @@ int ha_partition::open(const char *name,
   m_start_key.length= 0;
   m_rec0= table->record[0];
   m_rec_length= table_share->reclength;
-  alloc_len= m_tot_parts * (m_rec_length + PARTITION_BYTES_IN_POS);
-  alloc_len+= table_share->max_key_length;
   if (!m_ordered_rec_buffer)
   {
+    alloc_len= m_tot_parts * (m_rec_length + PARTITION_BYTES_IN_POS);
+    alloc_len+= table_share->max_key_length;
     if (!(m_ordered_rec_buffer= (uchar*)my_malloc(alloc_len, MYF(MY_WME))))
     {
       DBUG_RETURN(1);
@@ -2438,11 +2455,15 @@ int ha_partition::open(const char *name,
   }
 
   /* Initialize the bitmap we use to minimize ha_start_bulk_insert calls */
-  if (bitmap_init(&m_bulk_insert_started, NULL, m_tot_parts + 1, FALSE))
+  if (bitmap_init(&m_bulk_insert_started, NULL, m_tot_parts, FALSE))
     DBUG_RETURN(1);
-  /* Initialize the bitmap we use to determine what partitions are used */
+  m_bulk_insert_active= FALSE;
   if (!is_clone)
   {
+    /*
+      Initialize the bitmap we use to determine what partitions are used.
+      This is set in prune_partitions.
+    */
     if (bitmap_init(&(m_part_info->used_partitions), NULL, m_tot_parts, TRUE))
     {
       bitmap_free(&m_bulk_insert_started);
@@ -2451,6 +2472,20 @@ int ha_partition::open(const char *name,
     bitmap_set_all(&(m_part_info->used_partitions));
   }
 
+  /*
+    Initialize the bitmap that tracks opened partitions,
+    so that we can call reset on them later. Same for rnd_init(0), index_init
+    and HA_EXTRA_CACHE.
+  */
+  if (bitmap_init(&m_reset_partitions, NULL, m_tot_parts, TRUE))
+    goto err_handler;
+  if (bitmap_init(&m_rnd_partitions, NULL, m_tot_parts, TRUE))
+    goto err_handler;
+  if (bitmap_init(&m_index_partitions, NULL, m_tot_parts, TRUE))
+    goto err_handler;
+  if (bitmap_init(&m_cache_partitions, NULL, m_tot_parts, TRUE))
+    goto err_handler;
+
   file= m_file;
   do
   {
@@ -2476,7 +2511,6 @@ int ha_partition::open(const char *name,
                                     ~(PARTITION_DISABLED_TABLE_FLAGS)) |
                                    (PARTITION_ENABLED_TABLE_FLAGS)))
     {
-      error= HA_ERR_INITIALIZATION;
       goto err_handler;
     }
   } while (*(++file));
@@ -2521,6 +2555,7 @@ int ha_partition::open(const char *name,
     }
     DBUG_PRINT("info", ("table_share->ha_data 0x%p", ha_data));
     bzero(ha_data, sizeof(HA_DATA_PARTITION));
+    pthread_mutex_init(&ha_data->mutex, MY_MUTEX_INIT_FAST);
   }
   if (is_not_tmp_table)
     pthread_mutex_unlock(&table_share->mutex);
@@ -2543,6 +2578,10 @@ err_handler:
   while (file-- != m_file)
     (*file)->close();
   bitmap_free(&m_bulk_insert_started);
+  bitmap_free(&m_reset_partitions);
+  bitmap_free(&m_rnd_partitions);
+  bitmap_free(&m_index_partitions);
+  bitmap_free(&m_cache_partitions);
   if (!is_clone)
     bitmap_free(&(m_part_info->used_partitions));
 
@@ -2591,6 +2630,9 @@ int ha_partition::close(void)
   DBUG_ASSERT(table->s == table_share);
   delete_queue(&m_queue);
   bitmap_free(&m_bulk_insert_started);
+  bitmap_free(&m_reset_partitions);
+  bitmap_free(&m_rnd_partitions);
+  bitmap_free(&m_index_partitions);
   if (!is_clone)
     bitmap_free(&(m_part_info->used_partitions));
   file= m_file;
@@ -2612,6 +2654,100 @@ repeat:
   DBUG_RETURN(0);
 }
 
+
+/*
+  prepare_use_partition called directly before use of a partition,
+  to initialize index_init, rnd_init, bulk_start_insert etc.
+  if not done previously.
+*/
+int ha_partition::prepare_use_partition(uint part_id, bool insert)
+{
+  int error= 0;
+  DBUG_ENTER("ha_partition::prepare_use_partition");
+  /* Mark for later reset */
+  bitmap_set_bit(&m_reset_partitions, part_id);
+
+  /* Start bulk insert if needed */
+  if (insert && m_bulk_insert_active)
+  {
+    if (!bitmap_is_set(&m_bulk_insert_started, part_id))
+    {
+      m_file[part_id]->ha_start_bulk_insert(guess_bulk_insert_rows());
+      bitmap_set_bit(&m_bulk_insert_started, part_id);
+    }
+    m_bulk_inserted_rows++;
+  }
+
+  /* do rnd_init(0), for rnd_pos */
+  if (m_scan_value == 0 && !bitmap_is_set(&m_rnd_partitions, part_id))
+  {
+    /*
+      rnd_init(0) has been called - prepared for rnd_pos()
+      rnd_init(1) is handled per partition when scanning.
+    */
+    DBUG_PRINT("info", ("rnd_init(0) on partition %d", part_id));
+    if ((error= m_file[part_id]->ha_rnd_init(0)))
+      DBUG_RETURN(error);
+    bitmap_set_bit(&m_rnd_partitions, part_id);
+  }
+  if (active_index != MAX_KEY && !bitmap_is_set(&m_index_partitions, part_id))
+  {
+    DBUG_PRINT("info", ("ha_index_init(%u, %u) on partition %d",
+                        active_index, m_ordered, part_id));
+    if ((error= m_file[part_id]->ha_index_init(active_index, m_ordered)))
+      DBUG_RETURN(error);
+    bitmap_set_bit(&m_index_partitions, part_id);
+  }
+  DBUG_ASSERT(!(active_index == MAX_KEY &&
+                bitmap_is_set(&m_index_partitions, part_id)));
+#ifdef NOT_USED
+  if (active_index == MAX_KEY && bitmap_is_set(&m_index_partitions, part_id))
+  {
+    if ((error= m_file[part_id]->ha_index_end()))
+      DBUG_RETURN(error);
+    bitmap_set_bit(&m_index_partitions, part_id);
+  }
+#endif /* NOT_USED */
+  DBUG_RETURN(error);
+}
+
+
+#ifdef NOT_USED
+/*
+  This will be enabled when one can close the partitions files without
+  closing the partitions handler.
+/*
+  prepare_close_partition, called before close partition, to end started
+  operations.
+*/
+int ha_partition::prepare_close_partition(uint close_id)
+{
+  int tmp, error= 0;
+  DBUG_ENTER("ha_partition::prepare_close_partition");
+  if (m_bulk_insert_active && bitmap_is_set(&m_bulk_insert_started, close_id))
+  {
+    if ((tmp= m_file[close_id]->ha_end_bulk_insert()))
+      error= tmp;
+    bitmap_clear_bit(&m_bulk_insert_started, close_id);
+  }
+  if (m_scan_value == 0 && bitmap_is_set(&m_rnd_partitions, close_id))
+  {
+    DBUG_PRINT("info", ("rnd_end() on partition %d", close_id));
+    if ((tmp= m_file[close_id]->ha_rnd_end()))
+      error= tmp;
+    bitmap_clear_bit(&m_rnd_partitions, close_id);
+  }
+  if (active_index != MAX_KEY && bitmap_is_set(&m_index_partitions, close_id))
+  {
+    DBUG_PRINT("info", ("index_end() on partition %d", close_id));
+    if ((tmp= m_file[close_id]->ha_index_end()))
+      error= tmp;
+    bitmap_clear_bit(&m_index_partitions, close_id);
+  }
+  DBUG_RETURN(error);
+}
+#endif /* NOT_USED */
+
 /****************************************************************************
                 MODULE start/end statement
 ****************************************************************************/
@@ -2977,13 +3113,16 @@ int ha_partition::write_row(uchar * buf)
   }
   m_last_part= part_id;
   DBUG_PRINT("info", ("Insert in partition %d", part_id));
-  start_part_bulk_insert(part_id);
 
-  tmp_disable_binlog(thd); /* Do not replicate the low-level changes. */
-  error= m_file[part_id]->ha_write_row(buf);
-  if (have_auto_increment && !table->s->next_number_keypart)
-    set_auto_increment_if_higher(table->next_number_field->val_int());
-  reenable_binlog(thd);
+  error= prepare_use_partition(part_id, TRUE);
+  if (!error)
+  {
+    tmp_disable_binlog(thd); /* Do not replicate the low-level changes. */
+    error= m_file[part_id]->ha_write_row(buf);
+    if (have_auto_increment && !table->s->next_number_keypart)
+      set_auto_increment_if_higher(table->next_number_field->val_int());
+    reenable_binlog(thd);
+  }
 exit:
   table->timestamp_field_type= orig_timestamp_type;
   DBUG_RETURN(error);
@@ -3041,7 +3180,8 @@ int ha_partition::update_row(const uchar
   }
 
   m_last_part= new_part_id;
-  start_part_bulk_insert(new_part_id);
+  if ((error= prepare_use_partition(new_part_id, TRUE)))
+    goto exit;
   if (new_part_id == old_part_id)
   {
     DBUG_PRINT("info", ("Update in partition %d", new_part_id));
@@ -3060,6 +3200,8 @@ int ha_partition::update_row(const uchar
     if (error)
       goto exit;
 
+    if ((error= prepare_use_partition(old_part_id, FALSE)))
+      goto exit;
     tmp_disable_binlog(thd); /* Do not replicate the low-level changes. */
     error= m_file[old_part_id]->ha_delete_row(old_data);
     reenable_binlog(thd);
@@ -3134,6 +3276,8 @@ int ha_partition::delete_row(const uchar
     DBUG_RETURN(error);
   }
   m_last_part= part_id;
+  if ((error= prepare_use_partition(part_id, FALSE)))
+    DBUG_RETURN(error);
   tmp_disable_binlog(thd);
   error= m_file[part_id]->ha_delete_row(buf);
   reenable_binlog(thd);
@@ -3181,6 +3325,8 @@ int ha_partition::delete_all_rows()
   file= m_file;
   do
   {
+    if ((error= prepare_use_partition(file - m_file, FALSE)))
+      DBUG_RETURN(error);
     if ((error= (*file)->ha_delete_all_rows()))
       DBUG_RETURN(error);
   } while (*(++file));
@@ -3205,31 +3351,14 @@ void ha_partition::start_bulk_insert(ha_
 {
   DBUG_ENTER("ha_partition::start_bulk_insert");
 
+  DBUG_ASSERT(!m_bulk_insert_active);
   m_bulk_inserted_rows= 0;
-  bitmap_clear_all(&m_bulk_insert_started);
-  /* use the last bit for marking if bulk_insert_started was called */
-  bitmap_set_bit(&m_bulk_insert_started, m_tot_parts);
+  m_bulk_insert_active= TRUE;
   DBUG_VOID_RETURN;
 }
 
 
 /*
-  Check if start_bulk_insert has been called for this partition,
-  if not, call it and mark it called
-*/
-void ha_partition::start_part_bulk_insert(uint part_id)
-{
-  if (!bitmap_is_set(&m_bulk_insert_started, part_id) &&
-      bitmap_is_set(&m_bulk_insert_started, m_tot_parts))
-  {
-    m_file[part_id]->ha_start_bulk_insert(guess_bulk_insert_rows());
-    bitmap_set_bit(&m_bulk_insert_started, part_id);
-  }
-  m_bulk_inserted_rows++;
-}
-
-
-/*
   Try to predict the number of inserts into this partition.
 
   If less than 10 rows (including 0 which means Unknown)
@@ -3277,7 +3406,7 @@ int ha_partition::end_bulk_insert()
   uint i;
   DBUG_ENTER("ha_partition::end_bulk_insert");
 
-  DBUG_ASSERT(bitmap_is_set(&m_bulk_insert_started, m_tot_parts));
+  DBUG_ASSERT(m_bulk_insert_active);
   for (i= 0; i < m_tot_parts; i++)
   {
     int tmp;
@@ -3286,6 +3415,7 @@ int ha_partition::end_bulk_insert()
       error= tmp;
   }
   bitmap_clear_all(&m_bulk_insert_started);
+  m_bulk_insert_active= FALSE;
   DBUG_RETURN(error);
 }
 
@@ -3363,14 +3493,13 @@ int ha_partition::rnd_init(bool scan)
   if (MY_BIT_NONE == part_id)
   {
     error= 0;
-    goto err1;
+    goto err;
   }
 
   /*
     We have a partition and we are scanning with rnd_next
     so we bump our cache
   */
-  DBUG_PRINT("info", ("rnd_init on partition %d", part_id));
   if (scan)
   {
     /*
@@ -3378,34 +3507,29 @@ int ha_partition::rnd_init(bool scan)
       is already in use
     */
     rnd_end();
-    late_extra_cache(part_id);
+    /* for scanning, only use cache/rnd_init on one partition at a time */
+    if ((error= prepare_use_partition((uint) part_id, FALSE)))
+      goto err;
     if ((error= m_file[part_id]->ha_rnd_init(scan)))
       goto err;
+    DBUG_PRINT("info", ("rnd_init(%u) on partition %d", scan, part_id));
+    late_extra_cache(part_id);
   }
   else
   {
-    for (i= part_id; i < m_tot_parts; i++)
-    {
-      if (bitmap_is_set(&(m_part_info->used_partitions), i))
-      {
-        if ((error= m_file[i]->ha_rnd_init(scan)))
-          goto err;
-      }
-    }
+    /*
+      no scan, don't use cache, and delay the ha_rnd_init(0) call to
+      be done in prepare_use_partition
+    */
   }
-  m_scan_value= scan;
+  m_scan_value= scan ? 1 : 0;
   m_part_spec.start_part= part_id;
   m_part_spec.end_part= m_tot_parts - 1;
   DBUG_PRINT("info", ("m_scan_value=%d", m_scan_value));
   DBUG_RETURN(0);
 
 err:
-  while ((int)--i >= (int)part_id)
-  {
-    if (bitmap_is_set(&(m_part_info->used_partitions), i))
-      m_file[i]->ha_rnd_end();
-  }
-err1:
+  DBUG_PRINT("error", ("i %u part_id %u scan %u", i, part_id, scan));
   m_scan_value= 2;
   m_part_spec.start_part= NO_CURRENT_PART_ID;
   DBUG_RETURN(error);
@@ -3429,11 +3553,14 @@ int ha_partition::rnd_end()
   DBUG_ENTER("ha_partition::rnd_end");
   switch (m_scan_value) {
   case 2:                                       // Error
+    DBUG_ASSERT(NO_CURRENT_PART_ID == m_part_spec.start_part);
     break;
   case 1:
     if (NO_CURRENT_PART_ID != m_part_spec.start_part)         // Table scan
     {
       late_extra_no_cache(m_part_spec.start_part);
+      DBUG_PRINT("info", ("rnd_end() on partition %u",
+                          m_part_spec.start_part));
       m_file[m_part_spec.start_part]->ha_rnd_end();
     }
     break;
@@ -3441,8 +3568,13 @@ int ha_partition::rnd_end()
     file= m_file;
     do
     {
-      if (bitmap_is_set(&(m_part_info->used_partitions), (file - m_file)))
+      uint i= file - m_file;
+      if (bitmap_is_set(&m_rnd_partitions, i))
+      {
+        DBUG_PRINT("info", ("rnd_end() on partition %u", i));
         (*file)->ha_rnd_end();
+        bitmap_clear_bit(&m_rnd_partitions, i);
+      }
     } while (*(++file));
     break;
   }
@@ -3489,11 +3621,17 @@ int ha_partition::rnd_next(uchar *buf)
   }
   
   DBUG_ASSERT(m_scan_value == 1);
+  if ((result= prepare_use_partition(part_id, FALSE)))
+  {
+    m_part_spec.start_part= NO_CURRENT_PART_ID;
+    table->status= STATUS_NOT_FOUND;
+    DBUG_RETURN(result);
+  }
   file= m_file[part_id];
   
   while (TRUE)
   {
-    int result= file->rnd_next(buf);
+    result= file->rnd_next(buf);
     if (!result)
     {
       m_last_part= part_id;
@@ -3529,7 +3667,9 @@ int ha_partition::rnd_next(uchar *buf)
     m_last_part= part_id;
     m_part_spec.start_part= part_id;
     file= m_file[part_id];
-    DBUG_PRINT("info", ("rnd_init on partition %d", part_id));
+    if ((result= prepare_use_partition(part_id, FALSE)))
+      break;
+    DBUG_PRINT("info", ("rnd_init(1) on partition %d", part_id));
     if ((result= file->ha_rnd_init(1)))
       break;
     late_extra_cache(part_id);
@@ -3619,14 +3759,14 @@ void ha_partition::column_bitmaps_signal
 int ha_partition::rnd_pos(uchar * buf, uchar *pos)
 {
   uint part_id;
-  handler *file;
   DBUG_ENTER("ha_partition::rnd_pos");
 
   part_id= uint2korr((const uchar *) pos);
   DBUG_ASSERT(part_id < m_tot_parts);
-  file= m_file[part_id];
+  /* rnd_init(0) must have been called (done in prepare_use_partition) */
+  DBUG_ASSERT(bitmap_is_set(&m_rnd_partitions, part_id));
   m_last_part= part_id;
-  DBUG_RETURN(file->rnd_pos(buf, (pos + PARTITION_BYTES_IN_POS)));
+  DBUG_RETURN(m_file[part_id]->rnd_pos(buf, (pos + PARTITION_BYTES_IN_POS)));
 }
 
 
@@ -3699,7 +3839,6 @@ int ha_partition::rnd_pos_by_record(ucha
 int ha_partition::index_init(uint inx, bool sorted)
 {
   int error= 0;
-  handler **file;
   DBUG_ENTER("ha_partition::index_init");
 
   DBUG_PRINT("info", ("inx %u sorted %u", inx, sorted));
@@ -3752,17 +3891,12 @@ int ha_partition::index_init(uint inx, b
                        (*key_info)->key_part[i].field->field_index);
     } while (*(++key_info));
   }
-  file= m_file;
-  do
-  {
-    /* TODO RONM: Change to index_init() when code is stable */
-    if (bitmap_is_set(&(m_part_info->used_partitions), (file - m_file)))
-      if ((error= (*file)->ha_index_init(inx, sorted)))
-      {
-        DBUG_ASSERT(0);                           // Should never happen
-        break;
-      }
-  } while (*(++file));
+  /*
+    The real ha_index_init call is delayed until prepare_use_partition
+    is called.
+  */
+  DBUG_ASSERT(m_index_inited == MAX_KEY);
+  m_index_inited= active_index;
   DBUG_RETURN(error);
 }
 
@@ -3784,20 +3918,25 @@ int ha_partition::index_init(uint inx, b
 
 int ha_partition::index_end()
 {
-  int error= 0;
+  int tmp, error= 0;
   handler **file;
+  uint part_id;
   DBUG_ENTER("ha_partition::index_end");
 
+  DBUG_ASSERT(active_index == m_index_inited);
   active_index= MAX_KEY;
+  m_index_inited= active_index;
   m_part_spec.start_part= NO_CURRENT_PART_ID;
   file= m_file;
   do
   {
-    int tmp;
-    /* TODO RONM: Change to index_end() when code is stable */
-    if (bitmap_is_set(&(m_part_info->used_partitions), (file - m_file)))
+    part_id= file - m_file;
+    if (bitmap_is_set(&m_index_partitions, part_id))
+    {
       if ((tmp= (*file)->ha_index_end()))
         error= tmp;
+      bitmap_clear_bit(&m_index_partitions, part_id);
+    }
   } while (*(++file));
   DBUG_RETURN(error);
 }
@@ -4010,12 +4149,13 @@ int ha_partition::common_first_last(ucha
 {
   int error;
 
+  DBUG_ENTER("ha_partition::common_first_last");
   if ((error= partition_scan_set_up(buf, FALSE)))
-    return error;
+    DBUG_RETURN(error);
   if (!m_ordered_scan_ongoing &&
       m_index_scan_type != partition_index_last)
-    return handle_unordered_scan_next_partition(buf);
-  return handle_ordered_index_scan(buf, FALSE);
+    DBUG_RETURN(handle_unordered_scan_next_partition(buf));
+  DBUG_RETURN(handle_ordered_index_scan(buf, FALSE));
 }
 
 
@@ -4042,6 +4182,7 @@ int ha_partition::index_read_last_map(uc
 {
   DBUG_ENTER("ha_partition::index_read_last");
 
+  DBUG_ASSERT(active_index != MAX_KEY && m_ordered);
   m_ordered= TRUE;				// Safety measure
   end_range= 0;
   m_index_scan_type= partition_index_read_last;
@@ -4397,6 +4538,8 @@ int ha_partition::handle_unordered_scan_
 
     if (!(bitmap_is_set(&(m_part_info->used_partitions), i)))
       continue;
+    if ((error= prepare_use_partition(i, FALSE)))
+      DBUG_RETURN(error);
     file= m_file[i];
     m_part_spec.start_part= i;
     switch (m_index_scan_type) {
@@ -4502,6 +4645,9 @@ int ha_partition::handle_ordered_index_s
     uchar *rec_buf_ptr= rec_buf(i);
     int error;
     handler *file= m_file[i];
+    DBUG_PRINT("info", ("looking for a record in part %u", i));
+    if ((error= prepare_use_partition(i, FALSE)))
+      DBUG_RETURN(error);
 
     switch (m_index_scan_type) {
     case partition_index_read:
@@ -4564,6 +4710,7 @@ int ha_partition::handle_ordered_index_s
     }
     if (!error)
     {
+      DBUG_PRINT("info", ("found a record in part %u", i));
       found= TRUE;
       /*
         Initialize queue without order first, simply insert
@@ -4639,6 +4786,8 @@ int ha_partition::handle_ordered_next(uc
   handler *file= m_file[part_id];
   DBUG_ENTER("ha_partition::handle_ordered_next");
   
+  if ((error= prepare_use_partition(part_id, FALSE)))
+    DBUG_RETURN(error);
   if (m_index_scan_type == partition_read_range)
   {
     error= file->read_range_next();
@@ -4693,6 +4842,8 @@ int ha_partition::handle_ordered_prev(uc
   handler *file= m_file[part_id];
   DBUG_ENTER("ha_partition::handle_ordered_prev");
 
+  if ((error= prepare_use_partition(part_id, FALSE)))
+    DBUG_RETURN(error);
   if ((error= file->index_prev(rec_buf(part_id))))
   {
     if (error == HA_ERR_END_OF_FILE)
@@ -4823,6 +4974,13 @@ int ha_partition::info(uint flag)
         do
         {
           file= *file_array;
+          if (prepare_use_partition(file_array - m_file, FALSE))
+          {
+            sql_print_error("failed to use partition %d in info/auto_increment",
+                            (int) (file_array - m_file));
+            auto_increment_value= ~(ulonglong)(0);
+            break;
+          }
           file->info(HA_STATUS_AUTO);
           set_if_bigger(auto_increment_value,
                         file->stats.auto_increment_value);
@@ -4830,7 +4988,8 @@ int ha_partition::info(uint flag)
 
         DBUG_ASSERT(auto_increment_value);
         stats.auto_increment_value= auto_increment_value;
-        if (auto_inc_is_first_in_idx)
+        if (auto_inc_is_first_in_idx &&
+            auto_increment_value != ~(ulonglong)(0))
         {
           set_if_bigger(ha_data->next_auto_inc_val, auto_increment_value);
           ha_data->auto_inc_initialized= TRUE;
@@ -4873,17 +5032,26 @@ int ha_partition::info(uint flag)
     file_array= m_file;
     do
     {
-      if (bitmap_is_set(&(m_part_info->used_partitions), (file_array - m_file)))
+      if (bitmap_is_set(&(m_part_info->used_partitions),
+                        (file_array - m_file)))
       {
         file= *file_array;
-        file->info(HA_STATUS_VARIABLE);
-        stats.records+= file->stats.records;
-        stats.deleted+= file->stats.deleted;
-        stats.data_file_length+= file->stats.data_file_length;
-        stats.index_file_length+= file->stats.index_file_length;
-        stats.delete_length+= file->stats.delete_length;
-        if (file->stats.check_time > stats.check_time)
-          stats.check_time= file->stats.check_time;
+        if (!prepare_use_partition(file_array - m_file, FALSE))
+        {
+          file->info(HA_STATUS_VARIABLE);
+          stats.records+= file->stats.records;
+          stats.deleted+= file->stats.deleted;
+          stats.data_file_length+= file->stats.data_file_length;
+          stats.index_file_length+= file->stats.index_file_length;
+          stats.delete_length+= file->stats.delete_length;
+          if (file->stats.check_time > stats.check_time)
+            stats.check_time= file->stats.check_time;
+        }
+        else
+        {
+          sql_print_error("failed to use partition %d in info/STATUS_VARIABLE",
+                          (int) (file_array - m_file));
+        }
       }
     } while (*(++file_array));
     if (stats.records < 2 &&
@@ -4948,8 +5116,13 @@ int ha_partition::info(uint flag)
     handler *file;
 
     file= m_file[0];
-    file->info(HA_STATUS_CONST);
-    stats.create_time= file->stats.create_time;
+    if (!prepare_use_partition(0, FALSE))
+    {
+      file->info(HA_STATUS_CONST);
+      stats.create_time= file->stats.create_time;
+    }
+    else
+      sql_print_error("failed to use partition 0 in info/STATUS_CONST");
     ref_length= m_ref_length;
   }
   if (flag & HA_STATUS_ERRKEY)
@@ -4979,9 +5152,15 @@ int ha_partition::info(uint flag)
     do
     {
       file= *file_array;
-      file->info(HA_STATUS_TIME);
-      if (file->stats.update_time > stats.update_time)
-	stats.update_time= file->stats.update_time;
+      if (!prepare_use_partition(file_array - m_file, FALSE))
+      {
+        file->info(HA_STATUS_TIME);
+        if (file->stats.update_time > stats.update_time)
+          stats.update_time= file->stats.update_time;
+      }
+      else
+        sql_print_error("failed to use partition %d in info/STATUS_CONST",
+                        (int) (file_array - m_file));
     } while (*(++file_array));
   }
   DBUG_RETURN(0);
@@ -4992,21 +5171,27 @@ void ha_partition::get_dynamic_partition
                                               uint part_id)
 {
   handler *file= m_file[part_id];
-  file->info(HA_STATUS_CONST | HA_STATUS_TIME | HA_STATUS_VARIABLE |
-             HA_STATUS_NO_LOCK);
+  if (!prepare_use_partition(part_id, FALSE))
+  {
+    file->info(HA_STATUS_CONST | HA_STATUS_TIME | HA_STATUS_VARIABLE |
+               HA_STATUS_NO_LOCK);
 
-  stat_info->records=              file->stats.records;
-  stat_info->mean_rec_length=      file->stats.mean_rec_length;
-  stat_info->data_file_length=     file->stats.data_file_length;
-  stat_info->max_data_file_length= file->stats.max_data_file_length;
-  stat_info->index_file_length=    file->stats.index_file_length;
-  stat_info->delete_length=        file->stats.delete_length;
-  stat_info->create_time=          file->stats.create_time;
-  stat_info->update_time=          file->stats.update_time;
-  stat_info->check_time=           file->stats.check_time;
-  stat_info->check_sum= 0;
-  if (file->ha_table_flags() & HA_HAS_CHECKSUM)
-    stat_info->check_sum= file->checksum();
+    stat_info->records=              file->stats.records;
+    stat_info->mean_rec_length=      file->stats.mean_rec_length;
+    stat_info->data_file_length=     file->stats.data_file_length;
+    stat_info->max_data_file_length= file->stats.max_data_file_length;
+    stat_info->index_file_length=    file->stats.index_file_length;
+    stat_info->delete_length=        file->stats.delete_length;
+    stat_info->create_time=          file->stats.create_time;
+    stat_info->update_time=          file->stats.update_time;
+    stat_info->check_time=           file->stats.check_time;
+    stat_info->check_sum= 0;
+    if (file->ha_table_flags() & HA_HAS_CHECKSUM)
+      stat_info->check_sum= file->checksum();
+  }
+  else
+    sql_print_error("failed to open partition %u in info/STATUS_CONST",
+                    part_id);
   return;
 }
 
@@ -5272,8 +5457,10 @@ void ha_partition::get_dynamic_partition
     contain HA_DUPLICATE_POS. The only handler having the HA_DUPLICATE_POS
     set is the MyISAM handler and so the only handler not receiving this
     call is MyISAM.
-    Thus in effect this call is called but never used. Could be removed
-    from sql_insert.cc
+    But partitioning does not support HA_DUPLICATE_POS.
+    Thus this call is only used by partitioned MyISAM.
+    Does not need to be called if not HA_EXTRA_WRITE_CACHE has been
+    called first.
   HA_EXTRA_NO_USER_CHANGE:
     Only used by MyISAM, never called.
     Simulates lock_type as locked.
@@ -5314,7 +5501,6 @@ void ha_partition::get_dynamic_partition
     AFTER DELETE/UPDATE triggers which access to subject table.
     These flags are reset by the handler::extra(HA_EXTRA_RESET) call.
 */
-
 int ha_partition::extra(enum ha_extra_function operation)
 {
   DBUG_ENTER("ha_partition:extra");
@@ -5357,17 +5543,35 @@ int ha_partition::extra(enum ha_extra_fu
     /*
       This is only done as a part of ha_open, which is also used in
       ha_partition::open, so no need to do anything.
+      This should be changed to default, and never called.
     */
     break;
   }
   case HA_EXTRA_CACHE:
   {
+    if (m_extra_cache)
+      break;
+    m_extra_cache= TRUE;
+    m_extra_write_cache= FALSE;
     prepare_extra_cache(0);
     break;
   }
   case HA_EXTRA_NO_CACHE:
+  {
+    if (!m_extra_cache &&
+        !m_extra_write_cache &&
+        m_extra_cache_size == 0)
+      break;
+    m_extra_write_cache= FALSE;
+    m_extra_cache= FALSE;
+    m_extra_cache_size= 0;
+    DBUG_RETURN(loop_extra(operation));
+  }
   case HA_EXTRA_WRITE_CACHE:
   {
+    if (m_extra_write_cache)
+      break;
+    m_extra_write_cache= TRUE;
     m_extra_cache= FALSE;
     m_extra_cache_size= 0;
     DBUG_RETURN(loop_extra(operation));
@@ -5442,14 +5646,22 @@ int ha_partition::reset(void)
   int result= 0, tmp;
   handler **file;
   DBUG_ENTER("ha_partition::reset");
+  DBUG_ASSERT(m_part_info);
   if (m_part_info)
     bitmap_set_all(&m_part_info->used_partitions);
   file= m_file;
   do
   {
-    if ((tmp= (*file)->ha_reset()))
-      result= tmp;
+    if (bitmap_is_set(&m_reset_partitions, file - m_file))
+    {
+      if ((tmp= (*file)->ha_reset()))
+        result= tmp;
+    }
   } while (*(++file));
+  DBUG_ASSERT(bitmap_is_clear_all(&m_rnd_partitions));
+  DBUG_ASSERT(bitmap_is_clear_all(&m_index_partitions));
+  DBUG_ASSERT(bitmap_is_clear_all(&m_cache_partitions));
+  bitmap_clear_all(&m_reset_partitions);
   DBUG_RETURN(result);
 }
 
@@ -5471,6 +5683,7 @@ int ha_partition::extra_opt(enum ha_extr
   DBUG_ENTER("ha_partition::extra_opt()");
 
   DBUG_ASSERT(HA_EXTRA_CACHE == operation);
+  m_extra_cache= TRUE;
   prepare_extra_cache(cachesize);
   DBUG_RETURN(0);
 }
@@ -5491,7 +5704,6 @@ void ha_partition::prepare_extra_cache(u
 {
   DBUG_ENTER("ha_partition::prepare_extra_cache()");
 
-  m_extra_cache= TRUE;
   m_extra_cache_size= cachesize;
   if (m_part_spec.start_part != NO_CURRENT_PART_ID)
   {
@@ -5542,22 +5754,80 @@ int ha_partition::prepare_for_rename()
   RETURN VALUE
     >0                    Error code
     0                     Success
+
+  DESCRIPTION
+    There are different categories of flags:
+    - Can be called without prior use of the partition.
+    - Only to be used on the partitions left after pruning.
+    - Can be delayed until the next handler call
+      (will be handled/enabled/disabled in prepare_use_partition)
 */
 
 int ha_partition::loop_extra(enum ha_extra_function operation)
 {
   int result= 0, tmp;
-  handler **file;
+  uint i;
+  bool only_used_partitions= FALSE, use_pruning= TRUE, use_delayed= TRUE;
+  bool do_use= TRUE;
   DBUG_ENTER("ha_partition::loop_extra()");
   
-  /* 
-    TODO, 5.2: this is where you could possibly add optimisations to add the bitmap
-    _if_ a SELECT.
-  */
-  for (file= m_file; *file; file++)
+  switch (operation) {
+    case HA_EXTRA_KEYREAD:
+    case HA_EXTRA_NO_KEYREAD:
+      /* when using keys, all partition will be used, so no need to delay */
+      use_delayed= FALSE;
+      do_use= FALSE;
+      break;
+    case HA_EXTRA_WRITE_CACHE:
+      /* currently no pruning on write operations */
+      use_pruning= FALSE;
+      /* fall-through */
+    case HA_EXTRA_NO_CACHE:
+    case HA_EXTRA_IGNORE_DUP_KEY:
+    case HA_EXTRA_NO_IGNORE_DUP_KEY:
+    case HA_EXTRA_KEYREAD_PRESERVE_FIELDS:
+    case HA_EXTRA_NORMAL:
+    case HA_EXTRA_QUICK:
+      /* only neccesary on already used partitions */
+      only_used_partitions= TRUE;
+      break;
+    case HA_EXTRA_PREPARE_FOR_RENAME:
+      /* must be done on all partitions directly */
+      use_pruning= FALSE;
+      use_delayed= FALSE;
+      break;
+    case HA_EXTRA_FLUSH:
+    case HA_EXTRA_CACHE:
+      /* How is it used, check in debug */
+      DBUG_ASSERT(0);
+      only_used_partitions= TRUE;
+      use_pruning= FALSE;
+      use_delayed= FALSE;
+      break;
+    default:
+      ;
+  }
+
+  if (use_delayed)
+    DBUG_RETURN(result);
+  for (i= 0; m_file[i]; i++)
   {
-    if ((tmp= (*file)->extra(operation)))
+    if (use_pruning && !bitmap_is_set(&(m_part_info->used_partitions), i))
+      continue;
+    if (!only_used_partitions &&
+        do_use &&
+        (tmp= prepare_use_partition(i, FALSE)))
+    {
+      sql_print_error("failed to use partition in loop_extra");
+      result= tmp;
+      continue;
+    }
+    DBUG_PRINT("info", ("extra (%u) on part %u", operation, i));
+    if ((tmp= m_file[i]->extra(operation)))
       result= tmp;
+    bitmap_set_bit(&m_reset_partitions, i);
+    if (operation == HA_EXTRA_NO_CACHE)
+       bitmap_clear_bit(&m_cache_partitions, i);
   }
   DBUG_RETURN(result);
 }
@@ -5576,16 +5846,17 @@ int ha_partition::loop_extra(enum ha_ext
 
 void ha_partition::late_extra_cache(uint partition_id)
 {
-  handler *file;
   DBUG_ENTER("ha_partition::late_extra_cache");
 
   if (!m_extra_cache)
     DBUG_VOID_RETURN;
-  file= m_file[partition_id];
+  if (bitmap_is_set(&m_cache_partitions, partition_id))
+    DBUG_VOID_RETURN;
   if (m_extra_cache_size == 0)
-    VOID(file->extra(HA_EXTRA_CACHE));
+    VOID(m_file[partition_id]->extra(HA_EXTRA_CACHE));
   else
-    VOID(file->extra_opt(HA_EXTRA_CACHE, m_extra_cache_size));
+    VOID(m_file[partition_id]->extra_opt(HA_EXTRA_CACHE, m_extra_cache_size));
+  bitmap_set_bit(&m_cache_partitions, partition_id);
   DBUG_VOID_RETURN;
 }
 
@@ -5603,13 +5874,12 @@ void ha_partition::late_extra_cache(uint
 
 void ha_partition::late_extra_no_cache(uint partition_id)
 {
-  handler *file;
   DBUG_ENTER("ha_partition::late_extra_no_cache");
 
   if (!m_extra_cache)
     DBUG_VOID_RETURN;
-  file= m_file[partition_id];
-  VOID(file->extra(HA_EXTRA_NO_CACHE));
+  VOID(m_file[partition_id]->extra(HA_EXTRA_NO_CACHE));
+  bitmap_clear_bit(&m_cache_partitions, partition_id);
   DBUG_VOID_RETURN;
 }
 
@@ -5649,12 +5919,12 @@ const key_map *ha_partition::keys_to_use
 double ha_partition::scan_time()
 {
   double scan_time= 0;
-  handler **file;
+  uint i;
   DBUG_ENTER("ha_partition::scan_time");
 
-  for (file= m_file; *file; file++)
-    if (bitmap_is_set(&(m_part_info->used_partitions), (file - m_file)))
-      scan_time+= (*file)->scan_time();
+  for (i= 0; m_file[i]; i++)
+    if (bitmap_is_set(&(m_part_info->used_partitions), i))
+      scan_time+= m_file[i]->scan_time();
   DBUG_RETURN(scan_time);
 }
 
@@ -5712,8 +5982,8 @@ double ha_partition::read_time(uint inde
 ha_rows ha_partition::records_in_range(uint inx, key_range *min_key,
 				       key_range *max_key)
 {
+  ha_rows rows, in_range= 0;
   handler **file;
-  ha_rows in_range= 0;
   DBUG_ENTER("ha_partition::records_in_range");
 
   file= m_file;
@@ -5721,10 +5991,10 @@ ha_rows ha_partition::records_in_range(u
   {
     if (bitmap_is_set(&(m_part_info->used_partitions), (file - m_file)))
     {
-      ha_rows tmp_in_range= (*file)->records_in_range(inx, min_key, max_key);
-      if (tmp_in_range == HA_POS_ERROR)
-        DBUG_RETURN(tmp_in_range);
-      in_range+= tmp_in_range;
+      rows= (*file)->records_in_range(inx, min_key, max_key);
+      if (rows == HA_POS_ERROR)
+        DBUG_RETURN(HA_POS_ERROR);
+      in_range+= rows;
     }
   } while (*(++file));
   DBUG_RETURN(in_range);
@@ -5778,6 +6048,7 @@ ha_rows ha_partition::records()
   handler **file;
   DBUG_ENTER("ha_partition::records");
 
+  /* see bug#37532, why used_partitions/pruning is not considered */
   file= m_file;
   do
   {
@@ -5848,19 +6119,26 @@ const char *ha_partition::index_type(uin
 }
 
 
+/*
+  Used in I_S.TABLES
+*/
 enum row_type ha_partition::get_row_type() const
 {
   handler **file;
-  enum row_type type= (*m_file)->get_row_type();
+  enum row_type type;
+  DBUG_ENTER("ha_partition::get_row_type");
+  file= m_file;
+  type= (*file)->get_row_type();
+  file++;
 
-  for (file= m_file, file++; *file; file++)
+  for (; *file; file++)
   {
     enum row_type part_type= (*file)->get_row_type();
     if (part_type != type)
-      return ROW_TYPE_NOT_USED;
+      DBUG_RETURN(ROW_TYPE_NOT_USED);
   }
 
-  return type;
+  DBUG_RETURN(type);
 }
 
 
@@ -5989,6 +6267,9 @@ const char **ha_partition::bas_ext() con
 { return ha_partition_ext; }
 
 
+/*
+  All these functions should be possible to use on an not yet opened handler
+*/
 uint ha_partition::min_of_the_max_uint(
                        uint (handler::*operator_func)(void) const) const
 {
@@ -6348,10 +6629,8 @@ int ha_partition::indexes_are_disabled(v
   int error= 0;
 
   for (file= m_file; *file; file++)
-  {
     if ((error= (*file)->indexes_are_disabled()))
       break;
-  }
   return error;
 }
 

=== modified file 'sql/ha_partition.h'
--- a/sql/ha_partition.h	2009-02-17 14:36:54 +0000
+++ b/sql/ha_partition.h	2009-02-17 15:44:59 +0000
@@ -45,6 +45,7 @@ typedef struct st_ha_data_partition
 {
   ulonglong next_auto_inc_val;                 /**< first non reserved value */
   bool auto_inc_initialized;
+  pthread_mutex_t mutex;                   /* hold while accessing fields */
 } HA_DATA_PARTITION;
 
 #define PARTITION_BYTES_IN_POS 2
@@ -117,7 +118,7 @@ private:
                                          // external_lock
   part_id_range m_part_spec;             // Which parts to scan
   uint m_scan_value;                     // Value passed in rnd_init
-                                         // call
+                                         // call, 0 rnd_pos, 1 rnd_next, 2 off
   uint m_ref_length;                     // Length of position in this
                                          // handler object
   key_range m_start_key;                 // index read key range
@@ -132,6 +133,7 @@ private:
   bool m_create_handler;                 // Handler used to create table
   bool m_is_sub_partitioned;             // Is subpartitioned
   bool m_ordered_scan_ongoing;
+  uint m_index_inited;                   // active index set in index_init
 
   /*
     We keep track if all underlying handlers are MyISAM since MyISAM has a
@@ -155,12 +157,10 @@ private:
   */
   bool m_extra_cache;
   uint m_extra_cache_size;
+  /* HA_EXTRA_WRITE_CACHE in effect */
+  bool m_extra_write_cache;
 
   void init_handler_variables();
-  /*
-    Variables for lock structures.
-  */
-  THR_LOCK_DATA lock;                   /* MySQL lock */
 #ifdef NOT_USED
   PARTITION_SHARE *share;               /* Shared lock info */
 #endif
@@ -177,10 +177,32 @@ private:
   */
   bool auto_increment_safe_stmt_log_lock;
   /** For optimizing ha_start_bulk_insert calls */
+  bool      m_bulk_insert_active;
   MY_BITMAP m_bulk_insert_started;
   ha_rows   m_bulk_inserted_rows;
   /* used for prediction of start_bulk_insert rows */
   enum_monotonicity_info m_part_func_monotonicity_info;
+  /*
+    Record every partition which have got a rnd_init(0) call, and use those in
+    rnd_end, rnd_init(1) - scan is only set on the currently scanned partition.
+  */
+  MY_BITMAP m_rnd_partitions;
+  /*
+    Record every partition which have got a HA_EXTRA_CACHE call, and use those
+    in HA_EXTRA_NO_CACHE.
+  */
+  MY_BITMAP m_cache_partitions;
+  /*
+    Record every partition which have got a call, and use those in ::reset.
+    Could be open_files, ha_rnd_init, partition_is_open.
+  */
+  MY_BITMAP m_reset_partitions;
+  /*
+    Record every partition which have got a index_init call, and use those in
+    index_end.
+  */
+  MY_BITMAP m_index_partitions;
+
 public:
   handler *clone(MEM_ROOT *mem_root);
   virtual void set_part_info(partition_info *part_info)
@@ -299,6 +321,12 @@ public:
   */
   virtual int open(const char *name, int mode, uint test_if_locked);
   virtual int close(void);
+private:
+  int  prepare_use_partition(uint part_id, bool insert);
+#ifdef NOT_YET_USED
+  int  prepare_close_partition(uint close_id);
+#endif
+public:
 
   /*
     -------------------------------------------------------------------------
@@ -922,8 +950,9 @@ private:
     DBUG_ASSERT(table_share->ha_data && !auto_increment_lock);
     if(table_share->tmp_table == NO_TMP_TABLE)
     {
+      HA_DATA_PARTITION *ha_data= (HA_DATA_PARTITION*) table_share->ha_data;
       auto_increment_lock= TRUE;
-      pthread_mutex_lock(&table_share->mutex);
+      pthread_mutex_lock(&ha_data->mutex);
     }
   }
   virtual void unlock_auto_increment()
@@ -936,7 +965,8 @@ private:
     */
     if(auto_increment_lock && !auto_increment_safe_stmt_log_lock)
     {
-      pthread_mutex_unlock(&table_share->mutex);
+      HA_DATA_PARTITION *ha_data= (HA_DATA_PARTITION*) table_share->ha_data;
+      pthread_mutex_unlock(&ha_data->mutex);
       auto_increment_lock= FALSE;
     }
   }

Thread
bzr commit into mysql-5.1 branch (mattias.jonsson:2797) WL#3513Mattias Jonsson17 Feb