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