sp_head.cc 93.2 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

unknown's avatar
unknown committed
27 28 29 30 31 32 33
/*
  Sufficient max length of printed destinations and frame offsets (all uints).
*/
#define SP_INSTR_UINT_MAXLEN  8
#define SP_STMT_PRINT_MAXLEN 40


34 35
#include <my_user.h>

36 37 38
Item_result
sp_map_result_type(enum enum_field_types type)
{
39
  switch (type) {
40 41 42 43 44 45 46
  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:
unknown's avatar
unknown committed
47 48
  case MYSQL_TYPE_NEWDECIMAL:
    return DECIMAL_RESULT;
49 50 51 52 53 54 55 56
  case MYSQL_TYPE_FLOAT:
  case MYSQL_TYPE_DOUBLE:
    return REAL_RESULT;
  default:
    return STRING_RESULT;
  }
}

57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82

Item::Type
sp_map_item_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 Item::INT_ITEM;
  case MYSQL_TYPE_DECIMAL:
  case MYSQL_TYPE_NEWDECIMAL:
    return Item::DECIMAL_ITEM;
  case MYSQL_TYPE_FLOAT:
  case MYSQL_TYPE_DOUBLE:
    return Item::REAL_ITEM;
  default:
    return Item::STRING_ITEM;
  }
}


/*
  Return a string representation of the Item value.

83 84
  NOTE: If the item has a string result type, the string is escaped
  according to its character set.
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112

  SYNOPSIS
    item    a pointer to the Item
    str     string buffer for representation of the value

  RETURN
    NULL  on error
    a pointer to valid a valid string on success
*/

static String *
sp_get_item_value(Item *item, String *str)
{
  Item_result result_type= item->result_type();

  switch (item->result_type()) {
  case REAL_RESULT:
  case INT_RESULT:
  case DECIMAL_RESULT:
    return item->val_str(str);

  case STRING_RESULT:
    {
      String *result= item->val_str(str);
      
      if (!result)
        return NULL;
      
113 114 115 116 117 118 119 120 121
      {
        char buf_holder[STRING_BUFFER_USUAL_SIZE];
        String buf(buf_holder, sizeof(buf_holder), result->charset());

        /* We must reset length of the buffer, because of String specificity. */
        buf.length(0);

        buf.append('_');
        buf.append(result->charset()->csname);
122 123 124
        if (result->charset()->escape_with_backslash_is_dangerous)
          buf.append(' ');
        append_query_string(result->charset(), result, &buf);
125 126 127 128
        str->copy(buf);

        return str;
      }
129 130 131 132 133 134 135 136 137
    }

  case ROW_RESULT:
  default:
    return NULL;
  }
}


138
/*
139 140 141 142 143 144 145 146 147 148 149 150 151
  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)
152
{
153 154 155 156 157 158 159 160 161 162
  uint flags;

  switch (lex->sql_command) {
  case SQLCOM_SELECT:
    if (lex->result)
    {
      flags= 0;                      /* This is a SELECT with INTO clause */
      break;
    }
    /* fallthrough */
163
  case SQLCOM_ANALYZE:
164
  case SQLCOM_BACKUP_TABLE:
165 166 167
  case SQLCOM_OPTIMIZE:
  case SQLCOM_PRELOAD_KEYS:
  case SQLCOM_ASSIGN_TO_KEYCACHE:
168
  case SQLCOM_CHECKSUM:
169
  case SQLCOM_CHECK:
170
  case SQLCOM_HA_READ:
171
  case SQLCOM_SHOW_AUTHORS:
172 173 174 175 176
  case SQLCOM_SHOW_BINLOGS:
  case SQLCOM_SHOW_BINLOG_EVENTS:
  case SQLCOM_SHOW_CHARSETS:
  case SQLCOM_SHOW_COLLATIONS:
  case SQLCOM_SHOW_COLUMN_TYPES:
177
  case SQLCOM_SHOW_CONTRIBUTORS:
178 179 180 181
  case SQLCOM_SHOW_CREATE:
  case SQLCOM_SHOW_CREATE_DB:
  case SQLCOM_SHOW_CREATE_FUNC:
  case SQLCOM_SHOW_CREATE_PROC:
182
  case SQLCOM_SHOW_CREATE_EVENT:
183 184 185
  case SQLCOM_SHOW_DATABASES:
  case SQLCOM_SHOW_ERRORS:
  case SQLCOM_SHOW_FIELDS:
186
  case SQLCOM_SHOW_FUNC_CODE:
187
  case SQLCOM_SHOW_GRANTS:
188 189 190
  case SQLCOM_SHOW_ENGINE_STATUS:
  case SQLCOM_SHOW_ENGINE_LOGS:
  case SQLCOM_SHOW_ENGINE_MUTEX:
191
  case SQLCOM_SHOW_EVENTS:
192 193 194 195 196 197
  case SQLCOM_SHOW_KEYS:
  case SQLCOM_SHOW_MASTER_STAT:
  case SQLCOM_SHOW_NEW_MASTER:
  case SQLCOM_SHOW_OPEN_TABLES:
  case SQLCOM_SHOW_PRIVILEGES:
  case SQLCOM_SHOW_PROCESSLIST:
198 199
  case SQLCOM_SHOW_PROC_CODE:
  case SQLCOM_SHOW_SCHEDULER_STATUS:
200 201 202 203 204 205 206 207 208
  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:
209 210
  case SQLCOM_REPAIR:
  case SQLCOM_RESTORE_TABLE:
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
    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;
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
  case SQLCOM_CREATE_TABLE:
    if (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)
      flags= 0;
    else
      flags= sp_head::HAS_COMMIT_OR_ROLLBACK;
    break;
  case SQLCOM_DROP_TABLE:
    if (lex->drop_temporary)
      flags= 0;
    else
      flags= sp_head::HAS_COMMIT_OR_ROLLBACK;
    break;
  case SQLCOM_CREATE_INDEX:
  case SQLCOM_CREATE_DB:
  case SQLCOM_CREATE_VIEW:
  case SQLCOM_CREATE_TRIGGER:
  case SQLCOM_CREATE_USER:
  case SQLCOM_ALTER_TABLE:
  case SQLCOM_BEGIN:
  case SQLCOM_RENAME_TABLE:
  case SQLCOM_RENAME_USER:
  case SQLCOM_DROP_INDEX:
  case SQLCOM_DROP_DB:
  case SQLCOM_DROP_USER:
  case SQLCOM_DROP_VIEW:
  case SQLCOM_DROP_TRIGGER:
  case SQLCOM_TRUNCATE:
  case SQLCOM_COMMIT:
  case SQLCOM_ROLLBACK:
255
  case SQLCOM_LOAD:
256 257 258 259 260 261 262 263
  case SQLCOM_LOAD_MASTER_DATA:
  case SQLCOM_LOCK_TABLES:
  case SQLCOM_CREATE_PROCEDURE:
  case SQLCOM_CREATE_SPFUNCTION:
  case SQLCOM_ALTER_PROCEDURE:
  case SQLCOM_ALTER_FUNCTION:
  case SQLCOM_DROP_PROCEDURE:
  case SQLCOM_DROP_FUNCTION:
264 265 266
  case SQLCOM_CREATE_EVENT:
  case SQLCOM_ALTER_EVENT:
  case SQLCOM_DROP_EVENT:
267 268 269
  case SQLCOM_FLUSH:
  case SQLCOM_INSTALL_PLUGIN:
  case SQLCOM_UNINSTALL_PLUGIN:
270 271
    flags= sp_head::HAS_COMMIT_OR_ROLLBACK;
    break;
272
  default:
273 274
    flags= 0;
    break;
275
  }
276
  return flags;
277 278
}

279 280

/*
281
  Prepare an Item for evaluation (call of fix_fields).
282 283 284 285 286 287 288 289 290 291 292

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

  RETURN
    NULL  error
    prepared item
*/

293
Item *
294 295 296
sp_prepare_func_item(THD* thd, Item **it_addr)
{
  DBUG_ENTER("sp_prepare_func_item");
297
  it_addr= (*it_addr)->this_item_addr(thd, it_addr);
298

299 300 301
  if (!(*it_addr)->fixed &&
      ((*it_addr)->fix_fields(thd, it_addr) ||
       (*it_addr)->check_cols(1)))
302 303 304 305 306 307 308 309
  {
    DBUG_PRINT("info", ("fix_fields() failed"));
    DBUG_RETURN(NULL);
  }
  DBUG_RETURN(*it_addr);
}


310
/*
311
  Evaluate an expression and store the result in the field.
312 313

  SYNOPSIS
314 315 316 317
    sp_eval_expr()
      thd                   - current thread object
      expr_item             - the root item of the expression
      result_field          - the field to store the result
318 319

  RETURN VALUES
320 321
    FALSE  on success
    TRUE   on error
322
*/
323

324
bool
325
sp_eval_expr(THD *thd, Field *result_field, Item **expr_item_ptr)
326
{
327 328
  Item *expr_item;

329
  DBUG_ENTER("sp_eval_expr");
330

unknown's avatar
unknown committed
331
  if (!*expr_item_ptr)
332
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
333

334
  if (!(expr_item= sp_prepare_func_item(thd, expr_item_ptr)))
335
    DBUG_RETURN(TRUE);
336

337
  bool err_status= FALSE;
338

339 340 341
  /*
    Set THD flags to emit warnings/errors in case of overflow/type errors
    during saving the item into the field.
342

343 344 345 346 347 348
    Save original values and restore them after save.
  */
  
  enum_check_fields save_count_cuted_fields= thd->count_cuted_fields;
  bool save_abort_on_warning= thd->abort_on_warning;
  bool save_no_trans_update= thd->no_trans_update;
349

350 351 352 353 354
  thd->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL;
  thd->abort_on_warning=
    thd->variables.sql_mode &
    (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES);
  thd->no_trans_update= 0;
355

356
  /* Save the value in the field. Convert the value if needed. */
357

358
  expr_item->save_in_field(result_field, 0);
359

360 361 362
  thd->count_cuted_fields= save_count_cuted_fields;
  thd->abort_on_warning= save_abort_on_warning;
  thd->no_trans_update= save_no_trans_update;
363

364
  if (thd->net.report_error)
365
  {
366 367
    /* Return error status if something went wrong. */
    err_status= TRUE;
368
  }
369 370

  DBUG_RETURN(err_status);
371 372
}

373 374 375 376 377 378 379 380 381 382

/*
 *
 *  sp_name
 *
 */

void
sp_name::init_qname(THD *thd)
{
383 384 385 386 387
  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;
388
  sprintf(m_qname.str, "%.*s.%.*s",
389 390 391 392
	  m_db.length, (m_db.length ? m_db.str : ""),
	  m_name.length, m_name.str);
}

393

394
/*
unknown's avatar
unknown committed
395 396 397 398 399 400 401 402 403 404
  Check that the name 'ident' is ok. It's assumed to be an 'ident'
  from the parser, so we only have to check length and trailing spaces.
  The former is a standard requirement (and 'show status' assumes a
  non-empty name), the latter is a mysql:ism as trailing spaces are
  removed by get_field().
 
  RETURN
   TRUE  - bad name
   FALSE - name is ok
*/
405 406

bool
unknown's avatar
unknown committed
407
check_routine_name(LEX_STRING ident)
408 409 410
{
  return (!ident.str || !ident.str[0] || ident.str[ident.length-1] == ' ');
}
411

412 413 414 415 416 417 418 419 420
/* ------------------------------------------------------------------ */


/*
 *
 *  sp_head
 *
 */

421 422 423 424 425 426 427 428
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);
unknown's avatar
unknown committed
429 430
  sp= (sp_head *) alloc_root(&own_root, size);
  sp->main_mem_root= own_root;
431
  DBUG_PRINT("info", ("mem_root 0x%lx", (ulong) &sp->mem_root));
432 433 434 435 436 437 438 439
  DBUG_RETURN(sp);
}

void 
sp_head::operator delete(void *ptr, size_t size)
{
  DBUG_ENTER("sp_head::operator delete");
  MEM_ROOT own_root;
unknown's avatar
unknown committed
440
  sp_head *sp= (sp_head *) ptr;
441

unknown's avatar
unknown committed
442 443
  /* Make a copy of main_mem_root as free_root will free the sp */
  own_root= sp->main_mem_root;
444 445
  DBUG_PRINT("info", ("mem_root 0x%lx moved to 0x%lx",
                      (ulong) &sp->mem_root, (ulong) &own_root));
446 447 448 449 450
  free_root(&own_root, MYF(0));

  DBUG_VOID_RETURN;
}

451

452
sp_head::sp_head()
453
  :Query_arena(&main_mem_root, INITIALIZED_FOR_SP),
454
   m_flags(0), m_recursion_level(0), m_next_cached_sp(0),
455 456
   m_first_instance(this), m_first_free_instance(this), m_last_cached_sp(this),
   m_cont_level(0)
457
{
458
  const LEX_STRING str_reset= { NULL, 0 };
459
  m_return_field_def.charset = NULL;
460 461 462 463 464 465
  /*
    FIXME: the only use case when name is NULL is events, and it should
    be rewritten soon. Remove the else part and replace 'if' with
    an assert when this is done.
  */
  m_db= m_name= m_qname= str_reset;
466

467 468
  extern byte *
    sp_table_key(const byte *ptr, uint *plen, my_bool first);
469
  DBUG_ENTER("sp_head::sp_head");
470 471

  m_backpatch.empty();
472
  m_cont_backpatch.empty();
473
  m_lex.empty();
474
  hash_init(&m_sptabs, system_charset_info, 0, 0, 0, sp_table_key, 0, 0);
475
  hash_init(&m_sroutines, system_charset_info, 0, 0, 0, sp_sroutine_key, 0, 0);
476 477 478
  DBUG_VOID_RETURN;
}

479

480
void
481
sp_head::init(LEX *lex)
482 483
{
  DBUG_ENTER("sp_head::init");
484

485
  lex->spcont= m_pcont= new sp_pcontext(NULL);
486

487 488 489 490 491
  /*
    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();
492
  my_init_dynamic_array(&m_instr, sizeof(sp_instr *), 16, 8);
unknown's avatar
unknown committed
493
  m_param_begin= m_param_end= m_body_begin= 0;
494
  m_qname.str= m_db.str= m_name.str= m_params.str=
495 496
    m_body.str= m_defstr.str= 0;
  m_qname.length= m_db.length= m_name.length= m_params.length=
unknown's avatar
unknown committed
497
    m_body.length= m_defstr.length= 0;
498
  m_return_field_def.charset= NULL;
499 500 501
  DBUG_VOID_RETURN;
}

502

503
void
504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526
sp_head::init_sp_name(THD *thd, sp_name *spname)
{
  DBUG_ENTER("sp_head::init_sp_name");

  /* Must be initialized in the parser. */

  DBUG_ASSERT(spname && spname->m_db.str && spname->m_db.length);

  /* We have to copy strings to get them into the right memroot. */

  m_db.length= spname->m_db.length;
  m_db.str= strmake_root(thd->mem_root, spname->m_db.str, spname->m_db.length);

  m_name.length= spname->m_name.length;
  m_name.str= strmake_root(thd->mem_root, spname->m_name.str,
                           spname->m_name.length);

  if (spname->m_qname.length == 0)
    spname->init_qname(thd);

  m_qname.length= spname->m_qname.length;
  m_qname.str= strmake_root(thd->mem_root, spname->m_qname.str,
                            m_qname.length);
527 528

  DBUG_VOID_RETURN;
529 530 531
}


532
void
533
sp_head::init_strings(THD *thd, LEX *lex)
534 535
{
  DBUG_ENTER("sp_head::init_strings");
unknown's avatar
unknown committed
536
  const uchar *endp;                            /* Used to trim the end */
unknown's avatar
unknown committed
537
  /* During parsing, we must use thd->mem_root */
unknown's avatar
unknown committed
538
  MEM_ROOT *root= thd->mem_root;
539

540
  if (m_param_begin && m_param_end)
541
  {
542 543 544
    m_params.length= m_param_end - m_param_begin;
    m_params.str= strmake_root(root,
                               (char *)m_param_begin, m_params.length);
545
  }
546

547 548 549 550 551 552
  /* If ptr has overrun end_of_query then end_of_query is the end */
  endp= (lex->ptr > lex->end_of_query ? lex->end_of_query : lex->ptr);
  /*
    Trim "garbage" at the end. This is sometimes needed with the
    "/ * ! VERSION... * /" wrapper in dump files.
  */
553
  endp= skip_rear_comments(m_body_begin, endp);
554 555

  m_body.length= endp - m_body_begin;
unknown's avatar
unknown committed
556
  m_body.str= strmake_root(root, (char *)m_body_begin, m_body.length);
557
  m_defstr.length= endp - lex->buf;
unknown's avatar
unknown committed
558
  m_defstr.str= strmake_root(root, (char *)lex->buf, m_defstr.length);
559
  DBUG_VOID_RETURN;
560 561
}

562 563 564

static TYPELIB *
create_typelib(MEM_ROOT *mem_root, create_field *field_def, List<String> *src)
unknown's avatar
unknown committed
565 566
{
  TYPELIB *result= NULL;
567 568
  CHARSET_INFO *cs= field_def->charset;
  DBUG_ENTER("create_typelib");
unknown's avatar
unknown committed
569

unknown's avatar
unknown committed
570 571 572 573 574 575
  if (src->elements)
  {
    result= (TYPELIB*) alloc_root(mem_root, sizeof(TYPELIB));
    result->count= src->elements;
    result->name= "";
    if (!(result->type_names=(const char **)
576
          alloc_root(mem_root,(sizeof(char *)+sizeof(int))*(result->count+1))))
unknown's avatar
unknown committed
577 578
      DBUG_RETURN(0);
    result->type_lengths= (uint*)(result->type_names + result->count+1);
unknown's avatar
unknown committed
579
    List_iterator<String> it(*src);
unknown's avatar
unknown committed
580 581
    String conv;
    for (uint i=0; i < result->count; i++)
582
    {
unknown's avatar
unknown committed
583 584 585 586
      uint32 dummy;
      uint length;
      String *tmp= it++;

587 588 589 590 591
      if (String::needs_conversion(tmp->length(), tmp->charset(),
      				   cs, &dummy))
      {
        uint cnv_errs;
        conv.copy(tmp->ptr(), tmp->length(), tmp->charset(), cs, &cnv_errs);
unknown's avatar
unknown committed
592 593 594 595

        length= conv.length();
        result->type_names[i]= (char*) strmake_root(mem_root, conv.ptr(),
                                                    length);
596
      }
unknown's avatar
unknown committed
597 598 599 600
      else
      {
        length= tmp->length();
        result->type_names[i]= strmake_root(mem_root, tmp->ptr(), length);
601
      }
602 603

      // Strip trailing spaces.
unknown's avatar
unknown committed
604 605 606
      length= cs->cset->lengthsp(cs, result->type_names[i], length);
      result->type_lengths[i]= length;
      ((uchar *)result->type_names[i])[length]= '\0';
607
    }
unknown's avatar
unknown committed
608
    result->type_names[result->count]= 0;
609
    result->type_lengths[result->count]= 0;
unknown's avatar
unknown committed
610
  }
unknown's avatar
unknown committed
611
  DBUG_RETURN(result);
unknown's avatar
unknown committed
612 613
}

614

615 616 617
int
sp_head::create(THD *thd)
{
618
  DBUG_ENTER("sp_head::create");
619 620
  int ret;

621 622
  DBUG_PRINT("info", ("type: %d name: %s params: %s body: %s",
		      m_type, m_name.str, m_params.str, m_body.str));
623

624
#ifndef DBUG_OFF
625
  optimize();
626
  {
627 628 629 630 631 632
    String s;
    sp_instr *i;
    uint ip= 0;
    while ((i = get_instr(ip)))
    {
      char buf[8];
633

634 635 636 637 638 639 640 641
      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()));
642 643 644
  }
#endif

645
  if (m_type == TYPE_ENUM_FUNCTION)
646
    ret= sp_create_function(thd, this);
647
  else
648
    ret= sp_create_procedure(thd, this);
649

650
  DBUG_RETURN(ret);
651 652
}

653 654 655
sp_head::~sp_head()
{
  destroy();
656
  delete m_next_cached_sp;
657 658 659 660
  if (m_thd)
    restore_thd_mem_root(m_thd);
}

661 662 663
void
sp_head::destroy()
{
664 665
  sp_instr *i;
  LEX *lex;
unknown's avatar
unknown committed
666 667
  DBUG_ENTER("sp_head::destroy");
  DBUG_PRINT("info", ("name: %s", m_name.str));
668 669 670

  for (uint ip = 0 ; (i = get_instr(ip)) ; ip++)
    delete i;
671 672
  delete_dynamic(&m_instr);
  m_pcont->destroy();
673
  free_items();
674 675 676 677 678 679 680 681 682 683

  /*
    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);
684 685
  while ((lex= (LEX *)m_lex.pop()))
  {
686
    lex_end(m_thd->lex);
687 688
    delete m_thd->lex;
    m_thd->lex= lex;
689
  }
690

691
  hash_free(&m_sptabs);
692
  hash_free(&m_sroutines);
693
  DBUG_VOID_RETURN;
694
}
695

unknown's avatar
unknown committed
696

697
/*
698 699 700 701
  This is only used for result fields from functions (both during
  fix_length_and_dec() and evaluation).
*/

unknown's avatar
unknown committed
702
Field *
703 704
sp_head::create_result_field(uint field_max_length, const char *field_name,
                             TABLE *table)
unknown's avatar
unknown committed
705
{
706
  uint field_length;
unknown's avatar
unknown committed
707
  Field *field;
708 709 710 711 712 713

  DBUG_ENTER("sp_head::create_result_field");

  field_length= !m_return_field_def.length ?
                field_max_length : m_return_field_def.length;

714 715
  field= ::make_field(table->s,                     /* TABLE_SHARE ptr */
                      (char*) 0,                    /* field ptr */
716 717 718 719 720 721 722 723 724
                      field_length,                 /* field [max] length */
                      (uchar*) "",                  /* null ptr */
                      0,                            /* null bit */
                      m_return_field_def.pack_flag,
                      m_return_field_def.sql_type,
                      m_return_field_def.charset,
                      m_return_field_def.geom_type,
                      Field::NONE,                  /* unreg check */
                      m_return_field_def.interval,
725
                      field_name ? field_name : (const char *) m_name.str);
unknown's avatar
unknown committed
726 727 728

  if (field)
    field->init(table);
729
  
unknown's avatar
unknown committed
730 731 732
  DBUG_RETURN(field);
}

733 734 735 736 737 738 739 740 741

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


/*
  StoredRoutinesBinlogging
742 743 744
  This paragraph applies only to statement-based binlogging. Row-based
  binlogging does not need anything special like this.

745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775
  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).
  
  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
776 777
     function execution (grep for start_union_events and stop_union_events)

778
   If the answers are No and Yes, we write the function call into the binary
779
   log as "SELECT spfunc(<param1value>, <param2value>, ...)"
780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804
  
  
  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)
805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823
*/


/*
  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
824 825 826 827
    FALSE  on success
           thd->query{_length} either has been appropriately replaced or there
           is no need for replacements.
    TRUE   out of memory error.
828 829
*/

830 831
static bool
subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str)
832 833 834 835 836
{
  DBUG_ENTER("subst_spvars");
  if (thd->prelocked_mode == NON_PRELOCKED && mysql_bin_log.is_open())
  {
    Dynamic_array<Item_splocal*> sp_vars_uses;
837 838 839
    char *pbuf, *cur, buffer[512];
    String qbuf(buffer, sizeof(buffer), &my_charset_bin);
    int prev_pos, res;
840

841
    /* Find all instances of Item_splocal used in this statement */
842 843
    for (Item *item= instr->free_list; item; item= item->next)
    {
unknown's avatar
unknown committed
844 845 846 847 848 849
      if (item->is_splocal())
      {
        Item_splocal *item_spl= (Item_splocal*)item;
        if (item_spl->pos_in_query)
          sp_vars_uses.append(item_spl);
      }
850 851
    }
    if (!sp_vars_uses.elements())
852
      DBUG_RETURN(FALSE);
853 854 855 856 857 858 859 860 861
      
    /* 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);
862 863
    cur= query_str->str;
    prev_pos= res= 0;
864 865 866
    for (Item_splocal **splocal= sp_vars_uses.front(); 
         splocal < sp_vars_uses.back(); splocal++)
    {
867
      Item *val;
868 869 870 871 872 873

      char str_buffer[STRING_BUFFER_USUAL_SIZE];
      String str_value_holder(str_buffer, sizeof(str_buffer),
                              &my_charset_latin1);
      String *str_value;
      
874
      /* append the text between sp ref occurences */
875
      res|= qbuf.append(cur + prev_pos, (*splocal)->pos_in_query - prev_pos);
876 877 878
      prev_pos= (*splocal)->pos_in_query + (*splocal)->m_name.length;
      
      /* append the spvar substitute */
879
      res|= qbuf.append(STRING_WITH_LEN(" NAME_CONST('"));
880
      res|= qbuf.append((*splocal)->m_name.str, (*splocal)->m_name.length);
881
      res|= qbuf.append(STRING_WITH_LEN("',"));
882 883 884 885 886
      res|= (*splocal)->fix_fields(thd, (Item **) splocal);

      if (res)
        break;

887
      val= (*splocal)->this_item();
888
      DBUG_PRINT("info", ("print %p", val));
889 890 891 892 893
      str_value= sp_get_item_value(val, &str_value_holder);
      if (str_value)
        res|= qbuf.append(*str_value);
      else
        res|= qbuf.append(STRING_WITH_LEN("NULL"));
894
      res|= qbuf.append(')');
895 896 897
      if (res)
        break;
    }
898
    res|= qbuf.append(cur + prev_pos, query_str->length - prev_pos);
899
    if (res)
900
      DBUG_RETURN(TRUE);
901

902
    if (!(pbuf= thd->strmake(qbuf.ptr(), qbuf.length())))
903
      DBUG_RETURN(TRUE);
904 905 906 907

    thd->query= pbuf;
    thd->query_length= qbuf.length();
  }
908
  DBUG_RETURN(FALSE);
909 910 911
}


912 913 914 915 916
/*
  Return appropriate error about recursion limit reaching

  SYNOPSIS
    sp_head::recursion_level_error()
unknown's avatar
unknown committed
917
    thd		Thread handle
918 919 920 921 922 923

  NOTE
    For functions and triggers we return error about prohibited recursion.
    For stored procedures we return about reaching recursion limit.
*/

unknown's avatar
unknown committed
924
void sp_head::recursion_level_error(THD *thd)
925 926 927 928 929
{
  if (m_type == TYPE_ENUM_PROCEDURE)
  {
    my_error(ER_SP_RECURSION_LIMIT, MYF(0),
             thd->variables.max_sp_recursion_depth,
930
             m_name.str);
931 932 933 934 935 936
  }
  else
    my_error(ER_SP_NO_RECURSION, MYF(0));
}


937 938 939 940 941
/*
  Execute the routine. The main instruction jump loop is there 
  Assume the parameters already set.
  
  RETURN
942 943
    FALSE  on success
    TRUE   on error
944 945 946

*/

947 948
bool
sp_head::execute(THD *thd)
949
{
950
  DBUG_ENTER("sp_head::execute");
unknown's avatar
unknown committed
951 952
  char old_db_buf[NAME_LEN+1];
  LEX_STRING old_db= { old_db_buf, sizeof(old_db_buf) };
953
  bool dbchanged;
954
  sp_rcontext *ctx;
955
  bool err_status= FALSE;
956
  uint ip= 0;
957
  ulong save_sql_mode;
958
  bool save_abort_on_warning;
unknown's avatar
unknown committed
959
  Query_arena *old_arena;
960 961 962
  /* per-instruction arena */
  MEM_ROOT execute_mem_root;
  Query_arena execute_arena(&execute_mem_root, INITIALIZED_FOR_SP),
unknown's avatar
Rename:  
unknown committed
963
              backup_arena;
964
  query_id_t old_query_id;
965 966 967 968
  TABLE *old_derived_tables;
  LEX *old_lex;
  Item_change_list old_change_list;
  String old_packet;
969

970
  /* Use some extra margin for possible SP recursion and functions */
971
  if (check_stack_overrun(thd, 8 * STACK_MIN_SIZE, (char*)&old_packet))
972
    DBUG_RETURN(TRUE);
973

974 975 976 977
  /* init per-instruction memroot */
  init_alloc_root(&execute_mem_root, MEM_ROOT_BLOCK_SIZE, 0);

  DBUG_ASSERT(!(m_flags & IS_INVOKED));
978
  m_flags|= IS_INVOKED;
979
  m_first_instance->m_first_free_instance= m_next_cached_sp;
unknown's avatar
unknown committed
980 981 982 983 984 985 986 987 988
  if (m_next_cached_sp)
  {
    DBUG_PRINT("info",
               ("first free for 0x%lx ++: 0x%lx->0x%lx  level: %lu  flags %x",
                (ulong)m_first_instance, (ulong) this,
                (ulong) m_next_cached_sp,
                m_next_cached_sp->m_recursion_level,
                m_next_cached_sp->m_flags));
  }
989 990 991 992 993 994 995 996 997
  /*
    Check that if there are not any instances after this one then
    pointer to the last instance points on this instance or if there are
    some instances after this one then recursion level of next instance
    greater then recursion level of current instance on 1
  */
  DBUG_ASSERT((m_next_cached_sp == 0 &&
               m_first_instance->m_last_cached_sp == this) ||
              (m_recursion_level + 1 == m_next_cached_sp->m_recursion_level));
998

999
  if (m_db.length &&
unknown's avatar
unknown committed
1000
      (err_status= sp_use_new_db(thd, m_db, &old_db, 0, &dbchanged)))
1001
    goto done;
1002

1003
  if ((ctx= thd->spcont))
1004
    ctx->clear_handler();
1005
  thd->query_error= 0;
unknown's avatar
Rename:  
unknown committed
1006
  old_arena= thd->stmt_arena;
1007

1008 1009 1010 1011 1012 1013 1014
  /*
    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;
1015 1016
  save_sql_mode= thd->variables.sql_mode;
  thd->variables.sql_mode= m_sql_mode;
1017 1018 1019 1020
  save_abort_on_warning= thd->abort_on_warning;
  thd->abort_on_warning=
    (m_sql_mode & (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES));

1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041
  /*
    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);

1042 1043 1044 1045
  /*
    Switch to per-instruction arena here. We can do it since we cleanup
    arena after every instruction.
  */
unknown's avatar
Rename:  
unknown committed
1046
  thd->set_n_backup_active_arena(&execute_arena, &backup_arena);
1047 1048 1049 1050 1051

  /*
    Save callers arena in order to store instruction results and out
    parameters in it later during sp_eval_func_item()
  */
unknown's avatar
Rename:  
unknown committed
1052
  thd->spcont->callers_arena= &backup_arena;
1053

1054 1055 1056
  do
  {
    sp_instr *i;
1057
    uint hip;			// Handler ip
1058 1059 1060 1061 1062

    i = get_instr(ip);	// Returns NULL when we're done.
    if (i == NULL)
      break;
    DBUG_PRINT("execute", ("Instruction %u", ip));
1063 1064 1065
    /* Don't change NOW() in FUNCTION or TRIGGER */
    if (!thd->in_sub_stmt)
      thd->set_time();		// Make current_time() et al work
1066
    
1067
    /*
unknown's avatar
Rename:  
unknown committed
1068
      We have to set thd->stmt_arena before executing the instruction
1069 1070 1071 1072
      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).
    */
unknown's avatar
Rename:  
unknown committed
1073
    thd->stmt_arena= i;
1074
    
1075 1076 1077 1078 1079
    /* 
      Will write this SP statement into binlog separately 
      (TODO: consider changing the condition to "not inside event union")
    */
    if (thd->prelocked_mode == NON_PRELOCKED)
1080 1081
      thd->user_var_events_alloc= thd->mem_root;
    
1082
    err_status= i->execute(thd, &ip);
1083

1084
    /*
1085 1086 1087
      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)
1088 1089
    */
    thd->net.no_send_error= 0;
1090 1091
    if (i->free_list)
      cleanup_items(i->free_list);
1092 1093 1094 1095 1096 1097 1098 1099 1100 1101
    
    /* 
      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
    }
1102

1103
    /* we should cleanup free_list and memroot, used by instruction */
1104
    thd->cleanup_after_query();
1105
    free_root(&execute_mem_root, MYF(0));    
1106

unknown's avatar
unknown committed
1107 1108
    /*
      Check if an exception has occurred and a handler has been found
1109 1110 1111 1112
      Note: We have to check even if err_status == FALSE, 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").
unknown's avatar
unknown committed
1113
    */
1114
    if (ctx)
1115 1116 1117
    {
      uint hf;

1118
      switch (ctx->found_handler(&hip, &hf)) {
1119 1120 1121
      case SP_HANDLER_NONE:
	break;
      case SP_HANDLER_CONTINUE:
unknown's avatar
Rename:  
unknown committed
1122 1123
        thd->restore_active_arena(&execute_arena, &backup_arena);
        thd->set_n_backup_active_arena(&execute_arena, &backup_arena);
1124
        ctx->push_hstack(ip);
unknown's avatar
unknown committed
1125
        // Fall through
1126 1127
      default:
	ip= hip;
1128
	err_status= FALSE;
1129
	ctx->clear_handler();
1130
	ctx->enter_handler(hip);
unknown's avatar
unknown committed
1131
        thd->clear_error();
1132
	thd->killed= THD::NOT_KILLED;
1133 1134 1135
	continue;
      }
    }
1136
  } while (!err_status && !thd->killed);
1137

unknown's avatar
Rename:  
unknown committed
1138
  thd->restore_active_arena(&execute_arena, &backup_arena);
1139

1140
  thd->spcont->pop_all_cursors(); // To avoid memory leaks after an error
1141

1142 1143 1144 1145 1146 1147 1148 1149 1150 1151
  /* 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;
1152
  thd->variables.sql_mode= save_sql_mode;
1153
  thd->abort_on_warning= save_abort_on_warning;
1154

unknown's avatar
Rename:  
unknown committed
1155
  thd->stmt_arena= old_arena;
1156
  state= EXECUTED;
1157

1158
 done:
1159
  DBUG_PRINT("info", ("err_status: %d  killed: %d  query_error: %d",
1160
		      err_status, thd->killed, thd->query_error));
1161

unknown's avatar
unknown committed
1162
  if (thd->killed)
1163
    err_status= TRUE;
1164 1165 1166 1167
  /*
    If the DB has changed, the pointer has changed too, but the
    original thd->db will then have been freed
  */
1168
  if (dbchanged)
1169
  {
1170 1171
    /*
      No access check when changing back to where we came from.
unknown's avatar
unknown committed
1172
      (It would generate an error from mysql_change_db() when old_db=="")
1173
    */
1174
    if (! thd->killed)
unknown's avatar
unknown committed
1175
      err_status|= mysql_change_db(thd, old_db.str, 1);
1176
  }
1177
  m_flags&= ~IS_INVOKED;
1178 1179 1180 1181 1182
  DBUG_PRINT("info",
             ("first free for 0x%lx --: 0x%lx->0x%lx, level: %lu, flags %x",
              (ulong) m_first_instance,
              (ulong) m_first_instance->m_first_free_instance,
              (ulong) this, m_recursion_level, m_flags));
1183 1184 1185 1186 1187 1188 1189 1190 1191
  /*
    Check that we have one of following:

    1) there are not free instances which means that this instance is last
    in the list of instances (pointer to the last instance point on it and
    ther are not other instances after this one in the list)

    2) There are some free instances which mean that first free instance
    should go just after this one and recursion level of that free instance
unknown's avatar
unknown committed
1192
    should be on 1 more then recursion level of this instance.
1193 1194 1195 1196 1197 1198 1199 1200 1201
  */
  DBUG_ASSERT((m_first_instance->m_first_free_instance == 0 &&
               this == m_first_instance->m_last_cached_sp &&
               m_next_cached_sp == 0) ||
              (m_first_instance->m_first_free_instance != 0 &&
               m_first_instance->m_first_free_instance == m_next_cached_sp &&
               m_first_instance->m_first_free_instance->m_recursion_level ==
               m_recursion_level + 1));
  m_first_instance->m_first_free_instance= this;
1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 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

  DBUG_RETURN(err_status);
}


#ifndef NO_EMBEDDED_ACCESS_CHECKS
/*
  set_routine_security_ctx() changes routine security context, and
  checks if there is an EXECUTE privilege in new context.  If there is
  no EXECUTE privilege, it changes the context back and returns a
  error.

  SYNOPSIS
    set_routine_security_ctx()
      thd         thread handle
      sp          stored routine to change the context for
      is_proc     TRUE is procedure, FALSE if function
      save_ctx    pointer to an old security context
   
  RETURN
    TRUE if there was a error, and the context wasn't changed.
    FALSE if the context was changed.
*/

bool
set_routine_security_ctx(THD *thd, sp_head *sp, bool is_proc,
                         Security_context **save_ctx)
{
  *save_ctx= 0;
  if (sp_change_security_context(thd, sp, save_ctx))
    return TRUE;

  /*
    If we changed context to run as another user, we need to check the
    access right for the new context again as someone may have revoked
    the right to use the procedure from this user.

    TODO:
      Cache if the definer has the right to use the object on the
      first usage and only reset the cache if someone does a GRANT
      statement that 'may' affect this.
  */
  if (*save_ctx &&
      check_routine_access(thd, EXECUTE_ACL,
                           sp->m_db.str, sp->m_name.str, is_proc, FALSE))
  {
    sp_restore_security_context(thd, *save_ctx);
    *save_ctx= 0;
    return TRUE;
  }

  return FALSE;
}
#endif // ! NO_EMBEDDED_ACCESS_CHECKS


/*
  Execute a trigger:
   - changes security context for triggers
   - switch to new memroot
   - call sp_head::execute
   - restore old memroot
   - restores security context

  SYNOPSIS
    sp_head::execute_trigger()
      thd               Thread handle
      db                database name
      table             table name
      grant_info        GRANT_INFO structure to be filled with
                        information about definer's privileges
                        on subject table
   
  RETURN
    FALSE  on success
    TRUE   on error
*/

bool
sp_head::execute_trigger(THD *thd, const char *db, const char *table,
                         GRANT_INFO *grant_info)
{
  sp_rcontext *octx = thd->spcont;
  sp_rcontext *nctx = NULL;
  bool err_status= FALSE;
  MEM_ROOT call_mem_root;
  Query_arena call_arena(&call_mem_root, Query_arena::INITIALIZED_FOR_SP);
  Query_arena backup_arena;

  DBUG_ENTER("sp_head::execute_trigger");
  DBUG_PRINT("info", ("trigger %s", m_name.str));

  /*
    Prepare arena and memroot for objects which lifetime is whole
    duration of trigger call (sp_rcontext, it's tables and items,
    sp_cursor and Item_cache holders for case expressions).  We can't
    use caller's arena/memroot for those objects because in this case
    some fixed amount of memory will be consumed for each trigger
    invocation and so statements which involve lot of them will hog
    memory.

    TODO: we should create sp_rcontext once per command and reuse it
    on subsequent executions of a trigger.
  */
  init_sql_alloc(&call_mem_root, MEM_ROOT_BLOCK_SIZE, 0);
  thd->set_n_backup_active_arena(&call_arena, &backup_arena);

  if (!(nctx= new sp_rcontext(m_pcont, 0, octx)) ||
      nctx->init(thd))
  {
    err_status= TRUE;
    goto err_with_cleanup;
  }

#ifndef DBUG_OFF
  nctx->sp= this;
#endif

  thd->spcont= nctx;

  err_status= execute(thd);

err_with_cleanup:
  thd->restore_active_arena(&call_arena, &backup_arena);
  delete nctx;
  call_arena.free_items();
  free_root(&call_mem_root, MYF(0));
  thd->spcont= octx;

1331
  DBUG_RETURN(err_status);
1332 1333 1334
}


1335 1336 1337
/*
  Execute a function:
   - evaluate parameters
1338 1339
   - changes security context for SUID routines
   - switch to new memroot
1340
   - call sp_head::execute
1341
   - restore old memroot
1342
   - evaluate the return value
1343
   - restores security context
1344 1345 1346

  SYNOPSIS
    sp_head::execute_function()
1347 1348 1349 1350 1351 1352
      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.
      return_value_fld  Save result here.
1353 1354
   
  RETURN
1355 1356
    FALSE  on success
    TRUE   on error
1357 1358
*/

1359 1360 1361
bool
sp_head::execute_function(THD *thd, Item **argp, uint argcount,
                          Field *return_value_fld)
1362
{
1363 1364
  ulonglong binlog_save_options;
  bool need_binlog_call;
1365
  uint arg_no;
1366 1367
  sp_rcontext *octx = thd->spcont;
  sp_rcontext *nctx = NULL;
1368 1369
  char buf[STRING_BUFFER_USUAL_SIZE];
  String binlog_buf(buf, sizeof(buf), &my_charset_bin);
1370
  bool err_status= FALSE;
1371 1372 1373
  MEM_ROOT call_mem_root;
  Query_arena call_arena(&call_mem_root, Query_arena::INITIALIZED_FOR_SP);
  Query_arena backup_arena;
1374 1375 1376 1377

  DBUG_ENTER("sp_head::execute_function");
  DBUG_PRINT("info", ("function %s", m_name.str));

unknown's avatar
unknown committed
1378
  LINT_INIT(binlog_save_options);
1379 1380 1381 1382 1383 1384 1385

  /*
    Check that the function is called with all specified arguments.

    If it is not, use my_error() to report an error, or it will not terminate
    the invoking query properly.
  */
1386
  if (argcount != m_pcont->context_var_count())
unknown's avatar
unknown committed
1387
  {
unknown's avatar
unknown committed
1388
    /*
1389
      Need to use my_error here, or it will not terminate the
unknown's avatar
unknown committed
1390 1391
      invoking query properly.
    */
1392
    my_error(ER_SP_WRONG_NO_OF_ARGS, MYF(0),
1393
             "FUNCTION", m_qname.str, m_pcont->context_var_count(), argcount);
1394
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
1395
  }
1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408
  /*
    Prepare arena and memroot for objects which lifetime is whole
    duration of function call (sp_rcontext, it's tables and items,
    sp_cursor and Item_cache holders for case expressions).
    We can't use caller's arena/memroot for those objects because
    in this case some fixed amount of memory will be consumed for
    each function/trigger invocation and so statements which involve
    lot of them will hog memory.
    TODO: we should create sp_rcontext once per command and reuse
    it on subsequent executions of a function/trigger.
  */
  init_sql_alloc(&call_mem_root, MEM_ROOT_BLOCK_SIZE, 0);
  thd->set_n_backup_active_arena(&call_arena, &backup_arena);
1409 1410 1411 1412

  if (!(nctx= new sp_rcontext(m_pcont, return_value_fld, octx)) ||
      nctx->init(thd))
  {
1413 1414 1415
    thd->restore_active_arena(&call_arena, &backup_arena);
    err_status= TRUE;
    goto err_with_cleanup;
1416 1417
  }

1418 1419 1420 1421 1422 1423 1424 1425
  /*
    We have to switch temporarily back to callers arena/memroot.
    Function arguments belong to the caller and so the may reference
    memory which they will allocate during calculation long after
    this function call will be finished (e.g. in Item::cleanup()).
  */
  thd->restore_active_arena(&call_arena, &backup_arena);

1426
#ifndef DBUG_OFF
1427
  nctx->sp= this;
1428
#endif
1429 1430

  /* Pass arguments. */
1431
  for (arg_no= 0; arg_no < argcount; arg_no++)
1432
  {
1433 1434
    /* Arguments must be fixed in Item_func_sp::fix_fields */
    DBUG_ASSERT(argp[arg_no]->fixed);
1435

unknown's avatar
unknown committed
1436
    if ((err_status= nctx->set_variable(thd, arg_no, &(argp[arg_no]))))
1437
      goto err_with_cleanup;
1438
  }
1439

1440 1441 1442 1443 1444
  /*
    If row-based binlogging, we don't need to binlog the function's call, let
    each substatement be binlogged its way.
  */
  need_binlog_call= mysql_bin_log.is_open() &&
1445
    (thd->options & OPTION_BIN_LOG) && !thd->current_stmt_binlog_row_based;
1446

1447 1448 1449 1450 1451
  /*
    Remember the original arguments for unrolled replication of functions
    before they are changed by execution.
  */
  if (need_binlog_call)
1452
  {
1453 1454 1455 1456 1457
    binlog_buf.length(0);
    binlog_buf.append(STRING_WITH_LEN("SELECT "));
    append_identifier(thd, &binlog_buf, m_name.str, m_name.length);
    binlog_buf.append('(');
    for (arg_no= 0; arg_no < argcount; arg_no++)
1458
    {
1459 1460
      String str_value_holder;
      String *str_value;
1461

1462 1463
      if (arg_no)
        binlog_buf.append(',');
1464

1465 1466
      str_value= sp_get_item_value(nctx->get_item(arg_no),
                                   &str_value_holder);
1467

1468 1469 1470 1471 1472 1473
      if (str_value)
        binlog_buf.append(*str_value);
      else
        binlog_buf.append(STRING_WITH_LEN("NULL"));
    }
    binlog_buf.append(')');
1474
  }
1475 1476
  thd->spcont= nctx;

1477 1478 1479 1480 1481 1482 1483 1484 1485
#ifndef NO_EMBEDDED_ACCESS_CHECKS
  Security_context *save_security_ctx;
  if (set_routine_security_ctx(thd, this, FALSE, &save_security_ctx))
  {
    err_status= TRUE;
    goto err_with_cleanup;
  }
#endif

1486
  if (need_binlog_call)
1487 1488
  {
    reset_dynamic(&thd->user_var_events);
1489
    mysql_bin_log.start_union_events(thd);
1490 1491
    binlog_save_options= thd->options;
    thd->options&= ~OPTION_BIN_LOG;
1492
  }
1493

1494 1495 1496 1497 1498 1499 1500 1501 1502 1503
  /*
    Switch to call arena/mem_root so objects like sp_cursor or
    Item_cache holders for case expressions can be allocated on it.

    TODO: In future we should associate call arena/mem_root with
          sp_rcontext and allocate all these objects (and sp_rcontext
          itself) on it directly rather than juggle with arenas.
  */
  thd->set_n_backup_active_arena(&call_arena, &backup_arena);

1504
  err_status= execute(thd);
1505

1506 1507
  thd->restore_active_arena(&call_arena, &backup_arena);

1508
  if (need_binlog_call)
1509
  {
1510 1511 1512
    mysql_bin_log.stop_union_events(thd);
    thd->options= binlog_save_options;
    if (thd->binlog_evt_union.unioned_events)
1513
    {
1514
      Query_log_event qinfo(thd, binlog_buf.ptr(), binlog_buf.length(),
1515 1516 1517 1518 1519 1520 1521 1522 1523
                            thd->binlog_evt_union.unioned_events_trans, FALSE);
      if (mysql_bin_log.write(&qinfo) &&
          thd->binlog_evt_union.unioned_events_trans)
      {
        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");
      }
      reset_dynamic(&thd->user_var_events);
1524 1525
    }
  }
1526

1527
  if (!err_status)
1528
  {
1529
    /* We need result only in function but not in trigger */
1530

1531
    if (!nctx->is_return_value_set())
1532
    {
1533
      my_error(ER_SP_NORETURNEND, MYF(0), m_name.str);
1534
      err_status= TRUE;
1535 1536
    }
  }
1537

1538 1539 1540
#ifndef NO_EMBEDDED_ACCESS_CHECKS
  sp_restore_security_context(thd, save_security_ctx);
#endif
1541 1542

err_with_cleanup:
1543
  delete nctx;
1544 1545
  call_arena.free_items();
  free_root(&call_mem_root, MYF(0));
1546
  thd->spcont= octx;
1547

1548
  DBUG_RETURN(err_status);
1549 1550
}

1551

1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562
/*
  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 
1563
   - changes security context for SUID routines
1564 1565
   - call sp_head::execute
   - copy back values of INOUT and OUT parameters
1566
   - restores security context
1567 1568

  RETURN
1569 1570
    FALSE  on success
    TRUE   on error
1571 1572
*/

1573 1574
bool
sp_head::execute_procedure(THD *thd, List<Item> *args)
1575
{
1576
  bool err_status= FALSE;
1577
  uint params = m_pcont->context_var_count();
1578
  sp_rcontext *save_spcont, *octx;
1579
  sp_rcontext *nctx = NULL;
unknown's avatar
unknown committed
1580
  bool save_enable_slow_log= false;
1581
  bool save_log_general= false;
1582 1583
  DBUG_ENTER("sp_head::execute_procedure");
  DBUG_PRINT("info", ("procedure %s", m_name.str));
1584

unknown's avatar
unknown committed
1585 1586
  if (args->elements != params)
  {
1587
    my_error(ER_SP_WRONG_NO_OF_ARGS, MYF(0), "PROCEDURE",
1588
             m_qname.str, params, args->elements);
1589
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
1590 1591
  }

1592
  save_spcont= octx= thd->spcont;
1593 1594
  if (! octx)
  {				// Create a temporary old context
1595 1596 1597 1598 1599 1600 1601
    if (!(octx= new sp_rcontext(m_pcont, NULL, octx)) ||
        octx->init(thd))
    {
      delete octx; /* Delete octx if it was init() that failed. */
      DBUG_RETURN(TRUE);
    }
    
1602
#ifndef DBUG_OFF
1603
    octx->sp= 0;
1604
#endif
1605 1606 1607 1608 1609 1610
    thd->spcont= octx;

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

1611 1612
  if (!(nctx= new sp_rcontext(m_pcont, NULL, octx)) ||
      nctx->init(thd))
1613
  {
1614
    delete nctx; /* Delete nctx if it was init() that failed. */
1615
    thd->spcont= save_spcont;
1616
    DBUG_RETURN(TRUE);
1617
  }
1618
#ifndef DBUG_OFF
1619
  nctx->sp= this;
1620
#endif
1621

1622
  if (params > 0)
1623
  {
1624
    List_iterator<Item> it_args(*args);
1625

1626
    DBUG_PRINT("info",(" %.*s: eval args", m_name.length, m_name.str));
1627 1628

    for (uint i= 0 ; i < params ; i++)
1629
    {
1630
      Item *arg_item= it_args++;
1631

1632 1633 1634
      if (!arg_item)
        break;

1635 1636
      sp_variable_t *spvar= m_pcont->find_variable(i);

1637
      if (!spvar)
1638 1639
        continue;

1640
      if (spvar->mode != sp_param_in)
1641
      {
1642 1643 1644 1645
        Settable_routine_parameter *srp=
          arg_item->get_settable_routine_parameter();

        if (!srp)
1646 1647 1648 1649 1650
        {
          my_error(ER_SP_NOT_VAR_ARG, MYF(0), i+1, m_qname.str);
          err_status= TRUE;
          break;
        }
1651 1652

        srp->set_required_privilege(spvar->mode == sp_param_inout);
1653 1654
      }

1655
      if (spvar->mode == sp_param_out)
1656 1657 1658 1659
      {
        Item_null *null_item= new Item_null();

        if (!null_item ||
1660
            nctx->set_variable(thd, i, (struct Item **)&null_item))
1661 1662 1663 1664 1665 1666 1667
        {
          err_status= TRUE;
          break;
        }
      }
      else
      {
1668
        if (nctx->set_variable(thd, i, it_args.ref()))
1669 1670 1671 1672
        {
          err_status= TRUE;
          break;
        }
1673
      }
1674
    }
1675

1676 1677
    /* 
      Okay, got values for all arguments. Close tables that might be used by 
1678 1679
      arguments evaluation. If arguments evaluation required prelocking mode, 
      we'll leave it here.
1680 1681
    */
    if (!thd->in_sub_stmt)
1682
      close_thread_tables(thd, 0, 0);
1683 1684

    DBUG_PRINT("info",(" %.*s: eval args done", m_name.length, m_name.str));
1685
  }
1686
  if (!(m_flags & LOG_SLOW_STATEMENTS) && thd->enable_slow_log)
unknown's avatar
unknown committed
1687 1688
  {
    DBUG_PRINT("info", ("Disabling slow log for the execution"));
1689
    save_enable_slow_log= true;
unknown's avatar
unknown committed
1690 1691
    thd->enable_slow_log= FALSE;
  }
1692 1693 1694 1695 1696 1697 1698
  if (!(m_flags & LOG_GENERAL_LOG) && !(thd->options & OPTION_LOG_OFF))
  {
    DBUG_PRINT("info", ("Disabling general log for the execution"));
    save_log_general= true;
    /* disable this bit */
    thd->options |= OPTION_LOG_OFF;
  }
1699 1700
  thd->spcont= nctx;

1701 1702 1703 1704 1705 1706
#ifndef NO_EMBEDDED_ACCESS_CHECKS
  Security_context *save_security_ctx= 0;
  if (!err_status)
    err_status= set_routine_security_ctx(thd, this, TRUE, &save_security_ctx);
#endif

1707 1708
  if (!err_status)
    err_status= execute(thd);
1709

1710 1711 1712 1713
  if (save_log_general)
    thd->options &= ~OPTION_LOG_OFF;
  if (save_enable_slow_log)
    thd->enable_slow_log= true;
1714 1715 1716 1717 1718 1719 1720
  /*
    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;
1721

1722
  if (!err_status && params > 0)
1723
  {
1724
    List_iterator<Item> it_args(*args);
1725

unknown's avatar
unknown committed
1726 1727 1728 1729
    /*
      Copy back all OUT or INOUT values to the previous frame, or
      set global user variables
    */
1730
    for (uint i= 0 ; i < params ; i++)
1731
    {
1732 1733 1734 1735 1736
      Item *arg_item= it_args++;

      if (!arg_item)
        break;

1737
      sp_variable_t *spvar= m_pcont->find_variable(i);
1738

1739
      if (spvar->mode == sp_param_in)
1740 1741
        continue;

1742 1743 1744 1745 1746
      Settable_routine_parameter *srp=
        arg_item->get_settable_routine_parameter();

      DBUG_ASSERT(srp);

1747
      if (srp->set_value(thd, octx, nctx->get_item_addr(i)))
1748
      {
1749 1750
        err_status= TRUE;
        break;
1751
      }
1752 1753 1754
    }
  }

1755 1756 1757 1758 1759
#ifndef NO_EMBEDDED_ACCESS_CHECKS
  if (save_security_ctx)
    sp_restore_security_context(thd, save_security_ctx);
#endif

1760
  if (!save_spcont)
1761
    delete octx;
1762

1763
  delete nctx;
1764
  thd->spcont= save_spcont;
1765

1766
  DBUG_RETURN(err_status);
1767 1768 1769
}


1770
// Reset lex during parsing, before we parse a sub statement.
1771 1772 1773
void
sp_head::reset_lex(THD *thd)
{
1774 1775
  DBUG_ENTER("sp_head::reset_lex");
  LEX *sublex;
1776
  LEX *oldlex= thd->lex;
1777
  my_lex_states state= oldlex->next_state; // Keep original next_state
1778

1779
  (void)m_lex.push_front(oldlex);
1780
  thd->lex= sublex= new st_lex;
unknown's avatar
unknown committed
1781

1782
  /* Reset most stuff. The length arguments doesn't matter here. */
unknown's avatar
unknown committed
1783
  lex_start(thd, oldlex->buf, (ulong) (oldlex->end_of_query - oldlex->ptr));
unknown's avatar
unknown committed
1784

1785 1786 1787 1788 1789
  /*
   * 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;
1790
  /* We must reset ptr and end_of_query again */
1791 1792 1793
  sublex->ptr= oldlex->ptr;
  sublex->end_of_query= oldlex->end_of_query;
  sublex->tok_start= oldlex->tok_start;
1794
  sublex->tok_end= oldlex->tok_end;
unknown's avatar
unknown committed
1795
  sublex->yylineno= oldlex->yylineno;
1796
  /* And keep the SP stuff too */
1797 1798
  sublex->sphead= oldlex->sphead;
  sublex->spcont= oldlex->spcont;
1799 1800
  /* And trigger related stuff too */
  sublex->trg_chistics= oldlex->trg_chistics;
1801
  sublex->trg_table_fields.empty();
1802
  sublex->sp_lex_in_use= FALSE;
1803

unknown's avatar
unknown committed
1804 1805
  sublex->in_comment= oldlex->in_comment;

1806 1807 1808 1809 1810 1811 1812 1813
  /* Reset type info. */

  sublex->charset= NULL;
  sublex->length= NULL;
  sublex->dec= NULL;
  sublex->interval_list.empty();
  sublex->type= 0;

1814
  DBUG_VOID_RETURN;
1815 1816
}

1817
// Restore lex during parsing, after we have parsed a sub statement.
1818 1819 1820
void
sp_head::restore_lex(THD *thd)
{
1821 1822
  DBUG_ENTER("sp_head::restore_lex");
  LEX *sublex= thd->lex;
1823 1824 1825 1826
  LEX *oldlex= (LEX *)m_lex.pop();

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

1828
  // Update some state in the old one first
1829
  oldlex->ptr= sublex->ptr;
1830
  oldlex->tok_end= sublex->tok_end;
1831
  oldlex->next_state= sublex->next_state;
1832
  oldlex->trg_table_fields.push_back(&sublex->trg_table_fields);
1833

unknown's avatar
unknown committed
1834 1835 1836 1837 1838 1839 1840 1841 1842 1843
#ifdef HAVE_ROW_BASED_REPLICATION
  /*
    If this substatement needs row-based, the entire routine does too (we
    cannot switch from statement-based to row-based only for this
    substatement).
  */
  if (sublex->binlog_row_based_if_mixed)
    m_flags|= BINLOG_ROW_BASED_IF_MIXED;
#endif

1844
  /*
1845 1846
    Add routines which are used by statement to respective set for
    this routine.
1847
  */
1848
  sp_update_sp_used_routines(&m_sroutines, &sublex->sroutines);
1849 1850 1851 1852 1853
  /*
    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);
1854
  if (! sublex->sp_lex_in_use)
1855 1856
  {
    lex_end(sublex);
1857
    delete sublex;
1858
  }
1859
  thd->lex= oldlex;
1860
  DBUG_VOID_RETURN;
1861 1862
}

1863
void
1864
sp_head::push_backpatch(sp_instr *i, sp_label_t *lab)
1865
{
1866
  bp_t *bp= (bp_t *)sql_alloc(sizeof(bp_t));
1867 1868 1869 1870 1871 1872 1873

  if (bp)
  {
    bp->lab= lab;
    bp->instr= i;
    (void)m_backpatch.push_front(bp);
  }
1874 1875 1876
}

void
1877
sp_head::backpatch(sp_label_t *lab)
1878
{
1879
  bp_t *bp;
1880
  uint dest= instructions();
1881
  List_iterator_fast<bp_t> li(m_backpatch);
1882

1883
  while ((bp= li++))
1884
  {
1885 1886
    if (bp->lab == lab)
      bp->instr->backpatch(dest, lab->ctx);
1887 1888 1889
  }
}

1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910
/*
  Prepare an instance of create_field for field creation (fill all necessary
  attributes).

  SYNOPSIS
    sp_head::fill_field_definition()
      thd         [IN] Thread handle
      lex         [IN] Yacc parsing context
      field_type  [IN] Field type
      field_def   [OUT] An instance of create_field to be filled

  RETURN
    FALSE  on success
    TRUE   on error
*/

bool
sp_head::fill_field_definition(THD *thd, LEX *lex,
                               enum enum_field_types field_type,
                               create_field *field_def)
{
1911
  HA_CREATE_INFO sp_db_info;
1912 1913 1914 1915
  LEX_STRING cmt = { 0, 0 };
  uint unused1= 0;
  int unused2= 0;

1916 1917
  load_db_opt_by_name(thd, m_db.str, &sp_db_info);

1918 1919 1920
  if (field_def->init(thd, (char*) "", field_type, lex->length, lex->dec,
                      lex->type, (Item*) 0, (Item*) 0, &cmt, 0,
                      &lex->interval_list,
1921 1922
                      (lex->charset ? lex->charset :
                                      sp_db_info.default_table_charset),
1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941
                      lex->uint_geom_type))
    return TRUE;

  if (field_def->interval_list.elements)
    field_def->interval= create_typelib(mem_root, field_def,
                                        &field_def->interval_list);

  sp_prepare_create_field(thd, field_def);

  if (prepare_create_field(field_def, &unused1, &unused2, &unused2,
                           HA_CAN_GEOMETRY))
  {
    return TRUE;
  }

  return FALSE;
}


1942
void
1943
sp_head::new_cont_backpatch(sp_instr_opt_meta *i)
1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954
{
  m_cont_level+= 1;
  if (i)
  {
    /* Use the cont. destination slot to store the level */
    i->m_cont_dest= m_cont_level;
    (void)m_cont_backpatch.push_front(i);
  }
}

void
1955
sp_head::add_cont_backpatch(sp_instr_opt_meta *i)
1956 1957 1958 1959 1960 1961 1962 1963 1964 1965
{
  i->m_cont_dest= m_cont_level;
  (void)m_cont_backpatch.push_front(i);
}

void
sp_head::do_cont_backpatch()
{
  uint dest= instructions();
  uint lev= m_cont_level--;
1966
  sp_instr_opt_meta *i;
1967 1968 1969 1970 1971 1972 1973 1974

  while ((i= m_cont_backpatch.head()) && i->m_cont_dest == lev)
  {
    i->m_cont_dest= dest;
    (void)m_cont_backpatch.pop();
  }
}

1975
void
1976
sp_head::set_info(longlong created, longlong modified,
1977
		  st_sp_chistics *chistics, ulong sql_mode)
1978 1979 1980
{
  m_created= created;
  m_modified= modified;
unknown's avatar
unknown committed
1981 1982
  m_chistics= (st_sp_chistics *) memdup_root(mem_root, (char*) chistics,
                                             sizeof(*chistics));
1983 1984 1985
  if (m_chistics->comment.length == 0)
    m_chistics->comment.str= 0;
  else
unknown's avatar
unknown committed
1986
    m_chistics->comment.str= strmake_root(mem_root,
1987 1988
					  m_chistics->comment.str,
					  m_chistics->comment.length);
1989
  m_sql_mode= sql_mode;
1990 1991
}

1992 1993

void
unknown's avatar
unknown committed
1994
sp_head::set_definer(const char *definer, uint definerlen)
1995
{
1996
  char user_name_holder[USERNAME_LENGTH + 1];
1997
  LEX_STRING user_name= { user_name_holder, USERNAME_LENGTH };
1998

1999
  char host_name_holder[HOSTNAME_LENGTH + 1];
2000
  LEX_STRING host_name= { host_name_holder, HOSTNAME_LENGTH };
2001

2002 2003
  parse_user(definer, definerlen, user_name.str, &user_name.length,
             host_name.str, &host_name.length);
2004

2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016
  set_definer(&user_name, &host_name);
}


void
sp_head::set_definer(const LEX_STRING *user_name, const LEX_STRING *host_name)
{
  m_definer_user.str= strmake_root(mem_root, user_name->str, user_name->length);
  m_definer_user.length= user_name->length;

  m_definer_host.str= strmake_root(mem_root, host_name->str, host_name->length);
  m_definer_host.length= host_name->length;
2017 2018 2019
}


2020 2021 2022
void
sp_head::reset_thd_mem_root(THD *thd)
{
2023
  DBUG_ENTER("sp_head::reset_thd_mem_root");
2024
  m_thd_root= thd->mem_root;
unknown's avatar
unknown committed
2025
  thd->mem_root= &main_mem_root;
2026 2027 2028
  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
2029 2030
  thd->free_list= NULL;	// Start a new one
  m_thd= thd;
2031
  DBUG_VOID_RETURN;
2032 2033 2034 2035 2036
}

void
sp_head::restore_thd_mem_root(THD *thd)
{
2037 2038
  DBUG_ENTER("sp_head::restore_thd_mem_root");
  Item *flist= free_list;	// The old list
unknown's avatar
Rename:  
unknown committed
2039
  set_query_arena(thd);         // Get new free_list and mem_root
2040
  state= INITIALIZED_FOR_SP;
2041

2042 2043
  DBUG_PRINT("info", ("mem_root 0x%lx returned from thd mem root 0x%lx",
                      (ulong) &mem_root, (ulong) &thd->mem_root));
2044 2045 2046
  thd->free_list= flist;	// Restore the old one
  thd->mem_root= m_thd_root;
  m_thd= NULL;
2047
  DBUG_VOID_RETURN;
2048 2049 2050
}


2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065
/*
  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)
2066 2067 2068 2069 2070
{
  TABLE_LIST tables;
  bzero((char*) &tables,sizeof(tables));
  tables.db= (char*) "mysql";
  tables.table_name= tables.alias= (char*) "proc";
2071
  *full_access= (!check_table_access(thd, SELECT_ACL, &tables, 1) ||
2072 2073 2074 2075
                 (!strcmp(sp->m_definer_user.str,
                          thd->security_ctx->priv_user) &&
                  !strcmp(sp->m_definer_host.str,
                          thd->security_ctx->priv_host)));
2076
  if (!*full_access)
2077 2078
    return check_some_routine_access(thd, sp->m_db.str, sp->m_name.str,
                                     sp->m_type == TYPE_ENUM_PROCEDURE);
2079 2080 2081 2082
  return 0;
}


unknown's avatar
unknown committed
2083 2084 2085 2086 2087 2088 2089 2090
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;
2091 2092
  byte *sql_mode_str;
  ulong sql_mode_len;
2093
  bool full_access;
unknown's avatar
unknown committed
2094 2095
  DBUG_ENTER("sp_head::show_create_procedure");
  DBUG_PRINT("info", ("procedure %s", m_name.str));
unknown's avatar
unknown committed
2096

2097 2098
  LINT_INIT(sql_mode_str);
  LINT_INIT(sql_mode_len);
2099

2100
  if (check_show_routine_access(thd, this, &full_access))
unknown's avatar
unknown committed
2101
    DBUG_RETURN(1);
2102

2103 2104 2105 2106
  sql_mode_str=
    sys_var_thd_sql_mode::symbolic_mode_representation(thd,
                                                       m_sql_mode,
                                                       &sql_mode_len);
2107
  field_list.push_back(new Item_empty_string("Procedure", NAME_LEN));
2108
  field_list.push_back(new Item_empty_string("sql_mode", sql_mode_len));
unknown's avatar
unknown committed
2109
  // 1024 is for not to confuse old clients
2110 2111 2112 2113 2114
  Item_empty_string *definition=
    new Item_empty_string("Create Procedure", max(buffer.length(),1024));
  definition->maybe_null= TRUE;
  field_list.push_back(definition);

2115 2116
  if (protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS |
                                         Protocol::SEND_EOF))
unknown's avatar
unknown committed
2117
    DBUG_RETURN(1);
unknown's avatar
unknown committed
2118 2119
  protocol->prepare_for_resend();
  protocol->store(m_name.str, m_name.length, system_charset_info);
2120
  protocol->store((char*) sql_mode_str, sql_mode_len, system_charset_info);
2121 2122
  if (full_access)
    protocol->store(m_defstr.str, m_defstr.length, system_charset_info);
2123 2124
  else
    protocol->store_null();
unknown's avatar
unknown committed
2125 2126
  res= protocol->write();
  send_eof(thd);
2127

unknown's avatar
unknown committed
2128 2129 2130
  DBUG_RETURN(res);
}

2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143

/*
  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;
2144 2145 2146 2147 2148 2149 2150
  /*
    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;
2151 2152 2153 2154
  insert_dynamic(&m_instr, (gptr)&instr);
}


unknown's avatar
unknown committed
2155 2156 2157 2158 2159 2160 2161 2162
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;
2163 2164
  byte *sql_mode_str;
  ulong sql_mode_len;
2165
  bool full_access;
unknown's avatar
unknown committed
2166 2167
  DBUG_ENTER("sp_head::show_create_function");
  DBUG_PRINT("info", ("procedure %s", m_name.str));
2168 2169
  LINT_INIT(sql_mode_str);
  LINT_INIT(sql_mode_len);
2170

2171
  if (check_show_routine_access(thd, this, &full_access))
unknown's avatar
unknown committed
2172
    DBUG_RETURN(1);
2173

2174 2175 2176 2177
  sql_mode_str=
    sys_var_thd_sql_mode::symbolic_mode_representation(thd,
                                                       m_sql_mode,
                                                       &sql_mode_len);
unknown's avatar
unknown committed
2178
  field_list.push_back(new Item_empty_string("Function",NAME_LEN));
2179
  field_list.push_back(new Item_empty_string("sql_mode", sql_mode_len));
2180 2181 2182 2183 2184
  Item_empty_string *definition=
    new Item_empty_string("Create Function", max(buffer.length(),1024));
  definition->maybe_null= TRUE;
  field_list.push_back(definition);

2185 2186
  if (protocol->send_fields(&field_list,
                            Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
unknown's avatar
unknown committed
2187
    DBUG_RETURN(1);
unknown's avatar
unknown committed
2188 2189
  protocol->prepare_for_resend();
  protocol->store(m_name.str, m_name.length, system_charset_info);
2190
  protocol->store((char*) sql_mode_str, sql_mode_len, system_charset_info);
2191 2192
  if (full_access)
    protocol->store(m_defstr.str, m_defstr.length, system_charset_info);
2193 2194
  else
    protocol->store_null();
unknown's avatar
unknown committed
2195 2196
  res= protocol->write();
  send_eof(thd);
2197

unknown's avatar
unknown committed
2198 2199
  DBUG_RETURN(res);
}
2200

2201 2202

/*
2203 2204 2205 2206
  Do some minimal optimization of the code:
    1) Mark used instructions
       1.1) While doing this, shortcut jumps to jump instructions
    2) Compact the code, removing unused instructions
2207 2208 2209 2210 2211 2212 2213 2214 2215

  This is the main mark and move loop; it relies on the following methods
  in sp_instr and its subclasses:

  opt_mark()           Mark instruction as reachable (will recurse for jumps)
  opt_shortcut_jump()  Shortcut jumps to the final destination;
                       used by opt_mark().
  opt_move()           Update moved instruction
  set_destination()    Set the new destination (jump instructions only)
2216 2217 2218
*/

void sp_head::optimize()
2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237
{
  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)
2238
      {                         // Move the instruction and update prev. jumps
2239 2240 2241 2242 2243
	sp_instr *ibp;
	List_iterator_fast<sp_instr> li(bp);

	set_dynamic(&m_instr, (gptr)&i, dst);
	while ((ibp= li++))
2244 2245 2246 2247
        {
          sp_instr_opt_meta *im= static_cast<sp_instr_opt_meta *>(ibp);
          im->set_destination(src, dst);
        }
2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266
      }
      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);
}

2267

unknown's avatar
unknown committed
2268
#ifndef DBUG_OFF
2269 2270 2271 2272
/*
  Return the routine instructions as a result set.
  Returns 0 if ok, !=0 on error.
*/
unknown's avatar
unknown committed
2273 2274 2275 2276 2277 2278 2279
int
sp_head::show_routine_code(THD *thd)
{
  Protocol *protocol= thd->protocol;
  char buff[2048];
  String buffer(buff, sizeof(buff), system_charset_info);
  List<Item> field_list;
2280
  sp_instr *i;
unknown's avatar
unknown committed
2281
  bool full_access;
2282
  int res= 0;
unknown's avatar
unknown committed
2283 2284
  uint ip;
  DBUG_ENTER("sp_head::show_routine_code");
2285
  DBUG_PRINT("info", ("procedure: %s", m_name.str));
unknown's avatar
unknown committed
2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299

  if (check_show_routine_access(thd, this, &full_access) || !full_access)
    DBUG_RETURN(1);

  field_list.push_back(new Item_uint("Pos", 9));
  // 1024 is for not to confuse old clients
  field_list.push_back(new Item_empty_string("Instruction",
					     max(buffer.length(), 1024)));
  if (protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS |
                                         Protocol::SEND_EOF))
    DBUG_RETURN(1);

  for (ip= 0; (i = get_instr(ip)) ; ip++)
  {
2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315
    /* 
      Consistency check. If these are different something went wrong
      during optimization.
    */
    if (ip != i->m_ip)
    {
      const char *format= "Instruction at position %u has m_ip=%u";
      char tmp[sizeof(format) + 2*SP_INSTR_UINT_MAXLEN + 1];

      sprintf(tmp, format, ip, i->m_ip);
      /*
        Since this is for debugging purposes only, we don't bother to
        introduce a special error code for it.
      */
      push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR, tmp);
    }
unknown's avatar
unknown committed
2316 2317 2318 2319 2320
    protocol->prepare_for_resend();
    protocol->store((longlong)ip);

    buffer.set("", 0, system_charset_info);
    i->print(&buffer);
2321
    protocol->store(buffer.ptr(), buffer.length(), system_charset_info);
unknown's avatar
unknown committed
2322 2323 2324 2325 2326 2327 2328 2329 2330 2331
    if ((res= protocol->write()))
      break;
  }
  send_eof(thd);

  DBUG_RETURN(res);
}
#endif // ifndef DBUG_OFF


2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371
/*
  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));
2372
  thd->query_id= next_query_id();
2373 2374
  VOID(pthread_mutex_unlock(&LOCK_thread_count));

2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394
  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);
2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410
  /*
    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);
unknown's avatar
unknown committed
2411
  thd->proc_info= 0;
2412

2413
  if (m_lex->query_tables_own_last)
2414
  {
2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427
    /*
      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.
    */
    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);
2428
  }
2429
  thd->rollback_item_tree_changes();
2430 2431 2432
  /* Update the state of the active arena. */
  thd->stmt_arena->state= Query_arena::EXECUTED;

2433 2434 2435 2436 2437 2438 2439 2440 2441 2442

  /*
    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()
  */
2443
  return res || thd->net.report_error;
2444 2445 2446
}


unknown's avatar
unknown committed
2447 2448 2449 2450
/*
  sp_instr class functions
*/

2451
int sp_instr::exec_core(THD *thd, uint *nextp)
2452
{
2453 2454
  DBUG_ASSERT(0);
  return 0;
2455 2456
}

unknown's avatar
unknown committed
2457 2458 2459 2460
/*
  sp_instr_stmt class functions
*/

2461
int
2462
sp_instr_stmt::execute(THD *thd, uint *nextp)
2463
{
2464 2465
  char *query;
  uint32 query_length;
2466
  int res;
2467
  DBUG_ENTER("sp_instr_stmt::execute");
2468
  DBUG_PRINT("info", ("command: %d", m_lex_keeper.sql_command()));
2469 2470 2471

  query= thd->query;
  query_length= thd->query_length;
2472 2473
  if (!(res= alloc_query(thd, m_query.str, m_query.length+1)) &&
      !(res=subst_spvars(thd, this, &m_query)))
2474
  {
2475 2476 2477 2478
    /*
      (the order of query cache and subst_spvars calls is irrelevant because
      queries with SP vars can't be cached)
    */
2479 2480 2481
    if (unlikely((thd->options & OPTION_LOG_OFF)==0))
      general_log_print(thd, COM_QUERY, "%s", thd->query);

2482 2483 2484
    if (query_cache_send_result_to_client(thd,
					  thd->query, thd->query_length) <= 0)
    {
2485
      res= m_lex_keeper.reset_lex_and_exec_core(thd, nextp, FALSE, this);
unknown's avatar
unknown committed
2486 2487
      if (!res && unlikely(thd->enable_slow_log))
        log_slow_statement(thd);
2488 2489
      query_cache_end_of_result(thd);
    }
2490 2491
    else
      *nextp= m_ip+1;
2492 2493 2494
    thd->query= query;
    thd->query_length= query_length;
  }
2495 2496 2497
  DBUG_RETURN(res);
}

2498

2499 2500 2501
void
sp_instr_stmt::print(String *str)
{
unknown's avatar
unknown committed
2502 2503
  uint i, len;

2504 2505
  /* stmt CMD "..." */
  if (str->reserve(SP_STMT_PRINT_MAXLEN+SP_INSTR_UINT_MAXLEN+8))
2506
    return;
2507
  str->qs_append(STRING_WITH_LEN("stmt "));
2508
  str->qs_append((uint)m_lex_keeper.sql_command());
2509
  str->qs_append(STRING_WITH_LEN(" \""));
unknown's avatar
unknown committed
2510 2511 2512 2513 2514
  len= m_query.length;
  /*
    Print the query string (but not too much of it), just to indicate which
    statement it is.
  */
2515 2516
  if (len > SP_STMT_PRINT_MAXLEN)
    len= SP_STMT_PRINT_MAXLEN-3;
unknown's avatar
unknown committed
2517 2518
  /* Copy the query string and replace '\n' with ' ' in the process */
  for (i= 0 ; i < len ; i++)
2519
  {
unknown's avatar
unknown committed
2520 2521 2522 2523
    char c= m_query.str[i];
    if (c == '\n')
      c= ' ';
    str->qs_append(c);
2524
  }
2525
  if (m_query.length > SP_STMT_PRINT_MAXLEN)
2526
    str->qs_append(STRING_WITH_LEN("...")); /* Indicate truncated string */
2527
  str->qs_append('"');
2528
}
unknown's avatar
unknown committed
2529

2530

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

unknown's avatar
unknown committed
2539 2540 2541 2542 2543

/*
  sp_instr_set class functions
*/

2544
int
2545
sp_instr_set::execute(THD *thd, uint *nextp)
2546
{
2547 2548
  DBUG_ENTER("sp_instr_set::execute");
  DBUG_PRINT("info", ("offset: %u", m_offset));
2549 2550 2551 2552

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

unknown's avatar
unknown committed
2553

2554 2555 2556
int
sp_instr_set::exec_core(THD *thd, uint *nextp)
{
2557
  int res= thd->spcont->set_variable(thd, m_offset, &m_value);
2558

2559
  if (res && thd->spcont->found_handler_here())
2560 2561
  {
    /*
2562 2563
      Failed to evaluate the value, and a handler has been found. Reset the
      variable to NULL.
2564 2565
    */

2566 2567 2568
    if (thd->spcont->set_variable(thd, m_offset, 0))
    {
      /* If this also failed, let's abort. */
2569

2570 2571
      sp_rcontext *spcont= thd->spcont;
    
2572 2573 2574 2575 2576 2577
      thd->spcont= 0;           /* Avoid handlers */
      my_error(ER_OUT_OF_RESOURCES, MYF(0));
      spcont->clear_handler();
      thd->spcont= spcont;
    }
  }
2578

2579
  *nextp = m_ip+1;
2580
  return res;
2581 2582
}

2583 2584 2585
void
sp_instr_set::print(String *str)
{
2586 2587
  /* set name@offset ... */
  int rsrv = SP_INSTR_UINT_MAXLEN+6;
2588
  sp_variable_t *var = m_ctx->find_variable(m_offset);
unknown's avatar
unknown committed
2589 2590 2591 2592

  /* 'var' should always be non-null, but just in case... */
  if (var)
    rsrv+= var->name.length;
2593 2594
  if (str->reserve(rsrv))
    return;
2595
  str->qs_append(STRING_WITH_LEN("set "));
unknown's avatar
unknown committed
2596 2597
  if (var)
  {
2598 2599
    str->qs_append(var->name.str, var->name.length);
    str->qs_append('@');
unknown's avatar
unknown committed
2600
  }
2601
  str->qs_append(m_offset);
2602
  str->qs_append(' ');
2603 2604 2605
  m_value->print(str);
}

2606

unknown's avatar
unknown committed
2607 2608 2609 2610
/*
  sp_instr_set_trigger_field class functions
*/

2611 2612 2613 2614
int
sp_instr_set_trigger_field::execute(THD *thd, uint *nextp)
{
  DBUG_ENTER("sp_instr_set_trigger_field::execute");
2615 2616 2617 2618 2619 2620 2621
  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)
{
2622
  const int res= (trigger_field->set_value(thd, &value) ? -1 : 0);
2623 2624
  *nextp = m_ip+1;
  return res;
2625 2626 2627 2628 2629
}

void
sp_instr_set_trigger_field::print(String *str)
{
2630
  str->append(STRING_WITH_LEN("set_trigger_field "));
2631
  trigger_field->print(str);
2632
  str->append(STRING_WITH_LEN(":="));
2633 2634 2635
  value->print(str);
}

unknown's avatar
unknown committed
2636 2637 2638 2639 2640

/*
 sp_instr_jump class functions
*/

2641 2642 2643 2644 2645 2646 2647 2648 2649 2650
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);
}

2651 2652 2653
void
sp_instr_jump::print(String *str)
{
2654 2655
  /* jump dest */
  if (str->reserve(SP_INSTR_UINT_MAXLEN+5))
2656
    return;
2657
  str->qs_append(STRING_WITH_LEN("jump "));
2658 2659 2660
  str->qs_append(m_dest);
}

2661 2662 2663
uint
sp_instr_jump::opt_mark(sp_head *sp)
{
2664
  m_dest= opt_shortcut_jump(sp, this);
2665 2666
  if (m_dest != m_ip+1)		/* Jumping to following instruction? */
    marked= 1;
2667 2668 2669 2670 2671
  m_optdest= sp->get_instr(m_dest);
  return m_dest;
}

uint
2672
sp_instr_jump::opt_shortcut_jump(sp_head *sp, sp_instr *start)
2673 2674 2675 2676 2677 2678
{
  uint dest= m_dest;
  sp_instr *i;

  while ((i= sp->get_instr(dest)))
  {
2679
    uint ndest;
2680

2681
    if (start == i || this == i)
2682 2683
      break;
    ndest= i->opt_shortcut_jump(sp, start);
2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700
    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;
}

unknown's avatar
unknown committed
2701 2702 2703 2704 2705

/*
  sp_instr_jump_if_not class functions
*/

2706 2707 2708
int
sp_instr_jump_if_not::execute(THD *thd, uint *nextp)
{
2709 2710
  DBUG_ENTER("sp_instr_jump_if_not::execute");
  DBUG_PRINT("info", ("destination: %u", m_dest));
2711 2712 2713 2714 2715 2716 2717
  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)
{
2718 2719
  Item *it;
  int res;
2720

2721
  it= sp_prepare_func_item(thd, &m_expr);
2722
  if (! it)
2723
  {
2724
    res= -1;
2725 2726
    *nextp = m_cont_dest;
  }
2727
  else
2728 2729
  {
    res= 0;
2730
    if (! it->val_bool())
2731 2732 2733 2734
      *nextp = m_dest;
    else
      *nextp = m_ip+1;
  }
2735 2736

  return res;
2737
}
2738

unknown's avatar
unknown committed
2739

2740 2741 2742
void
sp_instr_jump_if_not::print(String *str)
{
2743
  /* jump_if_not dest(cont) ... */
2744
  if (str->reserve(2*SP_INSTR_UINT_MAXLEN+14+32)) // Add some for the expr. too
2745
    return;
2746
  str->qs_append(STRING_WITH_LEN("jump_if_not "));
2747
  str->qs_append(m_dest);
2748
  str->qs_append('(');
2749
  str->qs_append(m_cont_dest);
2750
  str->qs_append(STRING_WITH_LEN(") "));
2751 2752 2753
  m_expr->print(str);
}

unknown's avatar
unknown committed
2754

2755 2756 2757 2758 2759 2760 2761 2762
uint
sp_instr_jump_if_not::opt_mark(sp_head *sp)
{
  sp_instr *i;

  marked= 1;
  if ((i= sp->get_instr(m_dest)))
  {
2763
    m_dest= i->opt_shortcut_jump(sp, this);
2764 2765 2766
    m_optdest= sp->get_instr(m_dest);
  }
  sp->opt_mark(m_dest);
2767 2768 2769 2770 2771 2772
  if ((i= sp->get_instr(m_cont_dest)))
  {
    m_cont_dest= i->opt_shortcut_jump(sp, this);
    m_cont_optdest= sp->get_instr(m_cont_dest);
  }
  sp->opt_mark(m_cont_dest);
2773 2774 2775
  return m_ip+1;
}

2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795
void
sp_instr_jump_if_not::opt_move(uint dst, List<sp_instr> *bp)
{
  /*
    cont. destinations may point backwards after shortcutting jumps
    during the mark phase. If it's still pointing forwards, only
    push this for backpatching if sp_instr_jump::opt_move() will not
    do it (i.e. if the m_dest points backwards).
   */
  if (m_cont_dest > m_ip)
  {                             // Forward
    if (m_dest < m_ip)
      bp->push_back(this);
  }
  else if (m_cont_optdest)
    m_cont_dest= m_cont_optdest->m_ip; // Backward
  /* This will take care of m_dest and m_ip */
  sp_instr_jump::opt_move(dst, bp);
}

unknown's avatar
unknown committed
2796 2797 2798 2799

/*
  sp_instr_freturn class functions
*/
2800

2801
int
2802
sp_instr_freturn::execute(THD *thd, uint *nextp)
2803
{
2804
  DBUG_ENTER("sp_instr_freturn::execute");
2805 2806 2807 2808 2809 2810 2811
  DBUG_RETURN(m_lex_keeper.reset_lex_and_exec_core(thd, nextp, TRUE, this));
}


int
sp_instr_freturn::exec_core(THD *thd, uint *nextp)
{
2812 2813 2814 2815
  /*
    Change <next instruction pointer>, so that this will be the last
    instruction in the stored function.
  */
2816

2817
  *nextp= UINT_MAX;
2818

2819 2820 2821 2822 2823 2824 2825 2826
  /*
    Evaluate the value of return expression and store it in current runtime
    context.

    NOTE: It's necessary to evaluate result item right here, because we must
    do it in scope of execution the current context/block.
  */

2827
  return thd->spcont->set_return_value(thd, &m_value);
2828
}
2829

2830 2831 2832
void
sp_instr_freturn::print(String *str)
{
2833 2834
  /* freturn type expr... */
  if (str->reserve(UINT_MAX+8+32)) // Add some for the expr. too
2835
    return;
2836
  str->qs_append(STRING_WITH_LEN("freturn "));
2837
  str->qs_append((uint)m_type);
2838
  str->qs_append(' ');
2839 2840 2841
  m_value->print(str);
}

unknown's avatar
unknown committed
2842 2843 2844 2845
/*
  sp_instr_hpush_jump class functions
*/

2846 2847 2848 2849 2850 2851 2852 2853
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++))
2854
    thd->spcont->push_handler(p, m_ip+1, m_type, m_frame);
2855 2856 2857 2858 2859

  *nextp= m_dest;
  DBUG_RETURN(0);
}

unknown's avatar
unknown committed
2860

2861 2862 2863
void
sp_instr_hpush_jump::print(String *str)
{
2864 2865
  /* hpush_jump dest fsize type */
  if (str->reserve(SP_INSTR_UINT_MAXLEN*2 + 21))
2866
    return;
2867
  str->qs_append(STRING_WITH_LEN("hpush_jump "));
2868
  str->qs_append(m_dest);
2869
  str->qs_append(' ');
2870
  str->qs_append(m_frame);
unknown's avatar
unknown committed
2871
  switch (m_type) {
unknown's avatar
unknown committed
2872
  case SP_HANDLER_NONE:
2873
    str->qs_append(STRING_WITH_LEN(" NONE")); // This would be a bug
unknown's avatar
unknown committed
2874 2875
    break;
  case SP_HANDLER_EXIT:
2876
    str->qs_append(STRING_WITH_LEN(" EXIT"));
unknown's avatar
unknown committed
2877 2878
    break;
  case SP_HANDLER_CONTINUE:
2879
    str->qs_append(STRING_WITH_LEN(" CONTINUE"));
unknown's avatar
unknown committed
2880 2881
    break;
  case SP_HANDLER_UNDO:
2882
    str->qs_append(STRING_WITH_LEN(" UNDO"));
unknown's avatar
unknown committed
2883 2884
    break;
  default:
unknown's avatar
unknown committed
2885 2886
    // This would be a bug as well
    str->qs_append(STRING_WITH_LEN(" UNKNOWN:"));
unknown's avatar
unknown committed
2887 2888
    str->qs_append(m_type);
  }
2889 2890
}

unknown's avatar
unknown committed
2891

2892 2893 2894 2895 2896 2897 2898 2899
uint
sp_instr_hpush_jump::opt_mark(sp_head *sp)
{
  sp_instr *i;

  marked= 1;
  if ((i= sp->get_instr(m_dest)))
  {
2900
    m_dest= i->opt_shortcut_jump(sp, this);
2901 2902 2903 2904 2905 2906
    m_optdest= sp->get_instr(m_dest);
  }
  sp->opt_mark(m_dest);
  return m_ip+1;
}

unknown's avatar
unknown committed
2907 2908 2909 2910 2911

/*
  sp_instr_hpop class functions
*/

2912 2913 2914 2915 2916 2917 2918 2919 2920
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);
}

2921 2922 2923
void
sp_instr_hpop::print(String *str)
{
2924 2925
  /* hpop count */
  if (str->reserve(SP_INSTR_UINT_MAXLEN+5))
2926
    return;
2927
  str->qs_append(STRING_WITH_LEN("hpop "));
2928 2929 2930
  str->qs_append(m_count);
}

2931

unknown's avatar
unknown committed
2932 2933 2934 2935
/*
  sp_instr_hreturn class functions
*/

2936 2937 2938 2939
int
sp_instr_hreturn::execute(THD *thd, uint *nextp)
{
  DBUG_ENTER("sp_instr_hreturn::execute");
2940 2941 2942 2943 2944 2945
  if (m_dest)
    *nextp= m_dest;
  else
  {
    *nextp= thd->spcont->pop_hstack();
  }
2946
  thd->spcont->exit_handler();
2947 2948
  DBUG_RETURN(0);
}
2949

unknown's avatar
unknown committed
2950

2951 2952 2953
void
sp_instr_hreturn::print(String *str)
{
2954 2955
  /* hreturn framesize dest */
  if (str->reserve(SP_INSTR_UINT_MAXLEN*2 + 9))
2956
    return;
2957
  str->qs_append(STRING_WITH_LEN("hreturn "));
2958
  str->qs_append(m_frame);
2959
  if (m_dest)
2960
  {
2961
    str->qs_append(' ');
2962
    str->qs_append(m_dest);
2963
  }
2964 2965
}

unknown's avatar
unknown committed
2966

2967 2968 2969 2970 2971 2972 2973 2974 2975 2976
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;
  }
2977 2978
}

2979

unknown's avatar
unknown committed
2980 2981 2982 2983
/*
  sp_instr_cpush class functions
*/

2984 2985 2986
int
sp_instr_cpush::execute(THD *thd, uint *nextp)
{
unknown's avatar
Rename:  
unknown committed
2987
  Query_arena backup_arena;
2988
  DBUG_ENTER("sp_instr_cpush::execute");
2989 2990 2991 2992 2993

  /*
    We should create cursors in the callers arena, as
    it could be (and usually is) used in several instructions.
  */
unknown's avatar
Rename:  
unknown committed
2994
  thd->set_n_backup_active_arena(thd->spcont->callers_arena, &backup_arena);
2995

2996
  thd->spcont->push_cursor(&m_lex_keeper, this);
2997

unknown's avatar
Rename:  
unknown committed
2998
  thd->restore_active_arena(thd->spcont->callers_arena, &backup_arena);
2999

3000
  *nextp= m_ip+1;
3001

3002 3003 3004
  DBUG_RETURN(0);
}

unknown's avatar
unknown committed
3005

3006 3007 3008
void
sp_instr_cpush::print(String *str)
{
unknown's avatar
unknown committed
3009 3010
  LEX_STRING n;
  my_bool found= m_ctx->find_cursor(m_cursor, &n);
3011 3012
  /* cpush name@offset */
  uint rsrv= SP_INSTR_UINT_MAXLEN+7;
unknown's avatar
unknown committed
3013

3014 3015 3016 3017
  if (found)
    rsrv+= n.length;
  if (str->reserve(rsrv))
    return;
3018
  str->qs_append(STRING_WITH_LEN("cpush "));
unknown's avatar
unknown committed
3019 3020
  if (found)
  {
3021 3022
    str->qs_append(n.str, n.length);
    str->qs_append('@');
unknown's avatar
unknown committed
3023 3024
  }
  str->qs_append(m_cursor);
3025 3026
}

unknown's avatar
unknown committed
3027 3028 3029 3030 3031

/*
  sp_instr_cpop class functions
*/

3032 3033 3034 3035 3036 3037 3038 3039 3040
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);
}

unknown's avatar
unknown committed
3041

3042 3043 3044
void
sp_instr_cpop::print(String *str)
{
3045 3046
  /* cpop count */
  if (str->reserve(SP_INSTR_UINT_MAXLEN+5))
3047
    return;
3048
  str->qs_append(STRING_WITH_LEN("cpop "));
3049 3050 3051
  str->qs_append(m_count);
}

unknown's avatar
unknown committed
3052 3053 3054 3055 3056

/*
  sp_instr_copen class functions
*/

3057 3058 3059
int
sp_instr_copen::execute(THD *thd, uint *nextp)
{
3060 3061 3062 3063
  /*
    We don't store a pointer to the cursor in the instruction to be
    able to reuse the same instruction among different threads in future.
  */
3064 3065 3066 3067 3068 3069 3070 3071
  sp_cursor *c= thd->spcont->get_cursor(m_cursor);
  int res;
  DBUG_ENTER("sp_instr_copen::execute");

  if (! c)
    res= -1;
  else
  {
3072 3073
    sp_lex_keeper *lex_keeper= c->get_lex_keeper();
    Query_arena *old_arena= thd->stmt_arena;
3074

3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093
    /*
      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.
    */
    thd->stmt_arena= c->get_instr();
    res= lex_keeper->reset_lex_and_exec_core(thd, nextp, FALSE, this);
    /* Cleanup the query's items */
    if (thd->stmt_arena->free_list)
      cleanup_items(thd->stmt_arena->free_list);
    thd->stmt_arena= old_arena;
    /*
      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.
    */
    if (!res)
    {
      uint dummy1, dummy2;
3094

3095 3096
      if (thd->spcont->found_handler(&dummy1, &dummy2))
        res= -1;
3097
    }
3098
    /* TODO: Assert here that we either have an error or a cursor */
3099 3100 3101 3102
  }
  DBUG_RETURN(res);
}

unknown's avatar
unknown committed
3103

3104 3105 3106
int
sp_instr_copen::exec_core(THD *thd, uint *nextp)
{
3107 3108
  sp_cursor *c= thd->spcont->get_cursor(m_cursor);
  int res= c->open(thd);
3109 3110 3111 3112
  *nextp= m_ip+1;
  return res;
}

3113 3114 3115
void
sp_instr_copen::print(String *str)
{
unknown's avatar
unknown committed
3116 3117
  LEX_STRING n;
  my_bool found= m_ctx->find_cursor(m_cursor, &n);
3118 3119
  /* copen name@offset */
  uint rsrv= SP_INSTR_UINT_MAXLEN+7;
unknown's avatar
unknown committed
3120

3121 3122 3123 3124
  if (found)
    rsrv+= n.length;
  if (str->reserve(rsrv))
    return;
3125
  str->qs_append(STRING_WITH_LEN("copen "));
unknown's avatar
unknown committed
3126 3127
  if (found)
  {
3128 3129
    str->qs_append(n.str, n.length);
    str->qs_append('@');
unknown's avatar
unknown committed
3130
  }
3131 3132 3133
  str->qs_append(m_cursor);
}

unknown's avatar
unknown committed
3134 3135 3136 3137 3138

/*
  sp_instr_cclose class functions
*/

3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153
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);
}

unknown's avatar
unknown committed
3154

3155 3156 3157
void
sp_instr_cclose::print(String *str)
{
unknown's avatar
unknown committed
3158 3159
  LEX_STRING n;
  my_bool found= m_ctx->find_cursor(m_cursor, &n);
3160 3161
  /* cclose name@offset */
  uint rsrv= SP_INSTR_UINT_MAXLEN+8;
unknown's avatar
unknown committed
3162

3163 3164 3165 3166
  if (found)
    rsrv+= n.length;
  if (str->reserve(rsrv))
    return;
3167
  str->qs_append(STRING_WITH_LEN("cclose "));
unknown's avatar
unknown committed
3168 3169
  if (found)
  {
3170 3171
    str->qs_append(n.str, n.length);
    str->qs_append('@');
unknown's avatar
unknown committed
3172
  }
3173 3174 3175
  str->qs_append(m_cursor);
}

unknown's avatar
unknown committed
3176 3177 3178 3179 3180

/*
  sp_instr_cfetch class functions
*/

3181 3182 3183 3184 3185
int
sp_instr_cfetch::execute(THD *thd, uint *nextp)
{
  sp_cursor *c= thd->spcont->get_cursor(m_cursor);
  int res;
unknown's avatar
Rename:  
unknown committed
3186
  Query_arena backup_arena;
3187 3188
  DBUG_ENTER("sp_instr_cfetch::execute");

3189
  res= c ? c->fetch(thd, &m_varlist) : -1;
3190

3191 3192 3193
  *nextp= m_ip+1;
  DBUG_RETURN(res);
}
3194

unknown's avatar
unknown committed
3195

3196 3197 3198
void
sp_instr_cfetch::print(String *str)
{
3199 3200
  List_iterator_fast<struct sp_variable> li(m_varlist);
  sp_variable_t *pv;
unknown's avatar
unknown committed
3201 3202
  LEX_STRING n;
  my_bool found= m_ctx->find_cursor(m_cursor, &n);
3203 3204
  /* cfetch name@offset vars... */
  uint rsrv= SP_INSTR_UINT_MAXLEN+8;
3205

3206 3207 3208 3209
  if (found)
    rsrv+= n.length;
  if (str->reserve(rsrv))
    return;
3210
  str->qs_append(STRING_WITH_LEN("cfetch "));
unknown's avatar
unknown committed
3211 3212
  if (found)
  {
3213 3214
    str->qs_append(n.str, n.length);
    str->qs_append('@');
unknown's avatar
unknown committed
3215
  }
3216 3217 3218
  str->qs_append(m_cursor);
  while ((pv= li++))
  {
3219
    if (str->reserve(pv->name.length+SP_INSTR_UINT_MAXLEN+2))
3220 3221 3222 3223
      return;
    str->qs_append(' ');
    str->qs_append(pv->name.str, pv->name.length);
    str->qs_append('@');
3224 3225 3226 3227
    str->qs_append(pv->offset);
  }
}

unknown's avatar
unknown committed
3228 3229 3230 3231 3232

/*
  sp_instr_error class functions
*/

3233 3234 3235 3236 3237
int
sp_instr_error::execute(THD *thd, uint *nextp)
{
  DBUG_ENTER("sp_instr_error::execute");

unknown's avatar
unknown committed
3238
  my_message(m_errcode, ER(m_errcode), MYF(0));
3239 3240 3241 3242
  *nextp= m_ip+1;
  DBUG_RETURN(-1);
}

unknown's avatar
unknown committed
3243

3244 3245 3246
void
sp_instr_error::print(String *str)
{
3247 3248
  /* error code */
  if (str->reserve(SP_INSTR_UINT_MAXLEN+6))
3249
    return;
3250
  str->qs_append(STRING_WITH_LEN("error "));
3251 3252 3253
  str->qs_append(m_errcode);
}

3254

3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270
/**************************************************************************
  sp_instr_set_case_expr class implementation
**************************************************************************/

int
sp_instr_set_case_expr::execute(THD *thd, uint *nextp)
{
  DBUG_ENTER("sp_instr_set_case_expr::execute");

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


int
sp_instr_set_case_expr::exec_core(THD *thd, uint *nextp)
{
3271
  int res= thd->spcont->set_case_expr(thd, m_case_expr_id, &m_case_expr);
3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284

  if (res &&
      !thd->spcont->get_case_expr(m_case_expr_id) &&
      thd->spcont->found_handler_here())
  {
    /*
      Failed to evaluate the value, the case expression is still not
      initialized, and a handler has been found. Set to NULL so we can continue.
    */

    Item *null_item= new Item_null();
    
    if (!null_item ||
3285
        thd->spcont->set_case_expr(thd, m_case_expr_id, &null_item))
3286 3287 3288 3289 3290 3291 3292 3293 3294 3295
    {
      /* If this also failed, we have to abort. */

      sp_rcontext *spcont= thd->spcont;
    
      thd->spcont= 0;           /* Avoid handlers */
      my_error(ER_OUT_OF_RESOURCES, MYF(0));
      spcont->clear_handler();
      thd->spcont= spcont;
    }
3296
    *nextp= m_cont_dest;        /* For continue handler */
3297
  }
3298 3299
  else
    *nextp= m_ip+1;
3300

3301
  return res;
3302 3303 3304 3305 3306 3307
}


void
sp_instr_set_case_expr::print(String *str)
{
3308 3309 3310 3311 3312
  /* set_case_expr (cont) id ... */
  str->reserve(2*SP_INSTR_UINT_MAXLEN+18+32); // Add some extra for expr too
  str->qs_append(STRING_WITH_LEN("set_case_expr ("));
  str->qs_append(m_cont_dest);
  str->qs_append(STRING_WITH_LEN(") "));
3313
  str->qs_append(m_case_expr_id);
3314
  str->qs_append(' ');
3315 3316 3317
  m_case_expr->print(str);
}

3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342
uint
sp_instr_set_case_expr::opt_mark(sp_head *sp)
{
  sp_instr *i;

  marked= 1;
  if ((i= sp->get_instr(m_cont_dest)))
  {
    m_cont_dest= i->opt_shortcut_jump(sp, this);
    m_cont_optdest= sp->get_instr(m_cont_dest);
  }
  sp->opt_mark(m_cont_dest);
  return m_ip+1;
}

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

3343

unknown's avatar
unknown committed
3344
/* ------------------------------------------------------------------ */
3345

unknown's avatar
unknown committed
3346 3347 3348
/*
  Security context swapping
*/
3349

3350
#ifndef NO_EMBEDDED_ACCESS_CHECKS
3351
bool
3352
sp_change_security_context(THD *thd, sp_head *sp, Security_context **backup)
3353
{
3354
  *backup= 0;
3355 3356 3357 3358 3359
  if (sp->m_chistics->suid != SP_IS_NOT_SUID &&
      (strcmp(sp->m_definer_user.str,
              thd->security_ctx->priv_user) ||
       my_strcasecmp(system_charset_info, sp->m_definer_host.str,
                     thd->security_ctx->priv_host)))
3360
  {
3361 3362 3363 3364 3365 3366 3367 3368
    if (acl_getroot_no_password(&sp->m_security_ctx, sp->m_definer_user.str,
                                sp->m_definer_host.str,
                                sp->m_definer_host.str,
                                sp->m_db.str))
    {
      my_error(ER_NO_SUCH_USER, MYF(0), sp->m_definer_user.str,
               sp->m_definer_host.str);
      return TRUE;
3369
    }
3370 3371
    *backup= thd->security_ctx;
    thd->security_ctx= &sp->m_security_ctx;
3372
  }
3373
  return FALSE;
3374 3375 3376
}

void
3377
sp_restore_security_context(THD *thd, Security_context *backup)
3378
{
3379 3380
  if (backup)
    thd->security_ctx= backup;
3381
}
3382 3383

#endif /* NO_EMBEDDED_ACCESS_CHECKS */
3384 3385

/*
3386 3387 3388 3389
  Structure that represent all instances of one table
  in optimized multi-set of tables used by routine.
*/

3390 3391
typedef struct st_sp_table
{
3392 3393 3394 3395 3396 3397 3398 3399
  /*
    Multi-set key:
      db_name\0table_name\0alias\0 - for normal tables
      db_name\0table_name\0        - for temporary tables
    Note that in both cases we don't take last '\0' into account when
    we count length of key.
  */
  LEX_STRING qname;
unknown's avatar
unknown committed
3400 3401 3402
  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 */
3403 3404
  uint lock_count;
  uint query_lock_count;
3405 3406 3407 3408 3409 3410 3411 3412 3413 3414
} 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;
}

3415

3416
/*
3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435
  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
*/

3436
bool
3437
sp_head::merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check)
3438
{
3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450
  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;
  }

3451
  for (; table ; table= table->next_global)
3452
    if (!table->derived && !table->schema_table)
3453
    {
unknown's avatar
unknown committed
3454
      char tname[(NAME_LEN + 1) * 3];           // db\0table\0alias\0
3455 3456 3457 3458
      uint tlen, alen;

      tlen= table->db_length;
      memcpy(tname, table->db, tlen);
unknown's avatar
unknown committed
3459
      tname[tlen++]= '\0';
3460 3461
      memcpy(tname+tlen, table->table_name, table->table_name_length);
      tlen+= table->table_name_length;
unknown's avatar
unknown committed
3462
      tname[tlen++]= '\0';
3463 3464 3465 3466 3467
      alen= strlen(table->alias);
      memcpy(tname+tlen, table->alias, alen);
      tlen+= alen;
      tname[tlen]= '\0';

3468
      /*
3469 3470 3471
        We ignore alias when we check if table was already marked as temporary
        (and therefore should not be prelocked). Otherwise we will erroneously
        treat table with same name but with different alias as non-temporary.
3472
      */
3473 3474 3475 3476
      if ((tab= (SP_TABLE *)hash_search(&m_sptabs, (byte *)tname, tlen)) ||
          ((tab= (SP_TABLE *)hash_search(&m_sptabs, (byte *)tname,
                                        tlen - alen - 1)) &&
           tab->temp))
3477
      {
3478 3479
        if (tab->lock_type < table->lock_type)
          tab->lock_type= table->lock_type; // Use the table with the highest lock type
3480 3481 3482
        tab->query_lock_count++;
        if (tab->query_lock_count > tab->lock_count)
          tab->lock_count++;
3483 3484 3485 3486 3487
      }
      else
      {
	if (!(tab= (SP_TABLE *)thd->calloc(sizeof(SP_TABLE))))
	  return FALSE;
3488
	if (lex_for_tmp_check->sql_command == SQLCOM_CREATE_TABLE &&
3489 3490
	    lex_for_tmp_check->query_tables == table &&
	    lex_for_tmp_check->create_info.options & HA_LEX_CREATE_TMP_TABLE)
3491
        {
3492
	  tab->temp= TRUE;
3493 3494 3495 3496 3497 3498 3499
          tab->qname.length= tlen - alen - 1;
        }
        else
          tab->qname.length= tlen;
        tab->qname.str= (char*) thd->memdup(tname, tab->qname.length + 1);
        if (!tab->qname.str)
          return FALSE;
unknown's avatar
unknown committed
3500 3501
        tab->table_name_length= table->table_name_length;
        tab->db_length= table->db_length;
3502
        tab->lock_type= table->lock_type;
3503 3504
        tab->lock_count= tab->query_lock_count= 1;
	my_hash_insert(&m_sptabs, (byte *)tab);
3505 3506 3507 3508 3509 3510
      }
    }
  return TRUE;
}


3511 3512
/*
  Add tables used by routine to the table list.
3513

3514 3515
  SYNOPSIS
    add_used_tables_to_table_list()
3516 3517 3518 3519 3520 3521
      thd                    [in]     Thread context
      query_tables_last_ptr  [in/out] Pointer to the next_global member of
                                      last element of the list where tables
                                      will be added (or to its root).
      belong_to_view         [in]     Uppermost view which uses this routine,
                                      0 if none.
3522

3523 3524 3525
  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'.
3526

3527 3528
    Elements of list will be allocated in PS memroot, so this list will be
    persistent between PS executions.
3529

3530 3531 3532
  RETURN VALUE
    TRUE - if some elements were added, FALSE - otherwise.
*/
3533

3534 3535
bool
sp_head::add_used_tables_to_table_list(THD *thd,
3536 3537
                                       TABLE_LIST ***query_tables_last_ptr,
                                       TABLE_LIST *belong_to_view)
3538 3539
{
  uint i;
unknown's avatar
unknown committed
3540
  Query_arena *arena, backup;
3541 3542 3543 3544
  bool result= FALSE;
  DBUG_ENTER("sp_head::add_used_tables_to_table_list");

  /*
3545 3546 3547 3548 3549 3550
    Use persistent arena for table list allocation to be PS/SP friendly.
    Note that we also have to copy database/table names and alias to PS/SP
    memory since current instance of sp_head object can pass away before
    next execution of PS/SP for which tables are added to prelocking list.
    This will be fixed by introducing of proper invalidation mechanism
    once new TDC is ready.
3551
  */
unknown's avatar
Rename:  
unknown committed
3552
  arena= thd->activate_stmt_arena_if_needed(&backup);
3553

3554
  for (i=0 ; i < m_sptabs.records ; i++)
3555
  {
3556
    char *tab_buff, *key_buff;
unknown's avatar
unknown committed
3557
    TABLE_LIST *table;
3558
    SP_TABLE *stab= (SP_TABLE *)hash_element(&m_sptabs, i);
3559 3560 3561
    if (stab->temp)
      continue;

3562
    if (!(tab_buff= (char *)thd->calloc(ALIGN_SIZE(sizeof(TABLE_LIST)) *
3563 3564 3565
                                        stab->lock_count)) ||
        !(key_buff= (char*)thd->memdup(stab->qname.str,
                                       stab->qname.length + 1)))
3566
      DBUG_RETURN(FALSE);
3567

3568 3569 3570 3571
    for (uint j= 0; j < stab->lock_count; j++)
    {
      table= (TABLE_LIST *)tab_buff;

3572
      table->db= key_buff;
unknown's avatar
unknown committed
3573 3574 3575 3576
      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;
3577
      table->lock_type= stab->lock_type;
3578 3579
      table->cacheable_table= 1;
      table->prelocking_placeholder= 1;
3580
      table->belong_to_view= belong_to_view;
3581 3582 3583 3584 3585 3586 3587 3588 3589 3590

      /* 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;
    }
3591
  }
3592 3593

  if (arena)
unknown's avatar
Rename:  
unknown committed
3594
    thd->restore_active_arena(arena, &backup);
3595 3596

  DBUG_RETURN(result);
3597 3598
}

unknown's avatar
unknown committed
3599

3600
/*
unknown's avatar
unknown committed
3601 3602 3603 3604
  Simple function for adding an explicetly named (systems) table to
  the global table list, e.g. "mysql", "proc".
*/

3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622
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;
3623
  table->select_lex= lex->current_select;
3624 3625 3626 3627 3628
  table->cacheable_table= 1;
  
  lex->add_to_query_tables(table);
  return table;
}
3629