~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/sql_class.cc

  • Committer: Monty Taylor
  • Date: 2008-10-23 00:05:28 UTC
  • Revision ID: monty@inaugust.com-20081023000528-grdvrd8c4058nutm
Moved my_handler to myisam, which is where it actually belongs.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
 
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3
 
 *
4
 
 *  Copyright (C) 2008 Sun Microsystems
5
 
 *
6
 
 *  This program is free software; you can redistribute it and/or modify
7
 
 *  it under the terms of the GNU General Public License as published by
8
 
 *  the Free Software Foundation; version 2 of the License.
9
 
 *
10
 
 *  This program is distributed in the hope that it will be useful,
11
 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 
 *  GNU General Public License for more details.
14
 
 *
15
 
 *  You should have received a copy of the GNU General Public License
16
 
 *  along with this program; if not, write to the Free Software
17
 
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
 
 */
19
 
 
20
 
/**
21
 
 * @file Implementation of the Session class and API
22
 
 */
23
 
 
24
 
#include "config.h"
25
 
#include <drizzled/session.h>
26
 
#include "drizzled/session_list.h"
 
1
/* Copyright (C) 2000-2006 MySQL AB
 
2
 
 
3
   This program is free software; you can redistribute it and/or modify
 
4
   it under the terms of the GNU General Public License as published by
 
5
   the Free Software Foundation; version 2 of the License.
 
6
 
 
7
   This program is distributed in the hope that it will be useful,
 
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
10
   GNU General Public License for more details.
 
11
 
 
12
   You should have received a copy of the GNU General Public License
 
13
   along with this program; if not, write to the Free Software
 
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
15
 
 
16
 
 
17
/*****************************************************************************
 
18
**
 
19
** This file implements classes defined in sql_class.h
 
20
** Especially the classes to handle a result from a select
 
21
**
 
22
*****************************************************************************/
 
23
#include <drizzled/server_includes.h>
 
24
#include "rpl_rli.h"
 
25
#include "rpl_record.h"
 
26
#include "log_event.h"
27
27
#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/probes.h"
45
 
#include "drizzled/table_proto.h"
46
 
#include "drizzled/db.h"
47
 
#include "drizzled/pthread_globals.h"
48
 
#include "drizzled/transaction_services.h"
49
 
#include "drizzled/drizzled.h"
50
 
 
51
 
#include "drizzled/table_share_instance.h"
52
 
 
53
 
#include "plugin/myisam/myisam.h"
54
 
#include "drizzled/internal/iocache.h"
55
 
#include "drizzled/internal/thread_var.h"
56
 
#include "drizzled/plugin/event_observer.h"
57
 
 
58
 
#include <fcntl.h>
59
 
#include <algorithm>
60
 
#include <climits>
61
 
#include "boost/filesystem.hpp" 
62
 
 
63
 
using namespace std;
64
 
 
65
 
namespace fs=boost::filesystem;
66
 
namespace drizzled
67
 
{
 
28
#include <mysys/thr_alarm.h>
 
29
#include <mysys/mysys_err.h>
 
30
#include <drizzled/drizzled_error_messages.h>
 
31
#include <drizzled/innodb_plugin_extras.h>
68
32
 
69
33
/*
70
34
  The following is used to initialise Table_ident with a internal
75
39
 
76
40
const char * const Session::DEFAULT_WHERE= "field list";
77
41
 
 
42
 
 
43
/*****************************************************************************
 
44
** Instansiate templates
 
45
*****************************************************************************/
 
46
 
 
47
#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
 
48
/* Used templates */
 
49
template class List<Key>;
 
50
template class List_iterator<Key>;
 
51
template class List<Key_part_spec>;
 
52
template class List_iterator<Key_part_spec>;
 
53
template class List<Alter_drop>;
 
54
template class List_iterator<Alter_drop>;
 
55
template class List<Alter_column>;
 
56
template class List_iterator<Alter_column>;
 
57
#endif
 
58
 
 
59
/****************************************************************************
 
60
** User variables
 
61
****************************************************************************/
 
62
 
 
63
extern "C" unsigned char *get_var_key(user_var_entry *entry, size_t *length,
 
64
                              bool not_used __attribute__((unused)))
 
65
{
 
66
  *length= entry->name.length;
 
67
  return (unsigned char*) entry->name.str;
 
68
}
 
69
 
 
70
extern "C" void free_user_var(user_var_entry *entry)
 
71
{
 
72
  char *pos= (char*) entry+ALIGN_SIZE(sizeof(*entry));
 
73
  if (entry->value && entry->value != pos)
 
74
    free(entry->value);
 
75
  free((char*) entry);
 
76
}
 
77
 
78
78
bool Key_part_spec::operator==(const Key_part_spec& other) const
79
79
{
80
80
  return length == other.length &&
82
82
         !strcmp(field_name.str, other.field_name.str);
83
83
}
84
84
 
85
 
Open_tables_state::Open_tables_state(uint64_t version_arg) :
86
 
  version(version_arg)
87
 
{
88
 
  open_tables= temporary_tables= derived_tables= NULL;
89
 
  extra_lock= lock= NULL;
 
85
/**
 
86
  Construct an (almost) deep copy of this key. Only those
 
87
  elements that are known to never change are not copied.
 
88
  If out of memory, a partial copy is returned and an error is set
 
89
  in Session.
 
90
*/
 
91
 
 
92
Key::Key(const Key &rhs, MEM_ROOT *mem_root)
 
93
  :type(rhs.type),
 
94
  key_create_info(rhs.key_create_info),
 
95
  columns(rhs.columns, mem_root),
 
96
  name(rhs.name),
 
97
  generated(rhs.generated)
 
98
{
 
99
  list_copy_and_replace_each_value(columns, mem_root);
 
100
}
 
101
 
 
102
/**
 
103
  Construct an (almost) deep copy of this foreign key. Only those
 
104
  elements that are known to never change are not copied.
 
105
  If out of memory, a partial copy is returned and an error is set
 
106
  in Session.
 
107
*/
 
108
 
 
109
Foreign_key::Foreign_key(const Foreign_key &rhs, MEM_ROOT *mem_root)
 
110
  :Key(rhs),
 
111
  ref_table(rhs.ref_table),
 
112
  ref_columns(rhs.ref_columns),
 
113
  delete_opt(rhs.delete_opt),
 
114
  update_opt(rhs.update_opt),
 
115
  match_opt(rhs.match_opt)
 
116
{
 
117
  list_copy_and_replace_each_value(ref_columns, mem_root);
 
118
}
 
119
 
 
120
/*
 
121
  Test if a foreign key (= generated key) is a prefix of the given key
 
122
  (ignoring key name, key type and order of columns)
 
123
 
 
124
  NOTES:
 
125
    This is only used to test if an index for a FOREIGN KEY exists
 
126
 
 
127
  IMPLEMENTATION
 
128
    We only compare field names
 
129
 
 
130
  RETURN
 
131
    0   Generated key is a prefix of other key
 
132
    1   Not equal
 
133
*/
 
134
 
 
135
bool foreign_key_prefix(Key *a, Key *b)
 
136
{
 
137
  /* Ensure that 'a' is the generated key */
 
138
  if (a->generated)
 
139
  {
 
140
    if (b->generated && a->columns.elements > b->columns.elements)
 
141
      std::swap(a, b);                       // Put shorter key in 'a'
 
142
  }
 
143
  else
 
144
  {
 
145
    if (!b->generated)
 
146
      return true;                              // No foreign key
 
147
    std::swap(a, b);                       // Put generated key in 'a'
 
148
  }
 
149
 
 
150
  /* Test if 'a' is a prefix of 'b' */
 
151
  if (a->columns.elements > b->columns.elements)
 
152
    return true;                                // Can't be prefix
 
153
 
 
154
  List_iterator<Key_part_spec> col_it1(a->columns);
 
155
  List_iterator<Key_part_spec> col_it2(b->columns);
 
156
  const Key_part_spec *col1, *col2;
 
157
 
 
158
#ifdef ENABLE_WHEN_INNODB_CAN_HANDLE_SWAPED_FOREIGN_KEY_COLUMNS
 
159
  while ((col1= col_it1++))
 
160
  {
 
161
    bool found= 0;
 
162
    col_it2.rewind();
 
163
    while ((col2= col_it2++))
 
164
    {
 
165
      if (*col1 == *col2)
 
166
      {
 
167
        found= true;
 
168
        break;
 
169
      }
 
170
    }
 
171
    if (!found)
 
172
      return true;                              // Error
 
173
  }
 
174
  return false;                                 // Is prefix
 
175
#else
 
176
  while ((col1= col_it1++))
 
177
  {
 
178
    col2= col_it2++;
 
179
    if (!(*col1 == *col2))
 
180
      return true;
 
181
  }
 
182
  return false;                                 // Is prefix
 
183
#endif
 
184
}
 
185
 
 
186
 
 
187
/*
 
188
  Check if the foreign key options are compatible with columns
 
189
  on which the FK is created.
 
190
 
 
191
  RETURN
 
192
    0   Key valid
 
193
    1   Key invalid
 
194
*/
 
195
bool Foreign_key::validate(List<Create_field> &table_fields)
 
196
{
 
197
  Create_field  *sql_field;
 
198
  Key_part_spec *column;
 
199
  List_iterator<Key_part_spec> cols(columns);
 
200
  List_iterator<Create_field> it(table_fields);
 
201
  while ((column= cols++))
 
202
  {
 
203
    it.rewind();
 
204
    while ((sql_field= it++) &&
 
205
           my_strcasecmp(system_charset_info,
 
206
                         column->field_name.str,
 
207
                         sql_field->field_name)) {}
 
208
    if (!sql_field)
 
209
    {
 
210
      my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), column->field_name.str);
 
211
      return true;
 
212
    }
 
213
    if (type == Key::FOREIGN_KEY && sql_field->vcol_info)
 
214
    {
 
215
      if (delete_opt == FK_OPTION_SET_NULL)
 
216
      {
 
217
        my_error(ER_WRONG_FK_OPTION_FOR_VIRTUAL_COLUMN, MYF(0), 
 
218
                 "ON DELETE SET NULL");
 
219
        return true;
 
220
      }
 
221
      if (update_opt == FK_OPTION_SET_NULL)
 
222
      {
 
223
        my_error(ER_WRONG_FK_OPTION_FOR_VIRTUAL_COLUMN, MYF(0), 
 
224
                 "ON UPDATE SET NULL");
 
225
        return true;
 
226
      }
 
227
      if (update_opt == FK_OPTION_CASCADE)
 
228
      {
 
229
        my_error(ER_WRONG_FK_OPTION_FOR_VIRTUAL_COLUMN, MYF(0), 
 
230
                 "ON UPDATE CASCADE");
 
231
        return true;
 
232
      }
 
233
    }
 
234
  }
 
235
  return false;
 
236
}
 
237
 
 
238
 
 
239
/****************************************************************************
 
240
** Thread specific functions
 
241
****************************************************************************/
 
242
 
 
243
Open_tables_state::Open_tables_state(ulong version_arg)
 
244
  :version(version_arg), state_flags(0U)
 
245
{
 
246
  reset_open_tables_state();
90
247
}
91
248
 
92
249
/*
93
250
  The following functions form part of the C plugin API
94
251
*/
95
 
int mysql_tmpfile(const char *prefix)
 
252
 
 
253
extern "C" int mysql_tmpfile(const char *prefix)
96
254
{
97
255
  char filename[FN_REFLEN];
98
 
  int fd = internal::create_temp_file(filename, drizzle_tmpdir.c_str(), prefix, MYF(MY_WME));
 
256
  File fd = create_temp_file(filename, mysql_tmpdir, prefix,
 
257
                             O_CREAT | O_EXCL | O_RDWR,
 
258
                             MYF(MY_WME));
99
259
  if (fd >= 0) {
100
260
    unlink(filename);
101
261
  }
103
263
  return fd;
104
264
}
105
265
 
 
266
 
 
267
extern "C"
 
268
int session_in_lock_tables(const Session *session)
 
269
{
 
270
  return test(session->in_lock_tables);
 
271
}
 
272
 
 
273
 
 
274
extern "C"
106
275
int session_tablespace_op(const Session *session)
107
276
{
108
277
  return test(session->tablespace_op);
109
278
}
110
279
 
 
280
 
111
281
/**
112
282
   Set the process info field of the Session structure.
113
283
 
116
286
 
117
287
   @see Session::set_proc_info
118
288
 */
119
 
void set_session_proc_info(Session *session, const char *info)
 
289
extern "C" void
 
290
set_session_proc_info(Session *session, const char *info)
120
291
{
121
292
  session->set_proc_info(info);
122
293
}
123
294
 
 
295
extern "C"
124
296
const char *get_session_proc_info(Session *session)
125
297
{
126
298
  return session->get_proc_info();
127
299
}
128
300
 
129
 
void **Session::getEngineData(const plugin::MonitoredInTransaction *monitored)
130
 
{
131
 
  return static_cast<void **>(&ha_data[monitored->getId()].ha_ptr);
132
 
}
133
 
 
134
 
ResourceContext *Session::getResourceContext(const plugin::MonitoredInTransaction *monitored,
135
 
                                             size_t index)
136
 
{
137
 
  return &ha_data[monitored->getId()].resource_context[index];
138
 
}
139
 
 
 
301
extern "C"
 
302
void **session_ha_data(const Session *session, const struct handlerton *hton)
 
303
{
 
304
  return (void **) &session->ha_data[hton->slot].ha_ptr;
 
305
}
 
306
 
 
307
extern "C"
140
308
int64_t session_test_options(const Session *session, int64_t test_options)
141
309
{
142
310
  return session->options & test_options;
143
311
}
144
312
 
 
313
extern "C"
145
314
int session_sql_command(const Session *session)
146
315
{
147
316
  return (int) session->lex->sql_command;
148
317
}
149
318
 
150
 
enum_tx_isolation session_tx_isolation(const Session *session)
151
 
{
152
 
  return (enum_tx_isolation)session->variables.tx_isolation;
153
 
}
154
 
 
155
 
Session::Session(plugin::Client *client_arg) :
156
 
  Open_tables_state(refresh_version),
157
 
  mem_root(&main_mem_root),
158
 
  lex(&main_lex),
159
 
  query(),
160
 
  client(client_arg),
161
 
  scheduler(NULL),
162
 
  scheduler_arg(NULL),
163
 
  lock_id(&main_lock_id),
164
 
  user_time(0),
165
 
  ha_data(plugin::num_trx_monitored_objects),
166
 
  arg_of_last_insert_id_function(false),
167
 
  first_successful_insert_id_in_prev_stmt(0),
168
 
  first_successful_insert_id_in_cur_stmt(0),
169
 
  limit_found_rows(0),
170
 
  global_read_lock(0),
171
 
  some_tables_deleted(false),
172
 
  no_errors(false),
173
 
  password(false),
174
 
  is_fatal_error(false),
175
 
  transaction_rollback_request(false),
176
 
  is_fatal_sub_stmt_error(0),
177
 
  derived_tables_processing(false),
178
 
  tablespace_op(false),
179
 
  m_lip(NULL),
180
 
  cached_table(0),
181
 
  transaction_message(NULL),
182
 
  statement_message(NULL),
183
 
  session_event_observers(NULL),
184
 
  use_usage(false)
185
 
{
186
 
  memset(process_list_info, 0, PROCESS_LIST_WIDTH);
187
 
  client->setSession(this);
 
319
extern "C"
 
320
int session_tx_isolation(const Session *session)
 
321
{
 
322
  return (int) session->variables.tx_isolation;
 
323
}
 
324
 
 
325
extern "C"
 
326
void session_inc_row_count(Session *session)
 
327
{
 
328
  session->row_count++;
 
329
}
 
330
 
 
331
/**
 
332
  Clear this diagnostics area. 
 
333
 
 
334
  Normally called at the end of a statement.
 
335
*/
 
336
 
 
337
void
 
338
Diagnostics_area::reset_diagnostics_area()
 
339
{
 
340
  can_overwrite_status= false;
 
341
  /** Don't take chances in production */
 
342
  m_message[0]= '\0';
 
343
  m_sql_errno= 0;
 
344
  m_server_status= 0;
 
345
  m_affected_rows= 0;
 
346
  m_last_insert_id= 0;
 
347
  m_total_warn_count= 0;
 
348
  is_sent= false;
 
349
  /** Tiny reset in debug mode to see garbage right away */
 
350
  m_status= DA_EMPTY;
 
351
}
 
352
 
 
353
 
 
354
/**
 
355
  Set OK status -- ends commands that do not return a
 
356
  result set, e.g. INSERT/UPDATE/DELETE.
 
357
*/
 
358
 
 
359
void
 
360
Diagnostics_area::set_ok_status(Session *session, ha_rows affected_rows_arg,
 
361
                                uint64_t last_insert_id_arg,
 
362
                                const char *message_arg)
 
363
{
 
364
  assert(! is_set());
 
365
  /*
 
366
    In production, refuse to overwrite an error or a custom response
 
367
    with an OK packet.
 
368
  */
 
369
  if (is_error() || is_disabled())
 
370
    return;
 
371
  /** Only allowed to report success if has not yet reported an error */
 
372
 
 
373
  m_server_status= session->server_status;
 
374
  m_total_warn_count= session->total_warn_count;
 
375
  m_affected_rows= affected_rows_arg;
 
376
  m_last_insert_id= last_insert_id_arg;
 
377
  if (message_arg)
 
378
    strmake(m_message, message_arg, sizeof(m_message) - 1);
 
379
  else
 
380
    m_message[0]= '\0';
 
381
  m_status= DA_OK;
 
382
}
 
383
 
 
384
 
 
385
/**
 
386
  Set EOF status.
 
387
*/
 
388
 
 
389
void
 
390
Diagnostics_area::set_eof_status(Session *session)
 
391
{
 
392
  /** Only allowed to report eof if has not yet reported an error */
 
393
 
 
394
  assert(! is_set());
 
395
  /*
 
396
    In production, refuse to overwrite an error or a custom response
 
397
    with an EOF packet.
 
398
  */
 
399
  if (is_error() || is_disabled())
 
400
    return;
 
401
 
 
402
  m_server_status= session->server_status;
 
403
  /*
 
404
    If inside a stored procedure, do not return the total
 
405
    number of warnings, since they are not available to the client
 
406
    anyway.
 
407
  */
 
408
  m_total_warn_count= session->total_warn_count;
 
409
 
 
410
  m_status= DA_EOF;
 
411
}
 
412
 
 
413
/**
 
414
  Set ERROR status.
 
415
*/
 
416
 
 
417
void
 
418
Diagnostics_area::set_error_status(Session *session __attribute__((unused)),
 
419
                                   uint32_t sql_errno_arg,
 
420
                                   const char *message_arg)
 
421
{
 
422
  /*
 
423
    Only allowed to report error if has not yet reported a success
 
424
    The only exception is when we flush the message to the client,
 
425
    an error can happen during the flush.
 
426
  */
 
427
  assert(! is_set() || can_overwrite_status);
 
428
  /*
 
429
    In production, refuse to overwrite a custom response with an
 
430
    ERROR packet.
 
431
  */
 
432
  if (is_disabled())
 
433
    return;
 
434
 
 
435
  m_sql_errno= sql_errno_arg;
 
436
  strmake(m_message, message_arg, sizeof(m_message) - 1);
 
437
 
 
438
  m_status= DA_ERROR;
 
439
}
 
440
 
 
441
 
 
442
/**
 
443
  Mark the diagnostics area as 'DISABLED'.
 
444
 
 
445
  This is used in rare cases when the COM_ command at hand sends a response
 
446
  in a custom format. One example is the query cache, another is
 
447
  COM_STMT_PREPARE.
 
448
*/
 
449
 
 
450
void
 
451
Diagnostics_area::disable_status()
 
452
{
 
453
  assert(! is_set());
 
454
  m_status= DA_DISABLED;
 
455
}
 
456
 
 
457
 
 
458
Session::Session()
 
459
   :Statement(&main_lex, &main_mem_root,
 
460
              /* statement id */ 0),
 
461
   Open_tables_state(refresh_version), rli_fake(0),
 
462
   lock_id(&main_lock_id),
 
463
   user_time(0),
 
464
   binlog_table_maps(0), binlog_flags(0UL),
 
465
   arg_of_last_insert_id_function(false),
 
466
   first_successful_insert_id_in_prev_stmt(0),
 
467
   first_successful_insert_id_in_prev_stmt_for_binlog(0),
 
468
   first_successful_insert_id_in_cur_stmt(0),
 
469
   stmt_depends_on_first_successful_insert_id_in_prev_stmt(false),
 
470
   global_read_lock(0),
 
471
   is_fatal_error(0),
 
472
   transaction_rollback_request(0),
 
473
   is_fatal_sub_stmt_error(0),
 
474
   rand_used(0),
 
475
   time_zone_used(0),
 
476
   in_lock_tables(0),
 
477
   derived_tables_processing(false),
 
478
   m_lip(NULL)
 
479
{
 
480
  ulong tmp;
188
481
 
189
482
  /*
190
483
    Pass nominal parameters to init_alloc_root only to ensure that
191
484
    the destructor works OK in case of an error. The main_mem_root
192
485
    will be re-initialized in init_for_queries().
193
486
  */
194
 
  memory::init_sql_alloc(&main_mem_root, memory::ROOT_MIN_BLOCK_SIZE, 0);
195
 
  thread_stack= NULL;
196
 
  count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL;
 
487
  init_sql_alloc(&main_mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0);
 
488
  thread_stack= 0;
 
489
  catalog= (char*)"std"; // the only catalog we have for now
 
490
  main_security_ctx.init();
 
491
  security_ctx= &main_security_ctx;
 
492
  some_tables_deleted=no_errors=password= 0;
 
493
  query_start_used= 0;
 
494
  count_cuted_fields= CHECK_FIELD_IGNORE;
197
495
  killed= NOT_KILLED;
198
 
  col_access= 0;
199
 
  tmp_table= 0;
200
 
  used_tables= 0;
 
496
  col_access=0;
 
497
  is_slave_error= thread_specific_used= false;
 
498
  hash_clear(&handler_tables_hash);
 
499
  tmp_table=0;
 
500
  used_tables=0;
201
501
  cuted_fields= sent_row_count= row_count= 0L;
 
502
  limit_found_rows= 0;
202
503
  row_count_func= -1;
203
504
  statement_id_counter= 0UL;
204
505
  // Must be reset to handle error with Session's created for init of mysqld
206
507
  start_time=(time_t) 0;
207
508
  start_utime= 0L;
208
509
  utime_after_lock= 0L;
 
510
  current_linfo =  0;
 
511
  slave_thread = 0;
209
512
  memset(&variables, 0, sizeof(variables));
210
513
  thread_id= 0;
 
514
  one_shot_set= 0;
211
515
  file_id = 0;
212
516
  query_id= 0;
213
 
  warn_query_id= 0;
214
 
  mysys_var= 0;
215
 
  scoreboard_index= -1;
 
517
  warn_id= 0;
 
518
  db_charset= global_system_variables.collation_database;
 
519
  memset(ha_data, 0, sizeof(ha_data));
 
520
  mysys_var=0;
 
521
  binlog_evt_union.do_union= false;
216
522
  dbug_sentry=Session_SENTRY_MAGIC;
217
 
  cleanup_done= abort_on_warning= no_warnings_for_error= false;  
218
 
 
219
 
  /* query_cache init */
220
 
  query_cache_key= "";
221
 
  resultset= NULL;
 
523
  net.vio=0;
 
524
  client_capabilities= 0;                       // minimalistic client
 
525
  system_thread= NON_SYSTEM_THREAD;
 
526
  cleanup_done= abort_on_warning= no_warnings_for_error= 0;
 
527
  peer_port= 0;                                 // For SHOW PROCESSLIST
 
528
  transaction.m_pending_rows_event= 0;
 
529
  transaction.on= 1;
 
530
  pthread_mutex_init(&LOCK_delete, MY_MUTEX_INIT_FAST);
222
531
 
223
532
  /* Variables with default values */
224
533
  proc_info="login";
225
534
  where= Session::DEFAULT_WHERE;
226
 
  command= COM_CONNECT;
227
 
 
228
 
  plugin_sessionvar_init(this);
229
 
  /*
230
 
    variables= global_system_variables above has reset
231
 
    variables.pseudo_thread_id to 0. We need to correct it here to
232
 
    avoid temporary tables replication failure.
233
 
  */
234
 
  variables.pseudo_thread_id= thread_id;
235
 
  server_status= SERVER_STATUS_AUTOCOMMIT;
236
 
  options= session_startup_options;
237
 
 
238
 
  if (variables.max_join_size == HA_POS_ERROR)
239
 
    options |= OPTION_BIG_SELECTS;
240
 
  else
241
 
    options &= ~OPTION_BIG_SELECTS;
242
 
 
243
 
  open_options=ha_open_options;
244
 
  update_lock_default= TL_WRITE;
245
 
  session_tx_isolation= (enum_tx_isolation) variables.tx_isolation;
246
 
  warn_list.empty();
247
 
  memset(warn_count, 0, sizeof(warn_count));
248
 
  total_warn_count= 0;
249
 
  memset(&status_var, 0, sizeof(status_var));
250
 
 
 
535
  server_id = ::server_id;
 
536
  slave_net = 0;
 
537
  command=COM_CONNECT;
 
538
  *scramble= '\0';
 
539
 
 
540
  init();
251
541
  /* Initialize sub structures */
252
 
  memory::init_sql_alloc(&warn_root, WARN_ALLOC_BLOCK_SIZE, WARN_ALLOC_PREALLOC_SIZE);
253
 
 
 
542
  init_sql_alloc(&warn_root, WARN_ALLOC_BLOCK_SIZE, WARN_ALLOC_PREALLOC_SIZE);
 
543
  user_connect=(USER_CONN *)0;
 
544
  hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0,
 
545
            (hash_get_key) get_var_key,
 
546
            (hash_free_key) free_user_var, 0);
 
547
 
 
548
  /* For user vars replication*/
 
549
  if (opt_bin_log)
 
550
    my_init_dynamic_array(&user_var_events,
 
551
                          sizeof(BINLOG_USER_VAR_EVENT *), 16, 16);
 
552
  else
 
553
    memset(&user_var_events, 0, sizeof(user_var_events));
 
554
 
 
555
  /* Protocol */
 
556
  protocol= &protocol_text;                     // Default protocol
 
557
  protocol_text.init(this);
 
558
 
 
559
  tablespace_op= false;
 
560
  tmp= sql_rnd();
 
561
  randominit(&rand, tmp + (ulong) &rand, tmp + (ulong) ::global_query_id);
254
562
  substitute_null_with_insert_id = false;
255
 
  lock_info.init(); /* safety: will be reset after start */
 
563
  thr_lock_info_init(&lock_info); /* safety: will be reset after start */
256
564
  thr_lock_owner_init(&main_lock_id, &lock_info);
257
565
 
258
566
  m_internal_handler= NULL;
259
 
  
260
 
  plugin::EventObserver::registerSessionEvents(*this); 
261
567
}
262
568
 
263
 
void Session::free_items()
264
 
{
265
 
  Item *next;
266
 
  /* This works because items are allocated with memory::sql_alloc() */
267
 
  for (; free_list; free_list= next)
268
 
  {
269
 
    next= free_list->next;
270
 
    free_list->delete_self();
271
 
  }
272
 
}
273
569
 
274
570
void Session::push_internal_handler(Internal_error_handler *handler)
275
571
{
281
577
  m_internal_handler= handler;
282
578
}
283
579
 
 
580
 
284
581
bool Session::handle_error(uint32_t sql_errno, const char *message,
285
582
                       DRIZZLE_ERROR::enum_warning_level level)
286
583
{
292
589
  return false;                                 // 'false', as per coding style
293
590
}
294
591
 
295
 
void Session::setAbort(bool arg)
296
 
{
297
 
  mysys_var->abort= arg;
298
 
}
299
 
 
300
 
void Session::lockOnSys()
301
 
{
302
 
  if (not mysys_var)
303
 
    return;
304
 
 
305
 
  setAbort(true);
306
 
  boost::mutex::scoped_lock scopedLock(mysys_var->mutex);
307
 
  if (mysys_var->current_cond)
308
 
  {
309
 
    mysys_var->current_mutex->lock();
310
 
    pthread_cond_broadcast(mysys_var->current_cond->native_handle());
311
 
    mysys_var->current_mutex->unlock();
312
 
  }
313
 
}
314
592
 
315
593
void Session::pop_internal_handler()
316
594
{
318
596
  m_internal_handler= NULL;
319
597
}
320
598
 
321
 
void Session::get_xid(DRIZZLE_XID *xid)
322
 
{
323
 
  *xid = *(DRIZZLE_XID *) &transaction.xid_state.xid;
324
 
}
 
599
extern "C"
 
600
void *session_alloc(Session *session, unsigned int size)
 
601
{
 
602
  return session->alloc(size);
 
603
}
 
604
 
 
605
extern "C"
 
606
void *session_calloc(Session *session, unsigned int size)
 
607
{
 
608
  return session->calloc(size);
 
609
}
 
610
 
 
611
extern "C"
 
612
char *session_strdup(Session *session, const char *str)
 
613
{
 
614
  return session->strdup(str);
 
615
}
 
616
 
 
617
extern "C"
 
618
char *session_strmake(Session *session, const char *str, unsigned int size)
 
619
{
 
620
  return session->strmake(str, size);
 
621
}
 
622
 
 
623
extern "C"
 
624
LEX_STRING *session_make_lex_string(Session *session, LEX_STRING *lex_str,
 
625
                                const char *str, unsigned int size,
 
626
                                int allocate_lex_string)
 
627
{
 
628
  return session->make_lex_string(lex_str, str, size,
 
629
                              (bool) allocate_lex_string);
 
630
}
 
631
 
 
632
extern "C"
 
633
void *session_memdup(Session *session, const void* str, unsigned int size)
 
634
{
 
635
  return session->memdup(str, size);
 
636
}
 
637
 
 
638
extern "C"
 
639
void session_get_xid(const Session *session, DRIZZLE_XID *xid)
 
640
{
 
641
  *xid = *(DRIZZLE_XID *) &session->transaction.xid_state.xid;
 
642
}
 
643
 
 
644
/*
 
645
  Init common variables that has to be reset on start and on change_user
 
646
*/
 
647
 
 
648
void Session::init(void)
 
649
{
 
650
  pthread_mutex_lock(&LOCK_global_system_variables);
 
651
  plugin_sessionvar_init(this);
 
652
  variables.time_format= date_time_format_copy((Session*) 0,
 
653
                                               variables.time_format);
 
654
  variables.date_format= date_time_format_copy((Session*) 0,
 
655
                                               variables.date_format);
 
656
  variables.datetime_format= date_time_format_copy((Session*) 0,
 
657
                                                   variables.datetime_format);
 
658
  /*
 
659
    variables= global_system_variables above has reset
 
660
    variables.pseudo_thread_id to 0. We need to correct it here to
 
661
    avoid temporary tables replication failure.
 
662
  */
 
663
  variables.pseudo_thread_id= thread_id;
 
664
  pthread_mutex_unlock(&LOCK_global_system_variables);
 
665
  server_status= SERVER_STATUS_AUTOCOMMIT;
 
666
  options= session_startup_options;
 
667
 
 
668
  if (variables.max_join_size == HA_POS_ERROR)
 
669
    options |= OPTION_BIG_SELECTS;
 
670
  else
 
671
    options &= ~OPTION_BIG_SELECTS;
 
672
 
 
673
  transaction.all.modified_non_trans_table= transaction.stmt.modified_non_trans_table= false;
 
674
  open_options=ha_open_options;
 
675
  update_lock_default= (variables.low_priority_updates ?
 
676
                        TL_WRITE_LOW_PRIORITY :
 
677
                        TL_WRITE);
 
678
  session_tx_isolation= (enum_tx_isolation) variables.tx_isolation;
 
679
  warn_list.empty();
 
680
  memset(warn_count, 0, sizeof(warn_count));
 
681
  total_warn_count= 0;
 
682
  update_charset();
 
683
  reset_current_stmt_binlog_row_based();
 
684
  memset(&status_var, 0, sizeof(status_var));
 
685
}
 
686
 
 
687
 
 
688
/*
 
689
  Init Session for query processing.
 
690
  This has to be called once before we call mysql_parse.
 
691
  See also comments in sql_class.h.
 
692
*/
 
693
 
 
694
void Session::init_for_queries()
 
695
{
 
696
  set_time(); 
 
697
  ha_enable_transaction(this,true);
 
698
 
 
699
  reset_root_defaults(mem_root, variables.query_alloc_block_size,
 
700
                      variables.query_prealloc_size);
 
701
  reset_root_defaults(&transaction.mem_root,
 
702
                      variables.trans_alloc_block_size,
 
703
                      variables.trans_prealloc_size);
 
704
  transaction.xid_state.xid.null();
 
705
  transaction.xid_state.in_session=1;
 
706
}
 
707
 
325
708
 
326
709
/* Do operations that may take a long time */
327
710
 
328
711
void Session::cleanup(void)
329
712
{
330
 
  assert(cleanup_done == false);
 
713
  assert(cleanup_done == 0);
331
714
 
332
715
  killed= KILL_CONNECTION;
333
716
#ifdef ENABLE_WHEN_BINLOG_WILL_BE_ABLE_TO_PREPARE
337
720
  }
338
721
#endif
339
722
  {
340
 
    TransactionServices &transaction_services= TransactionServices::singleton();
341
 
    transaction_services.rollbackTransaction(this, true);
 
723
    ha_rollback(this);
342
724
    xid_cache_delete(&transaction.xid_state);
343
725
  }
344
 
 
345
 
  for (UserVars::iterator iter= user_vars.begin();
346
 
       iter != user_vars.end();
347
 
       iter++)
 
726
  if (locked_tables)
348
727
  {
349
 
    user_var_entry *entry= (*iter).second;
350
 
    delete entry;
 
728
    lock=locked_tables; locked_tables=0;
 
729
    close_thread_tables(this);
351
730
  }
352
 
  user_vars.clear();
353
 
 
354
 
 
355
 
  close_temporary_tables();
356
 
 
 
731
  mysql_ha_cleanup(this);
 
732
  delete_dynamic(&user_var_events);
 
733
  hash_free(&user_vars);
 
734
  close_temporary_tables(this);
 
735
  free((char*) variables.time_format);
 
736
  free((char*) variables.date_format);
 
737
  free((char*) variables.datetime_format);
 
738
  
357
739
  if (global_read_lock)
358
740
    unlock_global_read_lock(this);
359
741
 
360
 
  cleanup_done= true;
 
742
  cleanup_done=1;
 
743
  return;
361
744
}
362
745
 
363
746
Session::~Session()
364
747
{
365
 
  this->checkSentry();
366
 
 
367
 
  if (client->isConnected())
368
 
  {
369
 
    if (global_system_variables.log_warnings)
370
 
        errmsg_printf(ERRMSG_LVL_WARN, ER(ER_FORCING_CLOSE),internal::my_progname,
371
 
                      thread_id,
372
 
                      (getSecurityContext().getUser().c_str() ?
373
 
                       getSecurityContext().getUser().c_str() : ""));
374
 
    disconnect(0, false);
375
 
  }
 
748
  Session_CHECK_SENTRY(this);
 
749
  /* Ensure that no one is using Session */
 
750
  pthread_mutex_lock(&LOCK_delete);
 
751
  pthread_mutex_unlock(&LOCK_delete);
 
752
  add_to_status(&global_status_var, &status_var);
376
753
 
377
754
  /* Close connection */
378
 
  client->close();
379
 
  delete client;
380
 
 
381
 
  if (cleanup_done == false)
 
755
  if (net.vio)
 
756
  {
 
757
    net_close(&net);
 
758
    net_end(&net);
 
759
  }
 
760
  if (!cleanup_done)
382
761
    cleanup();
383
762
 
384
 
  plugin::StorageEngine::closeConnection(this);
 
763
  ha_close_connection(this);
385
764
  plugin_sessionvar_cleanup(this);
386
765
 
387
 
  warn_root.free_root(MYF(0));
 
766
  main_security_ctx.destroy();
 
767
  if (db)
 
768
  {
 
769
    free(db);
 
770
    db= NULL;
 
771
  }
 
772
  free_root(&warn_root,MYF(0));
 
773
  free_root(&transaction.mem_root,MYF(0));
388
774
  mysys_var=0;                                  // Safety (shouldn't be needed)
 
775
  pthread_mutex_destroy(&LOCK_delete);
389
776
  dbug_sentry= Session_SENTRY_GONE;
390
 
 
391
 
  main_mem_root.free_root(MYF(0));
392
 
  currentMemRoot().release();
393
 
  currentSession().release();
394
 
 
395
 
  plugin::Logging::postEndDo(this);
396
 
  plugin::EventObserver::deregisterSessionEvents(*this); 
397
 
 
398
 
  for (PropertyMap::iterator iter= life_properties.begin(); iter != life_properties.end(); iter++)
 
777
  if (rli_fake)
399
778
  {
400
 
    delete (*iter).second;
 
779
    delete rli_fake;
 
780
    rli_fake= NULL;
401
781
  }
402
 
  life_properties.clear();
403
 
 
404
 
  /* Ensure that no one is using Session */
405
 
  LOCK_delete.unlock();
406
 
}
 
782
  
 
783
  free_root(&main_mem_root, MYF(0));
 
784
  return;
 
785
}
 
786
 
 
787
 
 
788
/*
 
789
  Add all status variables to another status variable array
 
790
 
 
791
  SYNOPSIS
 
792
   add_to_status()
 
793
   to_var       add to this array
 
794
   from_var     from this array
 
795
 
 
796
  NOTES
 
797
    This function assumes that all variables are long/ulong.
 
798
    If this assumption will change, then we have to explictely add
 
799
    the other variables after the while loop
 
800
*/
 
801
 
 
802
void add_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var)
 
803
{
 
804
  ulong *end= (ulong*) ((unsigned char*) to_var +
 
805
                        offsetof(STATUS_VAR, last_system_status_var) +
 
806
                        sizeof(ulong));
 
807
  ulong *to= (ulong*) to_var, *from= (ulong*) from_var;
 
808
 
 
809
  while (to != end)
 
810
    *(to++)+= *(from++);
 
811
}
 
812
 
 
813
/*
 
814
  Add the difference between two status variable arrays to another one.
 
815
 
 
816
  SYNOPSIS
 
817
    add_diff_to_status
 
818
    to_var       add to this array
 
819
    from_var     from this array
 
820
    dec_var      minus this array
 
821
  
 
822
  NOTE
 
823
    This function assumes that all variables are long/ulong.
 
824
*/
 
825
 
 
826
void add_diff_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var,
 
827
                        STATUS_VAR *dec_var)
 
828
{
 
829
  ulong *end= (ulong*) ((unsigned char*) to_var + offsetof(STATUS_VAR,
 
830
                                                  last_system_status_var) +
 
831
                        sizeof(ulong));
 
832
  ulong *to= (ulong*) to_var, *from= (ulong*) from_var, *dec= (ulong*) dec_var;
 
833
 
 
834
  while (to != end)
 
835
    *(to++)+= *(from++) - *(dec++);
 
836
}
 
837
 
407
838
 
408
839
void Session::awake(Session::killed_state state_to_set)
409
840
{
410
 
  this->checkSentry();
411
 
  safe_mutex_assert_owner(&LOCK_delete);
 
841
  Session_CHECK_SENTRY(this);
 
842
  safe_mutex_assert_owner(&LOCK_delete); 
412
843
 
413
844
  killed= state_to_set;
414
845
  if (state_to_set != Session::KILL_QUERY)
415
846
  {
416
 
    scheduler->killSession(this);
417
 
    DRIZZLE_CONNECTION_DONE(thread_id);
 
847
    thr_alarm_kill(thread_id);
 
848
    if (!slave_thread)
 
849
      thread_scheduler.post_kill_notification(this);
418
850
  }
419
851
  if (mysys_var)
420
852
  {
421
 
    boost::mutex::scoped_lock scopedLock(mysys_var->mutex);
 
853
    pthread_mutex_lock(&mysys_var->mutex);
 
854
    if (!system_thread)         // Don't abort locks
 
855
      mysys_var->abort=1;
422
856
    /*
423
 
      "
424
857
      This broadcast could be up in the air if the victim thread
425
858
      exits the cond in the time between read and broadcast, but that is
426
859
      ok since all we want to do is to make the victim thread get out
441
874
    */
442
875
    if (mysys_var->current_cond && mysys_var->current_mutex)
443
876
    {
444
 
      mysys_var->current_mutex->lock();
445
 
      pthread_cond_broadcast(mysys_var->current_cond->native_handle());
446
 
      mysys_var->current_mutex->unlock();
 
877
      pthread_mutex_lock(mysys_var->current_mutex);
 
878
      pthread_cond_broadcast(mysys_var->current_cond);
 
879
      pthread_mutex_unlock(mysys_var->current_mutex);
447
880
    }
 
881
    pthread_mutex_unlock(&mysys_var->mutex);
448
882
  }
 
883
  return;
449
884
}
450
885
 
451
886
/*
452
887
  Remember the location of thread info, the structure needed for
453
 
  memory::sql_alloc() and the structure for the net buffer
 
888
  sql_alloc() and the structure for the net buffer
454
889
*/
455
 
bool Session::storeGlobals()
 
890
 
 
891
bool Session::store_globals()
456
892
{
457
893
  /*
458
894
    Assert that thread_stack is initialized: it's necessary to be able
460
896
  */
461
897
  assert(thread_stack);
462
898
 
463
 
  currentSession().release();
464
 
  currentSession().reset(this);
465
 
 
466
 
  currentMemRoot().release();
467
 
  currentMemRoot().reset(&mem_root);
468
 
 
 
899
  if (pthread_setspecific(THR_Session,  this) ||
 
900
      pthread_setspecific(THR_MALLOC, &mem_root))
 
901
    return 1;
469
902
  mysys_var=my_thread_var;
470
 
 
471
903
  /*
472
904
    Let mysqld define the thread id (not mysys)
473
905
    This allows us to move Session to different threads if needed.
474
906
  */
475
907
  mysys_var->id= thread_id;
 
908
  real_id= pthread_self();                      // For debugging
476
909
 
477
910
  /*
478
911
    We have to call thr_lock_info_init() again here as Session may have been
479
912
    created in another thread
480
913
  */
481
 
  lock_info.init();
482
 
 
483
 
  return false;
 
914
  thr_lock_info_init(&lock_info);
 
915
  return 0;
484
916
}
485
917
 
 
918
 
486
919
/*
487
 
  Init Session for query processing.
488
 
  This has to be called once before we call mysql_parse.
489
 
  See also comments in session.h.
 
920
  Cleanup after query.
 
921
 
 
922
  SYNOPSIS
 
923
    Session::cleanup_after_query()
 
924
 
 
925
  DESCRIPTION
 
926
    This function is used to reset thread data to its default state.
 
927
 
 
928
  NOTE
 
929
    This function is not suitable for setting thread data to some
 
930
    non-default values, as there is only one replication thread, so
 
931
    different master threads may overwrite data of each other on
 
932
    slave.
490
933
*/
491
934
 
492
 
void Session::prepareForQueries()
493
 
{
494
 
  if (variables.max_join_size == HA_POS_ERROR)
495
 
    options |= OPTION_BIG_SELECTS;
496
 
 
497
 
  version= refresh_version;
498
 
  set_proc_info(NULL);
499
 
  command= COM_SLEEP;
500
 
  set_time();
501
 
 
502
 
  mem_root->reset_root_defaults(variables.query_alloc_block_size,
503
 
                                variables.query_prealloc_size);
504
 
  transaction.xid_state.xid.null();
505
 
  transaction.xid_state.in_session=1;
506
 
  if (use_usage)
507
 
    resetUsage();
508
 
}
509
 
 
510
 
bool Session::initGlobals()
511
 
{
512
 
  if (storeGlobals())
513
 
  {
514
 
    disconnect(ER_OUT_OF_RESOURCES, true);
515
 
    status_var.aborted_connects++;
516
 
    return true;
517
 
  }
518
 
  return false;
519
 
}
520
 
 
521
 
void Session::run()
522
 
{
523
 
  if (initGlobals() || authenticate())
524
 
  {
525
 
    disconnect(0, true);
526
 
    return;
527
 
  }
528
 
 
529
 
  prepareForQueries();
530
 
 
531
 
  while (! client->haveError() && killed != KILL_CONNECTION)
532
 
  {
533
 
    if (! executeStatement())
534
 
      break;
535
 
  }
536
 
 
537
 
  disconnect(0, true);
538
 
}
539
 
 
540
 
bool Session::schedule()
541
 
{
542
 
  scheduler= plugin::Scheduler::getScheduler();
543
 
  assert(scheduler);
544
 
 
545
 
  connection_count.increment();
546
 
 
547
 
  if (connection_count > current_global_counters.max_used_connections)
548
 
  {
549
 
    current_global_counters.max_used_connections= connection_count;
550
 
  }
551
 
 
552
 
  current_global_counters.connections++;
553
 
  thread_id= variables.pseudo_thread_id= global_thread_id++;
554
 
 
555
 
  LOCK_thread_count.lock();
556
 
  getSessionList().push_back(this);
557
 
  LOCK_thread_count.unlock();
558
 
 
559
 
  if (scheduler->addSession(this))
560
 
  {
561
 
    DRIZZLE_CONNECTION_START(thread_id);
562
 
    char error_message_buff[DRIZZLE_ERRMSG_SIZE];
563
 
 
564
 
    killed= Session::KILL_CONNECTION;
565
 
 
566
 
    status_var.aborted_connects++;
567
 
 
568
 
    /* Can't use my_error() since store_globals has not been called. */
569
 
    /* TODO replace will better error message */
570
 
    snprintf(error_message_buff, sizeof(error_message_buff),
571
 
             ER(ER_CANT_CREATE_THREAD), 1);
572
 
    client->sendError(ER_CANT_CREATE_THREAD, error_message_buff);
573
 
    return true;
574
 
  }
575
 
 
576
 
  return false;
577
 
}
578
 
 
579
 
 
580
 
const char* Session::enter_cond(boost::condition_variable &cond, boost::mutex &mutex, const char* msg)
581
 
{
582
 
  const char* old_msg = get_proc_info();
583
 
  safe_mutex_assert_owner(mutex);
584
 
  mysys_var->current_mutex = &mutex;
585
 
  mysys_var->current_cond = &cond;
586
 
  this->set_proc_info(msg);
587
 
  return old_msg;
588
 
}
589
 
 
590
 
void Session::exit_cond(const char* old_msg)
591
 
{
592
 
  /*
593
 
    Putting the mutex unlock in exit_cond() ensures that
594
 
    mysys_var->current_mutex is always unlocked _before_ mysys_var->mutex is
595
 
    locked (if that would not be the case, you'll get a deadlock if someone
596
 
    does a Session::awake() on you).
597
 
  */
598
 
  mysys_var->current_mutex->unlock();
599
 
  boost::mutex::scoped_lock scopedLock(mysys_var->mutex);
600
 
  mysys_var->current_mutex = 0;
601
 
  mysys_var->current_cond = 0;
602
 
  this->set_proc_info(old_msg);
603
 
}
604
 
 
605
 
bool Session::authenticate()
606
 
{
607
 
  lex_start(this);
608
 
  if (client->authenticate())
609
 
    return false;
610
 
 
611
 
  status_var.aborted_connects++;
612
 
 
613
 
  return true;
614
 
}
615
 
 
616
 
bool Session::checkUser(const char *passwd, uint32_t passwd_len, const char *in_db)
617
 
{
618
 
  const string passwd_str(passwd, passwd_len);
619
 
  bool is_authenticated=
620
 
    plugin::Authentication::isAuthenticated(getSecurityContext(),
621
 
                                            passwd_str);
622
 
 
623
 
  if (is_authenticated != true)
624
 
  {
625
 
    status_var.access_denied++;
626
 
    /* isAuthenticated has pushed the error message */
627
 
    return false;
628
 
  }
629
 
 
630
 
  /* Change database if necessary */
631
 
  if (in_db && in_db[0])
632
 
  {
633
 
    SchemaIdentifier identifier(in_db);
634
 
    if (mysql_change_db(this, identifier))
635
 
    {
636
 
      /* mysql_change_db() has pushed the error message. */
637
 
      return false;
638
 
    }
639
 
  }
640
 
  my_ok();
641
 
  password= test(passwd_len);          // remember for error messages
642
 
 
643
 
  /* Ready to handle queries */
644
 
  return true;
645
 
}
646
 
 
647
 
bool Session::executeStatement()
648
 
{
649
 
  char *l_packet= 0;
650
 
  uint32_t packet_length;
651
 
 
652
 
  enum enum_server_command l_command;
653
 
 
654
 
  /*
655
 
    indicator of uninitialized lex => normal flow of errors handling
656
 
    (see my_message_sql)
657
 
  */
658
 
  lex->current_select= 0;
659
 
  clear_error();
660
 
  main_da.reset_diagnostics_area();
661
 
 
662
 
  if (client->readCommand(&l_packet, &packet_length) == false)
663
 
    return false;
664
 
 
665
 
  if (killed == KILL_CONNECTION)
666
 
    return false;
667
 
 
668
 
  if (packet_length == 0)
669
 
    return true;
670
 
 
671
 
  l_command= (enum enum_server_command) (unsigned char) l_packet[0];
672
 
 
673
 
  if (command >= COM_END)
674
 
    command= COM_END;                           // Wrong command
675
 
 
676
 
  assert(packet_length);
677
 
  return ! dispatch_command(l_command, this, l_packet+1, (uint32_t) (packet_length-1));
678
 
}
679
 
 
680
 
bool Session::readAndStoreQuery(const char *in_packet, uint32_t in_packet_length)
681
 
{
682
 
  /* Remove garbage at start and end of query */
683
 
  while (in_packet_length > 0 && my_isspace(charset(), in_packet[0]))
684
 
  {
685
 
    in_packet++;
686
 
    in_packet_length--;
687
 
  }
688
 
  const char *pos= in_packet + in_packet_length; /* Point at end null */
689
 
  while (in_packet_length > 0 &&
690
 
         (pos[-1] == ';' || my_isspace(charset() ,pos[-1])))
691
 
  {
692
 
    pos--;
693
 
    in_packet_length--;
694
 
  }
695
 
 
696
 
  query.assign(in_packet, in_packet + in_packet_length);
697
 
 
698
 
  return true;
699
 
}
700
 
 
701
 
bool Session::endTransaction(enum enum_mysql_completiontype completion)
702
 
{
703
 
  bool do_release= 0;
704
 
  bool result= true;
705
 
  TransactionServices &transaction_services= TransactionServices::singleton();
706
 
 
707
 
  if (transaction.xid_state.xa_state != XA_NOTR)
708
 
  {
709
 
    my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[transaction.xid_state.xa_state]);
710
 
    return false;
711
 
  }
712
 
  switch (completion)
713
 
  {
714
 
    case COMMIT:
715
 
      /*
716
 
       * We don't use endActiveTransaction() here to ensure that this works
717
 
       * even if there is a problem with the OPTION_AUTO_COMMIT flag
718
 
       * (Which of course should never happen...)
719
 
       */
720
 
      server_status&= ~SERVER_STATUS_IN_TRANS;
721
 
      if (transaction_services.commitTransaction(this, true))
722
 
        result= false;
723
 
      options&= ~(OPTION_BEGIN);
724
 
      break;
725
 
    case COMMIT_RELEASE:
726
 
      do_release= 1; /* fall through */
727
 
    case COMMIT_AND_CHAIN:
728
 
      result= endActiveTransaction();
729
 
      if (result == true && completion == COMMIT_AND_CHAIN)
730
 
        result= startTransaction();
731
 
      break;
732
 
    case ROLLBACK_RELEASE:
733
 
      do_release= 1; /* fall through */
734
 
    case ROLLBACK:
735
 
    case ROLLBACK_AND_CHAIN:
736
 
    {
737
 
      server_status&= ~SERVER_STATUS_IN_TRANS;
738
 
      if (transaction_services.rollbackTransaction(this, true))
739
 
        result= false;
740
 
      options&= ~(OPTION_BEGIN);
741
 
      if (result == true && (completion == ROLLBACK_AND_CHAIN))
742
 
        result= startTransaction();
743
 
      break;
744
 
    }
745
 
    default:
746
 
      my_error(ER_UNKNOWN_COM_ERROR, MYF(0));
747
 
      return false;
748
 
  }
749
 
 
750
 
  if (result == false)
751
 
    my_error(killed_errno(), MYF(0));
752
 
  else if ((result == true) && do_release)
753
 
    killed= Session::KILL_CONNECTION;
754
 
 
755
 
  return result;
756
 
}
757
 
 
758
 
bool Session::endActiveTransaction()
759
 
{
760
 
  bool result= true;
761
 
  TransactionServices &transaction_services= TransactionServices::singleton();
762
 
 
763
 
  if (transaction.xid_state.xa_state != XA_NOTR)
764
 
  {
765
 
    my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[transaction.xid_state.xa_state]);
766
 
    return false;
767
 
  }
768
 
  if (options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
769
 
  {
770
 
    server_status&= ~SERVER_STATUS_IN_TRANS;
771
 
    if (transaction_services.commitTransaction(this, true))
772
 
      result= false;
773
 
  }
774
 
  options&= ~(OPTION_BEGIN);
775
 
  return result;
776
 
}
777
 
 
778
 
bool Session::startTransaction(start_transaction_option_t opt)
779
 
{
780
 
  bool result= true;
781
 
 
782
 
  if (! endActiveTransaction())
783
 
  {
784
 
    result= false;
785
 
  }
786
 
  else
787
 
  {
788
 
    options|= OPTION_BEGIN;
789
 
    server_status|= SERVER_STATUS_IN_TRANS;
790
 
 
791
 
    if (plugin::TransactionalStorageEngine::notifyStartTransaction(this, opt))
792
 
    {
793
 
      result= false;
794
 
    }
795
 
  }
796
 
 
797
 
  return result;
798
 
}
799
 
 
800
935
void Session::cleanup_after_query()
801
936
{
802
937
  /*
803
 
    Reset rand_used so that detection of calls to rand() will save random
 
938
    Reset rand_used so that detection of calls to rand() will save random 
804
939
    seeds if needed by the slave.
805
940
  */
806
941
  {
807
942
    /* Forget those values, for next binlogger: */
 
943
    stmt_depends_on_first_successful_insert_id_in_prev_stmt= 0;
808
944
    auto_inc_intervals_in_cur_stmt_for_binlog.empty();
 
945
    rand_used= 0;
809
946
  }
810
947
  if (first_successful_insert_id_in_cur_stmt > 0)
811
948
  {
812
949
    /* set what LAST_INSERT_ID() will return */
813
 
    first_successful_insert_id_in_prev_stmt= first_successful_insert_id_in_cur_stmt;
 
950
    first_successful_insert_id_in_prev_stmt= 
 
951
      first_successful_insert_id_in_cur_stmt;
814
952
    first_successful_insert_id_in_cur_stmt= 0;
815
953
    substitute_null_with_insert_id= true;
816
954
  }
817
 
  arg_of_last_insert_id_function= false;
 
955
  arg_of_last_insert_id_function= 0;
818
956
  /* Free Items that were created during this execution */
819
957
  free_items();
820
958
  /* Reset where. */
821
959
  where= Session::DEFAULT_WHERE;
822
 
 
823
 
  /* Reset the temporary shares we built */
824
 
  for (std::vector<TableShareInstance *>::iterator iter= temporary_shares.begin();
825
 
       iter != temporary_shares.end(); iter++)
826
 
  {
827
 
    delete *iter;
828
 
  }
829
 
  temporary_shares.clear();
830
960
}
831
961
 
 
962
 
832
963
/**
833
964
  Create a LEX_STRING in this connection.
834
965
 
840
971
  @return  NULL on failure, or pointer to the LEX_STRING object
841
972
*/
842
973
LEX_STRING *Session::make_lex_string(LEX_STRING *lex_str,
843
 
                                     const std::string &str,
844
 
                                     bool allocate_lex_string)
845
 
{
846
 
  return make_lex_string(lex_str, str.c_str(), str.length(), allocate_lex_string);
847
 
}
848
 
 
849
 
LEX_STRING *Session::make_lex_string(LEX_STRING *lex_str,
850
 
                                     const char* str, uint32_t length,
851
 
                                     bool allocate_lex_string)
 
974
                                 const char* str, uint32_t length,
 
975
                                 bool allocate_lex_string)
852
976
{
853
977
  if (allocate_lex_string)
854
978
    if (!(lex_str= (LEX_STRING *)alloc(sizeof(LEX_STRING))))
855
979
      return 0;
856
 
  if (!(lex_str->str= mem_root->strmake_root(str, length)))
 
980
  if (!(lex_str->str= strmake_root(mem_root, str, length)))
857
981
    return 0;
858
982
  lex_str->length= length;
859
983
  return lex_str;
860
984
}
861
985
 
 
986
 
 
987
/*
 
988
  Convert a string to another character set
 
989
 
 
990
  SYNOPSIS
 
991
    convert_string()
 
992
    to                          Store new allocated string here
 
993
    to_cs                       New character set for allocated string
 
994
    from                        String to convert
 
995
    from_length                 Length of string to convert
 
996
    from_cs                     Original character set
 
997
 
 
998
  NOTES
 
999
    to will be 0-terminated to make it easy to pass to system funcs
 
1000
 
 
1001
  RETURN
 
1002
    0   ok
 
1003
    1   End of memory.
 
1004
        In this case to->str will point to 0 and to->length will be 0.
 
1005
*/
 
1006
 
 
1007
bool Session::convert_string(LEX_STRING *to, const CHARSET_INFO * const to_cs,
 
1008
                         const char *from, uint32_t from_length,
 
1009
                         const CHARSET_INFO * const from_cs)
 
1010
{
 
1011
  size_t new_length= to_cs->mbmaxlen * from_length;
 
1012
  uint32_t dummy_errors;
 
1013
  if (!(to->str= (char*) alloc(new_length+1)))
 
1014
  {
 
1015
    to->length= 0;                              // Safety fix
 
1016
    return(1);                          // EOM
 
1017
  }
 
1018
  to->length= copy_and_convert((char*) to->str, new_length, to_cs,
 
1019
                               from, from_length, from_cs, &dummy_errors);
 
1020
  to->str[to->length]=0;                        // Safety
 
1021
  return(0);
 
1022
}
 
1023
 
 
1024
 
 
1025
/*
 
1026
  Convert string from source character set to target character set inplace.
 
1027
 
 
1028
  SYNOPSIS
 
1029
    Session::convert_string
 
1030
 
 
1031
  DESCRIPTION
 
1032
    Convert string using convert_buffer - buffer for character set 
 
1033
    conversion shared between all protocols.
 
1034
 
 
1035
  RETURN
 
1036
    0   ok
 
1037
   !0   out of memory
 
1038
*/
 
1039
 
 
1040
bool Session::convert_string(String *s, const CHARSET_INFO * const from_cs,
 
1041
                         const CHARSET_INFO * const to_cs)
 
1042
{
 
1043
  uint32_t dummy_errors;
 
1044
  if (convert_buffer.copy(s->ptr(), s->length(), from_cs, to_cs, &dummy_errors))
 
1045
    return true;
 
1046
  /* If convert_buffer >> s copying is more efficient long term */
 
1047
  if (convert_buffer.alloced_length() >= convert_buffer.length() * 2 ||
 
1048
      !s->is_alloced())
 
1049
  {
 
1050
    return s->copy(convert_buffer);
 
1051
  }
 
1052
  s->swap(convert_buffer);
 
1053
  return false;
 
1054
}
 
1055
 
 
1056
 
 
1057
/*
 
1058
  Update some cache variables when character set changes
 
1059
*/
 
1060
 
 
1061
void Session::update_charset()
 
1062
{
 
1063
  uint32_t not_used;
 
1064
  charset_is_system_charset= !String::needs_conversion(0,charset(),
 
1065
                                                       system_charset_info,
 
1066
                                                       &not_used);
 
1067
  charset_is_collation_connection= 
 
1068
    !String::needs_conversion(0,charset(),variables.collation_connection,
 
1069
                              &not_used);
 
1070
  charset_is_character_set_filesystem= 
 
1071
    !String::needs_conversion(0, charset(),
 
1072
                              variables.character_set_filesystem, &not_used);
 
1073
}
 
1074
 
 
1075
 
 
1076
/* routings to adding tables to list of changed in transaction tables */
 
1077
 
 
1078
inline static void list_include(CHANGED_TableList** prev,
 
1079
                                CHANGED_TableList* curr,
 
1080
                                CHANGED_TableList* new_table)
 
1081
{
 
1082
  if (new_table)
 
1083
  {
 
1084
    *prev = new_table;
 
1085
    (*prev)->next = curr;
 
1086
  }
 
1087
}
 
1088
 
 
1089
/* add table to list of changed in transaction tables */
 
1090
 
 
1091
void Session::add_changed_table(Table *table)
 
1092
{
 
1093
  assert((options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) &&
 
1094
              table->file->has_transactions());
 
1095
  add_changed_table(table->s->table_cache_key.str,
 
1096
                    (long) table->s->table_cache_key.length);
 
1097
  return;
 
1098
}
 
1099
 
 
1100
 
 
1101
void Session::add_changed_table(const char *key, long key_length)
 
1102
{
 
1103
  CHANGED_TableList **prev_changed = &transaction.changed_tables;
 
1104
  CHANGED_TableList *curr = transaction.changed_tables;
 
1105
 
 
1106
  for (; curr; prev_changed = &(curr->next), curr = curr->next)
 
1107
  {
 
1108
    int cmp =  (long)curr->key_length - (long)key_length;
 
1109
    if (cmp < 0)
 
1110
    {
 
1111
      list_include(prev_changed, curr, changed_table_dup(key, key_length));
 
1112
      return;
 
1113
    }
 
1114
    else if (cmp == 0)
 
1115
    {
 
1116
      cmp = memcmp(curr->key, key, curr->key_length);
 
1117
      if (cmp < 0)
 
1118
      {
 
1119
        list_include(prev_changed, curr, changed_table_dup(key, key_length));
 
1120
        return;
 
1121
      }
 
1122
      else if (cmp == 0)
 
1123
      {
 
1124
        return;
 
1125
      }
 
1126
    }
 
1127
  }
 
1128
  *prev_changed = changed_table_dup(key, key_length);
 
1129
  return;
 
1130
}
 
1131
 
 
1132
 
 
1133
CHANGED_TableList* Session::changed_table_dup(const char *key, long key_length)
 
1134
{
 
1135
  CHANGED_TableList* new_table = 
 
1136
    (CHANGED_TableList*) trans_alloc(ALIGN_SIZE(sizeof(CHANGED_TableList))+
 
1137
                                      key_length + 1);
 
1138
  if (!new_table)
 
1139
  {
 
1140
    my_error(EE_OUTOFMEMORY, MYF(ME_BELL),
 
1141
             ALIGN_SIZE(sizeof(TableList)) + key_length + 1);
 
1142
    killed= KILL_CONNECTION;
 
1143
    return 0;
 
1144
  }
 
1145
 
 
1146
  new_table->key= ((char*)new_table)+ ALIGN_SIZE(sizeof(CHANGED_TableList));
 
1147
  new_table->next = 0;
 
1148
  new_table->key_length = key_length;
 
1149
  ::memcpy(new_table->key, key, key_length);
 
1150
  return new_table;
 
1151
}
 
1152
 
 
1153
 
862
1154
int Session::send_explain_fields(select_result *result)
863
1155
{
864
1156
  List<Item> field_list;
894
1186
  }
895
1187
  item->maybe_null= 1;
896
1188
  field_list.push_back(new Item_empty_string("Extra", 255, cs));
897
 
  return (result->send_fields(field_list));
898
 
}
899
 
 
900
 
void select_result::send_error(uint32_t errcode, const char *err)
 
1189
  return (result->send_fields(field_list,
 
1190
                              Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF));
 
1191
}
 
1192
 
 
1193
 
 
1194
struct Item_change_record: public ilink
 
1195
{
 
1196
  Item **place;
 
1197
  Item *old_value;
 
1198
  /* Placement new was hidden by `new' in ilink (TODO: check): */
 
1199
  static void *operator new(size_t size __attribute__((unused)),
 
1200
                            void *mem)
 
1201
    { return mem; }
 
1202
  static void operator delete(void *ptr __attribute__((unused)),
 
1203
                              size_t size __attribute__((unused)))
 
1204
    {}
 
1205
  static void operator delete(void *ptr __attribute__((unused)),
 
1206
                              void *mem __attribute__((unused)))
 
1207
    { /* never called */ }
 
1208
};
 
1209
 
 
1210
 
 
1211
/*
 
1212
  Register an item tree tree transformation, performed by the query
 
1213
  optimizer. We need a pointer to runtime_memroot because it may be !=
 
1214
  session->mem_root (this may no longer be a true statement)
 
1215
*/
 
1216
 
 
1217
void Session::nocheck_register_item_tree_change(Item **place, Item *old_value,
 
1218
                                            MEM_ROOT *runtime_memroot)
 
1219
{
 
1220
  Item_change_record *change;
 
1221
  /*
 
1222
    Now we use one node per change, which adds some memory overhead,
 
1223
    but still is rather fast as we use alloc_root for allocations.
 
1224
    A list of item tree changes of an average query should be short.
 
1225
  */
 
1226
  void *change_mem= alloc_root(runtime_memroot, sizeof(*change));
 
1227
  if (change_mem == 0)
 
1228
  {
 
1229
    /*
 
1230
      OOM, session->fatal_error() is called by the error handler of the
 
1231
      memroot. Just return.
 
1232
    */
 
1233
    return;
 
1234
  }
 
1235
  change= new (change_mem) Item_change_record;
 
1236
  change->place= place;
 
1237
  change->old_value= old_value;
 
1238
  change_list.append(change);
 
1239
}
 
1240
 
 
1241
 
 
1242
void Session::rollback_item_tree_changes()
 
1243
{
 
1244
  I_List_iterator<Item_change_record> it(change_list);
 
1245
  Item_change_record *change;
 
1246
 
 
1247
  while ((change= it++))
 
1248
    *change->place= change->old_value;
 
1249
  /* We can forget about changes memory: it's allocated in runtime memroot */
 
1250
  change_list.empty();
 
1251
  return;
 
1252
}
 
1253
 
 
1254
 
 
1255
/*****************************************************************************
 
1256
** Functions to provide a interface to select results
 
1257
*****************************************************************************/
 
1258
 
 
1259
select_result::select_result()
 
1260
{
 
1261
  session=current_session;
 
1262
}
 
1263
 
 
1264
void select_result::send_error(uint32_t errcode,const char *err)
901
1265
{
902
1266
  my_message(errcode, err, MYF(0));
903
1267
}
904
1268
 
 
1269
 
 
1270
void select_result::cleanup()
 
1271
{
 
1272
  /* do nothing */
 
1273
}
 
1274
 
 
1275
bool select_result::check_simple_select() const
 
1276
{
 
1277
  my_error(ER_SP_BAD_CURSOR_QUERY, MYF(0));
 
1278
  return true;
 
1279
}
 
1280
 
 
1281
 
 
1282
static String default_line_term("\n",default_charset_info);
 
1283
static String default_escaped("\\",default_charset_info);
 
1284
static String default_field_term("\t",default_charset_info);
 
1285
 
 
1286
sql_exchange::sql_exchange(char *name, bool flag,
 
1287
                           enum enum_filetype filetype_arg)
 
1288
  :file_name(name), opt_enclosed(0), dumpfile(flag), skip_lines(0)
 
1289
{
 
1290
  filetype= filetype_arg;
 
1291
  field_term= &default_field_term;
 
1292
  enclosed=   line_start= &my_empty_string;
 
1293
  line_term=  &default_line_term;
 
1294
  escaped=    &default_escaped;
 
1295
  cs= NULL;
 
1296
}
 
1297
 
 
1298
bool select_send::send_fields(List<Item> &list, uint32_t flags)
 
1299
{
 
1300
  bool res;
 
1301
  if (!(res= session->protocol->send_fields(&list, flags)))
 
1302
    is_result_set_started= 1;
 
1303
  return res;
 
1304
}
 
1305
 
 
1306
void select_send::abort()
 
1307
{
 
1308
  return;
 
1309
}
 
1310
 
 
1311
 
 
1312
/** 
 
1313
  Cleanup an instance of this class for re-use
 
1314
  at next execution of a prepared statement/
 
1315
  stored procedure statement.
 
1316
*/
 
1317
 
 
1318
void select_send::cleanup()
 
1319
{
 
1320
  is_result_set_started= false;
 
1321
}
 
1322
 
 
1323
/* Send data to client. Returns 0 if ok */
 
1324
 
 
1325
bool select_send::send_data(List<Item> &items)
 
1326
{
 
1327
  if (unit->offset_limit_cnt)
 
1328
  {                                             // using limit offset,count
 
1329
    unit->offset_limit_cnt--;
 
1330
    return 0;
 
1331
  }
 
1332
 
 
1333
  /*
 
1334
    We may be passing the control from mysqld to the client: release the
 
1335
    InnoDB adaptive hash S-latch to avoid thread deadlocks if it was reserved
 
1336
    by session
 
1337
  */
 
1338
  ha_release_temporary_latches(session);
 
1339
 
 
1340
  List_iterator_fast<Item> li(items);
 
1341
  Protocol *protocol= session->protocol;
 
1342
  char buff[MAX_FIELD_WIDTH];
 
1343
  String buffer(buff, sizeof(buff), &my_charset_bin);
 
1344
 
 
1345
  protocol->prepare_for_resend();
 
1346
  Item *item;
 
1347
  while ((item=li++))
 
1348
  {
 
1349
    if (item->send(protocol, &buffer))
 
1350
    {
 
1351
      protocol->free();                         // Free used buffer
 
1352
      my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
 
1353
      break;
 
1354
    }
 
1355
  }
 
1356
  session->sent_row_count++;
 
1357
  if (session->is_error())
 
1358
  {
 
1359
    protocol->remove_last_row();
 
1360
    return(1);
 
1361
  }
 
1362
  if (session->vio_ok())
 
1363
    return(protocol->write());
 
1364
  return(0);
 
1365
}
 
1366
 
 
1367
bool select_send::send_eof()
 
1368
{
 
1369
  /* 
 
1370
    We may be passing the control from mysqld to the client: release the
 
1371
    InnoDB adaptive hash S-latch to avoid thread deadlocks if it was reserved
 
1372
    by session 
 
1373
  */
 
1374
  ha_release_temporary_latches(session);
 
1375
 
 
1376
  /* Unlock tables before sending packet to gain some speed */
 
1377
  if (session->lock)
 
1378
  {
 
1379
    mysql_unlock_tables(session, session->lock);
 
1380
    session->lock=0;
 
1381
  }
 
1382
  ::my_eof(session);
 
1383
  is_result_set_started= 0;
 
1384
  return false;
 
1385
}
 
1386
 
 
1387
 
905
1388
/************************************************************************
906
1389
  Handling writing to file
907
1390
************************************************************************/
911
1394
  my_message(errcode, err, MYF(0));
912
1395
  if (file > 0)
913
1396
  {
914
 
    (void) end_io_cache(cache);
915
 
    (void) internal::my_close(file, MYF(0));
916
 
    (void) internal::my_delete(path, MYF(0));           // Delete file on error
 
1397
    (void) end_io_cache(&cache);
 
1398
    (void) my_close(file,MYF(0));
 
1399
    (void) my_delete(path,MYF(0));              // Delete file on error
917
1400
    file= -1;
918
1401
  }
919
1402
}
921
1404
 
922
1405
bool select_to_file::send_eof()
923
1406
{
924
 
  int error= test(end_io_cache(cache));
925
 
  if (internal::my_close(file, MYF(MY_WME)))
 
1407
  int error= test(end_io_cache(&cache));
 
1408
  if (my_close(file,MYF(MY_WME)))
926
1409
    error= 1;
927
1410
  if (!error)
928
1411
  {
931
1414
      function, SELECT INTO has to have an own SQLCOM.
932
1415
      TODO: split from SQLCOM_SELECT
933
1416
    */
934
 
    session->my_ok(row_count);
 
1417
    ::my_ok(session,row_count);
935
1418
  }
936
1419
  file= -1;
937
1420
  return error;
943
1426
  /* In case of error send_eof() may be not called: close the file here. */
944
1427
  if (file >= 0)
945
1428
  {
946
 
    (void) end_io_cache(cache);
947
 
    (void) internal::my_close(file, MYF(0));
 
1429
    (void) end_io_cache(&cache);
 
1430
    (void) my_close(file,MYF(0));
948
1431
    file= -1;
949
1432
  }
950
1433
  path[0]= '\0';
951
1434
  row_count= 0;
952
1435
}
953
1436
 
954
 
select_to_file::select_to_file(file_exchange *ex)
955
 
  : exchange(ex),
956
 
    file(-1),
957
 
    cache(static_cast<internal::IO_CACHE *>(memory::sql_calloc(sizeof(internal::IO_CACHE)))),
958
 
    row_count(0L)
959
 
{
960
 
  path[0]=0;
961
 
}
962
1437
 
963
1438
select_to_file::~select_to_file()
964
1439
{
965
 
  cleanup();
 
1440
  if (file >= 0)
 
1441
  {                                     // This only happens in case of error
 
1442
    (void) end_io_cache(&cache);
 
1443
    (void) my_close(file,MYF(0));
 
1444
    file= -1;
 
1445
  }
966
1446
}
967
1447
 
968
1448
/***************************************************************************
991
1471
*/
992
1472
 
993
1473
 
994
 
static int create_file(Session *session, char *path, file_exchange *exchange, internal::IO_CACHE *cache)
 
1474
static File create_file(Session *session, char *path, sql_exchange *exchange,
 
1475
                        IO_CACHE *cache)
995
1476
{
996
 
  int file;
 
1477
  File file;
997
1478
  uint32_t option= MY_UNPACK_FILENAME | MY_RELATIVE_PATH;
998
1479
 
999
1480
#ifdef DONT_ALLOW_FULL_LOAD_DATA_PATHS
1000
1481
  option|= MY_REPLACE_DIR;                      // Force use of db directory
1001
1482
#endif
1002
1483
 
1003
 
  if (!internal::dirname_length(exchange->file_name))
 
1484
  if (!dirname_length(exchange->file_name))
1004
1485
  {
1005
 
    strcpy(path, getDataHomeCatalog().c_str());
1006
 
    strncat(path, "/", 1);
1007
 
    if (! session->db.empty())
1008
 
      strncat(path, session->db.c_str(), FN_REFLEN-getDataHomeCatalog().size());
1009
 
    (void) internal::fn_format(path, exchange->file_name, path, "", option);
 
1486
    strcpy(path, mysql_real_data_home);
 
1487
    if (session->db)
 
1488
      strncat(path, session->db, FN_REFLEN-strlen(mysql_real_data_home)-1);
 
1489
    (void) fn_format(path, exchange->file_name, path, "", option);
1010
1490
  }
1011
1491
  else
1012
 
    (void) internal::fn_format(path, exchange->file_name, getDataHomeCatalog().c_str(), "", option);
 
1492
    (void) fn_format(path, exchange->file_name, mysql_real_data_home, "", option);
1013
1493
 
1014
 
  if (opt_secure_file_priv)
 
1494
  if (opt_secure_file_priv &&
 
1495
      strncmp(opt_secure_file_priv, path, strlen(opt_secure_file_priv)))
1015
1496
  {
1016
 
    fs::path secure_file_path(fs::system_complete(fs::path(opt_secure_file_priv)));
1017
 
    fs::path target_path(fs::system_complete(fs::path(path)));
1018
 
    if (target_path.file_string().substr(0, secure_file_path.file_string().size()) != secure_file_path.file_string())
1019
 
    {
1020
 
      /* Write only allowed to dir or subdir specified by secure_file_priv */
1021
 
      my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--secure-file-priv");
1022
 
      return -1;
1023
 
    }
 
1497
    /* Write only allowed to dir or subdir specified by secure_file_priv */
 
1498
    my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--secure-file-priv");
 
1499
    return -1;
1024
1500
  }
1025
1501
 
1026
1502
  if (!access(path, F_OK))
1029
1505
    return -1;
1030
1506
  }
1031
1507
  /* Create the file world readable */
1032
 
  if ((file= internal::my_create(path, 0666, O_WRONLY|O_EXCL, MYF(MY_WME))) < 0)
 
1508
  if ((file= my_create(path, 0666, O_WRONLY|O_EXCL, MYF(MY_WME))) < 0)
1033
1509
    return file;
 
1510
#ifdef HAVE_FCHMOD
1034
1511
  (void) fchmod(file, 0666);                    // Because of umask()
1035
 
  if (init_io_cache(cache, file, 0L, internal::WRITE_CACHE, 0L, 1, MYF(MY_WME)))
 
1512
#else
 
1513
  (void) chmod(path, 0666);
 
1514
#endif
 
1515
  if (init_io_cache(cache, file, 0L, WRITE_CACHE, 0L, 1, MYF(MY_WME)))
1036
1516
  {
1037
 
    internal::my_close(file, MYF(0));
1038
 
    internal::my_delete(path, MYF(0));  // Delete file on error, it was just created
 
1517
    my_close(file, MYF(0));
 
1518
    my_delete(path, MYF(0));  // Delete file on error, it was just created 
1039
1519
    return -1;
1040
1520
  }
1041
1521
  return file;
1043
1523
 
1044
1524
 
1045
1525
int
1046
 
select_export::prepare(List<Item> &list, Select_Lex_Unit *u)
 
1526
select_export::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
1047
1527
{
1048
1528
  bool blob_flag=0;
1049
1529
  bool string_results= false, non_string_results= false;
1050
1530
  unit= u;
1051
 
  if ((uint32_t) strlen(exchange->file_name) + NAME_LEN >= FN_REFLEN)
1052
 
    strncpy(path,exchange->file_name,FN_REFLEN-1);
 
1531
  if ((uint) strlen(exchange->file_name) + NAME_LEN >= FN_REFLEN)
 
1532
    strmake(path,exchange->file_name,FN_REFLEN-1);
1053
1533
 
 
1534
  if ((file= create_file(session, path, exchange, &cache)) < 0)
 
1535
    return 1;
1054
1536
  /* Check if there is any blobs in data */
1055
1537
  {
1056
1538
    List_iterator_fast<Item> li(list);
1092
1574
      (exchange->opt_enclosed && non_string_results &&
1093
1575
       field_term_length && strchr(NUMERIC_CHARS, field_term_char)))
1094
1576
  {
1095
 
    my_error(ER_AMBIGUOUS_FIELD_TERM, MYF(0));
1096
 
    return 1;
 
1577
    push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
1578
                 ER_AMBIGUOUS_FIELD_TERM, ER(ER_AMBIGUOUS_FIELD_TERM));
 
1579
    is_ambiguous_field_term= true;
1097
1580
  }
1098
 
 
1099
 
  if ((file= create_file(session, path, exchange, cache)) < 0)
1100
 
    return 1;
 
1581
  else
 
1582
    is_ambiguous_field_term= false;
1101
1583
 
1102
1584
  return 0;
1103
1585
}
1104
1586
 
 
1587
 
 
1588
#define NEED_ESCAPING(x) ((int) (unsigned char) (x) == escape_char    || \
 
1589
                          (enclosed ? (int) (unsigned char) (x) == field_sep_char      \
 
1590
                                    : (int) (unsigned char) (x) == field_term_char) || \
 
1591
                          (int) (unsigned char) (x) == line_sep_char  || \
 
1592
                          !(x))
 
1593
 
1105
1594
bool select_export::send_data(List<Item> &items)
1106
1595
{
1107
1596
  char buff[MAX_FIELD_WIDTH],null_buff[2],space[MAX_FIELD_WIDTH];
1119
1608
  uint32_t used_length=0,items_left=items.elements;
1120
1609
  List_iterator_fast<Item> li(items);
1121
1610
 
1122
 
  if (my_b_write(cache,(unsigned char*) exchange->line_start->ptr(),
1123
 
                 exchange->line_start->length()))
 
1611
  if (my_b_write(&cache,(unsigned char*) exchange->line_start->ptr(),
 
1612
                 exchange->line_start->length()))
1124
1613
    goto err;
1125
1614
  while ((item=li++))
1126
1615
  {
1130
1619
    res=item->str_result(&tmp);
1131
1620
    if (res && enclosed)
1132
1621
    {
1133
 
      if (my_b_write(cache,(unsigned char*) exchange->enclosed->ptr(),
1134
 
                     exchange->enclosed->length()))
1135
 
        goto err;
 
1622
      if (my_b_write(&cache,(unsigned char*) exchange->enclosed->ptr(),
 
1623
                     exchange->enclosed->length()))
 
1624
        goto err;
1136
1625
    }
1137
1626
    if (!res)
1138
1627
    {                                           // NULL
1139
1628
      if (!fixed_row_size)
1140
1629
      {
1141
 
        if (escape_char != -1)                  // Use \N syntax
1142
 
        {
1143
 
          null_buff[0]=escape_char;
1144
 
          null_buff[1]='N';
1145
 
          if (my_b_write(cache,(unsigned char*) null_buff,2))
1146
 
            goto err;
1147
 
        }
1148
 
        else if (my_b_write(cache,(unsigned char*) "NULL",4))
1149
 
          goto err;
 
1630
        if (escape_char != -1)                  // Use \N syntax
 
1631
        {
 
1632
          null_buff[0]=escape_char;
 
1633
          null_buff[1]='N';
 
1634
          if (my_b_write(&cache,(unsigned char*) null_buff,2))
 
1635
            goto err;
 
1636
        }
 
1637
        else if (my_b_write(&cache,(unsigned char*) "NULL",4))
 
1638
          goto err;
1150
1639
      }
1151
1640
      else
1152
1641
      {
1153
 
        used_length=0;                          // Fill with space
 
1642
        used_length=0;                          // Fill with space
1154
1643
      }
1155
1644
    }
1156
1645
    else
1157
1646
    {
1158
1647
      if (fixed_row_size)
1159
 
        used_length= min(res->length(),item->max_length);
 
1648
        used_length=cmin(res->length(),item->max_length);
1160
1649
      else
1161
 
        used_length= res->length();
1162
 
 
 
1650
        used_length=res->length();
1163
1651
      if ((result_type == STRING_RESULT || is_unsafe_field_sep) &&
1164
 
          escape_char != -1)
 
1652
           escape_char != -1)
1165
1653
      {
1166
1654
        char *pos, *start, *end;
1167
1655
        const CHARSET_INFO * const res_charset= res->charset();
1168
 
        const CHARSET_INFO * const character_set_client= default_charset_info;
1169
 
 
 
1656
        const CHARSET_INFO * const character_set_client= session->variables.
 
1657
                                                            character_set_client;
1170
1658
        bool check_second_byte= (res_charset == &my_charset_bin) &&
1171
 
          character_set_client->
1172
 
          escape_with_backslash_is_dangerous;
 
1659
                                 character_set_client->
 
1660
                                 escape_with_backslash_is_dangerous;
1173
1661
        assert(character_set_client->mbmaxlen == 2 ||
1174
 
               !character_set_client->escape_with_backslash_is_dangerous);
1175
 
        for (start=pos=(char*) res->ptr(),end=pos+used_length ;
1176
 
             pos != end ;
1177
 
             pos++)
1178
 
        {
1179
 
          if (use_mb(res_charset))
1180
 
          {
1181
 
            int l;
1182
 
            if ((l=my_ismbchar(res_charset, pos, end)))
1183
 
            {
1184
 
              pos += l-1;
1185
 
              continue;
1186
 
            }
1187
 
          }
 
1662
                    !character_set_client->escape_with_backslash_is_dangerous);
 
1663
        for (start=pos=(char*) res->ptr(),end=pos+used_length ;
 
1664
             pos != end ;
 
1665
             pos++)
 
1666
        {
 
1667
#ifdef USE_MB
 
1668
          if (use_mb(res_charset))
 
1669
          {
 
1670
            int l;
 
1671
            if ((l=my_ismbchar(res_charset, pos, end)))
 
1672
            {
 
1673
              pos += l-1;
 
1674
              continue;
 
1675
            }
 
1676
          }
 
1677
#endif
1188
1678
 
1189
1679
          /*
1190
1680
            Special case when dumping BINARY/VARBINARY/BLOB values
1191
1681
            for the clients with character sets big5, cp932, gbk and sjis,
1192
1682
            which can have the escape character (0x5C "\" by default)
1193
1683
            as the second byte of a multi-byte sequence.
1194
 
 
 
1684
            
1195
1685
            If
1196
1686
            - pos[0] is a valid multi-byte head (e.g 0xEE) and
1197
1687
            - pos[1] is 0x00, which will be escaped as "\0",
1198
 
 
 
1688
            
1199
1689
            then we'll get "0xEE + 0x5C + 0x30" in the output file.
1200
 
 
 
1690
            
1201
1691
            If this file is later loaded using this sequence of commands:
1202
 
 
 
1692
            
1203
1693
            mysql> create table t1 (a varchar(128)) character set big5;
1204
1694
            mysql> LOAD DATA INFILE 'dump.txt' INTO Table t1;
1205
 
 
 
1695
            
1206
1696
            then 0x5C will be misinterpreted as the second byte
1207
1697
            of a multi-byte character "0xEE + 0x5C", instead of
1208
1698
            escape character for 0x00.
1209
 
 
 
1699
            
1210
1700
            To avoid this confusion, we'll escape the multi-byte
1211
1701
            head character too, so the sequence "0xEE + 0x00" will be
1212
1702
            dumped as "0x5C + 0xEE + 0x5C + 0x30".
1213
 
 
 
1703
            
1214
1704
            Note, in the condition below we only check if
1215
1705
            mbcharlen is equal to 2, because there are no
1216
1706
            character sets with mbmaxlen longer than 2
1218
1708
            assert before the loop makes that sure.
1219
1709
          */
1220
1710
 
1221
 
          if ((needs_escaping(*pos, enclosed) ||
 
1711
          if ((NEED_ESCAPING(*pos) ||
1222
1712
               (check_second_byte &&
1223
1713
                my_mbcharlen(character_set_client, (unsigned char) *pos) == 2 &&
1224
1714
                pos + 1 < end &&
1225
 
                needs_escaping(pos[1], enclosed))) &&
 
1715
                NEED_ESCAPING(pos[1]))) &&
1226
1716
              /*
1227
 
                Don't escape field_term_char by doubling - doubling is only
1228
 
                valid for ENCLOSED BY characters:
 
1717
               Don't escape field_term_char by doubling - doubling is only
 
1718
               valid for ENCLOSED BY characters:
1229
1719
              */
1230
1720
              (enclosed || !is_ambiguous_field_term ||
1231
1721
               (int) (unsigned char) *pos != field_term_char))
1232
1722
          {
1233
 
            char tmp_buff[2];
 
1723
            char tmp_buff[2];
1234
1724
            tmp_buff[0]= ((int) (unsigned char) *pos == field_sep_char &&
1235
1725
                          is_ambiguous_field_sep) ?
1236
 
              field_sep_char : escape_char;
1237
 
            tmp_buff[1]= *pos ? *pos : '0';
1238
 
            if (my_b_write(cache,(unsigned char*) start,(uint32_t) (pos-start)) ||
1239
 
                my_b_write(cache,(unsigned char*) tmp_buff,2))
1240
 
              goto err;
1241
 
            start=pos+1;
1242
 
          }
1243
 
        }
1244
 
        if (my_b_write(cache,(unsigned char*) start,(uint32_t) (pos-start)))
1245
 
          goto err;
 
1726
                          field_sep_char : escape_char;
 
1727
            tmp_buff[1]= *pos ? *pos : '0';
 
1728
            if (my_b_write(&cache,(unsigned char*) start,(uint) (pos-start)) ||
 
1729
                my_b_write(&cache,(unsigned char*) tmp_buff,2))
 
1730
              goto err;
 
1731
            start=pos+1;
 
1732
          }
 
1733
        }
 
1734
        if (my_b_write(&cache,(unsigned char*) start,(uint) (pos-start)))
 
1735
          goto err;
1246
1736
      }
1247
 
      else if (my_b_write(cache,(unsigned char*) res->ptr(),used_length))
1248
 
        goto err;
 
1737
      else if (my_b_write(&cache,(unsigned char*) res->ptr(),used_length))
 
1738
        goto err;
1249
1739
    }
1250
1740
    if (fixed_row_size)
1251
1741
    {                                           // Fill with space
1252
1742
      if (item->max_length > used_length)
1253
1743
      {
1254
 
        /* QQ:  Fix by adding a my_b_fill() function */
1255
 
        if (!space_inited)
1256
 
        {
1257
 
          space_inited=1;
1258
 
          memset(space, ' ', sizeof(space));
1259
 
        }
1260
 
        uint32_t length=item->max_length-used_length;
1261
 
        for (; length > sizeof(space) ; length-=sizeof(space))
1262
 
        {
1263
 
          if (my_b_write(cache,(unsigned char*) space,sizeof(space)))
1264
 
            goto err;
1265
 
        }
1266
 
        if (my_b_write(cache,(unsigned char*) space,length))
1267
 
          goto err;
 
1744
        /* QQ:  Fix by adding a my_b_fill() function */
 
1745
        if (!space_inited)
 
1746
        {
 
1747
          space_inited=1;
 
1748
          memset(space, ' ', sizeof(space));
 
1749
        }
 
1750
        uint32_t length=item->max_length-used_length;
 
1751
        for (; length > sizeof(space) ; length-=sizeof(space))
 
1752
        {
 
1753
          if (my_b_write(&cache,(unsigned char*) space,sizeof(space)))
 
1754
            goto err;
 
1755
        }
 
1756
        if (my_b_write(&cache,(unsigned char*) space,length))
 
1757
          goto err;
1268
1758
      }
1269
1759
    }
1270
1760
    if (res && enclosed)
1271
1761
    {
1272
 
      if (my_b_write(cache, (unsigned char*) exchange->enclosed->ptr(),
 
1762
      if (my_b_write(&cache, (unsigned char*) exchange->enclosed->ptr(),
1273
1763
                     exchange->enclosed->length()))
1274
1764
        goto err;
1275
1765
    }
1276
1766
    if (--items_left)
1277
1767
    {
1278
 
      if (my_b_write(cache, (unsigned char*) exchange->field_term->ptr(),
 
1768
      if (my_b_write(&cache, (unsigned char*) exchange->field_term->ptr(),
1279
1769
                     field_term_length))
1280
1770
        goto err;
1281
1771
    }
1282
1772
  }
1283
 
  if (my_b_write(cache,(unsigned char*) exchange->line_term->ptr(),
1284
 
                 exchange->line_term->length()))
 
1773
  if (my_b_write(&cache,(unsigned char*) exchange->line_term->ptr(),
 
1774
                 exchange->line_term->length()))
1285
1775
    goto err;
1286
1776
  return(0);
1287
1777
err:
1295
1785
 
1296
1786
 
1297
1787
int
1298
 
select_dump::prepare(List<Item> &, Select_Lex_Unit *u)
 
1788
select_dump::prepare(List<Item> &list __attribute__((unused)),
 
1789
                     SELECT_LEX_UNIT *u)
1299
1790
{
1300
1791
  unit= u;
1301
 
  return (int) ((file= create_file(session, path, exchange, cache)) < 0);
 
1792
  return (int) ((file= create_file(session, path, exchange, &cache)) < 0);
1302
1793
}
1303
1794
 
1304
1795
 
1315
1806
    unit->offset_limit_cnt--;
1316
1807
    return(0);
1317
1808
  }
1318
 
  if (row_count++ > 1)
 
1809
  if (row_count++ > 1) 
1319
1810
  {
1320
1811
    my_message(ER_TOO_MANY_ROWS, ER(ER_TOO_MANY_ROWS), MYF(0));
1321
1812
    goto err;
1325
1816
    res=item->str_result(&tmp);
1326
1817
    if (!res)                                   // If NULL
1327
1818
    {
1328
 
      if (my_b_write(cache,(unsigned char*) "",1))
 
1819
      if (my_b_write(&cache,(unsigned char*) "",1))
1329
1820
        goto err;
1330
1821
    }
1331
 
    else if (my_b_write(cache,(unsigned char*) res->ptr(),res->length()))
 
1822
    else if (my_b_write(&cache,(unsigned char*) res->ptr(),res->length()))
1332
1823
    {
1333
 
      my_error(ER_ERROR_ON_WRITE, MYF(0), path, errno);
 
1824
      my_error(ER_ERROR_ON_WRITE, MYF(0), path, my_errno);
1334
1825
      goto err;
1335
1826
    }
1336
1827
  }
1371
1862
void select_max_min_finder_subselect::cleanup()
1372
1863
{
1373
1864
  cache= 0;
 
1865
  return;
1374
1866
}
1375
1867
 
1376
1868
 
1477
1969
     sortcmp(val1, val2, cache->collation.collation) < 0);
1478
1970
}
1479
1971
 
1480
 
bool select_exists_subselect::send_data(List<Item> &)
 
1972
bool select_exists_subselect::send_data(List<Item> &items __attribute__((unused)))
1481
1973
{
1482
1974
  Item_exists_subselect *it= (Item_exists_subselect *)item;
1483
1975
  if (unit->offset_limit_cnt)
1490
1982
  return(0);
1491
1983
}
1492
1984
 
 
1985
 
 
1986
/***************************************************************************
 
1987
  Dump of select to variables
 
1988
***************************************************************************/
 
1989
 
 
1990
int select_dumpvar::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
 
1991
{
 
1992
  unit= u;
 
1993
  
 
1994
  if (var_list.elements != list.elements)
 
1995
  {
 
1996
    my_message(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT,
 
1997
               ER(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT), MYF(0));
 
1998
    return 1;
 
1999
  }               
 
2000
  return 0;
 
2001
}
 
2002
 
 
2003
 
 
2004
bool select_dumpvar::check_simple_select() const
 
2005
{
 
2006
  my_error(ER_SP_BAD_CURSOR_SELECT, MYF(0));
 
2007
  return true;
 
2008
}
 
2009
 
 
2010
 
 
2011
void select_dumpvar::cleanup()
 
2012
{
 
2013
  row_count= 0;
 
2014
}
 
2015
 
 
2016
 
 
2017
void Query_arena::free_items()
 
2018
{
 
2019
  Item *next;
 
2020
  /* This works because items are allocated with sql_alloc() */
 
2021
  for (; free_list; free_list= next)
 
2022
  {
 
2023
    next= free_list->next;
 
2024
    free_list->delete_self();
 
2025
  }
 
2026
  /* Postcondition: free_list is 0 */
 
2027
  return;
 
2028
}
 
2029
 
 
2030
 
 
2031
/*
 
2032
  Statement functions
 
2033
*/
 
2034
 
 
2035
Statement::Statement(LEX *lex_arg, MEM_ROOT *mem_root_arg, ulong id_arg)
 
2036
  :Query_arena(mem_root_arg),
 
2037
  id(id_arg),
 
2038
  mark_used_columns(MARK_COLUMNS_READ),
 
2039
  lex(lex_arg),
 
2040
  query(0),
 
2041
  query_length(0),
 
2042
  db(NULL),
 
2043
  db_length(0)
 
2044
{
 
2045
}
 
2046
 
 
2047
 
1493
2048
/*
1494
2049
  Don't free mem_root, as mem_root is freed in the end of dispatch_command
1495
2050
  (once for any command).
1498
2053
{
1499
2054
  /* Cleanup SQL processing state to reuse this statement in next query. */
1500
2055
  lex_end(lex);
1501
 
  query_cache_key= ""; // reset the cache key
1502
 
  resetResultsetMessage();
1503
2056
}
1504
2057
 
 
2058
 
1505
2059
bool Session::copy_db_to(char **p_db, size_t *p_db_length)
1506
2060
{
1507
 
  if (db.empty())
 
2061
  if (db == NULL)
1508
2062
  {
1509
2063
    my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
1510
2064
    return true;
1511
2065
  }
1512
 
  *p_db= strmake(db.c_str(), db.length());
1513
 
  *p_db_length= db.length();
 
2066
  *p_db= strmake(db, db_length);
 
2067
  *p_db_length= db_length;
1514
2068
  return false;
1515
2069
}
1516
2070
 
 
2071
 
 
2072
bool select_dumpvar::send_data(List<Item> &items)
 
2073
{
 
2074
  List_iterator_fast<my_var> var_li(var_list);
 
2075
  List_iterator<Item> it(items);
 
2076
  Item *item;
 
2077
  my_var *mv;
 
2078
 
 
2079
  if (unit->offset_limit_cnt)
 
2080
  {                                             // using limit offset,count
 
2081
    unit->offset_limit_cnt--;
 
2082
    return(0);
 
2083
  }
 
2084
  if (row_count++) 
 
2085
  {
 
2086
    my_message(ER_TOO_MANY_ROWS, ER(ER_TOO_MANY_ROWS), MYF(0));
 
2087
    return(1);
 
2088
  }
 
2089
  while ((mv= var_li++) && (item= it++))
 
2090
  {
 
2091
    if (mv->local == 0)
 
2092
    {
 
2093
      Item_func_set_user_var *suv= new Item_func_set_user_var(mv->s, item);
 
2094
      suv->fix_fields(session, 0);
 
2095
      suv->check(0);
 
2096
      suv->update();
 
2097
    }
 
2098
  }
 
2099
  return(session->is_error());
 
2100
}
 
2101
 
 
2102
bool select_dumpvar::send_eof()
 
2103
{
 
2104
  if (! row_count)
 
2105
    push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
2106
                 ER_SP_FETCH_NO_DATA, ER(ER_SP_FETCH_NO_DATA));
 
2107
  /*
 
2108
    In order to remember the value of affected rows for ROW_COUNT()
 
2109
    function, SELECT INTO has to have an own SQLCOM.
 
2110
    TODO: split from SQLCOM_SELECT
 
2111
  */
 
2112
  ::my_ok(session,row_count);
 
2113
  return 0;
 
2114
}
 
2115
 
1517
2116
/****************************************************************************
1518
 
  Tmp_Table_Param
 
2117
  TMP_TABLE_PARAM
1519
2118
****************************************************************************/
1520
2119
 
1521
 
void Tmp_Table_Param::init()
 
2120
void TMP_TABLE_PARAM::init()
1522
2121
{
1523
2122
  field_count= sum_func_count= func_count= hidden_field_count= 0;
1524
2123
  group_parts= group_length= group_null_parts= 0;
1525
2124
  quick_group= 1;
1526
2125
  table_charset= 0;
1527
2126
  precomputed_group_by= 0;
 
2127
  bit_fields_as_long= 0;
 
2128
  return;
1528
2129
}
1529
2130
 
1530
 
void Tmp_Table_Param::cleanup(void)
 
2131
 
 
2132
void session_increment_bytes_sent(ulong length)
1531
2133
{
1532
 
  /* Fix for Intel compiler */
1533
 
  if (copy_field)
1534
 
  {
1535
 
    delete [] copy_field;
1536
 
    save_copy_field= copy_field= 0;
 
2134
  Session *session=current_session;
 
2135
  if (likely(session != 0))
 
2136
  { /* current_session==0 when close_connection() calls net_send_error() */
 
2137
    session->status_var.bytes_sent+= length;
1537
2138
  }
1538
2139
}
1539
2140
 
 
2141
 
 
2142
void session_increment_bytes_received(ulong length)
 
2143
{
 
2144
  current_session->status_var.bytes_received+= length;
 
2145
}
 
2146
 
 
2147
 
 
2148
void session_increment_net_big_packet_count(ulong length)
 
2149
{
 
2150
  current_session->status_var.net_big_packet_count+= length;
 
2151
}
 
2152
 
1540
2153
void Session::send_kill_message() const
1541
2154
{
1542
2155
  int err= killed_errno();
1550
2163
}
1551
2164
 
1552
2165
 
1553
 
bool Session::set_db(const std::string &new_db)
1554
 
{
1555
 
  /* Do not reallocate memory if current chunk is big enough. */
1556
 
  if (new_db.length())
1557
 
    db= new_db;
1558
 
  else
1559
 
    db.clear();
1560
 
 
1561
 
  return false;
1562
 
}
1563
 
 
1564
 
 
1565
 
 
 
2166
void Security_context::init()
 
2167
{
 
2168
  user= ip= 0;
 
2169
}
 
2170
 
 
2171
 
 
2172
void Security_context::destroy()
 
2173
{
 
2174
  // If not pointer to constant
 
2175
  if (user)
 
2176
  {
 
2177
    free(user);
 
2178
    user= NULL;
 
2179
  }
 
2180
  if (ip)
 
2181
  {
 
2182
    free(ip);
 
2183
    ip= NULL;
 
2184
  }
 
2185
}
 
2186
 
 
2187
 
 
2188
void Security_context::skip_grants()
 
2189
{
 
2190
  /* privileges for the user are unknown everything is allowed */
 
2191
}
 
2192
 
 
2193
 
 
2194
/****************************************************************************
 
2195
  Handling of open and locked tables states.
 
2196
 
 
2197
  This is used when we want to open/lock (and then close) some tables when
 
2198
  we already have a set of tables open and locked. We use these methods for
 
2199
  access to mysql.proc table to find definitions of stored routines.
 
2200
****************************************************************************/
 
2201
 
 
2202
void Session::reset_n_backup_open_tables_state(Open_tables_state *backup)
 
2203
{
 
2204
  backup->set_open_tables_state(this);
 
2205
  reset_open_tables_state();
 
2206
  state_flags|= Open_tables_state::BACKUPS_AVAIL;
 
2207
  return;
 
2208
}
 
2209
 
 
2210
 
 
2211
void Session::restore_backup_open_tables_state(Open_tables_state *backup)
 
2212
{
 
2213
  /*
 
2214
    Before we will throw away current open tables state we want
 
2215
    to be sure that it was properly cleaned up.
 
2216
  */
 
2217
  assert(open_tables == 0 && temporary_tables == 0 &&
 
2218
              handler_tables == 0 && derived_tables == 0 &&
 
2219
              lock == 0 && locked_tables == 0);
 
2220
  set_open_tables_state(backup);
 
2221
  return;
 
2222
}
1566
2223
 
1567
2224
/**
1568
2225
  Check the killed state of a user thread
1570
2227
  @retval 0 the user thread is active
1571
2228
  @retval 1 the user thread has been killed
1572
2229
*/
1573
 
int session_killed(const Session *session)
 
2230
extern "C" int session_killed(const Session *session)
1574
2231
{
1575
2232
  return(session->killed);
1576
2233
}
1577
2234
 
1578
 
 
1579
 
const struct charset_info_st *session_charset(Session *session)
 
2235
/**
 
2236
  Return the thread id of a user thread
 
2237
  @param session user thread
 
2238
  @return thread id
 
2239
*/
 
2240
extern "C" unsigned long session_get_thread_id(const Session *session)
 
2241
{
 
2242
  return((unsigned long)session->thread_id);
 
2243
}
 
2244
 
 
2245
 
 
2246
#ifdef INNODB_COMPATIBILITY_HOOKS
 
2247
extern "C" const struct charset_info_st *session_charset(Session *session)
1580
2248
{
1581
2249
  return(session->charset());
1582
2250
}
1583
2251
 
 
2252
extern "C" char **session_query(Session *session)
 
2253
{
 
2254
  return(&session->query);
 
2255
}
 
2256
 
 
2257
extern "C" int session_slave_thread(const Session *session)
 
2258
{
 
2259
  return(session->slave_thread);
 
2260
}
 
2261
 
 
2262
extern "C" int session_non_transactional_update(const Session *session)
 
2263
{
 
2264
  return(session->transaction.all.modified_non_trans_table);
 
2265
}
 
2266
 
 
2267
extern "C" int session_binlog_format(const Session *session)
 
2268
{
 
2269
  return (int) session->variables.binlog_format;
 
2270
}
 
2271
 
 
2272
extern "C" void session_mark_transaction_to_rollback(Session *session, bool all)
 
2273
{
 
2274
  mark_transaction_to_rollback(session, all);
 
2275
}
 
2276
#endif // INNODB_COMPATIBILITY_HOOKS */
 
2277
 
 
2278
 
1584
2279
/**
1585
2280
  Mark transaction to rollback and mark error as fatal to a sub-statement.
1586
2281
 
1587
2282
  @param  session   Thread handle
1588
2283
  @param  all   true <=> rollback main transaction.
1589
2284
*/
 
2285
 
1590
2286
void mark_transaction_to_rollback(Session *session, bool all)
1591
2287
{
1592
2288
  if (session)
1595
2291
    session->transaction_rollback_request= all;
1596
2292
  }
1597
2293
}
1598
 
 
1599
 
void Session::disconnect(uint32_t errcode, bool should_lock)
1600
 
{
1601
 
  /* Allow any plugins to cleanup their session variables */
1602
 
  plugin_sessionvar_cleanup(this);
1603
 
 
1604
 
  /* If necessary, log any aborted or unauthorized connections */
1605
 
  if (killed || client->wasAborted())
1606
 
  {
1607
 
    status_var.aborted_threads++;
1608
 
  }
1609
 
 
1610
 
  if (client->wasAborted())
1611
 
  {
1612
 
    if (! killed && variables.log_warnings > 1)
1613
 
    {
1614
 
      SecurityContext *sctx= &security_ctx;
1615
 
 
1616
 
      errmsg_printf(ERRMSG_LVL_WARN, ER(ER_NEW_ABORTING_CONNECTION)
1617
 
                  , thread_id
1618
 
                  , (db.empty() ? "unconnected" : db.c_str())
1619
 
                  , sctx->getUser().empty() == false ? sctx->getUser().c_str() : "unauthenticated"
1620
 
                  , sctx->getIp().c_str()
1621
 
                  , (main_da.is_error() ? main_da.message() : ER(ER_UNKNOWN_ERROR)));
1622
 
    }
1623
 
  }
1624
 
 
1625
 
  /* Close out our connection to the client */
1626
 
  if (should_lock)
1627
 
    LOCK_thread_count.lock();
1628
 
  killed= Session::KILL_CONNECTION;
1629
 
  if (client->isConnected())
1630
 
  {
1631
 
    if (errcode)
1632
 
    {
1633
 
      /*my_error(errcode, ER(errcode));*/
1634
 
      client->sendError(errcode, ER(errcode));
1635
 
    }
1636
 
    client->close();
1637
 
  }
1638
 
  if (should_lock)
1639
 
    (void) LOCK_thread_count.unlock();
1640
 
}
1641
 
 
1642
 
void Session::reset_for_next_command()
1643
 
{
1644
 
  free_list= 0;
1645
 
  select_number= 1;
1646
 
  /*
1647
 
    Those two lines below are theoretically unneeded as
1648
 
    Session::cleanup_after_query() should take care of this already.
1649
 
  */
1650
 
  auto_inc_intervals_in_cur_stmt_for_binlog.empty();
1651
 
 
1652
 
  is_fatal_error= false;
1653
 
  server_status&= ~ (SERVER_MORE_RESULTS_EXISTS |
1654
 
                          SERVER_QUERY_NO_INDEX_USED |
1655
 
                          SERVER_QUERY_NO_GOOD_INDEX_USED);
1656
 
 
1657
 
  clear_error();
1658
 
  main_da.reset_diagnostics_area();
1659
 
  total_warn_count=0;                   // Warnings for this query
1660
 
  sent_row_count= examined_row_count= 0;
1661
 
}
1662
 
 
1663
 
/*
1664
 
  Close all temporary tables created by 'CREATE TEMPORARY TABLE' for thread
1665
 
*/
1666
 
 
1667
 
void Session::close_temporary_tables()
1668
 
{
1669
 
  Table *table;
1670
 
  Table *tmp_next;
1671
 
 
1672
 
  if (not temporary_tables)
1673
 
    return;
1674
 
 
1675
 
  for (table= temporary_tables; table; table= tmp_next)
1676
 
  {
1677
 
    tmp_next= table->getNext();
1678
 
    nukeTable(table);
1679
 
  }
1680
 
  temporary_tables= NULL;
1681
 
}
1682
 
 
1683
 
/*
1684
 
  unlink from session->temporary tables and close temporary table
1685
 
*/
1686
 
 
1687
 
void Session::close_temporary_table(Table *table)
1688
 
{
1689
 
  if (table->getPrev())
1690
 
  {
1691
 
    table->getPrev()->setNext(table->getNext());
1692
 
    if (table->getPrev()->getNext())
1693
 
    {
1694
 
      table->getNext()->setPrev(table->getPrev());
1695
 
    }
1696
 
  }
1697
 
  else
1698
 
  {
1699
 
    /* removing the item from the list */
1700
 
    assert(table == temporary_tables);
1701
 
    /*
1702
 
      slave must reset its temporary list pointer to zero to exclude
1703
 
      passing non-zero value to end_slave via rli->save_temporary_tables
1704
 
      when no temp tables opened, see an invariant below.
1705
 
    */
1706
 
    temporary_tables= table->getNext();
1707
 
    if (temporary_tables)
1708
 
    {
1709
 
      table->getNext()->setPrev(NULL);
1710
 
    }
1711
 
  }
1712
 
  nukeTable(table);
1713
 
}
1714
 
 
1715
 
/*
1716
 
  Close and drop a temporary table
1717
 
 
1718
 
  NOTE
1719
 
  This dosn't unlink table from session->temporary
1720
 
  If this is needed, use close_temporary_table()
1721
 
*/
1722
 
 
1723
 
void Session::nukeTable(Table *table)
1724
 
{
1725
 
  plugin::StorageEngine *table_type= table->getShare()->db_type();
1726
 
 
1727
 
  table->free_io_cache();
1728
 
  table->delete_table();
1729
 
 
1730
 
  TableIdentifier identifier(table->getShare()->getSchemaName(), table->getShare()->getTableName(), table->getShare()->getPath());
1731
 
  rm_temporary_table(table_type, identifier);
1732
 
 
1733
 
  delete table->getMutableShare();
1734
 
 
1735
 
  /* This makes me sad, but we're allocating it via malloc */
1736
 
  delete table;
1737
 
}
1738
 
 
1739
 
/** Clear most status variables. */
1740
 
extern time_t flush_status_time;
1741
 
 
1742
 
void Session::refresh_status()
1743
 
{
1744
 
  /* Reset thread's status variables */
1745
 
  memset(&status_var, 0, sizeof(status_var));
1746
 
 
1747
 
  flush_status_time= time((time_t*) 0);
1748
 
  current_global_counters.max_used_connections= 1; /* We set it to one, because we know we exist */
1749
 
  current_global_counters.connections= 0;
1750
 
}
1751
 
 
1752
 
user_var_entry *Session::getVariable(LEX_STRING &name, bool create_if_not_exists)
1753
 
{
1754
 
  user_var_entry *entry= NULL;
1755
 
  UserVarsRange ppp= user_vars.equal_range(std::string(name.str, name.length));
1756
 
 
1757
 
  for (UserVars::iterator iter= ppp.first;
1758
 
         iter != ppp.second; ++iter)
1759
 
  {
1760
 
    entry= (*iter).second;
1761
 
  }
1762
 
 
1763
 
  if ((entry == NULL) && create_if_not_exists)
1764
 
  {
1765
 
    entry= new (nothrow) user_var_entry(name.str, query_id);
1766
 
 
1767
 
    if (entry == NULL)
1768
 
      return NULL;
1769
 
 
1770
 
    std::pair<UserVars::iterator, bool> returnable= user_vars.insert(make_pair(std::string(name.str, name.length), entry));
1771
 
 
1772
 
    if (not returnable.second)
1773
 
    {
1774
 
      delete entry;
1775
 
      return NULL;
1776
 
    }
1777
 
  }
1778
 
 
1779
 
  return entry;
1780
 
}
1781
 
 
1782
 
void Session::mark_temp_tables_as_free_for_reuse()
1783
 
{
1784
 
  for (Table *table= temporary_tables ; table ; table= table->getNext())
1785
 
  {
1786
 
    if (table->query_id == query_id)
1787
 
    {
1788
 
      table->query_id= 0;
1789
 
      table->cursor->ha_reset();
1790
 
    }
1791
 
  }
1792
 
}
1793
 
 
1794
 
void Session::mark_used_tables_as_free_for_reuse(Table *table)
1795
 
{
1796
 
  for (; table ; table= table->getNext())
1797
 
  {
1798
 
    if (table->query_id == query_id)
1799
 
    {
1800
 
      table->query_id= 0;
1801
 
      table->cursor->ha_reset();
1802
 
    }
1803
 
  }
1804
 
}
1805
 
 
1806
 
/*
1807
 
  Unlocks tables and frees derived tables.
1808
 
  Put all normal tables used by thread in free list.
1809
 
 
1810
 
  It will only close/mark as free for reuse tables opened by this
1811
 
  substatement, it will also check if we are closing tables after
1812
 
  execution of complete query (i.e. we are on upper level) and will
1813
 
  leave prelocked mode if needed.
1814
 
*/
1815
 
void Session::close_thread_tables()
1816
 
{
1817
 
  if (derived_tables)
1818
 
    derived_tables= NULL; // They should all be invalid by this point
1819
 
 
1820
 
  /*
1821
 
    Mark all temporary tables used by this statement as free for reuse.
1822
 
  */
1823
 
  mark_temp_tables_as_free_for_reuse();
1824
 
  /*
1825
 
    Let us commit transaction for statement. Since in 5.0 we only have
1826
 
    one statement transaction and don't allow several nested statement
1827
 
    transactions this call will do nothing if we are inside of stored
1828
 
    function or trigger (i.e. statement transaction is already active and
1829
 
    does not belong to statement for which we do close_thread_tables()).
1830
 
    TODO: This should be fixed in later releases.
1831
 
   */
1832
 
  {
1833
 
    TransactionServices &transaction_services= TransactionServices::singleton();
1834
 
    main_da.can_overwrite_status= true;
1835
 
    transaction_services.autocommitOrRollback(this, is_error());
1836
 
    main_da.can_overwrite_status= false;
1837
 
    transaction.stmt.reset();
1838
 
  }
1839
 
 
1840
 
  if (lock)
1841
 
  {
1842
 
    /*
1843
 
      For RBR we flush the pending event just before we unlock all the
1844
 
      tables.  This means that we are at the end of a topmost
1845
 
      statement, so we ensure that the STMT_END_F flag is set on the
1846
 
      pending event.  For statements that are *inside* stored
1847
 
      functions, the pending event will not be flushed: that will be
1848
 
      handled either before writing a query log event (inside
1849
 
      binlog_query()) or when preparing a pending event.
1850
 
     */
1851
 
    mysql_unlock_tables(this, lock);
1852
 
    lock= 0;
1853
 
  }
1854
 
  /*
1855
 
    Note that we need to hold LOCK_open while changing the
1856
 
    open_tables list. Another thread may work on it.
1857
 
    (See: remove_table_from_cache(), mysql_wait_completed_table())
1858
 
    Closing a MERGE child before the parent would be fatal if the
1859
 
    other thread tries to abort the MERGE lock in between.
1860
 
  */
1861
 
  if (open_tables)
1862
 
    close_open_tables();
1863
 
}
1864
 
 
1865
 
void Session::close_tables_for_reopen(TableList **tables)
1866
 
{
1867
 
  /*
1868
 
    If table list consists only from tables from prelocking set, table list
1869
 
    for new attempt should be empty, so we have to update list's root pointer.
1870
 
  */
1871
 
  if (lex->first_not_own_table() == *tables)
1872
 
    *tables= 0;
1873
 
  lex->chop_off_not_own_tables();
1874
 
  for (TableList *tmp= *tables; tmp; tmp= tmp->next_global)
1875
 
    tmp->table= 0;
1876
 
  close_thread_tables();
1877
 
}
1878
 
 
1879
 
bool Session::openTablesLock(TableList *tables)
1880
 
{
1881
 
  uint32_t counter;
1882
 
  bool need_reopen;
1883
 
 
1884
 
  for ( ; ; )
1885
 
  {
1886
 
    if (open_tables_from_list(&tables, &counter))
1887
 
      return true;
1888
 
 
1889
 
    if (not lock_tables(tables, counter, &need_reopen))
1890
 
      break;
1891
 
    if (not need_reopen)
1892
 
      return true;
1893
 
    close_tables_for_reopen(&tables);
1894
 
  }
1895
 
  if ((mysql_handle_derived(lex, &mysql_derived_prepare) ||
1896
 
       (fill_derived_tables() &&
1897
 
        mysql_handle_derived(lex, &mysql_derived_filling))))
1898
 
    return true;
1899
 
 
1900
 
  return false;
1901
 
}
1902
 
 
1903
 
bool Session::openTables(TableList *tables, uint32_t flags)
1904
 
{
1905
 
  uint32_t counter;
1906
 
  bool ret= fill_derived_tables();
1907
 
  assert(ret == false);
1908
 
  if (open_tables_from_list(&tables, &counter, flags) ||
1909
 
      mysql_handle_derived(lex, &mysql_derived_prepare))
1910
 
  {
1911
 
    return true;
1912
 
  }
1913
 
  return false;
1914
 
}
1915
 
 
1916
 
/*
1917
 
  @note "best_effort" is used in cases were if a failure occurred on this
1918
 
  operation it would not be surprising because we are only removing because there
1919
 
  might be an issue (lame engines).
1920
 
*/
1921
 
 
1922
 
bool Session::rm_temporary_table(TableIdentifier &identifier, bool best_effort)
1923
 
{
1924
 
  if (plugin::StorageEngine::dropTable(*this, identifier))
1925
 
  {
1926
 
    if (not best_effort)
1927
 
    {
1928
 
      errmsg_printf(ERRMSG_LVL_WARN, _("Could not remove temporary table: '%s', error: %d"),
1929
 
                    identifier.getSQLPath().c_str(), errno);
1930
 
    }
1931
 
 
1932
 
    return true;
1933
 
  }
1934
 
 
1935
 
  return false;
1936
 
}
1937
 
 
1938
 
bool Session::rm_temporary_table(plugin::StorageEngine *base, TableIdentifier &identifier)
1939
 
{
1940
 
  assert(base);
1941
 
 
1942
 
  if (plugin::StorageEngine::dropTable(*this, *base, identifier))
1943
 
  {
1944
 
    errmsg_printf(ERRMSG_LVL_WARN, _("Could not remove temporary table: '%s', error: %d"),
1945
 
                  identifier.getSQLPath().c_str(), errno);
1946
 
 
1947
 
    return true;
1948
 
  }
1949
 
 
1950
 
  return false;
1951
 
}
1952
 
 
1953
 
/**
1954
 
  @note this will be removed, I am looking through Hudson to see if it is finding
1955
 
  any tables that are missed during cleanup.
1956
 
*/
1957
 
void Session::dumpTemporaryTableNames(const char *foo)
1958
 
{
1959
 
  Table *table;
1960
 
 
1961
 
  if (not temporary_tables)
1962
 
    return;
1963
 
 
1964
 
  cerr << "Begin Run: " << foo << "\n";
1965
 
  for (table= temporary_tables; table; table= table->getNext())
1966
 
  {
1967
 
    bool have_proto= false;
1968
 
 
1969
 
    message::Table *proto= table->getShare()->getTableProto();
1970
 
    if (table->getShare()->getTableProto())
1971
 
      have_proto= true;
1972
 
 
1973
 
    const char *answer= have_proto ? "true" : "false";
1974
 
 
1975
 
    if (have_proto)
1976
 
    {
1977
 
      cerr << "\tTable Name " << table->getShare()->getSchemaName() << "." << table->getShare()->getTableName() << " : " << answer << "\n";
1978
 
      cerr << "\t\t Proto " << proto->schema() << " " << proto->name() << "\n";
1979
 
    }
1980
 
    else
1981
 
      cerr << "\tTabl;e Name " << table->getShare()->getSchemaName() << "." << table->getShare()->getTableName() << " : " << answer << "\n";
1982
 
  }
1983
 
}
1984
 
 
1985
 
bool Session::storeTableMessage(const TableIdentifier &identifier, message::Table &table_message)
1986
 
{
1987
 
  table_message_cache.insert(make_pair(identifier.getPath(), table_message));
1988
 
 
1989
 
  return true;
1990
 
}
1991
 
 
1992
 
bool Session::removeTableMessage(const TableIdentifier &identifier)
1993
 
{
1994
 
  TableMessageCache::iterator iter;
1995
 
 
1996
 
  iter= table_message_cache.find(identifier.getPath());
1997
 
 
1998
 
  if (iter == table_message_cache.end())
1999
 
    return false;
2000
 
 
2001
 
  table_message_cache.erase(iter);
2002
 
 
2003
 
  return true;
2004
 
}
2005
 
 
2006
 
bool Session::getTableMessage(const TableIdentifier &identifier, message::Table &table_message)
2007
 
{
2008
 
  TableMessageCache::iterator iter;
2009
 
 
2010
 
  iter= table_message_cache.find(identifier.getPath());
2011
 
 
2012
 
  if (iter == table_message_cache.end())
2013
 
    return false;
2014
 
 
2015
 
  table_message.CopyFrom(((*iter).second));
2016
 
 
2017
 
  return true;
2018
 
}
2019
 
 
2020
 
bool Session::doesTableMessageExist(const TableIdentifier &identifier)
2021
 
{
2022
 
  TableMessageCache::iterator iter;
2023
 
 
2024
 
  iter= table_message_cache.find(identifier.getPath());
2025
 
 
2026
 
  if (iter == table_message_cache.end())
2027
 
  {
2028
 
    return false;
2029
 
  }
2030
 
 
2031
 
  return true;
2032
 
}
2033
 
 
2034
 
bool Session::renameTableMessage(const TableIdentifier &from, const TableIdentifier &to)
2035
 
{
2036
 
  TableMessageCache::iterator iter;
2037
 
 
2038
 
  table_message_cache[to.getPath()]= table_message_cache[from.getPath()];
2039
 
 
2040
 
  iter= table_message_cache.find(to.getPath());
2041
 
 
2042
 
  if (iter == table_message_cache.end())
2043
 
  {
2044
 
    return false;
2045
 
  }
2046
 
 
2047
 
  (*iter).second.set_schema(to.getSchemaName());
2048
 
  (*iter).second.set_name(to.getTableName());
2049
 
 
2050
 
  return true;
2051
 
}
2052
 
 
2053
 
TableShareInstance *Session::getTemporaryShare(TableIdentifier::Type type_arg)
2054
 
{
2055
 
  temporary_shares.push_back(new TableShareInstance(type_arg)); // This will not go into the tableshare cache, so no key is used.
2056
 
 
2057
 
  TableShareInstance *tmp_share= temporary_shares.back();
2058
 
 
2059
 
  assert(tmp_share);
2060
 
 
2061
 
  return tmp_share;
2062
 
}
2063
 
 
2064
 
} /* namespace drizzled */
 
2294
/***************************************************************************
 
2295
  Handling of XA id cacheing
 
2296
***************************************************************************/
 
2297
 
 
2298
pthread_mutex_t LOCK_xid_cache;
 
2299
HASH xid_cache;
 
2300
 
 
2301
extern "C" unsigned char *xid_get_hash_key(const unsigned char *, size_t *, bool);
 
2302
extern "C" void xid_free_hash(void *);
 
2303
 
 
2304
unsigned char *xid_get_hash_key(const unsigned char *ptr, size_t *length,
 
2305
                        bool not_used __attribute__((unused)))
 
2306
{
 
2307
  *length=((XID_STATE*)ptr)->xid.key_length();
 
2308
  return ((XID_STATE*)ptr)->xid.key();
 
2309
}
 
2310
 
 
2311
void xid_free_hash(void *ptr)
 
2312
{
 
2313
  if (!((XID_STATE*)ptr)->in_session)
 
2314
    free((unsigned char*)ptr);
 
2315
}
 
2316
 
 
2317
bool xid_cache_init()
 
2318
{
 
2319
  pthread_mutex_init(&LOCK_xid_cache, MY_MUTEX_INIT_FAST);
 
2320
  return hash_init(&xid_cache, &my_charset_bin, 100, 0, 0,
 
2321
                   xid_get_hash_key, xid_free_hash, 0) != 0;
 
2322
}
 
2323
 
 
2324
void xid_cache_free()
 
2325
{
 
2326
  if (hash_inited(&xid_cache))
 
2327
  {
 
2328
    hash_free(&xid_cache);
 
2329
    pthread_mutex_destroy(&LOCK_xid_cache);
 
2330
  }
 
2331
}
 
2332
 
 
2333
XID_STATE *xid_cache_search(XID *xid)
 
2334
{
 
2335
  pthread_mutex_lock(&LOCK_xid_cache);
 
2336
  XID_STATE *res=(XID_STATE *)hash_search(&xid_cache, xid->key(), xid->key_length());
 
2337
  pthread_mutex_unlock(&LOCK_xid_cache);
 
2338
  return res;
 
2339
}
 
2340
 
 
2341
 
 
2342
bool xid_cache_insert(XID *xid, enum xa_states xa_state)
 
2343
{
 
2344
  XID_STATE *xs;
 
2345
  bool res;
 
2346
  pthread_mutex_lock(&LOCK_xid_cache);
 
2347
  if (hash_search(&xid_cache, xid->key(), xid->key_length()))
 
2348
    res=0;
 
2349
  else if (!(xs=(XID_STATE *)my_malloc(sizeof(*xs), MYF(MY_WME))))
 
2350
    res=1;
 
2351
  else
 
2352
  {
 
2353
    xs->xa_state=xa_state;
 
2354
    xs->xid.set(xid);
 
2355
    xs->in_session=0;
 
2356
    res=my_hash_insert(&xid_cache, (unsigned char*)xs);
 
2357
  }
 
2358
  pthread_mutex_unlock(&LOCK_xid_cache);
 
2359
  return res;
 
2360
}
 
2361
 
 
2362
 
 
2363
bool xid_cache_insert(XID_STATE *xid_state)
 
2364
{
 
2365
  pthread_mutex_lock(&LOCK_xid_cache);
 
2366
  assert(hash_search(&xid_cache, xid_state->xid.key(),
 
2367
                          xid_state->xid.key_length())==0);
 
2368
  bool res=my_hash_insert(&xid_cache, (unsigned char*)xid_state);
 
2369
  pthread_mutex_unlock(&LOCK_xid_cache);
 
2370
  return res;
 
2371
}
 
2372
 
 
2373
 
 
2374
void xid_cache_delete(XID_STATE *xid_state)
 
2375
{
 
2376
  pthread_mutex_lock(&LOCK_xid_cache);
 
2377
  hash_delete(&xid_cache, (unsigned char *)xid_state);
 
2378
  pthread_mutex_unlock(&LOCK_xid_cache);
 
2379
}
 
2380
 
 
2381
/*
 
2382
  Implementation of interface to write rows to the binary log through the
 
2383
  thread.  The thread is responsible for writing the rows it has
 
2384
  inserted/updated/deleted.
 
2385
*/
 
2386
 
 
2387
 
 
2388
/*
 
2389
  Template member function for ensuring that there is an rows log
 
2390
  event of the apropriate type before proceeding.
 
2391
 
 
2392
  PRE CONDITION:
 
2393
    - Events of type 'RowEventT' have the type code 'type_code'.
 
2394
    
 
2395
  POST CONDITION:
 
2396
    If a non-NULL pointer is returned, the pending event for thread 'session' will
 
2397
    be an event of type 'RowEventT' (which have the type code 'type_code')
 
2398
    will either empty or have enough space to hold 'needed' bytes.  In
 
2399
    addition, the columns bitmap will be correct for the row, meaning that
 
2400
    the pending event will be flushed if the columns in the event differ from
 
2401
    the columns suppled to the function.
 
2402
 
 
2403
  RETURNS
 
2404
    If no error, a non-NULL pending event (either one which already existed or
 
2405
    the newly created one).
 
2406
    If error, NULL.
 
2407
 */
 
2408
 
 
2409
template <class RowsEventT> Rows_log_event* 
 
2410
Session::binlog_prepare_pending_rows_event(Table* table, uint32_t serv_id,
 
2411
                                       size_t needed,
 
2412
                                       bool is_transactional,
 
2413
                                       RowsEventT *hint __attribute__((unused)))
 
2414
{
 
2415
  /* Pre-conditions */
 
2416
  assert(table->s->table_map_id != UINT32_MAX);
 
2417
 
 
2418
  /* Fetch the type code for the RowsEventT template parameter */
 
2419
  int const type_code= RowsEventT::TYPE_CODE;
 
2420
 
 
2421
  /*
 
2422
    There is no good place to set up the transactional data, so we
 
2423
    have to do it here.
 
2424
  */
 
2425
  if (binlog_setup_trx_data())
 
2426
    return(NULL);
 
2427
 
 
2428
  Rows_log_event* pending= binlog_get_pending_rows_event();
 
2429
 
 
2430
  if (unlikely(pending && !pending->is_valid()))
 
2431
    return(NULL);
 
2432
 
 
2433
  /*
 
2434
    Check if the current event is non-NULL and a write-rows
 
2435
    event. Also check if the table provided is mapped: if it is not,
 
2436
    then we have switched to writing to a new table.
 
2437
    If there is no pending event, we need to create one. If there is a pending
 
2438
    event, but it's not about the same table id, or not of the same type
 
2439
    (between Write, Update and Delete), or not the same affected columns, or
 
2440
    going to be too big, flush this event to disk and create a new pending
 
2441
    event.
 
2442
 
 
2443
    The last test is necessary for the Cluster injector to work
 
2444
    correctly. The reason is that the Cluster can inject two write
 
2445
    rows with different column bitmaps if there is an insert followed
 
2446
    by an update in the same transaction, and these are grouped into a
 
2447
    single epoch/transaction when fed to the injector.
 
2448
 
 
2449
    TODO: Fix the code so that the last test can be removed.
 
2450
  */
 
2451
  if (!pending ||
 
2452
      pending->server_id != serv_id || 
 
2453
      pending->get_table_id() != table->s->table_map_id ||
 
2454
      pending->get_type_code() != type_code || 
 
2455
      pending->get_data_size() + needed > opt_binlog_rows_event_max_size ||
 
2456
      !bitmap_cmp(pending->get_cols(), table->write_set))
 
2457
    {
 
2458
    /* Create a new RowsEventT... */
 
2459
    Rows_log_event* const
 
2460
        ev= new RowsEventT(this, table, table->s->table_map_id,
 
2461
                           is_transactional);
 
2462
    if (unlikely(!ev))
 
2463
      return(NULL);
 
2464
    ev->server_id= serv_id; // I don't like this, it's too easy to forget.
 
2465
    /*
 
2466
      flush the pending event and replace it with the newly created
 
2467
      event...
 
2468
    */
 
2469
    if (unlikely(mysql_bin_log.flush_and_set_pending_rows_event(this, ev)))
 
2470
    {
 
2471
      delete ev;
 
2472
      return(NULL);
 
2473
    }
 
2474
 
 
2475
    return(ev);               /* This is the new pending event */
 
2476
  }
 
2477
  return(pending);        /* This is the current pending event */
 
2478
}
 
2479
 
 
2480
#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
 
2481
/*
 
2482
  Instantiate the versions we need, we have -fno-implicit-template as
 
2483
  compiling option.
 
2484
*/
 
2485
template Rows_log_event*
 
2486
Session::binlog_prepare_pending_rows_event(Table*, uint32_t, size_t, bool,
 
2487
                                       Write_rows_log_event*);
 
2488
 
 
2489
template Rows_log_event*
 
2490
Session::binlog_prepare_pending_rows_event(Table*, uint32_t, size_t, bool,
 
2491
                                       Delete_rows_log_event *);
 
2492
 
 
2493
template Rows_log_event* 
 
2494
Session::binlog_prepare_pending_rows_event(Table*, uint32_t, size_t, bool,
 
2495
                                       Update_rows_log_event *);
 
2496
#endif
 
2497
 
 
2498
namespace {
 
2499
  /**
 
2500
     Class to handle temporary allocation of memory for row data.
 
2501
 
 
2502
     The responsibilities of the class is to provide memory for
 
2503
     packing one or two rows of packed data (depending on what
 
2504
     constructor is called).
 
2505
 
 
2506
     In order to make the allocation more efficient for "simple" rows,
 
2507
     i.e., rows that do not contain any blobs, a pointer to the
 
2508
     allocated memory is of memory is stored in the table structure
 
2509
     for simple rows.  If memory for a table containing a blob field
 
2510
     is requested, only memory for that is allocated, and subsequently
 
2511
     released when the object is destroyed.
 
2512
 
 
2513
   */
 
2514
  class Row_data_memory {
 
2515
  public:
 
2516
    /**
 
2517
      Build an object to keep track of a block-local piece of memory
 
2518
      for storing a row of data.
 
2519
 
 
2520
      @param table
 
2521
      Table where the pre-allocated memory is stored.
 
2522
 
 
2523
      @param length
 
2524
      Length of data that is needed, if the record contain blobs.
 
2525
     */
 
2526
    Row_data_memory(Table *table, size_t const len1)
 
2527
      : m_memory(0)
 
2528
    {
 
2529
      m_alloc_checked= false;
 
2530
      allocate_memory(table, len1);
 
2531
      m_ptr[0]= has_memory() ? m_memory : 0;
 
2532
      m_ptr[1]= 0;
 
2533
    }
 
2534
 
 
2535
    Row_data_memory(Table *table, size_t const len1, size_t const len2)
 
2536
      : m_memory(0)
 
2537
    {
 
2538
      m_alloc_checked= false;
 
2539
      allocate_memory(table, len1 + len2);
 
2540
      m_ptr[0]= has_memory() ? m_memory        : 0;
 
2541
      m_ptr[1]= has_memory() ? m_memory + len1 : 0;
 
2542
    }
 
2543
 
 
2544
    ~Row_data_memory()
 
2545
    {
 
2546
      if (m_memory != 0 && m_release_memory_on_destruction)
 
2547
        free((unsigned char*) m_memory);
 
2548
    }
 
2549
 
 
2550
    /**
 
2551
       Is there memory allocated?
 
2552
 
 
2553
       @retval true There is memory allocated
 
2554
       @retval false Memory allocation failed
 
2555
     */
 
2556
    bool has_memory() const {
 
2557
      m_alloc_checked= true;
 
2558
      return m_memory != 0;
 
2559
    }
 
2560
 
 
2561
    unsigned char *slot(uint32_t s)
 
2562
    {
 
2563
      assert(s < sizeof(m_ptr)/sizeof(*m_ptr));
 
2564
      assert(m_ptr[s] != 0);
 
2565
      assert(m_alloc_checked == true);
 
2566
      return m_ptr[s];
 
2567
    }
 
2568
 
 
2569
  private:
 
2570
    void allocate_memory(Table *const table, size_t const total_length)
 
2571
    {
 
2572
      if (table->s->blob_fields == 0)
 
2573
      {
 
2574
        /*
 
2575
          The maximum length of a packed record is less than this
 
2576
          length. We use this value instead of the supplied length
 
2577
          when allocating memory for records, since we don't know how
 
2578
          the memory will be used in future allocations.
 
2579
 
 
2580
          Since table->s->reclength is for unpacked records, we have
 
2581
          to add two bytes for each field, which can potentially be
 
2582
          added to hold the length of a packed field.
 
2583
        */
 
2584
        size_t const maxlen= table->s->reclength + 2 * table->s->fields;
 
2585
 
 
2586
        /*
 
2587
          Allocate memory for two records if memory hasn't been
 
2588
          allocated. We allocate memory for two records so that it can
 
2589
          be used when processing update rows as well.
 
2590
        */
 
2591
        if (table->write_row_record == 0)
 
2592
          table->write_row_record=
 
2593
            (unsigned char *) alloc_root(&table->mem_root, 2 * maxlen);
 
2594
        m_memory= table->write_row_record;
 
2595
        m_release_memory_on_destruction= false;
 
2596
      }
 
2597
      else
 
2598
      {
 
2599
        m_memory= (unsigned char *) my_malloc(total_length, MYF(MY_WME));
 
2600
        m_release_memory_on_destruction= true;
 
2601
      }
 
2602
    }
 
2603
 
 
2604
    mutable bool m_alloc_checked;
 
2605
    bool m_release_memory_on_destruction;
 
2606
    unsigned char *m_memory;
 
2607
    unsigned char *m_ptr[2];
 
2608
  };
 
2609
}
 
2610
 
 
2611
 
 
2612
int Session::binlog_write_row(Table* table, bool is_trans, 
 
2613
                          unsigned char const *record) 
 
2614
 
2615
  assert(current_stmt_binlog_row_based && mysql_bin_log.is_open());
 
2616
 
 
2617
  /*
 
2618
    Pack records into format for transfer. We are allocating more
 
2619
    memory than needed, but that doesn't matter.
 
2620
  */
 
2621
  Row_data_memory memory(table, table->max_row_length(record));
 
2622
  if (!memory.has_memory())
 
2623
    return HA_ERR_OUT_OF_MEM;
 
2624
 
 
2625
  unsigned char *row_data= memory.slot(0);
 
2626
 
 
2627
  size_t const len= pack_row(table, table->write_set, row_data, record);
 
2628
 
 
2629
  Rows_log_event* const ev=
 
2630
    binlog_prepare_pending_rows_event(table, server_id, len, is_trans,
 
2631
                                      static_cast<Write_rows_log_event*>(0));
 
2632
 
 
2633
  if (unlikely(ev == 0))
 
2634
    return HA_ERR_OUT_OF_MEM;
 
2635
 
 
2636
  return ev->add_row_data(row_data, len);
 
2637
}
 
2638
 
 
2639
int Session::binlog_update_row(Table* table, bool is_trans,
 
2640
                           const unsigned char *before_record,
 
2641
                           const unsigned char *after_record)
 
2642
 
2643
  assert(current_stmt_binlog_row_based && mysql_bin_log.is_open());
 
2644
 
 
2645
  size_t const before_maxlen = table->max_row_length(before_record);
 
2646
  size_t const after_maxlen  = table->max_row_length(after_record);
 
2647
 
 
2648
  Row_data_memory row_data(table, before_maxlen, after_maxlen);
 
2649
  if (!row_data.has_memory())
 
2650
    return HA_ERR_OUT_OF_MEM;
 
2651
 
 
2652
  unsigned char *before_row= row_data.slot(0);
 
2653
  unsigned char *after_row= row_data.slot(1);
 
2654
 
 
2655
  size_t const before_size= pack_row(table, table->read_set, before_row,
 
2656
                                        before_record);
 
2657
  size_t const after_size= pack_row(table, table->write_set, after_row,
 
2658
                                       after_record);
 
2659
 
 
2660
  Rows_log_event* const ev=
 
2661
    binlog_prepare_pending_rows_event(table, server_id,
 
2662
                                      before_size + after_size, is_trans,
 
2663
                                      static_cast<Update_rows_log_event*>(0));
 
2664
 
 
2665
  if (unlikely(ev == 0))
 
2666
    return HA_ERR_OUT_OF_MEM;
 
2667
 
 
2668
  return
 
2669
    ev->add_row_data(before_row, before_size) ||
 
2670
    ev->add_row_data(after_row, after_size);
 
2671
}
 
2672
 
 
2673
int Session::binlog_delete_row(Table* table, bool is_trans, 
 
2674
                           unsigned char const *record)
 
2675
 
2676
  assert(current_stmt_binlog_row_based && mysql_bin_log.is_open());
 
2677
 
 
2678
  /* 
 
2679
     Pack records into format for transfer. We are allocating more
 
2680
     memory than needed, but that doesn't matter.
 
2681
  */
 
2682
  Row_data_memory memory(table, table->max_row_length(record));
 
2683
  if (unlikely(!memory.has_memory()))
 
2684
    return HA_ERR_OUT_OF_MEM;
 
2685
 
 
2686
  unsigned char *row_data= memory.slot(0);
 
2687
 
 
2688
  size_t const len= pack_row(table, table->read_set, row_data, record);
 
2689
 
 
2690
  Rows_log_event* const ev=
 
2691
    binlog_prepare_pending_rows_event(table, server_id, len, is_trans,
 
2692
                                      static_cast<Delete_rows_log_event*>(0));
 
2693
 
 
2694
  if (unlikely(ev == 0))
 
2695
    return HA_ERR_OUT_OF_MEM;
 
2696
 
 
2697
  return ev->add_row_data(row_data, len);
 
2698
}
 
2699
 
 
2700
 
 
2701
int Session::binlog_flush_pending_rows_event(bool stmt_end)
 
2702
{
 
2703
  /*
 
2704
    We shall flush the pending event even if we are not in row-based
 
2705
    mode: it might be the case that we left row-based mode before
 
2706
    flushing anything (e.g., if we have explicitly locked tables).
 
2707
   */
 
2708
  if (!mysql_bin_log.is_open())
 
2709
    return(0);
 
2710
 
 
2711
  /*
 
2712
    Mark the event as the last event of a statement if the stmt_end
 
2713
    flag is set.
 
2714
  */
 
2715
  int error= 0;
 
2716
  if (Rows_log_event *pending= binlog_get_pending_rows_event())
 
2717
  {
 
2718
    if (stmt_end)
 
2719
    {
 
2720
      pending->set_flags(Rows_log_event::STMT_END_F);
 
2721
      pending->flags|= LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F;
 
2722
      binlog_table_maps= 0;
 
2723
    }
 
2724
 
 
2725
    error= mysql_bin_log.flush_and_set_pending_rows_event(this, 0);
 
2726
  }
 
2727
 
 
2728
  return(error);
 
2729
}
 
2730
 
 
2731
 
 
2732
/*
 
2733
  Member function that will log query, either row-based or
 
2734
  statement-based depending on the value of the 'current_stmt_binlog_row_based'
 
2735
  the value of the 'qtype' flag.
 
2736
 
 
2737
  This function should be called after the all calls to ha_*_row()
 
2738
  functions have been issued, but before tables are unlocked and
 
2739
  closed.
 
2740
 
 
2741
  OBSERVE
 
2742
    There shall be no writes to any system table after calling
 
2743
    binlog_query(), so these writes has to be moved to before the call
 
2744
    of binlog_query() for correct functioning.
 
2745
 
 
2746
    This is necessesary not only for RBR, but the master might crash
 
2747
    after binlogging the query but before changing the system tables.
 
2748
    This means that the slave and the master are not in the same state
 
2749
    (after the master has restarted), so therefore we have to
 
2750
    eliminate this problem.
 
2751
 
 
2752
  RETURN VALUE
 
2753
    Error code, or 0 if no error.
 
2754
*/
 
2755
int Session::binlog_query(Session::enum_binlog_query_type qtype, char const *query_arg,
 
2756
                      ulong query_len, bool is_trans, bool suppress_use,
 
2757
                      Session::killed_state killed_status_arg)
 
2758
{
 
2759
  assert(query_arg && mysql_bin_log.is_open());
 
2760
 
 
2761
  if (int error= binlog_flush_pending_rows_event(true))
 
2762
    return(error);
 
2763
 
 
2764
  /*
 
2765
    If we are in statement mode and trying to log an unsafe statement,
 
2766
    we should print a warning.
 
2767
  */
 
2768
  if (lex->is_stmt_unsafe() &&
 
2769
      variables.binlog_format == BINLOG_FORMAT_STMT)
 
2770
  {
 
2771
    assert(this->query != NULL);
 
2772
    push_warning(this, DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
2773
                 ER_BINLOG_UNSAFE_STATEMENT,
 
2774
                 ER(ER_BINLOG_UNSAFE_STATEMENT));
 
2775
    if (!(binlog_flags & BINLOG_FLAG_UNSAFE_STMT_PRINTED))
 
2776
    {
 
2777
      char warn_buf[DRIZZLE_ERRMSG_SIZE];
 
2778
      snprintf(warn_buf, DRIZZLE_ERRMSG_SIZE, "%s Statement: %s",
 
2779
               ER(ER_BINLOG_UNSAFE_STATEMENT), this->query);
 
2780
      sql_print_warning("%s",warn_buf);
 
2781
      binlog_flags|= BINLOG_FLAG_UNSAFE_STMT_PRINTED;
 
2782
    }
 
2783
  }
 
2784
 
 
2785
  switch (qtype) {
 
2786
  case Session::ROW_QUERY_TYPE:
 
2787
    if (current_stmt_binlog_row_based)
 
2788
      return(0);
 
2789
    /* Otherwise, we fall through */
 
2790
  case Session::DRIZZLE_QUERY_TYPE:
 
2791
    /*
 
2792
      Using this query type is a conveniece hack, since we have been
 
2793
      moving back and forth between using RBR for replication of
 
2794
      system tables and not using it.
 
2795
 
 
2796
      Make sure to change in check_table_binlog_row_based() according
 
2797
      to how you treat this.
 
2798
    */
 
2799
  case Session::STMT_QUERY_TYPE:
 
2800
    /*
 
2801
      The DRIZZLE_LOG::write() function will set the STMT_END_F flag and
 
2802
      flush the pending rows event if necessary.
 
2803
     */
 
2804
    {
 
2805
      Query_log_event qinfo(this, query_arg, query_len, is_trans, suppress_use,
 
2806
                            killed_status_arg);
 
2807
      qinfo.flags|= LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F;
 
2808
      /*
 
2809
        Binlog table maps will be irrelevant after a Query_log_event
 
2810
        (they are just removed on the slave side) so after the query
 
2811
        log event is written to the binary log, we pretend that no
 
2812
        table maps were written.
 
2813
       */
 
2814
      int error= mysql_bin_log.write(&qinfo);
 
2815
      binlog_table_maps= 0;
 
2816
      return(error);
 
2817
    }
 
2818
    break;
 
2819
 
 
2820
  case Session::QUERY_TYPE_COUNT:
 
2821
  default:
 
2822
    assert(0 <= qtype && qtype < QUERY_TYPE_COUNT);
 
2823
  }
 
2824
  return(0);
 
2825
}
 
2826
 
 
2827
bool Discrete_intervals_list::append(uint64_t start, uint64_t val,
 
2828
                                 uint64_t incr)
 
2829
{
 
2830
  /* first, see if this can be merged with previous */
 
2831
  if ((head == NULL) || tail->merge_if_contiguous(start, val, incr))
 
2832
  {
 
2833
    /* it cannot, so need to add a new interval */
 
2834
    Discrete_interval *new_interval= new Discrete_interval(start, val, incr);
 
2835
    return(append(new_interval));
 
2836
  }
 
2837
  return(0);
 
2838
}
 
2839
 
 
2840
bool Discrete_intervals_list::append(Discrete_interval *new_interval)
 
2841
{
 
2842
  if (unlikely(new_interval == NULL))
 
2843
    return(1);
 
2844
  if (head == NULL)
 
2845
    head= current= new_interval;
 
2846
  else
 
2847
    tail->next= new_interval;
 
2848
  tail= new_interval;
 
2849
  elements++;
 
2850
  return(0);
 
2851
}