~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/session.cc

  • Committer: Brian Aker
  • Date: 2009-11-18 06:24:48 UTC
  • mfrom: (1220.1.15 staging)
  • Revision ID: brian@gaz-20091118062448-o36lo3yv81sc6u9z
Merge Brian + Stewart

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3
3
 *
4
 
 *  Copyright (C) 2008 Sun Microsystems, Inc.
 
4
 *  Copyright (C) 2008 Sun Microsystems
5
5
 *
6
6
 *  This program is free software; you can redistribute it and/or modify
7
7
 *  it under the terms of the GNU General Public License as published by
21
21
 * @file Implementation of the Session class and API
22
22
 */
23
23
 
24
 
#include "config.h"
25
 
 
26
 
#include <drizzled/copy_field.h>
27
 
#include "drizzled/session.h"
28
 
#include "drizzled/session/cache.h"
29
 
#include "drizzled/error.h"
30
 
#include "drizzled/gettext.h"
31
 
#include "drizzled/query_id.h"
32
 
#include "drizzled/data_home.h"
33
 
#include "drizzled/sql_base.h"
34
 
#include "drizzled/lock.h"
35
 
#include "drizzled/item/cache.h"
36
 
#include "drizzled/item/float.h"
37
 
#include "drizzled/item/return_int.h"
38
 
#include "drizzled/item/empty_string.h"
39
 
#include "drizzled/show.h"
40
 
#include "drizzled/plugin/client.h"
 
24
#include <drizzled/server_includes.h>
 
25
#include <drizzled/session.h>
 
26
#include <sys/stat.h>
 
27
#include <mysys/mysys_err.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>
41
40
#include "drizzled/plugin/scheduler.h"
42
41
#include "drizzled/plugin/authentication.h"
43
 
#include "drizzled/plugin/logging.h"
44
 
#include "drizzled/plugin/transactional_storage_engine.h"
45
 
#include "drizzled/plugin/query_rewrite.h"
46
42
#include "drizzled/probes.h"
47
43
#include "drizzled/table_proto.h"
48
 
#include "drizzled/db.h"
49
 
#include "drizzled/pthread_globals.h"
50
 
#include "drizzled/transaction_services.h"
51
 
#include "drizzled/drizzled.h"
52
 
 
53
 
#include "drizzled/identifier.h"
54
 
 
55
 
#include <drizzled/refresh_version.h>
56
 
 
57
 
#include "drizzled/table/singular.h"
58
 
 
59
 
#include "plugin/myisam/myisam.h"
60
 
#include "drizzled/internal/iocache.h"
61
 
#include "drizzled/internal/thread_var.h"
62
 
#include "drizzled/plugin/event_observer.h"
63
 
 
64
 
#include "drizzled/util/functors.h"
65
 
 
66
 
#include "drizzled/display.h"
67
44
 
68
45
#include <algorithm>
69
 
#include <climits>
70
 
#include <fcntl.h>
71
 
#include <sys/stat.h>
72
 
 
73
 
#include <boost/filesystem.hpp>
74
 
#include <boost/checked_delete.hpp>
75
 
 
76
 
#include "drizzled/util/backtrace.h"
77
46
 
78
47
using namespace std;
 
48
using namespace drizzled;
79
49
 
80
 
namespace fs=boost::filesystem;
81
 
namespace drizzled
 
50
extern "C"
82
51
{
 
52
  unsigned char *get_var_key(user_var_entry *entry, size_t *length, bool );
 
53
  void free_user_var(user_var_entry *entry);
 
54
}
83
55
 
84
56
/*
85
57
  The following is used to initialise Table_ident with a internal
89
61
char empty_c_string[1]= {0};    /* used for not defined db */
90
62
 
91
63
const char * const Session::DEFAULT_WHERE= "field list";
 
64
extern pthread_key_t THR_Session;
 
65
extern pthread_key_t THR_Mem_root;
 
66
extern uint32_t max_used_connections;
 
67
extern drizzled::atomic<uint32_t> connection_count;
 
68
 
 
69
#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
 
70
/* Used templates */
 
71
template class List<Key>;
 
72
template class List_iterator<Key>;
 
73
template class List<Key_part_spec>;
 
74
template class List_iterator<Key_part_spec>;
 
75
template class List<AlterDrop>;
 
76
template class List_iterator<AlterDrop>;
 
77
template class List<AlterColumn>;
 
78
template class List_iterator<AlterColumn>;
 
79
#endif
 
80
 
 
81
/****************************************************************************
 
82
** User variables
 
83
****************************************************************************/
 
84
unsigned char *get_var_key(user_var_entry *entry, size_t *length, bool )
 
85
{
 
86
  *length= entry->name.length;
 
87
  return (unsigned char*) entry->name.str;
 
88
}
 
89
 
 
90
void free_user_var(user_var_entry *entry)
 
91
{
 
92
  delete entry;
 
93
}
92
94
 
93
95
bool Key_part_spec::operator==(const Key_part_spec& other) const
94
96
{
95
97
  return length == other.length &&
96
98
         field_name.length == other.field_name.length &&
97
 
    !my_strcasecmp(system_charset_info, field_name.str, other.field_name.str);
 
99
         !strcmp(field_name.str, other.field_name.str);
98
100
}
99
101
 
100
 
Open_tables_state::Open_tables_state(uint64_t version_arg) :
101
 
  version(version_arg)
 
102
Open_tables_state::Open_tables_state(ulong version_arg)
 
103
  :version(version_arg), backups_available(false)
102
104
{
103
 
  open_tables= temporary_tables= derived_tables= NULL;
104
 
  extra_lock= lock= NULL;
 
105
  reset_open_tables_state();
105
106
}
106
107
 
107
108
/*
108
109
  The following functions form part of the C plugin API
109
110
*/
110
 
int tmpfile(const char *prefix)
 
111
extern "C" int mysql_tmpfile(const char *prefix)
111
112
{
112
113
  char filename[FN_REFLEN];
113
 
  int fd = internal::create_temp_file(filename, drizzle_tmpdir.c_str(), prefix, MYF(MY_WME));
 
114
  File fd = create_temp_file(filename, drizzle_tmpdir, prefix, MYF(MY_WME));
114
115
  if (fd >= 0) {
115
116
    unlink(filename);
116
117
  }
118
119
  return fd;
119
120
}
120
121
 
121
 
void **Session::getEngineData(const plugin::MonitoredInTransaction *monitored)
122
 
{
123
 
  return static_cast<void **>(&ha_data[monitored->getId()].ha_ptr);
124
 
}
125
 
 
126
 
ResourceContext *Session::getResourceContext(const plugin::MonitoredInTransaction *monitored,
127
 
                                             size_t index)
128
 
{
129
 
  return &ha_data[monitored->getId()].resource_context[index];
130
 
}
131
 
 
 
122
extern "C"
 
123
int session_tablespace_op(const Session *session)
 
124
{
 
125
  return test(session->tablespace_op);
 
126
}
 
127
 
 
128
/**
 
129
   Set the process info field of the Session structure.
 
130
 
 
131
   This function is used by plug-ins. Internally, the
 
132
   Session::set_proc_info() function should be used.
 
133
 
 
134
   @see Session::set_proc_info
 
135
 */
 
136
extern "C" void
 
137
set_session_proc_info(Session *session, const char *info)
 
138
{
 
139
  session->set_proc_info(info);
 
140
}
 
141
 
 
142
extern "C"
 
143
const char *get_session_proc_info(Session *session)
 
144
{
 
145
  return session->get_proc_info();
 
146
}
 
147
 
 
148
extern "C"
 
149
void **session_ha_data(const Session *session, const plugin::StorageEngine *engine)
 
150
{
 
151
  return (void **) &session->ha_data[engine->slot].ha_ptr;
 
152
}
 
153
 
 
154
extern "C"
132
155
int64_t session_test_options(const Session *session, int64_t test_options)
133
156
{
134
157
  return session->options & test_options;
135
158
}
136
159
 
137
 
Session::Session(plugin::Client *client_arg, catalog::Instance::shared_ptr catalog_arg) :
 
160
extern "C"
 
161
int session_sql_command(const Session *session)
 
162
{
 
163
  return (int) session->lex->sql_command;
 
164
}
 
165
 
 
166
extern "C"
 
167
int session_tx_isolation(const Session *session)
 
168
{
 
169
  return (int) session->variables.tx_isolation;
 
170
}
 
171
 
 
172
extern "C"
 
173
void session_inc_row_count(Session *session)
 
174
{
 
175
  session->row_count++;
 
176
}
 
177
 
 
178
Session::Session(plugin::Client *client_arg)
 
179
  :
138
180
  Open_tables_state(refresh_version),
139
181
  mem_root(&main_mem_root),
140
 
  xa_id(0),
141
182
  lex(&main_lex),
142
 
  query(new std::string),
143
 
  _schema(new std::string("")),
144
183
  client(client_arg),
145
184
  scheduler(NULL),
146
185
  scheduler_arg(NULL),
147
186
  lock_id(&main_lock_id),
148
 
  thread_stack(NULL),
149
 
  security_ctx(identifier::User::make_shared()),
150
 
  _where(Session::DEFAULT_WHERE),
151
 
  dbug_sentry(Session_SENTRY_MAGIC),
152
 
  mysys_var(0),
153
 
  command(COM_CONNECT),
154
 
  file_id(0),
155
 
  _epoch(boost::gregorian::date(1970,1,1)),
156
 
  _connect_time(boost::posix_time::microsec_clock::universal_time()),
157
 
  utime_after_lock(0),
158
 
  ha_data(plugin::num_trx_monitored_objects),
159
 
  query_id(0),
160
 
  warn_query_id(0),
161
 
  concurrent_execute_allowed(true),
 
187
  user_time(0),
162
188
  arg_of_last_insert_id_function(false),
163
189
  first_successful_insert_id_in_prev_stmt(0),
164
190
  first_successful_insert_id_in_cur_stmt(0),
165
191
  limit_found_rows(0),
166
 
  options(session_startup_options),
167
 
  row_count_func(-1),
168
 
  sent_row_count(0),
169
 
  examined_row_count(0),
170
 
  used_tables(0),
171
 
  total_warn_count(0),
172
 
  col_access(0),
173
 
  statement_id_counter(0),
174
 
  row_count(0),
175
 
  thread_id(0),
176
 
  tmp_table(0),
177
 
  _global_read_lock(NONE),
178
 
  count_cuted_fields(CHECK_FIELD_ERROR_FOR_NULL),
179
 
  _killed(NOT_KILLED),
 
192
  global_read_lock(0),
180
193
  some_tables_deleted(false),
181
194
  no_errors(false),
182
195
  password(false),
183
196
  is_fatal_error(false),
184
197
  transaction_rollback_request(false),
185
198
  is_fatal_sub_stmt_error(0),
 
199
  derived_tables_processing(false),
186
200
  tablespace_op(false),
187
 
  derived_tables_processing(false),
188
201
  m_lip(NULL),
189
202
  cached_table(0),
190
203
  transaction_message(NULL),
191
 
  statement_message(NULL),
192
 
  session_event_observers(NULL),
193
 
  _catalog(catalog_arg),
194
 
  use_usage(false)
 
204
  statement_message(NULL)
195
205
{
 
206
  memset(process_list_info, 0, PROCESS_LIST_WIDTH);
196
207
  client->setSession(this);
197
208
 
198
209
  /*
200
211
    the destructor works OK in case of an error. The main_mem_root
201
212
    will be re-initialized in init_for_queries().
202
213
  */
203
 
  memory::init_sql_alloc(&main_mem_root, memory::ROOT_MIN_BLOCK_SIZE, 0);
 
214
  init_sql_alloc(&main_mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0);
 
215
  thread_stack= NULL;
 
216
  count_cuted_fields= CHECK_FIELD_IGNORE;
 
217
  killed= NOT_KILLED;
 
218
  col_access= 0;
 
219
  tmp_table= 0;
 
220
  used_tables= 0;
204
221
  cuted_fields= sent_row_count= row_count= 0L;
 
222
  row_count_func= -1;
 
223
  statement_id_counter= 0UL;
205
224
  // Must be reset to handle error with Session's created for init of mysqld
206
225
  lex->current_select= 0;
 
226
  start_time=(time_t) 0;
 
227
  start_utime= 0L;
 
228
  utime_after_lock= 0L;
207
229
  memset(&variables, 0, sizeof(variables));
208
 
  scoreboard_index= -1;
209
 
  cleanup_done= abort_on_warning= no_warnings_for_error= false;  
210
 
 
211
 
  /* query_cache init */
212
 
  query_cache_key= "";
213
 
  resultset= NULL;
 
230
  thread_id= 0;
 
231
  file_id = 0;
 
232
  query_id= 0;
 
233
  query= NULL;
 
234
  query_length= 0;
 
235
  warn_id= 0;
 
236
  memset(ha_data, 0, sizeof(ha_data));
 
237
  replication_data= 0;
 
238
  mysys_var= 0;
 
239
  dbug_sentry=Session_SENTRY_MAGIC;
 
240
  cleanup_done= abort_on_warning= no_warnings_for_error= false;
 
241
  transaction.on= 1;
 
242
  pthread_mutex_init(&LOCK_delete, MY_MUTEX_INIT_FAST);
214
243
 
215
244
  /* Variables with default values */
216
245
  proc_info="login";
 
246
  where= Session::DEFAULT_WHERE;
 
247
  command= COM_CONNECT;
217
248
 
218
249
  plugin_sessionvar_init(this);
219
250
  /*
223
254
  */
224
255
  variables.pseudo_thread_id= thread_id;
225
256
  server_status= SERVER_STATUS_AUTOCOMMIT;
 
257
  options= session_startup_options;
226
258
 
227
259
  if (variables.max_join_size == HA_POS_ERROR)
228
260
    options |= OPTION_BIG_SELECTS;
229
261
  else
230
262
    options &= ~OPTION_BIG_SELECTS;
231
263
 
 
264
  transaction.all.modified_non_trans_table= transaction.stmt.modified_non_trans_table= false;
232
265
  open_options=ha_open_options;
233
266
  update_lock_default= TL_WRITE;
234
267
  session_tx_isolation= (enum_tx_isolation) variables.tx_isolation;
235
268
  warn_list.empty();
236
269
  memset(warn_count, 0, sizeof(warn_count));
 
270
  total_warn_count= 0;
237
271
  memset(&status_var, 0, sizeof(status_var));
238
272
 
239
273
  /* Initialize sub structures */
240
 
  memory::init_sql_alloc(&warn_root, WARN_ALLOC_BLOCK_SIZE, WARN_ALLOC_PREALLOC_SIZE);
 
274
  init_sql_alloc(&warn_root, WARN_ALLOC_BLOCK_SIZE, WARN_ALLOC_PREALLOC_SIZE);
 
275
  hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0,
 
276
            (hash_get_key) get_var_key,
 
277
            (hash_free_key) free_user_var, 0);
241
278
 
242
279
  substitute_null_with_insert_id = false;
243
 
  lock_info.init(); /* safety: will be reset after start */
 
280
  thr_lock_info_init(&lock_info); /* safety: will be reset after start */
244
281
  thr_lock_owner_init(&main_lock_id, &lock_info);
245
282
 
246
283
  m_internal_handler= NULL;
247
 
  
248
 
  plugin::EventObserver::registerSessionEvents(*this); 
249
284
}
250
285
 
251
286
void Session::free_items()
252
287
{
253
288
  Item *next;
254
 
  /* This works because items are allocated with memory::sql_alloc() */
 
289
  /* This works because items are allocated with sql_alloc() */
255
290
  for (; free_list; free_list= next)
256
291
  {
257
292
    next= free_list->next;
269
304
  m_internal_handler= handler;
270
305
}
271
306
 
272
 
bool Session::handle_error(drizzled::error_t sql_errno, const char *message,
273
 
                           DRIZZLE_ERROR::enum_warning_level level)
 
307
bool Session::handle_error(uint32_t sql_errno, const char *message,
 
308
                       DRIZZLE_ERROR::enum_warning_level level)
274
309
{
275
310
  if (m_internal_handler)
276
311
  {
280
315
  return false;                                 // 'false', as per coding style
281
316
}
282
317
 
283
 
void Session::setAbort(bool arg)
284
 
{
285
 
  mysys_var->abort= arg;
286
 
}
287
 
 
288
 
void Session::lockOnSys()
289
 
{
290
 
  if (not mysys_var)
291
 
    return;
292
 
 
293
 
  setAbort(true);
294
 
  boost_unique_lock_t scopedLock(mysys_var->mutex);
295
 
  if (mysys_var->current_cond)
296
 
  {
297
 
    mysys_var->current_mutex->lock();
298
 
    mysys_var->current_cond->notify_all();
299
 
    mysys_var->current_mutex->unlock();
300
 
  }
301
 
}
302
 
 
303
318
void Session::pop_internal_handler()
304
319
{
305
320
  assert(m_internal_handler != NULL);
306
321
  m_internal_handler= NULL;
307
322
}
308
323
 
309
 
void Session::get_xid(DRIZZLE_XID *xid)
310
 
{
311
 
  *xid = *(DRIZZLE_XID *) &transaction.xid_state.xid;
312
 
}
 
324
#if defined(__cplusplus)
 
325
extern "C" {
 
326
#endif
 
327
 
 
328
void *session_alloc(Session *session, unsigned int size)
 
329
{
 
330
  return session->alloc(size);
 
331
}
 
332
 
 
333
void *session_calloc(Session *session, unsigned int size)
 
334
{
 
335
  return session->calloc(size);
 
336
}
 
337
 
 
338
char *session_strdup(Session *session, const char *str)
 
339
{
 
340
  return session->strdup(str);
 
341
}
 
342
 
 
343
char *session_strmake(Session *session, const char *str, unsigned int size)
 
344
{
 
345
  return session->strmake(str, size);
 
346
}
 
347
 
 
348
void *session_memdup(Session *session, const void* str, unsigned int size)
 
349
{
 
350
  return session->memdup(str, size);
 
351
}
 
352
 
 
353
void session_get_xid(const Session *session, DRIZZLE_XID *xid)
 
354
{
 
355
  *xid = *(DRIZZLE_XID *) &session->transaction.xid_state.xid;
 
356
}
 
357
 
 
358
#if defined(__cplusplus)
 
359
}
 
360
#endif
313
361
 
314
362
/* Do operations that may take a long time */
315
363
 
317
365
{
318
366
  assert(cleanup_done == false);
319
367
 
320
 
  setKilled(KILL_CONNECTION);
 
368
  killed= KILL_CONNECTION;
321
369
#ifdef ENABLE_WHEN_BINLOG_WILL_BE_ABLE_TO_PREPARE
322
370
  if (transaction.xid_state.xa_state == XA_PREPARED)
323
371
  {
325
373
  }
326
374
#endif
327
375
  {
328
 
    TransactionServices &transaction_services= TransactionServices::singleton();
329
 
    transaction_services.rollbackTransaction(*this, true);
 
376
    ha_rollback(this);
330
377
    xid_cache_delete(&transaction.xid_state);
331
378
  }
332
 
 
333
 
  for (UserVars::iterator iter= user_vars.begin();
334
 
       iter != user_vars.end();
335
 
       iter++)
336
 
  {
337
 
    user_var_entry *entry= (*iter).second;
338
 
    boost::checked_delete(entry);
339
 
  }
340
 
  user_vars.clear();
341
 
 
342
 
 
 
379
  hash_free(&user_vars);
343
380
  close_temporary_tables();
344
381
 
345
382
  if (global_read_lock)
346
 
  {
347
 
    unlockGlobalReadLock();
348
 
  }
 
383
    unlock_global_read_lock(this);
349
384
 
350
385
  cleanup_done= true;
351
386
}
352
387
 
353
388
Session::~Session()
354
389
{
355
 
  this->checkSentry();
 
390
  Session_CHECK_SENTRY(this);
 
391
  add_to_status(&global_status_var, &status_var);
356
392
 
357
 
  if (client and client->isConnected())
 
393
  if (client->isConnected())
358
394
  {
359
 
    assert(security_ctx);
360
395
    if (global_system_variables.log_warnings)
361
 
    {
362
 
      errmsg_printf(error::WARN, ER(ER_FORCING_CLOSE),
363
 
                    internal::my_progname,
364
 
                    thread_id,
365
 
                    security_ctx->username().c_str());
366
 
    }
367
 
 
368
 
    disconnect();
 
396
        errmsg_printf(ERRMSG_LVL_WARN, ER(ER_FORCING_CLOSE),my_progname,
 
397
                      thread_id,
 
398
                      (security_ctx.user.c_str() ?
 
399
                       security_ctx.user.c_str() : ""));
 
400
    disconnect(0, false);
369
401
  }
370
402
 
371
403
  /* Close connection */
372
 
  if (client)
373
 
  {
374
 
    client->close();
375
 
    boost::checked_delete(client);
376
 
    client= NULL;
377
 
  }
 
404
  client->close();
 
405
  delete client;
378
406
 
379
407
  if (cleanup_done == false)
380
408
    cleanup();
382
410
  plugin::StorageEngine::closeConnection(this);
383
411
  plugin_sessionvar_cleanup(this);
384
412
 
385
 
  warn_root.free_root(MYF(0));
 
413
  free_root(&warn_root,MYF(0));
 
414
  free_root(&transaction.mem_root,MYF(0));
386
415
  mysys_var=0;                                  // Safety (shouldn't be needed)
387
416
  dbug_sentry= Session_SENTRY_GONE;
388
417
 
389
 
  main_mem_root.free_root(MYF(0));
390
 
  currentMemRoot().release();
391
 
  currentSession().release();
392
 
 
393
 
  plugin::Logging::postEndDo(this);
394
 
  plugin::EventObserver::deregisterSessionEvents(*this); 
395
 
}
396
 
 
397
 
void Session::setClient(plugin::Client *client_arg)
398
 
{
399
 
  client= client_arg;
400
 
  client->setSession(this);
401
 
}
402
 
 
403
 
void Session::awake(Session::killed_state_t state_to_set)
404
 
{
405
 
  if ((state_to_set == Session::KILL_QUERY) and (command == COM_SLEEP))
406
 
    return;
407
 
 
408
 
  this->checkSentry();
409
 
 
410
 
  setKilled(state_to_set);
411
 
  scheduler->killSession(this);
412
 
 
 
418
  free_root(&main_mem_root, MYF(0));
 
419
  pthread_setspecific(THR_Session,  0);
 
420
 
 
421
 
 
422
  /* Ensure that no one is using Session */
 
423
  pthread_mutex_unlock(&LOCK_delete);
 
424
  pthread_mutex_destroy(&LOCK_delete);
 
425
}
 
426
 
 
427
/*
 
428
  Add all status variables to another status variable array
 
429
 
 
430
  SYNOPSIS
 
431
   add_to_status()
 
432
   to_var       add to this array
 
433
   from_var     from this array
 
434
 
 
435
  NOTES
 
436
    This function assumes that all variables are long/ulong.
 
437
    If this assumption will change, then we have to explictely add
 
438
    the other variables after the while loop
 
439
*/
 
440
void add_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var)
 
441
{
 
442
  ulong *end= (ulong*) ((unsigned char*) to_var +
 
443
                        offsetof(STATUS_VAR, last_system_status_var) +
 
444
                        sizeof(ulong));
 
445
  ulong *to= (ulong*) to_var, *from= (ulong*) from_var;
 
446
 
 
447
  while (to != end)
 
448
    *(to++)+= *(from++);
 
449
}
 
450
 
 
451
/*
 
452
  Add the difference between two status variable arrays to another one.
 
453
 
 
454
  SYNOPSIS
 
455
    add_diff_to_status
 
456
    to_var       add to this array
 
457
    from_var     from this array
 
458
    dec_var      minus this array
 
459
 
 
460
  NOTE
 
461
    This function assumes that all variables are long/ulong.
 
462
*/
 
463
void add_diff_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var,
 
464
                        STATUS_VAR *dec_var)
 
465
{
 
466
  ulong *end= (ulong*) ((unsigned char*) to_var + offsetof(STATUS_VAR,
 
467
                                                  last_system_status_var) +
 
468
                        sizeof(ulong));
 
469
  ulong *to= (ulong*) to_var, *from= (ulong*) from_var, *dec= (ulong*) dec_var;
 
470
 
 
471
  while (to != end)
 
472
    *(to++)+= *(from++) - *(dec++);
 
473
}
 
474
 
 
475
void Session::awake(Session::killed_state state_to_set)
 
476
{
 
477
  Session_CHECK_SENTRY(this);
 
478
  safe_mutex_assert_owner(&LOCK_delete);
 
479
 
 
480
  killed= state_to_set;
413
481
  if (state_to_set != Session::KILL_QUERY)
414
482
  {
 
483
    scheduler->killSession(this);
415
484
    DRIZZLE_CONNECTION_DONE(thread_id);
416
485
  }
417
 
 
418
486
  if (mysys_var)
419
487
  {
420
 
    boost_unique_lock_t scopedLock(mysys_var->mutex);
 
488
    pthread_mutex_lock(&mysys_var->mutex);
421
489
    /*
422
 
      "
423
490
      This broadcast could be up in the air if the victim thread
424
491
      exits the cond in the time between read and broadcast, but that is
425
492
      ok since all we want to do is to make the victim thread get out
440
507
    */
441
508
    if (mysys_var->current_cond && mysys_var->current_mutex)
442
509
    {
443
 
      mysys_var->current_mutex->lock();
444
 
      mysys_var->current_cond->notify_all();
445
 
      mysys_var->current_mutex->unlock();
 
510
      pthread_mutex_lock(mysys_var->current_mutex);
 
511
      pthread_cond_broadcast(mysys_var->current_cond);
 
512
      pthread_mutex_unlock(mysys_var->current_mutex);
446
513
    }
 
514
    pthread_mutex_unlock(&mysys_var->mutex);
447
515
  }
448
516
}
449
517
 
450
518
/*
451
519
  Remember the location of thread info, the structure needed for
452
 
  memory::sql_alloc() and the structure for the net buffer
 
520
  sql_alloc() and the structure for the net buffer
453
521
*/
454
522
bool Session::storeGlobals()
455
523
{
459
527
  */
460
528
  assert(thread_stack);
461
529
 
462
 
  currentSession().release();
463
 
  currentSession().reset(this);
464
 
 
465
 
  currentMemRoot().release();
466
 
  currentMemRoot().reset(&mem_root);
 
530
  if (pthread_setspecific(THR_Session,  this) ||
 
531
      pthread_setspecific(THR_Mem_root, &mem_root))
 
532
    return true;
467
533
 
468
534
  mysys_var=my_thread_var;
469
535
 
472
538
    This allows us to move Session to different threads if needed.
473
539
  */
474
540
  mysys_var->id= thread_id;
 
541
  real_id= pthread_self();                      // For debugging
475
542
 
476
543
  /*
477
544
    We have to call thr_lock_info_init() again here as Session may have been
478
545
    created in another thread
479
546
  */
480
 
  lock_info.init();
481
 
 
 
547
  thr_lock_info_init(&lock_info);
482
548
  return false;
483
549
}
484
550
 
497
563
  set_proc_info(NULL);
498
564
  command= COM_SLEEP;
499
565
  set_time();
 
566
  ha_enable_transaction(this,true);
500
567
 
501
 
  mem_root->reset_root_defaults(variables.query_alloc_block_size,
502
 
                                variables.query_prealloc_size);
 
568
  reset_root_defaults(mem_root, variables.query_alloc_block_size,
 
569
                      variables.query_prealloc_size);
 
570
  reset_root_defaults(&transaction.mem_root,
 
571
                      variables.trans_alloc_block_size,
 
572
                      variables.trans_prealloc_size);
503
573
  transaction.xid_state.xid.null();
504
574
  transaction.xid_state.in_session=1;
505
 
  if (use_usage)
506
 
    resetUsage();
507
575
}
508
576
 
509
577
bool Session::initGlobals()
510
578
{
511
579
  if (storeGlobals())
512
580
  {
513
 
    disconnect(ER_OUT_OF_RESOURCES);
514
 
    status_var.aborted_connects++;
 
581
    disconnect(ER_OUT_OF_RESOURCES, true);
 
582
    statistic_increment(aborted_connects, &LOCK_status);
515
583
    return true;
516
584
  }
517
585
  return false;
521
589
{
522
590
  if (initGlobals() || authenticate())
523
591
  {
524
 
    disconnect();
 
592
    disconnect(0, true);
525
593
    return;
526
594
  }
527
595
 
528
596
  prepareForQueries();
529
597
 
530
 
  while (not client->haveError() && getKilled() != KILL_CONNECTION)
 
598
  while (! client->haveError() && killed != KILL_CONNECTION)
531
599
  {
532
 
    if (not executeStatement())
 
600
    if (! executeStatement())
533
601
      break;
534
602
  }
535
603
 
536
 
  disconnect();
 
604
  disconnect(0, true);
537
605
}
538
606
 
539
 
bool Session::schedule(Session::shared_ptr &arg)
 
607
bool Session::schedule()
540
608
{
541
 
  arg->scheduler= plugin::Scheduler::getScheduler();
542
 
  assert(arg->scheduler);
 
609
  scheduler= plugin::Scheduler::getScheduler();
 
610
  assert(scheduler);
543
611
 
544
612
  ++connection_count;
545
613
 
546
 
  long current_connections= connection_count;
547
 
 
548
 
  if (current_connections > 0 and static_cast<uint64_t>(current_connections) > current_global_counters.max_used_connections)
549
 
  {
550
 
    current_global_counters.max_used_connections= static_cast<uint64_t>(connection_count);
551
 
  }
552
 
 
553
 
  current_global_counters.connections++;
554
 
  arg->thread_id= arg->variables.pseudo_thread_id= global_thread_id++;
555
 
 
556
 
  session::Cache::singleton().insert(arg);
557
 
 
558
 
  if (unlikely(plugin::EventObserver::connectSession(*arg)))
559
 
  {
560
 
    // We should do something about an error...
561
 
  }
562
 
 
563
 
  if (plugin::Scheduler::getScheduler()->addSession(arg))
564
 
  {
565
 
    DRIZZLE_CONNECTION_START(arg->getSessionId());
 
614
  if (connection_count > max_used_connections)
 
615
    max_used_connections= connection_count;
 
616
 
 
617
  thread_id= variables.pseudo_thread_id= global_thread_id++;
 
618
 
 
619
  pthread_mutex_lock(&LOCK_thread_count);
 
620
  session_list.push_back(this);
 
621
  pthread_mutex_unlock(&LOCK_thread_count);
 
622
 
 
623
  if (scheduler->addSession(this))
 
624
  {
 
625
    DRIZZLE_CONNECTION_START(thread_id);
566
626
    char error_message_buff[DRIZZLE_ERRMSG_SIZE];
567
627
 
568
 
    arg->setKilled(Session::KILL_CONNECTION);
 
628
    killed= Session::KILL_CONNECTION;
569
629
 
570
 
    arg->status_var.aborted_connects++;
 
630
    statistic_increment(aborted_connects, &LOCK_status);
571
631
 
572
632
    /* Can't use my_error() since store_globals has not been called. */
573
633
    /* TODO replace will better error message */
574
634
    snprintf(error_message_buff, sizeof(error_message_buff),
575
635
             ER(ER_CANT_CREATE_THREAD), 1);
576
 
    arg->client->sendError(ER_CANT_CREATE_THREAD, error_message_buff);
577
 
 
 
636
    client->sendError(ER_CANT_CREATE_THREAD, error_message_buff);
578
637
    return true;
579
638
  }
580
639
 
581
640
  return false;
582
641
}
583
642
 
584
 
 
585
 
/*
586
 
  Is this session viewable by the current user?
587
 
*/
588
 
bool Session::isViewable(identifier::User::const_reference user_arg) const
589
 
{
590
 
  return plugin::Authorization::isAuthorized(user_arg, this, false);
591
 
}
592
 
 
593
 
 
594
 
const char* Session::enter_cond(boost::condition_variable_any &cond, boost::mutex &mutex, const char* msg)
595
 
{
596
 
  const char* old_msg = get_proc_info();
597
 
  safe_mutex_assert_owner(mutex);
598
 
  mysys_var->current_mutex = &mutex;
599
 
  mysys_var->current_cond = &cond;
600
 
  this->set_proc_info(msg);
601
 
  return old_msg;
602
 
}
603
 
 
604
 
void Session::exit_cond(const char* old_msg)
605
 
{
606
 
  /*
607
 
    Putting the mutex unlock in exit_cond() ensures that
608
 
    mysys_var->current_mutex is always unlocked _before_ mysys_var->mutex is
609
 
    locked (if that would not be the case, you'll get a deadlock if someone
610
 
    does a Session::awake() on you).
611
 
  */
612
 
  mysys_var->current_mutex->unlock();
613
 
  boost_unique_lock_t scopedLock(mysys_var->mutex);
614
 
  mysys_var->current_mutex = 0;
615
 
  mysys_var->current_cond = 0;
616
 
  this->set_proc_info(old_msg);
617
 
}
618
 
 
619
643
bool Session::authenticate()
620
644
{
 
645
  lex_start(this);
621
646
  if (client->authenticate())
622
647
    return false;
623
648
 
624
 
  status_var.aborted_connects++;
625
 
 
 
649
  statistic_increment(aborted_connects, &LOCK_status);
626
650
  return true;
627
651
}
628
652
 
629
 
bool Session::checkUser(const std::string &passwd_str,
630
 
                        const std::string &in_db)
 
653
bool Session::checkUser(const char *passwd, uint32_t passwd_len, const char *in_db)
631
654
{
632
 
  bool is_authenticated=
633
 
    plugin::Authentication::isAuthenticated(user(), passwd_str);
 
655
  LEX_STRING db_str= { (char *) in_db, in_db ? strlen(in_db) : 0 };
 
656
  bool is_authenticated;
 
657
 
 
658
  if (passwd_len != 0 && passwd_len != SCRAMBLE_LENGTH)
 
659
  {
 
660
    my_error(ER_HANDSHAKE_ERROR, MYF(0), security_ctx.ip.c_str());
 
661
    return false;
 
662
  }
 
663
 
 
664
  is_authenticated= plugin::Authentication::isAuthenticated(this, passwd);
634
665
 
635
666
  if (is_authenticated != true)
636
667
  {
637
 
    status_var.access_denied++;
638
 
    /* isAuthenticated has pushed the error message */
 
668
    my_error(ER_ACCESS_DENIED_ERROR, MYF(0),
 
669
             security_ctx.user.c_str(),
 
670
             security_ctx.ip.c_str(),
 
671
             passwd_len ? ER(ER_YES) : ER(ER_NO));
 
672
 
639
673
    return false;
640
674
  }
641
675
 
 
676
  security_ctx.skip_grants();
 
677
 
642
678
  /* Change database if necessary */
643
 
  if (not in_db.empty())
 
679
  if (in_db && in_db[0])
644
680
  {
645
 
    identifier::Schema identifier(in_db);
646
 
    if (change_db(this, identifier))
 
681
    if (mysql_change_db(this, &db_str, false))
647
682
    {
648
 
      /* change_db() has pushed the error message. */
 
683
      /* mysql_change_db() has pushed the error message. */
649
684
      return false;
650
685
    }
651
686
  }
652
687
  my_ok();
653
 
  password= not passwd_str.empty();
 
688
  password= test(passwd_len);          // remember for error messages
654
689
 
655
690
  /* Ready to handle queries */
656
691
  return true;
672
707
  main_da.reset_diagnostics_area();
673
708
 
674
709
  if (client->readCommand(&l_packet, &packet_length) == false)
675
 
  {
676
 
    return false;
677
 
  }
678
 
 
679
 
  if (getKilled() == KILL_CONNECTION)
680
710
    return false;
681
711
 
682
712
  if (packet_length == 0)
683
713
    return true;
684
714
 
685
 
  l_command= static_cast<enum_server_command>(l_packet[0]);
 
715
  l_command= (enum enum_server_command) (unsigned char) l_packet[0];
686
716
 
687
717
  if (command >= COM_END)
688
718
    command= COM_END;                           // Wrong command
689
719
 
690
720
  assert(packet_length);
691
 
  return not dispatch_command(l_command, this, l_packet+1, (uint32_t) (packet_length-1));
 
721
  return ! dispatch_command(l_command, this, l_packet+1, (uint32_t) (packet_length-1));
692
722
}
693
723
 
694
724
bool Session::readAndStoreQuery(const char *in_packet, uint32_t in_packet_length)
700
730
    in_packet_length--;
701
731
  }
702
732
  const char *pos= in_packet + in_packet_length; /* Point at end null */
703
 
  while (in_packet_length > 0 && (pos[-1] == ';' || my_isspace(charset() ,pos[-1])))
 
733
  while (in_packet_length > 0 &&
 
734
         (pos[-1] == ';' || my_isspace(charset() ,pos[-1])))
704
735
  {
705
736
    pos--;
706
737
    in_packet_length--;
707
738
  }
708
739
 
709
 
  std::string *new_query= new std::string(in_packet, in_packet + in_packet_length);
710
 
  // We can not be entirely sure _schema has a value
711
 
  if (_schema)
712
 
  {
713
 
    plugin::QueryRewriter::rewriteQuery(*_schema, *new_query);
714
 
  }
715
 
  query.reset(new_query);
716
 
  _state.reset(new session::State(in_packet, in_packet_length));
 
740
  /* We must allocate some extra memory for the cached query string */
 
741
  query_length= 0; /* Extra safety: Avoid races */
 
742
  query= (char*) memdup_w_gap((unsigned char*) in_packet, in_packet_length, db.length() + 1);
 
743
  if (! query)
 
744
    return false;
 
745
 
 
746
  query[in_packet_length]=0;
 
747
  query_length= in_packet_length;
717
748
 
718
749
  return true;
719
750
}
722
753
{
723
754
  bool do_release= 0;
724
755
  bool result= true;
725
 
  TransactionServices &transaction_services= TransactionServices::singleton();
726
756
 
727
757
  if (transaction.xid_state.xa_state != XA_NOTR)
728
758
  {
738
768
       * (Which of course should never happen...)
739
769
       */
740
770
      server_status&= ~SERVER_STATUS_IN_TRANS;
741
 
      if (transaction_services.commitTransaction(*this, true))
 
771
      if (ha_commit(this))
742
772
        result= false;
743
773
      options&= ~(OPTION_BEGIN);
 
774
      transaction.all.modified_non_trans_table= false;
744
775
      break;
745
776
    case COMMIT_RELEASE:
746
777
      do_release= 1; /* fall through */
755
786
    case ROLLBACK_AND_CHAIN:
756
787
    {
757
788
      server_status&= ~SERVER_STATUS_IN_TRANS;
758
 
      if (transaction_services.rollbackTransaction(*this, true))
 
789
      if (ha_rollback(this))
759
790
        result= false;
760
791
      options&= ~(OPTION_BEGIN);
 
792
      transaction.all.modified_non_trans_table= false;
761
793
      if (result == true && (completion == ROLLBACK_AND_CHAIN))
762
794
        result= startTransaction();
763
795
      break;
768
800
  }
769
801
 
770
802
  if (result == false)
771
 
  {
772
 
    my_error(static_cast<drizzled::error_t>(killed_errno()), MYF(0));
773
 
  }
 
803
    my_error(killed_errno(), MYF(0));
774
804
  else if ((result == true) && do_release)
775
 
  {
776
 
    setKilled(Session::KILL_CONNECTION);
777
 
  }
 
805
    killed= Session::KILL_CONNECTION;
778
806
 
779
807
  return result;
780
808
}
782
810
bool Session::endActiveTransaction()
783
811
{
784
812
  bool result= true;
785
 
  TransactionServices &transaction_services= TransactionServices::singleton();
786
813
 
787
814
  if (transaction.xid_state.xa_state != XA_NOTR)
788
815
  {
792
819
  if (options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
793
820
  {
794
821
    server_status&= ~SERVER_STATUS_IN_TRANS;
795
 
    if (transaction_services.commitTransaction(*this, true))
 
822
    if (ha_commit(this))
796
823
      result= false;
797
824
  }
798
825
  options&= ~(OPTION_BEGIN);
 
826
  transaction.all.modified_non_trans_table= false;
799
827
  return result;
800
828
}
801
829
 
803
831
{
804
832
  bool result= true;
805
833
 
806
 
  assert(! inTransaction());
807
 
 
808
 
  options|= OPTION_BEGIN;
809
 
  server_status|= SERVER_STATUS_IN_TRANS;
810
 
 
811
 
  if (plugin::TransactionalStorageEngine::notifyStartTransaction(this, opt))
 
834
  if (! endActiveTransaction())
812
835
  {
813
836
    result= false;
814
837
  }
 
838
  else
 
839
  {
 
840
    options|= OPTION_BEGIN;
 
841
    server_status|= SERVER_STATUS_IN_TRANS;
 
842
 
 
843
    if (opt == START_TRANS_OPT_WITH_CONS_SNAPSHOT)
 
844
    {
 
845
      // TODO make this a loop for all engines, not just this one (Inno only
 
846
      // right now)
 
847
      if (plugin::StorageEngine::startConsistentSnapshot(this))
 
848
      {
 
849
        result= false;
 
850
      }
 
851
    }
 
852
  }
815
853
 
816
854
  return result;
817
855
}
833
871
    first_successful_insert_id_in_cur_stmt= 0;
834
872
    substitute_null_with_insert_id= true;
835
873
  }
836
 
 
837
874
  arg_of_last_insert_id_function= false;
838
 
 
839
875
  /* Free Items that were created during this execution */
840
876
  free_items();
841
 
 
842
 
  /* Reset _where. */
843
 
  _where= Session::DEFAULT_WHERE;
844
 
 
845
 
  /* Reset the temporary shares we built */
846
 
  for_each(temporary_shares.begin(),
847
 
           temporary_shares.end(),
848
 
           DeletePtr());
849
 
  temporary_shares.clear();
 
877
  /* Reset where. */
 
878
  where= Session::DEFAULT_WHERE;
850
879
}
851
880
 
852
881
/**
860
889
  @return  NULL on failure, or pointer to the LEX_STRING object
861
890
*/
862
891
LEX_STRING *Session::make_lex_string(LEX_STRING *lex_str,
863
 
                                     const std::string &str,
864
 
                                     bool allocate_lex_string)
865
 
{
866
 
  return make_lex_string(lex_str, str.c_str(), str.length(), allocate_lex_string);
867
 
}
868
 
 
869
 
LEX_STRING *Session::make_lex_string(LEX_STRING *lex_str,
870
 
                                     const char* str, uint32_t length,
871
 
                                     bool allocate_lex_string)
 
892
                                 const char* str, uint32_t length,
 
893
                                 bool allocate_lex_string)
872
894
{
873
895
  if (allocate_lex_string)
874
 
    if (!(lex_str= (LEX_STRING *)getMemRoot()->allocate(sizeof(LEX_STRING))))
 
896
    if (!(lex_str= (LEX_STRING *)alloc(sizeof(LEX_STRING))))
875
897
      return 0;
876
 
  if (!(lex_str->str= mem_root->strmake_root(str, length)))
 
898
  if (!(lex_str->str= strmake_root(mem_root, str, length)))
877
899
    return 0;
878
900
  lex_str->length= length;
879
901
  return lex_str;
880
902
}
881
903
 
 
904
/* routings to adding tables to list of changed in transaction tables */
 
905
inline static void list_include(CHANGED_TableList** prev,
 
906
                                CHANGED_TableList* curr,
 
907
                                CHANGED_TableList* new_table)
 
908
{
 
909
  if (new_table)
 
910
  {
 
911
    *prev = new_table;
 
912
    (*prev)->next = curr;
 
913
  }
 
914
}
 
915
 
 
916
/* add table to list of changed in transaction tables */
 
917
 
 
918
void Session::add_changed_table(Table *table)
 
919
{
 
920
  assert((options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) &&
 
921
              table->cursor->has_transactions());
 
922
  add_changed_table(table->s->table_cache_key.str,
 
923
                    (long) table->s->table_cache_key.length);
 
924
}
 
925
 
 
926
 
 
927
void Session::add_changed_table(const char *key, long key_length)
 
928
{
 
929
  CHANGED_TableList **prev_changed = &transaction.changed_tables;
 
930
  CHANGED_TableList *curr = transaction.changed_tables;
 
931
 
 
932
  for (; curr; prev_changed = &(curr->next), curr = curr->next)
 
933
  {
 
934
    int cmp =  (long)curr->key_length - (long)key_length;
 
935
    if (cmp < 0)
 
936
    {
 
937
      list_include(prev_changed, curr, changed_table_dup(key, key_length));
 
938
      return;
 
939
    }
 
940
    else if (cmp == 0)
 
941
    {
 
942
      cmp = memcmp(curr->key, key, curr->key_length);
 
943
      if (cmp < 0)
 
944
      {
 
945
        list_include(prev_changed, curr, changed_table_dup(key, key_length));
 
946
        return;
 
947
      }
 
948
      else if (cmp == 0)
 
949
      {
 
950
        return;
 
951
      }
 
952
    }
 
953
  }
 
954
  *prev_changed = changed_table_dup(key, key_length);
 
955
}
 
956
 
 
957
 
 
958
CHANGED_TableList* Session::changed_table_dup(const char *key, long key_length)
 
959
{
 
960
  CHANGED_TableList* new_table =
 
961
    (CHANGED_TableList*) trans_alloc(ALIGN_SIZE(sizeof(CHANGED_TableList))+
 
962
                                      key_length + 1);
 
963
  if (!new_table)
 
964
  {
 
965
    my_error(EE_OUTOFMEMORY, MYF(ME_BELL),
 
966
             ALIGN_SIZE(sizeof(TableList)) + key_length + 1);
 
967
    killed= KILL_CONNECTION;
 
968
    return 0;
 
969
  }
 
970
 
 
971
  new_table->key= ((char*)new_table)+ ALIGN_SIZE(sizeof(CHANGED_TableList));
 
972
  new_table->next = 0;
 
973
  new_table->key_length = key_length;
 
974
  ::memcpy(new_table->key, key, key_length);
 
975
  return new_table;
 
976
}
 
977
 
 
978
 
882
979
int Session::send_explain_fields(select_result *result)
883
980
{
884
981
  List<Item> field_list;
917
1014
  return (result->send_fields(field_list));
918
1015
}
919
1016
 
920
 
void select_result::send_error(drizzled::error_t errcode, const char *err)
921
 
{
922
 
  my_message(errcode, err, MYF(0));
923
 
}
924
 
 
925
1017
/************************************************************************
926
1018
  Handling writing to file
927
1019
************************************************************************/
928
1020
 
929
 
void select_to_file::send_error(drizzled::error_t errcode,const char *err)
 
1021
void select_to_file::send_error(uint32_t errcode,const char *err)
930
1022
{
931
1023
  my_message(errcode, err, MYF(0));
932
1024
  if (file > 0)
933
1025
  {
934
 
    (void) cache->end_io_cache();
935
 
    (void) internal::my_close(file, MYF(0));
936
 
    (void) internal::my_delete(path.file_string().c_str(), MYF(0));             // Delete file on error
 
1026
    (void) end_io_cache(&cache);
 
1027
    (void) my_close(file, MYF(0));
 
1028
    (void) my_delete(path, MYF(0));             // Delete file on error
937
1029
    file= -1;
938
1030
  }
939
1031
}
941
1033
 
942
1034
bool select_to_file::send_eof()
943
1035
{
944
 
  int error= test(cache->end_io_cache());
945
 
  if (internal::my_close(file, MYF(MY_WME)))
 
1036
  int error= test(end_io_cache(&cache));
 
1037
  if (my_close(file, MYF(MY_WME)))
946
1038
    error= 1;
947
1039
  if (!error)
948
1040
  {
963
1055
  /* In case of error send_eof() may be not called: close the file here. */
964
1056
  if (file >= 0)
965
1057
  {
966
 
    (void) cache->end_io_cache();
967
 
    (void) internal::my_close(file, MYF(0));
 
1058
    (void) end_io_cache(&cache);
 
1059
    (void) my_close(file, MYF(0));
968
1060
    file= -1;
969
1061
  }
970
 
  path= "";
 
1062
  path[0]= '\0';
971
1063
  row_count= 0;
972
1064
}
973
1065
 
974
 
select_to_file::select_to_file(file_exchange *ex)
975
 
  : exchange(ex),
976
 
    file(-1),
977
 
    cache(static_cast<internal::IO_CACHE *>(memory::sql_calloc(sizeof(internal::IO_CACHE)))),
978
 
    row_count(0L)
979
 
{
980
 
  path= "";
981
 
}
982
1066
 
983
1067
select_to_file::~select_to_file()
984
1068
{
985
 
  cleanup();
 
1069
  if (file >= 0)
 
1070
  {                                     // This only happens in case of error
 
1071
    (void) end_io_cache(&cache);
 
1072
    (void) my_close(file, MYF(0));
 
1073
    file= -1;
 
1074
  }
986
1075
}
987
1076
 
988
1077
/***************************************************************************
1011
1100
*/
1012
1101
 
1013
1102
 
1014
 
static int create_file(Session *session,
1015
 
                       fs::path &target_path,
1016
 
                       file_exchange *exchange,
1017
 
                       internal::IO_CACHE *cache)
 
1103
static File create_file(Session *session, char *path, file_exchange *exchange, IO_CACHE *cache)
1018
1104
{
1019
 
  fs::path to_file(exchange->file_name);
1020
 
  int file;
1021
 
 
1022
 
  if (not to_file.has_root_directory())
 
1105
  File file;
 
1106
  uint32_t option= MY_UNPACK_FILENAME | MY_RELATIVE_PATH;
 
1107
 
 
1108
#ifdef DONT_ALLOW_FULL_LOAD_DATA_PATHS
 
1109
  option|= MY_REPLACE_DIR;                      // Force use of db directory
 
1110
#endif
 
1111
 
 
1112
  if (!dirname_length(exchange->file_name))
1023
1113
  {
1024
 
    target_path= fs::system_complete(getDataHomeCatalog());
1025
 
    util::string::const_shared_ptr schema(session->schema());
1026
 
    if (schema and not schema->empty())
1027
 
    {
1028
 
      int count_elements= 0;
1029
 
      for (fs::path::iterator iter= to_file.begin();
1030
 
           iter != to_file.end();
1031
 
           ++iter, ++count_elements)
1032
 
      { }
1033
 
 
1034
 
      if (count_elements == 1)
1035
 
      {
1036
 
        target_path /= *schema;
1037
 
      }
1038
 
    }
1039
 
    target_path /= to_file;
 
1114
    strcpy(path, drizzle_real_data_home);
 
1115
    if (! session->db.empty())
 
1116
      strncat(path, session->db.c_str(), FN_REFLEN-strlen(drizzle_real_data_home)-1);
 
1117
    (void) fn_format(path, exchange->file_name, path, "", option);
1040
1118
  }
1041
1119
  else
1042
 
  {
1043
 
    target_path = exchange->file_name;
1044
 
  }
1045
 
 
1046
 
  if (not secure_file_priv.string().empty())
1047
 
  {
1048
 
    if (target_path.file_string().substr(0, secure_file_priv.file_string().size()) != secure_file_priv.file_string())
1049
 
    {
1050
 
      /* Write only allowed to dir or subdir specified by secure_file_priv */
1051
 
      my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--secure-file-priv");
1052
 
      return -1;
1053
 
    }
1054
 
  }
1055
 
 
1056
 
  if (!access(target_path.file_string().c_str(), F_OK))
 
1120
    (void) fn_format(path, exchange->file_name, drizzle_real_data_home, "", option);
 
1121
 
 
1122
  if (opt_secure_file_priv &&
 
1123
      strncmp(opt_secure_file_priv, path, strlen(opt_secure_file_priv)))
 
1124
  {
 
1125
    /* Write only allowed to dir or subdir specified by secure_file_priv */
 
1126
    my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--secure-file-priv");
 
1127
    return -1;
 
1128
  }
 
1129
 
 
1130
  if (!access(path, F_OK))
1057
1131
  {
1058
1132
    my_error(ER_FILE_EXISTS_ERROR, MYF(0), exchange->file_name);
1059
1133
    return -1;
1060
1134
  }
1061
1135
  /* Create the file world readable */
1062
 
  if ((file= internal::my_create(target_path.file_string().c_str(), 0666, O_WRONLY|O_EXCL, MYF(MY_WME))) < 0)
 
1136
  if ((file= my_create(path, 0666, O_WRONLY|O_EXCL, MYF(MY_WME))) < 0)
1063
1137
    return file;
 
1138
#ifdef HAVE_FCHMOD
1064
1139
  (void) fchmod(file, 0666);                    // Because of umask()
1065
 
  if (cache->init_io_cache(file, 0L, internal::WRITE_CACHE, 0L, 1, MYF(MY_WME)))
 
1140
#else
 
1141
  (void) chmod(path, 0666);
 
1142
#endif
 
1143
  if (init_io_cache(cache, file, 0L, WRITE_CACHE, 0L, 1, MYF(MY_WME)))
1066
1144
  {
1067
 
    internal::my_close(file, MYF(0));
1068
 
    internal::my_delete(target_path.file_string().c_str(), MYF(0));  // Delete file on error, it was just created
 
1145
    my_close(file, MYF(0));
 
1146
    my_delete(path, MYF(0));  // Delete file on error, it was just created
1069
1147
    return -1;
1070
1148
  }
1071
1149
  return file;
1079
1157
  bool string_results= false, non_string_results= false;
1080
1158
  unit= u;
1081
1159
  if ((uint32_t) strlen(exchange->file_name) + NAME_LEN >= FN_REFLEN)
1082
 
  {
1083
 
    path= exchange->file_name;
1084
 
  }
 
1160
    strncpy(path,exchange->file_name,FN_REFLEN-1);
1085
1161
 
1086
1162
  /* Check if there is any blobs in data */
1087
1163
  {
1091
1167
    {
1092
1168
      if (item->max_length >= MAX_BLOB_WIDTH)
1093
1169
      {
1094
 
        blob_flag=1;
1095
 
        break;
 
1170
        blob_flag=1;
 
1171
        break;
1096
1172
      }
1097
 
 
1098
1173
      if (item->result_type() == STRING_RESULT)
1099
1174
        string_results= true;
1100
1175
      else
1129
1204
    return 1;
1130
1205
  }
1131
1206
 
1132
 
  if ((file= create_file(session, path, exchange, cache)) < 0)
 
1207
  if ((file= create_file(session, path, exchange, &cache)) < 0)
1133
1208
    return 1;
1134
1209
 
1135
1210
  return 0;
1136
1211
}
1137
1212
 
 
1213
 
 
1214
#define NEED_ESCAPING(x) ((int) (unsigned char) (x) == escape_char    || \
 
1215
                          (enclosed ? (int) (unsigned char) (x) == field_sep_char      \
 
1216
                                    : (int) (unsigned char) (x) == field_term_char) || \
 
1217
                          (int) (unsigned char) (x) == line_sep_char  || \
 
1218
                          !(x))
 
1219
 
1138
1220
bool select_export::send_data(List<Item> &items)
1139
1221
{
1140
1222
  char buff[MAX_FIELD_WIDTH],null_buff[2],space[MAX_FIELD_WIDTH];
1145
1227
  if (unit->offset_limit_cnt)
1146
1228
  {                                             // using limit offset,count
1147
1229
    unit->offset_limit_cnt--;
1148
 
    return false;
 
1230
    return(0);
1149
1231
  }
1150
1232
  row_count++;
1151
1233
  Item *item;
1152
1234
  uint32_t used_length=0,items_left=items.elements;
1153
1235
  List_iterator_fast<Item> li(items);
1154
1236
 
1155
 
  if (my_b_write(cache,(unsigned char*) exchange->line_start->ptr(),
 
1237
  if (my_b_write(&cache,(unsigned char*) exchange->line_start->ptr(),
1156
1238
                 exchange->line_start->length()))
1157
 
    return true;
1158
 
 
 
1239
    goto err;
1159
1240
  while ((item=li++))
1160
1241
  {
1161
1242
    Item_result result_type=item->result_type();
1164
1245
    res=item->str_result(&tmp);
1165
1246
    if (res && enclosed)
1166
1247
    {
1167
 
      if (my_b_write(cache,(unsigned char*) exchange->enclosed->ptr(),
 
1248
      if (my_b_write(&cache,(unsigned char*) exchange->enclosed->ptr(),
1168
1249
                     exchange->enclosed->length()))
1169
 
        return true;
 
1250
        goto err;
1170
1251
    }
1171
1252
    if (!res)
1172
1253
    {                                           // NULL
1176
1257
        {
1177
1258
          null_buff[0]=escape_char;
1178
1259
          null_buff[1]='N';
1179
 
          if (my_b_write(cache,(unsigned char*) null_buff,2))
1180
 
            return true;
 
1260
          if (my_b_write(&cache,(unsigned char*) null_buff,2))
 
1261
            goto err;
1181
1262
        }
1182
 
        else if (my_b_write(cache,(unsigned char*) "NULL",4))
1183
 
          return true;
 
1263
        else if (my_b_write(&cache,(unsigned char*) "NULL",4))
 
1264
          goto err;
1184
1265
      }
1185
1266
      else
1186
1267
      {
1190
1271
    else
1191
1272
    {
1192
1273
      if (fixed_row_size)
1193
 
        used_length= min(res->length(), static_cast<size_t>(item->max_length));
 
1274
        used_length= min(res->length(),item->max_length);
1194
1275
      else
1195
1276
        used_length= res->length();
1196
1277
 
1252
1333
            assert before the loop makes that sure.
1253
1334
          */
1254
1335
 
1255
 
          if ((needs_escaping(*pos, enclosed) ||
 
1336
          if ((NEED_ESCAPING(*pos) ||
1256
1337
               (check_second_byte &&
1257
1338
                my_mbcharlen(character_set_client, (unsigned char) *pos) == 2 &&
1258
1339
                pos + 1 < end &&
1259
 
                needs_escaping(pos[1], enclosed))) &&
 
1340
                NEED_ESCAPING(pos[1]))) &&
1260
1341
              /*
1261
1342
                Don't escape field_term_char by doubling - doubling is only
1262
1343
                valid for ENCLOSED BY characters:
1269
1350
                          is_ambiguous_field_sep) ?
1270
1351
              field_sep_char : escape_char;
1271
1352
            tmp_buff[1]= *pos ? *pos : '0';
1272
 
            if (my_b_write(cache,(unsigned char*) start,(uint32_t) (pos-start)) ||
1273
 
                my_b_write(cache,(unsigned char*) tmp_buff,2))
1274
 
              return true;
 
1353
            if (my_b_write(&cache,(unsigned char*) start,(uint32_t) (pos-start)) ||
 
1354
                my_b_write(&cache,(unsigned char*) tmp_buff,2))
 
1355
              goto err;
1275
1356
            start=pos+1;
1276
1357
          }
1277
1358
        }
1278
 
        if (my_b_write(cache,(unsigned char*) start,(uint32_t) (pos-start)))
1279
 
          return true;
 
1359
        if (my_b_write(&cache,(unsigned char*) start,(uint32_t) (pos-start)))
 
1360
          goto err;
1280
1361
      }
1281
 
      else if (my_b_write(cache,(unsigned char*) res->ptr(),used_length))
1282
 
        return true;
 
1362
      else if (my_b_write(&cache,(unsigned char*) res->ptr(),used_length))
 
1363
        goto err;
1283
1364
    }
1284
1365
    if (fixed_row_size)
1285
1366
    {                                           // Fill with space
1294
1375
        uint32_t length=item->max_length-used_length;
1295
1376
        for (; length > sizeof(space) ; length-=sizeof(space))
1296
1377
        {
1297
 
          if (my_b_write(cache,(unsigned char*) space,sizeof(space)))
1298
 
            return true;
 
1378
          if (my_b_write(&cache,(unsigned char*) space,sizeof(space)))
 
1379
            goto err;
1299
1380
        }
1300
 
        if (my_b_write(cache,(unsigned char*) space,length))
1301
 
          return true;
 
1381
        if (my_b_write(&cache,(unsigned char*) space,length))
 
1382
          goto err;
1302
1383
      }
1303
1384
    }
1304
1385
    if (res && enclosed)
1305
1386
    {
1306
 
      if (my_b_write(cache, (unsigned char*) exchange->enclosed->ptr(),
 
1387
      if (my_b_write(&cache, (unsigned char*) exchange->enclosed->ptr(),
1307
1388
                     exchange->enclosed->length()))
1308
 
        return true;
 
1389
        goto err;
1309
1390
    }
1310
1391
    if (--items_left)
1311
1392
    {
1312
 
      if (my_b_write(cache, (unsigned char*) exchange->field_term->ptr(),
 
1393
      if (my_b_write(&cache, (unsigned char*) exchange->field_term->ptr(),
1313
1394
                     field_term_length))
1314
 
        return true;
 
1395
        goto err;
1315
1396
    }
1316
1397
  }
1317
 
  if (my_b_write(cache,(unsigned char*) exchange->line_term->ptr(),
 
1398
  if (my_b_write(&cache,(unsigned char*) exchange->line_term->ptr(),
1318
1399
                 exchange->line_term->length()))
1319
 
  {
1320
 
    return true;
1321
 
  }
1322
 
 
1323
 
  return false;
 
1400
    goto err;
 
1401
  return(0);
 
1402
err:
 
1403
  return(1);
1324
1404
}
1325
1405
 
1326
1406
 
1333
1413
select_dump::prepare(List<Item> &, Select_Lex_Unit *u)
1334
1414
{
1335
1415
  unit= u;
1336
 
  return (int) ((file= create_file(session, path, exchange, cache)) < 0);
 
1416
  return (int) ((file= create_file(session, path, exchange, &cache)) < 0);
1337
1417
}
1338
1418
 
1339
1419
 
1353
1433
  if (row_count++ > 1)
1354
1434
  {
1355
1435
    my_message(ER_TOO_MANY_ROWS, ER(ER_TOO_MANY_ROWS), MYF(0));
1356
 
    return 1;
 
1436
    goto err;
1357
1437
  }
1358
1438
  while ((item=li++))
1359
1439
  {
1360
1440
    res=item->str_result(&tmp);
1361
1441
    if (!res)                                   // If NULL
1362
1442
    {
1363
 
      if (my_b_write(cache,(unsigned char*) "",1))
1364
 
        return 1;
 
1443
      if (my_b_write(&cache,(unsigned char*) "",1))
 
1444
        goto err;
1365
1445
    }
1366
 
    else if (my_b_write(cache,(unsigned char*) res->ptr(),res->length()))
 
1446
    else if (my_b_write(&cache,(unsigned char*) res->ptr(),res->length()))
1367
1447
    {
1368
 
      my_error(ER_ERROR_ON_WRITE, MYF(0), path.file_string().c_str(), errno);
1369
 
      return 1;
 
1448
      my_error(ER_ERROR_ON_WRITE, MYF(0), path, my_errno);
 
1449
      goto err;
1370
1450
    }
1371
1451
  }
1372
1452
  return(0);
 
1453
err:
 
1454
  return(1);
1373
1455
}
1374
1456
 
1375
1457
 
1427
1509
      switch (val_item->result_type())
1428
1510
      {
1429
1511
      case REAL_RESULT:
1430
 
        op= &select_max_min_finder_subselect::cmp_real;
1431
 
        break;
 
1512
        op= &select_max_min_finder_subselect::cmp_real;
 
1513
        break;
1432
1514
      case INT_RESULT:
1433
 
        op= &select_max_min_finder_subselect::cmp_int;
1434
 
        break;
 
1515
        op= &select_max_min_finder_subselect::cmp_int;
 
1516
        break;
1435
1517
      case STRING_RESULT:
1436
 
        op= &select_max_min_finder_subselect::cmp_str;
1437
 
        break;
 
1518
        op= &select_max_min_finder_subselect::cmp_str;
 
1519
        break;
1438
1520
      case DECIMAL_RESULT:
1439
1521
        op= &select_max_min_finder_subselect::cmp_decimal;
1440
1522
        break;
1441
1523
      case ROW_RESULT:
1442
1524
        // This case should never be choosen
1443
 
        assert(0);
1444
 
        op= 0;
 
1525
        assert(0);
 
1526
        op= 0;
1445
1527
      }
1446
1528
    }
1447
1529
    cache->store(val_item);
1480
1562
bool select_max_min_finder_subselect::cmp_decimal()
1481
1563
{
1482
1564
  Item *maxmin= ((Item_singlerow_subselect *)item)->element_index(0);
1483
 
  type::Decimal cval, *cvalue= cache->val_decimal(&cval);
1484
 
  type::Decimal mval, *mvalue= maxmin->val_decimal(&mval);
 
1565
  my_decimal cval, *cvalue= cache->val_decimal(&cval);
 
1566
  my_decimal mval, *mvalue= maxmin->val_decimal(&mval);
1485
1567
  if (fmax)
1486
1568
    return (cache->null_value && !maxmin->null_value) ||
1487
1569
      (!cache->null_value && !maxmin->null_value &&
1488
 
       class_decimal_cmp(cvalue, mvalue) > 0) ;
 
1570
       my_decimal_cmp(cvalue, mvalue) > 0) ;
1489
1571
  return (maxmin->null_value && !cache->null_value) ||
1490
1572
    (!cache->null_value && !maxmin->null_value &&
1491
 
     class_decimal_cmp(cvalue,mvalue) < 0);
 
1573
     my_decimal_cmp(cvalue,mvalue) < 0);
1492
1574
}
1493
1575
 
1494
1576
bool select_max_min_finder_subselect::cmp_str()
1530
1612
void Session::end_statement()
1531
1613
{
1532
1614
  /* Cleanup SQL processing state to reuse this statement in next query. */
1533
 
  lex->end();
1534
 
  query_cache_key= ""; // reset the cache key
1535
 
  resetResultsetMessage();
 
1615
  lex_end(lex);
1536
1616
}
1537
1617
 
1538
1618
bool Session::copy_db_to(char **p_db, size_t *p_db_length)
1539
1619
{
1540
 
  assert(_schema);
1541
 
  if (_schema and _schema->empty())
1542
 
  {
1543
 
    my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
1544
 
    return true;
1545
 
  }
1546
 
  else if (not _schema)
1547
 
  {
1548
 
    my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
1549
 
    return true;
1550
 
  }
1551
 
  assert(_schema);
1552
 
 
1553
 
  *p_db= strmake(_schema->c_str(), _schema->size());
1554
 
  *p_db_length= _schema->size();
1555
 
 
 
1620
  if (db.empty())
 
1621
  {
 
1622
    my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
 
1623
    return true;
 
1624
  }
 
1625
  *p_db= strmake(db.c_str(), db.length());
 
1626
  *p_db_length= db.length();
1556
1627
  return false;
1557
1628
}
1558
1629
 
1567
1638
  quick_group= 1;
1568
1639
  table_charset= 0;
1569
1640
  precomputed_group_by= 0;
 
1641
  bit_fields_as_long= 0;
1570
1642
}
1571
1643
 
1572
1644
void Tmp_Table_Param::cleanup(void)
1574
1646
  /* Fix for Intel compiler */
1575
1647
  if (copy_field)
1576
1648
  {
1577
 
    boost::checked_array_delete(copy_field);
1578
 
    save_copy_field= save_copy_field_end= copy_field= copy_field_end= 0;
 
1649
    delete [] copy_field;
 
1650
    save_copy_field= copy_field= 0;
1579
1651
  }
1580
1652
}
1581
1653
 
1582
1654
void Session::send_kill_message() const
1583
1655
{
1584
 
  drizzled::error_t err= static_cast<drizzled::error_t>(killed_errno());
1585
 
  if (err != EE_OK)
 
1656
  int err= killed_errno();
 
1657
  if (err)
1586
1658
    my_message(err, ER(err), MYF(0));
1587
1659
}
1588
1660
 
1591
1663
  memset(&status_var, 0, sizeof(status_var));
1592
1664
}
1593
1665
 
1594
 
 
1595
 
void Session::set_db(const std::string &new_db)
 
1666
void Security_context::skip_grants()
 
1667
{
 
1668
  /* privileges for the user are unknown everything is allowed */
 
1669
}
 
1670
 
 
1671
 
 
1672
/****************************************************************************
 
1673
  Handling of open and locked tables states.
 
1674
 
 
1675
  This is used when we want to open/lock (and then close) some tables when
 
1676
  we already have a set of tables open and locked. We use these methods for
 
1677
  access to mysql.proc table to find definitions of stored routines.
 
1678
****************************************************************************/
 
1679
 
 
1680
void Session::reset_n_backup_open_tables_state(Open_tables_state *backup)
 
1681
{
 
1682
  backup->set_open_tables_state(this);
 
1683
  reset_open_tables_state();
 
1684
  backups_available= false;
 
1685
}
 
1686
 
 
1687
 
 
1688
void Session::restore_backup_open_tables_state(Open_tables_state *backup)
 
1689
{
 
1690
  /*
 
1691
    Before we will throw away current open tables state we want
 
1692
    to be sure that it was properly cleaned up.
 
1693
  */
 
1694
  assert(open_tables == 0 && temporary_tables == 0 &&
 
1695
              derived_tables == 0 &&
 
1696
              lock == 0);
 
1697
  set_open_tables_state(backup);
 
1698
}
 
1699
 
 
1700
 
 
1701
bool Session::set_db(const char *new_db, size_t length)
1596
1702
{
1597
1703
  /* Do not reallocate memory if current chunk is big enough. */
1598
 
  if (new_db.length())
1599
 
  {
1600
 
    _schema.reset(new std::string(new_db));
1601
 
  }
 
1704
  if (length)
 
1705
    db= new_db;
1602
1706
  else
1603
 
  {
1604
 
    _schema.reset(new std::string(""));
1605
 
  }
1606
 
}
1607
 
 
 
1707
    db.clear();
 
1708
 
 
1709
  return false;
 
1710
}
 
1711
 
 
1712
 
 
1713
/**
 
1714
  Check the killed state of a user thread
 
1715
  @param session  user thread
 
1716
  @retval 0 the user thread is active
 
1717
  @retval 1 the user thread has been killed
 
1718
*/
 
1719
extern "C" int session_killed(const Session *session)
 
1720
{
 
1721
  return(session->killed);
 
1722
}
 
1723
 
 
1724
/**
 
1725
  Return the session id of a user session
 
1726
  @param pointer to Session object
 
1727
  @return session's id
 
1728
*/
 
1729
extern "C" unsigned long session_get_thread_id(const Session *session)
 
1730
{
 
1731
  return (unsigned long) session->getSessionId();
 
1732
}
 
1733
 
 
1734
 
 
1735
extern "C"
 
1736
LEX_STRING *session_make_lex_string(Session *session, LEX_STRING *lex_str,
 
1737
                                const char *str, unsigned int size,
 
1738
                                int allocate_lex_string)
 
1739
{
 
1740
  return session->make_lex_string(lex_str, str, size,
 
1741
                              (bool) allocate_lex_string);
 
1742
}
 
1743
 
 
1744
const struct charset_info_st *session_charset(Session *session)
 
1745
{
 
1746
  return(session->charset());
 
1747
}
 
1748
 
 
1749
char **session_query(Session *session)
 
1750
{
 
1751
  return(&session->query);
 
1752
}
 
1753
 
 
1754
int session_non_transactional_update(const Session *session)
 
1755
{
 
1756
  return(session->transaction.all.modified_non_trans_table);
 
1757
}
 
1758
 
 
1759
void session_mark_transaction_to_rollback(Session *session, bool all)
 
1760
{
 
1761
  mark_transaction_to_rollback(session, all);
 
1762
}
1608
1763
 
1609
1764
/**
1610
1765
  Mark transaction to rollback and mark error as fatal to a sub-statement.
1612
1767
  @param  session   Thread handle
1613
1768
  @param  all   true <=> rollback main transaction.
1614
1769
*/
1615
 
void Session::markTransactionForRollback(bool all)
 
1770
void mark_transaction_to_rollback(Session *session, bool all)
1616
1771
{
1617
 
  is_fatal_sub_stmt_error= true;
1618
 
  transaction_rollback_request= all;
 
1772
  if (session)
 
1773
  {
 
1774
    session->is_fatal_sub_stmt_error= true;
 
1775
    session->transaction_rollback_request= all;
 
1776
  }
1619
1777
}
1620
1778
 
1621
 
void Session::disconnect(enum error_t errcode)
 
1779
void Session::disconnect(uint32_t errcode, bool should_lock)
1622
1780
{
1623
1781
  /* Allow any plugins to cleanup their session variables */
1624
1782
  plugin_sessionvar_cleanup(this);
1625
1783
 
1626
1784
  /* If necessary, log any aborted or unauthorized connections */
1627
 
  if (getKilled() || client->wasAborted())
1628
 
  {
1629
 
    status_var.aborted_threads++;
1630
 
  }
 
1785
  if (killed || client->wasAborted())
 
1786
    statistic_increment(aborted_threads, &LOCK_status);
1631
1787
 
1632
1788
  if (client->wasAborted())
1633
1789
  {
1634
 
    if (not getKilled() && variables.log_warnings > 1)
 
1790
    if (! killed && variables.log_warnings > 1)
1635
1791
    {
1636
 
      errmsg_printf(error::WARN, ER(ER_NEW_ABORTING_CONNECTION)
 
1792
      Security_context *sctx= &security_ctx;
 
1793
 
 
1794
      errmsg_printf(ERRMSG_LVL_WARN, ER(ER_NEW_ABORTING_CONNECTION)
1637
1795
                  , thread_id
1638
 
                  , (_schema->empty() ? "unconnected" : _schema->c_str())
1639
 
                  , security_ctx->username().empty() == false ? security_ctx->username().c_str() : "unauthenticated"
1640
 
                  , security_ctx->address().c_str()
 
1796
                  , (db.empty() ? "unconnected" : db.c_str())
 
1797
                  , sctx->user.empty() == false ? sctx->user.c_str() : "unauthenticated"
 
1798
                  , sctx->ip.c_str()
1641
1799
                  , (main_da.is_error() ? main_da.message() : ER(ER_UNKNOWN_ERROR)));
1642
1800
    }
1643
1801
  }
1644
1802
 
1645
 
  setKilled(Session::KILL_CONNECTION);
1646
 
 
 
1803
  /* Close out our connection to the client */
 
1804
  if (should_lock)
 
1805
    (void) pthread_mutex_lock(&LOCK_thread_count);
 
1806
  killed= Session::KILL_CONNECTION;
1647
1807
  if (client->isConnected())
1648
1808
  {
1649
 
    if (errcode != EE_OK)
 
1809
    if (errcode)
1650
1810
    {
1651
1811
      /*my_error(errcode, ER(errcode));*/
1652
1812
      client->sendError(errcode, ER(errcode));
1653
1813
    }
1654
1814
    client->close();
1655
1815
  }
 
1816
  if (should_lock)
 
1817
    (void) pthread_mutex_unlock(&LOCK_thread_count);
1656
1818
}
1657
1819
 
1658
1820
void Session::reset_for_next_command()
1669
1831
  server_status&= ~ (SERVER_MORE_RESULTS_EXISTS |
1670
1832
                          SERVER_QUERY_NO_INDEX_USED |
1671
1833
                          SERVER_QUERY_NO_GOOD_INDEX_USED);
 
1834
  /*
 
1835
    If in autocommit mode and not in a transaction, reset
 
1836
    OPTION_STATUS_NO_TRANS_UPDATE to not get warnings
 
1837
    in ha_rollback_trans() about some tables couldn't be rolled back.
 
1838
  */
 
1839
  if (!(options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))
 
1840
  {
 
1841
    transaction.all.modified_non_trans_table= false;
 
1842
  }
1672
1843
 
1673
1844
  clear_error();
1674
1845
  main_da.reset_diagnostics_area();
1680
1851
  Close all temporary tables created by 'CREATE TEMPORARY TABLE' for thread
1681
1852
*/
1682
1853
 
1683
 
void Open_tables_state::close_temporary_tables()
 
1854
void Session::close_temporary_tables()
1684
1855
{
1685
1856
  Table *table;
1686
1857
  Table *tmp_next;
1687
1858
 
1688
 
  if (not temporary_tables)
 
1859
  if (!temporary_tables)
1689
1860
    return;
1690
1861
 
1691
1862
  for (table= temporary_tables; table; table= tmp_next)
1692
1863
  {
1693
 
    tmp_next= table->getNext();
1694
 
    nukeTable(table);
 
1864
    tmp_next= table->next;
 
1865
    close_temporary(table);
1695
1866
  }
1696
1867
  temporary_tables= NULL;
1697
1868
}
1700
1871
  unlink from session->temporary tables and close temporary table
1701
1872
*/
1702
1873
 
1703
 
void Open_tables_state::close_temporary_table(Table *table)
 
1874
void Session::close_temporary_table(Table *table)
 
1875
                         
1704
1876
{
1705
 
  if (table->getPrev())
 
1877
  if (table->prev)
1706
1878
  {
1707
 
    table->getPrev()->setNext(table->getNext());
1708
 
    if (table->getPrev()->getNext())
1709
 
    {
1710
 
      table->getNext()->setPrev(table->getPrev());
1711
 
    }
 
1879
    table->prev->next= table->next;
 
1880
    if (table->prev->next)
 
1881
      table->next->prev= table->prev;
1712
1882
  }
1713
1883
  else
1714
1884
  {
1719
1889
      passing non-zero value to end_slave via rli->save_temporary_tables
1720
1890
      when no temp tables opened, see an invariant below.
1721
1891
    */
1722
 
    temporary_tables= table->getNext();
 
1892
    temporary_tables= table->next;
1723
1893
    if (temporary_tables)
1724
 
    {
1725
 
      table->getNext()->setPrev(NULL);
1726
 
    }
 
1894
      table->next->prev= NULL;
1727
1895
  }
1728
 
  nukeTable(table);
 
1896
  close_temporary(table);
1729
1897
}
1730
1898
 
1731
1899
/*
1732
 
  Close and drop a temporary table
 
1900
  Close and delete a temporary table
1733
1901
 
1734
1902
  NOTE
1735
1903
  This dosn't unlink table from session->temporary
1736
1904
  If this is needed, use close_temporary_table()
1737
1905
*/
1738
1906
 
1739
 
void Open_tables_state::nukeTable(Table *table)
 
1907
void Session::close_temporary(Table *table)
1740
1908
{
1741
 
  plugin::StorageEngine *table_type= table->getShare()->db_type();
 
1909
  plugin::StorageEngine *table_type= table->s->db_type();
1742
1910
 
1743
1911
  table->free_io_cache();
1744
 
  table->delete_table();
1745
 
 
1746
 
  identifier::Table identifier(table->getShare()->getSchemaName(), table->getShare()->getTableName(), table->getShare()->getPath());
1747
 
  rm_temporary_table(table_type, identifier);
1748
 
 
1749
 
  boost::checked_delete(table->getMutableShare());
1750
 
 
1751
 
  boost::checked_delete(table);
 
1912
  table->closefrm(false);
 
1913
 
 
1914
  rm_temporary_table(table_type, table->s->path.str);
 
1915
 
 
1916
  table->s->free_table_share();
 
1917
  /* This makes me sad, but we're allocating it via malloc */
 
1918
  free(table);
1752
1919
}
1753
1920
 
1754
1921
/** Clear most status variables. */
1755
1922
extern time_t flush_status_time;
 
1923
extern uint32_t max_used_connections;
1756
1924
 
1757
1925
void Session::refresh_status()
1758
1926
{
 
1927
  pthread_mutex_lock(&LOCK_status);
 
1928
 
 
1929
  /* Add thread's status variabes to global status */
 
1930
  add_to_status(&global_status_var, &status_var);
 
1931
 
1759
1932
  /* Reset thread's status variables */
1760
1933
  memset(&status_var, 0, sizeof(status_var));
1761
1934
 
 
1935
  /* Reset some global variables */
 
1936
  reset_status_vars();
 
1937
 
 
1938
  /* Reset the counters of all key caches (default and named). */
 
1939
  reset_key_cache_counters();
1762
1940
  flush_status_time= time((time_t*) 0);
1763
 
  current_global_counters.max_used_connections= 1; /* We set it to one, because we know we exist */
1764
 
  current_global_counters.connections= 0;
 
1941
  max_used_connections= 1; /* We set it to one, because we know we exist */
 
1942
  pthread_mutex_unlock(&LOCK_status);
1765
1943
}
1766
1944
 
1767
1945
user_var_entry *Session::getVariable(LEX_STRING &name, bool create_if_not_exists)
1768
1946
{
1769
 
  return getVariable(std::string(name.str, name.length), create_if_not_exists);
1770
 
}
1771
 
 
1772
 
user_var_entry *Session::getVariable(const std::string  &name, bool create_if_not_exists)
1773
 
{
1774
 
  if (cleanup_done)
1775
 
    return NULL;
1776
 
 
1777
 
  UserVars::iterator iter= user_vars.find(name);
1778
 
  if (iter != user_vars.end())
1779
 
    return (*iter).second;
1780
 
 
1781
 
  if (not create_if_not_exists)
1782
 
    return NULL;
1783
 
 
1784
1947
  user_var_entry *entry= NULL;
1785
 
  entry= new (nothrow) user_var_entry(name.c_str(), query_id);
1786
 
 
1787
 
  if (entry == NULL)
1788
 
    return NULL;
1789
 
 
1790
 
  std::pair<UserVars::iterator, bool> returnable= user_vars.insert(make_pair(name, entry));
1791
 
 
1792
 
  if (not returnable.second)
 
1948
 
 
1949
  entry= (user_var_entry*) hash_search(&user_vars, (unsigned char*) name.str, name.length);
 
1950
 
 
1951
  if ((entry == NULL) && create_if_not_exists)
1793
1952
  {
1794
 
    boost::checked_delete(entry);
 
1953
    if (!hash_inited(&user_vars))
 
1954
      return NULL;
 
1955
    entry= new (nothrow) user_var_entry(name.str, query_id);
 
1956
 
 
1957
    if (entry == NULL)
 
1958
      return NULL;
 
1959
 
 
1960
    if (my_hash_insert(&user_vars, (unsigned char*) entry))
 
1961
    {
 
1962
      assert(1);
 
1963
      free((char*) entry);
 
1964
      return 0;
 
1965
    }
 
1966
 
1795
1967
  }
1796
1968
 
1797
1969
  return entry;
1798
1970
}
1799
1971
 
1800
 
void Session::setVariable(const std::string &name, const std::string &value)
1801
 
{
1802
 
  user_var_entry *updateable_var= getVariable(name.c_str(), true);
1803
 
  if (updateable_var)
1804
 
  {
1805
 
    updateable_var->update_hash(false,
1806
 
                                (void*)value.c_str(),
1807
 
                                static_cast<uint32_t>(value.length()), STRING_RESULT,
1808
 
                                &my_charset_bin,
1809
 
                                DERIVATION_IMPLICIT, false);
1810
 
  }
1811
 
}
1812
 
 
1813
 
void Open_tables_state::mark_temp_tables_as_free_for_reuse()
1814
 
{
1815
 
  for (Table *table= temporary_tables ; table ; table= table->getNext())
1816
 
  {
1817
 
    if (table->query_id == getQueryId())
 
1972
void Session::mark_temp_tables_as_free_for_reuse()
 
1973
{
 
1974
  for (Table *table= temporary_tables ; table ; table= table->next)
 
1975
  {
 
1976
    if (table->query_id == query_id)
1818
1977
    {
1819
1978
      table->query_id= 0;
1820
1979
      table->cursor->ha_reset();
1824
1983
 
1825
1984
void Session::mark_used_tables_as_free_for_reuse(Table *table)
1826
1985
{
1827
 
  for (; table ; table= table->getNext())
 
1986
  for (; table ; table= table->next)
1828
1987
  {
1829
 
    if (table->query_id == getQueryId())
 
1988
    if (table->query_id == query_id)
1830
1989
    {
1831
1990
      table->query_id= 0;
1832
1991
      table->cursor->ha_reset();
1845
2004
*/
1846
2005
void Session::close_thread_tables()
1847
2006
{
1848
 
  clearDerivedTables();
 
2007
  Table *table;
 
2008
 
 
2009
  /*
 
2010
    We are assuming here that session->derived_tables contains ONLY derived
 
2011
    tables for this substatement. i.e. instead of approach which uses
 
2012
    query_id matching for determining which of the derived tables belong
 
2013
    to this substatement we rely on the ability of substatements to
 
2014
    save/restore session->derived_tables during their execution.
 
2015
 
 
2016
    TODO: Probably even better approach is to simply associate list of
 
2017
          derived tables with (sub-)statement instead of thread and destroy
 
2018
          them at the end of its execution.
 
2019
  */
 
2020
  if (derived_tables)
 
2021
  {
 
2022
    Table *next;
 
2023
    /*
 
2024
      Close all derived tables generated in queries like
 
2025
      SELECT * FROM (SELECT * FROM t1)
 
2026
    */
 
2027
    for (table= derived_tables ; table ; table= next)
 
2028
    {
 
2029
      next= table->next;
 
2030
      table->free_tmp_table(this);
 
2031
    }
 
2032
    derived_tables= 0;
 
2033
  }
1849
2034
 
1850
2035
  /*
1851
2036
    Mark all temporary tables used by this statement as free for reuse.
1859
2044
    does not belong to statement for which we do close_thread_tables()).
1860
2045
    TODO: This should be fixed in later releases.
1861
2046
   */
 
2047
  if (backups_available == false)
1862
2048
  {
1863
 
    TransactionServices &transaction_services= TransactionServices::singleton();
1864
2049
    main_da.can_overwrite_status= true;
1865
 
    transaction_services.autocommitOrRollback(*this, is_error());
 
2050
    ha_autocommit_or_rollback(this, is_error());
1866
2051
    main_da.can_overwrite_status= false;
1867
2052
    transaction.stmt.reset();
1868
2053
  }
1878
2063
      handled either before writing a query log event (inside
1879
2064
      binlog_query()) or when preparing a pending event.
1880
2065
     */
1881
 
    unlockTables(lock);
 
2066
    mysql_unlock_tables(this, lock);
1882
2067
    lock= 0;
1883
2068
  }
1884
2069
  /*
1885
 
    Note that we need to hold table::Cache::singleton().mutex() while changing the
 
2070
    Note that we need to hold LOCK_open while changing the
1886
2071
    open_tables list. Another thread may work on it.
1887
 
    (See: table::Cache::singleton().removeTable(), wait_completed_table())
 
2072
    (See: remove_table_from_cache(), mysql_wait_completed_table())
1888
2073
    Closing a MERGE child before the parent would be fatal if the
1889
2074
    other thread tries to abort the MERGE lock in between.
1890
2075
  */
1916
2101
    if (open_tables_from_list(&tables, &counter))
1917
2102
      return true;
1918
2103
 
1919
 
    if (not lock_tables(tables, counter, &need_reopen))
 
2104
    if (!lock_tables(tables, counter, &need_reopen))
1920
2105
      break;
1921
 
 
1922
 
    if (not need_reopen)
 
2106
    if (!need_reopen)
1923
2107
      return true;
1924
 
 
1925
2108
    close_tables_for_reopen(&tables);
1926
2109
  }
1927
 
 
1928
 
  if ((handle_derived(lex, &derived_prepare) || (handle_derived(lex, &derived_filling))))
1929
 
    return true;
1930
 
 
1931
 
  return false;
1932
 
}
1933
 
 
1934
 
/*
1935
 
  @note "best_effort" is used in cases were if a failure occurred on this
1936
 
  operation it would not be surprising because we are only removing because there
1937
 
  might be an issue (lame engines).
1938
 
*/
1939
 
 
1940
 
bool Open_tables_state::rm_temporary_table(const identifier::Table &identifier, bool best_effort)
1941
 
{
1942
 
  if (not plugin::StorageEngine::dropTable(*static_cast<Session *>(this), identifier))
1943
 
  {
1944
 
    if (not best_effort)
1945
 
    {
1946
 
      std::string path;
1947
 
      identifier.getSQLPath(path);
1948
 
      errmsg_printf(error::WARN, _("Could not remove temporary table: '%s', error: %d"),
1949
 
                    path.c_str(), errno);
1950
 
    }
1951
 
 
1952
 
    return true;
1953
 
  }
1954
 
 
1955
 
  return false;
1956
 
}
1957
 
 
1958
 
bool Open_tables_state::rm_temporary_table(plugin::StorageEngine *base, const identifier::Table &identifier)
1959
 
{
1960
 
  drizzled::error_t error;
 
2110
  if ((mysql_handle_derived(lex, &mysql_derived_prepare) ||
 
2111
       (fill_derived_tables() &&
 
2112
        mysql_handle_derived(lex, &mysql_derived_filling))))
 
2113
    return true;
 
2114
 
 
2115
  return false;
 
2116
}
 
2117
 
 
2118
bool Session::openTables(TableList *tables, uint32_t flags)
 
2119
{
 
2120
  uint32_t counter;
 
2121
  bool ret= fill_derived_tables();
 
2122
  assert(ret == false);
 
2123
  if (open_tables_from_list(&tables, &counter, flags) ||
 
2124
      mysql_handle_derived(lex, &mysql_derived_prepare))
 
2125
    return true;
 
2126
  return false;
 
2127
}
 
2128
 
 
2129
bool Session::rm_temporary_table(plugin::StorageEngine *base, char *path)
 
2130
{
 
2131
  bool error=0;
 
2132
 
1961
2133
  assert(base);
1962
2134
 
1963
 
  if (not plugin::StorageEngine::dropTable(*static_cast<Session *>(this), *base, identifier, error))
1964
 
  {
1965
 
    std::string path;
1966
 
    identifier.getSQLPath(path);
1967
 
    errmsg_printf(error::WARN, _("Could not remove temporary table: '%s', error: %d"),
1968
 
                  path.c_str(), error);
1969
 
 
1970
 
    return true;
1971
 
  }
1972
 
 
1973
 
  return false;
1974
 
}
1975
 
 
1976
 
/**
1977
 
  @note this will be removed, I am looking through Hudson to see if it is finding
1978
 
  any tables that are missed during cleanup.
1979
 
*/
1980
 
void Open_tables_state::dumpTemporaryTableNames(const char *foo)
1981
 
{
1982
 
  Table *table;
1983
 
 
1984
 
  if (not temporary_tables)
1985
 
    return;
1986
 
 
1987
 
  cerr << "Begin Run: " << foo << "\n";
1988
 
  for (table= temporary_tables; table; table= table->getNext())
1989
 
  {
1990
 
    bool have_proto= false;
1991
 
 
1992
 
    message::Table *proto= table->getShare()->getTableMessage();
1993
 
    if (table->getShare()->getTableMessage())
1994
 
      have_proto= true;
1995
 
 
1996
 
    const char *answer= have_proto ? "true" : "false";
1997
 
 
1998
 
    if (have_proto)
1999
 
    {
2000
 
      cerr << "\tTable Name " << table->getShare()->getSchemaName() << "." << table->getShare()->getTableName() << " : " << answer << "\n";
2001
 
      cerr << "\t\t Proto " << proto->schema() << " " << proto->name() << "\n";
2002
 
    }
2003
 
    else
2004
 
    {
2005
 
      cerr << "\tTabl;e Name " << table->getShare()->getSchemaName() << "." << table->getShare()->getTableName() << " : " << answer << "\n";
2006
 
    }
2007
 
  }
2008
 
}
2009
 
 
2010
 
table::Singular *Session::getInstanceTable()
2011
 
{
2012
 
  temporary_shares.push_back(new table::Singular()); // This will not go into the tableshare cache, so no key is used.
2013
 
 
2014
 
  table::Singular *tmp_share= temporary_shares.back();
2015
 
 
2016
 
  assert(tmp_share);
2017
 
 
2018
 
  return tmp_share;
2019
 
}
2020
 
 
2021
 
 
2022
 
/**
2023
 
  Create a reduced Table object with properly set up Field list from a
2024
 
  list of field definitions.
2025
 
 
2026
 
    The created table doesn't have a table Cursor associated with
2027
 
    it, has no keys, no group/distinct, no copy_funcs array.
2028
 
    The sole purpose of this Table object is to use the power of Field
2029
 
    class to read/write data to/from table->getInsertRecord(). Then one can store
2030
 
    the record in any container (RB tree, hash, etc).
2031
 
    The table is created in Session mem_root, so are the table's fields.
2032
 
    Consequently, if you don't BLOB fields, you don't need to free it.
2033
 
 
2034
 
  @param session         connection handle
2035
 
  @param field_list  list of column definitions
2036
 
 
2037
 
  @return
2038
 
    0 if out of memory, Table object in case of success
2039
 
*/
2040
 
table::Singular *Session::getInstanceTable(List<CreateField> &field_list)
2041
 
{
2042
 
  temporary_shares.push_back(new table::Singular(this, field_list)); // This will not go into the tableshare cache, so no key is used.
2043
 
 
2044
 
  table::Singular *tmp_share= temporary_shares.back();
2045
 
 
2046
 
  assert(tmp_share);
2047
 
 
2048
 
  return tmp_share;
2049
 
}
2050
 
 
2051
 
namespace display  {
2052
 
 
2053
 
static const std::string NONE= "NONE";
2054
 
static const std::string GOT_GLOBAL_READ_LOCK= "HAS GLOBAL READ LOCK";
2055
 
static const std::string MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT= "HAS GLOBAL READ LOCK WITH BLOCKING COMMIT";
2056
 
 
2057
 
const std::string &type(drizzled::Session::global_read_lock_t type)
2058
 
{
2059
 
  switch (type) {
2060
 
    default:
2061
 
    case Session::NONE:
2062
 
      return NONE;
2063
 
    case Session::GOT_GLOBAL_READ_LOCK:
2064
 
      return GOT_GLOBAL_READ_LOCK;
2065
 
    case Session::MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT:
2066
 
      return MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT;
2067
 
  }
2068
 
}
2069
 
 
2070
 
size_t max_string_length(drizzled::Session::global_read_lock_t)
2071
 
{
2072
 
  return MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT.size();
2073
 
}
2074
 
 
2075
 
} /* namespace display */
2076
 
 
2077
 
} /* namespace drizzled */
 
2135
  if (delete_table_proto_file(path))
 
2136
    error=1;
 
2137
 
 
2138
  if (base->doDropTable(*this, path))
 
2139
  {
 
2140
    error=1;
 
2141
    errmsg_printf(ERRMSG_LVL_WARN, _("Could not remove temporary table: '%s', error: %d"),
 
2142
                  path, my_errno);
 
2143
  }
 
2144
  return(error);
 
2145
}
 
2146
 
 
2147