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