1 /* Copyright (c) 2012, 2021, Oracle and/or its affiliates.
2 
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License, version 2.0,
5    as published by the Free Software Foundation.
6 
7    This program is also distributed with certain software (including
8    but not limited to OpenSSL) that is licensed under separate terms,
9    as designated in a particular file or component or in included license
10    documentation.  The authors of MySQL hereby grant you an additional
11    permission to link the program and your derivative works with the
12    separately licensed software that they have included with MySQL.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License, version 2.0, for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
22 
23 #ifndef _SP_INSTR_H_
24 #define _SP_INSTR_H_
25 
26 #include "my_global.h"    // NO_EMBEDDED_ACCESS_CHECKS
27 #include "sp_pcontext.h"  // sp_pcontext
28 #include "sql_class.h"    // THD
29 #include "sp_head.h"      // sp_printable
30 
31 ///////////////////////////////////////////////////////////////////////////
32 // This file contains SP-instruction classes.
33 ///////////////////////////////////////////////////////////////////////////
34 
35 /**
36   An interface for all SP-instructions with destinations that
37   need to be updated by the SP-optimizer.
38 */
39 class sp_branch_instr
40 {
41 public:
42   /**
43     Update the destination; used by the SP-instruction-optimizer.
44 
45     @param old_dest current (old) destination (instruction pointer).
46     @param new_dest new destination (instruction pointer).
47   */
48   virtual void set_destination(uint old_dest, uint new_dest) = 0;
49 
50   /**
51     Update all instruction with the given label in the backpatch list to
52     the specified instruction pointer.
53 
54     @param dest     destination instruction pointer.
55   */
56   virtual void backpatch(uint dest) = 0;
57 
~sp_branch_instr()58   virtual ~sp_branch_instr()
59   { }
60 };
61 
62 ///////////////////////////////////////////////////////////////////////////
63 
64 /**
65   Base class for every SP-instruction. sp_instr defines interface and provides
66   base implementation.
67 */
68 class sp_instr : public Query_arena,
69                  public Sql_alloc,
70                  public sp_printable
71 {
72 public:
sp_instr(uint ip,sp_pcontext * ctx)73   sp_instr(uint ip, sp_pcontext *ctx)
74    :Query_arena(0, STMT_INITIALIZED_FOR_SP),
75     m_marked(false),
76     m_ip(ip),
77     m_parsing_ctx(ctx)
78   { }
79 
~sp_instr()80   virtual ~sp_instr()
81   { free_items(); }
82 
83   /**
84     Execute this instruction
85 
86     @param thd         Thread context
87     @param[out] nextp  index of the next instruction to execute. (For most
88                        instructions this will be the instruction following this
89                        one). Note that this parameter is undefined in case of
90                        errors, use get_cont_dest() to find the continuation
91                        instruction for CONTINUE error handlers.
92 
93     @return Error status.
94   */
95   virtual bool execute(THD *thd, uint *nextp) = 0;
96 #ifdef HAVE_PSI_INTERFACE
97   virtual PSI_statement_info* get_psi_info() = 0;
98 #endif
99 
get_ip()100   uint get_ip() const
101   { return m_ip; }
102 
103   /**
104     Get the continuation destination (instruction pointer for the CONTINUE
105     HANDLER) of this instruction.
106     @return the continuation destination
107   */
get_cont_dest()108   virtual uint get_cont_dest() const
109   { return get_ip() + 1; }
110 
get_parsing_ctx()111   sp_pcontext *get_parsing_ctx() const
112   { return m_parsing_ctx; }
113 
114 protected:
115   /**
116     Clear diagnostics area.
117     @param thd         Thread context
118   */
clear_da(THD * thd)119   void clear_da(THD *thd) const
120   {
121     thd->get_stmt_da()->reset_diagnostics_area();
122     thd->get_stmt_da()->reset_condition_info(thd);
123   }
124 
125   ///////////////////////////////////////////////////////////////////////////
126   // The following operations are used solely for SP-code-optimizer.
127   ///////////////////////////////////////////////////////////////////////////
128 
129 public:
130   /**
131     Mark this instruction as reachable during optimization and return the
132     index to the next instruction. Jump instruction will add their
133     destination to the leads list.
134   */
opt_mark(sp_head * sp,List<sp_instr> * leads)135   virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads)
136   {
137     m_marked= true;
138     return get_ip() + 1;
139   }
140 
141   /**
142     Short-cut jumps to jumps during optimization. This is used by the
143     jump instructions' opt_mark() methods. 'start' is the starting point,
144     used to prevent the mark sweep from looping for ever. Return the
145     end destination.
146   */
opt_shortcut_jump(sp_head * sp,sp_instr * start)147   virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start)
148   { return get_ip(); }
149 
150   /**
151     Inform the instruction that it has been moved during optimization.
152     Most instructions will simply update its index, but jump instructions
153     must also take care of their destination pointers. Forward jumps get
154     pushed to the backpatch list 'ibp'.
155   */
opt_move(uint dst,List<sp_branch_instr> * ibp)156   virtual void opt_move(uint dst, List<sp_branch_instr> *ibp)
157   { m_ip= dst; }
158 
opt_is_marked()159   bool opt_is_marked() const
160   { return m_marked; }
161 
get_instr_trig_field_list()162   virtual SQL_I_List<Item_trigger_field>* get_instr_trig_field_list()
163   { return NULL; }
164 
165 protected:
166   /// Show if this instruction is reachable within the SP
167   /// (used by SP-optimizer).
168   bool m_marked;
169 
170   /// Instruction pointer.
171   uint m_ip;
172 
173   /// Instruction parsing context.
174   sp_pcontext *m_parsing_ctx;
175 
176 private:
177   // Prevent use of copy constructor and assignment operator.
178   sp_instr(const sp_instr &);
179   void operator= (sp_instr &);
180 };
181 
182 ///////////////////////////////////////////////////////////////////////////
183 
184 /**
185   sp_lex_instr is a class providing the interface and base implementation
186   for SP-instructions, whose execution is based on expression evaluation.
187 
188   sp_lex_instr keeps LEX-object to be able to evaluate the expression.
189 
190   sp_lex_instr also provides possibility to re-parse the original query
191   string if for some reason the LEX-object is not valid any longer.
192 */
193 class sp_lex_instr : public sp_instr
194 {
195 public:
sp_lex_instr(uint ip,sp_pcontext * ctx,LEX * lex,bool is_lex_owner)196   sp_lex_instr(uint ip, sp_pcontext *ctx, LEX *lex, bool is_lex_owner)
197    :sp_instr(ip, ctx),
198     m_lex(NULL),
199     m_is_lex_owner(false),
200     m_first_execution(true),
201     m_prelocking_tables(NULL),
202     m_lex_query_tables_own_last(NULL)
203   {
204     set_lex(lex, is_lex_owner);
205     memset(&m_lex_mem_root, 0, sizeof (MEM_ROOT));
206   }
207 
~sp_lex_instr()208   virtual ~sp_lex_instr()
209   {
210     free_lex();
211     /*
212       If the instruction is reparsed, m_lex_mem_root was used to allocate
213       the items, then freeing the memroot, frees the items. Also free the
214       items allocated on heap as well.
215     */
216     if (alloc_root_inited(&m_lex_mem_root))
217       free_items();
218     free_root(&m_lex_mem_root, MYF(0));
219   }
220 
221   /**
222     Make a few attempts to execute the instruction.
223 
224     Basically, this operation does the following things:
225       - install Reprepare_observer to catch metadata changes (if any);
226       - calls reset_lex_and_exec_core() to execute the instruction;
227       - if the execution fails due to a change in metadata, re-parse the
228         instruction's SQL-statement and repeat execution.
229 
230     @param      thd           Thread context.
231     @param[out] nextp         Next instruction pointer
232     @param      open_tables   Flag to specify if the function should check read
233                               access to tables in LEX's table list and open and
234                               lock them (used in instructions which need to
235                               calculate some expression and don't execute
236                               complete statement).
237 
238     @return Error status.
239   */
240   bool validate_lex_and_execute_core(THD *thd, uint *nextp, bool open_tables);
241 
get_instr_trig_field_list()242   virtual SQL_I_List<Item_trigger_field>* get_instr_trig_field_list()
243   { return &m_trig_field_list; }
244 
245 private:
246   /**
247     Prepare LEX and thread for execution of instruction, if requested open
248     and lock LEX's tables, execute instruction's core function, perform
249     cleanup afterwards.
250 
251     @param thd           thread context
252     @param nextp[out]    next instruction pointer
253     @param open_tables   if TRUE then check read access to tables in LEX's table
254                          list and open and lock them (used in instructions which
255                          need to calculate some expression and don't execute
256                          complete statement).
257 
258     @note
259       We are not saving/restoring some parts of THD which may need this because
260       we do this once for whole routine execution in sp_head::execute().
261 
262     @return Error status.
263   */
264   bool reset_lex_and_exec_core(THD *thd, uint *nextp, bool open_tables);
265 
266   /**
267     (Re-)parse the query corresponding to this instruction and return a new
268     LEX-object.
269 
270     @param thd  Thread context.
271     @param sp   The stored program.
272 
273     @return new LEX-object or NULL in case of failure.
274   */
275   LEX *parse_expr(THD *thd, sp_head *sp);
276 
277   /**
278      Set LEX-object.
279 
280      Previously assigned LEX-object (if any) will be properly cleaned up
281      and destroyed.
282 
283      @param lex          LEX-object to be used by this instance of sp_lex_instr.
284      @param is_lex_owner the flag specifying if this instance sp_lex_instr
285                          owns (and thus deletes when needed) passed LEX-object.
286   */
287   void set_lex(LEX *lex, bool is_lex_owner);
288 
289   /**
290      Cleanup and destroy assigned LEX-object if needed.
291   */
292   void free_lex();
293 
294 public:
295   /////////////////////////////////////////////////////////////////////////
296   // sp_instr implementation.
297   /////////////////////////////////////////////////////////////////////////
298 
execute(THD * thd,uint * nextp)299   virtual bool execute(THD *thd, uint *nextp)
300   {
301     /*
302       SP instructions with expressions should clear DA before execution.
303       Note that sp_instr_stmt will override execute(), but it clears DA
304       during normal mysql_execute_command().
305     */
306     clear_da(thd);
307     return validate_lex_and_execute_core(thd, nextp, true);
308   }
309 
310 protected:
311   /////////////////////////////////////////////////////////////////////////
312   // Interface (virtual) methods.
313   /////////////////////////////////////////////////////////////////////////
314 
315   /**
316     Execute core function of instruction after all preparations
317     (e.g. setting of proper LEX, saving part of the thread context).
318 
319     @param thd  Thread context.
320     @param nextp[out]    next instruction pointer
321 
322     @return Error flag.
323   */
324   virtual bool exec_core(THD *thd, uint *nextp) = 0;
325 
326   /**
327     @retval false if the object (i.e. LEX-object) is valid and exec_core() can be
328     just called.
329 
330     @retval true if the object is not valid any longer, exec_core() can not be
331     called. The original query string should be re-parsed and a new LEX-object
332     should be used.
333   */
334   virtual bool is_invalid() const = 0;
335 
336   /**
337     Invalidate the object.
338   */
339   virtual void invalidate() = 0;
340 
341   /**
342     Return the query string, which can be passed to the parser. I.e. the
343     operation should return a valid SQL-statement query string.
344 
345     @param[out] sql_query SQL-statement query string.
346   */
347   virtual void get_query(String *sql_query) const;
348 
349   /**
350     @return the expression query string. This string can not be passed directly
351     to the parser as it is most likely not a valid SQL-statement.
352 
353     @note as it can be seen in the get_query() implementation, get_expr_query()
354     might return EMPTY_STR. EMPTY_STR means that no query-expression is
355     available. That happens when class provides different implementation of
356     get_query(). Strictly speaking, this is a drawback of the current class
357     hierarchy.
358   */
get_expr_query()359   virtual LEX_STRING get_expr_query() const
360   { return EMPTY_STR; }
361 
362   /**
363     Callback function which is called after the statement query string is
364     successfully parsed, and the thread context has not been switched to the
365     outer context. The thread context contains new LEX-object corresponding to
366     the parsed query string.
367 
368     @param thd  Thread context.
369 
370     @return Error flag.
371   */
on_after_expr_parsing(THD * thd)372   virtual bool on_after_expr_parsing(THD *thd)
373   { return false; }
374 
375   /**
376     Destroy items in the free list before re-parsing the statement query
377     string (and thus, creating new items).
378 
379     @param thd  Thread context.
380   */
381   virtual void cleanup_before_parsing(THD *thd);
382 
383   /// LEX-object.
384   LEX *m_lex;
385 private:
386   /**
387     Mem-root for storing the LEX-tree during reparse. This
388     mem-root is freed when a reparse is triggered or the stored
389     routine is dropped.
390   */
391   MEM_ROOT m_lex_mem_root;
392 
393 
394   /**
395     Indicates whether this sp_lex_instr instance is responsible for
396     LEX-object deletion.
397   */
398   bool m_is_lex_owner;
399 
400   /**
401     Indicates whether exec_core() has not been already called on the current
402     LEX-object.
403   */
404   bool m_first_execution;
405 
406   /*****************************************************************************
407     Support for being able to execute this statement in two modes:
408     a) inside prelocked mode set by the calling procedure or its ancestor.
409     b) outside of prelocked mode, when this statement enters/leaves
410        prelocked mode itself.
411   *****************************************************************************/
412 
413   /**
414     List of additional tables this statement needs to lock when it
415     enters/leaves prelocked mode on its own.
416   */
417   TABLE_LIST *m_prelocking_tables;
418 
419   /**
420     The value m_lex->query_tables_own_last should be set to this when the
421     statement enters/leaves prelocked mode on its own.
422   */
423   TABLE_LIST **m_lex_query_tables_own_last;
424 
425   /**
426     List of all the Item_trigger_field's of instruction.
427   */
428   SQL_I_List<Item_trigger_field> m_trig_field_list;
429 };
430 
431 ///////////////////////////////////////////////////////////////////////////
432 
433 /**
434   sp_instr_stmt represents almost all conventional SQL-statements, which are
435   supported outside stored programs.
436 
437   SET-statements, which deal with SP-variable or NEW/OLD trigger pseudo-rows are
438   not represented by this instruction.
439 */
440 class sp_instr_stmt : public sp_lex_instr
441 {
442 public:
sp_instr_stmt(uint ip,LEX * lex,LEX_STRING query)443   sp_instr_stmt(uint ip,
444                 LEX *lex,
445                 LEX_STRING query)
446    :sp_lex_instr(ip, lex->get_sp_current_parsing_ctx(), lex, true),
447     m_query(query),
448     m_valid(true)
449   { }
450 
451   /////////////////////////////////////////////////////////////////////////
452   // sp_instr implementation.
453   /////////////////////////////////////////////////////////////////////////
454 
455   virtual bool execute(THD *thd, uint *nextp);
456 
457   /////////////////////////////////////////////////////////////////////////
458   // sp_printable implementation.
459   /////////////////////////////////////////////////////////////////////////
460 
461   virtual void print(String *str);
462 
463   /////////////////////////////////////////////////////////////////////////
464   // sp_lex_instr implementation.
465   /////////////////////////////////////////////////////////////////////////
466 
467   virtual bool exec_core(THD *thd, uint *nextp);
468 
is_invalid()469   virtual bool is_invalid() const
470   { return !m_valid; }
471 
invalidate()472   virtual void invalidate()
473   { m_valid= false; }
474 
get_query(String * sql_query)475   virtual void get_query(String *sql_query) const
476   { sql_query->append(m_query.str, m_query.length); }
477 
on_after_expr_parsing(THD * thd)478   virtual bool on_after_expr_parsing(THD *thd)
479   {
480     m_valid= true;
481     return false;
482   }
483 
484 private:
485   /// Complete query of the SQL-statement.
486   LEX_STRING m_query;
487 
488   /// Specify if the stored LEX-object is up-to-date.
489   bool m_valid;
490 
491 #ifdef HAVE_PSI_INTERFACE
492 public:
get_psi_info()493   virtual PSI_statement_info* get_psi_info()
494   {
495     return & psi_info;
496   }
497 
498   static PSI_statement_info psi_info;
499 #endif
500 };
501 
502 ///////////////////////////////////////////////////////////////////////////
503 
504 /**
505   sp_instr_set represents SET-statements, which deal with SP-variables.
506 */
507 class sp_instr_set : public sp_lex_instr
508 {
509 public:
sp_instr_set(uint ip,LEX * lex,uint offset,Item * value_item,LEX_STRING value_query,bool is_lex_owner)510   sp_instr_set(uint ip,
511                LEX *lex,
512 	       uint offset,
513                Item *value_item,
514                LEX_STRING value_query,
515                bool is_lex_owner)
516    :sp_lex_instr(ip, lex->get_sp_current_parsing_ctx(), lex, is_lex_owner),
517     m_offset(offset),
518     m_value_item(value_item),
519     m_value_query(value_query)
520   { }
521 
522   /////////////////////////////////////////////////////////////////////////
523   // sp_printable implementation.
524   /////////////////////////////////////////////////////////////////////////
525 
526   virtual void print(String *str);
527 
528   /////////////////////////////////////////////////////////////////////////
529   // sp_lex_instr implementation.
530   /////////////////////////////////////////////////////////////////////////
531 
532   virtual bool exec_core(THD *thd, uint *nextp);
533 
is_invalid()534   virtual bool is_invalid() const
535   { return m_value_item == NULL; }
536 
invalidate()537   virtual void invalidate()
538   { m_value_item= NULL; }
539 
on_after_expr_parsing(THD * thd)540   virtual bool on_after_expr_parsing(THD *thd)
541   {
542     assert(thd->lex->select_lex->item_list.elements == 1);
543 
544     m_value_item= thd->lex->select_lex->item_list.head();
545 
546     return false;
547   }
548 
get_expr_query()549   virtual LEX_STRING get_expr_query() const
550   { return m_value_query; }
551 
552 private:
553   /// Frame offset.
554   uint m_offset;
555 
556   /// Value expression item of the SET-statement.
557   Item *m_value_item;
558 
559   /// SQL-query corresponding to the value expression.
560   LEX_STRING m_value_query;
561 
562 #ifdef HAVE_PSI_INTERFACE
563 public:
564   static PSI_statement_info psi_info;
get_psi_info()565   virtual PSI_statement_info* get_psi_info()
566   {
567     return & psi_info;
568   }
569 #endif
570 };
571 
572 ///////////////////////////////////////////////////////////////////////////
573 
574 /**
575   sp_instr_set_trigger_field represents SET-statements, which deal with NEW/OLD
576   trigger pseudo-rows.
577 */
578 class sp_instr_set_trigger_field : public sp_lex_instr
579 {
580 public:
sp_instr_set_trigger_field(uint ip,LEX * lex,LEX_STRING trigger_field_name,Item_trigger_field * trigger_field,Item * value_item,LEX_STRING value_query)581   sp_instr_set_trigger_field(uint ip,
582                              LEX *lex,
583                              LEX_STRING trigger_field_name,
584                              Item_trigger_field *trigger_field,
585                              Item *value_item,
586                              LEX_STRING value_query)
587    :sp_lex_instr(ip, lex->get_sp_current_parsing_ctx(), lex, true),
588     m_trigger_field_name(trigger_field_name),
589     m_trigger_field(trigger_field),
590     m_value_item(value_item),
591     m_value_query(value_query)
592   { }
593 
594   /////////////////////////////////////////////////////////////////////////
595   // sp_printable implementation.
596   /////////////////////////////////////////////////////////////////////////
597 
598   virtual void print(String *str);
599 
600   /////////////////////////////////////////////////////////////////////////
601   // sp_lex_instr implementation.
602   /////////////////////////////////////////////////////////////////////////
603 
604   virtual bool exec_core(THD *thd, uint *nextp);
605 
is_invalid()606   virtual bool is_invalid() const
607   { return m_value_item == NULL; }
608 
invalidate()609   virtual void invalidate()
610   { m_value_item= NULL; }
611 
612   virtual bool on_after_expr_parsing(THD *thd);
613 
614   virtual void cleanup_before_parsing(THD *thd);
615 
get_expr_query()616   virtual LEX_STRING get_expr_query() const
617   { return m_value_query; }
618 
619 private:
620   /// Trigger field name ("field_name" of the "NEW.field_name").
621   LEX_STRING m_trigger_field_name;
622 
623   /// Item corresponding to the NEW/OLD trigger field.
624   Item_trigger_field *m_trigger_field;
625 
626   /// Value expression item of the SET-statement.
627   Item *m_value_item;
628 
629   /// SQL-query corresponding to the value expression.
630   LEX_STRING m_value_query;
631 
632 #ifdef HAVE_PSI_INTERFACE
633 public:
get_psi_info()634   virtual PSI_statement_info* get_psi_info()
635   {
636     return & psi_info;
637   }
638 
639   static PSI_statement_info psi_info;
640 #endif
641 };
642 
643 ///////////////////////////////////////////////////////////////////////////
644 
645 /**
646   sp_instr_freturn represents RETURN statement in stored functions.
647 */
648 class sp_instr_freturn : public sp_lex_instr
649 {
650 public:
sp_instr_freturn(uint ip,LEX * lex,Item * expr_item,LEX_STRING expr_query,enum enum_field_types return_field_type)651   sp_instr_freturn(uint ip,
652                    LEX *lex,
653 		   Item *expr_item,
654                    LEX_STRING expr_query,
655                    enum enum_field_types return_field_type)
656    :sp_lex_instr(ip, lex->get_sp_current_parsing_ctx(), lex, true),
657     m_expr_item(expr_item),
658     m_expr_query(expr_query),
659     m_return_field_type(return_field_type)
660   { }
661 
662   /////////////////////////////////////////////////////////////////////////
663   // sp_printable implementation.
664   /////////////////////////////////////////////////////////////////////////
665 
666   virtual void print(String *str);
667 
668   /////////////////////////////////////////////////////////////////////////
669   // sp_instr implementation.
670   /////////////////////////////////////////////////////////////////////////
671 
opt_mark(sp_head * sp,List<sp_instr> * leads)672   virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads)
673   {
674     m_marked= true;
675     return UINT_MAX;
676   }
677 
678   /////////////////////////////////////////////////////////////////////////
679   // sp_lex_instr implementation.
680   /////////////////////////////////////////////////////////////////////////
681 
682   virtual bool exec_core(THD *thd, uint *nextp);
683 
is_invalid()684   virtual bool is_invalid() const
685   { return m_expr_item == NULL; }
686 
invalidate()687   virtual void invalidate()
688   {
689     // it's already deleted.
690     m_expr_item= NULL;
691   }
692 
on_after_expr_parsing(THD * thd)693   virtual bool on_after_expr_parsing(THD *thd)
694   {
695     assert(thd->lex->select_lex->item_list.elements == 1);
696 
697     m_expr_item= thd->lex->select_lex->item_list.head();
698 
699     return false;
700   }
701 
get_expr_query()702   virtual LEX_STRING get_expr_query() const
703   { return m_expr_query; }
704 
705 private:
706   /// RETURN-expression item.
707   Item *m_expr_item;
708 
709   /// SQL-query corresponding to the RETURN-expression.
710   LEX_STRING m_expr_query;
711 
712   /// RETURN-field type code.
713   enum enum_field_types m_return_field_type;
714 
715 #ifdef HAVE_PSI_INTERFACE
716 public:
get_psi_info()717   virtual PSI_statement_info* get_psi_info()
718   {
719     return & psi_info;
720   }
721 
722   static PSI_statement_info psi_info;
723 #endif
724 };
725 
726 ///////////////////////////////////////////////////////////////////////////
727 
728 /**
729   This is base class for all kinds of jump instructions.
730 
731   @note this is the only class, we directly construct instances of, that has
732   subclasses. We also redefine sp_instr_jump behavior in those subclasses.
733 
734   @todo later we will consider introducing a new class, which will be the base
735   for sp_instr_jump, sp_instr_set_case_expr and sp_instr_jump_case_when.
736   Something like sp_regular_branch_instr (similar to sp_lex_branch_instr).
737 */
738 class sp_instr_jump : public sp_instr,
739                       public sp_branch_instr
740 {
741 public:
sp_instr_jump(uint ip,sp_pcontext * ctx)742   sp_instr_jump(uint ip, sp_pcontext *ctx)
743    :sp_instr(ip, ctx),
744     m_dest(0),
745     m_optdest(NULL)
746   { }
747 
sp_instr_jump(uint ip,sp_pcontext * ctx,uint dest)748   sp_instr_jump(uint ip, sp_pcontext *ctx, uint dest)
749    :sp_instr(ip, ctx),
750     m_dest(dest),
751     m_optdest(NULL)
752   { }
753 
754   /////////////////////////////////////////////////////////////////////////
755   // sp_printable implementation.
756   /////////////////////////////////////////////////////////////////////////
757 
758   virtual void print(String *str);
759 
760   /////////////////////////////////////////////////////////////////////////
761   // sp_instr implementation.
762   /////////////////////////////////////////////////////////////////////////
763 
execute(THD * thd,uint * nextp)764   virtual bool execute(THD *thd, uint *nextp)
765   {
766     *nextp= m_dest;
767     return false;
768   }
769 
770   virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads);
771 
772   virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start);
773 
774   virtual void opt_move(uint dst, List<sp_branch_instr> *ibp);
775 
776   /////////////////////////////////////////////////////////////////////////
777   // sp_branch_instr implementation.
778   /////////////////////////////////////////////////////////////////////////
779 
set_destination(uint old_dest,uint new_dest)780   virtual void set_destination(uint old_dest, uint new_dest)
781   {
782     if (m_dest == old_dest)
783       m_dest= new_dest;
784   }
785 
backpatch(uint dest)786   virtual void backpatch(uint dest)
787   {
788     /* Calling backpatch twice is a logic flaw in jump resolution. */
789     assert(m_dest == 0);
790     m_dest= dest;
791   }
792 
793 protected:
794   /// Where we will go.
795   uint m_dest;
796 
797   // The following attribute is used by SP-optimizer.
798   sp_instr *m_optdest;
799 
800 #ifdef HAVE_PSI_INTERFACE
801 public:
get_psi_info()802   virtual PSI_statement_info* get_psi_info()
803   {
804     return & psi_info;
805   }
806 
807   static PSI_statement_info psi_info;
808 #endif
809 };
810 
811 ///////////////////////////////////////////////////////////////////////////
812 
813 /**
814   sp_lex_branch_instr is a base class for SP-instructions, which might perform
815   conditional jump depending on the value of an SQL-expression.
816 */
817 class sp_lex_branch_instr : public sp_lex_instr,
818                             public sp_branch_instr
819 {
820 protected:
sp_lex_branch_instr(uint ip,sp_pcontext * ctx,LEX * lex,Item * expr_item,LEX_STRING expr_query)821   sp_lex_branch_instr(uint ip, sp_pcontext *ctx, LEX *lex,
822                       Item *expr_item, LEX_STRING expr_query)
823    :sp_lex_instr(ip, ctx, lex, true),
824     m_dest(0),
825     m_cont_dest(0),
826     m_optdest(NULL),
827     m_cont_optdest(NULL),
828     m_expr_item(expr_item),
829     m_expr_query(expr_query)
830   { }
831 
sp_lex_branch_instr(uint ip,sp_pcontext * ctx,LEX * lex,Item * expr_item,LEX_STRING expr_query,uint dest)832   sp_lex_branch_instr(uint ip, sp_pcontext *ctx, LEX *lex,
833                       Item *expr_item, LEX_STRING expr_query,
834                       uint dest)
835    :sp_lex_instr(ip, ctx, lex, true),
836     m_dest(dest),
837     m_cont_dest(0),
838     m_optdest(NULL),
839     m_cont_optdest(NULL),
840     m_expr_item(expr_item),
841     m_expr_query(expr_query)
842   { }
843 
844 public:
set_cont_dest(uint cont_dest)845   void set_cont_dest(uint cont_dest)
846   { m_cont_dest= cont_dest; }
847 
848   /////////////////////////////////////////////////////////////////////////
849   // sp_instr implementation.
850   /////////////////////////////////////////////////////////////////////////
851 
852   virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads);
853 
854   virtual void opt_move(uint dst, List<sp_branch_instr> *ibp);
855 
get_cont_dest()856   virtual uint get_cont_dest() const
857   { return m_cont_dest; }
858 
859   /////////////////////////////////////////////////////////////////////////
860   // sp_lex_instr implementation.
861   /////////////////////////////////////////////////////////////////////////
862 
is_invalid()863   virtual bool is_invalid() const
864   { return m_expr_item == NULL; }
865 
invalidate()866   virtual void invalidate()
867   { m_expr_item= NULL; /* it's already deleted. */ }
868 
get_expr_query()869   virtual LEX_STRING get_expr_query() const
870   { return m_expr_query; }
871 
872   /////////////////////////////////////////////////////////////////////////
873   // sp_branch_instr implementation.
874   /////////////////////////////////////////////////////////////////////////
875 
set_destination(uint old_dest,uint new_dest)876   virtual void set_destination(uint old_dest, uint new_dest)
877   {
878     if (m_dest == old_dest)
879       m_dest= new_dest;
880 
881     if (m_cont_dest == old_dest)
882       m_cont_dest= new_dest;
883   }
884 
backpatch(uint dest)885   virtual void backpatch(uint dest)
886   {
887     /* Calling backpatch twice is a logic flaw in jump resolution. */
888     assert(m_dest == 0);
889     m_dest= dest;
890   }
891 
892 protected:
893   /// Where we will go.
894   uint m_dest;
895 
896   /// Where continue handlers will go.
897   uint m_cont_dest;
898 
899   // The following attributes are used by SP-optimizer.
900   sp_instr *m_optdest;
901   sp_instr *m_cont_optdest;
902 
903   /// Expression item.
904   Item *m_expr_item;
905 
906   /// SQL-query corresponding to the expression.
907   LEX_STRING m_expr_query;
908 };
909 
910 ///////////////////////////////////////////////////////////////////////////
911 
912 /**
913   sp_instr_jump_if_not implements SP-instruction, which does the jump if its
914   SQL-expression is false.
915 */
916 class sp_instr_jump_if_not : public sp_lex_branch_instr
917 {
918 public:
sp_instr_jump_if_not(uint ip,LEX * lex,Item * expr_item,LEX_STRING expr_query)919   sp_instr_jump_if_not(uint ip,
920                        LEX *lex,
921                        Item *expr_item,
922                        LEX_STRING expr_query)
923    :sp_lex_branch_instr(ip, lex->get_sp_current_parsing_ctx(), lex,
924                         expr_item, expr_query)
925   { }
926 
sp_instr_jump_if_not(uint ip,LEX * lex,Item * expr_item,LEX_STRING expr_query,uint dest)927   sp_instr_jump_if_not(uint ip,
928                        LEX *lex,
929                        Item *expr_item,
930                        LEX_STRING expr_query,
931                        uint dest)
932    :sp_lex_branch_instr(ip, lex->get_sp_current_parsing_ctx(), lex,
933                         expr_item, expr_query, dest)
934   { }
935 
936   /////////////////////////////////////////////////////////////////////////
937   // sp_printable implementation.
938   /////////////////////////////////////////////////////////////////////////
939 
940   virtual void print(String *str);
941 
942   /////////////////////////////////////////////////////////////////////////
943   // sp_lex_instr implementation.
944   /////////////////////////////////////////////////////////////////////////
945 
946   virtual bool exec_core(THD *thd, uint *nextp);
947 
on_after_expr_parsing(THD * thd)948   virtual bool on_after_expr_parsing(THD *thd)
949   {
950     assert(thd->lex->select_lex->item_list.elements == 1);
951 
952     m_expr_item= thd->lex->select_lex->item_list.head();
953 
954     return false;
955   }
956 
957 #ifdef HAVE_PSI_INTERFACE
958 public:
get_psi_info()959   virtual PSI_statement_info* get_psi_info()
960   {
961     return & psi_info;
962   }
963 
964   static PSI_statement_info psi_info;
965 #endif
966 };
967 
968 ///////////////////////////////////////////////////////////////////////////
969 // Instructions used for the "simple CASE" implementation.
970 ///////////////////////////////////////////////////////////////////////////
971 
972 /**
973   sp_instr_set_case_expr is used in the "simple CASE" implementation to evaluate
974   and store the CASE-expression in the runtime context.
975 */
976 class sp_instr_set_case_expr : public sp_lex_branch_instr
977 {
978 public:
sp_instr_set_case_expr(uint ip,LEX * lex,uint case_expr_id,Item * case_expr_item,LEX_STRING case_expr_query)979   sp_instr_set_case_expr(uint ip,
980                          LEX *lex,
981                          uint case_expr_id,
982                          Item *case_expr_item,
983                          LEX_STRING case_expr_query)
984    :sp_lex_branch_instr(ip, lex->get_sp_current_parsing_ctx(), lex,
985                         case_expr_item, case_expr_query),
986     m_case_expr_id(case_expr_id)
987   { }
988 
989   /////////////////////////////////////////////////////////////////////////
990   // sp_printable implementation.
991   /////////////////////////////////////////////////////////////////////////
992 
993   virtual void print(String *str);
994 
995   /////////////////////////////////////////////////////////////////////////
996   // sp_instr implementation.
997   /////////////////////////////////////////////////////////////////////////
998 
999   virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads);
1000 
1001   virtual void opt_move(uint dst, List<sp_branch_instr> *ibp);
1002 
1003   /////////////////////////////////////////////////////////////////////////
1004   // sp_branch_instr implementation.
1005   /////////////////////////////////////////////////////////////////////////
1006 
1007   /*
1008     NOTE: set_destination() and backpatch() are overriden here just because the
1009     m_dest attribute is not used by this class, so there is no need to do
1010     anything about it.
1011 
1012     @todo These operations probably should be left as they are (i.e. do not
1013     override them here). The m_dest attribute would be set and not used, but
1014     that should not be a big deal.
1015 
1016     @todo This also indicates deficiency of the current SP-istruction class
1017     hierarchy.
1018   */
1019 
set_destination(uint old_dest,uint new_dest)1020   virtual void set_destination(uint old_dest, uint new_dest)
1021   {
1022     if (m_cont_dest == old_dest)
1023       m_cont_dest= new_dest;
1024   }
1025 
backpatch(uint dest)1026   virtual void backpatch(uint dest)
1027   { }
1028 
1029   /////////////////////////////////////////////////////////////////////////
1030   // sp_lex_instr implementation.
1031   /////////////////////////////////////////////////////////////////////////
1032 
1033   virtual bool exec_core(THD *thd, uint *nextp);
1034 
on_after_expr_parsing(THD * thd)1035   virtual bool on_after_expr_parsing(THD *thd)
1036   {
1037     assert(thd->lex->select_lex->item_list.elements == 1);
1038 
1039     m_expr_item= thd->lex->select_lex->item_list.head();
1040 
1041     return false;
1042   }
1043 
1044 private:
1045   /// Identifier (index) of the CASE-expression in the runtime context.
1046   uint m_case_expr_id;
1047 
1048 #ifdef HAVE_PSI_INTERFACE
1049 public:
get_psi_info()1050   virtual PSI_statement_info* get_psi_info()
1051   {
1052     return & psi_info;
1053   }
1054 
1055   static PSI_statement_info psi_info;
1056 #endif
1057 };
1058 
1059 ///////////////////////////////////////////////////////////////////////////
1060 
1061 /**
1062   sp_instr_jump_case_when instruction is used in the "simple CASE"
1063   implementation. It's a jump instruction with the following condition:
1064     (CASE-expression = WHEN-expression)
1065   CASE-expression is retrieved from sp_rcontext;
1066   WHEN-expression is kept by this instruction.
1067 */
1068 class sp_instr_jump_case_when : public sp_lex_branch_instr
1069 {
1070 public:
sp_instr_jump_case_when(uint ip,LEX * lex,int case_expr_id,Item * when_expr_item,LEX_STRING when_expr_query)1071   sp_instr_jump_case_when(uint ip,
1072                           LEX *lex,
1073                           int case_expr_id,
1074                           Item *when_expr_item,
1075                           LEX_STRING when_expr_query)
1076    :sp_lex_branch_instr(ip, lex->get_sp_current_parsing_ctx(), lex,
1077                         when_expr_item, when_expr_query),
1078     m_case_expr_id(case_expr_id)
1079   { }
1080 
1081   /////////////////////////////////////////////////////////////////////////
1082   // sp_printable implementation.
1083   /////////////////////////////////////////////////////////////////////////
1084 
1085   virtual void print(String *str);
1086 
1087   /////////////////////////////////////////////////////////////////////////
1088   // sp_lex_instr implementation.
1089   /////////////////////////////////////////////////////////////////////////
1090 
1091   virtual bool exec_core(THD *thd, uint *nextp);
1092 
invalidate()1093   virtual void invalidate()
1094   {
1095     // Items should be already deleted in lex-keeper.
1096     m_case_expr_item= NULL;
1097     m_eq_item= NULL;
1098     m_expr_item= NULL; // it's a WHEN-expression.
1099   }
1100 
on_after_expr_parsing(THD * thd)1101   virtual bool on_after_expr_parsing(THD *thd)
1102   { return build_expr_items(thd); }
1103 
1104 private:
1105   /**
1106     Build CASE-expression item tree:
1107       Item_func_eq(case-expression, when-i-expression)
1108 
1109     This function is used for the following form of CASE statement:
1110       CASE case-expression
1111         WHEN when-1-expression THEN ...
1112         WHEN when-2-expression THEN ...
1113         ...
1114         WHEN when-n-expression THEN ...
1115       END CASE
1116 
1117     The thing is that after the parsing we have an item (item tree) for the
1118     case-expression and for each when-expression. Here we build jump
1119     conditions: expressions like (case-expression = when-i-expression).
1120 
1121     @param thd  Thread context.
1122 
1123     @return Error flag.
1124   */
1125   bool build_expr_items(THD *thd);
1126 
1127 private:
1128   /// Identifier (index) of the CASE-expression in the runtime context.
1129   int m_case_expr_id;
1130 
1131   /// Item representing the CASE-expression.
1132   Item_case_expr *m_case_expr_item;
1133 
1134   /**
1135     Item corresponding to the main item of the jump-condition-expression:
1136     it's the equal function (=) in the (case-expression = when-i-expression)
1137     expression.
1138   */
1139   Item *m_eq_item;
1140 
1141 #ifdef HAVE_PSI_INTERFACE
1142 public:
get_psi_info()1143   virtual PSI_statement_info* get_psi_info()
1144   {
1145     return & psi_info;
1146   }
1147 
1148   static PSI_statement_info psi_info;
1149 #endif
1150 };
1151 
1152 ///////////////////////////////////////////////////////////////////////////
1153 // SQL-condition handler instructions.
1154 ///////////////////////////////////////////////////////////////////////////
1155 
1156 class sp_instr_hpush_jump : public sp_instr_jump
1157 {
1158 public:
sp_instr_hpush_jump(uint ip,sp_pcontext * ctx,sp_handler * handler)1159   sp_instr_hpush_jump(uint ip,
1160                       sp_pcontext *ctx,
1161                       sp_handler *handler)
1162    :sp_instr_jump(ip, ctx),
1163     m_handler(handler),
1164     m_opt_hpop(0),
1165     m_frame(ctx->current_var_count())
1166   {
1167     assert(m_handler->condition_values.elements == 0);
1168   }
1169 
~sp_instr_hpush_jump()1170   virtual ~sp_instr_hpush_jump()
1171   {
1172     m_handler->condition_values.empty();
1173     m_handler= NULL;
1174   }
1175 
add_condition(sp_condition_value * condition_value)1176   void add_condition(sp_condition_value *condition_value)
1177   { m_handler->condition_values.push_back(condition_value); }
1178 
get_handler()1179   sp_handler *get_handler()
1180   { return m_handler; }
1181 
1182   /////////////////////////////////////////////////////////////////////////
1183   // sp_printable implementation.
1184   /////////////////////////////////////////////////////////////////////////
1185 
1186   virtual void print(String *str);
1187 
1188   /////////////////////////////////////////////////////////////////////////
1189   // sp_instr implementation.
1190   /////////////////////////////////////////////////////////////////////////
1191 
1192   virtual bool execute(THD *thd, uint *nextp);
1193 
1194   virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads);
1195 
1196   /** Override sp_instr_jump's shortcut; we stop here. */
opt_shortcut_jump(sp_head * sp,sp_instr * start)1197   virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start)
1198   { return get_ip(); }
1199 
1200   /////////////////////////////////////////////////////////////////////////
1201   // sp_branch_instr implementation.
1202   /////////////////////////////////////////////////////////////////////////
1203 
backpatch(uint dest)1204   virtual void backpatch(uint dest)
1205   {
1206     assert(!m_dest || !m_opt_hpop);
1207     if (!m_dest)
1208       m_dest= dest;
1209     else
1210       m_opt_hpop= dest;
1211   }
1212 
1213 private:
1214   /// Handler.
1215   sp_handler *m_handler;
1216 
1217   /// hpop marking end of handler scope.
1218   uint m_opt_hpop;
1219 
1220   // This attribute is needed for SHOW PROCEDURE CODE only (i.e. it's needed in
1221   // debug version only). It's used in print().
1222   uint m_frame;
1223 
1224 #ifdef HAVE_PSI_INTERFACE
1225 public:
get_psi_info()1226   virtual PSI_statement_info* get_psi_info()
1227   {
1228     return & psi_info;
1229   }
1230 
1231   static PSI_statement_info psi_info;
1232 #endif
1233 };
1234 
1235 ///////////////////////////////////////////////////////////////////////////
1236 
1237 class sp_instr_hpop : public sp_instr
1238 {
1239 public:
sp_instr_hpop(uint ip,sp_pcontext * ctx)1240   sp_instr_hpop(uint ip, sp_pcontext *ctx)
1241     : sp_instr(ip, ctx)
1242   { }
1243 
1244   /////////////////////////////////////////////////////////////////////////
1245   // sp_printable implementation.
1246   /////////////////////////////////////////////////////////////////////////
1247 
print(String * str)1248   virtual void print(String *str)
1249   { str->append(STRING_WITH_LEN("hpop")); }
1250 
1251   /////////////////////////////////////////////////////////////////////////
1252   // sp_instr implementation.
1253   /////////////////////////////////////////////////////////////////////////
1254 
1255   virtual bool execute(THD *thd, uint *nextp);
1256 
1257 #ifdef HAVE_PSI_INTERFACE
1258 public:
get_psi_info()1259   virtual PSI_statement_info* get_psi_info()
1260   {
1261     return & psi_info;
1262   }
1263 
1264   static PSI_statement_info psi_info;
1265 #endif
1266 };
1267 
1268 ///////////////////////////////////////////////////////////////////////////
1269 
1270 class sp_instr_hreturn : public sp_instr_jump
1271 {
1272 public:
sp_instr_hreturn(uint ip,sp_pcontext * ctx)1273   sp_instr_hreturn(uint ip, sp_pcontext *ctx)
1274    :sp_instr_jump(ip, ctx),
1275     m_frame(ctx->current_var_count())
1276   { }
1277 
1278   /////////////////////////////////////////////////////////////////////////
1279   // sp_printable implementation.
1280   /////////////////////////////////////////////////////////////////////////
1281 
1282   virtual void print(String *str);
1283 
1284   /////////////////////////////////////////////////////////////////////////
1285   // sp_instr implementation.
1286   /////////////////////////////////////////////////////////////////////////
1287 
1288   virtual bool execute(THD *thd, uint *nextp);
1289 
1290   /** Override sp_instr_jump's shortcut; we stop here. */
opt_shortcut_jump(sp_head * sp,sp_instr * start)1291   virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start)
1292   { return get_ip(); }
1293 
1294   virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads);
1295 
1296 private:
1297   // This attribute is needed for SHOW PROCEDURE CODE only (i.e. it's needed in
1298   // debug version only). It's used in print().
1299   uint m_frame;
1300 
1301 #ifdef HAVE_PSI_INTERFACE
1302 public:
get_psi_info()1303   virtual PSI_statement_info* get_psi_info()
1304   {
1305     return & psi_info;
1306   }
1307 
1308   static PSI_statement_info psi_info;
1309 #endif
1310 };
1311 
1312 ///////////////////////////////////////////////////////////////////////////
1313 // Cursor implementation.
1314 ///////////////////////////////////////////////////////////////////////////
1315 
1316 /**
1317   sp_instr_cpush corresponds to DECLARE CURSOR, implements DECLARE CURSOR and
1318   OPEN.
1319 
1320   This is the most important instruction in cursor implementation. It is created
1321   and added to sp_head when DECLARE CURSOR is being parsed. The arena of this
1322   instruction contains LEX-object for the cursor's SELECT-statement.
1323 
1324   This instruction is actually used to open the cursor.
1325 
1326   execute() operation "implements" DECLARE CURSOR statement -- it merely pushes
1327   a new cursor object into the stack in sp_rcontext object.
1328 
1329   exec_core() operation implements OPEN statement. It is important to implement
1330   OPEN statement in this instruction, because OPEN may lead to re-parsing of the
1331   SELECT-statement. So, the original Arena and parsing context must be used.
1332 */
1333 class sp_instr_cpush : public sp_lex_instr
1334 {
1335 public:
sp_instr_cpush(uint ip,sp_pcontext * ctx,LEX * cursor_lex,LEX_STRING cursor_query,int cursor_idx)1336   sp_instr_cpush(uint ip,
1337                  sp_pcontext *ctx,
1338                  LEX *cursor_lex,
1339                  LEX_STRING cursor_query,
1340                  int cursor_idx)
1341    :sp_lex_instr(ip, ctx, cursor_lex, true),
1342     m_cursor_query(cursor_query),
1343     m_valid(true),
1344     m_cursor_idx(cursor_idx)
1345   {
1346     // Cursor can't be stored in Query Cache, so we should prevent opening QC
1347     // for try to write results which are absent.
1348 
1349     cursor_lex->safe_to_cache_query= false;
1350   }
1351 
1352   /////////////////////////////////////////////////////////////////////////
1353   // sp_printable implementation.
1354   /////////////////////////////////////////////////////////////////////////
1355 
1356   virtual void print(String *str);
1357 
1358   /////////////////////////////////////////////////////////////////////////
1359   // Query_arena implementation.
1360   /////////////////////////////////////////////////////////////////////////
1361 
1362   /**
1363     This call is used to cleanup the instruction when a sensitive
1364     cursor is closed. For now stored procedures always use materialized
1365     cursors and the call is not used.
1366   */
cleanup_stmt()1367   virtual void cleanup_stmt()
1368   { /* no op */ }
1369 
1370   /////////////////////////////////////////////////////////////////////////
1371   // sp_instr implementation.
1372   /////////////////////////////////////////////////////////////////////////
1373 
1374   virtual bool execute(THD *thd, uint *nextp);
1375 
1376   /////////////////////////////////////////////////////////////////////////
1377   // sp_lex_instr implementation.
1378   /////////////////////////////////////////////////////////////////////////
1379 
1380   virtual bool exec_core(THD *thd, uint *nextp);
1381 
is_invalid()1382   virtual bool is_invalid() const
1383   { return !m_valid; }
1384 
invalidate()1385   virtual void invalidate()
1386   { m_valid= false; }
1387 
get_query(String * sql_query)1388   virtual void get_query(String *sql_query) const
1389   { sql_query->append(m_cursor_query.str, m_cursor_query.length); }
1390 
on_after_expr_parsing(THD * thd)1391   virtual bool on_after_expr_parsing(THD *thd)
1392   {
1393     m_valid= true;
1394     return false;
1395   }
1396 
1397 private:
1398   /// This attribute keeps the cursor SELECT statement.
1399   LEX_STRING m_cursor_query;
1400 
1401   /// Flag if the LEX-object of this instruction is valid or not.
1402   /// The LEX-object is not valid when metadata have changed.
1403   bool m_valid;
1404 
1405   /// Used to identify the cursor in the sp_rcontext.
1406   int m_cursor_idx;
1407 
1408 #ifdef HAVE_PSI_INTERFACE
1409 public:
get_psi_info()1410   virtual PSI_statement_info* get_psi_info()
1411   {
1412     return & psi_info;
1413   }
1414 
1415   static PSI_statement_info psi_info;
1416 #endif
1417 };
1418 
1419 ///////////////////////////////////////////////////////////////////////////
1420 
1421 /**
1422   sp_instr_cpop instruction is added at the end of BEGIN..END block.
1423   It's used to remove declared cursors so that they are not visible any longer.
1424 */
1425 class sp_instr_cpop : public sp_instr
1426 {
1427 public:
sp_instr_cpop(uint ip,sp_pcontext * ctx,uint count)1428   sp_instr_cpop(uint ip, sp_pcontext *ctx, uint count)
1429    :sp_instr(ip, ctx),
1430     m_count(count)
1431   { }
1432 
1433   /////////////////////////////////////////////////////////////////////////
1434   // sp_printable implementation.
1435   /////////////////////////////////////////////////////////////////////////
1436 
1437   virtual void print(String *str);
1438 
1439   /////////////////////////////////////////////////////////////////////////
1440   // sp_instr implementation.
1441   /////////////////////////////////////////////////////////////////////////
1442 
1443   virtual bool execute(THD *thd, uint *nextp);
1444 
1445 private:
1446   uint m_count;
1447 
1448 #ifdef HAVE_PSI_INTERFACE
1449 public:
get_psi_info()1450   virtual PSI_statement_info* get_psi_info()
1451   {
1452     return & psi_info;
1453   }
1454 
1455   static PSI_statement_info psi_info;
1456 #endif
1457 };
1458 
1459 ///////////////////////////////////////////////////////////////////////////
1460 
1461 /**
1462   sp_instr_copen represents OPEN statement (opens the cursor).
1463   However, the actual implementation is in sp_instr_cpush::exec_core().
1464 */
1465 class sp_instr_copen : public sp_instr
1466 {
1467 public:
sp_instr_copen(uint ip,sp_pcontext * ctx,int cursor_idx)1468   sp_instr_copen(uint ip, sp_pcontext *ctx, int cursor_idx)
1469    :sp_instr(ip, ctx),
1470     m_cursor_idx(cursor_idx)
1471   { }
1472 
1473   /////////////////////////////////////////////////////////////////////////
1474   // sp_printable implementation.
1475   /////////////////////////////////////////////////////////////////////////
1476 
1477   virtual void print(String *str);
1478 
1479   /////////////////////////////////////////////////////////////////////////
1480   // sp_instr implementation.
1481   /////////////////////////////////////////////////////////////////////////
1482 
1483   virtual bool execute(THD *thd, uint *nextp);
1484 
1485 private:
1486   /// Used to identify the cursor in the sp_rcontext.
1487   int m_cursor_idx;
1488 
1489 #ifdef HAVE_PSI_INTERFACE
1490 public:
get_psi_info()1491   virtual PSI_statement_info* get_psi_info()
1492   {
1493     return & psi_info;
1494   }
1495 
1496   static PSI_statement_info psi_info;
1497 #endif
1498 };
1499 
1500 ///////////////////////////////////////////////////////////////////////////
1501 
1502 /**
1503   The instruction corresponds to the CLOSE statement.
1504   It just forwards the close-call to the appropriate sp_cursor object in the
1505   sp_rcontext.
1506 */
1507 class sp_instr_cclose : public sp_instr
1508 {
1509 public:
sp_instr_cclose(uint ip,sp_pcontext * ctx,int cursor_idx)1510   sp_instr_cclose(uint ip, sp_pcontext *ctx, int cursor_idx)
1511    :sp_instr(ip, ctx),
1512     m_cursor_idx(cursor_idx)
1513   { }
1514 
1515   /////////////////////////////////////////////////////////////////////////
1516   // sp_printable implementation.
1517   /////////////////////////////////////////////////////////////////////////
1518 
1519   virtual void print(String *str);
1520 
1521   /////////////////////////////////////////////////////////////////////////
1522   // sp_instr implementation.
1523   /////////////////////////////////////////////////////////////////////////
1524 
1525   virtual bool execute(THD *thd, uint *nextp);
1526 
1527 private:
1528   /// Used to identify the cursor in the sp_rcontext.
1529   int m_cursor_idx;
1530 
1531 #ifdef HAVE_PSI_INTERFACE
1532 public:
get_psi_info()1533   virtual PSI_statement_info* get_psi_info()
1534   {
1535     return & psi_info;
1536   }
1537 
1538   static PSI_statement_info psi_info;
1539 #endif
1540 };
1541 
1542 ///////////////////////////////////////////////////////////////////////////
1543 
1544 /**
1545   The instruction corresponds to the FETCH statement.
1546   It just forwards the close-call to the appropriate sp_cursor object in the
1547   sp_rcontext.
1548 */
1549 class sp_instr_cfetch : public sp_instr
1550 {
1551 public:
sp_instr_cfetch(uint ip,sp_pcontext * ctx,int cursor_idx)1552   sp_instr_cfetch(uint ip, sp_pcontext *ctx, int cursor_idx)
1553    :sp_instr(ip, ctx),
1554     m_cursor_idx(cursor_idx)
1555   { }
1556 
1557   /////////////////////////////////////////////////////////////////////////
1558   // sp_printable implementation.
1559   /////////////////////////////////////////////////////////////////////////
1560 
1561   virtual void print(String *str);
1562 
1563   /////////////////////////////////////////////////////////////////////////
1564   // sp_instr implementation.
1565   /////////////////////////////////////////////////////////////////////////
1566 
1567   virtual bool execute(THD *thd, uint *nextp);
1568 
add_to_varlist(sp_variable * var)1569   void add_to_varlist(sp_variable *var)
1570   { m_varlist.push_back(var); }
1571 
1572 private:
1573   /// List of SP-variables to store fetched values.
1574   List<sp_variable> m_varlist;
1575 
1576   /// Used to identify the cursor in the sp_rcontext.
1577   int m_cursor_idx;
1578 
1579 #ifdef HAVE_PSI_INTERFACE
1580 public:
get_psi_info()1581   virtual PSI_statement_info* get_psi_info()
1582   {
1583     return & psi_info;
1584   }
1585 
1586   static PSI_statement_info psi_info;
1587 #endif
1588 };
1589 
1590 ///////////////////////////////////////////////////////////////////////////
1591 ///////////////////////////////////////////////////////////////////////////
1592 
1593 /**
1594   sp_instr_error just throws an SQL-condition if the execution flow comes to it.
1595   It's used in the CASE implementation to perform runtime-check that the
1596   CASE-expression is handled by some WHEN/ELSE clause.
1597 */
1598 class sp_instr_error : public sp_instr
1599 {
1600 public:
sp_instr_error(uint ip,sp_pcontext * ctx,int errcode)1601   sp_instr_error(uint ip, sp_pcontext *ctx, int errcode)
1602    :sp_instr(ip, ctx),
1603     m_errcode(errcode)
1604   { }
1605 
1606   /////////////////////////////////////////////////////////////////////////
1607   // sp_printable implementation.
1608   /////////////////////////////////////////////////////////////////////////
1609 
1610   virtual void print(String *str);
1611 
1612   /////////////////////////////////////////////////////////////////////////
1613   // sp_instr implementation.
1614   /////////////////////////////////////////////////////////////////////////
1615 
execute(THD * thd,uint * nextp)1616   virtual bool execute(THD *thd, uint *nextp)
1617   {
1618     my_message(m_errcode, ER(m_errcode), MYF(0));
1619     *nextp= get_ip() + 1;
1620     return true;
1621   }
1622 
opt_mark(sp_head * sp,List<sp_instr> * leads)1623   virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads)
1624   {
1625     m_marked= true;
1626     return UINT_MAX;
1627   }
1628 
1629 private:
1630   /// The error code, which should be raised by this instruction.
1631   int m_errcode;
1632 
1633 #ifdef HAVE_PSI_INTERFACE
1634 public:
get_psi_info()1635   virtual PSI_statement_info* get_psi_info()
1636   {
1637     return & psi_info;
1638   }
1639 
1640   static PSI_statement_info psi_info;
1641 #endif
1642 };
1643 
1644 ///////////////////////////////////////////////////////////////////////////
1645 
1646 #endif // _SP_INSTR_H_
1647