List:Commits« Previous MessageNext Message »
From:mattiasj Date:February 21 2008 9:09am
Subject:bk commit into 5.1 tree (mattiasj:1.2518) BUG#33479
View as plain text  
Below is the list of changes that have just been committed into a local
5.1 repository of mattiasj.  When mattiasj does a push these changes
will be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet@stripped, 2008-02-21 10:09:43+01:00, mattiasj@witty. +3 -0
  Bug#33479: auto_increment failures in partitioning
  
  Several problems with auto_increment in partitioning
  (with MyISAM, InnoDB and Falcon)
  
  Code only patch (the test cases will be in a separate patches
  5.1+ (InnoDB+MyISAM) and 6.0 (Falcon)
  
  Changed the auto_increment handling for partitioning:
  Added a ha_data variable in table_share for storage engine specific data such as
  auto_increment value handling in partitioning
  and using the ha_data->mutex to lock around read + update.
  
  The idea is this:
  Store the table's reserved auto_increment value in
  the TABLE_SHARE and use a mutex to lock it for reading and updateing it,
  only accessing all partitions when it is not initialized.
  Also allow reservations of ranges, and if no one has done a reservation
  afterwards, lower the reservation to what was actually used after
  the statement is done (via release_auto_increment from WL#3146).
  
  This should be quite fast and work with any local storage engine.

  sql/ha_partition.cc@stripped, 2008-02-21 10:09:42+01:00, mattiasj@witty. +262 -88
    Bug#33479: Failures using auto_increment and partitioning
    
    Changed ha_partition::get_auto_increment from file->get_auto_increment
    to file->info(HA_AUTO_STATUS), since it is works better with InnoDB
    
    Using the new table_share->ha_data for keeping the auto_increment
    value, shared by all instances of the same table.
    It is read+updated when holding a auto_increment specific mutex.
    Also added release_auto_increment to decrease gaps if possible.

  sql/ha_partition.h@stripped, 2008-02-21 10:09:42+01:00, mattiasj@witty. +39 -1
    Bug#33479: Failures using auto_increment and partitioning
    
    Added a new struct HA_DATA_PARTITION to be used in table_share->ha_data
    Added a private function to set auto_increment values if needed
    Removed the restore_auto_increment (the hander version is better)
    Added lock/unlock functions for auto_increment handling.

  sql/table.h@stripped, 2008-02-21 10:09:42+01:00, mattiasj@witty. +4 -0
    Bug#33479: Failures using auto_increment and partitioning
    
    Added a variable in table_share: ha_data for storage of storage engine
    specific data (such as auto_increment handling in partitioning).

diff -Nrup a/sql/ha_partition.cc b/sql/ha_partition.cc
--- a/sql/ha_partition.cc	2007-12-20 19:16:51 +01:00
+++ b/sql/ha_partition.cc	2008-02-21 10:09:42 +01:00
@@ -1570,13 +1570,13 @@ int ha_partition::copy_partitions(ulongl
            table since it doesn't fit into any partition any longer due to
            changed partitioning ranges or list values.
         */
-        deleted++;
+        (*deleted)++;
       }
       else
       {
         THD *thd= ha_thd();
         /* Copy record to new handler */
-        copied++;
+        (*copied)++;
         tmp_disable_binlog(thd); /* Do not replicate the low-level changes. */
         result= m_new_file[new_part]->ha_write_row(m_rec0);
         reenable_binlog(thd);
@@ -2354,6 +2354,24 @@ int ha_partition::open(const char *name,
                          0, key_rec_cmp, (void*)this)))
     goto err_handler;
 
+
+  if (table_share->tmp_table == NO_TMP_TABLE)
+    pthread_mutex_lock(&table->s->mutex);
+  if (!table_share->ha_data)
+  {
+    HA_DATA_PARTITION *ha_data;
+    /* currently only needed for auto_increment */
+    table_share->ha_data= alloc_root(&table_share->mem_root,
+                                     sizeof(HA_DATA_PARTITION));
+    if (!table_share->ha_data)
+      goto err_handler;
+    ha_data= (HA_DATA_PARTITION*) table_share->ha_data;
+    bzero(ha_data, sizeof(HA_DATA_PARTITION));
+    if (table_share->tmp_table == NO_TMP_TABLE)
+      pthread_mutex_init(&ha_data->mutex, MY_MUTEX_INIT_FAST);
+  }
+  if (table_share->tmp_table == NO_TMP_TABLE)
+    pthread_mutex_unlock(&table->s->mutex);
   /*
     Some handlers update statistics as part of the open call. This will in
     some cases corrupt the statistics of the partition handler and thus
@@ -2695,8 +2713,10 @@ int ha_partition::write_row(uchar * buf)
   uint32 part_id;
   int error;
   longlong func_value;
-  bool autoincrement_lock= FALSE;
+  bool have_auto_increment= table->next_number_field && buf == table->record[0];
+  bool auto_increment_lock= FALSE;
   my_bitmap_map *old_map;
+  HA_DATA_PARTITION *ha_data= (HA_DATA_PARTITION*) table_share->ha_data;
   THD *thd= ha_thd();
 #ifdef NOT_NEEDED
   uchar *rec0= m_rec0;
@@ -2712,31 +2732,33 @@ int ha_partition::write_row(uchar * buf)
     If we have an auto_increment column and we are writing a changed row
     or a new row, then update the auto_increment value in the record.
   */
-  if (table->next_number_field && buf == table->record[0])
+  if (have_auto_increment)
   {
     /*
-      Some engines (InnoDB for example) can change autoincrement
-      counter only after 'table->write_row' operation.
-      So if another thread gets inside the ha_partition::write_row
-      before it is complete, it gets same auto_increment value,
-      which means DUP_KEY error (bug #27405)
-      Here we separate the access using table_share->mutex, and
-      use autoincrement_lock variable to avoid unnecessary locks.
-      Probably not an ideal solution.
+      must initialize it before write if it explicity set,
+      since the partitions can have higher auto_increment_value
+      which should be used.
     */
-    if (table_share->tmp_table == NO_TMP_TABLE)
+    if (!ha_data->auto_inc_initialized && !table->s->next_number_keypart)
     {
-      /*
-        Bug#30878 crash when alter table from non partitioned table
-        to partitioned.
-        Checking if tmp table then there is no need to lock,
-        and the table_share->mutex may not be initialised.
-      */
-      autoincrement_lock= TRUE;
-      pthread_mutex_lock(&table_share->mutex);
+      if (table_share->tmp_table != NO_TMP_TABLE)
+        info(HA_STATUS_AUTO);
+      else
+      {
+        /*
+          If auto_increment in table_share is not initialized, we must
+          have a mutex around update_auto_increment,
+          get_auto_increment and write_row.
+          (get_auto_increment can be called from update_auto_increment
+          and update_auto_increment can be called from write_row).
+          Not needed for tmp-tables, or auto_increment in secondary
+          columns in multi-column index.
+          Also check ha_partition::get_auto_increment().
+        */
+        lock_auto_increment(&auto_increment_lock);
+      }
     }
     error= update_auto_increment();
-
     /*
       If we have failed to set the auto-increment value for this row,
       it is highly likely that we will not be able to insert it into
@@ -2771,10 +2793,11 @@ int ha_partition::write_row(uchar * buf)
   DBUG_PRINT("info", ("Insert in partition %d", 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(&auto_increment_lock);
   reenable_binlog(thd);
 exit:
-  if (autoincrement_lock)
-    pthread_mutex_unlock(&table_share->mutex);
+  unlock_auto_increment(&auto_increment_lock);
   DBUG_RETURN(error);
 }
 
@@ -2838,17 +2861,25 @@ int ha_partition::update_row(const uchar
     goto exit;
   }
 
-  /*
-    TODO:
-      set_internal_auto_increment=
-        max(set_internal_auto_increment, new_data->auto_increment)
-  */
   m_last_part= new_part_id;
   if (new_part_id == old_part_id)
   {
     DBUG_PRINT("info", ("Update in partition %d", new_part_id));
     tmp_disable_binlog(thd); /* Do not replicate the low-level changes. */
     error= m_file[new_part_id]->ha_update_row(old_data, new_data);
+    /*
+      if updating a auto_increment row, update
+      auto_increment_value in table_share if needed
+      (not to be used if auto_increment on secondary field in a multi-
+      column index)
+    */
+    if (table->next_number_field && new_data == table->record[0] &&
+        !table->s->next_number_keypart)
+    {
+      bool auto_increment_lock= FALSE;
+      set_auto_increment_if_higher(&auto_increment_lock);
+      unlock_auto_increment(&auto_increment_lock);
+    }
     reenable_binlog(thd);
     goto exit;
   }
@@ -4412,20 +4443,46 @@ int ha_partition::handle_ordered_prev(uc
 int ha_partition::info(uint flag)
 {
   handler *file, **file_array;
+  HA_DATA_PARTITION *ha_data= (HA_DATA_PARTITION*) table_share->ha_data;
   DBUG_ENTER("ha_partition:info");
 
   if (flag & HA_STATUS_AUTO)
   {
-    ulonglong auto_increment_value= 0;
+    bool auto_increment_lock= FALSE;
     DBUG_PRINT("info", ("HA_STATUS_AUTO"));
-    file_array= m_file;
-    do
+    if (ha_data->auto_inc_initialized && !table_share->next_number_keypart)
     {
-      file= *file_array;
-      file->info(HA_STATUS_AUTO);
-      set_if_bigger(auto_increment_value, file->stats.auto_increment_value);
-    } while (*(++file_array));
-    stats.auto_increment_value= auto_increment_value;
+      DBUG_PRINT("info", ("Using ha_data->next_auto_inc_val: %llu",
+                          ha_data->next_auto_inc_val));
+
+      lock_auto_increment(&auto_increment_lock);
+      stats.auto_increment_value= ha_data->next_auto_inc_val;
+      unlock_auto_increment(&auto_increment_lock);
+    }
+    else
+    {
+      ulonglong auto_increment_value= 0;
+      file_array= m_file;
+      DBUG_PRINT("info", ("checking all partitions for auto_increment_value"));
+      do
+      {
+        file= *file_array;
+        file->info(HA_STATUS_AUTO);
+        set_if_bigger(auto_increment_value, file->stats.auto_increment_value);
+        DBUG_PRINT("info", ("file->stats.auto_increment_value: %llu",
+                            file->stats.auto_increment_value));
+      } while (*(++file_array));
+      stats.auto_increment_value= auto_increment_value;
+      if (!table_share->next_number_keypart)
+      {
+        lock_auto_increment(&auto_increment_lock);
+        set_if_bigger(ha_data->next_auto_inc_val, auto_increment_value);
+        ha_data->auto_inc_initialized= TRUE;
+        unlock_auto_increment(&auto_increment_lock);
+      }
+    }
+    DBUG_PRINT("info", ("stats.auto_increment_value: %llu",
+                        stats.auto_increment_value));
   }
   if (flag & HA_STATUS_VARIABLE)
   {
@@ -5579,19 +5636,29 @@ int ha_partition::cmp_ref(const uchar *r
                 MODULE auto increment
 ****************************************************************************/
 
-void ha_partition::restore_auto_increment(ulonglong)
-{
-  DBUG_ENTER("ha_partition::restore_auto_increment");
 
-  DBUG_VOID_RETURN;
+int ha_partition::ha_reset_auto_increment(ulonglong value)
+{
+  handler **pos, **end;
+  int res;
+  HA_DATA_PARTITION *ha_data= (HA_DATA_PARTITION*) table_share->ha_data;
+  DBUG_ENTER("ha_partition::ha_reset_auto_increment");
+  DBUG_PRINT("info", ("value: %llu", value));
+  for (pos=m_file, end= m_file+ m_tot_parts; pos != end ; pos++)
+    if ((res= (*pos)->ha_reset_auto_increment(value)) != 0)
+      DBUG_RETURN(res);
+  ha_data->auto_inc_initialized= FALSE;
+  DBUG_RETURN(0);
 }
 
 
 /*
   This method is called by update_auto_increment which in turn is called
-  by the individual handlers as part of write_row. We will always let
-  the first handler keep track of the auto increment value for all
-  partitions.
+  by the individual handlers as part of write_row. We use the
+  table_share->ha_data->next_auto_inc_val, or search all
+  partitions for the highest auto_increment_value if not initialized or
+  if auto_increment field is a secondary part of a key, we must search
+  every partition with a mutex to be sure of correctness.
 */
 
 void ha_partition::get_auto_increment(ulonglong offset, ulonglong increment,
@@ -5599,59 +5666,143 @@ void ha_partition::get_auto_increment(ul
                                       ulonglong *first_value,
                                       ulonglong *nb_reserved_values)
 {
-  ulonglong first_value_part, last_value_part, nb_reserved_values_part,
-    last_value= ~ (ulonglong) 0;
-  handler **pos, **end;
-  bool retry= TRUE;
+  HA_DATA_PARTITION *ha_data= (HA_DATA_PARTITION*) table_share->ha_data;
   DBUG_ENTER("ha_partition::get_auto_increment");
-
-again:
-  for (pos=m_file, end= m_file+ m_tot_parts; pos != end ; pos++)
+  DBUG_PRINT("info", ("offset: %llu inc: %llu desired_values: %llu "
+                      "first_value: %llu", offset, increment,
+                      nb_desired_values, *first_value));
+  DBUG_ASSERT(increment && nb_desired_values);
+  *first_value= 0;
+  if (table->s->next_number_keypart)
   {
-    first_value_part= *first_value;
-    (*pos)->get_auto_increment(offset, increment, nb_desired_values,
-                               &first_value_part, &nb_reserved_values_part);
-    if (first_value_part == ~(ulonglong)(0)) // error in one partition
-    {
-      *first_value= first_value_part;
-      sql_print_error("Partition failed to reserve auto_increment value");
-      DBUG_VOID_RETURN;
-    }
     /*
-      Partition has reserved an interval. Intersect it with the intervals
-      already reserved for the previous partitions.
+      next_number_keypart is != 0 if the auto_increment column is a secondary
+      column in the index (it is allowed in MyISAM)
     */
-    last_value_part= (nb_reserved_values_part == ULONGLONG_MAX) ?
-      ULONGLONG_MAX : (first_value_part + nb_reserved_values_part * increment);
-    set_if_bigger(*first_value, first_value_part);
-    set_if_smaller(last_value, last_value_part);
-  }
-  if (last_value < *first_value) /* empty intersection, error */
-  {
+    DBUG_PRINT("info", ("next_number_keypart != 0"));
+    ulonglong first_value_part, last_value_part, nb_reserved_values_part,
+      last_value= ~ (ulonglong) 0;
+    handler **pos, **end;
+    bool auto_increment_lock= FALSE;
     /*
-      When we have an empty intersection, it means that one or more
-      partitions may have a significantly different autoinc next value.
-      We should not fail here - it just means that we should try to
-      find a new reservation making use of the current *first_value
-      wbich should now be compatible with all partitions.
+      Must lock and find highest value among all partitions
     */
-    if (retry)
+    lock_auto_increment(&auto_increment_lock);
+    for (pos=m_file, end= m_file+ m_tot_parts; pos != end ; pos++)
     {
-      retry= FALSE;
-      last_value= ~ (ulonglong) 0;
-      release_auto_increment();
-      goto again;
+      first_value_part= 0;
+      (*pos)->get_auto_increment(offset, increment, nb_desired_values,
+                                 &first_value_part, &nb_reserved_values_part);
+      if (first_value_part == ~(ulonglong)(0)) // error in one partition
+      {
+        *first_value= first_value_part;
+        sql_print_error("Partition failed to reserve auto_increment value");
+        unlock_auto_increment(&auto_increment_lock);
+        DBUG_VOID_RETURN;
+      }
+      DBUG_PRINT("info", ("partition loop, first_value_part: %llu", first_value_part));
+      /*
+        Partition has reserved an interval. Intersect it with the intervals
+        already reserved for the previous partitions.
+      */
+      last_value_part= (nb_reserved_values_part == ULONGLONG_MAX) ?
+        ULONGLONG_MAX : (first_value_part + nb_reserved_values_part * increment);
+      set_if_bigger(*first_value, first_value_part);
+      set_if_smaller(last_value, last_value_part);
+    }
+    DBUG_PRINT("info", ("*first_value: %llu last_value: %llu", *first_value,
+                        last_value));
+    if (last_value < *first_value)
+    {
+      /*
+        Set last_value to *first_value. This is safe because of the mutex.
+      */
+      last_value= *first_value;
+    }
+    if (increment)                                // If not check for values
+    {
+      *nb_reserved_values= (last_value == ULONGLONG_MAX) ?
+        ULONGLONG_MAX : ((last_value - *first_value) / increment);
     }
+    unlock_auto_increment(&auto_increment_lock);
+  }
+  else if (!ha_data->auto_inc_initialized)
+  {
+    ulonglong first_value_part;
+    handler **pos, **end;
     /*
-      We should not get here.
+      Not initialized, but should be locked in ha_partition::write_row().
+      (Or is a temporary table).
+      Initialize to highest value among all partitions
     */
-    sql_print_error("Failed to calculate auto_increment value for partition");
-    
-    *first_value= ~(ulonglong)(0);
+    DBUG_PRINT("info", ("Initializing auto_increment in table_share"));
+    for (pos=m_file, end= m_file+ m_tot_parts; pos != end ; pos++)
+    {
+      first_value_part= 0;
+      /*
+        Use (*pos)->info() and (*pos)->stats.auto_increment_value instead of
+        (*pos)->get_auto_increment() since InnoDB does not handle it correctly
+        for partitioned tables.
+      */
+      (*pos)->info(HA_STATUS_AUTO);
+      first_value_part= (*pos)->stats.auto_increment_value;
+      if (first_value_part == ~(ulonglong)(0)) // error in one partition
+      {
+        *first_value= first_value_part;
+        sql_print_error("Partition failed to reserve auto_increment value");
+        DBUG_VOID_RETURN;
+      }
+      DBUG_PRINT("info", ("partition loop, first_value_part: %llu", first_value_part));
+      set_if_bigger(*first_value, first_value_part);
+    }
+    if (*first_value == 0 &&
+        !(table->auto_increment_field_not_null &&
+          table->next_number_field->val_int() == 0 &&
+          current_thd->variables.sql_mode & MODE_NO_AUTO_VALUE_ON_ZERO))
+    {
+      /*
+        First auto_increment, set to 1
+        (if not explicit number 0 and not null and sql_mode set)
+      */
+      DBUG_PRINT("info", ("Setting *first_value to 1"));
+      *first_value= 1;
+    }
+    DBUG_PRINT("info", ("*first_value: %llu", *first_value));
+
+    ha_data->next_auto_inc_val= *first_value + nb_desired_values * increment;
+    ha_data->auto_inc_initialized= TRUE;
+    *nb_reserved_values= nb_desired_values;
   }
-  if (increment)                                // If not check for values
-    *nb_reserved_values= (last_value == ULONGLONG_MAX) ?
-      ULONGLONG_MAX : ((last_value - *first_value) / increment);
+  else
+  {
+    /*
+      This is an optimized solution that not require
+      a mutex around write_row for auto_increment handling 
+      Only for a picking the next auto_increment_value.
+
+      Get a lock for handling the auto_increment in table_share->ha_data
+      for avoiding two concurrent statements getting the same
+      number.
+    */ 
+    bool auto_increment_lock= FALSE;
+
+    DBUG_PRINT("info", ("reserving %llu auto_inc values", nb_desired_values));
+    lock_auto_increment(&auto_increment_lock);
+
+    DBUG_PRINT("info", ("ha_data->next_auto_inc_val: %llu",
+                        ha_data->next_auto_inc_val));
+    /* this gets corrected (for offset) in update_auto_increment */
+    *first_value= ha_data->next_auto_inc_val;
+    ha_data->next_auto_inc_val= *first_value + nb_desired_values * increment;
+
+    unlock_auto_increment(&auto_increment_lock);
+    *nb_reserved_values= nb_desired_values;
+  }
+  DBUG_PRINT("info", ("first_value: %llu next_auto_inc_val: %llu "
+                      "nb_reserved_values: %llu", *first_value,
+                      ha_data->next_auto_inc_val,
+                      *nb_reserved_values));
+
   DBUG_VOID_RETURN;
 }
 
@@ -5659,9 +5810,32 @@ void ha_partition::release_auto_incremen
 {
   DBUG_ENTER("ha_partition::release_auto_increment");
 
-  for (uint i= 0; i < m_tot_parts; i++)
+  if (table->s->next_number_keypart)
+  {
+    for (uint i= 0; i < m_tot_parts; i++)
+      {
+      m_file[i]->ha_release_auto_increment();
+    }
+  }
+  else
   {
-    m_file[i]->ha_release_auto_increment();
+    HA_DATA_PARTITION *ha_data= (HA_DATA_PARTITION*) table_share->ha_data;
+    bool auto_increment_lock= FALSE;
+    DBUG_PRINT("info", ("next_auto_inc_val: %llu cur_row_max: %llu min: %llu",
+                        ha_data->next_auto_inc_val,
+                        auto_inc_interval_for_cur_row.maximum(),
+                        auto_inc_interval_for_cur_row.minimum()));
+    if (next_insert_id)
+    {
+      lock_auto_increment(&auto_increment_lock);
+      if (next_insert_id < ha_data->next_auto_inc_val &&
+          auto_inc_interval_for_cur_row.maximum() >= ha_data->next_auto_inc_val)
+        ha_data->next_auto_inc_val= next_insert_id;
+      unlock_auto_increment(&auto_increment_lock);
+    }
+    DBUG_PRINT("info", ("next_auto_inc_val: %llu next_ins_id: %llu init: %u",
+                        ha_data->next_auto_inc_val, next_insert_id,
+                        ha_data->auto_inc_initialized));
   }
   DBUG_VOID_RETURN;
 }
diff -Nrup a/sql/ha_partition.h b/sql/ha_partition.h
--- a/sql/ha_partition.h	2007-09-24 15:30:28 +02:00
+++ b/sql/ha_partition.h	2008-02-21 10:09:42 +01:00
@@ -37,6 +37,13 @@ typedef struct st_partition_share
 } PARTITION_SHARE;
 #endif
 
+/* TODO: move all partition specific data from TABLE_SHARE here */
+typedef struct st_ha_data_partition
+{
+  ulonglong next_auto_inc_val;
+  bool auto_inc_initialized;
+  pthread_mutex_t mutex;
+} HA_DATA_PARTITION;
 
 #define PARTITION_BYTES_IN_POS 2
 class ha_partition :public handler
@@ -828,12 +835,43 @@ public:
     auto_increment_column_changed
      -------------------------------------------------------------------------
   */
-  virtual void restore_auto_increment(ulonglong prev_insert_id);
   virtual void get_auto_increment(ulonglong offset, ulonglong increment,
                                   ulonglong nb_desired_values,
                                   ulonglong *first_value,
                                   ulonglong *nb_reserved_values);
   virtual void release_auto_increment();
+  virtual int ha_reset_auto_increment(ulonglong value);
+private:
+  inline virtual void lock_auto_increment(bool *is_locked)
+  {
+    if(!(*is_locked) && table_share->tmp_table == NO_TMP_TABLE)
+    {
+      HA_DATA_PARTITION *ha_data= (HA_DATA_PARTITION*) table_share->ha_data;
+      *is_locked= TRUE;
+      pthread_mutex_lock(&ha_data->mutex);
+    }
+  }
+  inline virtual void unlock_auto_increment(bool *is_locked)
+  {
+    if(*is_locked)
+    {
+      HA_DATA_PARTITION *ha_data= (HA_DATA_PARTITION*) table_share->ha_data;
+      pthread_mutex_unlock(&ha_data->mutex);
+      *is_locked= FALSE;
+    }
+  }
+  inline virtual void set_auto_increment_if_higher(bool *is_locked)
+  {
+    ulonglong nr= table->next_number_field->val_int();
+    HA_DATA_PARTITION *ha_data= (HA_DATA_PARTITION*) table_share->ha_data;
+    if (nr >= ha_data->next_auto_inc_val)
+    {
+      lock_auto_increment(is_locked);
+      ha_data->next_auto_inc_val= nr + 1;
+    }
+  }
+
+public:
 
   /*
      -------------------------------------------------------------------------
diff -Nrup a/sql/table.h b/sql/table.h
--- a/sql/table.h	2007-12-20 21:24:07 +01:00
+++ b/sql/table.h	2008-02-21 10:09:42 +01:00
@@ -358,6 +358,7 @@ typedef struct st_table_share
   */
   int cached_row_logging_check;
 
+  /* TODO: Move into *ha_data for partitioning */
 #ifdef WITH_PARTITION_STORAGE_ENGINE
   bool auto_partitioned;
   const char *partition_info;
@@ -367,6 +368,9 @@ typedef struct st_table_share
   uint part_state_len;
   handlerton *default_part_db_type;
 #endif
+
+  /* place to store storage engine specific data */
+  void *ha_data;
 
 
   /*
Thread
bk commit into 5.1 tree (mattiasj:1.2518) BUG#33479mattiasj21 Feb
  • Re: bk commit into 5.1 tree (mattiasj:1.2518) BUG#33479Sergei Golubchik29 Feb
    • Re: bk commit into 5.1 tree (mattiasj:1.2518) BUG#33479Mattias Jonsson3 Mar
      • Re: bk commit into 5.1 tree (mattiasj:1.2518) BUG#33479Sergei Golubchik7 Mar