sp_head.cc 72.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/* Copyright (C) 2002 MySQL AB

   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.

   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.

   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 */

17
#include "mysql_priv.h"
18
#ifdef USE_PRAGMA_IMPLEMENTATION
19 20 21
#pragma implementation
#endif
#include "sp_head.h"
22
#include "sp.h"
23 24
#include "sp_pcontext.h"
#include "sp_rcontext.h"
25
#include "sp_cache.h"
26

27 28 29 30 31 32 33 34 35 36 37 38
Item_result
sp_map_result_type(enum enum_field_types type)
{
  switch (type)
  {
  case MYSQL_TYPE_TINY:
  case MYSQL_TYPE_SHORT:
  case MYSQL_TYPE_LONG:
  case MYSQL_TYPE_LONGLONG:
  case MYSQL_TYPE_INT24:
    return INT_RESULT;
  case MYSQL_TYPE_DECIMAL:
39 40
  case MYSQL_TYPE_NEWDECIMAL:
    return DECIMAL_RESULT;
41 42 43 44 45 46 47 48
  case MYSQL_TYPE_FLOAT:
  case MYSQL_TYPE_DOUBLE:
    return REAL_RESULT;
  default:
    return STRING_RESULT;
  }
}

49
/*
50 51 52 53 54 55 56 57 58 59 60 61 62
  SYNOPSIS
    sp_get_flags_for_command()

  DESCRIPTION
    Returns a combination of:
    * sp_head::MULTI_RESULTS: added if the 'cmd' is a command that might
      result in multiple result sets being sent back.
    * sp_head::CONTAINS_DYNAMIC_SQL: added if 'cmd' is one of PREPARE,
      EXECUTE, DEALLOCATE.
*/

uint
sp_get_flags_for_command(LEX *lex)
63
{
64 65 66 67 68 69 70 71 72 73
  uint flags;

  switch (lex->sql_command) {
  case SQLCOM_SELECT:
    if (lex->result)
    {
      flags= 0;                      /* This is a SELECT with INTO clause */
      break;
    }
    /* fallthrough */
74
  case SQLCOM_ANALYZE:
75
  case SQLCOM_CHECKSUM:
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
  case SQLCOM_HA_READ:
  case SQLCOM_SHOW_BINLOGS:
  case SQLCOM_SHOW_BINLOG_EVENTS:
  case SQLCOM_SHOW_CHARSETS:
  case SQLCOM_SHOW_COLLATIONS:
  case SQLCOM_SHOW_COLUMN_TYPES:
  case SQLCOM_SHOW_CREATE:
  case SQLCOM_SHOW_CREATE_DB:
  case SQLCOM_SHOW_CREATE_FUNC:
  case SQLCOM_SHOW_CREATE_PROC:
  case SQLCOM_SHOW_DATABASES:
  case SQLCOM_SHOW_ERRORS:
  case SQLCOM_SHOW_FIELDS:
  case SQLCOM_SHOW_GRANTS:
  case SQLCOM_SHOW_INNODB_STATUS:
  case SQLCOM_SHOW_KEYS:
  case SQLCOM_SHOW_LOGS:
  case SQLCOM_SHOW_MASTER_STAT:
94
  case SQLCOM_SHOW_MUTEX_STATUS:
95 96 97 98 99 100 101 102 103 104 105 106 107
  case SQLCOM_SHOW_NEW_MASTER:
  case SQLCOM_SHOW_OPEN_TABLES:
  case SQLCOM_SHOW_PRIVILEGES:
  case SQLCOM_SHOW_PROCESSLIST:
  case SQLCOM_SHOW_SLAVE_HOSTS:
  case SQLCOM_SHOW_SLAVE_STAT:
  case SQLCOM_SHOW_STATUS:
  case SQLCOM_SHOW_STATUS_FUNC:
  case SQLCOM_SHOW_STATUS_PROC:
  case SQLCOM_SHOW_STORAGE_ENGINES:
  case SQLCOM_SHOW_TABLES:
  case SQLCOM_SHOW_VARIABLES:
  case SQLCOM_SHOW_WARNS:
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
    flags= sp_head::MULTI_RESULTS;
    break;
  /*
    EXECUTE statement may return a result set, but doesn't have to.
    We can't, however, know it in advance, and therefore must add
    this statement here. This is ok, as is equivalent to a result-set
    statement within an IF condition.
  */
  case SQLCOM_EXECUTE:
    flags= sp_head::MULTI_RESULTS | sp_head::CONTAINS_DYNAMIC_SQL;
    break;
  case SQLCOM_PREPARE:
  case SQLCOM_DEALLOCATE_PREPARE:
    flags= sp_head::CONTAINS_DYNAMIC_SQL;
    break;
123
  default:
124 125
    flags= 0;
    break;
126
  }
127
  return flags;
128 129
}

130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150

/*
  Prepare Item for execution (call of fix_fields)

  SYNOPSIS
    sp_prepare_func_item()
    thd       thread handler
    it_addr   pointer on item refernce

  RETURN
    NULL  error
    prepared item
*/

static Item *
sp_prepare_func_item(THD* thd, Item **it_addr)
{
  Item *it= *it_addr;
  DBUG_ENTER("sp_prepare_func_item");
  it_addr= it->this_item_addr(thd, it_addr);

151
  if (!it->fixed && (*it_addr)->fix_fields(thd, it_addr))
152 153 154 155 156 157 158 159
  {
    DBUG_PRINT("info", ("fix_fields() failed"));
    DBUG_RETURN(NULL);
  }
  DBUG_RETURN(*it_addr);
}


160
/* Macro to switch arena in sp_eval_func_item */
161 162 163 164
#define CREATE_ON_CALLERS_ARENA(new_command, condition, backup_arena)   \
  do                                                                    \
  {                                                                     \
    if (condition)                                                      \
konstantin@mysql.com's avatar
konstantin@mysql.com committed
165 166
      thd->set_n_backup_active_arena(thd->spcont->callers_arena,        \
                                     backup_arena);                     \
167 168
    new_command;                                                        \
    if (condition)                                                      \
konstantin@mysql.com's avatar
konstantin@mysql.com committed
169 170
      thd->restore_active_arena(thd->spcont->callers_arena,             \
                                backup_arena);                          \
171
  } while(0)
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191

/*
  Evaluate an item and store it in the returned item

  SYNOPSIS
    sp_eval_func_item()
      name                  - current thread object
      it_addr               - pointer to the item to evaluate
      type                  - type of the item we evaluating
      reuse                 - used if we would like to reuse existing item
                              instead of allocation of the new one
      use_callers_arena     - TRUE if we want to use caller's arena
                              rather then current one.
  DESCRIPTION
   We use this function to evaluate result for stored functions
   and stored procedure parameters. It is also used to evaluate and
   (re) allocate variables.

  RETURN VALUES
    Evaluated item is returned
192
*/
193

194
Item *
195
sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type,
196
		  Item *reuse, bool use_callers_arena)
197
{
198
  DBUG_ENTER("sp_eval_func_item");
199
  Item *it= sp_prepare_func_item(thd, it_addr);
200
  uint rsize;
konstantin@mysql.com's avatar
konstantin@mysql.com committed
201
  Query_arena backup_arena;
202
  DBUG_PRINT("info", ("type: %d", type));
203

204
  if (!it)
205
  {
206
    DBUG_RETURN(NULL);
207
  }
208

209 210
  switch (sp_map_result_type(type)) {
  case INT_RESULT:
211 212
  {
    longlong i= it->val_int();
213

214 215 216 217
    if (it->null_value)
    {
      DBUG_PRINT("info", ("INT_RESULT: null"));
      goto return_null_item;
218
    }
219 220
    DBUG_PRINT("info", ("INT_RESULT: %d", i));
    CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize) Item_int(i),
konstantin@mysql.com's avatar
konstantin@mysql.com committed
221
                            use_callers_arena, &backup_arena);
222 223
    break;
  }
224
  case REAL_RESULT:
225 226 227 228
  {
    double d= it->val_real();
    uint8 decimals;
    uint32 max_length;
229

230 231 232 233
    if (it->null_value)
    {
      DBUG_PRINT("info", ("REAL_RESULT: null"));
      goto return_null_item;
234
    }
235 236 237 238 239 240 241 242 243

    /*
      There's some difference between Item::new_item() and the
      constructor; the former crashes, the latter works... weird.
    */
    decimals= it->decimals;
    max_length= it->max_length;
    DBUG_PRINT("info", ("REAL_RESULT: %g", d));
    CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize) Item_float(d),
konstantin@mysql.com's avatar
konstantin@mysql.com committed
244
                            use_callers_arena, &backup_arena);
245 246 247 248
    it->decimals= decimals;
    it->max_length= max_length;
    break;
  }
249
  case DECIMAL_RESULT:
250 251 252 253 254
  {
    my_decimal value, *val= it->val_decimal(&value);
    if (it->null_value)
      goto return_null_item;
    CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize) Item_decimal(val),
konstantin@mysql.com's avatar
konstantin@mysql.com committed
255
                            use_callers_arena, &backup_arena);
256
#ifndef DBUG_OFF
257
    {
258
      char dbug_buff[DECIMAL_MAX_STR_LENGTH+1];
259 260
      DBUG_PRINT("info", ("DECIMAL_RESULT: %s",
                          dbug_decimal_as_string(dbug_buff, val)));
261
    }
262
#endif
263 264
    break;
  }
265
  case STRING_RESULT:
266 267 268 269
  {
    char buffer[MAX_FIELD_WIDTH];
    String tmp(buffer, sizeof(buffer), it->collation.collation);
    String *s= it->val_str(&tmp);
270

271 272 273 274
    if (type == MYSQL_TYPE_NULL || it->null_value)
    {
      DBUG_PRINT("info", ("STRING_RESULT: null"));
      goto return_null_item;
275
    }
276 277
    DBUG_PRINT("info",("STRING_RESULT: %*s",
                       s->length(), s->c_ptr_quick()));
278 279 280 281 282 283 284 285 286 287 288 289 290
    /*
      Reuse mechanism in sp_eval_func_item() is only employed for assignments
      to local variables and OUT/INOUT SP parameters repsesented by
      Item_splocal. Usually we have some expression, which needs
      to be calculated and stored into the local variable. However in the
      case if "it" equals to "reuse", there is no "calculation" step. So,
      no reason to employ reuse mechanism to save variable into itself.
    */
    if (it == reuse)
      DBUG_RETURN(it);

    CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize)
                            Item_string(it->collation.collation),
konstantin@mysql.com's avatar
konstantin@mysql.com committed
291
                            use_callers_arena, &backup_arena);
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
    /*
      We have to use special constructor and allocate string
      on system heap here. This is because usual Item_string
      constructor would allocate memory in the callers arena.
      This would lead to the memory leak in SP loops.
      See Bug #11333 "Stored Procedure: Memory blow up on
      repeated SELECT ... INTO query" for sample of such SP.
      TODO: Usage of the system heap gives significant overhead,
      however usual "reuse" mechanism does not work here, as
      Item_string has no max size. That is, if we have a loop, which
      has string variable with constantly increasing size, we would have
      to allocate new pieces of memory again and again on each iteration.
      In future we should probably reserve some area of memory for
      not-very-large strings and reuse it. But for large strings
      we would have to use system heap anyway.
    */
    ((Item_string*) it)->set_str_with_copy(s->ptr(), s->length());
309 310
    break;
  }
311 312 313
  case ROW_RESULT:
  default:
    DBUG_ASSERT(0);
314
  }
315
  it->rsize= rsize;
316

317 318 319 320
  DBUG_RETURN(it);

return_null_item:
  CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize) Item_null(),
konstantin@mysql.com's avatar
konstantin@mysql.com committed
321
                    use_callers_arena, &backup_arena);
322 323
  it->rsize= rsize;

324
  DBUG_RETURN(it);
325 326
}

327 328 329 330 331 332 333 334 335 336

/*
 *
 *  sp_name
 *
 */

void
sp_name::init_qname(THD *thd)
{
337 338 339 340 341
  m_sroutines_key.length=  m_db.length + m_name.length + 2;
  if (!(m_sroutines_key.str= thd->alloc(m_sroutines_key.length + 1)))
    return;
  m_qname.length= m_sroutines_key.length - 1;
  m_qname.str= m_sroutines_key.str + 1;
342 343 344 345 346
  sprintf(m_qname.str, "%*s.%*s",
	  m_db.length, (m_db.length ? m_db.str : ""),
	  m_name.length, m_name.str);
}

347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366
sp_name *
sp_name_current_db_new(THD *thd, LEX_STRING name)
{
  sp_name *qname;

  if (! thd->db)
    qname= new sp_name(name);
  else
  {
    LEX_STRING db;

    db.length= strlen(thd->db);
    db.str= thd->strmake(thd->db, db.length);
    qname= new sp_name(db, name);
  }
  qname->init_qname(thd);
  return qname;
}


367 368 369 370 371 372 373 374 375
/* ------------------------------------------------------------------ */


/*
 *
 *  sp_head
 *
 */

376 377 378 379 380 381 382 383
void *
sp_head::operator new(size_t size)
{
  DBUG_ENTER("sp_head::operator new");
  MEM_ROOT own_root;
  sp_head *sp;

  init_alloc_root(&own_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
monty@mysql.com's avatar
monty@mysql.com committed
384 385
  sp= (sp_head *) alloc_root(&own_root, size);
  sp->main_mem_root= own_root;
386
  DBUG_PRINT("info", ("mem_root 0x%lx", (ulong) &sp->mem_root));
387 388 389 390 391 392 393 394
  DBUG_RETURN(sp);
}

void 
sp_head::operator delete(void *ptr, size_t size)
{
  DBUG_ENTER("sp_head::operator delete");
  MEM_ROOT own_root;
monty@mysql.com's avatar
monty@mysql.com committed
395
  sp_head *sp= (sp_head *) ptr;
396

monty@mysql.com's avatar
monty@mysql.com committed
397 398
  /* Make a copy of main_mem_root as free_root will free the sp */
  own_root= sp->main_mem_root;
399 400
  DBUG_PRINT("info", ("mem_root 0x%lx moved to 0x%lx",
                      (ulong) &sp->mem_root, (ulong) &own_root));
401 402 403 404 405
  free_root(&own_root, MYF(0));

  DBUG_VOID_RETURN;
}

406

407
sp_head::sp_head()
408
  :Query_arena(&main_mem_root, INITIALIZED_FOR_SP),
409
   m_flags(0), m_returns_cs(NULL)
410
{
411 412
  extern byte *
    sp_table_key(const byte *ptr, uint *plen, my_bool first);
413
  DBUG_ENTER("sp_head::sp_head");
414 415 416

  m_backpatch.empty();
  m_lex.empty();
417
  hash_init(&m_sptabs, system_charset_info, 0, 0, 0, sp_table_key, 0, 0);
418
  hash_init(&m_sroutines, system_charset_info, 0, 0, 0, sp_sroutine_key, 0, 0);
419 420 421
  DBUG_VOID_RETURN;
}

422

423
void
424
sp_head::init(LEX *lex)
425 426
{
  DBUG_ENTER("sp_head::init");
427

428
  lex->spcont= m_pcont= new sp_pcontext(NULL);
429 430 431 432 433
  /*
    Altough trg_table_fields list is used only in triggers we init for all
    types of stored procedures to simplify reset_lex()/restore_lex() code.
  */
  lex->trg_table_fields.empty();
434
  my_init_dynamic_array(&m_instr, sizeof(sp_instr *), 16, 8);
435 436
  m_param_begin= m_param_end= m_body_begin= 0;
  m_qname.str= m_db.str= m_name.str= m_params.str= 
437 438
    m_body.str= m_defstr.str= 0;
  m_qname.length= m_db.length= m_name.length= m_params.length=
439
    m_body.length= m_defstr.length= 0;
440
  m_returns_cs= NULL;
441 442 443 444
  DBUG_VOID_RETURN;
}

void
445
sp_head::init_strings(THD *thd, LEX *lex, sp_name *name)
446 447
{
  DBUG_ENTER("sp_head::init_strings");
448
  uint n;			/* Counter for nul trimming */ 
449
  /* During parsing, we must use thd->mem_root */
monty@mysql.com's avatar
monty@mysql.com committed
450
  MEM_ROOT *root= thd->mem_root;
451

452
  /* We have to copy strings to get them into the right memroot */
453 454
  if (name)
  {
455
    m_db.length= name->m_db.length;
456
    if (name->m_db.length == 0)
457
      m_db.str= NULL;
458 459 460 461 462 463 464 465 466 467
    else
      m_db.str= strmake_root(root, name->m_db.str, name->m_db.length);
    m_name.length= name->m_name.length;
    m_name.str= strmake_root(root, name->m_name.str, name->m_name.length);

    if (name->m_qname.length == 0)
      name->init_qname(thd);
    m_qname.length= name->m_qname.length;
    m_qname.str= strmake_root(root, name->m_qname.str, m_qname.length);
  }
468
  else if (thd->db)
469
  {
470
    m_db.length= thd->db_length;
471
    m_db.str= strmake_root(root, thd->db, m_db.length);
472
  }
473

474
  if (m_param_begin && m_param_end)
475
  {
476 477 478
    m_params.length= m_param_end - m_param_begin;
    m_params.str= strmake_root(root,
                               (char *)m_param_begin, m_params.length);
479
  }
480

481 482 483 484 485 486 487 488
  m_body.length= lex->ptr - m_body_begin;
  /* Trim nuls at the end */
  n= 0;
  while (m_body.length && m_body_begin[m_body.length-1] == '\0')
  {
    m_body.length-= 1;
    n+= 1;
  }
489
  m_body.str= strmake_root(root, (char *)m_body_begin, m_body.length);
490 491
  m_defstr.length= lex->ptr - lex->buf;
  m_defstr.length-= n;
492
  m_defstr.str= strmake_root(root, (char *)lex->buf, m_defstr.length);
493
  DBUG_VOID_RETURN;
494 495
}

496 497 498 499
TYPELIB *
sp_head::create_typelib(List<String> *src)
{
  TYPELIB *result= NULL;
500
  CHARSET_INFO *cs= m_returns_cs;
501 502 503 504 505 506 507
  DBUG_ENTER("sp_head::clone_typelib");
  if (src->elements)
  {
    result= (TYPELIB*) alloc_root(mem_root, sizeof(TYPELIB));
    result->count= src->elements;
    result->name= "";
    if (!(result->type_names=(const char **)
508
          alloc_root(mem_root,(sizeof(char *)+sizeof(int))*(result->count+1))))
509
      return 0;
510
    result->type_lengths= (unsigned int *)(result->type_names + result->count+1);
511
    List_iterator<String> it(*src);
512 513
    String conv;
    for (uint i=0; i < result->count; i++)
514
    {
515 516 517 518
      uint32 dummy;
      uint length;
      String *tmp= it++;

519 520 521 522 523
      if (String::needs_conversion(tmp->length(), tmp->charset(),
      				   cs, &dummy))
      {
        uint cnv_errs;
        conv.copy(tmp->ptr(), tmp->length(), tmp->charset(), cs, &cnv_errs);
524 525 526 527

        length= conv.length();
        result->type_names[i]= (char*) strmake_root(mem_root, conv.ptr(),
                                                    length);
528
      }
529 530 531 532
      else
      {
        length= tmp->length();
        result->type_names[i]= strmake_root(mem_root, tmp->ptr(), length);
533
      }
534 535

      // Strip trailing spaces.
536 537 538
      length= cs->cset->lengthsp(cs, result->type_names[i], length);
      result->type_lengths[i]= length;
      ((uchar *)result->type_names[i])[length]= '\0';
539
    }
540
    result->type_names[result->count]= 0;
541
    result->type_lengths[result->count]= 0;
542 543 544 545
  }
  return result;
}

546 547 548
int
sp_head::create(THD *thd)
{
549
  DBUG_ENTER("sp_head::create");
550 551
  int ret;

552 553
  DBUG_PRINT("info", ("type: %d name: %s params: %s body: %s",
		      m_type, m_name.str, m_params.str, m_body.str));
554

555
#ifndef DBUG_OFF
556
  optimize();
557
  {
558 559 560 561 562 563
    String s;
    sp_instr *i;
    uint ip= 0;
    while ((i = get_instr(ip)))
    {
      char buf[8];
564

565 566 567 568 569 570 571 572
      sprintf(buf, "%4u: ", ip);
      s.append(buf);
      i->print(&s);
      s.append('\n');
      ip+= 1;
    }
    s.append('\0');
    DBUG_PRINT("info", ("Code %s\n%s", m_qname.str, s.ptr()));
573 574 575
  }
#endif

576
  if (m_type == TYPE_ENUM_FUNCTION)
577
    ret= sp_create_function(thd, this);
578
  else
579
    ret= sp_create_procedure(thd, this);
580

581
  DBUG_RETURN(ret);
582 583
}

584 585 586 587 588 589 590
sp_head::~sp_head()
{
  destroy();
  if (m_thd)
    restore_thd_mem_root(m_thd);
}

591 592 593
void
sp_head::destroy()
{
594 595
  sp_instr *i;
  LEX *lex;
596 597
  DBUG_ENTER("sp_head::destroy");
  DBUG_PRINT("info", ("name: %s", m_name.str));
598 599 600

  for (uint ip = 0 ; (i = get_instr(ip)) ; ip++)
    delete i;
601 602
  delete_dynamic(&m_instr);
  m_pcont->destroy();
603
  free_items();
604 605 606 607 608 609 610 611 612 613

  /*
    If we have non-empty LEX stack then we just came out of parser with
    error. Now we should delete all auxilary LEXes and restore original
    THD::lex (In this case sp_head::restore_thd_mem_root() was not called
    too, so m_thd points to the current thread context).
    It is safe to not update LEX::ptr because further query string parsing
    and execution will be stopped anyway.
  */
  DBUG_ASSERT(m_lex.is_empty() || m_thd);
614 615
  while ((lex= (LEX *)m_lex.pop()))
  {
616 617
    delete m_thd->lex;
    m_thd->lex= lex;
618
  }
619

620
  hash_free(&m_sptabs);
621
  hash_free(&m_sroutines);
622
  DBUG_VOID_RETURN;
623
}
624

625

626
/*
627 628 629 630
  This is only used for result fields from functions (both during
  fix_length_and_dec() and evaluation).
*/

631 632 633 634 635
Field *
sp_head::make_field(uint max_length, const char *name, TABLE *dummy)
{
  Field *field;
  DBUG_ENTER("sp_head::make_field");
636

637 638 639
  field= ::make_field((char *)0,
		!m_returns_len ? max_length : m_returns_len, 
		(uchar *)"", 0, m_returns_pack, m_returns, m_returns_cs,
640
		m_geom_returns, Field::NONE, 
641 642 643 644 645
		m_returns_typelib,
		name ? name : (const char *)m_name.str, dummy);
  DBUG_RETURN(field);
}

646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691

int cmp_splocal_locations(Item_splocal * const *a, Item_splocal * const *b)
{
  return (int)((*a)->pos_in_query - (*b)->pos_in_query);
}


/*
  StoredRoutinesBinlogging
  Top-down overview:

  1. Statements

  Statements that have is_update_query(stmt) == TRUE are written into the
  binary log verbatim.
  Examples:
    UPDATE tbl SET tbl.x = spfunc_w_side_effects()
    UPDATE tbl SET tbl.x=1 WHERE spfunc_w_side_effect_that_returns_false(tbl.y)

  Statements that have is_update_query(stmt) == FALSE (e.g. SELECTs) are not
  written into binary log. Instead we catch function calls the statement
  makes and write it into binary log separately (see #3).
  
  We actually can easily write SELECT statements into the binary log in the 
  right order (we don't have issues with const tables being unlocked early
  because SELECTs that use FUNCTIONs unlock all tables at once) We don't do 
  it because replication slave thread currently can't execute SELECT
  statements. Fixing this is on the TODO.
  
  2. PROCEDURE calls

  CALL statements are not written into binary log. Instead
  * Any FUNCTION invocation (in SET, IF, WHILE, OPEN CURSOR and other SP
    instructions) is written into binlog separately.

  * Each statement executed in SP is binlogged separately, according to rules
    in #1, with the exception that we modify query string: we replace uses
    of SP local variables with NAME_CONST('spvar_name', <spvar-value>) calls.
    This substitution is done in subst_spvars().

  3. FUNCTION calls
  
  In sp_head::execute_function(), we check 
   * If this function invocation is done from a statement that is written
     into the binary log.
   * If there were any attempts to write events to the binary log during
692 693
     function execution (grep for start_union_events and stop_union_events)

694 695
   If the answers are No and Yes, we write the function call into the binary
   log as "DO spfunc(<param1value>, <param2value>, ...)"
696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720
  
  
  4. Miscellaneous issues.
  
  4.1 User variables. 

  When we call mysql_bin_log.write() for an SP statement, thd->user_var_events
  must hold set<{var_name, value}> pairs for all user variables used during 
  the statement execution.
  This set is produced by tracking user variable reads during statement
  execution. 

  Fo SPs, this has the following implications:
  1) thd->user_var_events may contain events from several SP statements and 
     needs to be valid after exection of these statements was finished. In 
     order to achieve that, we
     * Allocate user_var_events array elements on appropriate mem_root (grep
       for user_var_events_alloc).
     * Use is_query_in_union() to determine if user_var_event is created.
     
  2) We need to empty thd->user_var_events after we have wrote a function
     call. This is currently done by making 
     reset_dynamic(&thd->user_var_events);
     calls in several different places. (TODO cosider moving this into
     mysql_bin_log.write() function)
721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739
*/


/*
  Replace thd->query{_length} with a string that one can write to the binlog.
 
  SYNOPSIS
    subst_spvars()
      thd        Current thread. 
      instr      Instruction (we look for Item_splocal instances in
                 instr->free_list)
      query_str  Original query string
     
  DESCRIPTION

  The binlog-suitable string is produced by replacing references to SP local 
  variables with NAME_CONST('sp_var_name', value) calls.
 
  RETURN
740
    0  Ok, thd->query{_length} either has been appropriately replaced or
741 742 743 744 745 746 747 748 749 750
       there is no need for replacements.
    1  Out of memory error.
*/

static bool subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str)
{
  DBUG_ENTER("subst_spvars");
  if (thd->prelocked_mode == NON_PRELOCKED && mysql_bin_log.is_open())
  {
    Dynamic_array<Item_splocal*> sp_vars_uses;
751 752 753
    char *pbuf, *cur, buffer[512];
    String qbuf(buffer, sizeof(buffer), &my_charset_bin);
    int prev_pos, res;
754 755 756 757

    /* Find all instances of item_splocal used in this statement */
    for (Item *item= instr->free_list; item; item= item->next)
    {
758 759 760 761 762 763
      if (item->is_splocal())
      {
        Item_splocal *item_spl= (Item_splocal*)item;
        if (item_spl->pos_in_query)
          sp_vars_uses.append(item_spl);
      }
764 765 766 767 768 769 770 771 772 773 774 775
    }
    if (!sp_vars_uses.elements())
      DBUG_RETURN(0);
      
    /* Sort SP var refs by their occurences in the query */
    sp_vars_uses.sort(cmp_splocal_locations);

    /* 
      Construct a statement string where SP local var refs are replaced
      with "NAME_CONST(name, value)"
    */
    qbuf.length(0);
776 777
    cur= query_str->str;
    prev_pos= res= 0;
778 779 780
    for (Item_splocal **splocal= sp_vars_uses.front(); 
         splocal < sp_vars_uses.back(); splocal++)
    {
781
      Item *val;
782
      /* append the text between sp ref occurences */
783
      res|= qbuf.append(cur + prev_pos, (*splocal)->pos_in_query - prev_pos);
784 785 786
      prev_pos= (*splocal)->pos_in_query + (*splocal)->m_name.length;
      
      /* append the spvar substitute */
787 788 789 790
      res|= qbuf.append(" NAME_CONST('");
      res|= qbuf.append((*splocal)->m_name.str, (*splocal)->m_name.length);
      res|= qbuf.append("',");
      val= (*splocal)->this_item();
791 792
      DBUG_PRINT("info", ("print %p", val));
      val->print(&qbuf);
793
      res|= qbuf.append(')');
794 795 796
      if (res)
        break;
    }
797
    res|= qbuf.append(cur + prev_pos, query_str->length - prev_pos);
798 799 800
    if (res)
      DBUG_RETURN(1);

801
    if (!(pbuf= thd->strmake(qbuf.ptr(), qbuf.length())))
802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820
      DBUG_RETURN(1);

    thd->query= pbuf;
    thd->query_length= qbuf.length();
  }
  DBUG_RETURN(0);
}


/*
  Execute the routine. The main instruction jump loop is there 
  Assume the parameters already set.
  
  RETURN
    -1  on error

*/

int sp_head::execute(THD *thd)
821
{
822
  DBUG_ENTER("sp_head::execute");
823
  char olddb[128];
824
  bool dbchanged;
825
  sp_rcontext *ctx;
826
  int ret= 0;
827
  uint ip= 0;
828
  ulong save_sql_mode;
serg@serg.mylan's avatar
serg@serg.mylan committed
829
  Query_arena *old_arena;
830 831 832
  /* per-instruction arena */
  MEM_ROOT execute_mem_root;
  Query_arena execute_arena(&execute_mem_root, INITIALIZED_FOR_SP),
konstantin@mysql.com's avatar
konstantin@mysql.com committed
833
              backup_arena;
834
  query_id_t old_query_id;
835 836 837 838
  TABLE *old_derived_tables;
  LEX *old_lex;
  Item_change_list old_change_list;
  String old_packet;
839

840 841 842 843
  /* init per-instruction memroot */
  init_alloc_root(&execute_mem_root, MEM_ROOT_BLOCK_SIZE, 0);


844
  /* Use some extra margin for possible SP recursion and functions */
845
  if (check_stack_overrun(thd, 4*STACK_MIN_SIZE, olddb))
846 847 848
  {
    DBUG_RETURN(-1);
  }
849

850
  if (m_flags & IS_INVOKED)
851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869
  {
    /*
      We have to disable recursion for stored routines since in
      many cases LEX structure and many Item's can't be used in
      reentrant way now.

      TODO: We can circumvent this problem by using separate
      sp_head instances for each recursive invocation.

      NOTE: Theoretically arguments of procedure can be evaluated
      before its invocation so there should be no problem with
      recursion. But since we perform cleanup for CALL statement
      as for any other statement only after its execution, its LEX
      structure is not reusable for recursive calls. Thus we have
      to prohibit recursion for stored procedures too.
    */
    my_error(ER_SP_NO_RECURSION, MYF(0));
    DBUG_RETURN(-1);
  }
870
  m_flags|= IS_INVOKED;
871

872
  dbchanged= FALSE;
873 874
  if (m_db.length &&
      (ret= sp_use_new_db(thd, m_db.str, olddb, sizeof(olddb), 0, &dbchanged)))
875
    goto done;
876

877
  if ((ctx= thd->spcont))
878
    ctx->clear_handler();
879
  thd->query_error= 0;
konstantin@mysql.com's avatar
konstantin@mysql.com committed
880
  old_arena= thd->stmt_arena;
881

882 883 884 885 886 887 888
  /*
    We have to save/restore this info when we are changing call level to
    be able properly do close_thread_tables() in instructions.
  */
  old_query_id= thd->query_id;
  old_derived_tables= thd->derived_tables;
  thd->derived_tables= 0;
889 890
  save_sql_mode= thd->variables.sql_mode;
  thd->variables.sql_mode= m_sql_mode;
891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911
  /*
    It is also more efficient to save/restore current thd->lex once when
    do it in each instruction
  */
  old_lex= thd->lex;
  /*
    We should also save Item tree change list to avoid rollback something
    too early in the calling query.
  */
  old_change_list= thd->change_list;
  thd->change_list.empty();
  /*
    Cursors will use thd->packet, so they may corrupt data which was prepared
    for sending by upper level. OTOH cursors in the same routine can share this
    buffer safely so let use use routine-local packet instead of having own
    packet buffer for each cursor.

    It is probably safe to use same thd->convert_buff everywhere.
  */
  old_packet.swap(thd->packet);

912 913 914 915
  /*
    Switch to per-instruction arena here. We can do it since we cleanup
    arena after every instruction.
  */
konstantin@mysql.com's avatar
konstantin@mysql.com committed
916
  thd->set_n_backup_active_arena(&execute_arena, &backup_arena);
917 918 919 920 921

  /*
    Save callers arena in order to store instruction results and out
    parameters in it later during sp_eval_func_item()
  */
konstantin@mysql.com's avatar
konstantin@mysql.com committed
922
  thd->spcont->callers_arena= &backup_arena;
923

924 925 926
  do
  {
    sp_instr *i;
927
    uint hip;			// Handler ip
928 929 930 931 932

    i = get_instr(ip);	// Returns NULL when we're done.
    if (i == NULL)
      break;
    DBUG_PRINT("execute", ("Instruction %u", ip));
933 934 935
    /* Don't change NOW() in FUNCTION or TRIGGER */
    if (!thd->in_sub_stmt)
      thd->set_time();		// Make current_time() et al work
936
    
937
    /*
konstantin@mysql.com's avatar
konstantin@mysql.com committed
938
      We have to set thd->stmt_arena before executing the instruction
939 940 941 942
      to store in the instruction free_list all new items, created
      during the first execution (for example expanding of '*' or the
      items made during other permanent subquery transformations).
    */
konstantin@mysql.com's avatar
konstantin@mysql.com committed
943
    thd->stmt_arena= i;
944
    
945 946 947 948 949
    /* 
      Will write this SP statement into binlog separately 
      (TODO: consider changing the condition to "not inside event union")
    */
    if (thd->prelocked_mode == NON_PRELOCKED)
950 951
      thd->user_var_events_alloc= thd->mem_root;
    
952
    ret= i->execute(thd, &ip);
953

954
    /*
955 956 957
      If this SP instruction have sent eof, it has caused no_send_error to be
      set. Clear it back to allow the next instruction to send error. (multi-
      statement execution code clears no_send_error between statements too)
958 959
    */
    thd->net.no_send_error= 0;
960 961
    if (i->free_list)
      cleanup_items(i->free_list);
962
    i->state= Query_arena::EXECUTED;
963 964 965 966 967 968 969 970 971 972
    
    /* 
      If we've set thd->user_var_events_alloc to mem_root of this SP
      statement, clean all the events allocated in it.
    */
    if (thd->prelocked_mode == NON_PRELOCKED)
    {
      reset_dynamic(&thd->user_var_events);
      thd->user_var_events_alloc= NULL;//DEBUG
    }
973

974 975
    /* we should cleanup free_list and memroot, used by instruction */
    thd->free_items();
976
    free_root(&execute_mem_root, MYF(0));    
977

978 979 980 981 982 983 984 985
    /*
      Check if an exception has occurred and a handler has been found
      Note: We havo to check even if ret==0, since warnings (and some
      errors don't return a non-zero value.
      We also have to check even if thd->killed != 0, since some
      errors return with this even when a handler has been found
      (e.g. "bad data").
    */
986
    if (ctx)
987 988 989
    {
      uint hf;

990
      switch (ctx->found_handler(&hip, &hf)) {
991 992 993
      case SP_HANDLER_NONE:
	break;
      case SP_HANDLER_CONTINUE:
konstantin@mysql.com's avatar
konstantin@mysql.com committed
994
        thd->restore_active_arena(&execute_arena, &backup_arena);
995
        ctx->save_variables(hf);
konstantin@mysql.com's avatar
konstantin@mysql.com committed
996
        thd->set_n_backup_active_arena(&execute_arena, &backup_arena);
997
        ctx->push_hstack(ip);
998
        // Fall through
999 1000 1001 1002
      default:
	ip= hip;
	ret= 0;
	ctx->clear_handler();
1003
	ctx->in_handler= TRUE;
1004
        thd->clear_error();
1005
	thd->killed= THD::NOT_KILLED;
1006 1007 1008
	continue;
      }
    }
1009
  } while (ret == 0 && !thd->killed);
1010

konstantin@mysql.com's avatar
konstantin@mysql.com committed
1011
  thd->restore_active_arena(&execute_arena, &backup_arena);
1012 1013


1014 1015 1016 1017 1018 1019 1020 1021 1022 1023
  /* Restore all saved */
  old_packet.swap(thd->packet);
  DBUG_ASSERT(thd->change_list.is_empty());
  thd->change_list= old_change_list;
  /* To avoid wiping out thd->change_list on old_change_list destruction */
  old_change_list.empty();
  thd->lex= old_lex;
  thd->query_id= old_query_id;
  DBUG_ASSERT(!thd->derived_tables);
  thd->derived_tables= old_derived_tables;
1024
  thd->variables.sql_mode= save_sql_mode;
1025

konstantin@mysql.com's avatar
konstantin@mysql.com committed
1026
  thd->stmt_arena= old_arena;
1027
  state= EXECUTED;
1028

1029
 done:
1030 1031
  DBUG_PRINT("info", ("ret=%d killed=%d query_error=%d",
		      ret, thd->killed, thd->query_error));
1032

1033
  if (thd->killed)
1034
    ret= -1;
1035 1036
  /* If the DB has changed, the pointer has changed too, but the
     original thd->db will then have been freed */
1037
  if (dbchanged)
1038
  {
1039
    if (! thd->killed)
jimw@mysql.com's avatar
jimw@mysql.com committed
1040
      ret= mysql_change_db(thd, olddb, 0);
1041
  }
1042
  m_flags&= ~IS_INVOKED;
1043 1044 1045 1046
  DBUG_RETURN(ret);
}


1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065
/*
  Execute a function:
   - evaluate parameters
   - call sp_head::execute
   - evaluate the return value

  SYNOPSIS
    sp_head::execute_function()
      thd        Thread handle
      argp       Passed arguments (these are items from containing statement?)
      argcount   Number of passed arguments. We need to check if this is
                 correct.
      resp   OUT Put result item here (q: is it a constant Item always?) 
   
  RETURN
    0      on OK
    other  on error
*/

1066 1067 1068
int
sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp)
{
1069 1070 1071
  Item **param_values;
  ulonglong binlog_save_options;
  bool need_binlog_call;
1072
  DBUG_ENTER("sp_head::execute_function");
1073
  DBUG_PRINT("info", ("function %s", m_name.str));
1074 1075 1076 1077
  uint csize = m_pcont->max_pvars();
  uint params = m_pcont->current_pvars();
  uint hmax = m_pcont->max_handlers();
  uint cmax = m_pcont->max_cursors();
1078 1079 1080
  sp_rcontext *octx = thd->spcont;
  sp_rcontext *nctx = NULL;
  uint i;
1081
  int ret= -1;                                  // Assume error
1082

1083 1084
  if (argcount != params)
  {
1085
    /*
1086
      Need to use my_error here, or it will not terminate the
1087 1088
      invoking query properly.
    */
1089
    my_error(ER_SP_WRONG_NO_OF_ARGS, MYF(0),
1090
             "FUNCTION", m_qname.str, params, argcount);
1091
    goto end;
1092 1093
  }

1094 1095
  if (!(param_values= (Item**)thd->alloc(sizeof(Item*)*argcount)))
    DBUG_RETURN(-1);
1096

1097
  // QQ Should have some error checking here? (types, etc...)
1098 1099
  if (!(nctx= new sp_rcontext(csize, hmax, cmax)))
    goto end;
1100
  for (i= 0 ; i < argcount ; i++)
1101
  {
1102
    sp_pvar_t *pvar = m_pcont->find_pvar(i);
1103
    Item *it= sp_eval_func_item(thd, argp++, pvar->type, NULL, FALSE);
1104
    param_values[i]= it;
1105

1106 1107 1108
    if (!it)
      goto end;                                 // EOM error
    nctx->push_item(it);
1109
  }
1110

1111

1112 1113
  /*
    The rest of the frame are local variables which are all IN.
1114 1115
    Push NULLs to get the right size (and make the reuse mechanism work) -
    the will be initialized by set instructions in each frame.
1116
  */
1117
  for (; i < csize ; i++)
1118 1119
    nctx->push_item(NULL);

1120 1121
  thd->spcont= nctx;

1122 1123 1124
  binlog_save_options= thd->options;
  need_binlog_call= mysql_bin_log.is_open() && (thd->options & OPTION_BIN_LOG);
  if (need_binlog_call)
1125 1126
  {
    reset_dynamic(&thd->user_var_events);
1127
    mysql_bin_log.start_union_events(thd);
1128
  }
1129 1130
    
  thd->options&= ~OPTION_BIN_LOG;
1131
  ret= execute(thd);
1132 1133 1134 1135 1136
  thd->options= binlog_save_options;
  
  if (need_binlog_call)
    mysql_bin_log.stop_union_events(thd);

1137
  if (need_binlog_call && thd->binlog_evt_union.unioned_events)
1138
  {
1139
    char buf[256];
1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152
    String bufstr(buf, sizeof(buf), &my_charset_bin);
    bufstr.length(0);
    bufstr.append("DO ", 3);
    append_identifier(thd, &bufstr, m_name.str, m_name.length);
    bufstr.append('(');
    for (uint i=0; i < argcount; i++)
    {
      if (i)
        bufstr.append(',');
      param_values[i]->print(&bufstr);
    }
    bufstr.append(')');
    
1153 1154 1155 1156
    Query_log_event qinfo(thd, bufstr.ptr(), bufstr.length(),
                          thd->binlog_evt_union.unioned_events_trans, FALSE);
    if (mysql_bin_log.write(&qinfo) && 
        thd->binlog_evt_union.unioned_events_trans)
1157
    {
1158 1159 1160
      push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
                   "Invoked ROUTINE modified a transactional table but MySQL "
                   "failed to reflect this change in the binary log");
1161
    }
1162
    reset_dynamic(&thd->user_var_events);
1163
  }
1164 1165

  if (m_type == TYPE_ENUM_FUNCTION && ret == 0)
1166
  {
1167
    /* We need result only in function but not in trigger */
1168 1169 1170
    Item *it= nctx->get_result();

    if (it)
1171
      *resp= sp_eval_func_item(thd, &it, m_returns, NULL, FALSE);
1172 1173
    else
    {
1174
      my_error(ER_SP_NORETURNEND, MYF(0), m_name.str);
1175 1176 1177
      ret= -1;
    }
  }
1178

1179
  nctx->pop_all_cursors();	// To avoid memory leaks after an error
1180
  delete nctx;                                  // Doesn't do anything
1181
  thd->spcont= octx;
1182

1183
end:
1184 1185 1186
  DBUG_RETURN(ret);
}

1187 1188

static Item_func_get_user_var *item_is_user_var(Item *it)
1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199
{
  if (it->type() == Item::FUNC_ITEM)
  {
    Item_func *fi= static_cast<Item_func*>(it);

    if (fi->functype() == Item_func::GUSERVAR_FUNC)
      return static_cast<Item_func_get_user_var*>(fi);
  }
  return NULL;
}

1200

1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219
/*
  Execute a procedure. 
  SYNOPSIS
    sp_head::execute_procedure()
      thd    Thread handle
      args   List of values passed as arguments.
      
  DESCRIPTION

  The function does the following steps:
   - Set all parameters 
   - call sp_head::execute
   - copy back values of INOUT and OUT parameters

  RETURN
    0   Ok
    -1  Error
*/

1220
int sp_head::execute_procedure(THD *thd, List<Item> *args)
1221
{
1222
  int ret= 0;
1223 1224 1225 1226
  uint csize = m_pcont->max_pvars();
  uint params = m_pcont->current_pvars();
  uint hmax = m_pcont->max_handlers();
  uint cmax = m_pcont->max_cursors();
1227
  sp_rcontext *save_spcont, *octx;
1228
  sp_rcontext *nctx = NULL;
1229 1230
  DBUG_ENTER("sp_head::execute_procedure");
  DBUG_PRINT("info", ("procedure %s", m_name.str));
1231

1232 1233
  if (args->elements != params)
  {
1234
    my_error(ER_SP_WRONG_NO_OF_ARGS, MYF(0), "PROCEDURE",
1235
             m_qname.str, params, args->elements);
1236 1237 1238
    DBUG_RETURN(-1);
  }

1239
  save_spcont= octx= thd->spcont;
1240 1241
  if (! octx)
  {				// Create a temporary old context
1242 1243
    if (!(octx= new sp_rcontext(csize, hmax, cmax)))
      DBUG_RETURN(-1);
1244 1245 1246 1247 1248 1249
    thd->spcont= octx;

    /* set callers_arena to thd, for upper-level function to work */
    thd->spcont->callers_arena= thd;
  }

1250 1251 1252 1253 1254
  if (!(nctx= new sp_rcontext(csize, hmax, cmax)))
  {
    thd->spcont= save_spcont;
    DBUG_RETURN(-1);
  }
1255

1256
  if (csize > 0 || hmax > 0 || cmax > 0)
1257
  {
1258
    Item_null *nit= NULL;	// Re-use this, and only create if needed
1259
    uint i;
1260
    List_iterator<Item> li(*args);
1261
    Item *it;
1262

1263
    /* Evaluate SP arguments (i.e. get the values passed as parameters) */
1264
    // QQ: Should do type checking?
1265
    DBUG_PRINT("info",(" %.*s: eval args", m_name.length, m_name.str));
1266 1267
    for (i = 0 ; (it= li++) && i < params ; i++)
    {
1268
      sp_pvar_t *pvar= m_pcont->find_pvar(i);
1269

1270
      if (pvar)
1271
      {
1272 1273 1274 1275 1276 1277 1278 1279 1280
	if (pvar->mode != sp_param_in)
	{
	  if (!it->is_splocal() && !item_is_user_var(it))
	  {
	    my_error(ER_SP_NOT_VAR_ARG, MYF(0), i+1, m_qname.str);
	    ret= -1;
	    break;
	  }
	}
1281
	if (pvar->mode == sp_param_out)
1282 1283
	{
	  if (! nit)
1284 1285 1286 1287 1288 1289 1290
          {
	    if (!(nit= new Item_null()))
            {
              ret= -1;
              break;
            }
          }
1291 1292
	  nctx->push_item(nit); // OUT
	}
1293
	else
1294
	{
1295
	  Item *it2= sp_eval_func_item(thd, li.ref(), pvar->type, NULL, FALSE);
1296

1297
	  if (!it2)
1298 1299 1300 1301
	  {
	    ret= -1;		// Eval failed
	    break;
	  }
1302
          nctx->push_item(it2); // IN or INOUT
1303
	}
1304
      }
1305
    }
1306

1307 1308
    /* 
      Okay, got values for all arguments. Close tables that might be used by 
1309 1310
      arguments evaluation. If arguments evaluation required prelocking mode, 
      we'll leave it here.
1311 1312
    */
    if (!thd->in_sub_stmt)
1313
      close_thread_tables(thd, 0, 0);
1314 1315

    DBUG_PRINT("info",(" %.*s: eval args done", m_name.length, m_name.str));
1316

1317 1318
    /*
      The rest of the frame are local variables which are all IN.
1319 1320
      Push NULLs to get the right size (and make the reuse mechanism work) -
      the will be initialized by set instructions in each frame.
1321
    */
1322
    for (; i < csize ; i++)
1323
      nctx->push_item(NULL);
1324 1325
  }

1326 1327
  thd->spcont= nctx;

1328 1329
  if (! ret)
    ret= execute(thd);
1330 1331 1332 1333 1334 1335 1336 1337

  /*
    In the case when we weren't able to employ reuse mechanism for
    OUT/INOUT paranmeters, we should reallocate memory. This
    allocation should be done on the arena which will live through
    all execution of calling routine.
  */
  thd->spcont->callers_arena= octx->callers_arena;
1338

1339
  if (!ret && csize > 0)
1340
  {
1341
    List_iterator<Item> li(*args);
1342
    Item *it;
1343

1344 1345 1346 1347
    /*
      Copy back all OUT or INOUT values to the previous frame, or
      set global user variables
    */
1348
    for (uint i = 0 ; (it= li++) && i < params ; i++)
1349
    {
1350
      sp_pvar_t *pvar= m_pcont->find_pvar(i);
1351

1352
      if (pvar->mode != sp_param_in)
1353
      {
1354
	if (it->is_splocal())
1355 1356 1357 1358 1359 1360 1361
	{
	  // Have to copy the item to the caller's mem_root
	  Item *copy;
	  uint offset= static_cast<Item_splocal *>(it)->get_offset();
	  Item *val= nctx->get_item(i);
	  Item *orig= octx->get_item(offset);
	  Item *o_item_next;
1362 1363 1364
          /* we'll use callers_arena in sp_eval_func_item */
	  Item *o_free_list= thd->spcont->callers_arena->free_list;

1365 1366 1367 1368
	  LINT_INIT(o_item_next);

	  if (orig)
	    o_item_next= orig->next;
1369 1370 1371 1372 1373 1374 1375

          /*
            We might need to allocate new item if we weren't able to
            employ reuse mechanism. Then we should do it on the callers arena.
          */
	  copy= sp_eval_func_item(thd, &val, pvar->type, orig, TRUE); // Copy

1376 1377 1378 1379 1380 1381 1382 1383 1384
	  if (!copy)
	  {
	    ret= -1;
	    break;
	  }
	  if (copy != orig)
	    octx->set_item(offset, copy);
	  if (orig && copy == orig)
	  {
1385 1386 1387 1388
	    /*
              A reused item slot, where the constructor put it in the
              free_list, so we have to restore the list.
            */
1389
	    thd->spcont->callers_arena->free_list= o_free_list;
1390 1391 1392
	    copy->next= o_item_next;
	  }
	}
1393
	else
1394
	{
1395 1396 1397
	  Item_func_get_user_var *guv= item_is_user_var(it);

	  if (guv)
1398
	  {
1399 1400 1401 1402 1403 1404 1405 1406
	    Item *item= nctx->get_item(i);
	    Item_func_set_user_var *suv;

	    suv= new Item_func_set_user_var(guv->get_name(), item);
	    /*
	      we do not check suv->fixed, because it can't be fixed after
	      creation
	    */
1407
	    suv->fix_fields(thd, &item);
1408 1409 1410
	    suv->fix_length_and_dec();
	    suv->check();
	    suv->update();
1411
	  }
1412 1413
	}
      }
1414 1415 1416
    }
  }

1417 1418
  if (!save_spcont)
    delete octx;                                // Does nothing
1419

1420
  nctx->pop_all_cursors();	// To avoid memory leaks after an error
1421 1422
  delete nctx;                                  // Does nothing
  thd->spcont= save_spcont;
1423

1424
  DBUG_RETURN(ret);
1425 1426 1427
}


1428
// Reset lex during parsing, before we parse a sub statement.
1429 1430 1431
void
sp_head::reset_lex(THD *thd)
{
1432 1433
  DBUG_ENTER("sp_head::reset_lex");
  LEX *sublex;
1434
  LEX *oldlex= thd->lex;
1435
  my_lex_states state= oldlex->next_state; // Keep original next_state
1436

1437
  (void)m_lex.push_front(oldlex);
1438
  thd->lex= sublex= new st_lex;
serg@serg.mylan's avatar
serg@serg.mylan committed
1439

1440
  /* Reset most stuff. The length arguments doesn't matter here. */
monty@mysql.com's avatar
monty@mysql.com committed
1441
  lex_start(thd, oldlex->buf, (ulong) (oldlex->end_of_query - oldlex->ptr));
serg@serg.mylan's avatar
serg@serg.mylan committed
1442

1443 1444 1445 1446 1447
  /*
   * next_state is normally the same (0), but it happens that we swap lex in
   * "mid-sentence", so we must restore it.
   */
  sublex->next_state= state;
1448
  /* We must reset ptr and end_of_query again */
1449 1450 1451
  sublex->ptr= oldlex->ptr;
  sublex->end_of_query= oldlex->end_of_query;
  sublex->tok_start= oldlex->tok_start;
serg@serg.mylan's avatar
serg@serg.mylan committed
1452
  sublex->yylineno= oldlex->yylineno;
1453
  /* And keep the SP stuff too */
1454 1455
  sublex->sphead= oldlex->sphead;
  sublex->spcont= oldlex->spcont;
1456 1457
  /* And trigger related stuff too */
  sublex->trg_chistics= oldlex->trg_chistics;
1458
  sublex->trg_table_fields.empty();
1459
  sublex->sp_lex_in_use= FALSE;
1460
  DBUG_VOID_RETURN;
1461 1462
}

1463
// Restore lex during parsing, after we have parsed a sub statement.
1464 1465 1466
void
sp_head::restore_lex(THD *thd)
{
1467 1468
  DBUG_ENTER("sp_head::restore_lex");
  LEX *sublex= thd->lex;
1469 1470 1471 1472
  LEX *oldlex= (LEX *)m_lex.pop();

  if (! oldlex)
    return;			// Nothing to restore
1473

1474
  // Update some state in the old one first
1475 1476
  oldlex->ptr= sublex->ptr;
  oldlex->next_state= sublex->next_state;
1477
  oldlex->trg_table_fields.push_back(&sublex->trg_table_fields);
1478

1479
  /*
1480 1481
    Add routines which are used by statement to respective set for
    this routine.
1482
  */
1483
  sp_update_sp_used_routines(&m_sroutines, &sublex->sroutines);
1484 1485 1486 1487 1488
  /*
    Merge tables used by this statement (but not by its functions or
    procedures) to multiset of tables used by this routine.
  */
  merge_table_list(thd, sublex->query_tables, sublex);
1489 1490 1491
  if (! sublex->sp_lex_in_use)
    delete sublex;
  thd->lex= oldlex;
1492
  DBUG_VOID_RETURN;
1493 1494
}

1495
void
1496
sp_head::push_backpatch(sp_instr *i, sp_label_t *lab)
1497
{
1498
  bp_t *bp= (bp_t *)sql_alloc(sizeof(bp_t));
1499 1500 1501 1502 1503 1504 1505

  if (bp)
  {
    bp->lab= lab;
    bp->instr= i;
    (void)m_backpatch.push_front(bp);
  }
1506 1507 1508
}

void
1509
sp_head::backpatch(sp_label_t *lab)
1510
{
1511
  bp_t *bp;
1512
  uint dest= instructions();
1513
  List_iterator_fast<bp_t> li(m_backpatch);
1514

1515
  while ((bp= li++))
1516 1517 1518 1519
  {
    if (bp->lab == lab ||
	(bp->lab->type == SP_LAB_REF &&
	 my_strcasecmp(system_charset_info, bp->lab->name, lab->name) == 0))
1520
    {
1521 1522 1523 1524 1525
      if (bp->lab->type != SP_LAB_REF)
	bp->instr->backpatch(dest, lab->ctx);
      else
      {
	sp_label_t *dstlab= bp->lab->ctx->find_label(lab->name);
1526

1527 1528 1529 1530 1531 1532
	if (dstlab)
	{
	  bp->lab= lab;
	  bp->instr->backpatch(dest, dstlab->ctx);
	}
      }
1533 1534 1535 1536 1537 1538 1539 1540 1541
    }
  }
}

int
sp_head::check_backpatch(THD *thd)
{
  bp_t *bp;
  List_iterator_fast<bp_t> li(m_backpatch);
1542

1543 1544 1545 1546
  while ((bp= li++))
  {
    if (bp->lab->type == SP_LAB_REF)
    {
1547
      my_error(ER_SP_LILABEL_MISMATCH, MYF(0), "GOTO", bp->lab->name);
1548
      return -1;
1549
    }
1550 1551
  }
  return 0;
1552 1553
}

1554 1555 1556
void
sp_head::set_info(char *definer, uint definerlen,
		  longlong created, longlong modified,
1557
		  st_sp_chistics *chistics, ulong sql_mode)
1558 1559 1560 1561 1562 1563 1564
{
  char *p= strchr(definer, '@');
  uint len;

  if (! p)
    p= definer;		// Weird...
  len= p-definer;
monty@mysql.com's avatar
monty@mysql.com committed
1565
  m_definer_user.str= strmake_root(mem_root, definer, len);
1566 1567
  m_definer_user.length= len;
  len= definerlen-len-1;
monty@mysql.com's avatar
monty@mysql.com committed
1568
  m_definer_host.str= strmake_root(mem_root, p+1, len);
1569 1570 1571
  m_definer_host.length= len;
  m_created= created;
  m_modified= modified;
monty@mysql.com's avatar
monty@mysql.com committed
1572 1573
  m_chistics= (st_sp_chistics *) memdup_root(mem_root, (char*) chistics,
                                             sizeof(*chistics));
1574 1575 1576
  if (m_chistics->comment.length == 0)
    m_chistics->comment.str= 0;
  else
monty@mysql.com's avatar
monty@mysql.com committed
1577
    m_chistics->comment.str= strmake_root(mem_root,
1578 1579
					  m_chistics->comment.str,
					  m_chistics->comment.length);
1580
  m_sql_mode= sql_mode;
1581 1582
}

1583 1584 1585
void
sp_head::reset_thd_mem_root(THD *thd)
{
1586
  DBUG_ENTER("sp_head::reset_thd_mem_root");
1587
  m_thd_root= thd->mem_root;
monty@mysql.com's avatar
monty@mysql.com committed
1588
  thd->mem_root= &main_mem_root;
1589 1590 1591
  DBUG_PRINT("info", ("mem_root 0x%lx moved to thd mem root 0x%lx",
                      (ulong) &mem_root, (ulong) &thd->mem_root));
  free_list= thd->free_list; // Keep the old list
1592 1593 1594
  thd->free_list= NULL;	// Start a new one
  /* Copy the db, since substatements will point to it */
  m_thd_db= thd->db;
monty@mysql.com's avatar
monty@mysql.com committed
1595
  thd->db= thd->strmake(thd->db, thd->db_length);
1596
  m_thd= thd;
1597
  DBUG_VOID_RETURN;
1598 1599 1600 1601 1602
}

void
sp_head::restore_thd_mem_root(THD *thd)
{
1603 1604
  DBUG_ENTER("sp_head::restore_thd_mem_root");
  Item *flist= free_list;	// The old list
konstantin@mysql.com's avatar
konstantin@mysql.com committed
1605
  set_query_arena(thd);         // Get new free_list and mem_root
1606
  state= INITIALIZED_FOR_SP;
1607

1608 1609
  DBUG_PRINT("info", ("mem_root 0x%lx returned from thd mem root 0x%lx",
                      (ulong) &mem_root, (ulong) &thd->mem_root));
1610 1611 1612 1613
  thd->free_list= flist;	// Restore the old one
  thd->db= m_thd_db;		// Restore the original db pointer
  thd->mem_root= m_thd_root;
  m_thd= NULL;
1614
  DBUG_VOID_RETURN;
1615 1616 1617
}


1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632
/*
  Check if a user has access right to a routine

  SYNOPSIS
    check_show_routine_access()
    thd			Thread handler
    sp			SP
    full_access		Set to 1 if the user has SELECT right to the
			'mysql.proc' able or is the owner of the routine
  RETURN
    0  ok
    1  error
*/

bool check_show_routine_access(THD *thd, sp_head *sp, bool *full_access)
1633 1634 1635 1636 1637
{
  TABLE_LIST tables;
  bzero((char*) &tables,sizeof(tables));
  tables.db= (char*) "mysql";
  tables.table_name= tables.alias= (char*) "proc";
1638 1639 1640 1641
  *full_access= (!check_table_access(thd, SELECT_ACL, &tables, 1) ||
                 (!strcmp(sp->m_definer_user.str, thd->priv_user) &&
                  !strcmp(sp->m_definer_host.str, thd->priv_host)));
  if (!*full_access)
1642 1643
    return check_some_routine_access(thd, sp->m_db.str, sp->m_name.str,
                                     sp->m_type == TYPE_ENUM_PROCEDURE);
1644 1645 1646 1647
  return 0;
}


1648 1649 1650 1651 1652 1653 1654 1655
int
sp_head::show_create_procedure(THD *thd)
{
  Protocol *protocol= thd->protocol;
  char buff[2048];
  String buffer(buff, sizeof(buff), system_charset_info);
  int res;
  List<Item> field_list;
1656 1657
  byte *sql_mode_str;
  ulong sql_mode_len;
1658
  bool full_access;
1659 1660 1661

  DBUG_ENTER("sp_head::show_create_procedure");
  DBUG_PRINT("info", ("procedure %s", m_name.str));
1662 1663
  LINT_INIT(sql_mode_str);
  LINT_INIT(sql_mode_len);
1664

1665
  if (check_show_routine_access(thd, this, &full_access))
1666
    return 1;
1667

1668 1669 1670 1671
  sql_mode_str=
    sys_var_thd_sql_mode::symbolic_mode_representation(thd,
                                                       m_sql_mode,
                                                       &sql_mode_len);
1672
  field_list.push_back(new Item_empty_string("Procedure", NAME_LEN));
1673
  field_list.push_back(new Item_empty_string("sql_mode", sql_mode_len));
1674 1675
  // 1024 is for not to confuse old clients
  field_list.push_back(new Item_empty_string("Create Procedure",
1676
					     max(buffer.length(), 1024)));
1677 1678
  if (protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS |
                                         Protocol::SEND_EOF))
1679 1680 1681 1682
  {
    res= 1;
    goto done;
  }
1683 1684
  protocol->prepare_for_resend();
  protocol->store(m_name.str, m_name.length, system_charset_info);
1685
  protocol->store((char*) sql_mode_str, sql_mode_len, system_charset_info);
1686 1687
  if (full_access)
    protocol->store(m_defstr.str, m_defstr.length, system_charset_info);
1688 1689
  res= protocol->write();
  send_eof(thd);
1690 1691

 done:
1692 1693 1694
  DBUG_RETURN(res);
}

1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707

/*
  Add instruction to SP

  SYNOPSIS
    sp_head::add_instr()
    instr   Instruction
*/

void sp_head::add_instr(sp_instr *instr)
{
  instr->free_list= m_thd->free_list;
  m_thd->free_list= 0;
1708 1709 1710 1711 1712 1713 1714
  /*
    Memory root of every instruction is designated for permanent
    transformations (optimizations) made on the parsed tree during
    the first execution. It points to the memory root of the
    entire stored procedure, as their life span is equal.
  */
  instr->mem_root= &main_mem_root;
1715 1716 1717 1718
  insert_dynamic(&m_instr, (gptr)&instr);
}


1719 1720 1721 1722 1723 1724 1725 1726
int
sp_head::show_create_function(THD *thd)
{
  Protocol *protocol= thd->protocol;
  char buff[2048];
  String buffer(buff, sizeof(buff), system_charset_info);
  int res;
  List<Item> field_list;
1727 1728
  byte *sql_mode_str;
  ulong sql_mode_len;
1729
  bool full_access;
1730 1731
  DBUG_ENTER("sp_head::show_create_function");
  DBUG_PRINT("info", ("procedure %s", m_name.str));
1732 1733
  LINT_INIT(sql_mode_str);
  LINT_INIT(sql_mode_len);
1734

1735
  if (check_show_routine_access(thd, this, &full_access))
1736 1737
    return 1;

1738 1739 1740 1741
  sql_mode_str=
    sys_var_thd_sql_mode::symbolic_mode_representation(thd,
                                                       m_sql_mode,
                                                       &sql_mode_len);
1742
  field_list.push_back(new Item_empty_string("Function",NAME_LEN));
1743
  field_list.push_back(new Item_empty_string("sql_mode", sql_mode_len));
1744 1745
  field_list.push_back(new Item_empty_string("Create Function",
					     max(buffer.length(),1024)));
1746 1747
  if (protocol->send_fields(&field_list,
                            Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
1748 1749 1750 1751
  {
    res= 1;
    goto done;
  }
1752 1753
  protocol->prepare_for_resend();
  protocol->store(m_name.str, m_name.length, system_charset_info);
1754
  protocol->store((char*) sql_mode_str, sql_mode_len, system_charset_info);
1755 1756
  if (full_access)
    protocol->store(m_defstr.str, m_defstr.length, system_charset_info);
1757 1758
  res= protocol->write();
  send_eof(thd);
1759 1760

 done:
1761 1762
  DBUG_RETURN(res);
}
1763

1764 1765 1766 1767 1768 1769

/*
  TODO: what does this do??
*/

void sp_head::optimize()
1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818
{
  List<sp_instr> bp;
  sp_instr *i;
  uint src, dst;

  opt_mark(0);

  bp.empty();
  src= dst= 0;
  while ((i= get_instr(src)))
  {
    if (! i->marked)
    {
      delete i;
      src+= 1;
    }
    else
    {
      if (src != dst)
      {
	sp_instr *ibp;
	List_iterator_fast<sp_instr> li(bp);

	set_dynamic(&m_instr, (gptr)&i, dst);
	while ((ibp= li++))
	{
	  sp_instr_jump *ji= static_cast<sp_instr_jump *>(ibp);
	  if (ji->m_dest == src)
	    ji->m_dest= dst;
	}
      }
      i->opt_move(dst, &bp);
      src+= 1;
      dst+= 1;
    }
  }
  m_instr.elements= dst;
  bp.empty();
}

void
sp_head::opt_mark(uint ip)
{
  sp_instr *i;

  while ((i= get_instr(ip)) && !i->marked)
    ip= i->opt_mark(this);
}

1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859

/*
  Prepare LEX and thread for execution of instruction, if requested open
  and lock LEX's tables, execute instruction's core function, perform
  cleanup afterwards.

  SYNOPSIS
    reset_lex_and_exec_core()
      thd         - thread context
      nextp       - out - next instruction
      open_tables - if TRUE then check read access to tables in LEX's table
                    list and open and lock them (used in instructions which
                    need to calculate some expression and don't execute
                    complete statement).
      sp_instr    - instruction for which we prepare context, and which core
                    function execute by calling its exec_core() method.

  NOTE
    We are not saving/restoring some parts of THD which may need this because
    we do this once for whole routine execution in sp_head::execute().

  RETURN VALUE
    0/non-0 - Success/Failure
*/

int
sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
                                       bool open_tables, sp_instr* instr)
{
  int res= 0;

  DBUG_ASSERT(!thd->derived_tables);
  DBUG_ASSERT(thd->change_list.is_empty());
  /*
    Use our own lex.
    We should not save old value since it is saved/restored in
    sp_head::execute() when we are entering/leaving routine.
  */
  thd->lex= m_lex;

  VOID(pthread_mutex_lock(&LOCK_thread_count));
1860
  thd->query_id= next_query_id();
1861 1862
  VOID(pthread_mutex_unlock(&LOCK_thread_count));

1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882
  if (thd->prelocked_mode == NON_PRELOCKED)
  {
    /*
      This statement will enter/leave prelocked mode on its own.
      Entering prelocked mode changes table list and related members
      of LEX, so we'll need to restore them.
    */
    if (lex_query_tables_own_last)
    {
      /*
        We've already entered/left prelocked mode with this statement.
        Attach the list of tables that need to be prelocked and mark m_lex
        as having such list attached.
      */
      *lex_query_tables_own_last= prelocking_tables;
      m_lex->mark_as_requiring_prelocking(lex_query_tables_own_last);
    }
  }
    
  reinit_stmt_before_use(thd, m_lex);
1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898
  /*
    If requested check whenever we have access to tables in LEX's table list
    and open and lock them before executing instructtions core function.
  */
  if (open_tables &&
      (check_table_access(thd, SELECT_ACL, m_lex->query_tables, 0) ||
       open_and_lock_tables(thd, m_lex->query_tables)))
      res= -1;

  if (!res)
    res= instr->exec_core(thd, nextp);

  m_lex->unit.cleanup();

  thd->proc_info="closing tables";
  close_thread_tables(thd);
1899
  thd->proc_info= 0;
1900

1901
  if (m_lex->query_tables_own_last)
1902
  {
1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919
    /*
      We've entered and left prelocking mode when executing statement
      stored in m_lex. 
      m_lex->query_tables(->next_global)* list now has a 'tail' - a list
      of tables that are added for prelocking. (If this is the first
      execution, the 'tail' was added by open_tables(), otherwise we've
      attached it above in this function).
      Now we'll save the 'tail', and detach it.
    */
    DBUG_ASSERT(!lex_query_tables_own_last ||
                lex_query_tables_own_last == m_lex->query_tables_own_last &&
                prelocking_tables == *(m_lex->query_tables_own_last));

    lex_query_tables_own_last= m_lex->query_tables_own_last;
    prelocking_tables= *lex_query_tables_own_last;
    *lex_query_tables_own_last= NULL;
    m_lex->mark_as_requiring_prelocking(NULL);
1920
  }
1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935
  thd->rollback_item_tree_changes();

  /*
    Unlike for PS we should not call Item's destructors for newly created
    items after execution of each instruction in stored routine. This is
    because SP often create Item (like Item_int, Item_string etc...) when
    they want to store some value in local variable, pass return value and
    etc... So their life time should be longer than one instruction.

    cleanup_items() is called in sp_head::execute()
  */
  return res;
}


1936 1937 1938 1939
/*
  sp_instr class functions
*/

1940
int sp_instr::exec_core(THD *thd, uint *nextp)
1941
{
1942 1943
  DBUG_ASSERT(0);
  return 0;
1944 1945
}

1946 1947 1948 1949
/*
  sp_instr_stmt class functions
*/

1950
int
1951
sp_instr_stmt::execute(THD *thd, uint *nextp)
1952
{
1953 1954
  char *query;
  uint32 query_length;
1955
  int res;
1956
  DBUG_ENTER("sp_instr_stmt::execute");
1957
  DBUG_PRINT("info", ("command: %d", m_lex_keeper.sql_command()));
1958 1959 1960

  query= thd->query;
  query_length= thd->query_length;
1961 1962
  if (!(res= alloc_query(thd, m_query.str, m_query.length+1)) &&
      !(res=subst_spvars(thd, this, &m_query)))
1963
  {
1964 1965 1966 1967
    /*
      (the order of query cache and subst_spvars calls is irrelevant because
      queries with SP vars can't be cached)
    */
1968 1969 1970
    if (query_cache_send_result_to_client(thd,
					  thd->query, thd->query_length) <= 0)
    {
1971
      res= m_lex_keeper.reset_lex_and_exec_core(thd, nextp, FALSE, this);
1972 1973
      query_cache_end_of_result(thd);
    }
1974 1975
    else
      *nextp= m_ip+1;
1976 1977 1978
    thd->query= query;
    thd->query_length= query_length;
  }
1979 1980 1981
  DBUG_RETURN(res);
}

1982 1983 1984 1985 1986
void
sp_instr_stmt::print(String *str)
{
  str->reserve(12);
  str->append("stmt ");
1987
  str->qs_append((uint)m_lex_keeper.sql_command());
1988 1989 1990
}


1991
int
1992
sp_instr_stmt::exec_core(THD *thd, uint *nextp)
1993
{
1994 1995
  int res= mysql_execute_command(thd);
  *nextp= m_ip+1;
1996
  return res;
1997 1998
}

1999 2000 2001 2002 2003

/*
  sp_instr_set class functions
*/

2004
int
2005
sp_instr_set::execute(THD *thd, uint *nextp)
2006
{
2007 2008
  DBUG_ENTER("sp_instr_set::execute");
  DBUG_PRINT("info", ("offset: %u", m_offset));
2009 2010 2011 2012

  DBUG_RETURN(m_lex_keeper.reset_lex_and_exec_core(thd, nextp, TRUE, this));
}

2013

2014 2015 2016
int
sp_instr_set::exec_core(THD *thd, uint *nextp)
{
2017
  int res= thd->spcont->set_item_eval(thd, m_offset, &m_value, m_type);
2018

2019
  *nextp = m_ip+1;
2020
  return res;
2021 2022
}

2023 2024 2025 2026 2027 2028 2029 2030 2031 2032
void
sp_instr_set::print(String *str)
{
  str->reserve(12);
  str->append("set ");
  str->qs_append(m_offset);
  str->append(' ');
  m_value->print(str);
}

2033

2034 2035 2036 2037
/*
  sp_instr_set_trigger_field class functions
*/

2038 2039 2040 2041
int
sp_instr_set_trigger_field::execute(THD *thd, uint *nextp)
{
  DBUG_ENTER("sp_instr_set_trigger_field::execute");
2042 2043 2044 2045 2046 2047 2048 2049 2050 2051
  DBUG_RETURN(m_lex_keeper.reset_lex_and_exec_core(thd, nextp, TRUE, this));
}


int
sp_instr_set_trigger_field::exec_core(THD *thd, uint *nextp)
{
  int res= 0;
  Item *it= sp_prepare_func_item(thd, &value);
  if (!it ||
2052
      !trigger_field->fixed && trigger_field->fix_fields(thd, 0) ||
2053
      (it->save_in_field(trigger_field->field, 0) < 0))
2054
    res= -1;
2055 2056
  *nextp = m_ip+1;
  return res;
2057 2058 2059 2060 2061 2062
}

void
sp_instr_set_trigger_field::print(String *str)
{
  str->append("set ", 4);
2063
  trigger_field->print(str);
2064 2065 2066 2067
  str->append(":=", 2);
  value->print(str);
}

2068 2069 2070 2071 2072

/*
 sp_instr_jump class functions
*/

2073 2074 2075 2076 2077 2078 2079 2080 2081 2082
int
sp_instr_jump::execute(THD *thd, uint *nextp)
{
  DBUG_ENTER("sp_instr_jump::execute");
  DBUG_PRINT("info", ("destination: %u", m_dest));

  *nextp= m_dest;
  DBUG_RETURN(0);
}

2083 2084 2085 2086 2087 2088 2089 2090
void
sp_instr_jump::print(String *str)
{
  str->reserve(12);
  str->append("jump ");
  str->qs_append(m_dest);
}

2091 2092 2093
uint
sp_instr_jump::opt_mark(sp_head *sp)
{
2094
  m_dest= opt_shortcut_jump(sp, this);
2095 2096
  if (m_dest != m_ip+1)		/* Jumping to following instruction? */
    marked= 1;
2097 2098 2099 2100 2101
  m_optdest= sp->get_instr(m_dest);
  return m_dest;
}

uint
2102
sp_instr_jump::opt_shortcut_jump(sp_head *sp, sp_instr *start)
2103 2104 2105 2106 2107 2108
{
  uint dest= m_dest;
  sp_instr *i;

  while ((i= sp->get_instr(dest)))
  {
2109
    uint ndest;
2110

2111
    if (start == i || this == i)
2112 2113
      break;
    ndest= i->opt_shortcut_jump(sp, start);
2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130
    if (ndest == dest)
      break;
    dest= ndest;
  }
  return dest;
}

void
sp_instr_jump::opt_move(uint dst, List<sp_instr> *bp)
{
  if (m_dest > m_ip)
    bp->push_back(this);	// Forward
  else if (m_optdest)
    m_dest= m_optdest->m_ip;	// Backward
  m_ip= dst;
}

2131 2132 2133 2134

/*
  sp_instr_jump_if class functions
*/
2135

2136 2137 2138
int
sp_instr_jump_if::execute(THD *thd, uint *nextp)
{
2139 2140
  DBUG_ENTER("sp_instr_jump_if::execute");
  DBUG_PRINT("info", ("destination: %u", m_dest));
2141 2142 2143 2144 2145 2146
  DBUG_RETURN(m_lex_keeper.reset_lex_and_exec_core(thd, nextp, TRUE, this));
}

int
sp_instr_jump_if::exec_core(THD *thd, uint *nextp)
{
2147 2148
  Item *it;
  int res;
2149

2150
  it= sp_prepare_func_item(thd, &m_expr);
2151 2152
  if (!it)
    res= -1;
2153
  else
2154 2155
  {
    res= 0;
2156
    if (it->val_bool())
2157 2158 2159 2160
      *nextp = m_dest;
    else
      *nextp = m_ip+1;
  }
2161 2162

  return res;
2163 2164
}

2165 2166 2167 2168 2169 2170 2171 2172 2173 2174
void
sp_instr_jump_if::print(String *str)
{
  str->reserve(12);
  str->append("jump_if ");
  str->qs_append(m_dest);
  str->append(' ');
  m_expr->print(str);
}

2175 2176 2177 2178 2179 2180 2181 2182
uint
sp_instr_jump_if::opt_mark(sp_head *sp)
{
  sp_instr *i;

  marked= 1;
  if ((i= sp->get_instr(m_dest)))
  {
2183
    m_dest= i->opt_shortcut_jump(sp, this);
2184 2185 2186 2187 2188 2189
    m_optdest= sp->get_instr(m_dest);
  }
  sp->opt_mark(m_dest);
  return m_ip+1;
}

2190 2191 2192 2193 2194

/*
  sp_instr_jump_if_not class functions
*/

2195 2196 2197
int
sp_instr_jump_if_not::execute(THD *thd, uint *nextp)
{
2198 2199
  DBUG_ENTER("sp_instr_jump_if_not::execute");
  DBUG_PRINT("info", ("destination: %u", m_dest));
2200 2201 2202 2203 2204 2205 2206
  DBUG_RETURN(m_lex_keeper.reset_lex_and_exec_core(thd, nextp, TRUE, this));
}


int
sp_instr_jump_if_not::exec_core(THD *thd, uint *nextp)
{
2207 2208
  Item *it;
  int res;
2209

2210
  it= sp_prepare_func_item(thd, &m_expr);
2211 2212
  if (! it)
    res= -1;
2213
  else
2214 2215
  {
    res= 0;
2216
    if (! it->val_bool())
2217 2218 2219 2220
      *nextp = m_dest;
    else
      *nextp = m_ip+1;
  }
2221 2222

  return res;
2223
}
2224

2225

2226 2227 2228 2229 2230 2231 2232 2233 2234 2235
void
sp_instr_jump_if_not::print(String *str)
{
  str->reserve(16);
  str->append("jump_if_not ");
  str->qs_append(m_dest);
  str->append(' ');
  m_expr->print(str);
}

2236

2237 2238 2239 2240 2241 2242 2243 2244
uint
sp_instr_jump_if_not::opt_mark(sp_head *sp)
{
  sp_instr *i;

  marked= 1;
  if ((i= sp->get_instr(m_dest)))
  {
2245
    m_dest= i->opt_shortcut_jump(sp, this);
2246 2247 2248 2249 2250 2251
    m_optdest= sp->get_instr(m_dest);
  }
  sp->opt_mark(m_dest);
  return m_ip+1;
}

2252 2253 2254 2255

/*
  sp_instr_freturn class functions
*/
2256

2257
int
2258
sp_instr_freturn::execute(THD *thd, uint *nextp)
2259
{
2260
  DBUG_ENTER("sp_instr_freturn::execute");
2261 2262 2263 2264 2265 2266 2267
  DBUG_RETURN(m_lex_keeper.reset_lex_and_exec_core(thd, nextp, TRUE, this));
}


int
sp_instr_freturn::exec_core(THD *thd, uint *nextp)
{
2268 2269
  Item *it;
  int res;
2270

2271
  it= sp_eval_func_item(thd, &m_value, m_type, NULL, TRUE);
2272 2273 2274 2275 2276 2277 2278
  if (! it)
    res= -1;
  else
  {
    res= 0;
    thd->spcont->set_result(it);
  }
2279
  *nextp= UINT_MAX;
2280 2281

  return res;
2282
}
2283

2284 2285 2286 2287 2288
void
sp_instr_freturn::print(String *str)
{
  str->reserve(12);
  str->append("freturn ");
2289
  str->qs_append((uint)m_type);
2290 2291 2292 2293
  str->append(' ');
  m_value->print(str);
}

2294 2295 2296 2297
/*
  sp_instr_hpush_jump class functions
*/

2298 2299 2300 2301 2302 2303 2304 2305
int
sp_instr_hpush_jump::execute(THD *thd, uint *nextp)
{
  DBUG_ENTER("sp_instr_hpush_jump::execute");
  List_iterator_fast<sp_cond_type_t> li(m_cond);
  sp_cond_type_t *p;

  while ((p= li++))
2306
    thd->spcont->push_handler(p, m_ip+1, m_type, m_frame);
2307 2308 2309 2310 2311

  *nextp= m_dest;
  DBUG_RETURN(0);
}

2312 2313 2314 2315 2316
void
sp_instr_hpush_jump::print(String *str)
{
  str->reserve(32);
  str->append("hpush_jump ");
2317 2318
  str->qs_append(m_dest);
  str->append(" t=");
2319
  str->qs_append(m_type);
2320
  str->append(" f=");
2321
  str->qs_append(m_frame);
2322
  str->append(" h=");
2323
  str->qs_append(m_ip+1);
2324 2325
}

2326 2327 2328 2329 2330 2331 2332 2333
uint
sp_instr_hpush_jump::opt_mark(sp_head *sp)
{
  sp_instr *i;

  marked= 1;
  if ((i= sp->get_instr(m_dest)))
  {
2334
    m_dest= i->opt_shortcut_jump(sp, this);
2335 2336 2337 2338 2339 2340
    m_optdest= sp->get_instr(m_dest);
  }
  sp->opt_mark(m_dest);
  return m_ip+1;
}

2341 2342 2343 2344 2345

/*
  sp_instr_hpop class functions
*/

2346 2347 2348 2349 2350 2351 2352 2353 2354
int
sp_instr_hpop::execute(THD *thd, uint *nextp)
{
  DBUG_ENTER("sp_instr_hpop::execute");
  thd->spcont->pop_handlers(m_count);
  *nextp= m_ip+1;
  DBUG_RETURN(0);
}

2355 2356 2357 2358 2359 2360 2361 2362
void
sp_instr_hpop::print(String *str)
{
  str->reserve(12);
  str->append("hpop ");
  str->qs_append(m_count);
}

2363 2364 2365 2366 2367 2368 2369
void
sp_instr_hpop::backpatch(uint dest, sp_pcontext *dst_ctx)
{
  m_count= m_ctx->diff_handlers(dst_ctx);
}


2370 2371 2372 2373
/*
  sp_instr_hreturn class functions
*/

2374 2375 2376 2377
int
sp_instr_hreturn::execute(THD *thd, uint *nextp)
{
  DBUG_ENTER("sp_instr_hreturn::execute");
2378 2379 2380 2381 2382 2383 2384 2385
  if (m_dest)
    *nextp= m_dest;
  else
  {
    thd->spcont->restore_variables(m_frame);
    *nextp= thd->spcont->pop_hstack();
  }
  thd->spcont->in_handler= FALSE;
2386 2387
  DBUG_RETURN(0);
}
2388

2389

2390 2391 2392
void
sp_instr_hreturn::print(String *str)
{
2393
  str->reserve(16);
2394 2395
  str->append("hreturn ");
  str->qs_append(m_frame);
2396 2397 2398 2399
  if (m_dest)
    str->qs_append(m_dest);
}

2400

2401 2402 2403 2404 2405 2406 2407 2408 2409 2410
uint
sp_instr_hreturn::opt_mark(sp_head *sp)
{
  if (m_dest)
    return sp_instr_jump::opt_mark(sp);
  else
  {
    marked= 1;
    return UINT_MAX;
  }
2411 2412
}

2413

2414 2415 2416 2417
/*
  sp_instr_cpush class functions
*/

2418 2419 2420
int
sp_instr_cpush::execute(THD *thd, uint *nextp)
{
konstantin@mysql.com's avatar
konstantin@mysql.com committed
2421
  Query_arena backup_arena;
2422
  DBUG_ENTER("sp_instr_cpush::execute");
2423 2424 2425 2426 2427

  /*
    We should create cursors in the callers arena, as
    it could be (and usually is) used in several instructions.
  */
konstantin@mysql.com's avatar
konstantin@mysql.com committed
2428
  thd->set_n_backup_active_arena(thd->spcont->callers_arena, &backup_arena);
2429

2430
  thd->spcont->push_cursor(&m_lex_keeper, this);
2431

konstantin@mysql.com's avatar
konstantin@mysql.com committed
2432
  thd->restore_active_arena(thd->spcont->callers_arena, &backup_arena);
2433

2434
  *nextp= m_ip+1;
2435

2436 2437 2438
  DBUG_RETURN(0);
}

2439

2440 2441 2442 2443 2444 2445
void
sp_instr_cpush::print(String *str)
{
  str->append("cpush");
}

2446 2447 2448 2449 2450

/*
  sp_instr_cpop class functions
*/

2451 2452 2453 2454 2455 2456 2457 2458 2459
int
sp_instr_cpop::execute(THD *thd, uint *nextp)
{
  DBUG_ENTER("sp_instr_cpop::execute");
  thd->spcont->pop_cursors(m_count);
  *nextp= m_ip+1;
  DBUG_RETURN(0);
}

2460

2461 2462 2463 2464 2465 2466 2467 2468
void
sp_instr_cpop::print(String *str)
{
  str->reserve(12);
  str->append("cpop ");
  str->qs_append(m_count);
}

2469 2470 2471 2472 2473 2474
void
sp_instr_cpop::backpatch(uint dest, sp_pcontext *dst_ctx)
{
  m_count= m_ctx->diff_cursors(dst_ctx);
}

2475 2476 2477 2478 2479

/*
  sp_instr_copen class functions
*/

2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490
int
sp_instr_copen::execute(THD *thd, uint *nextp)
{
  sp_cursor *c= thd->spcont->get_cursor(m_cursor);
  int res;
  DBUG_ENTER("sp_instr_copen::execute");

  if (! c)
    res= -1;
  else
  {
2491
    sp_lex_keeper *lex_keeper= c->pre_open(thd);
monty@mysql.com's avatar
monty@mysql.com committed
2492
    if (!lex_keeper)                            // cursor already open or OOM
2493
    {
2494
      res= -1;
2495 2496
      *nextp= m_ip+1;
    }
2497
    else
2498
    {
konstantin@mysql.com's avatar
konstantin@mysql.com committed
2499
      Query_arena *old_arena= thd->stmt_arena;
2500 2501

      /*
2502 2503 2504 2505
        Get the Query_arena from the cpush instruction, which contains
        the free_list of the query, so new items (if any) are stored in
        the right free_list, and we can cleanup after each open.
      */
konstantin@mysql.com's avatar
konstantin@mysql.com committed
2506
      thd->stmt_arena= c->get_instr();
2507
      res= lex_keeper->reset_lex_and_exec_core(thd, nextp, FALSE, this);
2508
      /* Cleanup the query's items */
konstantin@mysql.com's avatar
konstantin@mysql.com committed
2509 2510 2511
      if (thd->stmt_arena->free_list)
        cleanup_items(thd->stmt_arena->free_list);
      thd->stmt_arena= old_arena;
monty@mysql.com's avatar
merge  
monty@mysql.com committed
2512 2513 2514 2515
      /*
        Work around the fact that errors in selects are not returned properly
        (but instead converted into a warning), so if a condition handler
        caught, we have lost the result code.
2516
      */
monty@mysql.com's avatar
merge  
monty@mysql.com committed
2517 2518 2519
      if (!res)
      {
        uint dummy1, dummy2;
2520

monty@mysql.com's avatar
merge  
monty@mysql.com committed
2521 2522 2523
        if (thd->spcont->found_handler(&dummy1, &dummy2))
  	  res= -1;
      }
monty@mysql.com's avatar
monty@mysql.com committed
2524
      c->post_open(thd, res ? FALSE : TRUE);
2525
    }
2526 2527 2528 2529
  }
  DBUG_RETURN(res);
}

monty@mysql.com's avatar
monty@mysql.com committed
2530

2531 2532 2533 2534 2535 2536 2537 2538
int
sp_instr_copen::exec_core(THD *thd, uint *nextp)
{
  int res= mysql_execute_command(thd);
  *nextp= m_ip+1;
  return res;
}

2539 2540 2541 2542 2543 2544 2545 2546
void
sp_instr_copen::print(String *str)
{
  str->reserve(12);
  str->append("copen ");
  str->qs_append(m_cursor);
}

2547 2548 2549 2550 2551

/*
  sp_instr_cclose class functions
*/

2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566
int
sp_instr_cclose::execute(THD *thd, uint *nextp)
{
  sp_cursor *c= thd->spcont->get_cursor(m_cursor);
  int res;
  DBUG_ENTER("sp_instr_cclose::execute");

  if (! c)
    res= -1;
  else
    res= c->close(thd);
  *nextp= m_ip+1;
  DBUG_RETURN(res);
}

2567

2568 2569 2570 2571 2572 2573 2574 2575
void
sp_instr_cclose::print(String *str)
{
  str->reserve(12);
  str->append("cclose ");
  str->qs_append(m_cursor);
}

2576 2577 2578 2579 2580

/*
  sp_instr_cfetch class functions
*/

2581 2582 2583 2584 2585
int
sp_instr_cfetch::execute(THD *thd, uint *nextp)
{
  sp_cursor *c= thd->spcont->get_cursor(m_cursor);
  int res;
konstantin@mysql.com's avatar
konstantin@mysql.com committed
2586
  Query_arena backup_arena;
2587 2588 2589 2590 2591
  DBUG_ENTER("sp_instr_cfetch::execute");

  if (! c)
    res= -1;
  else
2592
  {
konstantin@mysql.com's avatar
konstantin@mysql.com committed
2593
    thd->set_n_backup_active_arena(thd->spcont->callers_arena, &backup_arena);
2594
    res= c->fetch(thd, &m_varlist);
konstantin@mysql.com's avatar
konstantin@mysql.com committed
2595
    thd->restore_active_arena(thd->spcont->callers_arena, &backup_arena);
2596 2597
  }

2598 2599 2600
  *nextp= m_ip+1;
  DBUG_RETURN(res);
}
2601

2602

2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619
void
sp_instr_cfetch::print(String *str)
{
  List_iterator_fast<struct sp_pvar> li(m_varlist);
  sp_pvar_t *pv;

  str->reserve(12);
  str->append("cfetch ");
  str->qs_append(m_cursor);
  while ((pv= li++))
  {
    str->reserve(8);
    str->append(' ');
    str->qs_append(pv->offset);
  }
}

2620 2621 2622 2623 2624

/*
  sp_instr_error class functions
*/

2625 2626 2627 2628 2629
int
sp_instr_error::execute(THD *thd, uint *nextp)
{
  DBUG_ENTER("sp_instr_error::execute");

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2630
  my_message(m_errcode, ER(m_errcode), MYF(0));
2631 2632 2633 2634
  *nextp= m_ip+1;
  DBUG_RETURN(-1);
}

2635

2636 2637 2638 2639 2640 2641 2642 2643
void
sp_instr_error::print(String *str)
{
  str->reserve(12);
  str->append("error ");
  str->qs_append(m_errcode);
}

2644

2645
/* ------------------------------------------------------------------ */
2646

2647 2648 2649
/*
  Security context swapping
*/
2650

2651
#ifndef NO_EMBEDDED_ACCESS_CHECKS
2652 2653 2654
void
sp_change_security_context(THD *thd, sp_head *sp, st_sp_security_context *ctxp)
{
2655
  ctxp->changed= (sp->m_chistics->suid != SP_IS_NOT_SUID &&
2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700
		   (strcmp(sp->m_definer_user.str, thd->priv_user) ||
		    strcmp(sp->m_definer_host.str, thd->priv_host)));

  if (ctxp->changed)
  {
    ctxp->master_access= thd->master_access;
    ctxp->db_access= thd->db_access;
    ctxp->priv_user= thd->priv_user;
    strncpy(ctxp->priv_host, thd->priv_host, sizeof(ctxp->priv_host));
    ctxp->user= thd->user;
    ctxp->host= thd->host;
    ctxp->ip= thd->ip;

    /* Change thise just to do the acl_getroot_no_password */
    thd->user= sp->m_definer_user.str;
    thd->host= thd->ip = sp->m_definer_host.str;

    if (acl_getroot_no_password(thd))
    {			// Failed, run as invoker for now
      ctxp->changed= FALSE;
      thd->master_access= ctxp->master_access;
      thd->db_access= ctxp->db_access;
      thd->priv_user= ctxp->priv_user;
      strncpy(thd->priv_host, ctxp->priv_host, sizeof(thd->priv_host));
    }

    /* Restore these immiediately */
    thd->user= ctxp->user;
    thd->host= ctxp->host;
    thd->ip= ctxp->ip;
  }
}

void
sp_restore_security_context(THD *thd, sp_head *sp, st_sp_security_context *ctxp)
{
  if (ctxp->changed)
  {
    ctxp->changed= FALSE;
    thd->master_access= ctxp->master_access;
    thd->db_access= ctxp->db_access;
    thd->priv_user= ctxp->priv_user;
    strncpy(thd->priv_host, ctxp->priv_host, sizeof(thd->priv_host));
  }
}
2701 2702

#endif /* NO_EMBEDDED_ACCESS_CHECKS */
2703 2704

/*
2705 2706 2707 2708
  Structure that represent all instances of one table
  in optimized multi-set of tables used by routine.
*/

2709 2710
typedef struct st_sp_table
{
serg@serg.mylan's avatar
serg@serg.mylan committed
2711 2712 2713 2714
  LEX_STRING qname;     /* Multi-set key: db_name\0table_name\0alias\0 */
  uint db_length, table_name_length;
  bool temp;               /* true if corresponds to a temporary table */
  thr_lock_type lock_type; /* lock type used for prelocking */
2715 2716
  uint lock_count;
  uint query_lock_count;
2717 2718 2719 2720 2721 2722 2723 2724 2725 2726
} SP_TABLE;

byte *
sp_table_key(const byte *ptr, uint *plen, my_bool first)
{
  SP_TABLE *tab= (SP_TABLE *)ptr;
  *plen= tab->qname.length;
  return (byte *)tab->qname.str;
}

2727

2728
/*
2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747
  Merge the list of tables used by some query into the multi-set of
  tables used by routine.

  SYNOPSIS
    merge_table_list()
      thd               - thread context
      table             - table list
      lex_for_tmp_check - LEX of the query for which we are merging
                          table list.

  NOTE
    This method will use LEX provided to check whenever we are creating
    temporary table and mark it as such in target multi-set.

  RETURN VALUE
    TRUE  - Success
    FALSE - Error
*/

2748
bool
2749
sp_head::merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check)
2750
{
2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762
  SP_TABLE *tab;

  if (lex_for_tmp_check->sql_command == SQLCOM_DROP_TABLE &&
      lex_for_tmp_check->drop_temporary)
    return TRUE;

  for (uint i= 0 ; i < m_sptabs.records ; i++)
  {
    tab= (SP_TABLE *)hash_element(&m_sptabs, i);
    tab->query_lock_count= 0;
  }

2763
  for (; table ; table= table->next_global)
2764
    if (!table->derived && !table->schema_table)
2765
    {
serg@serg.mylan's avatar
serg@serg.mylan committed
2766
      char tname[(NAME_LEN + 1) * 3];           // db\0table\0alias\0
2767 2768 2769 2770
      uint tlen, alen;

      tlen= table->db_length;
      memcpy(tname, table->db, tlen);
serg@serg.mylan's avatar
serg@serg.mylan committed
2771
      tname[tlen++]= '\0';
2772 2773
      memcpy(tname+tlen, table->table_name, table->table_name_length);
      tlen+= table->table_name_length;
serg@serg.mylan's avatar
serg@serg.mylan committed
2774
      tname[tlen++]= '\0';
2775 2776 2777 2778 2779
      alen= strlen(table->alias);
      memcpy(tname+tlen, table->alias, alen);
      tlen+= alen;
      tname[tlen]= '\0';

2780 2781 2782 2783 2784
      /*
        It is safe to store pointer to table list elements in hash,
        since they are supposed to have the same lifetime.
      */
      if ((tab= (SP_TABLE *)hash_search(&m_sptabs, (byte *)tname, tlen)))
2785
      {
2786 2787
        if (tab->lock_type < table->lock_type)
          tab->lock_type= table->lock_type; // Use the table with the highest lock type
2788 2789 2790
        tab->query_lock_count++;
        if (tab->query_lock_count > tab->lock_count)
          tab->lock_count++;
2791 2792 2793 2794 2795 2796
      }
      else
      {
	if (!(tab= (SP_TABLE *)thd->calloc(sizeof(SP_TABLE))))
	  return FALSE;
	tab->qname.length= tlen;
serg@serg.mylan's avatar
serg@serg.mylan committed
2797
	tab->qname.str= (char*) thd->memdup(tname, tab->qname.length + 1);
2798 2799
	if (!tab->qname.str)
	  return FALSE;
2800
	if (lex_for_tmp_check->sql_command == SQLCOM_CREATE_TABLE &&
2801 2802 2803
	    lex_for_tmp_check->query_tables == table &&
	    lex_for_tmp_check->create_info.options & HA_LEX_CREATE_TMP_TABLE)
	  tab->temp= TRUE;
serg@serg.mylan's avatar
serg@serg.mylan committed
2804 2805
        tab->table_name_length= table->table_name_length;
        tab->db_length= table->db_length;
2806
        tab->lock_type= table->lock_type;
2807 2808
        tab->lock_count= tab->query_lock_count= 1;
	my_hash_insert(&m_sptabs, (byte *)tab);
2809 2810 2811 2812 2813 2814
      }
    }
  return TRUE;
}


2815 2816
/*
  Add tables used by routine to the table list.
2817

2818 2819 2820 2821 2822 2823
  SYNOPSIS
    add_used_tables_to_table_list()
      thd                   - thread context
      query_tables_last_ptr - (in/out) pointer the next_global member of last
                              element of the list where tables will be added
                              (or to its root).
2824

2825 2826 2827
  DESCRIPTION
    Converts multi-set of tables used by this routine to table list and adds
    this list to the end of table list specified by 'query_tables_last_ptr'.
2828

2829 2830
    Elements of list will be allocated in PS memroot, so this list will be
    persistent between PS executions.
2831

2832 2833 2834
  RETURN VALUE
    TRUE - if some elements were added, FALSE - otherwise.
*/
2835

2836 2837 2838
bool
sp_head::add_used_tables_to_table_list(THD *thd,
                                       TABLE_LIST ***query_tables_last_ptr)
2839 2840
{
  uint i;
serg@serg.mylan's avatar
serg@serg.mylan committed
2841
  Query_arena *arena, backup;
2842 2843 2844 2845 2846 2847
  bool result= FALSE;
  DBUG_ENTER("sp_head::add_used_tables_to_table_list");

  /*
    Use persistent arena for table list allocation to be PS friendly.
  */
konstantin@mysql.com's avatar
konstantin@mysql.com committed
2848
  arena= thd->activate_stmt_arena_if_needed(&backup);
2849

2850
  for (i=0 ; i < m_sptabs.records ; i++)
2851
  {
2852
    char *tab_buff;
serg@serg.mylan's avatar
serg@serg.mylan committed
2853
    TABLE_LIST *table;
2854
    SP_TABLE *stab= (SP_TABLE *)hash_element(&m_sptabs, i);
2855 2856 2857
    if (stab->temp)
      continue;

2858 2859 2860
    if (!(tab_buff= (char *)thd->calloc(ALIGN_SIZE(sizeof(TABLE_LIST)) *
                                        stab->lock_count)))
      DBUG_RETURN(FALSE);
2861

2862 2863 2864 2865 2866 2867 2868 2869 2870 2871
    for (uint j= 0; j < stab->lock_count; j++)
    {
      table= (TABLE_LIST *)tab_buff;

      /*
        It's enough to just copy the pointers as the data will not change
        during the lifetime of the SP. If the SP is used by PS, we assume
        that the PS will be invalidated if the functions is deleted or
        changed.
      */
serg@serg.mylan's avatar
serg@serg.mylan committed
2872 2873 2874 2875 2876
      table->db= stab->qname.str;
      table->db_length= stab->db_length;
      table->table_name= table->db + table->db_length + 1;
      table->table_name_length= stab->table_name_length;
      table->alias= table->table_name + table->table_name_length + 1;
2877
      table->lock_type= stab->lock_type;
2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889
      table->cacheable_table= 1;
      table->prelocking_placeholder= 1;

      /* Everyting else should be zeroed */

      **query_tables_last_ptr= table;
      table->prev_global= *query_tables_last_ptr;
      *query_tables_last_ptr= &table->next_global;

      tab_buff+= ALIGN_SIZE(sizeof(TABLE_LIST));
      result= TRUE;
    }
2890
  }
2891 2892

  if (arena)
konstantin@mysql.com's avatar
konstantin@mysql.com committed
2893
    thd->restore_active_arena(arena, &backup);
2894 2895

  DBUG_RETURN(result);
2896 2897
}

2898

2899
/*
2900 2901 2902 2903
  Simple function for adding an explicetly named (systems) table to
  the global table list, e.g. "mysql", "proc".
*/

2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927
TABLE_LIST *
sp_add_to_query_tables(THD *thd, LEX *lex,
		       const char *db, const char *name,
		       thr_lock_type locktype)
{
  TABLE_LIST *table;

  if (!(table= (TABLE_LIST *)thd->calloc(sizeof(TABLE_LIST))))
  {
    my_error(ER_OUTOFMEMORY, MYF(0), sizeof(TABLE_LIST));
    return NULL;
  }
  table->db_length= strlen(db);
  table->db= thd->strmake(db, table->db_length);
  table->table_name_length= strlen(name);
  table->table_name= thd->strmake(name, table->table_name_length);
  table->alias= thd->strdup(name);
  table->lock_type= locktype;
  table->select_lex= lex->current_select; // QQ?
  table->cacheable_table= 1;
  
  lex->add_to_query_tables(table);
  return table;
}
2928