1 /*
2 Copyright (c) 2016, 2021, MariaDB Corporation.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; version 2 of the License.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17
18 /**
19 All methods pertaining to temporary tables.
20 */
21
22 #include "mariadb.h"
23 #include "sql_acl.h" /* TMP_TABLE_ACLS */
24 #include "sql_base.h" /* tdc_create_key */
25 #include "lock.h" /* mysql_lock_remove */
26 #include "log_event.h" /* Query_log_event */
27 #include "sql_show.h" /* append_identifier */
28 #include "sql_handler.h" /* mysql_ha_rm_temporary_tables */
29 #include "rpl_rli.h" /* rpl_group_info */
30
31 #define IS_USER_TABLE(A) ((A->tmp_table == TRANSACTIONAL_TMP_TABLE) || \
32 (A->tmp_table == NON_TRANSACTIONAL_TMP_TABLE))
33
34 /**
35 Check whether temporary tables exist. The decision is made based on the
36 existence of TMP_TABLE_SHAREs in Open_tables_state::temporary_tables list.
37
38 @return false Temporary tables exist
39 true No temporary table exist
40 */
has_thd_temporary_tables()41 bool THD::has_thd_temporary_tables()
42 {
43 DBUG_ENTER("THD::has_thd_temporary_tables");
44 bool result= (temporary_tables && !temporary_tables->is_empty());
45 DBUG_RETURN(result);
46 }
47
48
49 /**
50 Create a temporary table, open it and return the TABLE handle.
51
52 @param frm [IN] Binary frm image
53 @param path [IN] File path (without extension)
54 @param db [IN] Schema name
55 @param table_name [IN] Table name
56
57 @return Success A pointer to table object
58 Failure NULL
59 */
create_and_open_tmp_table(LEX_CUSTRING * frm,const char * path,const char * db,const char * table_name,bool open_internal_tables)60 TABLE *THD::create_and_open_tmp_table(LEX_CUSTRING *frm,
61 const char *path,
62 const char *db,
63 const char *table_name,
64 bool open_internal_tables)
65 {
66 DBUG_ENTER("THD::create_and_open_tmp_table");
67
68 TMP_TABLE_SHARE *share;
69 TABLE *table= NULL;
70
71 if ((share= create_temporary_table(frm, path, db, table_name)))
72 {
73 open_options|= HA_OPEN_FOR_CREATE;
74 table= open_temporary_table(share, table_name);
75 open_options&= ~HA_OPEN_FOR_CREATE;
76
77 /*
78 Failed to open a temporary table instance. As we are not passing
79 the created TMP_TABLE_SHARE to the caller, we must remove it from
80 the list and free it here.
81 */
82 if (!table)
83 {
84 /* Remove the TABLE_SHARE from the list of temporary tables. */
85 temporary_tables->remove(share);
86
87 /* Free the TMP_TABLE_SHARE. */
88 free_tmp_table_share(share, false);
89 DBUG_RETURN(0);
90 }
91
92 /* Open any related tables */
93 if (open_internal_tables && table->internal_tables &&
94 open_and_lock_internal_tables(table, true))
95 {
96 drop_temporary_table(table, NULL, false);
97 DBUG_RETURN(0);
98 }
99 }
100
101 DBUG_RETURN(table);
102 }
103
104
105 /**
106 Check whether an open table with db/table name is in use.
107
108 @param db [IN] Database name
109 @param table_name [IN] Table name
110 @param state [IN] State of temp table to open
111
112 @return Success Pointer to first used table instance.
113 Failure NULL
114 */
find_temporary_table(const char * db,const char * table_name,Temporary_table_state state)115 TABLE *THD::find_temporary_table(const char *db,
116 const char *table_name,
117 Temporary_table_state state)
118 {
119 DBUG_ENTER("THD::find_temporary_table");
120
121 TABLE *table;
122 char key[MAX_DBKEY_LENGTH];
123 uint key_length;
124 bool locked;
125
126 if (!has_temporary_tables())
127 {
128 DBUG_RETURN(NULL);
129 }
130
131 key_length= create_tmp_table_def_key(key, db, table_name);
132
133 locked= lock_temporary_tables();
134 table= find_temporary_table(key, key_length, state);
135 if (locked)
136 {
137 DBUG_ASSERT(m_tmp_tables_locked);
138 unlock_temporary_tables();
139 }
140
141 DBUG_RETURN(table);
142 }
143
144
145 /**
146 Check whether an open table specified in TABLE_LIST is in use.
147
148 @return tl [IN] TABLE_LIST
149
150 @return Success Pointer to first used table instance.
151 Failure NULL
152 */
find_temporary_table(const TABLE_LIST * tl,Temporary_table_state state)153 TABLE *THD::find_temporary_table(const TABLE_LIST *tl,
154 Temporary_table_state state)
155 {
156 DBUG_ENTER("THD::find_temporary_table");
157 TABLE *table= find_temporary_table(tl->get_db_name(), tl->get_table_name(),
158 state);
159 DBUG_RETURN(table);
160 }
161
162
163 /**
164 Check whether a temporary table exists with the specified key.
165 The key, in this case, is not the usual key used for temporary tables.
166 It does not contain server_id & pseudo_thread_id. This function is
167 essentially used use to check whether there is any temporary table
168 which _shadows_ a base table.
169 (see: Query_cache::send_result_to_client())
170
171 @return Success A pointer to table share object
172 Failure NULL
173 */
find_tmp_table_share_w_base_key(const char * key,uint key_length)174 TMP_TABLE_SHARE *THD::find_tmp_table_share_w_base_key(const char *key,
175 uint key_length)
176 {
177 DBUG_ENTER("THD::find_tmp_table_share_w_base_key");
178
179 TMP_TABLE_SHARE *share;
180 TMP_TABLE_SHARE *result= NULL;
181 bool locked;
182
183 if (!has_temporary_tables())
184 {
185 DBUG_RETURN(NULL);
186 }
187
188 locked= lock_temporary_tables();
189
190 All_tmp_tables_list::Iterator it(*temporary_tables);
191 while ((share= it++))
192 {
193 if ((share->table_cache_key.length - TMP_TABLE_KEY_EXTRA) == key_length
194 && !memcmp(share->table_cache_key.str, key, key_length))
195 {
196 result= share;
197 }
198 }
199
200 if (locked)
201 {
202 DBUG_ASSERT(m_tmp_tables_locked);
203 unlock_temporary_tables();
204 }
205
206 DBUG_RETURN(result);
207 }
208
209
210 /**
211 Lookup the TMP_TABLE_SHARE using the given db/table_name.The server_id and
212 pseudo_thread_id used to generate table definition key is taken from THD
213 (see create_tmp_table_def_key()). Return NULL is none found.
214
215 @return Success A pointer to table share object
216 Failure NULL
217 */
find_tmp_table_share(const char * db,const char * table_name)218 TMP_TABLE_SHARE *THD::find_tmp_table_share(const char *db,
219 const char *table_name)
220 {
221 DBUG_ENTER("THD::find_tmp_table_share");
222
223 TMP_TABLE_SHARE *share;
224 char key[MAX_DBKEY_LENGTH];
225 uint key_length;
226
227 key_length= create_tmp_table_def_key(key, db, table_name);
228 share= find_tmp_table_share(key, key_length);
229
230 DBUG_RETURN(share);
231 }
232
233
234 /**
235 Lookup TMP_TABLE_SHARE using the specified TABLE_LIST element.
236 Return NULL is none found.
237
238 @param tl [IN] Table
239
240 @return Success A pointer to table share object
241 Failure NULL
242 */
find_tmp_table_share(const TABLE_LIST * tl)243 TMP_TABLE_SHARE *THD::find_tmp_table_share(const TABLE_LIST *tl)
244 {
245 DBUG_ENTER("THD::find_tmp_table_share");
246 TMP_TABLE_SHARE *share= find_tmp_table_share(tl->get_db_name(),
247 tl->get_table_name());
248 DBUG_RETURN(share);
249 }
250
251
252 /**
253 Lookup TMP_TABLE_SHARE using the specified table definition key.
254 Return NULL is none found.
255
256 @return Success A pointer to table share object
257 Failure NULL
258 */
find_tmp_table_share(const char * key,size_t key_length)259 TMP_TABLE_SHARE *THD::find_tmp_table_share(const char *key, size_t key_length)
260 {
261 DBUG_ENTER("THD::find_tmp_table_share");
262
263 TMP_TABLE_SHARE *share;
264 TMP_TABLE_SHARE *result= NULL;
265 bool locked;
266
267 if (!has_temporary_tables())
268 {
269 DBUG_RETURN(NULL);
270 }
271
272 locked= lock_temporary_tables();
273
274 All_tmp_tables_list::Iterator it(*temporary_tables);
275 while ((share= it++))
276 {
277 if (share->table_cache_key.length == key_length &&
278 !(memcmp(share->table_cache_key.str, key, key_length)))
279 {
280 result= share;
281 break;
282 }
283 }
284
285 if (locked)
286 {
287 DBUG_ASSERT(m_tmp_tables_locked);
288 unlock_temporary_tables();
289 }
290
291 DBUG_RETURN(result);
292 }
293
294
295 /**
296 Find a temporary table specified by TABLE_LIST instance in the open table
297 list and prepare its TABLE instance for use. If
298
299 This function tries to resolve this table in the list of temporary tables
300 of this thread. Temporary tables are thread-local and "shadow" base
301 tables with the same name.
302
303 @note In most cases one should use THD::open_tables() instead
304 of this call.
305
306 @note One should finalize process of opening temporary table for table
307 list element by calling open_and_process_table(). This function
308 is responsible for table version checking and handling of merge
309 tables.
310
311 @note We used to check global_read_lock before opening temporary tables.
312 However, that limitation was artificial and is removed now.
313
314 @param tl [IN] TABLE_LIST
315
316 @return Error status.
317 @retval false On success. If a temporary table exists
318 for the given key, tl->table is set.
319 @retval true On error. my_error() has been called.
320 */
open_temporary_table(TABLE_LIST * tl)321 bool THD::open_temporary_table(TABLE_LIST *tl)
322 {
323 DBUG_ENTER("THD::open_temporary_table");
324 DBUG_PRINT("enter", ("table: '%s'.'%s'", tl->db.str, tl->table_name.str));
325
326 TMP_TABLE_SHARE *share;
327 TABLE *table= NULL;
328
329 /*
330 Code in open_table() assumes that TABLE_LIST::table can be non-zero only
331 for pre-opened temporary tables.
332 */
333 DBUG_ASSERT(tl->table == NULL);
334
335 /*
336 This function should not be called for cases when derived or I_S
337 tables can be met since table list elements for such tables can
338 have invalid db or table name.
339 Instead THD::open_tables() should be used.
340 */
341 DBUG_ASSERT(!tl->derived);
342 DBUG_ASSERT(!tl->schema_table);
343 DBUG_ASSERT(has_temporary_tables());
344
345 if (tl->open_type == OT_BASE_ONLY)
346 {
347 DBUG_PRINT("info", ("skip_temporary is set or no temporary tables"));
348 DBUG_RETURN(false);
349 }
350
351 if (!tl->db.str)
352 {
353 DBUG_PRINT("info",
354 ("Table reference to a temporary table must have database set"));
355 DBUG_RETURN(false);
356 }
357
358 /*
359 Temporary tables are not safe for parallel replication. They were
360 designed to be visible to one thread only, so have no table locking.
361 Thus there is no protection against two conflicting transactions
362 committing in parallel and things like that.
363
364 So for now, anything that uses temporary tables will be serialised
365 with anything before it, when using parallel replication.
366 */
367
368 if (rgi_slave &&
369 rgi_slave->is_parallel_exec &&
370 find_temporary_table(tl) &&
371 wait_for_prior_commit())
372 DBUG_RETURN(true);
373
374 /*
375 First check if there is a reusable open table available in the
376 open table list.
377 */
378 if (find_and_use_tmp_table(tl, &table))
379 {
380 DBUG_RETURN(true); /* Error */
381 }
382
383 /*
384 No reusable table was found. We will have to open a new instance.
385 */
386 if (!table && (share= find_tmp_table_share(tl)))
387 {
388 table= open_temporary_table(share, tl->get_table_name());
389 /*
390 Temporary tables are not safe for parallel replication. They were
391 designed to be visible to one thread only, so have no table locking.
392 Thus there is no protection against two conflicting transactions
393 committing in parallel and things like that.
394
395 So for now, anything that uses temporary tables will be serialised
396 with anything before it, when using parallel replication.
397 */
398 if (table && rgi_slave &&
399 rgi_slave->is_parallel_exec &&
400 wait_for_prior_commit())
401 DBUG_RETURN(true);
402
403 if (!table && is_error())
404 DBUG_RETURN(true); // Error when opening table
405 }
406
407 if (!table)
408 {
409 if (tl->open_type == OT_TEMPORARY_ONLY &&
410 tl->open_strategy == TABLE_LIST::OPEN_NORMAL)
411 {
412 my_error(ER_NO_SUCH_TABLE, MYF(0), tl->db.str, tl->table_name.str);
413 DBUG_RETURN(true);
414 }
415 DBUG_RETURN(false);
416 }
417
418 #ifdef WITH_PARTITION_STORAGE_ENGINE
419 if (tl->partition_names)
420 {
421 /* Partitioned temporary tables is not supported. */
422 DBUG_ASSERT(!table->part_info);
423 my_error(ER_PARTITION_CLAUSE_ON_NONPARTITIONED, MYF(0));
424 DBUG_RETURN(true);
425 }
426 #endif
427
428 table->query_id= query_id;
429 thread_specific_used= true;
430
431 /* It is neither a derived table nor non-updatable view. */
432 tl->updatable= true;
433 tl->table= table;
434
435 table->init(this, tl);
436
437 DBUG_PRINT("info", ("Using temporary table"));
438 DBUG_RETURN(false);
439 }
440
441
442 /**
443 Pre-open temporary tables corresponding to table list elements.
444
445 @note One should finalize process of opening temporary tables
446 by calling open_tables(). This function is responsible
447 for table version checking and handling of merge tables.
448
449 @param tl [IN] TABLE_LIST
450
451 @return false On success. If a temporary table exists
452 for the given element, tl->table is set.
453 true On error. my_error() has been called.
454 */
open_temporary_tables(TABLE_LIST * tl)455 bool THD::open_temporary_tables(TABLE_LIST *tl)
456 {
457 TABLE_LIST *first_not_own;
458 DBUG_ENTER("THD::open_temporary_tables");
459
460 if (!has_temporary_tables())
461 DBUG_RETURN(0);
462
463 first_not_own= lex->first_not_own_table();
464 for (TABLE_LIST *table= tl; table && table != first_not_own;
465 table= table->next_global)
466 {
467 if (table->derived || table->schema_table)
468 {
469 /*
470 Derived and I_S tables will be handled by a later call to open_tables().
471 */
472 continue;
473 }
474
475 if (open_temporary_table(table))
476 {
477 DBUG_RETURN(true);
478 }
479 }
480
481 DBUG_RETURN(false);
482 }
483
484
485 /**
486 Close all temporary tables created by 'CREATE TEMPORARY TABLE' for thread
487 creates one DROP TEMPORARY TABLE binlog event for each pseudo-thread.
488
489 Temporary tables created in a sql slave is closed by
490 Relay_log_info::close_temporary_tables().
491
492 @return false Success
493 true Failure
494 */
close_temporary_tables()495 bool THD::close_temporary_tables()
496 {
497 DBUG_ENTER("THD::close_temporary_tables");
498
499 TMP_TABLE_SHARE *share;
500 TABLE *table;
501
502 bool error= false;
503
504 if (!has_thd_temporary_tables())
505 {
506 if (temporary_tables)
507 {
508 my_free(temporary_tables);
509 temporary_tables= NULL;
510 }
511 DBUG_RETURN(false);
512 }
513
514 DBUG_ASSERT(!rgi_slave);
515
516 /*
517 Ensure we don't have open HANDLERs for tables we are about to close.
518 This is necessary when THD::close_temporary_tables() is called as
519 part of execution of BINLOG statement (e.g. for format description event).
520 */
521 mysql_ha_rm_temporary_tables(this);
522
523 /* Close all open temporary tables. */
524 All_tmp_tables_list::Iterator it(*temporary_tables);
525 while ((share= it++))
526 {
527 /* Traverse the table list. */
528 while ((table= share->all_tmp_tables.pop_front()))
529 {
530 table->file->extra(HA_EXTRA_PREPARE_FOR_DROP);
531 free_temporary_table(table);
532 }
533 }
534
535 // Write DROP TEMPORARY TABLE query log events to binary log.
536 if (mysql_bin_log.is_open())
537 {
538 error= log_events_and_free_tmp_shares();
539 }
540 else
541 {
542 while ((share= temporary_tables->pop_front()))
543 {
544 free_tmp_table_share(share, true);
545 }
546 }
547
548 /* By now, there mustn't be any elements left in the list. */
549 DBUG_ASSERT(temporary_tables->is_empty());
550
551 my_free(temporary_tables);
552 temporary_tables= NULL;
553
554 DBUG_RETURN(error);
555 }
556
557
558 /**
559 Rename a temporary table.
560
561 @param table [IN] Table handle
562 @param db [IN] New schema name
563 @param table_name [IN] New table name
564
565 @return false Success
566 true Error
567 */
rename_temporary_table(TABLE * table,const LEX_CSTRING * db,const LEX_CSTRING * table_name)568 bool THD::rename_temporary_table(TABLE *table,
569 const LEX_CSTRING *db,
570 const LEX_CSTRING *table_name)
571 {
572 char *key;
573 uint key_length;
574 TABLE_SHARE *share= table->s;
575 DBUG_ENTER("THD::rename_temporary_table");
576
577 if (!(key= (char *) alloc_root(&share->mem_root, MAX_DBKEY_LENGTH)))
578 DBUG_RETURN(true);
579
580 /*
581 Temporary tables are renamed by simply changing their table definition key.
582 */
583 key_length= create_tmp_table_def_key(key, db->str, table_name->str);
584 share->set_table_cache_key(key, key_length);
585
586 DBUG_RETURN(false);
587 }
588
589
590 /**
591 Drop a temporary table.
592
593 Try to locate the table in the list of open temporary tables.
594 If the table is found:
595 - If the table is locked with LOCK TABLES or by prelocking,
596 unlock it and remove it from the list of locked tables
597 (THD::lock). Currently only transactional temporary tables
598 are locked.
599 - Close the temporary table, remove its .FRM.
600 - Remove the table share from the list of temporary table shares.
601
602 This function is used to drop user temporary tables, as well as
603 internal tables created in CREATE TEMPORARY TABLE ... SELECT
604 or ALTER TABLE.
605
606 @param table [IN] Temporary table to be deleted
607 @param is_trans [OUT] Is set to the type of the table:
608 transactional (e.g. innodb) as true or
609 non-transactional (e.g. myisam) as false.
610 @paral delete_table [IN] Whether to delete the table files?
611
612 @return false Table was dropped
613 true Error
614 */
drop_temporary_table(TABLE * table,bool * is_trans,bool delete_table)615 bool THD::drop_temporary_table(TABLE *table, bool *is_trans, bool delete_table)
616 {
617 DBUG_ENTER("THD::drop_temporary_table");
618
619 TMP_TABLE_SHARE *share;
620 TABLE *tab;
621 bool result= false;
622 bool locked;
623
624 DBUG_ASSERT(table);
625 DBUG_PRINT("tmptable", ("Dropping table: '%s'.'%s'",
626 table->s->db.str, table->s->table_name.str));
627
628 locked= lock_temporary_tables();
629
630 share= tmp_table_share(table);
631
632 /* Table might be in use by some outer statement. */
633 All_share_tables_list::Iterator it(share->all_tmp_tables);
634 while ((tab= it++))
635 {
636 if (tab != table && tab->query_id != 0)
637 {
638 /* Found a table instance in use. This table cannot be be dropped. */
639 my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias.c_ptr());
640 result= true;
641 goto end;
642 }
643 }
644
645 if (is_trans)
646 *is_trans= table->file->has_transactions();
647
648 /*
649 Iterate over the list of open tables and close them.
650 */
651 while ((tab= share->all_tmp_tables.pop_front()))
652 {
653 /*
654 We need to set the THD as it may be different in case of
655 parallel replication
656 */
657 tab->in_use= this;
658 if (delete_table)
659 tab->file->extra(HA_EXTRA_PREPARE_FOR_DROP);
660 free_temporary_table(tab);
661 }
662
663 DBUG_ASSERT(temporary_tables);
664
665 /* Remove the TABLE_SHARE from the list of temporary tables. */
666 temporary_tables->remove(share);
667
668 /* Free the TABLE_SHARE and/or delete the files. */
669 free_tmp_table_share(share, delete_table);
670
671 end:
672 if (locked)
673 {
674 DBUG_ASSERT(m_tmp_tables_locked);
675 unlock_temporary_tables();
676 }
677
678 DBUG_RETURN(result);
679 }
680
681
682 /**
683 Delete the temporary table files.
684
685 @param base [IN] Handlerton for table to be deleted.
686 @param path [IN] Path to the table to be deleted (i.e. path
687 to its .frm without an extension).
688
689 @return false Success
690 true Error
691 */
rm_temporary_table(handlerton * base,const char * path)692 bool THD::rm_temporary_table(handlerton *base, const char *path)
693 {
694 DBUG_ENTER("THD::rm_temporary_table");
695
696 bool error= false;
697 char frm_path[FN_REFLEN + 1];
698
699 strxnmov(frm_path, sizeof(frm_path) - 1, path, reg_ext, NullS);
700 if (mysql_file_delete(key_file_frm, frm_path,
701 MYF(MY_WME | MY_IGNORE_ENOENT)))
702 error= true;
703 if (base->drop_table(base, path) > 0)
704 {
705 error= true;
706 sql_print_warning("Could not remove temporary table: '%s', error: %d",
707 path, my_errno);
708 }
709
710 DBUG_RETURN(error);
711 }
712
713
714 /**
715 Mark all temporary tables which were used by the current statement or
716 sub-statement as free for reuse, but only if the query_id can be cleared.
717
718 @remark For temp tables associated with a open SQL HANDLER the query_id
719 is not reset until the HANDLER is closed.
720 */
mark_tmp_tables_as_free_for_reuse()721 void THD::mark_tmp_tables_as_free_for_reuse()
722 {
723 DBUG_ENTER("THD::mark_tmp_tables_as_free_for_reuse");
724
725 TMP_TABLE_SHARE *share;
726 TABLE *table;
727 bool locked;
728
729 if (query_id == 0)
730 {
731 /*
732 Thread has not executed any statement and has not used any
733 temporary tables.
734 */
735 DBUG_VOID_RETURN;
736 }
737
738 if (!has_temporary_tables())
739 {
740 DBUG_VOID_RETURN;
741 }
742
743 locked= lock_temporary_tables();
744
745 All_tmp_tables_list::Iterator it(*temporary_tables);
746 while ((share= it++))
747 {
748 All_share_tables_list::Iterator tables_it(share->all_tmp_tables);
749 while ((table= tables_it++))
750 {
751 if ((table->query_id == query_id) && !table->open_by_handler)
752 mark_tmp_table_as_free_for_reuse(table);
753 }
754 }
755
756 if (locked)
757 {
758 DBUG_ASSERT(m_tmp_tables_locked);
759 unlock_temporary_tables();
760 }
761
762 if (rgi_slave)
763 {
764 /*
765 Temporary tables are shared with other by sql execution threads.
766 As a safety measure, clear the pointer to the common area.
767 */
768 temporary_tables= NULL;
769 }
770
771 DBUG_VOID_RETURN;
772 }
773
774
775 /**
776 Reset a single temporary table. Effectively this "closes" one temporary
777 table in a session.
778
779 @param table Temporary table
780
781 @return void
782 */
mark_tmp_table_as_free_for_reuse(TABLE * table)783 void THD::mark_tmp_table_as_free_for_reuse(TABLE *table)
784 {
785 DBUG_ENTER("THD::mark_tmp_table_as_free_for_reuse");
786
787 DBUG_ASSERT(table->s->tmp_table);
788
789 table->query_id= 0;
790 table->file->ha_reset();
791
792 /* Detach temporary MERGE children from temporary parent. */
793 DBUG_ASSERT(table->file);
794 table->file->extra(HA_EXTRA_DETACH_CHILDREN);
795
796 /*
797 Reset temporary table lock type to it's default value (TL_WRITE).
798
799 Statements such as INSERT INTO .. SELECT FROM tmp, CREATE TABLE
800 .. SELECT FROM tmp and UPDATE may under some circumstances modify
801 the lock type of the tables participating in the statement. This
802 isn't a problem for non-temporary tables since their lock type is
803 reset at every open, but the same does not occur for temporary
804 tables for historical reasons.
805
806 Furthermore, the lock type of temporary tables is not really that
807 important because they can only be used by one query at a time.
808 Nonetheless, it's safer from a maintenance point of view to reset
809 the lock type of this singleton TABLE object as to not cause problems
810 when the table is reused.
811
812 Even under LOCK TABLES mode its okay to reset the lock type as
813 LOCK TABLES is allowed (but ignored) for a temporary table.
814 */
815 table->reginfo.lock_type= TL_WRITE;
816 DBUG_VOID_RETURN;
817 }
818
819
820 /**
821 Remove and return the specified table's TABLE_SHARE from the temporary
822 tables list.
823
824 @param table [IN] Table
825
826 @return TMP_TABLE_SHARE of the specified table.
827 */
save_tmp_table_share(TABLE * table)828 TMP_TABLE_SHARE *THD::save_tmp_table_share(TABLE *table)
829 {
830 DBUG_ENTER("THD::save_tmp_table_share");
831
832 TMP_TABLE_SHARE *share;
833
834 lock_temporary_tables();
835 DBUG_ASSERT(temporary_tables);
836 share= tmp_table_share(table);
837 temporary_tables->remove(share);
838 unlock_temporary_tables();
839
840 DBUG_RETURN(share);
841 }
842
843
844 /**
845 Add the specified TMP_TABLE_SHARE to the temporary tables list.
846
847 @param share [IN] Table share
848
849 @return void
850 */
restore_tmp_table_share(TMP_TABLE_SHARE * share)851 void THD::restore_tmp_table_share(TMP_TABLE_SHARE *share)
852 {
853 DBUG_ENTER("THD::restore_tmp_table_share");
854
855 lock_temporary_tables();
856 DBUG_ASSERT(temporary_tables);
857 temporary_tables->push_front(share);
858 unlock_temporary_tables();
859
860 DBUG_VOID_RETURN;
861 }
862
863
864 /**
865 If its a replication slave, report whether slave temporary tables
866 exist (Relay_log_info::save_temporary_tables) or report about THD
867 temporary table (Open_tables_state::temporary_tables) otherwise.
868
869 @return false Temporary tables exist
870 true No temporary table exist
871 */
has_temporary_tables()872 bool THD::has_temporary_tables()
873 {
874 DBUG_ENTER("THD::has_temporary_tables");
875 bool result=
876 #ifdef HAVE_REPLICATION
877 rgi_slave ? (rgi_slave->rli->save_temporary_tables &&
878 !rgi_slave->rli->save_temporary_tables->is_empty()) :
879 #endif
880 has_thd_temporary_tables();
881 DBUG_RETURN(result);
882 }
883
884
885 /**
886 Create a table definition key.
887
888 @param key [OUT] Buffer for the key to be created (must
889 be of size MAX_DBKRY_LENGTH)
890 @param db [IN] Database name
891 @param table_name [IN] Table name
892
893 @return Key length.
894
895 @note
896 The table key is create from:
897 db + \0
898 table_name + \0
899
900 Additionally, we add the following to make each temporary table unique on
901 the slave.
902
903 4 bytes of master thread id
904 4 bytes of pseudo thread id
905 */
create_tmp_table_def_key(char * key,const char * db,const char * table_name)906 uint THD::create_tmp_table_def_key(char *key, const char *db,
907 const char *table_name)
908 {
909 DBUG_ENTER("THD::create_tmp_table_def_key");
910
911 uint key_length;
912
913 key_length= tdc_create_key(key, db, table_name);
914 int4store(key + key_length, variables.server_id);
915 int4store(key + key_length + 4, variables.pseudo_thread_id);
916 key_length += TMP_TABLE_KEY_EXTRA;
917
918 DBUG_RETURN(key_length);
919 }
920
921
922 /**
923 Create a temporary table.
924
925 @param frm [IN] Binary frm image
926 @param path [IN] File path (without extension)
927 @param db [IN] Schema name
928 @param table_name [IN] Table name
929
930 @return Success A pointer to table share object
931 Failure NULL
932 */
create_temporary_table(LEX_CUSTRING * frm,const char * path,const char * db,const char * table_name)933 TMP_TABLE_SHARE *THD::create_temporary_table(LEX_CUSTRING *frm,
934 const char *path,
935 const char *db,
936 const char *table_name)
937 {
938 DBUG_ENTER("THD::create_temporary_table");
939
940 TMP_TABLE_SHARE *share;
941 char key_cache[MAX_DBKEY_LENGTH];
942 char *saved_key_cache;
943 char *tmp_path;
944 uint key_length;
945 bool locked;
946 int res;
947
948 /* Temporary tables are not safe for parallel replication. */
949 if (rgi_slave &&
950 rgi_slave->is_parallel_exec &&
951 wait_for_prior_commit())
952 DBUG_RETURN(NULL);
953
954 /* Create the table definition key for the temporary table. */
955 key_length= create_tmp_table_def_key(key_cache, db, table_name);
956
957 if (!(share= (TMP_TABLE_SHARE *) my_malloc(key_memory_table_share,
958 sizeof(TMP_TABLE_SHARE) +
959 strlen(path) + 1 + key_length,
960 MYF(MY_WME))))
961 {
962 DBUG_RETURN(NULL); /* Out of memory */
963 }
964
965 tmp_path= (char *)(share + 1);
966 saved_key_cache= strmov(tmp_path, path) + 1;
967 memcpy(saved_key_cache, key_cache, key_length);
968
969 init_tmp_table_share(this, share, saved_key_cache, key_length,
970 strend(saved_key_cache) + 1, tmp_path);
971
972 /*
973 Prefer using frm image over file. The image might not be available in
974 ALTER TABLE, when the discovering engine took over the ownership (see
975 TABLE::read_frm_image).
976 */
977 res= (frm->str)
978 ? share->init_from_binary_frm_image(this, false, frm->str, frm->length)
979 : open_table_def(this, share, GTS_TABLE | GTS_USE_DISCOVERY);
980
981 if (res)
982 {
983 /*
984 No need to lock share->mutex as this is not needed for temporary tables.
985 */
986 free_table_share(share);
987 my_free(share);
988 DBUG_RETURN(NULL);
989 }
990
991 share->m_psi= PSI_CALL_get_table_share(true, share);
992
993 locked= lock_temporary_tables();
994
995 /* Initialize the all_tmp_tables list. */
996 share->all_tmp_tables.empty();
997
998 /*
999 We need to alloc & initialize temporary_tables if this happens
1000 to be the very first temporary table.
1001 */
1002 if (!temporary_tables)
1003 {
1004 if ((temporary_tables=
1005 (All_tmp_tables_list *) my_malloc(key_memory_table_share,
1006 sizeof(All_tmp_tables_list),
1007 MYF(MY_WME))))
1008 {
1009 temporary_tables->empty();
1010 }
1011 else
1012 {
1013 DBUG_RETURN(NULL); /* Out of memory */
1014 }
1015 }
1016
1017 /* Add share to the head of the temporary table share list. */
1018 temporary_tables->push_front(share);
1019
1020 if (locked)
1021 {
1022 DBUG_ASSERT(m_tmp_tables_locked);
1023 unlock_temporary_tables();
1024 }
1025
1026 DBUG_RETURN(share);
1027 }
1028
1029
1030 /**
1031 Find a table with the specified key.
1032
1033 @param key [IN] Key
1034 @param key_length [IN] Key length
1035 @param state [IN] Open table state to look for
1036
1037 @return Success Pointer to the table instance.
1038 Failure NULL
1039 */
find_temporary_table(const char * key,uint key_length,Temporary_table_state state)1040 TABLE *THD::find_temporary_table(const char *key, uint key_length,
1041 Temporary_table_state state)
1042 {
1043 DBUG_ENTER("THD::find_temporary_table");
1044
1045 TMP_TABLE_SHARE *share;
1046 TABLE *table;
1047 TABLE *result= NULL;
1048 bool locked;
1049
1050 locked= lock_temporary_tables();
1051
1052 All_tmp_tables_list::Iterator it(*temporary_tables);
1053 while ((share= it++))
1054 {
1055 if (share->table_cache_key.length == key_length &&
1056 !(memcmp(share->table_cache_key.str, key, key_length)))
1057 {
1058 /* A matching TMP_TABLE_SHARE is found. */
1059 All_share_tables_list::Iterator tables_it(share->all_tmp_tables);
1060
1061 bool found= false;
1062 while (!found && (table= tables_it++))
1063 {
1064 switch (state)
1065 {
1066 case TMP_TABLE_IN_USE: found= table->query_id > 0; break;
1067 case TMP_TABLE_NOT_IN_USE: found= table->query_id == 0; break;
1068 case TMP_TABLE_ANY: found= true; break;
1069 }
1070 }
1071 if (table && unlikely(table->needs_reopen()))
1072 {
1073 share->all_tmp_tables.remove(table);
1074 free_temporary_table(table);
1075 it.rewind();
1076 continue;
1077 }
1078 result= table;
1079 break;
1080 }
1081 }
1082
1083 if (locked)
1084 {
1085 DBUG_ASSERT(m_tmp_tables_locked);
1086 unlock_temporary_tables();
1087 }
1088
1089 DBUG_RETURN(result);
1090 }
1091
1092
1093
1094 /**
1095 Open a table from the specified TABLE_SHARE with the given alias.
1096
1097 @param share [IN] Table share
1098 @param alias [IN] Table alias
1099
1100 @return Success A pointer to table object
1101 Failure NULL
1102 */
open_temporary_table(TMP_TABLE_SHARE * share,const char * alias_arg)1103 TABLE *THD::open_temporary_table(TMP_TABLE_SHARE *share,
1104 const char *alias_arg)
1105 {
1106 TABLE *table;
1107 LEX_CSTRING alias= {alias_arg, strlen(alias_arg) };
1108 DBUG_ENTER("THD::open_temporary_table");
1109
1110
1111 if (!(table= (TABLE *) my_malloc(key_memory_TABLE, sizeof(TABLE),
1112 MYF(MY_WME))))
1113 {
1114 DBUG_RETURN(NULL); /* Out of memory */
1115 }
1116
1117 if (open_table_from_share(this, share, &alias,
1118 (uint) HA_OPEN_KEYFILE,
1119 EXTRA_RECORD,
1120 (ha_open_options |
1121 (open_options & HA_OPEN_FOR_CREATE)),
1122 table, false))
1123 {
1124 my_free(table);
1125 DBUG_RETURN(NULL);
1126 }
1127
1128 table->reginfo.lock_type= TL_WRITE; /* Simulate locked */
1129 table->grant.privilege= TMP_TABLE_ACLS;
1130 table->query_id= query_id;
1131 share->tmp_table= (table->file->has_transaction_manager() ?
1132 TRANSACTIONAL_TMP_TABLE : NON_TRANSACTIONAL_TMP_TABLE);
1133 share->not_usable_by_query_cache= 1;
1134
1135 /* Add table to the head of table list. */
1136 share->all_tmp_tables.push_front(table);
1137
1138 /* Increment Slave_open_temp_table_definitions status variable count. */
1139 if (rgi_slave)
1140 slave_open_temp_tables++;
1141
1142 DBUG_PRINT("tmptable", ("Opened table: '%s'.'%s table: %p",
1143 table->s->db.str,
1144 table->s->table_name.str, table));
1145 DBUG_RETURN(table);
1146 }
1147
1148
1149 /**
1150 Find a reusable table in the open table list using the specified TABLE_LIST.
1151
1152 @param tl [IN] Table list
1153 @param out_table [OUT] Pointer to the requested TABLE object
1154
1155 @return Success false
1156 Failure true
1157 */
find_and_use_tmp_table(const TABLE_LIST * tl,TABLE ** out_table)1158 bool THD::find_and_use_tmp_table(const TABLE_LIST *tl, TABLE **out_table)
1159 {
1160 DBUG_ENTER("THD::find_and_use_tmp_table");
1161
1162 char key[MAX_DBKEY_LENGTH];
1163 uint key_length;
1164 bool result;
1165
1166 key_length= create_tmp_table_def_key(key, tl->get_db_name(),
1167 tl->get_table_name());
1168 result= use_temporary_table(find_temporary_table(key, key_length,
1169 TMP_TABLE_NOT_IN_USE),
1170 out_table);
1171 DBUG_RETURN(result);
1172 }
1173
1174 /**
1175 Mark table as in-use.
1176
1177 @param table [IN] Table to be marked in-use
1178 @param out_table [OUT] Pointer to the specified table
1179
1180 @return false Success
1181 true Error
1182 */
use_temporary_table(TABLE * table,TABLE ** out_table)1183 bool THD::use_temporary_table(TABLE *table, TABLE **out_table)
1184 {
1185 DBUG_ENTER("THD::use_temporary_table");
1186
1187 *out_table= table;
1188
1189 /* The following can happen if find_temporary_table() returns NULL */
1190 if (!table)
1191 DBUG_RETURN(false);
1192
1193 /*
1194 Temporary tables are not safe for parallel replication. They were
1195 designed to be visible to one thread only, so have no table locking.
1196 Thus there is no protection against two conflicting transactions
1197 committing in parallel and things like that.
1198
1199 So for now, anything that uses temporary tables will be serialised
1200 with anything before it, when using parallel replication.
1201
1202 TODO: We might be able to introduce a reference count or something
1203 on temp tables, and have slave worker threads wait for it to reach
1204 zero before being allowed to use the temp table. Might not be worth
1205 it though, as statement-based replication using temporary tables is
1206 in any case rather fragile.
1207 */
1208 if (rgi_slave &&
1209 rgi_slave->is_parallel_exec &&
1210 wait_for_prior_commit())
1211 DBUG_RETURN(true);
1212
1213 /*
1214 We need to set the THD as it may be different in case of
1215 parallel replication
1216 */
1217 table->in_use= this;
1218
1219 DBUG_RETURN(false);
1220 }
1221
1222
1223 /**
1224 Close a temporary table.
1225
1226 @param table [IN] Table handle
1227
1228 @return void
1229 */
close_temporary_table(TABLE * table)1230 void THD::close_temporary_table(TABLE *table)
1231 {
1232 DBUG_ENTER("THD::close_temporary_table");
1233
1234 DBUG_PRINT("tmptable", ("closing table: '%s'.'%s'%p alias: '%s'",
1235 table->s->db.str, table->s->table_name.str,
1236 table, table->alias.c_ptr()));
1237
1238 closefrm(table);
1239 my_free(table);
1240
1241 if (rgi_slave)
1242 {
1243 /* Natural invariant of temporary_tables */
1244 DBUG_ASSERT(slave_open_temp_tables || !temporary_tables);
1245 /* Decrement Slave_open_temp_table_definitions status variable count. */
1246 slave_open_temp_tables--;
1247 }
1248
1249 DBUG_VOID_RETURN;
1250 }
1251
1252
1253 /**
1254 Write query log events with "DROP TEMPORARY TABLES .." for each pseudo
1255 thread to the binary log.
1256
1257 @return false Success
1258 true Error
1259 */
log_events_and_free_tmp_shares()1260 bool THD::log_events_and_free_tmp_shares()
1261 {
1262 DBUG_ENTER("THD::log_events_and_free_tmp_shares");
1263
1264 DBUG_ASSERT(!rgi_slave);
1265
1266 TMP_TABLE_SHARE *share;
1267 TMP_TABLE_SHARE *sorted;
1268 TMP_TABLE_SHARE *prev_sorted;
1269 // Assume thd->variables.option_bits has OPTION_QUOTE_SHOW_CREATE.
1270 bool was_quote_show= true;
1271 bool error= false;
1272 bool found_user_tables= false;
1273 // Better add "IF EXISTS" in case a RESET MASTER has been done.
1274 const char stub[]= "DROP /*!40005 TEMPORARY */ TABLE IF EXISTS ";
1275 char buf[FN_REFLEN];
1276
1277 String s_query(buf, sizeof(buf), system_charset_info);
1278 s_query.copy(stub, sizeof(stub) - 1, system_charset_info);
1279
1280 /*
1281 Insertion sort of temporary tables by pseudo_thread_id to build ordered
1282 list of sublists of equal pseudo_thread_id.
1283 */
1284 All_tmp_tables_list::Iterator it_sorted(*temporary_tables);
1285 All_tmp_tables_list::Iterator it_unsorted(*temporary_tables);
1286 uint sorted_count= 0;
1287 while((share= it_unsorted++))
1288 {
1289 if (IS_USER_TABLE(share))
1290 {
1291 prev_sorted= NULL;
1292
1293 if (!found_user_tables) found_user_tables= true;
1294
1295 for (uint i= 0; i < sorted_count; i ++)
1296 {
1297 sorted= it_sorted ++;
1298
1299 if (!IS_USER_TABLE(sorted) ||
1300 (tmpkeyval(sorted) > tmpkeyval(share)))
1301 {
1302 /*
1303 Insert this share before the current element in
1304 the sorted part of the list.
1305 */
1306 temporary_tables->remove(share);
1307
1308 if (prev_sorted)
1309 {
1310 temporary_tables->insert_after(prev_sorted, share);
1311 }
1312 else
1313 {
1314 temporary_tables->push_front(share);
1315 }
1316 break;
1317 }
1318 prev_sorted= sorted;
1319 }
1320 it_sorted.rewind();
1321 }
1322 sorted_count ++;
1323 }
1324
1325 /*
1326 We always quote db & table names.
1327 */
1328 if (found_user_tables &&
1329 !(was_quote_show= MY_TEST(variables.option_bits &
1330 OPTION_QUOTE_SHOW_CREATE)))
1331 {
1332 variables.option_bits |= OPTION_QUOTE_SHOW_CREATE;
1333 }
1334
1335 /*
1336 Scan sorted temporary tables to generate sequence of DROP.
1337 */
1338 share= temporary_tables->pop_front();
1339 while (share)
1340 {
1341 if (IS_USER_TABLE(share))
1342 {
1343 bool save_thread_specific_used= thread_specific_used;
1344 my_thread_id save_pseudo_thread_id= variables.pseudo_thread_id;
1345 char db_buf[FN_REFLEN];
1346 String db(db_buf, sizeof(db_buf), system_charset_info);
1347 bool at_least_one_create_logged;
1348
1349 /*
1350 Set pseudo_thread_id to be that of the processed table.
1351 */
1352 variables.pseudo_thread_id= tmpkeyval(share);
1353
1354 db.copy(share->db.str, share->db.length, system_charset_info);
1355 /*
1356 Reset s_query() if changed by previous loop.
1357 */
1358 s_query.length(sizeof(stub) - 1);
1359
1360 /*
1361 Loop forward through all tables that belong to a common database
1362 within the sublist of common pseudo_thread_id to create single
1363 DROP query.
1364 */
1365 for (at_least_one_create_logged= false;
1366 share && IS_USER_TABLE(share) &&
1367 tmpkeyval(share) == variables.pseudo_thread_id &&
1368 share->db.length == db.length() &&
1369 memcmp(share->db.str, db.ptr(), db.length()) == 0;
1370 /* Get the next TABLE_SHARE in the list. */
1371 share= temporary_tables->pop_front())
1372 {
1373 if (share->table_creation_was_logged)
1374 {
1375 at_least_one_create_logged= true;
1376 /*
1377 We are going to add ` around the table names and possible more
1378 due to special characters.
1379 */
1380 append_identifier(this, &s_query, &share->table_name);
1381 s_query.append(',');
1382 }
1383 rm_temporary_table(share->db_type(), share->path.str);
1384 free_table_share(share);
1385 my_free(share);
1386 }
1387
1388 if (at_least_one_create_logged)
1389 {
1390 clear_error();
1391 CHARSET_INFO *cs_save= variables.character_set_client;
1392 variables.character_set_client= system_charset_info;
1393 thread_specific_used= true;
1394
1395 Query_log_event qinfo(this, s_query.ptr(),
1396 s_query.length() - 1 /* to remove trailing ',' */,
1397 false, true, false, 0);
1398 qinfo.db= db.ptr();
1399 qinfo.db_len= db.length();
1400 variables.character_set_client= cs_save;
1401
1402 get_stmt_da()->set_overwrite_status(true);
1403 transaction->stmt.mark_dropped_temp_table();
1404 bool error2= mysql_bin_log.write(&qinfo);
1405 if (unlikely(error|= error2))
1406 {
1407 /*
1408 If we're here following THD::cleanup, thence the connection
1409 has been closed already. So lets print a message to the
1410 error log instead of pushing yet another error into the
1411 stmt_da.
1412
1413 Also, we keep the error flag so that we propagate the error
1414 up in the stack. This way, if we're the SQL thread we notice
1415 that THD::close_tables failed. (Actually, the SQL
1416 thread only calls THD::close_tables while applying
1417 old Start_log_event_v3 events.)
1418 */
1419 sql_print_error("Failed to write the DROP statement for "
1420 "temporary tables to binary log");
1421 }
1422
1423 get_stmt_da()->set_overwrite_status(false);
1424 }
1425 variables.pseudo_thread_id= save_pseudo_thread_id;
1426 thread_specific_used= save_thread_specific_used;
1427 }
1428 else
1429 {
1430 free_tmp_table_share(share, true);
1431 /* Get the next TABLE_SHARE in the list. */
1432 share= temporary_tables->pop_front();
1433 }
1434 }
1435
1436 if (!was_quote_show)
1437 {
1438 /*
1439 Restore option.
1440 */
1441 variables.option_bits&= ~OPTION_QUOTE_SHOW_CREATE;
1442 }
1443
1444 DBUG_RETURN(error);
1445 }
1446
1447
1448 /**
1449 Delete the files and free the specified table share.
1450
1451 @param share [IN] TABLE_SHARE to free
1452 @param delete_table [IN] Whether to delete the table files?
1453
1454 @return void
1455 */
free_tmp_table_share(TMP_TABLE_SHARE * share,bool delete_table)1456 void THD::free_tmp_table_share(TMP_TABLE_SHARE *share, bool delete_table)
1457 {
1458 DBUG_ENTER("THD::free_tmp_table_share");
1459
1460 if (delete_table)
1461 {
1462 rm_temporary_table(share->db_type(), share->path.str);
1463 }
1464 free_table_share(share);
1465 my_free(share);
1466
1467 DBUG_VOID_RETURN;
1468 }
1469
1470
1471 /**
1472 Free the specified table object.
1473
1474 @param table [IN] Table object to free.
1475
1476 @return void
1477 */
free_temporary_table(TABLE * table)1478 void THD::free_temporary_table(TABLE *table)
1479 {
1480 DBUG_ENTER("THD::free_temporary_table");
1481
1482 /*
1483 If LOCK TABLES list is not empty and contains this table, unlock the table
1484 and remove the table from this list.
1485 */
1486 mysql_lock_remove(this, lock, table);
1487
1488 close_temporary_table(table);
1489
1490 DBUG_VOID_RETURN;
1491 }
1492
1493
1494 /**
1495 On replication slave, acquire the Relay_log_info's data_lock and use slave
1496 temporary tables.
1497
1498 @return true Lock acquired
1499 false Lock wasn't acquired
1500 */
lock_temporary_tables()1501 bool THD::lock_temporary_tables()
1502 {
1503 DBUG_ENTER("THD::lock_temporary_tables");
1504
1505 /* Do not proceed if a lock has already been taken. */
1506 if (m_tmp_tables_locked)
1507 {
1508 DBUG_RETURN(false);
1509 }
1510
1511 #ifdef HAVE_REPLICATION
1512 if (rgi_slave)
1513 {
1514 mysql_mutex_lock(&rgi_slave->rli->data_lock);
1515 temporary_tables= rgi_slave->rli->save_temporary_tables;
1516 m_tmp_tables_locked= true;
1517 }
1518 #endif
1519
1520 DBUG_RETURN(m_tmp_tables_locked);
1521 }
1522
1523
1524 /**
1525 On replication slave, release the Relay_log_info::data_lock previously
1526 acquired to use slave temporary tables.
1527
1528 @return void
1529 */
unlock_temporary_tables()1530 void THD::unlock_temporary_tables()
1531 {
1532 DBUG_ENTER("THD::unlock_temporary_tables");
1533
1534 if (!m_tmp_tables_locked)
1535 {
1536 DBUG_VOID_RETURN;
1537 }
1538
1539 #ifdef HAVE_REPLICATION
1540 if (rgi_slave)
1541 {
1542 rgi_slave->rli->save_temporary_tables= temporary_tables;
1543 temporary_tables= NULL; /* Safety */
1544 mysql_mutex_unlock(&rgi_slave->rli->data_lock);
1545 m_tmp_tables_locked= false;
1546 }
1547 #endif
1548
1549 DBUG_VOID_RETURN;
1550 }
1551
1552
1553 /**
1554 Close unused TABLE instances for given temporary table.
1555
1556 @param tl [IN] TABLE_LIST
1557
1558 Initial use case was TRUNCATE, which expects only one instance (which is used
1559 by TRUNCATE itself) to be open. Most probably some ALTER TABLE variants and
1560 REPAIR may have similar expectations.
1561 */
1562
close_unused_temporary_table_instances(const TABLE_LIST * tl)1563 void THD::close_unused_temporary_table_instances(const TABLE_LIST *tl)
1564 {
1565 TMP_TABLE_SHARE *share= find_tmp_table_share(tl);
1566
1567 if (share)
1568 {
1569 All_share_tables_list::Iterator tables_it(share->all_tmp_tables);
1570
1571 while (TABLE *table= tables_it++)
1572 {
1573 if (table->query_id == 0)
1574 {
1575 /* Note: removing current list element doesn't invalidate iterator. */
1576 share->all_tmp_tables.remove(table);
1577 free_temporary_table(table);
1578 }
1579 }
1580 }
1581 }
1582