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 | */ |
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 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 | */ |
63 | TABLE *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 | */ |
119 | TABLE *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 | */ |
156 | TABLE *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 | */ |
181 | TMP_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 | */ |
225 | TMP_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 | */ |
250 | TMP_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 | */ |
266 | TMP_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 | */ |
328 | bool 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 | */ |
437 | bool 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 | */ |
474 | bool 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 | */ |
546 | bool 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 | */ |
593 | bool 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 | |
650 | end: |
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 | */ |
671 | bool 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 | */ |
704 | void 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 | */ |
768 | void 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 | */ |
813 | TMP_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 | */ |
836 | void 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 | */ |
857 | inline 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 | */ |
889 | uint 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 | */ |
917 | TMP_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 | */ |
1025 | TABLE *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 | |
1078 | done: |
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 | */ |
1100 | TABLE *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 | */ |
1159 | bool 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 | */ |
1187 | bool 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 | */ |
1234 | void 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 | */ |
1264 | bool 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 | */ |
1452 | void 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 | */ |
1475 | void 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 | */ |
1498 | bool 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 | */ |
1525 | void 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 | |