1 /*
2 Copyright (c) 2000, 2021, Oracle and/or its affiliates.
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, version 2.0,
6 as published by the Free Software Foundation.
7
8 This program is also distributed with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation. The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have included with MySQL.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License, version 2.0, for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25
26 /*****************************************************************************
27 **
28 ** This file implements classes defined in sql_class.h
29 ** Especially the classes to handle a result from a select
30 **
31 *****************************************************************************/
32
33 #include "sql_class.h"
34
35 #include "mysys_err.h" // EE_DELETE
36 #include "connection_handler_manager.h" // Connection_handler_manager
37 #include "debug_sync.h" // DEBUG_SYNC
38 #include "lock.h" // mysql_lock_abort_for_thread
39 #include "locking_service.h" // release_all_locking_service_locks
40 #include "mysqld_thd_manager.h" // Global_THD_manager
41 #include "parse_tree_nodes.h" // PT_select_var
42 #include "rpl_filter.h" // binlog_filter
43 #include "rpl_rli.h" // Relay_log_info
44 #include "sp_cache.h" // sp_cache_clear
45 #include "sp_rcontext.h" // sp_rcontext
46 #include "sql_audit.h" // mysql_audit_release
47 #include "sql_base.h" // close_temporary_tables
48 #include "sql_callback.h" // MYSQL_CALLBACK
49 #include "sql_handler.h" // mysql_ha_cleanup
50 #include "sql_parse.h" // is_update_query
51 #include "sql_plugin.h" // plugin_unlock
52 #include "sql_prepare.h" // Prepared_statement
53 #include "sql_time.h" // my_timeval_trunc
54 #include "sql_timer.h" // thd_timer_destroy
55 #include "sql_thd_internal_api.h"
56 #include "transaction.h" // trans_rollback
57 #ifdef HAVE_REPLICATION
58 #include "rpl_rli_pdb.h" // Slave_worker
59 #include "rpl_slave_commit_order_manager.h"
60 #include "rpl_master.h" // unregister_slave
61 #endif
62
63 #include "pfs_file_provider.h"
64 #include "mysql/psi/mysql_file.h"
65
66 #include "pfs_idle_provider.h"
67 #include "mysql/psi/mysql_idle.h"
68
69 #include "mysql/psi/mysql_ps.h"
70 #ifdef WITH_WSREP
71 #include "wsrep_mysqld.h"
72 #include "wsrep_thd.h"
73 #endif
74
75 using std::min;
76 using std::max;
77
78 /*
79 The following is used to initialise Table_ident with a internal
80 table name
81 */
82 char internal_table_name[2]= "";
83 char empty_c_string[1]= {0}; /* used for not defined db */
84
85 LEX_STRING EMPTY_STR= { (char *) "", 0 };
86 LEX_STRING NULL_STR= { NULL, 0 };
87 LEX_CSTRING EMPTY_CSTR= { "", 0 };
88 LEX_CSTRING NULL_CSTR= { NULL, 0 };
89
90 const char * const THD::DEFAULT_WHERE= "field list";
91
92
backup(THD * thd)93 void THD::Transaction_state::backup(THD *thd)
94 {
95 this->m_sql_command= thd->lex->sql_command;
96 this->m_trx= thd->get_transaction();
97
98 for (int i= 0; i < MAX_HA; ++i)
99 this->m_ha_data[i]= thd->ha_data[i];
100
101 this->m_tx_isolation= thd->tx_isolation;
102 this->m_tx_read_only= thd->tx_read_only;
103 this->m_thd_option_bits= thd->variables.option_bits;
104 this->m_sql_mode= thd->variables.sql_mode;
105 this->m_transaction_psi= thd->m_transaction_psi;
106 this->m_server_status= thd->server_status;
107 }
108
109
restore(THD * thd)110 void THD::Transaction_state::restore(THD *thd)
111 {
112 thd->set_transaction(this->m_trx);
113
114 for (int i= 0; i < MAX_HA; ++i)
115 thd->ha_data[i]= this->m_ha_data[i];
116
117 thd->tx_isolation= this->m_tx_isolation;
118 thd->variables.sql_mode= this->m_sql_mode;
119 thd->tx_read_only= this->m_tx_read_only;
120 thd->variables.option_bits= this->m_thd_option_bits;
121
122 thd->m_transaction_psi= this->m_transaction_psi;
123 thd->server_status= this->m_server_status;
124 thd->lex->sql_command= this->m_sql_command;
125 }
126
Attachable_trx(THD * thd)127 THD::Attachable_trx::Attachable_trx(THD *thd)
128 :m_thd(thd)
129 {
130 // The THD::transaction_rollback_request is expected to be unset in the
131 // attachable transaction. It's weird to start attachable transaction when the
132 // SE asked to rollback the regular transaction.
133 assert(!m_thd->transaction_rollback_request);
134
135 // Save the transaction state.
136
137 m_trx_state.backup(m_thd);
138
139 // Save and reset query-tables-list and reset the sql-command.
140 //
141 // NOTE: ha_innobase::store_lock() takes the current sql-command into account.
142 // It must be SQLCOM_SELECT.
143 //
144 // Do NOT reset LEX if we're running tests. LEX is used by SELECT statements.
145
146 if (DBUG_EVALUATE_IF("use_attachable_trx", false, true))
147 {
148 m_thd->lex->reset_n_backup_query_tables_list(&m_trx_state.m_query_tables_list);
149 m_thd->lex->sql_command= SQLCOM_SELECT;
150 }
151
152 // Save and reset open-tables.
153
154 m_thd->reset_n_backup_open_tables_state(&m_trx_state.m_open_tables_state);
155
156 // Reset transaction state.
157
158 m_thd->m_transaction.release(); // it's been backed up.
159 m_thd->m_transaction.reset(new Transaction_ctx());
160
161 // Prepare for a new attachable transaction for read-only DD-transaction.
162
163 for (int i= 0; i < MAX_HA; ++i)
164 m_thd->ha_data[i]= Ha_data();
165
166 // The attachable transaction must used READ COMMITTED isolation level.
167
168 m_thd->tx_isolation= ISO_READ_COMMITTED;
169
170 // The attachable transaction must be read-only.
171
172 m_thd->tx_read_only= true;
173
174 // The attachable transaction must be AUTOCOMMIT.
175
176 m_thd->variables.option_bits|= OPTION_AUTOCOMMIT;
177 m_thd->variables.option_bits&= ~OPTION_NOT_AUTOCOMMIT;
178 m_thd->variables.option_bits&= ~OPTION_BEGIN;
179
180 // Possible parent's involvement to multi-statement transaction is masked
181
182 m_thd->server_status&= ~SERVER_STATUS_IN_TRANS;
183 m_thd->server_status&= ~SERVER_STATUS_IN_TRANS_READONLY;
184
185 // Reset SQL_MODE during system operations.
186
187 m_thd->variables.sql_mode= 0;
188
189 // Reset transaction instrumentation.
190
191 m_thd->m_transaction_psi= NULL;
192 }
193
194
~Attachable_trx()195 THD::Attachable_trx::~Attachable_trx()
196 {
197 // Ensure that the SE didn't request rollback in the attachable transaction.
198 // Having THD::transaction_rollback_request set most likely means that we've
199 // experienced some sort of deadlock/timeout while processing the attachable
200 // transaction. That is not possible by the definition of an attachable
201 // transaction.
202 assert(!m_thd->transaction_rollback_request);
203
204 // Commit the attachable transaction before discarding transaction state.
205 // This is mostly needed to properly reset transaction state in SE.
206 // Note: We can't rely on InnoDB hack which auto-magically commits InnoDB
207 // transaction when the last table for a statement in auto-commit mode is
208 // unlocked. Apparently it doesn't work correctly in some corner cases
209 // (for example, when statement is killed just after tables are locked but
210 // before any other operations on the table happes). We try not to rely on
211 // it in other places on SQL-layer as well.
212 trans_commit_attachable(m_thd);
213
214 // Close all the tables that are open till now.
215
216 close_thread_tables(m_thd);
217
218 // Cleanup connection specific state which was created for attachable
219 // transaction (for InnoDB removes cached transaction object).
220 //
221 // Note that we need to call handlerton::close_connection for all SEs
222 // and not only SEs which participated in attachable transaction since
223 // connection specific state can be created when TABLE object is simply
224 // expelled from the Table Cache (e.g. this happens for MyISAM).
225 ha_close_connection(m_thd);
226
227 // Restore the transaction state.
228
229 m_trx_state.restore(m_thd);
230
231 m_thd->restore_backup_open_tables_state(&m_trx_state.m_open_tables_state);
232
233 if (DBUG_EVALUATE_IF("use_attachable_trx", false, true))
234 {
235 m_thd->lex->restore_backup_query_tables_list(
236 &m_trx_state.m_query_tables_list);
237 }
238 }
239
240
241 /****************************************************************************
242 ** User variables
243 ****************************************************************************/
244
get_var_key(user_var_entry * entry,size_t * length,my_bool not_used MY_ATTRIBUTE ((unused)))245 extern "C" uchar *get_var_key(user_var_entry *entry, size_t *length,
246 my_bool not_used MY_ATTRIBUTE((unused)))
247 {
248 *length= entry->entry_name.length();
249 return (uchar*) entry->entry_name.ptr();
250 }
251
free_user_var(user_var_entry * entry)252 extern "C" void free_user_var(user_var_entry *entry)
253 {
254 entry->destroy();
255 }
256
operator ==(const Key_part_spec & other) const257 bool Key_part_spec::operator==(const Key_part_spec& other) const
258 {
259 return length == other.length &&
260 !my_strcasecmp(system_charset_info, field_name.str,
261 other.field_name.str);
262 }
263
264 /**
265 Construct an (almost) deep copy of this key. Only those
266 elements that are known to never change are not copied.
267 If out of memory, a partial copy is returned and an error is set
268 in THD.
269 */
270
Key(const Key & rhs,MEM_ROOT * mem_root)271 Key::Key(const Key &rhs, MEM_ROOT *mem_root)
272 :type(rhs.type),
273 key_create_info(rhs.key_create_info),
274 columns(rhs.columns, mem_root),
275 name(rhs.name),
276 generated(rhs.generated)
277 {
278 list_copy_and_replace_each_value(columns, mem_root);
279 }
280
281 /**
282 Construct an (almost) deep copy of this foreign key. Only those
283 elements that are known to never change are not copied.
284 If out of memory, a partial copy is returned and an error is set
285 in THD.
286 */
287
Foreign_key(const Foreign_key & rhs,MEM_ROOT * mem_root)288 Foreign_key::Foreign_key(const Foreign_key &rhs, MEM_ROOT *mem_root)
289 :Key(rhs, mem_root),
290 ref_db(rhs.ref_db),
291 ref_table(rhs.ref_table),
292 ref_columns(rhs.ref_columns, mem_root),
293 delete_opt(rhs.delete_opt),
294 update_opt(rhs.update_opt),
295 match_opt(rhs.match_opt)
296 {
297 list_copy_and_replace_each_value(ref_columns, mem_root);
298 }
299
300 /*
301 Test if a foreign key (= generated key) is a prefix of the given key
302 (ignoring key name, key type and order of columns)
303
304 NOTES:
305 This is only used to test if an index for a FOREIGN KEY exists
306
307 IMPLEMENTATION
308 We only compare field names
309
310 RETURN
311 0 Generated key is a prefix of other key
312 1 Not equal
313 */
314
foreign_key_prefix(Key * a,Key * b)315 bool foreign_key_prefix(Key *a, Key *b)
316 {
317 /* Ensure that 'a' is the generated key */
318 if (a->generated)
319 {
320 if (b->generated && a->columns.elements > b->columns.elements)
321 swap_variables(Key*, a, b); // Put shorter key in 'a'
322 }
323 else
324 {
325 if (!b->generated)
326 return TRUE; // No foreign key
327 swap_variables(Key*, a, b); // Put generated key in 'a'
328 }
329
330 /* Test if 'a' is a prefix of 'b' */
331 if (a->columns.elements > b->columns.elements)
332 return TRUE; // Can't be prefix
333
334 List_iterator<Key_part_spec> col_it1(a->columns);
335 List_iterator<Key_part_spec> col_it2(b->columns);
336 const Key_part_spec *col1, *col2;
337
338 #ifdef ENABLE_WHEN_INNODB_CAN_HANDLE_SWAPED_FOREIGN_KEY_COLUMNS
339 while ((col1= col_it1++))
340 {
341 bool found= 0;
342 col_it2.rewind();
343 while ((col2= col_it2++))
344 {
345 if (*col1 == *col2)
346 {
347 found= TRUE;
348 break;
349 }
350 }
351 if (!found)
352 return TRUE; // Error
353 }
354 return FALSE; // Is prefix
355 #else
356 while ((col1= col_it1++))
357 {
358 col2= col_it2++;
359 if (!(*col1 == *col2))
360 return TRUE;
361 }
362 return FALSE; // Is prefix
363 #endif
364 }
365
366 /**
367 @brief validate
368 Check if the foreign key options are compatible with columns
369 on which the FK is created.
370
371 @param table_fields List of columns
372
373 @return
374 false Key valid
375 @return
376 true Key invalid
377 */
validate(List<Create_field> & table_fields)378 bool Foreign_key::validate(List<Create_field> &table_fields)
379 {
380 Create_field *sql_field;
381 Key_part_spec *column;
382 List_iterator<Key_part_spec> cols(columns);
383 List_iterator<Create_field> it(table_fields);
384 DBUG_ENTER("Foreign_key::validate");
385 while ((column= cols++))
386 {
387 it.rewind();
388 while ((sql_field= it++) &&
389 my_strcasecmp(system_charset_info,
390 column->field_name.str,
391 sql_field->field_name)) {}
392 if (!sql_field)
393 {
394 my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), column->field_name.str);
395 DBUG_RETURN(TRUE);
396 }
397 if (type == KEYTYPE_FOREIGN && sql_field->gcol_info)
398 {
399 if (delete_opt == FK_OPTION_SET_NULL)
400 {
401 my_error(ER_WRONG_FK_OPTION_FOR_GENERATED_COLUMN, MYF(0),
402 "ON DELETE SET NULL");
403 DBUG_RETURN(TRUE);
404 }
405 if (update_opt == FK_OPTION_SET_NULL)
406 {
407 my_error(ER_WRONG_FK_OPTION_FOR_GENERATED_COLUMN, MYF(0),
408 "ON UPDATE SET NULL");
409 DBUG_RETURN(TRUE);
410 }
411 if (update_opt == FK_OPTION_CASCADE)
412 {
413 my_error(ER_WRONG_FK_OPTION_FOR_GENERATED_COLUMN, MYF(0),
414 "ON UPDATE CASCADE");
415 DBUG_RETURN(TRUE);
416 }
417 }
418 }
419 DBUG_RETURN(FALSE);
420 }
421
422 /****************************************************************************
423 ** Thread specific functions
424 ****************************************************************************/
425
426 /**
427 Get reference to scheduler data object
428
429 @param thd THD object
430
431 @retval Scheduler data object on THD
432 */
thd_get_scheduler_data(THD * thd)433 void *thd_get_scheduler_data(THD *thd)
434 {
435 return thd->scheduler.data;
436 }
437
438 /**
439 Set reference to Scheduler data object for THD object
440
441 @param thd THD object
442 @param psi Scheduler data object to set on THD
443 */
thd_set_scheduler_data(THD * thd,void * data)444 void thd_set_scheduler_data(THD *thd, void *data)
445 {
446 thd->scheduler.data= data;
447 }
448
get_psi()449 PSI_thread* THD::get_psi()
450 {
451 void *addr= & m_psi;
452 void * volatile * typed_addr= static_cast<void * volatile *>(addr);
453 void *ptr;
454 ptr= my_atomic_loadptr(typed_addr);
455 return static_cast<PSI_thread*>(ptr);
456 }
457
set_psi(PSI_thread * psi)458 void THD::set_psi(PSI_thread *psi)
459 {
460 void *addr= & m_psi;
461 void * volatile * typed_addr= static_cast<void * volatile *>(addr);
462 my_atomic_storeptr(typed_addr, psi);
463 }
464
465 /**
466 Get reference to Performance Schema object for THD object
467
468 @param thd THD object
469
470 @return Performance schema object for thread on THD
471 */
thd_get_psi(THD * thd)472 PSI_thread *thd_get_psi(THD *thd)
473 {
474 return thd->get_psi();
475 }
476
477
478 /**
479 Get net_wait_timeout for THD object
480
481 @param thd THD object
482
483 @retval net_wait_timeout value for thread on THD
484 */
thd_get_net_wait_timeout(THD * thd)485 ulong thd_get_net_wait_timeout(THD* thd)
486 {
487 return thd->variables.net_wait_timeout;
488 }
489
490 /**
491 Set reference to Performance Schema object for THD object
492
493 @param thd THD object
494 @param psi Performance schema object for thread
495 */
thd_set_psi(THD * thd,PSI_thread * psi)496 void thd_set_psi(THD *thd, PSI_thread *psi)
497 {
498 thd->set_psi(psi);
499 }
500
501 /**
502 Set the state on connection to killed
503
504 @param thd THD object
505 */
thd_set_killed(THD * thd)506 void thd_set_killed(THD *thd)
507 {
508 thd->killed= THD::KILL_CONNECTION;
509 }
510
511 /**
512 Clear errors from the previous THD
513
514 @param thd THD object
515 */
thd_clear_errors(THD * thd)516 void thd_clear_errors(THD *thd)
517 {
518 set_my_errno(0);
519 }
520
521 /**
522 Close the socket used by this connection
523
524 @param thd THD object
525 */
thd_close_connection(THD * thd)526 void thd_close_connection(THD *thd)
527 {
528 thd->get_protocol_classic()->shutdown();
529 }
530
531 /**
532 Get current THD object from thread local data
533
534 @retval The THD object for the thread, NULL if not connection thread
535 */
thd_get_current_thd()536 THD *thd_get_current_thd()
537 {
538 return current_thd;
539 }
540
541 /**
542 Reset thread globals associated.
543
544 @param thd THD object
545 */
reset_thread_globals(THD * thd)546 void reset_thread_globals(THD* thd)
547 {
548 thd->restore_globals();
549 thd->set_is_killable(false);
550 }
551
552 extern "C"
thd_binlog_pos(const THD * thd,const char ** file_var,unsigned long long * pos_var)553 void thd_binlog_pos(const THD *thd,
554 const char **file_var,
555 unsigned long long *pos_var)
556 {
557 thd->get_trans_pos(file_var, pos_var);
558 }
559
560 /**
561 Lock data that needs protection in THD object
562
563 @param thd THD object
564 */
thd_lock_data(THD * thd)565 void thd_lock_data(THD *thd)
566 {
567 mysql_mutex_lock(&thd->LOCK_thd_data);
568 }
569
570 /**
571 Unlock data that needs protection in THD object
572
573 @param thd THD object
574 */
thd_unlock_data(THD * thd)575 void thd_unlock_data(THD *thd)
576 {
577 mysql_mutex_unlock(&thd->LOCK_thd_data);
578 }
579
580 /**
581 Support method to check if connection has already started transaction
582
583 @param client_cntx Low level client context
584
585 @retval TRUE if connection already started transaction
586 */
thd_is_transaction_active(THD * thd)587 bool thd_is_transaction_active(THD *thd)
588 {
589 return thd->get_transaction()->is_active(Transaction_ctx::SESSION);
590 }
591
592 /**
593 Check if there is buffered data on the socket representing the connection
594
595 @param thd THD object
596 */
thd_connection_has_data(THD * thd)597 int thd_connection_has_data(THD *thd)
598 {
599 Vio *vio= thd->get_protocol_classic()->get_vio();
600 return vio->has_data(vio);
601 }
602
603 /**
604 Set reading/writing on socket, used by SHOW PROCESSLIST
605
606 @param thd THD object
607 @param val Value to set it to (0 or 1)
608 */
thd_set_net_read_write(THD * thd,uint val)609 void thd_set_net_read_write(THD *thd, uint val)
610 {
611 thd->get_protocol_classic()->get_net()->reading_or_writing= val;
612 }
613
614 /**
615 Get reading/writing on socket from THD object
616 @param thd THD object
617
618 @retval net.reading_or_writing value for thread on THD.
619 */
thd_get_net_read_write(THD * thd)620 uint thd_get_net_read_write(THD *thd)
621 {
622 return thd->get_protocol_classic()->get_rw_status();
623 }
624
625 /**
626 Mark the THD as not killable as it is not currently used by a thread.
627
628 @param thd THD object
629 */
thd_set_not_killable(THD * thd)630 void thd_set_not_killable(THD *thd)
631 {
632 thd->set_is_killable(false);
633 }
634
635 /**
636 Get socket file descriptor for this connection
637
638 @param thd THD object
639
640 @retval Socket of the connection
641 */
thd_get_fd(THD * thd)642 my_socket thd_get_fd(THD *thd)
643 {
644 return thd->get_protocol_classic()->get_socket();
645 }
646
647 /**
648 Set thread specific environment required for thd cleanup in thread pool.
649
650 @param thd THD object
651
652 @retval 1 if thread-specific enviroment could be set else 0
653 */
thd_store_globals(THD * thd)654 int thd_store_globals(THD* thd)
655 {
656 return thd->store_globals();
657 }
658
659 /**
660 Get thread attributes for connection threads
661
662 @retval Reference to thread attribute for connection threads
663 */
get_connection_attrib(void)664 my_thread_attr_t *get_connection_attrib(void)
665 {
666 return &connection_attrib;
667 }
668
669 /**
670 Get max number of connections
671
672 @retval Max number of connections for MySQL Server
673 */
get_max_connections(void)674 ulong get_max_connections(void)
675 {
676 return max_connections;
677 }
678
679 /*
680 The following functions form part of the C plugin API
681 */
682
mysql_tmpfile(const char * prefix)683 extern "C" int mysql_tmpfile(const char *prefix)
684 {
685 return mysql_tmpfile_path(mysql_tmpdir, prefix);
686 }
687
688
689 extern "C"
thd_in_lock_tables(const THD * thd)690 int thd_in_lock_tables(const THD *thd)
691 {
692 return MY_TEST(thd->in_lock_tables);
693 }
694
695
696 extern "C"
thd_tablespace_op(const THD * thd)697 int thd_tablespace_op(const THD *thd)
698 {
699 return MY_TEST(thd->tablespace_op);
700 }
701
702
703 extern "C"
set_thd_proc_info(MYSQL_THD thd_arg,const char * info,const char * calling_function,const char * calling_file,const unsigned int calling_line)704 const char *set_thd_proc_info(MYSQL_THD thd_arg, const char *info,
705 const char *calling_function,
706 const char *calling_file,
707 const unsigned int calling_line)
708 {
709 PSI_stage_info old_stage;
710 PSI_stage_info new_stage;
711
712 old_stage.m_key= 0;
713 old_stage.m_name= info;
714
715 set_thd_stage_info(thd_arg, & old_stage, & new_stage,
716 calling_function, calling_file, calling_line);
717
718 return new_stage.m_name;
719 }
720
721 extern "C"
set_thd_stage_info(void * opaque_thd,const PSI_stage_info * new_stage,PSI_stage_info * old_stage,const char * calling_func,const char * calling_file,const unsigned int calling_line)722 void set_thd_stage_info(void *opaque_thd,
723 const PSI_stage_info *new_stage,
724 PSI_stage_info *old_stage,
725 const char *calling_func,
726 const char *calling_file,
727 const unsigned int calling_line)
728 {
729 THD *thd= (THD*) opaque_thd;
730 if (thd == NULL)
731 thd= current_thd;
732
733 thd->enter_stage(new_stage, old_stage, calling_func, calling_file, calling_line);
734 }
735
736
enter_stage(const PSI_stage_info * new_stage,PSI_stage_info * old_stage,const char * calling_func,const char * calling_file,const unsigned int calling_line)737 void THD::enter_stage(const PSI_stage_info *new_stage,
738 PSI_stage_info *old_stage,
739 const char *calling_func,
740 const char *calling_file,
741 const unsigned int calling_line)
742 {
743 DBUG_PRINT("THD::enter_stage",
744 ("'%s' %s:%d", new_stage ? new_stage->m_name : "",
745 calling_file, calling_line));
746
747 if (old_stage != NULL)
748 {
749 old_stage->m_key= m_current_stage_key;
750 old_stage->m_name= proc_info;
751 }
752
753 if (new_stage != NULL)
754 {
755 const char *msg= new_stage->m_name;
756
757 #if defined(ENABLED_PROFILING)
758 profiling.status_change(msg, calling_func, calling_file, calling_line);
759 #endif
760
761 m_current_stage_key= new_stage->m_key;
762 proc_info= msg;
763
764 m_stage_progress_psi= MYSQL_SET_STAGE(m_current_stage_key, calling_file, calling_line);
765 }
766 else
767 {
768 m_stage_progress_psi= NULL;
769 }
770
771 return;
772 }
773
774 extern "C"
thd_enter_cond(void * opaque_thd,mysql_cond_t * cond,mysql_mutex_t * mutex,const PSI_stage_info * stage,PSI_stage_info * old_stage,const char * src_function,const char * src_file,int src_line)775 void thd_enter_cond(void *opaque_thd, mysql_cond_t *cond, mysql_mutex_t *mutex,
776 const PSI_stage_info *stage, PSI_stage_info *old_stage,
777 const char *src_function, const char *src_file,
778 int src_line)
779 {
780 THD *thd= static_cast<THD*>(opaque_thd);
781 if (!thd)
782 thd= current_thd;
783
784 return thd->enter_cond(cond, mutex, stage, old_stage,
785 src_function, src_file, src_line);
786 }
787
788 extern "C"
thd_exit_cond(void * opaque_thd,const PSI_stage_info * stage,const char * src_function,const char * src_file,int src_line)789 void thd_exit_cond(void *opaque_thd, const PSI_stage_info *stage,
790 const char *src_function, const char *src_file,
791 int src_line)
792 {
793 THD *thd= static_cast<THD*>(opaque_thd);
794 if (!thd)
795 thd= current_thd;
796
797 thd->exit_cond(stage, src_function, src_file, src_line);
798 }
799
800 extern "C"
thd_ha_data(const THD * thd,const struct handlerton * hton)801 void **thd_ha_data(const THD *thd, const struct handlerton *hton)
802 {
803 return (void **) &thd->ha_data[hton->slot].ha_ptr;
804 }
805
806 extern "C"
thd_storage_lock_wait(THD * thd,long long value)807 void thd_storage_lock_wait(THD *thd, long long value)
808 {
809 thd->utime_after_lock+= value;
810 }
811
812 /**
813 Provide a handler data getter to simplify coding
814 */
815 extern "C"
thd_get_ha_data(const THD * thd,const struct handlerton * hton)816 void *thd_get_ha_data(const THD *thd, const struct handlerton *hton)
817 {
818 return *thd_ha_data(thd, hton);
819 }
820
821 #ifdef WITH_WSREP
wsrep_on(void * thd)822 extern int wsrep_on(void *thd)
823 {
824 return (int)(WSREP(((THD*)thd)));
825 }
wsrep_thd_is_wsrep_on(THD * thd)826 extern "C" bool wsrep_thd_is_wsrep_on(THD *thd)
827 {
828 return thd->variables.wsrep_on;
829 }
830
wsrep_consistency_check(void * thd)831 extern "C" bool wsrep_consistency_check(void *thd)
832 {
833 return ((THD*)thd)->wsrep_consistency_check == CONSISTENCY_CHECK_RUNNING;
834 }
835
wsrep_thd_set_exec_mode(THD * thd,enum wsrep_exec_mode mode)836 extern "C" void wsrep_thd_set_exec_mode(THD *thd, enum wsrep_exec_mode mode)
837 {
838 thd->wsrep_exec_mode= mode;
839 }
wsrep_thd_set_query_state(THD * thd,enum wsrep_query_state state)840 extern "C" void wsrep_thd_set_query_state(
841 THD *thd, enum wsrep_query_state state)
842 {
843 if (!WSREP(thd)) return;
844 /* async slave thread should never flag IDLE state, as it may
845 give rollbacker thread chance to interfere and rollback async slave
846 transaction.
847 in fact, async slave thread is never idle as it reads complete
848 transactions from relay log and applies them, as a whole.
849 BF abort happens voluntarily by async slave thread.
850 */
851 if (thd->slave_thread && state == QUERY_IDLE) {
852 WSREP_DEBUG("Skipping IDLE state change for slave SQL");
853 return;
854 }
855
856 thd->wsrep_query_state= state;
857 }
wsrep_thd_set_conflict_state(THD * thd,bool lock,enum wsrep_conflict_state state)858 extern "C" void wsrep_thd_set_conflict_state(
859 THD *thd, bool lock, enum wsrep_conflict_state state)
860 {
861 if (WSREP(thd))
862 {
863 if (lock) mysql_mutex_lock(&thd->LOCK_wsrep_thd);
864 thd->wsrep_conflict_state= state;
865 if (lock) mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
866 }
867 }
868
869
wsrep_thd_exec_mode(THD * thd)870 extern "C" enum wsrep_exec_mode wsrep_thd_exec_mode(THD *thd)
871 {
872 return thd->wsrep_exec_mode;
873 }
874
wsrep_thd_exec_mode_str(THD * thd)875 extern "C" const char *wsrep_thd_exec_mode_str(THD *thd)
876 {
877 return
878 (!thd) ? "void" :
879 (thd->wsrep_exec_mode == LOCAL_STATE) ? "local" :
880 (thd->wsrep_exec_mode == REPL_RECV) ? "applier" :
881 (thd->wsrep_exec_mode == TOTAL_ORDER) ? "total order" :
882 (thd->wsrep_exec_mode == LOCAL_COMMIT) ? "local commit" : "void";
883 }
884
wsrep_thd_query_state(THD * thd)885 extern "C" enum wsrep_query_state wsrep_thd_query_state(THD *thd)
886 {
887 return thd->wsrep_query_state;
888 }
889
wsrep_thd_query_state_str(THD * thd)890 extern "C" const char *wsrep_thd_query_state_str(THD *thd)
891 {
892 return
893 (!thd) ? "void" :
894 (thd->wsrep_query_state == QUERY_IDLE) ? "idle" :
895 (thd->wsrep_query_state == QUERY_EXEC) ? "executing" :
896 (thd->wsrep_query_state == QUERY_COMMITTING) ? "committing" :
897 (thd->wsrep_query_state == QUERY_EXITING) ? "exiting" :
898 (thd->wsrep_query_state == QUERY_ROLLINGBACK) ? "rolling back" : "void";
899 }
900
wsrep_thd_conflict_state(THD * thd)901 extern "C" enum wsrep_conflict_state wsrep_thd_conflict_state(THD *thd)
902 {
903 return thd->wsrep_conflict_state;
904 }
wsrep_thd_conflict_state_str(THD * thd)905 extern "C" const char *wsrep_thd_conflict_state_str(THD *thd)
906 {
907 return
908 (!thd) ? "void" :
909 (thd->wsrep_conflict_state == NO_CONFLICT) ? "no conflict" :
910 (thd->wsrep_conflict_state == MUST_ABORT) ? "must abort" :
911 (thd->wsrep_conflict_state == ABORTING) ? "aborting" :
912 (thd->wsrep_conflict_state == ABORTED) ? "aborted" :
913 (thd->wsrep_conflict_state == MUST_REPLAY) ? "must replay" :
914 (thd->wsrep_conflict_state == REPLAYING) ? "replaying" :
915 (thd->wsrep_conflict_state == RETRY_AUTOCOMMIT) ? "retrying" :
916 (thd->wsrep_conflict_state == CERT_FAILURE) ? "cert failure" : "void";
917 }
918
wsrep_thd_ws_handle(THD * thd)919 extern "C" wsrep_ws_handle_t* wsrep_thd_ws_handle(THD *thd)
920 {
921 return &thd->wsrep_ws_handle;
922 }
923
wsrep_thd_LOCK(THD * thd)924 extern "C" void wsrep_thd_LOCK(THD *thd)
925 {
926 mysql_mutex_lock(&thd->LOCK_wsrep_thd);
927 }
wsrep_thd_UNLOCK(THD * thd)928 extern "C" void wsrep_thd_UNLOCK(THD *thd)
929 {
930 mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
931 }
wsrep_thd_query_start(THD * thd)932 extern "C" time_t wsrep_thd_query_start(THD *thd)
933 {
934 return thd->query_start();
935 }
wsrep_thd_wsrep_rand(THD * thd)936 extern "C" uint32 wsrep_thd_wsrep_rand(THD *thd)
937 {
938 return thd->wsrep_rand;
939 }
wsrep_thd_thread_id(THD * thd)940 extern "C" my_thread_id wsrep_thd_thread_id(THD *thd)
941 {
942 return thd->thread_id();
943 }
wsrep_thd_trx_seqno(THD * thd)944 extern "C" wsrep_seqno_t wsrep_thd_trx_seqno(THD *thd)
945 {
946 return (thd) ? thd->wsrep_trx_meta.gtid.seqno : WSREP_SEQNO_UNDEFINED;
947 }
wsrep_thd_query_id(THD * thd)948 extern "C" query_id_t wsrep_thd_query_id(THD *thd)
949 {
950 return thd->query_id;
951 }
wsrep_thd_next_trx_id(THD * thd)952 extern "C" wsrep_trx_id_t wsrep_thd_next_trx_id(THD *thd)
953 {
954 return thd->wsrep_next_trx_id();
955 }
wsrep_thd_set_next_trx_id(THD * thd)956 extern "C" void wsrep_thd_set_next_trx_id(THD *thd)
957 {
958 if (thd->wsrep_trx_id() == WSREP_UNDEFINED_TRX_ID)
959 {
960 thd->set_wsrep_next_trx_id(thd->query_id);
961 }
962 }
wsrep_thd_trx_id(THD * thd)963 extern "C" wsrep_trx_id_t wsrep_thd_trx_id(THD *thd)
964 {
965 return thd->wsrep_trx_id();
966 }
wsrep_thd_query(THD * thd)967 extern "C" const char *wsrep_thd_query(THD *thd)
968 {
969 return (thd) ? thd->query().str : NULL;
970 }
wsrep_thd_wsrep_last_query_id(THD * thd)971 extern "C" query_id_t wsrep_thd_wsrep_last_query_id(THD *thd)
972 {
973 return thd->wsrep_last_query_id;
974 }
wsrep_thd_set_wsrep_last_query_id(THD * thd,query_id_t id)975 extern "C" void wsrep_thd_set_wsrep_last_query_id(THD *thd, query_id_t id)
976 {
977 thd->wsrep_last_query_id= id;
978 }
wsrep_thd_awake(THD * thd,my_bool signal)979 extern "C" void wsrep_thd_awake(THD *thd, my_bool signal)
980 {
981 if (signal)
982 {
983 mysql_mutex_lock(&thd->LOCK_thd_data);
984 thd->awake(THD::KILL_QUERY);
985 mysql_mutex_unlock(&thd->LOCK_thd_data);
986 }
987 else
988 {
989 mysql_mutex_lock(&LOCK_wsrep_replaying);
990 mysql_cond_broadcast(&COND_wsrep_replaying);
991 mysql_mutex_unlock(&LOCK_wsrep_replaying);
992 }
993 }
wsrep_thd_retry_counter(THD * thd)994 extern "C" int wsrep_thd_retry_counter(THD *thd)
995 {
996 return(thd->wsrep_retry_counter);
997 }
998
999 extern int
wsrep_trx_order_before(void * thd1,void * thd2)1000 wsrep_trx_order_before(void *thd1, void *thd2)
1001 {
1002 if (wsrep_thd_trx_seqno((THD*)thd1) < wsrep_thd_trx_seqno((THD*)thd2)) {
1003 WSREP_DEBUG("BF conflict, order: %lld %lld\n",
1004 (long long)wsrep_thd_trx_seqno((THD*)thd1),
1005 (long long)wsrep_thd_trx_seqno((THD*)thd2));
1006 return 1;
1007 }
1008 WSREP_DEBUG("waiting for BF, trx order: %lld %lld\n",
1009 (long long)wsrep_thd_trx_seqno((THD*)thd1),
1010 (long long)wsrep_thd_trx_seqno((THD*)thd2));
1011 return 0;
1012 }
1013 extern "C" int
wsrep_trx_is_aborting(void * thd_ptr)1014 wsrep_trx_is_aborting(void *thd_ptr)
1015 {
1016 mysql_mutex_lock(&((THD*)thd_ptr)->LOCK_wsrep_thd);
1017 if (thd_ptr) {
1018 if ((((THD *)thd_ptr)->wsrep_conflict_state == MUST_ABORT) ||
1019 (((THD *)thd_ptr)->wsrep_conflict_state == ABORTING)) {
1020 mysql_mutex_unlock(&((THD*)thd_ptr)->LOCK_wsrep_thd);
1021 return 1;
1022 }
1023 }
1024 mysql_mutex_unlock(&((THD*)thd_ptr)->LOCK_wsrep_thd);
1025 return 0;
1026 }
1027 #endif
1028
1029 /**
1030 Provide a handler data setter to simplify coding
1031 @see thd_set_ha_data() definition in plugin.h
1032 */
1033 extern "C"
thd_set_ha_data(THD * thd,const struct handlerton * hton,const void * ha_data)1034 void thd_set_ha_data(THD *thd, const struct handlerton *hton,
1035 const void *ha_data)
1036 {
1037 plugin_ref *lock= &thd->ha_data[hton->slot].lock;
1038 if (ha_data && !*lock)
1039 *lock= ha_lock_engine(NULL, (handlerton*) hton);
1040 else if (!ha_data && *lock)
1041 {
1042 plugin_unlock(NULL, *lock);
1043 *lock= NULL;
1044 }
1045 *thd_ha_data(thd, hton)= (void*) ha_data;
1046 }
1047
1048
1049 extern "C"
thd_test_options(const THD * thd,long long test_options)1050 long long thd_test_options(const THD *thd, long long test_options)
1051 {
1052 return thd->variables.option_bits & test_options;
1053 }
1054
1055 extern "C"
thd_sql_command(const THD * thd)1056 int thd_sql_command(const THD *thd)
1057 {
1058 return (int) thd->lex->sql_command;
1059 }
1060
1061 extern "C"
thd_tx_isolation(const THD * thd)1062 int thd_tx_isolation(const THD *thd)
1063 {
1064 return (int) thd->tx_isolation;
1065 }
1066
1067 extern "C"
thd_tx_is_read_only(const THD * thd)1068 int thd_tx_is_read_only(const THD *thd)
1069 {
1070 return (int) thd->tx_read_only;
1071 }
1072
1073 extern "C"
thd_tx_priority(const THD * thd)1074 int thd_tx_priority(const THD* thd)
1075 {
1076 return (thd->thd_tx_priority != 0
1077 ? thd->thd_tx_priority
1078 : thd->tx_priority);
1079 }
1080
1081 extern "C"
thd_tx_arbitrate(THD * requestor,THD * holder)1082 THD* thd_tx_arbitrate(THD *requestor, THD* holder)
1083 {
1084 /* Should be different sessions. */
1085 assert(holder != requestor);
1086
1087 return(thd_tx_priority(requestor) == thd_tx_priority(holder)
1088 ? requestor
1089 : ((thd_tx_priority(requestor)
1090 > thd_tx_priority(holder)) ? holder : requestor));
1091 }
1092
thd_tx_is_dd_trx(const THD * thd)1093 int thd_tx_is_dd_trx(const THD *thd)
1094 {
1095 return (int) thd->is_attachable_ro_transaction_active();
1096 }
1097
1098 extern "C"
thd_inc_row_count(THD * thd)1099 void thd_inc_row_count(THD *thd)
1100 {
1101 thd->get_stmt_da()->inc_current_row_for_condition();
1102 }
1103
1104
1105 /**
1106 Dumps a text description of a thread, its security context
1107 (user, host) and the current query.
1108
1109 @param thd thread context
1110 @param buffer pointer to preferred result buffer
1111 @param length length of buffer
1112 @param max_query_len how many chars of query to copy (0 for all)
1113
1114 @return Pointer to string
1115 */
1116
1117 extern "C"
thd_security_context(THD * thd,char * buffer,size_t length,size_t max_query_len)1118 char *thd_security_context(THD *thd, char *buffer, size_t length,
1119 size_t max_query_len)
1120 {
1121 String str(buffer, length, &my_charset_latin1);
1122 Security_context *sctx= &thd->m_main_security_ctx;
1123 char header[256];
1124 size_t len;
1125 /*
1126 The pointers thd->query and thd->proc_info might change since they are
1127 being modified concurrently. This is acceptable for proc_info since its
1128 values doesn't have to very accurate and the memory it points to is static,
1129 but we need to attempt a snapshot on the pointer values to avoid using NULL
1130 values. The pointer to thd->query however, doesn't point to static memory
1131 and has to be protected by LOCK_thd_query or risk pointing to
1132 uninitialized memory.
1133 */
1134 const char *proc_info= thd->proc_info;
1135
1136 len= my_snprintf(header, sizeof(header),
1137 "MySQL thread id %u, OS thread handle %lu, query id %lu",
1138 thd->thread_id(), (ulong)thd->real_id, (ulong)thd->query_id);
1139 str.length(0);
1140 str.append(header, len);
1141
1142 if (sctx->host().length)
1143 {
1144 str.append(' ');
1145 str.append(sctx->host().str);
1146 }
1147
1148 if (sctx->ip().length)
1149 {
1150 str.append(' ');
1151 str.append(sctx->ip().str);
1152 }
1153
1154 if (sctx->user().str)
1155 {
1156 str.append(' ');
1157 str.append(sctx->user().str);
1158 }
1159
1160 if (proc_info)
1161 {
1162 str.append(' ');
1163 str.append(proc_info);
1164 }
1165
1166 mysql_mutex_lock(&thd->LOCK_thd_query);
1167
1168 if (thd->query().str)
1169 {
1170 if (max_query_len < 1)
1171 len= thd->query().length;
1172 else
1173 len= min(thd->query().length, max_query_len);
1174 str.append('\n');
1175 str.append(thd->query().str, len);
1176 }
1177
1178 mysql_mutex_unlock(&thd->LOCK_thd_query);
1179
1180 if (str.c_ptr_safe() == buffer)
1181 return buffer;
1182
1183 /*
1184 We have to copy the new string to the destination buffer because the string
1185 was reallocated to a larger buffer to be able to fit.
1186 */
1187 assert(buffer != NULL);
1188 length= min(str.length(), length-1);
1189 memcpy(buffer, str.c_ptr_quick(), length);
1190 /* Make sure that the new string is null terminated */
1191 buffer[length]= '\0';
1192 return buffer;
1193 }
1194
1195
1196 /**
1197 Returns the partition_info working copy.
1198 Used to see if a table should be created with partitioning.
1199
1200 @param thd thread context
1201
1202 @return Pointer to the working copy of partition_info or NULL.
1203 */
1204
1205 extern "C"
thd_get_work_part_info(THD * thd)1206 partition_info *thd_get_work_part_info(THD *thd)
1207 {
1208 return thd->work_part_info;
1209 }
1210
1211
1212 /**
1213 Implementation of Drop_table_error_handler::handle_condition().
1214 The reason in having this implementation is to silence technical low-level
1215 warnings during DROP TABLE operation. Currently we don't want to expose
1216 the following warnings during DROP TABLE:
1217 - Some of table files are missed or invalid (the table is going to be
1218 deleted anyway, so why bother that something was missed);
1219 - A trigger associated with the table does not have DEFINER (One of the
1220 MySQL specifics now is that triggers are loaded for the table being
1221 dropped. So, we may have a warning that trigger does not have DEFINER
1222 attribute during DROP TABLE operation).
1223
1224 @return true if the condition is handled.
1225 */
handle_condition(THD * thd,uint sql_errno,const char * sqlstate,Sql_condition::enum_severity_level * level,const char * msg)1226 bool Drop_table_error_handler::handle_condition(THD *thd,
1227 uint sql_errno,
1228 const char* sqlstate,
1229 Sql_condition::enum_severity_level *level,
1230 const char* msg)
1231 {
1232 return ((sql_errno == EE_DELETE && my_errno() == ENOENT) ||
1233 sql_errno == ER_TRG_NO_DEFINER);
1234 }
1235
set_open_tables_state(Open_tables_state * state)1236 void Open_tables_state::set_open_tables_state(Open_tables_state *state)
1237 {
1238 this->open_tables= state->open_tables;
1239
1240 this->temporary_tables= state->temporary_tables;
1241 this->derived_tables= state->derived_tables;
1242
1243 this->lock= state->lock;
1244 this->extra_lock= state->extra_lock;
1245
1246 this->locked_tables_mode= state->locked_tables_mode;
1247
1248 this->state_flags= state->state_flags;
1249
1250 this->m_reprepare_observers= state->m_reprepare_observers;
1251 }
1252
1253
reset_open_tables_state()1254 void Open_tables_state::reset_open_tables_state()
1255 {
1256 open_tables= NULL;
1257 temporary_tables= NULL;
1258 derived_tables= NULL;
1259 lock= NULL;
1260 extra_lock= NULL;
1261 locked_tables_mode= LTM_NONE;
1262 state_flags= 0U;
1263 reset_reprepare_observers();
1264 }
1265
1266
1267 #ifdef WITH_WSREP
THD(bool enable_plugins,bool is_applier)1268 THD::THD(bool enable_plugins, bool is_applier)
1269 #else
1270 THD::THD(bool enable_plugins)
1271 #endif
1272 :Query_arena(&main_mem_root, STMT_CONVENTIONAL_EXECUTION),
1273 mark_used_columns(MARK_COLUMNS_READ),
1274 want_privilege(0),
1275 lex(&main_lex),
1276 gtid_executed_warning_issued(false),
1277 m_query_string(NULL_CSTR),
1278 m_db(NULL_CSTR),
1279 rli_fake(0), rli_slave(NULL),
1280 #ifdef EMBEDDED_LIBRARY
1281 mysql(NULL),
1282 #endif
1283 initial_status_var(NULL),
1284 status_var_aggregated(false),
1285 query_plan(this),
1286 m_current_stage_key(0),
1287 current_mutex(NULL),
1288 current_cond(NULL),
1289 in_sub_stmt(0),
1290 fill_status_recursion_level(0),
1291 fill_variables_recursion_level(0),
1292 binlog_row_event_extra_data(NULL),
1293 skip_readonly_check(false),
1294 binlog_unsafe_warning_flags(0),
1295 binlog_table_maps(0),
1296 binlog_accessed_db_names(NULL),
1297 m_trans_log_file(NULL),
1298 m_trans_fixed_log_file(NULL),
1299 m_trans_end_pos(0),
1300 m_transaction(new Transaction_ctx()),
1301 m_attachable_trx(NULL),
1302 table_map_for_update(0),
1303 m_examined_row_count(0),
1304 m_stage_progress_psi(NULL),
1305 m_digest(NULL),
1306 m_statement_psi(NULL),
1307 m_transaction_psi(NULL),
1308 m_idle_psi(NULL),
1309 m_server_idle(false),
1310 user_var_events(key_memory_user_var_entry),
1311 next_to_commit(NULL),
1312 binlog_need_explicit_defaults_ts(false),
1313 is_fatal_error(0),
1314 transaction_rollback_request(0),
1315 is_fatal_sub_stmt_error(false),
1316 rand_used(0),
1317 time_zone_used(0),
1318 in_lock_tables(0),
1319 bootstrap(0),
1320 derived_tables_processing(FALSE),
1321 sp_runtime_ctx(NULL),
1322 #ifdef WITH_WSREP
1323 wsrep_applier(is_applier),
1324 wsrep_applier_closing(FALSE),
1325 wsrep_client_thread(0),
1326 wsrep_po_handle(WSREP_PO_INITIALIZER),
1327 wsrep_po_cnt(0),
1328 wsrep_po_in_trans(FALSE),
1329 wsrep_apply_format(0),
1330 wsrep_apply_toi(false),
1331 wsrep_gtid_event_buf(NULL),
1332 wsrep_gtid_event_buf_len(0),
1333 #endif
1334 m_parser_state(NULL),
1335 work_part_info(NULL),
1336 #ifndef EMBEDDED_LIBRARY
1337 // No need to instrument, highly unlikely to have that many plugins.
1338 audit_class_plugins(PSI_NOT_INSTRUMENTED),
1339 audit_class_mask(PSI_NOT_INSTRUMENTED),
1340 #endif
1341 #if defined(ENABLED_DEBUG_SYNC)
1342 debug_sync_control(0),
1343 #endif /* defined(ENABLED_DEBUG_SYNC) */
1344 m_enable_plugins(enable_plugins),
1345 #ifdef HAVE_GTID_NEXT_LIST
1346 owned_gtid_set(global_sid_map),
1347 #endif
1348 skip_gtid_rollback(false),
1349 is_commit_in_middle_of_statement(false),
1350 has_gtid_consistency_violation(false),
1351 main_da(false),
1352 m_parser_da(false),
1353 m_query_rewrite_plugin_da(false),
1354 m_query_rewrite_plugin_da_ptr(&m_query_rewrite_plugin_da),
1355 m_stmt_da(&main_da),
1356 duplicate_slave_id(false),
1357 is_a_srv_session_thd(false)
1358 {
1359 main_lex.reset();
1360 set_psi(NULL);
1361 mdl_context.init(this);
1362 init_sql_alloc(key_memory_thd_main_mem_root,
1363 &main_mem_root,
1364 global_system_variables.query_alloc_block_size,
1365 global_system_variables.query_prealloc_size);
1366 stmt_arena= this;
1367 thread_stack= 0;
1368 m_catalog.str= "std";
1369 m_catalog.length= 3;
1370 m_security_ctx= &m_main_security_ctx;
1371 no_errors= 0;
1372 password= 0;
1373 query_start_usec_used= 0;
1374 count_cuted_fields= CHECK_FIELD_IGNORE;
1375 killed= NOT_KILLED;
1376 col_access=0;
1377 is_slave_error= thread_specific_used= FALSE;
1378 my_hash_clear(&handler_tables_hash);
1379 my_hash_clear(&ull_hash);
1380 tmp_table=0;
1381 cuted_fields= 0L;
1382 m_sent_row_count= 0L;
1383 current_found_rows= 0;
1384 previous_found_rows= 0;
1385 is_operating_gtid_table_implicitly= false;
1386 is_operating_substatement_implicitly= false;
1387 m_row_count_func= -1;
1388 statement_id_counter= 0UL;
1389 // Must be reset to handle error with THD's created for init of mysqld
1390 lex->thd= NULL;
1391 lex->set_current_select(0);
1392 utime_after_lock= 0L;
1393 current_linfo = 0;
1394 slave_thread = 0;
1395 memset(&variables, 0, sizeof(variables));
1396 m_thread_id= Global_THD_manager::reserved_thread_id;
1397 file_id = 0;
1398 query_id= 0;
1399 query_name_consts= 0;
1400 db_charset= global_system_variables.collation_database;
1401 memset(ha_data, 0, sizeof(ha_data));
1402 is_killable= false;
1403 binlog_evt_union.do_union= FALSE;
1404 enable_slow_log= 0;
1405 commit_error= CE_NONE;
1406 durability_property= HA_REGULAR_DURABILITY;
1407 #ifndef NDEBUG
1408 dbug_sentry=THD_SENTRY_MAGIC;
1409 #endif
1410 #ifndef EMBEDDED_LIBRARY
1411 mysql_audit_init_thd(this);
1412 net.vio=0;
1413 #endif
1414 system_thread= NON_SYSTEM_THREAD;
1415 cleanup_done= 0;
1416 m_release_resources_done= false;
1417 peer_port= 0; // For SHOW PROCESSLIST
1418 get_transaction()->m_flags.enabled= true;
1419 active_vio = 0;
1420 m_SSL = NULL;
1421 my_atomic_store32(&m_safe_to_display, 0);
1422 mysql_mutex_init(key_LOCK_thd_data, &LOCK_thd_data, MY_MUTEX_INIT_FAST);
1423 mysql_mutex_init(key_LOCK_thd_query, &LOCK_thd_query, MY_MUTEX_INIT_FAST);
1424 mysql_mutex_init(key_LOCK_thd_sysvar, &LOCK_thd_sysvar, MY_MUTEX_INIT_FAST);
1425 mysql_mutex_init(key_LOCK_query_plan, &LOCK_query_plan, MY_MUTEX_INIT_FAST);
1426 mysql_mutex_init(key_LOCK_current_cond, &LOCK_current_cond,
1427 MY_MUTEX_INIT_FAST);
1428 mysql_cond_init(key_COND_thr_lock, &COND_thr_lock);
1429
1430 /* Variables with default values */
1431 proc_info="login";
1432 where= THD::DEFAULT_WHERE;
1433 server_id = ::server_id;
1434 unmasked_server_id = server_id;
1435 slave_net = 0;
1436 set_command(COM_CONNECT);
1437 *scramble= '\0';
1438
1439 #ifdef WITH_WSREP
1440 mysql_mutex_init(key_LOCK_wsrep_thd, &LOCK_wsrep_thd, MY_MUTEX_INIT_FAST);
1441 mysql_cond_init(key_COND_wsrep_thd, &COND_wsrep_thd);
1442 wsrep_ws_handle.trx_id = WSREP_UNDEFINED_TRX_ID;
1443 wsrep_ws_handle.opaque = NULL;
1444 wsrep_retry_counter = 0;
1445 wsrep_PA_safe = true;
1446 wsrep_retry_query = NULL;
1447 wsrep_retry_query_len = 0;
1448 wsrep_retry_command = COM_CONNECT;
1449 wsrep_consistency_check = NO_CONSISTENCY_CHECK;
1450 wsrep_status_vars = 0;
1451 wsrep_mysql_replicated = 0;
1452 wsrep_TOI_pre_query = NULL;
1453 wsrep_TOI_pre_query_len = 0;
1454 wsrep_sync_wait_gtid = WSREP_GTID_UNDEFINED;
1455 wsrep_affected_rows = 0;
1456 wsrep_replicate_GTID = false;
1457 wsrep_skip_wsrep_GTID = false;
1458 m_wsrep_next_trx_id = WSREP_UNDEFINED_TRX_ID;
1459 #endif
1460 /* Call to init() below requires fully initialized Open_tables_state. */
1461 reset_open_tables_state();
1462
1463 init();
1464 #if defined(ENABLED_PROFILING)
1465 profiling.set_thd(this);
1466 #endif
1467 m_user_connect= NULL;
1468 my_hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0,
1469 (my_hash_get_key) get_var_key,
1470 (my_hash_free_key) free_user_var, 0,
1471 key_memory_user_var_entry);
1472
1473 sp_proc_cache= NULL;
1474 sp_func_cache= NULL;
1475
1476 /* Protocol */
1477 m_protocol= &protocol_text; // Default protocol
1478 protocol_text.init(this);
1479 protocol_binary.init(this);
1480 protocol_text.set_client_capabilities(0); // minimalistic client
1481
1482 tablespace_op= false;
1483 substitute_null_with_insert_id = FALSE;
1484
1485 /*
1486 Make sure thr_lock_info_init() is called for threads which do not get
1487 assigned a proper thread_id value but keep using reserved_thread_id.
1488 */
1489 thr_lock_info_init(&lock_info, m_thread_id, &COND_thr_lock);
1490 #ifdef WITH_WSREP
1491 lock_info.mysql_thd= (void *)this;
1492 lock_info.in_lock_tables= false;
1493 #ifdef WSREP_PROC_INFO
1494 wsrep_info[sizeof(wsrep_info) - 1] = '\0'; /* make sure it is 0-terminated */
1495 #endif /* WSREP_PROC_INFO */
1496 #endif /* WITH_WSREP */
1497
1498 m_internal_handler= NULL;
1499 m_binlog_invoker= FALSE;
1500 memset(&m_invoker_user, 0, sizeof(m_invoker_user));
1501 memset(&m_invoker_host, 0, sizeof(m_invoker_host));
1502
1503 binlog_next_event_pos.file_name= NULL;
1504 binlog_next_event_pos.pos= 0;
1505
1506 timer= NULL;
1507 timer_cache= NULL;
1508
1509 m_token_array= NULL;
1510 if (max_digest_length > 0)
1511 {
1512 m_token_array= (unsigned char*) my_malloc(PSI_INSTRUMENT_ME,
1513 max_digest_length,
1514 MYF(MY_WME));
1515 }
1516 }
1517
1518
set_transaction(Transaction_ctx * transaction_ctx)1519 void THD::set_transaction(Transaction_ctx *transaction_ctx)
1520 {
1521 assert(is_attachable_ro_transaction_active());
1522
1523 delete m_transaction.release();
1524 m_transaction.reset(transaction_ctx);
1525 }
1526
1527
push_internal_handler(Internal_error_handler * handler)1528 void THD::push_internal_handler(Internal_error_handler *handler)
1529 {
1530 if (m_internal_handler)
1531 {
1532 handler->m_prev_internal_handler= m_internal_handler;
1533 m_internal_handler= handler;
1534 }
1535 else
1536 m_internal_handler= handler;
1537 }
1538
1539
handle_condition(uint sql_errno,const char * sqlstate,Sql_condition::enum_severity_level * level,const char * msg)1540 bool THD::handle_condition(uint sql_errno,
1541 const char* sqlstate,
1542 Sql_condition::enum_severity_level *level,
1543 const char* msg)
1544 {
1545 if (!m_internal_handler)
1546 return false;
1547
1548 for (Internal_error_handler *error_handler= m_internal_handler;
1549 error_handler;
1550 error_handler= error_handler->m_prev_internal_handler)
1551 {
1552 if (error_handler->handle_condition(this, sql_errno, sqlstate, level, msg))
1553 return true;
1554 }
1555 return false;
1556 }
1557
1558
pop_internal_handler()1559 Internal_error_handler *THD::pop_internal_handler()
1560 {
1561 assert(m_internal_handler != NULL);
1562 Internal_error_handler *popped_handler= m_internal_handler;
1563 m_internal_handler= m_internal_handler->m_prev_internal_handler;
1564 return popped_handler;
1565 }
1566
1567
raise_error(uint sql_errno)1568 void THD::raise_error(uint sql_errno)
1569 {
1570 const char* msg= ER(sql_errno);
1571 (void) raise_condition(sql_errno,
1572 NULL,
1573 Sql_condition::SL_ERROR,
1574 msg);
1575 }
1576
raise_error_printf(uint sql_errno,...)1577 void THD::raise_error_printf(uint sql_errno, ...)
1578 {
1579 va_list args;
1580 char ebuff[MYSQL_ERRMSG_SIZE];
1581 DBUG_ENTER("THD::raise_error_printf");
1582 DBUG_PRINT("my", ("nr: %d errno: %d", sql_errno, errno));
1583 const char* format= ER(sql_errno);
1584 va_start(args, sql_errno);
1585 my_vsnprintf(ebuff, sizeof(ebuff), format, args);
1586 va_end(args);
1587 (void) raise_condition(sql_errno,
1588 NULL,
1589 Sql_condition::SL_ERROR,
1590 ebuff);
1591 DBUG_VOID_RETURN;
1592 }
1593
raise_warning(uint sql_errno)1594 void THD::raise_warning(uint sql_errno)
1595 {
1596 const char* msg= ER(sql_errno);
1597 (void) raise_condition(sql_errno,
1598 NULL,
1599 Sql_condition::SL_WARNING,
1600 msg);
1601 }
1602
raise_warning_printf(uint sql_errno,...)1603 void THD::raise_warning_printf(uint sql_errno, ...)
1604 {
1605 va_list args;
1606 char ebuff[MYSQL_ERRMSG_SIZE];
1607 DBUG_ENTER("THD::raise_warning_printf");
1608 DBUG_PRINT("enter", ("warning: %u", sql_errno));
1609 const char* format= ER(sql_errno);
1610 va_start(args, sql_errno);
1611 my_vsnprintf(ebuff, sizeof(ebuff), format, args);
1612 va_end(args);
1613 (void) raise_condition(sql_errno,
1614 NULL,
1615 Sql_condition::SL_WARNING,
1616 ebuff);
1617 DBUG_VOID_RETURN;
1618 }
1619
raise_note(uint sql_errno)1620 void THD::raise_note(uint sql_errno)
1621 {
1622 DBUG_ENTER("THD::raise_note");
1623 DBUG_PRINT("enter", ("code: %d", sql_errno));
1624 if (!(variables.option_bits & OPTION_SQL_NOTES))
1625 DBUG_VOID_RETURN;
1626 const char* msg= ER(sql_errno);
1627 (void) raise_condition(sql_errno,
1628 NULL,
1629 Sql_condition::SL_NOTE,
1630 msg);
1631 DBUG_VOID_RETURN;
1632 }
1633
raise_note_printf(uint sql_errno,...)1634 void THD::raise_note_printf(uint sql_errno, ...)
1635 {
1636 va_list args;
1637 char ebuff[MYSQL_ERRMSG_SIZE];
1638 DBUG_ENTER("THD::raise_note_printf");
1639 DBUG_PRINT("enter",("code: %u", sql_errno));
1640 if (!(variables.option_bits & OPTION_SQL_NOTES))
1641 DBUG_VOID_RETURN;
1642 const char* format= ER(sql_errno);
1643 va_start(args, sql_errno);
1644 my_vsnprintf(ebuff, sizeof(ebuff), format, args);
1645 va_end(args);
1646 (void) raise_condition(sql_errno,
1647 NULL,
1648 Sql_condition::SL_NOTE,
1649 ebuff);
1650 DBUG_VOID_RETURN;
1651 }
1652
1653
query_start_timeval_trunc(uint decimals)1654 struct timeval THD::query_start_timeval_trunc(uint decimals)
1655 {
1656 struct timeval tv;
1657 tv.tv_sec= start_time.tv_sec;
1658 if (decimals)
1659 {
1660 tv.tv_usec= start_time.tv_usec;
1661 my_timeval_trunc(&tv, decimals);
1662 query_start_usec_used= 1;
1663 }
1664 else
1665 {
1666 tv.tv_usec= 0;
1667 }
1668 return tv;
1669 }
1670
1671
raise_condition(uint sql_errno,const char * sqlstate,Sql_condition::enum_severity_level level,const char * msg,bool use_condition_handler)1672 Sql_condition* THD::raise_condition(uint sql_errno,
1673 const char* sqlstate,
1674 Sql_condition::enum_severity_level level,
1675 const char* msg,
1676 bool use_condition_handler)
1677 {
1678 DBUG_ENTER("THD::raise_condition");
1679
1680 if (!(variables.option_bits & OPTION_SQL_NOTES) &&
1681 (level == Sql_condition::SL_NOTE))
1682 DBUG_RETURN(NULL);
1683
1684 assert(sql_errno != 0);
1685 if (sql_errno == 0) /* Safety in release build */
1686 sql_errno= ER_UNKNOWN_ERROR;
1687 if (msg == NULL)
1688 msg= ER(sql_errno);
1689 if (sqlstate == NULL)
1690 sqlstate= mysql_errno_to_sqlstate(sql_errno);
1691
1692 if (use_condition_handler &&
1693 handle_condition(sql_errno, sqlstate, &level, msg))
1694 DBUG_RETURN(NULL);
1695
1696 if (level == Sql_condition::SL_NOTE || level == Sql_condition::SL_WARNING)
1697 got_warning= true;
1698
1699 query_cache.abort(&query_cache_tls);
1700
1701 Diagnostics_area *da= get_stmt_da();
1702 if (level == Sql_condition::SL_ERROR)
1703 {
1704 is_slave_error= true; // needed to catch query errors during replication
1705
1706 if (!da->is_error())
1707 {
1708 set_row_count_func(-1);
1709 da->set_error_status(sql_errno, msg, sqlstate);
1710 }
1711 }
1712
1713 /*
1714 Avoid pushing a condition for fatal out of memory errors as this will
1715 require memory allocation and therefore might fail. Non fatal out of
1716 memory errors can occur if raised by SIGNAL/RESIGNAL statement.
1717 */
1718 Sql_condition *cond= NULL;
1719 if (!(is_fatal_error && (sql_errno == EE_OUTOFMEMORY ||
1720 sql_errno == ER_OUTOFMEMORY)))
1721 {
1722 cond= da->push_warning(this, sql_errno, sqlstate, level, msg);
1723 }
1724 DBUG_RETURN(cond);
1725 }
1726
1727 extern "C"
thd_alloc(MYSQL_THD thd,size_t size)1728 void *thd_alloc(MYSQL_THD thd, size_t size)
1729 {
1730 return thd->alloc(size);
1731 }
1732
1733 extern "C"
thd_calloc(MYSQL_THD thd,size_t size)1734 void *thd_calloc(MYSQL_THD thd, size_t size)
1735 {
1736 return thd->mem_calloc(size);
1737 }
1738
1739 extern "C"
thd_strdup(MYSQL_THD thd,const char * str)1740 char *thd_strdup(MYSQL_THD thd, const char *str)
1741 {
1742 return thd->mem_strdup(str);
1743 }
1744
1745 extern "C"
thd_strmake(MYSQL_THD thd,const char * str,size_t size)1746 char *thd_strmake(MYSQL_THD thd, const char *str, size_t size)
1747 {
1748 return thd->strmake(str, size);
1749 }
1750
1751 extern "C"
thd_make_lex_string(THD * thd,LEX_STRING * lex_str,const char * str,size_t size,int allocate_lex_string)1752 LEX_STRING *thd_make_lex_string(THD *thd, LEX_STRING *lex_str,
1753 const char *str, size_t size,
1754 int allocate_lex_string)
1755 {
1756 return thd->make_lex_string(lex_str, str, size,
1757 (bool) allocate_lex_string);
1758 }
1759
1760 extern "C"
thd_memdup(MYSQL_THD thd,const void * str,size_t size)1761 void *thd_memdup(MYSQL_THD thd, const void* str, size_t size)
1762 {
1763 return thd->memdup(str, size);
1764 }
1765
1766 extern "C"
thd_get_xid(const MYSQL_THD thd,MYSQL_XID * xid)1767 void thd_get_xid(const MYSQL_THD thd, MYSQL_XID *xid)
1768 {
1769 *xid = *(MYSQL_XID *) thd->get_transaction()->xid_state()->get_xid();
1770 }
1771
1772 #if defined(_WIN32)
_current_thd_noinline(void)1773 extern "C" THD *_current_thd_noinline(void)
1774 {
1775 return my_thread_get_THR_THD();
1776 }
1777 #endif
1778 /*
1779 Init common variables that has to be reset on start and on cleanup_connection
1780 */
1781
init(void)1782 void THD::init(void)
1783 {
1784 mysql_mutex_lock(&LOCK_global_system_variables);
1785 plugin_thdvar_init(this, m_enable_plugins);
1786 /*
1787 variables= global_system_variables above has reset
1788 variables.pseudo_thread_id to 0. We need to correct it here to
1789 avoid temporary tables replication failure.
1790 */
1791 variables.pseudo_thread_id= m_thread_id;
1792 mysql_mutex_unlock(&LOCK_global_system_variables);
1793
1794 /*
1795 NOTE: reset_connection command will reset the THD to its default state.
1796 All system variables whose scope is SESSION ONLY should be set to their
1797 default values here.
1798 */
1799 reset_first_successful_insert_id();
1800 user_time.tv_sec= user_time.tv_usec= 0;
1801 start_time.tv_sec= start_time.tv_usec= 0;
1802 set_time();
1803 auto_inc_intervals_forced.empty();
1804 {
1805 ulong tmp;
1806 tmp= sql_rnd_with_mutex();
1807 randominit(&rand, tmp + (ulong) &rand, tmp + (ulong) ::global_query_id);
1808 }
1809
1810 server_status= SERVER_STATUS_AUTOCOMMIT;
1811 if (variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES)
1812 server_status|= SERVER_STATUS_NO_BACKSLASH_ESCAPES;
1813
1814 get_transaction()->reset_unsafe_rollback_flags(Transaction_ctx::SESSION);
1815 get_transaction()->reset_unsafe_rollback_flags(Transaction_ctx::STMT);
1816 open_options=ha_open_options;
1817 update_lock_default= (variables.low_priority_updates ?
1818 TL_WRITE_LOW_PRIORITY :
1819 TL_WRITE);
1820 insert_lock_default= (variables.low_priority_updates ?
1821 TL_WRITE_LOW_PRIORITY :
1822 TL_WRITE_CONCURRENT_INSERT);
1823 tx_isolation= (enum_tx_isolation) variables.tx_isolation;
1824 tx_read_only= variables.tx_read_only;
1825 tx_priority= 0;
1826 thd_tx_priority= 0;
1827 update_charset();
1828 reset_current_stmt_binlog_format_row();
1829 reset_binlog_local_stmt_filter();
1830 memset(&status_var, 0, sizeof(status_var));
1831 #ifdef WITH_WSREP
1832 wsrep_exec_mode= wsrep_applier ? REPL_RECV : LOCAL_STATE;
1833 wsrep_conflict_state= NO_CONFLICT;
1834 wsrep_thd_set_query_state(this, QUERY_IDLE);
1835 wsrep_last_query_id= 0;
1836 wsrep_trx_meta.gtid= WSREP_GTID_UNDEFINED;
1837 wsrep_trx_meta.depends_on= WSREP_SEQNO_UNDEFINED;
1838 wsrep_converted_lock_session= false;
1839 wsrep_retry_counter= 0;
1840 wsrep_rli= NULL;
1841 wsrep_PA_safe= true;
1842 wsrep_consistency_check = NO_CONSISTENCY_CHECK;
1843 wsrep_mysql_replicated = 0;
1844 wsrep_TOI_pre_query = NULL;
1845 wsrep_TOI_pre_query_len = 0;
1846 wsrep_sync_wait_gtid = WSREP_GTID_UNDEFINED;
1847 wsrep_affected_rows = 0;
1848 wsrep_replicate_GTID = false;
1849 wsrep_skip_wsrep_GTID = false;
1850 wsrep_gtid_event_buf = NULL;
1851 wsrep_gtid_event_buf_len = 0;
1852 m_wsrep_next_trx_id = WSREP_UNDEFINED_TRX_ID;
1853 #endif
1854 status_var_aggregated= false;
1855 binlog_row_event_extra_data= 0;
1856
1857 if (variables.sql_log_bin)
1858 variables.option_bits|= OPTION_BIN_LOG;
1859 else
1860 variables.option_bits&= ~OPTION_BIN_LOG;
1861
1862 #if defined(ENABLED_DEBUG_SYNC)
1863 /* Initialize the Debug Sync Facility. See debug_sync.cc. */
1864 debug_sync_init_thread(this);
1865 #endif /* defined(ENABLED_DEBUG_SYNC) */
1866
1867 /* Initialize session_tracker and create all tracker objects */
1868 session_tracker.init(this->charset());
1869 session_tracker.enable(this);
1870
1871 owned_gtid.clear();
1872 owned_sid.clear();
1873 owned_gtid.dbug_print(NULL, "set owned_gtid (clear) in THD::init");
1874
1875 rpl_thd_ctx.dependency_tracker_ctx().set_last_session_sequence_number(0);
1876 }
1877
1878
1879 /*
1880 Init THD for query processing.
1881 This has to be called once before we call mysql_parse.
1882 See also comments in sql_class.h.
1883 */
1884
init_for_queries(Relay_log_info * rli)1885 void THD::init_for_queries(Relay_log_info *rli)
1886 {
1887 set_time();
1888 ha_enable_transaction(this,TRUE);
1889
1890 reset_root_defaults(mem_root, variables.query_alloc_block_size,
1891 variables.query_prealloc_size);
1892 get_transaction()->init_mem_root_defaults(variables.trans_alloc_block_size,
1893 variables.trans_prealloc_size);
1894 get_transaction()->xid_state()->reset();
1895 #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
1896 if (rli)
1897 {
1898 if ((rli->deferred_events_collecting= rpl_filter->is_on()))
1899 {
1900 rli->deferred_events= new Deferred_log_events(rli);
1901 }
1902 rli_slave= rli;
1903
1904 assert(rli_slave->info_thd == this && slave_thread);
1905 }
1906 #endif
1907 }
1908
1909
set_new_thread_id()1910 void THD::set_new_thread_id()
1911 {
1912 m_thread_id= Global_THD_manager::get_instance()->get_new_thread_id();
1913 variables.pseudo_thread_id= m_thread_id;
1914 thr_lock_info_init(&lock_info, m_thread_id, &COND_thr_lock);
1915 }
1916
1917
1918 /*
1919 Do what's needed when one invokes change user
1920
1921 SYNOPSIS
1922 cleanup_connection()
1923
1924 IMPLEMENTATION
1925 Reset all resources that are connection specific
1926 */
1927
1928
cleanup_connection(void)1929 void THD::cleanup_connection(void)
1930 {
1931 mysql_mutex_lock(&LOCK_status);
1932 add_to_status(&global_status_var, &status_var, true);
1933 mysql_mutex_unlock(&LOCK_status);
1934
1935 cleanup();
1936 #if defined(ENABLED_DEBUG_SYNC)
1937 /* End the Debug Sync Facility. See debug_sync.cc. */
1938 debug_sync_end_thread(this);
1939 #endif /* defined(ENABLED_DEBUG_SYNC) */
1940 killed= NOT_KILLED;
1941 cleanup_done= 0;
1942 init();
1943 stmt_map.reset();
1944 my_hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0,
1945 (my_hash_get_key) get_var_key,
1946 (my_hash_free_key) free_user_var, 0,
1947 key_memory_user_var_entry);
1948 sp_cache_clear(&sp_proc_cache);
1949 sp_cache_clear(&sp_func_cache);
1950
1951 clear_error();
1952 // clear the warnings
1953 get_stmt_da()->reset_condition_info(this);
1954 // clear profiling information
1955 #if defined(ENABLED_PROFILING)
1956 profiling.cleanup();
1957 #endif
1958
1959 #ifndef NDEBUG
1960 /* DEBUG code only (begin) */
1961 bool check_cleanup= FALSE;
1962 DBUG_EXECUTE_IF("debug_test_cleanup_connection", check_cleanup= TRUE;);
1963 if(check_cleanup)
1964 {
1965 /* isolation level should be default */
1966 assert(variables.tx_isolation == ISO_REPEATABLE_READ);
1967 /* check autocommit is ON by default */
1968 assert(server_status == SERVER_STATUS_AUTOCOMMIT);
1969 /* check prepared stmts are cleaned up */
1970 assert(prepared_stmt_count == 0);
1971 /* check diagnostic area is cleaned up */
1972 assert(get_stmt_da()->status() == Diagnostics_area::DA_EMPTY);
1973 /* check if temp tables are deleted */
1974 assert(temporary_tables == NULL);
1975 /* check if tables are unlocked */
1976 assert(locked_tables_list.locked_tables() == NULL);
1977 }
1978 /* DEBUG code only (end) */
1979 #endif
1980
1981 }
1982
1983
1984 /*
1985 Do what's needed when one invokes change user.
1986 Also used during THD::release_resources, i.e. prior to THD destruction.
1987 */
cleanup(void)1988 void THD::cleanup(void)
1989 {
1990 Transaction_ctx *trn_ctx= get_transaction();
1991 XID_STATE *xs= trn_ctx->xid_state();
1992
1993 DBUG_ENTER("THD::cleanup");
1994 assert(cleanup_done == 0);
1995 DEBUG_SYNC(this, "thd_cleanup_start");
1996
1997 killed= KILL_CONNECTION;
1998 if (trn_ctx->xid_state()->has_state(XID_STATE::XA_PREPARED))
1999 {
2000 transaction_cache_detach(trn_ctx);
2001 }
2002 else
2003 {
2004 xs->set_state(XID_STATE::XA_NOTR);
2005 trans_rollback(this);
2006 transaction_cache_delete(trn_ctx);
2007 }
2008
2009 locked_tables_list.unlock_locked_tables(this);
2010 mysql_ha_cleanup(this);
2011
2012 assert(open_tables == NULL);
2013 /*
2014 If the thread was in the middle of an ongoing transaction (rolled
2015 back a few lines above) or under LOCK TABLES (unlocked the tables
2016 and left the mode a few lines above), there will be outstanding
2017 metadata locks. Release them.
2018 */
2019 mdl_context.release_transactional_locks();
2020
2021 /* Release the global read lock, if acquired. */
2022 if (global_read_lock.is_acquired())
2023 global_read_lock.unlock_global_read_lock(this);
2024
2025 mysql_ull_cleanup(this);
2026 /*
2027 All locking service locks must be released on disconnect.
2028 */
2029 release_all_locking_service_locks(this);
2030
2031 /* All metadata locks must have been released by now. */
2032 assert(!mdl_context.has_locks());
2033
2034 /* Protects user_vars. */
2035 mysql_mutex_lock(&LOCK_thd_data);
2036 my_hash_free(&user_vars);
2037 mysql_mutex_unlock(&LOCK_thd_data);
2038
2039 /*
2040 When we call drop table for temporary tables, the
2041 user_var_events container is not cleared this might
2042 cause error if the container was filled before the
2043 drop table command is called.
2044 So call this before calling close_temporary_tables.
2045 */
2046 user_var_events.clear();
2047 close_temporary_tables(this);
2048 sp_cache_clear(&sp_proc_cache);
2049 sp_cache_clear(&sp_func_cache);
2050
2051 /*
2052 Actions above might generate events for the binary log, so we
2053 commit the current transaction coordinator after executing cleanup
2054 actions.
2055 */
2056 if (tc_log && !trn_ctx->xid_state()->has_state(XID_STATE::XA_PREPARED))
2057 tc_log->commit(this, true);
2058
2059 /*
2060 Destroy trackers only after finishing manipulations with transaction
2061 state to avoid issues with Transaction_state_tracker.
2062 */
2063 session_tracker.deinit();
2064
2065 cleanup_done=1;
2066 DBUG_VOID_RETURN;
2067 }
2068
2069
2070 /**
2071 Release most resources, prior to THD destruction.
2072 */
release_resources()2073 void THD::release_resources()
2074 {
2075 assert(m_release_resources_done == false);
2076
2077 Global_THD_manager::get_instance()->release_thread_id(m_thread_id);
2078
2079 /* Ensure that no one is using THD */
2080 mysql_mutex_lock(&LOCK_thd_data);
2081 mysql_mutex_lock(&LOCK_query_plan);
2082
2083 /* Close connection */
2084 #ifndef EMBEDDED_LIBRARY
2085 if (is_classic_protocol() && get_protocol_classic()->get_vio())
2086 {
2087 vio_delete(get_protocol_classic()->get_vio());
2088 get_protocol_classic()->end_net();
2089 }
2090 #endif
2091
2092 /* modification plan for UPDATE/DELETE should be freed. */
2093 assert(query_plan.get_modification_plan() == NULL);
2094 mysql_mutex_unlock(&LOCK_query_plan);
2095 mysql_mutex_unlock(&LOCK_thd_data);
2096 mysql_mutex_lock(&LOCK_thd_query);
2097 mysql_mutex_unlock(&LOCK_thd_query);
2098
2099 stmt_map.reset(); /* close all prepared statements */
2100 if (!cleanup_done)
2101 cleanup();
2102
2103 mdl_context.destroy();
2104 ha_close_connection(this);
2105
2106 /*
2107 Debug sync system must be closed after ha_close_connection, because
2108 DEBUG_SYNC is used in InnoDB connection handlerton close.
2109 */
2110 #if defined(ENABLED_DEBUG_SYNC)
2111 /* End the Debug Sync Facility. See debug_sync.cc. */
2112 debug_sync_end_thread(this);
2113 #endif /* defined(ENABLED_DEBUG_SYNC) */
2114
2115 plugin_thdvar_cleanup(this, m_enable_plugins);
2116
2117 assert(timer == NULL);
2118
2119 if (timer_cache)
2120 thd_timer_destroy(timer_cache);
2121
2122 #ifndef EMBEDDED_LIBRARY
2123 if (rli_fake)
2124 {
2125 rli_fake->end_info();
2126 delete rli_fake;
2127 rli_fake= NULL;
2128 }
2129 mysql_audit_free_thd(this);
2130 #endif
2131
2132 if (current_thd == this)
2133 restore_globals();
2134
2135 mysql_mutex_lock(&LOCK_status);
2136 add_to_status(&global_status_var, &status_var, false);
2137 /*
2138 Status queries after this point should not aggregate THD::status_var
2139 since the values has been added to global_status_var.
2140 The status values are not reset so that they can still be read
2141 by performance schema.
2142 */
2143 status_var_aggregated= true;
2144 mysql_mutex_unlock(&LOCK_status);
2145
2146 m_release_resources_done= true;
2147 #ifdef WITH_WSREP
2148 mysql_mutex_lock(&LOCK_wsrep_thd);
2149 mysql_mutex_unlock(&LOCK_wsrep_thd);
2150 mysql_mutex_destroy(&LOCK_wsrep_thd);
2151 mysql_cond_destroy(&COND_wsrep_thd);
2152 if (wsrep_rli)
2153 {
2154 delete wsrep_rli->current_mts_submode;
2155 wsrep_rli->current_mts_submode = 0;
2156 delete wsrep_rli;
2157 if (rli_slave == wsrep_rli) {
2158 rli_slave = NULL;
2159 }
2160 wsrep_rli = NULL;
2161 }
2162 wsrep_free_status(this);
2163 #endif
2164 }
2165
2166
~THD()2167 THD::~THD()
2168 {
2169 THD_CHECK_SENTRY(this);
2170 DBUG_ENTER("~THD()");
2171 DBUG_PRINT("info", ("THD dtor, this %p", this));
2172
2173 if (!m_release_resources_done)
2174 release_resources();
2175
2176 clear_next_event_pos();
2177
2178 /* Ensure that no one is using THD */
2179 mysql_mutex_lock(&LOCK_thd_data);
2180 mysql_mutex_unlock(&LOCK_thd_data);
2181 mysql_mutex_lock(&LOCK_thd_query);
2182 mysql_mutex_unlock(&LOCK_thd_query);
2183
2184 assert(!m_attachable_trx);
2185
2186 my_free(const_cast<char*>(m_db.str));
2187 m_db= NULL_CSTR;
2188 get_transaction()->free_memory(MYF(0));
2189 mysql_mutex_destroy(&LOCK_query_plan);
2190 mysql_mutex_destroy(&LOCK_thd_data);
2191 mysql_mutex_destroy(&LOCK_thd_query);
2192 mysql_mutex_destroy(&LOCK_thd_sysvar);
2193 mysql_mutex_destroy(&LOCK_current_cond);
2194 mysql_cond_destroy(&COND_thr_lock);
2195 #ifndef NDEBUG
2196 dbug_sentry= THD_SENTRY_GONE;
2197 #endif
2198
2199 #ifndef EMBEDDED_LIBRARY
2200 if (variables.gtid_next_list.gtid_set != NULL)
2201 {
2202 #ifdef HAVE_GTID_NEXT_LIST
2203 delete variables.gtid_next_list.gtid_set;
2204 variables.gtid_next_list.gtid_set= NULL;
2205 variables.gtid_next_list.is_non_null= false;
2206 #else
2207 assert(0);
2208 #endif
2209 }
2210 if (rli_slave)
2211 rli_slave->cleanup_after_session();
2212 /*
2213 As slaves can be added in one mysql command like COM_REGISTER_SLAVE
2214 but then need to be removed on error scenarios, we call this method
2215 here.
2216 */
2217 unregister_slave(this, true, true);
2218 #endif
2219
2220 free_root(&main_mem_root, MYF(0));
2221
2222 if (m_token_array != NULL)
2223 {
2224 my_free(m_token_array);
2225 }
2226 DBUG_VOID_RETURN;
2227 }
2228
2229
2230 /*
2231 Add all status variables to another status variable array
2232
2233 SYNOPSIS
2234 add_to_status()
2235 to_var add to this array
2236 from_var from this array
2237 reset_from_var if true, then memset from_var variable with 0
2238
2239 NOTES
2240 This function assumes that all variables are longlong/ulonglong.
2241 If this assumption will change, then we have to explictely add
2242 the other variables after the while loop
2243 */
2244
add_to_status(STATUS_VAR * to_var,STATUS_VAR * from_var,bool reset_from_var)2245 void add_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var, bool reset_from_var)
2246 {
2247 int c;
2248 ulonglong *end= (ulonglong*) ((uchar*) to_var +
2249 offsetof(STATUS_VAR, LAST_STATUS_VAR) +
2250 sizeof(ulonglong));
2251 ulonglong *to= (ulonglong*) to_var, *from= (ulonglong*) from_var;
2252
2253 while (to != end)
2254 *(to++)+= *(from++);
2255
2256 to_var->com_other+= from_var->com_other;
2257
2258 for (c= 0; c< SQLCOM_END; c++)
2259 to_var->com_stat[(uint) c] += from_var->com_stat[(uint) c];
2260
2261 if (reset_from_var)
2262 {
2263 memset (from_var, 0, sizeof(*from_var));
2264 }
2265 }
2266
2267 /*
2268 Add the difference between two status variable arrays to another one.
2269
2270 SYNOPSIS
2271 add_diff_to_status
2272 to_var add to this array
2273 from_var from this array
2274 dec_var minus this array
2275
2276 NOTE
2277 This function assumes that all variables are longlong/ulonglong.
2278 */
2279
add_diff_to_status(STATUS_VAR * to_var,STATUS_VAR * from_var,STATUS_VAR * dec_var)2280 void add_diff_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var,
2281 STATUS_VAR *dec_var)
2282 {
2283 int c;
2284 ulonglong *end= (ulonglong*) ((uchar*) to_var + offsetof(STATUS_VAR, LAST_STATUS_VAR) +
2285 sizeof(ulonglong));
2286 ulonglong *to= (ulonglong*) to_var,
2287 *from= (ulonglong*) from_var,
2288 *dec= (ulonglong*) dec_var;
2289
2290 while (to != end)
2291 *(to++)+= *(from++) - *(dec++);
2292
2293 to_var->com_other+= from_var->com_other - dec_var->com_other;
2294
2295 for (c= 0; c< SQLCOM_END; c++)
2296 to_var->com_stat[(uint) c] += from_var->com_stat[(uint) c] -dec_var->com_stat[(uint) c];
2297 }
2298
2299
2300 /**
2301 Awake a thread.
2302
2303 @param[in] state_to_set value for THD::killed
2304
2305 This is normally called from another thread's THD object.
2306
2307 @note Do always call this while holding LOCK_thd_data.
2308 */
2309
awake(THD::killed_state state_to_set)2310 void THD::awake(THD::killed_state state_to_set)
2311 {
2312 DBUG_ENTER("THD::awake");
2313 DBUG_PRINT("enter", ("this: %p current_thd: %p", this, current_thd));
2314 THD_CHECK_SENTRY(this);
2315 mysql_mutex_assert_owner(&LOCK_thd_data);
2316
2317 /*
2318 Set killed flag if the connection is being killed (state_to_set
2319 is KILL_CONNECTION) or the connection is processing a query
2320 (state_to_set is KILL_QUERY and m_server_idle flag is not set).
2321 If the connection is idle and state_to_set is KILL QUERY, the
2322 the killed flag is not set so that it doesn't affect the next
2323 command incorrectly.
2324 */
2325 if (this->m_server_idle && state_to_set == KILL_QUERY)
2326 { /* nothing */ }
2327 else
2328 {
2329 killed= state_to_set;
2330 }
2331
2332 if (state_to_set != THD::KILL_QUERY && state_to_set != THD::KILL_TIMEOUT)
2333 {
2334 if (this != current_thd)
2335 {
2336 /*
2337 Before sending a signal, let's close the socket of the thread
2338 that is being killed ("this", which is not the current thread).
2339 This is to make sure it does not block if the signal is lost.
2340 This needs to be done only on platforms where signals are not
2341 a reliable interruption mechanism.
2342
2343 Note that the downside of this mechanism is that we could close
2344 the connection while "this" target thread is in the middle of
2345 sending a result to the application, thus violating the client-
2346 server protocol.
2347
2348 On the other hand, without closing the socket we have a race
2349 condition. If "this" target thread passes the check of
2350 thd->killed, and then the current thread runs through
2351 THD::awake(), sets the 'killed' flag and completes the
2352 signaling, and then the target thread runs into read(), it will
2353 block on the socket. As a result of the discussions around
2354 Bug#37780, it has been decided that we accept the race
2355 condition. A second KILL awakes the target from read().
2356
2357 If we are killing ourselves, we know that we are not blocked.
2358 We also know that we will check thd->killed before we go for
2359 reading the next statement.
2360 */
2361
2362 shutdown_active_vio();
2363 }
2364
2365 /* Send an event to the scheduler that a thread should be killed. */
2366 if (!slave_thread)
2367 MYSQL_CALLBACK(Connection_handler_manager::event_functions,
2368 post_kill_notification, (this));
2369 }
2370
2371 /* Interrupt target waiting inside a storage engine. */
2372 if (state_to_set != THD::NOT_KILLED)
2373 ha_kill_connection(this);
2374
2375 if (state_to_set == THD::KILL_TIMEOUT)
2376 {
2377 assert(!status_var_aggregated);
2378 status_var.max_execution_time_exceeded++;
2379 }
2380
2381
2382 /* Broadcast a condition to kick the target if it is waiting on it. */
2383 if (is_killable)
2384 {
2385 mysql_mutex_lock(&LOCK_current_cond);
2386 /*
2387 This broadcast could be up in the air if the victim thread
2388 exits the cond in the time between read and broadcast, but that is
2389 ok since all we want to do is to make the victim thread get out
2390 of waiting on current_cond.
2391 If we see a non-zero current_cond: it cannot be an old value (because
2392 then exit_cond() should have run and it can't because we have mutex); so
2393 it is the true value but maybe current_mutex is not yet non-zero (we're
2394 in the middle of enter_cond() and there is a "memory order
2395 inversion"). So we test the mutex too to not lock 0.
2396
2397 Note that there is a small chance we fail to kill. If victim has locked
2398 current_mutex, but hasn't yet entered enter_cond() (which means that
2399 current_cond and current_mutex are 0), then the victim will not get
2400 a signal and it may wait "forever" on the cond (until
2401 we issue a second KILL or the status it's waiting for happens).
2402 It's true that we have set its thd->killed but it may not
2403 see it immediately and so may have time to reach the cond_wait().
2404
2405 However, where possible, we test for killed once again after
2406 enter_cond(). This should make the signaling as safe as possible.
2407 However, there is still a small chance of failure on platforms with
2408 instruction or memory write reordering.
2409 */
2410 if (current_cond && current_mutex)
2411 {
2412 DBUG_EXECUTE_IF("before_dump_thread_acquires_current_mutex",
2413 {
2414 const char act[]=
2415 "now signal dump_thread_signal wait_for go_dump_thread";
2416 assert(!debug_sync_set_action(current_thd,
2417 STRING_WITH_LEN(act)));
2418 };);
2419 mysql_mutex_lock(current_mutex);
2420 mysql_cond_broadcast(current_cond);
2421 mysql_mutex_unlock(current_mutex);
2422 }
2423 mysql_mutex_unlock(&LOCK_current_cond);
2424 }
2425 DBUG_VOID_RETURN;
2426 }
2427
2428
2429 /**
2430 Close the Vio associated this session.
2431
2432 @remark LOCK_thd_data is taken due to the fact that
2433 the Vio might be disassociated concurrently.
2434 */
2435
disconnect(bool server_shutdown)2436 void THD::disconnect(bool server_shutdown)
2437 {
2438 Vio *vio= NULL;
2439
2440 mysql_mutex_lock(&LOCK_thd_data);
2441
2442 killed= THD::KILL_CONNECTION;
2443
2444 /*
2445 Since a active vio might might have not been set yet, in
2446 any case save a reference to avoid closing a inexistent
2447 one or closing the vio twice if there is a active one.
2448 */
2449 vio= active_vio;
2450 shutdown_active_vio();
2451
2452 /* Disconnect even if a active vio is not associated. */
2453 if (is_classic_protocol() &&
2454 get_protocol_classic()->get_vio() != vio &&
2455 get_protocol_classic()->connection_alive())
2456 {
2457 m_protocol->shutdown(server_shutdown);
2458 }
2459
2460 mysql_mutex_unlock(&LOCK_thd_data);
2461 }
2462
2463
notify_shared_lock(MDL_context_owner * ctx_in_use,bool needs_thr_lock_abort)2464 void THD::notify_shared_lock(MDL_context_owner *ctx_in_use,
2465 bool needs_thr_lock_abort)
2466 {
2467 THD *in_use= ctx_in_use->get_thd();
2468
2469 if (needs_thr_lock_abort)
2470 {
2471 mysql_mutex_lock(&in_use->LOCK_thd_data);
2472 for (TABLE *thd_table= in_use->open_tables;
2473 thd_table ;
2474 thd_table= thd_table->next)
2475 {
2476 /*
2477 Check for TABLE::needs_reopen() is needed since in some places we call
2478 handler::close() for table instance (and set TABLE::db_stat to 0)
2479 and do not remove such instances from the THD::open_tables
2480 for some time, during which other thread can see those instances
2481 (e.g. see partitioning code).
2482 */
2483 if (!thd_table->needs_reopen())
2484 #ifdef WITH_WSREP
2485 {
2486 #endif /* WITH_WSREP */
2487 mysql_lock_abort_for_thread(this, thd_table);
2488 #ifdef WITH_WSREP
2489 if (WSREP_NNULL(this) && wsrep_thd_is_BF((void *)this, FALSE))
2490 {
2491 wsrep_abort_thd((void *)this, (void *)in_use, FALSE);
2492 }
2493 }
2494 #endif /* WITH_WSREP */
2495 }
2496 mysql_mutex_unlock(&in_use->LOCK_thd_data);
2497 }
2498 }
2499
2500
2501 /*
2502 Remember the location of thread info, the structure needed for
2503 sql_alloc() and the structure for the net buffer
2504 */
2505
store_globals()2506 bool THD::store_globals()
2507 {
2508 /*
2509 Assert that thread_stack is initialized: it's necessary to be able
2510 to track stack overrun.
2511 */
2512 assert(thread_stack);
2513
2514 if (my_thread_set_THR_THD(this) ||
2515 my_thread_set_THR_MALLOC(&mem_root))
2516 return true;
2517 /*
2518 is_killable is concurrently readable by a killer thread.
2519 It is protected by LOCK_thd_data, it is not needed to lock while the
2520 value is changing from false not true. If the kill thread reads
2521 true we need to ensure that the thread doesn't proceed to assign
2522 another thread to the same TLS reference.
2523 */
2524 is_killable= true;
2525 #ifndef NDEBUG
2526 /*
2527 Let mysqld define the thread id (not mysys)
2528 This allows us to move THD to different threads if needed.
2529 */
2530 set_my_thread_var_id(m_thread_id);
2531 #endif
2532 real_id= my_thread_self(); // For debugging
2533
2534 return false;
2535 }
2536
2537 /*
2538 Remove the thread specific info (THD and mem_root pointer) stored during
2539 store_global call for this thread.
2540 */
restore_globals()2541 void THD::restore_globals()
2542 {
2543 /*
2544 Assert that thread_stack is initialized: it's necessary to be able
2545 to track stack overrun.
2546 */
2547 assert(thread_stack);
2548
2549 /* Undocking the thread specific data. */
2550 my_thread_set_THR_THD(NULL);
2551 my_thread_set_THR_MALLOC(NULL);
2552 }
2553
2554
2555 /*
2556 Cleanup after query.
2557
2558 SYNOPSIS
2559 THD::cleanup_after_query()
2560
2561 DESCRIPTION
2562 This function is used to reset thread data to its default state.
2563
2564 NOTE
2565 This function is not suitable for setting thread data to some
2566 non-default values, as there is only one replication thread, so
2567 different master threads may overwrite data of each other on
2568 slave.
2569 */
2570
cleanup_after_query()2571 void THD::cleanup_after_query()
2572 {
2573
2574 /*
2575 Reset rand_used so that detection of calls to rand() will save random
2576 seeds if needed by the slave.
2577
2578 Do not reset rand_used if inside a stored function or trigger because
2579 only the call to these operations is logged. Thus only the calling
2580 statement needs to detect rand() calls made by its substatements. These
2581 substatements must not set rand_used to 0 because it would remove the
2582 detection of rand() by the calling statement.
2583 */
2584 if (!in_sub_stmt) /* stored functions and triggers are a special case */
2585 {
2586 /* Forget those values, for next binlogger: */
2587 stmt_depends_on_first_successful_insert_id_in_prev_stmt= 0;
2588 auto_inc_intervals_in_cur_stmt_for_binlog.empty();
2589 rand_used= 0;
2590 binlog_accessed_db_names= NULL;
2591
2592 #ifndef EMBEDDED_LIBRARY
2593 /*
2594 Clean possible unused INSERT_ID events by current statement.
2595 is_update_query() is needed to ignore SET statements:
2596 Statements that don't update anything directly and don't
2597 used stored functions. This is mostly necessary to ignore
2598 statements in binlog between SET INSERT_ID and DML statement
2599 which is intended to consume its event (there can be other
2600 SET statements between them).
2601 */
2602 if ((rli_slave || rli_fake) && is_update_query(lex->sql_command))
2603 auto_inc_intervals_forced.empty();
2604 #endif
2605 }
2606
2607 /*
2608 In case of stored procedures, stored functions, triggers and events
2609 m_trans_fixed_log_file will not be set to NULL. The memory will be reused.
2610 */
2611 if (!sp_runtime_ctx)
2612 m_trans_fixed_log_file= NULL;
2613
2614 /*
2615 Forget the binlog stmt filter for the next query.
2616 There are some code paths that:
2617 - do not call THD::decide_logging_format()
2618 - do call THD::binlog_query(),
2619 making this reset necessary.
2620 */
2621 reset_binlog_local_stmt_filter();
2622 if (first_successful_insert_id_in_cur_stmt > 0)
2623 {
2624 /* set what LAST_INSERT_ID() will return */
2625 first_successful_insert_id_in_prev_stmt=
2626 first_successful_insert_id_in_cur_stmt;
2627 first_successful_insert_id_in_cur_stmt= 0;
2628 substitute_null_with_insert_id= TRUE;
2629 }
2630 arg_of_last_insert_id_function= 0;
2631 /* Free Items that were created during this execution */
2632 free_items();
2633 /* Reset where. */
2634 where= THD::DEFAULT_WHERE;
2635 /* reset table map for multi-table update */
2636 table_map_for_update= 0;
2637 m_binlog_invoker= FALSE;
2638 /* reset replication info structure */
2639 if (lex)
2640 {
2641 lex->mi.repl_ignore_server_ids.clear();
2642 }
2643 #ifndef EMBEDDED_LIBRARY
2644 if (rli_slave)
2645 rli_slave->cleanup_after_query();
2646 #endif
2647
2648 #ifdef WITH_WSREP
2649 wsrep_sync_wait_gtid= WSREP_GTID_UNDEFINED;
2650 if (!in_active_multi_stmt_transaction())
2651 wsrep_affected_rows= 0;
2652 #endif /* WITH_WSREP */
2653 }
2654
2655 LEX_CSTRING *
make_lex_string_root(MEM_ROOT * mem_root,LEX_CSTRING * lex_str,const char * str,size_t length,bool allocate_lex_string)2656 make_lex_string_root(MEM_ROOT *mem_root,
2657 LEX_CSTRING *lex_str, const char* str, size_t length,
2658 bool allocate_lex_string)
2659 {
2660 if (allocate_lex_string)
2661 if (!(lex_str= (LEX_CSTRING *)alloc_root(mem_root, sizeof(LEX_CSTRING))))
2662 return 0;
2663 if (!(lex_str->str= strmake_root(mem_root, str, length)))
2664 return 0;
2665 lex_str->length= length;
2666 return lex_str;
2667 }
2668
2669
2670 LEX_STRING *
make_lex_string_root(MEM_ROOT * mem_root,LEX_STRING * lex_str,const char * str,size_t length,bool allocate_lex_string)2671 make_lex_string_root(MEM_ROOT *mem_root,
2672 LEX_STRING *lex_str, const char* str, size_t length,
2673 bool allocate_lex_string)
2674 {
2675 if (allocate_lex_string)
2676 if (!(lex_str= (LEX_STRING *)alloc_root(mem_root, sizeof(LEX_STRING))))
2677 return 0;
2678 if (!(lex_str->str= strmake_root(mem_root, str, length)))
2679 return 0;
2680 lex_str->length= length;
2681 return lex_str;
2682 }
2683
2684
2685
make_lex_string(LEX_CSTRING * lex_str,const char * str,size_t length,bool allocate_lex_string)2686 LEX_CSTRING *THD::make_lex_string(LEX_CSTRING *lex_str,
2687 const char* str, size_t length,
2688 bool allocate_lex_string)
2689 {
2690 return make_lex_string_root (mem_root, lex_str, str,
2691 length, allocate_lex_string);
2692 }
2693
2694
2695
2696 /**
2697 Create a LEX_STRING in this connection.
2698
2699 @param lex_str pointer to LEX_STRING object to be initialized
2700 @param str initializer to be copied into lex_str
2701 @param length length of str, in bytes
2702 @param allocate_lex_string if TRUE, allocate new LEX_STRING object,
2703 instead of using lex_str value
2704 @return NULL on failure, or pointer to the LEX_STRING object
2705 */
make_lex_string(LEX_STRING * lex_str,const char * str,size_t length,bool allocate_lex_string)2706 LEX_STRING *THD::make_lex_string(LEX_STRING *lex_str,
2707 const char* str, size_t length,
2708 bool allocate_lex_string)
2709 {
2710 return make_lex_string_root (mem_root, lex_str, str,
2711 length, allocate_lex_string);
2712 }
2713
2714
2715 /*
2716 Convert a string to another character set
2717
2718 @param to Store new allocated string here
2719 @param to_cs New character set for allocated string
2720 @param from String to convert
2721 @param from_length Length of string to convert
2722 @param from_cs Original character set
2723
2724 @note to will be 0-terminated to make it easy to pass to system funcs
2725
2726 @retval false ok
2727 @retval true End of memory.
2728 In this case to->str will point to 0 and to->length will be 0.
2729 */
2730
convert_string(LEX_STRING * to,const CHARSET_INFO * to_cs,const char * from,size_t from_length,const CHARSET_INFO * from_cs)2731 bool THD::convert_string(LEX_STRING *to, const CHARSET_INFO *to_cs,
2732 const char *from, size_t from_length,
2733 const CHARSET_INFO *from_cs)
2734 {
2735 DBUG_ENTER("convert_string");
2736 size_t new_length= to_cs->mbmaxlen * from_length;
2737 uint errors= 0;
2738 if (!(to->str= (char*) alloc(new_length+1)))
2739 {
2740 to->length= 0; // Safety fix
2741 DBUG_RETURN(1); // EOM
2742 }
2743 to->length= copy_and_convert(to->str, new_length, to_cs,
2744 from, from_length, from_cs, &errors);
2745 to->str[to->length]=0; // Safety
2746 if (errors != 0)
2747 {
2748 char printable_buff[32];
2749 convert_to_printable(printable_buff, sizeof(printable_buff),
2750 from, from_length, from_cs, 6);
2751 push_warning_printf(this, Sql_condition::SL_WARNING,
2752 ER_INVALID_CHARACTER_STRING,
2753 ER_THD(this, ER_INVALID_CHARACTER_STRING),
2754 from_cs->csname, printable_buff);
2755 }
2756
2757 DBUG_RETURN(0);
2758 }
2759
2760
2761 /*
2762 Convert string from source character set to target character set inplace.
2763
2764 SYNOPSIS
2765 THD::convert_string
2766
2767 DESCRIPTION
2768 Convert string using convert_buffer - buffer for character set
2769 conversion shared between all protocols.
2770
2771 RETURN
2772 0 ok
2773 !0 out of memory
2774 */
2775
convert_string(String * s,const CHARSET_INFO * from_cs,const CHARSET_INFO * to_cs)2776 bool THD::convert_string(String *s, const CHARSET_INFO *from_cs,
2777 const CHARSET_INFO *to_cs)
2778 {
2779 uint dummy_errors;
2780 if (convert_buffer.copy(s->ptr(), s->length(), from_cs, to_cs, &dummy_errors))
2781 return TRUE;
2782 /* If convert_buffer >> s copying is more efficient long term */
2783 if (convert_buffer.alloced_length() >= convert_buffer.length() * 2 ||
2784 !s->is_alloced())
2785 {
2786 return s->copy(convert_buffer);
2787 }
2788 s->swap(convert_buffer);
2789 return FALSE;
2790 }
2791
2792
2793 /*
2794 Update some cache variables when character set changes
2795 */
2796
update_charset()2797 void THD::update_charset()
2798 {
2799 size_t not_used;
2800 charset_is_system_charset=
2801 !String::needs_conversion(0,
2802 variables.character_set_client,
2803 system_charset_info,
2804 ¬_used);
2805 charset_is_collation_connection=
2806 !String::needs_conversion(0,
2807 variables.character_set_client,
2808 variables.collation_connection,
2809 ¬_used);
2810 charset_is_character_set_filesystem=
2811 !String::needs_conversion(0,
2812 variables.character_set_client,
2813 variables.character_set_filesystem,
2814 ¬_used);
2815 }
2816
2817
2818 /* add table to list of changed in transaction tables */
2819
add_changed_table(TABLE * table)2820 void THD::add_changed_table(TABLE *table)
2821 {
2822 DBUG_ENTER("THD::add_changed_table(table)");
2823
2824 assert(in_multi_stmt_transaction_mode() && table->file->has_transactions());
2825 add_changed_table(table->s->table_cache_key.str,
2826 (long) table->s->table_cache_key.length);
2827 DBUG_VOID_RETURN;
2828 }
2829
2830
add_changed_table(const char * key,long key_length)2831 void THD::add_changed_table(const char *key, long key_length)
2832 {
2833 DBUG_ENTER("THD::add_changed_table(key)");
2834 if (get_transaction()->add_changed_table(key, key_length))
2835 killed= KILL_CONNECTION;
2836 DBUG_VOID_RETURN;
2837 }
2838
2839
send_explain_fields(Query_result * result)2840 int THD::send_explain_fields(Query_result *result)
2841 {
2842 List<Item> field_list;
2843 Item *item;
2844 CHARSET_INFO *cs= system_charset_info;
2845 field_list.push_back(new Item_return_int("id",3, MYSQL_TYPE_LONGLONG));
2846 field_list.push_back(new Item_empty_string("select_type", 19, cs));
2847 field_list.push_back(item= new Item_empty_string("table", NAME_CHAR_LEN, cs));
2848 item->maybe_null= 1;
2849 /* Maximum length of string that make_used_partitions_str() can produce */
2850 item= new Item_empty_string("partitions", MAX_PARTITIONS * (1 + FN_LEN),
2851 cs);
2852 field_list.push_back(item);
2853 item->maybe_null= 1;
2854 field_list.push_back(item= new Item_empty_string("type", 10, cs));
2855 item->maybe_null= 1;
2856 field_list.push_back(item=new Item_empty_string("possible_keys",
2857 NAME_CHAR_LEN*MAX_KEY, cs));
2858 item->maybe_null=1;
2859 field_list.push_back(item=new Item_empty_string("key", NAME_CHAR_LEN, cs));
2860 item->maybe_null=1;
2861 field_list.push_back(item=new Item_empty_string("key_len",
2862 NAME_CHAR_LEN*MAX_KEY));
2863 item->maybe_null=1;
2864 field_list.push_back(item=new Item_empty_string("ref",
2865 NAME_CHAR_LEN*MAX_REF_PARTS,
2866 cs));
2867 item->maybe_null=1;
2868 field_list.push_back(item= new Item_return_int("rows", 10,
2869 MYSQL_TYPE_LONGLONG));
2870 item->maybe_null= 1;
2871 field_list.push_back(item= new Item_float(NAME_STRING("filtered"),
2872 0.1234, 2, 4));
2873 item->maybe_null=1;
2874 field_list.push_back(new Item_empty_string("Extra", 255, cs));
2875 item->maybe_null= 1;
2876 return (result->send_result_set_metadata(field_list, Protocol::SEND_NUM_ROWS |
2877 Protocol::SEND_EOF));
2878 }
2879
get_vio_type()2880 enum_vio_type THD::get_vio_type()
2881 {
2882 #ifndef EMBEDDED_LIBRARY
2883 DBUG_ENTER("THD::get_vio_type");
2884 DBUG_RETURN(get_protocol()->connection_type());
2885 #else
2886 return NO_VIO_TYPE;
2887 #endif
2888 }
2889
shutdown_active_vio()2890 void THD::shutdown_active_vio()
2891 {
2892 DBUG_ENTER("shutdown_active_vio");
2893 mysql_mutex_assert_owner(&LOCK_thd_data);
2894 #ifndef EMBEDDED_LIBRARY
2895 if (active_vio)
2896 {
2897 vio_shutdown(active_vio);
2898 active_vio = 0;
2899 m_SSL = NULL;
2900 }
2901 #endif
2902 DBUG_VOID_RETURN;
2903 }
2904
2905
2906 /*
2907 Register an item tree tree transformation, performed by the query
2908 optimizer.
2909 */
2910
nocheck_register_item_tree_change(Item ** place,Item * new_value)2911 void THD::nocheck_register_item_tree_change(Item **place,
2912 Item *new_value)
2913 {
2914 Item_change_record *change;
2915 /*
2916 Now we use one node per change, which adds some memory overhead,
2917 but still is rather fast as we use alloc_root for allocations.
2918 A list of item tree changes of an average query should be short.
2919 */
2920 void *change_mem= alloc_root(mem_root, sizeof(*change));
2921 if (change_mem == 0)
2922 {
2923 /*
2924 OOM, thd->fatal_error() is called by the error handler of the
2925 memroot. Just return.
2926 */
2927 return;
2928 }
2929 change= new (change_mem) Item_change_record(place, new_value);
2930 change_list.push_front(change);
2931 }
2932
2933
replace_rollback_place(Item ** new_place)2934 void THD::replace_rollback_place(Item **new_place)
2935 {
2936 I_List_iterator<Item_change_record> it(change_list);
2937 Item_change_record *change;
2938 while ((change= it++))
2939 {
2940 if (change->new_value == *new_place)
2941 {
2942 DBUG_PRINT("info", ("replace_rollback_place new_value %p place %p",
2943 *new_place, new_place));
2944 change->place= new_place;
2945 break;
2946 }
2947 }
2948 }
2949
2950
rollback_item_tree_changes()2951 void THD::rollback_item_tree_changes()
2952 {
2953 I_List_iterator<Item_change_record> it(change_list);
2954 Item_change_record *change;
2955 DBUG_ENTER("rollback_item_tree_changes");
2956
2957 while ((change= it++))
2958 {
2959 DBUG_PRINT("info",
2960 ("rollback_item_tree_changes "
2961 "place %p curr_value %p old_value %p",
2962 change->place, *change->place, change->old_value));
2963 *change->place= change->old_value;
2964 }
2965 /* We can forget about changes memory: it's allocated in runtime memroot */
2966 change_list.empty();
2967 DBUG_VOID_RETURN;
2968 }
2969
2970
2971 /*****************************************************************************
2972 ** Functions to provide a interface to select results
2973 *****************************************************************************/
2974
2975 static const String default_line_term("\n",default_charset_info);
2976 static const String default_escaped("\\",default_charset_info);
2977 static const String default_field_term("\t",default_charset_info);
2978 static const String default_xml_row_term("<row>", default_charset_info);
2979 static const String my_empty_string("",default_charset_info);
2980
2981
sql_exchange(const char * name,bool flag,enum enum_filetype filetype_arg)2982 sql_exchange::sql_exchange(const char *name, bool flag,
2983 enum enum_filetype filetype_arg)
2984 :file_name(name), dumpfile(flag), skip_lines(0)
2985 {
2986 field.opt_enclosed= 0;
2987 filetype= filetype_arg;
2988 field.field_term= &default_field_term;
2989 field.enclosed= line.line_start= &my_empty_string;
2990 line.line_term= filetype == FILETYPE_CSV ?
2991 &default_line_term : &default_xml_row_term;
2992 field.escaped= &default_escaped;
2993 cs= NULL;
2994 }
2995
escaped_given(void)2996 bool sql_exchange::escaped_given(void)
2997 {
2998 return field.escaped != &default_escaped;
2999 }
3000
3001
send_result_set_metadata(List<Item> & list,uint flags)3002 bool Query_result_send::send_result_set_metadata(List<Item> &list, uint flags)
3003 {
3004 bool res;
3005 #ifdef WITH_WSREP
3006 if (WSREP(thd) && thd->wsrep_retry_query)
3007 {
3008 WSREP_DEBUG("skipping select metadata");
3009 return FALSE;
3010 }
3011 #endif /* WITH_WSREP */
3012 if (!(res= thd->send_result_metadata(&list, flags)))
3013 is_result_set_started= 1;
3014 return res;
3015 }
3016
abort_result_set()3017 void Query_result_send::abort_result_set()
3018 {
3019 DBUG_ENTER("Query_result_send::abort_result_set");
3020
3021 if (is_result_set_started && thd->sp_runtime_ctx)
3022 {
3023 /*
3024 We're executing a stored procedure, have an open result
3025 set and an SQL exception condition. In this situation we
3026 must abort the current statement, silence the error and
3027 start executing the continue/exit handler if one is found.
3028 Before aborting the statement, let's end the open result set, as
3029 otherwise the client will hang due to the violation of the
3030 client/server protocol.
3031 */
3032 thd->sp_runtime_ctx->end_partial_result_set= TRUE;
3033 }
3034 DBUG_VOID_RETURN;
3035 }
3036
3037
3038 /* Send data to client. Returns 0 if ok */
3039
send_data(List<Item> & items)3040 bool Query_result_send::send_data(List<Item> &items)
3041 {
3042 Protocol *protocol= thd->get_protocol();
3043 DBUG_ENTER("Query_result_send::send_data");
3044
3045 if (unit->offset_limit_cnt)
3046 { // using limit offset,count
3047 unit->offset_limit_cnt--;
3048 DBUG_RETURN(FALSE);
3049 }
3050
3051 /*
3052 We may be passing the control from mysqld to the client: release the
3053 InnoDB adaptive hash S-latch to avoid thread deadlocks if it was reserved
3054 by thd
3055 */
3056 ha_release_temporary_latches(thd);
3057
3058 protocol->start_row();
3059 if (thd->send_result_set_row(&items))
3060 {
3061 protocol->abort_row();
3062 DBUG_RETURN(TRUE);
3063 }
3064
3065 thd->inc_sent_row_count(1);
3066 DBUG_RETURN(protocol->end_row());
3067 }
3068
send_eof()3069 bool Query_result_send::send_eof()
3070 {
3071 /*
3072 We may be passing the control from mysqld to the client: release the
3073 InnoDB adaptive hash S-latch to avoid thread deadlocks if it was reserved
3074 by thd
3075 */
3076 ha_release_temporary_latches(thd);
3077
3078 /*
3079 Don't send EOF if we're in error condition (which implies we've already
3080 sent or are sending an error)
3081 */
3082 if (thd->is_error())
3083 return TRUE;
3084 ::my_eof(thd);
3085 is_result_set_started= 0;
3086 return FALSE;
3087 }
3088
3089
3090 /************************************************************************
3091 Handling writing to file
3092 ************************************************************************/
3093
send_error(uint errcode,const char * err)3094 void Query_result_to_file::send_error(uint errcode,const char *err)
3095 {
3096 my_message(errcode, err, MYF(0));
3097 if (file > 0)
3098 {
3099 (void) end_io_cache(&cache);
3100 mysql_file_close(file, MYF(0));
3101 /* Delete file on error */
3102 mysql_file_delete(key_select_to_file, path, MYF(0));
3103 file= -1;
3104 }
3105 }
3106
3107
send_eof()3108 bool Query_result_to_file::send_eof()
3109 {
3110 int error= MY_TEST(end_io_cache(&cache));
3111 if (mysql_file_close(file, MYF(MY_WME)) || thd->is_error())
3112 error= true;
3113
3114 if (!error)
3115 {
3116 ::my_ok(thd,row_count);
3117 }
3118 file= -1;
3119 return error;
3120 }
3121
3122
cleanup()3123 void Query_result_to_file::cleanup()
3124 {
3125 /* In case of error send_eof() may be not called: close the file here. */
3126 if (file >= 0)
3127 {
3128 (void) end_io_cache(&cache);
3129 mysql_file_close(file, MYF(0));
3130 file= -1;
3131 }
3132 path[0]= '\0';
3133 row_count= 0;
3134 }
3135
3136
~Query_result_to_file()3137 Query_result_to_file::~Query_result_to_file()
3138 {
3139 if (file >= 0)
3140 { // This only happens in case of error
3141 (void) end_io_cache(&cache);
3142 mysql_file_close(file, MYF(0));
3143 file= -1;
3144 }
3145 }
3146
3147 /***************************************************************************
3148 ** Export of select to textfile
3149 ***************************************************************************/
3150
3151 /*
3152 Create file with IO cache
3153
3154 SYNOPSIS
3155 create_file()
3156 thd Thread handle
3157 path File name
3158 exchange Excange class
3159 cache IO cache
3160
3161 RETURN
3162 >= 0 File handle
3163 -1 Error
3164 */
3165
3166
create_file(THD * thd,char * path,sql_exchange * exchange,IO_CACHE * cache)3167 static File create_file(THD *thd, char *path, sql_exchange *exchange,
3168 IO_CACHE *cache)
3169 {
3170 File file;
3171 uint option= MY_UNPACK_FILENAME | MY_RELATIVE_PATH;
3172
3173 if (!dirname_length(exchange->file_name))
3174 {
3175 strxnmov(path, FN_REFLEN-1, mysql_real_data_home,
3176 thd->db().str ? thd->db().str : "",
3177 NullS);
3178 (void) fn_format(path, exchange->file_name, path, "", option);
3179 }
3180 else
3181 (void) fn_format(path, exchange->file_name, mysql_real_data_home, "", option);
3182
3183 if (!is_secure_file_path(path))
3184 {
3185 /* Write only allowed to dir or subdir specified by secure_file_priv */
3186 my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--secure-file-priv");
3187 return -1;
3188 }
3189
3190 if (!access(path, F_OK))
3191 {
3192 my_error(ER_FILE_EXISTS_ERROR, MYF(0), exchange->file_name);
3193 return -1;
3194 }
3195 /* Create the file world readable */
3196 if ((file= mysql_file_create(key_select_to_file,
3197 path, 0666, O_WRONLY|O_EXCL, MYF(MY_WME))) < 0)
3198 return file;
3199 #ifdef HAVE_FCHMOD
3200 (void) fchmod(file, 0666); // Because of umask()
3201 #else
3202 (void) chmod(path, 0666);
3203 #endif
3204 if (init_io_cache(cache, file, 0L, WRITE_CACHE, 0L, 1, MYF(MY_WME)))
3205 {
3206 mysql_file_close(file, MYF(0));
3207 /* Delete file on error, it was just created */
3208 mysql_file_delete(key_select_to_file, path, MYF(0));
3209 return -1;
3210 }
3211 return file;
3212 }
3213
3214
prepare(List<Item> & list,SELECT_LEX_UNIT * u)3215 int Query_result_export::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
3216 {
3217 bool blob_flag=0;
3218 bool string_results= FALSE, non_string_results= FALSE;
3219 unit= u;
3220 if (strlen(exchange->file_name) + NAME_LEN >= FN_REFLEN)
3221 strmake(path,exchange->file_name,FN_REFLEN-1);
3222
3223 write_cs= exchange->cs ? exchange->cs : &my_charset_bin;
3224
3225 if ((file= create_file(thd, path, exchange, &cache)) < 0)
3226 return 1;
3227 /* Check if there is any blobs in data */
3228 {
3229 List_iterator_fast<Item> li(list);
3230 Item *item;
3231 while ((item=li++))
3232 {
3233 if (item->max_length >= MAX_BLOB_WIDTH)
3234 {
3235 blob_flag=1;
3236 break;
3237 }
3238 if (item->result_type() == STRING_RESULT)
3239 string_results= TRUE;
3240 else
3241 non_string_results= TRUE;
3242 }
3243 }
3244 if (exchange->field.escaped->numchars() > 1 ||
3245 exchange->field.enclosed->numchars() > 1)
3246 {
3247 my_error(ER_WRONG_FIELD_TERMINATORS, MYF(0));
3248 return TRUE;
3249 }
3250 if (exchange->field.escaped->length() > 1 ||
3251 exchange->field.enclosed->length() > 1 ||
3252 !my_isascii(exchange->field.escaped->ptr()[0]) ||
3253 !my_isascii(exchange->field.enclosed->ptr()[0]) ||
3254 !exchange->field.field_term->is_ascii() ||
3255 !exchange->line.line_term->is_ascii() ||
3256 !exchange->line.line_start->is_ascii())
3257 {
3258 /*
3259 Current LOAD DATA INFILE recognizes field/line separators "as is" without
3260 converting from client charset to data file charset. So, it is supposed,
3261 that input file of LOAD DATA INFILE consists of data in one charset and
3262 separators in other charset. For the compatibility with that [buggy]
3263 behaviour SELECT INTO OUTFILE implementation has been saved "as is" too,
3264 but the new warning message has been added:
3265
3266 Non-ASCII separator arguments are not fully supported
3267 */
3268 push_warning(thd, Sql_condition::SL_WARNING,
3269 WARN_NON_ASCII_SEPARATOR_NOT_IMPLEMENTED,
3270 ER(WARN_NON_ASCII_SEPARATOR_NOT_IMPLEMENTED));
3271 }
3272 field_term_length=exchange->field.field_term->length();
3273 field_term_char= field_term_length ?
3274 (int) (uchar) (*exchange->field.field_term)[0] : INT_MAX;
3275 if (!exchange->line.line_term->length())
3276 exchange->line.line_term=exchange->field.field_term;// Use this if it exists
3277 field_sep_char= (exchange->field.enclosed->length() ?
3278 (int) (uchar) (*exchange->field.enclosed)[0] :
3279 field_term_char);
3280 if (exchange->field.escaped->length() && (exchange->escaped_given() ||
3281 !(thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES)))
3282 escape_char= (int) (uchar) (*exchange->field.escaped)[0];
3283 else
3284 escape_char= -1;
3285 is_ambiguous_field_sep= MY_TEST(strchr(ESCAPE_CHARS, field_sep_char));
3286 is_unsafe_field_sep= MY_TEST(strchr(NUMERIC_CHARS, field_sep_char));
3287 line_sep_char= (exchange->line.line_term->length() ?
3288 (int) (uchar) (*exchange->line.line_term)[0] : INT_MAX);
3289 if (!field_term_length)
3290 exchange->field.opt_enclosed=0;
3291 if (!exchange->field.enclosed->length())
3292 exchange->field.opt_enclosed=1; // A little quicker loop
3293 fixed_row_size= (!field_term_length && !exchange->field.enclosed->length() &&
3294 !blob_flag);
3295 if ((is_ambiguous_field_sep && exchange->field.enclosed->is_empty() &&
3296 (string_results || is_unsafe_field_sep)) ||
3297 (exchange->field.opt_enclosed && non_string_results &&
3298 field_term_length && strchr(NUMERIC_CHARS, field_term_char)))
3299 {
3300 push_warning(thd, Sql_condition::SL_WARNING,
3301 ER_AMBIGUOUS_FIELD_TERM, ER(ER_AMBIGUOUS_FIELD_TERM));
3302 is_ambiguous_field_term= TRUE;
3303 }
3304 else
3305 is_ambiguous_field_term= FALSE;
3306
3307 return 0;
3308 }
3309
3310
3311 #define NEED_ESCAPING(x) ((int) (uchar) (x) == escape_char || \
3312 (enclosed ? (int) (uchar) (x) == field_sep_char \
3313 : (int) (uchar) (x) == field_term_char) || \
3314 (int) (uchar) (x) == line_sep_char || \
3315 !(x))
3316
send_data(List<Item> & items)3317 bool Query_result_export::send_data(List<Item> &items)
3318 {
3319
3320 DBUG_ENTER("Query_result_export::send_data");
3321 char buff[MAX_FIELD_WIDTH],null_buff[2],space[MAX_FIELD_WIDTH];
3322 char cvt_buff[MAX_FIELD_WIDTH];
3323 String cvt_str(cvt_buff, sizeof(cvt_buff), write_cs);
3324 bool space_inited=0;
3325 String tmp(buff,sizeof(buff),&my_charset_bin),*res;
3326 tmp.length(0);
3327
3328 if (unit->offset_limit_cnt)
3329 { // using limit offset,count
3330 unit->offset_limit_cnt--;
3331 DBUG_RETURN(0);
3332 }
3333 row_count++;
3334 Item *item;
3335 size_t used_length=0;
3336 uint items_left=items.elements;
3337 List_iterator_fast<Item> li(items);
3338
3339 if (my_b_write(&cache,(uchar*) exchange->line.line_start->ptr(),
3340 exchange->line.line_start->length()))
3341 goto err;
3342 while ((item=li++))
3343 {
3344 Item_result result_type=item->result_type();
3345 bool enclosed = (exchange->field.enclosed->length() &&
3346 (!exchange->field.opt_enclosed ||
3347 result_type == STRING_RESULT));
3348 res=item->str_result(&tmp);
3349 if (res && !my_charset_same(write_cs, res->charset()) &&
3350 !my_charset_same(write_cs, &my_charset_bin))
3351 {
3352 const char *well_formed_error_pos;
3353 const char *cannot_convert_error_pos;
3354 const char *from_end_pos;
3355 const char *error_pos;
3356 size_t bytes;
3357 uint64 estimated_bytes=
3358 ((uint64) res->length() / res->charset()->mbminlen + 1) *
3359 write_cs->mbmaxlen + 1;
3360 set_if_smaller(estimated_bytes, UINT_MAX32);
3361 if (cvt_str.mem_realloc((uint32) estimated_bytes))
3362 {
3363 my_error(ER_OUTOFMEMORY, MYF(ME_FATALERROR), (uint32) estimated_bytes);
3364 goto err;
3365 }
3366
3367 bytes= well_formed_copy_nchars(write_cs, (char *) cvt_str.ptr(),
3368 cvt_str.alloced_length(),
3369 res->charset(), res->ptr(), res->length(),
3370 UINT_MAX32, // copy all input chars,
3371 // i.e. ignore nchars parameter
3372 &well_formed_error_pos,
3373 &cannot_convert_error_pos,
3374 &from_end_pos);
3375 error_pos= well_formed_error_pos ? well_formed_error_pos
3376 : cannot_convert_error_pos;
3377 if (error_pos)
3378 {
3379 char printable_buff[32];
3380 convert_to_printable(printable_buff, sizeof(printable_buff),
3381 error_pos, res->ptr() + res->length() - error_pos,
3382 res->charset(), 6);
3383 push_warning_printf(thd, Sql_condition::SL_WARNING,
3384 ER_TRUNCATED_WRONG_VALUE_FOR_FIELD,
3385 ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
3386 "string", printable_buff,
3387 item->item_name.ptr(), static_cast<long>(row_count));
3388 }
3389 else if (from_end_pos < res->ptr() + res->length())
3390 {
3391 /*
3392 result is longer than UINT_MAX32 and doesn't fit into String
3393 */
3394 push_warning_printf(thd, Sql_condition::SL_WARNING,
3395 WARN_DATA_TRUNCATED, ER(WARN_DATA_TRUNCATED),
3396 item->full_name(), static_cast<long>(row_count));
3397 }
3398 cvt_str.length(bytes);
3399 res= &cvt_str;
3400 }
3401 if (res && enclosed)
3402 {
3403 if (my_b_write(&cache,(uchar*) exchange->field.enclosed->ptr(),
3404 exchange->field.enclosed->length()))
3405 goto err;
3406 }
3407 if (!res)
3408 { // NULL
3409 if (!fixed_row_size)
3410 {
3411 if (escape_char != -1) // Use \N syntax
3412 {
3413 null_buff[0]=escape_char;
3414 null_buff[1]='N';
3415 if (my_b_write(&cache,(uchar*) null_buff,2))
3416 goto err;
3417 }
3418 else if (my_b_write(&cache,(uchar*) "NULL",4))
3419 goto err;
3420 }
3421 else
3422 {
3423 used_length=0; // Fill with space
3424 }
3425 }
3426 else
3427 {
3428 if (fixed_row_size)
3429 used_length=min<size_t>(res->length(),item->max_length);
3430 else
3431 used_length=res->length();
3432 if ((result_type == STRING_RESULT || is_unsafe_field_sep) &&
3433 escape_char != -1)
3434 {
3435 char *pos, *start, *end;
3436 bool escape_4_bytes= false;
3437 int in_escapable_4_bytes= 0;
3438 const CHARSET_INFO *res_charset= res->charset();
3439 const CHARSET_INFO *character_set_client=
3440 thd->variables.character_set_client;
3441 bool check_following_byte= (res_charset == &my_charset_bin) &&
3442 character_set_client->
3443 escape_with_backslash_is_dangerous;
3444 /*
3445 The judgement of mbmaxlenlen == 2 is for gb18030 only.
3446 Since there are several charsets with mbmaxlen == 4,
3447 so we have to use mbmaxlenlen == 2 here, which is only true
3448 for gb18030 currently.
3449 */
3450 assert(character_set_client->mbmaxlen == 2 ||
3451 my_mbmaxlenlen(character_set_client) == 2 ||
3452 !character_set_client->escape_with_backslash_is_dangerous);
3453 for (start=pos=(char*) res->ptr(),end=pos+used_length ;
3454 pos != end ;
3455 pos++)
3456 {
3457 bool need_escape= false;
3458 if (use_mb(res_charset))
3459 {
3460 int l;
3461 if ((l=my_ismbchar(res_charset, pos, end)))
3462 {
3463 pos += l-1;
3464 continue;
3465 }
3466 }
3467
3468 /*
3469 Special case when dumping BINARY/VARBINARY/BLOB values
3470 for the clients with character sets big5, cp932, gbk, sjis
3471 and gb18030, which can have the escape character
3472 (0x5C "\" by default) as the second byte of a multi-byte sequence.
3473
3474 The escape character had better be single-byte character,
3475 non-ASCII characters are not prohibited, but not fully supported.
3476
3477 If
3478 - pos[0] is a valid multi-byte head (e.g 0xEE) and
3479 - pos[1] is 0x00, which will be escaped as "\0",
3480
3481 then we'll get "0xEE + 0x5C + 0x30" in the output file.
3482
3483 If this file is later loaded using this sequence of commands:
3484
3485 mysql> create table t1 (a varchar(128)) character set big5;
3486 mysql> LOAD DATA INFILE 'dump.txt' INTO TABLE t1;
3487
3488 then 0x5C will be misinterpreted as the second byte
3489 of a multi-byte character "0xEE + 0x5C", instead of
3490 escape character for 0x00.
3491
3492 To avoid this confusion, we'll escape the multi-byte
3493 head character too, so the sequence "0xEE + 0x00" will be
3494 dumped as "0x5C + 0xEE + 0x5C + 0x30".
3495
3496 Note, in the condition below we only check if
3497 mbcharlen is equal to 2, because there are no
3498 character sets with mbmaxlen longer than 2
3499 and with escape_with_backslash_is_dangerous set.
3500 assert before the loop makes that sure.
3501
3502 But gb18030 is an exception. First of all, 2-byte codes
3503 would be affected by the issue above without doubt.
3504 Then, 4-byte gb18030 codes would be affected as well.
3505
3506 Supposing the input is GB+81358130, and the
3507 field_term_char is set to '5', escape char is 0x5C by default.
3508 When we come to the first byte 0x81, if we don't escape it but
3509 escape the second byte 0x35 as it's the field_term_char,
3510 we would get 0x81 0x5C 0x35 0x81 0x30 for the gb18030 character.
3511 That would be the same issue as mentioned above.
3512
3513 Also, if we just escape the leading 2 bytes, we would get
3514 0x5C 0x81 0x5C 0x35 0x81 0x30 in this case.
3515 The reader of this sequence would assume that 0x81 0x30
3516 is the starting of a new gb18030 character, which would
3517 result in further confusion.
3518
3519 Once we find any byte of the 4-byte gb18030 character should
3520 be escaped, we have to escape all the 4 bytes.
3521 So for GB+81358130, we will get:
3522 0x5C 0x81 0x5C 0x35 0x5C 0x81 0x30
3523
3524 The byte 0x30 shouldn't be escaped(no matter it's the second
3525 or fourth byte in the sequence), since '\0' would be treated
3526 as 0x00, which is not what we expect. And 0x30 would be treated as
3527 an ASCII char when we read it, which is correct.
3528 */
3529
3530 assert(in_escapable_4_bytes >= 0);
3531 if (in_escapable_4_bytes > 0)
3532 {
3533 assert(check_following_byte);
3534 /* We should escape or not escape all the 4 bytes. */
3535 need_escape= escape_4_bytes;
3536 }
3537 else if (NEED_ESCAPING(*pos))
3538 {
3539 need_escape= true;
3540 if (my_mbmaxlenlen(character_set_client) == 2 &&
3541 my_mbcharlen_ptr(character_set_client, pos, end) == 4)
3542 {
3543 in_escapable_4_bytes= 4;
3544 escape_4_bytes= true;
3545 }
3546 }
3547 else if (check_following_byte)
3548 {
3549 int len= my_mbcharlen_ptr(character_set_client, pos, end);
3550 if (len == 2 && pos + 1 < end && NEED_ESCAPING(pos[1]))
3551 need_escape= true;
3552 else if (len == 4 && my_mbmaxlenlen(character_set_client) == 2 &&
3553 pos + 3 < end)
3554 {
3555 in_escapable_4_bytes= 4;
3556 escape_4_bytes= (NEED_ESCAPING(pos[1]) ||
3557 NEED_ESCAPING(pos[2]) ||
3558 NEED_ESCAPING(pos[3]));
3559 need_escape= escape_4_bytes;
3560 }
3561 }
3562 /* Mark how many coming bytes should be escaped, only for gb18030 */
3563 if (in_escapable_4_bytes > 0)
3564 {
3565 in_escapable_4_bytes--;
3566 /*
3567 Note that '0' (0x30) in the middle of a 4-byte sequence
3568 can't be escaped. Please read more details from above comments.
3569 2-byte codes won't be affected by this issue.
3570 */
3571 if (pos[0] == 0x30)
3572 need_escape= false;
3573 }
3574
3575 if (need_escape &&
3576 /*
3577 Don't escape field_term_char by doubling - doubling is only
3578 valid for ENCLOSED BY characters:
3579 */
3580 (enclosed || !is_ambiguous_field_term ||
3581 (int) (uchar) *pos != field_term_char))
3582 {
3583 char tmp_buff[2];
3584 tmp_buff[0]= ((int) (uchar) *pos == field_sep_char &&
3585 is_ambiguous_field_sep) ?
3586 field_sep_char : escape_char;
3587 tmp_buff[1]= *pos ? *pos : '0';
3588 if (my_b_write(&cache,(uchar*) start,(uint) (pos-start)) ||
3589 my_b_write(&cache,(uchar*) tmp_buff,2))
3590 goto err;
3591 start=pos+1;
3592 }
3593 }
3594
3595 /* Assert that no escape mode is active here */
3596 assert(in_escapable_4_bytes == 0);
3597
3598 if (my_b_write(&cache,(uchar*) start,(uint) (pos-start)))
3599 goto err;
3600 }
3601 else if (my_b_write(&cache,(uchar*) res->ptr(),used_length))
3602 goto err;
3603 }
3604 if (fixed_row_size)
3605 { // Fill with space
3606 if (item->max_length > used_length)
3607 {
3608 /* QQ: Fix by adding a my_b_fill() function */
3609 if (!space_inited)
3610 {
3611 space_inited=1;
3612 memset(space, ' ', sizeof(space));
3613 }
3614 size_t length=item->max_length-used_length;
3615 for (; length > sizeof(space) ; length-=sizeof(space))
3616 {
3617 if (my_b_write(&cache,(uchar*) space,sizeof(space)))
3618 goto err;
3619 }
3620 if (my_b_write(&cache,(uchar*) space,length))
3621 goto err;
3622 }
3623 }
3624 if (res && enclosed)
3625 {
3626 if (my_b_write(&cache, (uchar*) exchange->field.enclosed->ptr(),
3627 exchange->field.enclosed->length()))
3628 goto err;
3629 }
3630 if (--items_left)
3631 {
3632 if (my_b_write(&cache, (uchar*) exchange->field.field_term->ptr(),
3633 field_term_length))
3634 goto err;
3635 }
3636 }
3637 if (my_b_write(&cache,(uchar*) exchange->line.line_term->ptr(),
3638 exchange->line.line_term->length()))
3639 goto err;
3640 DBUG_RETURN(0);
3641 err:
3642 DBUG_RETURN(1);
3643 }
3644
3645
3646 /***************************************************************************
3647 ** Dump of query to a binary file
3648 ***************************************************************************/
3649
3650
prepare(List<Item> & list MY_ATTRIBUTE ((unused)),SELECT_LEX_UNIT * u)3651 int Query_result_dump::prepare(List<Item> &list MY_ATTRIBUTE((unused)),
3652 SELECT_LEX_UNIT *u)
3653 {
3654 unit= u;
3655 return (int) ((file= create_file(thd, path, exchange, &cache)) < 0);
3656 }
3657
3658
send_data(List<Item> & items)3659 bool Query_result_dump::send_data(List<Item> &items)
3660 {
3661 List_iterator_fast<Item> li(items);
3662 char buff[MAX_FIELD_WIDTH];
3663 String tmp(buff,sizeof(buff),&my_charset_bin),*res;
3664 tmp.length(0);
3665 Item *item;
3666 DBUG_ENTER("Query_result_dump::send_data");
3667
3668 if (unit->offset_limit_cnt)
3669 { // using limit offset,count
3670 unit->offset_limit_cnt--;
3671 DBUG_RETURN(0);
3672 }
3673 if (row_count++ > 1)
3674 {
3675 my_message(ER_TOO_MANY_ROWS, ER(ER_TOO_MANY_ROWS), MYF(0));
3676 goto err;
3677 }
3678 while ((item=li++))
3679 {
3680 res=item->str_result(&tmp);
3681 if (!res) // If NULL
3682 {
3683 if (my_b_write(&cache,(uchar*) "",1))
3684 goto err;
3685 }
3686 else if (my_b_write(&cache,(uchar*) res->ptr(),res->length()))
3687 {
3688 char errbuf[MYSYS_STRERROR_SIZE];
3689 my_error(ER_ERROR_ON_WRITE, MYF(0), path, my_errno(),
3690 my_strerror(errbuf, sizeof(errbuf), my_errno()));
3691 goto err;
3692 }
3693 }
3694 DBUG_RETURN(0);
3695 err:
3696 DBUG_RETURN(1);
3697 }
3698
3699
3700 /***************************************************************************
3701 Dump of select to variables
3702 ***************************************************************************/
3703
prepare(List<Item> & list,SELECT_LEX_UNIT * u)3704 int Query_dumpvar::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
3705 {
3706 unit= u;
3707
3708 if (var_list.elements != list.elements)
3709 {
3710 my_message(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT,
3711 ER(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT), MYF(0));
3712 return 1;
3713 }
3714
3715 return 0;
3716 }
3717
3718
check_simple_select() const3719 bool Query_dumpvar::check_simple_select() const
3720 {
3721 my_error(ER_SP_BAD_CURSOR_SELECT, MYF(0));
3722 return TRUE;
3723 }
3724
3725
free_items()3726 void Query_arena::free_items()
3727 {
3728 Item *next;
3729 DBUG_ENTER("Query_arena::free_items");
3730 /* This works because items are allocated with sql_alloc() */
3731 for (; free_list; free_list= next)
3732 {
3733 next= free_list->next;
3734 free_list->delete_self();
3735 }
3736 /* Postcondition: free_list is 0 */
3737 DBUG_VOID_RETURN;
3738 }
3739
3740
set_query_arena(Query_arena * set)3741 void Query_arena::set_query_arena(Query_arena *set)
3742 {
3743 mem_root= set->mem_root;
3744 free_list= set->free_list;
3745 state= set->state;
3746 }
3747
3748
cleanup_stmt()3749 void Query_arena::cleanup_stmt()
3750 {
3751 assert(! "Query_arena::cleanup_stmt() not implemented");
3752 }
3753
3754
end_statement()3755 void THD::end_statement()
3756 {
3757 /* Cleanup SQL processing state to reuse this statement in next query. */
3758 lex_end(lex);
3759 delete lex->result;
3760 lex->result= 0;
3761 /* Note that free_list is freed in cleanup_after_query() */
3762
3763 /*
3764 Don't free mem_root, as mem_root is freed in the end of dispatch_command
3765 (once for any command).
3766 */
3767 }
3768
3769
set_n_backup_active_arena(Query_arena * set,Query_arena * backup)3770 void THD::set_n_backup_active_arena(Query_arena *set, Query_arena *backup)
3771 {
3772 DBUG_ENTER("THD::set_n_backup_active_arena");
3773 assert(backup->is_backup_arena == FALSE);
3774
3775 backup->set_query_arena(this);
3776 set_query_arena(set);
3777 #ifndef NDEBUG
3778 backup->is_backup_arena= TRUE;
3779 #endif
3780 DBUG_VOID_RETURN;
3781 }
3782
3783
restore_active_arena(Query_arena * set,Query_arena * backup)3784 void THD::restore_active_arena(Query_arena *set, Query_arena *backup)
3785 {
3786 DBUG_ENTER("THD::restore_active_arena");
3787 assert(backup->is_backup_arena);
3788 set->set_query_arena(this);
3789 set_query_arena(backup);
3790 #ifndef NDEBUG
3791 backup->is_backup_arena= FALSE;
3792 #endif
3793 DBUG_VOID_RETURN;
3794 }
3795
3796 C_MODE_START
3797
3798 static uchar *
get_statement_id_as_hash_key(const uchar * record,size_t * key_length,my_bool not_used MY_ATTRIBUTE ((unused)))3799 get_statement_id_as_hash_key(const uchar *record, size_t *key_length,
3800 my_bool not_used MY_ATTRIBUTE((unused)))
3801 {
3802 const Prepared_statement *statement= (const Prepared_statement *) record;
3803 *key_length= sizeof(statement->id);
3804 return (uchar *) &(statement)->id;
3805 }
3806
delete_statement_as_hash_key(void * key)3807 static void delete_statement_as_hash_key(void *key)
3808 {
3809 delete (Prepared_statement *) key;
3810 }
3811
get_stmt_name_hash_key(Prepared_statement * entry,size_t * length,my_bool not_used MY_ATTRIBUTE ((unused)))3812 static uchar *get_stmt_name_hash_key(Prepared_statement *entry, size_t *length,
3813 my_bool not_used MY_ATTRIBUTE((unused)))
3814 {
3815 *length= entry->name().length;
3816 return reinterpret_cast<uchar *>(const_cast<char *>(entry->name().str));
3817 }
3818
3819 C_MODE_END
3820
Prepared_statement_map()3821 Prepared_statement_map::Prepared_statement_map()
3822 :m_last_found_statement(NULL)
3823 {
3824 enum
3825 {
3826 START_STMT_HASH_SIZE = 16,
3827 START_NAME_HASH_SIZE = 16
3828 };
3829 my_hash_init(&st_hash, &my_charset_bin, START_STMT_HASH_SIZE, 0, 0,
3830 get_statement_id_as_hash_key,
3831 delete_statement_as_hash_key, MYF(0),
3832 key_memory_prepared_statement_map);
3833 my_hash_init(&names_hash, system_charset_info, START_NAME_HASH_SIZE, 0, 0,
3834 (my_hash_get_key) get_stmt_name_hash_key,
3835 NULL, MYF(0),
3836 key_memory_prepared_statement_map);
3837 }
3838
3839
insert(THD * thd,Prepared_statement * statement)3840 int Prepared_statement_map::insert(THD *thd, Prepared_statement *statement)
3841 {
3842 if (my_hash_insert(&st_hash, (uchar*) statement))
3843 {
3844 /*
3845 Delete is needed only in case of an insert failure. In all other
3846 cases hash_delete will also delete the statement.
3847 */
3848 delete statement;
3849 my_error(ER_OUT_OF_RESOURCES, MYF(0));
3850 goto err_st_hash;
3851 }
3852 if (statement->name().str && my_hash_insert(&names_hash, (uchar*) statement))
3853 {
3854 my_error(ER_OUT_OF_RESOURCES, MYF(0));
3855 goto err_names_hash;
3856 }
3857 mysql_mutex_lock(&LOCK_prepared_stmt_count);
3858 /*
3859 We don't check that prepared_stmt_count is <= max_prepared_stmt_count
3860 because we would like to allow to lower the total limit
3861 of prepared statements below the current count. In that case
3862 no new statements can be added until prepared_stmt_count drops below
3863 the limit.
3864 */
3865 if (prepared_stmt_count >= max_prepared_stmt_count)
3866 {
3867 mysql_mutex_unlock(&LOCK_prepared_stmt_count);
3868 my_error(ER_MAX_PREPARED_STMT_COUNT_REACHED, MYF(0),
3869 max_prepared_stmt_count);
3870 goto err_max;
3871 }
3872 prepared_stmt_count++;
3873 mysql_mutex_unlock(&LOCK_prepared_stmt_count);
3874
3875 m_last_found_statement= statement;
3876 return 0;
3877
3878 err_max:
3879 if (statement->name().str)
3880 my_hash_delete(&names_hash, (uchar*) statement);
3881 err_names_hash:
3882 my_hash_delete(&st_hash, (uchar*) statement);
3883 err_st_hash:
3884 return 1;
3885 }
3886
3887
3888 Prepared_statement
find_by_name(const LEX_CSTRING & name)3889 *Prepared_statement_map::find_by_name(const LEX_CSTRING &name)
3890 {
3891 return reinterpret_cast<Prepared_statement*>
3892 (my_hash_search(&names_hash, (uchar*)name.str, name.length));
3893 }
3894
3895
find(ulong id)3896 Prepared_statement *Prepared_statement_map::find(ulong id)
3897 {
3898 if (m_last_found_statement == NULL || id != m_last_found_statement->id)
3899 {
3900 Prepared_statement *stmt=
3901 reinterpret_cast<Prepared_statement*>
3902 (my_hash_search(&st_hash, (uchar *) &id, sizeof(id)));
3903 if (stmt && stmt->name().str)
3904 return NULL;
3905 m_last_found_statement= stmt;
3906 }
3907 return m_last_found_statement;
3908 }
3909
3910
erase(Prepared_statement * statement)3911 void Prepared_statement_map::erase(Prepared_statement *statement)
3912 {
3913 if (statement == m_last_found_statement)
3914 m_last_found_statement= NULL;
3915 if (statement->name().str)
3916 my_hash_delete(&names_hash, (uchar *) statement);
3917
3918 my_hash_delete(&st_hash, (uchar *) statement);
3919 mysql_mutex_lock(&LOCK_prepared_stmt_count);
3920 assert(prepared_stmt_count > 0);
3921 prepared_stmt_count--;
3922 mysql_mutex_unlock(&LOCK_prepared_stmt_count);
3923 }
3924
claim_memory_ownership()3925 void Prepared_statement_map::claim_memory_ownership()
3926 {
3927 my_hash_claim(&names_hash);
3928 my_hash_claim(&st_hash);
3929 }
3930
reset()3931 void Prepared_statement_map::reset()
3932 {
3933 /* Must be first, hash_free will reset st_hash.records */
3934 if (st_hash.records > 0)
3935 {
3936 #ifdef HAVE_PSI_PS_INTERFACE
3937 for (uint i=0 ; i < st_hash.records ; i++)
3938 {
3939 Prepared_statement *stmt=
3940 reinterpret_cast<Prepared_statement *>(my_hash_element(&st_hash, i));
3941 MYSQL_DESTROY_PS(stmt->get_PS_prepared_stmt());
3942 }
3943 #endif
3944 mysql_mutex_lock(&LOCK_prepared_stmt_count);
3945 assert(prepared_stmt_count >= st_hash.records);
3946 prepared_stmt_count-= st_hash.records;
3947 mysql_mutex_unlock(&LOCK_prepared_stmt_count);
3948 }
3949 my_hash_reset(&names_hash);
3950 my_hash_reset(&st_hash);
3951 m_last_found_statement= NULL;
3952 }
3953
3954
~Prepared_statement_map()3955 Prepared_statement_map::~Prepared_statement_map()
3956 {
3957 /*
3958 We do not want to grab the global LOCK_prepared_stmt_count mutex here.
3959 reset() should already have been called to maintain prepared_stmt_count.
3960 */
3961 assert(st_hash.records == 0);
3962
3963 my_hash_free(&names_hash);
3964 my_hash_free(&st_hash);
3965 }
3966
3967
send_data(List<Item> & items)3968 bool Query_dumpvar::send_data(List<Item> &items)
3969 {
3970 List_iterator_fast<PT_select_var> var_li(var_list);
3971 List_iterator<Item> it(items);
3972 Item *item;
3973 PT_select_var *mv;
3974 DBUG_ENTER("Query_dumpvar::send_data");
3975
3976 if (unit->offset_limit_cnt)
3977 { // using limit offset,count
3978 unit->offset_limit_cnt--;
3979 DBUG_RETURN(false);
3980 }
3981 if (row_count++)
3982 {
3983 my_message(ER_TOO_MANY_ROWS, ER(ER_TOO_MANY_ROWS), MYF(0));
3984 DBUG_RETURN(true);
3985 }
3986 while ((mv= var_li++) && (item= it++))
3987 {
3988 if (mv->is_local())
3989 {
3990 if (thd->sp_runtime_ctx->set_variable(thd, mv->get_offset(), &item))
3991 DBUG_RETURN(true);
3992 }
3993 else
3994 {
3995 /*
3996 Create Item_func_set_user_vars with delayed non-constness. We
3997 do this so that Item_get_user_var::const_item() will return
3998 the same result during
3999 Item_func_set_user_var::save_item_result() as they did during
4000 optimization and execution.
4001 */
4002 Item_func_set_user_var *suv=
4003 new Item_func_set_user_var(mv->name, item, true);
4004 if (suv->fix_fields(thd, 0))
4005 DBUG_RETURN(true);
4006 suv->save_item_result(item);
4007 if (suv->update())
4008 DBUG_RETURN(true);
4009 }
4010 }
4011 DBUG_RETURN(thd->is_error());
4012 }
4013
send_eof()4014 bool Query_dumpvar::send_eof()
4015 {
4016 if (! row_count)
4017 push_warning(thd, Sql_condition::SL_WARNING,
4018 ER_SP_FETCH_NO_DATA, ER(ER_SP_FETCH_NO_DATA));
4019 /*
4020 Don't send EOF if we're in error condition (which implies we've already
4021 sent or are sending an error)
4022 */
4023 if (thd->is_error())
4024 return true;
4025
4026 ::my_ok(thd,row_count);
4027 return 0;
4028 }
4029
4030
thd_increment_bytes_sent(size_t length)4031 void thd_increment_bytes_sent(size_t length)
4032 {
4033 THD *thd= current_thd;
4034 if (likely(thd != NULL))
4035 { /* current_thd==NULL when close_connection() calls net_send_error() */
4036 thd->status_var.bytes_sent+= length;
4037 }
4038 }
4039
4040
thd_increment_bytes_received(size_t length)4041 void thd_increment_bytes_received(size_t length)
4042 {
4043 THD *thd= current_thd;
4044 if (likely(thd != NULL))
4045 thd->status_var.bytes_received+= length;
4046 }
4047
4048
set_status_var_init()4049 void THD::set_status_var_init()
4050 {
4051 memset(&status_var, 0, sizeof(status_var));
4052 }
4053
4054
4055 /****************************************************************************
4056 Handling of open and locked tables states.
4057
4058 This is used when we want to open/lock (and then close) some tables when
4059 we already have a set of tables open and locked. We use these methods for
4060 access to mysql.proc table to find definitions of stored routines.
4061 ****************************************************************************/
4062
reset_n_backup_open_tables_state(Open_tables_backup * backup)4063 void THD::reset_n_backup_open_tables_state(Open_tables_backup *backup)
4064 {
4065 DBUG_ENTER("reset_n_backup_open_tables_state");
4066 backup->set_open_tables_state(this);
4067 backup->mdl_system_tables_svp= mdl_context.mdl_savepoint();
4068 reset_open_tables_state();
4069 state_flags|= Open_tables_state::BACKUPS_AVAIL;
4070 DBUG_VOID_RETURN;
4071 }
4072
4073
restore_backup_open_tables_state(Open_tables_backup * backup)4074 void THD::restore_backup_open_tables_state(Open_tables_backup *backup)
4075 {
4076 DBUG_ENTER("restore_backup_open_tables_state");
4077 mdl_context.rollback_to_savepoint(backup->mdl_system_tables_svp);
4078 /*
4079 Before we will throw away current open tables state we want
4080 to be sure that it was properly cleaned up.
4081 */
4082 assert(open_tables == 0 && temporary_tables == 0 &&
4083 derived_tables == 0 &&
4084 lock == 0 &&
4085 locked_tables_mode == LTM_NONE &&
4086 get_reprepare_observer() == NULL);
4087
4088 set_open_tables_state(backup);
4089 DBUG_VOID_RETURN;
4090 }
4091
4092
begin_attachable_ro_transaction()4093 void THD::begin_attachable_ro_transaction()
4094 {
4095 assert(!m_attachable_trx);
4096
4097 m_attachable_trx= new Attachable_trx(this);
4098 }
4099
4100
end_attachable_transaction()4101 void THD::end_attachable_transaction()
4102 {
4103 assert(m_attachable_trx);
4104
4105 delete m_attachable_trx;
4106 m_attachable_trx= NULL;
4107 }
4108
4109
4110 /**
4111 Check the killed state of a user thread
4112 @param thd user thread
4113 @retval 0 the user thread is active
4114 @retval 1 the user thread has been killed
4115 */
thd_killed(const MYSQL_THD thd)4116 extern "C" int thd_killed(const MYSQL_THD thd)
4117 {
4118 if (thd == NULL)
4119 return current_thd != NULL ? current_thd->killed : 0;
4120 return thd->killed;
4121 }
4122
4123 /**
4124 Set the killed status of the current statement.
4125
4126 @param thd user thread connection handle
4127 */
thd_set_kill_status(const MYSQL_THD thd)4128 extern "C" void thd_set_kill_status(const MYSQL_THD thd)
4129 {
4130 thd->send_kill_message();
4131 }
4132
4133 /**
4134 Return the thread id of a user thread
4135 @param thd user thread
4136 @return thread id
4137 */
thd_get_thread_id(const MYSQL_THD thd)4138 extern "C" unsigned long thd_get_thread_id(const MYSQL_THD thd)
4139 {
4140 return((unsigned long)thd->thread_id());
4141 }
4142
4143 /**
4144 Check if batching is allowed for the thread
4145 @param thd user thread
4146 @retval 1 batching allowed
4147 @retval 0 batching not allowed
4148 */
thd_allow_batch(MYSQL_THD thd)4149 extern "C" int thd_allow_batch(MYSQL_THD thd)
4150 {
4151 if ((thd->variables.option_bits & OPTION_ALLOW_BATCH) ||
4152 (thd->slave_thread && opt_slave_allow_batching))
4153 return 1;
4154 return 0;
4155 }
4156
thd_get_trx_isolation(const MYSQL_THD thd)4157 enum_tx_isolation thd_get_trx_isolation(const MYSQL_THD thd)
4158 {
4159 return thd->tx_isolation;
4160 }
4161
4162 #ifdef INNODB_COMPATIBILITY_HOOKS
thd_charset(MYSQL_THD thd)4163 extern "C" const struct charset_info_st *thd_charset(MYSQL_THD thd)
4164 {
4165 return(thd->charset());
4166 }
4167
4168 /**
4169 Get the current query string for the thread.
4170
4171 @param thd The MySQL internal thread pointer
4172
4173 @return query string and length. May be non-null-terminated.
4174
4175 @note This function is not thread safe and should only be called
4176 from the thread owning thd. @see thd_query_safe().
4177 */
thd_query_unsafe(MYSQL_THD thd)4178 extern "C" LEX_CSTRING thd_query_unsafe(MYSQL_THD thd)
4179 {
4180 assert(current_thd == thd);
4181 return thd->query();
4182 }
4183
4184 /**
4185 Get the current query string for the thread.
4186
4187 @param thd The MySQL internal thread pointer
4188 @param buf Buffer where the query string will be copied
4189 @param buflen Length of the buffer
4190
4191 @return Length of the query
4192
4193 @note This function is thread safe as the query string is
4194 accessed under mutex protection and the string is copied
4195 into the provided buffer. @see thd_query_unsafe().
4196 */
thd_query_safe(MYSQL_THD thd,char * buf,size_t buflen)4197 extern "C" size_t thd_query_safe(MYSQL_THD thd, char *buf, size_t buflen)
4198 {
4199 mysql_mutex_lock(&thd->LOCK_thd_query);
4200 LEX_CSTRING query_string= thd->query();
4201 size_t len= MY_MIN(buflen - 1, query_string.length);
4202 strncpy(buf, query_string.str, len);
4203 buf[len]= '\0';
4204 mysql_mutex_unlock(&thd->LOCK_thd_query);
4205 return len;
4206 }
4207
thd_slave_thread(const MYSQL_THD thd)4208 extern "C" int thd_slave_thread(const MYSQL_THD thd)
4209 {
4210 return(thd->slave_thread);
4211 }
4212
thd_non_transactional_update(const MYSQL_THD thd)4213 extern "C" int thd_non_transactional_update(const MYSQL_THD thd)
4214 {
4215 return thd->get_transaction()->has_modified_non_trans_table(
4216 Transaction_ctx::SESSION);
4217 }
4218
thd_has_active_attachable_trx(const MYSQL_THD thd)4219 extern "C" int thd_has_active_attachable_trx(const MYSQL_THD thd)
4220 {
4221 return thd->is_attachable_transaction_active();
4222 }
4223
thd_is_operating_gtid_table_implicitly(const MYSQL_THD thd)4224 extern "C" int thd_is_operating_gtid_table_implicitly(const MYSQL_THD thd)
4225 {
4226 return thd->is_operating_gtid_table_implicitly;
4227 }
4228
thd_binlog_format(const MYSQL_THD thd)4229 extern "C" int thd_binlog_format(const MYSQL_THD thd)
4230 {
4231 #ifdef WITH_WSREP
4232 if (WSREP(thd))
4233 {
4234 /* for wsrep binlog format is meaningful also when binlogging is off */
4235 return (int) WSREP_BINLOG_FORMAT(thd->variables.binlog_format);
4236 }
4237 #endif /* WITH_WSREP */
4238 if (mysql_bin_log.is_open() && (thd->variables.option_bits & OPTION_BIN_LOG))
4239 return (int) thd->variables.binlog_format;
4240 else
4241 return BINLOG_FORMAT_UNSPEC;
4242 }
4243
thd_mark_transaction_to_rollback(MYSQL_THD thd,int all)4244 extern "C" void thd_mark_transaction_to_rollback(MYSQL_THD thd, int all)
4245 {
4246 DBUG_ENTER("thd_mark_transaction_to_rollback");
4247 assert(thd);
4248 /*
4249 The parameter "all" has type int since the function is defined
4250 in plugin.h. The corresponding parameter in the call below has
4251 type bool. The comment in plugin.h states that "all != 0"
4252 means to rollback the main transaction. Thus, check this
4253 specifically.
4254 */
4255 thd->mark_transaction_to_rollback((all != 0));
4256 DBUG_VOID_RETURN;
4257 }
4258
thd_binlog_filter_ok(const MYSQL_THD thd)4259 extern "C" bool thd_binlog_filter_ok(const MYSQL_THD thd)
4260 {
4261 return binlog_filter->db_ok(thd->db().str);
4262 }
4263
thd_sqlcom_can_generate_row_events(const MYSQL_THD thd)4264 extern "C" bool thd_sqlcom_can_generate_row_events(const MYSQL_THD thd)
4265 {
4266 return sqlcom_can_generate_row_events(thd->lex->sql_command);
4267 }
4268
thd_get_durability_property(const MYSQL_THD thd)4269 extern "C" enum durability_properties thd_get_durability_property(const MYSQL_THD thd)
4270 {
4271 enum durability_properties ret= HA_REGULAR_DURABILITY;
4272
4273 if (thd != NULL)
4274 ret= thd->durability_property;
4275
4276 return ret;
4277 }
4278
4279 /** Get the auto_increment_offset auto_increment_increment.
4280 Needed by InnoDB.
4281 @param thd Thread object
4282 @param off auto_increment_offset
4283 @param inc auto_increment_increment */
thd_get_autoinc(const MYSQL_THD thd,ulong * off,ulong * inc)4284 extern "C" void thd_get_autoinc(const MYSQL_THD thd, ulong* off, ulong* inc)
4285 {
4286 *off = thd->variables.auto_increment_offset;
4287 *inc = thd->variables.auto_increment_increment;
4288 }
4289
4290
4291 /**
4292 Is strict sql_mode set.
4293 Needed by InnoDB.
4294 @param thd Thread object
4295 @return True if sql_mode has strict mode (all or trans).
4296 @retval true sql_mode has strict mode (all or trans).
4297 @retval false sql_mode has not strict mode (all or trans).
4298 */
thd_is_strict_mode(const MYSQL_THD thd)4299 extern "C" bool thd_is_strict_mode(const MYSQL_THD thd)
4300 {
4301 return thd->is_strict_mode();
4302 }
4303
4304
4305 #ifndef EMBEDDED_LIBRARY
4306 extern "C" void thd_pool_wait_begin(MYSQL_THD thd, int wait_type);
4307 extern "C" void thd_pool_wait_end(MYSQL_THD thd);
4308
4309 /*
4310 Interface for MySQL Server, plugins and storage engines to report
4311 when they are going to sleep/stall.
4312
4313 SYNOPSIS
4314 thd_wait_begin()
4315 thd Thread object
4316 wait_type Type of wait
4317 1 -- short wait (e.g. for mutex)
4318 2 -- medium wait (e.g. for disk io)
4319 3 -- large wait (e.g. for locked row/table)
4320 NOTES
4321 This is used by the threadpool to have better knowledge of which
4322 threads that currently are actively running on CPUs. When a thread
4323 reports that it's going to sleep/stall, the threadpool scheduler is
4324 free to start another thread in the pool most likely. The expected wait
4325 time is simply an indication of how long the wait is expected to
4326 become, the real wait time could be very different.
4327
4328 thd_wait_end MUST be called immediately after waking up again.
4329 */
thd_wait_begin(MYSQL_THD thd,int wait_type)4330 extern "C" void thd_wait_begin(MYSQL_THD thd, int wait_type)
4331 {
4332 MYSQL_CALLBACK(Connection_handler_manager::event_functions,
4333 thd_wait_begin, (thd, wait_type));
4334 }
4335
4336 /**
4337 Interface for MySQL Server, plugins and storage engines to report
4338 when they waking up from a sleep/stall.
4339
4340 @param thd Thread handle
4341 */
thd_wait_end(MYSQL_THD thd)4342 extern "C" void thd_wait_end(MYSQL_THD thd)
4343 {
4344 MYSQL_CALLBACK(Connection_handler_manager::event_functions,
4345 thd_wait_end, (thd));
4346 }
4347 #else
thd_wait_begin(MYSQL_THD thd,int wait_type)4348 extern "C" void thd_wait_begin(MYSQL_THD thd, int wait_type)
4349 {
4350 /* do NOTHING for the embedded library */
4351 return;
4352 }
4353
thd_wait_end(MYSQL_THD thd)4354 extern "C" void thd_wait_end(MYSQL_THD thd)
4355 {
4356 /* do NOTHING for the embedded library */
4357 return;
4358 }
4359 #endif
4360 #endif // INNODB_COMPATIBILITY_HOOKS */
4361
4362 #ifndef EMBEDDED_LIBRARY
4363 /**
4364 Interface for Engine to report row lock conflict.
4365 The caller should guarantee thd_wait_for does not be freed, when it is
4366 called.
4367 */
4368 extern "C"
thd_report_row_lock_wait(THD * self,THD * wait_for)4369 void thd_report_row_lock_wait(THD* self, THD *wait_for)
4370 {
4371 DBUG_ENTER("thd_report_row_lock_wait");
4372
4373 if (self != NULL && wait_for != NULL &&
4374 is_mts_worker(self) && is_mts_worker(wait_for))
4375 commit_order_manager_check_deadlock(self, wait_for);
4376
4377 DBUG_VOID_RETURN;
4378 }
4379 #else
4380 extern "C"
thd_report_row_lock_wait(THD * thd_wait_for)4381 void thd_report_row_lock_wait(THD *thd_wait_for)
4382 {
4383 return;
4384 }
4385 #endif
4386
4387 /****************************************************************************
4388 Handling of statement states in functions and triggers.
4389
4390 This is used to ensure that the function/trigger gets a clean state
4391 to work with and does not cause any side effects of the calling statement.
4392
4393 It also allows most stored functions and triggers to replicate even
4394 if they are used items that would normally be stored in the binary
4395 replication (like last_insert_id() etc...)
4396
4397 The following things is done
4398 - Disable binary logging for the duration of the statement
4399 - Disable multi-result-sets for the duration of the statement
4400 - Value of last_insert_id() is saved and restored
4401 - Value set by 'SET INSERT_ID=#' is reset and restored
4402 - Value for found_rows() is reset and restored
4403 - examined_row_count is added to the total
4404 - cuted_fields is added to the total
4405 - new savepoint level is created and destroyed
4406
4407 NOTES:
4408 Seed for random() is saved for the first! usage of RAND()
4409 We reset examined_row_count and cuted_fields and add these to the
4410 result to ensure that if we have a bug that would reset these within
4411 a function, we are not loosing any rows from the main statement.
4412
4413 We do not reset value of last_insert_id().
4414 ****************************************************************************/
4415
reset_sub_statement_state(Sub_statement_state * backup,uint new_state)4416 void THD::reset_sub_statement_state(Sub_statement_state *backup,
4417 uint new_state)
4418 {
4419 #ifndef EMBEDDED_LIBRARY
4420 /* BUG#33029, if we are replicating from a buggy master, reset
4421 auto_inc_intervals_forced to prevent substatement
4422 (triggers/functions) from using erroneous INSERT_ID value
4423 */
4424 if (rpl_master_erroneous_autoinc(this))
4425 {
4426 assert(backup->auto_inc_intervals_forced.nb_elements() == 0);
4427 auto_inc_intervals_forced.swap(&backup->auto_inc_intervals_forced);
4428 }
4429 #endif
4430
4431 backup->option_bits= variables.option_bits;
4432 backup->count_cuted_fields= count_cuted_fields;
4433 backup->in_sub_stmt= in_sub_stmt;
4434 backup->enable_slow_log= enable_slow_log;
4435 backup->current_found_rows= current_found_rows;
4436 backup->previous_found_rows= previous_found_rows;
4437 backup->examined_row_count= m_examined_row_count;
4438 backup->sent_row_count= m_sent_row_count;
4439 backup->cuted_fields= cuted_fields;
4440 backup->client_capabilities= m_protocol->get_client_capabilities();
4441 backup->savepoints= get_transaction()->m_savepoints;
4442 backup->first_successful_insert_id_in_prev_stmt=
4443 first_successful_insert_id_in_prev_stmt;
4444 backup->first_successful_insert_id_in_cur_stmt=
4445 first_successful_insert_id_in_cur_stmt;
4446
4447 if ((!lex->requires_prelocking() || is_update_query(lex->sql_command)) &&
4448 !is_current_stmt_binlog_format_row())
4449 {
4450 variables.option_bits&= ~OPTION_BIN_LOG;
4451 }
4452
4453 if ((backup->option_bits & OPTION_BIN_LOG) &&
4454 is_update_query(lex->sql_command) &&
4455 !is_current_stmt_binlog_format_row())
4456 mysql_bin_log.start_union_events(this, this->query_id);
4457
4458 /* Disable result sets */
4459 if (is_classic_protocol())
4460 get_protocol_classic()->remove_client_capability(CLIENT_MULTI_RESULTS);
4461 in_sub_stmt|= new_state;
4462 m_examined_row_count= 0;
4463 m_sent_row_count= 0;
4464 cuted_fields= 0;
4465 get_transaction()->m_savepoints= 0;
4466 first_successful_insert_id_in_cur_stmt= 0;
4467
4468 /* Reset savepoint on transaction write set */
4469 if (is_current_stmt_binlog_row_enabled_with_write_set_extraction())
4470 {
4471 get_transaction()->get_transaction_write_set_ctx()
4472 ->reset_savepoint_list();
4473 }
4474 }
4475
4476
restore_sub_statement_state(Sub_statement_state * backup)4477 void THD::restore_sub_statement_state(Sub_statement_state *backup)
4478 {
4479 DBUG_ENTER("THD::restore_sub_statement_state");
4480 #ifndef EMBEDDED_LIBRARY
4481 /* BUG#33029, if we are replicating from a buggy master, restore
4482 auto_inc_intervals_forced so that the top statement can use the
4483 INSERT_ID value set before this statement.
4484 */
4485 if (rpl_master_erroneous_autoinc(this))
4486 {
4487 backup->auto_inc_intervals_forced.swap(&auto_inc_intervals_forced);
4488 assert(backup->auto_inc_intervals_forced.nb_elements() == 0);
4489 }
4490 #endif
4491
4492 /*
4493 To save resources we want to release savepoints which were created
4494 during execution of function or trigger before leaving their savepoint
4495 level. It is enough to release first savepoint set on this level since
4496 all later savepoints will be released automatically.
4497 */
4498 if (get_transaction()->m_savepoints)
4499 {
4500 SAVEPOINT *sv;
4501 for (sv= get_transaction()->m_savepoints; sv->prev; sv= sv->prev)
4502 {}
4503 /* ha_release_savepoint() never returns error. */
4504 (void)ha_release_savepoint(this, sv);
4505 }
4506 count_cuted_fields= backup->count_cuted_fields;
4507 get_transaction()->m_savepoints= backup->savepoints;
4508 variables.option_bits= backup->option_bits;
4509 in_sub_stmt= backup->in_sub_stmt;
4510 enable_slow_log= backup->enable_slow_log;
4511 first_successful_insert_id_in_prev_stmt=
4512 backup->first_successful_insert_id_in_prev_stmt;
4513 first_successful_insert_id_in_cur_stmt=
4514 backup->first_successful_insert_id_in_cur_stmt;
4515 current_found_rows= backup->current_found_rows;
4516 previous_found_rows= backup->previous_found_rows;
4517 set_sent_row_count(backup->sent_row_count);
4518 if (is_classic_protocol())
4519 get_protocol_classic()->set_client_capabilities(backup->client_capabilities);
4520
4521 /*
4522 If we've left sub-statement mode, reset the fatal error flag.
4523 Otherwise keep the current value, to propagate it up the sub-statement
4524 stack.
4525
4526 NOTE: is_fatal_sub_stmt_error can be set only if we've been in the
4527 sub-statement mode.
4528 */
4529
4530 if (!in_sub_stmt)
4531 is_fatal_sub_stmt_error= false;
4532
4533 if ((variables.option_bits & OPTION_BIN_LOG) && is_update_query(lex->sql_command) &&
4534 !is_current_stmt_binlog_format_row())
4535 mysql_bin_log.stop_union_events(this);
4536
4537 /*
4538 The following is added to the old values as we are interested in the
4539 total complexity of the query
4540 */
4541 inc_examined_row_count(backup->examined_row_count);
4542 cuted_fields+= backup->cuted_fields;
4543
4544 /* Restore savepoint on transaction write set */
4545 if (is_current_stmt_binlog_row_enabled_with_write_set_extraction())
4546 {
4547 get_transaction()->get_transaction_write_set_ctx()
4548 ->restore_savepoint_list();
4549 }
4550
4551 DBUG_VOID_RETURN;
4552 }
4553
set_sent_row_count(ha_rows count)4554 void THD::set_sent_row_count(ha_rows count)
4555 {
4556 m_sent_row_count= count;
4557 MYSQL_SET_STATEMENT_ROWS_SENT(m_statement_psi, m_sent_row_count);
4558 }
4559
set_examined_row_count(ha_rows count)4560 void THD::set_examined_row_count(ha_rows count)
4561 {
4562 m_examined_row_count= count;
4563 MYSQL_SET_STATEMENT_ROWS_EXAMINED(m_statement_psi, m_examined_row_count);
4564 }
4565
inc_sent_row_count(ha_rows count)4566 void THD::inc_sent_row_count(ha_rows count)
4567 {
4568 m_sent_row_count+= count;
4569 MYSQL_SET_STATEMENT_ROWS_SENT(m_statement_psi, m_sent_row_count);
4570 }
4571
inc_examined_row_count(ha_rows count)4572 void THD::inc_examined_row_count(ha_rows count)
4573 {
4574 m_examined_row_count+= count;
4575 MYSQL_SET_STATEMENT_ROWS_EXAMINED(m_statement_psi, m_examined_row_count);
4576 }
4577
inc_status_created_tmp_disk_tables()4578 void THD::inc_status_created_tmp_disk_tables()
4579 {
4580 assert(!status_var_aggregated);
4581 status_var.created_tmp_disk_tables++;
4582 #ifdef HAVE_PSI_STATEMENT_INTERFACE
4583 PSI_STATEMENT_CALL(inc_statement_created_tmp_disk_tables)(m_statement_psi, 1);
4584 #endif
4585 }
4586
inc_status_created_tmp_tables()4587 void THD::inc_status_created_tmp_tables()
4588 {
4589 assert(!status_var_aggregated);
4590 status_var.created_tmp_tables++;
4591 #ifdef HAVE_PSI_STATEMENT_INTERFACE
4592 PSI_STATEMENT_CALL(inc_statement_created_tmp_tables)(m_statement_psi, 1);
4593 #endif
4594 }
4595
inc_status_select_full_join()4596 void THD::inc_status_select_full_join()
4597 {
4598 assert(!status_var_aggregated);
4599 status_var.select_full_join_count++;
4600 #ifdef HAVE_PSI_STATEMENT_INTERFACE
4601 PSI_STATEMENT_CALL(inc_statement_select_full_join)(m_statement_psi, 1);
4602 #endif
4603 }
4604
inc_status_select_full_range_join()4605 void THD::inc_status_select_full_range_join()
4606 {
4607 assert(!status_var_aggregated);
4608 status_var.select_full_range_join_count++;
4609 #ifdef HAVE_PSI_STATEMENT_INTERFACE
4610 PSI_STATEMENT_CALL(inc_statement_select_full_range_join)(m_statement_psi, 1);
4611 #endif
4612 }
4613
inc_status_select_range()4614 void THD::inc_status_select_range()
4615 {
4616 assert(!status_var_aggregated);
4617 status_var.select_range_count++;
4618 #ifdef HAVE_PSI_STATEMENT_INTERFACE
4619 PSI_STATEMENT_CALL(inc_statement_select_range)(m_statement_psi, 1);
4620 #endif
4621 }
4622
inc_status_select_range_check()4623 void THD::inc_status_select_range_check()
4624 {
4625 assert(!status_var_aggregated);
4626 status_var.select_range_check_count++;
4627 #ifdef HAVE_PSI_STATEMENT_INTERFACE
4628 PSI_STATEMENT_CALL(inc_statement_select_range_check)(m_statement_psi, 1);
4629 #endif
4630 }
4631
inc_status_select_scan()4632 void THD::inc_status_select_scan()
4633 {
4634 assert(!status_var_aggregated);
4635 status_var.select_scan_count++;
4636 #ifdef HAVE_PSI_STATEMENT_INTERFACE
4637 PSI_STATEMENT_CALL(inc_statement_select_scan)(m_statement_psi, 1);
4638 #endif
4639 }
4640
inc_status_sort_merge_passes()4641 void THD::inc_status_sort_merge_passes()
4642 {
4643 assert(!status_var_aggregated);
4644 status_var.filesort_merge_passes++;
4645 #ifdef HAVE_PSI_STATEMENT_INTERFACE
4646 PSI_STATEMENT_CALL(inc_statement_sort_merge_passes)(m_statement_psi, 1);
4647 #endif
4648 }
4649
inc_status_sort_range()4650 void THD::inc_status_sort_range()
4651 {
4652 assert(!status_var_aggregated);
4653 status_var.filesort_range_count++;
4654 #ifdef HAVE_PSI_STATEMENT_INTERFACE
4655 PSI_STATEMENT_CALL(inc_statement_sort_range)(m_statement_psi, 1);
4656 #endif
4657 }
4658
inc_status_sort_rows(ha_rows count)4659 void THD::inc_status_sort_rows(ha_rows count)
4660 {
4661 status_var.filesort_rows+= count;
4662 #ifdef HAVE_PSI_STATEMENT_INTERFACE
4663 PSI_STATEMENT_CALL(inc_statement_sort_rows)(m_statement_psi,
4664 static_cast<ulong>(count));
4665 #endif
4666 }
4667
inc_status_sort_scan()4668 void THD::inc_status_sort_scan()
4669 {
4670 assert(!status_var_aggregated);
4671 status_var.filesort_scan_count++;
4672 #ifdef HAVE_PSI_STATEMENT_INTERFACE
4673 PSI_STATEMENT_CALL(inc_statement_sort_scan)(m_statement_psi, 1);
4674 #endif
4675 }
4676
set_status_no_index_used()4677 void THD::set_status_no_index_used()
4678 {
4679 server_status|= SERVER_QUERY_NO_INDEX_USED;
4680 #ifdef HAVE_PSI_STATEMENT_INTERFACE
4681 PSI_STATEMENT_CALL(set_statement_no_index_used)(m_statement_psi);
4682 #endif
4683 }
4684
set_status_no_good_index_used()4685 void THD::set_status_no_good_index_used()
4686 {
4687 server_status|= SERVER_QUERY_NO_GOOD_INDEX_USED;
4688 #ifdef HAVE_PSI_STATEMENT_INTERFACE
4689 PSI_STATEMENT_CALL(set_statement_no_good_index_used)(m_statement_psi);
4690 #endif
4691 }
4692
set_command(enum enum_server_command command)4693 void THD::set_command(enum enum_server_command command)
4694 {
4695 m_command= command;
4696 #ifdef HAVE_PSI_THREAD_INTERFACE
4697 PSI_STATEMENT_CALL(set_thread_command)(m_command);
4698 #endif
4699 }
4700
4701
set_query(const LEX_CSTRING & query_arg)4702 void THD::set_query(const LEX_CSTRING& query_arg)
4703 {
4704 assert(this == current_thd);
4705 mysql_mutex_lock(&LOCK_thd_query);
4706 m_query_string= query_arg;
4707 mysql_mutex_unlock(&LOCK_thd_query);
4708 }
4709
4710
4711 /**
4712 Set the rewritten query (with passwords obfuscated etc.) on the THD.
4713 Wraps this in the LOCK_thd_query mutex to protect against race conditions
4714 with SHOW PROCESSLIST inspecting that string.
4715
4716 This uses swap() and therefore "steals" the argument from the caller;
4717 the caller MUST take care not to try to use its own string after calling
4718 this function! This is an optimization for mysql_rewrite_query() so we
4719 don't copy its temporary string (which may get very long, up to
4720 @@max_allowed_packet).
4721
4722 Using this outside of mysql_rewrite_query() is almost certainly wrong;
4723 please check with the runtime team!
4724
4725 @param query_arg The rewritten query to use for slow/bin/general logging.
4726 The value will be released in the caller and MUST NOT
4727 be used there after calling this function.
4728 */
swap_rewritten_query(String & query_arg)4729 void THD::swap_rewritten_query(String& query_arg)
4730 {
4731 assert(this == current_thd);
4732
4733 mysql_mutex_lock(&LOCK_thd_query);
4734 m_rewritten_query.mem_free();
4735 m_rewritten_query.swap(query_arg);
4736 // The rewritten query should always be a valid C string, just in case.
4737 (void) m_rewritten_query.c_ptr_safe();
4738 mysql_mutex_unlock(&LOCK_thd_query);
4739 }
4740
4741
4742 /**
4743 Leave explicit LOCK TABLES or prelocked mode and restore value of
4744 transaction sentinel in MDL subsystem.
4745 */
4746
leave_locked_tables_mode()4747 void THD::leave_locked_tables_mode()
4748 {
4749 if (locked_tables_mode == LTM_LOCK_TABLES)
4750 {
4751 /*
4752 When leaving LOCK TABLES mode we have to change the duration of most
4753 of the metadata locks being held, except for HANDLER and GRL locks,
4754 to transactional for them to be properly released at UNLOCK TABLES.
4755 */
4756 mdl_context.set_transaction_duration_for_all_locks();
4757 /*
4758 Make sure we don't release the global read lock and commit blocker
4759 when leaving LTM.
4760 */
4761 global_read_lock.set_explicit_lock_duration(this);
4762 /*
4763 Also ensure that we don't release metadata locks for open HANDLERs
4764 and user-level locks.
4765 */
4766 if (handler_tables_hash.records)
4767 mysql_ha_set_explicit_lock_duration(this);
4768 if (ull_hash.records)
4769 mysql_ull_set_explicit_lock_duration(this);
4770 }
4771 locked_tables_mode= LTM_NONE;
4772 }
4773
get_definer(LEX_USER * definer)4774 void THD::get_definer(LEX_USER *definer)
4775 {
4776 binlog_invoker();
4777 #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
4778 if (slave_thread && has_invoker())
4779 {
4780 definer->user= m_invoker_user;
4781 definer->host= m_invoker_host;
4782 definer->plugin.str= (char *) "";
4783 definer->plugin.length= 0;
4784 definer->auth.str= NULL;
4785 definer->auth.length= 0;
4786 }
4787 else
4788 #endif
4789 get_default_definer(this, definer);
4790 }
4791
4792
4793 /**
4794 Mark transaction to rollback and mark error as fatal to a sub-statement.
4795
4796 @param all TRUE <=> rollback main transaction.
4797 */
4798
mark_transaction_to_rollback(bool all)4799 void THD::mark_transaction_to_rollback(bool all)
4800 {
4801 /*
4802 There is no point in setting is_fatal_sub_stmt_error unless
4803 we are actually in_sub_stmt.
4804 */
4805 if (in_sub_stmt)
4806 is_fatal_sub_stmt_error= true;
4807
4808 transaction_rollback_request= all;
4809
4810 }
4811
4812
set_next_event_pos(const char * _filename,ulonglong _pos)4813 void THD::set_next_event_pos(const char* _filename, ulonglong _pos)
4814 {
4815 char*& filename= binlog_next_event_pos.file_name;
4816 if (filename == NULL)
4817 {
4818 /* First time, allocate maximal buffer */
4819 filename= (char*) my_malloc(key_memory_LOG_POS_COORD,
4820 FN_REFLEN+1, MYF(MY_WME));
4821 if (filename == NULL) return;
4822 }
4823
4824 assert(strlen(_filename) <= FN_REFLEN);
4825 strcpy(filename, _filename);
4826 filename[ FN_REFLEN ]= 0;
4827
4828 binlog_next_event_pos.pos= _pos;
4829 };
4830
clear_next_event_pos()4831 void THD::clear_next_event_pos()
4832 {
4833 if (binlog_next_event_pos.file_name != NULL)
4834 {
4835 my_free(binlog_next_event_pos.file_name);
4836 }
4837 binlog_next_event_pos.file_name= NULL;
4838 binlog_next_event_pos.pos= 0;
4839 };
4840
4841 #ifdef HAVE_REPLICATION
set_currently_executing_gtid_for_slave_thread()4842 void THD::set_currently_executing_gtid_for_slave_thread()
4843 {
4844 /*
4845 This function may be called in four cases:
4846
4847 - From SQL thread while executing Gtid_log_event::do_apply_event
4848
4849 - From an mts worker thread that executes a Gtid_log_event::do_apply_event.
4850
4851 - From an mts worker thread that is processing an old binlog that
4852 is missing Gtid events completely, from gtid_pre_statement_checks().
4853
4854 - From a normal client thread that is executing output from
4855 mysqlbinlog when mysqlbinlog is processing an old binlog file
4856 that is missing Gtid events completely, from
4857 gtid_pre_statement_checks() for a statement that appears after a
4858 BINLOG statement containing a Format_description_log_event
4859 originating from the master.
4860
4861 Because of the last case, we need to add the following conditions to set
4862 currently_executing_gtid.
4863 */
4864 if (system_thread == SYSTEM_THREAD_SLAVE_SQL ||
4865 system_thread == SYSTEM_THREAD_SLAVE_WORKER)
4866 rli_slave->currently_executing_gtid= variables.gtid_next;
4867 }
4868 #endif
4869
set_user_connect(USER_CONN * uc)4870 void THD::set_user_connect(USER_CONN *uc)
4871 {
4872 DBUG_ENTER("THD::set_user_connect");
4873
4874 m_user_connect= uc;
4875
4876 DBUG_VOID_RETURN;
4877 }
4878
increment_user_connections_counter()4879 void THD::increment_user_connections_counter()
4880 {
4881 DBUG_ENTER("THD::increment_user_connections_counter");
4882
4883 m_user_connect->connections++;
4884
4885 DBUG_VOID_RETURN;
4886 }
4887
decrement_user_connections_counter()4888 void THD::decrement_user_connections_counter()
4889 {
4890 DBUG_ENTER("THD::decrement_user_connections_counter");
4891
4892 assert(m_user_connect->connections > 0);
4893 m_user_connect->connections--;
4894
4895 DBUG_VOID_RETURN;
4896 }
4897
increment_con_per_hour_counter()4898 void THD::increment_con_per_hour_counter()
4899 {
4900 DBUG_ENTER("THD::increment_con_per_hour_counter");
4901
4902 m_user_connect->conn_per_hour++;
4903
4904 DBUG_VOID_RETURN;
4905 }
4906
increment_updates_counter()4907 void THD::increment_updates_counter()
4908 {
4909 DBUG_ENTER("THD::increment_updates_counter");
4910
4911 m_user_connect->updates++;
4912
4913 DBUG_VOID_RETURN;
4914 }
4915
increment_questions_counter()4916 void THD::increment_questions_counter()
4917 {
4918 DBUG_ENTER("THD::increment_questions_counter");
4919
4920 m_user_connect->questions++;
4921
4922 DBUG_VOID_RETURN;
4923 }
4924
4925 /*
4926 Reset per-hour user resource limits when it has been more than
4927 an hour since they were last checked
4928
4929 SYNOPSIS:
4930 time_out_user_resource_limits()
4931
4932 NOTE:
4933 This assumes that the LOCK_user_conn mutex has been acquired, so it is
4934 safe to test and modify members of the USER_CONN structure.
4935 */
time_out_user_resource_limits()4936 void THD::time_out_user_resource_limits()
4937 {
4938 mysql_mutex_assert_owner(&LOCK_user_conn);
4939 ulonglong check_time= start_utime;
4940 DBUG_ENTER("time_out_user_resource_limits");
4941
4942 /* If more than a hour since last check, reset resource checking */
4943 if (check_time - m_user_connect->reset_utime >= 3600000000LL)
4944 {
4945 m_user_connect->questions=1;
4946 m_user_connect->updates=0;
4947 m_user_connect->conn_per_hour=0;
4948 m_user_connect->reset_utime= check_time;
4949 }
4950
4951 DBUG_VOID_RETURN;
4952 }
4953
4954
4955 #ifndef NDEBUG
assert_plan_is_locked_if_other() const4956 void THD::Query_plan::assert_plan_is_locked_if_other() const
4957 {
4958 if (current_thd != thd)
4959 mysql_mutex_assert_owner(&thd->LOCK_query_plan);
4960 }
4961 #endif
4962
set_query_plan(enum_sql_command sql_cmd,LEX * lex_arg,bool ps)4963 void THD::Query_plan::set_query_plan(enum_sql_command sql_cmd,
4964 LEX *lex_arg, bool ps)
4965 {
4966 assert(current_thd == thd);
4967
4968 // No need to grab mutex for repeated (SQLCOM_END, NULL, false).
4969 if (sql_command == sql_cmd &&
4970 lex == lex_arg &&
4971 is_ps == ps)
4972 {
4973 return;
4974 }
4975
4976 thd->lock_query_plan();
4977 sql_command= sql_cmd;
4978 lex= lex_arg;
4979 is_ps= ps;
4980 thd->unlock_query_plan();
4981 }
4982
4983
set_modification_plan(Modification_plan * plan_arg)4984 void THD::Query_plan::set_modification_plan(Modification_plan *plan_arg)
4985 {
4986 assert(current_thd == thd);
4987 mysql_mutex_assert_owner(&thd->LOCK_query_plan);
4988 modification_plan= plan_arg;
4989 }
4990
4991 /**
4992 Push an error message into MySQL diagnostic area with line
4993 and position information.
4994
4995 This function provides semantic action implementers with a way
4996 to push the famous "You have a syntax error near..." error
4997 message into the diagnostic area, which is normally produced only if
4998 a parse error is discovered internally by the Bison generated
4999 parser.
5000
5001 @note Parse-time only function!
5002
5003 @param thd YYTHD
5004 @param location YYSTYPE object: error position
5005 @param s error message: NULL default means ER(ER_SYNTAX_ERROR)
5006 */
5007
parse_error_at(const YYLTYPE & location,const char * s)5008 void THD::parse_error_at(const YYLTYPE &location, const char *s)
5009 {
5010 uint lineno= location.raw.start ?
5011 m_parser_state->m_lip.get_lineno(location.raw.start) : 1;
5012 const char *pos= location.raw.start ? location.raw.start : "";
5013 ErrConvString err(pos, variables.character_set_client);
5014 my_printf_error(ER_PARSE_ERROR, ER(ER_PARSE_ERROR), MYF(0),
5015 s ? s : ER(ER_SYNTAX_ERROR), err.ptr(), lineno);
5016 }
5017
send_result_metadata(List<Item> * list,uint flags)5018 bool THD::send_result_metadata(List<Item> *list, uint flags)
5019 {
5020 DBUG_ENTER("send_result_metadata");
5021 List_iterator_fast<Item> it(*list);
5022 Item *item;
5023 uchar buff[MAX_FIELD_WIDTH];
5024 String tmp((char *) buff, sizeof(buff), &my_charset_bin);
5025
5026 if (m_protocol->start_result_metadata(list->elements, flags,
5027 variables.character_set_results))
5028 goto err;
5029
5030 #ifdef EMBEDDED_LIBRARY // bootstrap file handling
5031 if(!mysql)
5032 DBUG_RETURN(false);
5033 #endif
5034
5035 while ((item= it++))
5036 {
5037 Send_field field;
5038 item->make_field(&field);
5039 #ifndef EMBEDDED_LIBRARY
5040 m_protocol->start_row();
5041 if (m_protocol->send_field_metadata(&field,
5042 item->charset_for_protocol()))
5043 goto err;
5044 if (flags & Protocol::SEND_DEFAULTS)
5045 item->send(m_protocol, &tmp);
5046 if (m_protocol->end_row())
5047 DBUG_RETURN(true);
5048 #else
5049 if(m_protocol->send_field_metadata(&field, item->charset_for_protocol()))
5050 goto err;
5051 if (flags & Protocol::SEND_DEFAULTS)
5052 get_protocol_classic()->send_string_metadata(item->val_str(&tmp));
5053 #endif
5054 }
5055
5056 DBUG_RETURN(m_protocol->end_result_metadata());
5057
5058 err:
5059 my_error(ER_OUT_OF_RESOURCES, MYF(0)); /* purecov: inspected */
5060 DBUG_RETURN(1); /* purecov: inspected */
5061 }
5062
send_result_set_row(List<Item> * row_items)5063 bool THD::send_result_set_row(List<Item> *row_items)
5064 {
5065 char buffer[MAX_FIELD_WIDTH];
5066 String str_buffer(buffer, sizeof (buffer), &my_charset_bin);
5067 List_iterator_fast<Item> it(*row_items);
5068
5069 DBUG_ENTER("send_result_set_row");
5070
5071 for (Item *item= it++; item; item= it++)
5072 {
5073 if (item->send(m_protocol, &str_buffer) || is_error())
5074 DBUG_RETURN(true);
5075 /*
5076 Reset str_buffer to its original state, as it may have been altered in
5077 Item::send().
5078 */
5079 str_buffer.set(buffer, sizeof(buffer), &my_charset_bin);
5080 }
5081 DBUG_RETURN(false);
5082 }
5083
send_statement_status()5084 void THD::send_statement_status()
5085 {
5086 DBUG_ENTER("send_statement_status");
5087 assert(!get_stmt_da()->is_sent());
5088 bool error= false;
5089 Diagnostics_area *da= get_stmt_da();
5090
5091 /* Can not be true, but do not take chances in production. */
5092 if (da->is_sent())
5093 DBUG_VOID_RETURN;
5094
5095 switch (da->status())
5096 {
5097 case Diagnostics_area::DA_ERROR:
5098 /* The query failed, send error to log and abort bootstrap. */
5099 error= m_protocol->send_error(
5100 da->mysql_errno(), da->message_text(), da->returned_sqlstate());
5101 break;
5102 case Diagnostics_area::DA_EOF:
5103 error= m_protocol->send_eof(
5104 server_status, da->last_statement_cond_count());
5105 break;
5106 case Diagnostics_area::DA_OK:
5107 error= m_protocol->send_ok(
5108 server_status, da->last_statement_cond_count(),
5109 da->affected_rows(), da->last_insert_id(), da->message_text());
5110 break;
5111 case Diagnostics_area::DA_DISABLED:
5112 break;
5113 case Diagnostics_area::DA_EMPTY:
5114 default:
5115 assert(0);
5116 error= m_protocol->send_ok(server_status, 0, 0, 0, NULL);
5117 break;
5118 }
5119 if (!error)
5120 da->set_is_sent(true);
5121 DBUG_VOID_RETURN;
5122 }
5123
claim_memory_ownership()5124 void THD::claim_memory_ownership()
5125 {
5126 /*
5127 Ownership of the THD object is transfered to this thread.
5128 This happens typically:
5129 - in the event scheduler,
5130 when the scheduler thread creates a work item and
5131 starts a worker thread to run it
5132 - in the main thread, when the code that accepts a new
5133 network connection creates a work item and starts a
5134 connection thread to run it.
5135 Accounting for memory statistics needs to be told
5136 that memory allocated by thread X now belongs to thread Y,
5137 so that statistics by thread/account/user/host are accurate.
5138 Inspect every piece of memory allocated in THD,
5139 and call PSI_MEMORY_CALL(memory_claim)().
5140 */
5141 #ifdef HAVE_PSI_MEMORY_INTERFACE
5142 claim_root(&main_mem_root);
5143 my_claim(m_token_array);
5144 Protocol_classic *p= get_protocol_classic();
5145 if (p != NULL)
5146 p->claim_memory_ownership();
5147 session_tracker.claim_memory_ownership();
5148 session_sysvar_res_mgr.claim_memory_ownership();
5149 my_hash_claim(&user_vars);
5150 #if defined(ENABLED_DEBUG_SYNC)
5151 debug_sync_claim_memory_ownership(this);
5152 #endif /* defined(ENABLED_DEBUG_SYNC) */
5153 get_transaction()->claim_memory_ownership();
5154 stmt_map.claim_memory_ownership();
5155 #endif /* HAVE_PSI_MEMORY_INTERFACE */
5156 }
5157
5158
rpl_detach_engine_ha_data()5159 void THD::rpl_detach_engine_ha_data()
5160 {
5161 #ifdef HAVE_REPLICATION
5162 Relay_log_info *rli=
5163 is_binlog_applier() ? rli_fake : (slave_thread ? rli_slave : NULL);
5164
5165 assert(!rli_fake || !rli_fake-> is_engine_ha_data_detached);
5166 assert(!rli_slave || !rli_slave->is_engine_ha_data_detached);
5167
5168 if (rli)
5169 rli->detach_engine_ha_data(this);
5170 #endif
5171 };
5172
rpl_reattach_engine_ha_data()5173 void THD::rpl_reattach_engine_ha_data()
5174 {
5175 #ifdef HAVE_REPLICATION
5176 Relay_log_info *rli =
5177 is_binlog_applier() ? rli_fake : (slave_thread ? rli_slave : NULL);
5178
5179 assert(!rli_fake || !rli_fake->is_engine_ha_data_detached);
5180 assert(!rli_slave || !rli_slave->is_engine_ha_data_detached);
5181
5182 if (rli) rli->reattach_engine_ha_data(this);
5183 #endif
5184 }
5185
rpl_unflag_detached_engine_ha_data()5186 bool THD::rpl_unflag_detached_engine_ha_data()
5187 {
5188 #ifdef HAVE_REPLICATION
5189 Relay_log_info *rli=
5190 is_binlog_applier() ? rli_fake : (slave_thread ? rli_slave : NULL);
5191 return rli ? rli->unflag_detached_engine_ha_data() : false;
5192 #else
5193 return false;
5194 #endif
5195 }
5196
5197 /**
5198 Determine if binlogging is disabled for this session
5199 @retval 0 if the current statement binlogging is disabled
5200 (could be because of binlog closed/binlog option
5201 is set to false).
5202 @retval 1 if the current statement will be binlogged
5203 */
is_current_stmt_binlog_disabled() const5204 bool THD::is_current_stmt_binlog_disabled() const
5205 {
5206 return (!(variables.option_bits & OPTION_BIN_LOG) ||
5207 !mysql_bin_log.is_open());
5208 }
5209
is_current_stmt_binlog_row_enabled_with_write_set_extraction() const5210 bool THD::is_current_stmt_binlog_row_enabled_with_write_set_extraction() const
5211 {
5212 return ((variables.transaction_write_set_extraction != HASH_ALGORITHM_OFF) &&
5213 is_current_stmt_binlog_format_row() &&
5214 !is_current_stmt_binlog_disabled());
5215 }
5216