~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/session.cc

  • Committer: Stewart Smith
  • Date: 2009-06-17 06:44:38 UTC
  • mto: This revision was merged to the branch mainline in revision 1094.
  • Revision ID: stewart@flamingspork.com-20090617064438-062owpgtdzgr4lvx
type_float.test for MyISAM as temp only

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"
25
 
#include "drizzled/session.h"
26
 
#include "drizzled/session/cache.h"
 
24
#include <drizzled/server_includes.h>
 
25
#include <drizzled/session.h>
27
26
#include <sys/stat.h>
28
 
#include "drizzled/error.h"
29
 
#include "drizzled/gettext.h"
30
 
#include "drizzled/query_id.h"
31
 
#include "drizzled/data_home.h"
32
 
#include "drizzled/sql_base.h"
33
 
#include "drizzled/lock.h"
34
 
#include "drizzled/item/cache.h"
35
 
#include "drizzled/item/float.h"
36
 
#include "drizzled/item/return_int.h"
37
 
#include "drizzled/item/empty_string.h"
38
 
#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/plugin/query_rewrite.h"
45
 
#include "drizzled/probes.h"
46
 
#include "drizzled/table_proto.h"
47
 
#include "drizzled/db.h"
48
 
#include "drizzled/pthread_globals.h"
49
 
#include "drizzled/transaction_services.h"
50
 
#include "drizzled/drizzled.h"
51
 
 
52
 
#include "drizzled/table/instance.h"
53
 
 
54
 
#include "plugin/myisam/myisam.h"
55
 
#include "drizzled/internal/iocache.h"
56
 
#include "drizzled/internal/thread_var.h"
57
 
#include "drizzled/plugin/event_observer.h"
58
 
 
59
 
#include "drizzled/util/functors.h"
60
 
 
61
 
#include "drizzled/display.h"
62
 
 
63
 
#include <fcntl.h>
64
 
#include <algorithm>
65
 
#include <climits>
66
 
#include <boost/filesystem.hpp>
67
 
 
68
 
#include "drizzled/util/backtrace.h"
69
 
 
70
 
using namespace std;
71
 
 
72
 
namespace fs=boost::filesystem;
73
 
namespace drizzled
74
 
{
 
27
#include <mysys/mysys_err.h>
 
28
#include <drizzled/error.h>
 
29
#include <drizzled/query_id.h>
 
30
#include <drizzled/data_home.h>
 
31
#include <drizzled/sql_base.h>
 
32
#include <drizzled/lock.h>
 
33
#include <drizzled/item/cache.h>
 
34
#include <drizzled/item/float.h>
 
35
#include <drizzled/item/return_int.h>
 
36
#include <drizzled/item/empty_string.h>
 
37
#include <drizzled/show.h>
 
38
#include <drizzled/scheduling.h>
75
39
 
76
40
/*
77
41
  The following is used to initialise Table_ident with a internal
81
45
char empty_c_string[1]= {0};    /* used for not defined db */
82
46
 
83
47
const char * const Session::DEFAULT_WHERE= "field list";
 
48
extern pthread_key_t THR_Session;
 
49
extern pthread_key_t THR_Mem_root;
 
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
 
62
 
 
63
/****************************************************************************
 
64
** User variables
 
65
****************************************************************************/
 
66
extern "C" unsigned char *get_var_key(user_var_entry *entry, size_t *length,
 
67
                              bool )
 
68
{
 
69
  *length= entry->name.length;
 
70
  return (unsigned char*) entry->name.str;
 
71
}
 
72
 
 
73
extern "C" void free_user_var(user_var_entry *entry)
 
74
{
 
75
  char *pos= (char*) entry+ALIGN_SIZE(sizeof(*entry));
 
76
  if (entry->value && entry->value != pos)
 
77
    free(entry->value);
 
78
  free((char*) entry);
 
79
}
84
80
 
85
81
bool Key_part_spec::operator==(const Key_part_spec& other) const
86
82
{
87
83
  return length == other.length &&
88
84
         field_name.length == other.field_name.length &&
89
 
    !my_strcasecmp(system_charset_info, field_name.str, other.field_name.str);
 
85
         !strcmp(field_name.str, other.field_name.str);
90
86
}
91
87
 
92
 
Open_tables_state::Open_tables_state(uint64_t version_arg) :
93
 
  version(version_arg)
 
88
Open_tables_state::Open_tables_state(ulong version_arg)
 
89
  :version(version_arg), state_flags(0U)
94
90
{
95
 
  open_tables= temporary_tables= derived_tables= NULL;
96
 
  extra_lock= lock= NULL;
 
91
  reset_open_tables_state();
97
92
}
98
93
 
99
94
/*
100
95
  The following functions form part of the C plugin API
101
96
*/
102
 
int mysql_tmpfile(const char *prefix)
 
97
extern "C" int mysql_tmpfile(const char *prefix)
103
98
{
104
99
  char filename[FN_REFLEN];
105
 
  int fd = internal::create_temp_file(filename, drizzle_tmpdir.c_str(), prefix, MYF(MY_WME));
 
100
  File fd = create_temp_file(filename, drizzle_tmpdir, prefix, MYF(MY_WME));
106
101
  if (fd >= 0) {
107
102
    unlink(filename);
108
103
  }
110
105
  return fd;
111
106
}
112
107
 
 
108
extern "C"
113
109
int session_tablespace_op(const Session *session)
114
110
{
115
111
  return test(session->tablespace_op);
123
119
 
124
120
   @see Session::set_proc_info
125
121
 */
126
 
void set_session_proc_info(Session *session, const char *info)
 
122
extern "C" void
 
123
set_session_proc_info(Session *session, const char *info)
127
124
{
128
125
  session->set_proc_info(info);
129
126
}
130
127
 
 
128
extern "C"
131
129
const char *get_session_proc_info(Session *session)
132
130
{
133
131
  return session->get_proc_info();
134
132
}
135
133
 
136
 
void **Session::getEngineData(const plugin::MonitoredInTransaction *monitored)
137
 
{
138
 
  return static_cast<void **>(&ha_data[monitored->getId()].ha_ptr);
139
 
}
140
 
 
141
 
ResourceContext *Session::getResourceContext(const plugin::MonitoredInTransaction *monitored,
142
 
                                             size_t index)
143
 
{
144
 
  return &ha_data[monitored->getId()].resource_context[index];
145
 
}
146
 
 
 
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;
 
138
}
 
139
 
 
140
extern "C"
147
141
int64_t session_test_options(const Session *session, int64_t test_options)
148
142
{
149
143
  return session->options & test_options;
150
144
}
151
145
 
 
146
extern "C"
152
147
int session_sql_command(const Session *session)
153
148
{
154
149
  return (int) session->lex->sql_command;
155
150
}
156
151
 
157
 
enum_tx_isolation session_tx_isolation(const Session *session)
158
 
{
159
 
  return (enum_tx_isolation)session->variables.tx_isolation;
160
 
}
161
 
 
162
 
Session::Session(plugin::Client *client_arg) :
 
152
extern "C"
 
153
int session_tx_isolation(const Session *session)
 
154
{
 
155
  return (int) session->variables.tx_isolation;
 
156
}
 
157
 
 
158
extern "C"
 
159
void session_inc_row_count(Session *session)
 
160
{
 
161
  session->row_count++;
 
162
}
 
163
 
 
164
Session::Session(Protocol *protocol_arg)
 
165
  :
 
166
  Statement(&main_lex, &main_mem_root, /* statement id */ 0),
163
167
  Open_tables_state(refresh_version),
164
 
  mem_root(&main_mem_root),
165
 
  xa_id(0),
166
 
  lex(&main_lex),
167
 
  query(new std::string),
168
 
  _schema(new std::string("")),
169
 
  catalog("LOCAL"),
170
 
  client(client_arg),
171
 
  scheduler(NULL),
172
 
  scheduler_arg(NULL),
173
168
  lock_id(&main_lock_id),
174
169
  user_time(0),
175
 
  ha_data(plugin::num_trx_monitored_objects),
176
 
  concurrent_execute_allowed(true),
177
170
  arg_of_last_insert_id_function(false),
178
171
  first_successful_insert_id_in_prev_stmt(0),
179
172
  first_successful_insert_id_in_cur_stmt(0),
180
173
  limit_found_rows(0),
181
 
  _global_read_lock(NONE),
182
 
  _killed(NOT_KILLED),
 
174
  global_read_lock(0),
183
175
  some_tables_deleted(false),
184
176
  no_errors(false),
185
177
  password(false),
189
181
  derived_tables_processing(false),
190
182
  tablespace_op(false),
191
183
  m_lip(NULL),
192
 
  cached_table(0),
193
 
  transaction_message(NULL),
194
 
  statement_message(NULL),
195
 
  session_event_observers(NULL),
196
 
  use_usage(false)
 
184
  scheduler(0),
 
185
  cached_table(0)
197
186
{
198
 
  client->setSession(this);
 
187
  uint64_t tmp;
 
188
 
 
189
  memset(process_list_info, 0, PROCESS_LIST_WIDTH);
199
190
 
200
191
  /*
201
192
    Pass nominal parameters to init_alloc_root only to ensure that
202
193
    the destructor works OK in case of an error. The main_mem_root
203
194
    will be re-initialized in init_for_queries().
204
195
  */
205
 
  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);
206
197
  thread_stack= NULL;
207
 
  count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL;
 
198
  count_cuted_fields= CHECK_FIELD_IGNORE;
 
199
  killed= NOT_KILLED;
208
200
  col_access= 0;
209
201
  tmp_table= 0;
210
202
  used_tables= 0;
220
212
  thread_id= 0;
221
213
  file_id = 0;
222
214
  query_id= 0;
223
 
  warn_query_id= 0;
 
215
  warn_id= 0;
 
216
  memset(ha_data, 0, sizeof(ha_data));
 
217
  replication_data= 0;
224
218
  mysys_var= 0;
225
 
  scoreboard_index= -1;
226
219
  dbug_sentry=Session_SENTRY_MAGIC;
227
 
  cleanup_done= abort_on_warning= no_warnings_for_error= false;  
228
 
 
229
 
  /* query_cache init */
230
 
  query_cache_key= "";
231
 
  resultset= NULL;
 
220
  client_capabilities= 0;                       // minimalistic client
 
221
  cleanup_done= abort_on_warning= no_warnings_for_error= false;
 
222
  peer_port= 0;                                 // For SHOW PROCESSLIST
 
223
  transaction.on= 1;
 
224
  pthread_mutex_init(&LOCK_delete, MY_MUTEX_INIT_FAST);
232
225
 
233
226
  /* Variables with default values */
234
227
  proc_info="login";
250
243
  else
251
244
    options &= ~OPTION_BIG_SELECTS;
252
245
 
 
246
  transaction.all.modified_non_trans_table= transaction.stmt.modified_non_trans_table= false;
253
247
  open_options=ha_open_options;
254
248
  update_lock_default= TL_WRITE;
255
249
  session_tx_isolation= (enum_tx_isolation) variables.tx_isolation;
259
253
  memset(&status_var, 0, sizeof(status_var));
260
254
 
261
255
  /* Initialize sub structures */
262
 
  memory::init_sql_alloc(&warn_root, WARN_ALLOC_BLOCK_SIZE, WARN_ALLOC_PREALLOC_SIZE);
263
 
 
 
256
  init_sql_alloc(&warn_root, WARN_ALLOC_BLOCK_SIZE, WARN_ALLOC_PREALLOC_SIZE);
 
257
  hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0,
 
258
            (hash_get_key) get_var_key,
 
259
            (hash_free_key) free_user_var, 0);
 
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());
264
269
  substitute_null_with_insert_id = false;
265
 
  lock_info.init(); /* safety: will be reset after start */
 
270
  thr_lock_info_init(&lock_info); /* safety: will be reset after start */
266
271
  thr_lock_owner_init(&main_lock_id, &lock_info);
267
272
 
268
273
  m_internal_handler= NULL;
269
 
  
270
 
  plugin::EventObserver::registerSessionEvents(*this); 
271
274
}
272
275
 
273
 
void Session::free_items()
 
276
void Statement::free_items()
274
277
{
275
278
  Item *next;
276
 
  /* This works because items are allocated with memory::sql_alloc() */
 
279
  /* This works because items are allocated with sql_alloc() */
277
280
  for (; free_list; free_list= next)
278
281
  {
279
282
    next= free_list->next;
302
305
  return false;                                 // 'false', as per coding style
303
306
}
304
307
 
305
 
void Session::setAbort(bool arg)
306
 
{
307
 
  mysys_var->abort= arg;
308
 
}
309
 
 
310
 
void Session::lockOnSys()
311
 
{
312
 
  if (not mysys_var)
313
 
    return;
314
 
 
315
 
  setAbort(true);
316
 
  boost_unique_lock_t scopedLock(mysys_var->mutex);
317
 
  if (mysys_var->current_cond)
318
 
  {
319
 
    mysys_var->current_mutex->lock();
320
 
    mysys_var->current_cond->notify_all();
321
 
    mysys_var->current_mutex->unlock();
322
 
  }
323
 
}
324
 
 
325
308
void Session::pop_internal_handler()
326
309
{
327
310
  assert(m_internal_handler != NULL);
328
311
  m_internal_handler= NULL;
329
312
}
330
313
 
331
 
void Session::get_xid(DRIZZLE_XID *xid)
332
 
{
333
 
  *xid = *(DRIZZLE_XID *) &transaction.xid_state.xid;
334
 
}
 
314
#if defined(__cplusplus)
 
315
extern "C" {
 
316
#endif
 
317
 
 
318
void *session_alloc(Session *session, unsigned int size)
 
319
{
 
320
  return session->alloc(size);
 
321
}
 
322
 
 
323
void *session_calloc(Session *session, unsigned int size)
 
324
{
 
325
  return session->calloc(size);
 
326
}
 
327
 
 
328
char *session_strdup(Session *session, const char *str)
 
329
{
 
330
  return session->strdup(str);
 
331
}
 
332
 
 
333
char *session_strmake(Session *session, const char *str, unsigned int size)
 
334
{
 
335
  return session->strmake(str, size);
 
336
}
 
337
 
 
338
void *session_memdup(Session *session, const void* str, unsigned int size)
 
339
{
 
340
  return session->memdup(str, size);
 
341
}
 
342
 
 
343
void session_get_xid(const Session *session, DRIZZLE_XID *xid)
 
344
{
 
345
  *xid = *(DRIZZLE_XID *) &session->transaction.xid_state.xid;
 
346
}
 
347
 
 
348
#if defined(__cplusplus)
 
349
}
 
350
#endif
 
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
 
335
372
 
336
373
/* Do operations that may take a long time */
337
374
 
339
376
{
340
377
  assert(cleanup_done == false);
341
378
 
342
 
  setKilled(KILL_CONNECTION);
 
379
  killed= KILL_CONNECTION;
343
380
#ifdef ENABLE_WHEN_BINLOG_WILL_BE_ABLE_TO_PREPARE
344
381
  if (transaction.xid_state.xa_state == XA_PREPARED)
345
382
  {
347
384
  }
348
385
#endif
349
386
  {
350
 
    TransactionServices &transaction_services= TransactionServices::singleton();
351
 
    transaction_services.rollbackTransaction(this, true);
 
387
    ha_rollback(this);
352
388
    xid_cache_delete(&transaction.xid_state);
353
389
  }
354
 
 
355
 
  for (UserVars::iterator iter= user_vars.begin();
356
 
       iter != user_vars.end();
357
 
       iter++)
358
 
  {
359
 
    user_var_entry *entry= (*iter).second;
360
 
    delete entry;
361
 
  }
362
 
  user_vars.clear();
363
 
 
364
 
 
 
390
  hash_free(&user_vars);
365
391
  close_temporary_tables();
366
392
 
367
393
  if (global_read_lock)
368
 
  {
369
 
    unlockGlobalReadLock();
370
 
  }
 
394
    unlock_global_read_lock(this);
371
395
 
372
396
  cleanup_done= true;
373
397
}
374
398
 
375
399
Session::~Session()
376
400
{
377
 
  this->checkSentry();
 
401
  Session_CHECK_SENTRY(this);
 
402
  add_to_status(&global_status_var, &status_var);
378
403
 
379
 
  if (client->isConnected())
 
404
  if (protocol->isConnected())
380
405
  {
381
406
    if (global_system_variables.log_warnings)
382
 
        errmsg_printf(ERRMSG_LVL_WARN, ER(ER_FORCING_CLOSE),internal::my_progname,
 
407
        errmsg_printf(ERRMSG_LVL_WARN, ER(ER_FORCING_CLOSE),my_progname,
383
408
                      thread_id,
384
 
                      (getSecurityContext().getUser().c_str() ?
385
 
                       getSecurityContext().getUser().c_str() : ""));
 
409
                      (security_ctx.user.c_str() ?
 
410
                       security_ctx.user.c_str() : ""));
386
411
    disconnect(0, false);
387
412
  }
388
413
 
389
414
  /* Close connection */
390
 
  client->close();
391
 
  delete client;
 
415
  protocol->close();
 
416
  delete protocol;
392
417
 
393
418
  if (cleanup_done == false)
394
419
    cleanup();
395
420
 
396
 
  plugin::StorageEngine::closeConnection(this);
 
421
  ha_close_connection(this);
397
422
  plugin_sessionvar_cleanup(this);
398
423
 
399
 
  warn_root.free_root(MYF(0));
 
424
  if (db)
 
425
  {
 
426
    free(db);
 
427
    db= NULL;
 
428
  }
 
429
  free_root(&warn_root,MYF(0));
 
430
  free_root(&transaction.mem_root,MYF(0));
400
431
  mysys_var=0;                                  // Safety (shouldn't be needed)
401
432
  dbug_sentry= Session_SENTRY_GONE;
402
433
 
403
 
  main_mem_root.free_root(MYF(0));
404
 
  currentMemRoot().release();
405
 
  currentSession().release();
406
 
 
407
 
  plugin::Logging::postEndDo(this);
408
 
  plugin::EventObserver::deregisterSessionEvents(*this); 
409
 
 
410
 
  for (PropertyMap::iterator iter= life_properties.begin(); iter != life_properties.end(); iter++)
411
 
  {
412
 
    delete (*iter).second;
413
 
  }
414
 
  life_properties.clear();
415
 
}
416
 
 
417
 
void Session::setClient(plugin::Client *client_arg)
418
 
{
419
 
  client= client_arg;
420
 
  client->setSession(this);
421
 
}
422
 
 
423
 
void Session::awake(Session::killed_state_t state_to_set)
424
 
{
425
 
  if ((state_to_set == Session::KILL_QUERY) and (command == COM_SLEEP))
426
 
    return;
427
 
 
428
 
  this->checkSentry();
429
 
 
430
 
  setKilled(state_to_set);
431
 
  scheduler->killSession(this);
432
 
 
 
434
  free_root(&main_mem_root, MYF(0));
 
435
  pthread_setspecific(THR_Session,  0);
 
436
 
 
437
 
 
438
  /* Ensure that no one is using Session */
 
439
  pthread_mutex_unlock(&LOCK_delete);
 
440
  pthread_mutex_destroy(&LOCK_delete);
 
441
}
 
442
 
 
443
/*
 
444
  Add all status variables to another status variable array
 
445
 
 
446
  SYNOPSIS
 
447
   add_to_status()
 
448
   to_var       add to this array
 
449
   from_var     from this array
 
450
 
 
451
  NOTES
 
452
    This function assumes that all variables are long/ulong.
 
453
    If this assumption will change, then we have to explictely add
 
454
    the other variables after the while loop
 
455
*/
 
456
void add_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var)
 
457
{
 
458
  ulong *end= (ulong*) ((unsigned char*) to_var +
 
459
                        offsetof(STATUS_VAR, last_system_status_var) +
 
460
                        sizeof(ulong));
 
461
  ulong *to= (ulong*) to_var, *from= (ulong*) from_var;
 
462
 
 
463
  while (to != end)
 
464
    *(to++)+= *(from++);
 
465
}
 
466
 
 
467
/*
 
468
  Add the difference between two status variable arrays to another one.
 
469
 
 
470
  SYNOPSIS
 
471
    add_diff_to_status
 
472
    to_var       add to this array
 
473
    from_var     from this array
 
474
    dec_var      minus this array
 
475
 
 
476
  NOTE
 
477
    This function assumes that all variables are long/ulong.
 
478
*/
 
479
void add_diff_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var,
 
480
                        STATUS_VAR *dec_var)
 
481
{
 
482
  ulong *end= (ulong*) ((unsigned char*) to_var + offsetof(STATUS_VAR,
 
483
                                                  last_system_status_var) +
 
484
                        sizeof(ulong));
 
485
  ulong *to= (ulong*) to_var, *from= (ulong*) from_var, *dec= (ulong*) dec_var;
 
486
 
 
487
  while (to != end)
 
488
    *(to++)+= *(from++) - *(dec++);
 
489
}
 
490
 
 
491
void Session::awake(Session::killed_state state_to_set)
 
492
{
 
493
  Session_CHECK_SENTRY(this);
 
494
  safe_mutex_assert_owner(&LOCK_delete);
 
495
  Scheduler &thread_scheduler= get_thread_scheduler();
 
496
 
 
497
  killed= state_to_set;
433
498
  if (state_to_set != Session::KILL_QUERY)
434
499
  {
435
 
    DRIZZLE_CONNECTION_DONE(thread_id);
 
500
    thread_scheduler.post_kill_notification(this);
436
501
  }
437
 
 
438
502
  if (mysys_var)
439
503
  {
440
 
    boost_unique_lock_t scopedLock(mysys_var->mutex);
 
504
    pthread_mutex_lock(&mysys_var->mutex);
441
505
    /*
442
 
      "
443
506
      This broadcast could be up in the air if the victim thread
444
507
      exits the cond in the time between read and broadcast, but that is
445
508
      ok since all we want to do is to make the victim thread get out
460
523
    */
461
524
    if (mysys_var->current_cond && mysys_var->current_mutex)
462
525
    {
463
 
      mysys_var->current_mutex->lock();
464
 
      mysys_var->current_cond->notify_all();
465
 
      mysys_var->current_mutex->unlock();
 
526
      pthread_mutex_lock(mysys_var->current_mutex);
 
527
      pthread_cond_broadcast(mysys_var->current_cond);
 
528
      pthread_mutex_unlock(mysys_var->current_mutex);
466
529
    }
 
530
    pthread_mutex_unlock(&mysys_var->mutex);
467
531
  }
468
532
}
469
533
 
470
534
/*
471
535
  Remember the location of thread info, the structure needed for
472
 
  memory::sql_alloc() and the structure for the net buffer
 
536
  sql_alloc() and the structure for the net buffer
473
537
*/
474
 
bool Session::storeGlobals()
 
538
bool Session::store_globals()
475
539
{
476
540
  /*
477
541
    Assert that thread_stack is initialized: it's necessary to be able
479
543
  */
480
544
  assert(thread_stack);
481
545
 
482
 
  currentSession().release();
483
 
  currentSession().reset(this);
484
 
 
485
 
  currentMemRoot().release();
486
 
  currentMemRoot().reset(&mem_root);
487
 
 
 
546
  if (pthread_setspecific(THR_Session,  this) ||
 
547
      pthread_setspecific(THR_Mem_root, &mem_root))
 
548
    return 1;
488
549
  mysys_var=my_thread_var;
489
550
 
490
551
  /*
492
553
    This allows us to move Session to different threads if needed.
493
554
  */
494
555
  mysys_var->id= thread_id;
 
556
  real_id= pthread_self();                      // For debugging
495
557
 
496
558
  /*
497
559
    We have to call thr_lock_info_init() again here as Session may have been
498
560
    created in another thread
499
561
  */
500
 
  lock_info.init();
501
 
 
502
 
  return false;
 
562
  thr_lock_info_init(&lock_info);
 
563
  return 0;
503
564
}
504
565
 
505
 
/*
506
 
  Init Session for query processing.
507
 
  This has to be called once before we call mysql_parse.
508
 
  See also comments in session.h.
509
 
*/
510
 
 
511
566
void Session::prepareForQueries()
512
567
{
513
568
  if (variables.max_join_size == HA_POS_ERROR)
514
569
    options |= OPTION_BIG_SELECTS;
 
570
  if (client_capabilities & CLIENT_COMPRESS)
 
571
  {
 
572
    protocol->enableCompression();
 
573
  }
515
574
 
516
575
  version= refresh_version;
517
576
  set_proc_info(NULL);
518
577
  command= COM_SLEEP;
519
578
  set_time();
520
 
 
521
 
  mem_root->reset_root_defaults(variables.query_alloc_block_size,
522
 
                                variables.query_prealloc_size);
523
 
  transaction.xid_state.xid.null();
524
 
  transaction.xid_state.in_session=1;
525
 
  if (use_usage)
526
 
    resetUsage();
 
579
  init_for_queries();
527
580
}
528
581
 
529
582
bool Session::initGlobals()
530
583
{
531
 
  if (storeGlobals())
 
584
  if (store_globals())
532
585
  {
533
586
    disconnect(ER_OUT_OF_RESOURCES, true);
534
 
    status_var.aborted_connects++;
535
 
    return true;
536
 
  }
537
 
  return false;
538
 
}
539
 
 
540
 
void Session::run()
541
 
{
542
 
  if (initGlobals() || authenticate())
543
 
  {
544
 
    disconnect(0, true);
545
 
    return;
546
 
  }
547
 
 
548
 
  prepareForQueries();
549
 
 
550
 
  while (not client->haveError() && getKilled() != KILL_CONNECTION)
551
 
  {
552
 
    if (not executeStatement())
553
 
      break;
554
 
  }
555
 
 
556
 
  disconnect(0, true);
557
 
}
558
 
 
559
 
bool Session::schedule(Session::shared_ptr &arg)
560
 
{
561
 
  arg->scheduler= plugin::Scheduler::getScheduler();
562
 
  assert(arg->scheduler);
563
 
 
564
 
  connection_count.increment();
565
 
 
566
 
  if (connection_count > current_global_counters.max_used_connections)
567
 
  {
568
 
    current_global_counters.max_used_connections= connection_count;
569
 
  }
570
 
 
571
 
  current_global_counters.connections++;
572
 
  arg->thread_id= arg->variables.pseudo_thread_id= global_thread_id++;
573
 
 
574
 
  session::Cache::singleton().insert(arg);
575
 
 
576
 
  if (unlikely(plugin::EventObserver::connectSession(*arg)))
577
 
  {
578
 
    // We should do something about an error...
579
 
  }
580
 
 
581
 
  if (plugin::Scheduler::getScheduler()->addSession(arg))
582
 
  {
583
 
    DRIZZLE_CONNECTION_START(arg->getSessionId());
584
 
    char error_message_buff[DRIZZLE_ERRMSG_SIZE];
585
 
 
586
 
    arg->setKilled(Session::KILL_CONNECTION);
587
 
 
588
 
    arg->status_var.aborted_connects++;
589
 
 
590
 
    /* Can't use my_error() since store_globals has not been called. */
591
 
    /* TODO replace will better error message */
592
 
    snprintf(error_message_buff, sizeof(error_message_buff),
593
 
             ER(ER_CANT_CREATE_THREAD), 1);
594
 
    arg->client->sendError(ER_CANT_CREATE_THREAD, error_message_buff);
595
 
 
596
 
    return true;
597
 
  }
598
 
 
599
 
  return false;
600
 
}
601
 
 
602
 
 
603
 
/*
604
 
  Is this session viewable by the current user?
605
 
*/
606
 
bool Session::isViewable() const
607
 
{
608
 
  return plugin::Authorization::isAuthorized(current_session->getSecurityContext(),
609
 
                                             this,
610
 
                                             false);
611
 
}
612
 
 
613
 
 
614
 
const char* Session::enter_cond(boost::condition_variable_any &cond, boost::mutex &mutex, const char* msg)
615
 
{
616
 
  const char* old_msg = get_proc_info();
617
 
  safe_mutex_assert_owner(mutex);
618
 
  mysys_var->current_mutex = &mutex;
619
 
  mysys_var->current_cond = &cond;
620
 
  this->set_proc_info(msg);
621
 
  return old_msg;
622
 
}
623
 
 
624
 
void Session::exit_cond(const char* old_msg)
625
 
{
626
 
  /*
627
 
    Putting the mutex unlock in exit_cond() ensures that
628
 
    mysys_var->current_mutex is always unlocked _before_ mysys_var->mutex is
629
 
    locked (if that would not be the case, you'll get a deadlock if someone
630
 
    does a Session::awake() on you).
631
 
  */
632
 
  mysys_var->current_mutex->unlock();
633
 
  boost_unique_lock_t scopedLock(mysys_var->mutex);
634
 
  mysys_var->current_mutex = 0;
635
 
  mysys_var->current_cond = 0;
636
 
  this->set_proc_info(old_msg);
 
587
    statistic_increment(aborted_connects, &LOCK_status);
 
588
    Scheduler &thread_scheduler= get_thread_scheduler();
 
589
    thread_scheduler.end_thread(this, 0);
 
590
    return false;
 
591
  }
 
592
  return true;
637
593
}
638
594
 
639
595
bool Session::authenticate()
640
596
{
641
 
  lex->start(this);
642
 
  if (client->authenticate())
 
597
  lex_start(this);
 
598
  if (protocol->authenticate())
 
599
    return true;
 
600
 
 
601
  statistic_increment(aborted_connects, &LOCK_status);
 
602
  return false;
 
603
}
 
604
 
 
605
bool Session::checkUser(const char *passwd, uint32_t passwd_len, const char *in_db)
 
606
{
 
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());
643
621
    return false;
644
 
 
645
 
  status_var.aborted_connects++;
646
 
 
647
 
  return true;
648
 
}
649
 
 
650
 
bool Session::checkUser(const std::string &passwd_str,
651
 
                        const std::string &in_db)
652
 
{
653
 
  bool is_authenticated=
654
 
    plugin::Authentication::isAuthenticated(getSecurityContext(),
655
 
                                            passwd_str);
 
622
  }
 
623
 
 
624
  is_authenticated= authenticate_user(this, passwd);
656
625
 
657
626
  if (is_authenticated != true)
658
627
  {
659
 
    status_var.access_denied++;
660
 
    /* 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
 
661
633
    return false;
662
634
  }
663
635
 
 
636
  security_ctx.skip_grants();
 
637
 
664
638
  /* Change database if necessary */
665
 
  if (not in_db.empty())
 
639
  if (in_db && in_db[0])
666
640
  {
667
 
    SchemaIdentifier identifier(in_db);
668
 
    if (mysql_change_db(this, identifier))
 
641
    if (mysql_change_db(this, &db_str, false))
669
642
    {
670
643
      /* mysql_change_db() has pushed the error message. */
671
644
      return false;
672
645
    }
673
646
  }
674
647
  my_ok();
675
 
  password= not passwd_str.empty();
 
648
  password= test(passwd_len);          // remember for error messages
676
649
 
677
650
  /* Ready to handle queries */
678
651
  return true;
690
663
    (see my_message_sql)
691
664
  */
692
665
  lex->current_select= 0;
693
 
  clear_error();
694
 
  main_da.reset_diagnostics_area();
695
 
 
696
 
  if (client->readCommand(&l_packet, &packet_length) == false)
697
 
  {
698
 
    return false;
699
 
  }
700
 
 
701
 
  if (getKilled() == KILL_CONNECTION)
 
666
 
 
667
  if (protocol->readCommand(&l_packet, &packet_length) == false)
702
668
    return false;
703
669
 
704
670
  if (packet_length == 0)
705
671
    return true;
706
672
 
707
 
  l_command= static_cast<enum_server_command>(l_packet[0]);
 
673
  l_command= (enum enum_server_command) (unsigned char) l_packet[0];
708
674
 
709
675
  if (command >= COM_END)
710
676
    command= COM_END;                           // Wrong command
711
677
 
712
678
  assert(packet_length);
713
 
  return not dispatch_command(l_command, this, l_packet+1, (uint32_t) (packet_length-1));
 
679
  return ! dispatch_command(l_command, this, l_packet+1, (uint32_t) (packet_length-1));
714
680
}
715
681
 
716
682
bool Session::readAndStoreQuery(const char *in_packet, uint32_t in_packet_length)
722
688
    in_packet_length--;
723
689
  }
724
690
  const char *pos= in_packet + in_packet_length; /* Point at end null */
725
 
  while (in_packet_length > 0 && (pos[-1] == ';' || my_isspace(charset() ,pos[-1])))
 
691
  while (in_packet_length > 0 &&
 
692
         (pos[-1] == ';' || my_isspace(charset() ,pos[-1])))
726
693
  {
727
694
    pos--;
728
695
    in_packet_length--;
729
696
  }
730
697
 
731
 
  std::string *new_query= new std::string(in_packet, in_packet + in_packet_length);
732
 
  // We can not be entirely sure _schema has a value
733
 
  if (_schema)
734
 
  {
735
 
    plugin::QueryRewriter::rewriteQuery(*_schema, *new_query);
736
 
  }
737
 
  query.reset(new_query);
738
 
  _state.reset(new State(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);
739
710
 
740
711
  return true;
741
712
}
744
715
{
745
716
  bool do_release= 0;
746
717
  bool result= true;
747
 
  TransactionServices &transaction_services= TransactionServices::singleton();
748
718
 
749
719
  if (transaction.xid_state.xa_state != XA_NOTR)
750
720
  {
751
721
    my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[transaction.xid_state.xa_state]);
752
722
    return false;
753
723
  }
754
 
  switch (completion)
 
724
  switch (completion) 
755
725
  {
756
726
    case COMMIT:
757
727
      /*
760
730
       * (Which of course should never happen...)
761
731
       */
762
732
      server_status&= ~SERVER_STATUS_IN_TRANS;
763
 
      if (transaction_services.commitTransaction(this, true))
 
733
      if (ha_commit(this))
764
734
        result= false;
765
 
      options&= ~(OPTION_BEGIN);
 
735
      options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
 
736
      transaction.all.modified_non_trans_table= false;
766
737
      break;
767
738
    case COMMIT_RELEASE:
768
739
      do_release= 1; /* fall through */
777
748
    case ROLLBACK_AND_CHAIN:
778
749
    {
779
750
      server_status&= ~SERVER_STATUS_IN_TRANS;
780
 
      if (transaction_services.rollbackTransaction(this, true))
 
751
      if (ha_rollback(this))
781
752
        result= false;
782
 
      options&= ~(OPTION_BEGIN);
 
753
      options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
 
754
      transaction.all.modified_non_trans_table= false;
783
755
      if (result == true && (completion == ROLLBACK_AND_CHAIN))
784
756
        result= startTransaction();
785
757
      break;
790
762
  }
791
763
 
792
764
  if (result == false)
793
 
  {
794
765
    my_error(killed_errno(), MYF(0));
795
 
  }
796
766
  else if ((result == true) && do_release)
797
 
  {
798
 
    setKilled(Session::KILL_CONNECTION);
799
 
  }
 
767
    killed= Session::KILL_CONNECTION;
800
768
 
801
769
  return result;
802
770
}
804
772
bool Session::endActiveTransaction()
805
773
{
806
774
  bool result= true;
807
 
  TransactionServices &transaction_services= TransactionServices::singleton();
808
775
 
809
776
  if (transaction.xid_state.xa_state != XA_NOTR)
810
777
  {
814
781
  if (options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
815
782
  {
816
783
    server_status&= ~SERVER_STATUS_IN_TRANS;
817
 
    if (transaction_services.commitTransaction(this, true))
 
784
    if (ha_commit(this))
818
785
      result= false;
819
786
  }
820
 
  options&= ~(OPTION_BEGIN);
 
787
  options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
 
788
  transaction.all.modified_non_trans_table= false;
821
789
  return result;
822
790
}
823
791
 
824
 
bool Session::startTransaction(start_transaction_option_t opt)
 
792
bool Session::startTransaction()
825
793
{
826
794
  bool result= true;
827
795
 
828
796
  if (! endActiveTransaction())
829
 
  {
830
797
    result= false;
831
 
  }
832
798
  else
833
799
  {
834
800
    options|= OPTION_BEGIN;
835
801
    server_status|= SERVER_STATUS_IN_TRANS;
836
 
 
837
 
    if (plugin::TransactionalStorageEngine::notifyStartTransaction(this, opt))
838
 
    {
839
 
      result= false;
840
 
    }
 
802
    if (lex->start_transaction_opt & DRIZZLE_START_TRANS_OPT_WITH_CONS_SNAPSHOT)
 
803
      if (ha_start_consistent_snapshot(this))
 
804
        result= false;
841
805
  }
842
 
 
843
806
  return result;
844
807
}
845
808
 
865
828
  free_items();
866
829
  /* Reset where. */
867
830
  where= Session::DEFAULT_WHERE;
868
 
 
869
 
  /* Reset the temporary shares we built */
870
 
  for_each(temporary_shares.begin(),
871
 
           temporary_shares.end(),
872
 
           DeletePtr());
873
 
  temporary_shares.clear();
874
831
}
875
832
 
876
833
/**
884
841
  @return  NULL on failure, or pointer to the LEX_STRING object
885
842
*/
886
843
LEX_STRING *Session::make_lex_string(LEX_STRING *lex_str,
887
 
                                     const std::string &str,
888
 
                                     bool allocate_lex_string)
889
 
{
890
 
  return make_lex_string(lex_str, str.c_str(), str.length(), allocate_lex_string);
891
 
}
892
 
 
893
 
LEX_STRING *Session::make_lex_string(LEX_STRING *lex_str,
894
 
                                     const char* str, uint32_t length,
895
 
                                     bool allocate_lex_string)
 
844
                                 const char* str, uint32_t length,
 
845
                                 bool allocate_lex_string)
896
846
{
897
847
  if (allocate_lex_string)
898
848
    if (!(lex_str= (LEX_STRING *)alloc(sizeof(LEX_STRING))))
899
849
      return 0;
900
 
  if (!(lex_str->str= mem_root->strmake_root(str, length)))
 
850
  if (!(lex_str->str= strmake_root(mem_root, str, length)))
901
851
    return 0;
902
852
  lex_str->length= length;
903
853
  return lex_str;
904
854
}
905
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
 
906
931
int Session::send_explain_fields(select_result *result)
907
932
{
908
933
  List<Item> field_list;
938
963
  }
939
964
  item->maybe_null= 1;
940
965
  field_list.push_back(new Item_empty_string("Extra", 255, cs));
941
 
  return (result->send_fields(field_list));
942
 
}
943
 
 
944
 
void select_result::send_error(uint32_t errcode, const char *err)
945
 
{
946
 
  my_message(errcode, err, MYF(0));
 
966
  return (result->send_fields(field_list,
 
967
                              Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF));
947
968
}
948
969
 
949
970
/************************************************************************
955
976
  my_message(errcode, err, MYF(0));
956
977
  if (file > 0)
957
978
  {
958
 
    (void) cache->end_io_cache();
959
 
    (void) internal::my_close(file, MYF(0));
960
 
    (void) internal::my_delete(path.file_string().c_str(), 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
961
982
    file= -1;
962
983
  }
963
984
}
965
986
 
966
987
bool select_to_file::send_eof()
967
988
{
968
 
  int error= test(cache->end_io_cache());
969
 
  if (internal::my_close(file, MYF(MY_WME)))
 
989
  int error= test(end_io_cache(&cache));
 
990
  if (my_close(file,MYF(MY_WME)))
970
991
    error= 1;
971
992
  if (!error)
972
993
  {
987
1008
  /* In case of error send_eof() may be not called: close the file here. */
988
1009
  if (file >= 0)
989
1010
  {
990
 
    (void) cache->end_io_cache();
991
 
    (void) internal::my_close(file, MYF(0));
 
1011
    (void) end_io_cache(&cache);
 
1012
    (void) my_close(file,MYF(0));
992
1013
    file= -1;
993
1014
  }
994
 
  path= "";
 
1015
  path[0]= '\0';
995
1016
  row_count= 0;
996
1017
}
997
1018
 
998
 
select_to_file::select_to_file(file_exchange *ex)
999
 
  : exchange(ex),
1000
 
    file(-1),
1001
 
    cache(static_cast<internal::IO_CACHE *>(memory::sql_calloc(sizeof(internal::IO_CACHE)))),
1002
 
    row_count(0L)
1003
 
{
1004
 
  path= "";
1005
 
}
1006
1019
 
1007
1020
select_to_file::~select_to_file()
1008
1021
{
1009
 
  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
  }
1010
1028
}
1011
1029
 
1012
1030
/***************************************************************************
1035
1053
*/
1036
1054
 
1037
1055
 
1038
 
static int create_file(Session *session,
1039
 
                       fs::path &target_path,
1040
 
                       file_exchange *exchange,
1041
 
                       internal::IO_CACHE *cache)
 
1056
static File create_file(Session *session, char *path, file_exchange *exchange, IO_CACHE *cache)
1042
1057
{
1043
 
  fs::path to_file(exchange->file_name);
1044
 
  int file;
1045
 
 
1046
 
  if (not to_file.has_root_directory())
 
1058
  File file;
 
1059
  uint32_t option= MY_UNPACK_FILENAME | MY_RELATIVE_PATH;
 
1060
 
 
1061
#ifdef DONT_ALLOW_FULL_LOAD_DATA_PATHS
 
1062
  option|= MY_REPLACE_DIR;                      // Force use of db directory
 
1063
#endif
 
1064
 
 
1065
  if (!dirname_length(exchange->file_name))
1047
1066
  {
1048
 
    target_path= fs::system_complete(getDataHomeCatalog());
1049
 
    util::string::const_shared_ptr schema(session->schema());
1050
 
    if (schema and not schema->empty())
1051
 
    {
1052
 
      int count_elements= 0;
1053
 
      for (fs::path::iterator iter= to_file.begin();
1054
 
           iter != to_file.end();
1055
 
           ++iter, ++count_elements)
1056
 
      { }
1057
 
 
1058
 
      if (count_elements == 1)
1059
 
      {
1060
 
        target_path /= *schema;
1061
 
      }
1062
 
    }
1063
 
    target_path /= to_file;
 
1067
    strcpy(path, drizzle_real_data_home);
 
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);
1064
1071
  }
1065
1072
  else
1066
 
  {
1067
 
    target_path = exchange->file_name;
1068
 
  }
1069
 
 
1070
 
  if (not secure_file_priv.string().empty())
1071
 
  {
1072
 
    if (target_path.file_string().substr(0, secure_file_priv.file_string().size()) != secure_file_priv.file_string())
1073
 
    {
1074
 
      /* Write only allowed to dir or subdir specified by secure_file_priv */
1075
 
      my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--secure-file-priv");
1076
 
      return -1;
1077
 
    }
1078
 
  }
1079
 
 
1080
 
  if (!access(target_path.file_string().c_str(), F_OK))
 
1073
    (void) fn_format(path, exchange->file_name, drizzle_real_data_home, "", option);
 
1074
 
 
1075
  if (opt_secure_file_priv &&
 
1076
      strncmp(opt_secure_file_priv, path, strlen(opt_secure_file_priv)))
 
1077
  {
 
1078
    /* Write only allowed to dir or subdir specified by secure_file_priv */
 
1079
    my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--secure-file-priv");
 
1080
    return -1;
 
1081
  }
 
1082
 
 
1083
  if (!access(path, F_OK))
1081
1084
  {
1082
1085
    my_error(ER_FILE_EXISTS_ERROR, MYF(0), exchange->file_name);
1083
1086
    return -1;
1084
1087
  }
1085
1088
  /* Create the file world readable */
1086
 
  if ((file= internal::my_create(target_path.file_string().c_str(), 0666, O_WRONLY|O_EXCL, MYF(MY_WME))) < 0)
 
1089
  if ((file= my_create(path, 0666, O_WRONLY|O_EXCL, MYF(MY_WME))) < 0)
1087
1090
    return file;
 
1091
#ifdef HAVE_FCHMOD
1088
1092
  (void) fchmod(file, 0666);                    // Because of umask()
1089
 
  if (cache->init_io_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)))
1090
1097
  {
1091
 
    internal::my_close(file, MYF(0));
1092
 
    internal::my_delete(target_path.file_string().c_str(), 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
1093
1100
    return -1;
1094
1101
  }
1095
1102
  return file;
1103
1110
  bool string_results= false, non_string_results= false;
1104
1111
  unit= u;
1105
1112
  if ((uint32_t) strlen(exchange->file_name) + NAME_LEN >= FN_REFLEN)
1106
 
  {
1107
 
    path= exchange->file_name;
1108
 
  }
 
1113
    strncpy(path,exchange->file_name,FN_REFLEN-1);
1109
1114
 
1110
1115
  /* Check if there is any blobs in data */
1111
1116
  {
1115
1120
    {
1116
1121
      if (item->max_length >= MAX_BLOB_WIDTH)
1117
1122
      {
1118
 
        blob_flag=1;
1119
 
        break;
 
1123
        blob_flag=1;
 
1124
        break;
1120
1125
      }
1121
 
 
1122
1126
      if (item->result_type() == STRING_RESULT)
1123
1127
        string_results= true;
1124
1128
      else
1153
1157
    return 1;
1154
1158
  }
1155
1159
 
1156
 
  if ((file= create_file(session, path, exchange, cache)) < 0)
 
1160
  if ((file= create_file(session, path, exchange, &cache)) < 0)
1157
1161
    return 1;
1158
1162
 
1159
1163
  return 0;
1160
1164
}
1161
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
 
1162
1173
bool select_export::send_data(List<Item> &items)
1163
1174
{
1164
1175
  char buff[MAX_FIELD_WIDTH],null_buff[2],space[MAX_FIELD_WIDTH];
1169
1180
  if (unit->offset_limit_cnt)
1170
1181
  {                                             // using limit offset,count
1171
1182
    unit->offset_limit_cnt--;
1172
 
    return false;
 
1183
    return(0);
1173
1184
  }
1174
1185
  row_count++;
1175
1186
  Item *item;
1176
1187
  uint32_t used_length=0,items_left=items.elements;
1177
1188
  List_iterator_fast<Item> li(items);
1178
1189
 
1179
 
  if (my_b_write(cache,(unsigned char*) exchange->line_start->ptr(),
1180
 
                 exchange->line_start->length()))
1181
 
    return true;
1182
 
 
 
1190
  if (my_b_write(&cache,(unsigned char*) exchange->line_start->ptr(),
 
1191
                 exchange->line_start->length()))
 
1192
    goto err;
1183
1193
  while ((item=li++))
1184
1194
  {
1185
1195
    Item_result result_type=item->result_type();
1188
1198
    res=item->str_result(&tmp);
1189
1199
    if (res && enclosed)
1190
1200
    {
1191
 
      if (my_b_write(cache,(unsigned char*) exchange->enclosed->ptr(),
1192
 
                     exchange->enclosed->length()))
1193
 
        return true;
 
1201
      if (my_b_write(&cache,(unsigned char*) exchange->enclosed->ptr(),
 
1202
                     exchange->enclosed->length()))
 
1203
        goto err;
1194
1204
    }
1195
1205
    if (!res)
1196
1206
    {                                           // NULL
1197
1207
      if (!fixed_row_size)
1198
1208
      {
1199
 
        if (escape_char != -1)                  // Use \N syntax
1200
 
        {
1201
 
          null_buff[0]=escape_char;
1202
 
          null_buff[1]='N';
1203
 
          if (my_b_write(cache,(unsigned char*) null_buff,2))
1204
 
            return true;
1205
 
        }
1206
 
        else if (my_b_write(cache,(unsigned char*) "NULL",4))
1207
 
          return true;
 
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;
1208
1218
      }
1209
1219
      else
1210
1220
      {
1211
 
        used_length=0;                          // Fill with space
 
1221
        used_length=0;                          // Fill with space
1212
1222
      }
1213
1223
    }
1214
1224
    else
1215
1225
    {
1216
1226
      if (fixed_row_size)
1217
 
        used_length= min(res->length(), static_cast<size_t>(item->max_length));
 
1227
        used_length=cmin(res->length(),item->max_length);
1218
1228
      else
1219
 
        used_length= res->length();
1220
 
 
 
1229
        used_length=res->length();
1221
1230
      if ((result_type == STRING_RESULT || is_unsafe_field_sep) &&
1222
 
          escape_char != -1)
 
1231
           escape_char != -1)
1223
1232
      {
1224
1233
        char *pos, *start, *end;
1225
1234
        const CHARSET_INFO * const res_charset= res->charset();
1226
1235
        const CHARSET_INFO * const character_set_client= default_charset_info;
1227
1236
 
1228
1237
        bool check_second_byte= (res_charset == &my_charset_bin) &&
1229
 
          character_set_client->
1230
 
          escape_with_backslash_is_dangerous;
 
1238
                                 character_set_client->
 
1239
                                 escape_with_backslash_is_dangerous;
1231
1240
        assert(character_set_client->mbmaxlen == 2 ||
1232
1241
               !character_set_client->escape_with_backslash_is_dangerous);
1233
 
        for (start=pos=(char*) res->ptr(),end=pos+used_length ;
1234
 
             pos != end ;
1235
 
             pos++)
1236
 
        {
1237
 
          if (use_mb(res_charset))
1238
 
          {
1239
 
            int l;
1240
 
            if ((l=my_ismbchar(res_charset, pos, end)))
1241
 
            {
1242
 
              pos += l-1;
1243
 
              continue;
1244
 
            }
1245
 
          }
 
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
1246
1257
 
1247
1258
          /*
1248
1259
            Special case when dumping BINARY/VARBINARY/BLOB values
1276
1287
            assert before the loop makes that sure.
1277
1288
          */
1278
1289
 
1279
 
          if ((needs_escaping(*pos, enclosed) ||
 
1290
          if ((NEED_ESCAPING(*pos) ||
1280
1291
               (check_second_byte &&
1281
1292
                my_mbcharlen(character_set_client, (unsigned char) *pos) == 2 &&
1282
1293
                pos + 1 < end &&
1283
 
                needs_escaping(pos[1], enclosed))) &&
 
1294
                NEED_ESCAPING(pos[1]))) &&
1284
1295
              /*
1285
 
                Don't escape field_term_char by doubling - doubling is only
1286
 
                valid for ENCLOSED BY characters:
 
1296
               Don't escape field_term_char by doubling - doubling is only
 
1297
               valid for ENCLOSED BY characters:
1287
1298
              */
1288
1299
              (enclosed || !is_ambiguous_field_term ||
1289
1300
               (int) (unsigned char) *pos != field_term_char))
1290
1301
          {
1291
 
            char tmp_buff[2];
 
1302
            char tmp_buff[2];
1292
1303
            tmp_buff[0]= ((int) (unsigned char) *pos == field_sep_char &&
1293
1304
                          is_ambiguous_field_sep) ?
1294
 
              field_sep_char : escape_char;
1295
 
            tmp_buff[1]= *pos ? *pos : '0';
1296
 
            if (my_b_write(cache,(unsigned char*) start,(uint32_t) (pos-start)) ||
1297
 
                my_b_write(cache,(unsigned char*) tmp_buff,2))
1298
 
              return true;
1299
 
            start=pos+1;
1300
 
          }
1301
 
        }
1302
 
        if (my_b_write(cache,(unsigned char*) start,(uint32_t) (pos-start)))
1303
 
          return true;
 
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;
1304
1315
      }
1305
 
      else if (my_b_write(cache,(unsigned char*) res->ptr(),used_length))
1306
 
        return true;
 
1316
      else if (my_b_write(&cache,(unsigned char*) res->ptr(),used_length))
 
1317
        goto err;
1307
1318
    }
1308
1319
    if (fixed_row_size)
1309
1320
    {                                           // Fill with space
1310
1321
      if (item->max_length > used_length)
1311
1322
      {
1312
 
        /* QQ:  Fix by adding a my_b_fill() function */
1313
 
        if (!space_inited)
1314
 
        {
1315
 
          space_inited=1;
1316
 
          memset(space, ' ', sizeof(space));
1317
 
        }
1318
 
        uint32_t length=item->max_length-used_length;
1319
 
        for (; length > sizeof(space) ; length-=sizeof(space))
1320
 
        {
1321
 
          if (my_b_write(cache,(unsigned char*) space,sizeof(space)))
1322
 
            return true;
1323
 
        }
1324
 
        if (my_b_write(cache,(unsigned char*) space,length))
1325
 
          return true;
 
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;
1326
1337
      }
1327
1338
    }
1328
1339
    if (res && enclosed)
1329
1340
    {
1330
 
      if (my_b_write(cache, (unsigned char*) exchange->enclosed->ptr(),
 
1341
      if (my_b_write(&cache, (unsigned char*) exchange->enclosed->ptr(),
1331
1342
                     exchange->enclosed->length()))
1332
 
        return true;
 
1343
        goto err;
1333
1344
    }
1334
1345
    if (--items_left)
1335
1346
    {
1336
 
      if (my_b_write(cache, (unsigned char*) exchange->field_term->ptr(),
 
1347
      if (my_b_write(&cache, (unsigned char*) exchange->field_term->ptr(),
1337
1348
                     field_term_length))
1338
 
        return true;
 
1349
        goto err;
1339
1350
    }
1340
1351
  }
1341
 
  if (my_b_write(cache,(unsigned char*) exchange->line_term->ptr(),
1342
 
                 exchange->line_term->length()))
1343
 
  {
1344
 
    return true;
1345
 
  }
1346
 
 
1347
 
  return false;
 
1352
  if (my_b_write(&cache,(unsigned char*) exchange->line_term->ptr(),
 
1353
                 exchange->line_term->length()))
 
1354
    goto err;
 
1355
  return(0);
 
1356
err:
 
1357
  return(1);
1348
1358
}
1349
1359
 
1350
1360
 
1357
1367
select_dump::prepare(List<Item> &, Select_Lex_Unit *u)
1358
1368
{
1359
1369
  unit= u;
1360
 
  return (int) ((file= create_file(session, path, exchange, cache)) < 0);
 
1370
  return (int) ((file= create_file(session, path, exchange, &cache)) < 0);
1361
1371
}
1362
1372
 
1363
1373
 
1377
1387
  if (row_count++ > 1)
1378
1388
  {
1379
1389
    my_message(ER_TOO_MANY_ROWS, ER(ER_TOO_MANY_ROWS), MYF(0));
1380
 
    return 1;
 
1390
    goto err;
1381
1391
  }
1382
1392
  while ((item=li++))
1383
1393
  {
1384
1394
    res=item->str_result(&tmp);
1385
1395
    if (!res)                                   // If NULL
1386
1396
    {
1387
 
      if (my_b_write(cache,(unsigned char*) "",1))
1388
 
        return 1;
 
1397
      if (my_b_write(&cache,(unsigned char*) "",1))
 
1398
        goto err;
1389
1399
    }
1390
 
    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()))
1391
1401
    {
1392
 
      my_error(ER_ERROR_ON_WRITE, MYF(0), path.file_string().c_str(), errno);
1393
 
      return 1;
 
1402
      my_error(ER_ERROR_ON_WRITE, MYF(0), path, my_errno);
 
1403
      goto err;
1394
1404
    }
1395
1405
  }
1396
1406
  return(0);
 
1407
err:
 
1408
  return(1);
1397
1409
}
1398
1410
 
1399
1411
 
1451
1463
      switch (val_item->result_type())
1452
1464
      {
1453
1465
      case REAL_RESULT:
1454
 
        op= &select_max_min_finder_subselect::cmp_real;
1455
 
        break;
 
1466
        op= &select_max_min_finder_subselect::cmp_real;
 
1467
        break;
1456
1468
      case INT_RESULT:
1457
 
        op= &select_max_min_finder_subselect::cmp_int;
1458
 
        break;
 
1469
        op= &select_max_min_finder_subselect::cmp_int;
 
1470
        break;
1459
1471
      case STRING_RESULT:
1460
 
        op= &select_max_min_finder_subselect::cmp_str;
1461
 
        break;
 
1472
        op= &select_max_min_finder_subselect::cmp_str;
 
1473
        break;
1462
1474
      case DECIMAL_RESULT:
1463
1475
        op= &select_max_min_finder_subselect::cmp_decimal;
1464
1476
        break;
1465
1477
      case ROW_RESULT:
1466
1478
        // This case should never be choosen
1467
 
        assert(0);
1468
 
        op= 0;
 
1479
        assert(0);
 
1480
        op= 0;
1469
1481
      }
1470
1482
    }
1471
1483
    cache->store(val_item);
1554
1566
void Session::end_statement()
1555
1567
{
1556
1568
  /* Cleanup SQL processing state to reuse this statement in next query. */
1557
 
  lex->end();
1558
 
  query_cache_key= ""; // reset the cache key
1559
 
  resetResultsetMessage();
 
1569
  lex_end(lex);
1560
1570
}
1561
1571
 
1562
1572
bool Session::copy_db_to(char **p_db, size_t *p_db_length)
1563
1573
{
1564
 
  assert(_schema);
1565
 
  if (_schema and _schema->empty())
1566
 
  {
1567
 
    my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
1568
 
    return true;
1569
 
  }
1570
 
  else if (not _schema)
1571
 
  {
1572
 
    my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
1573
 
    return true;
1574
 
  }
1575
 
  assert(_schema);
1576
 
 
1577
 
  *p_db= strmake(_schema->c_str(), _schema->size());
1578
 
  *p_db_length= _schema->size();
1579
 
 
 
1574
  if (db == NULL)
 
1575
  {
 
1576
    my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
 
1577
    return true;
 
1578
  }
 
1579
  *p_db= strmake(db, db_length);
 
1580
  *p_db_length= db_length;
1580
1581
  return false;
1581
1582
}
1582
1583
 
1591
1592
  quick_group= 1;
1592
1593
  table_charset= 0;
1593
1594
  precomputed_group_by= 0;
 
1595
  bit_fields_as_long= 0;
1594
1596
}
1595
1597
 
1596
1598
void Tmp_Table_Param::cleanup(void)
1603
1605
  }
1604
1606
}
1605
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
 
1606
1630
void Session::send_kill_message() const
1607
1631
{
1608
1632
  int err= killed_errno();
1615
1639
  memset(&status_var, 0, sizeof(status_var));
1616
1640
}
1617
1641
 
1618
 
 
1619
 
void Session::set_db(const std::string &new_db)
 
1642
void Security_context::skip_grants()
 
1643
{
 
1644
  /* privileges for the user are unknown everything is allowed */
 
1645
}
 
1646
 
 
1647
 
 
1648
/****************************************************************************
 
1649
  Handling of open and locked tables states.
 
1650
 
 
1651
  This is used when we want to open/lock (and then close) some tables when
 
1652
  we already have a set of tables open and locked. We use these methods for
 
1653
  access to mysql.proc table to find definitions of stored routines.
 
1654
****************************************************************************/
 
1655
 
 
1656
void Session::reset_n_backup_open_tables_state(Open_tables_state *backup)
 
1657
{
 
1658
  backup->set_open_tables_state(this);
 
1659
  reset_open_tables_state();
 
1660
  state_flags|= Open_tables_state::BACKUPS_AVAIL;
 
1661
}
 
1662
 
 
1663
 
 
1664
void Session::restore_backup_open_tables_state(Open_tables_state *backup)
 
1665
{
 
1666
  /*
 
1667
    Before we will throw away current open tables state we want
 
1668
    to be sure that it was properly cleaned up.
 
1669
  */
 
1670
  assert(open_tables == 0 && temporary_tables == 0 &&
 
1671
              derived_tables == 0 &&
 
1672
              lock == 0);
 
1673
  set_open_tables_state(backup);
 
1674
}
 
1675
 
 
1676
 
 
1677
bool Session::set_db(const char *new_db, size_t new_db_len)
1620
1678
{
1621
1679
  /* Do not reallocate memory if current chunk is big enough. */
1622
 
  if (new_db.length())
1623
 
  {
1624
 
    _schema.reset(new std::string(new_db));
1625
 
  }
 
1680
  if (db && new_db && db_length >= new_db_len)
 
1681
    memcpy(db, new_db, new_db_len+1);
1626
1682
  else
1627
1683
  {
1628
 
    _schema.reset(new std::string(""));
 
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;
1629
1697
  }
1630
 
}
1631
 
 
 
1698
  db_length= db ? new_db_len : 0;
 
1699
  return new_db && !db;
 
1700
}
 
1701
 
 
1702
 
 
1703
/**
 
1704
  Check the killed state of a user thread
 
1705
  @param session  user thread
 
1706
  @retval 0 the user thread is active
 
1707
  @retval 1 the user thread has been killed
 
1708
*/
 
1709
extern "C" int session_killed(const Session *session)
 
1710
{
 
1711
  return(session->killed);
 
1712
}
 
1713
 
 
1714
/**
 
1715
  Return the thread id of a user thread
 
1716
  @param session user thread
 
1717
  @return thread id
 
1718
*/
 
1719
extern "C" unsigned long session_get_thread_id(const Session *session)
 
1720
{
 
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)
 
1735
{
 
1736
  return(session->charset());
 
1737
}
 
1738
 
 
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)
 
1750
{
 
1751
  mark_transaction_to_rollback(session, all);
 
1752
}
1632
1753
 
1633
1754
/**
1634
1755
  Mark transaction to rollback and mark error as fatal to a sub-statement.
1651
1772
  plugin_sessionvar_cleanup(this);
1652
1773
 
1653
1774
  /* If necessary, log any aborted or unauthorized connections */
1654
 
  if (getKilled() || client->wasAborted())
1655
 
  {
1656
 
    status_var.aborted_threads++;
1657
 
  }
 
1775
  if (killed || protocol->wasAborted())
 
1776
    statistic_increment(aborted_threads, &LOCK_status);
1658
1777
 
1659
 
  if (client->wasAborted())
 
1778
  if (protocol->wasAborted())
1660
1779
  {
1661
 
    if (not getKilled() && variables.log_warnings > 1)
 
1780
    if (! killed && variables.log_warnings > 1)
1662
1781
    {
1663
 
      SecurityContext *sctx= &security_ctx;
 
1782
      Security_context *sctx= &security_ctx;
1664
1783
 
1665
1784
      errmsg_printf(ERRMSG_LVL_WARN, ER(ER_NEW_ABORTING_CONNECTION)
1666
1785
                  , thread_id
1667
 
                  , (_schema->empty() ? "unconnected" : _schema->c_str())
1668
 
                  , sctx->getUser().empty() == false ? sctx->getUser().c_str() : "unauthenticated"
1669
 
                  , sctx->getIp().c_str()
 
1786
                  , (db ? db : "unconnected")
 
1787
                  , sctx->user.empty() == false ? sctx->user.c_str() : "unauthenticated"
 
1788
                  , sctx->ip.c_str()
1670
1789
                  , (main_da.is_error() ? main_da.message() : ER(ER_UNKNOWN_ERROR)));
1671
1790
    }
1672
1791
  }
1673
1792
 
1674
1793
  /* Close out our connection to the client */
1675
1794
  if (should_lock)
1676
 
    session::Cache::singleton().mutex().lock();
1677
 
 
1678
 
  setKilled(Session::KILL_CONNECTION);
1679
 
 
1680
 
  if (client->isConnected())
 
1795
    (void) pthread_mutex_lock(&LOCK_thread_count);
 
1796
  killed= Session::KILL_CONNECTION;
 
1797
  if (protocol->isConnected())
1681
1798
  {
1682
1799
    if (errcode)
1683
1800
    {
1684
1801
      /*my_error(errcode, ER(errcode));*/
1685
 
      client->sendError(errcode, ER(errcode));
 
1802
      protocol->sendError(errcode, ER(errcode)); /* purecov: inspected */
1686
1803
    }
1687
 
    client->close();
 
1804
    protocol->close();
1688
1805
  }
1689
 
 
1690
1806
  if (should_lock)
1691
 
  {
1692
 
    session::Cache::singleton().mutex().unlock();
1693
 
  }
 
1807
    (void) pthread_mutex_unlock(&LOCK_thread_count);
1694
1808
}
1695
1809
 
1696
1810
void Session::reset_for_next_command()
1707
1821
  server_status&= ~ (SERVER_MORE_RESULTS_EXISTS |
1708
1822
                          SERVER_QUERY_NO_INDEX_USED |
1709
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
  }
1710
1834
 
1711
1835
  clear_error();
1712
1836
  main_da.reset_diagnostics_area();
1716
1840
 
1717
1841
/*
1718
1842
  Close all temporary tables created by 'CREATE TEMPORARY TABLE' for thread
 
1843
  creates one DROP TEMPORARY Table binlog event for each pseudo-thread
1719
1844
*/
1720
1845
 
1721
 
void Open_tables_state::close_temporary_tables()
 
1846
void Session::close_temporary_tables()
1722
1847
{
1723
1848
  Table *table;
1724
1849
  Table *tmp_next;
1725
1850
 
1726
 
  if (not temporary_tables)
 
1851
  if (!temporary_tables)
1727
1852
    return;
1728
1853
 
1729
1854
  for (table= temporary_tables; table; table= tmp_next)
1730
1855
  {
1731
 
    tmp_next= table->getNext();
1732
 
    nukeTable(table);
 
1856
    tmp_next= table->next;
 
1857
    close_temporary(table, true, true);
1733
1858
  }
1734
1859
  temporary_tables= NULL;
1735
1860
}
1736
1861
 
1737
 
/*
1738
 
  unlink from session->temporary tables and close temporary table
1739
 
*/
1740
 
 
1741
 
void Open_tables_state::close_temporary_table(Table *table)
1742
 
{
1743
 
  if (table->getPrev())
1744
 
  {
1745
 
    table->getPrev()->setNext(table->getNext());
1746
 
    if (table->getPrev()->getNext())
1747
 
    {
1748
 
      table->getNext()->setPrev(table->getPrev());
1749
 
    }
1750
 
  }
1751
 
  else
1752
 
  {
1753
 
    /* removing the item from the list */
1754
 
    assert(table == temporary_tables);
1755
 
    /*
1756
 
      slave must reset its temporary list pointer to zero to exclude
1757
 
      passing non-zero value to end_slave via rli->save_temporary_tables
1758
 
      when no temp tables opened, see an invariant below.
1759
 
    */
1760
 
    temporary_tables= table->getNext();
1761
 
    if (temporary_tables)
1762
 
    {
1763
 
      table->getNext()->setPrev(NULL);
1764
 
    }
1765
 
  }
1766
 
  nukeTable(table);
1767
 
}
1768
 
 
1769
 
/*
1770
 
  Close and drop a temporary table
1771
 
 
1772
 
  NOTE
1773
 
  This dosn't unlink table from session->temporary
1774
 
  If this is needed, use close_temporary_table()
1775
 
*/
1776
 
 
1777
 
void Open_tables_state::nukeTable(Table *table)
1778
 
{
1779
 
  plugin::StorageEngine *table_type= table->getShare()->db_type();
1780
 
 
1781
 
  table->free_io_cache();
1782
 
  table->delete_table();
1783
 
 
1784
 
  TableIdentifier identifier(table->getShare()->getSchemaName(), table->getShare()->getTableName(), table->getShare()->getPath());
1785
 
  rm_temporary_table(table_type, identifier);
1786
 
 
1787
 
  delete table->getMutableShare();
1788
 
 
1789
 
  /* This makes me sad, but we're allocating it via malloc */
1790
 
  delete table;
1791
 
}
1792
1862
 
1793
1863
/** Clear most status variables. */
1794
1864
extern time_t flush_status_time;
 
1865
extern uint32_t max_used_connections;
1795
1866
 
1796
1867
void Session::refresh_status()
1797
1868
{
 
1869
  pthread_mutex_lock(&LOCK_status);
 
1870
 
 
1871
  /* Add thread's status variabes to global status */
 
1872
  add_to_status(&global_status_var, &status_var);
 
1873
 
1798
1874
  /* Reset thread's status variables */
1799
1875
  memset(&status_var, 0, sizeof(status_var));
1800
1876
 
 
1877
  /* Reset some global variables */
 
1878
  reset_status_vars();
 
1879
 
 
1880
  /* Reset the counters of all key caches (default and named). */
 
1881
  process_key_caches(reset_key_cache_counters);
1801
1882
  flush_status_time= time((time_t*) 0);
1802
 
  current_global_counters.max_used_connections= 1; /* We set it to one, because we know we exist */
1803
 
  current_global_counters.connections= 0;
 
1883
  max_used_connections= 1; /* We set it to one, because we know we exist */
 
1884
  pthread_mutex_unlock(&LOCK_status);
1804
1885
}
1805
1886
 
 
1887
#define extra_size sizeof(double)
 
1888
 
1806
1889
user_var_entry *Session::getVariable(LEX_STRING &name, bool create_if_not_exists)
1807
1890
{
1808
 
  return getVariable(std::string(name.str, name.length), create_if_not_exists);
1809
 
}
1810
 
 
1811
 
user_var_entry *Session::getVariable(const std::string  &name, bool create_if_not_exists)
1812
 
{
1813
 
  UserVarsRange ppp= user_vars.equal_range(name);
1814
 
 
1815
 
  for (UserVars::iterator iter= ppp.first;
1816
 
       iter != ppp.second; ++iter)
1817
 
  {
1818
 
    return (*iter).second;
1819
 
  }
1820
 
 
1821
 
  if (not create_if_not_exists)
1822
 
    return NULL;
1823
 
 
1824
1891
  user_var_entry *entry= NULL;
1825
 
  entry= new (nothrow) user_var_entry(name.c_str(), query_id);
1826
 
 
1827
 
  if (entry == NULL)
1828
 
    return NULL;
1829
 
 
1830
 
  std::pair<UserVars::iterator, bool> returnable= user_vars.insert(make_pair(name, entry));
1831
 
 
1832
 
  if (not returnable.second)
 
1892
 
 
1893
  assert(name.length == strlen (name.str));
 
1894
  entry= (user_var_entry*) hash_search(&user_vars, (unsigned char*) name.str, name.length);
 
1895
 
 
1896
  if ((entry == NULL) && create_if_not_exists)
1833
1897
  {
1834
 
    delete entry;
 
1898
    uint32_t size=ALIGN_SIZE(sizeof(user_var_entry))+name.length+1+extra_size;
 
1899
    if (!hash_inited(&user_vars))
 
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);
 
1924
    if (my_hash_insert(&user_vars, (unsigned char*) entry))
 
1925
    {
 
1926
      assert(1);
 
1927
      free((char*) entry);
 
1928
      return 0;
 
1929
    }
 
1930
 
1835
1931
  }
1836
1932
 
1837
1933
  return entry;
1838
1934
}
1839
1935
 
1840
 
void Session::setVariable(const std::string &name, const std::string &value)
1841
 
{
1842
 
  user_var_entry *updateable_var= getVariable(name.c_str(), true);
1843
 
 
1844
 
  updateable_var->update_hash(false,
1845
 
                              (void*)value.c_str(),
1846
 
                              static_cast<uint32_t>(value.length()), STRING_RESULT,
1847
 
                              &my_charset_bin,
1848
 
                              DERIVATION_IMPLICIT, false);
1849
 
}
1850
 
 
1851
 
void Open_tables_state::mark_temp_tables_as_free_for_reuse()
1852
 
{
1853
 
  for (Table *table= temporary_tables ; table ; table= table->getNext())
 
1936
void Session::mark_temp_tables_as_free_for_reuse()
 
1937
{
 
1938
  for (Table *table= temporary_tables ; table ; table= table->next)
1854
1939
  {
1855
 
    if (table->query_id == getQueryId())
 
1940
    if (table->query_id == query_id)
1856
1941
    {
1857
1942
      table->query_id= 0;
1858
 
      table->cursor->ha_reset();
 
1943
      table->file->ha_reset();
1859
1944
    }
1860
1945
  }
1861
1946
}
1862
1947
 
1863
1948
void Session::mark_used_tables_as_free_for_reuse(Table *table)
1864
1949
{
1865
 
  for (; table ; table= table->getNext())
 
1950
  for (; table ; table= table->next)
1866
1951
  {
1867
 
    if (table->query_id == getQueryId())
 
1952
    if (table->query_id == query_id)
1868
1953
    {
1869
1954
      table->query_id= 0;
1870
 
      table->cursor->ha_reset();
 
1955
      table->file->ha_reset();
1871
1956
    }
1872
1957
  }
1873
1958
}
1883
1968
*/
1884
1969
void Session::close_thread_tables()
1885
1970
{
1886
 
  clearDerivedTables();
 
1971
  Table *table;
 
1972
 
 
1973
  /*
 
1974
    We are assuming here that session->derived_tables contains ONLY derived
 
1975
    tables for this substatement. i.e. instead of approach which uses
 
1976
    query_id matching for determining which of the derived tables belong
 
1977
    to this substatement we rely on the ability of substatements to
 
1978
    save/restore session->derived_tables during their execution.
 
1979
 
 
1980
    TODO: Probably even better approach is to simply associate list of
 
1981
          derived tables with (sub-)statement instead of thread and destroy
 
1982
          them at the end of its execution.
 
1983
  */
 
1984
  if (derived_tables)
 
1985
  {
 
1986
    Table *next;
 
1987
    /*
 
1988
      Close all derived tables generated in queries like
 
1989
      SELECT * FROM (SELECT * FROM t1)
 
1990
    */
 
1991
    for (table= derived_tables ; table ; table= next)
 
1992
    {
 
1993
      next= table->next;
 
1994
      table->free_tmp_table(this);
 
1995
    }
 
1996
    derived_tables= 0;
 
1997
  }
1887
1998
 
1888
1999
  /*
1889
2000
    Mark all temporary tables used by this statement as free for reuse.
1897
2008
    does not belong to statement for which we do close_thread_tables()).
1898
2009
    TODO: This should be fixed in later releases.
1899
2010
   */
 
2011
  if (!(state_flags & Open_tables_state::BACKUPS_AVAIL))
1900
2012
  {
1901
 
    TransactionServices &transaction_services= TransactionServices::singleton();
1902
2013
    main_da.can_overwrite_status= true;
1903
 
    transaction_services.autocommitOrRollback(this, is_error());
 
2014
    ha_autocommit_or_rollback(this, is_error());
1904
2015
    main_da.can_overwrite_status= false;
1905
2016
    transaction.stmt.reset();
1906
2017
  }
1916
2027
      handled either before writing a query log event (inside
1917
2028
      binlog_query()) or when preparing a pending event.
1918
2029
     */
1919
 
    unlockTables(lock);
 
2030
    mysql_unlock_tables(this, lock);
1920
2031
    lock= 0;
1921
2032
  }
1922
2033
  /*
1923
 
    Note that we need to hold table::Cache::singleton().mutex() while changing the
 
2034
    Note that we need to hold LOCK_open while changing the
1924
2035
    open_tables list. Another thread may work on it.
1925
 
    (See: table::Cache::singleton().removeTable(), mysql_wait_completed_table())
 
2036
    (See: remove_table_from_cache(), mysql_wait_completed_table())
1926
2037
    Closing a MERGE child before the parent would be fatal if the
1927
2038
    other thread tries to abort the MERGE lock in between.
1928
2039
  */
1944
2055
  close_thread_tables();
1945
2056
}
1946
2057
 
1947
 
bool Session::openTablesLock(TableList *tables)
 
2058
int Session::open_and_lock_tables(TableList *tables)
1948
2059
{
1949
2060
  uint32_t counter;
1950
2061
  bool need_reopen;
1951
2062
 
1952
2063
  for ( ; ; )
1953
2064
  {
1954
 
    if (open_tables_from_list(&tables, &counter))
1955
 
      return true;
 
2065
    if (open_tables_from_list(&tables, &counter, 0))
 
2066
      return -1;
1956
2067
 
1957
 
    if (not lock_tables(tables, counter, &need_reopen))
 
2068
    if (!lock_tables(this, tables, counter, &need_reopen))
1958
2069
      break;
1959
 
    if (not need_reopen)
1960
 
      return true;
 
2070
    if (!need_reopen)
 
2071
      return -1;
1961
2072
    close_tables_for_reopen(&tables);
1962
2073
  }
1963
2074
  if ((mysql_handle_derived(lex, &mysql_derived_prepare) ||
1964
 
       (
 
2075
       (fill_derived_tables() &&
1965
2076
        mysql_handle_derived(lex, &mysql_derived_filling))))
1966
 
    return true;
1967
 
 
1968
 
  return false;
1969
 
}
1970
 
 
1971
 
/*
1972
 
  @note "best_effort" is used in cases were if a failure occurred on this
1973
 
  operation it would not be surprising because we are only removing because there
1974
 
  might be an issue (lame engines).
1975
 
*/
1976
 
 
1977
 
bool Open_tables_state::rm_temporary_table(const TableIdentifier &identifier, bool best_effort)
1978
 
{
1979
 
  if (plugin::StorageEngine::dropTable(*static_cast<Session *>(this), identifier))
1980
 
  {
1981
 
    if (not best_effort)
1982
 
    {
1983
 
      std::string path;
1984
 
      identifier.getSQLPath(path);
1985
 
      errmsg_printf(ERRMSG_LVL_WARN, _("Could not remove temporary table: '%s', error: %d"),
1986
 
                    path.c_str(), errno);
1987
 
    }
1988
 
 
1989
 
    return true;
1990
 
  }
1991
 
 
1992
 
  return false;
1993
 
}
1994
 
 
1995
 
bool Open_tables_state::rm_temporary_table(plugin::StorageEngine *base, const TableIdentifier &identifier)
1996
 
{
1997
 
  assert(base);
1998
 
 
1999
 
  if (plugin::StorageEngine::dropTable(*static_cast<Session *>(this), *base, identifier))
2000
 
  {
2001
 
    std::string path;
2002
 
    identifier.getSQLPath(path);
2003
 
    errmsg_printf(ERRMSG_LVL_WARN, _("Could not remove temporary table: '%s', error: %d"),
2004
 
                  path.c_str(), errno);
2005
 
 
2006
 
    return true;
2007
 
  }
2008
 
 
2009
 
  return false;
2010
 
}
2011
 
 
2012
 
/**
2013
 
  @note this will be removed, I am looking through Hudson to see if it is finding
2014
 
  any tables that are missed during cleanup.
2015
 
*/
2016
 
void Open_tables_state::dumpTemporaryTableNames(const char *foo)
2017
 
{
2018
 
  Table *table;
2019
 
 
2020
 
  if (not temporary_tables)
2021
 
    return;
2022
 
 
2023
 
  cerr << "Begin Run: " << foo << "\n";
2024
 
  for (table= temporary_tables; table; table= table->getNext())
2025
 
  {
2026
 
    bool have_proto= false;
2027
 
 
2028
 
    message::Table *proto= table->getShare()->getTableProto();
2029
 
    if (table->getShare()->getTableProto())
2030
 
      have_proto= true;
2031
 
 
2032
 
    const char *answer= have_proto ? "true" : "false";
2033
 
 
2034
 
    if (have_proto)
2035
 
    {
2036
 
      cerr << "\tTable Name " << table->getShare()->getSchemaName() << "." << table->getShare()->getTableName() << " : " << answer << "\n";
2037
 
      cerr << "\t\t Proto " << proto->schema() << " " << proto->name() << "\n";
2038
 
    }
2039
 
    else
2040
 
    {
2041
 
      cerr << "\tTabl;e Name " << table->getShare()->getSchemaName() << "." << table->getShare()->getTableName() << " : " << answer << "\n";
2042
 
    }
2043
 
  }
2044
 
}
2045
 
 
2046
 
bool Session::TableMessages::storeTableMessage(const TableIdentifier &identifier, message::Table &table_message)
2047
 
{
2048
 
  table_message_cache.insert(make_pair(identifier.getPath(), table_message));
2049
 
 
2050
 
  return true;
2051
 
}
2052
 
 
2053
 
bool Session::TableMessages::removeTableMessage(const TableIdentifier &identifier)
2054
 
{
2055
 
  TableMessageCache::iterator iter;
2056
 
 
2057
 
  iter= table_message_cache.find(identifier.getPath());
2058
 
 
2059
 
  if (iter == table_message_cache.end())
2060
 
    return false;
2061
 
 
2062
 
  table_message_cache.erase(iter);
2063
 
 
2064
 
  return true;
2065
 
}
2066
 
 
2067
 
bool Session::TableMessages::getTableMessage(const TableIdentifier &identifier, message::Table &table_message)
2068
 
{
2069
 
  TableMessageCache::iterator iter;
2070
 
 
2071
 
  iter= table_message_cache.find(identifier.getPath());
2072
 
 
2073
 
  if (iter == table_message_cache.end())
2074
 
    return false;
2075
 
 
2076
 
  table_message.CopyFrom(((*iter).second));
2077
 
 
2078
 
  return true;
2079
 
}
2080
 
 
2081
 
bool Session::TableMessages::doesTableMessageExist(const TableIdentifier &identifier)
2082
 
{
2083
 
  TableMessageCache::iterator iter;
2084
 
 
2085
 
  iter= table_message_cache.find(identifier.getPath());
2086
 
 
2087
 
  if (iter == table_message_cache.end())
2088
 
  {
2089
 
    return false;
2090
 
  }
2091
 
 
2092
 
  return true;
2093
 
}
2094
 
 
2095
 
bool Session::TableMessages::renameTableMessage(const TableIdentifier &from, const TableIdentifier &to)
2096
 
{
2097
 
  TableMessageCache::iterator iter;
2098
 
 
2099
 
  table_message_cache[to.getPath()]= table_message_cache[from.getPath()];
2100
 
 
2101
 
  iter= table_message_cache.find(to.getPath());
2102
 
 
2103
 
  if (iter == table_message_cache.end())
2104
 
  {
2105
 
    return false;
2106
 
  }
2107
 
 
2108
 
  (*iter).second.set_schema(to.getSchemaName());
2109
 
  (*iter).second.set_name(to.getTableName());
2110
 
 
2111
 
  return true;
2112
 
}
2113
 
 
2114
 
table::Instance *Session::getInstanceTable()
2115
 
{
2116
 
  temporary_shares.push_back(new table::Instance()); // This will not go into the tableshare cache, so no key is used.
2117
 
 
2118
 
  table::Instance *tmp_share= temporary_shares.back();
2119
 
 
2120
 
  assert(tmp_share);
2121
 
 
2122
 
  return tmp_share;
2123
 
}
2124
 
 
2125
 
 
2126
 
/**
2127
 
  Create a reduced Table object with properly set up Field list from a
2128
 
  list of field definitions.
2129
 
 
2130
 
    The created table doesn't have a table Cursor associated with
2131
 
    it, has no keys, no group/distinct, no copy_funcs array.
2132
 
    The sole purpose of this Table object is to use the power of Field
2133
 
    class to read/write data to/from table->getInsertRecord(). Then one can store
2134
 
    the record in any container (RB tree, hash, etc).
2135
 
    The table is created in Session mem_root, so are the table's fields.
2136
 
    Consequently, if you don't BLOB fields, you don't need to free it.
2137
 
 
2138
 
  @param session         connection handle
2139
 
  @param field_list  list of column definitions
2140
 
 
2141
 
  @return
2142
 
    0 if out of memory, Table object in case of success
2143
 
*/
2144
 
table::Instance *Session::getInstanceTable(List<CreateField> &field_list)
2145
 
{
2146
 
  temporary_shares.push_back(new table::Instance(this, field_list)); // This will not go into the tableshare cache, so no key is used.
2147
 
 
2148
 
  table::Instance *tmp_share= temporary_shares.back();
2149
 
 
2150
 
  assert(tmp_share);
2151
 
 
2152
 
  return tmp_share;
2153
 
}
2154
 
 
2155
 
namespace display  {
2156
 
 
2157
 
static const std::string NONE= "NONE";
2158
 
static const std::string GOT_GLOBAL_READ_LOCK= "HAS GLOBAL READ LOCK";
2159
 
static const std::string MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT= "HAS GLOBAL READ LOCK WITH BLOCKING COMMIT";
2160
 
 
2161
 
const std::string &type(drizzled::Session::global_read_lock_t type)
2162
 
{
2163
 
  switch (type) {
2164
 
    default:
2165
 
    case Session::NONE:
2166
 
      return NONE;
2167
 
    case Session::GOT_GLOBAL_READ_LOCK:
2168
 
      return GOT_GLOBAL_READ_LOCK;
2169
 
    case Session::MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT:
2170
 
      return MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT;
2171
 
  }
2172
 
}
2173
 
 
2174
 
size_t max_string_length(drizzled::Session::global_read_lock_t)
2175
 
{
2176
 
  return MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT.size();
2177
 
}
2178
 
 
2179
 
} /* namespace display */
2180
 
 
2181
 
} /* namespace drizzled */
 
2077
    return 1; /* purecov: inspected */
 
2078
 
 
2079
  return 0;
 
2080
}
 
2081
 
 
2082
bool Session::open_normal_and_derived_tables(TableList *tables, uint32_t flags)
 
2083
{
 
2084
  uint32_t counter;
 
2085
  assert(!(fill_derived_tables()));
 
2086
  if (open_tables_from_list(&tables, &counter, flags) ||
 
2087
      mysql_handle_derived(lex, &mysql_derived_prepare))
 
2088
    return true; /* purecov: inspected */
 
2089
  return false;
 
2090
}