diff -Narup ./004_mariadb-10.0.15-slave-trx-retry/sql/ha_partition.cc ./005_mariadb-10.0.15-hs/sql/ha_partition.cc
--- ./004_mariadb-10.0.15-slave-trx-retry/sql/ha_partition.cc	2014-11-29 17:01:25.372795661 +0900
+++ ./005_mariadb-10.0.15-hs/sql/ha_partition.cc	2014-11-29 17:01:50.121564027 +0900
@@ -75,7 +75,6 @@
 #define PARTITION_DISABLED_TABLE_FLAGS (HA_CAN_GEOMETRY | \
                                         HA_CAN_FULLTEXT | \
                                         HA_DUPLICATE_POS | \
-                                        HA_CAN_SQL_HANDLER | \
                                         HA_CAN_INSERT_DELAYED | \
                                         HA_READ_BEFORE_WRITE_REMOVAL)
 static const char *ha_par_ext= ".par";
@@ -5691,7 +5690,8 @@ int ha_partition::index_next(uchar * buf
     and if direction changes, we must step back those partitions in
     the record queue so we don't return a value from the wrong direction.
   */
-  DBUG_ASSERT(m_index_scan_type != partition_index_last);
+  if (m_index_scan_type == partition_index_last)
+    DBUG_RETURN(HA_ERR_WRONG_COMMAND);
   if (!m_ordered_scan_ongoing)
   {
     DBUG_RETURN(handle_unordered_next(buf, FALSE));
@@ -5724,7 +5724,8 @@ int ha_partition::index_next_same(uchar 
   decrement_statistics(&SSV::ha_read_next_count);
 
   DBUG_ASSERT(keylen == m_start_key.length);
-  DBUG_ASSERT(m_index_scan_type != partition_index_last);
+  if (m_index_scan_type == partition_index_last)
+    DBUG_RETURN(HA_ERR_WRONG_COMMAND);
   if (!m_ordered_scan_ongoing)
     DBUG_RETURN(handle_unordered_next(buf, TRUE));
   DBUG_RETURN(handle_ordered_next(buf, TRUE));
@@ -5752,7 +5753,8 @@ int ha_partition::index_prev(uchar * buf
   decrement_statistics(&SSV::ha_read_prev_count);
 
   /* TODO: read comment in index_next */
-  DBUG_ASSERT(m_index_scan_type != partition_index_first);
+  if (m_index_scan_type == partition_index_first)
+    DBUG_RETURN(HA_ERR_WRONG_COMMAND);
   DBUG_RETURN(handle_ordered_prev(buf));
 }
 
@@ -6373,7 +6375,7 @@ int ha_partition::handle_ordered_next(uc
 
   if (error)
   {
-    if (error == HA_ERR_END_OF_FILE)
+    if (error == HA_ERR_END_OF_FILE && m_queue.elements)
     {
       /* Return next buffered row */
       queue_remove_top(&m_queue);
@@ -6425,7 +6427,7 @@ int ha_partition::handle_ordered_prev(uc
 
   if ((error= file->ha_index_prev(rec_buf)))
   {
-    if (error == HA_ERR_END_OF_FILE)
+    if (error == HA_ERR_END_OF_FILE && m_queue.elements)
     {
       queue_remove_top(&m_queue);
       if (m_queue.elements)
diff -Narup ./004_mariadb-10.0.15-slave-trx-retry/sql/ha_partition.h ./005_mariadb-10.0.15-hs/sql/ha_partition.h
--- ./004_mariadb-10.0.15-slave-trx-retry/sql/ha_partition.h	2014-11-29 17:01:25.373795437 +0900
+++ ./005_mariadb-10.0.15-hs/sql/ha_partition.h	2014-11-29 17:01:50.121564027 +0900
@@ -930,7 +930,7 @@ public:
     special file for handling names of partitions, engine types.
     HA_REC_NOT_IN_SEQ is always set for partition handler since we cannot
     guarantee that the records will be returned in sequence.
-    HA_CAN_GEOMETRY, HA_CAN_FULLTEXT, HA_CAN_SQL_HANDLER, HA_DUPLICATE_POS,
+    HA_CAN_GEOMETRY, HA_CAN_FULLTEXT, HA_DUPLICATE_POS,
     HA_CAN_INSERT_DELAYED, HA_PRIMARY_KEY_REQUIRED_FOR_POSITION is disabled
     until further investigated.
   */
diff -Narup ./004_mariadb-10.0.15-slave-trx-retry/sql/mysqld.cc ./005_mariadb-10.0.15-hs/sql/mysqld.cc
--- ./004_mariadb-10.0.15-slave-trx-retry/sql/mysqld.cc	2014-11-29 17:01:38.858391526 +0900
+++ ./005_mariadb-10.0.15-hs/sql/mysqld.cc	2014-11-29 17:01:50.131814500 +0900
@@ -3777,6 +3777,12 @@ SHOW_VAR com_status_vars[]= {
   {"xa_recover",           (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_XA_RECOVER]),SHOW_LONG_STATUS},
   {"xa_rollback",          (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_XA_ROLLBACK]),SHOW_LONG_STATUS},
   {"xa_start",             (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_XA_START]),SHOW_LONG_STATUS},
+  {"hs_open",              (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_HS_OPEN]),SHOW_LONG_STATUS},
+  {"hs_close",             (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_HS_CLOSE]),SHOW_LONG_STATUS},
+  {"hs_read",              (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_HS_READ]),SHOW_LONG_STATUS},
+  {"hs_insert",            (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_HS_INSERT]),SHOW_LONG_STATUS},
+  {"hs_update",            (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_HS_UPDATE]),SHOW_LONG_STATUS},
+  {"hs_delete",            (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_HS_DELETE]),SHOW_LONG_STATUS},
   {NullS, NullS, SHOW_LONG}
 };
 
diff -Narup ./004_mariadb-10.0.15-slave-trx-retry/sql/sql_cmd.h ./005_mariadb-10.0.15-hs/sql/sql_cmd.h
--- ./004_mariadb-10.0.15-slave-trx-retry/sql/sql_cmd.h	2014-11-22 06:02:53.000000000 +0900
+++ ./005_mariadb-10.0.15-hs/sql/sql_cmd.h	2014-11-29 17:01:50.134394628 +0900
@@ -99,6 +99,12 @@ enum enum_sql_command {
     When a command is added here, be sure it's also added in mysqld.cc
     in "struct show_var_st status_vars[]= {" ...
   */
+  SQLCOM_HS_OPEN,
+  SQLCOM_HS_CLOSE,
+  SQLCOM_HS_READ,
+  SQLCOM_HS_INSERT,
+  SQLCOM_HS_UPDATE,
+  SQLCOM_HS_DELETE,
   /* This should be the last !!! */
   SQLCOM_END
 };
diff -Narup ./004_mariadb-10.0.15-slave-trx-retry/sql/sql_handler.cc ./005_mariadb-10.0.15-hs/sql/sql_handler.cc
--- ./004_mariadb-10.0.15-slave-trx-retry/sql/sql_handler.cc	2014-11-22 06:02:56.000000000 +0900
+++ ./005_mariadb-10.0.15-hs/sql/sql_handler.cc	2014-11-29 17:01:50.137796781 +0900
@@ -140,6 +140,38 @@ static void mysql_ha_hash_free(SQL_HANDL
   delete table;
 }
 
+static void mysql_ha_close_childs(THD *thd, TABLE_LIST *tables)
+{
+  TABLE_LIST *table_list;
+  DBUG_ENTER("mysql_ha_close_childs");
+  for (table_list = tables->next_global; table_list;
+    table_list = table_list->next_global)
+  {
+    DBUG_PRINT("info",("table_name %s.%s", table_list->table->s->db.str,
+      table_list->table->s->table_name.str));
+    if (table_list->parent_l == tables)
+    {
+      DBUG_PRINT("info",("find child"));
+      if (table_list->table && !table_list->table->s->tmp_table)
+      {
+        table_list->table->open_by_handler= 0;
+        (void) close_thread_table(thd, &table_list->table);
+        thd->mdl_context.release_lock(table_list->mdl_request.ticket);
+        mysql_ha_close_childs(thd, table_list);
+      }
+      else if (table_list->table)
+      {
+        TABLE *table= table_list->table;
+        table->query_id= thd->query_id;
+        table->open_by_handler= 0;
+        mark_tmp_table_for_reuse(table);
+        mysql_ha_close_childs(thd, table_list);
+      }
+    }
+  }
+  DBUG_VOID_RETURN;
+}
+
 /**
   Close a HANDLER table.
 
@@ -174,6 +206,7 @@ static void mysql_ha_close_table(SQL_HAN
     table->open_by_handler= 0;
     close_thread_table(thd, &table);
     thd->mdl_context.release_lock(handler->mdl_request.ticket);
+    mysql_ha_close_childs(thd, table->pos_in_table_list);
   }
   else
   {
@@ -183,6 +216,7 @@ static void mysql_ha_close_table(SQL_HAN
     table->open_by_handler= 0;
     mark_tmp_table_for_reuse(table);
   }
+  my_free(table->pos_in_table_list);
   my_free(handler->lock);
   handler->init();
 }
@@ -212,6 +246,7 @@ static void mysql_ha_close_table(SQL_HAN
 bool mysql_ha_open(THD *thd, TABLE_LIST *tables, SQL_HANDLER *reopen)
 {
   SQL_HANDLER   *sql_handler= 0;
+  TABLE_LIST    *tmp_tables;
   uint          counter;
   bool          error;
   TABLE         *table, *backup_open_tables;
@@ -261,6 +296,15 @@ bool mysql_ha_open(THD *thd, TABLE_LIST 
     }
   }
 
+  if (!(tmp_tables= (TABLE_LIST *) my_malloc(sizeof(TABLE_LIST),
+                                              MYF(MY_WME))))
+  {
+    DBUG_PRINT("exit",("ERROR"));
+    DBUG_RETURN(TRUE);
+  }
+  memcpy(tmp_tables, tables, sizeof(TABLE_LIST));
+  tables= tmp_tables;
+
   /*
     Save and reset the open_tables list so that open_tables() won't
     be able to access (or know about) the previous list. And on return
@@ -311,15 +355,24 @@ bool mysql_ha_open(THD *thd, TABLE_LIST 
     goto err;
   }
 
-  if (tables->mdl_request.ticket &&
-      thd->mdl_context.has_lock(mdl_savepoint, tables->mdl_request.ticket))
+  DBUG_PRINT("info",("clone_tickets start"));
+  for (TABLE_LIST *table_list= tables; table_list;
+    table_list= table_list->next_global)
+  {
+    DBUG_PRINT("info",("table_list %s.%s", table_list->table->s->db.str,
+      table_list->table->s->table_name.str));
+  if (table_list->mdl_request.ticket &&
+      thd->mdl_context.has_lock(mdl_savepoint, table_list->mdl_request.ticket))
   {
+      DBUG_PRINT("info",("clone_tickets"));
     /* The ticket returned is within a savepoint. Make a copy.  */
-    error= thd->mdl_context.clone_ticket(&tables->mdl_request);
-    tables->table->mdl_ticket= tables->mdl_request.ticket;
+    error= thd->mdl_context.clone_ticket(&table_list->mdl_request);
+    table_list->table->mdl_ticket= table_list->mdl_request.ticket;
     if (error)
       goto err;
   }
+  }
+  DBUG_PRINT("info",("clone_tickets end"));
 
   if (! reopen)
   {
@@ -379,12 +432,26 @@ bool mysql_ha_open(THD *thd, TABLE_LIST 
 
   /* Restore the state. */
   thd->set_open_tables(backup_open_tables);
+  DBUG_PRINT("info",("set_lock_duration start"));
   if (sql_handler->mdl_request.ticket)
   {
     thd->mdl_context.set_lock_duration(sql_handler->mdl_request.ticket,
                                        MDL_EXPLICIT);
     thd->mdl_context.set_needs_thr_lock_abort(TRUE);
   }
+  for (TABLE_LIST *table_list= tables->next_global; table_list;
+    table_list= table_list->next_global)
+  {
+    DBUG_PRINT("info",("table_list %s.%s", table_list->table->s->db.str,
+      table_list->table->s->table_name.str));
+    if (table_list->mdl_request.ticket)
+    {
+      thd->mdl_context.set_lock_duration(table_list->mdl_request.ticket,
+                                         MDL_EXPLICIT);
+      thd->mdl_context.set_needs_thr_lock_abort(TRUE);
+    }
+  }
+  DBUG_PRINT("info",("set_lock_duration end"));
 
   /*
     Assert that the above check prevents opening of views and merge tables.
@@ -392,14 +459,20 @@ bool mysql_ha_open(THD *thd, TABLE_LIST 
     was opened for HANDLER as it is used to link them together
     (see thd->temporary_tables).
   */
+/*
   DBUG_ASSERT(sql_handler->table->next == NULL ||
               sql_handler->table->s->tmp_table);
+*/
   /*
     If it's a temp table, don't reset table->query_id as the table is
     being used by this handler. For non-temp tables we use this flag
     in asserts.
   */
-  table->open_by_handler= 1;
+  for (TABLE_LIST *table_list= tables; table_list;
+    table_list= table_list->next_global)
+  {
+    table_list->table->open_by_handler= 1;
+  }
 
   /* Safety, cleanup the pointer to satisfy MDL assertions. */
   tables->mdl_request.ticket= NULL;
@@ -426,6 +499,7 @@ err:
     else
       sql_handler->reset(); // or should it be init() ?
   }
+  my_free(tmp_tables);
   DBUG_PRINT("exit",("ERROR"));
   DBUG_RETURN(TRUE);
 }
