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