Skip to content

Commit 627deed

Browse files
committed
Bug#32416811: Handler.ha_rnd_next failure
This failure may occur when we have a cursor created inside a stored procedure and need to recreate the temporary table behind the cursor because the storage limitation of the primary temporary table is exceeded. In that case, the code that populates the temporary table will recreate the temporary table in another storage engine, move the contents of the primary table to the new one, and insert the remaining part of the query result to this new table. However, the handler for the new table is created on the current THD's mem_root, which may not provide the storage lifetime expected by cursors. Cursor objects exist over several roundtrips and we need to enforce proper lifetime for them. For the primary temporay table, this is ensured by using a special mem_root created in the cursor object. However, we have no control over when the new temporary table may be created, thus we may use the wrong mem_root for the allocation. The fix is to save the memory allocator used when instantiating the primary temporary table, and ensure to use the same allocator when recreating the table with a different storage engine. The pointer to the memory allocator is stored in the TABLE_SHARE object and is only used for internal temporary tables. Reviewed by: Sergey Glukhov <sergey.glukhov@oracle.com>
1 parent 62002bf commit 627deed

File tree

2 files changed

+16
-4
lines changed

2 files changed

+16
-4
lines changed

sql/sql_tmp_table.cc

+10-4
Original file line numberDiff line numberDiff line change
@@ -2081,7 +2081,10 @@ bool setup_tmp_table_handler(THD *thd, TABLE *table, ulonglong select_options,
20812081
}
20822082
assert(share->db_plugin != nullptr);
20832083

2084-
table->file = get_new_handler(share, false, thd->mem_root, share->db_type());
2084+
share->alloc_for_tmp_file_handler = thd->mem_root;
2085+
2086+
table->file = get_new_handler(share, false, share->alloc_for_tmp_file_handler,
2087+
share->db_type());
20852088
if (table->file == nullptr) return true;
20862089

20872090
// Update the handler with information about the table object
@@ -2225,7 +2228,8 @@ static bool create_tmp_table_with_fallback(THD *thd, TABLE *table) {
22252228
table->file->create(share->table_name.str, table, &create_info, nullptr);
22262229
if (error == HA_ERR_RECORD_FILE_FULL &&
22272230
table->s->db_type() == temptable_hton) {
2228-
table->file = get_new_handler(table->s, false, thd->mem_root, innodb_hton);
2231+
table->file = get_new_handler(
2232+
table->s, false, share->alloc_for_tmp_file_handler, innodb_hton);
22292233
error = table->file->create(share->table_name.str, table, &create_info,
22302234
nullptr);
22312235
}
@@ -2580,8 +2584,10 @@ bool create_ondisk_from_heap(THD *thd, TABLE *wtable, int error,
25802584

25812585
new_table.s = &share; // New table points to new share
25822586

2583-
if (!(new_table.file = get_new_handler(&share, false, thd->mem_root,
2584-
new_table.s->db_type())))
2587+
new_table.file =
2588+
get_new_handler(&share, false, old_share->alloc_for_tmp_file_handler,
2589+
new_table.s->db_type());
2590+
if (new_table.file == nullptr)
25852591
goto err_after_proc_info; /* purecov: inspected */
25862592
if (new_table.file->set_ha_share_ref(&share.ha_share))
25872593
goto err_after_alloc; /* purecov: inspected */

sql/table.h

+6
Original file line numberDiff line numberDiff line change
@@ -707,6 +707,12 @@ struct TABLE_SHARE {
707707
/* hash of field names (contains pointers to elements of field array) */
708708
collation_unordered_map<std::string, Field **> *name_hash{nullptr};
709709
MEM_ROOT mem_root;
710+
/**
711+
Used to allocate new handler for internal temporary table when the
712+
size limitation of the primary storage engine is exceeded.
713+
*/
714+
MEM_ROOT *alloc_for_tmp_file_handler{nullptr};
715+
710716
TYPELIB keynames; /* Pointers to keynames */
711717
TYPELIB *intervals{nullptr}; /* pointer to interval info */
712718
mysql_mutex_t LOCK_ha_data; /* To protect access to ha_data */

0 commit comments

Comments
 (0)