sp_head.h 35.1 KB
Newer Older
1
/* -*- C++ -*- */
2
/*
Sergei Golubchik's avatar
Sergei Golubchik committed
3
   Copyright (c) 2002, 2011, Oracle and/or its affiliates.
4 5 6

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
unknown's avatar
unknown committed
7
   the Free Software Foundation; version 2 of the License.
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
16
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
17 18 19 20

#ifndef _SP_HEAD_H_
#define _SP_HEAD_H_

21
#ifdef USE_PRAGMA_INTERFACE
22 23 24
#pragma interface			/* gcc class implementation */
#endif

25 26 27 28 29
/*
  It is necessary to include set_var.h instead of item.h because there
  are dependencies on include order for set_var.h and item.h. This
  will be resolved later.
*/
30
#include "my_global.h"                          /* NO_EMBEDDED_ACCESS_CHECKS */
31 32
#include "sql_class.h"                          // THD, set_var.h: THD
#include "set_var.h"                            // Item
33
#include "sp_pcontext.h"                        // sp_pcontext
34
#include <stddef.h>
35
#include "sp.h"
36

37 38 39 40 41
/**
  @defgroup Stored_Routines Stored Routines
  @ingroup Runtime_Environment
  @{
*/
42

43 44 45 46 47
// Values for the type enum. This reflects the order of the enum declaration
// in the CREATE TABLE command.
//#define TYPE_ENUM_FUNCTION  1 #define TYPE_ENUM_PROCEDURE 2 #define
//TYPE_ENUM_TRIGGER   3 #define TYPE_ENUM_PROXY     4

48 49 50
Item_result
sp_map_result_type(enum enum_field_types type);

51 52 53
Item::Type
sp_map_item_type(enum enum_field_types type);

54 55
uint
sp_get_flags_for_command(LEX *lex);
56

57
class sp_instr;
58
class sp_instr_opt_meta;
59
class sp_instr_jump_if_not;
60

unknown's avatar
unknown committed
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
/*************************************************************************/

/**
  Stored_program_creation_ctx -- base class for creation context of stored
  programs (stored routines, triggers, events).
*/

class Stored_program_creation_ctx :public Default_object_creation_ctx
{
public:
  CHARSET_INFO *get_db_cl()
  {
    return m_db_cl;
  }

public:
  virtual Stored_program_creation_ctx *clone(MEM_ROOT *mem_root) = 0;

protected:
  Stored_program_creation_ctx(THD *thd)
    : Default_object_creation_ctx(thd),
      m_db_cl(thd->variables.collation_database)
  { }

  Stored_program_creation_ctx(CHARSET_INFO *client_cs,
                              CHARSET_INFO *connection_cl,
                              CHARSET_INFO *db_cl)
    : Default_object_creation_ctx(client_cs, connection_cl),
      m_db_cl(db_cl)
  { }

protected:
  virtual void change_env(THD *thd) const
  {
    thd->variables.collation_database= m_db_cl;

    Default_object_creation_ctx::change_env(thd);
  }

protected:
  /**
    db_cl stores the value of the database collation. Both character set
    and collation attributes are used.

    Database collation is included into the context because it defines the
    default collation for stored-program variables.
  */
  CHARSET_INFO *m_db_cl;
};

/*************************************************************************/

113 114 115 116 117 118 119
class sp_name : public Sql_alloc
{
public:

  LEX_STRING m_db;
  LEX_STRING m_name;
  LEX_STRING m_qname;
120
  bool       m_explicit_name;                   /**< Prepend the db name? */
121

122 123
  sp_name(LEX_STRING db, LEX_STRING name, bool use_explicit_name)
    : m_db(db), m_name(name), m_explicit_name(use_explicit_name)
124
  {
Konstantin Osipov's avatar
Konstantin Osipov committed
125 126
    m_qname.str= 0;
    m_qname.length= 0;
127 128
  }

Konstantin Osipov's avatar
Konstantin Osipov committed
129 130
  /** Create temporary sp_name object from MDL key. */
  sp_name(const MDL_key *key, char *qname_buff);
131 132 133 134 135 136 137 138

  // Init. the qualified name from the db and name.
  void init_qname(THD *thd);	// thd for memroot allocation

  ~sp_name()
  {}
};

139

140
bool
141
check_routine_name(LEX_STRING *ident);
142

unknown's avatar
unknown committed
143
class sp_head :private Query_arena
144
{
unknown's avatar
unknown committed
145
  sp_head(const sp_head &);	/**< Prevent use of these */
146 147
  void operator=(sp_head &);

148
  MEM_ROOT main_mem_root;
149
public:
unknown's avatar
unknown committed
150
  /** Possible values of m_flags */
151
  enum {
152 153 154
    HAS_RETURN= 1,              // For FUNCTIONs only: is set if has RETURN
    MULTI_RESULTS= 8,           // Is set if a procedure with SELECT(s)
    CONTAINS_DYNAMIC_SQL= 16,   // Is set if a procedure with PREPARE/EXECUTE
155
    IS_INVOKED= 32,             // Is set if this sp_head is being used
156 157
    HAS_SET_AUTOCOMMIT_STMT= 64,// Is set if a procedure with 'set autocommit'
    /* Is set if a procedure with COMMIT (implicit or explicit) | ROLLBACK */
unknown's avatar
unknown committed
158
    HAS_COMMIT_OR_ROLLBACK= 128,
159
    LOG_SLOW_STATEMENTS= 256,   // Used by events
unknown's avatar
unknown committed
160
    LOG_GENERAL_LOG= 512,        // Used by events
161 162
    HAS_SQLCOM_RESET= 1024,
    HAS_SQLCOM_FLUSH= 2048
163
  };
164

165
  stored_procedure_type m_type;
166
  uint m_flags;                 // Boolean attributes of a stored routine
167

unknown's avatar
unknown committed
168
  Create_field m_return_field_def; /**< This is used for FUNCTIONs only. */
169

unknown's avatar
unknown committed
170
  const char *m_tmp_query;	///< Temporary pointer to sub query string
171
  st_sp_chistics *m_chistics;
172
  ulonglong m_sql_mode;		///< For SHOW CREATE and execution
unknown's avatar
unknown committed
173
  LEX_STRING m_qname;		///< db.name
174
  bool m_explicit_name;         ///< Prepend the db name? */
175
  LEX_STRING m_db;
176 177 178
  LEX_STRING m_name;
  LEX_STRING m_params;
  LEX_STRING m_body;
unknown's avatar
unknown committed
179
  LEX_STRING m_body_utf8;
180
  LEX_STRING m_defstr;
181 182
  LEX_STRING m_definer_user;
  LEX_STRING m_definer_host;
unknown's avatar
unknown committed
183

Konstantin Osipov's avatar
Konstantin Osipov committed
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
  /**
    Is this routine being executed?
  */
  bool is_invoked() const { return m_flags & IS_INVOKED; }

  /**
    Get the value of the SP cache version, as remembered
    when the routine was inserted into the cache.
  */
  ulong sp_cache_version() const { return m_sp_cache_version; }

  /** Set the value of the SP cache version.  */
  void set_sp_cache_version(ulong version_arg)
  {
    m_sp_cache_version= version_arg;
  }
unknown's avatar
unknown committed
200
private:
Konstantin Osipov's avatar
Konstantin Osipov committed
201 202 203 204 205 206 207 208 209 210 211
  /**
    Version of the stored routine cache at the moment when the
    routine was added to it. Is used only for functions and
    procedures, not used for triggers or events.  When sp_head is
    created, its version is 0. When it's added to the cache, the
    version is assigned the global value 'Cversion'.
    If later on Cversion is incremented, we know that the routine
    is obsolete and should not be used --
    sp_cache_flush_obsolete() will purge it.
  */
  ulong m_sp_cache_version;
unknown's avatar
unknown committed
212
  Stored_program_creation_ctx *m_creation_ctx;
213 214 215 216 217
  /**
    Boolean combination of (1<<flag), where flag is a member of
    LEX::enum_binlog_stmt_unsafe.
  */
  uint32 unsafe_flags;
unknown's avatar
unknown committed
218 219 220 221 222 223 224 225 226 227 228 229

public:
  inline Stored_program_creation_ctx *get_creation_ctx()
  {
    return m_creation_ctx;
  }

  inline void set_creation_ctx(Stored_program_creation_ctx *creation_ctx)
  {
    m_creation_ctx= creation_ctx->clone(mem_root);
  }

230 231
  longlong m_created;
  longlong m_modified;
unknown's avatar
unknown committed
232
  /** Recursion level of the current SP instance. The levels are numbered from 0 */
233
  ulong m_recursion_level;
unknown's avatar
unknown committed
234
  /**
235 236 237 238 239 240
    A list of diferent recursion level instances for the same procedure.
    For every recursion level we have a sp_head instance. This instances
    connected in the list. The list ordered by increasing recursion level
    (m_recursion_level).
  */
  sp_head *m_next_cached_sp;
unknown's avatar
unknown committed
241
  /**
242 243 244
    Pointer to the first element of the above list
  */
  sp_head *m_first_instance;
unknown's avatar
unknown committed
245
  /**
246 247 248 249 250 251 252
    Pointer to the first free (non-INVOKED) routine in the list of
    cached instances for this SP. This pointer is set only for the first
    SP in the list of instences (see above m_first_cached_sp pointer).
    The pointer equal to 0 if we have no free instances.
    For non-first instance value of this pointer meanless (point to itself);
  */
  sp_head *m_first_free_instance;
unknown's avatar
unknown committed
253
  /**
254 255 256 257
    Pointer to the last element in the list of instances of the SP.
    For non-first instance value of this pointer meanless (point to itself);
  */
  sp_head *m_last_cached_sp;
unknown's avatar
unknown committed
258
  /**
259 260 261 262 263
    Set containing names of stored routines used by this routine.
    Note that unlike elements of similar set for statement elements of this
    set are not linked in one list. Because of this we are able save memory
    by using for this set same objects that are used in 'sroutines' sets
    for statements of which this stored routine consists.
264
  */
265
  HASH m_sroutines;
266
  // Pointers set during parsing
267 268
  const char *m_param_begin;
  const char *m_param_end;
269 270

private:
271
  const char *m_body_begin;
272

273
public:
274 275 276 277 278
  /*
    Security context for stored routine which should be run under
    definer privileges.
  */
  Security_context m_security_ctx;
279

280 281 282 283 284 285 286 287 288
  /**
    List of all items (Item_trigger_field objects) representing fields in
    old/new version of row in trigger. We use this list for checking whenever
    all such fields are valid at trigger creation time and for binding these
    fields to TABLE object at table open (although for latter pointer to table
    being opened is probably enough).
  */
  SQL_I_List<Item_trigger_field> m_trg_table_fields;

289
  static void *
290
  operator new(size_t size) throw ();
291

292
  static void
293
  operator delete(void *ptr, size_t size) throw ();
294

295 296
  sp_head();

unknown's avatar
unknown committed
297
  /// Initialize after we have reset mem_root
298
  void
299 300
  init(LEX *lex);

unknown's avatar
unknown committed
301
  /** Copy sp name from parser. */
302 303 304
  void
  init_sp_name(THD *thd, sp_name *spname);

unknown's avatar
unknown committed
305
  /** Set the body-definition start position. */
306
  void
unknown's avatar
unknown committed
307 308 309 310 311
  set_body_start(THD *thd, const char *begin_ptr);

  /** Set the statement-definition (body-definition) end position. */
  void
  set_stmt_end(THD *thd);
unknown's avatar
unknown committed
312

313 314
  virtual ~sp_head();

315
  bool
316 317 318 319
  execute_trigger(THD *thd,
                  const LEX_STRING *db_name,
                  const LEX_STRING *table_name,
                  GRANT_INFO *grant_info);
320

321 322
  bool
  execute_function(THD *thd, Item **args, uint argcount, Field *return_fld);
323

324
  bool
325
  execute_procedure(THD *thd, List<Item> *args);
326

unknown's avatar
unknown committed
327 328
  bool
  show_create_routine(THD *thd, int type);
unknown's avatar
unknown committed
329

330
  int
331
  add_instr(sp_instr *instr);
332 333 334 335 336 337 338

  inline uint
  instructions()
  {
    return m_instr.elements;
  }

339 340 341 342 343
  inline sp_instr *
  last_instruction()
  {
    sp_instr *i;

344
    get_dynamic(&m_instr, (uchar*)&i, m_instr.elements-1);
345 346 347
    return i;
  }

unknown's avatar
unknown committed
348 349 350 351 352
  /*
    Resets lex in 'thd' and keeps a copy of the old one.

    @todo Conflicting comment in sp_head.cc
  */
353
  bool
354 355
  reset_lex(THD *thd);

unknown's avatar
unknown committed
356 357 358 359 360 361
  /**
    Restores lex in 'thd' from our copy, but keeps some status from the
    one in 'thd', like ptr, tables, fields, etc.

    @todo Conflicting comment in sp_head.cc
  */
362
  bool
363 364
  restore_lex(THD *thd);

unknown's avatar
unknown committed
365
  /// Put the instruction on the backpatch list, associated with the label.
366
  int
367
  push_backpatch(sp_instr *, sp_label *);
368

unknown's avatar
unknown committed
369 370
  /// Update all instruction with this label in the backpatch list to
  /// the current position.
371
  void
372
  backpatch(sp_label *);
373

unknown's avatar
unknown committed
374
  /// Start a new cont. backpatch level. If 'i' is NULL, the level is just incr.
375
  int
376
  new_cont_backpatch(sp_instr_opt_meta *i);
377

unknown's avatar
unknown committed
378
  /// Add an instruction to the current level
379
  int
380
  add_cont_backpatch(sp_instr_opt_meta *i);
381

unknown's avatar
unknown committed
382
  /// Backpatch (and pop) the current level to the current position.
383 384 385
  void
  do_cont_backpatch();

386 387 388
  char *name(uint *lenp = 0) const
  {
    if (lenp)
389
      *lenp= (uint) m_name.length;
390
    return m_name.str;
391 392
  }

393 394
  char *create_string(THD *thd, ulong *lenp);

395 396 397 398 399
  Field *create_result_field(uint field_max_length, const char *field_name,
                             TABLE *table);

  bool fill_field_definition(THD *thd, LEX *lex,
                             enum enum_field_types field_type,
unknown's avatar
unknown committed
400
                             Create_field *field_def);
401

402
  void set_info(longlong created, longlong modified,
403
		st_sp_chistics *chistics, ulonglong sql_mode);
404

unknown's avatar
unknown committed
405
  void set_definer(const char *definer, uint definerlen);
406
  void set_definer(const LEX_STRING *user_name, const LEX_STRING *host_name);
407

408 409 410
  void reset_thd_mem_root(THD *thd);

  void restore_thd_mem_root(THD *thd);
411

412 413 414
  /**
    Optimize the code.
  */
415
  void optimize();
416 417 418 419 420 421 422 423 424

  /**
    Helper used during flow analysis during code optimization.
    See the implementation of <code>opt_mark()</code>.
    @param ip the instruction to add to the leads list
    @param leads the list of remaining paths to explore in the graph that
    represents the code, during flow analysis.
  */
  void add_mark_lead(uint ip, List<sp_instr> *leads);
425

unknown's avatar
unknown committed
426
  void recursion_level_error(THD *thd);
427

428 429 430 431 432 433
  inline sp_instr *
  get_instr(uint i)
  {
    sp_instr *ip;

    if (i < m_instr.elements)
434
      get_dynamic(&m_instr, (uchar*)&ip, i);
435 436 437 438
    else
      ip= NULL;
    return ip;
  }
unknown's avatar
unknown committed
439

440 441
  /* Add tables used by routine to the table list. */
  bool add_used_tables_to_table_list(THD *thd,
442 443
                                     TABLE_LIST ***query_tables_last_ptr,
                                     TABLE_LIST *belong_to_view);
444

unknown's avatar
unknown committed
445
  /**
446 447 448 449 450 451 452 453 454 455
    Check if this stored routine contains statements disallowed
    in a stored function or trigger, and set an appropriate error message
    if this is the case.
  */
  bool is_not_allowed_in_function(const char *where)
  {
    if (m_flags & CONTAINS_DYNAMIC_SQL)
      my_error(ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0), "Dynamic SQL");
    else if (m_flags & MULTI_RESULTS)
      my_error(ER_SP_NO_RETSET, MYF(0), where);
456 457
    else if (m_flags & HAS_SET_AUTOCOMMIT_STMT)
      my_error(ER_SP_CANT_SET_AUTOCOMMIT, MYF(0));
458
    else if (m_flags & HAS_COMMIT_OR_ROLLBACK)
459
      my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0));
460 461 462 463 464
    else if (m_flags & HAS_SQLCOM_RESET)
      my_error(ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0), "RESET");
    else if (m_flags & HAS_SQLCOM_FLUSH)
      my_error(ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0), "FLUSH");

465
    return test(m_flags &
466 467
		(CONTAINS_DYNAMIC_SQL|MULTI_RESULTS|HAS_SET_AUTOCOMMIT_STMT|
                 HAS_COMMIT_OR_ROLLBACK|HAS_SQLCOM_RESET|HAS_SQLCOM_FLUSH));
468
  }
unknown's avatar
unknown committed
469 470 471 472 473

#ifndef DBUG_OFF
  int show_routine_code(THD *thd);
#endif

unknown's avatar
unknown committed
474 475
  /*
    This method is intended for attributes of a routine which need
Konstantin Osipov's avatar
Konstantin Osipov committed
476 477
    to propagate upwards to the Query_tables_list of the caller (when
    a property of a sp_head needs to "taint" the calling statement).
unknown's avatar
unknown committed
478
  */
Konstantin Osipov's avatar
Konstantin Osipov committed
479
  void propagate_attributes(Query_tables_list *prelocking_ctx)
unknown's avatar
unknown committed
480
  {
481
    DBUG_ENTER("sp_head::propagate_attributes");
unknown's avatar
unknown committed
482 483 484 485 486 487
    /*
      If this routine needs row-based binary logging, the entire top statement
      too (we cannot switch from statement-based to row-based only for this
      routine, as in statement-based the top-statement may be binlogged and
      the substatements not).
    */
488
    DBUG_PRINT("info", ("lex->get_stmt_unsafe_flags(): 0x%x",
489
                        prelocking_ctx->get_stmt_unsafe_flags()));
490 491
    DBUG_PRINT("info", ("sp_head(0x%p=%s)->unsafe_flags: 0x%x",
                        this, name(), unsafe_flags));
492
    prelocking_ctx->set_stmt_unsafe_flags(unsafe_flags);
493
    DBUG_VOID_RETURN;
unknown's avatar
unknown committed
494 495
  }

Sergey Glukhov's avatar
Sergey Glukhov committed
496
  sp_pcontext *get_parse_context() { return m_pcont; }
unknown's avatar
unknown committed
497

498 499
private:

unknown's avatar
unknown committed
500 501
  MEM_ROOT *m_thd_root;		///< Temp. store for thd's mem_root
  THD *m_thd;			///< Set if we have reset mem_root
502

unknown's avatar
unknown committed
503 504 505
  sp_pcontext *m_pcont;		///< Parse context
  List<LEX> m_lex;		///< Temp. store for the other lex
  DYNAMIC_ARRAY m_instr;	///< The "instructions"
506 507
  typedef struct
  {
508
    sp_label *lab;
509 510
    sp_instr *instr;
  } bp_t;
unknown's avatar
unknown committed
511 512
  List<bp_t> m_backpatch;	///< Instructions needing backpatching
  /**
513
    We need a special list for backpatching of instructions with a continue
514 515
    destination (in the case of a continue handler catching an error in
    the test), since it would otherwise interfere with the normal backpatch
516
    mechanism - e.g. jump_if_not instructions have two different destinations
517 518 519
    which are to be patched differently.
    Since these occur in a more restricted way (always the same "level" in
    the code), we don't need the label.
unknown's avatar
unknown committed
520
  */
521
  List<sp_instr_opt_meta> m_cont_backpatch;
522 523
  uint m_cont_level;            // The current cont. backpatch level

unknown's avatar
unknown committed
524
  /**
525 526
    Multi-set representing optimized list of tables to be locked by this
    routine. Does not include tables which are used by invoked routines.
527

unknown's avatar
unknown committed
528 529
    @note
    For prelocking-free SPs this multiset is constructed too.
530 531
    We do so because the same instance of sp_head may be called both
    in prelocked mode and in non-prelocked mode.
532 533
  */
  HASH m_sptabs;
534

535
  bool
536
  execute(THD *thd, bool merge_da_on_success);
537

538 539 540 541 542 543
  /**
    Perform a forward flow analysis in the generated code.
    Mark reachable instructions, for the optimizer.
  */
  void opt_mark();

unknown's avatar
unknown committed
544
  /**
545 546 547 548
    Merge the list of tables used by query into the multi-set of tables used
    by routine.
  */
  bool merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check);
549 550 551
}; // class sp_head : public Sql_alloc


552 553 554 555
//
// "Instructions"...
//

556
class sp_instr :public Query_arena, public Sql_alloc
557
{
unknown's avatar
unknown committed
558
  sp_instr(const sp_instr &);	/**< Prevent use of these */
559 560 561 562
  void operator=(sp_instr &);

public:

563
  uint marked;
unknown's avatar
unknown committed
564 565
  uint m_ip;			///< My index
  sp_pcontext *m_ctx;		///< My parse context
566

unknown's avatar
unknown committed
567
  /// Should give each a name or type code for debugging purposes?
568
  sp_instr(uint ip, sp_pcontext *ctx)
569
    :Query_arena(0, STMT_INITIALIZED_FOR_SP), marked(0), m_ip(ip), m_ctx(ctx)
570 571 572
  {}

  virtual ~sp_instr()
573
  { free_items(); }
574

575

unknown's avatar
unknown committed
576
  /**
577 578
    Execute this instruction

unknown's avatar
unknown committed
579 580 581 582 583 584 585 586 587 588
   
    @param thd         Thread handle
    @param[out] nextp  index of the next instruction to execute. (For most
                       instructions this will be the instruction following this
                       one). Note that this parameter is undefined in case of
                       errors, use get_cont_dest() to find the continuation
                       instruction for CONTINUE error handlers.
   
    @retval 0      on success, 
    @retval other  if some error occured
589
  */
590

591 592
  virtual int execute(THD *thd, uint *nextp) = 0;

593 594 595 596 597 598 599 600 601
  /**
    Execute <code>open_and_lock_tables()</code> for this statement.
    Open and lock the tables used by this statement, as a pre-requisite
    to execute the core logic of this instruction with
    <code>exec_core()</code>.
    @param thd the current thread
    @param tables the list of tables to open and lock
    @return zero on success, non zero on failure.
  */
602
  int exec_open_and_lock_tables(THD *thd, TABLE_LIST *tables);
603 604 605

  /**
    Get the continuation destination of this instruction.
606
    @return the continuation destination
607
  */
608
  virtual uint get_cont_dest() const;
609

610 611 612 613 614 615 616
  /*
    Execute core function of instruction after all preparations (e.g.
    setting of proper LEX, saving part of the thread context have been
    done).

    Should be implemented for instructions using expressions or whole
    statements (thus having to have own LEX). Used in concert with
617
    sp_lex_keeper class and its descendants (there are none currently).
618 619 620
  */
  virtual int exec_core(THD *thd, uint *nextp);

621
  virtual void print(String *str) = 0;
622

623
  virtual void backpatch(uint dest, sp_pcontext *dst_ctx)
624
  {}
625

unknown's avatar
unknown committed
626
  /**
627
    Mark this instruction as reachable during optimization and return the
628 629
    index to the next instruction. Jump instruction will add their
    destination to the leads list.
630
  */
631
  virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads)
632 633 634 635 636
  {
    marked= 1;
    return m_ip+1;
  }

unknown's avatar
unknown committed
637
  /**
638 639 640 641 642
    Short-cut jumps to jumps during optimization. This is used by the
    jump instructions' opt_mark() methods. 'start' is the starting point,
    used to prevent the mark sweep from looping for ever. Return the
    end destination.
  */
643
  virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start)
644 645 646 647
  {
    return m_ip;
  }

unknown's avatar
unknown committed
648
  /**
649 650 651 652 653
    Inform the instruction that it has been moved during optimization.
    Most instructions will simply update its index, but jump instructions
    must also take care of their destination pointers. Forward jumps get
    pushed to the backpatch list 'ibp'.
  */
654 655 656 657
  virtual void opt_move(uint dst, List<sp_instr> *ibp)
  {
    m_ip= dst;
  }
658

659 660 661
}; // class sp_instr : public Sql_alloc


unknown's avatar
unknown committed
662
/**
663 664 665 666 667 668 669
  Auxilary class to which instructions delegate responsibility
  for handling LEX and preparations before executing statement
  or calculating complex expression.

  Exist mainly to avoid having double hierarchy between instruction
  classes.

unknown's avatar
unknown committed
670 671 672
  @todo
    Add ability to not store LEX and do any preparations if
    expression used is simple.
673 674 675 676
*/

class sp_lex_keeper
{
unknown's avatar
unknown committed
677
  /** Prevent use of these */
678 679 680 681 682
  sp_lex_keeper(const sp_lex_keeper &);
  void operator=(sp_lex_keeper &);
public:

  sp_lex_keeper(LEX *lex, bool lex_resp)
683 684
    : m_lex(lex), m_lex_resp(lex_resp), 
      lex_query_tables_own_last(NULL)
685 686 687 688 689 690
  {
    lex->sp_lex_in_use= TRUE;
  }
  virtual ~sp_lex_keeper()
  {
    if (m_lex_resp)
691
    {
692 693
      /* Prevent endless recursion. */
      m_lex->sphead= NULL;
694
      lex_end(m_lex);
695
      delete m_lex;
696
    }
697 698
  }

unknown's avatar
unknown committed
699
  /**
700 701 702
    Prepare execution of instruction using LEX, if requested check whenever
    we have read access to tables used and open/lock them, call instruction's
    exec_core() method, perform cleanup afterwards.
unknown's avatar
unknown committed
703 704
   
    @todo Conflicting comment in sp_head.cc
705 706 707 708 709 710 711 712 713
  */
  int reset_lex_and_exec_core(THD *thd, uint *nextp, bool open_tables,
                              sp_instr* instr);

  inline uint sql_command() const
  {
    return (uint)m_lex->sql_command;
  }

714 715 716 717
  void disable_query_cache()
  {
    m_lex->safe_to_cache_query= 0;
  }
718 719 720
private:

  LEX *m_lex;
unknown's avatar
unknown committed
721
  /**
722 723 724 725
    Indicates whenever this sp_lex_keeper instance responsible
    for LEX deletion.
  */
  bool m_lex_resp;
726 727 728 729 730 731 732 733

  /*
    Support for being able to execute this statement in two modes:
    a) inside prelocked mode set by the calling procedure or its ancestor.
    b) outside of prelocked mode, when this statement enters/leaves
       prelocked mode itself.
  */
  
unknown's avatar
unknown committed
734
  /**
735 736 737 738 739
    List of additional tables this statement needs to lock when it
    enters/leaves prelocked mode on its own.
  */
  TABLE_LIST *prelocking_tables;

unknown's avatar
unknown committed
740
  /**
741 742 743 744
    The value m_lex->query_tables_own_last should be set to this when the
    statement enters/leaves prelocked mode on its own.
  */
  TABLE_LIST **lex_query_tables_own_last;
745 746 747
};


unknown's avatar
unknown committed
748 749 750
/**
  Call out to some prepared SQL statement.
*/
751 752
class sp_instr_stmt : public sp_instr
{
unknown's avatar
unknown committed
753
  sp_instr_stmt(const sp_instr_stmt &);	/**< Prevent use of these */
754 755 756 757
  void operator=(sp_instr_stmt &);

public:

unknown's avatar
unknown committed
758
  LEX_STRING m_query;		///< For thd->query
759

760 761
  sp_instr_stmt(uint ip, sp_pcontext *ctx, LEX *lex)
    : sp_instr(ip, ctx), m_lex_keeper(lex, TRUE)
762 763 764 765
  {
    m_query.str= 0;
    m_query.length= 0;
  }
766

767 768
  virtual ~sp_instr_stmt()
  {};
769

770
  virtual int execute(THD *thd, uint *nextp);
771

772
  virtual int exec_core(THD *thd, uint *nextp);
773

774
  virtual void print(String *str);
775

776 777
private:

778
  sp_lex_keeper m_lex_keeper;
779 780 781 782 783 784

}; // class sp_instr_stmt : public sp_instr


class sp_instr_set : public sp_instr
{
unknown's avatar
unknown committed
785
  sp_instr_set(const sp_instr_set &);	/**< Prevent use of these */
786 787 788 789
  void operator=(sp_instr_set &);

public:

790
  sp_instr_set(uint ip, sp_pcontext *ctx,
791
	       uint offset, Item *val, enum enum_field_types type_arg,
792
               LEX *lex, bool lex_resp)
793
    : sp_instr(ip, ctx), m_offset(offset), m_value(val), m_type(type_arg),
794
      m_lex_keeper(lex, lex_resp)
795 796 797 798 799
  {}

  virtual ~sp_instr_set()
  {}

800
  virtual int execute(THD *thd, uint *nextp);
801

802 803
  virtual int exec_core(THD *thd, uint *nextp);

804 805
  virtual void print(String *str);

806 807
private:

unknown's avatar
unknown committed
808
  uint m_offset;		///< Frame offset
809
  Item *m_value;
unknown's avatar
unknown committed
810
  enum enum_field_types m_type;	///< The declared type
811
  sp_lex_keeper m_lex_keeper;
812 813 814

}; // class sp_instr_set : public sp_instr

815

unknown's avatar
unknown committed
816
/**
817 818 819 820 821 822 823 824 825
  Set NEW/OLD row field value instruction. Used in triggers.
*/
class sp_instr_set_trigger_field : public sp_instr
{
  sp_instr_set_trigger_field(const sp_instr_set_trigger_field &);
  void operator=(sp_instr_set_trigger_field &);

public:

unknown's avatar
unknown committed
826
  sp_instr_set_trigger_field(uint ip, sp_pcontext *ctx,
827 828
                             Item_trigger_field *trg_fld,
                             Item *val, LEX *lex)
unknown's avatar
unknown committed
829
    : sp_instr(ip, ctx),
830
      trigger_field(trg_fld),
831
      value(val), m_lex_keeper(lex, TRUE)
832 833 834 835 836 837 838
  {}

  virtual ~sp_instr_set_trigger_field()
  {}

  virtual int execute(THD *thd, uint *nextp);

839 840
  virtual int exec_core(THD *thd, uint *nextp);

841 842
  virtual void print(String *str);

843
private:
844
  Item_trigger_field *trigger_field;
845
  Item *value;
846
  sp_lex_keeper m_lex_keeper;
847 848 849
}; // class sp_instr_trigger_field : public sp_instr


unknown's avatar
unknown committed
850
/**
851 852
  An abstract class for all instructions with destinations that
  needs to be updated by the optimizer.
unknown's avatar
unknown committed
853

854 855
  Even if not all subclasses will use both the normal destination and
  the continuation destination, we put them both here for simplicity.
unknown's avatar
unknown committed
856
*/
857 858 859 860
class sp_instr_opt_meta : public sp_instr
{
public:

unknown's avatar
unknown committed
861 862
  uint m_dest;			///< Where we will go
  uint m_cont_dest;             ///< Where continue handlers will go
863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879

  sp_instr_opt_meta(uint ip, sp_pcontext *ctx)
    : sp_instr(ip, ctx),
      m_dest(0), m_cont_dest(0), m_optdest(0), m_cont_optdest(0)
  {}

  sp_instr_opt_meta(uint ip, sp_pcontext *ctx, uint dest)
    : sp_instr(ip, ctx),
      m_dest(dest), m_cont_dest(0), m_optdest(0), m_cont_optdest(0)
  {}

  virtual ~sp_instr_opt_meta()
  {}

  virtual void set_destination(uint old_dest, uint new_dest)
    = 0;

880
  virtual uint get_cont_dest() const;
881

882 883
protected:

unknown's avatar
unknown committed
884 885
  sp_instr *m_optdest;		///< Used during optimization
  sp_instr *m_cont_optdest;     ///< Used during optimization
886 887 888 889

}; // class sp_instr_opt_meta : public sp_instr

class sp_instr_jump : public sp_instr_opt_meta
890
{
unknown's avatar
unknown committed
891
  sp_instr_jump(const sp_instr_jump &);	/**< Prevent use of these */
892 893 894 895
  void operator=(sp_instr_jump &);

public:

896
  sp_instr_jump(uint ip, sp_pcontext *ctx)
897
    : sp_instr_opt_meta(ip, ctx)
898 899
  {}

900
  sp_instr_jump(uint ip, sp_pcontext *ctx, uint dest)
901
    : sp_instr_opt_meta(ip, ctx, dest)
902 903 904 905 906
  {}

  virtual ~sp_instr_jump()
  {}

907
  virtual int execute(THD *thd, uint *nextp);
908

909 910
  virtual void print(String *str);

911
  virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads);
912

913
  virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start);
914 915 916

  virtual void opt_move(uint dst, List<sp_instr> *ibp);

917
  virtual void backpatch(uint dest, sp_pcontext *dst_ctx)
918
  {
unknown's avatar
unknown committed
919 920 921
    /* Calling backpatch twice is a logic flaw in jump resolution. */
    DBUG_ASSERT(m_dest == 0);
    m_dest= dest;
922 923
  }

unknown's avatar
unknown committed
924
  /**
925 926
    Update the destination; used by the optimizer.
  */
927
  virtual void set_destination(uint old_dest, uint new_dest)
928
  {
929 930
    if (m_dest == old_dest)
      m_dest= new_dest;
931 932
  }

933
}; // class sp_instr_jump : public sp_instr_opt_meta
934 935 936 937


class sp_instr_jump_if_not : public sp_instr_jump
{
unknown's avatar
unknown committed
938
  sp_instr_jump_if_not(const sp_instr_jump_if_not &); /**< Prevent use of these */
939 940 941 942
  void operator=(sp_instr_jump_if_not &);

public:

943
  sp_instr_jump_if_not(uint ip, sp_pcontext *ctx, Item *i, LEX *lex)
944 945
    : sp_instr_jump(ip, ctx), m_expr(i),
      m_lex_keeper(lex, TRUE)
946 947
  {}

948
  sp_instr_jump_if_not(uint ip, sp_pcontext *ctx, Item *i, uint dest, LEX *lex)
949 950
    : sp_instr_jump(ip, ctx, dest), m_expr(i),
      m_lex_keeper(lex, TRUE)
951 952 953 954 955 956 957
  {}

  virtual ~sp_instr_jump_if_not()
  {}

  virtual int execute(THD *thd, uint *nextp);

958 959
  virtual int exec_core(THD *thd, uint *nextp);

960 961
  virtual void print(String *str);

962
  virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads);
963

unknown's avatar
unknown committed
964
  /** Override sp_instr_jump's shortcut; we stop here */
965
  virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start)
966 967 968 969
  {
    return m_ip;
  }

970 971 972 973 974 975 976 977 978
  virtual void opt_move(uint dst, List<sp_instr> *ibp);

  virtual void set_destination(uint old_dest, uint new_dest)
  {
    sp_instr_jump::set_destination(old_dest, new_dest);
    if (m_cont_dest == old_dest)
      m_cont_dest= new_dest;
  }

979 980
private:

unknown's avatar
unknown committed
981
  Item *m_expr;			///< The condition
982
  sp_lex_keeper m_lex_keeper;
983 984 985

}; // class sp_instr_jump_if_not : public sp_instr_jump

986

987
class sp_instr_freturn : public sp_instr
988
{
unknown's avatar
unknown committed
989
  sp_instr_freturn(const sp_instr_freturn &);	/**< Prevent use of these */
990
  void operator=(sp_instr_freturn &);
991 992 993

public:

994
  sp_instr_freturn(uint ip, sp_pcontext *ctx,
995 996 997
		   Item *val, enum enum_field_types type_arg, LEX *lex)
    : sp_instr(ip, ctx), m_value(val), m_type(type_arg),
      m_lex_keeper(lex, TRUE)
998 999
  {}

1000
  virtual ~sp_instr_freturn()
1001 1002 1003 1004
  {}

  virtual int execute(THD *thd, uint *nextp);

1005 1006
  virtual int exec_core(THD *thd, uint *nextp);

1007 1008
  virtual void print(String *str);

1009
  virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads)
1010 1011 1012 1013 1014
  {
    marked= 1;
    return UINT_MAX;
  }

1015 1016 1017 1018
protected:

  Item *m_value;
  enum enum_field_types m_type;
1019
  sp_lex_keeper m_lex_keeper;
1020

1021 1022 1023 1024 1025
}; // class sp_instr_freturn : public sp_instr


class sp_instr_hpush_jump : public sp_instr_jump
{
unknown's avatar
unknown committed
1026
  sp_instr_hpush_jump(const sp_instr_hpush_jump &); /**< Prevent use of these */
1027 1028 1029 1030
  void operator=(sp_instr_hpush_jump &);

public:

1031 1032 1033 1034 1035 1036 1037
  sp_instr_hpush_jump(uint ip,
                      sp_pcontext *ctx,
                      sp_handler *handler)
   :sp_instr_jump(ip, ctx),
    m_handler(handler),
    m_opt_hpop(0),
    m_frame(ctx->current_var_count())
1038
  {
1039
    DBUG_ASSERT(m_handler->condition_values.elements == 0);
1040 1041 1042 1043
  }

  virtual ~sp_instr_hpush_jump()
  {
1044 1045
    m_handler->condition_values.empty();
    m_handler= NULL;
1046 1047 1048 1049
  }

  virtual int execute(THD *thd, uint *nextp);

1050 1051
  virtual void print(String *str);

1052
  virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads);
1053

unknown's avatar
unknown committed
1054
  /** Override sp_instr_jump's shortcut; we stop here. */
1055
  virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start)
1056 1057 1058 1059
  {
    return m_ip;
  }

1060 1061 1062 1063 1064 1065 1066 1067 1068
  virtual void backpatch(uint dest, sp_pcontext *dst_ctx)
  {
    DBUG_ASSERT(!m_dest || !m_opt_hpop);
    if (!m_dest)
      m_dest= dest;
    else
      m_opt_hpop= dest;
  }

1069 1070 1071 1072 1073 1074 1075
  void add_condition(sp_condition_value *condition_value)
  { m_handler->condition_values.push_back(condition_value); }

  sp_handler *get_handler()
  { return m_handler; }

private:
1076 1077

private:
1078 1079 1080 1081 1082
  /// Handler.
  sp_handler *m_handler;

  /// hpop marking end of handler scope.
  uint m_opt_hpop;
1083

1084 1085
  // This attribute is needed for SHOW PROCEDURE CODE only (i.e. it's needed in
  // debug version only). It's used in print().
1086 1087 1088 1089 1090 1091 1092
  uint m_frame;

}; // class sp_instr_hpush_jump : public sp_instr_jump


class sp_instr_hpop : public sp_instr
{
unknown's avatar
unknown committed
1093
  sp_instr_hpop(const sp_instr_hpop &);	/**< Prevent use of these */
1094 1095 1096 1097
  void operator=(sp_instr_hpop &);

public:

1098 1099
  sp_instr_hpop(uint ip, sp_pcontext *ctx, uint count)
    : sp_instr(ip, ctx), m_count(count)
1100 1101 1102 1103 1104 1105 1106
  {}

  virtual ~sp_instr_hpop()
  {}

  virtual int execute(THD *thd, uint *nextp);

1107 1108
  virtual void print(String *str);

1109 1110 1111 1112 1113 1114 1115
private:

  uint m_count;

}; // class sp_instr_hpop : public sp_instr


1116
class sp_instr_hreturn : public sp_instr_jump
1117
{
unknown's avatar
unknown committed
1118
  sp_instr_hreturn(const sp_instr_hreturn &);	/**< Prevent use of these */
1119 1120 1121 1122
  void operator=(sp_instr_hreturn &);

public:

1123 1124 1125
  sp_instr_hreturn(uint ip, sp_pcontext *ctx)
   :sp_instr_jump(ip, ctx),
    m_frame(ctx->current_var_count())
1126 1127 1128 1129 1130 1131 1132
  {}

  virtual ~sp_instr_hreturn()
  {}

  virtual int execute(THD *thd, uint *nextp);

1133 1134
  virtual void print(String *str);

1135 1136 1137 1138 1139 1140
  /* This instruction will not be short cut optimized. */
  virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start)
  {
    return m_ip;
  }

1141
  virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads);
1142

1143 1144 1145 1146
private:

  uint m_frame;

1147
}; // class sp_instr_hreturn : public sp_instr_jump
1148

1149

unknown's avatar
unknown committed
1150
/** This is DECLARE CURSOR */
1151 1152
class sp_instr_cpush : public sp_instr
{
unknown's avatar
unknown committed
1153
  sp_instr_cpush(const sp_instr_cpush &); /**< Prevent use of these */
1154 1155 1156 1157
  void operator=(sp_instr_cpush &);

public:

unknown's avatar
unknown committed
1158 1159
  sp_instr_cpush(uint ip, sp_pcontext *ctx, LEX *lex, uint offset)
    : sp_instr(ip, ctx), m_lex_keeper(lex, TRUE), m_cursor(offset)
1160 1161
  {}

1162 1163
  virtual ~sp_instr_cpush()
  {}
1164 1165 1166

  virtual int execute(THD *thd, uint *nextp);

1167 1168
  virtual void print(String *str);

unknown's avatar
unknown committed
1169
  /**
1170 1171 1172 1173 1174
    This call is used to cleanup the instruction when a sensitive
    cursor is closed. For now stored procedures always use materialized
    cursors and the call is not used.
  */
  virtual void cleanup_stmt() { /* no op */ }
1175 1176
private:

1177
  sp_lex_keeper m_lex_keeper;
unknown's avatar
unknown committed
1178
  uint m_cursor;                /**< Frame offset (for debugging) */
1179 1180 1181 1182 1183 1184

}; // class sp_instr_cpush : public sp_instr


class sp_instr_cpop : public sp_instr
{
unknown's avatar
unknown committed
1185
  sp_instr_cpop(const sp_instr_cpop &); /**< Prevent use of these */
1186 1187 1188 1189
  void operator=(sp_instr_cpop &);

public:

1190 1191
  sp_instr_cpop(uint ip, sp_pcontext *ctx, uint count)
    : sp_instr(ip, ctx), m_count(count)
1192 1193 1194 1195 1196 1197 1198
  {}

  virtual ~sp_instr_cpop()
  {}

  virtual int execute(THD *thd, uint *nextp);

1199 1200
  virtual void print(String *str);

1201 1202 1203 1204 1205 1206 1207
private:

  uint m_count;

}; // class sp_instr_cpop : public sp_instr


1208
class sp_instr_copen : public sp_instr
1209
{
unknown's avatar
unknown committed
1210
  sp_instr_copen(const sp_instr_copen &); /**< Prevent use of these */
1211 1212 1213 1214
  void operator=(sp_instr_copen &);

public:

1215
  sp_instr_copen(uint ip, sp_pcontext *ctx, uint c)
1216
    : sp_instr(ip, ctx), m_cursor(c)
1217 1218 1219 1220 1221 1222 1223
  {}

  virtual ~sp_instr_copen()
  {}

  virtual int execute(THD *thd, uint *nextp);

1224 1225
  virtual int exec_core(THD *thd, uint *nextp);

1226 1227
  virtual void print(String *str);

1228 1229
private:

unknown's avatar
unknown committed
1230
  uint m_cursor;		///< Stack index
1231 1232 1233 1234 1235 1236

}; // class sp_instr_copen : public sp_instr_stmt


class sp_instr_cclose : public sp_instr
{
unknown's avatar
unknown committed
1237
  sp_instr_cclose(const sp_instr_cclose &); /**< Prevent use of these */
1238 1239 1240 1241
  void operator=(sp_instr_cclose &);

public:

1242 1243
  sp_instr_cclose(uint ip, sp_pcontext *ctx, uint c)
    : sp_instr(ip, ctx), m_cursor(c)
1244 1245 1246 1247 1248 1249 1250
  {}

  virtual ~sp_instr_cclose()
  {}

  virtual int execute(THD *thd, uint *nextp);

1251 1252
  virtual void print(String *str);

1253 1254 1255 1256 1257 1258 1259 1260 1261
private:

  uint m_cursor;

}; // class sp_instr_cclose : public sp_instr


class sp_instr_cfetch : public sp_instr
{
unknown's avatar
unknown committed
1262
  sp_instr_cfetch(const sp_instr_cfetch &); /**< Prevent use of these */
1263 1264 1265 1266
  void operator=(sp_instr_cfetch &);

public:

1267 1268
  sp_instr_cfetch(uint ip, sp_pcontext *ctx, uint c)
    : sp_instr(ip, ctx), m_cursor(c)
1269 1270 1271 1272 1273 1274 1275 1276 1277
  {
    m_varlist.empty();
  }

  virtual ~sp_instr_cfetch()
  {}

  virtual int execute(THD *thd, uint *nextp);

1278 1279
  virtual void print(String *str);

1280
  void add_to_varlist(sp_variable *var)
1281 1282 1283 1284 1285 1286 1287
  {
    m_varlist.push_back(var);
  }

private:

  uint m_cursor;
1288
  List<sp_variable> m_varlist;
1289 1290 1291 1292

}; // class sp_instr_cfetch : public sp_instr


1293 1294
class sp_instr_error : public sp_instr
{
unknown's avatar
unknown committed
1295
  sp_instr_error(const sp_instr_error &); /**< Prevent use of these */
1296 1297 1298 1299
  void operator=(sp_instr_error &);

public:

1300 1301
  sp_instr_error(uint ip, sp_pcontext *ctx, int errcode)
    : sp_instr(ip, ctx), m_errcode(errcode)
1302 1303 1304 1305 1306 1307 1308 1309 1310
  {}

  virtual ~sp_instr_error()
  {}

  virtual int execute(THD *thd, uint *nextp);

  virtual void print(String *str);

1311
  virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads)
1312 1313 1314 1315 1316
  {
    marked= 1;
    return UINT_MAX;
  }

1317 1318 1319 1320 1321 1322 1323
private:

  int m_errcode;

}; // class sp_instr_error : public sp_instr


1324
class sp_instr_set_case_expr : public sp_instr_opt_meta
1325 1326 1327 1328 1329
{
public:

  sp_instr_set_case_expr(uint ip, sp_pcontext *ctx, uint case_expr_id,
                         Item *case_expr, LEX *lex)
1330 1331 1332 1333 1334 1335
    : sp_instr_opt_meta(ip, ctx),
      m_case_expr_id(case_expr_id), m_case_expr(case_expr),
      m_lex_keeper(lex, TRUE)
  {}

  virtual ~sp_instr_set_case_expr()
1336 1337 1338 1339 1340 1341 1342 1343
  {}

  virtual int execute(THD *thd, uint *nextp);

  virtual int exec_core(THD *thd, uint *nextp);

  virtual void print(String *str);

1344
  virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads);
1345 1346 1347 1348 1349 1350 1351 1352 1353

  virtual void opt_move(uint dst, List<sp_instr> *ibp);

  virtual void set_destination(uint old_dest, uint new_dest)
  {
    if (m_cont_dest == old_dest)
      m_cont_dest= new_dest;
  }

1354 1355 1356 1357 1358 1359
private:

  uint m_case_expr_id;
  Item *m_case_expr;
  sp_lex_keeper m_lex_keeper;

1360
}; // class sp_instr_set_case_expr : public sp_instr_opt_meta
1361 1362


1363
#ifndef NO_EMBEDDED_ACCESS_CHECKS
1364 1365
bool
sp_change_security_context(THD *thd, sp_head *sp,
1366
                           Security_context **backup);
1367
void
1368
sp_restore_security_context(THD *thd, Security_context *backup);
1369 1370 1371 1372

bool
set_routine_security_ctx(THD *thd, sp_head *sp, bool is_proc,
                         Security_context **save_ctx);
1373
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
1374

1375 1376 1377
TABLE_LIST *
sp_add_to_query_tables(THD *thd, LEX *lex,
		       const char *db, const char *name,
1378 1379 1380
                       thr_lock_type locktype,
                       enum_mdl_type mdl_type);

1381 1382
Item *
sp_prepare_func_item(THD* thd, Item **it_addr);
1383

1384
bool
1385
sp_eval_expr(THD *thd, Field *result_field, Item **expr_item_ptr);
1386

1387 1388 1389 1390
/**
  @} (end of group Stored_Routines)
*/

1391
#endif /* _SP_HEAD_H_ */