~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/session.cc

Replace MAX_(DATE|TIME).*_WIDTH defines in definitions.h with real (and correct) static const members to Temporal types.

This fixes the buffer overflow in https://bugs.launchpad.net/drizzle/+bug/373468

It also removes a handwritten snprintf in field/datetime.cc
However... this caused us to have to change Temporal to have a way to not
"convert" the int64_t value (so 20090101 becomes 20090101000000 etc) as it
has already been converted and we just want the Temporal type to do the
to_string conversion.

This still causes a failure in 'metadata' test due to size of timestamp type. I need feedback from Jay on when the usecond code comes into play to know the correct fix for this.

Show diffs side-by-side

added added

removed removed

Lines of Context:
21
21
 * @file Implementation of the Session class and API
22
22
 */
23
23
 
24
 
#include "config.h"
 
24
#include <drizzled/server_includes.h>
25
25
#include <drizzled/session.h>
26
 
#include "drizzled/session_list.h"
27
26
#include <sys/stat.h>
 
27
#include <mysys/mysys_err.h>
28
28
#include <drizzled/error.h>
29
 
#include <drizzled/gettext.h>
30
29
#include <drizzled/query_id.h>
31
30
#include <drizzled/data_home.h>
32
31
#include <drizzled/sql_base.h>
36
35
#include <drizzled/item/return_int.h>
37
36
#include <drizzled/item/empty_string.h>
38
37
#include <drizzled/show.h>
39
 
#include <drizzled/plugin/client.h>
40
 
#include "drizzled/plugin/scheduler.h"
41
 
#include "drizzled/plugin/authentication.h"
42
 
#include "drizzled/plugin/logging.h"
43
 
#include "drizzled/plugin/transactional_storage_engine.h"
44
 
#include "drizzled/probes.h"
45
 
#include "drizzled/table_proto.h"
46
 
#include "drizzled/db.h"
47
 
#include "drizzled/pthread_globals.h"
48
 
#include "drizzled/transaction_services.h"
49
 
 
50
 
#include "plugin/myisam/myisam.h"
51
 
#include "drizzled/internal/iocache.h"
52
 
 
53
 
#include <fcntl.h>
54
 
#include <algorithm>
55
 
#include <climits>
56
 
 
57
 
using namespace std;
58
 
namespace drizzled
59
 
{
60
 
 
61
 
extern "C"
62
 
{
63
 
  unsigned char *get_var_key(user_var_entry *entry, size_t *length, bool );
64
 
  void free_user_var(user_var_entry *entry);
65
 
}
 
38
#include <drizzled/scheduling.h>
66
39
 
67
40
/*
68
41
  The following is used to initialise Table_ident with a internal
74
47
const char * const Session::DEFAULT_WHERE= "field list";
75
48
extern pthread_key_t THR_Session;
76
49
extern pthread_key_t THR_Mem_root;
77
 
extern uint32_t max_used_connections;
78
 
extern atomic<uint32_t> connection_count;
79
50
 
 
51
#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
 
52
/* Used templates */
 
53
template class List<Key>;
 
54
template class List_iterator<Key>;
 
55
template class List<Key_part_spec>;
 
56
template class List_iterator<Key_part_spec>;
 
57
template class List<Alter_drop>;
 
58
template class List_iterator<Alter_drop>;
 
59
template class List<Alter_column>;
 
60
template class List_iterator<Alter_column>;
 
61
#endif
80
62
 
81
63
/****************************************************************************
82
64
** User variables
83
65
****************************************************************************/
84
 
unsigned char *get_var_key(user_var_entry *entry, size_t *length, bool )
 
66
extern "C" unsigned char *get_var_key(user_var_entry *entry, size_t *length,
 
67
                              bool )
85
68
{
86
69
  *length= entry->name.length;
87
70
  return (unsigned char*) entry->name.str;
88
71
}
89
72
 
90
 
void free_user_var(user_var_entry *entry)
 
73
extern "C" void free_user_var(user_var_entry *entry)
91
74
{
92
 
  delete entry;
 
75
  char *pos= (char*) entry+ALIGN_SIZE(sizeof(*entry));
 
76
  if (entry->value && entry->value != pos)
 
77
    free(entry->value);
 
78
  free((char*) entry);
93
79
}
94
80
 
95
81
bool Key_part_spec::operator==(const Key_part_spec& other) const
99
85
         !strcmp(field_name.str, other.field_name.str);
100
86
}
101
87
 
102
 
Open_tables_state::Open_tables_state(uint64_t version_arg)
103
 
  :version(version_arg), backups_available(false)
 
88
Open_tables_state::Open_tables_state(ulong version_arg)
 
89
  :version(version_arg), state_flags(0U)
104
90
{
105
91
  reset_open_tables_state();
106
92
}
111
97
extern "C" int mysql_tmpfile(const char *prefix)
112
98
{
113
99
  char filename[FN_REFLEN];
114
 
  int fd = internal::create_temp_file(filename, drizzle_tmpdir, prefix, MYF(MY_WME));
 
100
  File fd = create_temp_file(filename, drizzle_tmpdir, prefix, MYF(MY_WME));
115
101
  if (fd >= 0) {
116
102
    unlink(filename);
117
103
  }
145
131
  return session->get_proc_info();
146
132
}
147
133
 
148
 
void **Session::getEngineData(const plugin::MonitoredInTransaction *monitored)
149
 
{
150
 
  return static_cast<void **>(&ha_data[monitored->getId()].ha_ptr);
151
 
}
152
 
 
153
 
ResourceContext *Session::getResourceContext(const plugin::MonitoredInTransaction *monitored,
154
 
                                             size_t index)
155
 
{
156
 
  return &ha_data[monitored->getId()].resource_context[index];
 
134
extern "C"
 
135
void **session_ha_data(const Session *session, const struct StorageEngine *engine)
 
136
{
 
137
  return (void **) &session->ha_data[engine->slot].ha_ptr;
157
138
}
158
139
 
159
140
extern "C"
174
155
  return (int) session->variables.tx_isolation;
175
156
}
176
157
 
177
 
Session::Session(plugin::Client *client_arg)
 
158
extern "C"
 
159
void session_inc_row_count(Session *session)
 
160
{
 
161
  session->row_count++;
 
162
}
 
163
 
 
164
Session::Session(Protocol *protocol_arg)
178
165
  :
 
166
  Statement(&main_lex, &main_mem_root, /* statement id */ 0),
179
167
  Open_tables_state(refresh_version),
180
 
  mem_root(&main_mem_root),
181
 
  lex(&main_lex),
182
 
  query(),
183
 
  client(client_arg),
184
 
  scheduler(NULL),
185
 
  scheduler_arg(NULL),
186
168
  lock_id(&main_lock_id),
187
169
  user_time(0),
188
 
  ha_data(plugin::num_trx_monitored_objects),
189
170
  arg_of_last_insert_id_function(false),
190
171
  first_successful_insert_id_in_prev_stmt(0),
191
172
  first_successful_insert_id_in_cur_stmt(0),
200
181
  derived_tables_processing(false),
201
182
  tablespace_op(false),
202
183
  m_lip(NULL),
203
 
  cached_table(0),
204
 
  transaction_message(NULL),
205
 
  statement_message(NULL)
 
184
  scheduler(0),
 
185
  cached_table(0)
206
186
{
 
187
  uint64_t tmp;
 
188
 
207
189
  memset(process_list_info, 0, PROCESS_LIST_WIDTH);
208
 
  client->setSession(this);
209
190
 
210
191
  /*
211
192
    Pass nominal parameters to init_alloc_root only to ensure that
212
193
    the destructor works OK in case of an error. The main_mem_root
213
194
    will be re-initialized in init_for_queries().
214
195
  */
215
 
  memory::init_sql_alloc(&main_mem_root, memory::ROOT_MIN_BLOCK_SIZE, 0);
 
196
  init_sql_alloc(&main_mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0);
216
197
  thread_stack= NULL;
217
198
  count_cuted_fields= CHECK_FIELD_IGNORE;
218
199
  killed= NOT_KILLED;
231
212
  thread_id= 0;
232
213
  file_id = 0;
233
214
  query_id= 0;
234
 
  warn_query_id= 0;
 
215
  warn_id= 0;
 
216
  memset(ha_data, 0, sizeof(ha_data));
 
217
  replication_data= 0;
235
218
  mysys_var= 0;
236
219
  dbug_sentry=Session_SENTRY_MAGIC;
 
220
  client_capabilities= 0;                       // minimalistic client
237
221
  cleanup_done= abort_on_warning= no_warnings_for_error= false;
 
222
  peer_port= 0;                                 // For SHOW PROCESSLIST
 
223
  transaction.on= 1;
238
224
  pthread_mutex_init(&LOCK_delete, MY_MUTEX_INIT_FAST);
239
225
 
240
226
  /* Variables with default values */
257
243
  else
258
244
    options &= ~OPTION_BIG_SELECTS;
259
245
 
 
246
  transaction.all.modified_non_trans_table= transaction.stmt.modified_non_trans_table= false;
260
247
  open_options=ha_open_options;
261
248
  update_lock_default= TL_WRITE;
262
249
  session_tx_isolation= (enum_tx_isolation) variables.tx_isolation;
266
253
  memset(&status_var, 0, sizeof(status_var));
267
254
 
268
255
  /* Initialize sub structures */
269
 
  memory::init_sql_alloc(&warn_root, WARN_ALLOC_BLOCK_SIZE, WARN_ALLOC_PREALLOC_SIZE);
 
256
  init_sql_alloc(&warn_root, WARN_ALLOC_BLOCK_SIZE, WARN_ALLOC_PREALLOC_SIZE);
270
257
  hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0,
271
258
            (hash_get_key) get_var_key,
272
259
            (hash_free_key) free_user_var, 0);
273
260
 
 
261
  /* Protocol */
 
262
  protocol= protocol_arg;
 
263
  protocol->setSession(this);
 
264
 
 
265
  const Query_id& local_query_id= Query_id::get_query_id();
 
266
  tmp= sql_rnd();
 
267
  protocol->setRandom(tmp + (uint64_t) &protocol,
 
268
                      tmp + (uint64_t)local_query_id.value());
274
269
  substitute_null_with_insert_id = false;
275
270
  thr_lock_info_init(&lock_info); /* safety: will be reset after start */
276
271
  thr_lock_owner_init(&main_lock_id, &lock_info);
278
273
  m_internal_handler= NULL;
279
274
}
280
275
 
281
 
void Session::free_items()
 
276
void Statement::free_items()
282
277
{
283
278
  Item *next;
284
 
  /* This works because items are allocated with memory::sql_alloc() */
 
279
  /* This works because items are allocated with sql_alloc() */
285
280
  for (; free_list; free_list= next)
286
281
  {
287
282
    next= free_list->next;
354
349
}
355
350
#endif
356
351
 
 
352
/*
 
353
  Init Session for query processing.
 
354
  This has to be called once before we call mysql_parse.
 
355
  See also comments in session.h.
 
356
*/
 
357
 
 
358
void Session::init_for_queries()
 
359
{
 
360
  set_time();
 
361
  ha_enable_transaction(this,true);
 
362
 
 
363
  reset_root_defaults(mem_root, variables.query_alloc_block_size,
 
364
                      variables.query_prealloc_size);
 
365
  reset_root_defaults(&transaction.mem_root,
 
366
                      variables.trans_alloc_block_size,
 
367
                      variables.trans_prealloc_size);
 
368
  transaction.xid_state.xid.null();
 
369
  transaction.xid_state.in_session=1;
 
370
}
 
371
 
 
372
 
357
373
/* Do operations that may take a long time */
358
374
 
359
375
void Session::cleanup(void)
368
384
  }
369
385
#endif
370
386
  {
371
 
    TransactionServices &transaction_services= TransactionServices::singleton();
372
 
    transaction_services.ha_rollback_trans(this, true);
 
387
    ha_rollback(this);
373
388
    xid_cache_delete(&transaction.xid_state);
374
389
  }
375
390
  hash_free(&user_vars);
383
398
 
384
399
Session::~Session()
385
400
{
386
 
  this->checkSentry();
 
401
  Session_CHECK_SENTRY(this);
387
402
  add_to_status(&global_status_var, &status_var);
388
403
 
389
 
  if (client->isConnected())
 
404
  if (protocol->isConnected())
390
405
  {
391
406
    if (global_system_variables.log_warnings)
392
 
        errmsg_printf(ERRMSG_LVL_WARN, ER(ER_FORCING_CLOSE),internal::my_progname,
 
407
        errmsg_printf(ERRMSG_LVL_WARN, ER(ER_FORCING_CLOSE),my_progname,
393
408
                      thread_id,
394
 
                      (getSecurityContext().getUser().c_str() ?
395
 
                       getSecurityContext().getUser().c_str() : ""));
 
409
                      (security_ctx.user.c_str() ?
 
410
                       security_ctx.user.c_str() : ""));
396
411
    disconnect(0, false);
397
412
  }
398
413
 
399
414
  /* Close connection */
400
 
  client->close();
401
 
  delete client;
 
415
  protocol->close();
 
416
  delete protocol;
402
417
 
403
418
  if (cleanup_done == false)
404
419
    cleanup();
405
420
 
406
 
  plugin::StorageEngine::closeConnection(this);
 
421
  ha_close_connection(this);
407
422
  plugin_sessionvar_cleanup(this);
408
423
 
 
424
  if (db)
 
425
  {
 
426
    free(db);
 
427
    db= NULL;
 
428
  }
409
429
  free_root(&warn_root,MYF(0));
 
430
  free_root(&transaction.mem_root,MYF(0));
410
431
  mysys_var=0;                                  // Safety (shouldn't be needed)
411
432
  dbug_sentry= Session_SENTRY_GONE;
412
433
 
413
434
  free_root(&main_mem_root, MYF(0));
414
435
  pthread_setspecific(THR_Session,  0);
415
436
 
416
 
  plugin::Logging::postEndDo(this);
417
437
 
418
438
  /* Ensure that no one is using Session */
419
439
  pthread_mutex_unlock(&LOCK_delete);
433
453
    If this assumption will change, then we have to explictely add
434
454
    the other variables after the while loop
435
455
*/
436
 
void add_to_status(system_status_var *to_var, system_status_var *from_var)
 
456
void add_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var)
437
457
{
438
458
  ulong *end= (ulong*) ((unsigned char*) to_var +
439
 
                        offsetof(system_status_var, last_system_status_var) +
 
459
                        offsetof(STATUS_VAR, last_system_status_var) +
440
460
                        sizeof(ulong));
441
461
  ulong *to= (ulong*) to_var, *from= (ulong*) from_var;
442
462
 
456
476
  NOTE
457
477
    This function assumes that all variables are long/ulong.
458
478
*/
459
 
void add_diff_to_status(system_status_var *to_var, system_status_var *from_var,
460
 
                        system_status_var *dec_var)
 
479
void add_diff_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var,
 
480
                        STATUS_VAR *dec_var)
461
481
{
462
 
  ulong *end= (ulong*) ((unsigned char*) to_var + offsetof(system_status_var,
 
482
  ulong *end= (ulong*) ((unsigned char*) to_var + offsetof(STATUS_VAR,
463
483
                                                  last_system_status_var) +
464
484
                        sizeof(ulong));
465
485
  ulong *to= (ulong*) to_var, *from= (ulong*) from_var, *dec= (ulong*) dec_var;
470
490
 
471
491
void Session::awake(Session::killed_state state_to_set)
472
492
{
473
 
  this->checkSentry();
 
493
  Session_CHECK_SENTRY(this);
474
494
  safe_mutex_assert_owner(&LOCK_delete);
 
495
  Scheduler &thread_scheduler= get_thread_scheduler();
475
496
 
476
497
  killed= state_to_set;
477
498
  if (state_to_set != Session::KILL_QUERY)
478
499
  {
479
 
    scheduler->killSession(this);
480
 
    DRIZZLE_CONNECTION_DONE(thread_id);
 
500
    thread_scheduler.post_kill_notification(this);
481
501
  }
482
502
  if (mysys_var)
483
503
  {
513
533
 
514
534
/*
515
535
  Remember the location of thread info, the structure needed for
516
 
  memory::sql_alloc() and the structure for the net buffer
 
536
  sql_alloc() and the structure for the net buffer
517
537
*/
518
 
bool Session::storeGlobals()
 
538
bool Session::store_globals()
519
539
{
520
540
  /*
521
541
    Assert that thread_stack is initialized: it's necessary to be able
525
545
 
526
546
  if (pthread_setspecific(THR_Session,  this) ||
527
547
      pthread_setspecific(THR_Mem_root, &mem_root))
528
 
    return true;
529
 
 
 
548
    return 1;
530
549
  mysys_var=my_thread_var;
531
550
 
532
551
  /*
541
560
    created in another thread
542
561
  */
543
562
  thr_lock_info_init(&lock_info);
544
 
  return false;
 
563
  return 0;
545
564
}
546
565
 
547
 
/*
548
 
  Init Session for query processing.
549
 
  This has to be called once before we call mysql_parse.
550
 
  See also comments in session.h.
551
 
*/
552
 
 
553
566
void Session::prepareForQueries()
554
567
{
555
568
  if (variables.max_join_size == HA_POS_ERROR)
556
569
    options |= OPTION_BIG_SELECTS;
 
570
  if (client_capabilities & CLIENT_COMPRESS)
 
571
  {
 
572
    protocol->enableCompression();
 
573
  }
557
574
 
558
575
  version= refresh_version;
559
576
  set_proc_info(NULL);
560
577
  command= COM_SLEEP;
561
578
  set_time();
562
 
 
563
 
  reset_root_defaults(mem_root, variables.query_alloc_block_size,
564
 
                      variables.query_prealloc_size);
565
 
  transaction.xid_state.xid.null();
566
 
  transaction.xid_state.in_session=1;
 
579
  init_for_queries();
567
580
}
568
581
 
569
582
bool Session::initGlobals()
570
583
{
571
 
  if (storeGlobals())
 
584
  if (store_globals())
572
585
  {
573
586
    disconnect(ER_OUT_OF_RESOURCES, true);
574
587
    statistic_increment(aborted_connects, &LOCK_status);
575
 
    return true;
576
 
  }
577
 
  return false;
578
 
}
579
 
 
580
 
void Session::run()
581
 
{
582
 
  if (initGlobals() || authenticate())
583
 
  {
584
 
    disconnect(0, true);
585
 
    return;
586
 
  }
587
 
 
588
 
  prepareForQueries();
589
 
 
590
 
  while (! client->haveError() && killed != KILL_CONNECTION)
591
 
  {
592
 
    if (! executeStatement())
593
 
      break;
594
 
  }
595
 
 
596
 
  disconnect(0, true);
597
 
}
598
 
 
599
 
bool Session::schedule()
600
 
{
601
 
  scheduler= plugin::Scheduler::getScheduler();
602
 
  assert(scheduler);
603
 
 
604
 
  connection_count.increment();
605
 
 
606
 
  if (connection_count > max_used_connections)
607
 
    max_used_connections= connection_count;
608
 
 
609
 
  thread_id= variables.pseudo_thread_id= global_thread_id++;
610
 
 
611
 
  pthread_mutex_lock(&LOCK_thread_count);
612
 
  getSessionList().push_back(this);
613
 
  pthread_mutex_unlock(&LOCK_thread_count);
614
 
 
615
 
  if (scheduler->addSession(this))
616
 
  {
617
 
    DRIZZLE_CONNECTION_START(thread_id);
618
 
    char error_message_buff[DRIZZLE_ERRMSG_SIZE];
619
 
 
620
 
    killed= Session::KILL_CONNECTION;
621
 
 
622
 
    statistic_increment(aborted_connects, &LOCK_status);
623
 
 
624
 
    /* Can't use my_error() since store_globals has not been called. */
625
 
    /* TODO replace will better error message */
626
 
    snprintf(error_message_buff, sizeof(error_message_buff),
627
 
             ER(ER_CANT_CREATE_THREAD), 1);
628
 
    client->sendError(ER_CANT_CREATE_THREAD, error_message_buff);
629
 
    return true;
630
 
  }
631
 
 
632
 
  return false;
633
 
}
634
 
 
635
 
 
636
 
const char* Session::enter_cond(pthread_cond_t *cond,
637
 
                                pthread_mutex_t* mutex,
638
 
                                const char* msg)
639
 
{
640
 
  const char* old_msg = get_proc_info();
641
 
  safe_mutex_assert_owner(mutex);
642
 
  mysys_var->current_mutex = mutex;
643
 
  mysys_var->current_cond = cond;
644
 
  this->set_proc_info(msg);
645
 
  return old_msg;
646
 
}
647
 
 
648
 
void Session::exit_cond(const char* old_msg)
649
 
{
650
 
  /*
651
 
    Putting the mutex unlock in exit_cond() ensures that
652
 
    mysys_var->current_mutex is always unlocked _before_ mysys_var->mutex is
653
 
    locked (if that would not be the case, you'll get a deadlock if someone
654
 
    does a Session::awake() on you).
655
 
  */
656
 
  pthread_mutex_unlock(mysys_var->current_mutex);
657
 
  pthread_mutex_lock(&mysys_var->mutex);
658
 
  mysys_var->current_mutex = 0;
659
 
  mysys_var->current_cond = 0;
660
 
  this->set_proc_info(old_msg);
661
 
  pthread_mutex_unlock(&mysys_var->mutex);
 
588
    Scheduler &thread_scheduler= get_thread_scheduler();
 
589
    thread_scheduler.end_thread(this, 0);
 
590
    return false;
 
591
  }
 
592
  return true;
662
593
}
663
594
 
664
595
bool Session::authenticate()
665
596
{
666
597
  lex_start(this);
667
 
  if (client->authenticate())
668
 
    return false;
 
598
  if (protocol->authenticate())
 
599
    return true;
669
600
 
670
601
  statistic_increment(aborted_connects, &LOCK_status);
671
 
  return true;
 
602
  return false;
672
603
}
673
604
 
674
605
bool Session::checkUser(const char *passwd, uint32_t passwd_len, const char *in_db)
675
606
{
676
 
  const string passwd_str(passwd, passwd_len);
677
 
  bool is_authenticated=
678
 
    plugin::Authentication::isAuthenticated(getSecurityContext(),
679
 
                                            passwd_str);
 
607
  LEX_STRING db_str= { (char *) in_db, in_db ? strlen(in_db) : 0 };
 
608
  bool is_authenticated;
 
609
 
 
610
  /*
 
611
    Clear session->db as it points to something, that will be freed when
 
612
    connection is closed. We don't want to accidentally free a wrong
 
613
    pointer if connect failed. Also in case of 'CHANGE USER' failure,
 
614
    current database will be switched to 'no database selected'.
 
615
  */
 
616
  reset_db(NULL, 0);
 
617
 
 
618
  if (passwd_len != 0 && passwd_len != SCRAMBLE_LENGTH)
 
619
  {
 
620
    my_error(ER_HANDSHAKE_ERROR, MYF(0), security_ctx.ip.c_str());
 
621
    return false;
 
622
  }
 
623
 
 
624
  is_authenticated= authenticate_user(this, passwd);
680
625
 
681
626
  if (is_authenticated != true)
682
627
  {
683
 
    /* isAuthenticated has pushed the error message */
 
628
    my_error(ER_ACCESS_DENIED_ERROR, MYF(0),
 
629
             security_ctx.user.c_str(),
 
630
             security_ctx.ip.c_str(),
 
631
             passwd_len ? ER(ER_YES) : ER(ER_NO));
 
632
 
684
633
    return false;
685
634
  }
686
635
 
 
636
  security_ctx.skip_grants();
 
637
 
687
638
  /* Change database if necessary */
688
639
  if (in_db && in_db[0])
689
640
  {
690
 
    SchemaIdentifier identifier(in_db);
691
 
    if (mysql_change_db(this, identifier))
 
641
    if (mysql_change_db(this, &db_str, false))
692
642
    {
693
643
      /* mysql_change_db() has pushed the error message. */
694
644
      return false;
713
663
    (see my_message_sql)
714
664
  */
715
665
  lex->current_select= 0;
716
 
  clear_error();
717
 
  main_da.reset_diagnostics_area();
718
666
 
719
 
  if (client->readCommand(&l_packet, &packet_length) == false)
 
667
  if (protocol->readCommand(&l_packet, &packet_length) == false)
720
668
    return false;
721
669
 
722
670
  if (packet_length == 0)
747
695
    in_packet_length--;
748
696
  }
749
697
 
750
 
  query.assign(in_packet, in_packet + in_packet_length);
 
698
  /* We must allocate some extra memory for the cached query string */
 
699
  query_length= 0; /* Extra safety: Avoid races */
 
700
  query= (char*) memdup_w_gap((unsigned char*) in_packet, in_packet_length, db_length + 1);
 
701
  if (! query)
 
702
    return false;
 
703
 
 
704
  query[in_packet_length]=0;
 
705
  query_length= in_packet_length;
 
706
 
 
707
  /* Reclaim some memory */
 
708
  packet.shrink(variables.net_buffer_length);
 
709
  convert_buffer.shrink(variables.net_buffer_length);
751
710
 
752
711
  return true;
753
712
}
756
715
{
757
716
  bool do_release= 0;
758
717
  bool result= true;
759
 
  TransactionServices &transaction_services= TransactionServices::singleton();
760
718
 
761
719
  if (transaction.xid_state.xa_state != XA_NOTR)
762
720
  {
763
721
    my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[transaction.xid_state.xa_state]);
764
722
    return false;
765
723
  }
766
 
  switch (completion)
 
724
  switch (completion) 
767
725
  {
768
726
    case COMMIT:
769
727
      /*
772
730
       * (Which of course should never happen...)
773
731
       */
774
732
      server_status&= ~SERVER_STATUS_IN_TRANS;
775
 
      if (transaction_services.ha_commit_trans(this, true))
 
733
      if (ha_commit(this))
776
734
        result= false;
777
 
      options&= ~(OPTION_BEGIN);
 
735
      options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
 
736
      transaction.all.modified_non_trans_table= false;
778
737
      break;
779
738
    case COMMIT_RELEASE:
780
739
      do_release= 1; /* fall through */
789
748
    case ROLLBACK_AND_CHAIN:
790
749
    {
791
750
      server_status&= ~SERVER_STATUS_IN_TRANS;
792
 
      if (transaction_services.ha_rollback_trans(this, true))
 
751
      if (ha_rollback(this))
793
752
        result= false;
794
 
      options&= ~(OPTION_BEGIN);
 
753
      options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
 
754
      transaction.all.modified_non_trans_table= false;
795
755
      if (result == true && (completion == ROLLBACK_AND_CHAIN))
796
756
        result= startTransaction();
797
757
      break;
812
772
bool Session::endActiveTransaction()
813
773
{
814
774
  bool result= true;
815
 
  TransactionServices &transaction_services= TransactionServices::singleton();
816
775
 
817
776
  if (transaction.xid_state.xa_state != XA_NOTR)
818
777
  {
822
781
  if (options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
823
782
  {
824
783
    server_status&= ~SERVER_STATUS_IN_TRANS;
825
 
    if (transaction_services.ha_commit_trans(this, true))
 
784
    if (ha_commit(this))
826
785
      result= false;
827
786
  }
828
 
  options&= ~(OPTION_BEGIN);
 
787
  options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
 
788
  transaction.all.modified_non_trans_table= false;
829
789
  return result;
830
790
}
831
791
 
832
 
bool Session::startTransaction(start_transaction_option_t opt)
 
792
bool Session::startTransaction()
833
793
{
834
794
  bool result= true;
835
795
 
836
796
  if (! endActiveTransaction())
837
 
  {
838
797
    result= false;
839
 
  }
840
798
  else
841
799
  {
842
800
    options|= OPTION_BEGIN;
843
801
    server_status|= SERVER_STATUS_IN_TRANS;
844
 
 
845
 
    if (plugin::TransactionalStorageEngine::notifyStartTransaction(this, opt))
846
 
    {
847
 
      result= false;
848
 
    }
 
802
    if (lex->start_transaction_opt & DRIZZLE_START_TRANS_OPT_WITH_CONS_SNAPSHOT)
 
803
      if (ha_start_consistent_snapshot(this))
 
804
        result= false;
849
805
  }
850
 
 
851
806
  return result;
852
807
}
853
808
 
886
841
  @return  NULL on failure, or pointer to the LEX_STRING object
887
842
*/
888
843
LEX_STRING *Session::make_lex_string(LEX_STRING *lex_str,
889
 
                                     const std::string &str,
890
 
                                     bool allocate_lex_string)
891
 
{
892
 
  return make_lex_string(lex_str, str.c_str(), str.length(), allocate_lex_string);
893
 
}
894
 
 
895
 
LEX_STRING *Session::make_lex_string(LEX_STRING *lex_str,
896
 
                                     const char* str, uint32_t length,
897
 
                                     bool allocate_lex_string)
 
844
                                 const char* str, uint32_t length,
 
845
                                 bool allocate_lex_string)
898
846
{
899
847
  if (allocate_lex_string)
900
848
    if (!(lex_str= (LEX_STRING *)alloc(sizeof(LEX_STRING))))
905
853
  return lex_str;
906
854
}
907
855
 
 
856
/* routings to adding tables to list of changed in transaction tables */
 
857
inline static void list_include(CHANGED_TableList** prev,
 
858
                                CHANGED_TableList* curr,
 
859
                                CHANGED_TableList* new_table)
 
860
{
 
861
  if (new_table)
 
862
  {
 
863
    *prev = new_table;
 
864
    (*prev)->next = curr;
 
865
  }
 
866
}
 
867
 
 
868
/* add table to list of changed in transaction tables */
 
869
 
 
870
void Session::add_changed_table(Table *table)
 
871
{
 
872
  assert((options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) &&
 
873
              table->file->has_transactions());
 
874
  add_changed_table(table->s->table_cache_key.str,
 
875
                    (long) table->s->table_cache_key.length);
 
876
}
 
877
 
 
878
 
 
879
void Session::add_changed_table(const char *key, long key_length)
 
880
{
 
881
  CHANGED_TableList **prev_changed = &transaction.changed_tables;
 
882
  CHANGED_TableList *curr = transaction.changed_tables;
 
883
 
 
884
  for (; curr; prev_changed = &(curr->next), curr = curr->next)
 
885
  {
 
886
    int cmp =  (long)curr->key_length - (long)key_length;
 
887
    if (cmp < 0)
 
888
    {
 
889
      list_include(prev_changed, curr, changed_table_dup(key, key_length));
 
890
      return;
 
891
    }
 
892
    else if (cmp == 0)
 
893
    {
 
894
      cmp = memcmp(curr->key, key, curr->key_length);
 
895
      if (cmp < 0)
 
896
      {
 
897
        list_include(prev_changed, curr, changed_table_dup(key, key_length));
 
898
        return;
 
899
      }
 
900
      else if (cmp == 0)
 
901
      {
 
902
        return;
 
903
      }
 
904
    }
 
905
  }
 
906
  *prev_changed = changed_table_dup(key, key_length);
 
907
}
 
908
 
 
909
 
 
910
CHANGED_TableList* Session::changed_table_dup(const char *key, long key_length)
 
911
{
 
912
  CHANGED_TableList* new_table =
 
913
    (CHANGED_TableList*) trans_alloc(ALIGN_SIZE(sizeof(CHANGED_TableList))+
 
914
                                      key_length + 1);
 
915
  if (!new_table)
 
916
  {
 
917
    my_error(EE_OUTOFMEMORY, MYF(ME_BELL),
 
918
             ALIGN_SIZE(sizeof(TableList)) + key_length + 1);
 
919
    killed= KILL_CONNECTION;
 
920
    return 0;
 
921
  }
 
922
 
 
923
  new_table->key= ((char*)new_table)+ ALIGN_SIZE(sizeof(CHANGED_TableList));
 
924
  new_table->next = 0;
 
925
  new_table->key_length = key_length;
 
926
  ::memcpy(new_table->key, key, key_length);
 
927
  return new_table;
 
928
}
 
929
 
 
930
 
908
931
int Session::send_explain_fields(select_result *result)
909
932
{
910
933
  List<Item> field_list;
940
963
  }
941
964
  item->maybe_null= 1;
942
965
  field_list.push_back(new Item_empty_string("Extra", 255, cs));
943
 
  return (result->send_fields(field_list));
944
 
}
945
 
 
946
 
void select_result::send_error(uint32_t errcode, const char *err)
947
 
{
948
 
  my_message(errcode, err, MYF(0));
 
966
  return (result->send_fields(field_list,
 
967
                              Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF));
949
968
}
950
969
 
951
970
/************************************************************************
957
976
  my_message(errcode, err, MYF(0));
958
977
  if (file > 0)
959
978
  {
960
 
    (void) end_io_cache(cache);
961
 
    (void) internal::my_close(file, MYF(0));
962
 
    (void) internal::my_delete(path, MYF(0));           // Delete file on error
 
979
    (void) end_io_cache(&cache);
 
980
    (void) my_close(file,MYF(0));
 
981
    (void) my_delete(path,MYF(0));              // Delete file on error
963
982
    file= -1;
964
983
  }
965
984
}
967
986
 
968
987
bool select_to_file::send_eof()
969
988
{
970
 
  int error= test(end_io_cache(cache));
971
 
  if (internal::my_close(file, MYF(MY_WME)))
 
989
  int error= test(end_io_cache(&cache));
 
990
  if (my_close(file,MYF(MY_WME)))
972
991
    error= 1;
973
992
  if (!error)
974
993
  {
989
1008
  /* In case of error send_eof() may be not called: close the file here. */
990
1009
  if (file >= 0)
991
1010
  {
992
 
    (void) end_io_cache(cache);
993
 
    (void) internal::my_close(file, MYF(0));
 
1011
    (void) end_io_cache(&cache);
 
1012
    (void) my_close(file,MYF(0));
994
1013
    file= -1;
995
1014
  }
996
1015
  path[0]= '\0';
997
1016
  row_count= 0;
998
1017
}
999
1018
 
1000
 
select_to_file::select_to_file(file_exchange *ex)
1001
 
  : exchange(ex),
1002
 
    file(-1),
1003
 
    cache(static_cast<internal::IO_CACHE *>(memory::sql_calloc(sizeof(internal::IO_CACHE)))),
1004
 
    row_count(0L)
1005
 
{
1006
 
  path[0]=0;
1007
 
}
1008
1019
 
1009
1020
select_to_file::~select_to_file()
1010
1021
{
1011
 
  cleanup();
 
1022
  if (file >= 0)
 
1023
  {                                     // This only happens in case of error
 
1024
    (void) end_io_cache(&cache);
 
1025
    (void) my_close(file,MYF(0));
 
1026
    file= -1;
 
1027
  }
1012
1028
}
1013
1029
 
1014
1030
/***************************************************************************
1037
1053
*/
1038
1054
 
1039
1055
 
1040
 
static int create_file(Session *session, char *path, file_exchange *exchange, internal::IO_CACHE *cache)
 
1056
static File create_file(Session *session, char *path, file_exchange *exchange, IO_CACHE *cache)
1041
1057
{
1042
 
  int file;
 
1058
  File file;
1043
1059
  uint32_t option= MY_UNPACK_FILENAME | MY_RELATIVE_PATH;
1044
1060
 
1045
1061
#ifdef DONT_ALLOW_FULL_LOAD_DATA_PATHS
1046
1062
  option|= MY_REPLACE_DIR;                      // Force use of db directory
1047
1063
#endif
1048
1064
 
1049
 
  if (!internal::dirname_length(exchange->file_name))
 
1065
  if (!dirname_length(exchange->file_name))
1050
1066
  {
1051
1067
    strcpy(path, drizzle_real_data_home);
1052
 
    if (! session->db.empty())
1053
 
      strncat(path, session->db.c_str(), FN_REFLEN-strlen(drizzle_real_data_home)-1);
1054
 
    (void) internal::fn_format(path, exchange->file_name, path, "", option);
 
1068
    if (session->db)
 
1069
      strncat(path, session->db, FN_REFLEN-strlen(drizzle_real_data_home)-1);
 
1070
    (void) fn_format(path, exchange->file_name, path, "", option);
1055
1071
  }
1056
1072
  else
1057
 
    (void) internal::fn_format(path, exchange->file_name, drizzle_real_data_home, "", option);
 
1073
    (void) fn_format(path, exchange->file_name, drizzle_real_data_home, "", option);
1058
1074
 
1059
1075
  if (opt_secure_file_priv &&
1060
1076
      strncmp(opt_secure_file_priv, path, strlen(opt_secure_file_priv)))
1070
1086
    return -1;
1071
1087
  }
1072
1088
  /* Create the file world readable */
1073
 
  if ((file= internal::my_create(path, 0666, O_WRONLY|O_EXCL, MYF(MY_WME))) < 0)
 
1089
  if ((file= my_create(path, 0666, O_WRONLY|O_EXCL, MYF(MY_WME))) < 0)
1074
1090
    return file;
 
1091
#ifdef HAVE_FCHMOD
1075
1092
  (void) fchmod(file, 0666);                    // Because of umask()
1076
 
  if (init_io_cache(cache, file, 0L, internal::WRITE_CACHE, 0L, 1, MYF(MY_WME)))
 
1093
#else
 
1094
  (void) chmod(path, 0666);
 
1095
#endif
 
1096
  if (init_io_cache(cache, file, 0L, WRITE_CACHE, 0L, 1, MYF(MY_WME)))
1077
1097
  {
1078
 
    internal::my_close(file, MYF(0));
1079
 
    internal::my_delete(path, MYF(0));  // Delete file on error, it was just created
 
1098
    my_close(file, MYF(0));
 
1099
    my_delete(path, MYF(0));  // Delete file on error, it was just created
1080
1100
    return -1;
1081
1101
  }
1082
1102
  return file;
1137
1157
    return 1;
1138
1158
  }
1139
1159
 
1140
 
  if ((file= create_file(session, path, exchange, cache)) < 0)
 
1160
  if ((file= create_file(session, path, exchange, &cache)) < 0)
1141
1161
    return 1;
1142
1162
 
1143
1163
  return 0;
1144
1164
}
1145
1165
 
 
1166
 
 
1167
#define NEED_ESCAPING(x) ((int) (unsigned char) (x) == escape_char    || \
 
1168
                          (enclosed ? (int) (unsigned char) (x) == field_sep_char      \
 
1169
                                    : (int) (unsigned char) (x) == field_term_char) || \
 
1170
                          (int) (unsigned char) (x) == line_sep_char  || \
 
1171
                          !(x))
 
1172
 
1146
1173
bool select_export::send_data(List<Item> &items)
1147
1174
{
1148
1175
  char buff[MAX_FIELD_WIDTH],null_buff[2],space[MAX_FIELD_WIDTH];
1160
1187
  uint32_t used_length=0,items_left=items.elements;
1161
1188
  List_iterator_fast<Item> li(items);
1162
1189
 
1163
 
  if (my_b_write(cache,(unsigned char*) exchange->line_start->ptr(),
1164
 
                 exchange->line_start->length()))
 
1190
  if (my_b_write(&cache,(unsigned char*) exchange->line_start->ptr(),
 
1191
                 exchange->line_start->length()))
1165
1192
    goto err;
1166
1193
  while ((item=li++))
1167
1194
  {
1171
1198
    res=item->str_result(&tmp);
1172
1199
    if (res && enclosed)
1173
1200
    {
1174
 
      if (my_b_write(cache,(unsigned char*) exchange->enclosed->ptr(),
1175
 
                     exchange->enclosed->length()))
1176
 
        goto err;
 
1201
      if (my_b_write(&cache,(unsigned char*) exchange->enclosed->ptr(),
 
1202
                     exchange->enclosed->length()))
 
1203
        goto err;
1177
1204
    }
1178
1205
    if (!res)
1179
1206
    {                                           // NULL
1180
1207
      if (!fixed_row_size)
1181
1208
      {
1182
 
        if (escape_char != -1)                  // Use \N syntax
1183
 
        {
1184
 
          null_buff[0]=escape_char;
1185
 
          null_buff[1]='N';
1186
 
          if (my_b_write(cache,(unsigned char*) null_buff,2))
1187
 
            goto err;
1188
 
        }
1189
 
        else if (my_b_write(cache,(unsigned char*) "NULL",4))
1190
 
          goto err;
 
1209
        if (escape_char != -1)                  // Use \N syntax
 
1210
        {
 
1211
          null_buff[0]=escape_char;
 
1212
          null_buff[1]='N';
 
1213
          if (my_b_write(&cache,(unsigned char*) null_buff,2))
 
1214
            goto err;
 
1215
        }
 
1216
        else if (my_b_write(&cache,(unsigned char*) "NULL",4))
 
1217
          goto err;
1191
1218
      }
1192
1219
      else
1193
1220
      {
1194
 
        used_length=0;                          // Fill with space
 
1221
        used_length=0;                          // Fill with space
1195
1222
      }
1196
1223
    }
1197
1224
    else
1198
1225
    {
1199
1226
      if (fixed_row_size)
1200
 
        used_length= min(res->length(),item->max_length);
 
1227
        used_length=cmin(res->length(),item->max_length);
1201
1228
      else
1202
 
        used_length= res->length();
1203
 
 
 
1229
        used_length=res->length();
1204
1230
      if ((result_type == STRING_RESULT || is_unsafe_field_sep) &&
1205
 
          escape_char != -1)
 
1231
           escape_char != -1)
1206
1232
      {
1207
1233
        char *pos, *start, *end;
1208
1234
        const CHARSET_INFO * const res_charset= res->charset();
1209
1235
        const CHARSET_INFO * const character_set_client= default_charset_info;
1210
1236
 
1211
1237
        bool check_second_byte= (res_charset == &my_charset_bin) &&
1212
 
          character_set_client->
1213
 
          escape_with_backslash_is_dangerous;
 
1238
                                 character_set_client->
 
1239
                                 escape_with_backslash_is_dangerous;
1214
1240
        assert(character_set_client->mbmaxlen == 2 ||
1215
1241
               !character_set_client->escape_with_backslash_is_dangerous);
1216
 
        for (start=pos=(char*) res->ptr(),end=pos+used_length ;
1217
 
             pos != end ;
1218
 
             pos++)
1219
 
        {
1220
 
          if (use_mb(res_charset))
1221
 
          {
1222
 
            int l;
1223
 
            if ((l=my_ismbchar(res_charset, pos, end)))
1224
 
            {
1225
 
              pos += l-1;
1226
 
              continue;
1227
 
            }
1228
 
          }
 
1242
        for (start=pos=(char*) res->ptr(),end=pos+used_length ;
 
1243
             pos != end ;
 
1244
             pos++)
 
1245
        {
 
1246
#ifdef USE_MB
 
1247
          if (use_mb(res_charset))
 
1248
          {
 
1249
            int l;
 
1250
            if ((l=my_ismbchar(res_charset, pos, end)))
 
1251
            {
 
1252
              pos += l-1;
 
1253
              continue;
 
1254
            }
 
1255
          }
 
1256
#endif
1229
1257
 
1230
1258
          /*
1231
1259
            Special case when dumping BINARY/VARBINARY/BLOB values
1259
1287
            assert before the loop makes that sure.
1260
1288
          */
1261
1289
 
1262
 
          if ((needs_escaping(*pos, enclosed) ||
 
1290
          if ((NEED_ESCAPING(*pos) ||
1263
1291
               (check_second_byte &&
1264
1292
                my_mbcharlen(character_set_client, (unsigned char) *pos) == 2 &&
1265
1293
                pos + 1 < end &&
1266
 
                needs_escaping(pos[1], enclosed))) &&
 
1294
                NEED_ESCAPING(pos[1]))) &&
1267
1295
              /*
1268
 
                Don't escape field_term_char by doubling - doubling is only
1269
 
                valid for ENCLOSED BY characters:
 
1296
               Don't escape field_term_char by doubling - doubling is only
 
1297
               valid for ENCLOSED BY characters:
1270
1298
              */
1271
1299
              (enclosed || !is_ambiguous_field_term ||
1272
1300
               (int) (unsigned char) *pos != field_term_char))
1273
1301
          {
1274
 
            char tmp_buff[2];
 
1302
            char tmp_buff[2];
1275
1303
            tmp_buff[0]= ((int) (unsigned char) *pos == field_sep_char &&
1276
1304
                          is_ambiguous_field_sep) ?
1277
 
              field_sep_char : escape_char;
1278
 
            tmp_buff[1]= *pos ? *pos : '0';
1279
 
            if (my_b_write(cache,(unsigned char*) start,(uint32_t) (pos-start)) ||
1280
 
                my_b_write(cache,(unsigned char*) tmp_buff,2))
1281
 
              goto err;
1282
 
            start=pos+1;
1283
 
          }
1284
 
        }
1285
 
        if (my_b_write(cache,(unsigned char*) start,(uint32_t) (pos-start)))
1286
 
          goto err;
 
1305
                          field_sep_char : escape_char;
 
1306
            tmp_buff[1]= *pos ? *pos : '0';
 
1307
            if (my_b_write(&cache,(unsigned char*) start,(uint32_t) (pos-start)) ||
 
1308
                my_b_write(&cache,(unsigned char*) tmp_buff,2))
 
1309
              goto err;
 
1310
            start=pos+1;
 
1311
          }
 
1312
        }
 
1313
        if (my_b_write(&cache,(unsigned char*) start,(uint32_t) (pos-start)))
 
1314
          goto err;
1287
1315
      }
1288
 
      else if (my_b_write(cache,(unsigned char*) res->ptr(),used_length))
1289
 
        goto err;
 
1316
      else if (my_b_write(&cache,(unsigned char*) res->ptr(),used_length))
 
1317
        goto err;
1290
1318
    }
1291
1319
    if (fixed_row_size)
1292
1320
    {                                           // Fill with space
1293
1321
      if (item->max_length > used_length)
1294
1322
      {
1295
 
        /* QQ:  Fix by adding a my_b_fill() function */
1296
 
        if (!space_inited)
1297
 
        {
1298
 
          space_inited=1;
1299
 
          memset(space, ' ', sizeof(space));
1300
 
        }
1301
 
        uint32_t length=item->max_length-used_length;
1302
 
        for (; length > sizeof(space) ; length-=sizeof(space))
1303
 
        {
1304
 
          if (my_b_write(cache,(unsigned char*) space,sizeof(space)))
1305
 
            goto err;
1306
 
        }
1307
 
        if (my_b_write(cache,(unsigned char*) space,length))
1308
 
          goto err;
 
1323
        /* QQ:  Fix by adding a my_b_fill() function */
 
1324
        if (!space_inited)
 
1325
        {
 
1326
          space_inited=1;
 
1327
          memset(space, ' ', sizeof(space));
 
1328
        }
 
1329
        uint32_t length=item->max_length-used_length;
 
1330
        for (; length > sizeof(space) ; length-=sizeof(space))
 
1331
        {
 
1332
          if (my_b_write(&cache,(unsigned char*) space,sizeof(space)))
 
1333
            goto err;
 
1334
        }
 
1335
        if (my_b_write(&cache,(unsigned char*) space,length))
 
1336
          goto err;
1309
1337
      }
1310
1338
    }
1311
1339
    if (res && enclosed)
1312
1340
    {
1313
 
      if (my_b_write(cache, (unsigned char*) exchange->enclosed->ptr(),
 
1341
      if (my_b_write(&cache, (unsigned char*) exchange->enclosed->ptr(),
1314
1342
                     exchange->enclosed->length()))
1315
1343
        goto err;
1316
1344
    }
1317
1345
    if (--items_left)
1318
1346
    {
1319
 
      if (my_b_write(cache, (unsigned char*) exchange->field_term->ptr(),
 
1347
      if (my_b_write(&cache, (unsigned char*) exchange->field_term->ptr(),
1320
1348
                     field_term_length))
1321
1349
        goto err;
1322
1350
    }
1323
1351
  }
1324
 
  if (my_b_write(cache,(unsigned char*) exchange->line_term->ptr(),
1325
 
                 exchange->line_term->length()))
 
1352
  if (my_b_write(&cache,(unsigned char*) exchange->line_term->ptr(),
 
1353
                 exchange->line_term->length()))
1326
1354
    goto err;
1327
1355
  return(0);
1328
1356
err:
1339
1367
select_dump::prepare(List<Item> &, Select_Lex_Unit *u)
1340
1368
{
1341
1369
  unit= u;
1342
 
  return (int) ((file= create_file(session, path, exchange, cache)) < 0);
 
1370
  return (int) ((file= create_file(session, path, exchange, &cache)) < 0);
1343
1371
}
1344
1372
 
1345
1373
 
1366
1394
    res=item->str_result(&tmp);
1367
1395
    if (!res)                                   // If NULL
1368
1396
    {
1369
 
      if (my_b_write(cache,(unsigned char*) "",1))
 
1397
      if (my_b_write(&cache,(unsigned char*) "",1))
1370
1398
        goto err;
1371
1399
    }
1372
 
    else if (my_b_write(cache,(unsigned char*) res->ptr(),res->length()))
 
1400
    else if (my_b_write(&cache,(unsigned char*) res->ptr(),res->length()))
1373
1401
    {
1374
 
      my_error(ER_ERROR_ON_WRITE, MYF(0), path, errno);
 
1402
      my_error(ER_ERROR_ON_WRITE, MYF(0), path, my_errno);
1375
1403
      goto err;
1376
1404
    }
1377
1405
  }
1543
1571
 
1544
1572
bool Session::copy_db_to(char **p_db, size_t *p_db_length)
1545
1573
{
1546
 
  if (db.empty())
 
1574
  if (db == NULL)
1547
1575
  {
1548
1576
    my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
1549
1577
    return true;
1550
1578
  }
1551
 
  *p_db= strmake(db.c_str(), db.length());
1552
 
  *p_db_length= db.length();
 
1579
  *p_db= strmake(db, db_length);
 
1580
  *p_db_length= db_length;
1553
1581
  return false;
1554
1582
}
1555
1583
 
1564
1592
  quick_group= 1;
1565
1593
  table_charset= 0;
1566
1594
  precomputed_group_by= 0;
 
1595
  bit_fields_as_long= 0;
1567
1596
}
1568
1597
 
1569
1598
void Tmp_Table_Param::cleanup(void)
1576
1605
  }
1577
1606
}
1578
1607
 
 
1608
 
 
1609
void session_increment_bytes_sent(ulong length)
 
1610
{
 
1611
  Session *session=current_session;
 
1612
  if (likely(session != 0))
 
1613
  { /* current_session==0 when disconnect() calls net_send_error() */
 
1614
    session->status_var.bytes_sent+= length;
 
1615
  }
 
1616
}
 
1617
 
 
1618
 
 
1619
void session_increment_bytes_received(ulong length)
 
1620
{
 
1621
  current_session->status_var.bytes_received+= length;
 
1622
}
 
1623
 
 
1624
 
 
1625
void session_increment_net_big_packet_count(ulong length)
 
1626
{
 
1627
  current_session->status_var.net_big_packet_count+= length;
 
1628
}
 
1629
 
1579
1630
void Session::send_kill_message() const
1580
1631
{
1581
1632
  int err= killed_errno();
1588
1639
  memset(&status_var, 0, sizeof(status_var));
1589
1640
}
1590
1641
 
 
1642
void Security_context::skip_grants()
 
1643
{
 
1644
  /* privileges for the user are unknown everything is allowed */
 
1645
}
 
1646
 
1591
1647
 
1592
1648
/****************************************************************************
1593
1649
  Handling of open and locked tables states.
1601
1657
{
1602
1658
  backup->set_open_tables_state(this);
1603
1659
  reset_open_tables_state();
1604
 
  backups_available= false;
 
1660
  state_flags|= Open_tables_state::BACKUPS_AVAIL;
1605
1661
}
1606
1662
 
1607
1663
 
1617
1673
  set_open_tables_state(backup);
1618
1674
}
1619
1675
 
1620
 
bool Session::set_db(const std::string &new_db)
 
1676
 
 
1677
bool Session::set_db(const char *new_db, size_t new_db_len)
1621
1678
{
1622
1679
  /* Do not reallocate memory if current chunk is big enough. */
1623
 
  if (new_db.length())
1624
 
    db= new_db;
 
1680
  if (db && new_db && db_length >= new_db_len)
 
1681
    memcpy(db, new_db, new_db_len+1);
1625
1682
  else
1626
 
    db.clear();
1627
 
 
1628
 
  return false;
 
1683
  {
 
1684
    if (db)
 
1685
      free(db);
 
1686
    if (new_db)
 
1687
    {
 
1688
      db= (char *)malloc(new_db_len + 1);
 
1689
      if (db != NULL)
 
1690
      {
 
1691
        memcpy(db, new_db, new_db_len);
 
1692
        db[new_db_len]= 0;
 
1693
      }
 
1694
    }
 
1695
    else
 
1696
      db= NULL;
 
1697
  }
 
1698
  db_length= db ? new_db_len : 0;
 
1699
  return new_db && !db;
1629
1700
}
1630
1701
 
1631
1702
 
1632
 
 
1633
 
 
1634
1703
/**
1635
1704
  Check the killed state of a user thread
1636
1705
  @param session  user thread
1643
1712
}
1644
1713
 
1645
1714
/**
1646
 
  Return the session id of a user session
1647
 
  @param pointer to Session object
1648
 
  @return session's id
 
1715
  Return the thread id of a user thread
 
1716
  @param session user thread
 
1717
  @return thread id
1649
1718
*/
1650
1719
extern "C" unsigned long session_get_thread_id(const Session *session)
1651
1720
{
1652
 
  return (unsigned long) session->getSessionId();
1653
 
}
1654
 
 
1655
 
 
1656
 
const struct charset_info_st *session_charset(Session *session)
 
1721
  return((unsigned long)session->thread_id);
 
1722
}
 
1723
 
 
1724
 
 
1725
extern "C"
 
1726
LEX_STRING *session_make_lex_string(Session *session, LEX_STRING *lex_str,
 
1727
                                const char *str, unsigned int size,
 
1728
                                int allocate_lex_string)
 
1729
{
 
1730
  return session->make_lex_string(lex_str, str, size,
 
1731
                              (bool) allocate_lex_string);
 
1732
}
 
1733
 
 
1734
extern "C" const struct charset_info_st *session_charset(Session *session)
1657
1735
{
1658
1736
  return(session->charset());
1659
1737
}
1660
1738
 
1661
 
int session_non_transactional_update(const Session *session)
1662
 
{
1663
 
  return(session->transaction.all.hasModifiedNonTransData());
1664
 
}
1665
 
 
1666
 
void session_mark_transaction_to_rollback(Session *session, bool all)
 
1739
extern "C" char **session_query(Session *session)
 
1740
{
 
1741
  return(&session->query);
 
1742
}
 
1743
 
 
1744
extern "C" int session_non_transactional_update(const Session *session)
 
1745
{
 
1746
  return(session->transaction.all.modified_non_trans_table);
 
1747
}
 
1748
 
 
1749
extern "C" void session_mark_transaction_to_rollback(Session *session, bool all)
1667
1750
{
1668
1751
  mark_transaction_to_rollback(session, all);
1669
1752
}
1689
1772
  plugin_sessionvar_cleanup(this);
1690
1773
 
1691
1774
  /* If necessary, log any aborted or unauthorized connections */
1692
 
  if (killed || client->wasAborted())
 
1775
  if (killed || protocol->wasAborted())
1693
1776
    statistic_increment(aborted_threads, &LOCK_status);
1694
1777
 
1695
 
  if (client->wasAborted())
 
1778
  if (protocol->wasAborted())
1696
1779
  {
1697
1780
    if (! killed && variables.log_warnings > 1)
1698
1781
    {
1699
 
      SecurityContext *sctx= &security_ctx;
 
1782
      Security_context *sctx= &security_ctx;
1700
1783
 
1701
1784
      errmsg_printf(ERRMSG_LVL_WARN, ER(ER_NEW_ABORTING_CONNECTION)
1702
1785
                  , thread_id
1703
 
                  , (db.empty() ? "unconnected" : db.c_str())
1704
 
                  , sctx->getUser().empty() == false ? sctx->getUser().c_str() : "unauthenticated"
1705
 
                  , sctx->getIp().c_str()
 
1786
                  , (db ? db : "unconnected")
 
1787
                  , sctx->user.empty() == false ? sctx->user.c_str() : "unauthenticated"
 
1788
                  , sctx->ip.c_str()
1706
1789
                  , (main_da.is_error() ? main_da.message() : ER(ER_UNKNOWN_ERROR)));
1707
1790
    }
1708
1791
  }
1711
1794
  if (should_lock)
1712
1795
    (void) pthread_mutex_lock(&LOCK_thread_count);
1713
1796
  killed= Session::KILL_CONNECTION;
1714
 
  if (client->isConnected())
 
1797
  if (protocol->isConnected())
1715
1798
  {
1716
1799
    if (errcode)
1717
1800
    {
1718
1801
      /*my_error(errcode, ER(errcode));*/
1719
 
      client->sendError(errcode, ER(errcode));
 
1802
      protocol->sendError(errcode, ER(errcode)); /* purecov: inspected */
1720
1803
    }
1721
 
    client->close();
 
1804
    protocol->close();
1722
1805
  }
1723
1806
  if (should_lock)
1724
1807
    (void) pthread_mutex_unlock(&LOCK_thread_count);
1738
1821
  server_status&= ~ (SERVER_MORE_RESULTS_EXISTS |
1739
1822
                          SERVER_QUERY_NO_INDEX_USED |
1740
1823
                          SERVER_QUERY_NO_GOOD_INDEX_USED);
 
1824
  /*
 
1825
    If in autocommit mode and not in a transaction, reset
 
1826
    OPTION_STATUS_NO_TRANS_UPDATE | OPTION_KEEP_LOG to not get warnings
 
1827
    in ha_rollback_trans() about some tables couldn't be rolled back.
 
1828
  */
 
1829
  if (!(options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))
 
1830
  {
 
1831
    options&= ~OPTION_KEEP_LOG;
 
1832
    transaction.all.modified_non_trans_table= false;
 
1833
  }
1741
1834
 
1742
1835
  clear_error();
1743
1836
  main_da.reset_diagnostics_area();
1747
1840
 
1748
1841
/*
1749
1842
  Close all temporary tables created by 'CREATE TEMPORARY TABLE' for thread
 
1843
  creates one DROP TEMPORARY Table binlog event for each pseudo-thread
1750
1844
*/
1751
1845
 
1752
1846
void Session::close_temporary_tables()
1754
1848
  Table *table;
1755
1849
  Table *tmp_next;
1756
1850
 
1757
 
  if (not temporary_tables)
 
1851
  if (!temporary_tables)
1758
1852
    return;
1759
1853
 
1760
1854
  for (table= temporary_tables; table; table= tmp_next)
1761
1855
  {
1762
1856
    tmp_next= table->next;
1763
 
    nukeTable(table);
 
1857
    close_temporary(table, true, true);
1764
1858
  }
1765
1859
  temporary_tables= NULL;
1766
1860
}
1767
1861
 
1768
 
/*
1769
 
  unlink from session->temporary tables and close temporary table
1770
 
*/
1771
 
 
1772
 
void Session::close_temporary_table(Table *table)
1773
 
{
1774
 
  if (table->prev)
1775
 
  {
1776
 
    table->prev->next= table->next;
1777
 
    if (table->prev->next)
1778
 
      table->next->prev= table->prev;
1779
 
  }
1780
 
  else
1781
 
  {
1782
 
    /* removing the item from the list */
1783
 
    assert(table == temporary_tables);
1784
 
    /*
1785
 
      slave must reset its temporary list pointer to zero to exclude
1786
 
      passing non-zero value to end_slave via rli->save_temporary_tables
1787
 
      when no temp tables opened, see an invariant below.
1788
 
    */
1789
 
    temporary_tables= table->next;
1790
 
    if (temporary_tables)
1791
 
      table->next->prev= NULL;
1792
 
  }
1793
 
  nukeTable(table);
1794
 
}
1795
 
 
1796
 
/*
1797
 
  Close and drop a temporary table
1798
 
 
1799
 
  NOTE
1800
 
  This dosn't unlink table from session->temporary
1801
 
  If this is needed, use close_temporary_table()
1802
 
*/
1803
 
 
1804
 
void Session::nukeTable(Table *table)
1805
 
{
1806
 
  plugin::StorageEngine *table_type= table->s->db_type();
1807
 
 
1808
 
  table->free_io_cache();
1809
 
  table->closefrm(false);
1810
 
 
1811
 
  TableIdentifier identifier(table->s->getSchemaName(), table->s->table_name.str, table->s->path.str);
1812
 
  rm_temporary_table(table_type, identifier);
1813
 
 
1814
 
  table->s->free_table_share();
1815
 
 
1816
 
  /* This makes me sad, but we're allocating it via malloc */
1817
 
  free(table);
1818
 
}
1819
1862
 
1820
1863
/** Clear most status variables. */
1821
1864
extern time_t flush_status_time;
1835
1878
  reset_status_vars();
1836
1879
 
1837
1880
  /* Reset the counters of all key caches (default and named). */
1838
 
  reset_key_cache_counters();
 
1881
  process_key_caches(reset_key_cache_counters);
1839
1882
  flush_status_time= time((time_t*) 0);
1840
1883
  max_used_connections= 1; /* We set it to one, because we know we exist */
1841
1884
  pthread_mutex_unlock(&LOCK_status);
1842
1885
}
1843
1886
 
 
1887
#define extra_size sizeof(double)
 
1888
 
1844
1889
user_var_entry *Session::getVariable(LEX_STRING &name, bool create_if_not_exists)
1845
1890
{
1846
1891
  user_var_entry *entry= NULL;
1847
1892
 
 
1893
  assert(name.length == strlen (name.str));
1848
1894
  entry= (user_var_entry*) hash_search(&user_vars, (unsigned char*) name.str, name.length);
1849
1895
 
1850
1896
  if ((entry == NULL) && create_if_not_exists)
1851
1897
  {
 
1898
    uint32_t size=ALIGN_SIZE(sizeof(user_var_entry))+name.length+1+extra_size;
1852
1899
    if (!hash_inited(&user_vars))
1853
 
      return NULL;
1854
 
    entry= new (nothrow) user_var_entry(name.str, query_id);
1855
 
 
1856
 
    if (entry == NULL)
1857
 
      return NULL;
1858
 
 
 
1900
      return 0;
 
1901
    if (!(entry = (user_var_entry*) malloc(size)))
 
1902
      return 0;
 
1903
    entry->name.str=(char*) entry+ ALIGN_SIZE(sizeof(user_var_entry))+
 
1904
      extra_size;
 
1905
    entry->name.length=name.length;
 
1906
    entry->value=0;
 
1907
    entry->length=0;
 
1908
    entry->update_query_id=0;
 
1909
    entry->collation.set(NULL, DERIVATION_IMPLICIT);
 
1910
    entry->unsigned_flag= 0;
 
1911
    /*
 
1912
      If we are here, we were called from a SET or a query which sets a
 
1913
      variable. Imagine it is this:
 
1914
      INSERT INTO t SELECT @a:=10, @a:=@a+1.
 
1915
      Then when we have a Item_func_get_user_var (because of the @a+1) so we
 
1916
      think we have to write the value of @a to the binlog. But before that,
 
1917
      we have a Item_func_set_user_var to create @a (@a:=10), in this we mark
 
1918
      the variable as "already logged" (line below) so that it won't be logged
 
1919
      by Item_func_get_user_var (because that's not necessary).
 
1920
    */
 
1921
    entry->used_query_id= query_id;
 
1922
    entry->type=STRING_RESULT;
 
1923
    memcpy(entry->name.str, name.str, name.length+1);
1859
1924
    if (my_hash_insert(&user_vars, (unsigned char*) entry))
1860
1925
    {
1861
1926
      assert(1);
1875
1940
    if (table->query_id == query_id)
1876
1941
    {
1877
1942
      table->query_id= 0;
1878
 
      table->cursor->ha_reset();
 
1943
      table->file->ha_reset();
1879
1944
    }
1880
1945
  }
1881
1946
}
1887
1952
    if (table->query_id == query_id)
1888
1953
    {
1889
1954
      table->query_id= 0;
1890
 
      table->cursor->ha_reset();
 
1955
      table->file->ha_reset();
1891
1956
    }
1892
1957
  }
1893
1958
}
1943
2008
    does not belong to statement for which we do close_thread_tables()).
1944
2009
    TODO: This should be fixed in later releases.
1945
2010
   */
1946
 
  if (backups_available == false)
 
2011
  if (!(state_flags & Open_tables_state::BACKUPS_AVAIL))
1947
2012
  {
1948
 
    TransactionServices &transaction_services= TransactionServices::singleton();
1949
2013
    main_da.can_overwrite_status= true;
1950
 
    transaction_services.ha_autocommit_or_rollback(this, is_error());
 
2014
    ha_autocommit_or_rollback(this, is_error());
1951
2015
    main_da.can_overwrite_status= false;
1952
2016
    transaction.stmt.reset();
1953
2017
  }
1991
2055
  close_thread_tables();
1992
2056
}
1993
2057
 
1994
 
bool Session::openTablesLock(TableList *tables)
 
2058
int Session::open_and_lock_tables(TableList *tables)
1995
2059
{
1996
2060
  uint32_t counter;
1997
2061
  bool need_reopen;
1998
2062
 
1999
2063
  for ( ; ; )
2000
2064
  {
2001
 
    if (open_tables_from_list(&tables, &counter))
2002
 
      return true;
 
2065
    if (open_tables_from_list(&tables, &counter, 0))
 
2066
      return -1;
2003
2067
 
2004
 
    if (not lock_tables(tables, counter, &need_reopen))
 
2068
    if (!lock_tables(this, tables, counter, &need_reopen))
2005
2069
      break;
2006
 
    if (not need_reopen)
2007
 
      return true;
 
2070
    if (!need_reopen)
 
2071
      return -1;
2008
2072
    close_tables_for_reopen(&tables);
2009
2073
  }
2010
2074
  if ((mysql_handle_derived(lex, &mysql_derived_prepare) ||
2011
2075
       (fill_derived_tables() &&
2012
2076
        mysql_handle_derived(lex, &mysql_derived_filling))))
2013
 
    return true;
 
2077
    return 1; /* purecov: inspected */
2014
2078
 
2015
 
  return false;
 
2079
  return 0;
2016
2080
}
2017
2081
 
2018
 
bool Session::openTables(TableList *tables, uint32_t flags)
 
2082
bool Session::open_normal_and_derived_tables(TableList *tables, uint32_t flags)
2019
2083
{
2020
2084
  uint32_t counter;
2021
 
  bool ret= fill_derived_tables();
2022
 
  assert(ret == false);
 
2085
  assert(!(fill_derived_tables()));
2023
2086
  if (open_tables_from_list(&tables, &counter, flags) ||
2024
2087
      mysql_handle_derived(lex, &mysql_derived_prepare))
2025
 
    return true;
2026
 
  return false;
2027
 
}
2028
 
 
2029
 
bool Session::rm_temporary_table(TableIdentifier &identifier)
2030
 
{
2031
 
  if (plugin::StorageEngine::dropTable(*this, identifier))
2032
 
  {
2033
 
    errmsg_printf(ERRMSG_LVL_WARN, _("Could not remove temporary table: '%s', error: %d"),
2034
 
                  identifier.getSQLPath().c_str(), errno);
2035
 
    dumpTemporaryTableNames("rm_temporary_table()");
2036
 
 
2037
 
    return true;
2038
 
  }
2039
 
 
2040
 
  return false;
2041
 
}
2042
 
 
2043
 
bool Session::rm_temporary_table(plugin::StorageEngine *base, TableIdentifier &identifier)
2044
 
{
2045
 
  assert(base);
2046
 
 
2047
 
  if (plugin::StorageEngine::dropTable(*this, *base, identifier))
2048
 
  {
2049
 
    errmsg_printf(ERRMSG_LVL_WARN, _("Could not remove temporary table: '%s', error: %d"),
2050
 
                  identifier.getSQLPath().c_str(), errno);
2051
 
    dumpTemporaryTableNames("rm_temporary_table()");
2052
 
 
2053
 
    return true;
2054
 
  }
2055
 
 
2056
 
  return false;
2057
 
}
2058
 
 
2059
 
/**
2060
 
  @note this will be removed, I am looking through Hudson to see if it is finding
2061
 
  any tables that are missed during cleanup.
2062
 
*/
2063
 
void Session::dumpTemporaryTableNames(const char *foo)
2064
 
{
2065
 
  Table *table;
2066
 
 
2067
 
  if (not temporary_tables)
2068
 
    return;
2069
 
 
2070
 
  cerr << "Begin Run: " << foo << "\n";
2071
 
  for (table= temporary_tables; table; table= table->next)
2072
 
  {
2073
 
    bool have_proto= false;
2074
 
 
2075
 
    message::Table *proto= table->s->getTableProto();
2076
 
    if (table->s->getTableProto())
2077
 
      have_proto= true;
2078
 
 
2079
 
    const char *answer= have_proto ? "true" : "false";
2080
 
 
2081
 
    if (have_proto)
2082
 
    {
2083
 
      cerr << "\tTable Name " << table->s->getSchemaName() << "." << table->s->table_name.str << " : " << answer << "\n";
2084
 
      cerr << "\t\t Proto " << proto->schema() << " " << proto->name() << "\n";
2085
 
    }
2086
 
    else
2087
 
      cerr << "\tTabl;e Name " << table->s->getSchemaName() << "." << table->s->table_name.str << " : " << answer << "\n";
2088
 
  }
2089
 
}
2090
 
 
2091
 
bool Session::storeTableMessage(TableIdentifier &identifier, message::Table &table_message)
2092
 
{
2093
 
  table_message_cache.insert(make_pair(identifier.getPath(), table_message));
2094
 
 
2095
 
  return true;
2096
 
}
2097
 
 
2098
 
bool Session::removeTableMessage(TableIdentifier &identifier)
2099
 
{
2100
 
  TableMessageCache::iterator iter;
2101
 
 
2102
 
  iter= table_message_cache.find(identifier.getPath());
2103
 
 
2104
 
  if (iter == table_message_cache.end())
2105
 
    return false;
2106
 
 
2107
 
  table_message_cache.erase(iter);
2108
 
 
2109
 
  return true;
2110
 
}
2111
 
 
2112
 
bool Session::getTableMessage(TableIdentifier &identifier, message::Table &table_message)
2113
 
{
2114
 
  TableMessageCache::iterator iter;
2115
 
 
2116
 
  iter= table_message_cache.find(identifier.getPath());
2117
 
 
2118
 
  if (iter == table_message_cache.end())
2119
 
    return false;
2120
 
 
2121
 
  table_message.CopyFrom(((*iter).second));
2122
 
 
2123
 
  return true;
2124
 
}
2125
 
 
2126
 
bool Session::doesTableMessageExist(TableIdentifier &identifier)
2127
 
{
2128
 
  TableMessageCache::iterator iter;
2129
 
 
2130
 
  iter= table_message_cache.find(identifier.getPath());
2131
 
 
2132
 
  if (iter == table_message_cache.end())
2133
 
  {
2134
 
    return false;
2135
 
  }
2136
 
 
2137
 
  return true;
2138
 
}
2139
 
 
2140
 
bool Session::renameTableMessage(TableIdentifier &from, TableIdentifier &to)
2141
 
{
2142
 
  TableMessageCache::iterator iter;
2143
 
 
2144
 
  table_message_cache[to.getPath()]= table_message_cache[from.getPath()];
2145
 
 
2146
 
  iter= table_message_cache.find(to.getPath());
2147
 
 
2148
 
  if (iter == table_message_cache.end())
2149
 
  {
2150
 
    return false;
2151
 
  }
2152
 
 
2153
 
  (*iter).second.set_schema(to.getSchemaName());
2154
 
  (*iter).second.set_name(to.getTableName());
2155
 
 
2156
 
  return true;
2157
 
}
2158
 
 
2159
 
} /* namespace drizzled */
 
2088
    return true; /* purecov: inspected */
 
2089
  return false;
 
2090
}