sql_class.cc 46 KB
Newer Older
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
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 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.
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
7

bk@work.mysql.com's avatar
bk@work.mysql.com 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.
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
12

bk@work.mysql.com's avatar
bk@work.mysql.com 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
bk@work.mysql.com's avatar
bk@work.mysql.com committed
26 27
#pragma implementation				// gcc: Class implementation
#endif
28 29

#include "mysql_priv.h"
bk@work.mysql.com's avatar
bk@work.mysql.com committed
30 31
#include <m_ctype.h>
#include <sys/stat.h>
32
#include <thr_alarm.h>
bk@work.mysql.com's avatar
bk@work.mysql.com committed
33 34 35
#ifdef	__WIN__
#include <io.h>
#endif
36
#include <mysys_err.h>
bk@work.mysql.com's avatar
bk@work.mysql.com committed
37

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

44

bk@work.mysql.com's avatar
bk@work.mysql.com committed
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
/*****************************************************************************
** Instansiate templates
*****************************************************************************/

#ifdef __GNUC__
/* 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
****************************************************************************/

65 66
extern "C" byte *get_var_key(user_var_entry *entry, uint *length,
			     my_bool not_used __attribute__((unused)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
67 68 69 70 71
{
  *length=(uint) entry->name.length;
  return (byte*) entry->name.str;
}

72
extern "C" void free_user_var(user_var_entry *entry)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
73 74 75 76 77 78 79
{
  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));
}

80 81 82 83 84
bool key_part_spec::operator==(const key_part_spec& other) const
{
  return length == other.length && !strcmp(field_name, other.field_name);
}

85 86

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

  /* 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++))
130
    {
131 132 133 134 135
      if (*col1 == *col2)
      {
        found= TRUE;
	break;
      }
136
    }
137 138 139 140 141 142 143 144 145 146
    if (!found)
      return TRUE;                              // Error
  }
  return FALSE;                                 // Is prefix
#else
  while ((col1= col_it1++))
  {
    col2= col_it2++;
    if (!(*col1 == *col2))
      return TRUE;
147
  }
148 149
  return FALSE;                                 // Is prefix
#endif
150 151 152
}


bk@work.mysql.com's avatar
bk@work.mysql.com committed
153 154 155 156
/****************************************************************************
** Thread specific functions
****************************************************************************/

157 158 159 160 161
THD::THD()
  :user_time(0), global_read_lock(0), is_fatal_error(0),
   last_insert_id_used(0),
   insert_id_used(0), rand_used(0), time_zone_used(0),
   in_lock_tables(0), bootstrap(0)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
162
{
163
  current_arena= this;
164
  host= user= priv_user= db= ip=0;
165
  host_or_ip= "connecting host";
monty@mysql.com's avatar
monty@mysql.com committed
166 167
  locked=some_tables_deleted=no_errors=password= 0;
  killed=0;
konstantin@oak.local's avatar
konstantin@oak.local committed
168
  query_start_used= 0;
169
  count_cuted_fields= CHECK_FIELD_IGNORE;
170
  db_length= col_access= 0;
171
  query_error= tmp_table_used= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
172
  next_insert_id=last_insert_id=0;
173
  open_tables= temporary_tables= handler_tables= derived_tables= 0;
174
  hash_clear(&handler_tables_hash);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
175 176
  tmp_table=0;
  lock=locked_tables=0;
177
  used_tables=0;
178
  cuted_fields= sent_row_count= 0L;
179
  limit_found_rows= 0;
180
  statement_id_counter= 0UL;
181
  // Must be reset to handle error with THD's created for init of mysqld
182
  lex->current_select= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
183
  start_time=(time_t) 0;
184
  time_after_lock=(time_t) 0;
185
  current_linfo =  0;
186
  slave_thread = 0;
187
  variables.pseudo_thread_id= 0;
188
  one_shot_set= 0;
189
  file_id = 0;
190
  query_id= 0;
191
  warn_id= 0;
192
  db_charset= global_system_variables.collation_database;
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
193
  mysys_var=0;
194 195
#ifndef DBUG_OFF
  dbug_sentry=THD_SENTRY_MAGIC;
196 197
#endif
#ifndef EMBEDDED_LIBRARY  
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
198
  net.vio=0;
199
#endif
200
  net.last_error[0]=0;				// If error on boot
201
  client_capabilities= 0;                       // minimalistic client
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
202
  ull=0;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
203
  system_thread=cleanup_done=0;
204
  peer_port= 0;					// For SHOW PROCESSLIST
205
  transaction.changed_tables = 0;
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
206 207 208 209 210 211
#ifdef	__WIN__
  real_id = 0;
#endif
#ifdef SIGNAL_WITH_VIO_CLOSE
  active_vio = 0;
#endif  
212
  pthread_mutex_init(&LOCK_delete, MY_MUTEX_INIT_FAST);
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
213 214 215 216 217

  /* Variables with default values */
  proc_info="login";
  where="field list";
  server_id = ::server_id;
218
  slave_net = 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
219
  command=COM_CONNECT;
hf@deer.(none)'s avatar
hf@deer.(none) committed
220
#ifndef NO_EMBEDDED_ACCESS_CHECKS
bk@work.mysql.com's avatar
bk@work.mysql.com committed
221
  db_access=NO_ACCESS;
hf@deer.(none)'s avatar
hf@deer.(none) committed
222
#endif
223
  version=refresh_version;			// For boot
224
  *scramble= '\0';
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
225

226
  init();
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
227
  /* Initialize sub structures */
228
  init_sql_alloc(&warn_root, WARN_ALLOC_BLOCK_SIZE, WARN_ALLOC_PREALLOC_SIZE);
229
  user_connect=(USER_CONN *)0;
230
  hash_init(&user_vars, &my_charset_bin, USER_VARS_HASH_SIZE, 0, 0,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
231
	    (hash_get_key) get_var_key,
232
	    (hash_free_key) free_user_var,0);
233

234 235 236 237 238 239 240 241
  /* For user vars replication*/
  if (opt_bin_log)
    my_init_dynamic_array(&user_var_events,
			  sizeof(BINLOG_USER_VAR_EVENT *),
			  16,
			  16);
  else
    bzero((char*) &user_var_events, sizeof(user_var_events));
242

243 244 245 246 247
  /* Protocol */
  protocol= &protocol_simple;			// Default protocol
  protocol_simple.init(this);
  protocol_prep.init(this);

heikki@hundin.mysql.fi's avatar
heikki@hundin.mysql.fi committed
248
  tablespace_op=FALSE;
249
#ifdef USING_TRANSACTIONS
250
  bzero((char*) &transaction,sizeof(transaction));
251 252 253 254 255
  /*
    Binlog is always open (if needed) before a THD is created (including
    bootstrap).
  */
  if (opt_using_transactions && mysql_bin_log.is_open())
256 257 258 259 260 261 262
  {
    if (open_cached_file(&transaction.trans_log,
			 mysql_tmpdir, LOG_PREFIX, binlog_cache_size,
			 MYF(MY_WME)))
      killed=1;
    transaction.trans_log.end_of_file= max_binlog_cache_size;
  }
263
#endif
264
  init_sql_alloc(&transaction.mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0);
265
  {
266
    ulong tmp=sql_rnd_with_mutex();
267
    randominit(&rand, tmp + (ulong) &rand, tmp + (ulong) ::query_id);
268
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
269 270
}

271 272 273 274 275 276 277

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

void THD::init(void)
{
278 279
  pthread_mutex_lock(&LOCK_global_system_variables);
  variables= global_system_variables;
280 281 282 283 284 285
  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);
286 287 288
#ifdef HAVE_NDBCLUSTER_DB
  variables.ndb_use_transactions= 1;
#endif
289
  pthread_mutex_unlock(&LOCK_global_system_variables);
290 291 292
  server_status= SERVER_STATUS_AUTOCOMMIT;
  options= thd_startup_options;
  open_options=ha_open_options;
293 294 295
  update_lock_default= (variables.low_priority_updates ?
			TL_WRITE_LOW_PRIORITY :
			TL_WRITE);
296
  session_tx_isolation= (enum_tx_isolation) variables.tx_isolation;
297 298 299
  warn_list.empty();
  bzero((char*) warn_count, sizeof(warn_count));
  total_warn_count= 0;
300
  update_charset();
bar@mysql.com's avatar
bar@mysql.com committed
301
  variables.lc_time_names = &my_locale_en_US;
302 303
}

304

305 306 307 308 309 310 311 312
/*
  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()
{
313
  ha_enable_transaction(this,TRUE);
314

315
  reset_root_defaults(mem_root, variables.query_alloc_block_size,
316 317 318 319
                      variables.query_prealloc_size);
  reset_root_defaults(&transaction.mem_root,
                      variables.trans_alloc_block_size,
                      variables.trans_prealloc_size);
320 321 322
}


323 324 325 326 327 328 329 330 331 332 333 334 335 336
/*
  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();
337
  cleanup_done= 0;
338
  init();
339
  stmt_map.reset();
340
  hash_init(&user_vars, &my_charset_bin, USER_VARS_HASH_SIZE, 0, 0,
341
	    (hash_get_key) get_var_key,
342
	    (hash_free_key) free_user_var, 0);
343 344 345
}


monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
346 347 348
/* Do operations that may take a long time */

void THD::cleanup(void)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
349
{
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
350
  DBUG_ENTER("THD::cleanup");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
351 352 353 354 355 356
  ha_rollback(this);
  if (locked_tables)
  {
    lock=locked_tables; locked_tables=0;
    close_thread_tables(this);
  }
357
  mysql_ha_flush(this, (TABLE_LIST*) 0,
358
                 MYSQL_HA_CLOSE_FINAL | MYSQL_HA_FLUSH_ALL, FALSE);
359
  hash_free(&handler_tables_hash);
360 361
  delete_dynamic(&user_var_events);
  hash_free(&user_vars);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
362
  close_temporary_tables(this);
363 364 365
  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));
366 367 368
  if (global_read_lock)
    unlock_global_read_lock(this);
  if (ull)
369
  {
370 371 372 373
    pthread_mutex_lock(&LOCK_user_locks);
    item_user_lock_release(ull);
    pthread_mutex_unlock(&LOCK_user_locks);
    ull= 0;
374
  }
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
375 376 377 378
  cleanup_done=1;
  DBUG_VOID_RETURN;
}

379

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
380 381
THD::~THD()
{
382
  THD_CHECK_SENTRY(this);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
383
  DBUG_ENTER("~THD()");
384 385 386 387
  /* Ensure that no one is using THD */
  pthread_mutex_lock(&LOCK_delete);
  pthread_mutex_unlock(&LOCK_delete);

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
388
  /* Close connection */
389
#ifndef EMBEDDED_LIBRARY  
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
390 391 392 393 394
  if (net.vio)
  {
    vio_delete(net.vio);
    net_end(&net); 
  }
395
#endif
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
396 397
  if (!cleanup_done)
    cleanup();
398 399
#ifdef USING_TRANSACTIONS
  if (opt_using_transactions)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
400
  {
401 402
    close_cached_file(&transaction.trans_log);
    ha_close_connection(this);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
403
  }
404
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
405 406

  DBUG_PRINT("info", ("freeing host"));
hf@deer.(none)'s avatar
hf@deer.(none) committed
407
  if (host != my_localhost)			// If not pointer to constant
408
    safeFree(host);
409 410
  if (user != delayed_user)
    safeFree(user);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
411
  safeFree(ip);
412
  safeFree(db);
413
  free_root(&warn_root,MYF(0));
414
  free_root(&transaction.mem_root,MYF(0));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
415
  mysys_var=0;					// Safety (shouldn't be needed)
416
  pthread_mutex_destroy(&LOCK_delete);
417 418
#ifndef DBUG_OFF
  dbug_sentry = THD_SENTRY_GONE;
419
#endif  
420
  /* Reset stmt_backup.mem_root to not double-free memory from thd.mem_root */
421
  clear_alloc_root(&stmt_backup.main_mem_root);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
422 423 424
  DBUG_VOID_RETURN;
}

425

426
void THD::awake(bool prepare_to_die)
427
{
428
  THD_CHECK_SENTRY(this);
429 430
  safe_mutex_assert_owner(&LOCK_delete); 

431
  thr_alarm_kill(real_id);
432 433
  if (prepare_to_die)
    killed = 1;
434
#ifdef SIGNAL_WITH_VIO_CLOSE
435 436
  else
    close_active_vio();
437 438
#endif    
  if (mysys_var)
439 440 441 442 443 444 445 446 447
  {
    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.
448 449 450 451 452
      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.
453

454
      Note that there is a small chance we fail to kill. If victim has locked
455 456 457 458 459
      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
460
      see it immediately and so may have time to reach the cond_wait().
461
    */
462
    if (mysys_var->current_cond && mysys_var->current_mutex)
463
    {
464 465 466
      pthread_mutex_lock(mysys_var->current_mutex);
      pthread_cond_broadcast(mysys_var->current_cond);
      pthread_mutex_unlock(mysys_var->current_mutex);
467
    }
468 469
    pthread_mutex_unlock(&mysys_var->mutex);
  }
470 471
}

472 473 474 475
/*
  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
476 477 478

bool THD::store_globals()
{
479
  if (my_pthread_setspecific_ptr(THR_THD,  this) ||
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
480
      my_pthread_setspecific_ptr(THR_MALLOC, &mem_root))
481 482 483
    return 1;
  mysys_var=my_thread_var;
  dbug_thread_id=my_thread_id();
guilhem@mysql.com's avatar
guilhem@mysql.com committed
484 485 486 487
  /*
    By default 'slave_proxy_id' is 'thread_id'. They may later become different
    if this is the slave SQL thread.
  */
488
  variables.pseudo_thread_id= thread_id;
489
  return 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
490 491
}

492

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518
/*
  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;
519
  uint dummy_errors;
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
520 521 522 523 524 525
  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,
526
			       from, from_length, from_cs, &dummy_errors);
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
527 528 529 530 531
  to->str[to->length]=0;			// Safety
  DBUG_RETURN(0);
}


532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548
/*
  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)
{
549 550
  uint dummy_errors;
  if (convert_buffer.copy(s->ptr(), s->length(), from_cs, to_cs, &dummy_errors))
551 552 553 554 555 556 557 558 559 560 561
    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;
}

562

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
563 564 565 566 567 568
/*
  Update some cache variables when character set changes
*/

void THD::update_charset()
{
569 570 571 572 573 574 575
  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);
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
576 577 578
}


579 580 581 582 583 584 585 586 587 588 589 590 591 592
/* 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 */
593

594 595
void THD::add_changed_table(TABLE *table)
{
596
  DBUG_ENTER("THD::add_changed_table(table)");
597

598
  DBUG_ASSERT((options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) &&
599
	      table->file->has_transactions());
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
600 601
  add_changed_table(table->table_cache_key, table->key_length);
  DBUG_VOID_RETURN;
602
}
603

604

605 606 607
void THD::add_changed_table(const char *key, long key_length)
{
  DBUG_ENTER("THD::add_changed_table(key)");
608 609
  CHANGED_TABLE_LIST **prev_changed = &transaction.changed_tables;
  CHANGED_TABLE_LIST *curr = transaction.changed_tables;
610

611
  for (; curr; prev_changed = &(curr->next), curr = curr->next)
612
  {
613
    int cmp =  (long)curr->key_length - (long)key_length;
614 615
    if (cmp < 0)
    {
616
      list_include(prev_changed, curr, changed_table_dup(key, key_length));
617
      DBUG_PRINT("info", 
618
		 ("key_length %u %u", key_length, (*prev_changed)->key_length));
619 620 621 622
      DBUG_VOID_RETURN;
    }
    else if (cmp == 0)
    {
623
      cmp = memcmp(curr->key, key, curr->key_length);
624 625
      if (cmp < 0)
      {
626
	list_include(prev_changed, curr, changed_table_dup(key, key_length));
627
	DBUG_PRINT("info", 
628
		   ("key_length %u %u", key_length,
629
		    (*prev_changed)->key_length));
630 631 632 633 634 635 636 637 638
	DBUG_VOID_RETURN;
      }
      else if (cmp == 0)
      {
	DBUG_PRINT("info", ("already in list"));
	DBUG_VOID_RETURN;
      }
    }
  }
639
  *prev_changed = changed_table_dup(key, key_length);
640
  DBUG_PRINT("info", ("key_length %u %u", key_length,
641
		      (*prev_changed)->key_length));
642 643 644
  DBUG_VOID_RETURN;
}

645

646
CHANGED_TABLE_LIST* THD::changed_table_dup(const char *key, long key_length)
647 648 649
{
  CHANGED_TABLE_LIST* new_table = 
    (CHANGED_TABLE_LIST*) trans_alloc(ALIGN_SIZE(sizeof(CHANGED_TABLE_LIST))+
650
				      key_length + 1);
651 652 653
  if (!new_table)
  {
    my_error(EE_OUTOFMEMORY, MYF(ME_BELL),
654
	     ALIGN_SIZE(sizeof(TABLE_LIST)) + key_length + 1);
655 656 657 658 659 660 661
    killed= 1;
    return 0;
  }

  new_table->key = (char *) (((byte*)new_table)+
			     ALIGN_SIZE(sizeof(CHANGED_TABLE_LIST)));
  new_table->next = 0;
662 663
  new_table->key_length = key_length;
  ::memcpy(new_table->key, key, key_length);
664 665 666
  return new_table;
}

667

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
668 669 670 671
int THD::send_explain_fields(select_result *result)
{
  List<Item> field_list;
  Item *item;
672
  CHARSET_INFO *cs= system_charset_info;
673
  field_list.push_back(new Item_return_int("id",3, MYSQL_TYPE_LONGLONG));
674
  field_list.push_back(new Item_empty_string("select_type", 19, cs));
igor@rurik.mysql.com's avatar
igor@rurik.mysql.com committed
675 676 677 678
  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;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
679
  field_list.push_back(item=new Item_empty_string("possible_keys",
680
						  NAME_LEN*MAX_KEY, cs));
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
681
  item->maybe_null=1;
682
  field_list.push_back(item=new Item_empty_string("key", NAME_LEN, cs));
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
683
  item->maybe_null=1;
684 685
  field_list.push_back(item=new Item_return_int("key_len",3,
						MYSQL_TYPE_LONGLONG));
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
686 687
  item->maybe_null=1;
  field_list.push_back(item=new Item_empty_string("ref",
688
						  NAME_LEN*MAX_REF_PARTS, cs));
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
689
  item->maybe_null=1;
igor@rurik.mysql.com's avatar
igor@rurik.mysql.com committed
690 691 692
  field_list.push_back(item= new Item_return_int("rows", 10,
                                                 MYSQL_TYPE_LONGLONG));
  item->maybe_null= 1;
693
  field_list.push_back(new Item_empty_string("Extra", 255, cs));
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
694 695
  return (result->send_fields(field_list,1));
}
696

697 698 699
#ifdef SIGNAL_WITH_VIO_CLOSE
void THD::close_active_vio()
{
700
  DBUG_ENTER("close_active_vio");
701
  safe_mutex_assert_owner(&LOCK_delete); 
702
#ifndef EMBEDDED_LIBRARY
703 704 705 706 707
  if (active_vio)
  {
    vio_close(active_vio);
    active_vio = 0;
  }
708
#endif
709
  DBUG_VOID_RETURN;
710 711 712
}
#endif

713

714 715 716 717 718
struct Item_change_record: public ilink
{
  Item **place;
  Item *old_value;
  /* Placement new was hidden by `new' in ilink (TODO: check): */
719
  static void *operator new(size_t size, void *mem) { return mem; }
720 721
  static void operator delete(void *ptr, size_t size) {}
  static void operator delete(void *ptr, void *mem) { /* never called */ }
722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748
};


/*
  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;
749
  change_list.append(change);
750 751 752 753 754 755 756 757 758 759 760 761 762 763
}


void THD::rollback_item_tree_changes()
{
  I_List_iterator<Item_change_record> it(change_list);
  Item_change_record *change;
  while ((change= it++))
    *change->place= change->old_value;
  /* We can forget about changes memory: it's allocated in runtime memroot */
  change_list.empty();
}


bk@work.mysql.com's avatar
bk@work.mysql.com committed
764 765 766 767 768 769 770 771 772
/*****************************************************************************
** Functions to provide a interface to select results
*****************************************************************************/

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

773 774 775 776 777
void select_result::send_error(uint errcode,const char *err)
{
  ::send_error(thd, errcode, err);
}

778 779 780 781 782 783

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

784 785 786
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
787 788 789 790 791

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
792
  enclosed=   line_start= &my_empty_string;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
793 794 795 796 797 798
  line_term=  &default_line_term;
  escaped=    &default_escaped;
}

bool select_send::send_fields(List<Item> &list,uint flag)
{
799
  return thd->protocol->send_fields(&list,flag);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
800 801 802 803 804 805
}

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

bool select_send::send_data(List<Item> &items)
{
806
  if (unit->offset_limit_cnt)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
807
  {						// using limit offset,count
808
    unit->offset_limit_cnt--;
809
    return 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
810
  }
811

812
#ifdef HAVE_INNOBASE_DB
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
813 814 815 816 817
  /*
    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
  */
818 819 820 821
  if (thd->transaction.all.innobase_tid)
    ha_release_temporary_latches(thd);
#endif

822 823 824
  List_iterator_fast<Item> li(items);
  Protocol *protocol= thd->protocol;
  char buff[MAX_FIELD_WIDTH];
825
  String buffer(buff, sizeof(buff), &my_charset_bin);
826
  DBUG_ENTER("select_send::send_data");
827 828

  protocol->prepare_for_resend();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
829 830 831
  Item *item;
  while ((item=li++))
  {
832
    if (item->send(protocol, &buffer))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
833
    {
834
      protocol->free();				// Free used buffer
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
835
      my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
836
      break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
837 838
    }
  }
839
  thd->sent_row_count++;
840
  if (!thd->vio_ok())
841
    DBUG_RETURN(0);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
842
  if (!thd->net.report_error)
843 844
    DBUG_RETURN(protocol->write());
  DBUG_RETURN(1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
845 846 847 848
}

bool select_send::send_eof()
{
849 850 851 852 853 854 855 856
#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 */
  if (thd->transaction.all.innobase_tid)
    ha_release_temporary_latches(thd);
#endif

bk@work.mysql.com's avatar
bk@work.mysql.com committed
857 858 859
  /* Unlock tables before sending packet to gain some speed */
  if (thd->lock)
  {
860 861
    mysql_unlock_tables(thd, thd->lock);
    thd->lock=0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
862
  }
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
863 864
  if (!thd->net.report_error)
  {
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
865
    ::send_eof(thd);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
866 867 868 869
    return 0;
  }
  else
    return 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
870 871 872
}


873 874 875
/************************************************************************
  Handling writing to file
************************************************************************/
bk@work.mysql.com's avatar
bk@work.mysql.com committed
876

877 878 879 880 881 882 883 884 885 886 887
void select_to_file::send_error(uint errcode,const char *err)
{
  ::send_error(thd,errcode,err);
  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
888

889

890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915
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;
}


916
select_to_file::~select_to_file()
bk@work.mysql.com's avatar
bk@work.mysql.com committed
917 918 919 920 921 922 923
{
  if (file >= 0)
  {					// This only happens in case of error
    (void) end_io_cache(&cache);
    (void) my_close(file,MYF(0));
    file= -1;
  }
924 925 926 927 928 929 930 931
}

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

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

935

936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953
/*
  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
954
{
955 956
  File file;
  uint option= MY_UNPACK_FILENAME;
957

bk@work.mysql.com's avatar
bk@work.mysql.com committed
958
#ifdef DONT_ALLOW_FULL_LOAD_DATA_PATHS
959
  option|= MY_REPLACE_DIR;			// Force use of db directory
bk@work.mysql.com's avatar
bk@work.mysql.com committed
960
#endif
961

hf@deer.(none)'s avatar
hf@deer.(none) committed
962
  if (!dirname_length(exchange->file_name))
963 964 965 966 967 968 969
  {
    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);
    
970
  if (!access(path, F_OK))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
971
  {
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
972
    my_error(ER_FILE_EXISTS_ERROR, MYF(0), exchange->file_name);
973
    return -1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
974 975
  }
  /* Create the file world readable */
serg@serg.mylan's avatar
serg@serg.mylan committed
976
  if ((file= my_create(path, 0666, O_WRONLY|O_EXCL, MYF(MY_WME))) < 0)
977
    return file;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
978
#ifdef HAVE_FCHMOD
979
  (void) fchmod(file, 0666);			// Because of umask()
bk@work.mysql.com's avatar
bk@work.mysql.com committed
980
#else
981
  (void) chmod(path, 0666);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
982
#endif
983
  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
984
  {
985
    my_close(file, MYF(0));
986
    my_delete(path, MYF(0));  // Delete file on error, it was just created 
987
    return -1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
988
  }
989
  return file;
990 991 992 993 994 995 996 997 998 999 1000
}


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

1001
  if ((file= create_file(thd, path, exchange, &cache)) < 0)
1002
    return 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1003 1004
  /* Check if there is any blobs in data */
  {
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
1005
    List_iterator_fast<Item> li(list);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036
    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)
{

1037
  DBUG_ENTER("select_export::send_data");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1038 1039
  char buff[MAX_FIELD_WIDTH],null_buff[2],space[MAX_FIELD_WIDTH];
  bool space_inited=0;
1040
  String tmp(buff,sizeof(buff),&my_charset_bin),*res;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1041 1042
  tmp.length(0);

1043
  if (unit->offset_limit_cnt)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1044
  {						// using limit offset,count
1045
    unit->offset_limit_cnt--;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1046 1047 1048 1049 1050 1051
    DBUG_RETURN(0);
  }
  row_count++;
  Item *item;
  char *buff_ptr=buff;
  uint used_length=0,items_left=items.elements;
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
1052
  List_iterator_fast<Item> li(items);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
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 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100

  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
1101 1102
          CHARSET_INFO *res_charset=res->charset();
	  if (use_mb(res_charset))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1103 1104
	  {
	    int l;
1105
	    if ((l=my_ismbchar(res_charset, pos, end)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
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
	    {
	      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;
1141
	for (; length > sizeof(space) ; length-=sizeof(space))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1142 1143 1144 1145 1146 1147 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
	{
	  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
1179 1180
select_dump::prepare(List<Item> &list __attribute__((unused)),
		     SELECT_LEX_UNIT *u)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1181
{
1182
  unit= u;
1183
  return (int) ((file= create_file(thd, path, exchange, &cache)) < 0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1184 1185 1186 1187 1188
}


bool select_dump::send_data(List<Item> &items)
{
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
1189
  List_iterator_fast<Item> li(items);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1190
  char buff[MAX_FIELD_WIDTH];
1191
  String tmp(buff,sizeof(buff),&my_charset_bin),*res;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1192 1193
  tmp.length(0);
  Item *item;
1194
  DBUG_ENTER("select_dump::send_data");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1195

1196
  if (unit->offset_limit_cnt)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1197
  {						// using limit offset,count
1198
    unit->offset_limit_cnt--;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1199 1200 1201 1202
    DBUG_RETURN(0);
  }
  if (row_count++ > 1) 
  {
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1203
    my_error(ER_TOO_MANY_ROWS, MYF(0));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1204 1205 1206 1207 1208
    goto err;
  }
  while ((item=li++))
  {
    res=item->str_result(&tmp);
1209
    if (!res)					// If NULL
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1210
    {
1211 1212
      if (my_b_write(&cache,(byte*) "",1))
	goto err;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225
    }
    else if (my_b_write(&cache,(byte*) res->ptr(),res->length()))
    {
      my_error(ER_ERROR_ON_WRITE,MYF(0), path, my_errno);
      goto err;
    }
  }
  DBUG_RETURN(0);
err:
  DBUG_RETURN(1);
}


1226
select_subselect::select_subselect(Item_subselect *item_arg)
1227
{
1228
  item= item_arg;
1229 1230
}

1231

1232
bool select_singlerow_subselect::send_data(List<Item> &items)
1233
{
1234 1235
  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
1236 1237
  if (it->assigned())
  {
1238
    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
1239 1240 1241
    DBUG_RETURN(1);
  }
  if (unit->offset_limit_cnt)
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1242
  {				          // Using limit offset,count
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1243 1244
    unit->offset_limit_cnt--;
    DBUG_RETURN(0);
1245
  }
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1246
  List_iterator_fast<Item> li(items);
1247 1248 1249
  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
1250
  it->assigned(1);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1251
  DBUG_RETURN(0);
1252
}
1253

1254

1255 1256 1257 1258 1259 1260 1261 1262
void select_max_min_finder_subselect::cleanup()
{
  DBUG_ENTER("select_max_min_finder_subselect::cleanup");
  cache= 0;
  DBUG_VOID_RETURN;
}


1263 1264 1265
bool select_max_min_finder_subselect::send_data(List<Item> &items)
{
  DBUG_ENTER("select_max_min_finder_subselect::send_data");
1266
  Item_maxmin_subselect *it= (Item_maxmin_subselect *)item;
1267 1268
  List_iterator_fast<Item> li(items);
  Item *val_item= li++;
1269
  it->register_value();
1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352
  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;
      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);
  double val1= cache->val(), val2= maxmin->val();
  if (fmax)
    return (cache->null_value && !maxmin->null_value) ||
      (!cache->null_value && !maxmin->null_value &&
       val1 > val2);
  else
    return (maxmin->null_value && !cache->null_value) ||
      (!cache->null_value && !maxmin->null_value &&
       val1 < val2);
}

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);
  else
    return (maxmin->null_value && !cache->null_value) ||
      (!cache->null_value && !maxmin->null_value &&
       val1 < val2);
}

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) ;
  else
    return (maxmin->null_value && !cache->null_value) ||
      (!cache->null_value && !maxmin->null_value &&
       sortcmp(val1, val2, cache->collation.collation) < 0);
}

1353 1354 1355 1356 1357 1358 1359 1360 1361 1362
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
1363
  it->assigned(1);
1364 1365 1366
  DBUG_RETURN(0);
}

Sinisa@sinisa.nasamreza.org's avatar
Sinisa@sinisa.nasamreza.org committed
1367 1368

/***************************************************************************
1369
  Dump of select to variables
Sinisa@sinisa.nasamreza.org's avatar
Sinisa@sinisa.nasamreza.org committed
1370
***************************************************************************/
1371

1372
int select_dumpvar::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
Sinisa@sinisa.nasamreza.org's avatar
Sinisa@sinisa.nasamreza.org committed
1373
{
1374 1375
  List_iterator_fast<Item> li(list);
  List_iterator_fast<LEX_STRING> gl(var_list);
Sinisa@sinisa.nasamreza.org's avatar
Sinisa@sinisa.nasamreza.org committed
1376 1377
  Item *item;
  LEX_STRING *ls;
1378
  if (var_list.elements != list.elements)
Sinisa@sinisa.nasamreza.org's avatar
Sinisa@sinisa.nasamreza.org committed
1379
  {
1380 1381
    my_error(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT, MYF(0));
    return 1;
Sinisa@sinisa.nasamreza.org's avatar
Sinisa@sinisa.nasamreza.org committed
1382
  }
1383
  unit=u;
1384
  while ((item=li++))
Sinisa@sinisa.nasamreza.org's avatar
Sinisa@sinisa.nasamreza.org committed
1385
  {
1386
    ls= gl++;
Sinisa@sinisa.nasamreza.org's avatar
Sinisa@sinisa.nasamreza.org committed
1387
    Item_func_set_user_var *xx = new Item_func_set_user_var(*ls,item);
1388 1389 1390 1391
    /*
      Item_func_set_user_var can't substitute something else on its place =>
      0 can be passed as last argument (reference on item)
    */
1392
    xx->fix_fields(thd,(TABLE_LIST*) thd->lex->select_lex.table_list.first,
1393
		   0);
Sinisa@sinisa.nasamreza.org's avatar
Sinisa@sinisa.nasamreza.org committed
1394
    xx->fix_length_and_dec();
1395
    vars.push_back(xx);
Sinisa@sinisa.nasamreza.org's avatar
Sinisa@sinisa.nasamreza.org committed
1396
  }
1397 1398
  return 0;
}
1399 1400


1401 1402 1403 1404 1405 1406 1407
void select_dumpvar::cleanup()
{
  vars.empty();
  row_count=0;
}


1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418
/*
  Create arena for already constructed THD.

  SYNOPSYS
    Item_arena()
      thd - thread for which arena is created

  DESCRIPTION
    Create arena for already existing THD using its variables as parameters
    for memory root initialization.
*/
1419
Item_arena::Item_arena(THD* thd)
1420 1421
  :free_list(0), mem_root(&main_mem_root),
   state(INITIALIZED)
1422
{
1423
  init_sql_alloc(&main_mem_root,
1424 1425 1426 1427 1428
                 thd->variables.query_alloc_block_size,
                 thd->variables.query_prealloc_size);
}


1429 1430
/*
  Create arena and optionally initialize memory root.
1431

1432 1433 1434
  SYNOPSYS
    Item_arena()
      init_mem_root - whenever we need to initialize memory root
1435

1436 1437 1438
  DESCRIPTION
    Create arena and optionally initialize memory root with minimal
    possible parameters.
1439

1440 1441 1442 1443 1444
  NOTE
    We use this constructor when arena is part of THD, but reinitialize
    its memory root in THD::init_for_queries() before execution of real
    statements.
*/
1445
Item_arena::Item_arena(bool init_mem_root)
1446
  :free_list(0), mem_root(&main_mem_root),
1447
  state(CONVENTIONAL_EXECUTION)
1448 1449
{
  if (init_mem_root)
1450
    init_sql_alloc(&main_mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0);
1451 1452
}

1453

1454 1455 1456 1457 1458 1459 1460
Item_arena::Type Item_arena::type() const
{
  DBUG_ASSERT("Item_arena::type()" == "abstract");
  return STATEMENT;
}


1461 1462 1463 1464 1465
/*
  Statement functions 
*/

Statement::Statement(THD *thd)
1466 1467
  :Item_arena(thd),
  id(++thd->statement_id_counter),
1468 1469 1470 1471
  set_query_id(1),
  allow_sum_func(0),
  lex(&main_lex),
  query(0),
1472
  query_length(0)
1473
{
1474
  name.str= NULL;
1475 1476 1477 1478 1479 1480 1481 1482 1483
}

/*
  This constructor is called when statement is a subobject of THD:
  Some variables are initialized in THD::init due to locking problems
  This statement object will be used to 
*/

Statement::Statement()
1484 1485
  :Item_arena((bool)TRUE),
  id(0),
1486 1487 1488 1489
  set_query_id(1),
  allow_sum_func(0),                            /* initialized later */
  lex(&main_lex),
  query(0),                                     /* these two are set */ 
1490
  query_length(0)                               /* in alloc_query() */
1491 1492 1493 1494
{
}


1495
Item_arena::Type Statement::type() const
1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511
{
  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;
}


1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526
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);
}


1527
void THD::end_statement()
1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541
{
  /* Cleanup SQL processing state to resuse this statement in next query. */
  lex_end(lex);
  delete lex->result;
  lex->result= 0;
  free_items(free_list);
  free_list= 0;
  /*
    Don't free mem_root, as mem_root is freed in the end of dispatch_command
    (once for any command).
  */
}


1542
void Item_arena::set_n_backup_item_arena(Item_arena *set, Item_arena *backup)
1543
{
1544
  DBUG_ENTER("Item_arena::set_n_backup_item_arena");
1545
  backup->set_item_arena(this);
1546
  set_item_arena(set);
1547
  DBUG_VOID_RETURN;
1548 1549 1550
}


1551
void Item_arena::restore_backup_item_arena(Item_arena *set, Item_arena *backup)
1552
{
1553
  DBUG_ENTER("Item_arena::restore_backup_item_arena");
1554 1555
  set->set_item_arena(this);
  set_item_arena(backup);
1556 1557 1558 1559 1560 1561 1562 1563 1564 1565
#ifdef NOT_NEEDED_NOW
  /*
    Reset backup mem_root to avoid its freeing.
    Since Item_arena's mem_root is freed only when it is part of Statement
    we need this only if we use some Statement's arena as backup storage.
    But we do this only with THD::stmt_backup and this Statement is specially
    handled in this respect. So this code is not really needed now.
  */
  clear_alloc_root(&backup->mem_root);
#endif
1566
  DBUG_VOID_RETURN;
1567 1568
}

1569
void Item_arena::set_item_arena(Item_arena *set)
1570
{
1571
  mem_root=  set->mem_root;
1572
  free_list= set->free_list;
1573
  state= set->state;
1574 1575
}

1576 1577
Statement::~Statement()
{
1578
  free_root(&main_mem_root, MYF(0));
1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596
}

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

1597 1598
static byte *get_stmt_name_hash_key(Statement *entry, uint *length,
                                    my_bool not_used __attribute__((unused)))
1599 1600 1601 1602 1603
{
  *length=(uint) entry->name.length;
  return (byte*) entry->name.str;
}

1604 1605 1606 1607 1608
C_MODE_END

Statement_map::Statement_map() :
  last_found_statement(0)
{
1609 1610 1611 1612 1613
  enum
  {
    START_STMT_HASH_SIZE = 16,
    START_NAME_HASH_SIZE = 16
  };
1614
  hash_init(&st_hash, &my_charset_bin, START_STMT_HASH_SIZE, 0, 0,
1615 1616
            get_statement_id_as_hash_key,
            delete_statement_as_hash_key, MYF(0));
1617
  hash_init(&names_hash, system_charset_info, START_NAME_HASH_SIZE, 0, 0,
1618 1619
            (hash_get_key) get_stmt_name_hash_key,
            NULL,MYF(0));
1620 1621
}

1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643
/*
  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)
1644
{
1645 1646 1647 1648 1649 1650 1651 1652 1653 1654
  if (my_hash_insert(&st_hash, (byte*) statement))
  {
    /*
      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;
  }
1655 1656 1657
  if (statement->name.str)
  {
    /*
1658
      If there is a statement with the same name, remove it. It is ok to
1659 1660 1661 1662
      remove old and fail to insert new one at the same time.
    */
    Statement *old_stmt;
    if ((old_stmt= find_by_name(&statement->name)))
1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707
      erase(old_stmt);
    if (my_hash_insert(&names_hash, (byte*) statement))
    {
      my_error(ER_OUT_OF_RESOURCES, MYF(0));
      goto err_names_hash;
    }
  }
  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);
    my_error(ER_UNKNOWN_ERROR, MYF(0));
    goto err_max;
  }
  prepared_stmt_count++;
  pthread_mutex_unlock(&LOCK_prepared_stmt_count);

  last_found_statement= statement;
  return 0;

err_max:
  if (statement->name.str)
    hash_delete(&names_hash, (byte*) statement);
err_names_hash:
  hash_delete(&st_hash, (byte*) statement);
err_st_hash:
  send_error(thd);
  return 1;
}


void Statement_map::erase(Statement *statement)
{
  if (statement == last_found_statement)
    last_found_statement= 0;
  if (statement->name.str)
  {
    hash_delete(&names_hash, (byte *) statement);
1708
  }
1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727
  hash_delete(&st_hash, (byte *) statement);
  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;
1728 1729
}

1730

1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743
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);

}

1744 1745 1746 1747 1748 1749
bool select_dumpvar::send_data(List<Item> &items)
{
  List_iterator_fast<Item_func_set_user_var> li(vars);
  Item_func_set_user_var *xx;
  DBUG_ENTER("send_data");

1750 1751 1752 1753 1754
  if (unit->offset_limit_cnt)
  {				          // Using limit offset,count
    unit->offset_limit_cnt--;
    DBUG_RETURN(0);
  }
1755 1756 1757 1758 1759 1760
  if (row_count++) 
  {
    my_error(ER_TOO_MANY_ROWS, MYF(0));
    DBUG_RETURN(1);
  }
  while ((xx=li++))
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1761 1762
  {
    xx->check();
1763
    xx->update();
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1764
  }
Sinisa@sinisa.nasamreza.org's avatar
Sinisa@sinisa.nasamreza.org committed
1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780
  DBUG_RETURN(0);
}

bool select_dumpvar::send_eof()
{
  if (row_count)
  {
    ::send_ok(thd,row_count);
    return 0;
  }
  else
  {
    my_error(ER_EMPTY_QUERY,MYF(0));
    return 1;
  }
}
1781 1782 1783 1784 1785 1786 1787

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

void TMP_TABLE_PARAM::init()
{
1788 1789
  DBUG_ENTER("TMP_TABLE_PARAM::init");
  DBUG_PRINT("enter", ("this: 0x%lx", (ulong)this));
1790 1791 1792
  field_count= sum_func_count= func_count= hidden_field_count= 0;
  group_parts= group_length= group_null_parts= 0;
  quick_group= 1;
1793
  DBUG_VOID_RETURN;
1794
}