diff options
Diffstat (limited to 'sql')
-rw-r--r-- | sql/ha_partition.cc | 28 | ||||
-rw-r--r-- | sql/ha_partition.h | 3 | ||||
-rw-r--r-- | sql/handler.h | 4 | ||||
-rw-r--r-- | sql/sql_handler.cc | 108 |
4 files changed, 119 insertions, 24 deletions
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 043f7fb280b..193e9b7a02f 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -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"; @@ -5672,7 +5671,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)); @@ -5705,7 +5705,8 @@ int ha_partition::index_next_same(uchar *buf, const uchar *key, uint keylen) 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)); @@ -5733,7 +5734,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)); } @@ -6352,7 +6354,7 @@ int ha_partition::handle_ordered_next(uchar *buf, bool is_next_same) 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); @@ -6404,7 +6406,7 @@ int ha_partition::handle_ordered_prev(uchar *buf) 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) @@ -9097,6 +9099,20 @@ int ha_partition::check_for_upgrade(HA_CHECK_OPT *check_opt) } +TABLE_LIST *ha_partition::get_next_global_for_child() +{ + handler **file; + DBUG_ENTER("ha_partition::get_next_global_for_child"); + for (file= m_file; *file; file++) + { + TABLE_LIST *table_list; + if ((table_list= (*file)->get_next_global_for_child())) + DBUG_RETURN(table_list); + } + DBUG_RETURN(0); +} + + struct st_mysql_storage_engine partition_storage_engine= { MYSQL_HANDLERTON_INTERFACE_VERSION }; diff --git a/sql/ha_partition.h b/sql/ha_partition.h index 3ea8d4a855d..026e4d455a3 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -921,7 +921,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. */ @@ -1236,6 +1236,7 @@ public: /* Enabled keycache for performance reasons, WL#4571 */ virtual int assign_to_keycache(THD* thd, HA_CHECK_OPT *check_opt); virtual int preload_keys(THD* thd, HA_CHECK_OPT* check_opt); + virtual TABLE_LIST *get_next_global_for_child(); /* ------------------------------------------------------------------------- diff --git a/sql/handler.h b/sql/handler.h index cfb6836f6d4..c6510b9d6bd 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -3554,6 +3554,10 @@ public: pushed_idx_cond_keyno= MAX_KEY; in_range_check_pushed_down= false; } + + /* Needed for partition / spider */ + virtual TABLE_LIST *get_next_global_for_child() { return NULL; } + /** Part of old, deprecated in-place ALTER API. */ diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 7dcc6fa0e95..7e3506e51ce 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -140,6 +140,48 @@ static void mysql_ha_hash_free(SQL_HANDLER *table) delete table; } +static void mysql_ha_close_childs(THD *thd, TABLE_LIST *current_table_list, + TABLE_LIST **next_global) +{ + TABLE_LIST *table_list; + DBUG_ENTER("mysql_ha_close_childs"); + DBUG_PRINT("info",("current_table_list: %p", current_table_list)); + DBUG_PRINT("info",("next_global: %p", *next_global)); + for (table_list = *next_global; table_list; table_list = *next_global) + { + *next_global = table_list->next_global; + DBUG_PRINT("info",("table_name: %s.%s", table_list->table->s->db.str, + table_list->table->s->table_name.str)); + DBUG_PRINT("info",("parent_l: %p", table_list->parent_l)); + if (table_list->parent_l == current_table_list) + { + DBUG_PRINT("info",("found child")); + TABLE *table = table_list->table; + if (table) + { + table->open_by_handler= 0; + if (!table->s->tmp_table) + { + (void) close_thread_table(thd, &table); + thd->mdl_context.release_lock(table_list->mdl_request.ticket); + } + else + { + mark_tmp_table_for_reuse(table); + } + } + mysql_ha_close_childs(thd, table_list, next_global); + } + else + { + /* the end of child tables */ + *next_global = table_list; + break; + } + } + DBUG_VOID_RETURN; +} + /** Close a HANDLER table. @@ -156,11 +198,16 @@ static void mysql_ha_close_table(SQL_HANDLER *handler) { THD *thd= handler->thd; TABLE *table= handler->table; + TABLE_LIST *current_table_list= NULL, *next_global; /* check if table was already closed */ if (!table) return; + if ((next_global= table->file->get_next_global_for_child())) + current_table_list= next_global->parent_l; + + table->open_by_handler= 0; if (!table->s->tmp_table) { /* Non temporary table. */ @@ -171,16 +218,17 @@ static void mysql_ha_close_table(SQL_HANDLER *handler) } table->file->ha_index_or_rnd_end(); - table->open_by_handler= 0; close_thread_table(thd, &table); + if (current_table_list) + mysql_ha_close_childs(thd, current_table_list, &next_global); thd->mdl_context.release_lock(handler->mdl_request.ticket); } else { /* Must be a temporary table */ table->file->ha_index_or_rnd_end(); - table->query_id= thd->query_id; - table->open_by_handler= 0; + if (current_table_list) + mysql_ha_close_childs(thd, current_table_list, &next_global); mark_tmp_table_for_reuse(table); } my_free(handler->lock); @@ -311,15 +359,24 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, SQL_HANDLER *reopen) 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,27 +436,37 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, SQL_HANDLER *reopen) /* 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. - For temporary tables, TABLE::next can be set even if only one table - 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; @@ -756,7 +823,14 @@ retry: { int lock_error; - handler->lock->locks[0]->type= handler->lock->locks[0]->org_type; + THR_LOCK_DATA **pos,**end; + for (pos= handler->lock->locks, + end= handler->lock->locks + handler->lock->lock_count; + pos < end; + pos++) + { + pos[0]->type= pos[0]->org_type; + } /* save open_tables state */ TABLE* backup_open_tables= thd->open_tables; |