1/* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; version 2 of the License.
6
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
11
12 You should have received a copy of the GNU General Public License
13 along with this program; if not, write to the Free Software
14 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15
16#include "mariadb.h"
17#include "sql_priv.h"
18#include "unireg.h"
19#ifdef USE_PRAGMA_IMPLEMENTATION
20#pragma implementation
21#endif
22
23#include "sp_pcontext.h"
24#include "sp_head.h"
25
26bool sp_condition_value::equals(const sp_condition_value *cv) const
27{
28 DBUG_ASSERT(cv);
29
30 /*
31 The following test disallows duplicate handlers,
32 including user defined exceptions with the same WHEN clause:
33 DECLARE
34 a EXCEPTION;
35 b EXCEPTION;
36 BEGIN
37 RAUSE a;
38 EXCEPTION
39 WHEN a THEN RETURN 'a0';
40 WHEN a THEN RETURN 'a1';
41 END
42 */
43 if (this == cv)
44 return true;
45
46 /*
47 The test below considers two conditions of the same type as equal
48 (except for the user defined exceptions) to avoid declaring duplicate
49 handlers.
50
51 All user defined conditions have type==SQLSTATE
52 with the same SQL state and error code.
53 It's OK to have multiple user defined conditions:
54 DECLARE
55 a EXCEPTION;
56 b EXCEPTION;
57 BEGIN
58 RAISE a;
59 EXCEPTION
60 WHEN a THEN RETURN 'a';
61 WHEN b THEN RETURN 'b';
62 END;
63 */
64 if (type != cv->type || m_is_user_defined || cv->m_is_user_defined)
65 return false;
66
67 switch (type)
68 {
69 case sp_condition_value::ERROR_CODE:
70 return (get_sql_errno() == cv->get_sql_errno());
71
72 case sp_condition_value::SQLSTATE:
73 return Sql_state::eq(cv);
74
75 default:
76 return true;
77 }
78}
79
80
81void sp_pcontext::init(uint var_offset,
82 uint cursor_offset,
83 int num_case_expressions)
84{
85 m_var_offset= var_offset;
86 m_cursor_offset= cursor_offset;
87 m_num_case_exprs= num_case_expressions;
88
89 m_labels.empty();
90 m_goto_labels.empty();
91}
92
93
94sp_pcontext::sp_pcontext()
95 : Sql_alloc(),
96 m_max_var_index(0), m_max_cursor_index(0),
97 m_parent(NULL), m_pboundary(0),
98 m_scope(REGULAR_SCOPE)
99{
100 init(0, 0, 0);
101}
102
103
104sp_pcontext::sp_pcontext(sp_pcontext *prev, sp_pcontext::enum_scope scope)
105 : Sql_alloc(),
106 m_max_var_index(0), m_max_cursor_index(0),
107 m_parent(prev), m_pboundary(0),
108 m_scope(scope)
109{
110 init(prev->m_var_offset + prev->m_max_var_index,
111 prev->current_cursor_count(),
112 prev->get_num_case_exprs());
113}
114
115
116sp_pcontext::~sp_pcontext()
117{
118 for (size_t i= 0; i < m_children.elements(); ++i)
119 delete m_children.at(i);
120}
121
122
123sp_pcontext *sp_pcontext::push_context(THD *thd, sp_pcontext::enum_scope scope)
124{
125 sp_pcontext *child= new (thd->mem_root) sp_pcontext(this, scope);
126
127 if (child)
128 m_children.append(child);
129 return child;
130}
131
132
133bool cmp_labels(sp_label *a, sp_label *b)
134{
135 return (lex_string_cmp(system_charset_info, &a->name, &b->name) == 0 &&
136 a->type == b->type);
137}
138
139sp_pcontext *sp_pcontext::pop_context()
140{
141 m_parent->m_max_var_index+= m_max_var_index;
142
143 uint submax= max_cursor_index();
144 if (submax > m_parent->m_max_cursor_index)
145 m_parent->m_max_cursor_index= submax;
146
147 if (m_num_case_exprs > m_parent->m_num_case_exprs)
148 m_parent->m_num_case_exprs= m_num_case_exprs;
149
150 /*
151 ** Push unresolved goto label to parent context
152 */
153 sp_label *label;
154 List_iterator_fast<sp_label> li(m_goto_labels);
155 while ((label= li++))
156 {
157 if (label->ip == 0)
158 {
159 m_parent->m_goto_labels.add_unique(label, &cmp_labels);
160 }
161 }
162 return m_parent;
163}
164
165
166uint sp_pcontext::diff_handlers(const sp_pcontext *ctx, bool exclusive) const
167{
168 uint n= 0;
169 const sp_pcontext *pctx= this;
170 const sp_pcontext *last_ctx= NULL;
171
172 while (pctx && pctx != ctx)
173 {
174 n+= (uint)pctx->m_handlers.elements();
175 last_ctx= pctx;
176 pctx= pctx->parent_context();
177 }
178 if (pctx)
179 return (exclusive && last_ctx ? n -(uint) last_ctx->m_handlers.elements() : n);
180 return 0; // Didn't find ctx
181}
182
183
184uint sp_pcontext::diff_cursors(const sp_pcontext *ctx, bool exclusive) const
185{
186 uint n= 0;
187 const sp_pcontext *pctx= this;
188 const sp_pcontext *last_ctx= NULL;
189
190 while (pctx && pctx != ctx)
191 {
192 n+= (uint)pctx->m_cursors.elements();
193 last_ctx= pctx;
194 pctx= pctx->parent_context();
195 }
196 if (pctx)
197 return (exclusive && last_ctx ? (uint)(n - last_ctx->m_cursors.elements()) : n);
198 return 0; // Didn't find ctx
199}
200
201
202sp_variable *sp_pcontext::find_variable(const LEX_CSTRING *name,
203 bool current_scope_only) const
204{
205 size_t i= m_vars.elements() - m_pboundary;
206
207 while (i--)
208 {
209 sp_variable *p= m_vars.at(i);
210
211 if (my_strnncoll(system_charset_info,
212 (const uchar *)name->str, name->length,
213 (const uchar *)p->name.str, p->name.length) == 0)
214 {
215 return p;
216 }
217 }
218
219 return (!current_scope_only && m_parent) ?
220 m_parent->find_variable(name, false) :
221 NULL;
222}
223
224
225/*
226 Find a variable by its run-time offset.
227 If the variable with a desired run-time offset is not found in this
228 context frame, it's recursively searched on parent context frames.
229
230 Note, context frames can have holes:
231 CREATE PROCEDURE p1() AS
232 x0 INT:=100;
233 CURSOR cur(p0 INT, p1 INT) IS SELECT p0, p1;
234 x1 INT:=101;
235 BEGIN
236 ...
237 END;
238 The variables (x0 and x1) and the cursor parameters (p0 and p1)
239 reside in separate parse context frames.
240
241 The variables reside on the top level parse context frame:
242 - x0 has frame offset 0 and run-time offset 0
243 - x1 has frame offset 1 and run-time offset 3
244
245 The cursor parameters reside on the second level parse context frame:
246 - p0 has frame offset 0 and run-time offset 1
247 - p1 has frame offset 1 and run-time offset 2
248
249 Run-time offsets on a frame can have holes, but offsets monotonocally grow,
250 so run-time offsets of all variables are not greater than the run-time offset
251 of the very last variable in this frame.
252*/
253sp_variable *sp_pcontext::find_variable(uint offset) const
254{
255 if (m_var_offset <= offset &&
256 m_vars.elements() &&
257 offset <= get_last_context_variable()->offset)
258 {
259 for (uint i= 0; i < m_vars.elements(); i++)
260 {
261 if (m_vars.at(i)->offset == offset)
262 return m_vars.at(i); // This frame
263 }
264 }
265
266 return m_parent ?
267 m_parent->find_variable(offset) : // Some previous frame
268 NULL; // Index out of bounds
269}
270
271
272sp_variable *sp_pcontext::add_variable(THD *thd, const LEX_CSTRING *name)
273{
274 sp_variable *p=
275 new (thd->mem_root) sp_variable(name, m_var_offset + m_max_var_index);
276
277 if (!p)
278 return NULL;
279
280 ++m_max_var_index;
281
282 return m_vars.append(p) ? NULL : p;
283}
284
285sp_label *sp_pcontext::push_label(THD *thd, const LEX_CSTRING *name, uint ip,
286 sp_label::enum_type type,
287 List<sp_label> *list)
288{
289 sp_label *label=
290 new (thd->mem_root) sp_label(name, ip, type, this);
291
292 if (!label)
293 return NULL;
294
295 list->push_front(label, thd->mem_root);
296
297 return label;
298}
299
300sp_label *sp_pcontext::find_goto_label(const LEX_CSTRING *name, bool recusive)
301{
302 List_iterator_fast<sp_label> li(m_goto_labels);
303 sp_label *lab;
304
305 while ((lab= li++))
306 {
307 if (lex_string_cmp(system_charset_info, name, &lab->name) == 0)
308 return lab;
309 }
310
311 if (!recusive)
312 return NULL;
313
314 /*
315 Note about exception handlers.
316 See SQL:2003 SQL/PSM (ISO/IEC 9075-4:2003),
317 section 13.1 <compound statement>,
318 syntax rule 4.
319 In short, a DECLARE HANDLER block can not refer
320 to labels from the parent context, as they are out of scope.
321 */
322 if (m_scope == HANDLER_SCOPE && m_parent)
323 {
324 if (m_parent->m_parent)
325 {
326 // Skip the parent context
327 return m_parent->m_parent->find_goto_label(name);
328 }
329 }
330
331 return m_parent && (m_scope == REGULAR_SCOPE) ?
332 m_parent->find_goto_label(name) :
333 NULL;
334}
335
336
337sp_label *sp_pcontext::find_label(const LEX_CSTRING *name)
338{
339 List_iterator_fast<sp_label> li(m_labels);
340 sp_label *lab;
341
342 while ((lab= li++))
343 {
344 if (lex_string_cmp(system_charset_info, name, &lab->name) == 0)
345 return lab;
346 }
347
348 /*
349 Note about exception handlers.
350 See SQL:2003 SQL/PSM (ISO/IEC 9075-4:2003),
351 section 13.1 <compound statement>,
352 syntax rule 4.
353 In short, a DECLARE HANDLER block can not refer
354 to labels from the parent context, as they are out of scope.
355 */
356 return (m_parent && (m_scope == REGULAR_SCOPE)) ?
357 m_parent->find_label(name) :
358 NULL;
359}
360
361
362sp_label *sp_pcontext::find_label_current_loop_start()
363{
364 List_iterator_fast<sp_label> li(m_labels);
365 sp_label *lab;
366
367 while ((lab= li++))
368 {
369 if (lab->type == sp_label::ITERATION)
370 return lab;
371 }
372 // See a comment in sp_pcontext::find_label()
373 return (m_parent && (m_scope == REGULAR_SCOPE)) ?
374 m_parent->find_label_current_loop_start() :
375 NULL;
376}
377
378
379bool sp_pcontext::add_condition(THD *thd,
380 const LEX_CSTRING *name,
381 sp_condition_value *value)
382{
383 sp_condition *p= new (thd->mem_root) sp_condition(name, value);
384
385 if (p == NULL)
386 return true;
387
388 return m_conditions.append(p);
389}
390
391
392sp_condition_value *sp_pcontext::find_condition(const LEX_CSTRING *name,
393 bool current_scope_only) const
394{
395 size_t i= m_conditions.elements();
396
397 while (i--)
398 {
399 sp_condition *p= m_conditions.at(i);
400
401 if (p->eq_name(name))
402 {
403 return p->value;
404 }
405 }
406
407 return (!current_scope_only && m_parent) ?
408 m_parent->find_condition(name, false) :
409 NULL;
410}
411
412
413static sp_condition_value
414 // Warnings
415 cond_no_data_found(ER_SP_FETCH_NO_DATA, "01000"),
416 // Errors
417 cond_invalid_cursor(ER_SP_CURSOR_NOT_OPEN, "24000"),
418 cond_dup_val_on_index(ER_DUP_ENTRY, "23000"),
419 cond_dup_val_on_index2(ER_DUP_ENTRY_WITH_KEY_NAME, "23000"),
420 cond_too_many_rows(ER_TOO_MANY_ROWS, "42000");
421
422
423static sp_condition sp_predefined_conditions[]=
424{
425 // Warnings
426 sp_condition(STRING_WITH_LEN("NO_DATA_FOUND"), &cond_no_data_found),
427 // Errors
428 sp_condition(STRING_WITH_LEN("INVALID_CURSOR"), &cond_invalid_cursor),
429 sp_condition(STRING_WITH_LEN("DUP_VAL_ON_INDEX"), &cond_dup_val_on_index),
430 sp_condition(STRING_WITH_LEN("DUP_VAL_ON_INDEX"), &cond_dup_val_on_index2),
431 sp_condition(STRING_WITH_LEN("TOO_MANY_ROWS"), &cond_too_many_rows)
432};
433
434
435sp_condition_value *
436sp_pcontext::find_predefined_condition(const LEX_CSTRING *name) const
437{
438 for (uint i= 0; i < array_elements(sp_predefined_conditions) ; i++)
439 {
440 if (sp_predefined_conditions[i].eq_name(name))
441 return sp_predefined_conditions[i].value;
442 }
443 return NULL;
444}
445
446
447sp_handler *sp_pcontext::add_handler(THD *thd,
448 sp_handler::enum_type type)
449{
450 sp_handler *h= new (thd->mem_root) sp_handler(type);
451
452 if (!h)
453 return NULL;
454
455 return m_handlers.append(h) ? NULL : h;
456}
457
458
459bool sp_pcontext::check_duplicate_handler(
460 const sp_condition_value *cond_value) const
461{
462 for (size_t i= 0; i < m_handlers.elements(); ++i)
463 {
464 sp_handler *h= m_handlers.at(i);
465
466 List_iterator_fast<sp_condition_value> li(h->condition_values);
467 sp_condition_value *cv;
468
469 while ((cv= li++))
470 {
471 if (cond_value->equals(cv))
472 return true;
473 }
474 }
475
476 return false;
477}
478
479
480bool sp_condition_value::matches(const Sql_condition_identity &value,
481 const sp_condition_value *found_cv) const
482{
483 bool user_value_matched= !value.get_user_condition_value() ||
484 this == value.get_user_condition_value();
485
486 switch (type)
487 {
488 case sp_condition_value::ERROR_CODE:
489 return user_value_matched &&
490 value.get_sql_errno() == get_sql_errno() &&
491 (!found_cv || found_cv->type > sp_condition_value::ERROR_CODE);
492
493 case sp_condition_value::SQLSTATE:
494 return user_value_matched &&
495 Sql_state::eq(&value) &&
496 (!found_cv || found_cv->type > sp_condition_value::SQLSTATE);
497
498 case sp_condition_value::WARNING:
499 return user_value_matched &&
500 (value.Sql_state::is_warning() ||
501 value.get_level() == Sql_condition::WARN_LEVEL_WARN) &&
502 !found_cv;
503
504 case sp_condition_value::NOT_FOUND:
505 return user_value_matched &&
506 value.Sql_state::is_not_found() &&
507 !found_cv;
508
509 case sp_condition_value::EXCEPTION:
510 /*
511 In sql_mode=ORACLE this construct should catch both errors and warnings:
512 EXCEPTION
513 WHEN OTHERS THEN ...;
514 E.g. NO_DATA_FOUND is more like a warning than an error,
515 and it should be caught.
516
517 We don't check user_value_matched here.
518 "WHEN OTHERS" catches all user defined exception.
519 */
520 return (((current_thd->variables.sql_mode & MODE_ORACLE) ||
521 (value.Sql_state::is_exception() &&
522 value.get_level() == Sql_condition::WARN_LEVEL_ERROR)) &&
523 !found_cv);
524 }
525 return false;
526}
527
528
529sp_handler*
530sp_pcontext::find_handler(const Sql_condition_identity &value) const
531{
532 sp_handler *found_handler= NULL;
533 sp_condition_value *found_cv= NULL;
534
535 for (size_t i= 0; i < m_handlers.elements(); ++i)
536 {
537 sp_handler *h= m_handlers.at(i);
538
539 List_iterator_fast<sp_condition_value> li(h->condition_values);
540 sp_condition_value *cv;
541
542 while ((cv= li++))
543 {
544 if (cv->matches(value, found_cv))
545 {
546 found_cv= cv;
547 found_handler= h;
548 }
549 }
550 }
551
552 if (found_handler)
553 return found_handler;
554
555
556 // There is no appropriate handler in this parsing context. We need to look up
557 // in parent contexts. There might be two cases here:
558 //
559 // 1. The current context has REGULAR_SCOPE. That means, it's a simple
560 // BEGIN..END block:
561 // ...
562 // BEGIN
563 // ... # We're here.
564 // END
565 // ...
566 // In this case we simply call find_handler() on parent's context recursively.
567 //
568 // 2. The current context has HANDLER_SCOPE. That means, we're inside an
569 // SQL-handler block:
570 // ...
571 // DECLARE ... HANDLER FOR ...
572 // BEGIN
573 // ... # We're here.
574 // END
575 // ...
576 // In this case we can not just call parent's find_handler(), because
577 // parent's handler don't catch conditions from this scope. Instead, we should
578 // try to find first parent context (we might have nested handler
579 // declarations), which has REGULAR_SCOPE (i.e. which is regular BEGIN..END
580 // block).
581
582 const sp_pcontext *p= this;
583
584 while (p && p->m_scope == HANDLER_SCOPE)
585 p= p->m_parent;
586
587 if (!p || !p->m_parent)
588 return NULL;
589
590 return p->m_parent->find_handler(value);
591}
592
593
594bool sp_pcontext::add_cursor(const LEX_CSTRING *name, sp_pcontext *param_ctx,
595 sp_lex_cursor *lex)
596{
597 if (m_cursors.elements() == m_max_cursor_index)
598 ++m_max_cursor_index;
599
600 return m_cursors.append(sp_pcursor(name, param_ctx, lex));
601}
602
603
604const sp_pcursor *sp_pcontext::find_cursor(const LEX_CSTRING *name,
605 uint *poff,
606 bool current_scope_only) const
607{
608 uint i= (uint)m_cursors.elements();
609
610 while (i--)
611 {
612 LEX_CSTRING n= m_cursors.at(i);
613
614 if (my_strnncoll(system_charset_info,
615 (const uchar *) name->str, name->length,
616 (const uchar *) n.str, n.length) == 0)
617 {
618 *poff= m_cursor_offset + i;
619 return &m_cursors.at(i);
620 }
621 }
622
623 return (!current_scope_only && m_parent) ?
624 m_parent->find_cursor(name, poff, false) :
625 NULL;
626}
627
628
629void sp_pcontext::retrieve_field_definitions(
630 List<Spvar_definition> *field_def_lst) const
631{
632 /* Put local/context fields in the result list. */
633
634 size_t next_child= 0;
635 for (size_t i= 0; i < m_vars.elements(); ++i)
636 {
637 sp_variable *var_def= m_vars.at(i);
638
639 /*
640 The context can have holes in run-time offsets,
641 the missing offsets reside on the children contexts in such cases.
642 Example:
643 CREATE PROCEDURE p1() AS
644 x0 INT:=100; -- context 0, position 0, run-time 0
645 CURSOR cur(
646 p0 INT, -- context 1, position 0, run-time 1
647 p1 INT -- context 1, position 1, run-time 2
648 ) IS SELECT p0, p1;
649 x1 INT:=101; -- context 0, position 1, run-time 3
650 BEGIN
651 ...
652 END;
653 See more comments in sp_pcontext::find_variable().
654 We must retrieve the definitions in the order of their run-time offsets.
655 Check that there are children that should go before the current variable.
656 */
657 for ( ; next_child < m_children.elements(); next_child++)
658 {
659 sp_pcontext *child= m_children.at(next_child);
660 if (!child->context_var_count() ||
661 child->get_context_variable(0)->offset > var_def->offset)
662 break;
663 /*
664 All variables on the embedded context (that fills holes of the parent)
665 should have the run-time offset strictly less than var_def.
666 */
667 DBUG_ASSERT(child->get_context_variable(0)->offset < var_def->offset);
668 DBUG_ASSERT(child->get_last_context_variable()->offset < var_def->offset);
669 child->retrieve_field_definitions(field_def_lst);
670 }
671 field_def_lst->push_back(&var_def->field_def);
672 }
673
674 /* Put the fields of the remaining enclosed contexts in the result list. */
675
676 for (size_t i= next_child; i < m_children.elements(); ++i)
677 m_children.at(i)->retrieve_field_definitions(field_def_lst);
678}
679
680
681const sp_pcursor *sp_pcontext::find_cursor(uint offset) const
682{
683 if (m_cursor_offset <= offset &&
684 offset < m_cursor_offset + m_cursors.elements())
685 {
686 return &m_cursors.at(offset - m_cursor_offset); // This frame
687 }
688
689 return m_parent ?
690 m_parent->find_cursor(offset) : // Some previous frame
691 NULL; // Index out of bounds
692}
693
694
695bool sp_pcursor::check_param_count_with_error(uint param_count) const
696{
697 if (param_count != (m_param_context ?
698 m_param_context->context_var_count() : 0))
699 {
700 my_error(ER_WRONG_PARAMCOUNT_TO_CURSOR, MYF(0), LEX_CSTRING::str);
701 return true;
702 }
703 return false;
704}
705
706
707const Spvar_definition *
708sp_variable::find_row_field(const LEX_CSTRING *var_name,
709 const LEX_CSTRING *field_name,
710 uint *row_field_offset)
711{
712 if (!field_def.is_row())
713 {
714 my_printf_error(ER_UNKNOWN_ERROR,
715 "'%s' is not a row variable", MYF(0), var_name->str);
716 return NULL;
717 }
718 const Spvar_definition *def;
719 if ((def= field_def.find_row_field_by_name(field_name, row_field_offset)))
720 return def;
721 my_error(ER_ROW_VARIABLE_DOES_NOT_HAVE_FIELD, MYF(0),
722 var_name->str, field_name->str);
723 return NULL;
724}
725