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-1301  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 
28 class sp_pcontext;
29 
30 typedef enum
31 {
32   sp_param_in,
33   sp_param_out,
34   sp_param_inout
35 } sp_param_mode_t;
36 
37 typedef struct sp_variable
38 {
39   LEX_STRING name;
40   enum enum_field_types type;
41   sp_param_mode_t mode;
42 
43   /*
44     offset -- this the index to the variable's value in the runtime frame.
45     This is calculated during parsing and used when creating sp_instr_set
46     instructions and Item_splocal items.
47     I.e. values are set/referred by array indexing in runtime.
48   */
49   uint offset;
50 
51   Item *dflt;
52   Create_field field_def;
53 } sp_variable_t;
54 
55 
56 #define SP_LAB_IMPL  0		// Implicit label generated by parser
57 #define SP_LAB_BEGIN 1		// Label at BEGIN
58 #define SP_LAB_ITER  2		// Label at iteration control
59 
60 /*
61   An SQL/PSM label. Can refer to the identifier used with the
62   "label_name:" construct which may precede some SQL/PSM statements, or
63   to an implicit implementation-dependent identifier which the parser
64   inserts before a high-level flow control statement such as
65   IF/WHILE/REPEAT/LOOP, when such statement is rewritten into
66   a combination of low-level jump/jump_if instructions and labels.
67 */
68 
69 typedef struct sp_label
70 {
71   char *name;
72   uint ip;			// Instruction index
73   int type;			// begin/iter or ref/free
74   sp_pcontext *ctx;             // The label's context
75 } sp_label_t;
76 
77 typedef struct sp_cond_type
78 {
79   enum { number, state, warning, notfound, exception } type;
80   char sqlstate[SQLSTATE_LENGTH+1];
81   uint mysqlerr;
82 } sp_cond_type_t;
83 
84 /*
85   Sanity check for SQLSTATEs. Will not check if it's really an existing
86   state (there are just too many), but will check length bad characters.
87 */
88 extern bool
89 sp_cond_check(LEX_STRING *sqlstate);
90 
91 typedef struct sp_cond
92 {
93   LEX_STRING name;
94   sp_cond_type_t *val;
95 } sp_cond_t;
96 
97 /**
98   The scope of a label in Stored Procedures,
99   for name resolution of labels in a parsing context.
100 */
101 enum label_scope_type
102 {
103   /**
104     The labels declared in a parent context are in scope.
105   */
106   LABEL_DEFAULT_SCOPE,
107   /**
108     The labels declared in a parent context are not in scope.
109   */
110   LABEL_HANDLER_SCOPE
111 };
112 
113 /**
114   The parse-time context, used to keep track of declared variables/parameters,
115   conditions, handlers, cursors and labels, during parsing.
116   sp_contexts are organized as a tree, with one object for each begin-end
117   block, one object for each exception handler,
118   plus a root-context for the parameters.
119   This is used during parsing for looking up defined names (e.g. declared
120   variables and visible labels), for error checking, and to calculate offsets
121   to be used at runtime. (During execution variable values, active handlers
122   and cursors, etc, are referred to by an index in a stack.)
123   Parsing contexts for exception handlers limit the visibility of labels.
124   The pcontext tree is also kept during execution and is used for error
125   checking (e.g. correct number of parameters), and in the future, used by
126   the debugger.
127 */
128 
129 class sp_pcontext : public Sql_alloc
130 {
131 public:
132 
133   /**
134     Constructor.
135     Builds a parsing context root node.
136   */
137   sp_pcontext();
138 
139   // Free memory
140   void
141   destroy();
142 
143   /**
144     Create and push a new context in the tree.
145     @param label_scope label scope for the new parsing context
146     @return the node created
147   */
148   sp_pcontext *
149   push_context(label_scope_type label_scope);
150 
151   /**
152     Pop a node from the parsing context tree.
153     @return the parent node
154   */
155   sp_pcontext *
156   pop_context();
157 
158   sp_pcontext *
parent_context()159   parent_context()
160   {
161     return m_parent;
162   }
163 
164   /*
165     Number of handlers/cursors to pop between this context and 'ctx'.
166     If 'exclusive' is true, don't count the last block we are leaving;
167     this is used for LEAVE where we will jump to the cpop/hpop instructions.
168   */
169   uint
170   diff_handlers(sp_pcontext *ctx, bool exclusive);
171   uint
172   diff_cursors(sp_pcontext *ctx, bool exclusive);
173 
174 
175   //
176   // Parameters and variables
177   //
178 
179   /*
180     The maximum number of variables used in this and all child contexts
181     In the root, this gives us the number of slots needed for variables
182     during execution.
183   */
184   inline uint
max_var_index()185   max_var_index()
186   {
187     return m_max_var_index;
188   }
189 
190   /*
191     The current number of variables used in the parents (from the root),
192     including this context.
193   */
194   inline uint
current_var_count()195   current_var_count()
196   {
197     return m_var_offset + m_vars.elements;
198   }
199 
200   /* The number of variables in this context alone */
201   inline uint
context_var_count()202   context_var_count()
203   {
204     return m_vars.elements;
205   }
206 
207   /* Map index in this pcontext to runtime offset */
208   inline uint
var_context2runtime(uint i)209   var_context2runtime(uint i)
210   {
211     return m_var_offset + i;
212   }
213 
214   /* Set type of variable. 'i' is the offset from the top */
215   inline void
set_type(uint i,enum enum_field_types type)216   set_type(uint i, enum enum_field_types type)
217   {
218     sp_variable_t *p= find_variable(i);
219 
220     if (p)
221       p->type= type;
222   }
223 
224   /* Set default value of variable. 'i' is the offset from the top */
225   inline void
set_default(uint i,Item * it)226   set_default(uint i, Item *it)
227   {
228     sp_variable_t *p= find_variable(i);
229 
230     if (p)
231       p->dflt= it;
232   }
233 
234   sp_variable_t *
235   push_variable(LEX_STRING *name, enum enum_field_types type,
236                 sp_param_mode_t mode);
237 
238   /*
239     Retrieve definitions of fields from the current context and its
240     children.
241   */
242   void
243   retrieve_field_definitions(List<Create_field> *field_def_lst);
244 
245   // Find by name
246   sp_variable_t *
247   find_variable(LEX_STRING *name, my_bool scoped=0);
248 
249   // Find by offset (from the top)
250   sp_variable_t *
251   find_variable(uint offset);
252 
253   /*
254     Set the current scope boundary (for default values).
255     The argument is the number of variables to skip.
256   */
257   inline void
declare_var_boundary(uint n)258   declare_var_boundary(uint n)
259   {
260     m_pboundary= n;
261   }
262 
263   /*
264     CASE expressions support.
265   */
266 
267   inline int
register_case_expr()268   register_case_expr()
269   {
270     return m_num_case_exprs++;
271   }
272 
273   inline int
get_num_case_exprs()274   get_num_case_exprs() const
275   {
276     return m_num_case_exprs;
277   }
278 
279   inline bool
push_case_expr_id(int case_expr_id)280   push_case_expr_id(int case_expr_id)
281   {
282     return insert_dynamic(&m_case_expr_id_lst, (uchar*) &case_expr_id);
283   }
284 
285   inline void
pop_case_expr_id()286   pop_case_expr_id()
287   {
288     pop_dynamic(&m_case_expr_id_lst);
289   }
290 
291   inline int
get_current_case_expr_id()292   get_current_case_expr_id() const
293   {
294     int case_expr_id;
295 
296     get_dynamic((DYNAMIC_ARRAY*)&m_case_expr_id_lst, (uchar*) &case_expr_id,
297                 m_case_expr_id_lst.elements - 1);
298 
299     return case_expr_id;
300   }
301 
302   //
303   // Labels
304   //
305 
306   sp_label_t *
307   push_label(char *name, uint ip);
308 
309   sp_label_t *
310   find_label(char *name);
311 
312   inline sp_label_t *
last_label()313   last_label()
314   {
315     sp_label_t *lab= m_label.head();
316 
317     if (!lab && m_parent)
318       lab= m_parent->last_label();
319     return lab;
320   }
321 
322   inline sp_label_t *
pop_label()323   pop_label()
324   {
325     return m_label.pop();
326   }
327 
328   //
329   // Conditions
330   //
331 
332   int
333   push_cond(LEX_STRING *name, sp_cond_type_t *val);
334 
335   sp_cond_type_t *
336   find_cond(LEX_STRING *name, my_bool scoped=0);
337 
338   //
339   // Handlers
340   //
341 
342   inline void
push_handler(sp_cond_type_t * cond)343   push_handler(sp_cond_type_t *cond)
344   {
345     insert_dynamic(&m_handlers, (uchar*)&cond);
346   }
347 
348   bool
349   find_handler(sp_cond_type *cond);
350 
351   inline uint
max_handler_index()352   max_handler_index()
353   {
354     return m_max_handler_index + m_context_handlers;
355   }
356 
357   inline void
add_handlers(uint n)358   add_handlers(uint n)
359   {
360     m_context_handlers+= n;
361   }
362 
363   //
364   // Cursors
365   //
366 
367   int
368   push_cursor(LEX_STRING *name);
369 
370   my_bool
371   find_cursor(LEX_STRING *name, uint *poff, my_bool scoped=0);
372 
373   /* Find by offset (for debugging only) */
374   my_bool
375   find_cursor(uint offset, LEX_STRING *n);
376 
377   inline uint
max_cursor_index()378   max_cursor_index()
379   {
380     return m_max_cursor_index + m_cursors.elements;
381   }
382 
383   inline uint
current_cursor_count()384   current_cursor_count()
385   {
386     return m_cursor_offset + m_cursors.elements;
387   }
388 
389 protected:
390 
391   /**
392     Constructor for a tree node.
393     @param prev the parent parsing context
394     @param label_scope label_scope for this parsing context
395   */
396   sp_pcontext(sp_pcontext *prev, label_scope_type label_scope);
397 
398   /*
399     m_max_var_index -- number of variables (including all types of arguments)
400     in this context including all children contexts.
401 
402     m_max_var_index >= m_vars.elements.
403 
404     m_max_var_index of the root parsing context contains number of all
405     variables (including arguments) in all enclosed contexts.
406   */
407   uint m_max_var_index;
408 
409   // The maximum sub context's framesizes
410   uint m_max_cursor_index;
411   uint m_max_handler_index;
412   uint m_context_handlers;      // No. of handlers in this context
413 
414 private:
415 
416   sp_pcontext *m_parent;	// Parent context
417 
418   /*
419     m_var_offset -- this is an index of the first variable in this
420                     parsing context.
421 
422     m_var_offset is 0 for root context.
423 
424     Since now each variable is stored in separate place, no reuse is done,
425     so m_var_offset is different for all enclosed contexts.
426   */
427   uint m_var_offset;
428 
429   uint m_cursor_offset;		// Cursor offset for this context
430 
431   /*
432     Boundary for finding variables in this context. This is the number
433     of variables currently "invisible" to default clauses.
434     This is normally 0, but will be larger during parsing of
435     DECLARE ... DEFAULT, to get the scope right for DEFAULT values.
436   */
437   uint m_pboundary;
438 
439   int m_num_case_exprs;
440 
441   DYNAMIC_ARRAY m_vars;		// Parameters/variables
442   DYNAMIC_ARRAY m_case_expr_id_lst; /* Stack of CASE expression ids. */
443   DYNAMIC_ARRAY m_conds;        // Conditions
444   DYNAMIC_ARRAY m_cursors;	// Cursors
445   DYNAMIC_ARRAY m_handlers;	// Handlers, for checking for duplicates
446 
447   List<sp_label_t> m_label;	// The label list
448 
449   List<sp_pcontext> m_children;	// Children contexts, used for destruction
450 
451   /**
452     Scope of labels for this parsing context.
453   */
454   label_scope_type m_label_scope;
455 
456 private:
457   sp_pcontext(const sp_pcontext &); /* Prevent use of these */
458   void operator=(sp_pcontext &);
459 }; // class sp_pcontext : public Sql_alloc
460 
461 
462 #endif /* _SP_PCONTEXT_H_ */
463