diff -Narup ./037_mariadb-10.0.15-partition_bka/sql/ha_partition.cc ./038_mariadb-10.0.15-partition_fulltext2/sql/ha_partition.cc
--- ./037_mariadb-10.0.15-partition_bka/sql/ha_partition.cc	2014-11-29 17:08:41.168796738 +0900
+++ ./038_mariadb-10.0.15-partition_fulltext2/sql/ha_partition.cc	2014-11-29 17:08:53.572795615 +0900
@@ -5546,7 +5546,6 @@ int ha_partition::rnd_pos(uchar * buf, u
   file= m_file[part_id];
   DBUG_ASSERT(bitmap_is_set(&(m_part_info->read_partitions), part_id));
   m_last_part= part_id;
-  ft_current_part= part_id;
   DBUG_RETURN(file->ha_rnd_pos(buf, (pos + PARTITION_BYTES_IN_POS)));
 }
 
@@ -6004,18 +6003,6 @@ int ha_partition::pre_read_range_first(c
 }
 
 
-int ha_partition::pre_ft_read(bool use_parallel)
-{
-  int error;
-  DBUG_ENTER("ha_partition::pre_ft_read");
-  m_pre_calling= TRUE;
-  m_pre_call_use_parallel= use_parallel;
-  error = ft_read(table->record[0]);
-  m_pre_calling= FALSE;
-  DBUG_RETURN(error);
-}
-
-
 int ha_partition::pre_rnd_next(bool use_parallel)
 {
   int error;
@@ -7015,7 +7002,7 @@ float ha_partition::ft_find_relevance(
   FT_INFO *handler, uchar *record, uint length)
 {
   st_partition_ft_info *info = (st_partition_ft_info *) handler;
-  FT_INFO *m_handler= info->part_ft_info[ft_current_part];
+  FT_INFO *m_handler= info->part_ft_info[m_last_part];
   DBUG_ENTER("ha_partition::ft_find_relevance");
   if (
     m_handler &&
@@ -7039,7 +7026,7 @@ float partition_ft_get_relevance(FT_INFO
 float ha_partition::ft_get_relevance(FT_INFO *handler)
 {
   st_partition_ft_info *info = (st_partition_ft_info *) handler;
-  FT_INFO *m_handler= info->part_ft_info[ft_current_part];
+  FT_INFO *m_handler= info->part_ft_info[m_last_part];
   DBUG_ENTER("ha_partition::ft_get_relevance");
   if (
     m_handler &&
@@ -7089,42 +7076,236 @@ _ft_vft partition_ft_vft = {
 
 int ha_partition::ft_init()
 {
-  int error= 0;
-  handler **file;
+  int error;
+  uint i= 0;
+  uint32 part_id;
   DBUG_ENTER("ha_partition::ft_init");
-  file= m_file;
-  do
+  DBUG_PRINT("info",("partition this=%p", this));
+  /*
+    For operations that may need to change data, we may need to extend
+    read_set.
+  */
+  if (m_lock_type == F_WRLCK)
   {
-    if (bitmap_is_set(&(m_part_info->read_partitions), (file - m_file)))
-      if ((error= (*file)->ft_init()))
-      {
-        DBUG_ASSERT(0);
-        DBUG_RETURN(error);
-      }
-  } while (*(++file));
-  m_ordered= FALSE;
-  end_range= 0;
-  m_index_scan_type= partition_ft_read;
-  ft_init_and_first= TRUE;
+    /*
+      If write_set contains any of the fields used in partition and
+      subpartition expression, we need to set all bits in read_set because
+      the row may need to be inserted in a different [sub]partition. In
+      other words update_row() can be converted into write_row(), which
+      requires a complete record.
+    */
+    if (bitmap_is_overlapping(&m_part_info->full_part_field_set,
+                              table->write_set))
+      bitmap_set_all(table->read_set);
+    else
+    {
+      /*
+        Some handlers only read fields as specified by the bitmap for the
+        read set. For partitioned handlers we always require that the
+        fields of the partition functions are read such that we can
+        calculate the partition id to place updated and deleted records.
+      */
+      bitmap_union(table->read_set, &m_part_info->full_part_field_set);
+    }
+  }
+
+  /* Now we see what the index of our first important partition is */
+  DBUG_PRINT("info", ("m_part_info->read_partitions: 0x%lx",
+                      (long) m_part_info->read_partitions.bitmap));
+  part_id= bitmap_get_first_set(&(m_part_info->read_partitions));
+  DBUG_PRINT("info", ("m_part_spec.start_part %d", part_id));
+
+  if (MY_BIT_NONE == part_id)
+  {
+    error= 0;
+    goto err1;
+  }
+
+  DBUG_PRINT("info", ("ft_init on partition %d", part_id));
+  /*
+    ft_end() is needed for partitioning to reset internal data if scan
+    is already in use
+  */
+  ft_end();
+  late_extra_cache(part_id);
+  m_index_scan_type = partition_ft_read;
+  for (i= part_id; i < m_tot_parts; i++)
+  {
+    if (bitmap_is_set(&(m_part_info->read_partitions), i))
+    {
+      if ((error= m_file[i]->ft_init()))
+        goto err2;
+    }
+  }
+  m_scan_value= 1;
+  m_part_spec.start_part= part_id;
+  m_part_spec.end_part= m_tot_parts - 1;
+  m_ft_init_and_first = TRUE;
+  DBUG_PRINT("info", ("m_scan_value=%d", m_scan_value));
   DBUG_RETURN(0);
+
+err2:
+  late_extra_no_cache(part_id);
+  while ((int)--i >= (int)part_id)
+  {
+    if (bitmap_is_set(&(m_part_info->read_partitions), i))
+      m_file[i]->ft_end();
+  }
+err1:
+  m_scan_value= 2;
+  m_part_spec.start_part= NO_CURRENT_PART_ID;
+  DBUG_RETURN(error);
 }
 
 
+#ifdef HA_CAN_BULK_ACCESS
+int ha_partition::pre_ft_init()
+{
+  int error;
+  uint i= 0;
+  uint32 part_id;
+  DBUG_ENTER("ha_partition::pre_ft_init");
+  DBUG_PRINT("info",("partition this=%p", this));
+  /*
+    For operations that may need to change data, we may need to extend
+    read_set.
+  */
+  if (m_lock_type == F_WRLCK)
+  {
+    /*
+      If write_set contains any of the fields used in partition and
+      subpartition expression, we need to set all bits in read_set because
+      the row may need to be inserted in a different [sub]partition. In
+      other words update_row() can be converted into write_row(), which
+      requires a complete record.
+    */
+    if (bitmap_is_overlapping(&m_part_info->full_part_field_set,
+                              table->write_set))
+      bitmap_set_all(table->read_set);
+    else
+    {
+      /*
+        Some handlers only read fields as specified by the bitmap for the
+        read set. For partitioned handlers we always require that the
+        fields of the partition functions are read such that we can
+        calculate the partition id to place updated and deleted records.
+      */
+      bitmap_union(table->read_set, &m_part_info->full_part_field_set);
+    }
+  }
+
+  /* Now we see what the index of our first important partition is */
+  DBUG_PRINT("info", ("m_part_info->read_partitions: 0x%lx",
+                      (long) m_part_info->read_partitions.bitmap));
+  part_id= bitmap_get_first_set(&(m_part_info->read_partitions));
+  DBUG_PRINT("info", ("m_part_spec.start_part %d", part_id));
+
+  if (MY_BIT_NONE == part_id)
+  {
+    error= 0;
+    goto err1;
+  }
+
+  DBUG_PRINT("info", ("ft_init on partition %d", part_id));
+  /*
+    ft_end() is needed for partitioning to reset internal data if scan
+    is already in use
+  */
+  if ((error= pre_ft_end()))
+    goto err1;
+  late_extra_cache(part_id);
+  m_index_scan_type = partition_ft_read;
+  for (i= part_id; i < m_tot_parts; i++)
+  {
+    if (bitmap_is_set(&(m_part_info->read_partitions), i))
+    {
+      if ((error= m_file[i]->pre_ft_init()))
+        goto err2;
+      bitmap_set_bit(&bulk_access_exec_bitmap, i);
+    }
+  }
+  m_scan_value= 1;
+  m_part_spec.start_part= part_id;
+  m_part_spec.end_part= m_tot_parts - 1;
+  m_ft_init_and_first = TRUE;
+  DBUG_PRINT("info", ("m_scan_value=%d", m_scan_value));
+  DBUG_RETURN(0);
+
+err2:
+  late_extra_no_cache(part_id);
+  while ((int)--i >= (int)part_id)
+  {
+    if (bitmap_is_set(&(m_part_info->read_partitions), i))
+      m_file[i]->pre_ft_end();
+  }
+err1:
+  m_scan_value= 2;
+  m_part_spec.start_part= NO_CURRENT_PART_ID;
+  DBUG_RETURN(error);
+}
+#endif
+
+
 void ha_partition::ft_end()
 {
   handler **file;
   DBUG_ENTER("ha_partition::ft_end");
-  file= m_file;
-  do
-  {
-    if (bitmap_is_set(&(m_part_info->read_partitions), (file - m_file)))
-      (*file)->ft_end();
-  } while (*(++file));
-  ft_current = NULL;
+  DBUG_PRINT("info",("partition this=%p", this));
+  switch (m_scan_value) {
+  case 2:                                       // Error
+    break;
+  case 1:
+    if (NO_CURRENT_PART_ID != m_part_spec.start_part)         // Table scan
+    {
+      late_extra_no_cache(m_part_spec.start_part);
+    }
+    file= m_file;
+    do
+    {
+      if (bitmap_is_set(&(m_part_info->read_partitions), (file - m_file)))
+        (*file)->ft_end();
+    } while (*(++file));
+    break;
+  }
+  m_scan_value= 2;
+  m_part_spec.start_part= NO_CURRENT_PART_ID;
   DBUG_VOID_RETURN;
 }
 
 
+#ifdef HA_CAN_BULK_ACCESS
+int ha_partition::pre_ft_end()
+{
+  int error = 0, tmp_error;
+  handler **file;
+  DBUG_ENTER("ha_partition::pre_ft_end");
+  DBUG_PRINT("info",("partition this=%p", this));
+  switch (m_scan_value) {
+  case 2:                                       // Error
+    break;
+  case 1:
+    if (NO_CURRENT_PART_ID != m_part_spec.start_part)         // Table scan
+    {
+      late_extra_no_cache(m_part_spec.start_part);
+    }
+    file= m_file;
+    do
+    {
+      if (bitmap_is_set(&(m_part_info->read_partitions), (file - m_file)))
+      {
+        if ((tmp_error = (*file)->pre_ft_end()))
+          error = tmp_error;
+      }
+    } while (*(++file));
+    break;
+  }
+  m_scan_value= 2;
+  m_part_spec.start_part= NO_CURRENT_PART_ID;
+  DBUG_RETURN(error);
+}
+#endif
+
+
 FT_INFO *ha_partition::ft_init_ext(
   uint flags,
   uint inx,
@@ -7192,20 +7373,103 @@ FT_INFO *ha_partition::ft_init_ext(
 }
 
 
+int ha_partition::pre_ft_read(
+  bool use_parallel
+) {
+  int error;
+  DBUG_ENTER("ha_partition::pre_ft_read");
+  DBUG_PRINT("info",("partition this=%p", this));
+  m_pre_calling= TRUE;
+  m_pre_call_use_parallel= use_parallel;
+  error = ft_read(table->record[0]);
+  m_pre_calling= FALSE;
+  DBUG_RETURN(error);
+}
+
+
 int ha_partition::ft_read(
   uchar *buf
 ) {
+  handler *file;
+  int result= HA_ERR_END_OF_FILE, error;
+  uint part_id= m_part_spec.start_part;
   DBUG_ENTER("ha_partition::ft_read");
-  if (ft_init_and_first)
+  DBUG_PRINT("info",("partition this=%p", this));
+  DBUG_PRINT("info", ("part_id=%u", part_id));
+
+  if (NO_CURRENT_PART_ID == part_id)
   {
-    ft_init_and_first= FALSE;
-    DBUG_RETURN(common_index_read(buf, FALSE));
+    /*
+      The original set of partitions to scan was empty and thus we report
+      the result here.
+    */
+    DBUG_PRINT("info", ("NO_CURRENT_PART_ID"));
+    goto end;
   }
-  if (!m_ordered_scan_ongoing)
+  
+  DBUG_ASSERT(m_scan_value == 1);
+
+  if (m_ft_init_and_first)
   {
-    DBUG_RETURN(handle_unordered_next(buf, FALSE));
+    m_ft_init_and_first = FALSE;
+    if (!bulk_access_executing)
+    {
+      if (check_parallel_search())
+        error= handle_pre_scan(FALSE, TRUE);
+      else
+        error = handle_pre_scan(FALSE, FALSE);
+      if (m_pre_calling || error)
+        DBUG_RETURN(error);
+    }
   }
-  DBUG_RETURN(handle_ordered_next(buf, FALSE));
+
+  file= m_file[part_id];
+  
+  while (TRUE)
+  {
+    result= file->ft_read(buf);
+    if (!result)
+    {
+      m_last_part= part_id;
+      m_part_spec.start_part= part_id;
+      table->status= 0;
+      DBUG_RETURN(0);
+    }
+
+    /*
+      if we get here, then the current partition ft_next returned failure
+    */
+    if (result == HA_ERR_RECORD_DELETED)
+      continue;                               // Probably MyISAM
+
+    if (result != HA_ERR_END_OF_FILE)
+      goto end_dont_reset_start_part;         // Return error
+
+    /* End current partition */
+    late_extra_no_cache(part_id);
+    DBUG_PRINT("info", ("ft_end on partition %d", part_id));
+    
+    /* Shift to next partition */
+    while (++part_id < m_tot_parts &&
+           !bitmap_is_set(&(m_part_info->read_partitions), part_id))
+      ;
+    if (part_id >= m_tot_parts)
+    {
+      result= HA_ERR_END_OF_FILE;
+      break;
+    }
+    m_last_part= part_id;
+    m_part_spec.start_part= part_id;
+    file= m_file[part_id];
+    DBUG_PRINT("info", ("ft_init on partition %d", part_id));
+    late_extra_cache(part_id);
+  }
+
+end:
+  m_part_spec.start_part= NO_CURRENT_PART_ID;
+end_dont_reset_start_part:
+  table->status= STATUS_NOT_FOUND;
+  DBUG_RETURN(result);
 }
 
 
@@ -7241,9 +7505,6 @@ int ha_partition::partition_scan_set_up(
 
   if (idx_read_flag)
   {
-    if (m_index_scan_type == partition_ft_read)
-      get_partition_set(table,buf,MAX_KEY,&m_start_key,&m_part_spec);
-    else
     get_partition_set(table,buf,active_index,&m_start_key,&m_part_spec);
   }
   else
@@ -7547,15 +7808,6 @@ int ha_partition::handle_unordered_next(
       DBUG_RETURN(0);
     }
   }
-  else if (m_index_scan_type == partition_ft_read)
-  {
-    if (!(error= file->ft_read(buf)))
-    {
-      ft_current_part= m_part_spec.start_part;
-      m_last_part= m_part_spec.start_part;
-      DBUG_RETURN(0);
-    }
-  }
   else if (is_next_same)
   {
     if (!(error= file->ha_index_next_same(buf, m_start_key.key,
@@ -7633,11 +7885,6 @@ int ha_partition::handle_unordered_scan_
       error= file->read_range_first(m_start_key.key? &m_start_key: NULL,
                                     end_range, eq_range, FALSE);
       break;
-    case partition_ft_read:
-      DBUG_PRINT("info", ("ft_read on partition %d", i));
-      error= file->ft_read(buf);
-      ft_current_part= i;
-      break;
     case partition_index_read:
       DBUG_PRINT("info", ("index_read on partition %d", i));
       error= file->ha_index_read_map(buf, m_start_key.key,
@@ -7832,11 +8079,6 @@ int ha_partition::handle_ordered_index_s
       }
       break;
     }
-    case partition_ft_read:
-      error= file->ft_read(rec_buf_ptr);
-      ft_current_part= i;
-      reverse_order= FALSE;
-      break;
     default:
       DBUG_ASSERT(FALSE);
       DBUG_RETURN(HA_ERR_END_OF_FILE);
@@ -8175,11 +8417,6 @@ int ha_partition::handle_ordered_next(uc
       }
     }
   }
-  else if (m_index_scan_type == partition_ft_read)
-  {
-    error= file->ft_read(rec_buf);
-    ft_current_part= part_id;
-  }
   else if (!is_next_same)
     error= file->ha_index_next(rec_buf);
   else
diff -Narup ./037_mariadb-10.0.15-partition_bka/sql/ha_partition.h ./038_mariadb-10.0.15-partition_fulltext2/sql/ha_partition.h
--- ./037_mariadb-10.0.15-partition_bka/sql/ha_partition.h	2014-11-29 17:07:29.309796916 +0900
+++ ./038_mariadb-10.0.15-partition_fulltext2/sql/ha_partition.h	2014-11-29 17:08:53.572795615 +0900
@@ -1340,14 +1340,15 @@ public:
   */
   st_partition_ft_info *ft_first;
   st_partition_ft_info *ft_current;
-  uint ft_current_part;
-  bool ft_init_and_first;
+  bool m_ft_init_and_first;
   virtual float ft_find_relevance(
     FT_INFO *handler, uchar *record, uint length);
   virtual float ft_get_relevance(FT_INFO *handler);
   void ft_close_search(FT_INFO *handler);
   virtual int ft_init();
-  void ft_end();
+  virtual int pre_ft_init();
+  virtual void ft_end();
+  virtual int pre_ft_end();
   virtual FT_INFO *ft_init_ext(uint flags,uint inx,String *key);
   virtual int ft_read(uchar *buf);
 
diff -Narup ./037_mariadb-10.0.15-partition_bka/sql/handler.h ./038_mariadb-10.0.15-partition_fulltext2/sql/handler.h
--- ./037_mariadb-10.0.15-partition_bka/sql/handler.h	2014-11-29 17:08:10.843795533 +0900
+++ ./038_mariadb-10.0.15-partition_fulltext2/sql/handler.h	2014-11-29 17:08:53.576754903 +0900
@@ -3134,7 +3134,9 @@ public:
   int compare_key(key_range *range);
   int compare_key2(key_range *range);
   virtual int ft_init() { return HA_ERR_WRONG_COMMAND; }
-  void ft_end() { ft_handler=NULL; }
+  virtual int pre_ft_init() { return HA_ERR_WRONG_COMMAND; }
+  virtual void ft_end() { ft_handler=NULL; }
+  virtual int pre_ft_end() { return 0; }
   virtual FT_INFO *ft_init_ext(uint flags, uint inx,String *key)
     { return NULL; }
 private:
