MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
sp_pcontext.cc
1 /* Copyright (c) 2002, 2011, 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 Foundation,
14  51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
15 
16 #include "sql_priv.h"
17 #include "unireg.h"
18 #include "sp_pcontext.h"
19 #include "sp_head.h"
20 
21 
23 {
24  DBUG_ASSERT(cv);
25 
26  if (this == cv)
27  return true;
28 
29  if (type != cv->type)
30  return false;
31 
32  switch (type)
33  {
34  case sp_condition_value::ERROR_CODE:
35  return (mysqlerr == cv->mysqlerr);
36 
37  case sp_condition_value::SQLSTATE:
38  return (strcmp(sql_state, cv->sql_state) == 0);
39 
40  default:
41  return true;
42  }
43 }
44 
45 
46 void sp_pcontext::init(uint var_offset,
47  uint cursor_offset,
48  int num_case_expressions)
49 {
50  m_var_offset= var_offset;
51  m_cursor_offset= cursor_offset;
52  m_num_case_exprs= num_case_expressions;
53 
54  m_labels.empty();
55 }
56 
57 
58 sp_pcontext::sp_pcontext()
59  : Sql_alloc(),
60  m_level(0),
61  m_max_var_index(0), m_max_cursor_index(0),
62  m_parent(NULL), m_pboundary(0),
63  m_scope(REGULAR_SCOPE)
64 {
65  init(0, 0, 0);
66 }
67 
68 
69 sp_pcontext::sp_pcontext(sp_pcontext *prev, sp_pcontext::enum_scope scope)
70  : Sql_alloc(),
71  m_level(prev->m_level + 1),
72  m_max_var_index(0), m_max_cursor_index(0),
73  m_parent(prev), m_pboundary(0),
74  m_scope(scope)
75 {
76  init(prev->m_var_offset + prev->m_max_var_index,
77  prev->current_cursor_count(),
78  prev->get_num_case_exprs());
79 }
80 
81 
82 sp_pcontext::~sp_pcontext()
83 {
84  for (int i= 0; i < m_children.elements(); ++i)
85  delete m_children.at(i);
86 }
87 
88 
90 {
91  sp_pcontext *child= new (thd->mem_root) sp_pcontext(this, scope);
92 
93  if (child)
94  m_children.append(child);
95  return child;
96 }
97 
98 
100 {
101  m_parent->m_max_var_index+= m_max_var_index;
102 
103  uint submax= max_cursor_index();
104  if (submax > m_parent->m_max_cursor_index)
105  m_parent->m_max_cursor_index= submax;
106 
107  if (m_num_case_exprs > m_parent->m_num_case_exprs)
108  m_parent->m_num_case_exprs= m_num_case_exprs;
109 
110  return m_parent;
111 }
112 
113 
114 uint sp_pcontext::diff_handlers(const sp_pcontext *ctx, bool exclusive) const
115 {
116  uint n= 0;
117  const sp_pcontext *pctx= this;
118  const sp_pcontext *last_ctx= NULL;
119 
120  while (pctx && pctx != ctx)
121  {
122  n+= pctx->m_handlers.elements();
123  last_ctx= pctx;
124  pctx= pctx->parent_context();
125  }
126  if (pctx)
127  return (exclusive && last_ctx ? n - last_ctx->m_handlers.elements() : n);
128  return 0; // Didn't find ctx
129 }
130 
131 
132 uint sp_pcontext::diff_cursors(const sp_pcontext *ctx, bool exclusive) const
133 {
134  uint n= 0;
135  const sp_pcontext *pctx= this;
136  const sp_pcontext *last_ctx= NULL;
137 
138  while (pctx && pctx != ctx)
139  {
140  n+= pctx->m_cursors.elements();
141  last_ctx= pctx;
142  pctx= pctx->parent_context();
143  }
144  if (pctx)
145  return (exclusive && last_ctx ? n - last_ctx->m_cursors.elements() : n);
146  return 0; // Didn't find ctx
147 }
148 
149 
151  bool current_scope_only) const
152 {
153  uint i= m_vars.elements() - m_pboundary;
154 
155  while (i--)
156  {
157  sp_variable *p= m_vars.at(i);
158 
159  if (my_strnncoll(system_charset_info,
160  (const uchar *)name.str, name.length,
161  (const uchar *)p->name.str, p->name.length) == 0)
162  {
163  return p;
164  }
165  }
166 
167  return (!current_scope_only && m_parent) ?
168  m_parent->find_variable(name, false) :
169  NULL;
170 }
171 
172 
174 {
175  if (m_var_offset <= offset && offset < m_var_offset + m_vars.elements())
176  return m_vars.at(offset - m_var_offset); // This frame
177 
178  return m_parent ?
179  m_parent->find_variable(offset) : // Some previous frame
180  NULL; // Index out of bounds
181 }
182 
183 
186  enum enum_field_types type,
187  sp_variable::enum_mode mode)
188 {
189  sp_variable *p=
190  new (thd->mem_root) sp_variable(name, type,mode, current_var_count());
191 
192  if (!p)
193  return NULL;
194 
195  ++m_max_var_index;
196 
197  return m_vars.append(p) ? NULL : p;
198 }
199 
200 
201 sp_label *sp_pcontext::push_label(THD *thd, LEX_STRING name, uint ip)
202 {
203  sp_label *label=
204  new (thd->mem_root) sp_label(name, ip, sp_label::IMPLICIT, this);
205 
206  if (!label)
207  return NULL;
208 
209  m_labels.push_front(label);
210 
211  return label;
212 }
213 
214 
215 sp_label *sp_pcontext::find_label(LEX_STRING name)
216 {
217  List_iterator_fast<sp_label> li(m_labels);
218  sp_label *lab;
219 
220  while ((lab= li++))
221  {
222  if (my_strcasecmp(system_charset_info, name.str, lab->name.str) == 0)
223  return lab;
224  }
225 
226  /*
227  Note about exception handlers.
228  See SQL:2003 SQL/PSM (ISO/IEC 9075-4:2003),
229  section 13.1 <compound statement>,
230  syntax rule 4.
231  In short, a DECLARE HANDLER block can not refer
232  to labels from the parent context, as they are out of scope.
233  */
234  return (m_parent && (m_scope == REGULAR_SCOPE)) ?
235  m_parent->find_label(name) :
236  NULL;
237 }
238 
239 
240 bool sp_pcontext::add_condition(THD *thd,
241  LEX_STRING name,
242  sp_condition_value *value)
243 {
244  sp_condition *p= new (thd->mem_root) sp_condition(name, value);
245 
246  if (p == NULL)
247  return true;
248 
249  return m_conditions.append(p);
250 }
251 
252 
254  bool current_scope_only) const
255 {
256  uint i= m_conditions.elements();
257 
258  while (i--)
259  {
260  sp_condition *p= m_conditions.at(i);
261 
262  if (my_strnncoll(system_charset_info,
263  (const uchar *) name.str, name.length,
264  (const uchar *) p->name.str, p->name.length) == 0)
265  {
266  return p->value;
267  }
268  }
269 
270  return (!current_scope_only && m_parent) ?
271  m_parent->find_condition(name, false) :
272  NULL;
273 }
274 
275 
276 sp_handler *sp_pcontext::add_handler(THD *thd,
278 {
279  sp_handler *h= new (thd->mem_root) sp_handler(type, this);
280 
281  if (!h)
282  return NULL;
283 
284  return m_handlers.append(h) ? NULL : h;
285 }
286 
287 
289  const sp_condition_value *cond_value) const
290 {
291  for (int i= 0; i < m_handlers.elements(); ++i)
292  {
293  sp_handler *h= m_handlers.at(i);
294 
296  sp_condition_value *cv;
297 
298  while ((cv= li++))
299  {
300  if (cond_value->equals(cv))
301  return true;
302  }
303  }
304 
305  return false;
306 }
307 
308 
309 sp_handler*
310 sp_pcontext::find_handler(const char *sql_state,
311  uint sql_errno,
312  Sql_condition::enum_warning_level level) const
313 {
314  sp_handler *found_handler= NULL;
315  sp_condition_value *found_cv= NULL;
316 
317  for (int i= 0; i < m_handlers.elements(); ++i)
318  {
319  sp_handler *h= m_handlers.at(i);
320 
322  sp_condition_value *cv;
323 
324  while ((cv= li++))
325  {
326  switch (cv->type)
327  {
328  case sp_condition_value::ERROR_CODE:
329  if (sql_errno == cv->mysqlerr &&
330  (!found_cv ||
331  found_cv->type > sp_condition_value::ERROR_CODE))
332  {
333  found_cv= cv;
334  found_handler= h;
335  }
336  break;
337 
338  case sp_condition_value::SQLSTATE:
339  if (strcmp(sql_state, cv->sql_state) == 0 &&
340  (!found_cv ||
341  found_cv->type > sp_condition_value::SQLSTATE))
342  {
343  found_cv= cv;
344  found_handler= h;
345  }
346  break;
347 
348  case sp_condition_value::WARNING:
349  if ((is_sqlstate_warning(sql_state) ||
350  level == Sql_condition::WARN_LEVEL_WARN) && !found_cv)
351  {
352  found_cv= cv;
353  found_handler= h;
354  }
355  break;
356 
357  case sp_condition_value::NOT_FOUND:
358  if (is_sqlstate_not_found(sql_state) && !found_cv)
359  {
360  found_cv= cv;
361  found_handler= h;
362  }
363  break;
364 
365  case sp_condition_value::EXCEPTION:
366  if (is_sqlstate_exception(sql_state) &&
367  level == Sql_condition::WARN_LEVEL_ERROR && !found_cv)
368  {
369  found_cv= cv;
370  found_handler= h;
371  }
372  break;
373  }
374  }
375  }
376 
377  if (found_handler)
378  return found_handler;
379 
380 
381  // There is no appropriate handler in this parsing context. We need to look up
382  // in parent contexts. There might be two cases here:
383  //
384  // 1. The current context has REGULAR_SCOPE. That means, it's a simple
385  // BEGIN..END block:
386  // ...
387  // BEGIN
388  // ... # We're here.
389  // END
390  // ...
391  // In this case we simply call find_handler() on parent's context recursively.
392  //
393  // 2. The current context has HANDLER_SCOPE. That means, we're inside an
394  // SQL-handler block:
395  // ...
396  // DECLARE ... HANDLER FOR ...
397  // BEGIN
398  // ... # We're here.
399  // END
400  // ...
401  // In this case we can not just call parent's find_handler(), because
402  // parent's handler don't catch conditions from this scope. Instead, we should
403  // try to find first parent context (we might have nested handler
404  // declarations), which has REGULAR_SCOPE (i.e. which is regular BEGIN..END
405  // block).
406 
407  const sp_pcontext *p= this;
408 
409  while (p && p->m_scope == HANDLER_SCOPE)
410  p= p->m_parent;
411 
412  if (!p || !p->m_parent)
413  return NULL;
414 
415  return p->m_parent->find_handler(sql_state, sql_errno, level);
416 }
417 
418 
419 bool sp_pcontext::add_cursor(LEX_STRING name)
420 {
421  if (m_cursors.elements() == (int) m_max_cursor_index)
422  ++m_max_cursor_index;
423 
424  return m_cursors.append(name);
425 }
426 
427 
429  uint *poff,
430  bool current_scope_only) const
431 {
432  uint i= m_cursors.elements();
433 
434  while (i--)
435  {
436  LEX_STRING n= m_cursors.at(i);
437 
438  if (my_strnncoll(system_charset_info,
439  (const uchar *) name.str, name.length,
440  (const uchar *) n.str, n.length) == 0)
441  {
442  *poff= m_cursor_offset + i;
443  return true;
444  }
445  }
446 
447  return (!current_scope_only && m_parent) ?
448  m_parent->find_cursor(name, poff, false) :
449  false;
450 }
451 
452 
454  List<Create_field> *field_def_lst) const
455 {
456  /* Put local/context fields in the result list. */
457 
458  for (int i= 0; i < m_vars.elements(); ++i)
459  {
460  sp_variable *var_def= m_vars.at(i);
461 
462  field_def_lst->push_back(&var_def->field_def);
463  }
464 
465  /* Put the fields of the enclosed contexts in the result list. */
466 
467  for (int i= 0; i < m_children.elements(); ++i)
468  m_children.at(i)->retrieve_field_definitions(field_def_lst);
469 }
470 
471 
473 {
474  if (m_cursor_offset <= offset &&
475  offset < m_cursor_offset + m_cursors.elements())
476  {
477  return &m_cursors.at(offset - m_cursor_offset); // This frame
478  }
479 
480  return m_parent ?
481  m_parent->find_cursor(offset) : // Some previous frame
482  NULL; // Index out of bounds
483 }