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#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
33class sp_variable : public Sql_alloc
34{
35public:
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.
63 const Type_handler *type_handler() const { return field_def.type_handler(); }
64
65public:
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
99class sp_label : public Sql_alloc
100{
101public:
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
129public:
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
150class sp_condition_value : public Sql_alloc, public Sql_state_errno
151{
152 bool m_is_user_defined;
153public:
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
166public:
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
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)
182 :Sql_alloc(),
183 Sql_state_errno(0, _sql_state),
184 m_is_user_defined(is_user_defined),
185 type(SQLSTATE)
186 { }
187
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
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
226class sp_condition_value_user_defined: public sp_condition_value
227{
228public:
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
240class sp_condition : public Sql_alloc
241{
242public:
243 /// Name of the condition.
244 LEX_CSTRING name;
245
246 /// Value of the condition.
247 sp_condition_value *value;
248
249public:
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 { }
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 }
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*/
289class 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
293public:
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 { }
298 class sp_pcontext *param_context() const { return m_param_context; }
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
308class sp_handler : public Sql_alloc
309{
310public:
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
325public:
326 /// The constructor.
327 ///
328 /// @param _type SQL-handler 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
360class sp_pcontext : public Sql_alloc
361{
362public:
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:
375 Lex_for_loop() { init(); }
376 };
377
378public:
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
394 sp_pcontext *parent_context() const
395 { return m_parent; }
396
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.
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.
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.
440 uint context_var_count() const
441 { return (uint)m_vars.elements(); }
442
443 /// return the i-th variable on the current context
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.
502 void declare_var_boundary(uint n)
503 { m_pboundary= n; }
504
505 /////////////////////////////////////////////////////////////////////////
506 // CASE expressions.
507 /////////////////////////////////////////////////////////////////////////
508
509 int register_case_expr()
510 { return m_num_case_exprs++; }
511
512 int get_num_case_exprs() const
513 { return m_num_case_exprs; }
514
515 bool push_case_expr_id(int case_expr_id)
516 { return m_case_expr_ids.append(case_expr_id); }
517
518 void pop_case_expr_id()
519 { m_case_expr_ids.pop(); }
520
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
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
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
539 sp_label *push_label(THD *thd, const LEX_CSTRING *name, uint ip)
540 { return push_label(thd, name, ip, sp_label::IMPLICIT); }
541
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
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
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
564 sp_label *last_goto_label()
565 {
566 return m_goto_labels.head();
567 }
568
569 sp_label *pop_label()
570 { return m_labels.pop(); }
571
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(const LEX_CSTRING *name) const
596 {
597 sp_condition_value *p= find_condition(name, false);
598 if (p)
599 return p;
600 return find_predefined_condition(name);
601 }
602
603 bool declare_condition(THD *thd, const LEX_CSTRING *name,
604 sp_condition_value *val)
605 {
606 if (find_condition(name, true))
607 {
608 my_error(ER_SP_DUP_COND, MYF(0), name->str);
609 return true;
610 }
611 return add_condition(thd, name, val);
612 }
613
614 /////////////////////////////////////////////////////////////////////////
615 // Handlers.
616 /////////////////////////////////////////////////////////////////////////
617
618 sp_handler *add_handler(THD* thd, sp_handler::enum_type type);
619
620 /// This is an auxilary parsing-time function to check if an SQL-handler
621 /// exists in the current parsing context (current scope) for the given
622 /// SQL-condition. This function is used to check for duplicates during
623 /// the parsing phase.
624 ///
625 /// This function can not be used during the runtime phase to check
626 /// SQL-handler existence because it searches for the SQL-handler in the
627 /// current scope only (during runtime, current and parent scopes
628 /// should be checked according to the SQL-handler resolution rules).
629 ///
630 /// @param condition_value the handler condition value
631 /// (not SQL-condition!).
632 ///
633 /// @retval true if such SQL-handler exists.
634 /// @retval false otherwise.
635 bool check_duplicate_handler(const sp_condition_value *cond_value) const;
636
637 /// Find an SQL handler for the given SQL condition according to the
638 /// SQL-handler resolution rules. This function is used at runtime.
639 ///
640 /// @param value The error code and the SQL state
641 /// @param level The SQL condition level
642 ///
643 /// @return a pointer to the found SQL-handler or NULL.
644 sp_handler *find_handler(const Sql_condition_identity &identity) const;
645
646 /////////////////////////////////////////////////////////////////////////
647 // Cursors.
648 /////////////////////////////////////////////////////////////////////////
649
650 bool add_cursor(const LEX_CSTRING *name, sp_pcontext *param_ctx,
651 class sp_lex_cursor *lex);
652
653 /// See comment for find_variable() above.
654 const sp_pcursor *find_cursor(const LEX_CSTRING *name,
655 uint *poff, bool current_scope_only) const;
656
657 const sp_pcursor *find_cursor_with_error(const LEX_CSTRING *name,
658 uint *poff,
659 bool current_scope_only) const
660 {
661 const sp_pcursor *pcursor= find_cursor(name, poff, current_scope_only);
662 if (!pcursor)
663 {
664 my_error(ER_SP_CURSOR_MISMATCH, MYF(0), name->str);
665 return NULL;
666 }
667 return pcursor;
668 }
669 /// Find cursor by offset (for SHOW {PROCEDURE|FUNCTION} CODE only).
670 const sp_pcursor *find_cursor(uint offset) const;
671
672 const sp_pcursor *get_cursor_by_local_frame_offset(uint offset) const
673 { return &m_cursors.at(offset); }
674
675 uint cursor_offset() const
676 { return m_cursor_offset; }
677
678 uint frame_cursor_count() const
679 { return (uint)m_cursors.elements(); }
680
681 uint max_cursor_index() const
682 { return m_max_cursor_index + (uint)m_cursors.elements(); }
683
684 uint current_cursor_count() const
685 { return m_cursor_offset + (uint)m_cursors.elements(); }
686
687 void set_for_loop(const Lex_for_loop_st &for_loop)
688 {
689 m_for_loop.init(for_loop);
690 }
691 const Lex_for_loop_st &for_loop()
692 {
693 return m_for_loop;
694 }
695
696private:
697 /// Constructor for a tree node.
698 /// @param prev the parent parsing context
699 /// @param scope scope of this parsing context
700 sp_pcontext(sp_pcontext *prev, enum_scope scope);
701
702 void init(uint var_offset, uint cursor_offset, int num_case_expressions);
703
704 /* Prevent use of these */
705 sp_pcontext(const sp_pcontext &);
706 void operator=(sp_pcontext &);
707
708 sp_condition_value *find_predefined_condition(const LEX_CSTRING *name) const;
709
710private:
711 /// m_max_var_index -- number of variables (including all types of arguments)
712 /// in this context including all children contexts.
713 ///
714 /// m_max_var_index >= m_vars.elements().
715 ///
716 /// m_max_var_index of the root parsing context contains number of all
717 /// variables (including arguments) in all enclosed contexts.
718 uint m_max_var_index;
719
720 /// The maximum sub context's framesizes.
721 uint m_max_cursor_index;
722
723 /// Parent context.
724 sp_pcontext *m_parent;
725
726 /// An index of the first SP-variable in this parsing context. The index
727 /// belongs to a runtime table of SP-variables.
728 ///
729 /// Note:
730 /// - m_var_offset is 0 for root parsing context;
731 /// - m_var_offset is different for all nested parsing contexts.
732 uint m_var_offset;
733
734 /// Cursor offset for this context.
735 uint m_cursor_offset;
736
737 /// Boundary for finding variables in this context. This is the number of
738 /// variables currently "invisible" to default clauses. This is normally 0,
739 /// but will be larger during parsing of DECLARE ... DEFAULT, to get the
740 /// scope right for DEFAULT values.
741 uint m_pboundary;
742
743 int m_num_case_exprs;
744
745 /// SP parameters/variables.
746 Dynamic_array<sp_variable *> m_vars;
747
748 /// Stack of CASE expression ids.
749 Dynamic_array<int> m_case_expr_ids;
750
751 /// Stack of SQL-conditions.
752 Dynamic_array<sp_condition *> m_conditions;
753
754 /// Stack of cursors.
755 Dynamic_array<sp_pcursor> m_cursors;
756
757 /// Stack of SQL-handlers.
758 Dynamic_array<sp_handler *> m_handlers;
759
760 /*
761 In the below example the label <<lab>> has two meanings:
762 - GOTO lab : must go before the beginning of the loop
763 - CONTINUE lab : must go to the beginning of the loop
764 We solve this by storing block labels and goto labels into separate lists.
765
766 BEGIN
767 <<lab>>
768 FOR i IN a..10 LOOP
769 ...
770 GOTO lab;
771 ...
772 CONTINUE lab;
773 ...
774 END LOOP;
775 END;
776 */
777 /// List of block labels
778 List<sp_label> m_labels;
779 /// List of goto labels
780 List<sp_label> m_goto_labels;
781
782 /// Children contexts, used for destruction.
783 Dynamic_array<sp_pcontext *> m_children;
784
785 /// Scope of this parsing context.
786 enum_scope m_scope;
787
788 /// FOR LOOP characteristics
789 Lex_for_loop m_for_loop;
790}; // class sp_pcontext : public Sql_alloc
791
792
793#endif /* _SP_PCONTEXT_H_ */
794