sp_head.cc 112 KB
Newer Older
Marc Alff's avatar
Marc Alff committed
1
/* Copyright 2002-2008 MySQL AB, 2008-2010 Sun Microsystems, Inc.
2 3 4

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
unknown's avatar
unknown committed
5
   the Free Software Foundation; version 2 of the License.
6 7 8 9 10 11 12 13 14 15

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

16
#include "my_global.h"                          /* NO_EMBEDDED_ACCESS_CHECKS */
17 18
#include "sql_priv.h"
#include "unireg.h"
19
#include "sql_prepare.h"
20
#include "sql_cache.h"                          // query_cache_*
21
#include "probes_mysql.h"
22 23 24 25 26 27 28 29
#include "sql_show.h"                           // append_identifier
#include "sql_db.h"            // mysql_opt_change_db, mysql_change_db
#include "sql_table.h"         // sp_prepare_create_field,
                               // prepare_create_field
#include "sql_acl.h"           // *_ACL
#include "sql_array.h"         // Dynamic_array
#include "log_event.h"         // append_query_string, Query_log_event

30
#ifdef USE_PRAGMA_IMPLEMENTATION
31 32 33
#pragma implementation
#endif
#include "sp_head.h"
34
#include "sp.h"
35 36
#include "sp_pcontext.h"
#include "sp_rcontext.h"
37
#include "sp_cache.h"
38
#include "set_var.h"
39 40
#include "sql_parse.h"                          // cleanup_items
#include "sql_base.h"                           // close_thread_tables
41
#include "transaction.h"       // trans_commit_stmt
42

unknown's avatar
unknown committed
43 44 45 46 47 48 49
/*
  Sufficient max length of printed destinations and frame offsets (all uints).
*/
#define SP_INSTR_UINT_MAXLEN  8
#define SP_STMT_PRINT_MAXLEN 40


50 51
#include <my_user.h>

52 53
extern "C" uchar *sp_table_key(const uchar *ptr, size_t *plen, my_bool first);

54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
/**
  Helper function which operates on a THD object to set the query start_time to
  the current time.

  @param[in, out] thd The session object

*/

static void reset_start_time_for_sp(THD *thd)
{
  if (!thd->in_sub_stmt)
  {
    /*
      First investigate if there is a cached time stamp
    */
    if (thd->user_time)
    {
      thd->start_time= thd->user_time;
    }
    else
    {
      my_micro_time_and_time(&thd->start_time);
    }
  }
}

80 81 82
Item_result
sp_map_result_type(enum enum_field_types type)
{
83
  switch (type) {
84
  case MYSQL_TYPE_BIT:
85 86 87 88 89 90 91
  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
92 93
  case MYSQL_TYPE_NEWDECIMAL:
    return DECIMAL_RESULT;
94 95 96 97 98 99 100 101
  case MYSQL_TYPE_FLOAT:
  case MYSQL_TYPE_DOUBLE:
    return REAL_RESULT;
  default:
    return STRING_RESULT;
  }
}

102 103 104 105 106

Item::Type
sp_map_item_type(enum enum_field_types type)
{
  switch (type) {
107
  case MYSQL_TYPE_BIT:
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
  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;
  }
}


unknown's avatar
unknown committed
126
/**
127 128
  Return a string representation of the Item value.

unknown's avatar
unknown committed
129 130
  @param thd     thread handle
  @param str     string buffer for representation of the value
131

unknown's avatar
unknown committed
132 133 134
  @note
    If the item has a string result type, the string is escaped
    according to its character set.
135

unknown's avatar
unknown committed
136 137 138 139
  @retval
    NULL      on error
  @retval
    non-NULL  a pointer to valid a valid string on success
140 141 142
*/

static String *
143
sp_get_item_value(THD *thd, Item *item, String *str)
144 145 146 147 148
{
  switch (item->result_type()) {
  case REAL_RESULT:
  case INT_RESULT:
  case DECIMAL_RESULT:
149 150 151
    if (item->field_type() != MYSQL_TYPE_BIT)
      return item->val_str(str);
    else {/* Bit type is handled as binary string */}
152 153 154
  case STRING_RESULT:
    {
      String *result= item->val_str(str);
Davi Arnaut's avatar
Davi Arnaut committed
155

156 157
      if (!result)
        return NULL;
Davi Arnaut's avatar
Davi Arnaut committed
158

159 160 161
      {
        char buf_holder[STRING_BUFFER_USUAL_SIZE];
        String buf(buf_holder, sizeof(buf_holder), result->charset());
162
        CHARSET_INFO *cs= thd->variables.character_set_client;
163 164 165 166 167 168

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

        buf.append('_');
        buf.append(result->charset()->csname);
169
        if (cs->escape_with_backslash_is_dangerous)
170
          buf.append(' ');
171
        append_query_string(cs, result, &buf);
172 173 174
        buf.append(" COLLATE '");
        buf.append(item->collation.collation->name);
        buf.append('\'');
175 176 177 178
        str->copy(buf);

        return str;
      }
179 180 181 182 183 184 185 186 187
    }

  case ROW_RESULT:
  default:
    return NULL;
  }
}


unknown's avatar
unknown committed
188 189 190 191 192 193
/**
   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.
194 195 196 197
*/

uint
sp_get_flags_for_command(LEX *lex)
198
{
199 200 201 202 203 204 205 206 207 208
  uint flags;

  switch (lex->sql_command) {
  case SQLCOM_SELECT:
    if (lex->result)
    {
      flags= 0;                      /* This is a SELECT with INTO clause */
      break;
    }
    /* fallthrough */
209
  case SQLCOM_ANALYZE:
210 211 212
  case SQLCOM_OPTIMIZE:
  case SQLCOM_PRELOAD_KEYS:
  case SQLCOM_ASSIGN_TO_KEYCACHE:
213
  case SQLCOM_CHECKSUM:
214
  case SQLCOM_CHECK:
215
  case SQLCOM_HA_READ:
216
  case SQLCOM_SHOW_AUTHORS:
217 218
  case SQLCOM_SHOW_BINLOGS:
  case SQLCOM_SHOW_BINLOG_EVENTS:
219
  case SQLCOM_SHOW_RELAYLOG_EVENTS:
220 221
  case SQLCOM_SHOW_CHARSETS:
  case SQLCOM_SHOW_COLLATIONS:
222
  case SQLCOM_SHOW_CONTRIBUTORS:
223 224 225 226
  case SQLCOM_SHOW_CREATE:
  case SQLCOM_SHOW_CREATE_DB:
  case SQLCOM_SHOW_CREATE_FUNC:
  case SQLCOM_SHOW_CREATE_PROC:
227
  case SQLCOM_SHOW_CREATE_EVENT:
unknown's avatar
unknown committed
228
  case SQLCOM_SHOW_CREATE_TRIGGER:
229 230 231
  case SQLCOM_SHOW_DATABASES:
  case SQLCOM_SHOW_ERRORS:
  case SQLCOM_SHOW_FIELDS:
232
  case SQLCOM_SHOW_FUNC_CODE:
233
  case SQLCOM_SHOW_GRANTS:
234 235 236
  case SQLCOM_SHOW_ENGINE_STATUS:
  case SQLCOM_SHOW_ENGINE_LOGS:
  case SQLCOM_SHOW_ENGINE_MUTEX:
237
  case SQLCOM_SHOW_EVENTS:
238 239 240 241 242 243
  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:
244
  case SQLCOM_SHOW_PROC_CODE:
245 246 247 248 249 250 251
  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:
252
  case SQLCOM_SHOW_TABLE_STATUS:
253 254
  case SQLCOM_SHOW_VARIABLES:
  case SQLCOM_SHOW_WARNS:
255
  case SQLCOM_REPAIR:
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
    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;
271 272 273 274 275 276 277 278 279 280 281 282
  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;
283 284 285 286 287 288
  case SQLCOM_FLUSH:
    flags= sp_head::HAS_SQLCOM_FLUSH;
    break;
  case SQLCOM_RESET:
    flags= sp_head::HAS_SQLCOM_RESET;
    break;
289 290 291 292 293 294
  case SQLCOM_CREATE_INDEX:
  case SQLCOM_CREATE_DB:
  case SQLCOM_CREATE_VIEW:
  case SQLCOM_CREATE_TRIGGER:
  case SQLCOM_CREATE_USER:
  case SQLCOM_ALTER_TABLE:
295 296
  case SQLCOM_GRANT:
  case SQLCOM_REVOKE:
297 298 299 300 301
  case SQLCOM_BEGIN:
  case SQLCOM_RENAME_TABLE:
  case SQLCOM_RENAME_USER:
  case SQLCOM_DROP_INDEX:
  case SQLCOM_DROP_DB:
302
  case SQLCOM_REVOKE_ALL:
303 304 305 306 307 308
  case SQLCOM_DROP_USER:
  case SQLCOM_DROP_VIEW:
  case SQLCOM_DROP_TRIGGER:
  case SQLCOM_TRUNCATE:
  case SQLCOM_COMMIT:
  case SQLCOM_ROLLBACK:
309
  case SQLCOM_LOAD:
310 311 312 313 314 315 316
  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:
317 318 319
  case SQLCOM_CREATE_EVENT:
  case SQLCOM_ALTER_EVENT:
  case SQLCOM_DROP_EVENT:
320 321
  case SQLCOM_INSTALL_PLUGIN:
  case SQLCOM_UNINSTALL_PLUGIN:
322 323
    flags= sp_head::HAS_COMMIT_OR_ROLLBACK;
    break;
324
  default:
325 326
    flags= 0;
    break;
327
  }
328
  return flags;
329 330
}

unknown's avatar
unknown committed
331
/**
332
  Prepare an Item for evaluation (call of fix_fields).
333

unknown's avatar
unknown committed
334 335
  @param thd       thread handler
  @param it_addr   pointer on item refernce
336

unknown's avatar
unknown committed
337 338 339 340
  @retval
    NULL      error
  @retval
    non-NULL  prepared item
341 342
*/

343
Item *
344 345 346
sp_prepare_func_item(THD* thd, Item **it_addr)
{
  DBUG_ENTER("sp_prepare_func_item");
347
  it_addr= (*it_addr)->this_item_addr(thd, it_addr);
348

349 350 351
  if (!(*it_addr)->fixed &&
      ((*it_addr)->fix_fields(thd, it_addr) ||
       (*it_addr)->check_cols(1)))
352 353 354 355 356 357 358 359
  {
    DBUG_PRINT("info", ("fix_fields() failed"));
    DBUG_RETURN(NULL);
  }
  DBUG_RETURN(*it_addr);
}


unknown's avatar
unknown committed
360
/**
361
  Evaluate an expression and store the result in the field.
362

unknown's avatar
unknown committed
363 364 365
  @param thd                    current thread object
  @param result_field           the field to store the result
  @param expr_item_ptr          the root item of the expression
366

unknown's avatar
unknown committed
367
  @retval
368
    FALSE  on success
unknown's avatar
unknown committed
369
  @retval
370
    TRUE   on error
371
*/
372

373
bool
374
sp_eval_expr(THD *thd, Field *result_field, Item **expr_item_ptr)
375
{
376
  Item *expr_item;
377 378 379 380
  enum_check_fields save_count_cuted_fields= thd->count_cuted_fields;
  bool save_abort_on_warning= thd->abort_on_warning;
  bool save_stmt_modified_non_trans_table= 
    thd->transaction.stmt.modified_non_trans_table;
381

382
  DBUG_ENTER("sp_eval_expr");
383

unknown's avatar
unknown committed
384
  if (!*expr_item_ptr)
385
    goto error;
unknown's avatar
unknown committed
386

387
  if (!(expr_item= sp_prepare_func_item(thd, expr_item_ptr)))
388
    goto error;
389

390 391 392
  /*
    Set THD flags to emit warnings/errors in case of overflow/type errors
    during saving the item into the field.
393

394 395
    Save original values and restore them after save.
  */
Davi Arnaut's avatar
Davi Arnaut committed
396

397 398 399 400
  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);
unknown's avatar
unknown committed
401
  thd->transaction.stmt.modified_non_trans_table= FALSE;
402

403
  /* Save the value in the field. Convert the value if needed. */
404

405
  expr_item->save_in_field(result_field, 0);
406

407 408
  thd->count_cuted_fields= save_count_cuted_fields;
  thd->abort_on_warning= save_abort_on_warning;
unknown's avatar
unknown committed
409
  thd->transaction.stmt.modified_non_trans_table= save_stmt_modified_non_trans_table;
410

411 412
  if (!thd->is_error())
    DBUG_RETURN(FALSE);
413

414 415 416 417 418 419 420 421 422
error:
  /*
    In case of error during evaluation, leave the result field set to NULL.
    Sic: we can't do it in the beginning of the function because the 
    result field might be needed for its own re-evaluation, e.g. case of 
    set x = x + 1;
  */
  result_field->set_null();
  DBUG_RETURN (TRUE);
423 424
}

425

Konstantin Osipov's avatar
Konstantin Osipov committed
426 427
/**
  Create temporary sp_name object from MDL key.
428

Konstantin Osipov's avatar
Konstantin Osipov committed
429 430 431 432 433 434 435 436 437 438
  @note The lifetime of this object is bound to the lifetime of the MDL_key.
        This should be fine as sp_name objects created by this constructor
        are mainly used for SP-cache lookups.

  @param key         MDL key containing database and routine name.
  @param qname_buff  Buffer to be used for storing quoted routine name
                     (should be at least 2*NAME_LEN+1+1 bytes).
*/

sp_name::sp_name(const MDL_key *key, char *qname_buff)
439
{
Konstantin Osipov's avatar
Konstantin Osipov committed
440 441 442 443 444 445
  m_db.str= (char*)key->db_name();
  m_db.length= key->db_name_length();
  m_name.str= (char*)key->name();
  m_name.length= key->name_length();
  m_qname.str= qname_buff;
  if (m_db.length)
446
  {
Konstantin Osipov's avatar
Konstantin Osipov committed
447 448
    strxmov(qname_buff, m_db.str, ".", m_name.str, NullS);
    m_qname.length= m_db.length + 1 + m_name.length;
449 450 451
  }
  else
  {
Konstantin Osipov's avatar
Konstantin Osipov committed
452 453
    strmov(qname_buff, m_name.str);
    m_qname.length= m_name.length;
454 455 456 457
  }
  m_explicit_name= false;
}

458

unknown's avatar
unknown committed
459 460 461
/**
  Init the qualified name from the db and name.
*/
462 463 464
void
sp_name::init_qname(THD *thd)
{
465
  const uint dot= !!m_db.length;
Konstantin Osipov's avatar
Konstantin Osipov committed
466 467 468
  /* m_qname format: [database + dot] + name + '\0' */
  m_qname.length= m_db.length + dot + m_name.length;
  if (!(m_qname.str= (char*) thd->alloc(m_qname.length + 1)))
469
    return;
470 471 472 473
  sprintf(m_qname.str, "%.*s%.*s%.*s",
          (int) m_db.length, (m_db.length ? m_db.str : ""),
          dot, ".",
          (int) m_name.length, m_name.str);
474 475
}

476

unknown's avatar
unknown committed
477 478
/**
  Check that the name 'ident' is ok.  It's assumed to be an 'ident'
unknown's avatar
unknown committed
479 480 481 482
  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().
unknown's avatar
unknown committed
483 484 485 486 487

  @retval
    TRUE    bad name
  @retval
    FALSE   name is ok
unknown's avatar
unknown committed
488
*/
489 490

bool
491
check_routine_name(LEX_STRING *ident)
492
{
493 494
  if (!ident || !ident->str || !ident->str[0] ||
      ident->str[ident->length-1] == ' ')
Davi Arnaut's avatar
Davi Arnaut committed
495
  {
496 497 498 499 500 501 502 503 504 505 506
    my_error(ER_SP_WRONG_NAME, MYF(0), ident->str);
    return TRUE;
  }
  if (check_string_char_length(ident, "", NAME_CHAR_LEN,
                               system_charset_info, 1))
  {
    my_error(ER_TOO_LONG_IDENT, MYF(0), ident->str);
    return TRUE;
  }

  return FALSE;
507
}
508

509 510 511 512 513 514 515

/*
 *
 *  sp_head
 *
 */

516
void *
517
sp_head::operator new(size_t size) throw()
518 519 520 521 522
{
  DBUG_ENTER("sp_head::operator new");
  MEM_ROOT own_root;
  sp_head *sp;

523
  init_sql_alloc(&own_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
unknown's avatar
unknown committed
524
  sp= (sp_head *) alloc_root(&own_root, size);
525
  if (sp == NULL)
526
    DBUG_RETURN(NULL);
unknown's avatar
unknown committed
527
  sp->main_mem_root= own_root;
528
  DBUG_PRINT("info", ("mem_root 0x%lx", (ulong) &sp->mem_root));
529 530 531
  DBUG_RETURN(sp);
}

Davi Arnaut's avatar
Davi Arnaut committed
532
void
unknown's avatar
unknown committed
533
sp_head::operator delete(void *ptr, size_t size) throw()
534 535 536
{
  DBUG_ENTER("sp_head::operator delete");
  MEM_ROOT own_root;
537 538 539 540

  if (ptr == NULL)
    DBUG_VOID_RETURN;

unknown's avatar
unknown committed
541
  sp_head *sp= (sp_head *) ptr;
542

unknown's avatar
unknown committed
543 544
  /* Make a copy of main_mem_root as free_root will free the sp */
  own_root= sp->main_mem_root;
545 546
  DBUG_PRINT("info", ("mem_root 0x%lx moved to 0x%lx",
                      (ulong) &sp->mem_root, (ulong) &own_root));
547 548 549 550 551
  free_root(&own_root, MYF(0));

  DBUG_VOID_RETURN;
}

552

553
sp_head::sp_head()
554
  :Query_arena(&main_mem_root, INITIALIZED_FOR_SP),
Konstantin Osipov's avatar
Konstantin Osipov committed
555 556
   m_flags(0),
   m_sp_cache_version(0),
557
   unsafe_flags(0),
Konstantin Osipov's avatar
Konstantin Osipov committed
558 559
   m_recursion_level(0),
   m_next_cached_sp(0),
560
   m_cont_level(0)
561
{
562
  const LEX_STRING str_reset= { NULL, 0 };
563 564 565 566 567

  m_first_instance= this;
  m_first_free_instance= this;
  m_last_cached_sp= this;

568
  m_return_field_def.charset = NULL;
569 570 571 572 573 574
  /*
    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;
575

576
  DBUG_ENTER("sp_head::sp_head");
577 578

  m_backpatch.empty();
579
  m_cont_backpatch.empty();
580
  m_lex.empty();
Konstantin Osipov's avatar
Konstantin Osipov committed
581 582 583
  my_hash_init(&m_sptabs, system_charset_info, 0, 0, 0, sp_table_key, 0, 0);
  my_hash_init(&m_sroutines, system_charset_info, 0, 0, 0, sp_sroutine_key,
               0, 0);
unknown's avatar
unknown committed
584 585 586 587

  m_body_utf8.str= NULL;
  m_body_utf8.length= 0;

588 589 590
  DBUG_VOID_RETURN;
}

591

592
void
593
sp_head::init(LEX *lex)
594 595
{
  DBUG_ENTER("sp_head::init");
596

597
  lex->spcont= m_pcont= new sp_pcontext();
598

599 600 601
  if (!lex->spcont)
    DBUG_VOID_RETURN;

602 603 604 605 606
  /*
    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();
607
  my_init_dynamic_array(&m_instr, sizeof(sp_instr *), 16, 8);
608 609 610 611 612 613 614 615 616

  m_param_begin= NULL;
  m_param_end= NULL;

  m_body_begin= NULL ;

  m_qname.str= NULL;
  m_qname.length= 0;

617 618
  m_explicit_name= false;

619 620 621 622 623 624 625 626 627 628 629 630 631 632 633
  m_db.str= NULL;
  m_db.length= 0;

  m_name.str= NULL;
  m_name.length= 0;

  m_params.str= NULL;
  m_params.length= 0;

  m_body.str= NULL;
  m_body.length= 0;

  m_defstr.str= NULL;
  m_defstr.length= 0;

634
  m_return_field_def.charset= NULL;
635

636 637 638
  DBUG_VOID_RETURN;
}

639

640
void
641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657
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);

658 659
  m_explicit_name= spname->m_explicit_name;

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

Konstantin Osipov's avatar
Konstantin Osipov committed
663 664 665 666
  m_qname.length= spname->m_qname.length;
  m_qname.str= (char*) memdup_root(thd->mem_root,
                                   spname->m_qname.str,
                                   spname->m_qname.length + 1);
667 668

  DBUG_VOID_RETURN;
669 670 671
}


672
void
unknown's avatar
unknown committed
673
sp_head::set_body_start(THD *thd, const char *begin_ptr)
674
{
unknown's avatar
unknown committed
675
  m_body_begin= begin_ptr;
676
  thd->m_parser_state->m_lip.body_utf8_start(thd, begin_ptr);
unknown's avatar
unknown committed
677 678 679 680 681
}


void
sp_head::set_stmt_end(THD *thd)
682
{
683
  Lex_input_stream *lip= & thd->m_parser_state->m_lip; /* shortcut */
unknown's avatar
unknown committed
684 685 686
  const char *end_ptr= lip->get_cpp_ptr(); /* shortcut */

  /* Make the string of parameters. */
687

688
  if (m_param_begin && m_param_end)
689
  {
690
    m_params.length= m_param_end - m_param_begin;
unknown's avatar
unknown committed
691
    m_params.str= thd->strmake(m_param_begin, m_params.length);
692
  }
693

unknown's avatar
unknown committed
694
  /* Remember end pointer for further dumping of whole statement. */
695

unknown's avatar
unknown committed
696 697 698 699 700 701
  thd->lex->stmt_definition_end= end_ptr;

  /* Make the string of body (in the original character set). */

  m_body.length= end_ptr - m_body_begin;
  m_body.str= thd->strmake(m_body_begin, m_body.length);
702 703
  trim_whitespace(thd->charset(), & m_body);

unknown's avatar
unknown committed
704
  /* Make the string of UTF-body. */
705

unknown's avatar
unknown committed
706 707 708 709 710 711
  lip->body_utf8_append(end_ptr);

  m_body_utf8.length= lip->get_body_utf8_length();
  m_body_utf8.str= thd->strmake(lip->get_body_utf8_str(), m_body_utf8.length);
  trim_whitespace(thd->charset(), & m_body_utf8);

712
  /*
unknown's avatar
unknown committed
713 714
    Make the string of whole stored-program-definition query (in the
    original character set).
715 716
  */

unknown's avatar
unknown committed
717 718 719
  m_defstr.length= end_ptr - lip->get_cpp_buf();
  m_defstr.str= thd->strmake(lip->get_cpp_buf(), m_defstr.length);
  trim_whitespace(thd->charset(), & m_defstr);
720 721
}

722 723

static TYPELIB *
unknown's avatar
unknown committed
724
create_typelib(MEM_ROOT *mem_root, Create_field *field_def, List<String> *src)
unknown's avatar
unknown committed
725 726
{
  TYPELIB *result= NULL;
727 728
  CHARSET_INFO *cs= field_def->charset;
  DBUG_ENTER("create_typelib");
unknown's avatar
unknown committed
729

unknown's avatar
unknown committed
730 731 732 733 734 735
  if (src->elements)
  {
    result= (TYPELIB*) alloc_root(mem_root, sizeof(TYPELIB));
    result->count= src->elements;
    result->name= "";
    if (!(result->type_names=(const char **)
736
          alloc_root(mem_root,(sizeof(char *)+sizeof(int))*(result->count+1))))
unknown's avatar
unknown committed
737 738
      DBUG_RETURN(0);
    result->type_lengths= (uint*)(result->type_names + result->count+1);
unknown's avatar
unknown committed
739
    List_iterator<String> it(*src);
unknown's avatar
unknown committed
740 741
    String conv;
    for (uint i=0; i < result->count; i++)
742
    {
unknown's avatar
unknown committed
743 744 745 746
      uint32 dummy;
      uint length;
      String *tmp= it++;

747
      if (String::needs_conversion(tmp->length(), tmp->charset(),
Davi Arnaut's avatar
Davi Arnaut committed
748
                                   cs, &dummy))
749 750 751
      {
        uint cnv_errs;
        conv.copy(tmp->ptr(), tmp->length(), tmp->charset(), cs, &cnv_errs);
unknown's avatar
unknown committed
752 753 754 755

        length= conv.length();
        result->type_names[i]= (char*) strmake_root(mem_root, conv.ptr(),
                                                    length);
756
      }
unknown's avatar
unknown committed
757 758 759 760
      else
      {
        length= tmp->length();
        result->type_names[i]= strmake_root(mem_root, tmp->ptr(), length);
761
      }
762 763

      // Strip trailing spaces.
unknown's avatar
unknown committed
764 765 766
      length= cs->cset->lengthsp(cs, result->type_names[i], length);
      result->type_lengths[i]= length;
      ((uchar *)result->type_names[i])[length]= '\0';
767
    }
unknown's avatar
unknown committed
768
    result->type_names[result->count]= 0;
769
    result->type_lengths[result->count]= 0;
unknown's avatar
unknown committed
770
  }
unknown's avatar
unknown committed
771
  DBUG_RETURN(result);
unknown's avatar
unknown committed
772 773
}

774

775 776
sp_head::~sp_head()
{
777 778
  LEX *lex;
  sp_instr *i;
unknown's avatar
unknown committed
779
  DBUG_ENTER("sp_head::~sp_head");
780

781 782
  /* sp_head::restore_thd_mem_root() must already have been called. */
  DBUG_ASSERT(m_thd == NULL);
783 784 785

  for (uint ip = 0 ; (i = get_instr(ip)) ; ip++)
    delete i;
786 787
  delete_dynamic(&m_instr);
  m_pcont->destroy();
788
  free_items();
789 790 791 792

  /*
    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
793 794
    THD::lex. It is safe to not update LEX::ptr because further query
    string parsing and execution will be stopped anyway.
795
  */
796 797
  while ((lex= (LEX *)m_lex.pop()))
  {
798
    THD *thd= lex->thd;
799
    thd->lex->sphead= NULL;
800 801 802
    lex_end(thd->lex);
    delete thd->lex;
    thd->lex= lex;
803
  }
804

Konstantin Osipov's avatar
Konstantin Osipov committed
805 806
  my_hash_free(&m_sptabs);
  my_hash_free(&m_sroutines);
807 808 809

  delete m_next_cached_sp;

810
  DBUG_VOID_RETURN;
811
}
812

unknown's avatar
unknown committed
813

unknown's avatar
unknown committed
814
/**
815 816 817 818
  This is only used for result fields from functions (both during
  fix_length_and_dec() and evaluation).
*/

unknown's avatar
unknown committed
819
Field *
820 821
sp_head::create_result_field(uint field_max_length, const char *field_name,
                             TABLE *table)
unknown's avatar
unknown committed
822
{
823
  uint field_length;
unknown's avatar
unknown committed
824
  Field *field;
825 826 827 828 829 830

  DBUG_ENTER("sp_head::create_result_field");

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

831
  field= ::make_field(table->s,                     /* TABLE_SHARE ptr */
832
                      (uchar*) 0,                   /* field ptr */
833 834 835 836 837 838 839 840 841
                      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,
842
                      field_name ? field_name : (const char *) m_name.str);
unknown's avatar
unknown committed
843 844 845

  if (field)
    field->init(table);
Davi Arnaut's avatar
Davi Arnaut committed
846

unknown's avatar
unknown committed
847 848 849
  DBUG_RETURN(field);
}

850 851 852 853 854 855 856 857 858

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


/*
  StoredRoutinesBinlogging
859 860 861
  This paragraph applies only to statement-based binlogging. Row-based
  binlogging does not need anything special like this.

862 863 864 865 866 867 868 869 870 871 872 873 874
  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).
Davi Arnaut's avatar
Davi Arnaut committed
875

876 877 878 879 880 881 882 883 884 885 886 887
  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
Davi Arnaut's avatar
Davi Arnaut committed
888 889

  In sp_head::execute_function(), we check
890 891 892
   * 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
893 894
     function execution (grep for start_union_events and stop_union_events)

895
   If the answers are No and Yes, we write the function call into the binary
896
   log as "SELECT spfunc(<param1value>, <param2value>, ...)"
Davi Arnaut's avatar
Davi Arnaut committed
897 898


899
  4. Miscellaneous issues.
Davi Arnaut's avatar
Davi Arnaut committed
900 901

  4.1 User variables.
902 903

  When we call mysql_bin_log.write() for an SP statement, thd->user_var_events
Davi Arnaut's avatar
Davi Arnaut committed
904
  must hold set<{var_name, value}> pairs for all user variables used during
905 906
  the statement execution.
  This set is produced by tracking user variable reads during statement
Davi Arnaut's avatar
Davi Arnaut committed
907
  execution.
908

909
  For SPs, this has the following implications:
Davi Arnaut's avatar
Davi Arnaut committed
910 911
  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
912 913 914 915
     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.
Davi Arnaut's avatar
Davi Arnaut committed
916

917
  2) We need to empty thd->user_var_events after we have wrote a function
Davi Arnaut's avatar
Davi Arnaut committed
918
     call. This is currently done by making
919 920 921
     reset_dynamic(&thd->user_var_events);
     calls in several different places. (TODO cosider moving this into
     mysql_bin_log.write() function)
922 923 924 925 926 927 928 929

  4.2 Auto_increment storage in binlog

  As we may write two statements to binlog from one single logical statement
  (case of "SELECT func1(),func2()": it is binlogged as "SELECT func1()" and
  then "SELECT func2()"), we need to reset auto_increment binlog variables
  after each binlogged SELECT. Otherwise, the auto_increment value of the
  first SELECT would be used for the second too.
930 931 932
*/


unknown's avatar
unknown committed
933 934 935
/**
  Replace thd->query{_length} with a string that one can write to
  the binlog.
936

Davi Arnaut's avatar
Davi Arnaut committed
937
  The binlog-suitable string is produced by replacing references to SP local
unknown's avatar
unknown committed
938 939 940 941 942 943 944 945 946 947 948 949
  variables with NAME_CONST('sp_var_name', value) calls.

  @param thd        Current thread.
  @param instr      Instruction (we look for Item_splocal instances in
                    instr->free_list)
  @param query_str  Original query string

  @return
    - FALSE  on success.
    thd->query{_length} either has been appropriately replaced or there
    is no need for replacements.
    - TRUE   out of memory error.
950 951
*/

952 953
static bool
subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str)
954 955 956
{
  DBUG_ENTER("subst_spvars");

957 958 959 960
  Dynamic_array<Item_splocal*> sp_vars_uses;
  char *pbuf, *cur, buffer[512];
  String qbuf(buffer, sizeof(buffer), &my_charset_bin);
  int prev_pos, res, buf_len;
961

962 963 964 965
  /* Find all instances of Item_splocal used in this statement */
  for (Item *item= instr->free_list; item; item= item->next)
  {
    if (item->is_splocal())
966
    {
967 968 969
      Item_splocal *item_spl= (Item_splocal*)item;
      if (item_spl->pos_in_query)
        sp_vars_uses.append(item_spl);
970
    }
971 972 973
  }
  if (!sp_vars_uses.elements())
    DBUG_RETURN(FALSE);
Davi Arnaut's avatar
Davi Arnaut committed
974

975 976
  /* Sort SP var refs by their occurences in the query */
  sp_vars_uses.sort(cmp_splocal_locations);
977

Davi Arnaut's avatar
Davi Arnaut committed
978
  /*
979 980 981 982 983 984
    Construct a statement string where SP local var refs are replaced
    with "NAME_CONST(name, value)"
  */
  qbuf.length(0);
  cur= query_str->str;
  prev_pos= res= 0;
985
  thd->query_name_consts= 0;
Davi Arnaut's avatar
Davi Arnaut committed
986

987 988 989 990
  for (Item_splocal **splocal= sp_vars_uses.front(); 
       splocal < sp_vars_uses.back(); splocal++)
  {
    Item *val;
991

992 993 994 995
    char str_buffer[STRING_BUFFER_USUAL_SIZE];
    String str_value_holder(str_buffer, sizeof(str_buffer),
                            &my_charset_latin1);
    String *str_value;
Davi Arnaut's avatar
Davi Arnaut committed
996

997 998
    /* append the text between sp ref occurences */
    res|= qbuf.append(cur + prev_pos, (*splocal)->pos_in_query - prev_pos);
unknown's avatar
unknown committed
999
    prev_pos= (*splocal)->pos_in_query + (*splocal)->len_in_query;
Davi Arnaut's avatar
Davi Arnaut committed
1000

1001
    res|= (*splocal)->fix_fields(thd, (Item **) splocal);
Davi Arnaut's avatar
Davi Arnaut committed
1002
    if (res)
1003 1004 1005 1006 1007 1008 1009 1010
      break;

    if ((*splocal)->limit_clause_param)
    {
      res|= qbuf.append_ulonglong((*splocal)->val_uint());
      continue;
    }

1011 1012 1013 1014
    /* append the spvar substitute */
    res|= qbuf.append(STRING_WITH_LEN(" NAME_CONST('"));
    res|= qbuf.append((*splocal)->m_name.str, (*splocal)->m_name.length);
    res|= qbuf.append(STRING_WITH_LEN("',"));
1015

1016
    if (res)
1017
      break;
1018

1019
    val= (*splocal)->this_item();
1020
    DBUG_PRINT("info", ("print 0x%lx", (long) val));
1021 1022 1023 1024 1025 1026 1027 1028
    str_value= sp_get_item_value(thd, val, &str_value_holder);
    if (str_value)
      res|= qbuf.append(*str_value);
    else
      res|= qbuf.append(STRING_WITH_LEN("NULL"));
    res|= qbuf.append(')');
    if (res)
      break;
Davi Arnaut's avatar
Davi Arnaut committed
1029

1030
    thd->query_name_consts++;
1031 1032 1033 1034
  }
  res|= qbuf.append(cur + prev_pos, query_str->length - prev_pos);
  if (res)
    DBUG_RETURN(TRUE);
1035

1036 1037 1038 1039 1040
  /*
    Allocate additional space at the end of the new query string for the
    query_cache_send_result_to_client function.
  */
  buf_len= qbuf.length() + thd->db_length + 1 + QUERY_CACHE_FLAGS_SIZE + 1;
unknown's avatar
unknown committed
1041
  if ((pbuf= (char *) alloc_root(thd->mem_root, buf_len)))
1042 1043 1044
  {
    memcpy(pbuf, qbuf.ptr(), qbuf.length());
    pbuf[qbuf.length()]= 0;
1045
  }
1046 1047 1048
  else
    DBUG_RETURN(TRUE);

1049
  thd->set_query(pbuf, qbuf.length());
1050

1051
  DBUG_RETURN(FALSE);
1052 1053 1054
}


Davi Arnaut's avatar
Davi Arnaut committed
1055
/**
1056 1057
  Return appropriate error about recursion limit reaching

Davi Arnaut's avatar
Davi Arnaut committed
1058
  @param thd  Thread handle
1059

Davi Arnaut's avatar
Davi Arnaut committed
1060 1061 1062
  @remark For functions and triggers we return error about
          prohibited recursion. For stored procedures we
          return about reaching recursion limit.
1063 1064
*/

unknown's avatar
unknown committed
1065
void sp_head::recursion_level_error(THD *thd)
1066 1067 1068 1069 1070
{
  if (m_type == TYPE_ENUM_PROCEDURE)
  {
    my_error(ER_SP_RECURSION_LIMIT, MYF(0),
             thd->variables.max_sp_recursion_depth,
1071
             m_name.str);
1072 1073 1074 1075 1076 1077
  }
  else
    my_error(ER_SP_NO_RECURSION, MYF(0));
}


1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175
/**
  Find an SQL handler for any condition (warning or error) after execution
  of a stored routine instruction. Basically, this function looks for an
  appropriate SQL handler in RT-contexts. If an SQL handler is found, it is
  remembered in the RT-context for future activation (the context can be
  inactive at the moment).

  If there is no pending condition, the function just returns.

  If there was an error during the execution, an SQL handler for it will be
  searched within the current and outer scopes.

  There might be several errors in the Warning Info (that's possible by using
  SIGNAL/RESIGNAL in nested scopes) -- the function is looking for an SQL
  handler for the latest (current) error only.

  If there was a warning during the execution, an SQL handler for it will be
  searched within the current scope only.

  If several warnings were thrown during the execution and there are different
  SQL handlers for them, it is not determined which SQL handler will be chosen.
  Only one SQL handler will be executed.

  If warnings and errors were thrown during the execution, the error takes
  precedence. I.e. error handler will be executed. If there is no handler
  for that error, condition will remain unhandled.

  Once a warning or an error has been handled it is not removed from
  Warning Info.

  According to The Standard (quoting PeterG):

    An SQL procedure statement works like this ...
    SQL/Foundation 13.5 <SQL procedure statement>
    (General Rules) (greatly summarized) says:
    (1) Empty diagnostics area, thus clearing the condition.
    (2) Execute statement.
        During execution, if Exception Condition occurs,
        set Condition Area = Exception Condition and stop
        statement.
        During execution, if No Data occurs,
        set Condition Area = No Data Condition and continue
        statement.
        During execution, if Warning occurs,
        and Condition Area is not already full due to
        an earlier No Data condition, set Condition Area
        = Warning and continue statement.
    (3) Finish statement.
        At end of execution, if Condition Area is not
        already full due to an earlier No Data or Warning,
        set Condition Area = Successful Completion.
        In effect, this system means there is a precedence:
        Exception trumps No Data, No Data trumps Warning,
        Warning trumps Successful Completion.

    NB: "Procedure statements" include any DDL or DML or
    control statements. So CREATE and DELETE and WHILE
    and CALL and RETURN are procedure statements. But
    DECLARE and END are not procedure statements.

  @param thd thread handle
  @param ctx runtime context of the stored routine
*/

static void
find_handler_after_execution(THD *thd, sp_rcontext *ctx)
{
  if (thd->is_error())
  {
    ctx->find_handler(thd,
                      thd->stmt_da->sql_errno(),
                      thd->stmt_da->get_sqlstate(),
                      MYSQL_ERROR::WARN_LEVEL_ERROR,
                      thd->stmt_da->message());
  }
  else if (thd->warning_info->statement_warn_count())
  {
    List_iterator<MYSQL_ERROR> it(thd->warning_info->warn_list());
    MYSQL_ERROR *err;
    while ((err= it++))
    {
      if (err->get_level() != MYSQL_ERROR::WARN_LEVEL_WARN &&
          err->get_level() != MYSQL_ERROR::WARN_LEVEL_NOTE)
        continue;

      if (ctx->find_handler(thd,
                            err->get_sql_errno(),
                            err->get_sqlstate(),
                            err->get_level(),
                            err->get_message_text()))
      {
        break;
      }
    }
  }
}


unknown's avatar
unknown committed
1176 1177
/**
  Execute the routine. The main instruction jump loop is there.
1178
  Assume the parameters already set.
unknown's avatar
unknown committed
1179
  @todo
Davi Arnaut's avatar
Davi Arnaut committed
1180
    - Will write this SP statement into binlog separately
unknown's avatar
unknown committed
1181 1182 1183
    (TODO: consider changing the condition to "not inside event union")

  @retval
1184
    FALSE  on success
unknown's avatar
unknown committed
1185
  @retval
1186
    TRUE   on error
1187 1188
*/

1189 1190
bool
sp_head::execute(THD *thd)
1191
{
1192
  DBUG_ENTER("sp_head::execute");
1193 1194 1195 1196
  char saved_cur_db_name_buf[NAME_LEN+1];
  LEX_STRING saved_cur_db_name=
    { saved_cur_db_name_buf, sizeof(saved_cur_db_name_buf) };
  bool cur_db_changed= FALSE;
1197
  sp_rcontext *ctx= thd->spcont;
1198
  bool err_status= FALSE;
1199
  uint ip= 0;
1200
  ulong save_sql_mode;
1201
  bool save_abort_on_warning;
unknown's avatar
unknown committed
1202
  Query_arena *old_arena;
1203 1204 1205
  /* per-instruction arena */
  MEM_ROOT execute_mem_root;
  Query_arena execute_arena(&execute_mem_root, INITIALIZED_FOR_SP),
unknown's avatar
unknown committed
1206
              backup_arena;
1207
  query_id_t old_query_id;
1208 1209 1210 1211
  TABLE *old_derived_tables;
  LEX *old_lex;
  Item_change_list old_change_list;
  String old_packet;
1212
  Reprepare_observer *save_reprepare_observer= thd->m_reprepare_observer;
unknown's avatar
unknown committed
1213
  Object_creation_ctx *saved_creation_ctx;
Marc Alff's avatar
Marc Alff committed
1214
  Warning_info *saved_warning_info, warning_info(thd->warning_info->warn_id());
unknown's avatar
unknown committed
1215

1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230
  /*
    Just reporting a stack overrun error
    (@sa check_stack_overrun()) requires stack memory for error
    message buffer. Thus, we have to put the below check
    relatively close to the beginning of the execution stack,
    where available stack margin is still big. As long as the check
    has to be fairly high up the call stack, the amount of memory
    we "book" for has to stay fairly high as well, and hence
    not very accurate. The number below has been calculated
    by trial and error, and reflects the amount of memory necessary
    to execute a single stored procedure instruction, be it either
    an SQL statement, or, heaviest of all, a CALL, which involves
    parsing and loading of another stored procedure into the cache
    (@sa db_load_routine() and Bug#10100).
    At the time of measuring, a recursive SP invocation required
1231 1232
    3232 bytes of stack on 32 bit Linux, 6016 bytes on 64 bit Mac
    and 11152 on 64 bit Solaris sparc.
1233 1234 1235 1236
    The same with db_load_routine() required circa 7k bytes and
    14k bytes accordingly. Hence, here we book the stack with some
    reasonable margin.
  */
1237
  if (check_stack_overrun(thd, STACK_MIN_SIZE, (uchar*)&old_packet))
1238
    DBUG_RETURN(TRUE);
1239

1240
  /* init per-instruction memroot */
1241
  init_sql_alloc(&execute_mem_root, MEM_ROOT_BLOCK_SIZE, 0);
1242 1243

  DBUG_ASSERT(!(m_flags & IS_INVOKED));
1244
  m_flags|= IS_INVOKED;
1245
  m_first_instance->m_first_free_instance= m_next_cached_sp;
unknown's avatar
unknown committed
1246 1247 1248 1249 1250 1251 1252 1253 1254
  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));
  }
1255 1256 1257 1258 1259 1260 1261 1262 1263
  /*
    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));
1264

unknown's avatar
unknown committed
1265 1266 1267 1268 1269 1270
  /*
    NOTE: The SQL Standard does not specify the context that should be
    preserved for stored routines. However, at SAP/Walldorf meeting it was
    decided that current database should be preserved.
  */

1271
  if (m_db.length &&
1272 1273 1274
      (err_status= mysql_opt_change_db(thd, &m_db, &saved_cur_db_name, FALSE,
                                       &cur_db_changed)))
  {
1275
    goto done;
1276
  }
1277

1278
  thd->is_slave_error= 0;
unknown's avatar
unknown committed
1279
  old_arena= thd->stmt_arena;
1280

Marc Alff's avatar
Marc Alff committed
1281 1282 1283 1284 1285
  /* Push a new warning information area. */
  warning_info.append_warning_info(thd, thd->warning_info);
  saved_warning_info= thd->warning_info;
  thd->warning_info= &warning_info;

1286 1287 1288 1289 1290 1291
  /*
    Switch query context. This has to be done early as this is sometimes
    allocated trough sql_alloc
  */
  saved_creation_ctx= m_creation_ctx->set_n_backup(thd);

1292 1293 1294 1295 1296 1297 1298
  /*
    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;
1299 1300
  save_sql_mode= thd->variables.sql_mode;
  thd->variables.sql_mode= m_sql_mode;
1301
  save_abort_on_warning= thd->abort_on_warning;
1302
  thd->abort_on_warning= 0;
1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320
  /**
    When inside a substatement (a stored function or trigger
    statement), clear the metadata observer in THD, if any.
    Remember the value of the observer here, to be able
    to restore it when leaving the substatement.

    We reset the observer to suppress errors when a substatement
    uses temporary tables. If a temporary table does not exist
    at start of the main statement, it's not prelocked
    and thus is not validated with other prelocked tables.

    Later on, when the temporary table is opened, metadata
    versions mismatch, expectedly.

    The proper solution for the problem is to re-validate tables
    of substatements (Bug#12257, Bug#27011, Bug#32868, Bug#33000),
    but it's not implemented yet.
  */
1321
  thd->m_reprepare_observer= 0;
1322

1323 1324 1325 1326 1327 1328 1329 1330 1331
  /*
    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.
  */
Tor Didriksen's avatar
Tor Didriksen committed
1332
  thd->change_list.move_elements_to(&old_change_list);
1333 1334 1335 1336 1337 1338 1339 1340 1341 1342
  /*
    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);

1343 1344 1345 1346
  /*
    Switch to per-instruction arena here. We can do it since we cleanup
    arena after every instruction.
  */
unknown's avatar
unknown committed
1347
  thd->set_n_backup_active_arena(&execute_arena, &backup_arena);
1348 1349 1350 1351 1352

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

1355
#if defined(ENABLED_PROFILING)
1356 1357 1358
  /* Discard the initial part of executing routines. */
  thd->profiling.discard_current_query();
#endif
1359 1360 1361 1362
  do
  {
    sp_instr *i;

1363
#if defined(ENABLED_PROFILING)
Davi Arnaut's avatar
Davi Arnaut committed
1364
    /*
1365 1366 1367 1368 1369 1370 1371 1372
     Treat each "instr" of a routine as discrete unit that could be profiled.
     Profiling only records information for segments of code that set the
     source of the query, and almost all kinds of instructions in s-p do not.
    */
    thd->profiling.finish_current_query();
    thd->profiling.start_new_query("continuing inside routine");
#endif

Davi Arnaut's avatar
Davi Arnaut committed
1373 1374
    /* get_instr returns NULL when we're done. */
    i = get_instr(ip);
1375
    if (i == NULL)
1376
    {
1377
#if defined(ENABLED_PROFILING)
1378 1379
      thd->profiling.discard_current_query();
#endif
1380
      break;
1381 1382
    }

1383 1384 1385
    /* Reset number of warnings for this query. */
    thd->warning_info->reset_for_next_command();

1386
    DBUG_PRINT("execute", ("Instruction %u", ip));
1387

Davi Arnaut's avatar
Davi Arnaut committed
1388
    /*
1389 1390 1391
      We need to reset start_time to allow for time to flow inside a stored
      procedure. This is only done for SP since time is suppose to be constant
      during execution of triggers and functions.
Davi Arnaut's avatar
Davi Arnaut committed
1392
    */
1393
    reset_start_time_for_sp(thd);
Davi Arnaut's avatar
Davi Arnaut committed
1394

1395
    /*
unknown's avatar
unknown committed
1396
      We have to set thd->stmt_arena before executing the instruction
1397 1398 1399 1400
      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
unknown committed
1401
    thd->stmt_arena= i;
Davi Arnaut's avatar
Davi Arnaut committed
1402 1403 1404 1405

    /*
      Will write this SP statement into binlog separately.
      TODO: consider changing the condition to "not inside event union".
1406
    */
Konstantin Osipov's avatar
Konstantin Osipov committed
1407
    if (thd->locked_tables_mode <= LTM_LOCK_TABLES)
1408
      thd->user_var_events_alloc= thd->mem_root;
1409

1410
    err_status= i->execute(thd, &ip);
1411

1412 1413
    if (i->free_list)
      cleanup_items(i->free_list);
Davi Arnaut's avatar
Davi Arnaut committed
1414 1415

    /*
1416 1417 1418
      If we've set thd->user_var_events_alloc to mem_root of this SP
      statement, clean all the events allocated in it.
    */
Konstantin Osipov's avatar
Konstantin Osipov committed
1419
    if (thd->locked_tables_mode <= LTM_LOCK_TABLES)
1420 1421 1422 1423
    {
      reset_dynamic(&thd->user_var_events);
      thd->user_var_events_alloc= NULL;//DEBUG
    }
1424

1425
    /* we should cleanup free_list and memroot, used by instruction */
1426
    thd->cleanup_after_query();
Davi Arnaut's avatar
Davi Arnaut committed
1427
    free_root(&execute_mem_root, MYF(0));
1428

unknown's avatar
unknown committed
1429
    /*
1430 1431 1432
      Find and process SQL handlers unless it is a fatal error (fatal
      errors are not catchable by SQL handlers) or the connection has been
      killed during execution.
unknown's avatar
unknown committed
1433
    */
1434
    if (!thd->is_fatal_error && !thd->killed_errno())
1435
    {
1436 1437 1438 1439 1440 1441 1442
      /*
        Find SQL handler in the appropriate RT-contexts:
          - warnings can be handled by SQL handlers within
            the current scope only;
          - errors can be handled by any SQL handler from outer scope.
      */
      find_handler_after_execution(thd, ctx);
1443

1444 1445
      /* If found, activate handler for the current scope. */
      if (ctx->activate_handler(thd, &ip, i, &execute_arena, &backup_arena))
Davi Arnaut's avatar
Davi Arnaut committed
1446
        err_status= FALSE;
1447
    }
1448 1449 1450 1451

    /* Reset sp_rcontext::end_partial_result_set flag. */
    ctx->end_partial_result_set= FALSE;

Marc Alff's avatar
Marc Alff committed
1452
  } while (!err_status && !thd->killed && !thd->is_fatal_error);
1453

1454
#if defined(ENABLED_PROFILING)
1455 1456 1457 1458
  thd->profiling.finish_current_query();
  thd->profiling.start_new_query("tail end of routine");
#endif

unknown's avatar
unknown committed
1459 1460 1461 1462 1463 1464
  /* Restore query context. */

  m_creation_ctx->restore_env(thd, saved_creation_ctx);

  /* Restore arena. */

unknown's avatar
unknown committed
1465
  thd->restore_active_arena(&execute_arena, &backup_arena);
1466

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

1469 1470 1471
  /* Restore all saved */
  old_packet.swap(thd->packet);
  DBUG_ASSERT(thd->change_list.is_empty());
Tor Didriksen's avatar
Tor Didriksen committed
1472
  old_change_list.move_elements_to(&thd->change_list);
1473
  thd->lex= old_lex;
1474
  thd->set_query_id(old_query_id);
1475 1476
  DBUG_ASSERT(!thd->derived_tables);
  thd->derived_tables= old_derived_tables;
1477
  thd->variables.sql_mode= save_sql_mode;
1478
  thd->abort_on_warning= save_abort_on_warning;
1479
  thd->m_reprepare_observer= save_reprepare_observer;
1480

unknown's avatar
unknown committed
1481
  thd->stmt_arena= old_arena;
1482
  state= EXECUTED;
1483

Marc Alff's avatar
Marc Alff committed
1484 1485 1486 1487
  /* Restore the caller's original warning information area. */
  saved_warning_info->merge_with_routine_info(thd, thd->warning_info);
  thd->warning_info= saved_warning_info;

1488
 done:
1489
  DBUG_PRINT("info", ("err_status: %d  killed: %d  is_slave_error: %d  report_error: %d",
Davi Arnaut's avatar
Davi Arnaut committed
1490
                      err_status, thd->killed, thd->is_slave_error,
1491
                      thd->is_error()));
1492

unknown's avatar
unknown committed
1493
  if (thd->killed)
1494
    err_status= TRUE;
1495 1496 1497 1498
  /*
    If the DB has changed, the pointer has changed too, but the
    original thd->db will then have been freed
  */
1499
  if (cur_db_changed && !thd->killed)
1500
  {
1501
    /*
1502 1503
      Force switching back to the saved current database, because it may be
      NULL. In this case, mysql_change_db() would generate an error.
1504
    */
1505 1506

    err_status|= mysql_change_db(thd, &saved_cur_db_name, TRUE);
1507
  }
1508
  m_flags&= ~IS_INVOKED;
1509 1510 1511 1512 1513
  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));
1514 1515 1516 1517 1518 1519 1520 1521 1522
  /*
    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
1523
    should be on 1 more then recursion level of this instance.
1524 1525 1526 1527 1528 1529 1530 1531 1532
  */
  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;
1533 1534 1535 1536 1537 1538

  DBUG_RETURN(err_status);
}


#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
1539
/**
1540 1541 1542 1543 1544
  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.

unknown's avatar
unknown committed
1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558
  @param thd         thread handle
  @param sp          stored routine to change the context for
  @param is_proc     TRUE is procedure, FALSE if function
  @param save_ctx    pointer to an old security context

  @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.

  @retval
    TRUE   if there was a error, and the context wasn't changed.
  @retval
    FALSE  if the context was changed.
1559 1560 1561 1562 1563 1564 1565
*/

bool
set_routine_security_ctx(THD *thd, sp_head *sp, bool is_proc,
                         Security_context **save_ctx)
{
  *save_ctx= 0;
1566 1567 1568 1569 1570
  if (sp->m_chistics->suid != SP_IS_NOT_SUID &&
      sp->m_security_ctx.change_security_context(thd, &sp->m_definer_user,
                                                 &sp->m_definer_host,
                                                 &sp->m_db,
                                                 save_ctx))
1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586
    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))
  {
1587
    sp->m_security_ctx.restore_security_context(thd, *save_ctx);
1588 1589 1590 1591 1592 1593 1594 1595 1596
    *save_ctx= 0;
    return TRUE;
  }

  return FALSE;
}
#endif // ! NO_EMBEDDED_ACCESS_CHECKS


1597 1598
/**
  Execute trigger stored program.
1599

unknown's avatar
unknown committed
1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615
  - changes security context for triggers
  - switch to new memroot
  - call sp_head::execute
  - restore old memroot
  - restores security context

  @param thd               Thread handle
  @param db                database name
  @param table             table name
  @param grant_info        GRANT_INFO structure to be filled with
                           information about definer's privileges
                           on subject table

  @todo
    - TODO: we should create sp_rcontext once per command and reuse it
    on subsequent executions of a trigger.
1616

unknown's avatar
unknown committed
1617 1618 1619 1620
  @retval
    FALSE  on success
  @retval
    TRUE   on error
1621 1622 1623
*/

bool
1624 1625 1626
sp_head::execute_trigger(THD *thd,
                         const LEX_STRING *db_name,
                         const LEX_STRING *table_name,
1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638
                         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));

1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678
#ifndef NO_EMBEDDED_ACCESS_CHECKS
  Security_context *save_ctx= NULL;


  if (m_chistics->suid != SP_IS_NOT_SUID &&
      m_security_ctx.change_security_context(thd,
                                             &m_definer_user,
                                             &m_definer_host,
                                             &m_db,
                                             &save_ctx))
    DBUG_RETURN(TRUE);

  /*
    Fetch information about table-level privileges for subject table into
    GRANT_INFO instance. The access check itself will happen in
    Item_trigger_field, where this information will be used along with
    information about column-level privileges.
  */

  fill_effective_table_privileges(thd,
                                  grant_info,
                                  db_name->str,
                                  table_name->str);

  /* Check that the definer has TRIGGER privilege on the subject table. */

  if (!(grant_info->privilege & TRIGGER_ACL))
  {
    char priv_desc[128];
    get_privilege_desc(priv_desc, sizeof(priv_desc), TRIGGER_ACL);

    my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), priv_desc,
             thd->security_ctx->priv_user, thd->security_ctx->host_or_ip,
             table_name->str);

    m_security_ctx.restore_security_context(thd, save_ctx);
    DBUG_RETURN(TRUE);
  }
#endif // NO_EMBEDDED_ACCESS_CHECKS

1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710
  /*
    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);
1711 1712 1713 1714 1715

#ifndef NO_EMBEDDED_ACCESS_CHECKS
  m_security_ctx.restore_security_context(thd, save_ctx);
#endif // NO_EMBEDDED_ACCESS_CHECKS

1716 1717 1718 1719 1720
  delete nctx;
  call_arena.free_items();
  free_root(&call_mem_root, MYF(0));
  thd->spcont= octx;

1721 1722 1723
  if (thd->killed)
    thd->send_kill_message();

1724
  DBUG_RETURN(err_status);
1725 1726 1727
}


unknown's avatar
unknown committed
1728 1729 1730
/**
  Execute a function.

1731
   - evaluate parameters
1732 1733
   - changes security context for SUID routines
   - switch to new memroot
1734
   - call sp_head::execute
1735
   - restore old memroot
1736
   - evaluate the return value
1737
   - restores security context
1738

unknown's avatar
unknown committed
1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755
  @param thd               Thread handle
  @param argp              Passed arguments (these are items from containing
                           statement?)
  @param argcount          Number of passed arguments. We need to check if
                           this is correct.
  @param return_value_fld  Save result here.

  @todo
    We should create sp_rcontext once per command and reuse
    it on subsequent executions of a function/trigger.

  @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.

  @retval
1756
    FALSE  on success
unknown's avatar
unknown committed
1757
  @retval
1758
    TRUE   on error
1759 1760
*/

1761 1762 1763
bool
sp_head::execute_function(THD *thd, Item **argp, uint argcount,
                          Field *return_value_fld)
1764
{
1765
  ulonglong binlog_save_options;
1766
  bool need_binlog_call= FALSE;
1767
  uint arg_no;
1768 1769
  sp_rcontext *octx = thd->spcont;
  sp_rcontext *nctx = NULL;
1770 1771
  char buf[STRING_BUFFER_USUAL_SIZE];
  String binlog_buf(buf, sizeof(buf), &my_charset_bin);
1772
  bool err_status= FALSE;
1773 1774 1775
  MEM_ROOT call_mem_root;
  Query_arena call_arena(&call_mem_root, Query_arena::INITIALIZED_FOR_SP);
  Query_arena backup_arena;
1776 1777 1778
  DBUG_ENTER("sp_head::execute_function");
  DBUG_PRINT("info", ("function %s", m_name.str));

1779
  LINT_INIT(binlog_save_options);
1780 1781 1782 1783 1784 1785 1786

  /*
    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.
  */
1787
  if (argcount != m_pcont->context_var_count())
unknown's avatar
unknown committed
1788
  {
unknown's avatar
unknown committed
1789
    /*
1790
      Need to use my_error here, or it will not terminate the
unknown's avatar
unknown committed
1791 1792
      invoking query properly.
    */
1793
    my_error(ER_SP_WRONG_NO_OF_ARGS, MYF(0),
1794
             "FUNCTION", m_qname.str, m_pcont->context_var_count(), argcount);
1795
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
1796
  }
1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809
  /*
    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);
1810 1811 1812 1813

  if (!(nctx= new sp_rcontext(m_pcont, return_value_fld, octx)) ||
      nctx->init(thd))
  {
1814 1815 1816
    thd->restore_active_arena(&call_arena, &backup_arena);
    err_status= TRUE;
    goto err_with_cleanup;
1817 1818
  }

1819 1820 1821 1822 1823 1824 1825 1826
  /*
    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);

1827
#ifndef DBUG_OFF
1828
  nctx->sp= this;
1829
#endif
1830 1831

  /* Pass arguments. */
1832
  for (arg_no= 0; arg_no < argcount; arg_no++)
1833
  {
1834 1835
    /* Arguments must be fixed in Item_func_sp::fix_fields */
    DBUG_ASSERT(argp[arg_no]->fixed);
1836

1837
    if ((err_status= nctx->set_variable(thd, arg_no, &(argp[arg_no]))))
1838
      goto err_with_cleanup;
1839
  }
1840

1841 1842 1843 1844 1845
  /*
    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() &&
unknown's avatar
unknown committed
1846 1847
                    (thd->variables.option_bits & OPTION_BIN_LOG) &&
                    !thd->is_current_stmt_binlog_format_row();
1848

1849 1850 1851 1852 1853
  /*
    Remember the original arguments for unrolled replication of functions
    before they are changed by execution.
  */
  if (need_binlog_call)
1854
  {
1855 1856
    binlog_buf.length(0);
    binlog_buf.append(STRING_WITH_LEN("SELECT "));
1857 1858
    append_identifier(thd, &binlog_buf, m_db.str, m_db.length);
    binlog_buf.append('.');
1859 1860 1861
    append_identifier(thd, &binlog_buf, m_name.str, m_name.length);
    binlog_buf.append('(');
    for (arg_no= 0; arg_no < argcount; arg_no++)
1862
    {
1863 1864
      String str_value_holder;
      String *str_value;
1865

1866 1867
      if (arg_no)
        binlog_buf.append(',');
1868

1869
      str_value= sp_get_item_value(thd, nctx->get_item(arg_no),
1870
                                   &str_value_holder);
1871

1872 1873 1874 1875 1876 1877
      if (str_value)
        binlog_buf.append(*str_value);
      else
        binlog_buf.append(STRING_WITH_LEN("NULL"));
    }
    binlog_buf.append(')');
1878
  }
1879 1880
  thd->spcont= nctx;

1881 1882 1883 1884 1885 1886 1887 1888 1889
#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

1890
  if (need_binlog_call)
1891
  {
1892
    query_id_t q;
1893
    reset_dynamic(&thd->user_var_events);
1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905
    /*
      In case of artificially constructed events for function calls
      we have separate union for each such event and hence can't use
      query_id of real calling statement as the start of all these
      unions (this will break logic of replication of user-defined
      variables). So we use artifical value which is guaranteed to
      be greater than all query_id's of all statements belonging
      to previous events/unions.
      Possible alternative to this is logging of all function invocations
      as one select and not resetting THD::user_var_events before
      each invocation.
    */
Marc Alff's avatar
Marc Alff committed
1906
    mysql_mutex_lock(&LOCK_thread_count);
1907
    q= global_query_id;
Marc Alff's avatar
Marc Alff committed
1908
    mysql_mutex_unlock(&LOCK_thread_count);
1909
    mysql_bin_log.start_union_events(thd, q + 1);
1910 1911
    binlog_save_options= thd->variables.option_bits;
    thd->variables.option_bits&= ~OPTION_BIN_LOG;
1912
  }
1913

1914 1915 1916 1917 1918 1919 1920 1921 1922 1923
  /*
    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);

1924
  err_status= execute(thd);
1925

1926 1927
  thd->restore_active_arena(&call_arena, &backup_arena);

1928
  if (need_binlog_call)
1929
  {
1930
    mysql_bin_log.stop_union_events(thd);
1931
    thd->variables.option_bits= binlog_save_options;
1932
    if (thd->binlog_evt_union.unioned_events)
1933
    {
1934
      int errcode = query_error_code(thd, thd->killed == THD::NOT_KILLED);
1935
      Query_log_event qinfo(thd, binlog_buf.ptr(), binlog_buf.length(),
1936
                            thd->binlog_evt_union.unioned_events_trans, FALSE, FALSE, errcode);
1937 1938 1939 1940 1941 1942
      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");
1943
        err_status= TRUE;
1944 1945
      }
      reset_dynamic(&thd->user_var_events);
1946 1947 1948
      /* Forget those values, in case more function calls are binlogged: */
      thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt= 0;
      thd->auto_inc_intervals_in_cur_stmt_for_binlog.empty();
1949 1950
    }
  }
1951

1952
  if (!err_status)
1953
  {
1954
    /* We need result only in function but not in trigger */
1955

1956
    if (!nctx->is_return_value_set())
1957
    {
1958
      my_error(ER_SP_NORETURNEND, MYF(0), m_name.str);
1959
      err_status= TRUE;
1960 1961
    }
  }
1962

1963
#ifndef NO_EMBEDDED_ACCESS_CHECKS
1964
  m_security_ctx.restore_security_context(thd, save_security_ctx);
1965
#endif
1966 1967

err_with_cleanup:
1968
  delete nctx;
1969 1970
  call_arena.free_items();
  free_root(&call_mem_root, MYF(0));
1971
  thd->spcont= octx;
1972

1973 1974 1975 1976 1977 1978 1979 1980
  /*
    If not insided a procedure and a function printing warning
    messsages.
  */
  if (need_binlog_call && 
      thd->spcont == NULL && !thd->binlog_evt_union.do_union)
    thd->issue_unsafe_warnings();

1981
  DBUG_RETURN(err_status);
1982 1983
}

1984

unknown's avatar
unknown committed
1985
/**
Davi Arnaut's avatar
Davi Arnaut committed
1986
  Execute a procedure.
1987 1988

  The function does the following steps:
Davi Arnaut's avatar
Davi Arnaut committed
1989
   - Set all parameters
1990
   - changes security context for SUID routines
1991 1992
   - call sp_head::execute
   - copy back values of INOUT and OUT parameters
1993
   - restores security context
1994

unknown's avatar
unknown committed
1995 1996 1997 1998
  @param thd    Thread handle
  @param args   List of values passed as arguments.

  @retval
1999
    FALSE  on success
unknown's avatar
unknown committed
2000
  @retval
2001
    TRUE   on error
2002 2003
*/

2004 2005
bool
sp_head::execute_procedure(THD *thd, List<Item> *args)
2006
{
2007
  bool err_status= FALSE;
2008
  uint params = m_pcont->context_var_count();
2009 2010
  /* Query start time may be reset in a multi-stmt SP; keep this for later. */
  ulonglong utime_before_sp_exec= thd->utime_after_lock;
2011
  sp_rcontext *save_spcont, *octx;
2012
  sp_rcontext *nctx = NULL;
unknown's avatar
unknown committed
2013
  bool save_enable_slow_log= false;
2014
  bool save_log_general= false;
2015 2016
  DBUG_ENTER("sp_head::execute_procedure");
  DBUG_PRINT("info", ("procedure %s", m_name.str));
2017

unknown's avatar
unknown committed
2018 2019
  if (args->elements != params)
  {
2020
    my_error(ER_SP_WRONG_NO_OF_ARGS, MYF(0), "PROCEDURE",
2021
             m_qname.str, params, args->elements);
2022
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
2023 2024
  }

2025
  save_spcont= octx= thd->spcont;
2026
  if (! octx)
Davi Arnaut's avatar
Davi Arnaut committed
2027 2028 2029
  {
    /* Create a temporary old context. */
    if (!(octx= new sp_rcontext(m_pcont, NULL, octx)) || octx->init(thd))
2030 2031 2032 2033
    {
      delete octx; /* Delete octx if it was init() that failed. */
      DBUG_RETURN(TRUE);
    }
Davi Arnaut's avatar
Davi Arnaut committed
2034

2035
#ifndef DBUG_OFF
2036
    octx->sp= 0;
2037
#endif
2038 2039 2040 2041 2042 2043
    thd->spcont= octx;

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

2044 2045
  if (!(nctx= new sp_rcontext(m_pcont, NULL, octx)) ||
      nctx->init(thd))
2046
  {
2047
    delete nctx; /* Delete nctx if it was init() that failed. */
2048
    thd->spcont= save_spcont;
2049
    DBUG_RETURN(TRUE);
2050
  }
2051
#ifndef DBUG_OFF
2052
  nctx->sp= this;
2053
#endif
2054

2055
  if (params > 0)
2056
  {
2057
    List_iterator<Item> it_args(*args);
2058

2059
    DBUG_PRINT("info",(" %.*s: eval args", (int) m_name.length, m_name.str));
2060 2061

    for (uint i= 0 ; i < params ; i++)
2062
    {
2063
      Item *arg_item= it_args++;
2064

2065 2066 2067
      if (!arg_item)
        break;

2068 2069
      sp_variable_t *spvar= m_pcont->find_variable(i);

2070
      if (!spvar)
2071 2072
        continue;

2073
      if (spvar->mode != sp_param_in)
2074
      {
2075 2076 2077 2078
        Settable_routine_parameter *srp=
          arg_item->get_settable_routine_parameter();

        if (!srp)
2079 2080 2081 2082 2083
        {
          my_error(ER_SP_NOT_VAR_ARG, MYF(0), i+1, m_qname.str);
          err_status= TRUE;
          break;
        }
2084 2085

        srp->set_required_privilege(spvar->mode == sp_param_inout);
2086 2087
      }

2088
      if (spvar->mode == sp_param_out)
2089 2090 2091 2092
      {
        Item_null *null_item= new Item_null();

        if (!null_item ||
2093
            nctx->set_variable(thd, i, (Item **)&null_item))
2094 2095 2096 2097 2098 2099 2100
        {
          err_status= TRUE;
          break;
        }
      }
      else
      {
2101
        if (nctx->set_variable(thd, i, it_args.ref()))
2102 2103 2104 2105
        {
          err_status= TRUE;
          break;
        }
2106
      }
2107
    }
2108

Konstantin Osipov's avatar
Konstantin Osipov committed
2109 2110 2111
    /*
      Okay, got values for all arguments. Close tables that might be used by
      arguments evaluation. If arguments evaluation required prelocking mode,
2112
      we'll leave it here.
2113
    */
2114 2115
    thd->lex->unit.cleanup();

2116
    if (!thd->in_sub_stmt)
2117
    {
2118 2119 2120 2121
      thd->stmt_da->can_overwrite_status= TRUE;
      thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd);
      thd->stmt_da->can_overwrite_status= FALSE;
    }
Konstantin Osipov's avatar
Konstantin Osipov committed
2122

2123 2124 2125
    thd_proc_info(thd, "closing tables");
    close_thread_tables(thd);
    thd_proc_info(thd, 0);
Konstantin Osipov's avatar
Konstantin Osipov committed
2126

2127 2128 2129 2130
    if (! thd->in_sub_stmt && ! thd->in_multi_stmt_transaction_mode())
      thd->mdl_context.release_transactional_locks();

    thd->rollback_item_tree_changes();
2131

2132 2133
    DBUG_PRINT("info",(" %.*s: eval args done", (int) m_name.length, 
                       m_name.str));
2134
  }
2135
  if (!(m_flags & LOG_SLOW_STATEMENTS) && thd->enable_slow_log)
unknown's avatar
unknown committed
2136 2137
  {
    DBUG_PRINT("info", ("Disabling slow log for the execution"));
2138
    save_enable_slow_log= true;
unknown's avatar
unknown committed
2139 2140
    thd->enable_slow_log= FALSE;
  }
2141
  if (!(m_flags & LOG_GENERAL_LOG) && !(thd->variables.option_bits & OPTION_LOG_OFF))
2142 2143 2144 2145
  {
    DBUG_PRINT("info", ("Disabling general log for the execution"));
    save_log_general= true;
    /* disable this bit */
2146
    thd->variables.option_bits |= OPTION_LOG_OFF;
2147
  }
2148 2149
  thd->spcont= nctx;

2150 2151 2152 2153 2154 2155
#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

2156 2157
  if (!err_status)
    err_status= execute(thd);
2158

2159
  if (save_log_general)
2160
    thd->variables.option_bits &= ~OPTION_LOG_OFF;
2161 2162
  if (save_enable_slow_log)
    thd->enable_slow_log= true;
2163 2164 2165 2166 2167 2168 2169
  /*
    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;
2170

2171
  if (!err_status && params > 0)
2172
  {
2173
    List_iterator<Item> it_args(*args);
2174

unknown's avatar
unknown committed
2175 2176 2177 2178
    /*
      Copy back all OUT or INOUT values to the previous frame, or
      set global user variables
    */
2179
    for (uint i= 0 ; i < params ; i++)
2180
    {
2181 2182 2183 2184 2185
      Item *arg_item= it_args++;

      if (!arg_item)
        break;

2186
      sp_variable_t *spvar= m_pcont->find_variable(i);
2187

2188
      if (spvar->mode == sp_param_in)
2189 2190
        continue;

2191 2192 2193 2194 2195
      Settable_routine_parameter *srp=
        arg_item->get_settable_routine_parameter();

      DBUG_ASSERT(srp);

2196
      if (srp->set_value(thd, octx, nctx->get_item_addr(i)))
2197
      {
2198 2199
        err_status= TRUE;
        break;
2200
      }
2201

2202
      Send_field *out_param_info= new (thd->mem_root) Send_field();
2203 2204 2205 2206 2207 2208 2209 2210
      nctx->get_item(i)->make_field(out_param_info);
      out_param_info->db_name= m_db.str;
      out_param_info->table_name= m_name.str;
      out_param_info->org_table_name= m_name.str;
      out_param_info->col_name= spvar->name.str;
      out_param_info->org_col_name= spvar->name.str;

      srp->set_out_param_info(out_param_info);
2211 2212 2213
    }
  }

2214 2215
#ifndef NO_EMBEDDED_ACCESS_CHECKS
  if (save_security_ctx)
2216
    m_security_ctx.restore_security_context(thd, save_security_ctx);
2217 2218
#endif

2219
  if (!save_spcont)
2220
    delete octx;
2221

2222
  delete nctx;
2223
  thd->spcont= save_spcont;
2224
  thd->utime_after_lock= utime_before_sp_exec;
2225

2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236
  /*
    If not insided a procedure and a function printing warning
    messsages.
  */ 
  bool need_binlog_call= mysql_bin_log.is_open() &&
                         (thd->variables.option_bits & OPTION_BIN_LOG) &&
                         !thd->is_current_stmt_binlog_format_row();
  if (need_binlog_call && thd->spcont == NULL &&
      !thd->binlog_evt_union.do_union)
    thd->issue_unsafe_warnings();

2237
  DBUG_RETURN(err_status);
2238 2239 2240
}


2241
/**
2242
  Reset lex during parsing, before we parse a sub statement.
2243 2244 2245 2246 2247 2248 2249 2250 2251

  @param thd Thread handler.

  @return Error state
    @retval true An error occurred.
    @retval false Success.
*/

bool
2252 2253
sp_head::reset_lex(THD *thd)
{
2254 2255
  DBUG_ENTER("sp_head::reset_lex");
  LEX *sublex;
2256
  LEX *oldlex= thd->lex;
2257

2258 2259 2260 2261 2262
  sublex= new (thd->mem_root)st_lex_local;
  if (sublex == 0)
    DBUG_RETURN(TRUE);

  thd->lex= sublex;
2263
  (void)m_lex.push_front(oldlex);
unknown's avatar
unknown committed
2264

2265 2266
  /* Reset most stuff. */
  lex_start(thd);
unknown's avatar
unknown committed
2267

2268
  /* And keep the SP stuff too */
2269 2270
  sublex->sphead= oldlex->sphead;
  sublex->spcont= oldlex->spcont;
2271 2272
  /* And trigger related stuff too */
  sublex->trg_chistics= oldlex->trg_chistics;
2273
  sublex->trg_table_fields.empty();
2274
  sublex->sp_lex_in_use= FALSE;
2275 2276 2277 2278 2279 2280 2281 2282 2283

  /* Reset type info. */

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

2284 2285 2286
  /* Reset part of parser state which needs this. */
  thd->m_parser_state->m_yacc.reset_before_substatement();

2287
  DBUG_RETURN(FALSE);
2288 2289
}

2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301

/**
  Restore lex during parsing, after we have parsed a sub statement.

  @param thd Thread handle

  @return
    @retval TRUE failure
    @retval FALSE success
*/

bool
2302 2303
sp_head::restore_lex(THD *thd)
{
2304 2305
  DBUG_ENTER("sp_head::restore_lex");
  LEX *sublex= thd->lex;
2306 2307 2308
  LEX *oldlex;

  sublex->set_trg_event_type_for_tables();
2309

2310
  oldlex= (LEX *)m_lex.pop();
2311
  if (! oldlex)
Davi Arnaut's avatar
Davi Arnaut committed
2312
    DBUG_RETURN(FALSE); // Nothing to restore
2313

2314
  oldlex->trg_table_fields.push_back(&sublex->trg_table_fields);
2315

2316 2317 2318 2319
  /* If this substatement is unsafe, the entire routine is too. */
  DBUG_PRINT("info", ("lex->get_stmt_unsafe_flags: 0x%x",
                      thd->lex->get_stmt_unsafe_flags()));
  unsafe_flags|= sublex->get_stmt_unsafe_flags();
unknown's avatar
unknown committed
2320

2321
  /*
2322 2323
    Add routines which are used by statement to respective set for
    this routine.
2324
  */
2325 2326
  if (sp_update_sp_used_routines(&m_sroutines, &sublex->sroutines))
    DBUG_RETURN(TRUE);
2327 2328 2329 2330 2331
  /*
    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);
2332
  if (! sublex->sp_lex_in_use)
2333
  {
2334
    sublex->sphead= NULL;
2335
    lex_end(sublex);
2336
    delete sublex;
2337
  }
2338
  thd->lex= oldlex;
2339
  DBUG_RETURN(FALSE);
2340 2341
}

unknown's avatar
unknown committed
2342 2343 2344
/**
  Put the instruction on the backpatch list, associated with the label.
*/
2345
int
2346
sp_head::push_backpatch(sp_instr *i, sp_label_t *lab)
2347
{
2348
  bp_t *bp= (bp_t *)sql_alloc(sizeof(bp_t));
2349

2350 2351 2352 2353 2354
  if (!bp)
    return 1;
  bp->lab= lab;
  bp->instr= i;
  return m_backpatch.push_front(bp);
2355 2356
}

unknown's avatar
unknown committed
2357 2358 2359 2360
/**
  Update all instruction with this label in the backpatch list to
  the current position.
*/
2361
void
2362
sp_head::backpatch(sp_label_t *lab)
2363
{
2364
  bp_t *bp;
2365
  uint dest= instructions();
2366
  List_iterator_fast<bp_t> li(m_backpatch);
2367

unknown's avatar
unknown committed
2368
  DBUG_ENTER("sp_head::backpatch");
2369
  while ((bp= li++))
2370
  {
2371
    if (bp->lab == lab)
unknown's avatar
unknown committed
2372 2373 2374
    {
      DBUG_PRINT("info", ("backpatch: (m_ip %d, label 0x%lx <%s>) to dest %d",
                          bp->instr->m_ip, (ulong) lab, lab->name, dest));
2375
      bp->instr->backpatch(dest, lab->ctx);
unknown's avatar
unknown committed
2376
    }
2377
  }
unknown's avatar
unknown committed
2378
  DBUG_VOID_RETURN;
2379 2380
}

unknown's avatar
unknown committed
2381
/**
unknown's avatar
unknown committed
2382
  Prepare an instance of Create_field for field creation (fill all necessary
2383 2384
  attributes).

unknown's avatar
unknown committed
2385 2386 2387 2388
  @param[in]  thd          Thread handle
  @param[in]  lex          Yacc parsing context
  @param[in]  field_type   Field type
  @param[out] field_def    An instance of create_field to be filled
2389

unknown's avatar
unknown committed
2390
  @retval
2391
    FALSE  on success
unknown's avatar
unknown committed
2392
  @retval
2393 2394 2395 2396 2397 2398
    TRUE   on error
*/

bool
sp_head::fill_field_definition(THD *thd, LEX *lex,
                               enum enum_field_types field_type,
unknown's avatar
unknown committed
2399
                               Create_field *field_def)
2400 2401 2402 2403 2404 2405 2406 2407
{
  LEX_STRING cmt = { 0, 0 };
  uint unused1= 0;
  int unused2= 0;

  if (field_def->init(thd, (char*) "", field_type, lex->length, lex->dec,
                      lex->type, (Item*) 0, (Item*) 0, &cmt, 0,
                      &lex->interval_list,
unknown's avatar
unknown committed
2408 2409
                      lex->charset ? lex->charset :
                                     thd->variables.collation_database,
2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428
                      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;
}


2429
int
2430
sp_head::new_cont_backpatch(sp_instr_opt_meta *i)
2431 2432 2433 2434 2435 2436
{
  m_cont_level+= 1;
  if (i)
  {
    /* Use the cont. destination slot to store the level */
    i->m_cont_dest= m_cont_level;
2437 2438
    if (m_cont_backpatch.push_front(i))
      return 1;
2439
  }
2440
  return 0;
2441 2442
}

2443
int
2444
sp_head::add_cont_backpatch(sp_instr_opt_meta *i)
2445 2446
{
  i->m_cont_dest= m_cont_level;
2447
  return m_cont_backpatch.push_front(i);
2448 2449 2450 2451 2452 2453 2454
}

void
sp_head::do_cont_backpatch()
{
  uint dest= instructions();
  uint lev= m_cont_level--;
2455
  sp_instr_opt_meta *i;
2456 2457 2458 2459 2460 2461 2462 2463

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

2464
void
2465
sp_head::set_info(longlong created, longlong modified,
Davi Arnaut's avatar
Davi Arnaut committed
2466
                  st_sp_chistics *chistics, ulong sql_mode)
2467 2468 2469
{
  m_created= created;
  m_modified= modified;
unknown's avatar
unknown committed
2470 2471
  m_chistics= (st_sp_chistics *) memdup_root(mem_root, (char*) chistics,
                                             sizeof(*chistics));
2472 2473 2474
  if (m_chistics->comment.length == 0)
    m_chistics->comment.str= 0;
  else
unknown's avatar
unknown committed
2475
    m_chistics->comment.str= strmake_root(mem_root,
Davi Arnaut's avatar
Davi Arnaut committed
2476 2477
                                          m_chistics->comment.str,
                                          m_chistics->comment.length);
2478
  m_sql_mode= sql_mode;
2479 2480
}

2481 2482

void
unknown's avatar
unknown committed
2483
sp_head::set_definer(const char *definer, uint definerlen)
2484
{
unknown's avatar
unknown committed
2485
  char user_name_holder[USERNAME_LENGTH + 1];
unknown's avatar
unknown committed
2486
  LEX_STRING user_name= { user_name_holder, USERNAME_LENGTH };
2487

2488
  char host_name_holder[HOSTNAME_LENGTH + 1];
2489
  LEX_STRING host_name= { host_name_holder, HOSTNAME_LENGTH };
2490

2491 2492
  parse_user(definer, definerlen, user_name.str, &user_name.length,
             host_name.str, &host_name.length);
2493

2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505
  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;
2506 2507 2508
}


2509 2510 2511
void
sp_head::reset_thd_mem_root(THD *thd)
{
2512
  DBUG_ENTER("sp_head::reset_thd_mem_root");
2513
  m_thd_root= thd->mem_root;
unknown's avatar
unknown committed
2514
  thd->mem_root= &main_mem_root;
2515 2516 2517
  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
Davi Arnaut's avatar
Davi Arnaut committed
2518
  thd->free_list= NULL; // Start a new one
2519
  m_thd= thd;
2520
  DBUG_VOID_RETURN;
2521 2522 2523 2524 2525
}

void
sp_head::restore_thd_mem_root(THD *thd)
{
2526
  DBUG_ENTER("sp_head::restore_thd_mem_root");
Davi Arnaut's avatar
Davi Arnaut committed
2527
  Item *flist= free_list;       // The old list
unknown's avatar
unknown committed
2528
  set_query_arena(thd);         // Get new free_list and mem_root
2529
  state= INITIALIZED_FOR_SP;
2530

2531 2532
  DBUG_PRINT("info", ("mem_root 0x%lx returned from thd mem root 0x%lx",
                      (ulong) &mem_root, (ulong) &thd->mem_root));
Davi Arnaut's avatar
Davi Arnaut committed
2533
  thd->free_list= flist;        // Restore the old one
2534 2535
  thd->mem_root= m_thd_root;
  m_thd= NULL;
2536
  DBUG_VOID_RETURN;
2537 2538 2539
}


unknown's avatar
unknown committed
2540 2541 2542
/**
  Check if a user has access right to a routine.

Davi Arnaut's avatar
Davi Arnaut committed
2543 2544 2545 2546
  @param thd          Thread handler
  @param sp           SP
  @param full_access  Set to 1 if the user has SELECT right to the
                      'mysql.proc' able or is the owner of the routine
unknown's avatar
unknown committed
2547 2548 2549 2550
  @retval
    false ok
  @retval
    true  error
2551 2552 2553
*/

bool check_show_routine_access(THD *thd, sp_head *sp, bool *full_access)
2554 2555 2556 2557 2558
{
  TABLE_LIST tables;
  bzero((char*) &tables,sizeof(tables));
  tables.db= (char*) "mysql";
  tables.table_name= tables.alias= (char*) "proc";
2559 2560
  *full_access= (!check_table_access(thd, SELECT_ACL, &tables, FALSE,
                                     1, TRUE) ||
2561 2562 2563 2564
                 (!strcmp(sp->m_definer_user.str,
                          thd->security_ctx->priv_user) &&
                  !strcmp(sp->m_definer_host.str,
                          thd->security_ctx->priv_host)));
2565
  if (!*full_access)
2566 2567
    return check_some_routine_access(thd, sp->m_db.str, sp->m_name.str,
                                     sp->m_type == TYPE_ENUM_PROCEDURE);
2568 2569 2570 2571
  return 0;
}


unknown's avatar
unknown committed
2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585
/**
  Implement SHOW CREATE statement for stored routines.

  @param thd  Thread context.
  @param type         Stored routine type
                      (TYPE_ENUM_PROCEDURE or TYPE_ENUM_FUNCTION)

  @return Error status.
    @retval FALSE on success
    @retval TRUE on error
*/

bool
sp_head::show_create_routine(THD *thd, int type)
unknown's avatar
unknown committed
2586
{
unknown's avatar
unknown committed
2587 2588 2589 2590 2591 2592 2593 2594
  const char *col1_caption= type == TYPE_ENUM_PROCEDURE ?
                            "Procedure" : "Function";

  const char *col3_caption= type == TYPE_ENUM_PROCEDURE ?
                            "Create Procedure" : "Create Function";

  bool err_status;

unknown's avatar
unknown committed
2595
  Protocol *protocol= thd->protocol;
unknown's avatar
unknown committed
2596 2597
  List<Item> fields;

2598
  LEX_STRING sql_mode;
unknown's avatar
unknown committed
2599

2600
  bool full_access;
unknown's avatar
unknown committed
2601 2602 2603 2604 2605 2606

  DBUG_ENTER("sp_head::show_create_routine");
  DBUG_PRINT("info", ("routine %s", m_name.str));

  DBUG_ASSERT(type == TYPE_ENUM_PROCEDURE ||
              type == TYPE_ENUM_FUNCTION);
unknown's avatar
unknown committed
2607

2608
  if (check_show_routine_access(thd, this, &full_access))
unknown's avatar
unknown committed
2609
    DBUG_RETURN(TRUE);
2610

2611
  sql_mode_string_representation(thd, m_sql_mode, &sql_mode);
unknown's avatar
unknown committed
2612 2613 2614

  /* Send header. */

unknown's avatar
unknown committed
2615
  fields.push_back(new Item_empty_string(col1_caption, NAME_CHAR_LEN));
unknown's avatar
unknown committed
2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632
  fields.push_back(new Item_empty_string("sql_mode", sql_mode.length));

  {
    /*
      NOTE: SQL statement field must be not less than 1024 in order not to
      confuse old clients.
    */

    Item_empty_string *stmt_fld=
      new Item_empty_string(col3_caption,
                            max(m_defstr.length, 1024));

    stmt_fld->maybe_null= TRUE;

    fields.push_back(stmt_fld);
  }

unknown's avatar
unknown committed
2633 2634 2635 2636 2637 2638 2639 2640 2641
  fields.push_back(new Item_empty_string("character_set_client",
                                         MY_CS_NAME_SIZE));

  fields.push_back(new Item_empty_string("collation_connection",
                                         MY_CS_NAME_SIZE));

  fields.push_back(new Item_empty_string("Database Collation",
                                         MY_CS_NAME_SIZE));

2642
  if (protocol->send_result_set_metadata(&fields,
unknown's avatar
unknown committed
2643 2644 2645 2646 2647 2648
                            Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
  {
    DBUG_RETURN(TRUE);
  }

  /* Send data. */
2649

unknown's avatar
unknown committed
2650
  protocol->prepare_for_resend();
unknown's avatar
unknown committed
2651

unknown's avatar
unknown committed
2652
  protocol->store(m_name.str, m_name.length, system_charset_info);
unknown's avatar
unknown committed
2653 2654
  protocol->store(sql_mode.str, sql_mode.length, system_charset_info);

2655
  if (full_access)
2656 2657
    protocol->store(m_defstr.str, m_defstr.length,
                    m_creation_ctx->get_client_cs());
2658 2659
  else
    protocol->store_null();
2660

unknown's avatar
unknown committed
2661 2662 2663 2664 2665

  protocol->store(m_creation_ctx->get_client_cs()->csname, system_charset_info);
  protocol->store(m_creation_ctx->get_connection_cl()->name, system_charset_info);
  protocol->store(m_creation_ctx->get_db_cl()->name, system_charset_info);

unknown's avatar
unknown committed
2666 2667 2668
  err_status= protocol->write();

  if (!err_status)
2669
    my_eof(thd);
unknown's avatar
unknown committed
2670 2671

  DBUG_RETURN(err_status);
unknown's avatar
unknown committed
2672 2673
}

2674

unknown's avatar
unknown committed
2675 2676
/**
  Add instruction to SP.
2677

unknown's avatar
unknown committed
2678
  @param instr   Instruction
2679 2680
*/

2681
int sp_head::add_instr(sp_instr *instr)
2682 2683 2684
{
  instr->free_list= m_thd->free_list;
  m_thd->free_list= 0;
2685 2686 2687 2688 2689 2690 2691
  /*
    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;
Alexey Botchkov's avatar
Alexey Botchkov committed
2692
  return insert_dynamic(&m_instr, (uchar*)&instr);
unknown's avatar
unknown committed
2693
}
2694

2695

unknown's avatar
unknown committed
2696
/**
2697
  Do some minimal optimization of the code:
unknown's avatar
unknown committed
2698 2699 2700
    -# Mark used instructions
    -# While doing this, shortcut jumps to jump instructions
    -# Compact the code, removing unused instructions.
2701 2702 2703 2704

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

unknown's avatar
unknown committed
2705 2706 2707 2708 2709
    - opt_mark()         :  Mark instruction as reachable
    - 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)
2710 2711 2712
*/

void sp_head::optimize()
2713 2714 2715 2716 2717
{
  List<sp_instr> bp;
  sp_instr *i;
  uint src, dst;

2718
  opt_mark();
2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731

  bp.empty();
  src= dst= 0;
  while ((i= get_instr(src)))
  {
    if (! i->marked)
    {
      delete i;
      src+= 1;
    }
    else
    {
      if (src != dst)
Marc Alff's avatar
Marc Alff committed
2732 2733
      {
        /* Move the instruction and update prev. jumps */
Davi Arnaut's avatar
Davi Arnaut committed
2734 2735
        sp_instr *ibp;
        List_iterator_fast<sp_instr> li(bp);
2736

Davi Arnaut's avatar
Davi Arnaut committed
2737 2738
        set_dynamic(&m_instr, (uchar*)&i, dst);
        while ((ibp= li++))
2739 2740 2741 2742
        {
          sp_instr_opt_meta *im= static_cast<sp_instr_opt_meta *>(ibp);
          im->set_destination(src, dst);
        }
2743 2744 2745 2746 2747 2748 2749 2750 2751 2752
      }
      i->opt_move(dst, &bp);
      src+= 1;
      dst+= 1;
    }
  }
  m_instr.elements= dst;
  bp.empty();
}

2753 2754 2755 2756 2757 2758 2759 2760
void sp_head::add_mark_lead(uint ip, List<sp_instr> *leads)
{
  sp_instr *i= get_instr(ip);

  if (i && ! i->marked)
    leads->push_front(i);
}

2761
void
2762
sp_head::opt_mark()
2763
{
2764
  uint ip;
2765
  sp_instr *i;
2766
  List<sp_instr> leads;
2767

2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796
  /*
    Forward flow analysis algorithm in the instruction graph:
    - first, add the entry point in the graph (the first instruction) to the
      'leads' list of paths to explore.
    - while there are still leads to explore:
      - pick one lead, and follow the path forward. Mark instruction reached.
        Stop only if the end of the routine is reached, or the path converge
        to code already explored (marked).
      - while following a path, collect in the 'leads' list any fork to
        another path (caused by conditional jumps instructions), so that these
        paths can be explored as well.
  */

  /* Add the entry point */
  i= get_instr(0);
  leads.push_front(i);

  /* For each path of code ... */
  while (leads.elements != 0)
  {
    i= leads.pop();

    /* Mark the entire path, collecting new leads. */
    while (i && ! i->marked)
    {
      ip= i->opt_mark(this, & leads);
      i= get_instr(ip);
    }
  }
2797 2798
}

2799

unknown's avatar
unknown committed
2800
#ifndef DBUG_OFF
unknown's avatar
unknown committed
2801
/**
2802
  Return the routine instructions as a result set.
unknown's avatar
unknown committed
2803 2804
  @return
    0 if ok, !=0 on error.
2805
*/
unknown's avatar
unknown committed
2806 2807 2808 2809 2810 2811 2812
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;
2813
  sp_instr *i;
unknown's avatar
unknown committed
2814
  bool full_access;
2815
  int res= 0;
unknown's avatar
unknown committed
2816 2817
  uint ip;
  DBUG_ENTER("sp_head::show_routine_code");
2818
  DBUG_PRINT("info", ("procedure: %s", m_name.str));
unknown's avatar
unknown committed
2819 2820 2821 2822 2823 2824 2825

  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",
2826 2827
                                             max(buffer.length(), 1024)));
  if (protocol->send_result_set_metadata(&field_list, Protocol::SEND_NUM_ROWS |
unknown's avatar
unknown committed
2828 2829 2830 2831 2832
                                         Protocol::SEND_EOF))
    DBUG_RETURN(1);

  for (ip= 0; (i = get_instr(ip)) ; ip++)
  {
Davi Arnaut's avatar
Davi Arnaut committed
2833
    /*
2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848
      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
2849 2850 2851 2852 2853
    protocol->prepare_for_resend();
    protocol->store((longlong)ip);

    buffer.set("", 0, system_charset_info);
    i->print(&buffer);
2854
    protocol->store(buffer.ptr(), buffer.length(), system_charset_info);
unknown's avatar
unknown committed
2855 2856 2857
    if ((res= protocol->write()))
      break;
  }
unknown's avatar
unknown committed
2858 2859

  if (!res)
2860
    my_eof(thd);
unknown's avatar
unknown committed
2861 2862 2863 2864 2865 2866

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


unknown's avatar
unknown committed
2867
/**
2868 2869 2870 2871
  Prepare LEX and thread for execution of instruction, if requested open
  and lock LEX's tables, execute instruction's core function, perform
  cleanup afterwards.

unknown's avatar
unknown committed
2872 2873 2874 2875 2876 2877 2878 2879
  @param thd           thread context
  @param nextp         out - next instruction
  @param 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).
  @param sp_instr      instruction for which we prepare context, and which core
                       function execute by calling its exec_core() method.
2880

unknown's avatar
unknown committed
2881
  @note
2882 2883 2884
    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().

unknown's avatar
unknown committed
2885
  @return
2886 2887 2888 2889 2890 2891 2892 2893
    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;
2894
  DBUG_ENTER("reset_lex_and_exec_core");
2895

Davi Arnaut's avatar
Davi Arnaut committed
2896
  /*
unknown's avatar
unknown committed
2897 2898 2899 2900 2901
    The flag is saved at the entry to the following substatement.
    It's reset further in the common code part.
    It's merged with the saved parent's value at the exit of this func.
  */
  bool parent_modified_non_trans_table= thd->transaction.stmt.modified_non_trans_table;
2902 2903 2904
  if (check_stack_overrun(thd, STACK_MIN_SIZE, (uchar*)&parent_modified_non_trans_table))
    DBUG_RETURN(TRUE);

unknown's avatar
unknown committed
2905
  thd->transaction.stmt.modified_non_trans_table= FALSE;
2906 2907 2908 2909 2910 2911 2912 2913 2914
  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;

2915
  thd->set_query_id(next_query_id());
2916

Konstantin Osipov's avatar
Konstantin Osipov committed
2917
  if (thd->locked_tables_mode <= LTM_LOCK_TABLES)
2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934
  {
    /*
      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);
    }
  }
2935

2936
  reinit_stmt_before_use(thd, m_lex);
2937 2938

  if (open_tables)
2939
    res= instr->exec_open_and_lock_tables(thd, m_lex->query_tables);
2940 2941

  if (!res)
2942
  {
2943
    res= instr->exec_core(thd, nextp);
2944 2945
    DBUG_PRINT("info",("exec_core returned: %d", res));
  }
2946

2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963
  /*
    Call after unit->cleanup() to close open table
    key read.
  */
  if (open_tables)
  {
    m_lex->unit.cleanup();
    /* Here we also commit or rollback the current statement. */
    if (! thd->in_sub_stmt)
    {
      thd->stmt_da->can_overwrite_status= TRUE;
      thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd);
      thd->stmt_da->can_overwrite_status= FALSE;
    }
    thd_proc_info(thd, "closing tables");
    close_thread_tables(thd);
    thd_proc_info(thd, 0);
2964

2965 2966 2967
    if (! thd->in_sub_stmt && ! thd->in_multi_stmt_transaction_mode())
      thd->mdl_context.release_transactional_locks();
  }
2968

2969
  if (m_lex->query_tables_own_last)
2970
  {
2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983
    /*
      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);
2984
  }
2985
  thd->rollback_item_tree_changes();
2986 2987 2988 2989 2990
  /*
    Update the state of the active arena if no errors on
    open_tables stage.
  */
  if (!res || !thd->is_error() ||
2991 2992 2993
      (thd->stmt_da->sql_errno() != ER_CANT_REOPEN_TABLE &&
       thd->stmt_da->sql_errno() != ER_NO_SUCH_TABLE &&
       thd->stmt_da->sql_errno() != ER_UPDATE_TABLE_USED))
2994
    thd->stmt_arena->state= Query_arena::EXECUTED;
2995

unknown's avatar
unknown committed
2996 2997 2998 2999 3000
  /*
    Merge here with the saved parent's values
    what is needed from the substatement gained
  */
  thd->transaction.stmt.modified_non_trans_table |= parent_modified_non_trans_table;
3001 3002 3003 3004 3005 3006 3007 3008 3009
  /*
    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()
  */
3010
  DBUG_RETURN(res || thd->is_error());
3011 3012 3013
}


unknown's avatar
unknown committed
3014 3015 3016 3017
/*
  sp_instr class functions
*/

3018
int sp_instr::exec_open_and_lock_tables(THD *thd, TABLE_LIST *tables)
3019 3020 3021 3022 3023 3024 3025
{
  int result;

  /*
    Check whenever we have access to tables for this statement
    and open and lock them before executing instructions core function.
  */
3026
  if (check_table_access(thd, SELECT_ACL, tables, FALSE, UINT_MAX, FALSE)
3027
      || open_and_lock_tables(thd, tables, TRUE, 0))
3028 3029 3030 3031 3032 3033 3034
    result= -1;
  else
    result= 0;

  return result;
}

3035
uint sp_instr::get_cont_dest()
3036
{
3037
  return (m_ip+1);
3038 3039 3040
}


3041
int sp_instr::exec_core(THD *thd, uint *nextp)
3042
{
3043 3044
  DBUG_ASSERT(0);
  return 0;
3045 3046
}

unknown's avatar
unknown committed
3047 3048 3049 3050
/*
  sp_instr_stmt class functions
*/

3051
int
3052
sp_instr_stmt::execute(THD *thd, uint *nextp)
3053
{
3054 3055
  char *query;
  uint32 query_length;
3056
  int res;
3057
  DBUG_ENTER("sp_instr_stmt::execute");
3058
  DBUG_PRINT("info", ("command: %d", m_lex_keeper.sql_command()));
3059

3060 3061 3062
  if (check_stack_overrun(thd, STACK_MIN_SIZE, (uchar*)&res))
    DBUG_RETURN(TRUE);

3063 3064
  query= thd->query();
  query_length= thd->query_length();
3065
#if defined(ENABLED_PROFILING)
3066 3067 3068
  /* This s-p instr is profilable and will be captured. */
  thd->profiling.set_query_source(m_query.str, m_query.length);
#endif
3069
  if (!(res= alloc_query(thd, m_query.str, m_query.length)) &&
3070
      !(res=subst_spvars(thd, this, &m_query)))
3071
  {
3072 3073 3074 3075
    /*
      (the order of query cache and subst_spvars calls is irrelevant because
      queries with SP vars can't be cached)
    */
3076
    if (unlikely((thd->variables.option_bits & OPTION_LOG_OFF)==0))
3077
      general_log_write(thd, COM_QUERY, thd->query(), thd->query_length());
3078

Davi Arnaut's avatar
Davi Arnaut committed
3079 3080
    if (query_cache_send_result_to_client(thd, thd->query(),
                                          thd->query_length()) <= 0)
3081
    {
3082
      res= m_lex_keeper.reset_lex_and_exec_core(thd, nextp, FALSE, this);
3083

Marc Alff's avatar
Marc Alff committed
3084
      if (thd->stmt_da->is_eof())
3085
        thd->protocol->end_statement();
3086 3087 3088

      query_cache_end_of_result(thd);

unknown's avatar
unknown committed
3089 3090
      if (!res && unlikely(thd->enable_slow_log))
        log_slow_statement(thd);
3091
    }
3092 3093
    else
      *nextp= m_ip+1;
3094
    thd->set_query(query, query_length);
3095
    thd->query_name_consts= 0;
3096 3097

    if (!thd->is_error())
Marc Alff's avatar
Marc Alff committed
3098
      thd->stmt_da->reset_diagnostics_area();
3099
  }
3100
  DBUG_RETURN(res || thd->is_error());
3101 3102
}

3103

3104 3105 3106
void
sp_instr_stmt::print(String *str)
{
unknown's avatar
unknown committed
3107 3108
  uint i, len;

3109 3110
  /* stmt CMD "..." */
  if (str->reserve(SP_STMT_PRINT_MAXLEN+SP_INSTR_UINT_MAXLEN+8))
3111
    return;
3112
  str->qs_append(STRING_WITH_LEN("stmt "));
3113
  str->qs_append((uint)m_lex_keeper.sql_command());
3114
  str->qs_append(STRING_WITH_LEN(" \""));
unknown's avatar
unknown committed
3115 3116 3117 3118 3119
  len= m_query.length;
  /*
    Print the query string (but not too much of it), just to indicate which
    statement it is.
  */
3120 3121
  if (len > SP_STMT_PRINT_MAXLEN)
    len= SP_STMT_PRINT_MAXLEN-3;
unknown's avatar
unknown committed
3122 3123
  /* Copy the query string and replace '\n' with ' ' in the process */
  for (i= 0 ; i < len ; i++)
3124
  {
unknown's avatar
unknown committed
3125 3126 3127 3128
    char c= m_query.str[i];
    if (c == '\n')
      c= ' ';
    str->qs_append(c);
3129
  }
3130
  if (m_query.length > SP_STMT_PRINT_MAXLEN)
3131
    str->qs_append(STRING_WITH_LEN("...")); /* Indicate truncated string */
3132
  str->qs_append('"');
3133
}
unknown's avatar
unknown committed
3134

3135

3136
int
3137
sp_instr_stmt::exec_core(THD *thd, uint *nextp)
3138
{
3139
  MYSQL_QUERY_EXEC_START(thd->query(),
3140 3141 3142
                         thd->thread_id,
                         (char *) (thd->db ? thd->db : ""),
                         thd->security_ctx->priv_user,
3143
                         (char *)thd->security_ctx->host_or_ip,
3144
                         3);
3145
  int res= mysql_execute_command(thd);
3146
  MYSQL_QUERY_EXEC_DONE(res);
3147
  *nextp= m_ip+1;
3148
  return res;
3149 3150
}

unknown's avatar
unknown committed
3151 3152 3153 3154 3155

/*
  sp_instr_set class functions
*/

3156
int
3157
sp_instr_set::execute(THD *thd, uint *nextp)
3158
{
3159 3160
  DBUG_ENTER("sp_instr_set::execute");
  DBUG_PRINT("info", ("offset: %u", m_offset));
3161 3162 3163 3164

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

unknown's avatar
unknown committed
3165

3166 3167 3168
int
sp_instr_set::exec_core(THD *thd, uint *nextp)
{
3169
  int res= thd->spcont->set_variable(thd, m_offset, &m_value);
3170

3171
  if (res)
3172
  {
3173
    /* Failed to evaluate the value. Reset the variable to NULL. */
3174

3175 3176 3177
    if (thd->spcont->set_variable(thd, m_offset, 0))
    {
      /* If this also failed, let's abort. */
3178
      my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR));
3179 3180
    }
  }
3181

3182
  *nextp = m_ip+1;
3183
  return res;
3184 3185
}

3186 3187 3188
void
sp_instr_set::print(String *str)
{
3189 3190
  /* set name@offset ... */
  int rsrv = SP_INSTR_UINT_MAXLEN+6;
3191
  sp_variable_t *var = m_ctx->find_variable(m_offset);
unknown's avatar
unknown committed
3192 3193 3194 3195

  /* 'var' should always be non-null, but just in case... */
  if (var)
    rsrv+= var->name.length;
3196 3197
  if (str->reserve(rsrv))
    return;
3198
  str->qs_append(STRING_WITH_LEN("set "));
unknown's avatar
unknown committed
3199 3200
  if (var)
  {
3201 3202
    str->qs_append(var->name.str, var->name.length);
    str->qs_append('@');
unknown's avatar
unknown committed
3203
  }
3204
  str->qs_append(m_offset);
3205
  str->qs_append(' ');
3206
  m_value->print(str, QT_ORDINARY);
3207 3208
}

3209

unknown's avatar
unknown committed
3210 3211 3212 3213
/*
  sp_instr_set_trigger_field class functions
*/

3214 3215 3216 3217
int
sp_instr_set_trigger_field::execute(THD *thd, uint *nextp)
{
  DBUG_ENTER("sp_instr_set_trigger_field::execute");
3218
  thd->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL;
3219 3220 3221 3222 3223 3224 3225
  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)
{
3226
  const int res= (trigger_field->set_value(thd, &value) ? -1 : 0);
3227 3228
  *nextp = m_ip+1;
  return res;
3229 3230 3231 3232 3233
}

void
sp_instr_set_trigger_field::print(String *str)
{
3234
  str->append(STRING_WITH_LEN("set_trigger_field "));
3235
  trigger_field->print(str, QT_ORDINARY);
3236
  str->append(STRING_WITH_LEN(":="));
3237
  value->print(str, QT_ORDINARY);
3238 3239
}

3240 3241 3242 3243
/*
  sp_instr_opt_meta
*/

3244
uint sp_instr_opt_meta::get_cont_dest()
3245
{
3246
  return m_cont_dest;
3247 3248
}

unknown's avatar
unknown committed
3249 3250 3251 3252 3253

/*
 sp_instr_jump class functions
*/

3254 3255 3256 3257 3258 3259 3260 3261 3262 3263
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);
}

3264 3265 3266
void
sp_instr_jump::print(String *str)
{
3267 3268
  /* jump dest */
  if (str->reserve(SP_INSTR_UINT_MAXLEN+5))
3269
    return;
3270
  str->qs_append(STRING_WITH_LEN("jump "));
3271 3272 3273
  str->qs_append(m_dest);
}

3274
uint
3275
sp_instr_jump::opt_mark(sp_head *sp, List<sp_instr> *leads)
3276
{
3277
  m_dest= opt_shortcut_jump(sp, this);
Davi Arnaut's avatar
Davi Arnaut committed
3278
  if (m_dest != m_ip+1)   /* Jumping to following instruction? */
3279
    marked= 1;
3280 3281 3282 3283 3284
  m_optdest= sp->get_instr(m_dest);
  return m_dest;
}

uint
3285
sp_instr_jump::opt_shortcut_jump(sp_head *sp, sp_instr *start)
3286 3287 3288 3289 3290 3291
{
  uint dest= m_dest;
  sp_instr *i;

  while ((i= sp->get_instr(dest)))
  {
3292
    uint ndest;
3293

3294
    if (start == i || this == i)
3295 3296
      break;
    ndest= i->opt_shortcut_jump(sp, start);
3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307
    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)
Davi Arnaut's avatar
Davi Arnaut committed
3308
    bp->push_back(this);      // Forward
3309
  else if (m_optdest)
Davi Arnaut's avatar
Davi Arnaut committed
3310
    m_dest= m_optdest->m_ip;  // Backward
3311 3312 3313
  m_ip= dst;
}

unknown's avatar
unknown committed
3314 3315 3316 3317 3318

/*
  sp_instr_jump_if_not class functions
*/

3319 3320 3321
int
sp_instr_jump_if_not::execute(THD *thd, uint *nextp)
{
3322 3323
  DBUG_ENTER("sp_instr_jump_if_not::execute");
  DBUG_PRINT("info", ("destination: %u", m_dest));
3324 3325 3326 3327 3328 3329 3330
  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)
{
3331 3332
  Item *it;
  int res;
3333

3334
  it= sp_prepare_func_item(thd, &m_expr);
3335
  if (! it)
3336
  {
3337
    res= -1;
3338
  }
3339
  else
3340 3341
  {
    res= 0;
3342
    if (! it->val_bool())
3343 3344 3345 3346
      *nextp = m_dest;
    else
      *nextp = m_ip+1;
  }
3347 3348

  return res;
3349
}
3350

unknown's avatar
unknown committed
3351

3352 3353 3354
void
sp_instr_jump_if_not::print(String *str)
{
3355
  /* jump_if_not dest(cont) ... */
3356
  if (str->reserve(2*SP_INSTR_UINT_MAXLEN+14+32)) // Add some for the expr. too
3357
    return;
3358
  str->qs_append(STRING_WITH_LEN("jump_if_not "));
3359
  str->qs_append(m_dest);
3360
  str->qs_append('(');
3361
  str->qs_append(m_cont_dest);
3362
  str->qs_append(STRING_WITH_LEN(") "));
3363
  m_expr->print(str, QT_ORDINARY);
3364 3365
}

unknown's avatar
unknown committed
3366

3367
uint
3368
sp_instr_jump_if_not::opt_mark(sp_head *sp, List<sp_instr> *leads)
3369 3370 3371 3372 3373 3374
{
  sp_instr *i;

  marked= 1;
  if ((i= sp->get_instr(m_dest)))
  {
3375
    m_dest= i->opt_shortcut_jump(sp, this);
3376 3377
    m_optdest= sp->get_instr(m_dest);
  }
3378
  sp->add_mark_lead(m_dest, leads);
3379 3380 3381 3382 3383
  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);
  }
3384
  sp->add_mark_lead(m_cont_dest, leads);
3385 3386 3387
  return m_ip+1;
}

3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407
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
3408 3409 3410 3411

/*
  sp_instr_freturn class functions
*/
3412

3413
int
3414
sp_instr_freturn::execute(THD *thd, uint *nextp)
3415
{
3416
  DBUG_ENTER("sp_instr_freturn::execute");
3417 3418 3419 3420 3421 3422 3423
  DBUG_RETURN(m_lex_keeper.reset_lex_and_exec_core(thd, nextp, TRUE, this));
}


int
sp_instr_freturn::exec_core(THD *thd, uint *nextp)
{
3424 3425 3426 3427
  /*
    Change <next instruction pointer>, so that this will be the last
    instruction in the stored function.
  */
3428

3429
  *nextp= UINT_MAX;
3430

3431 3432 3433 3434 3435 3436 3437 3438
  /*
    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.
  */

3439
  return thd->spcont->set_return_value(thd, &m_value);
3440
}
3441

3442 3443 3444
void
sp_instr_freturn::print(String *str)
{
3445
  /* freturn type expr... */
3446
  if (str->reserve(1024+8+32)) // Add some for the expr. too
3447
    return;
3448
  str->qs_append(STRING_WITH_LEN("freturn "));
3449
  str->qs_append((uint)m_type);
3450
  str->qs_append(' ');
3451
  m_value->print(str, QT_ORDINARY);
3452 3453
}

unknown's avatar
unknown committed
3454 3455 3456 3457
/*
  sp_instr_hpush_jump class functions
*/

3458 3459 3460 3461 3462 3463 3464 3465
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++))
Marc Alff's avatar
Marc Alff committed
3466
    thd->spcont->push_handler(p, m_ip+1, m_type);
3467 3468 3469 3470 3471

  *nextp= m_dest;
  DBUG_RETURN(0);
}

unknown's avatar
unknown committed
3472

3473 3474 3475
void
sp_instr_hpush_jump::print(String *str)
{
3476 3477
  /* hpush_jump dest fsize type */
  if (str->reserve(SP_INSTR_UINT_MAXLEN*2 + 21))
3478
    return;
3479
  str->qs_append(STRING_WITH_LEN("hpush_jump "));
3480
  str->qs_append(m_dest);
3481
  str->qs_append(' ');
3482
  str->qs_append(m_frame);
unknown's avatar
unknown committed
3483
  switch (m_type) {
unknown's avatar
unknown committed
3484
  case SP_HANDLER_NONE:
3485
    str->qs_append(STRING_WITH_LEN(" NONE")); // This would be a bug
unknown's avatar
unknown committed
3486 3487
    break;
  case SP_HANDLER_EXIT:
3488
    str->qs_append(STRING_WITH_LEN(" EXIT"));
unknown's avatar
unknown committed
3489 3490
    break;
  case SP_HANDLER_CONTINUE:
3491
    str->qs_append(STRING_WITH_LEN(" CONTINUE"));
unknown's avatar
unknown committed
3492 3493
    break;
  case SP_HANDLER_UNDO:
3494
    str->qs_append(STRING_WITH_LEN(" UNDO"));
unknown's avatar
unknown committed
3495 3496
    break;
  default:
unknown's avatar
unknown committed
3497 3498
    // This would be a bug as well
    str->qs_append(STRING_WITH_LEN(" UNKNOWN:"));
unknown's avatar
unknown committed
3499 3500
    str->qs_append(m_type);
  }
3501 3502
}

unknown's avatar
unknown committed
3503

3504
uint
3505
sp_instr_hpush_jump::opt_mark(sp_head *sp, List<sp_instr> *leads)
3506 3507 3508 3509 3510 3511
{
  sp_instr *i;

  marked= 1;
  if ((i= sp->get_instr(m_dest)))
  {
3512
    m_dest= i->opt_shortcut_jump(sp, this);
3513 3514
    m_optdest= sp->get_instr(m_dest);
  }
3515
  sp->add_mark_lead(m_dest, leads);
3516 3517 3518
  return m_ip+1;
}

unknown's avatar
unknown committed
3519 3520 3521 3522 3523

/*
  sp_instr_hpop class functions
*/

3524 3525 3526 3527 3528 3529 3530 3531 3532
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);
}

3533 3534 3535
void
sp_instr_hpop::print(String *str)
{
3536 3537
  /* hpop count */
  if (str->reserve(SP_INSTR_UINT_MAXLEN+5))
3538
    return;
3539
  str->qs_append(STRING_WITH_LEN("hpop "));
3540 3541 3542
  str->qs_append(m_count);
}

3543

unknown's avatar
unknown committed
3544 3545 3546 3547
/*
  sp_instr_hreturn class functions
*/

3548 3549 3550 3551
int
sp_instr_hreturn::execute(THD *thd, uint *nextp)
{
  DBUG_ENTER("sp_instr_hreturn::execute");
3552 3553 3554 3555 3556 3557
  if (m_dest)
    *nextp= m_dest;
  else
  {
    *nextp= thd->spcont->pop_hstack();
  }
3558
  thd->spcont->exit_handler();
3559 3560
  DBUG_RETURN(0);
}
3561

unknown's avatar
unknown committed
3562

3563 3564 3565
void
sp_instr_hreturn::print(String *str)
{
3566 3567
  /* hreturn framesize dest */
  if (str->reserve(SP_INSTR_UINT_MAXLEN*2 + 9))
3568
    return;
3569
  str->qs_append(STRING_WITH_LEN("hreturn "));
3570
  str->qs_append(m_frame);
3571
  if (m_dest)
3572
  {
3573
    str->qs_append(' ');
3574
    str->qs_append(m_dest);
3575
  }
3576 3577
}

unknown's avatar
unknown committed
3578

3579
uint
3580
sp_instr_hreturn::opt_mark(sp_head *sp, List<sp_instr> *leads)
3581
{
3582
  marked= 1;
Davi Arnaut's avatar
Davi Arnaut committed
3583

3584 3585 3586 3587 3588 3589 3590
  if (m_dest)
  {
    /*
      This is an EXIT handler; next instruction step is in m_dest.
     */
    return m_dest;
  }
Davi Arnaut's avatar
Davi Arnaut committed
3591

3592 3593 3594 3595
  /*
    This is a CONTINUE handler; next instruction step will come from
    the handler stack and not from opt_mark.
   */
3596
  return UINT_MAX;
3597 3598
}

3599

unknown's avatar
unknown committed
3600 3601 3602 3603
/*
  sp_instr_cpush class functions
*/

3604 3605 3606
int
sp_instr_cpush::execute(THD *thd, uint *nextp)
{
unknown's avatar
unknown committed
3607
  Query_arena backup_arena;
3608
  DBUG_ENTER("sp_instr_cpush::execute");
3609 3610 3611 3612 3613

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

3616
  thd->spcont->push_cursor(&m_lex_keeper, this);
3617

unknown's avatar
unknown committed
3618
  thd->restore_active_arena(thd->spcont->callers_arena, &backup_arena);
3619

3620
  *nextp= m_ip+1;
3621

3622 3623 3624
  DBUG_RETURN(0);
}

unknown's avatar
unknown committed
3625

3626 3627 3628
void
sp_instr_cpush::print(String *str)
{
unknown's avatar
unknown committed
3629 3630
  LEX_STRING n;
  my_bool found= m_ctx->find_cursor(m_cursor, &n);
3631 3632
  /* cpush name@offset */
  uint rsrv= SP_INSTR_UINT_MAXLEN+7;
unknown's avatar
unknown committed
3633

3634 3635 3636 3637
  if (found)
    rsrv+= n.length;
  if (str->reserve(rsrv))
    return;
3638
  str->qs_append(STRING_WITH_LEN("cpush "));
unknown's avatar
unknown committed
3639 3640
  if (found)
  {
3641 3642
    str->qs_append(n.str, n.length);
    str->qs_append('@');
unknown's avatar
unknown committed
3643 3644
  }
  str->qs_append(m_cursor);
3645 3646
}

unknown's avatar
unknown committed
3647 3648 3649 3650 3651

/*
  sp_instr_cpop class functions
*/

3652 3653 3654 3655 3656 3657 3658 3659 3660
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
3661

3662 3663 3664
void
sp_instr_cpop::print(String *str)
{
3665 3666
  /* cpop count */
  if (str->reserve(SP_INSTR_UINT_MAXLEN+5))
3667
    return;
3668
  str->qs_append(STRING_WITH_LEN("cpop "));
3669 3670 3671
  str->qs_append(m_count);
}

unknown's avatar
unknown committed
3672 3673 3674 3675 3676

/*
  sp_instr_copen class functions
*/

unknown's avatar
unknown committed
3677 3678 3679 3680 3681
/**
  @todo
    Assert that we either have an error or a cursor
*/

3682 3683 3684
int
sp_instr_copen::execute(THD *thd, uint *nextp)
{
3685 3686 3687 3688
  /*
    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.
  */
3689 3690 3691 3692 3693 3694 3695 3696
  sp_cursor *c= thd->spcont->get_cursor(m_cursor);
  int res;
  DBUG_ENTER("sp_instr_copen::execute");

  if (! c)
    res= -1;
  else
  {
3697 3698
    sp_lex_keeper *lex_keeper= c->get_lex_keeper();
    Query_arena *old_arena= thd->stmt_arena;
3699

3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711
    /*
      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;
    /* TODO: Assert here that we either have an error or a cursor */
3712 3713 3714 3715
  }
  DBUG_RETURN(res);
}

unknown's avatar
unknown committed
3716

3717 3718 3719
int
sp_instr_copen::exec_core(THD *thd, uint *nextp)
{
3720 3721
  sp_cursor *c= thd->spcont->get_cursor(m_cursor);
  int res= c->open(thd);
3722 3723 3724 3725
  *nextp= m_ip+1;
  return res;
}

3726 3727 3728
void
sp_instr_copen::print(String *str)
{
unknown's avatar
unknown committed
3729 3730
  LEX_STRING n;
  my_bool found= m_ctx->find_cursor(m_cursor, &n);
3731 3732
  /* copen name@offset */
  uint rsrv= SP_INSTR_UINT_MAXLEN+7;
unknown's avatar
unknown committed
3733

3734 3735 3736 3737
  if (found)
    rsrv+= n.length;
  if (str->reserve(rsrv))
    return;
3738
  str->qs_append(STRING_WITH_LEN("copen "));
unknown's avatar
unknown committed
3739 3740
  if (found)
  {
3741 3742
    str->qs_append(n.str, n.length);
    str->qs_append('@');
unknown's avatar
unknown committed
3743
  }
3744 3745 3746
  str->qs_append(m_cursor);
}

unknown's avatar
unknown committed
3747 3748 3749 3750 3751

/*
  sp_instr_cclose class functions
*/

3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766
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
3767

3768 3769 3770
void
sp_instr_cclose::print(String *str)
{
unknown's avatar
unknown committed
3771 3772
  LEX_STRING n;
  my_bool found= m_ctx->find_cursor(m_cursor, &n);
3773 3774
  /* cclose name@offset */
  uint rsrv= SP_INSTR_UINT_MAXLEN+8;
unknown's avatar
unknown committed
3775

3776 3777 3778 3779
  if (found)
    rsrv+= n.length;
  if (str->reserve(rsrv))
    return;
3780
  str->qs_append(STRING_WITH_LEN("cclose "));
unknown's avatar
unknown committed
3781 3782
  if (found)
  {
3783 3784
    str->qs_append(n.str, n.length);
    str->qs_append('@');
unknown's avatar
unknown committed
3785
  }
3786 3787 3788
  str->qs_append(m_cursor);
}

unknown's avatar
unknown committed
3789 3790 3791 3792 3793

/*
  sp_instr_cfetch class functions
*/

3794 3795 3796 3797 3798
int
sp_instr_cfetch::execute(THD *thd, uint *nextp)
{
  sp_cursor *c= thd->spcont->get_cursor(m_cursor);
  int res;
unknown's avatar
unknown committed
3799
  Query_arena backup_arena;
3800 3801
  DBUG_ENTER("sp_instr_cfetch::execute");

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

3804 3805 3806
  *nextp= m_ip+1;
  DBUG_RETURN(res);
}
3807

unknown's avatar
unknown committed
3808

3809 3810 3811
void
sp_instr_cfetch::print(String *str)
{
3812 3813
  List_iterator_fast<struct sp_variable> li(m_varlist);
  sp_variable_t *pv;
unknown's avatar
unknown committed
3814 3815
  LEX_STRING n;
  my_bool found= m_ctx->find_cursor(m_cursor, &n);
3816 3817
  /* cfetch name@offset vars... */
  uint rsrv= SP_INSTR_UINT_MAXLEN+8;
3818

3819 3820 3821 3822
  if (found)
    rsrv+= n.length;
  if (str->reserve(rsrv))
    return;
3823
  str->qs_append(STRING_WITH_LEN("cfetch "));
unknown's avatar
unknown committed
3824 3825
  if (found)
  {
3826 3827
    str->qs_append(n.str, n.length);
    str->qs_append('@');
unknown's avatar
unknown committed
3828
  }
3829 3830 3831
  str->qs_append(m_cursor);
  while ((pv= li++))
  {
3832
    if (str->reserve(pv->name.length+SP_INSTR_UINT_MAXLEN+2))
3833 3834 3835 3836
      return;
    str->qs_append(' ');
    str->qs_append(pv->name.str, pv->name.length);
    str->qs_append('@');
3837 3838 3839 3840
    str->qs_append(pv->offset);
  }
}

unknown's avatar
unknown committed
3841 3842 3843 3844 3845

/*
  sp_instr_error class functions
*/

3846 3847 3848 3849 3850
int
sp_instr_error::execute(THD *thd, uint *nextp)
{
  DBUG_ENTER("sp_instr_error::execute");

unknown's avatar
unknown committed
3851
  my_message(m_errcode, ER(m_errcode), MYF(0));
3852 3853 3854 3855
  *nextp= m_ip+1;
  DBUG_RETURN(-1);
}

unknown's avatar
unknown committed
3856

3857 3858 3859
void
sp_instr_error::print(String *str)
{
3860 3861
  /* error code */
  if (str->reserve(SP_INSTR_UINT_MAXLEN+6))
3862
    return;
3863
  str->qs_append(STRING_WITH_LEN("error "));
3864 3865 3866
  str->qs_append(m_errcode);
}

3867

3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883
/**************************************************************************
  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)
{
3884
  int res= thd->spcont->set_case_expr(thd, m_case_expr_id, &m_case_expr);
3885

3886
  if (res && !thd->spcont->get_case_expr(m_case_expr_id))
3887 3888 3889
  {
    /*
      Failed to evaluate the value, the case expression is still not
3890
      initialized. Set to NULL so we can continue.
3891 3892 3893
    */

    Item *null_item= new Item_null();
Davi Arnaut's avatar
Davi Arnaut committed
3894

3895
    if (!null_item ||
3896
        thd->spcont->set_case_expr(thd, m_case_expr_id, &null_item))
3897 3898
    {
      /* If this also failed, we have to abort. */
3899
      my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR));
3900 3901
    }
  }
3902 3903
  else
    *nextp= m_ip+1;
3904

3905
  return res;
3906 3907 3908 3909 3910 3911
}


void
sp_instr_set_case_expr::print(String *str)
{
3912 3913 3914 3915 3916
  /* 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(") "));
3917
  str->qs_append(m_case_expr_id);
3918
  str->qs_append(' ');
3919
  m_case_expr->print(str, QT_ORDINARY);
3920 3921
}

3922
uint
3923
sp_instr_set_case_expr::opt_mark(sp_head *sp, List<sp_instr> *leads)
3924 3925 3926 3927 3928 3929 3930 3931 3932
{
  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);
  }
3933
  sp->add_mark_lead(m_cont_dest, leads);
3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946
  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;
}

3947

unknown's avatar
unknown committed
3948
/* ------------------------------------------------------------------ */
3949

3950 3951

/*
3952 3953 3954 3955
  Structure that represent all instances of one table
  in optimized multi-set of tables used by routine.
*/

3956 3957
typedef struct st_sp_table
{
3958 3959 3960 3961 3962 3963 3964 3965
  /*
    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
3966 3967 3968
  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 */
3969 3970
  uint lock_count;
  uint query_lock_count;
3971
  uint8 trg_event_map;
3972 3973
} SP_TABLE;

3974 3975

uchar *sp_table_key(const uchar *ptr, size_t *plen, my_bool first)
3976 3977 3978
{
  SP_TABLE *tab= (SP_TABLE *)ptr;
  *plen= tab->qname.length;
3979
  return (uchar *)tab->qname.str;
3980 3981
}

3982

unknown's avatar
unknown committed
3983
/**
3984 3985 3986
  Merge the list of tables used by some query into the multi-set of
  tables used by routine.

unknown's avatar
unknown committed
3987 3988 3989 3990
  @param thd                 thread context
  @param table               table list
  @param lex_for_tmp_check   LEX of the query for which we are merging
                             table list.
3991

unknown's avatar
unknown committed
3992
  @note
3993 3994 3995
    This method will use LEX provided to check whenever we are creating
    temporary table and mark it as such in target multi-set.

unknown's avatar
unknown committed
3996 3997 3998 3999
  @retval
    TRUE    Success
  @retval
    FALSE   Error
4000 4001
*/

4002
bool
4003
sp_head::merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check)
4004
{
4005 4006 4007 4008 4009 4010 4011 4012
  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++)
  {
Konstantin Osipov's avatar
Konstantin Osipov committed
4013
    tab= (SP_TABLE*) my_hash_element(&m_sptabs, i);
4014 4015 4016
    tab->query_lock_count= 0;
  }

4017
  for (; table ; table= table->next_global)
4018
    if (!table->derived && !table->schema_table)
4019
    {
unknown's avatar
unknown committed
4020
      char tname[(NAME_LEN + 1) * 3];           // db\0table\0alias\0
4021 4022 4023 4024
      uint tlen, alen;

      tlen= table->db_length;
      memcpy(tname, table->db, tlen);
unknown's avatar
unknown committed
4025
      tname[tlen++]= '\0';
4026 4027
      memcpy(tname+tlen, table->table_name, table->table_name_length);
      tlen+= table->table_name_length;
unknown's avatar
unknown committed
4028
      tname[tlen++]= '\0';
4029 4030 4031 4032 4033
      alen= strlen(table->alias);
      memcpy(tname+tlen, table->alias, alen);
      tlen+= alen;
      tname[tlen]= '\0';

unknown's avatar
unknown committed
4034 4035 4036 4037 4038 4039 4040 4041
      /*
        Upgrade the lock type because this table list will be used
        only in pre-locked mode, in which DELAYED inserts are always
        converted to normal inserts.
      */
      if (table->lock_type == TL_WRITE_DELAYED)
        table->lock_type= TL_WRITE;

4042
      /*
4043 4044 4045
        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.
4046
      */
Konstantin Osipov's avatar
Konstantin Osipov committed
4047 4048
      if ((tab= (SP_TABLE*) my_hash_search(&m_sptabs, (uchar *)tname, tlen)) ||
          ((tab= (SP_TABLE*) my_hash_search(&m_sptabs, (uchar *)tname,
4049 4050
                                        tlen - alen - 1)) &&
           tab->temp))
4051
      {
4052 4053
        if (tab->lock_type < table->lock_type)
          tab->lock_type= table->lock_type; // Use the table with the highest lock type
4054 4055 4056
        tab->query_lock_count++;
        if (tab->query_lock_count > tab->lock_count)
          tab->lock_count++;
4057
        tab->trg_event_map|= table->trg_event_map;
4058 4059 4060
      }
      else
      {
Davi Arnaut's avatar
Davi Arnaut committed
4061 4062 4063 4064 4065
        if (!(tab= (SP_TABLE *)thd->calloc(sizeof(SP_TABLE))))
          return FALSE;
        if (lex_for_tmp_check->sql_command == SQLCOM_CREATE_TABLE &&
            lex_for_tmp_check->query_tables == table &&
            lex_for_tmp_check->create_info.options & HA_LEX_CREATE_TMP_TABLE)
4066
        {
Davi Arnaut's avatar
Davi Arnaut committed
4067
          tab->temp= TRUE;
4068 4069 4070 4071 4072 4073 4074
          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
4075 4076
        tab->table_name_length= table->table_name_length;
        tab->db_length= table->db_length;
4077
        tab->lock_type= table->lock_type;
4078
        tab->lock_count= tab->query_lock_count= 1;
4079
        tab->trg_event_map= table->trg_event_map;
Davi Arnaut's avatar
Davi Arnaut committed
4080
        if (my_hash_insert(&m_sptabs, (uchar *)tab))
4081
          return FALSE;
4082 4083 4084 4085 4086 4087
      }
    }
  return TRUE;
}


unknown's avatar
unknown committed
4088
/**
4089
  Add tables used by routine to the table list.
4090

4091 4092
    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'.
4093

4094 4095
    Elements of list will be allocated in PS memroot, so this list will be
    persistent between PS executions.
4096

unknown's avatar
unknown committed
4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107
  @param[in] thd                        Thread context
  @param[in,out] query_tables_last_ptr  Pointer to the next_global member of
    last element of the list where tables
    will be added (or to its root).
  @param[in] belong_to_view             Uppermost view which uses this routine,
    0 if none.

  @retval
    TRUE    if some elements were added
  @retval
    FALSE   otherwise.
4108
*/
4109

4110 4111
bool
sp_head::add_used_tables_to_table_list(THD *thd,
4112 4113
                                       TABLE_LIST ***query_tables_last_ptr,
                                       TABLE_LIST *belong_to_view)
4114 4115
{
  uint i;
unknown's avatar
unknown committed
4116
  Query_arena *arena, backup;
4117 4118 4119 4120
  bool result= FALSE;
  DBUG_ENTER("sp_head::add_used_tables_to_table_list");

  /*
4121 4122 4123 4124 4125 4126
    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.
4127
  */
unknown's avatar
unknown committed
4128
  arena= thd->activate_stmt_arena_if_needed(&backup);
4129

4130
  for (i=0 ; i < m_sptabs.records ; i++)
4131
  {
4132
    char *tab_buff, *key_buff;
unknown's avatar
unknown committed
4133
    TABLE_LIST *table;
Konstantin Osipov's avatar
Konstantin Osipov committed
4134
    SP_TABLE *stab= (SP_TABLE*) my_hash_element(&m_sptabs, i);
4135 4136 4137
    if (stab->temp)
      continue;

4138
    if (!(tab_buff= (char *)thd->calloc(ALIGN_SIZE(sizeof(TABLE_LIST)) *
4139 4140 4141
                                        stab->lock_count)) ||
        !(key_buff= (char*)thd->memdup(stab->qname.str,
                                       stab->qname.length + 1)))
4142
      DBUG_RETURN(FALSE);
4143

4144 4145 4146 4147
    for (uint j= 0; j < stab->lock_count; j++)
    {
      table= (TABLE_LIST *)tab_buff;

4148
      table->db= key_buff;
unknown's avatar
unknown committed
4149 4150 4151 4152
      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;
4153
      table->lock_type= stab->lock_type;
4154 4155
      table->cacheable_table= 1;
      table->prelocking_placeholder= 1;
4156
      table->belong_to_view= belong_to_view;
4157
      table->trg_event_map= stab->trg_event_map;
4158 4159 4160 4161 4162
      /*
        Since we don't allow DDL on base tables in prelocked mode it
        is safe to infer the type of metadata lock from the type of
        table lock.
      */
Konstantin Osipov's avatar
Konstantin Osipov committed
4163
      table->mdl_request.init(MDL_key::TABLE, table->db, table->table_name,
4164 4165
                              table->lock_type >= TL_WRITE_ALLOW_WRITE ?
                              MDL_SHARED_WRITE : MDL_SHARED_READ);
4166 4167 4168 4169 4170 4171 4172 4173 4174 4175

      /* 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;
    }
4176
  }
4177 4178

  if (arena)
unknown's avatar
unknown committed
4179
    thd->restore_active_arena(arena, &backup);
4180 4181

  DBUG_RETURN(result);
4182 4183
}

unknown's avatar
unknown committed
4184

unknown's avatar
unknown committed
4185
/**
4186
  Simple function for adding an explicitly named (systems) table to
unknown's avatar
unknown committed
4187 4188 4189
  the global table list, e.g. "mysql", "proc".
*/

4190 4191 4192
TABLE_LIST *
sp_add_to_query_tables(THD *thd, LEX *lex,
		       const char *db, const char *name,
4193 4194
                       thr_lock_type locktype,
                       enum_mdl_type mdl_type)
4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205
{
  TABLE_LIST *table;

  if (!(table= (TABLE_LIST *)thd->calloc(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;
4206
  table->select_lex= lex->current_select;
4207
  table->cacheable_table= 1;
Konstantin Osipov's avatar
Konstantin Osipov committed
4208
  table->mdl_request.init(MDL_key::TABLE, table->db, table->table_name,
4209
                          mdl_type);
Konstantin Osipov's avatar
Konstantin Osipov committed
4210

4211 4212 4213
  lex->add_to_query_tables(table);
  return table;
}
4214