sql_class.cc 103 KB
Newer Older
1
/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc.
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2

bk@work.mysql.com's avatar
bk@work.mysql.com committed
3 4
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
5
   the Free Software Foundation; version 2 of the License.
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
6

bk@work.mysql.com's avatar
bk@work.mysql.com committed
7 8 9 10
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
11

bk@work.mysql.com's avatar
bk@work.mysql.com committed
12 13 14 15 16 17 18 19 20 21 22 23
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */


/*****************************************************************************
**
** This file implements classes defined in sql_class.h
** Especially the classes to handle a result from a select
**
*****************************************************************************/

24
#ifdef USE_PRAGMA_IMPLEMENTATION
bk@work.mysql.com's avatar
bk@work.mysql.com committed
25 26 27 28
#pragma implementation				// gcc: Class implementation
#endif

#include "mysql_priv.h"
29
#include "rpl_rli.h"
30
#include "rpl_record.h"
31
#include "slave.h"
32 33
#include <my_bitmap.h>
#include "log_event.h"
bk@work.mysql.com's avatar
bk@work.mysql.com committed
34 35
#include <m_ctype.h>
#include <sys/stat.h>
36
#include <thr_alarm.h>
bk@work.mysql.com's avatar
bk@work.mysql.com committed
37 38 39
#ifdef	__WIN__
#include <io.h>
#endif
40
#include <mysys_err.h>
bk@work.mysql.com's avatar
bk@work.mysql.com committed
41

monty@mysql.com's avatar
monty@mysql.com committed
42 43
#include "sp_rcontext.h"
#include "sp_cache.h"
44

45 46 47 48 49
/*
  The following is used to initialise Table_ident with a internal
  table name
*/
char internal_table_name[2]= "*";
50
char empty_c_string[1]= {0};    /* used for not defined db */
51

52 53
const char * const THD::DEFAULT_WHERE= "field list";

54

bk@work.mysql.com's avatar
bk@work.mysql.com committed
55 56 57 58
/*****************************************************************************
** Instansiate templates
*****************************************************************************/

59
#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
bk@work.mysql.com's avatar
bk@work.mysql.com committed
60 61 62
/* Used templates */
template class List<Key>;
template class List_iterator<Key>;
63 64
template class List<Key_part_spec>;
template class List_iterator<Key_part_spec>;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
65 66 67 68 69 70 71 72 73 74
template class List<Alter_drop>;
template class List_iterator<Alter_drop>;
template class List<Alter_column>;
template class List_iterator<Alter_column>;
#endif

/****************************************************************************
** User variables
****************************************************************************/

75 76
extern "C" uchar *get_var_key(user_var_entry *entry, size_t *length,
                              my_bool not_used __attribute__((unused)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
77
{
78 79
  *length= entry->name.length;
  return (uchar*) entry->name.str;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
80 81
}

82
extern "C" void free_user_var(user_var_entry *entry)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
83 84 85 86 87 88 89
{
  char *pos= (char*) entry+ALIGN_SIZE(sizeof(*entry));
  if (entry->value && entry->value != pos)
    my_free(entry->value, MYF(0));
  my_free((char*) entry,MYF(0));
}

90
bool Key_part_spec::operator==(const Key_part_spec& other) const
91 92 93 94
{
  return length == other.length && !strcmp(field_name, other.field_name);
}

95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
/**
  Construct an (almost) deep copy of this key. Only those
  elements that are known to never change are not copied.
  If out of memory, a partial copy is returned and an error is set
  in THD.
*/

Key::Key(const Key &rhs, MEM_ROOT *mem_root)
  :type(rhs.type),
  key_create_info(rhs.key_create_info),
  columns(rhs.columns, mem_root),
  name(rhs.name),
  generated(rhs.generated)
{
  list_copy_and_replace_each_value(columns, mem_root);
}

/**
  Construct an (almost) deep copy of this foreign key. Only those
  elements that are known to never change are not copied.
  If out of memory, a partial copy is returned and an error is set
  in THD.
*/

119
Foreign_key::Foreign_key(const Foreign_key &rhs, MEM_ROOT *mem_root)
120 121 122 123 124 125 126 127 128
  :Key(rhs),
  ref_table(rhs.ref_table),
  ref_columns(rhs.ref_columns),
  delete_opt(rhs.delete_opt),
  update_opt(rhs.update_opt),
  match_opt(rhs.match_opt)
{
  list_copy_and_replace_each_value(ref_columns, mem_root);
}
129 130

/*
131
  Test if a foreign key (= generated key) is a prefix of the given key
132 133 134 135 136 137 138 139 140 141 142 143 144 145
  (ignoring key name, key type and order of columns)

  NOTES:
    This is only used to test if an index for a FOREIGN KEY exists

  IMPLEMENTATION
    We only compare field names

  RETURN
    0	Generated key is a prefix of other key
    1	Not equal
*/

bool foreign_key_prefix(Key *a, Key *b)
146
{
147 148 149 150
  /* Ensure that 'a' is the generated key */
  if (a->generated)
  {
    if (b->generated && a->columns.elements > b->columns.elements)
151
      swap_variables(Key*, a, b);               // Put shorter key in 'a'
152 153
  }
  else
154
  {
155 156
    if (!b->generated)
      return TRUE;                              // No foreign key
157
    swap_variables(Key*, a, b);                 // Put generated key in 'a'
158 159 160 161 162 163
  }

  /* Test if 'a' is a prefix of 'b' */
  if (a->columns.elements > b->columns.elements)
    return TRUE;                                // Can't be prefix

164 165 166
  List_iterator<Key_part_spec> col_it1(a->columns);
  List_iterator<Key_part_spec> col_it2(b->columns);
  const Key_part_spec *col1, *col2;
167 168 169 170 171 172 173

#ifdef ENABLE_WHEN_INNODB_CAN_HANDLE_SWAPED_FOREIGN_KEY_COLUMNS
  while ((col1= col_it1++))
  {
    bool found= 0;
    col_it2.rewind();
    while ((col2= col_it2++))
174
    {
175 176 177 178 179
      if (*col1 == *col2)
      {
        found= TRUE;
	break;
      }
180
    }
181 182 183 184 185 186 187 188 189 190
    if (!found)
      return TRUE;                              // Error
  }
  return FALSE;                                 // Is prefix
#else
  while ((col1= col_it1++))
  {
    col2= col_it2++;
    if (!(*col1 == *col2))
      return TRUE;
191
  }
192 193
  return FALSE;                                 // Is prefix
#endif
194 195 196
}


bk@work.mysql.com's avatar
bk@work.mysql.com committed
197 198 199
/****************************************************************************
** Thread specific functions
****************************************************************************/
200

201 202 203 204 205 206 207 208 209 210 211 212 213
/** Push an error to the error stack and return TRUE for now. */

bool
Reprepare_observer::report_error(THD *thd)
{
  my_error(ER_NEED_REPREPARE, MYF(ME_NO_WARNING_FOR_ERROR|ME_NO_SP_HANDLER));

  m_invalidated= TRUE;

  return TRUE;
}


214
Open_tables_state::Open_tables_state(ulong version_arg)
215
  :version(version_arg), state_flags(0U)
216 217 218 219
{
  reset_open_tables_state();
}

antony@ppcg5.local's avatar
antony@ppcg5.local committed
220 221 222 223
/*
  The following functions form part of the C plugin API
*/

224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
extern "C" int mysql_tmpfile(const char *prefix)
{
  char filename[FN_REFLEN];
  File fd = create_temp_file(filename, mysql_tmpdir, prefix,
#ifdef __WIN__
                             O_BINARY | O_TRUNC | O_SEQUENTIAL |
                             O_SHORT_LIVED |
#endif /* __WIN__ */
                             O_CREAT | O_EXCL | O_RDWR | O_TEMPORARY,
                             MYF(MY_WME));
  if (fd >= 0) {
#ifndef __WIN__
    /*
      This can be removed once the following bug is fixed:
      Bug #28903  create_temp_file() doesn't honor O_TEMPORARY option
                  (file not removed) (Unix)
    */
    unlink(filename);
#endif /* !__WIN__ */
  }

  return fd;
}


antony@ppcg5.local's avatar
antony@ppcg5.local committed
249
extern "C"
antony@ppcg5.local's avatar
antony@ppcg5.local committed
250
int thd_in_lock_tables(const THD *thd)
251
{
antony@ppcg5.local's avatar
antony@ppcg5.local committed
252
  return test(thd->in_lock_tables);
253 254 255
}


antony@ppcg5.local's avatar
antony@ppcg5.local committed
256
extern "C"
antony@ppcg5.local's avatar
antony@ppcg5.local committed
257
int thd_tablespace_op(const THD *thd)
258
{
antony@ppcg5.local's avatar
antony@ppcg5.local committed
259
  return test(thd->tablespace_op);
260 261 262
}


antony@ppcg5.local's avatar
antony@ppcg5.local committed
263
extern "C"
264 265 266 267
const char *set_thd_proc_info(THD *thd, const char *info, 
                              const char *calling_function, 
                              const char *calling_file, 
                              const unsigned int calling_line)
268 269
{
  const char *old_info= thd->proc_info;
270 271
  DBUG_PRINT("proc_info", ("%s:%d  %s", calling_file, calling_line, 
                           (info != NULL) ? info : "(null)"));
272 273 274
#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
  thd->profiling.status_change(info, calling_function, calling_file, calling_line);
#endif
275 276 277 278
  thd->proc_info= info;
  return old_info;
}

antony@ppcg5.local's avatar
antony@ppcg5.local committed
279
extern "C"
280 281
void **thd_ha_data(const THD *thd, const struct handlerton *hton)
{
282
  return (void **) &thd->ha_data[hton->slot].ha_ptr;
283 284
}

antony@ppcg5.local's avatar
antony@ppcg5.local committed
285
extern "C"
antony@ppcg5.local's avatar
antony@ppcg5.local committed
286 287 288 289 290
long long thd_test_options(const THD *thd, long long test_options)
{
  return thd->options & test_options;
}

antony@ppcg5.local's avatar
antony@ppcg5.local committed
291
extern "C"
antony@ppcg5.local's avatar
antony@ppcg5.local committed
292 293 294 295 296
int thd_sql_command(const THD *thd)
{
  return (int) thd->lex->sql_command;
}

297 298 299 300 301 302
extern "C"
int thd_tx_isolation(const THD *thd)
{
  return (int) thd->variables.tx_isolation;
}

303 304 305 306 307
extern "C"
void thd_inc_row_count(THD *thd)
{
  thd->row_count++;
}
antony@ppcg5.local's avatar
antony@ppcg5.local committed
308

309 310

/**
antony@ppcg5.local's avatar
antony@ppcg5.local committed
311 312
  Dumps a text description of a thread, its security context
  (user, host) and the current query.
313

314
  @param thd thread context
315 316 317 318 319 320 321 322 323 324 325
  @param buffer pointer to preferred result buffer
  @param length length of buffer
  @param max_query_len how many chars of query to copy (0 for all)

  @req LOCK_thread_count
  
  @note LOCK_thread_count mutex is not necessary when the function is invoked on
   the currently running thread (current_thd) or if the caller in some other
   way guarantees that access to thd->query is serialized.
 
  @return Pointer to string
antony@ppcg5.local's avatar
antony@ppcg5.local committed
326
*/
327

antony@ppcg5.local's avatar
antony@ppcg5.local committed
328
extern "C"
serg@janus.mylan's avatar
serg@janus.mylan committed
329 330
char *thd_security_context(THD *thd, char *buffer, unsigned int length,
                           unsigned int max_query_len)
antony@ppcg5.local's avatar
antony@ppcg5.local committed
331 332 333 334 335
{
  String str(buffer, length, &my_charset_latin1);
  const Security_context *sctx= &thd->main_security_ctx;
  char header[64];
  int len;
336 337 338 339 340 341 342 343 344 345
  /*
    The pointers thd->query and thd->proc_info might change since they are
    being modified concurrently. This is acceptable for proc_info since its
    values doesn't have to very accurate and the memory it points to is static,
    but we need to attempt a snapshot on the pointer values to avoid using NULL
    values. The pointer to thd->query however, doesn't point to static memory
    and has to be protected by LOCK_thread_count or risk pointing to
    uninitialized memory.
  */
  const char *proc_info= thd->proc_info;
346 347

  len= my_snprintf(header, sizeof(header),
antony@ppcg5.local's avatar
antony@ppcg5.local committed
348 349 350 351
                   "MySQL thread id %lu, query id %lu",
                   thd->thread_id, (ulong) thd->query_id);
  str.length(0);
  str.append(header, len);
352

antony@ppcg5.local's avatar
antony@ppcg5.local committed
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370
  if (sctx->host)
  {
    str.append(' ');
    str.append(sctx->host);
  }

  if (sctx->ip)
  {
    str.append(' ');
    str.append(sctx->ip);
  }

  if (sctx->user)
  {
    str.append(' ');
    str.append(sctx->user);
  }

371
  if (proc_info)
antony@ppcg5.local's avatar
antony@ppcg5.local committed
372 373
  {
    str.append(' ');
374
    str.append(proc_info);
antony@ppcg5.local's avatar
antony@ppcg5.local committed
375 376 377 378 379 380 381 382 383 384 385 386 387
  }

  if (thd->query)
  {
    if (max_query_len < 1)
      len= thd->query_length;
    else
      len= min(thd->query_length, max_query_len);
    str.append('\n');
    str.append(thd->query, len);
  }
  if (str.c_ptr_safe() == buffer)
    return buffer;
388 389 390 391 392 393 394 395 396 397 398

  /*
    We have to copy the new string to the destination buffer because the string
    was reallocated to a larger buffer to be able to fit.
  */
  DBUG_ASSERT(buffer != NULL);
  length= min(str.length(), length-1);
  memcpy(buffer, str.c_ptr_quick(), length);
  /* Make sure that the new string is null terminated */
  buffer[length]= '\0';
  return buffer;
antony@ppcg5.local's avatar
antony@ppcg5.local committed
399
}
400

401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432
/**
  Clear this diagnostics area. 

  Normally called at the end of a statement.
*/

void
Diagnostics_area::reset_diagnostics_area()
{
#ifdef DBUG_OFF
  can_overwrite_status= FALSE;
  /** Don't take chances in production */
  m_message[0]= '\0';
  m_sql_errno= 0;
  m_server_status= 0;
  m_affected_rows= 0;
  m_last_insert_id= 0;
  m_total_warn_count= 0;
#endif
  is_sent= FALSE;
  /** Tiny reset in debug mode to see garbage right away */
  m_status= DA_EMPTY;
}


/**
  Set OK status -- ends commands that do not return a
  result set, e.g. INSERT/UPDATE/DELETE.
*/

void
Diagnostics_area::set_ok_status(THD *thd, ha_rows affected_rows_arg,
433
                                ulonglong last_insert_id_arg,
434 435 436 437
                                const char *message_arg)
{
  DBUG_ASSERT(! is_set());
#ifdef DBUG_OFF
438 439 440 441 442
  /*
    In production, refuse to overwrite an error or a custom response
    with an OK packet.
  */
  if (is_error() || is_disabled())
443 444 445 446 447 448 449 450 451
    return;
#endif
  /** Only allowed to report success if has not yet reported an error */

  m_server_status= thd->server_status;
  m_total_warn_count= thd->total_warn_count;
  m_affected_rows= affected_rows_arg;
  m_last_insert_id= last_insert_id_arg;
  if (message_arg)
452
    strmake(m_message, message_arg, sizeof(m_message) - 1);
453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469
  else
    m_message[0]= '\0';
  m_status= DA_OK;
}


/**
  Set EOF status.
*/

void
Diagnostics_area::set_eof_status(THD *thd)
{
  /** Only allowed to report eof if has not yet reported an error */

  DBUG_ASSERT(! is_set());
#ifdef DBUG_OFF
470 471 472 473 474
  /*
    In production, refuse to overwrite an error or a custom response
    with an EOF packet.
  */
  if (is_error() || is_disabled())
475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502
    return;
#endif

  m_server_status= thd->server_status;
  /*
    If inside a stored procedure, do not return the total
    number of warnings, since they are not available to the client
    anyway.
  */
  m_total_warn_count= thd->spcont ? 0 : thd->total_warn_count;

  m_status= DA_EOF;
}

/**
  Set ERROR status.
*/

void
Diagnostics_area::set_error_status(THD *thd, uint sql_errno_arg,
                                   const char *message_arg)
{
  /*
    Only allowed to report error if has not yet reported a success
    The only exception is when we flush the message to the client,
    an error can happen during the flush.
  */
  DBUG_ASSERT(! is_set() || can_overwrite_status);
503 504 505 506 507 508 509 510
#ifdef DBUG_OFF
  /*
    In production, refuse to overwrite a custom response with an
    ERROR packet.
  */
  if (is_disabled())
    return;
#endif
511 512

  m_sql_errno= sql_errno_arg;
513
  strmake(m_message, message_arg, sizeof(m_message) - 1);
514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532

  m_status= DA_ERROR;
}


/**
  Mark the diagnostics area as 'DISABLED'.

  This is used in rare cases when the COM_ command at hand sends a response
  in a custom format. One example is the query cache, another is
  COM_STMT_PREPARE.
*/

void
Diagnostics_area::disable_status()
{
  DBUG_ASSERT(! is_set());
  m_status= DA_DISABLED;
}
533

bk@work.mysql.com's avatar
bk@work.mysql.com committed
534

535
THD::THD()
536 537
   :Statement(&main_lex, &main_mem_root, CONVENTIONAL_EXECUTION,
              /* statement id */ 0),
538
   Open_tables_state(refresh_version), rli_fake(0),
539
   lock_id(&main_lock_id),
540
   user_time(0), in_sub_stmt(0),
541
   sql_log_bin_toplevel(false),
542
   binlog_table_maps(0), binlog_flags(0UL),
He Zhenxing's avatar
He Zhenxing committed
543
   table_map_for_update(0),
544 545 546 547 548
   arg_of_last_insert_id_function(FALSE),
   first_successful_insert_id_in_prev_stmt(0),
   first_successful_insert_id_in_prev_stmt_for_binlog(0),
   first_successful_insert_id_in_cur_stmt(0),
   stmt_depends_on_first_successful_insert_id_in_prev_stmt(FALSE),
serg@janus.mylan's avatar
serg@janus.mylan committed
549 550
   global_read_lock(0),
   is_fatal_error(0),
551 552
   transaction_rollback_request(0),
   is_fatal_sub_stmt_error(0),
serg@janus.mylan's avatar
serg@janus.mylan committed
553 554 555 556 557
   rand_used(0),
   time_zone_used(0),
   in_lock_tables(0),
   bootstrap(0),
   derived_tables_processing(FALSE),
558
   spcont(NULL),
559
   m_parser_state(NULL)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
560
{
561 562
  ulong tmp;

563 564 565 566 567 568
  /*
    Pass nominal parameters to init_alloc_root only to ensure that
    the destructor works OK in case of an error. The main_mem_root
    will be re-initialized in init_for_queries().
  */
  init_sql_alloc(&main_mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0);
konstantin@mysql.com's avatar
konstantin@mysql.com committed
569
  stmt_arena= this;
570
  thread_stack= 0;
571
  catalog= (char*)"std"; // the only catalog we have for now
572 573
  main_security_ctx.init();
  security_ctx= &main_security_ctx;
pem@mysql.com's avatar
pem@mysql.com committed
574
  locked=some_tables_deleted=no_errors=password= 0;
konstantin@oak.local's avatar
konstantin@oak.local committed
575
  query_start_used= 0;
576
  count_cuted_fields= CHECK_FIELD_IGNORE;
hf@genie.(none)'s avatar
SCRUM  
hf@genie.(none) committed
577
  killed= NOT_KILLED;
578
  col_access=0;
579
  is_slave_error= thread_specific_used= FALSE;
580
  hash_clear(&handler_tables_hash);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
581
  tmp_table=0;
582
  used_tables=0;
583
  cuted_fields= sent_row_count= row_count= 0L;
584
  limit_found_rows= 0;
585
  row_count_func= -1;
586
  statement_id_counter= 0UL;
587 588 589
#ifdef ERROR_INJECT_SUPPORT
  error_inject_value= 0UL;
#endif
590
  // Must be reset to handle error with THD's created for init of mysqld
konstantin@oak.local's avatar
konstantin@oak.local committed
591
  lex->current_select= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
592
  start_time=(time_t) 0;
593 594
  start_utime= 0L;
  utime_after_lock= 0L;
595
  current_linfo =  0;
596
  slave_thread = 0;
597
  bzero(&variables, sizeof(variables));
598
  thread_id= 0;
599
  one_shot_set= 0;
600
  file_id = 0;
601
  query_id= 0;
602
  query_name_consts= 0;
603
  warn_id= 0;
604
  db_charset= global_system_variables.collation_database;
605
  bzero(ha_data, sizeof(ha_data));
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
606
  mysys_var=0;
607
  binlog_evt_union.do_union= FALSE;
608
  enable_slow_log= 0;
609 610
#ifndef DBUG_OFF
  dbug_sentry=THD_SENTRY_MAGIC;
611
#endif
612
#ifndef EMBEDDED_LIBRARY
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
613
  net.vio=0;
614
#endif
615
  client_capabilities= 0;                       // minimalistic client
616
#ifdef HAVE_QUERY_CACHE
617
  query_cache_init_query(&net);                 // If error on boot
618
#endif
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
619
  ull=0;
620 621
  system_thread= NON_SYSTEM_THREAD;
  cleanup_done= abort_on_warning= no_warnings_for_error= 0;
622
  peer_port= 0;					// For SHOW PROCESSLIST
623
  transaction.m_pending_rows_event= 0;
624
  transaction.on= 1;
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
625 626
#ifdef SIGNAL_WITH_VIO_CLOSE
  active_vio = 0;
627
#endif
628
  pthread_mutex_init(&LOCK_delete, MY_MUTEX_INIT_FAST);
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
629 630 631

  /* Variables with default values */
  proc_info="login";
632
  where= THD::DEFAULT_WHERE;
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
633
  server_id = ::server_id;
634
  slave_net = 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
635
  command=COM_CONNECT;
636
  *scramble= '\0';
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
637

638
  init();
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
639
  /* Initialize sub structures */
640
  init_sql_alloc(&warn_root, WARN_ALLOC_BLOCK_SIZE, WARN_ALLOC_PREALLOC_SIZE);
641
#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
642
  profiling.set_thd(this);
643
#endif
644
  user_connect=(USER_CONN *)0;
645
  hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
646
	    (hash_get_key) get_var_key,
647
	    (hash_free_key) free_user_var, 0);
648

649 650
  sp_proc_cache= NULL;
  sp_func_cache= NULL;
651

652 653 654
  /* For user vars replication*/
  if (opt_bin_log)
    my_init_dynamic_array(&user_var_events,
655
			  sizeof(BINLOG_USER_VAR_EVENT *), 16, 16);
656 657 658
  else
    bzero((char*) &user_var_events, sizeof(user_var_events));

659
  /* Protocol */
660 661 662
  protocol= &protocol_text;			// Default protocol
  protocol_text.init(this);
  protocol_binary.init(this);
663

heikki@hundin.mysql.fi's avatar
heikki@hundin.mysql.fi committed
664
  tablespace_op=FALSE;
665 666
  tmp= sql_rnd_with_mutex();
  randominit(&rand, tmp + (ulong) &rand, tmp + (ulong) ::global_query_id);
667
  substitute_null_with_insert_id = FALSE;
668 669
  thr_lock_info_init(&lock_info); /* safety: will be reset after start */
  thr_lock_owner_init(&main_lock_id, &lock_info);
670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685

  m_internal_handler= NULL;
}


void THD::push_internal_handler(Internal_error_handler *handler)
{
  /*
    TODO: The current implementation is limited to 1 handler at a time only.
    THD and sp_rcontext need to be modified to use a common handler stack.
  */
  DBUG_ASSERT(m_internal_handler == NULL);
  m_internal_handler= handler;
}


686
bool THD::handle_error(uint sql_errno, const char *message,
687 688 689 690
                       MYSQL_ERROR::enum_warning_level level)
{
  if (m_internal_handler)
  {
691
    return m_internal_handler->handle_error(sql_errno, message, level, this);
692 693 694 695 696 697 698 699 700 701
  }

  return FALSE;                                 // 'FALSE', as per coding style
}


void THD::pop_internal_handler()
{
  DBUG_ASSERT(m_internal_handler != NULL);
  m_internal_handler= NULL;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
702 703
}

704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742
extern "C"
void *thd_alloc(MYSQL_THD thd, unsigned int size)
{
  return thd->alloc(size);
}

extern "C"
void *thd_calloc(MYSQL_THD thd, unsigned int size)
{
  return thd->calloc(size);
}

extern "C"
char *thd_strdup(MYSQL_THD thd, const char *str)
{
  return thd->strdup(str);
}

extern "C"
char *thd_strmake(MYSQL_THD thd, const char *str, unsigned int size)
{
  return thd->strmake(str, size);
}

extern "C"
LEX_STRING *thd_make_lex_string(THD *thd, LEX_STRING *lex_str,
                                const char *str, unsigned int size,
                                int allocate_lex_string)
{
  return thd->make_lex_string(lex_str, str, size,
                              (bool) allocate_lex_string);
}

extern "C"
void *thd_memdup(MYSQL_THD thd, const void* str, unsigned int size)
{
  return thd->memdup(str, size);
}

743
extern "C"
744 745 746 747
void thd_get_xid(const MYSQL_THD thd, MYSQL_XID *xid)
{
  *xid = *(MYSQL_XID *) &thd->transaction.xid_state.xid;
}
748 749 750 751 752 753 754

/*
  Init common variables that has to be reset on start and on change_user
*/

void THD::init(void)
{
755
  pthread_mutex_lock(&LOCK_global_system_variables);
antony@ppcg5.local's avatar
antony@ppcg5.local committed
756
  plugin_thdvar_init(this);
757 758 759 760 761 762
  variables.time_format= date_time_format_copy((THD*) 0,
					       variables.time_format);
  variables.date_format= date_time_format_copy((THD*) 0,
					       variables.date_format);
  variables.datetime_format= date_time_format_copy((THD*) 0,
						   variables.datetime_format);
763 764 765 766 767 768
  /*
    variables= global_system_variables above has reset
    variables.pseudo_thread_id to 0. We need to correct it here to
    avoid temporary tables replication failure.
  */
  variables.pseudo_thread_id= thread_id;
769
  pthread_mutex_unlock(&LOCK_global_system_variables);
770
  server_status= SERVER_STATUS_AUTOCOMMIT;
771 772
  if (variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES)
    server_status|= SERVER_STATUS_NO_BACKSLASH_ESCAPES;
773
  options= thd_startup_options;
774 775 776 777 778 779

  if (variables.max_join_size == HA_POS_ERROR)
    options |= OPTION_BIG_SELECTS;
  else
    options &= ~OPTION_BIG_SELECTS;

780
  transaction.all.modified_non_trans_table= transaction.stmt.modified_non_trans_table= FALSE;
781
  open_options=ha_open_options;
782 783 784
  update_lock_default= (variables.low_priority_updates ?
			TL_WRITE_LOW_PRIORITY :
			TL_WRITE);
785
  session_tx_isolation= (enum_tx_isolation) variables.tx_isolation;
786 787 788
  warn_list.empty();
  bzero((char*) warn_count, sizeof(warn_count));
  total_warn_count= 0;
789
  update_charset();
790
  reset_current_stmt_binlog_row_based();
791
  bzero((char *) &status_var, sizeof(status_var));
792
  sql_log_bin_toplevel= options & OPTION_BIN_LOG;
793 794
}

795

796 797 798 799 800 801 802 803
/*
  Init THD for query processing.
  This has to be called once before we call mysql_parse.
  See also comments in sql_class.h.
*/

void THD::init_for_queries()
{
804
  set_time(); 
805
  ha_enable_transaction(this,TRUE);
806

807
  reset_root_defaults(mem_root, variables.query_alloc_block_size,
808
                      variables.query_prealloc_size);
809
#ifdef USING_TRANSACTIONS
810 811 812
  reset_root_defaults(&transaction.mem_root,
                      variables.trans_alloc_block_size,
                      variables.trans_prealloc_size);
813
#endif
814 815
  transaction.xid_state.xid.null();
  transaction.xid_state.in_thd=1;
816 817 818
}


819 820 821 822 823 824 825 826 827 828 829 830 831
/*
  Do what's needed when one invokes change user

  SYNOPSIS
    change_user()

  IMPLEMENTATION
    Reset all resources that are connection specific
*/


void THD::change_user(void)
{
832 833 834 835
  pthread_mutex_lock(&LOCK_status);
  add_to_status(&global_status_var, &status_var);
  pthread_mutex_unlock(&LOCK_status);

836
  cleanup();
837
  killed= NOT_KILLED;
838
  cleanup_done= 0;
839
  init();
840
  stmt_map.reset();
841
  hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0,
842
	    (hash_get_key) get_var_key,
843
	    (hash_free_key) free_user_var, 0);
844 845
  sp_cache_clear(&sp_proc_cache);
  sp_cache_clear(&sp_func_cache);
846 847 848
}


monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
849 850 851
/* Do operations that may take a long time */

void THD::cleanup(void)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
852
{
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
853
  DBUG_ENTER("THD::cleanup");
854 855
  DBUG_ASSERT(cleanup_done == 0);

856
  killed= KILL_CONNECTION;
857
#ifdef ENABLE_WHEN_BINLOG_WILL_BE_ABLE_TO_PREPARE
858 859 860 861
  if (transaction.xid_state.xa_state == XA_PREPARED)
  {
#error xid_state in the cache should be replaced by the allocated value
  }
862
#endif
863
  {
serg@serg.mylan's avatar
serg@serg.mylan committed
864
    ha_rollback(this);
865 866
    xid_cache_delete(&transaction.xid_state);
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
867 868 869 870 871
  if (locked_tables)
  {
    lock=locked_tables; locked_tables=0;
    close_thread_tables(this);
  }
872
  mysql_ha_cleanup(this);
873 874
  delete_dynamic(&user_var_events);
  hash_free(&user_vars);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
875
  close_temporary_tables(this);
876 877 878
  my_free((char*) variables.time_format, MYF(MY_ALLOW_ZERO_PTR));
  my_free((char*) variables.date_format, MYF(MY_ALLOW_ZERO_PTR));
  my_free((char*) variables.datetime_format, MYF(MY_ALLOW_ZERO_PTR));
879
  
880
  sp_cache_clear(&sp_proc_cache);
881 882
  sp_cache_clear(&sp_func_cache);

883 884 885
  if (global_read_lock)
    unlock_global_read_lock(this);
  if (ull)
886
  {
887 888 889
    pthread_mutex_lock(&LOCK_user_locks);
    item_user_lock_release(ull);
    pthread_mutex_unlock(&LOCK_user_locks);
890
    ull= NULL;
891
  }
892

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
893 894 895 896
  cleanup_done=1;
  DBUG_VOID_RETURN;
}

897

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
898 899
THD::~THD()
{
900
  THD_CHECK_SENTRY(this);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
901
  DBUG_ENTER("~THD()");
902 903 904
  /* Ensure that no one is using THD */
  pthread_mutex_lock(&LOCK_delete);
  pthread_mutex_unlock(&LOCK_delete);
905
  add_to_status(&global_status_var, &status_var);
906

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
907
  /* Close connection */
serg@serg.mylan's avatar
serg@serg.mylan committed
908
#ifndef EMBEDDED_LIBRARY
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
909 910 911
  if (net.vio)
  {
    vio_delete(net.vio);
serg@serg.mylan's avatar
serg@serg.mylan committed
912
    net_end(&net);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
913
  }
914
#endif
915
  stmt_map.reset();                     /* close all prepared statements */
916
  DBUG_ASSERT(lock_info.n_cursors == 0);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
917 918
  if (!cleanup_done)
    cleanup();
919

serg@serg.mylan's avatar
serg@serg.mylan committed
920
  ha_close_connection(this);
antony@ppcg5.local's avatar
antony@ppcg5.local committed
921
  plugin_thdvar_cleanup(this);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
922

923 924
  DBUG_PRINT("info", ("freeing security context"));
  main_security_ctx.destroy();
925
  safeFree(db);
926
  free_root(&warn_root,MYF(0));
927
#ifdef USING_TRANSACTIONS
928
  free_root(&transaction.mem_root,MYF(0));
929
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
930
  mysys_var=0;					// Safety (shouldn't be needed)
931
  pthread_mutex_destroy(&LOCK_delete);
932
#ifndef DBUG_OFF
konstantin@oak.local's avatar
konstantin@oak.local committed
933
  dbug_sentry= THD_SENTRY_GONE;
934
#endif  
935 936
#ifndef EMBEDDED_LIBRARY
  if (rli_fake)
937
  {
938
    delete rli_fake;
939 940
    rli_fake= NULL;
  }
941 942
#endif

943
  free_root(&main_mem_root, MYF(0));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
944 945 946
  DBUG_VOID_RETURN;
}

947

948
/*
949 950 951 952 953 954
  Add all status variables to another status variable array

  SYNOPSIS
   add_to_status()
   to_var       add to this array
   from_var     from this array
955 956 957 958 959 960 961 962 963

  NOTES
    This function assumes that all variables are long/ulong.
    If this assumption will change, then we have to explictely add
    the other variables after the while loop
*/

void add_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var)
{
964
  ulong *end= (ulong*) ((uchar*) to_var +
965
                        offsetof(STATUS_VAR, last_system_status_var) +
966 967 968 969 970 971 972
			sizeof(ulong));
  ulong *to= (ulong*) to_var, *from= (ulong*) from_var;

  while (to != end)
    *(to++)+= *(from++);
}

973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988
/*
  Add the difference between two status variable arrays to another one.

  SYNOPSIS
    add_diff_to_status
    to_var       add to this array
    from_var     from this array
    dec_var      minus this array
  
  NOTE
    This function assumes that all variables are long/ulong.
*/

void add_diff_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var,
                        STATUS_VAR *dec_var)
{
989
  ulong *end= (ulong*) ((uchar*) to_var + offsetof(STATUS_VAR,
990 991 992 993 994 995 996 997
						  last_system_status_var) +
			sizeof(ulong));
  ulong *to= (ulong*) to_var, *from= (ulong*) from_var, *dec= (ulong*) dec_var;

  while (to != end)
    *(to++)+= *(from++) - *(dec++);
}

998

hf@genie.(none)'s avatar
SCRUM  
hf@genie.(none) committed
999
void THD::awake(THD::killed_state state_to_set)
1000
{
1001
  DBUG_ENTER("THD::awake");
1002
  DBUG_PRINT("enter", ("this: 0x%lx", (long) this));
1003
  THD_CHECK_SENTRY(this);
1004 1005
  safe_mutex_assert_owner(&LOCK_delete); 

hf@genie.(none)'s avatar
SCRUM  
hf@genie.(none) committed
1006 1007
  killed= state_to_set;
  if (state_to_set != THD::KILL_QUERY)
1008
  {
1009 1010 1011
    thr_alarm_kill(thread_id);
    if (!slave_thread)
      thread_scheduler.post_kill_notification(this);
1012
#ifdef SIGNAL_WITH_VIO_CLOSE
1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026
    if (this != current_thd)
    {
      /*
        In addition to a signal, let's close the socket of the thread that
        is being killed. This is to make sure it does not block if the
        signal is lost. This needs to be done only on platforms where
        signals are not a reliable interruption mechanism.

        If we're killing ourselves, we know that we're not blocked, so this
        hack is not used.
      */

      close_active_vio();
    }
1027
#endif    
1028
  }
1029
  if (mysys_var)
1030 1031 1032 1033 1034 1035 1036 1037 1038
  {
    pthread_mutex_lock(&mysys_var->mutex);
    if (!system_thread)		// Don't abort locks
      mysys_var->abort=1;
    /*
      This broadcast could be up in the air if the victim thread
      exits the cond in the time between read and broadcast, but that is
      ok since all we want to do is to make the victim thread get out
      of waiting on current_cond.
1039 1040 1041 1042 1043
      If we see a non-zero current_cond: it cannot be an old value (because
      then exit_cond() should have run and it can't because we have mutex); so
      it is the true value but maybe current_mutex is not yet non-zero (we're
      in the middle of enter_cond() and there is a "memory order
      inversion"). So we test the mutex too to not lock 0.
1044

1045
      Note that there is a small chance we fail to kill. If victim has locked
1046 1047 1048 1049 1050
      current_mutex, but hasn't yet entered enter_cond() (which means that
      current_cond and current_mutex are 0), then the victim will not get
      a signal and it may wait "forever" on the cond (until
      we issue a second KILL or the status it's waiting for happens).
      It's true that we have set its thd->killed but it may not
1051
      see it immediately and so may have time to reach the cond_wait().
1052
    */
1053
    if (mysys_var->current_cond && mysys_var->current_mutex)
1054
    {
1055 1056 1057
      pthread_mutex_lock(mysys_var->current_mutex);
      pthread_cond_broadcast(mysys_var->current_cond);
      pthread_mutex_unlock(mysys_var->current_mutex);
1058
    }
1059 1060
    pthread_mutex_unlock(&mysys_var->mutex);
  }
1061
  DBUG_VOID_RETURN;
1062 1063
}

1064 1065 1066 1067
/*
  Remember the location of thread info, the structure needed for
  sql_alloc() and the structure for the net buffer
*/
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1068 1069 1070

bool THD::store_globals()
{
1071 1072 1073 1074
  /*
    Assert that thread_stack is initialized: it's necessary to be able
    to track stack overrun.
  */
1075
  DBUG_ASSERT(thread_stack);
1076

1077
  if (my_pthread_setspecific_ptr(THR_THD,  this) ||
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1078
      my_pthread_setspecific_ptr(THR_MALLOC, &mem_root))
1079 1080
    return 1;
  mysys_var=my_thread_var;
guilhem@mysql.com's avatar
guilhem@mysql.com committed
1081
  /*
1082 1083
    Let mysqld define the thread id (not mysys)
    This allows us to move THD to different threads if needed.
guilhem@mysql.com's avatar
guilhem@mysql.com committed
1084
  */
1085 1086 1087
  mysys_var->id= thread_id;
  real_id= pthread_self();                      // For debugging

1088 1089 1090 1091
  /*
    We have to call thr_lock_info_init() again here as THD may have been
    created in another thread
  */
1092
  thr_lock_info_init(&lock_info);
1093
  return 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1094 1095
}

1096

1097 1098 1099 1100 1101
/*
  Cleanup after query.

  SYNOPSIS
    THD::cleanup_after_query()
1102

1103
  DESCRIPTION
1104
    This function is used to reset thread data to its default state.
1105 1106 1107 1108 1109 1110 1111

  NOTE
    This function is not suitable for setting thread data to some
    non-default values, as there is only one replication thread, so
    different master threads may overwrite data of each other on
    slave.
*/
1112

1113 1114
void THD::cleanup_after_query()
{
1115 1116 1117 1118 1119 1120 1121 1122 1123 1124
  /*
    Reset rand_used so that detection of calls to rand() will save random 
    seeds if needed by the slave.

    Do not reset rand_used if inside a stored function or trigger because 
    only the call to these operations is logged. Thus only the calling 
    statement needs to detect rand() calls made by its substatements. These
    substatements must not set rand_used to 0 because it would remove the
    detection of rand() by the calling statement. 
  */
1125 1126 1127 1128 1129
  if (!in_sub_stmt) /* stored functions and triggers are a special case */
  {
    /* Forget those values, for next binlogger: */
    stmt_depends_on_first_successful_insert_id_in_prev_stmt= 0;
    auto_inc_intervals_in_cur_stmt_for_binlog.empty();
1130
    rand_used= 0;
1131
  }
1132
  if (first_successful_insert_id_in_cur_stmt > 0)
1133
  {
1134 1135 1136 1137
    /* set what LAST_INSERT_ID() will return */
    first_successful_insert_id_in_prev_stmt= 
      first_successful_insert_id_in_cur_stmt;
    first_successful_insert_id_in_cur_stmt= 0;
evgen@sunlight.local's avatar
evgen@sunlight.local committed
1138
    substitute_null_with_insert_id= TRUE;
1139
  }
1140
  arg_of_last_insert_id_function= 0;
1141
  /* Free Items that were created during this execution */
1142
  free_items();
1143 1144
  /* Reset where. */
  where= THD::DEFAULT_WHERE;
1145 1146
  /* reset table map for multi-table update */
  table_map_for_update= 0;
1147 1148
}

1149

1150
/**
1151
  Create a LEX_STRING in this connection.
1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173

  @param lex_str  pointer to LEX_STRING object to be initialized
  @param str      initializer to be copied into lex_str
  @param length   length of str, in bytes
  @param allocate_lex_string  if TRUE, allocate new LEX_STRING object,
                              instead of using lex_str value
  @return  NULL on failure, or pointer to the LEX_STRING object
*/
LEX_STRING *THD::make_lex_string(LEX_STRING *lex_str,
                                 const char* str, uint length,
                                 bool allocate_lex_string)
{
  if (allocate_lex_string)
    if (!(lex_str= (LEX_STRING *)alloc(sizeof(LEX_STRING))))
      return 0;
  if (!(lex_str->str= strmake_root(mem_root, str, length)))
    return 0;
  lex_str->length= length;
  return lex_str;
}


monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198
/*
  Convert a string to another character set

  SYNOPSIS
    convert_string()
    to				Store new allocated string here
    to_cs			New character set for allocated string
    from			String to convert
    from_length			Length of string to convert
    from_cs			Original character set

  NOTES
    to will be 0-terminated to make it easy to pass to system funcs

  RETURN
    0	ok
    1	End of memory.
        In this case to->str will point to 0 and to->length will be 0.
*/

bool THD::convert_string(LEX_STRING *to, CHARSET_INFO *to_cs,
			 const char *from, uint from_length,
			 CHARSET_INFO *from_cs)
{
  DBUG_ENTER("convert_string");
1199
  size_t new_length= to_cs->mbmaxlen * from_length;
1200
  uint dummy_errors;
1201
  if (!(to->str= (char*) alloc(new_length+1)))
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1202 1203 1204 1205 1206
  {
    to->length= 0;				// Safety fix
    DBUG_RETURN(1);				// EOM
  }
  to->length= copy_and_convert((char*) to->str, new_length, to_cs,
1207
			       from, from_length, from_cs, &dummy_errors);
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1208 1209 1210 1211 1212
  to->str[to->length]=0;			// Safety
  DBUG_RETURN(0);
}


1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229
/*
  Convert string from source character set to target character set inplace.

  SYNOPSIS
    THD::convert_string

  DESCRIPTION
    Convert string using convert_buffer - buffer for character set 
    conversion shared between all protocols.

  RETURN
    0   ok
   !0   out of memory
*/

bool THD::convert_string(String *s, CHARSET_INFO *from_cs, CHARSET_INFO *to_cs)
{
1230 1231
  uint dummy_errors;
  if (convert_buffer.copy(s->ptr(), s->length(), from_cs, to_cs, &dummy_errors))
1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242
    return TRUE;
  /* If convert_buffer >> s copying is more efficient long term */
  if (convert_buffer.alloced_length() >= convert_buffer.length() * 2 ||
      !s->is_alloced())
  {
    return s->copy(convert_buffer);
  }
  s->swap(convert_buffer);
  return FALSE;
}

1243

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1244 1245 1246 1247 1248 1249
/*
  Update some cache variables when character set changes
*/

void THD::update_charset()
{
1250 1251 1252 1253 1254 1255 1256
  uint32 not_used;
  charset_is_system_charset= !String::needs_conversion(0,charset(),
                                                       system_charset_info,
                                                       &not_used);
  charset_is_collation_connection= 
    !String::needs_conversion(0,charset(),variables.collation_connection,
                              &not_used);
1257 1258 1259
  charset_is_character_set_filesystem= 
    !String::needs_conversion(0, charset(),
                              variables.character_set_filesystem, &not_used);
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1260 1261 1262
}


1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276
/* routings to adding tables to list of changed in transaction tables */

inline static void list_include(CHANGED_TABLE_LIST** prev,
				CHANGED_TABLE_LIST* curr,
				CHANGED_TABLE_LIST* new_table)
{
  if (new_table)
  {
    *prev = new_table;
    (*prev)->next = curr;
  }
}

/* add table to list of changed in transaction tables */
1277

1278 1279
void THD::add_changed_table(TABLE *table)
{
1280
  DBUG_ENTER("THD::add_changed_table(table)");
1281

1282
  DBUG_ASSERT((options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) &&
1283
	      table->file->has_transactions());
1284
  add_changed_table(table->s->table_cache_key.str,
1285
                    (long) table->s->table_cache_key.length);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1286
  DBUG_VOID_RETURN;
1287
}
1288

1289

1290 1291 1292
void THD::add_changed_table(const char *key, long key_length)
{
  DBUG_ENTER("THD::add_changed_table(key)");
1293 1294
  CHANGED_TABLE_LIST **prev_changed = &transaction.changed_tables;
  CHANGED_TABLE_LIST *curr = transaction.changed_tables;
1295

1296
  for (; curr; prev_changed = &(curr->next), curr = curr->next)
1297
  {
1298
    int cmp =  (long)curr->key_length - (long)key_length;
1299 1300
    if (cmp < 0)
    {
1301
      list_include(prev_changed, curr, changed_table_dup(key, key_length));
1302
      DBUG_PRINT("info", 
1303 1304
		 ("key_length: %ld  %u", key_length,
                  (*prev_changed)->key_length));
1305 1306 1307 1308
      DBUG_VOID_RETURN;
    }
    else if (cmp == 0)
    {
1309
      cmp = memcmp(curr->key, key, curr->key_length);
1310 1311
      if (cmp < 0)
      {
1312
	list_include(prev_changed, curr, changed_table_dup(key, key_length));
1313
	DBUG_PRINT("info", 
1314
		   ("key_length:  %ld  %u", key_length,
1315
		    (*prev_changed)->key_length));
1316 1317 1318 1319 1320 1321 1322 1323 1324
	DBUG_VOID_RETURN;
      }
      else if (cmp == 0)
      {
	DBUG_PRINT("info", ("already in list"));
	DBUG_VOID_RETURN;
      }
    }
  }
1325
  *prev_changed = changed_table_dup(key, key_length);
1326
  DBUG_PRINT("info", ("key_length: %ld  %u", key_length,
1327
		      (*prev_changed)->key_length));
1328 1329 1330
  DBUG_VOID_RETURN;
}

1331

1332
CHANGED_TABLE_LIST* THD::changed_table_dup(const char *key, long key_length)
1333 1334 1335
{
  CHANGED_TABLE_LIST* new_table = 
    (CHANGED_TABLE_LIST*) trans_alloc(ALIGN_SIZE(sizeof(CHANGED_TABLE_LIST))+
1336
				      key_length + 1);
1337 1338
  if (!new_table)
  {
1339 1340
    my_error(EE_OUTOFMEMORY, MYF(ME_BELL),
             ALIGN_SIZE(sizeof(TABLE_LIST)) + key_length + 1);
hf@genie.(none)'s avatar
SCRUM  
hf@genie.(none) committed
1341
    killed= KILL_CONNECTION;
1342 1343 1344
    return 0;
  }

1345
  new_table->key= ((char*)new_table)+ ALIGN_SIZE(sizeof(CHANGED_TABLE_LIST));
1346
  new_table->next = 0;
1347 1348
  new_table->key_length = key_length;
  ::memcpy(new_table->key, key, key_length);
1349 1350 1351
  return new_table;
}

1352

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1353 1354 1355 1356
int THD::send_explain_fields(select_result *result)
{
  List<Item> field_list;
  Item *item;
1357
  CHARSET_INFO *cs= system_charset_info;
1358
  field_list.push_back(new Item_return_int("id",3, MYSQL_TYPE_LONGLONG));
1359
  field_list.push_back(new Item_empty_string("select_type", 19, cs));
1360
  field_list.push_back(item= new Item_empty_string("table", NAME_CHAR_LEN, cs));
igor@rurik.mysql.com's avatar
igor@rurik.mysql.com committed
1361
  item->maybe_null= 1;
1362 1363
  if (lex->describe & DESCRIBE_PARTITIONS)
  {
1364 1365 1366 1367
    /* Maximum length of string that make_used_partitions_str() can produce */
    item= new Item_empty_string("partitions", MAX_PARTITIONS * (1 + FN_LEN),
                                cs);
    field_list.push_back(item);
1368 1369
    item->maybe_null= 1;
  }
igor@rurik.mysql.com's avatar
igor@rurik.mysql.com committed
1370 1371
  field_list.push_back(item= new Item_empty_string("type", 10, cs));
  item->maybe_null= 1;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1372
  field_list.push_back(item=new Item_empty_string("possible_keys",
1373
						  NAME_CHAR_LEN*MAX_KEY, cs));
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1374
  item->maybe_null=1;
1375
  field_list.push_back(item=new Item_empty_string("key", NAME_CHAR_LEN, cs));
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1376
  item->maybe_null=1;
1377
  field_list.push_back(item=new Item_empty_string("key_len",
1378
						  NAME_CHAR_LEN*MAX_KEY));
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1379 1380
  item->maybe_null=1;
  field_list.push_back(item=new Item_empty_string("ref",
1381 1382
                                                  NAME_CHAR_LEN*MAX_REF_PARTS,
                                                  cs));
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1383
  item->maybe_null=1;
igor@rurik.mysql.com's avatar
igor@rurik.mysql.com committed
1384 1385
  field_list.push_back(item= new Item_return_int("rows", 10,
                                                 MYSQL_TYPE_LONGLONG));
1386 1387 1388 1389 1390
  if (lex->describe & DESCRIBE_EXTENDED)
  {
    field_list.push_back(item= new Item_float("filtered", 0.1234, 2, 4));
    item->maybe_null=1;
  }
igor@rurik.mysql.com's avatar
igor@rurik.mysql.com committed
1391
  item->maybe_null= 1;
1392
  field_list.push_back(new Item_empty_string("Extra", 255, cs));
1393 1394
  return (result->send_fields(field_list,
                              Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF));
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1395
}
1396

1397 1398 1399
#ifdef SIGNAL_WITH_VIO_CLOSE
void THD::close_active_vio()
{
1400
  DBUG_ENTER("close_active_vio");
1401
  safe_mutex_assert_owner(&LOCK_delete); 
1402
#ifndef EMBEDDED_LIBRARY
1403 1404 1405 1406 1407
  if (active_vio)
  {
    vio_close(active_vio);
    active_vio = 0;
  }
1408
#endif
1409
  DBUG_VOID_RETURN;
1410 1411 1412
}
#endif

1413

1414 1415 1416 1417 1418
struct Item_change_record: public ilink
{
  Item **place;
  Item *old_value;
  /* Placement new was hidden by `new' in ilink (TODO: check): */
1419
  static void *operator new(size_t size, void *mem) { return mem; }
1420 1421
  static void operator delete(void *ptr, size_t size) {}
  static void operator delete(void *ptr, void *mem) { /* never called */ }
1422 1423 1424 1425 1426 1427
};


/*
  Register an item tree tree transformation, performed by the query
  optimizer. We need a pointer to runtime_memroot because it may be !=
konstantin@mysql.com's avatar
konstantin@mysql.com committed
1428
  thd->mem_root (due to possible set_n_backup_active_arena called for thd).
1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442
*/

void THD::nocheck_register_item_tree_change(Item **place, Item *old_value,
                                            MEM_ROOT *runtime_memroot)
{
  Item_change_record *change;
  /*
    Now we use one node per change, which adds some memory overhead,
    but still is rather fast as we use alloc_root for allocations.
    A list of item tree changes of an average query should be short.
  */
  void *change_mem= alloc_root(runtime_memroot, sizeof(*change));
  if (change_mem == 0)
  {
1443 1444 1445 1446
    /*
      OOM, thd->fatal_error() is called by the error handler of the
      memroot. Just return.
    */
1447 1448 1449 1450 1451
    return;
  }
  change= new (change_mem) Item_change_record;
  change->place= place;
  change->old_value= old_value;
1452
  change_list.append(change);
1453 1454 1455 1456 1457 1458 1459
}


void THD::rollback_item_tree_changes()
{
  I_List_iterator<Item_change_record> it(change_list);
  Item_change_record *change;
monty@mysql.com's avatar
monty@mysql.com committed
1460 1461
  DBUG_ENTER("rollback_item_tree_changes");

1462 1463 1464 1465
  while ((change= it++))
    *change->place= change->old_value;
  /* We can forget about changes memory: it's allocated in runtime memroot */
  change_list.empty();
monty@mysql.com's avatar
monty@mysql.com committed
1466
  DBUG_VOID_RETURN;
1467 1468 1469
}


bk@work.mysql.com's avatar
bk@work.mysql.com committed
1470 1471 1472 1473 1474 1475 1476
/*****************************************************************************
** Functions to provide a interface to select results
*****************************************************************************/

select_result::select_result()
{
  thd=current_thd;
1477
  nest_level= -1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1478 1479
}

1480 1481
void select_result::send_error(uint errcode,const char *err)
{
1482
  my_message(errcode, err, MYF(0));
1483 1484
}

1485 1486 1487 1488 1489 1490

void select_result::cleanup()
{
  /* do nothing */
}

1491 1492 1493 1494 1495 1496 1497
bool select_result::check_simple_select() const
{
  my_error(ER_SP_BAD_CURSOR_QUERY, MYF(0));
  return TRUE;
}


1498 1499 1500
static String default_line_term("\n",default_charset_info);
static String default_escaped("\\",default_charset_info);
static String default_field_term("\t",default_charset_info);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1501 1502 1503 1504 1505

sql_exchange::sql_exchange(char *name,bool flag)
  :file_name(name), opt_enclosed(0), dumpfile(flag), skip_lines(0)
{
  field_term= &default_field_term;
hf@deer.(none)'s avatar
SCRUM  
hf@deer.(none) committed
1506
  enclosed=   line_start= &my_empty_string;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1507 1508
  line_term=  &default_line_term;
  escaped=    &default_escaped;
1509
  cs= NULL;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1510 1511
}

1512 1513 1514 1515 1516 1517
bool sql_exchange::escaped_given(void)
{
  return escaped != &default_escaped;
}


1518
bool select_send::send_fields(List<Item> &list, uint flags)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1519
{
1520 1521
  bool res;
  if (!(res= thd->protocol->send_fields(&list, flags)))
1522
    is_result_set_started= 1;
1523
  return res;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1524 1525
}

1526 1527 1528
void select_send::abort()
{
  DBUG_ENTER("select_send::abort");
1529
  if (is_result_set_started && thd->spcont &&
1530
      thd->spcont->find_handler(thd, thd->main_da.sql_errno(),
1531 1532 1533
                                MYSQL_ERROR::WARN_LEVEL_ERROR))
  {
    /*
1534
      We're executing a stored procedure, have an open result
1535
      set, an SQL exception condition and a handler for it.
1536 1537 1538 1539 1540 1541
      In this situation we must abort the current statement,
      silence the error and start executing the continue/exit
      handler.
      Before aborting the statement, let's end the open result set, as
      otherwise the client will hang due to the violation of the
      client/server protocol.
1542
    */
1543
    thd->protocol->end_partial_result_set(thd);
1544 1545 1546 1547 1548
  }
  DBUG_VOID_RETURN;
}


1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559
/** 
  Cleanup an instance of this class for re-use
  at next execution of a prepared statement/
  stored procedure statement.
*/

void select_send::cleanup()
{
  is_result_set_started= FALSE;
}

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1560 1561 1562 1563
/* Send data to client. Returns 0 if ok */

bool select_send::send_data(List<Item> &items)
{
1564
  if (unit->offset_limit_cnt)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1565
  {						// using limit offset,count
1566
    unit->offset_limit_cnt--;
1567
    return 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1568
  }
1569

monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1570 1571 1572 1573 1574
  /*
    We may be passing the control from mysqld to the client: release the
    InnoDB adaptive hash S-latch to avoid thread deadlocks if it was reserved
    by thd
  */
1575
  ha_release_temporary_latches(thd);
1576

1577 1578 1579
  List_iterator_fast<Item> li(items);
  Protocol *protocol= thd->protocol;
  char buff[MAX_FIELD_WIDTH];
1580
  String buffer(buff, sizeof(buff), &my_charset_bin);
1581
  DBUG_ENTER("select_send::send_data");
1582 1583

  protocol->prepare_for_resend();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1584 1585 1586
  Item *item;
  while ((item=li++))
  {
1587
    if (item->send(protocol, &buffer))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1588
    {
1589
      protocol->free();				// Free used buffer
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1590
      my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
1591
      break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1592
    }
1593 1594 1595 1596 1597
    /*
      Reset buffer to its original state, as it may have been altered in
      Item::send().
    */
    buffer.set(buff, sizeof(buff), &my_charset_bin);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1598
  }
1599
  thd->sent_row_count++;
1600 1601 1602 1603 1604 1605
  if (thd->is_error())
  {
    protocol->remove_last_row();
    DBUG_RETURN(1);
  }
  if (thd->vio_ok())
1606
    DBUG_RETURN(protocol->write());
1607
  DBUG_RETURN(0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1608 1609 1610 1611
}

bool select_send::send_eof()
{
1612 1613 1614 1615 1616 1617
  /* 
    We may be passing the control from mysqld to the client: release the
    InnoDB adaptive hash S-latch to avoid thread deadlocks if it was reserved
    by thd 
  */
  ha_release_temporary_latches(thd);
1618

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1619 1620 1621
  /* Unlock tables before sending packet to gain some speed */
  if (thd->lock)
  {
1622 1623
    mysql_unlock_tables(thd, thd->lock);
    thd->lock=0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1624
  }
1625 1626 1627 1628 1629 1630
  /* 
    Don't send EOF if we're in error condition (which implies we've already
    sent or are sending an error)
  */
  if (thd->is_error())
    return TRUE;
1631
  ::my_eof(thd);
1632 1633
  is_result_set_started= 0;
  return FALSE;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1634 1635 1636
}


1637 1638 1639
/************************************************************************
  Handling writing to file
************************************************************************/
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1640

1641 1642
void select_to_file::send_error(uint errcode,const char *err)
{
1643
  my_message(errcode, err, MYF(0));
1644 1645 1646 1647 1648 1649 1650 1651
  if (file > 0)
  {
    (void) end_io_cache(&cache);
    (void) my_close(file,MYF(0));
    (void) my_delete(path,MYF(0));		// Delete file on error
    file= -1;
  }
}
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1652 1653


1654 1655 1656 1657 1658 1659
bool select_to_file::send_eof()
{
  int error= test(end_io_cache(&cache));
  if (my_close(file,MYF(MY_WME)))
    error= 1;
  if (!error)
1660 1661 1662 1663 1664 1665
  {
    /*
      In order to remember the value of affected rows for ROW_COUNT()
      function, SELECT INTO has to have an own SQLCOM.
      TODO: split from SQLCOM_SELECT
    */
1666
    ::my_ok(thd,row_count);
1667
  }
1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686
  file= -1;
  return error;
}


void select_to_file::cleanup()
{
  /* In case of error send_eof() may be not called: close the file here. */
  if (file >= 0)
  {
    (void) end_io_cache(&cache);
    (void) my_close(file,MYF(0));
    file= -1;
  }
  path[0]= '\0';
  row_count= 0;
}


1687
select_to_file::~select_to_file()
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1688 1689 1690 1691 1692 1693 1694
{
  if (file >= 0)
  {					// This only happens in case of error
    (void) end_io_cache(&cache);
    (void) my_close(file,MYF(0));
    file= -1;
  }
1695 1696 1697 1698 1699 1700 1701 1702
}

/***************************************************************************
** Export of select to textfile
***************************************************************************/

select_export::~select_export()
{
1703
  thd->sent_row_count=row_count;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1704 1705
}

1706

1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724
/*
  Create file with IO cache

  SYNOPSIS
    create_file()
    thd			Thread handle
    path		File name
    exchange		Excange class
    cache		IO cache

  RETURN
    >= 0 	File handle
   -1		Error
*/


static File create_file(THD *thd, char *path, sql_exchange *exchange,
			IO_CACHE *cache)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1725
{
1726
  File file;
1727
  uint option= MY_UNPACK_FILENAME | MY_RELATIVE_PATH;
1728

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1729
#ifdef DONT_ALLOW_FULL_LOAD_DATA_PATHS
1730
  option|= MY_REPLACE_DIR;			// Force use of db directory
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1731
#endif
1732

hf@deer.(none)'s avatar
hf@deer.(none) committed
1733
  if (!dirname_length(exchange->file_name))
1734
  {
1735 1736
    strxnmov(path, FN_REFLEN-1, mysql_real_data_home, thd->db ? thd->db : "",
             NullS);
1737 1738 1739 1740
    (void) fn_format(path, exchange->file_name, path, "", option);
  }
  else
    (void) fn_format(path, exchange->file_name, mysql_real_data_home, "", option);
1741 1742 1743 1744 1745 1746 1747 1748 1749

  if (opt_secure_file_priv &&
      strncmp(opt_secure_file_priv, path, strlen(opt_secure_file_priv)))
  {
    /* Write only allowed to dir or subdir specified by secure_file_priv */
    my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--secure-file-priv");
    return -1;
  }

1750
  if (!access(path, F_OK))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1751
  {
1752
    my_error(ER_FILE_EXISTS_ERROR, MYF(0), exchange->file_name);
1753
    return -1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1754 1755
  }
  /* Create the file world readable */
serg@serg.mylan's avatar
serg@serg.mylan committed
1756
  if ((file= my_create(path, 0666, O_WRONLY|O_EXCL, MYF(MY_WME))) < 0)
1757
    return file;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1758
#ifdef HAVE_FCHMOD
1759
  (void) fchmod(file, 0666);			// Because of umask()
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1760
#else
1761
  (void) chmod(path, 0666);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1762
#endif
1763
  if (init_io_cache(cache, file, 0L, WRITE_CACHE, 0L, 1, MYF(MY_WME)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1764
  {
1765
    my_close(file, MYF(0));
1766
    my_delete(path, MYF(0));  // Delete file on error, it was just created 
1767
    return -1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1768
  }
1769
  return file;
1770 1771 1772 1773 1774 1775 1776
}


int
select_export::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
{
  bool blob_flag=0;
1777
  bool string_results= FALSE, non_string_results= FALSE;
1778 1779 1780 1781
  unit= u;
  if ((uint) strlen(exchange->file_name) + NAME_LEN >= FN_REFLEN)
    strmake(path,exchange->file_name,FN_REFLEN-1);

1782
  if ((file= create_file(thd, path, exchange, &cache)) < 0)
1783
    return 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1784 1785
  /* Check if there is any blobs in data */
  {
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
1786
    List_iterator_fast<Item> li(list);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1787 1788 1789 1790 1791 1792 1793 1794
    Item *item;
    while ((item=li++))
    {
      if (item->max_length >= MAX_BLOB_WIDTH)
      {
	blob_flag=1;
	break;
      }
1795 1796 1797 1798
      if (item->result_type() == STRING_RESULT)
        string_results= TRUE;
      else
        non_string_results= TRUE;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1799 1800 1801
    }
  }
  field_term_length=exchange->field_term->length();
gshchepa/uchum@gleb.loc's avatar
gshchepa/uchum@gleb.loc committed
1802 1803
  field_term_char= field_term_length ?
                   (int) (uchar) (*exchange->field_term)[0] : INT_MAX;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1804 1805
  if (!exchange->line_term->length())
    exchange->line_term=exchange->field_term;	// Use this if it exists
gshchepa/uchum@gleb.loc's avatar
gshchepa/uchum@gleb.loc committed
1806 1807
  field_sep_char= (exchange->enclosed->length() ?
                  (int) (uchar) (*exchange->enclosed)[0] : field_term_char);
1808 1809 1810 1811 1812
  if (exchange->escaped->length() && (exchange->escaped_given() ||
      !(thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES)))
    escape_char= (int) (uchar) (*exchange->escaped)[0];
  else
    escape_char= -1;
gshchepa/uchum@gleb.loc's avatar
gshchepa/uchum@gleb.loc committed
1813
  is_ambiguous_field_sep= test(strchr(ESCAPE_CHARS, field_sep_char));
gshchepa/uchum@gleb.loc's avatar
gshchepa/uchum@gleb.loc committed
1814
  is_unsafe_field_sep= test(strchr(NUMERIC_CHARS, field_sep_char));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1815
  line_sep_char= (exchange->line_term->length() ?
gshchepa/uchum@gleb.loc's avatar
gshchepa/uchum@gleb.loc committed
1816
                 (int) (uchar) (*exchange->line_term)[0] : INT_MAX);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1817 1818 1819 1820 1821 1822
  if (!field_term_length)
    exchange->opt_enclosed=0;
  if (!exchange->enclosed->length())
    exchange->opt_enclosed=1;			// A little quicker loop
  fixed_row_size= (!field_term_length && !exchange->enclosed->length() &&
		   !blob_flag);
1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834
  if ((is_ambiguous_field_sep && exchange->enclosed->is_empty() &&
       (string_results || is_unsafe_field_sep)) ||
      (exchange->opt_enclosed && non_string_results &&
       field_term_length && strchr(NUMERIC_CHARS, field_term_char)))
  {
    push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                 ER_AMBIGUOUS_FIELD_TERM, ER(ER_AMBIGUOUS_FIELD_TERM));
    is_ambiguous_field_term= TRUE;
  }
  else
    is_ambiguous_field_term= FALSE;

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1835 1836 1837 1838
  return 0;
}


1839
#define NEED_ESCAPING(x) ((int) (uchar) (x) == escape_char    || \
1840 1841
                          (enclosed ? (int) (uchar) (x) == field_sep_char      \
                                    : (int) (uchar) (x) == field_term_char) || \
1842 1843 1844
                          (int) (uchar) (x) == line_sep_char  || \
                          !(x))

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1845 1846 1847
bool select_export::send_data(List<Item> &items)
{

1848
  DBUG_ENTER("select_export::send_data");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1849 1850
  char buff[MAX_FIELD_WIDTH],null_buff[2],space[MAX_FIELD_WIDTH];
  bool space_inited=0;
1851
  String tmp(buff,sizeof(buff),&my_charset_bin),*res;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1852 1853
  tmp.length(0);

1854
  if (unit->offset_limit_cnt)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1855
  {						// using limit offset,count
1856
    unit->offset_limit_cnt--;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1857 1858 1859 1860 1861
    DBUG_RETURN(0);
  }
  row_count++;
  Item *item;
  uint used_length=0,items_left=items.elements;
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
1862
  List_iterator_fast<Item> li(items);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1863

1864
  if (my_b_write(&cache,(uchar*) exchange->line_start->ptr(),
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1865 1866 1867 1868 1869
		 exchange->line_start->length()))
    goto err;
  while ((item=li++))
  {
    Item_result result_type=item->result_type();
1870 1871
    bool enclosed = (exchange->enclosed->length() &&
                     (!exchange->opt_enclosed || result_type == STRING_RESULT));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1872
    res=item->str_result(&tmp);
1873
    if (res && enclosed)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1874
    {
1875
      if (my_b_write(&cache,(uchar*) exchange->enclosed->ptr(),
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886
		     exchange->enclosed->length()))
	goto err;
    }
    if (!res)
    {						// NULL
      if (!fixed_row_size)
      {
	if (escape_char != -1)			// Use \N syntax
	{
	  null_buff[0]=escape_char;
	  null_buff[1]='N';
1887
	  if (my_b_write(&cache,(uchar*) null_buff,2))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1888 1889
	    goto err;
	}
1890
	else if (my_b_write(&cache,(uchar*) "NULL",4))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903
	  goto err;
      }
      else
      {
	used_length=0;				// Fill with space
      }
    }
    else
    {
      if (fixed_row_size)
	used_length=min(res->length(),item->max_length);
      else
	used_length=res->length();
gshchepa/uchum@gleb.loc's avatar
gshchepa/uchum@gleb.loc committed
1904 1905
      if ((result_type == STRING_RESULT || is_unsafe_field_sep) &&
           escape_char != -1)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1906
      {
1907 1908 1909 1910 1911 1912 1913 1914 1915
        char *pos, *start, *end;
        CHARSET_INFO *res_charset= res->charset();
        CHARSET_INFO *character_set_client= thd->variables.
                                            character_set_client;
        bool check_second_byte= (res_charset == &my_charset_bin) &&
                                 character_set_client->
                                 escape_with_backslash_is_dangerous;
        DBUG_ASSERT(character_set_client->mbmaxlen == 2 ||
                    !character_set_client->escape_with_backslash_is_dangerous);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1916 1917 1918 1919 1920
	for (start=pos=(char*) res->ptr(),end=pos+used_length ;
	     pos != end ;
	     pos++)
	{
#ifdef USE_MB
1921
	  if (use_mb(res_charset))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1922 1923
	  {
	    int l;
1924
	    if ((l=my_ismbchar(res_charset, pos, end)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1925 1926 1927 1928 1929 1930
	    {
	      pos += l-1;
	      continue;
	    }
	  }
#endif
1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963

          /*
            Special case when dumping BINARY/VARBINARY/BLOB values
            for the clients with character sets big5, cp932, gbk and sjis,
            which can have the escape character (0x5C "\" by default)
            as the second byte of a multi-byte sequence.
            
            If
            - pos[0] is a valid multi-byte head (e.g 0xEE) and
            - pos[1] is 0x00, which will be escaped as "\0",
            
            then we'll get "0xEE + 0x5C + 0x30" in the output file.
            
            If this file is later loaded using this sequence of commands:
            
            mysql> create table t1 (a varchar(128)) character set big5;
            mysql> LOAD DATA INFILE 'dump.txt' INTO TABLE t1;
            
            then 0x5C will be misinterpreted as the second byte
            of a multi-byte character "0xEE + 0x5C", instead of
            escape character for 0x00.
            
            To avoid this confusion, we'll escape the multi-byte
            head character too, so the sequence "0xEE + 0x00" will be
            dumped as "0x5C + 0xEE + 0x5C + 0x30".
            
            Note, in the condition below we only check if
            mbcharlen is equal to 2, because there are no
            character sets with mbmaxlen longer than 2
            and with escape_with_backslash_is_dangerous set.
            DBUG_ASSERT before the loop makes that sure.
          */

1964 1965 1966 1967 1968 1969 1970 1971 1972
          if ((NEED_ESCAPING(*pos) ||
               (check_second_byte &&
                my_mbcharlen(character_set_client, (uchar) *pos) == 2 &&
                pos + 1 < end &&
                NEED_ESCAPING(pos[1]))) &&
              /*
               Don't escape field_term_char by doubling - doubling is only
               valid for ENCLOSED BY characters:
              */
gshchepa/uchum@gleb.loc's avatar
gshchepa/uchum@gleb.loc committed
1973 1974
              (enclosed || !is_ambiguous_field_term ||
               (int) (uchar) *pos != field_term_char))
1975
          {
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1976
	    char tmp_buff[2];
gshchepa/uchum@gleb.loc's avatar
gshchepa/uchum@gleb.loc committed
1977
            tmp_buff[0]= ((int) (uchar) *pos == field_sep_char &&
gshchepa/uchum@gleb.loc's avatar
gshchepa/uchum@gleb.loc committed
1978 1979
                          is_ambiguous_field_sep) ?
                          field_sep_char : escape_char;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1980
	    tmp_buff[1]= *pos ? *pos : '0';
1981 1982
	    if (my_b_write(&cache,(uchar*) start,(uint) (pos-start)) ||
		my_b_write(&cache,(uchar*) tmp_buff,2))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1983 1984 1985 1986
	      goto err;
	    start=pos+1;
	  }
	}
1987
	if (my_b_write(&cache,(uchar*) start,(uint) (pos-start)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1988 1989
	  goto err;
      }
1990
      else if (my_b_write(&cache,(uchar*) res->ptr(),used_length))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003
	goto err;
    }
    if (fixed_row_size)
    {						// Fill with space
      if (item->max_length > used_length)
      {
	/* QQ:  Fix by adding a my_b_fill() function */
	if (!space_inited)
	{
	  space_inited=1;
	  bfill(space,sizeof(space),' ');
	}
	uint length=item->max_length-used_length;
2004
	for (; length > sizeof(space) ; length-=sizeof(space))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2005
	{
2006
	  if (my_b_write(&cache,(uchar*) space,sizeof(space)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2007 2008
	    goto err;
	}
2009
	if (my_b_write(&cache,(uchar*) space,length))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2010 2011 2012
	  goto err;
      }
    }
2013
    if (res && enclosed)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2014
    {
2015
      if (my_b_write(&cache, (uchar*) exchange->enclosed->ptr(),
2016 2017
                     exchange->enclosed->length()))
        goto err;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2018 2019 2020
    }
    if (--items_left)
    {
2021
      if (my_b_write(&cache, (uchar*) exchange->field_term->ptr(),
2022 2023
                     field_term_length))
        goto err;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2024 2025
    }
  }
2026
  if (my_b_write(&cache,(uchar*) exchange->line_term->ptr(),
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040
		 exchange->line_term->length()))
    goto err;
  DBUG_RETURN(0);
err:
  DBUG_RETURN(1);
}


/***************************************************************************
** Dump  of select to a binary file
***************************************************************************/


int
2041 2042
select_dump::prepare(List<Item> &list __attribute__((unused)),
		     SELECT_LEX_UNIT *u)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2043
{
2044
  unit= u;
2045
  return (int) ((file= create_file(thd, path, exchange, &cache)) < 0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2046 2047 2048 2049 2050
}


bool select_dump::send_data(List<Item> &items)
{
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
2051
  List_iterator_fast<Item> li(items);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2052
  char buff[MAX_FIELD_WIDTH];
2053
  String tmp(buff,sizeof(buff),&my_charset_bin),*res;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2054 2055
  tmp.length(0);
  Item *item;
2056
  DBUG_ENTER("select_dump::send_data");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2057

2058
  if (unit->offset_limit_cnt)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2059
  {						// using limit offset,count
2060
    unit->offset_limit_cnt--;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2061 2062 2063 2064
    DBUG_RETURN(0);
  }
  if (row_count++ > 1) 
  {
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2065
    my_message(ER_TOO_MANY_ROWS, ER(ER_TOO_MANY_ROWS), MYF(0));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2066 2067 2068 2069 2070
    goto err;
  }
  while ((item=li++))
  {
    res=item->str_result(&tmp);
2071
    if (!res)					// If NULL
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2072
    {
2073
      if (my_b_write(&cache,(uchar*) "",1))
2074
	goto err;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2075
    }
2076
    else if (my_b_write(&cache,(uchar*) res->ptr(),res->length()))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2077
    {
2078
      my_error(ER_ERROR_ON_WRITE, MYF(0), path, my_errno);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2079 2080 2081 2082 2083 2084 2085 2086 2087
      goto err;
    }
  }
  DBUG_RETURN(0);
err:
  DBUG_RETURN(1);
}


2088
select_subselect::select_subselect(Item_subselect *item_arg)
2089
{
2090
  item= item_arg;
2091 2092
}

2093

2094
bool select_singlerow_subselect::send_data(List<Item> &items)
2095
{
2096 2097
  DBUG_ENTER("select_singlerow_subselect::send_data");
  Item_singlerow_subselect *it= (Item_singlerow_subselect *)item;
Sinisa@sinisa.nasamreza.org's avatar
Sinisa@sinisa.nasamreza.org committed
2098 2099
  if (it->assigned())
  {
2100
    my_message(ER_SUBQUERY_NO_1_ROW, ER(ER_SUBQUERY_NO_1_ROW), MYF(0));
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2101 2102 2103
    DBUG_RETURN(1);
  }
  if (unit->offset_limit_cnt)
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2104
  {				          // Using limit offset,count
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2105 2106
    unit->offset_limit_cnt--;
    DBUG_RETURN(0);
2107
  }
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2108
  List_iterator_fast<Item> li(items);
2109 2110 2111
  Item *val_item;
  for (uint i= 0; (val_item= li++); i++)
    it->store(i, val_item);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2112
  it->assigned(1);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2113
  DBUG_RETURN(0);
2114
}
2115

2116

2117 2118 2119 2120 2121 2122 2123 2124
void select_max_min_finder_subselect::cleanup()
{
  DBUG_ENTER("select_max_min_finder_subselect::cleanup");
  cache= 0;
  DBUG_VOID_RETURN;
}


2125 2126 2127
bool select_max_min_finder_subselect::send_data(List<Item> &items)
{
  DBUG_ENTER("select_max_min_finder_subselect::send_data");
2128
  Item_maxmin_subselect *it= (Item_maxmin_subselect *)item;
2129 2130
  List_iterator_fast<Item> li(items);
  Item *val_item= li++;
2131
  it->register_value();
2132 2133 2134 2135 2136 2137 2138 2139 2140 2141
  if (it->assigned())
  {
    cache->store(val_item);
    if ((this->*op)())
      it->store(0, cache);
  }
  else
  {
    if (!cache)
    {
2142
      cache= Item_cache::get_cache(val_item);
2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153
      switch (val_item->result_type())
      {
      case REAL_RESULT:
	op= &select_max_min_finder_subselect::cmp_real;
	break;
      case INT_RESULT:
	op= &select_max_min_finder_subselect::cmp_int;
	break;
      case STRING_RESULT:
	op= &select_max_min_finder_subselect::cmp_str;
	break;
2154 2155 2156
      case DECIMAL_RESULT:
        op= &select_max_min_finder_subselect::cmp_decimal;
        break;
2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171
      case ROW_RESULT:
        // This case should never be choosen
	DBUG_ASSERT(0);
	op= 0;
      }
    }
    cache->store(val_item);
    it->store(0, cache);
  }
  it->assigned(1);
  DBUG_RETURN(0);
}

bool select_max_min_finder_subselect::cmp_real()
{
2172
  Item *maxmin= ((Item_singlerow_subselect *)item)->element_index(0);
2173
  double val1= cache->val_real(), val2= maxmin->val_real();
2174 2175 2176 2177
  if (fmax)
    return (cache->null_value && !maxmin->null_value) ||
      (!cache->null_value && !maxmin->null_value &&
       val1 > val2);
2178 2179 2180
  return (maxmin->null_value && !cache->null_value) ||
    (!cache->null_value && !maxmin->null_value &&
     val1 < val2);
2181 2182 2183 2184
}

bool select_max_min_finder_subselect::cmp_int()
{
2185
  Item *maxmin= ((Item_singlerow_subselect *)item)->element_index(0);
2186 2187 2188 2189 2190
  longlong val1= cache->val_int(), val2= maxmin->val_int();
  if (fmax)
    return (cache->null_value && !maxmin->null_value) ||
      (!cache->null_value && !maxmin->null_value &&
       val1 > val2);
2191 2192 2193
  return (maxmin->null_value && !cache->null_value) ||
    (!cache->null_value && !maxmin->null_value &&
     val1 < val2);
2194 2195
}

2196 2197
bool select_max_min_finder_subselect::cmp_decimal()
{
2198
  Item *maxmin= ((Item_singlerow_subselect *)item)->element_index(0);
2199 2200 2201 2202 2203 2204
  my_decimal cval, *cvalue= cache->val_decimal(&cval);
  my_decimal mval, *mvalue= maxmin->val_decimal(&mval);
  if (fmax)
    return (cache->null_value && !maxmin->null_value) ||
      (!cache->null_value && !maxmin->null_value &&
       my_decimal_cmp(cvalue, mvalue) > 0) ;
2205 2206 2207
  return (maxmin->null_value && !cache->null_value) ||
    (!cache->null_value && !maxmin->null_value &&
     my_decimal_cmp(cvalue,mvalue) < 0);
2208 2209
}

2210 2211 2212
bool select_max_min_finder_subselect::cmp_str()
{
  String *val1, *val2, buf1, buf2;
2213
  Item *maxmin= ((Item_singlerow_subselect *)item)->element_index(0);
2214 2215 2216 2217 2218 2219 2220 2221 2222 2223
  /*
    as far as both operand is Item_cache buf1 & buf2 will not be used,
    but added for safety
  */
  val1= cache->val_str(&buf1);
  val2= maxmin->val_str(&buf1);
  if (fmax)
    return (cache->null_value && !maxmin->null_value) ||
      (!cache->null_value && !maxmin->null_value &&
       sortcmp(val1, val2, cache->collation.collation) > 0) ;
2224 2225 2226
  return (maxmin->null_value && !cache->null_value) ||
    (!cache->null_value && !maxmin->null_value &&
     sortcmp(val1, val2, cache->collation.collation) < 0);
2227 2228
}

2229 2230 2231 2232 2233 2234 2235 2236 2237 2238
bool select_exists_subselect::send_data(List<Item> &items)
{
  DBUG_ENTER("select_exists_subselect::send_data");
  Item_exists_subselect *it= (Item_exists_subselect *)item;
  if (unit->offset_limit_cnt)
  {				          // Using limit offset,count
    unit->offset_limit_cnt--;
    DBUG_RETURN(0);
  }
  it->value= 1;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2239
  it->assigned(1);
2240 2241 2242
  DBUG_RETURN(0);
}

Sinisa@sinisa.nasamreza.org's avatar
Sinisa@sinisa.nasamreza.org committed
2243 2244

/***************************************************************************
2245
  Dump of select to variables
Sinisa@sinisa.nasamreza.org's avatar
Sinisa@sinisa.nasamreza.org committed
2246
***************************************************************************/
2247

2248
int select_dumpvar::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
Sinisa@sinisa.nasamreza.org's avatar
Sinisa@sinisa.nasamreza.org committed
2249
{
2250
  unit= u;
2251
  
2252
  if (var_list.elements != list.elements)
Sinisa@sinisa.nasamreza.org's avatar
Sinisa@sinisa.nasamreza.org committed
2253
  {
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2254 2255
    my_message(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT,
               ER(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT), MYF(0));
2256
    return 1;
2257
  }               
2258 2259
  return 0;
}
2260

2261

2262 2263 2264 2265 2266 2267 2268
bool select_dumpvar::check_simple_select() const
{
  my_error(ER_SP_BAD_CURSOR_SELECT, MYF(0));
  return TRUE;
}


2269 2270
void select_dumpvar::cleanup()
{
2271
  row_count= 0;
2272 2273 2274
}


serg@serg.mylan's avatar
serg@serg.mylan committed
2275
Query_arena::Type Query_arena::type() const
2276
{
monty@mysql.com's avatar
monty@mysql.com committed
2277
  DBUG_ASSERT(0); /* Should never be called */
2278
  return STATEMENT;
2279 2280 2281
}


2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296
void Query_arena::free_items()
{
  Item *next;
  DBUG_ENTER("Query_arena::free_items");
  /* This works because items are allocated with sql_alloc() */
  for (; free_list; free_list= next)
  {
    next= free_list->next;
    free_list->delete_self();
  }
  /* Postcondition: free_list is 0 */
  DBUG_VOID_RETURN;
}


2297 2298 2299 2300 2301 2302 2303 2304 2305 2306
void Query_arena::set_query_arena(Query_arena *set)
{
  mem_root=  set->mem_root;
  free_list= set->free_list;
  state= set->state;
}


void Query_arena::cleanup_stmt()
{
2307
  DBUG_ASSERT(! "Query_arena::cleanup_stmt() not implemented");
2308 2309
}

2310
/*
serg@janus.mylan's avatar
serg@janus.mylan committed
2311
  Statement functions
2312 2313
*/

2314 2315 2316
Statement::Statement(LEX *lex_arg, MEM_ROOT *mem_root_arg,
                     enum enum_state state_arg, ulong id_arg)
  :Query_arena(mem_root_arg, state_arg),
2317
  id(id_arg),
2318
  mark_used_columns(MARK_COLUMNS_READ),
2319
  lex(lex_arg),
2320
  query(0),
2321
  query_length(0),
2322 2323 2324
  cursor(0),
  db(NULL),
  db_length(0)
2325
{
2326
  name.str= NULL;
2327 2328 2329
}


serg@serg.mylan's avatar
serg@serg.mylan committed
2330
Query_arena::Type Statement::type() const
2331 2332 2333 2334 2335 2336 2337 2338
{
  return STATEMENT;
}


void Statement::set_statement(Statement *stmt)
{
  id=             stmt->id;
2339
  mark_used_columns=   stmt->mark_used_columns;
2340 2341 2342
  lex=            stmt->lex;
  query=          stmt->query;
  query_length=   stmt->query_length;
2343
  cursor=         stmt->cursor;
2344 2345 2346
}


2347 2348 2349
void
Statement::set_n_backup_statement(Statement *stmt, Statement *backup)
{
2350
  DBUG_ENTER("Statement::set_n_backup_statement");
2351 2352
  backup->set_statement(this);
  set_statement(stmt);
2353
  DBUG_VOID_RETURN;
2354 2355 2356 2357 2358
}


void Statement::restore_backup_statement(Statement *stmt, Statement *backup)
{
2359
  DBUG_ENTER("Statement::restore_backup_statement");
2360 2361
  stmt->set_statement(this);
  set_statement(backup);
2362
  DBUG_VOID_RETURN;
2363 2364 2365
}


2366
void THD::end_statement()
2367
{
2368
  /* Cleanup SQL processing state to reuse this statement in next query. */
2369 2370 2371
  lex_end(lex);
  delete lex->result;
  lex->result= 0;
2372 2373
  /* Note that free_list is freed in cleanup_after_query() */

2374 2375 2376 2377 2378 2379 2380
  /*
    Don't free mem_root, as mem_root is freed in the end of dispatch_command
    (once for any command).
  */
}


konstantin@mysql.com's avatar
konstantin@mysql.com committed
2381
void THD::set_n_backup_active_arena(Query_arena *set, Query_arena *backup)
2382
{
konstantin@mysql.com's avatar
konstantin@mysql.com committed
2383
  DBUG_ENTER("THD::set_n_backup_active_arena");
2384
  DBUG_ASSERT(backup->is_backup_arena == FALSE);
2385

konstantin@mysql.com's avatar
konstantin@mysql.com committed
2386 2387
  backup->set_query_arena(this);
  set_query_arena(set);
monty@mysql.com's avatar
monty@mysql.com committed
2388
#ifndef DBUG_OFF
2389
  backup->is_backup_arena= TRUE;
monty@mysql.com's avatar
monty@mysql.com committed
2390
#endif
2391
  DBUG_VOID_RETURN;
2392 2393 2394
}


konstantin@mysql.com's avatar
konstantin@mysql.com committed
2395
void THD::restore_active_arena(Query_arena *set, Query_arena *backup)
2396
{
konstantin@mysql.com's avatar
konstantin@mysql.com committed
2397
  DBUG_ENTER("THD::restore_active_arena");
2398
  DBUG_ASSERT(backup->is_backup_arena);
konstantin@mysql.com's avatar
konstantin@mysql.com committed
2399 2400
  set->set_query_arena(this);
  set_query_arena(backup);
monty@mysql.com's avatar
monty@mysql.com committed
2401
#ifndef DBUG_OFF
2402
  backup->is_backup_arena= FALSE;
2403
#endif
monty@mysql.com's avatar
monty@mysql.com committed
2404
  DBUG_VOID_RETURN;
2405 2406
}

2407 2408 2409 2410 2411 2412
Statement::~Statement()
{
}

C_MODE_START

2413 2414
static uchar *
get_statement_id_as_hash_key(const uchar *record, size_t *key_length,
2415 2416 2417 2418
                             my_bool not_used __attribute__((unused)))
{
  const Statement *statement= (const Statement *) record; 
  *key_length= sizeof(statement->id);
2419
  return (uchar *) &((const Statement *) statement)->id;
2420 2421 2422 2423 2424 2425 2426
}

static void delete_statement_as_hash_key(void *key)
{
  delete (Statement *) key;
}

2427
static uchar *get_stmt_name_hash_key(Statement *entry, size_t *length,
2428
                                    my_bool not_used __attribute__((unused)))
2429
{
2430 2431
  *length= entry->name.length;
  return (uchar*) entry->name.str;
2432 2433
}

2434 2435 2436 2437 2438
C_MODE_END

Statement_map::Statement_map() :
  last_found_statement(0)
{
2439 2440 2441 2442 2443
  enum
  {
    START_STMT_HASH_SIZE = 16,
    START_NAME_HASH_SIZE = 16
  };
2444
  hash_init(&st_hash, &my_charset_bin, START_STMT_HASH_SIZE, 0, 0,
2445 2446
            get_statement_id_as_hash_key,
            delete_statement_as_hash_key, MYF(0));
2447
  hash_init(&names_hash, system_charset_info, START_NAME_HASH_SIZE, 0, 0,
2448 2449
            (hash_get_key) get_stmt_name_hash_key,
            NULL,MYF(0));
2450 2451
}

2452

2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474
/*
  Insert a new statement to the thread-local statement map.

  DESCRIPTION
    If there was an old statement with the same name, replace it with the
    new one. Otherwise, check if max_prepared_stmt_count is not reached yet,
    increase prepared_stmt_count, and insert the new statement. It's okay
    to delete an old statement and fail to insert the new one.

  POSTCONDITIONS
    All named prepared statements are also present in names_hash.
    Statement names in names_hash are unique.
    The statement is added only if prepared_stmt_count < max_prepard_stmt_count
    last_found_statement always points to a valid statement or is 0

  RETURN VALUE
    0  success
    1  error: out of resources or max_prepared_stmt_count limit has been
       reached. An error is sent to the client, the statement is deleted.
*/

int Statement_map::insert(THD *thd, Statement *statement)
2475
{
2476
  if (my_hash_insert(&st_hash, (uchar*) statement))
2477
  {
2478 2479 2480 2481 2482 2483 2484 2485
    /*
      Delete is needed only in case of an insert failure. In all other
      cases hash_delete will also delete the statement.
    */
    delete statement;
    my_error(ER_OUT_OF_RESOURCES, MYF(0));
    goto err_st_hash;
  }
2486
  if (statement->name.str && my_hash_insert(&names_hash, (uchar*) statement))
2487
  {
2488 2489
    my_error(ER_OUT_OF_RESOURCES, MYF(0));
    goto err_names_hash;
2490
  }
2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501
  pthread_mutex_lock(&LOCK_prepared_stmt_count);
  /*
    We don't check that prepared_stmt_count is <= max_prepared_stmt_count
    because we would like to allow to lower the total limit
    of prepared statements below the current count. In that case
    no new statements can be added until prepared_stmt_count drops below
    the limit.
  */
  if (prepared_stmt_count >= max_prepared_stmt_count)
  {
    pthread_mutex_unlock(&LOCK_prepared_stmt_count);
2502 2503
    my_error(ER_MAX_PREPARED_STMT_COUNT_REACHED, MYF(0),
             max_prepared_stmt_count);
2504 2505 2506 2507 2508
    goto err_max;
  }
  prepared_stmt_count++;
  pthread_mutex_unlock(&LOCK_prepared_stmt_count);

2509
  last_found_statement= statement;
2510 2511 2512 2513
  return 0;

err_max:
  if (statement->name.str)
2514
    hash_delete(&names_hash, (uchar*) statement);
2515
err_names_hash:
2516
  hash_delete(&st_hash, (uchar*) statement);
2517 2518
err_st_hash:
  return 1;
2519 2520
}

2521

2522 2523
void Statement_map::close_transient_cursors()
{
2524
#ifdef TO_BE_IMPLEMENTED
2525 2526 2527
  Statement *stmt;
  while ((stmt= transient_cursor_list.head()))
    stmt->close_cursor();                 /* deletes itself from the list */
2528
#endif
2529 2530 2531
}


2532 2533 2534 2535 2536
void Statement_map::erase(Statement *statement)
{
  if (statement == last_found_statement)
    last_found_statement= 0;
  if (statement->name.str)
2537
    hash_delete(&names_hash, (uchar *) statement);
2538

2539
  hash_delete(&st_hash, (uchar *) statement);
2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557
  pthread_mutex_lock(&LOCK_prepared_stmt_count);
  DBUG_ASSERT(prepared_stmt_count > 0);
  prepared_stmt_count--;
  pthread_mutex_unlock(&LOCK_prepared_stmt_count);
}


void Statement_map::reset()
{
  /* Must be first, hash_free will reset st_hash.records */
  pthread_mutex_lock(&LOCK_prepared_stmt_count);
  DBUG_ASSERT(prepared_stmt_count >= st_hash.records);
  prepared_stmt_count-= st_hash.records;
  pthread_mutex_unlock(&LOCK_prepared_stmt_count);

  my_hash_reset(&names_hash);
  my_hash_reset(&st_hash);
  last_found_statement= 0;
2558 2559
}

2560

2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572
Statement_map::~Statement_map()
{
  /* Must go first, hash_free will reset st_hash.records */
  pthread_mutex_lock(&LOCK_prepared_stmt_count);
  DBUG_ASSERT(prepared_stmt_count >= st_hash.records);
  prepared_stmt_count-= st_hash.records;
  pthread_mutex_unlock(&LOCK_prepared_stmt_count);

  hash_free(&names_hash);
  hash_free(&st_hash);
}

2573 2574
bool select_dumpvar::send_data(List<Item> &items)
{
2575
  List_iterator_fast<my_var> var_li(var_list);
2576
  List_iterator<Item> it(items);
2577
  Item *item;
2578
  my_var *mv;
2579
  DBUG_ENTER("select_dumpvar::send_data");
2580

2581
  if (unit->offset_limit_cnt)
2582
  {						// using limit offset,count
2583 2584 2585
    unit->offset_limit_cnt--;
    DBUG_RETURN(0);
  }
2586 2587
  if (row_count++) 
  {
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2588
    my_message(ER_TOO_MANY_ROWS, ER(ER_TOO_MANY_ROWS), MYF(0));
2589 2590
    DBUG_RETURN(1);
  }
2591
  while ((mv= var_li++) && (item= it++))
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2592
  {
2593
    if (mv->local)
2594
    {
2595 2596
      if (thd->spcont->set_variable(thd, mv->offset, &item))
	    DBUG_RETURN(1);
2597 2598 2599
    }
    else
    {
2600 2601 2602
      Item_func_set_user_var *suv= new Item_func_set_user_var(mv->s, item);
      suv->fix_fields(thd, 0);
      suv->check(0);
2603
      suv->update();
2604
    }
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2605
  }
2606
  DBUG_RETURN(thd->is_error());
Sinisa@sinisa.nasamreza.org's avatar
Sinisa@sinisa.nasamreza.org committed
2607 2608 2609 2610
}

bool select_dumpvar::send_eof()
{
2611
  if (! row_count)
serg@serg.mylan's avatar
serg@serg.mylan committed
2612 2613
    push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                 ER_SP_FETCH_NO_DATA, ER(ER_SP_FETCH_NO_DATA));
2614 2615 2616 2617 2618
  /*
    In order to remember the value of affected rows for ROW_COUNT()
    function, SELECT INTO has to have an own SQLCOM.
    TODO: split from SQLCOM_SELECT
  */
2619
  ::my_ok(thd,row_count);
2620
  return 0;
Sinisa@sinisa.nasamreza.org's avatar
Sinisa@sinisa.nasamreza.org committed
2621
}
2622 2623 2624 2625 2626 2627 2628

/****************************************************************************
  TMP_TABLE_PARAM
****************************************************************************/

void TMP_TABLE_PARAM::init()
{
2629 2630
  DBUG_ENTER("TMP_TABLE_PARAM::init");
  DBUG_PRINT("enter", ("this: 0x%lx", (ulong)this));
2631 2632 2633
  field_count= sum_func_count= func_count= hidden_field_count= 0;
  group_parts= group_length= group_null_parts= 0;
  quick_group= 1;
2634
  table_charset= 0;
2635
  precomputed_group_by= 0;
2636
  DBUG_VOID_RETURN;
2637
}
2638 2639 2640 2641


void thd_increment_bytes_sent(ulong length)
{
serg@serg.mylan's avatar
serg@serg.mylan committed
2642
  THD *thd=current_thd;
lars@mysql.com's avatar
lars@mysql.com committed
2643
  if (likely(thd != 0))
serg@serg.mylan's avatar
serg@serg.mylan committed
2644 2645 2646
  { /* current_thd==0 when close_connection() calls net_send_error() */
    thd->status_var.bytes_sent+= length;
  }
2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665
}


void thd_increment_bytes_received(ulong length)
{
  current_thd->status_var.bytes_received+= length;
}


void thd_increment_net_big_packet_count(ulong length)
{
  current_thd->status_var.net_big_packet_count+= length;
}


void THD::set_status_var_init()
{
  bzero((char*) &status_var, sizeof(status_var));
}
2666

2667

2668
void Security_context::init()
2669 2670 2671
{
  host= user= priv_user= ip= 0;
  host_or_ip= "connecting host";
2672
  priv_host[0]= '\0';
2673
  master_access= 0;
2674 2675 2676 2677 2678 2679
#ifndef NO_EMBEDDED_ACCESS_CHECKS
  db_access= NO_ACCESS;
#endif
}


2680
void Security_context::destroy()
2681 2682 2683 2684 2685 2686 2687 2688 2689 2690
{
  // If not pointer to constant
  if (host != my_localhost)
    safeFree(host);
  if (user != delayed_user)
    safeFree(user);
  safeFree(ip);
}


2691
void Security_context::skip_grants()
2692 2693 2694 2695 2696 2697 2698 2699 2700
{
  /* privileges for the user are unknown everything is allowed */
  host_or_ip= (char *)"";
  master_access= ~NO_ACCESS;
  priv_user= (char *)"";
  *priv_host= '\0';
}


2701 2702 2703 2704 2705 2706 2707
bool Security_context::set_user(char *user_arg)
{
  safeFree(user);
  user= my_strdup(user_arg, MYF(0));
  return user == 0;
}

2708 2709 2710 2711 2712
#ifndef NO_EMBEDDED_ACCESS_CHECKS
/**
  Initialize this security context from the passed in credentials
  and activate it in the current thread.

kostja@bodhi.(none)'s avatar
kostja@bodhi.(none) committed
2713 2714 2715 2716
  @param       thd
  @param       definer_user
  @param       definer_host
  @param       db
2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807
  @param[out]  backup  Save a pointer to the current security context
                       in the thread. In case of success it points to the
                       saved old context, otherwise it points to NULL.


  During execution of a statement, multiple security contexts may
  be needed:
  - the security context of the authenticated user, used as the
    default security context for all top-level statements
  - in case of a view or a stored program, possibly the security
    context of the definer of the routine, if the object is
    defined with SQL SECURITY DEFINER option.

  The currently "active" security context is parameterized in THD
  member security_ctx. By default, after a connection is
  established, this member points at the "main" security context
  - the credentials of the authenticated user.

  Later, if we would like to execute some sub-statement or a part
  of a statement under credentials of a different user, e.g.
  definer of a procedure, we authenticate this user in a local
  instance of Security_context by means of this method (and
  ultimately by means of acl_getroot_no_password), and make the
  local instance active in the thread by re-setting
  thd->security_ctx pointer.

  Note, that the life cycle and memory management of the "main" and
  temporary security contexts are different.
  For the main security context, the memory for user/host/ip is
  allocated on system heap, and the THD class frees this memory in
  its destructor. The only case when contents of the main security
  context may change during its life time is when someone issued
  CHANGE USER command.
  Memory management of a "temporary" security context is
  responsibility of the module that creates it.

  @retval TRUE  there is no user with the given credentials. The erro
                is reported in the thread.
  @retval FALSE success
*/

bool
Security_context::
change_security_context(THD *thd,
                        LEX_STRING *definer_user,
                        LEX_STRING *definer_host,
                        LEX_STRING *db,
                        Security_context **backup)
{
  bool needs_change;

  DBUG_ENTER("Security_context::change_security_context");

  DBUG_ASSERT(definer_user->str && definer_host->str);

  *backup= NULL;
  /*
    The current security context may have NULL members
    if we have just started the thread and not authenticated
    any user. This use case is currently in events worker thread.
  */
  needs_change= (thd->security_ctx->priv_user == NULL ||
                 strcmp(definer_user->str, thd->security_ctx->priv_user) ||
                 thd->security_ctx->priv_host == NULL ||
                 my_strcasecmp(system_charset_info, definer_host->str,
                               thd->security_ctx->priv_host));
  if (needs_change)
  {
    if (acl_getroot_no_password(this, definer_user->str, definer_host->str,
                                definer_host->str, db->str))
    {
      my_error(ER_NO_SUCH_USER, MYF(0), definer_user->str,
               definer_host->str);
      DBUG_RETURN(TRUE);
    }
    *backup= thd->security_ctx;
    thd->security_ctx= this;
  }

  DBUG_RETURN(FALSE);
}


void
Security_context::restore_security_context(THD *thd,
                                           Security_context *backup)
{
  if (backup)
    thd->security_ctx= backup;
}
#endif
2808

2809

2810 2811 2812 2813 2814 2815 2816
bool Security_context::user_matches(Security_context *them)
{
  return ((user != NULL) && (them->user != NULL) &&
          !strcmp(user, them->user));
}


2817 2818 2819 2820 2821 2822 2823 2824
/****************************************************************************
  Handling of open and locked tables states.

  This is used when we want to open/lock (and then close) some tables when
  we already have a set of tables open and locked. We use these methods for
  access to mysql.proc table to find definitions of stored routines.
****************************************************************************/

2825
void THD::reset_n_backup_open_tables_state(Open_tables_state *backup)
2826
{
2827 2828
  DBUG_ENTER("reset_n_backup_open_tables_state");
  backup->set_open_tables_state(this);
2829
  reset_open_tables_state();
2830
  state_flags|= Open_tables_state::BACKUPS_AVAIL;
2831
  DBUG_VOID_RETURN;
2832 2833 2834
}


2835 2836 2837 2838 2839 2840 2841 2842 2843 2844
void THD::restore_backup_open_tables_state(Open_tables_state *backup)
{
  DBUG_ENTER("restore_backup_open_tables_state");
  /*
    Before we will throw away current open tables state we want
    to be sure that it was properly cleaned up.
  */
  DBUG_ASSERT(open_tables == 0 && temporary_tables == 0 &&
              handler_tables == 0 && derived_tables == 0 &&
              lock == 0 && locked_tables == 0 &&
2845
              prelocked_mode == NON_PRELOCKED &&
2846
              m_reprepare_observer == NULL);
2847
  set_open_tables_state(backup);
2848 2849
  DBUG_VOID_RETURN;
}
2850

2851 2852 2853 2854 2855 2856 2857 2858 2859 2860
/**
  Check the killed state of a user thread
  @param thd  user thread
  @retval 0 the user thread is active
  @retval 1 the user thread has been killed
*/
extern "C" int thd_killed(const MYSQL_THD thd)
{
  return(thd->killed);
}
2861

2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872
/**
  Return the thread id of a user thread
  @param thd user thread
  @return thread id
*/
extern "C" unsigned long thd_get_thread_id(const MYSQL_THD thd)
{
  return((unsigned long)thd->thread_id);
}


2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887
#ifdef INNODB_COMPATIBILITY_HOOKS
extern "C" struct charset_info_st *thd_charset(MYSQL_THD thd)
{
  return(thd->charset());
}

extern "C" char **thd_query(MYSQL_THD thd)
{
  return(&thd->query);
}

extern "C" int thd_slave_thread(const MYSQL_THD thd)
{
  return(thd->slave_thread);
}
2888

2889 2890
extern "C" int thd_non_transactional_update(const MYSQL_THD thd)
{
2891
  return(thd->transaction.all.modified_non_trans_table);
2892 2893
}

2894
extern "C" int thd_binlog_format(const MYSQL_THD thd)
2895
{
2896 2897 2898 2899
  if (mysql_bin_log.is_open() && (thd->options & OPTION_BIN_LOG))
    return (int) thd->variables.binlog_format;
  else
    return BINLOG_FORMAT_UNSPEC;
2900
}
2901 2902 2903 2904 2905

extern "C" void thd_mark_transaction_to_rollback(MYSQL_THD thd, bool all)
{
  mark_transaction_to_rollback(thd, all);
}
2906
#endif // INNODB_COMPATIBILITY_HOOKS */
2907

2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920
/****************************************************************************
  Handling of statement states in functions and triggers.

  This is used to ensure that the function/trigger gets a clean state
  to work with and does not cause any side effects of the calling statement.

  It also allows most stored functions and triggers to replicate even
  if they are used items that would normally be stored in the binary
  replication (like last_insert_id() etc...)

  The following things is done
  - Disable binary logging for the duration of the statement
  - Disable multi-result-sets for the duration of the statement
2921
  - Value of last_insert_id() is saved and restored
2922 2923 2924 2925
  - Value set by 'SET INSERT_ID=#' is reset and restored
  - Value for found_rows() is reset and restored
  - examined_row_count is added to the total
  - cuted_fields is added to the total
2926
  - new savepoint level is created and destroyed
2927 2928 2929 2930 2931 2932

  NOTES:
    Seed for random() is saved for the first! usage of RAND()
    We reset examined_row_count and cuted_fields and add these to the
    result to ensure that if we have a bug that would reset these within
    a function, we are not loosing any rows from the main statement.
2933 2934

    We do not reset value of last_insert_id().
2935 2936 2937 2938 2939
****************************************************************************/

void THD::reset_sub_statement_state(Sub_statement_state *backup,
                                    uint new_state)
{
2940 2941 2942 2943 2944 2945 2946
#ifndef EMBEDDED_LIBRARY
  /* BUG#33029, if we are replicating from a buggy master, reset
     auto_inc_intervals_forced to prevent substatement
     (triggers/functions) from using erroneous INSERT_ID value
   */
  if (rpl_master_erroneous_autoinc(this))
  {
2947 2948
    DBUG_ASSERT(backup->auto_inc_intervals_forced.nb_elements() == 0);
    auto_inc_intervals_forced.swap(&backup->auto_inc_intervals_forced);
2949 2950 2951
  }
#endif
  
2952 2953 2954 2955 2956 2957 2958 2959
  backup->options=         options;
  backup->in_sub_stmt=     in_sub_stmt;
  backup->enable_slow_log= enable_slow_log;
  backup->limit_found_rows= limit_found_rows;
  backup->examined_row_count= examined_row_count;
  backup->sent_row_count=   sent_row_count;
  backup->cuted_fields=     cuted_fields;
  backup->client_capabilities= client_capabilities;
2960
  backup->savepoints= transaction.savepoints;
2961 2962 2963 2964
  backup->first_successful_insert_id_in_prev_stmt= 
    first_successful_insert_id_in_prev_stmt;
  backup->first_successful_insert_id_in_cur_stmt= 
    first_successful_insert_id_in_cur_stmt;
2965

2966
  if ((!lex->requires_prelocking() || is_update_query(lex->sql_command)) &&
2967
      !current_stmt_binlog_row_based)
2968
  {
2969
    options&= ~OPTION_BIN_LOG;
2970
  }
2971 2972 2973 2974 2975

  if ((backup->options & OPTION_BIN_LOG) && is_update_query(lex->sql_command)&&
      !current_stmt_binlog_row_based)
    mysql_bin_log.start_union_events(this, this->query_id);

2976 2977 2978 2979 2980 2981
  /* Disable result sets */
  client_capabilities &= ~CLIENT_MULTI_RESULTS;
  in_sub_stmt|= new_state;
  examined_row_count= 0;
  sent_row_count= 0;
  cuted_fields= 0;
2982
  transaction.savepoints= 0;
2983
  first_successful_insert_id_in_cur_stmt= 0;
2984 2985 2986 2987 2988
}


void THD::restore_sub_statement_state(Sub_statement_state *backup)
{
2989 2990 2991 2992 2993 2994 2995
#ifndef EMBEDDED_LIBRARY
  /* BUG#33029, if we are replicating from a buggy master, restore
     auto_inc_intervals_forced so that the top statement can use the
     INSERT_ID value set before this statement.
   */
  if (rpl_master_erroneous_autoinc(this))
  {
2996 2997
    backup->auto_inc_intervals_forced.swap(&auto_inc_intervals_forced);
    DBUG_ASSERT(backup->auto_inc_intervals_forced.nb_elements() == 0);
2998 2999 3000
  }
#endif

3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015
  /*
    To save resources we want to release savepoints which were created
    during execution of function or trigger before leaving their savepoint
    level. It is enough to release first savepoint set on this level since
    all later savepoints will be released automatically.
  */
  if (transaction.savepoints)
  {
    SAVEPOINT *sv;
    for (sv= transaction.savepoints; sv->prev; sv= sv->prev)
    {}
    /* ha_release_savepoint() never returns error. */
    (void)ha_release_savepoint(this, sv);
  }
  transaction.savepoints= backup->savepoints;
3016 3017 3018
  options=          backup->options;
  in_sub_stmt=      backup->in_sub_stmt;
  enable_slow_log=  backup->enable_slow_log;
3019 3020 3021 3022
  first_successful_insert_id_in_prev_stmt= 
    backup->first_successful_insert_id_in_prev_stmt;
  first_successful_insert_id_in_cur_stmt= 
    backup->first_successful_insert_id_in_cur_stmt;
3023 3024 3025
  limit_found_rows= backup->limit_found_rows;
  sent_row_count=   backup->sent_row_count;
  client_capabilities= backup->client_capabilities;
3026 3027 3028 3029 3030 3031 3032
  /*
    If we've left sub-statement mode, reset the fatal error flag.
    Otherwise keep the current value, to propagate it up the sub-statement
    stack.
  */
  if (!in_sub_stmt)
    is_fatal_sub_stmt_error= FALSE;
3033

3034 3035 3036
  if ((options & OPTION_BIN_LOG) && is_update_query(lex->sql_command) &&
    !current_stmt_binlog_row_based)
    mysql_bin_log.stop_union_events(this);
3037

3038 3039 3040 3041 3042 3043 3044
  /*
    The following is added to the old values as we are interested in the
    total complexity of the query
  */
  examined_row_count+= backup->examined_row_count;
  cuted_fields+=       backup->cuted_fields;
}
3045 3046


3047 3048 3049 3050 3051 3052 3053 3054 3055
/**
  Mark transaction to rollback and mark error as fatal to a sub-statement.

  @param  thd   Thread handle
  @param  all   TRUE <=> rollback main transaction.
*/

void mark_transaction_to_rollback(THD *thd, bool all)
{
3056 3057 3058 3059 3060
  if (thd)
  {
    thd->is_fatal_sub_stmt_error= TRUE;
    thd->transaction_rollback_request= all;
  }
3061
}
3062 3063 3064 3065
/***************************************************************************
  Handling of XA id cacheing
***************************************************************************/

3066 3067 3068
pthread_mutex_t LOCK_xid_cache;
HASH xid_cache;

3069 3070 3071 3072
extern "C" uchar *xid_get_hash_key(const uchar *, size_t *, my_bool);
extern "C" void xid_free_hash(void *);

uchar *xid_get_hash_key(const uchar *ptr, size_t *length,
3073 3074
                                  my_bool not_used __attribute__((unused)))
{
3075 3076
  *length=((XID_STATE*)ptr)->xid.key_length();
  return ((XID_STATE*)ptr)->xid.key();
3077 3078
}

3079
void xid_free_hash(void *ptr)
3080 3081
{
  if (!((XID_STATE*)ptr)->in_thd)
3082
    my_free((uchar*)ptr, MYF(0));
3083 3084 3085 3086 3087
}

bool xid_cache_init()
{
  pthread_mutex_init(&LOCK_xid_cache, MY_MUTEX_INIT_FAST);
serg@sergbook.mysql.com's avatar
serg@sergbook.mysql.com committed
3088 3089
  return hash_init(&xid_cache, &my_charset_bin, 100, 0, 0,
                   xid_get_hash_key, xid_free_hash, 0) != 0;
3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103
}

void xid_cache_free()
{
  if (hash_inited(&xid_cache))
  {
    hash_free(&xid_cache);
    pthread_mutex_destroy(&LOCK_xid_cache);
  }
}

XID_STATE *xid_cache_search(XID *xid)
{
  pthread_mutex_lock(&LOCK_xid_cache);
3104
  XID_STATE *res=(XID_STATE *)hash_search(&xid_cache, xid->key(), xid->key_length());
3105 3106 3107 3108
  pthread_mutex_unlock(&LOCK_xid_cache);
  return res;
}

3109

3110 3111 3112 3113 3114
bool xid_cache_insert(XID *xid, enum xa_states xa_state)
{
  XID_STATE *xs;
  my_bool res;
  pthread_mutex_lock(&LOCK_xid_cache);
3115
  if (hash_search(&xid_cache, xid->key(), xid->key_length()))
3116 3117 3118 3119 3120 3121 3122 3123
    res=0;
  else if (!(xs=(XID_STATE *)my_malloc(sizeof(*xs), MYF(MY_WME))))
    res=1;
  else
  {
    xs->xa_state=xa_state;
    xs->xid.set(xid);
    xs->in_thd=0;
3124
    res=my_hash_insert(&xid_cache, (uchar*)xs);
3125 3126 3127 3128 3129
  }
  pthread_mutex_unlock(&LOCK_xid_cache);
  return res;
}

3130

3131 3132 3133
bool xid_cache_insert(XID_STATE *xid_state)
{
  pthread_mutex_lock(&LOCK_xid_cache);
3134 3135
  DBUG_ASSERT(hash_search(&xid_cache, xid_state->xid.key(),
                          xid_state->xid.key_length())==0);
3136
  my_bool res=my_hash_insert(&xid_cache, (uchar*)xid_state);
3137 3138 3139 3140
  pthread_mutex_unlock(&LOCK_xid_cache);
  return res;
}

3141

3142 3143 3144
void xid_cache_delete(XID_STATE *xid_state)
{
  pthread_mutex_lock(&LOCK_xid_cache);
3145
  hash_delete(&xid_cache, (uchar *)xid_state);
3146 3147 3148
  pthread_mutex_unlock(&LOCK_xid_cache);
}

3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180
/*
  Implementation of interface to write rows to the binary log through the
  thread.  The thread is responsible for writing the rows it has
  inserted/updated/deleted.
*/

#ifndef MYSQL_CLIENT

/*
  Template member function for ensuring that there is an rows log
  event of the apropriate type before proceeding.

  PRE CONDITION:
    - Events of type 'RowEventT' have the type code 'type_code'.
    
  POST CONDITION:
    If a non-NULL pointer is returned, the pending event for thread 'thd' will
    be an event of type 'RowEventT' (which have the type code 'type_code')
    will either empty or have enough space to hold 'needed' bytes.  In
    addition, the columns bitmap will be correct for the row, meaning that
    the pending event will be flushed if the columns in the event differ from
    the columns suppled to the function.

  RETURNS
    If no error, a non-NULL pending event (either one which already existed or
    the newly created one).
    If error, NULL.
 */

template <class RowsEventT> Rows_log_event* 
THD::binlog_prepare_pending_rows_event(TABLE* table, uint32 serv_id,
                                       MY_BITMAP const* cols,
3181 3182
                                       size_t colcnt,
                                       size_t needed,
3183 3184
                                       bool is_transactional,
				       RowsEventT *hint __attribute__((unused)))
3185
{
3186
  DBUG_ENTER("binlog_prepare_pending_rows_event");
3187
  /* Pre-conditions */
3188
  DBUG_ASSERT(table->s->table_map_id != ~0UL);
3189 3190 3191 3192 3193 3194 3195 3196 3197

  /* Fetch the type code for the RowsEventT template parameter */
  int const type_code= RowsEventT::TYPE_CODE;

  /*
    There is no good place to set up the transactional data, so we
    have to do it here.
  */
  if (binlog_setup_trx_data())
3198
    DBUG_RETURN(NULL);
3199 3200 3201 3202

  Rows_log_event* pending= binlog_get_pending_rows_event();

  if (unlikely(pending && !pending->is_valid()))
3203
    DBUG_RETURN(NULL);
3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227

  /*
    Check if the current event is non-NULL and a write-rows
    event. Also check if the table provided is mapped: if it is not,
    then we have switched to writing to a new table.
    If there is no pending event, we need to create one. If there is a pending
    event, but it's not about the same table id, or not of the same type
    (between Write, Update and Delete), or not the same affected columns, or
    going to be too big, flush this event to disk and create a new pending
    event.
  */
  if (!pending ||
      pending->server_id != serv_id || 
      pending->get_table_id() != table->s->table_map_id ||
      pending->get_type_code() != type_code || 
      pending->get_data_size() + needed > opt_binlog_rows_event_max_size || 
      pending->get_width() != colcnt ||
      !bitmap_cmp(pending->get_cols(), cols)) 
  {
    /* Create a new RowsEventT... */
    Rows_log_event* const
	ev= new RowsEventT(this, table, table->s->table_map_id, cols,
                           is_transactional);
    if (unlikely(!ev))
3228
      DBUG_RETURN(NULL);
3229 3230 3231 3232 3233 3234 3235 3236
    ev->server_id= serv_id; // I don't like this, it's too easy to forget.
    /*
      flush the pending event and replace it with the newly created
      event...
    */
    if (unlikely(mysql_bin_log.flush_and_set_pending_rows_event(this, ev)))
    {
      delete ev;
3237
      DBUG_RETURN(NULL);
3238 3239
    }

3240
    DBUG_RETURN(ev);               /* This is the new pending event */
3241
  }
3242
  DBUG_RETURN(pending);        /* This is the current pending event */
3243 3244
}

3245
#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
3246
/*
3247
  Instantiate the versions we need, we have -fno-implicit-template as
3248 3249 3250
  compiling option.
*/
template Rows_log_event*
3251
THD::binlog_prepare_pending_rows_event(TABLE*, uint32, MY_BITMAP const*,
3252
				       size_t, size_t, bool,
3253
				       Write_rows_log_event*);
3254 3255

template Rows_log_event*
3256
THD::binlog_prepare_pending_rows_event(TABLE*, uint32, MY_BITMAP const*,
3257
				       size_t colcnt, size_t, bool,
3258
				       Delete_rows_log_event *);
3259 3260

template Rows_log_event* 
3261
THD::binlog_prepare_pending_rows_event(TABLE*, uint32, MY_BITMAP const*,
3262
				       size_t colcnt, size_t, bool,
3263
				       Update_rows_log_event *);
3264
#endif
3265 3266

#ifdef NOT_USED
3267 3268 3269
static char const* 
field_type_name(enum_field_types type) 
{
3270
  switch (type) {
3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327
  case MYSQL_TYPE_DECIMAL:
    return "MYSQL_TYPE_DECIMAL";
  case MYSQL_TYPE_TINY:
    return "MYSQL_TYPE_TINY";
  case MYSQL_TYPE_SHORT:
    return "MYSQL_TYPE_SHORT";
  case MYSQL_TYPE_LONG:
    return "MYSQL_TYPE_LONG";
  case MYSQL_TYPE_FLOAT:
    return "MYSQL_TYPE_FLOAT";
  case MYSQL_TYPE_DOUBLE:
    return "MYSQL_TYPE_DOUBLE";
  case MYSQL_TYPE_NULL:
    return "MYSQL_TYPE_NULL";
  case MYSQL_TYPE_TIMESTAMP:
    return "MYSQL_TYPE_TIMESTAMP";
  case MYSQL_TYPE_LONGLONG:
    return "MYSQL_TYPE_LONGLONG";
  case MYSQL_TYPE_INT24:
    return "MYSQL_TYPE_INT24";
  case MYSQL_TYPE_DATE:
    return "MYSQL_TYPE_DATE";
  case MYSQL_TYPE_TIME:
    return "MYSQL_TYPE_TIME";
  case MYSQL_TYPE_DATETIME:
    return "MYSQL_TYPE_DATETIME";
  case MYSQL_TYPE_YEAR:
    return "MYSQL_TYPE_YEAR";
  case MYSQL_TYPE_NEWDATE:
    return "MYSQL_TYPE_NEWDATE";
  case MYSQL_TYPE_VARCHAR:
    return "MYSQL_TYPE_VARCHAR";
  case MYSQL_TYPE_BIT:
    return "MYSQL_TYPE_BIT";
  case MYSQL_TYPE_NEWDECIMAL:
    return "MYSQL_TYPE_NEWDECIMAL";
  case MYSQL_TYPE_ENUM:
    return "MYSQL_TYPE_ENUM";
  case MYSQL_TYPE_SET:
    return "MYSQL_TYPE_SET";
  case MYSQL_TYPE_TINY_BLOB:
    return "MYSQL_TYPE_TINY_BLOB";
  case MYSQL_TYPE_MEDIUM_BLOB:
    return "MYSQL_TYPE_MEDIUM_BLOB";
  case MYSQL_TYPE_LONG_BLOB:
    return "MYSQL_TYPE_LONG_BLOB";
  case MYSQL_TYPE_BLOB:
    return "MYSQL_TYPE_BLOB";
  case MYSQL_TYPE_VAR_STRING:
    return "MYSQL_TYPE_VAR_STRING";
  case MYSQL_TYPE_STRING:
    return "MYSQL_TYPE_STRING";
  case MYSQL_TYPE_GEOMETRY:
    return "MYSQL_TYPE_GEOMETRY";
  }
  return "Unknown";
}
3328
#endif
3329

3330

3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358
namespace {
  /**
     Class to handle temporary allocation of memory for row data.

     The responsibilities of the class is to provide memory for
     packing one or two rows of packed data (depending on what
     constructor is called).

     In order to make the allocation more efficient for "simple" rows,
     i.e., rows that do not contain any blobs, a pointer to the
     allocated memory is of memory is stored in the table structure
     for simple rows.  If memory for a table containing a blob field
     is requested, only memory for that is allocated, and subsequently
     released when the object is destroyed.

   */
  class Row_data_memory {
  public:
    /**
      Build an object to keep track of a block-local piece of memory
      for storing a row of data.

      @param table
      Table where the pre-allocated memory is stored.

      @param length
      Length of data that is needed, if the record contain blobs.
     */
3359
    Row_data_memory(TABLE *table, size_t const len1)
3360 3361 3362
      : m_memory(0)
    {
#ifndef DBUG_OFF
3363
      m_alloc_checked= FALSE;
3364 3365 3366 3367 3368 3369
#endif
      allocate_memory(table, len1);
      m_ptr[0]= has_memory() ? m_memory : 0;
      m_ptr[1]= 0;
    }

3370
    Row_data_memory(TABLE *table, size_t const len1, size_t const len2)
3371 3372 3373
      : m_memory(0)
    {
#ifndef DBUG_OFF
3374
      m_alloc_checked= FALSE;
3375 3376 3377 3378 3379 3380 3381 3382 3383
#endif
      allocate_memory(table, len1 + len2);
      m_ptr[0]= has_memory() ? m_memory        : 0;
      m_ptr[1]= has_memory() ? m_memory + len1 : 0;
    }

    ~Row_data_memory()
    {
      if (m_memory != 0 && m_release_memory_on_destruction)
3384
        my_free((uchar*) m_memory, MYF(MY_WME));
3385 3386 3387 3388 3389 3390 3391 3392 3393 3394
    }

    /**
       Is there memory allocated?

       @retval true There is memory allocated
       @retval false Memory allocation failed
     */
    bool has_memory() const {
#ifndef DBUG_OFF
3395
      m_alloc_checked= TRUE;
3396 3397 3398 3399
#endif
      return m_memory != 0;
    }

3400
    uchar *slot(uint s)
3401
    {
3402
      DBUG_ASSERT(s < sizeof(m_ptr)/sizeof(*m_ptr));
3403
      DBUG_ASSERT(m_ptr[s] != 0);
3404
      DBUG_ASSERT(m_alloc_checked == TRUE);
3405 3406 3407 3408
      return m_ptr[s];
    }

  private:
3409
    void allocate_memory(TABLE *const table, size_t const total_length)
3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422
    {
      if (table->s->blob_fields == 0)
      {
        /*
          The maximum length of a packed record is less than this
          length. We use this value instead of the supplied length
          when allocating memory for records, since we don't know how
          the memory will be used in future allocations.

          Since table->s->reclength is for unpacked records, we have
          to add two bytes for each field, which can potentially be
          added to hold the length of a packed field.
        */
3423
        size_t const maxlen= table->s->reclength + 2 * table->s->fields;
3424 3425 3426 3427 3428 3429 3430 3431

        /*
          Allocate memory for two records if memory hasn't been
          allocated. We allocate memory for two records so that it can
          be used when processing update rows as well.
        */
        if (table->write_row_record == 0)
          table->write_row_record=
3432
            (uchar *) alloc_root(&table->mem_root, 2 * maxlen);
3433
        m_memory= table->write_row_record;
3434
        m_release_memory_on_destruction= FALSE;
3435 3436 3437
      }
      else
      {
3438
        m_memory= (uchar *) my_malloc(total_length, MYF(MY_WME));
3439
        m_release_memory_on_destruction= TRUE;
3440 3441 3442 3443 3444 3445 3446
      }
    }

#ifndef DBUG_OFF
    mutable bool m_alloc_checked;
#endif
    bool m_release_memory_on_destruction;
3447 3448
    uchar *m_memory;
    uchar *m_ptr[2];
3449 3450 3451 3452
  };
}


3453
int THD::binlog_write_row(TABLE* table, bool is_trans, 
3454 3455
                          MY_BITMAP const* cols, size_t colcnt, 
                          uchar const *record) 
3456
{ 
3457
  DBUG_ASSERT(current_stmt_binlog_row_based && mysql_bin_log.is_open());
3458

3459 3460 3461
  /*
    Pack records into format for transfer. We are allocating more
    memory than needed, but that doesn't matter.
3462
  */
3463 3464 3465
  Row_data_memory memory(table, max_row_length(table, record));
  if (!memory.has_memory())
    return HA_ERR_OUT_OF_MEM;
3466

3467
  uchar *row_data= memory.slot(0);
3468

3469
  size_t const len= pack_row(table, cols, row_data, record);
3470

3471 3472 3473 3474 3475 3476 3477 3478 3479
  Rows_log_event* const ev=
    binlog_prepare_pending_rows_event(table, server_id, cols, colcnt,
                                      len, is_trans,
                                      static_cast<Write_rows_log_event*>(0));

  if (unlikely(ev == 0))
    return HA_ERR_OUT_OF_MEM;

  return ev->add_row_data(row_data, len);
3480 3481 3482
}

int THD::binlog_update_row(TABLE* table, bool is_trans,
3483 3484 3485
                           MY_BITMAP const* cols, size_t colcnt,
                           const uchar *before_record,
                           const uchar *after_record)
3486
{ 
3487
  DBUG_ASSERT(current_stmt_binlog_row_based && mysql_bin_log.is_open());
3488

3489 3490
  size_t const before_maxlen = max_row_length(table, before_record);
  size_t const after_maxlen  = max_row_length(table, after_record);
3491

3492 3493 3494 3495
  Row_data_memory row_data(table, before_maxlen, after_maxlen);
  if (!row_data.has_memory())
    return HA_ERR_OUT_OF_MEM;

3496 3497
  uchar *before_row= row_data.slot(0);
  uchar *after_row= row_data.slot(1);
3498

3499
  size_t const before_size= pack_row(table, cols, before_row,
3500
                                        before_record);
3501
  size_t const after_size= pack_row(table, cols, after_row,
3502
                                       after_record);
3503 3504 3505 3506 3507 3508

  /*
    Don't print debug messages when running valgrind since they can
    trigger false warnings.
   */
#ifndef HAVE_purify
3509 3510 3511 3512
  DBUG_DUMP("before_record", before_record, table->s->reclength);
  DBUG_DUMP("after_record",  after_record, table->s->reclength);
  DBUG_DUMP("before_row",    before_row, before_size);
  DBUG_DUMP("after_row",     after_row, after_size);
3513
#endif
3514

3515 3516 3517 3518
  Rows_log_event* const ev=
    binlog_prepare_pending_rows_event(table, server_id, cols, colcnt,
				      before_size + after_size, is_trans,
				      static_cast<Update_rows_log_event*>(0));
3519

3520 3521 3522 3523
  if (unlikely(ev == 0))
    return HA_ERR_OUT_OF_MEM;

  return
3524
    ev->add_row_data(before_row, before_size) ||
3525 3526 3527 3528
    ev->add_row_data(after_row, after_size);
}

int THD::binlog_delete_row(TABLE* table, bool is_trans, 
3529 3530
                           MY_BITMAP const* cols, size_t colcnt,
                           uchar const *record)
3531
{ 
3532
  DBUG_ASSERT(current_stmt_binlog_row_based && mysql_bin_log.is_open());
3533 3534 3535 3536 3537

  /* 
     Pack records into format for transfer. We are allocating more
     memory than needed, but that doesn't matter.
  */
3538 3539
  Row_data_memory memory(table, max_row_length(table, record));
  if (unlikely(!memory.has_memory()))
3540
    return HA_ERR_OUT_OF_MEM;
3541

3542
  uchar *row_data= memory.slot(0);
3543

3544
  size_t const len= pack_row(table, cols, row_data, record);
3545

3546 3547 3548 3549
  Rows_log_event* const ev=
    binlog_prepare_pending_rows_event(table, server_id, cols, colcnt,
				      len, is_trans,
				      static_cast<Delete_rows_log_event*>(0));
3550

3551 3552
  if (unlikely(ev == 0))
    return HA_ERR_OUT_OF_MEM;
3553

3554
  return ev->add_row_data(row_data, len);
3555 3556 3557
}


3558 3559
int THD::binlog_remove_pending_rows_event(bool clear_maps)
{
3560
  DBUG_ENTER("THD::binlog_remove_pending_rows_event");
3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572

  if (!mysql_bin_log.is_open())
    DBUG_RETURN(0);

  mysql_bin_log.remove_pending_rows_event(this);

  if (clear_maps)
    binlog_table_maps= 0;

  DBUG_RETURN(0);
}

3573 3574 3575
int THD::binlog_flush_pending_rows_event(bool stmt_end)
{
  DBUG_ENTER("THD::binlog_flush_pending_rows_event");
3576 3577 3578 3579 3580 3581
  /*
    We shall flush the pending event even if we are not in row-based
    mode: it might be the case that we left row-based mode before
    flushing anything (e.g., if we have explicitly locked tables).
   */
  if (!mysql_bin_log.is_open())
3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594
    DBUG_RETURN(0);

  /*
    Mark the event as the last event of a statement if the stmt_end
    flag is set.
  */
  int error= 0;
  if (Rows_log_event *pending= binlog_get_pending_rows_event())
  {
    if (stmt_end)
    {
      pending->set_flags(Rows_log_event::STMT_END_F);
      pending->flags|= LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F;
3595
      binlog_table_maps= 0;
3596 3597
    }

3598 3599
    error= mysql_bin_log.flush_and_set_pending_rows_event(this, 0);
  }
3600 3601 3602 3603 3604

  DBUG_RETURN(error);
}


3605
#if !defined(DBUG_OFF) && !defined(_lint)
3606 3607 3608 3609 3610 3611 3612 3613 3614 3615
static const char *
show_query_type(THD::enum_binlog_query_type qtype)
{
  switch (qtype) {
  case THD::ROW_QUERY_TYPE:
    return "ROW";
  case THD::STMT_QUERY_TYPE:
    return "STMT";
  case THD::MYSQL_QUERY_TYPE:
    return "MYSQL";
3616
  case THD::QUERY_TYPE_COUNT:
3617
  default:
3618
    DBUG_ASSERT(0 <= qtype && qtype < THD::QUERY_TYPE_COUNT);
3619
  }
3620 3621 3622
  static char buf[64];
  sprintf(buf, "UNKNOWN#%d", qtype);
  return buf;
3623
}
3624
#endif
3625 3626


3627 3628
/*
  Member function that will log query, either row-based or
3629 3630
  statement-based depending on the value of the 'current_stmt_binlog_row_based'
  the value of the 'qtype' flag.
3631 3632 3633 3634 3635

  This function should be called after the all calls to ha_*_row()
  functions have been issued, but before tables are unlocked and
  closed.

3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646
  OBSERVE
    There shall be no writes to any system table after calling
    binlog_query(), so these writes has to be moved to before the call
    of binlog_query() for correct functioning.

    This is necessesary not only for RBR, but the master might crash
    after binlogging the query but before changing the system tables.
    This means that the slave and the master are not in the same state
    (after the master has restarted), so therefore we have to
    eliminate this problem.

3647 3648 3649
  RETURN VALUE
    Error code, or 0 if no error.
*/
3650
int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg,
3651 3652
                      ulong query_len, bool is_trans, bool suppress_use,
                      THD::killed_state killed_status_arg)
3653 3654
{
  DBUG_ENTER("THD::binlog_query");
3655 3656
  DBUG_PRINT("enter", ("qtype: %s  query: '%s'",
                       show_query_type(qtype), query_arg));
3657
  DBUG_ASSERT(query_arg && mysql_bin_log.is_open());
3658

3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671
  /*
    If we are not in prelocked mode, mysql_unlock_tables() will be
    called after this binlog_query(), so we have to flush the pending
    rows event with the STMT_END_F set to unlock all tables at the
    slave side as well.

    If we are in prelocked mode, the flushing will be done inside the
    top-most close_thread_tables().
  */
  if (this->prelocked_mode == NON_PRELOCKED)
    if (int error= binlog_flush_pending_rows_event(TRUE))
      DBUG_RETURN(error);

3672 3673 3674 3675
  /*
    If we are in statement mode and trying to log an unsafe statement,
    we should print a warning.
  */
3676
  if (sql_log_bin_toplevel && lex->is_stmt_unsafe() &&
3677 3678 3679 3680 3681 3682 3683
      variables.binlog_format == BINLOG_FORMAT_STMT)
  {
    push_warning(this, MYSQL_ERROR::WARN_LEVEL_WARN,
                 ER_BINLOG_UNSAFE_STATEMENT,
                 ER(ER_BINLOG_UNSAFE_STATEMENT));
    if (!(binlog_flags & BINLOG_FLAG_UNSAFE_STMT_PRINTED))
    {
3684 3685 3686
      sql_print_warning("%s Statement: %.*s",
                        ER(ER_BINLOG_UNSAFE_STATEMENT),
                        MYSQL_ERRMSG_SIZE, query_arg);
3687 3688 3689 3690
      binlog_flags|= BINLOG_FLAG_UNSAFE_STMT_PRINTED;
    }
  }

3691
  switch (qtype) {
3692
  case THD::ROW_QUERY_TYPE:
3693 3694 3695
    DBUG_PRINT("debug",
               ("current_stmt_binlog_row_based: %d",
                current_stmt_binlog_row_based));
3696 3697 3698
    if (current_stmt_binlog_row_based)
      DBUG_RETURN(0);
    /* Otherwise, we fall through */
3699 3700 3701 3702 3703 3704
  case THD::MYSQL_QUERY_TYPE:
    /*
      Using this query type is a conveniece hack, since we have been
      moving back and forth between using RBR for replication of
      system tables and not using it.

3705
      Make sure to change in check_table_binlog_row_based() according
3706 3707 3708 3709
      to how you treat this.
    */
  case THD::STMT_QUERY_TYPE:
    /*
3710 3711
      The MYSQL_LOG::write() function will set the STMT_END_F flag and
      flush the pending rows event if necessary.
3712 3713
     */
    {
3714
      Query_log_event qinfo(this, query_arg, query_len, is_trans, suppress_use,
3715
                            killed_status_arg);
3716
      qinfo.flags|= LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F;
3717 3718 3719 3720 3721 3722 3723 3724 3725
      /*
        Binlog table maps will be irrelevant after a Query_log_event
        (they are just removed on the slave side) so after the query
        log event is written to the binary log, we pretend that no
        table maps were written.
       */
      int error= mysql_bin_log.write(&qinfo);
      binlog_table_maps= 0;
      DBUG_RETURN(error);
3726 3727 3728 3729 3730 3731 3732 3733 3734 3735
    }
    break;

  case THD::QUERY_TYPE_COUNT:
  default:
    DBUG_ASSERT(0 <= qtype && qtype < QUERY_TYPE_COUNT);
  }
  DBUG_RETURN(0);
}

3736 3737 3738 3739 3740 3741 3742 3743 3744
bool Discrete_intervals_list::append(ulonglong start, ulonglong val,
                                 ulonglong incr)
{
  DBUG_ENTER("Discrete_intervals_list::append");
  /* first, see if this can be merged with previous */
  if ((head == NULL) || tail->merge_if_contiguous(start, val, incr))
  {
    /* it cannot, so need to add a new interval */
    Discrete_interval *new_interval= new Discrete_interval(start, val, incr);
3745
    DBUG_RETURN(append(new_interval));
3746 3747 3748 3749
  }
  DBUG_RETURN(0);
}

3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764
bool Discrete_intervals_list::append(Discrete_interval *new_interval)
{
  DBUG_ENTER("Discrete_intervals_list::append");
  if (unlikely(new_interval == NULL))
    DBUG_RETURN(1);
  DBUG_PRINT("info",("adding new auto_increment interval"));
  if (head == NULL)
    head= current= new_interval;
  else
    tail->next= new_interval;
  tail= new_interval;
  elements++;
  DBUG_RETURN(0);
}

3765
#endif /* !defined(MYSQL_CLIENT) */