1 /* Copyright (c) 2002, 2015, 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, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License, version 2.0, for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software Foundation,
21 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
22
23 #include "sp_pcontext.h"
24 #include "sp_head.h"
25
26
equals(const sp_condition_value * cv) const27 bool sp_condition_value::equals(const sp_condition_value *cv) const
28 {
29 DBUG_ASSERT(cv);
30
31 if (this == cv)
32 return true;
33
34 if (type != cv->type)
35 return false;
36
37 switch (type)
38 {
39 case sp_condition_value::ERROR_CODE:
40 return (mysqlerr == cv->mysqlerr);
41
42 case sp_condition_value::SQLSTATE:
43 return (strcmp(sql_state, cv->sql_state) == 0);
44
45 default:
46 return true;
47 }
48 }
49
50
print(String * str) const51 void sp_condition_value::print(String *str) const
52 {
53 switch (type)
54 {
55 case sp_condition_value::ERROR_CODE:
56 str->append(STRING_WITH_LEN(" "));
57 str->append_ulonglong(static_cast<ulonglong>(mysqlerr));
58 break;
59 case sp_condition_value::SQLSTATE:
60 str->append(STRING_WITH_LEN(" SQLSTATE '"));
61 str->append(static_cast<const char *>(sql_state), 5);
62 str->append(STRING_WITH_LEN("'"));
63 break;
64 case sp_condition_value::WARNING:
65 str->append(STRING_WITH_LEN(" SQLWARNING"));
66 break;
67 case sp_condition_value::NOT_FOUND:
68 str->append(STRING_WITH_LEN(" NOT FOUND"));
69 break;
70 case sp_condition_value::EXCEPTION:
71 str->append(STRING_WITH_LEN(" SQLEXCEPTION"));
72 break;
73 default:
74 break;
75 }
76 }
77
78
print_conditions(String * str) const79 void sp_handler::print_conditions(String *str) const
80 {
81 List_iterator_fast<const sp_condition_value> li(
82 const_cast<List<const sp_condition_value>&>(condition_values));
83 const sp_condition_value *cv;
84 bool first= true;
85
86 while ((cv= li++))
87 {
88 if (first)
89 {
90 first= false;
91 str->append(STRING_WITH_LEN(" HANDLER FOR"));
92 }
93 else
94 str->append(STRING_WITH_LEN(","));
95
96 cv->print(str);
97 }
98 }
99
100
print(String * str) const101 void sp_handler::print(String *str) const
102 {
103 switch (type)
104 {
105 case sp_handler::EXIT:
106 str->append(STRING_WITH_LEN(" EXIT"));
107 break;
108 case sp_handler::CONTINUE:
109 str->append(STRING_WITH_LEN(" CONTINUE"));
110 break;
111 default:
112 // The handler type must be either CONTINUE or EXIT.
113 DBUG_ASSERT(0);
114 }
115
116 print_conditions(str);
117 }
118
119
init(uint var_offset,uint cursor_offset,int num_case_expressions)120 void sp_pcontext::init(uint var_offset,
121 uint cursor_offset,
122 int num_case_expressions)
123 {
124 m_var_offset= var_offset;
125 m_cursor_offset= cursor_offset;
126 m_num_case_exprs= num_case_expressions;
127
128 m_labels.empty();
129 }
130
131
sp_pcontext(THD * thd)132 sp_pcontext::sp_pcontext(THD *thd)
133 : Sql_alloc(),
134 m_level(0),
135 m_max_var_index(0), m_max_cursor_index(0),
136 m_parent(NULL), m_pboundary(0),
137 m_vars(thd->mem_root),
138 m_case_expr_ids(thd->mem_root),
139 m_conditions(thd->mem_root),
140 m_cursors(thd->mem_root),
141 m_handlers(thd->mem_root),
142 m_children(thd->mem_root),
143 m_scope(REGULAR_SCOPE)
144 {
145 init(0, 0, 0);
146 }
147
148
sp_pcontext(THD * thd,sp_pcontext * prev,sp_pcontext::enum_scope scope)149 sp_pcontext::sp_pcontext(THD *thd, sp_pcontext *prev,
150 sp_pcontext::enum_scope scope)
151 : Sql_alloc(),
152 m_level(prev->m_level + 1),
153 m_max_var_index(0), m_max_cursor_index(0),
154 m_parent(prev), m_pboundary(0),
155 m_vars(thd->mem_root),
156 m_case_expr_ids(thd->mem_root),
157 m_conditions(thd->mem_root),
158 m_cursors(thd->mem_root),
159 m_handlers(thd->mem_root),
160 m_children(thd->mem_root),
161 m_scope(scope)
162 {
163 init(prev->m_var_offset + prev->m_max_var_index,
164 prev->current_cursor_count(),
165 prev->get_num_case_exprs());
166 }
167
168
~sp_pcontext()169 sp_pcontext::~sp_pcontext()
170 {
171 for (size_t i= 0; i < m_children.size(); ++i)
172 delete m_children.at(i);
173 }
174
175
push_context(THD * thd,sp_pcontext::enum_scope scope)176 sp_pcontext *sp_pcontext::push_context(THD *thd, sp_pcontext::enum_scope scope)
177 {
178 sp_pcontext *child= new (thd->mem_root) sp_pcontext(thd, this, scope);
179
180 if (child)
181 m_children.push_back(child);
182 return child;
183 }
184
185
pop_context()186 sp_pcontext *sp_pcontext::pop_context()
187 {
188 m_parent->m_max_var_index+= m_max_var_index;
189
190 uint submax= max_cursor_index();
191 if (submax > m_parent->m_max_cursor_index)
192 m_parent->m_max_cursor_index= submax;
193
194 if (m_num_case_exprs > m_parent->m_num_case_exprs)
195 m_parent->m_num_case_exprs= m_num_case_exprs;
196
197 return m_parent;
198 }
199
200
diff_handlers(const sp_pcontext * ctx,bool exclusive) const201 size_t sp_pcontext::diff_handlers(const sp_pcontext *ctx, bool exclusive) const
202 {
203 size_t n= 0;
204 const sp_pcontext *pctx= this;
205 const sp_pcontext *last_ctx= NULL;
206
207 while (pctx && pctx != ctx)
208 {
209 n+= pctx->m_handlers.size();
210 last_ctx= pctx;
211 pctx= pctx->parent_context();
212 }
213 if (pctx)
214 return (exclusive && last_ctx ? n - last_ctx->m_handlers.size() : n);
215 return 0; // Didn't find ctx
216 }
217
218
diff_cursors(const sp_pcontext * ctx,bool exclusive) const219 size_t sp_pcontext::diff_cursors(const sp_pcontext *ctx, bool exclusive) const
220 {
221 size_t n= 0;
222 const sp_pcontext *pctx= this;
223 const sp_pcontext *last_ctx= NULL;
224
225 while (pctx && pctx != ctx)
226 {
227 n+= pctx->m_cursors.size();
228 last_ctx= pctx;
229 pctx= pctx->parent_context();
230 }
231 if (pctx)
232 return (exclusive && last_ctx ? n - last_ctx->m_cursors.size() : n);
233 return 0; // Didn't find ctx
234 }
235
236
find_variable(LEX_STRING name,bool current_scope_only) const237 sp_variable *sp_pcontext::find_variable(LEX_STRING name,
238 bool current_scope_only) const
239 {
240 size_t i= m_vars.size() - m_pboundary;
241
242 while (i--)
243 {
244 sp_variable *p= m_vars.at(i);
245
246 if (my_strnncoll(system_charset_info,
247 (const uchar *)name.str, name.length,
248 (const uchar *)p->name.str, p->name.length) == 0)
249 {
250 return p;
251 }
252 }
253
254 return (!current_scope_only && m_parent) ?
255 m_parent->find_variable(name, false) :
256 NULL;
257 }
258
259
find_variable(uint offset) const260 sp_variable *sp_pcontext::find_variable(uint offset) const
261 {
262 if (m_var_offset <= offset && offset < m_var_offset + m_vars.size())
263 return m_vars.at(offset - m_var_offset); // This frame
264
265 return m_parent ?
266 m_parent->find_variable(offset) : // Some previous frame
267 NULL; // Index out of bounds
268 }
269
270
add_variable(THD * thd,LEX_STRING name,enum enum_field_types type,sp_variable::enum_mode mode)271 sp_variable *sp_pcontext::add_variable(THD *thd,
272 LEX_STRING name,
273 enum enum_field_types type,
274 sp_variable::enum_mode mode)
275 {
276 sp_variable *p=
277 new (thd->mem_root) sp_variable(name, type,mode, current_var_count());
278
279 if (!p)
280 return NULL;
281
282 ++m_max_var_index;
283
284 return m_vars.push_back(p) ? NULL : p;
285 }
286
287
push_label(THD * thd,LEX_STRING name,uint ip)288 sp_label *sp_pcontext::push_label(THD *thd, LEX_STRING name, uint ip)
289 {
290 sp_label *label=
291 new (thd->mem_root) sp_label(name, ip, sp_label::IMPLICIT, this);
292
293 if (!label)
294 return NULL;
295
296 m_labels.push_front(label);
297
298 return label;
299 }
300
301
find_label(LEX_STRING name)302 sp_label *sp_pcontext::find_label(LEX_STRING name)
303 {
304 List_iterator_fast<sp_label> li(m_labels);
305 sp_label *lab;
306
307 while ((lab= li++))
308 {
309 if (my_strcasecmp(system_charset_info, name.str, lab->name.str) == 0)
310 return lab;
311 }
312
313 /*
314 Note about exception handlers.
315 See SQL:2003 SQL/PSM (ISO/IEC 9075-4:2003),
316 section 13.1 <compound statement>,
317 syntax rule 4.
318 In short, a DECLARE HANDLER block can not refer
319 to labels from the parent context, as they are out of scope.
320 */
321 return (m_parent && (m_scope == REGULAR_SCOPE)) ?
322 m_parent->find_label(name) :
323 NULL;
324 }
325
326
add_condition(THD * thd,LEX_STRING name,sp_condition_value * value)327 bool sp_pcontext::add_condition(THD *thd,
328 LEX_STRING name,
329 sp_condition_value *value)
330 {
331 sp_condition *p= new (thd->mem_root) sp_condition(name, value);
332
333 if (p == NULL)
334 return true;
335
336 return m_conditions.push_back(p);
337 }
338
339
find_condition(LEX_STRING name,bool current_scope_only) const340 sp_condition_value *sp_pcontext::find_condition(LEX_STRING name,
341 bool current_scope_only) const
342 {
343 size_t i= m_conditions.size();
344
345 while (i--)
346 {
347 sp_condition *p= m_conditions.at(i);
348
349 if (my_strnncoll(system_charset_info,
350 (const uchar *) name.str, name.length,
351 (const uchar *) p->name.str, p->name.length) == 0)
352 {
353 return p->value;
354 }
355 }
356
357 return (!current_scope_only && m_parent) ?
358 m_parent->find_condition(name, false) :
359 NULL;
360 }
361
362
add_handler(THD * thd,sp_handler::enum_type type)363 sp_handler *sp_pcontext::add_handler(THD *thd,
364 sp_handler::enum_type type)
365 {
366 sp_handler *h= new (thd->mem_root) sp_handler(type, this);
367
368 if (!h)
369 return NULL;
370
371 return m_handlers.push_back(h) ? NULL : h;
372 }
373
374
check_duplicate_handler(const sp_condition_value * cond_value) const375 bool sp_pcontext::check_duplicate_handler(
376 const sp_condition_value *cond_value) const
377 {
378 for (size_t i= 0; i < m_handlers.size(); ++i)
379 {
380 sp_handler *h= m_handlers.at(i);
381
382 List_iterator_fast<const sp_condition_value> li(h->condition_values);
383 const sp_condition_value *cv;
384
385 while ((cv= li++))
386 {
387 if (cond_value->equals(cv))
388 return true;
389 }
390 }
391
392 return false;
393 }
394
395
396 sp_handler*
find_handler(const char * sql_state,uint sql_errno,Sql_condition::enum_severity_level severity) const397 sp_pcontext::find_handler(const char *sql_state,
398 uint sql_errno,
399 Sql_condition::enum_severity_level severity) const
400 {
401 sp_handler *found_handler= NULL;
402 const sp_condition_value *found_cv= NULL;
403
404 for (size_t i= 0; i < m_handlers.size(); ++i)
405 {
406 sp_handler *h= m_handlers.at(i);
407
408 List_iterator_fast<const sp_condition_value> li(h->condition_values);
409 const sp_condition_value *cv;
410
411 while ((cv= li++))
412 {
413 switch (cv->type)
414 {
415 case sp_condition_value::ERROR_CODE:
416 if (sql_errno == cv->mysqlerr &&
417 (!found_cv ||
418 found_cv->type > sp_condition_value::ERROR_CODE))
419 {
420 found_cv= cv;
421 found_handler= h;
422 }
423 break;
424
425 case sp_condition_value::SQLSTATE:
426 if (strcmp(sql_state, cv->sql_state) == 0 &&
427 (!found_cv ||
428 found_cv->type > sp_condition_value::SQLSTATE))
429 {
430 found_cv= cv;
431 found_handler= h;
432 }
433 break;
434
435 case sp_condition_value::WARNING:
436 if ((is_sqlstate_warning(sql_state) ||
437 severity == Sql_condition::SL_WARNING) && !found_cv)
438 {
439 found_cv= cv;
440 found_handler= h;
441 }
442 break;
443
444 case sp_condition_value::NOT_FOUND:
445 if (is_sqlstate_not_found(sql_state) && !found_cv)
446 {
447 found_cv= cv;
448 found_handler= h;
449 }
450 break;
451
452 case sp_condition_value::EXCEPTION:
453 if (is_sqlstate_exception(sql_state) &&
454 severity == Sql_condition::SL_ERROR && !found_cv)
455 {
456 found_cv= cv;
457 found_handler= h;
458 }
459 break;
460 }
461 }
462 }
463
464 if (found_handler)
465 return found_handler;
466
467
468 // There is no appropriate handler in this parsing context. We need to look up
469 // in parent contexts. There might be two cases here:
470 //
471 // 1. The current context has REGULAR_SCOPE. That means, it's a simple
472 // BEGIN..END block:
473 // ...
474 // BEGIN
475 // ... # We're here.
476 // END
477 // ...
478 // In this case we simply call find_handler() on parent's context recursively.
479 //
480 // 2. The current context has HANDLER_SCOPE. That means, we're inside an
481 // SQL-handler block:
482 // ...
483 // DECLARE ... HANDLER FOR ...
484 // BEGIN
485 // ... # We're here.
486 // END
487 // ...
488 // In this case we can not just call parent's find_handler(), because
489 // parent's handler don't catch conditions from this scope. Instead, we should
490 // try to find first parent context (we might have nested handler
491 // declarations), which has REGULAR_SCOPE (i.e. which is regular BEGIN..END
492 // block).
493
494 const sp_pcontext *p= this;
495
496 while (p && p->m_scope == HANDLER_SCOPE)
497 p= p->m_parent;
498
499 if (!p || !p->m_parent)
500 return NULL;
501
502 return p->m_parent->find_handler(sql_state, sql_errno, severity);
503 }
504
505
add_cursor(LEX_STRING name)506 bool sp_pcontext::add_cursor(LEX_STRING name)
507 {
508 if (m_cursors.size() == m_max_cursor_index)
509 ++m_max_cursor_index;
510
511 return m_cursors.push_back(name);
512 }
513
514
find_cursor(LEX_STRING name,uint * poff,bool current_scope_only) const515 bool sp_pcontext::find_cursor(LEX_STRING name,
516 uint *poff,
517 bool current_scope_only) const
518 {
519 size_t i= m_cursors.size();
520
521 while (i--)
522 {
523 LEX_STRING n= m_cursors.at(i);
524
525 if (my_strnncoll(system_charset_info,
526 (const uchar *) name.str, name.length,
527 (const uchar *) n.str, n.length) == 0)
528 {
529 *poff= m_cursor_offset + i;
530 return true;
531 }
532 }
533
534 return (!current_scope_only && m_parent) ?
535 m_parent->find_cursor(name, poff, false) :
536 false;
537 }
538
539
retrieve_field_definitions(List<Create_field> * field_def_lst) const540 void sp_pcontext::retrieve_field_definitions(
541 List<Create_field> *field_def_lst) const
542 {
543 /* Put local/context fields in the result list. */
544
545 for (size_t i= 0; i < m_vars.size(); ++i)
546 {
547 sp_variable *var_def= m_vars.at(i);
548
549 field_def_lst->push_back(&var_def->field_def);
550 }
551
552 /* Put the fields of the enclosed contexts in the result list. */
553
554 for (size_t i= 0; i < m_children.size(); ++i)
555 m_children.at(i)->retrieve_field_definitions(field_def_lst);
556 }
557
558
find_cursor(uint offset) const559 const LEX_STRING *sp_pcontext::find_cursor(uint offset) const
560 {
561 if (m_cursor_offset <= offset &&
562 offset < m_cursor_offset + m_cursors.size())
563 {
564 return &m_cursors.at(offset - m_cursor_offset); // This frame
565 }
566
567 return m_parent ?
568 m_parent->find_cursor(offset) : // Some previous frame
569 NULL; // Index out of bounds
570 }
571