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