1 /* -*- C++ -*- */
2 /* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; version 2 of the License.
7 
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12 
13    You should have received a copy of the GNU General Public License
14    along with this program; if not, write to the Free Software
15    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335  USA */
16 
17 #ifndef _SP_PCONTEXT_H_
18 #define _SP_PCONTEXT_H_
19 
20 #ifdef USE_PRAGMA_INTERFACE
21 #pragma interface			/* gcc class implementation */
22 #endif
23 
24 #include "sql_string.h"                         // LEX_STRING
25 #include "field.h"                              // Create_field
26 #include "sql_array.h"                          // Dynamic_array
27 
28 
29 /// This class represents a stored program variable or a parameter
30 /// (also referenced as 'SP-variable').
31 
32 class sp_variable : public Sql_alloc
33 {
34 public:
35   enum enum_mode
36   {
37     MODE_IN,
38     MODE_OUT,
39     MODE_INOUT
40   };
41 
42   /// Name of the SP-variable.
43   LEX_CSTRING name;
44 
45   /// Mode of the SP-variable.
46   enum_mode mode;
47 
48   /// The index to the variable's value in the runtime frame.
49   ///
50   /// It is calculated during parsing and used when creating sp_instr_set
51   /// instructions and Item_splocal items. I.e. values are set/referred by
52   /// array indexing in runtime.
53   uint offset;
54 
55   /// Default value of the SP-variable (if any).
56   Item *default_value;
57 
58   /// Full type information (field meta-data) of the SP-variable.
59   Spvar_definition field_def;
60 
61   /// Field-type of the SP-variable.
type_handler()62   const Type_handler *type_handler() const { return field_def.type_handler(); }
63 
64 public:
sp_variable(const LEX_CSTRING * name_arg,uint offset_arg)65   sp_variable(const LEX_CSTRING *name_arg, uint offset_arg)
66    :Sql_alloc(),
67     name(*name_arg),
68     mode(MODE_IN),
69     offset(offset_arg),
70     default_value(NULL)
71   { }
72   /*
73     Find a ROW field by its qualified name.
74     @param      var_name - the name of the variable
75     @param      field_name - the name of the variable field
76     @param[OUT] row_field_offset - the index of the field
77 
78     @retval  NULL if the variable with the given name was not found,
79              or it is not a row variable, or it does not have a field
80              with the given name, or a non-null pointer otherwise.
81              row_field_offset[0] is set only when the method returns !NULL.
82   */
83   const Spvar_definition *find_row_field(const LEX_CSTRING *var_name,
84                                          const LEX_CSTRING *field_name,
85                                          uint *row_field_offset);
86 };
87 
88 ///////////////////////////////////////////////////////////////////////////
89 
90 /// This class represents an SQL/PSM label. Can refer to the identifier
91 /// used with the "label_name:" construct which may precede some SQL/PSM
92 /// statements, or to an implicit implementation-dependent identifier which
93 /// the parser inserts before a high-level flow control statement such as
94 /// IF/WHILE/REPEAT/LOOP, when such statement is rewritten into a
95 /// combination of low-level jump/jump_if instructions and labels.
96 
97 
98 class sp_label : public Sql_alloc
99 {
100 public:
101   enum enum_type
102   {
103     /// Implicit label generated by parser.
104     IMPLICIT,
105 
106     /// Label at BEGIN.
107     BEGIN,
108 
109     /// Label at iteration control
110     ITERATION,
111 
112     /// Label for jump
113     GOTO
114   };
115 
116   /// Name of the label.
117   LEX_CSTRING name;
118 
119   /// Instruction pointer of the label.
120   uint ip;
121 
122   /// Type of the label.
123   enum_type type;
124 
125   /// Scope of the label.
126   class sp_pcontext *ctx;
127 
128 public:
sp_label(const LEX_CSTRING * _name,uint _ip,enum_type _type,sp_pcontext * _ctx)129   sp_label(const LEX_CSTRING *_name,
130            uint _ip, enum_type _type, sp_pcontext *_ctx)
131    :Sql_alloc(),
132     name(*_name),
133     ip(_ip),
134     type(_type),
135     ctx(_ctx)
136   { }
137 };
138 
139 
140 ///////////////////////////////////////////////////////////////////////////
141 
142 /// This class represents condition-value term in DECLARE CONDITION or
143 /// DECLARE HANDLER statements. sp_condition_value has little to do with
144 /// SQL-conditions.
145 ///
146 /// In some sense, this class is a union -- a set of filled attributes
147 /// depends on the sp_condition_value::type value.
148 
149 class sp_condition_value : public Sql_alloc, public Sql_state_errno
150 {
151   bool m_is_user_defined;
152 public:
153   enum enum_type
154   {
155     ERROR_CODE,
156     SQLSTATE,
157     WARNING,
158     NOT_FOUND,
159     EXCEPTION
160   };
161 
162   /// Type of the condition value.
163   enum_type type;
164 
165 public:
sp_condition_value(uint _mysqlerr)166   sp_condition_value(uint _mysqlerr)
167    :Sql_alloc(),
168     Sql_state_errno(_mysqlerr),
169     m_is_user_defined(false),
170     type(ERROR_CODE)
171   { }
172 
sp_condition_value(uint _mysqlerr,const char * _sql_state)173   sp_condition_value(uint _mysqlerr, const char *_sql_state)
174    :Sql_alloc(),
175     Sql_state_errno(_mysqlerr, _sql_state),
176     m_is_user_defined(false),
177     type(ERROR_CODE)
178   { }
179 
180   sp_condition_value(const char *_sql_state, bool is_user_defined= false)
Sql_alloc()181    :Sql_alloc(),
182     Sql_state_errno(0, _sql_state),
183     m_is_user_defined(is_user_defined),
184     type(SQLSTATE)
185   { }
186 
sp_condition_value(enum_type _type)187   sp_condition_value(enum_type _type)
188    :Sql_alloc(),
189     m_is_user_defined(false),
190     type(_type)
191   {
192     DBUG_ASSERT(type != ERROR_CODE && type != SQLSTATE);
193   }
194 
195   /// Check if two instances of sp_condition_value are equal or not.
196   ///
197   /// @param cv another instance of sp_condition_value to check.
198   ///
199   /// @return true if the instances are equal, false otherwise.
200   bool equals(const sp_condition_value *cv) const;
201 
202 
203   /**
204     Checks if this condition is OK for search.
205     See also sp_context::find_handler().
206 
207     @param identity - The condition identity
208     @param found_cv - A previously found matching condition or NULL.
209     @return true    - If the current value matches identity and
210                       makes a stronger match than the previously
211                       found condition found_cv.
212     @return false   - If the current value does not match identity,
213                       of the current value makes a weaker match than found_cv.
214   */
215   bool matches(const Sql_condition_identity &identity,
216                const sp_condition_value *found_cv) const;
217 
get_user_condition_identity()218   Sql_user_condition_identity get_user_condition_identity() const
219   {
220     return Sql_user_condition_identity(m_is_user_defined ? this : NULL);
221   }
222 };
223 
224 
225 class sp_condition_value_user_defined: public sp_condition_value
226 {
227 public:
sp_condition_value_user_defined()228   sp_condition_value_user_defined()
229    :sp_condition_value("45000", true)
230   { }
231 };
232 
233 
234 ///////////////////////////////////////////////////////////////////////////
235 
236 /// This class represents 'DECLARE CONDITION' statement.
237 /// sp_condition has little to do with SQL-conditions.
238 
239 class sp_condition : public Sql_alloc
240 {
241 public:
242   /// Name of the condition.
243   LEX_CSTRING name;
244 
245   /// Value of the condition.
246   sp_condition_value *value;
247 
248 public:
sp_condition(const LEX_CSTRING * name_arg,sp_condition_value * value_arg)249   sp_condition(const LEX_CSTRING *name_arg, sp_condition_value *value_arg)
250    :Sql_alloc(),
251     name(*name_arg),
252     value(value_arg)
253   { }
sp_condition(const char * name_arg,size_t name_length_arg,sp_condition_value * value_arg)254   sp_condition(const char *name_arg, size_t name_length_arg,
255                sp_condition_value *value_arg)
256    :value(value_arg)
257   {
258     name.str=    name_arg;
259     name.length= name_length_arg;
260   }
eq_name(const LEX_CSTRING * str)261   bool eq_name(const LEX_CSTRING *str) const
262   {
263     return my_strnncoll(system_charset_info,
264                         (const uchar *) name.str, name.length,
265                         (const uchar *) str->str, str->length) == 0;
266   }
267 };
268 
269 
270 ///////////////////////////////////////////////////////////////////////////
271 
272 /**
273   class sp_pcursor.
274   Stores information about a cursor:
275   - Cursor's name in LEX_STRING.
276   - Cursor's formal parameter descriptions.
277 
278     Formal parameter descriptions reside in a separate context block,
279     pointed by the "m_param_context" member.
280 
281     m_param_context can be NULL. This means a cursor with no parameters.
282     Otherwise, the number of variables in m_param_context means
283     the number of cursor's formal parameters.
284 
285     Note, m_param_context can be not NULL, but have no variables.
286     This is also means a cursor with no parameters (similar to NULL).
287 */
288 class sp_pcursor: public LEX_CSTRING
289 {
290   class sp_pcontext *m_param_context; // Formal parameters
291   class sp_lex_cursor *m_lex;         // The cursor statement LEX
292 public:
sp_pcursor(const LEX_CSTRING * name,class sp_pcontext * param_ctx,class sp_lex_cursor * lex)293   sp_pcursor(const LEX_CSTRING *name, class sp_pcontext *param_ctx,
294              class sp_lex_cursor *lex)
295    :LEX_CSTRING(*name), m_param_context(param_ctx), m_lex(lex)
296   { }
param_context()297   class sp_pcontext *param_context() const { return m_param_context; }
lex()298   class sp_lex_cursor *lex() const { return m_lex; }
299   bool check_param_count_with_error(uint param_count) const;
300 };
301 
302 
303 ///////////////////////////////////////////////////////////////////////////
304 
305 /// This class represents 'DECLARE HANDLER' statement.
306 
307 class sp_handler : public Sql_alloc
308 {
309 public:
310   /// Enumeration of possible handler types.
311   /// Note: UNDO handlers are not (and have never been) supported.
312   enum enum_type
313   {
314     EXIT,
315     CONTINUE
316   };
317 
318   /// Handler type.
319   enum_type type;
320 
321   /// Conditions caught by this handler.
322   List<sp_condition_value> condition_values;
323 
324 public:
325   /// The constructor.
326   ///
327   /// @param _type SQL-handler type.
sp_handler(enum_type _type)328   sp_handler(enum_type _type)
329    :Sql_alloc(),
330     type(_type)
331   { }
332 };
333 
334 ///////////////////////////////////////////////////////////////////////////
335 
336 /// The class represents parse-time context, which keeps track of declared
337 /// variables/parameters, conditions, handlers, cursors and labels.
338 ///
339 /// sp_pcontext objects are organized in a tree according to the following
340 /// rules:
341 ///   - one sp_pcontext object corresponds for for each BEGIN..END block;
342 ///   - one sp_pcontext object corresponds for each exception handler;
343 ///   - one additional sp_pcontext object is created to contain
344 ///     Stored Program parameters.
345 ///
346 /// sp_pcontext objects are used both at parse-time and at runtime.
347 ///
348 /// During the parsing stage sp_pcontext objects are used:
349 ///   - to look up defined names (e.g. declared variables and visible
350 ///     labels);
351 ///   - to check for duplicates;
352 ///   - for error checking;
353 ///   - to calculate offsets to be used at runtime.
354 ///
355 /// During the runtime phase, a tree of sp_pcontext objects is used:
356 ///   - for error checking (e.g. to check correct number of parameters);
357 ///   - to resolve SQL-handlers.
358 
359 class sp_pcontext : public Sql_alloc
360 {
361 public:
362   enum enum_scope
363   {
364     /// REGULAR_SCOPE designates regular BEGIN ... END blocks.
365     REGULAR_SCOPE,
366 
367     /// HANDLER_SCOPE designates SQL-handler blocks.
368     HANDLER_SCOPE
369   };
370 
371   class Lex_for_loop: public Lex_for_loop_st
372   {
373   public:
Lex_for_loop()374     Lex_for_loop() { init(); }
375   };
376 
377 public:
378   sp_pcontext();
379   ~sp_pcontext();
380 
381 
382   /// Create and push a new context in the tree.
383 
384   /// @param thd   thread context.
385   /// @param scope scope of the new parsing context.
386   /// @return the node created.
387   sp_pcontext *push_context(THD *thd, enum_scope scope);
388 
389   /// Pop a node from the parsing context tree.
390   /// @return the parent node.
391   sp_pcontext *pop_context();
392 
parent_context()393   sp_pcontext *parent_context() const
394   { return m_parent; }
395 
child_context(uint i)396   sp_pcontext *child_context(uint i) const
397   { return i < m_children.elements() ? m_children.at(i) : NULL; }
398 
399   /// Calculate and return the number of handlers to pop between the given
400   /// context and this one.
401   ///
402   /// @param ctx       the other parsing context.
403   /// @param exclusive specifies if the last scope should be excluded.
404   ///
405   /// @return the number of handlers to pop between the given context and
406   /// this one.  If 'exclusive' is true, don't count the last scope we are
407   /// leaving; this is used for LEAVE where we will jump to the hpop
408   /// instructions.
409   uint diff_handlers(const sp_pcontext *ctx, bool exclusive) const;
410 
411   /// Calculate and return the number of cursors to pop between the given
412   /// context and this one.
413   ///
414   /// @param ctx       the other parsing context.
415   /// @param exclusive specifies if the last scope should be excluded.
416   ///
417   /// @return the number of cursors to pop between the given context and
418   /// this one.  If 'exclusive' is true, don't count the last scope we are
419   /// leaving; this is used for LEAVE where we will jump to the cpop
420   /// instructions.
421   uint diff_cursors(const sp_pcontext *ctx, bool exclusive) const;
422 
423   /////////////////////////////////////////////////////////////////////////
424   // SP-variables (parameters and variables).
425   /////////////////////////////////////////////////////////////////////////
426 
427   /// @return the maximum number of variables used in this and all child
428   /// contexts. For the root parsing context, this gives us the number of
429   /// slots needed for variables during the runtime phase.
max_var_index()430   uint max_var_index() const
431   { return m_max_var_index; }
432 
433   /// @return the current number of variables used in the parent contexts
434   /// (from the root), including this context.
current_var_count()435   uint current_var_count() const
436   { return m_var_offset + (uint)m_vars.elements(); }
437 
438   /// @return the number of variables in this context alone.
context_var_count()439   uint context_var_count() const
440   { return (uint)m_vars.elements(); }
441 
442   /// return the i-th variable on the current context
get_context_variable(uint i)443   sp_variable *get_context_variable(uint i) const
444   {
445     DBUG_ASSERT(i < m_vars.elements());
446     return m_vars.at(i);
447   }
448 
449   /*
450     Return the i-th last context variable.
451     If i is 0, then return the very last variable in m_vars.
452   */
453   sp_variable *get_last_context_variable(uint i= 0) const
454   {
455     DBUG_ASSERT(i < m_vars.elements());
456     return m_vars.at(m_vars.elements() - i - 1);
457   }
458 
459   /// Add SP-variable to the parsing context.
460   ///
461   /// @param thd  Thread context.
462   /// @param name Name of the SP-variable.
463   ///
464   /// @return instance of newly added SP-variable.
465   sp_variable *add_variable(THD *thd, const LEX_CSTRING *name);
466 
467   /// Retrieve full type information about SP-variables in this parsing
468   /// context and its children.
469   ///
470   /// @param field_def_lst[out] Container to store type information.
471   void retrieve_field_definitions(List<Spvar_definition> *field_def_lst) const;
472 
473   /// Find SP-variable by name.
474   ///
475   /// The function does a linear search (from newer to older variables,
476   /// in case we have shadowed names).
477   ///
478   /// The function is called only at parsing time.
479   ///
480   /// @param name               Variable name.
481   /// @param current_scope_only A flag if we search only in current scope.
482   ///
483   /// @return instance of found SP-variable, or NULL if not found.
484   sp_variable *find_variable(const LEX_CSTRING *name, bool current_scope_only) const;
485 
486   /// Find SP-variable by the offset in the root parsing context.
487   ///
488   /// The function is used for two things:
489   /// - When evaluating parameters at the beginning, and setting out parameters
490   ///   at the end, of invocation. (Top frame only, so no recursion then.)
491   /// - For printing of sp_instr_set. (Debug mode only.)
492   ///
493   /// @param offset Variable offset in the root parsing context.
494   ///
495   /// @return instance of found SP-variable, or NULL if not found.
496   sp_variable *find_variable(uint offset) const;
497 
498   /// Set the current scope boundary (for default values).
499   ///
500   /// @param n The number of variables to skip.
declare_var_boundary(uint n)501   void declare_var_boundary(uint n)
502   { m_pboundary= n; }
503 
504   /////////////////////////////////////////////////////////////////////////
505   // CASE expressions.
506   /////////////////////////////////////////////////////////////////////////
507 
register_case_expr()508   int register_case_expr()
509   { return m_num_case_exprs++; }
510 
get_num_case_exprs()511   int get_num_case_exprs() const
512   { return m_num_case_exprs; }
513 
push_case_expr_id(int case_expr_id)514   bool push_case_expr_id(int case_expr_id)
515   { return m_case_expr_ids.append(case_expr_id); }
516 
pop_case_expr_id()517   void pop_case_expr_id()
518   { m_case_expr_ids.pop(); }
519 
get_current_case_expr_id()520   int get_current_case_expr_id() const
521   { return *m_case_expr_ids.back(); }
522 
523   /////////////////////////////////////////////////////////////////////////
524   // Labels.
525   /////////////////////////////////////////////////////////////////////////
526 
527   sp_label *push_label(THD *thd, const LEX_CSTRING *name, uint ip,
528                        sp_label::enum_type type, List<sp_label> * list);
529 
push_label(THD * thd,const LEX_CSTRING * name,uint ip,sp_label::enum_type type)530   sp_label *push_label(THD *thd, const LEX_CSTRING *name, uint ip,
531                        sp_label::enum_type type)
532   { return push_label(thd, name, ip, type, &m_labels); }
533 
push_goto_label(THD * thd,const LEX_CSTRING * name,uint ip,sp_label::enum_type type)534   sp_label *push_goto_label(THD *thd, const LEX_CSTRING *name, uint ip,
535                             sp_label::enum_type type)
536   { return push_label(thd, name, ip, type, &m_goto_labels); }
537 
push_label(THD * thd,const LEX_CSTRING * name,uint ip)538   sp_label *push_label(THD *thd, const LEX_CSTRING *name, uint ip)
539   { return push_label(thd, name, ip, sp_label::IMPLICIT); }
540 
push_goto_label(THD * thd,const LEX_CSTRING * name,uint ip)541   sp_label *push_goto_label(THD *thd, const LEX_CSTRING *name, uint ip)
542   { return push_goto_label(thd, name, ip, sp_label::GOTO); }
543 
544   sp_label *find_label(const LEX_CSTRING *name);
545 
546   sp_label *find_goto_label(const LEX_CSTRING *name, bool recusive);
547 
find_goto_label(const LEX_CSTRING * name)548   sp_label *find_goto_label(const LEX_CSTRING *name)
549   { return find_goto_label(name, true); }
550 
551   sp_label *find_label_current_loop_start();
552 
last_label()553   sp_label *last_label()
554   {
555     sp_label *label= m_labels.head();
556 
557     if (!label && m_parent)
558       label= m_parent->last_label();
559 
560     return label;
561   }
562 
last_goto_label()563   sp_label *last_goto_label()
564   {
565     return m_goto_labels.head();
566   }
567 
pop_label()568   sp_label *pop_label()
569   { return m_labels.pop(); }
570 
block_label_declare(LEX_CSTRING * label)571   bool block_label_declare(LEX_CSTRING *label)
572   {
573     sp_label *lab= find_label(label);
574     if (lab)
575     {
576       my_error(ER_SP_LABEL_REDEFINE, MYF(0), label->str);
577       return true;
578     }
579     return false;
580   }
581 
582   /////////////////////////////////////////////////////////////////////////
583   // Conditions.
584   /////////////////////////////////////////////////////////////////////////
585 
586   bool add_condition(THD *thd, const LEX_CSTRING *name,
587                                sp_condition_value *value);
588 
589   /// See comment for find_variable() above.
590   sp_condition_value *find_condition(const LEX_CSTRING *name,
591                                      bool current_scope_only) const;
592 
593   sp_condition_value *
594   find_declared_or_predefined_condition(THD *thd, const LEX_CSTRING *name) const;
595 
declare_condition(THD * thd,const LEX_CSTRING * name,sp_condition_value * val)596   bool declare_condition(THD *thd, const LEX_CSTRING *name,
597                                    sp_condition_value *val)
598   {
599     if (find_condition(name, true))
600     {
601       my_error(ER_SP_DUP_COND, MYF(0), name->str);
602       return true;
603     }
604     return add_condition(thd, name, val);
605   }
606 
607   /////////////////////////////////////////////////////////////////////////
608   // Handlers.
609   /////////////////////////////////////////////////////////////////////////
610 
611   sp_handler *add_handler(THD* thd, sp_handler::enum_type type);
612 
613   /// This is an auxilary parsing-time function to check if an SQL-handler
614   /// exists in the current parsing context (current scope) for the given
615   /// SQL-condition. This function is used to check for duplicates during
616   /// the parsing phase.
617   ///
618   /// This function can not be used during the runtime phase to check
619   /// SQL-handler existence because it searches for the SQL-handler in the
620   /// current scope only (during runtime, current and parent scopes
621   /// should be checked according to the SQL-handler resolution rules).
622   ///
623   /// @param condition_value the handler condition value
624   ///                        (not SQL-condition!).
625   ///
626   /// @retval true if such SQL-handler exists.
627   /// @retval false otherwise.
628   bool check_duplicate_handler(const sp_condition_value *cond_value) const;
629 
630   /// Find an SQL handler for the given SQL condition according to the
631   /// SQL-handler resolution rules. This function is used at runtime.
632   ///
633   /// @param value            The error code and the SQL state
634   /// @param level            The SQL condition level
635   ///
636   /// @return a pointer to the found SQL-handler or NULL.
637   sp_handler *find_handler(const Sql_condition_identity &identity) const;
638 
639   /////////////////////////////////////////////////////////////////////////
640   // Cursors.
641   /////////////////////////////////////////////////////////////////////////
642 
643   bool add_cursor(const LEX_CSTRING *name, sp_pcontext *param_ctx,
644                   class sp_lex_cursor *lex);
645 
646   /// See comment for find_variable() above.
647   const sp_pcursor *find_cursor(const LEX_CSTRING *name,
648                                 uint *poff, bool current_scope_only) const;
649 
find_cursor_with_error(const LEX_CSTRING * name,uint * poff,bool current_scope_only)650   const sp_pcursor *find_cursor_with_error(const LEX_CSTRING *name,
651                                            uint *poff,
652                                            bool current_scope_only) const
653   {
654     const sp_pcursor *pcursor= find_cursor(name, poff, current_scope_only);
655     if (!pcursor)
656     {
657       my_error(ER_SP_CURSOR_MISMATCH, MYF(0), name->str);
658       return NULL;
659     }
660     return pcursor;
661   }
662   /// Find cursor by offset (for SHOW {PROCEDURE|FUNCTION} CODE only).
663   const sp_pcursor *find_cursor(uint offset) const;
664 
get_cursor_by_local_frame_offset(uint offset)665   const sp_pcursor *get_cursor_by_local_frame_offset(uint offset) const
666   { return &m_cursors.at(offset); }
667 
cursor_offset()668   uint cursor_offset() const
669   { return m_cursor_offset; }
670 
frame_cursor_count()671   uint frame_cursor_count() const
672   { return (uint)m_cursors.elements(); }
673 
max_cursor_index()674   uint max_cursor_index() const
675   { return m_max_cursor_index + (uint)m_cursors.elements(); }
676 
current_cursor_count()677   uint current_cursor_count() const
678   { return m_cursor_offset + (uint)m_cursors.elements(); }
679 
set_for_loop(const Lex_for_loop_st & for_loop)680   void set_for_loop(const Lex_for_loop_st &for_loop)
681   {
682     m_for_loop.init(for_loop);
683   }
for_loop()684   const Lex_for_loop_st &for_loop()
685   {
686     return m_for_loop;
687   }
688 
689 private:
690   /// Constructor for a tree node.
691   /// @param prev the parent parsing context
692   /// @param scope scope of this parsing context
693   sp_pcontext(sp_pcontext *prev, enum_scope scope);
694 
695   void init(uint var_offset, uint cursor_offset, int num_case_expressions);
696 
697   /* Prevent use of these */
698   sp_pcontext(const sp_pcontext &);
699   void operator=(sp_pcontext &);
700 
701   sp_condition_value *find_predefined_condition(const LEX_CSTRING *name) const;
702 
703 private:
704   /// m_max_var_index -- number of variables (including all types of arguments)
705   /// in this context including all children contexts.
706   ///
707   /// m_max_var_index >= m_vars.elements().
708   ///
709   /// m_max_var_index of the root parsing context contains number of all
710   /// variables (including arguments) in all enclosed contexts.
711   uint m_max_var_index;
712 
713   /// The maximum sub context's framesizes.
714   uint m_max_cursor_index;
715 
716   /// Parent context.
717   sp_pcontext *m_parent;
718 
719   /// An index of the first SP-variable in this parsing context. The index
720   /// belongs to a runtime table of SP-variables.
721   ///
722   /// Note:
723   ///   - m_var_offset is 0 for root parsing context;
724   ///   - m_var_offset is different for all nested parsing contexts.
725   uint m_var_offset;
726 
727   /// Cursor offset for this context.
728   uint m_cursor_offset;
729 
730   /// Boundary for finding variables in this context. This is the number of
731   /// variables currently "invisible" to default clauses. This is normally 0,
732   /// but will be larger during parsing of DECLARE ... DEFAULT, to get the
733   /// scope right for DEFAULT values.
734   uint m_pboundary;
735 
736   int m_num_case_exprs;
737 
738   /// SP parameters/variables.
739   Dynamic_array<sp_variable *> m_vars;
740 
741   /// Stack of CASE expression ids.
742   Dynamic_array<int> m_case_expr_ids;
743 
744   /// Stack of SQL-conditions.
745   Dynamic_array<sp_condition *> m_conditions;
746 
747   /// Stack of cursors.
748   Dynamic_array<sp_pcursor> m_cursors;
749 
750   /// Stack of SQL-handlers.
751   Dynamic_array<sp_handler *> m_handlers;
752 
753   /*
754    In the below example the label <<lab>> has two meanings:
755    - GOTO lab : must go before the beginning of the loop
756    - CONTINUE lab : must go to the beginning of the loop
757    We solve this by storing block labels and goto labels into separate lists.
758 
759    BEGIN
760      <<lab>>
761      FOR i IN a..10 LOOP
762        ...
763        GOTO lab;
764        ...
765        CONTINUE lab;
766        ...
767      END LOOP;
768    END;
769   */
770   /// List of block labels
771   List<sp_label> m_labels;
772   /// List of goto labels
773   List<sp_label> m_goto_labels;
774 
775   /// Children contexts, used for destruction.
776   Dynamic_array<sp_pcontext *> m_children;
777 
778   /// Scope of this parsing context.
779   enum_scope m_scope;
780 
781   /// FOR LOOP characteristics
782   Lex_for_loop m_for_loop;
783 }; // class sp_pcontext : public Sql_alloc
784 
785 
786 #endif /* _SP_PCONTEXT_H_ */
787