~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/session.cc

  • Committer: Toru Maesaka
  • Date: 2008-12-17 07:16:37 UTC
  • mto: (685.1.40 devel) (713.1.5 devel)
  • mto: This revision was merged to the branch mainline in revision 713.
  • Revision ID: dev@torum.net-20081217071637-7j9040w7lpms77r2
Removed my_time() and added error checking

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (C) 2000-2006 MySQL AB
2
 
 
3
 
   This program is free software; you can redistribute it and/or modify
4
 
   it under the terms of the GNU General Public License as published by
5
 
   the Free Software Foundation; version 2 of the License.
6
 
 
7
 
   This program is distributed in the hope that it will be useful,
8
 
   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 
   GNU General Public License for more details.
11
 
 
12
 
   You should have received a copy of the GNU General Public License
13
 
   along with this program; if not, write to the Free Software
14
 
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
 
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 
3
 *
 
4
 *  Copyright (C) 2008 Sun Microsystems
 
5
 *
 
6
 *  This program is free software; you can redistribute it and/or modify
 
7
 *  it under the terms of the GNU General Public License as published by
 
8
 *  the Free Software Foundation; version 2 of the License.
 
9
 *
 
10
 *  This program is distributed in the hope that it will be useful,
 
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 *  GNU General Public License for more details.
 
14
 *
 
15
 *  You should have received a copy of the GNU General Public License
 
16
 *  along with this program; if not, write to the Free Software
 
17
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
18
 */
15
19
 
16
20
 
17
21
/*****************************************************************************
18
22
**
19
 
** This file implements classes defined in sql_class.h
 
23
** This file implements classes defined in session.h
20
24
** Especially the classes to handle a result from a select
21
25
**
22
26
*****************************************************************************/
23
27
#include <drizzled/server_includes.h>
24
 
#include "rpl_rli.h"
25
 
#include "rpl_record.h"
26
 
#include "log_event.h"
 
28
#include <drizzled/session.h>
 
29
#include <drizzled/replication/rli.h>
 
30
#include <drizzled/replication/record.h>
 
31
#include <drizzled/log_event.h>
27
32
#include <sys/stat.h>
28
33
#include <mysys/thr_alarm.h>
29
34
#include <mysys/mysys_err.h>
30
 
#include <drizzled/drizzled_error_messages.h>
 
35
#include <drizzled/error.h>
 
36
#include <drizzled/query_id.h>
 
37
#include <drizzled/data_home.h>
 
38
#include <drizzled/sql_base.h>
 
39
#include <drizzled/lock.h>
 
40
#include <drizzled/item/cache.h>
 
41
#include <drizzled/item/float.h>
 
42
#include <drizzled/item/return_int.h>
 
43
#include <drizzled/item/empty_string.h>
31
44
 
 
45
extern scheduler_functions thread_scheduler;
32
46
/*
33
47
  The following is used to initialise Table_ident with a internal
34
48
  table name
36
50
char internal_table_name[2]= "*";
37
51
char empty_c_string[1]= {0};    /* used for not defined db */
38
52
 
39
 
const char * const THD::DEFAULT_WHERE= "field list";
 
53
const char * const Session::DEFAULT_WHERE= "field list";
 
54
extern pthread_key_t THR_Session;
 
55
extern pthread_key_t THR_Mem_root;
40
56
 
41
57
 
42
58
/*****************************************************************************
55
71
template class List_iterator<Alter_column>;
56
72
#endif
57
73
 
 
74
 
58
75
/****************************************************************************
59
76
** User variables
60
77
****************************************************************************/
85
102
  Construct an (almost) deep copy of this key. Only those
86
103
  elements that are known to never change are not copied.
87
104
  If out of memory, a partial copy is returned and an error is set
88
 
  in THD.
 
105
  in Session.
89
106
*/
90
107
 
91
108
Key::Key(const Key &rhs, MEM_ROOT *mem_root)
102
119
  Construct an (almost) deep copy of this foreign key. Only those
103
120
  elements that are known to never change are not copied.
104
121
  If out of memory, a partial copy is returned and an error is set
105
 
  in THD.
 
122
  in Session.
106
123
*/
107
124
 
108
125
Foreign_key::Foreign_key(const Foreign_key &rhs, MEM_ROOT *mem_root)
183
200
}
184
201
 
185
202
 
 
203
/*
 
204
  Check if the foreign key options are compatible with columns
 
205
  on which the FK is created.
 
206
 
 
207
  RETURN
 
208
    0   Key valid
 
209
    1   Key invalid
 
210
*/
 
211
bool Foreign_key::validate(List<Create_field> &table_fields)
 
212
{
 
213
  Create_field  *sql_field;
 
214
  Key_part_spec *column;
 
215
  List_iterator<Key_part_spec> cols(columns);
 
216
  List_iterator<Create_field> it(table_fields);
 
217
  while ((column= cols++))
 
218
  {
 
219
    it.rewind();
 
220
    while ((sql_field= it++) &&
 
221
           my_strcasecmp(system_charset_info,
 
222
                         column->field_name.str,
 
223
                         sql_field->field_name)) {}
 
224
    if (!sql_field)
 
225
    {
 
226
      my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), column->field_name.str);
 
227
      return true;
 
228
    }
 
229
    if (type == Key::FOREIGN_KEY && sql_field->vcol_info)
 
230
    {
 
231
      if (delete_opt == FK_OPTION_SET_NULL)
 
232
      {
 
233
        my_error(ER_WRONG_FK_OPTION_FOR_VIRTUAL_COLUMN, MYF(0),
 
234
                 "ON DELETE SET NULL");
 
235
        return true;
 
236
      }
 
237
      if (update_opt == FK_OPTION_SET_NULL)
 
238
      {
 
239
        my_error(ER_WRONG_FK_OPTION_FOR_VIRTUAL_COLUMN, MYF(0),
 
240
                 "ON UPDATE SET NULL");
 
241
        return true;
 
242
      }
 
243
      if (update_opt == FK_OPTION_CASCADE)
 
244
      {
 
245
        my_error(ER_WRONG_FK_OPTION_FOR_VIRTUAL_COLUMN, MYF(0),
 
246
                 "ON UPDATE CASCADE");
 
247
        return true;
 
248
      }
 
249
    }
 
250
  }
 
251
  return false;
 
252
}
 
253
 
 
254
 
186
255
/****************************************************************************
187
256
** Thread specific functions
188
257
****************************************************************************/
200
269
extern "C" int mysql_tmpfile(const char *prefix)
201
270
{
202
271
  char filename[FN_REFLEN];
203
 
  File fd = create_temp_file(filename, mysql_tmpdir, prefix,
204
 
                             O_CREAT | O_EXCL | O_RDWR | O_TEMPORARY,
 
272
  File fd = create_temp_file(filename, drizzle_tmpdir, prefix,
 
273
                             O_CREAT | O_EXCL | O_RDWR,
205
274
                             MYF(MY_WME));
206
275
  if (fd >= 0) {
207
 
    /*
208
 
      This can be removed once the following bug is fixed:
209
 
      Bug #28903  create_temp_file() doesn't honor O_TEMPORARY option
210
 
                  (file not removed) (Unix)
211
 
    */
212
276
    unlink(filename);
213
277
  }
214
278
 
217
281
 
218
282
 
219
283
extern "C"
220
 
int thd_in_lock_tables(const THD *thd)
221
 
{
222
 
  return test(thd->in_lock_tables);
223
 
}
224
 
 
225
 
 
226
 
extern "C"
227
 
int thd_tablespace_op(const THD *thd)
228
 
{
229
 
  return test(thd->tablespace_op);
230
 
}
231
 
 
232
 
 
233
 
extern "C"
234
 
const char *set_thd_proc_info(THD *thd, const char *info,
235
 
                              const char *calling_function __attribute__((unused)),
236
 
                              const char *calling_file __attribute__((unused)),
237
 
                              const unsigned int calling_line __attribute__((unused)))
238
 
{
239
 
  const char *old_info= thd->get_proc_info();
240
 
  thd->set_proc_info(info);
241
 
  return old_info;
242
 
}
243
 
 
244
 
extern "C"
245
 
void **thd_ha_data(const THD *thd, const struct handlerton *hton)
246
 
{
247
 
  return (void **) &thd->ha_data[hton->slot].ha_ptr;
248
 
}
249
 
 
250
 
extern "C"
251
 
int64_t thd_test_options(const THD *thd, int64_t test_options)
252
 
{
253
 
  return thd->options & test_options;
254
 
}
255
 
 
256
 
extern "C"
257
 
int thd_sql_command(const THD *thd)
258
 
{
259
 
  return (int) thd->lex->sql_command;
260
 
}
261
 
 
262
 
extern "C"
263
 
int thd_tx_isolation(const THD *thd)
264
 
{
265
 
  return (int) thd->variables.tx_isolation;
266
 
}
267
 
 
268
 
extern "C"
269
 
void thd_inc_row_count(THD *thd)
270
 
{
271
 
  thd->row_count++;
272
 
}
273
 
 
274
 
/**
275
 
  Clear this diagnostics area. 
 
284
int session_in_lock_tables(const Session *session)
 
285
{
 
286
  return test(session->in_lock_tables);
 
287
}
 
288
 
 
289
 
 
290
extern "C"
 
291
int session_tablespace_op(const Session *session)
 
292
{
 
293
  return test(session->tablespace_op);
 
294
}
 
295
 
 
296
 
 
297
/**
 
298
   Set the process info field of the Session structure.
 
299
 
 
300
   This function is used by plug-ins. Internally, the
 
301
   Session::set_proc_info() function should be used.
 
302
 
 
303
   @see Session::set_proc_info
 
304
 */
 
305
extern "C" void
 
306
set_session_proc_info(Session *session, const char *info)
 
307
{
 
308
  session->set_proc_info(info);
 
309
}
 
310
 
 
311
extern "C"
 
312
const char *get_session_proc_info(Session *session)
 
313
{
 
314
  return session->get_proc_info();
 
315
}
 
316
 
 
317
extern "C"
 
318
void **session_ha_data(const Session *session, const struct handlerton *hton)
 
319
{
 
320
  return (void **) &session->ha_data[hton->slot].ha_ptr;
 
321
}
 
322
 
 
323
extern "C"
 
324
int64_t session_test_options(const Session *session, int64_t test_options)
 
325
{
 
326
  return session->options & test_options;
 
327
}
 
328
 
 
329
extern "C"
 
330
int session_sql_command(const Session *session)
 
331
{
 
332
  return (int) session->lex->sql_command;
 
333
}
 
334
 
 
335
extern "C"
 
336
int session_tx_isolation(const Session *session)
 
337
{
 
338
  return (int) session->variables.tx_isolation;
 
339
}
 
340
 
 
341
extern "C"
 
342
void session_inc_row_count(Session *session)
 
343
{
 
344
  session->row_count++;
 
345
}
 
346
 
 
347
/**
 
348
  Clear this diagnostics area.
276
349
 
277
350
  Normally called at the end of a statement.
278
351
*/
300
373
*/
301
374
 
302
375
void
303
 
Diagnostics_area::set_ok_status(THD *thd, ha_rows affected_rows_arg,
 
376
Diagnostics_area::set_ok_status(Session *session, ha_rows affected_rows_arg,
304
377
                                uint64_t last_insert_id_arg,
305
378
                                const char *message_arg)
306
379
{
313
386
    return;
314
387
  /** Only allowed to report success if has not yet reported an error */
315
388
 
316
 
  m_server_status= thd->server_status;
317
 
  m_total_warn_count= thd->total_warn_count;
 
389
  m_server_status= session->server_status;
 
390
  m_total_warn_count= session->total_warn_count;
318
391
  m_affected_rows= affected_rows_arg;
319
392
  m_last_insert_id= last_insert_id_arg;
320
393
  if (message_arg)
321
 
    strmake(m_message, message_arg, sizeof(m_message) - 1);
 
394
    strncpy(m_message, message_arg, sizeof(m_message) - 1);
322
395
  else
323
396
    m_message[0]= '\0';
324
397
  m_status= DA_OK;
330
403
*/
331
404
 
332
405
void
333
 
Diagnostics_area::set_eof_status(THD *thd)
 
406
Diagnostics_area::set_eof_status(Session *session)
334
407
{
335
408
  /** Only allowed to report eof if has not yet reported an error */
336
409
 
342
415
  if (is_error() || is_disabled())
343
416
    return;
344
417
 
345
 
  m_server_status= thd->server_status;
 
418
  m_server_status= session->server_status;
346
419
  /*
347
420
    If inside a stored procedure, do not return the total
348
421
    number of warnings, since they are not available to the client
349
422
    anyway.
350
423
  */
351
 
  m_total_warn_count= thd->total_warn_count;
 
424
  m_total_warn_count= session->total_warn_count;
352
425
 
353
426
  m_status= DA_EOF;
354
427
}
358
431
*/
359
432
 
360
433
void
361
 
Diagnostics_area::set_error_status(THD *thd __attribute__((unused)),
 
434
Diagnostics_area::set_error_status(Session *session __attribute__((unused)),
362
435
                                   uint32_t sql_errno_arg,
363
436
                                   const char *message_arg)
364
437
{
376
449
    return;
377
450
 
378
451
  m_sql_errno= sql_errno_arg;
379
 
  strmake(m_message, message_arg, sizeof(m_message) - 1);
 
452
  strncpy(m_message, message_arg, sizeof(m_message) - 1);
380
453
 
381
454
  m_status= DA_ERROR;
382
455
}
398
471
}
399
472
 
400
473
 
401
 
THD::THD()
 
474
Session::Session()
402
475
   :Statement(&main_lex, &main_mem_root,
403
476
              /* statement id */ 0),
404
477
   Open_tables_state(refresh_version), rli_fake(0),
405
478
   lock_id(&main_lock_id),
406
 
   user_time(0), in_sub_stmt(0),
 
479
   user_time(0),
407
480
   binlog_table_maps(0), binlog_flags(0UL),
408
481
   arg_of_last_insert_id_function(false),
409
482
   first_successful_insert_id_in_prev_stmt(0),
410
 
   first_successful_insert_id_in_prev_stmt_for_binlog(0),
411
483
   first_successful_insert_id_in_cur_stmt(0),
412
 
   stmt_depends_on_first_successful_insert_id_in_prev_stmt(false),
413
484
   global_read_lock(0),
414
485
   is_fatal_error(0),
415
486
   transaction_rollback_request(0),
416
487
   is_fatal_sub_stmt_error(0),
417
 
   rand_used(0),
418
 
   time_zone_used(0),
419
488
   in_lock_tables(0),
420
 
   bootstrap(0),
421
489
   derived_tables_processing(false),
422
490
   m_lip(NULL)
423
491
{
446
514
  limit_found_rows= 0;
447
515
  row_count_func= -1;
448
516
  statement_id_counter= 0UL;
449
 
  // Must be reset to handle error with THD's created for init of mysqld
 
517
  // Must be reset to handle error with Session's created for init of mysqld
450
518
  lex->current_select= 0;
451
519
  start_time=(time_t) 0;
452
520
  start_utime= 0L;
455
523
  slave_thread = 0;
456
524
  memset(&variables, 0, sizeof(variables));
457
525
  thread_id= 0;
458
 
  one_shot_set= 0;
459
526
  file_id = 0;
460
527
  query_id= 0;
461
528
  warn_id= 0;
462
529
  db_charset= global_system_variables.collation_database;
463
530
  memset(ha_data, 0, sizeof(ha_data));
 
531
  replication_data= 0;
464
532
  mysys_var=0;
465
533
  binlog_evt_union.do_union= false;
466
 
  dbug_sentry=THD_SENTRY_MAGIC;
467
 
  net.vio=0;
 
534
  dbug_sentry=Session_SENTRY_MAGIC;
 
535
  net.vio= 0;
468
536
  client_capabilities= 0;                       // minimalistic client
469
537
  system_thread= NON_SYSTEM_THREAD;
470
538
  cleanup_done= abort_on_warning= no_warnings_for_error= 0;
475
543
 
476
544
  /* Variables with default values */
477
545
  proc_info="login";
478
 
  where= THD::DEFAULT_WHERE;
 
546
  where= Session::DEFAULT_WHERE;
479
547
  server_id = ::server_id;
480
 
  slave_net = 0;
 
548
  slave_net= NULL;
481
549
  command=COM_CONNECT;
482
550
  *scramble= '\0';
483
551
 
500
568
  protocol= &protocol_text;                     // Default protocol
501
569
  protocol_text.init(this);
502
570
 
 
571
  const Query_id& query_id= Query_id::get_query_id();
503
572
  tablespace_op= false;
504
573
  tmp= sql_rnd();
505
 
  randominit(&rand, tmp + (ulong) &rand, tmp + (ulong) ::global_query_id);
 
574
  randominit(&rand, tmp + (ulong) &rand, tmp + query_id.value());
506
575
  substitute_null_with_insert_id = false;
507
576
  thr_lock_info_init(&lock_info); /* safety: will be reset after start */
508
577
  thr_lock_owner_init(&main_lock_id, &lock_info);
511
580
}
512
581
 
513
582
 
514
 
void THD::push_internal_handler(Internal_error_handler *handler)
 
583
void Session::push_internal_handler(Internal_error_handler *handler)
515
584
{
516
585
  /*
517
586
    TODO: The current implementation is limited to 1 handler at a time only.
518
 
    THD and sp_rcontext need to be modified to use a common handler stack.
 
587
    Session and sp_rcontext need to be modified to use a common handler stack.
519
588
  */
520
589
  assert(m_internal_handler == NULL);
521
590
  m_internal_handler= handler;
522
591
}
523
592
 
524
593
 
525
 
bool THD::handle_error(uint32_t sql_errno, const char *message,
 
594
bool Session::handle_error(uint32_t sql_errno, const char *message,
526
595
                       DRIZZLE_ERROR::enum_warning_level level)
527
596
{
528
597
  if (m_internal_handler)
534
603
}
535
604
 
536
605
 
537
 
void THD::pop_internal_handler()
 
606
void Session::pop_internal_handler()
538
607
{
539
608
  assert(m_internal_handler != NULL);
540
609
  m_internal_handler= NULL;
541
610
}
542
611
 
543
 
extern "C"
544
 
void *thd_alloc(DRIZZLE_THD thd, unsigned int size)
545
 
{
546
 
  return thd->alloc(size);
547
 
}
548
 
 
549
 
extern "C"
550
 
void *thd_calloc(DRIZZLE_THD thd, unsigned int size)
551
 
{
552
 
  return thd->calloc(size);
553
 
}
554
 
 
555
 
extern "C"
556
 
char *thd_strdup(DRIZZLE_THD thd, const char *str)
557
 
{
558
 
  return thd->strdup(str);
559
 
}
560
 
 
561
 
extern "C"
562
 
char *thd_strmake(DRIZZLE_THD thd, const char *str, unsigned int size)
563
 
{
564
 
  return thd->strmake(str, size);
565
 
}
566
 
 
567
 
extern "C"
568
 
LEX_STRING *thd_make_lex_string(THD *thd, LEX_STRING *lex_str,
569
 
                                const char *str, unsigned int size,
570
 
                                int allocate_lex_string)
571
 
{
572
 
  return thd->make_lex_string(lex_str, str, size,
573
 
                              (bool) allocate_lex_string);
574
 
}
575
 
 
576
 
extern "C"
577
 
void *thd_memdup(DRIZZLE_THD thd, const void* str, unsigned int size)
578
 
{
579
 
  return thd->memdup(str, size);
580
 
}
581
 
 
582
 
extern "C"
583
 
void thd_get_xid(const DRIZZLE_THD thd, DRIZZLE_XID *xid)
584
 
{
585
 
  *xid = *(DRIZZLE_XID *) &thd->transaction.xid_state.xid;
586
 
}
 
612
#if defined(__cplusplus)
 
613
extern "C" {
 
614
#endif
 
615
 
 
616
void *session_alloc(Session *session, unsigned int size)
 
617
{
 
618
  return session->alloc(size);
 
619
}
 
620
 
 
621
void *session_calloc(Session *session, unsigned int size)
 
622
{
 
623
  return session->calloc(size);
 
624
}
 
625
 
 
626
char *session_strdup(Session *session, const char *str)
 
627
{
 
628
  return session->strdup(str);
 
629
}
 
630
 
 
631
char *session_strmake(Session *session, const char *str, unsigned int size)
 
632
{
 
633
  return session->strmake(str, size);
 
634
}
 
635
 
 
636
void *session_memdup(Session *session, const void* str, unsigned int size)
 
637
{
 
638
  return session->memdup(str, size);
 
639
}
 
640
 
 
641
void session_get_xid(const Session *session, DRIZZLE_XID *xid)
 
642
{
 
643
  *xid = *(DRIZZLE_XID *) &session->transaction.xid_state.xid;
 
644
}
 
645
 
 
646
#if defined(__cplusplus)
 
647
}
 
648
#endif
587
649
 
588
650
/*
589
651
  Init common variables that has to be reset on start and on change_user
590
652
*/
591
653
 
592
 
void THD::init(void)
 
654
void Session::init(void)
593
655
{
594
656
  pthread_mutex_lock(&LOCK_global_system_variables);
595
 
  plugin_thdvar_init(this);
596
 
  variables.time_format= date_time_format_copy((THD*) 0,
 
657
  plugin_sessionvar_init(this);
 
658
  variables.time_format= date_time_format_copy((Session*) 0,
597
659
                                               variables.time_format);
598
 
  variables.date_format= date_time_format_copy((THD*) 0,
 
660
  variables.date_format= date_time_format_copy((Session*) 0,
599
661
                                               variables.date_format);
600
 
  variables.datetime_format= date_time_format_copy((THD*) 0,
 
662
  variables.datetime_format= date_time_format_copy((Session*) 0,
601
663
                                                   variables.datetime_format);
602
664
  /*
603
665
    variables= global_system_variables above has reset
607
669
  variables.pseudo_thread_id= thread_id;
608
670
  pthread_mutex_unlock(&LOCK_global_system_variables);
609
671
  server_status= SERVER_STATUS_AUTOCOMMIT;
610
 
  options= thd_startup_options;
 
672
  options= session_startup_options;
611
673
 
612
674
  if (variables.max_join_size == HA_POS_ERROR)
613
675
    options |= OPTION_BIG_SELECTS;
624
686
  memset(warn_count, 0, sizeof(warn_count));
625
687
  total_warn_count= 0;
626
688
  update_charset();
627
 
  reset_current_stmt_binlog_row_based();
628
689
  memset(&status_var, 0, sizeof(status_var));
629
690
}
630
691
 
631
692
 
632
693
/*
633
 
  Init THD for query processing.
 
694
  Init Session for query processing.
634
695
  This has to be called once before we call mysql_parse.
635
 
  See also comments in sql_class.h.
 
696
  See also comments in session.h.
636
697
*/
637
698
 
638
 
void THD::init_for_queries()
 
699
void Session::init_for_queries()
639
700
{
640
 
  set_time(); 
 
701
  set_time();
641
702
  ha_enable_transaction(this,true);
642
703
 
643
704
  reset_root_defaults(mem_root, variables.query_alloc_block_size,
646
707
                      variables.trans_alloc_block_size,
647
708
                      variables.trans_prealloc_size);
648
709
  transaction.xid_state.xid.null();
649
 
  transaction.xid_state.in_thd=1;
 
710
  transaction.xid_state.in_session=1;
650
711
}
651
712
 
652
713
 
653
714
/* Do operations that may take a long time */
654
715
 
655
 
void THD::cleanup(void)
 
716
void Session::cleanup(void)
656
717
{
657
718
  assert(cleanup_done == 0);
658
719
 
679
740
  free((char*) variables.time_format);
680
741
  free((char*) variables.date_format);
681
742
  free((char*) variables.datetime_format);
682
 
  
 
743
 
683
744
  if (global_read_lock)
684
745
    unlock_global_read_lock(this);
685
746
 
687
748
  return;
688
749
}
689
750
 
690
 
THD::~THD()
 
751
Session::~Session()
691
752
{
692
 
  THD_CHECK_SENTRY(this);
693
 
  /* Ensure that no one is using THD */
 
753
  Session_CHECK_SENTRY(this);
 
754
  /* Ensure that no one is using Session */
694
755
  pthread_mutex_lock(&LOCK_delete);
695
756
  pthread_mutex_unlock(&LOCK_delete);
696
757
  add_to_status(&global_status_var, &status_var);
705
766
    cleanup();
706
767
 
707
768
  ha_close_connection(this);
708
 
  plugin_thdvar_cleanup(this);
 
769
  plugin_sessionvar_cleanup(this);
709
770
 
710
771
  main_security_ctx.destroy();
711
772
  if (db)
717
778
  free_root(&transaction.mem_root,MYF(0));
718
779
  mysys_var=0;                                  // Safety (shouldn't be needed)
719
780
  pthread_mutex_destroy(&LOCK_delete);
720
 
  dbug_sentry= THD_SENTRY_GONE;
 
781
  dbug_sentry= Session_SENTRY_GONE;
721
782
  if (rli_fake)
722
783
  {
723
784
    delete rli_fake;
724
785
    rli_fake= NULL;
725
786
  }
726
 
  
 
787
 
727
788
  free_root(&main_mem_root, MYF(0));
 
789
  pthread_setspecific(THR_Session,  0);
728
790
  return;
729
791
}
730
792
 
762
824
    to_var       add to this array
763
825
    from_var     from this array
764
826
    dec_var      minus this array
765
 
  
 
827
 
766
828
  NOTE
767
829
    This function assumes that all variables are long/ulong.
768
830
*/
780
842
}
781
843
 
782
844
 
783
 
void THD::awake(THD::killed_state state_to_set)
 
845
void Session::awake(Session::killed_state state_to_set)
784
846
{
785
 
  THD_CHECK_SENTRY(this);
786
 
  safe_mutex_assert_owner(&LOCK_delete); 
 
847
  Session_CHECK_SENTRY(this);
 
848
  safe_mutex_assert_owner(&LOCK_delete);
787
849
 
788
850
  killed= state_to_set;
789
 
  if (state_to_set != THD::KILL_QUERY)
 
851
  if (state_to_set != Session::KILL_QUERY)
790
852
  {
791
853
    thr_alarm_kill(thread_id);
792
854
    if (!slave_thread)
813
875
      current_cond and current_mutex are 0), then the victim will not get
814
876
      a signal and it may wait "forever" on the cond (until
815
877
      we issue a second KILL or the status it's waiting for happens).
816
 
      It's true that we have set its thd->killed but it may not
 
878
      It's true that we have set its session->killed but it may not
817
879
      see it immediately and so may have time to reach the cond_wait().
818
880
    */
819
881
    if (mysys_var->current_cond && mysys_var->current_mutex)
832
894
  sql_alloc() and the structure for the net buffer
833
895
*/
834
896
 
835
 
bool THD::store_globals()
 
897
bool Session::store_globals()
836
898
{
837
899
  /*
838
900
    Assert that thread_stack is initialized: it's necessary to be able
840
902
  */
841
903
  assert(thread_stack);
842
904
 
843
 
  if (my_pthread_setspecific_ptr(THR_THD,  this) ||
844
 
      my_pthread_setspecific_ptr(THR_MALLOC, &mem_root))
 
905
  if (pthread_setspecific(THR_Session,  this) ||
 
906
      pthread_setspecific(THR_Mem_root, &mem_root))
845
907
    return 1;
846
908
  mysys_var=my_thread_var;
847
909
  /*
848
910
    Let mysqld define the thread id (not mysys)
849
 
    This allows us to move THD to different threads if needed.
 
911
    This allows us to move Session to different threads if needed.
850
912
  */
851
913
  mysys_var->id= thread_id;
852
914
  real_id= pthread_self();                      // For debugging
853
915
 
854
916
  /*
855
 
    We have to call thr_lock_info_init() again here as THD may have been
 
917
    We have to call thr_lock_info_init() again here as Session may have been
856
918
    created in another thread
857
919
  */
858
920
  thr_lock_info_init(&lock_info);
864
926
  Cleanup after query.
865
927
 
866
928
  SYNOPSIS
867
 
    THD::cleanup_after_query()
 
929
    Session::cleanup_after_query()
868
930
 
869
931
  DESCRIPTION
870
932
    This function is used to reset thread data to its default state.
876
938
    slave.
877
939
*/
878
940
 
879
 
void THD::cleanup_after_query()
 
941
void Session::cleanup_after_query()
880
942
{
881
943
  /*
882
 
    Reset rand_used so that detection of calls to rand() will save random 
 
944
    Reset rand_used so that detection of calls to rand() will save random
883
945
    seeds if needed by the slave.
884
 
 
885
 
    Do not reset rand_used if inside a stored function or trigger because 
886
 
    only the call to these operations is logged. Thus only the calling 
887
 
    statement needs to detect rand() calls made by its substatements. These
888
 
    substatements must not set rand_used to 0 because it would remove the
889
 
    detection of rand() by the calling statement. 
890
946
  */
891
 
  if (!in_sub_stmt) /* stored functions and triggers are a special case */
892
947
  {
893
948
    /* Forget those values, for next binlogger: */
894
 
    stmt_depends_on_first_successful_insert_id_in_prev_stmt= 0;
895
949
    auto_inc_intervals_in_cur_stmt_for_binlog.empty();
896
 
    rand_used= 0;
897
950
  }
898
951
  if (first_successful_insert_id_in_cur_stmt > 0)
899
952
  {
900
953
    /* set what LAST_INSERT_ID() will return */
901
 
    first_successful_insert_id_in_prev_stmt= 
 
954
    first_successful_insert_id_in_prev_stmt=
902
955
      first_successful_insert_id_in_cur_stmt;
903
956
    first_successful_insert_id_in_cur_stmt= 0;
904
957
    substitute_null_with_insert_id= true;
907
960
  /* Free Items that were created during this execution */
908
961
  free_items();
909
962
  /* Reset where. */
910
 
  where= THD::DEFAULT_WHERE;
 
963
  where= Session::DEFAULT_WHERE;
911
964
}
912
965
 
913
966
 
921
974
                              instead of using lex_str value
922
975
  @return  NULL on failure, or pointer to the LEX_STRING object
923
976
*/
924
 
LEX_STRING *THD::make_lex_string(LEX_STRING *lex_str,
 
977
LEX_STRING *Session::make_lex_string(LEX_STRING *lex_str,
925
978
                                 const char* str, uint32_t length,
926
979
                                 bool allocate_lex_string)
927
980
{
955
1008
        In this case to->str will point to 0 and to->length will be 0.
956
1009
*/
957
1010
 
958
 
bool THD::convert_string(LEX_STRING *to, const CHARSET_INFO * const to_cs,
 
1011
bool Session::convert_string(LEX_STRING *to, const CHARSET_INFO * const to_cs,
959
1012
                         const char *from, uint32_t from_length,
960
1013
                         const CHARSET_INFO * const from_cs)
961
1014
{
977
1030
  Convert string from source character set to target character set inplace.
978
1031
 
979
1032
  SYNOPSIS
980
 
    THD::convert_string
 
1033
    Session::convert_string
981
1034
 
982
1035
  DESCRIPTION
983
 
    Convert string using convert_buffer - buffer for character set 
 
1036
    Convert string using convert_buffer - buffer for character set
984
1037
    conversion shared between all protocols.
985
1038
 
986
1039
  RETURN
988
1041
   !0   out of memory
989
1042
*/
990
1043
 
991
 
bool THD::convert_string(String *s, const CHARSET_INFO * const from_cs,
 
1044
bool Session::convert_string(String *s, const CHARSET_INFO * const from_cs,
992
1045
                         const CHARSET_INFO * const to_cs)
993
1046
{
994
1047
  uint32_t dummy_errors;
1009
1062
  Update some cache variables when character set changes
1010
1063
*/
1011
1064
 
1012
 
void THD::update_charset()
 
1065
void Session::update_charset()
1013
1066
{
1014
1067
  uint32_t not_used;
1015
1068
  charset_is_system_charset= !String::needs_conversion(0,charset(),
1016
1069
                                                       system_charset_info,
1017
1070
                                                       &not_used);
1018
 
  charset_is_collation_connection= 
 
1071
  charset_is_collation_connection=
1019
1072
    !String::needs_conversion(0,charset(),variables.collation_connection,
1020
1073
                              &not_used);
1021
 
  charset_is_character_set_filesystem= 
 
1074
  charset_is_character_set_filesystem=
1022
1075
    !String::needs_conversion(0, charset(),
1023
1076
                              variables.character_set_filesystem, &not_used);
1024
1077
}
1039
1092
 
1040
1093
/* add table to list of changed in transaction tables */
1041
1094
 
1042
 
void THD::add_changed_table(Table *table)
 
1095
void Session::add_changed_table(Table *table)
1043
1096
{
1044
1097
  assert((options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) &&
1045
1098
              table->file->has_transactions());
1049
1102
}
1050
1103
 
1051
1104
 
1052
 
void THD::add_changed_table(const char *key, long key_length)
 
1105
void Session::add_changed_table(const char *key, long key_length)
1053
1106
{
1054
1107
  CHANGED_TableList **prev_changed = &transaction.changed_tables;
1055
1108
  CHANGED_TableList *curr = transaction.changed_tables;
1081
1134
}
1082
1135
 
1083
1136
 
1084
 
CHANGED_TableList* THD::changed_table_dup(const char *key, long key_length)
 
1137
CHANGED_TableList* Session::changed_table_dup(const char *key, long key_length)
1085
1138
{
1086
 
  CHANGED_TableList* new_table = 
 
1139
  CHANGED_TableList* new_table =
1087
1140
    (CHANGED_TableList*) trans_alloc(ALIGN_SIZE(sizeof(CHANGED_TableList))+
1088
1141
                                      key_length + 1);
1089
1142
  if (!new_table)
1102
1155
}
1103
1156
 
1104
1157
 
1105
 
int THD::send_explain_fields(select_result *result)
 
1158
int Session::send_explain_fields(select_result *result)
1106
1159
{
1107
1160
  List<Item> field_list;
1108
1161
  Item *item;
1162
1215
/*
1163
1216
  Register an item tree tree transformation, performed by the query
1164
1217
  optimizer. We need a pointer to runtime_memroot because it may be !=
1165
 
  thd->mem_root (this may no longer be a true statement)
 
1218
  session->mem_root (this may no longer be a true statement)
1166
1219
*/
1167
1220
 
1168
 
void THD::nocheck_register_item_tree_change(Item **place, Item *old_value,
 
1221
void Session::nocheck_register_item_tree_change(Item **place, Item *old_value,
1169
1222
                                            MEM_ROOT *runtime_memroot)
1170
1223
{
1171
1224
  Item_change_record *change;
1178
1231
  if (change_mem == 0)
1179
1232
  {
1180
1233
    /*
1181
 
      OOM, thd->fatal_error() is called by the error handler of the
 
1234
      OOM, session->fatal_error() is called by the error handler of the
1182
1235
      memroot. Just return.
1183
1236
    */
1184
1237
    return;
1190
1243
}
1191
1244
 
1192
1245
 
1193
 
void THD::rollback_item_tree_changes()
 
1246
void Session::rollback_item_tree_changes()
1194
1247
{
1195
1248
  I_List_iterator<Item_change_record> it(change_list);
1196
1249
  Item_change_record *change;
1209
1262
 
1210
1263
select_result::select_result()
1211
1264
{
1212
 
  thd=current_thd;
 
1265
  session=current_session;
1213
1266
}
1214
1267
 
1215
1268
void select_result::send_error(uint32_t errcode,const char *err)
1249
1302
bool select_send::send_fields(List<Item> &list, uint32_t flags)
1250
1303
{
1251
1304
  bool res;
1252
 
  if (!(res= thd->protocol->send_fields(&list, flags)))
 
1305
  if (!(res= session->protocol->send_fields(&list, flags)))
1253
1306
    is_result_set_started= 1;
1254
1307
  return res;
1255
1308
}
1260
1313
}
1261
1314
 
1262
1315
 
1263
 
/** 
 
1316
/**
1264
1317
  Cleanup an instance of this class for re-use
1265
1318
  at next execution of a prepared statement/
1266
1319
  stored procedure statement.
1284
1337
  /*
1285
1338
    We may be passing the control from mysqld to the client: release the
1286
1339
    InnoDB adaptive hash S-latch to avoid thread deadlocks if it was reserved
1287
 
    by thd
 
1340
    by session
1288
1341
  */
1289
 
  ha_release_temporary_latches(thd);
 
1342
  ha_release_temporary_latches(session);
1290
1343
 
1291
1344
  List_iterator_fast<Item> li(items);
1292
 
  Protocol *protocol= thd->protocol;
 
1345
  Protocol *protocol= session->protocol;
1293
1346
  char buff[MAX_FIELD_WIDTH];
1294
1347
  String buffer(buff, sizeof(buff), &my_charset_bin);
1295
1348
 
1304
1357
      break;
1305
1358
    }
1306
1359
  }
1307
 
  thd->sent_row_count++;
1308
 
  if (thd->is_error())
 
1360
  session->sent_row_count++;
 
1361
  if (session->is_error())
1309
1362
  {
1310
1363
    protocol->remove_last_row();
1311
1364
    return(1);
1312
1365
  }
1313
 
  if (thd->vio_ok())
 
1366
  if (session->vio_ok())
1314
1367
    return(protocol->write());
1315
1368
  return(0);
1316
1369
}
1317
1370
 
1318
1371
bool select_send::send_eof()
1319
1372
{
1320
 
  /* 
 
1373
  /*
1321
1374
    We may be passing the control from mysqld to the client: release the
1322
1375
    InnoDB adaptive hash S-latch to avoid thread deadlocks if it was reserved
1323
 
    by thd 
 
1376
    by session
1324
1377
  */
1325
 
  ha_release_temporary_latches(thd);
 
1378
  ha_release_temporary_latches(session);
1326
1379
 
1327
1380
  /* Unlock tables before sending packet to gain some speed */
1328
 
  if (thd->lock)
 
1381
  if (session->lock)
1329
1382
  {
1330
 
    mysql_unlock_tables(thd, thd->lock);
1331
 
    thd->lock=0;
 
1383
    mysql_unlock_tables(session, session->lock);
 
1384
    session->lock=0;
1332
1385
  }
1333
 
  ::my_eof(thd);
 
1386
  ::my_eof(session);
1334
1387
  is_result_set_started= 0;
1335
1388
  return false;
1336
1389
}
1365
1418
      function, SELECT INTO has to have an own SQLCOM.
1366
1419
      TODO: split from SQLCOM_SELECT
1367
1420
    */
1368
 
    ::my_ok(thd,row_count);
 
1421
    ::my_ok(session,row_count);
1369
1422
  }
1370
1423
  file= -1;
1371
1424
  return error;
1402
1455
 
1403
1456
select_export::~select_export()
1404
1457
{
1405
 
  thd->sent_row_count=row_count;
 
1458
  session->sent_row_count=row_count;
1406
1459
}
1407
1460
 
1408
1461
 
1411
1464
 
1412
1465
  SYNOPSIS
1413
1466
    create_file()
1414
 
    thd                 Thread handle
 
1467
    session                     Thread handle
1415
1468
    path                File name
1416
1469
    exchange            Excange class
1417
1470
    cache               IO cache
1422
1475
*/
1423
1476
 
1424
1477
 
1425
 
static File create_file(THD *thd, char *path, sql_exchange *exchange,
 
1478
static File create_file(Session *session, char *path, sql_exchange *exchange,
1426
1479
                        IO_CACHE *cache)
1427
1480
{
1428
1481
  File file;
1434
1487
 
1435
1488
  if (!dirname_length(exchange->file_name))
1436
1489
  {
1437
 
    strxnmov(path, FN_REFLEN-1, mysql_real_data_home, thd->db ? thd->db : "",
1438
 
             NULL);
 
1490
    strcpy(path, drizzle_real_data_home);
 
1491
    if (session->db)
 
1492
      strncat(path, session->db, FN_REFLEN-strlen(drizzle_real_data_home)-1);
1439
1493
    (void) fn_format(path, exchange->file_name, path, "", option);
1440
1494
  }
1441
1495
  else
1442
 
    (void) fn_format(path, exchange->file_name, mysql_real_data_home, "", option);
 
1496
    (void) fn_format(path, exchange->file_name, drizzle_real_data_home, "", option);
1443
1497
 
1444
1498
  if (opt_secure_file_priv &&
1445
1499
      strncmp(opt_secure_file_priv, path, strlen(opt_secure_file_priv)))
1465
1519
  if (init_io_cache(cache, file, 0L, WRITE_CACHE, 0L, 1, MYF(MY_WME)))
1466
1520
  {
1467
1521
    my_close(file, MYF(0));
1468
 
    my_delete(path, MYF(0));  // Delete file on error, it was just created 
 
1522
    my_delete(path, MYF(0));  // Delete file on error, it was just created
1469
1523
    return -1;
1470
1524
  }
1471
1525
  return file;
1479
1533
  bool string_results= false, non_string_results= false;
1480
1534
  unit= u;
1481
1535
  if ((uint) strlen(exchange->file_name) + NAME_LEN >= FN_REFLEN)
1482
 
    strmake(path,exchange->file_name,FN_REFLEN-1);
 
1536
    strncpy(path,exchange->file_name,FN_REFLEN-1);
1483
1537
 
1484
 
  if ((file= create_file(thd, path, exchange, &cache)) < 0)
 
1538
  if ((file= create_file(session, path, exchange, &cache)) < 0)
1485
1539
    return 1;
1486
1540
  /* Check if there is any blobs in data */
1487
1541
  {
1524
1578
      (exchange->opt_enclosed && non_string_results &&
1525
1579
       field_term_length && strchr(NUMERIC_CHARS, field_term_char)))
1526
1580
  {
1527
 
    push_warning(thd, DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
1581
    push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
1528
1582
                 ER_AMBIGUOUS_FIELD_TERM, ER(ER_AMBIGUOUS_FIELD_TERM));
1529
1583
    is_ambiguous_field_term= true;
1530
1584
  }
1603
1657
      {
1604
1658
        char *pos, *start, *end;
1605
1659
        const CHARSET_INFO * const res_charset= res->charset();
1606
 
        const CHARSET_INFO * const character_set_client= thd->variables.
 
1660
        const CHARSET_INFO * const character_set_client= session->variables.
1607
1661
                                                            character_set_client;
1608
1662
        bool check_second_byte= (res_charset == &my_charset_bin) &&
1609
1663
                                 character_set_client->
1631
1685
            for the clients with character sets big5, cp932, gbk and sjis,
1632
1686
            which can have the escape character (0x5C "\" by default)
1633
1687
            as the second byte of a multi-byte sequence.
1634
 
            
 
1688
 
1635
1689
            If
1636
1690
            - pos[0] is a valid multi-byte head (e.g 0xEE) and
1637
1691
            - pos[1] is 0x00, which will be escaped as "\0",
1638
 
            
 
1692
 
1639
1693
            then we'll get "0xEE + 0x5C + 0x30" in the output file.
1640
 
            
 
1694
 
1641
1695
            If this file is later loaded using this sequence of commands:
1642
 
            
 
1696
 
1643
1697
            mysql> create table t1 (a varchar(128)) character set big5;
1644
1698
            mysql> LOAD DATA INFILE 'dump.txt' INTO Table t1;
1645
 
            
 
1699
 
1646
1700
            then 0x5C will be misinterpreted as the second byte
1647
1701
            of a multi-byte character "0xEE + 0x5C", instead of
1648
1702
            escape character for 0x00.
1649
 
            
 
1703
 
1650
1704
            To avoid this confusion, we'll escape the multi-byte
1651
1705
            head character too, so the sequence "0xEE + 0x00" will be
1652
1706
            dumped as "0x5C + 0xEE + 0x5C + 0x30".
1653
 
            
 
1707
 
1654
1708
            Note, in the condition below we only check if
1655
1709
            mbcharlen is equal to 2, because there are no
1656
1710
            character sets with mbmaxlen longer than 2
1739
1793
                     SELECT_LEX_UNIT *u)
1740
1794
{
1741
1795
  unit= u;
1742
 
  return (int) ((file= create_file(thd, path, exchange, &cache)) < 0);
 
1796
  return (int) ((file= create_file(session, path, exchange, &cache)) < 0);
1743
1797
}
1744
1798
 
1745
1799
 
1756
1810
    unit->offset_limit_cnt--;
1757
1811
    return(0);
1758
1812
  }
1759
 
  if (row_count++ > 1) 
 
1813
  if (row_count++ > 1)
1760
1814
  {
1761
1815
    my_message(ER_TOO_MANY_ROWS, ER(ER_TOO_MANY_ROWS), MYF(0));
1762
1816
    goto err;
1940
1994
int select_dumpvar::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
1941
1995
{
1942
1996
  unit= u;
1943
 
  
 
1997
 
1944
1998
  if (var_list.elements != list.elements)
1945
1999
  {
1946
2000
    my_message(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT,
1947
2001
               ER(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT), MYF(0));
1948
2002
    return 1;
1949
 
  }               
 
2003
  }
1950
2004
  return 0;
1951
2005
}
1952
2006
 
1999
2053
  Don't free mem_root, as mem_root is freed in the end of dispatch_command
2000
2054
  (once for any command).
2001
2055
*/
2002
 
void THD::end_statement()
 
2056
void Session::end_statement()
2003
2057
{
2004
2058
  /* Cleanup SQL processing state to reuse this statement in next query. */
2005
2059
  lex_end(lex);
2006
2060
}
2007
2061
 
2008
2062
 
2009
 
bool THD::copy_db_to(char **p_db, size_t *p_db_length)
 
2063
bool Session::copy_db_to(char **p_db, size_t *p_db_length)
2010
2064
{
2011
2065
  if (db == NULL)
2012
2066
  {
2031
2085
    unit->offset_limit_cnt--;
2032
2086
    return(0);
2033
2087
  }
2034
 
  if (row_count++) 
 
2088
  if (row_count++)
2035
2089
  {
2036
2090
    my_message(ER_TOO_MANY_ROWS, ER(ER_TOO_MANY_ROWS), MYF(0));
2037
2091
    return(1);
2041
2095
    if (mv->local == 0)
2042
2096
    {
2043
2097
      Item_func_set_user_var *suv= new Item_func_set_user_var(mv->s, item);
2044
 
      suv->fix_fields(thd, 0);
 
2098
      suv->fix_fields(session, 0);
2045
2099
      suv->check(0);
2046
2100
      suv->update();
2047
2101
    }
2048
2102
  }
2049
 
  return(thd->is_error());
 
2103
  return(session->is_error());
2050
2104
}
2051
2105
 
2052
2106
bool select_dumpvar::send_eof()
2053
2107
{
2054
2108
  if (! row_count)
2055
 
    push_warning(thd, DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
2109
    push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
2056
2110
                 ER_SP_FETCH_NO_DATA, ER(ER_SP_FETCH_NO_DATA));
2057
2111
  /*
2058
2112
    In order to remember the value of affected rows for ROW_COUNT()
2059
2113
    function, SELECT INTO has to have an own SQLCOM.
2060
2114
    TODO: split from SQLCOM_SELECT
2061
2115
  */
2062
 
  ::my_ok(thd,row_count);
 
2116
  ::my_ok(session,row_count);
2063
2117
  return 0;
2064
2118
}
2065
2119
 
2078
2132
  return;
2079
2133
}
2080
2134
 
2081
 
 
2082
 
void thd_increment_bytes_sent(ulong length)
2083
 
{
2084
 
  THD *thd=current_thd;
2085
 
  if (likely(thd != 0))
2086
 
  { /* current_thd==0 when close_connection() calls net_send_error() */
2087
 
    thd->status_var.bytes_sent+= length;
2088
 
  }
2089
 
}
2090
 
 
2091
 
 
2092
 
void thd_increment_bytes_received(ulong length)
2093
 
{
2094
 
  current_thd->status_var.bytes_received+= length;
2095
 
}
2096
 
 
2097
 
 
2098
 
void thd_increment_net_big_packet_count(ulong length)
2099
 
{
2100
 
  current_thd->status_var.net_big_packet_count+= length;
2101
 
}
2102
 
 
2103
 
void THD::send_kill_message() const
 
2135
void TMP_TABLE_PARAM::cleanup(void)
 
2136
{
 
2137
  /* Fix for Intel compiler */
 
2138
  if (copy_field)
 
2139
  {
 
2140
    delete [] copy_field;
 
2141
    save_copy_field= copy_field= 0;
 
2142
  }
 
2143
}
 
2144
 
 
2145
 
 
2146
void session_increment_bytes_sent(ulong length)
 
2147
{
 
2148
  Session *session=current_session;
 
2149
  if (likely(session != 0))
 
2150
  { /* current_session==0 when close_connection() calls net_send_error() */
 
2151
    session->status_var.bytes_sent+= length;
 
2152
  }
 
2153
}
 
2154
 
 
2155
 
 
2156
void session_increment_bytes_received(ulong length)
 
2157
{
 
2158
  current_session->status_var.bytes_received+= length;
 
2159
}
 
2160
 
 
2161
 
 
2162
void session_increment_net_big_packet_count(ulong length)
 
2163
{
 
2164
  current_session->status_var.net_big_packet_count+= length;
 
2165
}
 
2166
 
 
2167
void Session::send_kill_message() const
2104
2168
{
2105
2169
  int err= killed_errno();
2106
2170
  if (err)
2107
2171
    my_message(err, ER(err), MYF(0));
2108
2172
}
2109
2173
 
2110
 
void THD::set_status_var_init()
 
2174
void Session::set_status_var_init()
2111
2175
{
2112
2176
  memset(&status_var, 0, sizeof(status_var));
2113
2177
}
2149
2213
  access to mysql.proc table to find definitions of stored routines.
2150
2214
****************************************************************************/
2151
2215
 
2152
 
void THD::reset_n_backup_open_tables_state(Open_tables_state *backup)
 
2216
void Session::reset_n_backup_open_tables_state(Open_tables_state *backup)
2153
2217
{
2154
2218
  backup->set_open_tables_state(this);
2155
2219
  reset_open_tables_state();
2158
2222
}
2159
2223
 
2160
2224
 
2161
 
void THD::restore_backup_open_tables_state(Open_tables_state *backup)
 
2225
void Session::restore_backup_open_tables_state(Open_tables_state *backup)
2162
2226
{
2163
2227
  /*
2164
2228
    Before we will throw away current open tables state we want
2171
2235
  return;
2172
2236
}
2173
2237
 
 
2238
 
 
2239
bool Session::set_db(const char *new_db, size_t new_db_len)
 
2240
{
 
2241
  /* Do not reallocate memory if current chunk is big enough. */
 
2242
  if (db && new_db && db_length >= new_db_len)
 
2243
    memcpy(db, new_db, new_db_len+1);
 
2244
  else
 
2245
  {
 
2246
    if (db)
 
2247
      free(db);
 
2248
    if (new_db)
 
2249
    {
 
2250
      db= (char *)malloc(new_db_len + 1);
 
2251
      if (db != NULL)
 
2252
      {
 
2253
        memcpy(db, new_db, new_db_len);
 
2254
        db[new_db_len]= 0;
 
2255
      }
 
2256
    }
 
2257
    else
 
2258
      db= NULL;
 
2259
  }
 
2260
  db_length= db ? new_db_len : 0;
 
2261
  return new_db && !db;
 
2262
}
 
2263
 
 
2264
 
2174
2265
/**
2175
2266
  Check the killed state of a user thread
2176
 
  @param thd  user thread
 
2267
  @param session  user thread
2177
2268
  @retval 0 the user thread is active
2178
2269
  @retval 1 the user thread has been killed
2179
2270
*/
2180
 
extern "C" int thd_killed(const DRIZZLE_THD thd)
 
2271
extern "C" int session_killed(const Session *session)
2181
2272
{
2182
 
  return(thd->killed);
 
2273
  return(session->killed);
2183
2274
}
2184
2275
 
2185
2276
/**
2186
2277
  Return the thread id of a user thread
2187
 
  @param thd user thread
 
2278
  @param session user thread
2188
2279
  @return thread id
2189
2280
*/
2190
 
extern "C" unsigned long thd_get_thread_id(const DRIZZLE_THD thd)
2191
 
{
2192
 
  return((unsigned long)thd->thread_id);
2193
 
}
2194
 
 
2195
 
 
2196
 
#ifdef INNODB_COMPATIBILITY_HOOKS
2197
 
extern "C" const struct charset_info_st *thd_charset(DRIZZLE_THD thd)
2198
 
{
2199
 
  return(thd->charset());
2200
 
}
2201
 
 
2202
 
extern "C" char **thd_query(DRIZZLE_THD thd)
2203
 
{
2204
 
  return(&thd->query);
2205
 
}
2206
 
 
2207
 
extern "C" int thd_slave_thread(const DRIZZLE_THD thd)
2208
 
{
2209
 
  return(thd->slave_thread);
2210
 
}
2211
 
 
2212
 
extern "C" int thd_non_transactional_update(const DRIZZLE_THD thd)
2213
 
{
2214
 
  return(thd->transaction.all.modified_non_trans_table);
2215
 
}
2216
 
 
2217
 
extern "C" int thd_binlog_format(const DRIZZLE_THD thd)
2218
 
{
2219
 
  return (int) thd->variables.binlog_format;
2220
 
}
2221
 
 
2222
 
extern "C" void thd_mark_transaction_to_rollback(DRIZZLE_THD thd, bool all)
2223
 
{
2224
 
  mark_transaction_to_rollback(thd, all);
2225
 
}
2226
 
#endif // INNODB_COMPATIBILITY_HOOKS */
 
2281
extern "C" unsigned long session_get_thread_id(const Session *session)
 
2282
{
 
2283
  return((unsigned long)session->thread_id);
 
2284
}
 
2285
 
 
2286
 
 
2287
extern "C"
 
2288
LEX_STRING *session_make_lex_string(Session *session, LEX_STRING *lex_str,
 
2289
                                const char *str, unsigned int size,
 
2290
                                int allocate_lex_string)
 
2291
{
 
2292
  return session->make_lex_string(lex_str, str, size,
 
2293
                              (bool) allocate_lex_string);
 
2294
}
 
2295
 
 
2296
extern "C" const struct charset_info_st *session_charset(Session *session)
 
2297
{
 
2298
  return(session->charset());
 
2299
}
 
2300
 
 
2301
extern "C" char **session_query(Session *session)
 
2302
{
 
2303
  return(&session->query);
 
2304
}
 
2305
 
 
2306
extern "C" int session_slave_thread(const Session *session)
 
2307
{
 
2308
  return(session->slave_thread);
 
2309
}
 
2310
 
 
2311
extern "C" int session_non_transactional_update(const Session *session)
 
2312
{
 
2313
  return(session->transaction.all.modified_non_trans_table);
 
2314
}
 
2315
 
 
2316
extern "C" void session_mark_transaction_to_rollback(Session *session, bool all)
 
2317
{
 
2318
  mark_transaction_to_rollback(session, all);
 
2319
}
2227
2320
 
2228
2321
 
2229
2322
/**
2230
2323
  Mark transaction to rollback and mark error as fatal to a sub-statement.
2231
2324
 
2232
 
  @param  thd   Thread handle
 
2325
  @param  session   Thread handle
2233
2326
  @param  all   true <=> rollback main transaction.
2234
2327
*/
2235
2328
 
2236
 
void mark_transaction_to_rollback(THD *thd, bool all)
 
2329
void mark_transaction_to_rollback(Session *session, bool all)
2237
2330
{
2238
 
  if (thd)
 
2331
  if (session)
2239
2332
  {
2240
 
    thd->is_fatal_sub_stmt_error= true;
2241
 
    thd->transaction_rollback_request= all;
 
2333
    session->is_fatal_sub_stmt_error= true;
 
2334
    session->transaction_rollback_request= all;
2242
2335
  }
2243
2336
}
2244
2337
/***************************************************************************
2260
2353
 
2261
2354
void xid_free_hash(void *ptr)
2262
2355
{
2263
 
  if (!((XID_STATE*)ptr)->in_thd)
 
2356
  if (!((XID_STATE*)ptr)->in_session)
2264
2357
    free((unsigned char*)ptr);
2265
2358
}
2266
2359
 
2296
2389
  pthread_mutex_lock(&LOCK_xid_cache);
2297
2390
  if (hash_search(&xid_cache, xid->key(), xid->key_length()))
2298
2391
    res=0;
2299
 
  else if (!(xs=(XID_STATE *)my_malloc(sizeof(*xs), MYF(MY_WME))))
 
2392
  else if (!(xs=(XID_STATE *)malloc(sizeof(*xs))))
2300
2393
    res=1;
2301
2394
  else
2302
2395
  {
2303
2396
    xs->xa_state=xa_state;
2304
2397
    xs->xid.set(xid);
2305
 
    xs->in_thd=0;
 
2398
    xs->in_session=0;
2306
2399
    res=my_hash_insert(&xid_cache, (unsigned char*)xs);
2307
2400
  }
2308
2401
  pthread_mutex_unlock(&LOCK_xid_cache);
2328
2421
  pthread_mutex_unlock(&LOCK_xid_cache);
2329
2422
}
2330
2423
 
2331
 
/*
2332
 
  Implementation of interface to write rows to the binary log through the
2333
 
  thread.  The thread is responsible for writing the rows it has
2334
 
  inserted/updated/deleted.
2335
 
*/
2336
 
 
2337
 
 
2338
 
/*
2339
 
  Template member function for ensuring that there is an rows log
2340
 
  event of the apropriate type before proceeding.
2341
 
 
2342
 
  PRE CONDITION:
2343
 
    - Events of type 'RowEventT' have the type code 'type_code'.
2344
 
    
2345
 
  POST CONDITION:
2346
 
    If a non-NULL pointer is returned, the pending event for thread 'thd' will
2347
 
    be an event of type 'RowEventT' (which have the type code 'type_code')
2348
 
    will either empty or have enough space to hold 'needed' bytes.  In
2349
 
    addition, the columns bitmap will be correct for the row, meaning that
2350
 
    the pending event will be flushed if the columns in the event differ from
2351
 
    the columns suppled to the function.
2352
 
 
2353
 
  RETURNS
2354
 
    If no error, a non-NULL pending event (either one which already existed or
2355
 
    the newly created one).
2356
 
    If error, NULL.
2357
 
 */
2358
 
 
2359
 
template <class RowsEventT> Rows_log_event* 
2360
 
THD::binlog_prepare_pending_rows_event(Table* table, uint32_t serv_id,
2361
 
                                       size_t needed,
2362
 
                                       bool is_transactional,
2363
 
                                       RowsEventT *hint __attribute__((unused)))
2364
 
{
2365
 
  /* Pre-conditions */
2366
 
  assert(table->s->table_map_id != UINT32_MAX);
2367
 
 
2368
 
  /* Fetch the type code for the RowsEventT template parameter */
2369
 
  int const type_code= RowsEventT::TYPE_CODE;
2370
 
 
2371
 
  /*
2372
 
    There is no good place to set up the transactional data, so we
2373
 
    have to do it here.
2374
 
  */
2375
 
  if (binlog_setup_trx_data())
2376
 
    return(NULL);
2377
 
 
2378
 
  Rows_log_event* pending= binlog_get_pending_rows_event();
2379
 
 
2380
 
  if (unlikely(pending && !pending->is_valid()))
2381
 
    return(NULL);
2382
 
 
2383
 
  /*
2384
 
    Check if the current event is non-NULL and a write-rows
2385
 
    event. Also check if the table provided is mapped: if it is not,
2386
 
    then we have switched to writing to a new table.
2387
 
    If there is no pending event, we need to create one. If there is a pending
2388
 
    event, but it's not about the same table id, or not of the same type
2389
 
    (between Write, Update and Delete), or not the same affected columns, or
2390
 
    going to be too big, flush this event to disk and create a new pending
2391
 
    event.
2392
 
 
2393
 
    The last test is necessary for the Cluster injector to work
2394
 
    correctly. The reason is that the Cluster can inject two write
2395
 
    rows with different column bitmaps if there is an insert followed
2396
 
    by an update in the same transaction, and these are grouped into a
2397
 
    single epoch/transaction when fed to the injector.
2398
 
 
2399
 
    TODO: Fix the code so that the last test can be removed.
2400
 
  */
2401
 
  if (!pending ||
2402
 
      pending->server_id != serv_id || 
2403
 
      pending->get_table_id() != table->s->table_map_id ||
2404
 
      pending->get_type_code() != type_code || 
2405
 
      pending->get_data_size() + needed > opt_binlog_rows_event_max_size ||
2406
 
      !bitmap_cmp(pending->get_cols(), table->write_set))
2407
 
    {
2408
 
    /* Create a new RowsEventT... */
2409
 
    Rows_log_event* const
2410
 
        ev= new RowsEventT(this, table, table->s->table_map_id,
2411
 
                           is_transactional);
2412
 
    if (unlikely(!ev))
2413
 
      return(NULL);
2414
 
    ev->server_id= serv_id; // I don't like this, it's too easy to forget.
2415
 
    /*
2416
 
      flush the pending event and replace it with the newly created
2417
 
      event...
2418
 
    */
2419
 
    if (unlikely(mysql_bin_log.flush_and_set_pending_rows_event(this, ev)))
2420
 
    {
2421
 
      delete ev;
2422
 
      return(NULL);
2423
 
    }
2424
 
 
2425
 
    return(ev);               /* This is the new pending event */
2426
 
  }
2427
 
  return(pending);        /* This is the current pending event */
2428
 
}
2429
 
 
2430
 
#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
2431
 
/*
2432
 
  Instantiate the versions we need, we have -fno-implicit-template as
2433
 
  compiling option.
2434
 
*/
2435
 
template Rows_log_event*
2436
 
THD::binlog_prepare_pending_rows_event(Table*, uint32_t, size_t, bool,
2437
 
                                       Write_rows_log_event*);
2438
 
 
2439
 
template Rows_log_event*
2440
 
THD::binlog_prepare_pending_rows_event(Table*, uint32_t, size_t, bool,
2441
 
                                       Delete_rows_log_event *);
2442
 
 
2443
 
template Rows_log_event* 
2444
 
THD::binlog_prepare_pending_rows_event(Table*, uint32_t, size_t, bool,
2445
 
                                       Update_rows_log_event *);
2446
 
#endif
2447
 
 
2448
2424
namespace {
2449
2425
  /**
2450
2426
     Class to handle temporary allocation of memory for row data.
2546
2522
      }
2547
2523
      else
2548
2524
      {
2549
 
        m_memory= (unsigned char *) my_malloc(total_length, MYF(MY_WME));
 
2525
        m_memory= (unsigned char *) malloc(total_length);
2550
2526
        m_release_memory_on_destruction= true;
2551
2527
      }
2552
2528
    }
2558
2534
  };
2559
2535
}
2560
2536
 
2561
 
 
2562
 
int THD::binlog_write_row(Table* table, bool is_trans, 
2563
 
                          unsigned char const *record) 
2564
 
2565
 
  assert(current_stmt_binlog_row_based && mysql_bin_log.is_open());
2566
 
 
2567
 
  /*
2568
 
    Pack records into format for transfer. We are allocating more
2569
 
    memory than needed, but that doesn't matter.
2570
 
  */
2571
 
  Row_data_memory memory(table, table->max_row_length(record));
2572
 
  if (!memory.has_memory())
2573
 
    return HA_ERR_OUT_OF_MEM;
2574
 
 
2575
 
  unsigned char *row_data= memory.slot(0);
2576
 
 
2577
 
  size_t const len= pack_row(table, table->write_set, row_data, record);
2578
 
 
2579
 
  Rows_log_event* const ev=
2580
 
    binlog_prepare_pending_rows_event(table, server_id, len, is_trans,
2581
 
                                      static_cast<Write_rows_log_event*>(0));
2582
 
 
2583
 
  if (unlikely(ev == 0))
2584
 
    return HA_ERR_OUT_OF_MEM;
2585
 
 
2586
 
  return ev->add_row_data(row_data, len);
2587
 
}
2588
 
 
2589
 
int THD::binlog_update_row(Table* table, bool is_trans,
2590
 
                           const unsigned char *before_record,
2591
 
                           const unsigned char *after_record)
2592
 
2593
 
  assert(current_stmt_binlog_row_based && mysql_bin_log.is_open());
2594
 
 
2595
 
  size_t const before_maxlen = table->max_row_length(before_record);
2596
 
  size_t const after_maxlen  = table->max_row_length(after_record);
2597
 
 
2598
 
  Row_data_memory row_data(table, before_maxlen, after_maxlen);
2599
 
  if (!row_data.has_memory())
2600
 
    return HA_ERR_OUT_OF_MEM;
2601
 
 
2602
 
  unsigned char *before_row= row_data.slot(0);
2603
 
  unsigned char *after_row= row_data.slot(1);
2604
 
 
2605
 
  size_t const before_size= pack_row(table, table->read_set, before_row,
2606
 
                                        before_record);
2607
 
  size_t const after_size= pack_row(table, table->write_set, after_row,
2608
 
                                       after_record);
2609
 
 
2610
 
  Rows_log_event* const ev=
2611
 
    binlog_prepare_pending_rows_event(table, server_id,
2612
 
                                      before_size + after_size, is_trans,
2613
 
                                      static_cast<Update_rows_log_event*>(0));
2614
 
 
2615
 
  if (unlikely(ev == 0))
2616
 
    return HA_ERR_OUT_OF_MEM;
2617
 
 
2618
 
  return
2619
 
    ev->add_row_data(before_row, before_size) ||
2620
 
    ev->add_row_data(after_row, after_size);
2621
 
}
2622
 
 
2623
 
int THD::binlog_delete_row(Table* table, bool is_trans, 
2624
 
                           unsigned char const *record)
2625
 
2626
 
  assert(current_stmt_binlog_row_based && mysql_bin_log.is_open());
2627
 
 
2628
 
  /* 
2629
 
     Pack records into format for transfer. We are allocating more
2630
 
     memory than needed, but that doesn't matter.
2631
 
  */
2632
 
  Row_data_memory memory(table, table->max_row_length(record));
2633
 
  if (unlikely(!memory.has_memory()))
2634
 
    return HA_ERR_OUT_OF_MEM;
2635
 
 
2636
 
  unsigned char *row_data= memory.slot(0);
2637
 
 
2638
 
  size_t const len= pack_row(table, table->read_set, row_data, record);
2639
 
 
2640
 
  Rows_log_event* const ev=
2641
 
    binlog_prepare_pending_rows_event(table, server_id, len, is_trans,
2642
 
                                      static_cast<Delete_rows_log_event*>(0));
2643
 
 
2644
 
  if (unlikely(ev == 0))
2645
 
    return HA_ERR_OUT_OF_MEM;
2646
 
 
2647
 
  return ev->add_row_data(row_data, len);
2648
 
}
2649
 
 
2650
 
 
2651
 
int THD::binlog_flush_pending_rows_event(bool stmt_end)
2652
 
{
2653
 
  /*
2654
 
    We shall flush the pending event even if we are not in row-based
2655
 
    mode: it might be the case that we left row-based mode before
2656
 
    flushing anything (e.g., if we have explicitly locked tables).
2657
 
   */
2658
 
  if (!mysql_bin_log.is_open())
2659
 
    return(0);
2660
 
 
2661
 
  /*
2662
 
    Mark the event as the last event of a statement if the stmt_end
2663
 
    flag is set.
2664
 
  */
2665
 
  int error= 0;
2666
 
  if (Rows_log_event *pending= binlog_get_pending_rows_event())
2667
 
  {
2668
 
    if (stmt_end)
2669
 
    {
2670
 
      pending->set_flags(Rows_log_event::STMT_END_F);
2671
 
      pending->flags|= LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F;
2672
 
      binlog_table_maps= 0;
2673
 
    }
2674
 
 
2675
 
    error= mysql_bin_log.flush_and_set_pending_rows_event(this, 0);
2676
 
  }
2677
 
 
2678
 
  return(error);
2679
 
}
2680
 
 
2681
 
 
2682
 
/*
2683
 
  Member function that will log query, either row-based or
2684
 
  statement-based depending on the value of the 'current_stmt_binlog_row_based'
2685
 
  the value of the 'qtype' flag.
2686
 
 
2687
 
  This function should be called after the all calls to ha_*_row()
2688
 
  functions have been issued, but before tables are unlocked and
2689
 
  closed.
2690
 
 
2691
 
  OBSERVE
2692
 
    There shall be no writes to any system table after calling
2693
 
    binlog_query(), so these writes has to be moved to before the call
2694
 
    of binlog_query() for correct functioning.
2695
 
 
2696
 
    This is necessesary not only for RBR, but the master might crash
2697
 
    after binlogging the query but before changing the system tables.
2698
 
    This means that the slave and the master are not in the same state
2699
 
    (after the master has restarted), so therefore we have to
2700
 
    eliminate this problem.
2701
 
 
2702
 
  RETURN VALUE
2703
 
    Error code, or 0 if no error.
2704
 
*/
2705
 
int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg,
2706
 
                      ulong query_len, bool is_trans, bool suppress_use,
2707
 
                      THD::killed_state killed_status_arg)
2708
 
{
2709
 
  assert(query_arg && mysql_bin_log.is_open());
2710
 
 
2711
 
  if (int error= binlog_flush_pending_rows_event(true))
2712
 
    return(error);
2713
 
 
2714
 
  /*
2715
 
    If we are in statement mode and trying to log an unsafe statement,
2716
 
    we should print a warning.
2717
 
  */
2718
 
  if (lex->is_stmt_unsafe() &&
2719
 
      variables.binlog_format == BINLOG_FORMAT_STMT)
2720
 
  {
2721
 
    assert(this->query != NULL);
2722
 
    push_warning(this, DRIZZLE_ERROR::WARN_LEVEL_WARN,
2723
 
                 ER_BINLOG_UNSAFE_STATEMENT,
2724
 
                 ER(ER_BINLOG_UNSAFE_STATEMENT));
2725
 
    if (!(binlog_flags & BINLOG_FLAG_UNSAFE_STMT_PRINTED))
2726
 
    {
2727
 
      char warn_buf[DRIZZLE_ERRMSG_SIZE];
2728
 
      snprintf(warn_buf, DRIZZLE_ERRMSG_SIZE, "%s Statement: %s",
2729
 
               ER(ER_BINLOG_UNSAFE_STATEMENT), this->query);
2730
 
      sql_print_warning(warn_buf);
2731
 
      binlog_flags|= BINLOG_FLAG_UNSAFE_STMT_PRINTED;
2732
 
    }
2733
 
  }
2734
 
 
2735
 
  switch (qtype) {
2736
 
  case THD::ROW_QUERY_TYPE:
2737
 
    if (current_stmt_binlog_row_based)
2738
 
      return(0);
2739
 
    /* Otherwise, we fall through */
2740
 
  case THD::DRIZZLE_QUERY_TYPE:
2741
 
    /*
2742
 
      Using this query type is a conveniece hack, since we have been
2743
 
      moving back and forth between using RBR for replication of
2744
 
      system tables and not using it.
2745
 
 
2746
 
      Make sure to change in check_table_binlog_row_based() according
2747
 
      to how you treat this.
2748
 
    */
2749
 
  case THD::STMT_QUERY_TYPE:
2750
 
    /*
2751
 
      The DRIZZLE_LOG::write() function will set the STMT_END_F flag and
2752
 
      flush the pending rows event if necessary.
2753
 
     */
2754
 
    {
2755
 
      Query_log_event qinfo(this, query_arg, query_len, is_trans, suppress_use,
2756
 
                            killed_status_arg);
2757
 
      qinfo.flags|= LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F;
2758
 
      /*
2759
 
        Binlog table maps will be irrelevant after a Query_log_event
2760
 
        (they are just removed on the slave side) so after the query
2761
 
        log event is written to the binary log, we pretend that no
2762
 
        table maps were written.
2763
 
       */
2764
 
      int error= mysql_bin_log.write(&qinfo);
2765
 
      binlog_table_maps= 0;
2766
 
      return(error);
2767
 
    }
2768
 
    break;
2769
 
 
2770
 
  case THD::QUERY_TYPE_COUNT:
2771
 
  default:
2772
 
    assert(0 <= qtype && qtype < QUERY_TYPE_COUNT);
2773
 
  }
2774
 
  return(0);
2775
 
}
2776
 
 
2777
2537
bool Discrete_intervals_list::append(uint64_t start, uint64_t val,
2778
2538
                                 uint64_t incr)
2779
2539
{
2799
2559
  elements++;
2800
2560
  return(0);
2801
2561
}
 
2562
 
 
2563
/**
 
2564
  Close a connection.
 
2565
 
 
2566
  @param session                Thread handle
 
2567
  @param errcode        Error code to print to console
 
2568
  @param lock           1 if we have have to lock LOCK_thread_count
 
2569
 
 
2570
  @note
 
2571
    For the connection that is doing shutdown, this is called twice
 
2572
*/
 
2573
void close_connection(Session *session, uint32_t errcode, bool lock)
 
2574
{
 
2575
  st_vio *vio;
 
2576
  if (lock)
 
2577
    (void) pthread_mutex_lock(&LOCK_thread_count);
 
2578
  session->killed= Session::KILL_CONNECTION;
 
2579
  if ((vio= session->net.vio) != 0)
 
2580
  {
 
2581
    if (errcode)
 
2582
      net_send_error(session, errcode, ER(errcode)); /* purecov: inspected */
 
2583
    net_close(&(session->net));         /* vio is freed in delete session */
 
2584
  }
 
2585
  if (lock)
 
2586
    (void) pthread_mutex_unlock(&LOCK_thread_count);
 
2587
  return;;
 
2588
}