sql_class.cc 45.4 KB
Newer Older
unknown's avatar
unknown committed
1
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
unknown's avatar
unknown committed
2

unknown's avatar
unknown committed
3 4 5 6
   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
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
unknown's avatar
unknown committed
7

unknown's avatar
unknown committed
8 9 10 11
   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.
unknown's avatar
unknown committed
12

unknown's avatar
unknown committed
13 14 15 16 17 18 19 20 21 22 23 24
   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
**
*****************************************************************************/

25
#ifdef USE_PRAGMA_IMPLEMENTATION
unknown's avatar
unknown committed
26 27 28 29 30 31
#pragma implementation				// gcc: Class implementation
#endif

#include "mysql_priv.h"
#include <m_ctype.h>
#include <sys/stat.h>
32
#include <thr_alarm.h>
unknown's avatar
unknown committed
33 34 35
#ifdef	__WIN__
#include <io.h>
#endif
36
#include <mysys_err.h>
unknown's avatar
unknown committed
37

unknown's avatar
unknown committed
38 39
#include "sp_rcontext.h"
#include "sp_cache.h"
40

41 42 43 44 45 46
/*
  The following is used to initialise Table_ident with a internal
  table name
*/
char internal_table_name[2]= "*";

47

unknown's avatar
unknown committed
48 49 50 51
/*****************************************************************************
** Instansiate templates
*****************************************************************************/

52
#ifdef EXPLICIT_TEMPLATE_INSTANTIATION
unknown's avatar
unknown committed
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
/* Used templates */
template class List<Key>;
template class List_iterator<Key>;
template class List<key_part_spec>;
template class List_iterator<key_part_spec>;
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
****************************************************************************/

68 69
extern "C" byte *get_var_key(user_var_entry *entry, uint *length,
			     my_bool not_used __attribute__((unused)))
unknown's avatar
unknown committed
70 71 72 73 74
{
  *length=(uint) entry->name.length;
  return (byte*) entry->name.str;
}

75
extern "C" void free_user_var(user_var_entry *entry)
unknown's avatar
unknown committed
76 77 78 79 80 81 82
{
  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));
}

83 84 85 86 87
bool key_part_spec::operator==(const key_part_spec& other) const
{
  return length == other.length && !strcmp(field_name, other.field_name);
}

88 89

/*
90
  Test if a foreign key (= generated key) is a prefix of the given key
91 92 93 94 95 96 97 98 99 100 101 102 103 104
  (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)
105
{
106 107 108 109
  /* Ensure that 'a' is the generated key */
  if (a->generated)
  {
    if (b->generated && a->columns.elements > b->columns.elements)
110
      swap_variables(Key*, a, b);               // Put shorter key in 'a'
111 112
  }
  else
113
  {
114 115
    if (!b->generated)
      return TRUE;                              // No foreign key
116
    swap_variables(Key*, a, b);                 // Put generated key in 'a'
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
  }

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

  List_iterator<key_part_spec> col_it1(a->columns);
  List_iterator<key_part_spec> col_it2(b->columns);
  const key_part_spec *col1, *col2;

#ifdef ENABLE_WHEN_INNODB_CAN_HANDLE_SWAPED_FOREIGN_KEY_COLUMNS
  while ((col1= col_it1++))
  {
    bool found= 0;
    col_it2.rewind();
    while ((col2= col_it2++))
133
    {
134 135 136 137 138
      if (*col1 == *col2)
      {
        found= TRUE;
	break;
      }
139
    }
140 141 142 143 144 145 146 147 148 149
    if (!found)
      return TRUE;                              // Error
  }
  return FALSE;                                 // Is prefix
#else
  while ((col1= col_it1++))
  {
    col2= col_it2++;
    if (!(*col1 == *col2))
      return TRUE;
150
  }
151 152
  return FALSE;                                 // Is prefix
#endif
153 154 155
}


unknown's avatar
unknown committed
156 157 158 159
/****************************************************************************
** Thread specific functions
****************************************************************************/

160 161
THD::THD()
  :user_time(0), global_read_lock(0), is_fatal_error(0),
162 163
   rand_used(0), time_zone_used(0),
   last_insert_id_used(0), insert_id_used(0), clear_next_insert_id(0),
164 165
   in_lock_tables(0), bootstrap(0), derived_tables_processing(FALSE),
   spcont(NULL)
unknown's avatar
unknown committed
166
{
167
  current_arena= this;
unknown's avatar
unknown committed
168 169 170
#ifndef DBUG_OFF
  backup_arena= 0;
#endif
171
  host= user= priv_user= db= ip= 0;
172
  catalog= (char*)"std"; // the only catalog we have for now
173
  host_or_ip= "connecting host";
unknown's avatar
unknown committed
174
  locked=some_tables_deleted=no_errors=password= 0;
unknown's avatar
unknown committed
175
  query_start_used= 0;
176
  count_cuted_fields= CHECK_FIELD_IGNORE;
unknown's avatar
SCRUM  
unknown committed
177
  killed= NOT_KILLED;
178
  db_length= col_access=0;
unknown's avatar
unknown committed
179
  query_error= tmp_table_used= 0;
unknown's avatar
unknown committed
180
  next_insert_id=last_insert_id=0;
181
  open_tables= temporary_tables= handler_tables= derived_tables= 0;
182
  hash_clear(&handler_tables_hash);
unknown's avatar
unknown committed
183 184
  tmp_table=0;
  lock=locked_tables=0;
185
  used_tables=0;
186
  cuted_fields= sent_row_count= 0L;
187
  limit_found_rows= 0;
188
  statement_id_counter= 0UL;
189
  // Must be reset to handle error with THD's created for init of mysqld
unknown's avatar
unknown committed
190
  lex->current_select= 0;
unknown's avatar
unknown committed
191
  start_time=(time_t) 0;
unknown's avatar
unknown committed
192
  current_linfo =  0;
193
  slave_thread = 0;
unknown's avatar
unknown committed
194
  variables.pseudo_thread_id= 0;
195
  one_shot_set= 0;
196
  file_id = 0;
197
  query_id= 0;
198
  warn_id= 0;
199
  db_charset= global_system_variables.collation_database;
200
  bzero(ha_data, sizeof(ha_data));
unknown's avatar
unknown committed
201
  mysys_var=0;
202 203
#ifndef DBUG_OFF
  dbug_sentry=THD_SENTRY_MAGIC;
204
#endif
205
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
206
  net.vio=0;
207
#endif
208 209
  net.last_error[0]=0;                          // If error on boot
  net.query_cache_query=0;                      // If error on boot
unknown's avatar
unknown committed
210
  ull=0;
211
  system_thread= cleanup_done= abort_on_warning= no_warnings_for_error= 0;
212
  peer_port= 0;					// For SHOW PROCESSLIST
unknown's avatar
unknown committed
213 214 215 216 217
#ifdef	__WIN__
  real_id = 0;
#endif
#ifdef SIGNAL_WITH_VIO_CLOSE
  active_vio = 0;
218
#endif
219
  pthread_mutex_init(&LOCK_delete, MY_MUTEX_INIT_FAST);
unknown's avatar
unknown committed
220 221 222 223 224

  /* Variables with default values */
  proc_info="login";
  where="field list";
  server_id = ::server_id;
225
  slave_net = 0;
unknown's avatar
unknown committed
226
  command=COM_CONNECT;
unknown's avatar
unknown committed
227
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
228
  db_access=NO_ACCESS;
unknown's avatar
unknown committed
229
#endif
230
  version=refresh_version;			// For boot
unknown's avatar
unknown committed
231
  *scramble= '\0';
unknown's avatar
unknown committed
232

unknown's avatar
unknown committed
233
  init();
unknown's avatar
unknown committed
234
  /* Initialize sub structures */
235
  init_sql_alloc(&warn_root, WARN_ALLOC_BLOCK_SIZE, WARN_ALLOC_PREALLOC_SIZE);
236
  user_connect=(USER_CONN *)0;
237
  hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0,
unknown's avatar
unknown committed
238
	    (hash_get_key) get_var_key,
239
	    (hash_free_key) free_user_var, 0);
240

241 242
  sp_proc_cache= NULL;
  sp_func_cache= NULL;
243

unknown's avatar
unknown committed
244 245 246
  /* For user vars replication*/
  if (opt_bin_log)
    my_init_dynamic_array(&user_var_events,
247
			  sizeof(BINLOG_USER_VAR_EVENT *), 16, 16);
unknown's avatar
unknown committed
248 249 250
  else
    bzero((char*) &user_var_events, sizeof(user_var_events));

251 252 253 254 255
  /* Protocol */
  protocol= &protocol_simple;			// Default protocol
  protocol_simple.init(this);
  protocol_prep.init(this);

unknown's avatar
unknown committed
256
  tablespace_op=FALSE;
257 258
  ulong tmp=sql_rnd_with_mutex();
  randominit(&rand, tmp + (ulong) &rand, tmp + (ulong) ::query_id);
259
  prelocked_mode= NON_PRELOCKED;
unknown's avatar
unknown committed
260 261
}

unknown's avatar
unknown committed
262 263 264 265 266 267 268

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

void THD::init(void)
{
269 270
  pthread_mutex_lock(&LOCK_global_system_variables);
  variables= global_system_variables;
271 272 273 274 275 276
  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);
277 278 279
#ifdef HAVE_NDBCLUSTER_DB
  variables.ndb_use_transactions= 1;
#endif
280
  pthread_mutex_unlock(&LOCK_global_system_variables);
unknown's avatar
unknown committed
281 282 283
  server_status= SERVER_STATUS_AUTOCOMMIT;
  options= thd_startup_options;
  open_options=ha_open_options;
284 285 286
  update_lock_default= (variables.low_priority_updates ?
			TL_WRITE_LOW_PRIORITY :
			TL_WRITE);
unknown's avatar
unknown committed
287
  session_tx_isolation= (enum_tx_isolation) variables.tx_isolation;
288 289 290
  warn_list.empty();
  bzero((char*) warn_count, sizeof(warn_count));
  total_warn_count= 0;
291
  update_charset();
292
  bzero((char *) &status_var, sizeof(status_var));
unknown's avatar
unknown committed
293 294
}

295

296 297 298 299 300 301 302 303
/*
  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()
{
304
  ha_enable_transaction(this,TRUE);
305

unknown's avatar
unknown committed
306
  reset_root_defaults(mem_root, variables.query_alloc_block_size,
307
                      variables.query_prealloc_size);
308
#ifdef USING_TRANSACTIONS
309 310 311
  reset_root_defaults(&transaction.mem_root,
                      variables.trans_alloc_block_size,
                      variables.trans_prealloc_size);
312 313
#endif
  transaction.xid.null();
314 315 316
}


unknown's avatar
unknown committed
317 318 319 320 321 322 323 324 325 326 327 328 329 330
/*
  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)
{
  cleanup();
unknown's avatar
unknown committed
331
  cleanup_done= 0;
unknown's avatar
unknown committed
332
  init();
333
  stmt_map.reset();
334
  hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0,
unknown's avatar
unknown committed
335
	    (hash_get_key) get_var_key,
unknown's avatar
unknown committed
336
	    (hash_free_key) free_user_var, 0);
337 338
  sp_cache_clear(&sp_proc_cache);
  sp_cache_clear(&sp_func_cache);
unknown's avatar
unknown committed
339 340 341
}


unknown's avatar
unknown committed
342 343 344
/* Do operations that may take a long time */

void THD::cleanup(void)
unknown's avatar
unknown committed
345
{
unknown's avatar
unknown committed
346
  DBUG_ENTER("THD::cleanup");
unknown's avatar
unknown committed
347 348 349
#ifdef ENABLE_WHEN_BINLOG_WILL_BE_ABLE_TO_PREPARE
  if (transaction.xa_state != XA_PREPARED)
#endif
unknown's avatar
unknown committed
350
    ha_rollback(this);
unknown's avatar
unknown committed
351 352 353 354 355
  if (locked_tables)
  {
    lock=locked_tables; locked_tables=0;
    close_thread_tables(this);
  }
356 357 358
  mysql_ha_flush(this, (TABLE_LIST*) 0,
                 MYSQL_HA_CLOSE_FINAL | MYSQL_HA_FLUSH_ALL);
  hash_free(&handler_tables_hash);
unknown's avatar
unknown committed
359
  close_temporary_tables(this);
360 361 362
  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));
unknown's avatar
unknown committed
363
  delete_dynamic(&user_var_events);
unknown's avatar
unknown committed
364
  hash_free(&user_vars);
365 366
  sp_cache_clear(&sp_proc_cache);
  sp_cache_clear(&sp_func_cache);
unknown's avatar
unknown committed
367 368 369
  if (global_read_lock)
    unlock_global_read_lock(this);
  if (ull)
370
  {
unknown's avatar
unknown committed
371 372 373 374
    pthread_mutex_lock(&LOCK_user_locks);
    item_user_lock_release(ull);
    pthread_mutex_unlock(&LOCK_user_locks);
    ull= 0;
375
  }
376

unknown's avatar
unknown committed
377 378 379 380
  cleanup_done=1;
  DBUG_VOID_RETURN;
}

unknown's avatar
unknown committed
381

unknown's avatar
unknown committed
382 383
THD::~THD()
{
384
  THD_CHECK_SENTRY(this);
unknown's avatar
unknown committed
385
  DBUG_ENTER("~THD()");
386 387 388
  /* Ensure that no one is using THD */
  pthread_mutex_lock(&LOCK_delete);
  pthread_mutex_unlock(&LOCK_delete);
389
  add_to_status(&global_status_var, &status_var);
390

unknown's avatar
unknown committed
391
  /* Close connection */
unknown's avatar
unknown committed
392
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
393 394 395
  if (net.vio)
  {
    vio_delete(net.vio);
unknown's avatar
unknown committed
396
    net_end(&net);
unknown's avatar
unknown committed
397
  }
398
#endif
unknown's avatar
unknown committed
399 400
  if (!cleanup_done)
    cleanup();
401

unknown's avatar
unknown committed
402
  ha_close_connection(this);
unknown's avatar
unknown committed
403

404 405
  sp_cache_clear(&sp_proc_cache);
  sp_cache_clear(&sp_func_cache);
406

unknown's avatar
unknown committed
407
  DBUG_PRINT("info", ("freeing host"));
unknown's avatar
unknown committed
408
  if (host != my_localhost)			// If not pointer to constant
409
    safeFree(host);
410 411
  if (user != delayed_user)
    safeFree(user);
unknown's avatar
unknown committed
412
  safeFree(ip);
413
  safeFree(db);
414
  free_root(&warn_root,MYF(0));
415
#ifdef USING_TRANSACTIONS
416
  free_root(&transaction.mem_root,MYF(0));
417
#endif
unknown's avatar
unknown committed
418
  mysys_var=0;					// Safety (shouldn't be needed)
419
  pthread_mutex_destroy(&LOCK_delete);
420
#ifndef DBUG_OFF
unknown's avatar
unknown committed
421
  dbug_sentry= THD_SENTRY_GONE;
422
#endif  
unknown's avatar
unknown committed
423 424 425
  DBUG_VOID_RETURN;
}

426

427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444
/*
  Add to one status variable another status variable

  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)
{
  ulong *end= (ulong*) ((byte*) to_var + offsetof(STATUS_VAR,
						  last_system_status_var) +
			sizeof(ulong));
  ulong *to= (ulong*) to_var, *from= (ulong*) from_var;

  while (to != end)
    *(to++)+= *(from++);
445
  /* it doesn't make sense to add last_query_cost values */
446 447 448
}


unknown's avatar
SCRUM  
unknown committed
449
void THD::awake(THD::killed_state state_to_set)
450
{
451
  THD_CHECK_SENTRY(this);
452 453
  safe_mutex_assert_owner(&LOCK_delete); 

unknown's avatar
SCRUM  
unknown committed
454 455 456
  killed= state_to_set;
  if (state_to_set != THD::KILL_QUERY)
    thr_alarm_kill(real_id);
457 458 459 460
#ifdef SIGNAL_WITH_VIO_CLOSE
  close_active_vio();
#endif    
  if (mysys_var)
unknown's avatar
unknown committed
461 462 463 464 465 466 467 468 469
  {
    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.
470 471 472 473 474
      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.
475

476
      Note that there is a small chance we fail to kill. If victim has locked
477 478 479 480 481
      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
482
      see it immediately and so may have time to reach the cond_wait().
unknown's avatar
unknown committed
483
    */
484
    if (mysys_var->current_cond && mysys_var->current_mutex)
485
    {
unknown's avatar
unknown committed
486 487 488
      pthread_mutex_lock(mysys_var->current_mutex);
      pthread_cond_broadcast(mysys_var->current_cond);
      pthread_mutex_unlock(mysys_var->current_mutex);
489
    }
unknown's avatar
unknown committed
490 491
    pthread_mutex_unlock(&mysys_var->mutex);
  }
492 493
}

unknown's avatar
unknown committed
494 495 496 497
/*
  Remember the location of thread info, the structure needed for
  sql_alloc() and the structure for the net buffer
*/
unknown's avatar
unknown committed
498 499 500

bool THD::store_globals()
{
501
  if (my_pthread_setspecific_ptr(THR_THD,  this) ||
unknown's avatar
unknown committed
502
      my_pthread_setspecific_ptr(THR_MALLOC, &mem_root))
503 504 505
    return 1;
  mysys_var=my_thread_var;
  dbug_thread_id=my_thread_id();
unknown's avatar
unknown committed
506 507 508 509
  /*
    By default 'slave_proxy_id' is 'thread_id'. They may later become different
    if this is the slave SQL thread.
  */
510
  variables.pseudo_thread_id= thread_id;
511
  return 0;
unknown's avatar
unknown committed
512 513
}

unknown's avatar
unknown committed
514

515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532
/* Cleanup after a query */

void THD::cleanup_after_query()
{
  if (clear_next_insert_id)
  {
    clear_next_insert_id= 0;
    next_insert_id= 0;
  }
  /* Free Items that were created during this execution */
  free_items(free_list);
  /*
    In the rest of code we assume that free_list never points to garbage:
    Keep this predicate true.
  */
  free_list= 0;
}

unknown's avatar
unknown committed
533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558
/*
  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");
  size_s new_length= to_cs->mbmaxlen * from_length;
559
  uint dummy_errors;
unknown's avatar
unknown committed
560 561 562 563 564 565
  if (!(to->str= alloc(new_length+1)))
  {
    to->length= 0;				// Safety fix
    DBUG_RETURN(1);				// EOM
  }
  to->length= copy_and_convert((char*) to->str, new_length, to_cs,
566
			       from, from_length, from_cs, &dummy_errors);
unknown's avatar
unknown committed
567 568 569 570 571
  to->str[to->length]=0;			// Safety
  DBUG_RETURN(0);
}


572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588
/*
  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)
{
589 590
  uint dummy_errors;
  if (convert_buffer.copy(s->ptr(), s->length(), from_cs, to_cs, &dummy_errors))
591 592 593 594 595 596 597 598 599 600 601
    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;
}

602

unknown's avatar
unknown committed
603 604 605 606 607 608
/*
  Update some cache variables when character set changes
*/

void THD::update_charset()
{
609 610 611 612 613 614 615
  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);
unknown's avatar
unknown committed
616 617 618
}


619 620 621 622 623 624 625 626 627 628 629 630 631 632
/* 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 */
633

634 635
void THD::add_changed_table(TABLE *table)
{
636
  DBUG_ENTER("THD::add_changed_table(table)");
637

unknown's avatar
unknown committed
638
  DBUG_ASSERT((options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) &&
639
	      table->file->has_transactions());
640
  add_changed_table(table->s->table_cache_key, table->s->key_length);
unknown's avatar
unknown committed
641
  DBUG_VOID_RETURN;
unknown's avatar
unknown committed
642
}
643

644

unknown's avatar
unknown committed
645 646 647
void THD::add_changed_table(const char *key, long key_length)
{
  DBUG_ENTER("THD::add_changed_table(key)");
648 649
  CHANGED_TABLE_LIST **prev_changed = &transaction.changed_tables;
  CHANGED_TABLE_LIST *curr = transaction.changed_tables;
650

651
  for (; curr; prev_changed = &(curr->next), curr = curr->next)
652
  {
unknown's avatar
unknown committed
653
    int cmp =  (long)curr->key_length - (long)key_length;
654 655
    if (cmp < 0)
    {
656
      list_include(prev_changed, curr, changed_table_dup(key, key_length));
657
      DBUG_PRINT("info", 
658
		 ("key_length %u %u", key_length, (*prev_changed)->key_length));
659 660 661 662
      DBUG_VOID_RETURN;
    }
    else if (cmp == 0)
    {
unknown's avatar
unknown committed
663
      cmp = memcmp(curr->key, key, curr->key_length);
664 665
      if (cmp < 0)
      {
666
	list_include(prev_changed, curr, changed_table_dup(key, key_length));
667
	DBUG_PRINT("info", 
unknown's avatar
unknown committed
668
		   ("key_length %u %u", key_length,
669
		    (*prev_changed)->key_length));
670 671 672 673 674 675 676 677 678
	DBUG_VOID_RETURN;
      }
      else if (cmp == 0)
      {
	DBUG_PRINT("info", ("already in list"));
	DBUG_VOID_RETURN;
      }
    }
  }
679
  *prev_changed = changed_table_dup(key, key_length);
unknown's avatar
unknown committed
680
  DBUG_PRINT("info", ("key_length %u %u", key_length,
681
		      (*prev_changed)->key_length));
682 683 684
  DBUG_VOID_RETURN;
}

685

unknown's avatar
unknown committed
686
CHANGED_TABLE_LIST* THD::changed_table_dup(const char *key, long key_length)
687 688 689
{
  CHANGED_TABLE_LIST* new_table = 
    (CHANGED_TABLE_LIST*) trans_alloc(ALIGN_SIZE(sizeof(CHANGED_TABLE_LIST))+
unknown's avatar
unknown committed
690
				      key_length + 1);
691 692
  if (!new_table)
  {
693 694
    my_error(EE_OUTOFMEMORY, MYF(ME_BELL),
             ALIGN_SIZE(sizeof(TABLE_LIST)) + key_length + 1);
unknown's avatar
SCRUM  
unknown committed
695
    killed= KILL_CONNECTION;
696 697 698 699 700 701
    return 0;
  }

  new_table->key = (char *) (((byte*)new_table)+
			     ALIGN_SIZE(sizeof(CHANGED_TABLE_LIST)));
  new_table->next = 0;
unknown's avatar
unknown committed
702 703
  new_table->key_length = key_length;
  ::memcpy(new_table->key, key, key_length);
704 705 706
  return new_table;
}

707

unknown's avatar
unknown committed
708 709 710 711
int THD::send_explain_fields(select_result *result)
{
  List<Item> field_list;
  Item *item;
712
  CHARSET_INFO *cs= system_charset_info;
713
  field_list.push_back(new Item_return_int("id",3, MYSQL_TYPE_LONGLONG));
714
  field_list.push_back(new Item_empty_string("select_type", 19, cs));
unknown's avatar
unknown committed
715 716 717 718
  field_list.push_back(item= new Item_empty_string("table", NAME_LEN, cs));
  item->maybe_null= 1;
  field_list.push_back(item= new Item_empty_string("type", 10, cs));
  item->maybe_null= 1;
unknown's avatar
unknown committed
719
  field_list.push_back(item=new Item_empty_string("possible_keys",
720
						  NAME_LEN*MAX_KEY, cs));
unknown's avatar
unknown committed
721
  item->maybe_null=1;
722
  field_list.push_back(item=new Item_empty_string("key", NAME_LEN, cs));
unknown's avatar
unknown committed
723
  item->maybe_null=1;
unknown's avatar
unknown committed
724 725
  field_list.push_back(item=new Item_empty_string("key_len",
						  NAME_LEN*MAX_KEY));
unknown's avatar
unknown committed
726 727
  item->maybe_null=1;
  field_list.push_back(item=new Item_empty_string("ref",
728
						  NAME_LEN*MAX_REF_PARTS, cs));
unknown's avatar
unknown committed
729
  item->maybe_null=1;
unknown's avatar
unknown committed
730 731 732
  field_list.push_back(item= new Item_return_int("rows", 10,
                                                 MYSQL_TYPE_LONGLONG));
  item->maybe_null= 1;
733
  field_list.push_back(new Item_empty_string("Extra", 255, cs));
734 735
  return (result->send_fields(field_list,
                              Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF));
unknown's avatar
unknown committed
736
}
737

unknown's avatar
unknown committed
738 739 740
#ifdef SIGNAL_WITH_VIO_CLOSE
void THD::close_active_vio()
{
unknown's avatar
unknown committed
741
  DBUG_ENTER("close_active_vio");
unknown's avatar
unknown committed
742
  safe_mutex_assert_owner(&LOCK_delete); 
unknown's avatar
unknown committed
743
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
744 745 746 747 748
  if (active_vio)
  {
    vio_close(active_vio);
    active_vio = 0;
  }
unknown's avatar
unknown committed
749
#endif
750
  DBUG_VOID_RETURN;
unknown's avatar
unknown committed
751 752 753
}
#endif

754

755 756 757 758 759
struct Item_change_record: public ilink
{
  Item **place;
  Item *old_value;
  /* Placement new was hidden by `new' in ilink (TODO: check): */
760
  static void *operator new(size_t size, void *mem) { return mem; }
761 762
  static void operator delete(void *ptr, size_t size) {}
  static void operator delete(void *ptr, void *mem) { /* never called */ }
763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789
};


/*
  Register an item tree tree transformation, performed by the query
  optimizer. We need a pointer to runtime_memroot because it may be !=
  thd->mem_root (due to possible set_n_backup_item_arena called for thd).
*/

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)
  {
    fatal_error();
    return;
  }
  change= new (change_mem) Item_change_record;
  change->place= place;
  change->old_value= old_value;
790
  change_list.append(change);
791 792 793 794 795 796 797
}


void THD::rollback_item_tree_changes()
{
  I_List_iterator<Item_change_record> it(change_list);
  Item_change_record *change;
unknown's avatar
unknown committed
798 799
  DBUG_ENTER("rollback_item_tree_changes");

800 801 802 803
  while ((change= it++))
    *change->place= change->old_value;
  /* We can forget about changes memory: it's allocated in runtime memroot */
  change_list.empty();
unknown's avatar
unknown committed
804
  DBUG_VOID_RETURN;
805 806 807
}


unknown's avatar
unknown committed
808 809 810 811 812 813 814 815 816
/*****************************************************************************
** Functions to provide a interface to select results
*****************************************************************************/

select_result::select_result()
{
  thd=current_thd;
}

817 818
void select_result::send_error(uint errcode,const char *err)
{
unknown's avatar
unknown committed
819
  my_message(errcode, err, MYF(0));
820 821
}

822 823 824 825 826 827

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

828 829 830
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);
unknown's avatar
unknown committed
831 832 833 834 835

sql_exchange::sql_exchange(char *name,bool flag)
  :file_name(name), opt_enclosed(0), dumpfile(flag), skip_lines(0)
{
  field_term= &default_field_term;
unknown's avatar
SCRUM  
unknown committed
836
  enclosed=   line_start= &my_empty_string;
unknown's avatar
unknown committed
837 838 839 840
  line_term=  &default_line_term;
  escaped=    &default_escaped;
}

841
bool select_send::send_fields(List<Item> &list, uint flags)
unknown's avatar
unknown committed
842
{
843
  return thd->protocol->send_fields(&list, flags);
unknown's avatar
unknown committed
844 845 846 847 848 849
}

/* Send data to client. Returns 0 if ok */

bool select_send::send_data(List<Item> &items)
{
850
  if (unit->offset_limit_cnt)
unknown's avatar
unknown committed
851
  {						// using limit offset,count
852
    unit->offset_limit_cnt--;
853
    return 0;
unknown's avatar
unknown committed
854
  }
855

856
#ifdef HAVE_INNOBASE_DB
unknown's avatar
unknown committed
857 858 859 860 861
  /*
    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
  */
862 863 864
    ha_release_temporary_latches(thd);
#endif

865 866 867
  List_iterator_fast<Item> li(items);
  Protocol *protocol= thd->protocol;
  char buff[MAX_FIELD_WIDTH];
unknown's avatar
unknown committed
868
  String buffer(buff, sizeof(buff), &my_charset_bin);
869 870 871
  DBUG_ENTER("send_data");

  protocol->prepare_for_resend();
unknown's avatar
unknown committed
872 873 874
  Item *item;
  while ((item=li++))
  {
875
    if (item->send(protocol, &buffer))
unknown's avatar
unknown committed
876
    {
877
      protocol->free();				// Free used buffer
unknown's avatar
unknown committed
878
      my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
879
      break;
unknown's avatar
unknown committed
880 881
    }
  }
882
  thd->sent_row_count++;
883
  if (!thd->vio_ok())
884
    DBUG_RETURN(0);
unknown's avatar
unknown committed
885
  if (!thd->net.report_error)
886 887
    DBUG_RETURN(protocol->write());
  DBUG_RETURN(1);
unknown's avatar
unknown committed
888 889 890 891
}

bool select_send::send_eof()
{
892 893 894 895 896 897 898
#ifdef HAVE_INNOBASE_DB
  /* 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);
#endif

unknown's avatar
unknown committed
899 900 901
  /* Unlock tables before sending packet to gain some speed */
  if (thd->lock)
  {
902 903
    mysql_unlock_tables(thd, thd->lock);
    thd->lock=0;
unknown's avatar
unknown committed
904
  }
unknown's avatar
unknown committed
905 906
  if (!thd->net.report_error)
  {
unknown's avatar
unknown committed
907
    ::send_eof(thd);
unknown's avatar
unknown committed
908 909 910 911
    return 0;
  }
  else
    return 1;
unknown's avatar
unknown committed
912 913 914
}


915 916 917
/************************************************************************
  Handling writing to file
************************************************************************/
unknown's avatar
unknown committed
918

919 920
void select_to_file::send_error(uint errcode,const char *err)
{
unknown's avatar
unknown committed
921
  my_message(errcode, err, MYF(0));
922 923 924 925 926 927 928 929
  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;
  }
}
unknown's avatar
unknown committed
930 931


932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957
bool select_to_file::send_eof()
{
  int error= test(end_io_cache(&cache));
  if (my_close(file,MYF(MY_WME)))
    error= 1;
  if (!error)
    ::send_ok(thd,row_count);
  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;
}


958
select_to_file::~select_to_file()
unknown's avatar
unknown committed
959 960 961 962 963 964 965
{
  if (file >= 0)
  {					// This only happens in case of error
    (void) end_io_cache(&cache);
    (void) my_close(file,MYF(0));
    file= -1;
  }
966 967 968 969 970 971 972 973
}

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

select_export::~select_export()
{
974
  thd->sent_row_count=row_count;
unknown's avatar
unknown committed
975 976
}

977

978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995
/*
  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)
unknown's avatar
unknown committed
996
{
997 998
  File file;
  uint option= MY_UNPACK_FILENAME;
999

unknown's avatar
unknown committed
1000
#ifdef DONT_ALLOW_FULL_LOAD_DATA_PATHS
1001
  option|= MY_REPLACE_DIR;			// Force use of db directory
unknown's avatar
unknown committed
1002
#endif
1003

unknown's avatar
unknown committed
1004
  if (!dirname_length(exchange->file_name))
1005 1006 1007 1008 1009 1010 1011
  {
    strxnmov(path, FN_REFLEN, mysql_real_data_home, thd->db ? thd->db : "", NullS);
    (void) fn_format(path, exchange->file_name, path, "", option);
  }
  else
    (void) fn_format(path, exchange->file_name, mysql_real_data_home, "", option);
    
1012
  if (!access(path, F_OK))
unknown's avatar
unknown committed
1013
  {
1014
    my_error(ER_FILE_EXISTS_ERROR, MYF(0), exchange->file_name);
unknown's avatar
unknown committed
1015
    return -1;
unknown's avatar
unknown committed
1016 1017
  }
  /* Create the file world readable */
unknown's avatar
unknown committed
1018
  if ((file= my_create(path, 0666, O_WRONLY|O_EXCL, MYF(MY_WME))) < 0)
1019
    return file;
unknown's avatar
unknown committed
1020
#ifdef HAVE_FCHMOD
1021
  (void) fchmod(file, 0666);			// Because of umask()
unknown's avatar
unknown committed
1022
#else
1023
  (void) chmod(path, 0666);
unknown's avatar
unknown committed
1024
#endif
1025
  if (init_io_cache(cache, file, 0L, WRITE_CACHE, 0L, 1, MYF(MY_WME)))
unknown's avatar
unknown committed
1026
  {
1027
    my_close(file, MYF(0));
1028
    my_delete(path, MYF(0));  // Delete file on error, it was just created 
1029
    return -1;
unknown's avatar
unknown committed
1030
  }
1031
  return file;
1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042
}


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

1043
  if ((file= create_file(thd, path, exchange, &cache)) < 0)
1044
    return 1;
unknown's avatar
unknown committed
1045 1046
  /* Check if there is any blobs in data */
  {
unknown's avatar
unknown committed
1047
    List_iterator_fast<Item> li(list);
unknown's avatar
unknown committed
1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081
    Item *item;
    while ((item=li++))
    {
      if (item->max_length >= MAX_BLOB_WIDTH)
      {
	blob_flag=1;
	break;
      }
    }
  }
  field_term_length=exchange->field_term->length();
  if (!exchange->line_term->length())
    exchange->line_term=exchange->field_term;	// Use this if it exists
  field_sep_char= (exchange->enclosed->length() ? (*exchange->enclosed)[0] :
		   field_term_length ? (*exchange->field_term)[0] : INT_MAX);
  escape_char=	(exchange->escaped->length() ? (*exchange->escaped)[0] : -1);
  line_sep_char= (exchange->line_term->length() ?
		  (*exchange->line_term)[0] : INT_MAX);
  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);
  return 0;
}


bool select_export::send_data(List<Item> &items)
{

  DBUG_ENTER("send_data");
  char buff[MAX_FIELD_WIDTH],null_buff[2],space[MAX_FIELD_WIDTH];
  bool space_inited=0;
unknown's avatar
unknown committed
1082
  String tmp(buff,sizeof(buff),&my_charset_bin),*res;
unknown's avatar
unknown committed
1083 1084
  tmp.length(0);

1085
  if (unit->offset_limit_cnt)
unknown's avatar
unknown committed
1086
  {						// using limit offset,count
1087
    unit->offset_limit_cnt--;
unknown's avatar
unknown committed
1088 1089 1090 1091 1092 1093
    DBUG_RETURN(0);
  }
  row_count++;
  Item *item;
  char *buff_ptr=buff;
  uint used_length=0,items_left=items.elements;
unknown's avatar
unknown committed
1094
  List_iterator_fast<Item> li(items);
unknown's avatar
unknown committed
1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142

  if (my_b_write(&cache,(byte*) exchange->line_start->ptr(),
		 exchange->line_start->length()))
    goto err;
  while ((item=li++))
  {
    Item_result result_type=item->result_type();
    res=item->str_result(&tmp);
    if (res && (!exchange->opt_enclosed || result_type == STRING_RESULT))
    {
      if (my_b_write(&cache,(byte*) exchange->enclosed->ptr(),
		     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';
	  if (my_b_write(&cache,(byte*) null_buff,2))
	    goto err;
	}
	else if (my_b_write(&cache,(byte*) "NULL",4))
	  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();
      if (result_type == STRING_RESULT && escape_char != -1)
      {
	char *pos,*start,*end;

	for (start=pos=(char*) res->ptr(),end=pos+used_length ;
	     pos != end ;
	     pos++)
	{
#ifdef USE_MB
unknown's avatar
unknown committed
1143 1144
          CHARSET_INFO *res_charset=res->charset();
	  if (use_mb(res_charset))
unknown's avatar
unknown committed
1145 1146
	  {
	    int l;
unknown's avatar
unknown committed
1147
	    if ((l=my_ismbchar(res_charset, pos, end)))
unknown's avatar
unknown committed
1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182
	    {
	      pos += l-1;
	      continue;
	    }
	  }
#endif
	  if ((int) *pos == escape_char || (int) *pos == field_sep_char ||
	      (int) *pos == line_sep_char || !*pos)
	  {
	    char tmp_buff[2];
	    tmp_buff[0]= escape_char;
	    tmp_buff[1]= *pos ? *pos : '0';
	    if (my_b_write(&cache,(byte*) start,(uint) (pos-start)) ||
		my_b_write(&cache,(byte*) tmp_buff,2))
	      goto err;
	    start=pos+1;
	  }
	}
	if (my_b_write(&cache,(byte*) start,(uint) (pos-start)))
	  goto err;
      }
      else if (my_b_write(&cache,(byte*) res->ptr(),used_length))
	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;
1183
	for (; length > sizeof(space) ; length-=sizeof(space))
unknown's avatar
unknown committed
1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220
	{
	  if (my_b_write(&cache,(byte*) space,sizeof(space)))
	    goto err;
	}
	if (my_b_write(&cache,(byte*) space,length))
	  goto err;
      }
    }
    buff_ptr=buff;				// Place separators here
    if (res && (!exchange->opt_enclosed || result_type == STRING_RESULT))
    {
      memcpy(buff_ptr,exchange->enclosed->ptr(),exchange->enclosed->length());
      buff_ptr+=exchange->enclosed->length();
    }
    if (--items_left)
    {
      memcpy(buff_ptr,exchange->field_term->ptr(),field_term_length);
      buff_ptr+=field_term_length;
    }
    if (my_b_write(&cache,(byte*) buff,(uint) (buff_ptr-buff)))
      goto err;
  }
  if (my_b_write(&cache,(byte*) exchange->line_term->ptr(),
		 exchange->line_term->length()))
    goto err;
  DBUG_RETURN(0);
err:
  DBUG_RETURN(1);
}


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


int
1221 1222
select_dump::prepare(List<Item> &list __attribute__((unused)),
		     SELECT_LEX_UNIT *u)
unknown's avatar
unknown committed
1223
{
1224
  unit= u;
1225
  return (int) ((file= create_file(thd, path, exchange, &cache)) < 0);
unknown's avatar
unknown committed
1226 1227 1228 1229 1230
}


bool select_dump::send_data(List<Item> &items)
{
unknown's avatar
unknown committed
1231
  List_iterator_fast<Item> li(items);
unknown's avatar
unknown committed
1232
  char buff[MAX_FIELD_WIDTH];
unknown's avatar
unknown committed
1233
  String tmp(buff,sizeof(buff),&my_charset_bin),*res;
unknown's avatar
unknown committed
1234 1235 1236 1237
  tmp.length(0);
  Item *item;
  DBUG_ENTER("send_data");

1238
  if (unit->offset_limit_cnt)
unknown's avatar
unknown committed
1239
  {						// using limit offset,count
1240
    unit->offset_limit_cnt--;
unknown's avatar
unknown committed
1241 1242 1243 1244
    DBUG_RETURN(0);
  }
  if (row_count++ > 1) 
  {
unknown's avatar
unknown committed
1245
    my_message(ER_TOO_MANY_ROWS, ER(ER_TOO_MANY_ROWS), MYF(0));
unknown's avatar
unknown committed
1246 1247 1248 1249 1250
    goto err;
  }
  while ((item=li++))
  {
    res=item->str_result(&tmp);
1251
    if (!res)					// If NULL
unknown's avatar
unknown committed
1252
    {
1253 1254
      if (my_b_write(&cache,(byte*) "",1))
	goto err;
unknown's avatar
unknown committed
1255 1256 1257
    }
    else if (my_b_write(&cache,(byte*) res->ptr(),res->length()))
    {
1258
      my_error(ER_ERROR_ON_WRITE, MYF(0), path, my_errno);
unknown's avatar
unknown committed
1259 1260 1261 1262 1263 1264 1265 1266 1267
      goto err;
    }
  }
  DBUG_RETURN(0);
err:
  DBUG_RETURN(1);
}


1268
select_subselect::select_subselect(Item_subselect *item_arg)
1269
{
1270
  item= item_arg;
1271 1272
}

1273

unknown's avatar
unknown committed
1274
bool select_singlerow_subselect::send_data(List<Item> &items)
1275
{
unknown's avatar
unknown committed
1276 1277
  DBUG_ENTER("select_singlerow_subselect::send_data");
  Item_singlerow_subselect *it= (Item_singlerow_subselect *)item;
unknown's avatar
unknown committed
1278 1279
  if (it->assigned())
  {
1280
    my_message(ER_SUBQUERY_NO_1_ROW, ER(ER_SUBQUERY_NO_1_ROW), MYF(0));
unknown's avatar
unknown committed
1281 1282 1283
    DBUG_RETURN(1);
  }
  if (unit->offset_limit_cnt)
unknown's avatar
unknown committed
1284
  {				          // Using limit offset,count
unknown's avatar
unknown committed
1285 1286
    unit->offset_limit_cnt--;
    DBUG_RETURN(0);
1287
  }
unknown's avatar
unknown committed
1288
  List_iterator_fast<Item> li(items);
1289 1290 1291
  Item *val_item;
  for (uint i= 0; (val_item= li++); i++)
    it->store(i, val_item);
unknown's avatar
unknown committed
1292
  it->assigned(1);
unknown's avatar
unknown committed
1293
  DBUG_RETURN(0);
1294
}
unknown's avatar
unknown committed
1295

1296

1297 1298 1299 1300 1301 1302 1303 1304
void select_max_min_finder_subselect::cleanup()
{
  DBUG_ENTER("select_max_min_finder_subselect::cleanup");
  cache= 0;
  DBUG_VOID_RETURN;
}


1305 1306 1307
bool select_max_min_finder_subselect::send_data(List<Item> &items)
{
  DBUG_ENTER("select_max_min_finder_subselect::send_data");
1308
  Item_maxmin_subselect *it= (Item_maxmin_subselect *)item;
1309 1310
  List_iterator_fast<Item> li(items);
  Item *val_item= li++;
1311
  it->register_value();
1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333
  if (it->assigned())
  {
    cache->store(val_item);
    if ((this->*op)())
      it->store(0, cache);
  }
  else
  {
    if (!cache)
    {
      cache= Item_cache::get_cache(val_item->result_type());
      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;
unknown's avatar
unknown committed
1334 1335 1336
      case DECIMAL_RESULT:
        op= &select_max_min_finder_subselect::cmp_decimal;
        break;
1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352
      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()
{
  Item *maxmin= ((Item_singlerow_subselect *)item)->el(0);
1353
  double val1= cache->val_real(), val2= maxmin->val_real();
1354 1355 1356 1357
  if (fmax)
    return (cache->null_value && !maxmin->null_value) ||
      (!cache->null_value && !maxmin->null_value &&
       val1 > val2);
1358 1359 1360
  return (maxmin->null_value && !cache->null_value) ||
    (!cache->null_value && !maxmin->null_value &&
     val1 < val2);
1361 1362 1363 1364 1365 1366 1367 1368 1369 1370
}

bool select_max_min_finder_subselect::cmp_int()
{
  Item *maxmin= ((Item_singlerow_subselect *)item)->el(0);
  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);
1371 1372 1373
  return (maxmin->null_value && !cache->null_value) ||
    (!cache->null_value && !maxmin->null_value &&
     val1 < val2);
1374 1375
}

unknown's avatar
unknown committed
1376 1377 1378 1379 1380 1381 1382 1383 1384
bool select_max_min_finder_subselect::cmp_decimal()
{
  Item *maxmin= ((Item_singlerow_subselect *)item)->el(0);
  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) ;
1385 1386 1387
  return (maxmin->null_value && !cache->null_value) ||
    (!cache->null_value && !maxmin->null_value &&
     my_decimal_cmp(cvalue,mvalue) < 0);
unknown's avatar
unknown committed
1388 1389
}

1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403
bool select_max_min_finder_subselect::cmp_str()
{
  String *val1, *val2, buf1, buf2;
  Item *maxmin= ((Item_singlerow_subselect *)item)->el(0);
  /*
    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) ;
1404 1405 1406
  return (maxmin->null_value && !cache->null_value) ||
    (!cache->null_value && !maxmin->null_value &&
     sortcmp(val1, val2, cache->collation.collation) < 0);
1407 1408
}

unknown's avatar
unknown committed
1409 1410 1411 1412 1413 1414 1415 1416 1417 1418
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;
unknown's avatar
unknown committed
1419
  it->assigned(1);
unknown's avatar
unknown committed
1420 1421 1422
  DBUG_RETURN(0);
}

unknown's avatar
unknown committed
1423 1424

/***************************************************************************
1425
  Dump of select to variables
unknown's avatar
unknown committed
1426
***************************************************************************/
1427

1428
int select_dumpvar::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
unknown's avatar
unknown committed
1429
{
1430
  List_iterator_fast<Item> li(list);
unknown's avatar
unknown committed
1431
  List_iterator_fast<my_var> gl(var_list);
unknown's avatar
unknown committed
1432
  Item *item;
1433

1434 1435
  local_vars.empty();				// Clear list if SP
  unit= u;
1436
  row_count= 0;
1437

1438
  if (var_list.elements != list.elements)
unknown's avatar
unknown committed
1439
  {
unknown's avatar
unknown committed
1440 1441
    my_message(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT,
               ER(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT), MYF(0));
1442
    return 1;
unknown's avatar
unknown committed
1443
  }
1444
  while ((item=li++))
unknown's avatar
unknown committed
1445
  {
1446
    my_var *mv= gl++;
unknown's avatar
unknown committed
1447
    if (mv->local)
unknown's avatar
unknown committed
1448
      (void)local_vars.push_back(new Item_splocal(mv->s, mv->offset));
unknown's avatar
unknown committed
1449 1450
    else
    {
1451
      Item_func_set_user_var *xx = new Item_func_set_user_var(mv->s, item);
unknown's avatar
unknown committed
1452 1453 1454
      /*
        Item_func_set_user_var can't substitute something else on its place =>
        0 can be passed as last argument (reference on item)
unknown's avatar
unknown committed
1455 1456
        Item_func_set_user_var can't be fixed after creation, so we do not
        check xx->fixed
unknown's avatar
unknown committed
1457
      */
1458
      xx->fix_fields(thd, (TABLE_LIST*) thd->lex->select_lex.table_list.first,
unknown's avatar
unknown committed
1459
		     0);
unknown's avatar
unknown committed
1460 1461 1462
      xx->fix_length_and_dec();
      vars.push_back(xx);
    }
unknown's avatar
unknown committed
1463
  }
1464 1465
  return 0;
}
1466

1467

1468 1469 1470 1471 1472 1473 1474
void select_dumpvar::cleanup()
{
  vars.empty();
  row_count=0;
}


unknown's avatar
unknown committed
1475
Query_arena::Type Query_arena::type() const
1476
{
unknown's avatar
unknown committed
1477
  DBUG_ASSERT(0); /* Should never be called */
1478
  return STATEMENT;
1479 1480 1481
}


1482 1483 1484 1485 1486
/*
  Statement functions 
*/

Statement::Statement(THD *thd)
1487
  :Query_arena(&main_mem_root, INITIALIZED),
1488
  id(++thd->statement_id_counter),
1489 1490 1491 1492
  set_query_id(1),
  allow_sum_func(0),
  lex(&main_lex),
  query(0),
1493 1494
  query_length(0),
  cursor(0)
1495
{
1496
  name.str= NULL;
1497 1498 1499
  init_sql_alloc(&main_mem_root,
                 thd->variables.query_alloc_block_size,
                 thd->variables.query_prealloc_size);
1500 1501 1502
}

/*
1503 1504 1505
  This constructor is called when Statement is a parent of THD and
  for the backup statement. Some variables are initialized in
  THD::init due to locking problems.
1506 1507 1508
*/

Statement::Statement()
1509
  :Query_arena(&main_mem_root, CONVENTIONAL_EXECUTION),
1510
  id(0),
1511 1512 1513 1514
  set_query_id(1),
  allow_sum_func(0),                            /* initialized later */
  lex(&main_lex),
  query(0),                                     /* these two are set */ 
1515 1516
  query_length(0),                              /* in alloc_query() */
  cursor(0)
1517
{
1518 1519 1520 1521 1522 1523
  /*
    This is just to ensure that the destructor works correctly in
    case of an error and the backup statement. The memory root will
    be re-initialized in THD::init.
  */
  init_sql_alloc(&main_mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0);
1524 1525 1526
}


unknown's avatar
unknown committed
1527
Query_arena::Type Statement::type() const
1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540
{
  return STATEMENT;
}


void Statement::set_statement(Statement *stmt)
{
  id=             stmt->id;
  set_query_id=   stmt->set_query_id;
  allow_sum_func= stmt->allow_sum_func;
  lex=            stmt->lex;
  query=          stmt->query;
  query_length=   stmt->query_length;
1541
  cursor=         stmt->cursor;
1542 1543 1544
}


1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559
void
Statement::set_n_backup_statement(Statement *stmt, Statement *backup)
{
  backup->set_statement(this);
  set_statement(stmt);
}


void Statement::restore_backup_statement(Statement *stmt, Statement *backup)
{
  stmt->set_statement(this);
  set_statement(backup);
}


1560
void THD::end_statement()
1561 1562 1563 1564 1565
{
  /* Cleanup SQL processing state to resuse this statement in next query. */
  lex_end(lex);
  delete lex->result;
  lex->result= 0;
1566 1567
  /* Note that free_list is freed in cleanup_after_query() */

1568 1569 1570 1571 1572 1573 1574
  /*
    Don't free mem_root, as mem_root is freed in the end of dispatch_command
    (once for any command).
  */
}


unknown's avatar
unknown committed
1575
void Query_arena::set_n_backup_item_arena(Query_arena *set, Query_arena *backup)
unknown's avatar
unknown committed
1576
{
unknown's avatar
unknown committed
1577
  DBUG_ENTER("Query_arena::set_n_backup_item_arena");
unknown's avatar
unknown committed
1578
  DBUG_ASSERT(backup_arena == 0);
1579
  backup->set_item_arena(this);
unknown's avatar
unknown committed
1580
  set_item_arena(set);
unknown's avatar
unknown committed
1581 1582 1583
#ifndef DBUG_OFF
  backup_arena= 1;
#endif
1584
  DBUG_VOID_RETURN;
unknown's avatar
unknown committed
1585 1586 1587
}


unknown's avatar
unknown committed
1588
void Query_arena::restore_backup_item_arena(Query_arena *set, Query_arena *backup)
1589
{
unknown's avatar
unknown committed
1590
  DBUG_ENTER("Query_arena::restore_backup_item_arena");
1591 1592
  set->set_item_arena(this);
  set_item_arena(backup);
unknown's avatar
unknown committed
1593 1594
#ifndef DBUG_OFF
  backup_arena= 0;
1595
#endif
unknown's avatar
unknown committed
1596
  DBUG_VOID_RETURN;
1597 1598
}

unknown's avatar
unknown committed
1599
void Query_arena::set_item_arena(Query_arena *set)
unknown's avatar
unknown committed
1600
{
unknown's avatar
unknown committed
1601
  mem_root=  set->mem_root;
unknown's avatar
unknown committed
1602
  free_list= set->free_list;
1603
  state= set->state;
unknown's avatar
unknown committed
1604 1605
}

1606 1607
Statement::~Statement()
{
1608 1609 1610 1611 1612
  /*
    We must free `main_mem_root', not `mem_root' (pointer), to work
    correctly if this statement is used as a backup statement,
    for which `mem_root' may point to some other statement.
  */
unknown's avatar
unknown committed
1613
  free_root(&main_mem_root, MYF(0));
1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631
}

C_MODE_START

static byte *
get_statement_id_as_hash_key(const byte *record, uint *key_length,
                             my_bool not_used __attribute__((unused)))
{
  const Statement *statement= (const Statement *) record; 
  *key_length= sizeof(statement->id);
  return (byte *) &((const Statement *) statement)->id;
}

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

1632 1633
static byte *get_stmt_name_hash_key(Statement *entry, uint *length,
                                    my_bool not_used __attribute__((unused)))
1634 1635 1636 1637 1638
{
  *length=(uint) entry->name.length;
  return (byte*) entry->name.str;
}

1639 1640 1641 1642 1643
C_MODE_END

Statement_map::Statement_map() :
  last_found_statement(0)
{
1644 1645 1646 1647 1648
  enum
  {
    START_STMT_HASH_SIZE = 16,
    START_NAME_HASH_SIZE = 16
  };
1649
  hash_init(&st_hash, &my_charset_bin, START_STMT_HASH_SIZE, 0, 0,
1650 1651
            get_statement_id_as_hash_key,
            delete_statement_as_hash_key, MYF(0));
1652
  hash_init(&names_hash, system_charset_info, START_NAME_HASH_SIZE, 0, 0,
1653 1654
            (hash_get_key) get_stmt_name_hash_key,
            NULL,MYF(0));
1655 1656
}

1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674
int Statement_map::insert(Statement *statement)
{
  int rc= my_hash_insert(&st_hash, (byte *) statement);
  if (rc == 0)
    last_found_statement= statement;
  if (statement->name.str)
  {
    /*
      If there is a statement with the same name, remove it. It is ok to 
      remove old and fail to insert new one at the same time.
    */
    Statement *old_stmt;
    if ((old_stmt= find_by_name(&statement->name)))
      erase(old_stmt); 
    if ((rc= my_hash_insert(&names_hash, (byte*)statement)))
      hash_delete(&st_hash, (byte*)statement);
  }
  return rc;
1675 1676
}

1677

1678 1679 1680
bool select_dumpvar::send_data(List<Item> &items)
{
  List_iterator_fast<Item_func_set_user_var> li(vars);
unknown's avatar
unknown committed
1681 1682
  List_iterator_fast<Item_splocal> var_li(local_vars);
  List_iterator_fast<my_var> my_li(var_list);
1683
  List_iterator<Item> it(items);
1684
  Item_func_set_user_var *xx;
unknown's avatar
unknown committed
1685 1686
  Item_splocal *yy;
  my_var *zz;
1687
  DBUG_ENTER("send_data");
unknown's avatar
unknown committed
1688 1689 1690 1691 1692
  if (unit->offset_limit_cnt)
  {						// using limit offset,count
    unit->offset_limit_cnt--;
    DBUG_RETURN(0);
  }
1693

1694 1695 1696 1697 1698
  if (unit->offset_limit_cnt)
  {				          // Using limit offset,count
    unit->offset_limit_cnt--;
    DBUG_RETURN(0);
  }
1699 1700
  if (row_count++) 
  {
unknown's avatar
unknown committed
1701
    my_message(ER_TOO_MANY_ROWS, ER(ER_TOO_MANY_ROWS), MYF(0));
1702 1703
    DBUG_RETURN(1);
  }
1704
  while ((zz=my_li++) && (it++))
unknown's avatar
unknown committed
1705
  {
unknown's avatar
unknown committed
1706 1707 1708 1709
    if (zz->local)
    {
      if ((yy=var_li++)) 
      {
1710 1711
	if (thd->spcont->set_item_eval(current_thd,
				       yy->get_offset(), it.ref(), zz->type))
1712
	  DBUG_RETURN(1);
unknown's avatar
unknown committed
1713 1714 1715 1716 1717
      }
    }
    else
    {
      if ((xx=li++))
unknown's avatar
unknown committed
1718 1719
      {
        xx->check();
unknown's avatar
unknown committed
1720
	xx->update();
unknown's avatar
unknown committed
1721
      }
unknown's avatar
unknown committed
1722
    }
unknown's avatar
unknown committed
1723
  }
unknown's avatar
unknown committed
1724 1725 1726 1727 1728
  DBUG_RETURN(0);
}

bool select_dumpvar::send_eof()
{
1729
  if (! row_count)
unknown's avatar
unknown committed
1730 1731
    push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                 ER_SP_FETCH_NO_DATA, ER(ER_SP_FETCH_NO_DATA));
1732 1733
  ::send_ok(thd,row_count);
  return 0;
unknown's avatar
unknown committed
1734
}
1735 1736 1737 1738 1739 1740 1741 1742 1743 1744

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

void TMP_TABLE_PARAM::init()
{
  field_count= sum_func_count= func_count= hidden_field_count= 0;
  group_parts= group_length= group_null_parts= 0;
  quick_group= 1;
unknown's avatar
unknown committed
1745
  table_charset= 0;
1746
}
1747 1748 1749 1750


void thd_increment_bytes_sent(ulong length)
{
unknown's avatar
unknown committed
1751
  THD *thd=current_thd;
unknown's avatar
unknown committed
1752
  if (likely(thd != 0))
unknown's avatar
unknown committed
1753 1754 1755
  { /* current_thd==0 when close_connection() calls net_send_error() */
    thd->status_var.bytes_sent+= length;
  }
1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774
}


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));
}