MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
sql_signal.cc
1 /* Copyright (c) 2008, 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
14  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15 
16 #include "sql_priv.h"
17 #include "sp_head.h"
18 #include "sp_pcontext.h"
19 #include "sp_rcontext.h"
20 #include "sql_signal.h"
21 
22 /*
23  The parser accepts any error code (desired)
24  The runtime internally supports any error code (desired)
25  The client server protocol is limited to 16 bits error codes (restriction)
26  Enforcing the 65535 limit in the runtime until the protocol can change.
27 */
28 #define MAX_MYSQL_ERRNO UINT_MAX16
29 
30 const LEX_STRING Diag_condition_item_names[]=
31 {
32  { C_STRING_WITH_LEN("CLASS_ORIGIN") },
33  { C_STRING_WITH_LEN("SUBCLASS_ORIGIN") },
34  { C_STRING_WITH_LEN("CONSTRAINT_CATALOG") },
35  { C_STRING_WITH_LEN("CONSTRAINT_SCHEMA") },
36  { C_STRING_WITH_LEN("CONSTRAINT_NAME") },
37  { C_STRING_WITH_LEN("CATALOG_NAME") },
38  { C_STRING_WITH_LEN("SCHEMA_NAME") },
39  { C_STRING_WITH_LEN("TABLE_NAME") },
40  { C_STRING_WITH_LEN("COLUMN_NAME") },
41  { C_STRING_WITH_LEN("CURSOR_NAME") },
42  { C_STRING_WITH_LEN("MESSAGE_TEXT") },
43  { C_STRING_WITH_LEN("MYSQL_ERRNO") },
44 
45  { C_STRING_WITH_LEN("CONDITION_IDENTIFIER") },
46  { C_STRING_WITH_LEN("CONDITION_NUMBER") },
47  { C_STRING_WITH_LEN("CONNECTION_NAME") },
48  { C_STRING_WITH_LEN("MESSAGE_LENGTH") },
49  { C_STRING_WITH_LEN("MESSAGE_OCTET_LENGTH") },
50  { C_STRING_WITH_LEN("PARAMETER_MODE") },
51  { C_STRING_WITH_LEN("PARAMETER_NAME") },
52  { C_STRING_WITH_LEN("PARAMETER_ORDINAL_POSITION") },
53  { C_STRING_WITH_LEN("RETURNED_SQLSTATE") },
54  { C_STRING_WITH_LEN("ROUTINE_CATALOG") },
55  { C_STRING_WITH_LEN("ROUTINE_NAME") },
56  { C_STRING_WITH_LEN("ROUTINE_SCHEMA") },
57  { C_STRING_WITH_LEN("SERVER_NAME") },
58  { C_STRING_WITH_LEN("SPECIFIC_NAME") },
59  { C_STRING_WITH_LEN("TRIGGER_CATALOG") },
60  { C_STRING_WITH_LEN("TRIGGER_NAME") },
61  { C_STRING_WITH_LEN("TRIGGER_SCHEMA") }
62 };
63 
64 const LEX_STRING Diag_statement_item_names[]=
65 {
66  { C_STRING_WITH_LEN("NUMBER") },
67  { C_STRING_WITH_LEN("MORE") },
68  { C_STRING_WITH_LEN("COMMAND_FUNCTION") },
69  { C_STRING_WITH_LEN("COMMAND_FUNCTION_CODE") },
70  { C_STRING_WITH_LEN("DYNAMIC_FUNCTION") },
71  { C_STRING_WITH_LEN("DYNAMIC_FUNCTION_CODE") },
72  { C_STRING_WITH_LEN("ROW_COUNT") },
73  { C_STRING_WITH_LEN("TRANSACTIONS_COMMITTED") },
74  { C_STRING_WITH_LEN("TRANSACTIONS_ROLLED_BACK") },
75  { C_STRING_WITH_LEN("TRANSACTION_ACTIVE") }
76 };
77 
78 
79 Set_signal_information::Set_signal_information(
80  const Set_signal_information& set)
81 {
82  memcpy(m_item, set.m_item, sizeof(m_item));
83 }
84 
85 void Set_signal_information::clear()
86 {
87  memset(m_item, 0, sizeof(m_item));
88 }
89 
91  Sql_condition *cond,
92  bool set_level_code,
93  Sql_condition::enum_warning_level level,
94  int sqlcode)
95 {
96  if (set_level_code)
97  {
98  cond->m_level= level;
99  cond->m_sql_errno= sqlcode;
100  }
101  if (! cond->get_message_text())
102  cond->set_builtin_message_text(ER(sqlcode));
103 }
104 
106 {
107  DBUG_ASSERT(cond);
108 
109  const char* sqlstate;
110  bool set_defaults= (m_cond != 0);
111 
112  if (set_defaults)
113  {
114  /*
115  SIGNAL is restricted in sql_yacc.yy to only signal SQLSTATE conditions.
116  */
117  DBUG_ASSERT(m_cond->type == sp_condition_value::SQLSTATE);
118  sqlstate= m_cond->sql_state;
119  cond->set_sqlstate(sqlstate);
120  }
121  else
122  sqlstate= cond->get_sqlstate();
123 
124  DBUG_ASSERT(sqlstate);
125  /* SQLSTATE class "00": illegal, rejected in the parser. */
126  DBUG_ASSERT((sqlstate[0] != '0') || (sqlstate[1] != '0'));
127 
128  if ((sqlstate[0] == '0') && (sqlstate[1] == '1'))
129  {
130  /* SQLSTATE class "01": warning. */
131  assign_defaults(cond, set_defaults,
132  Sql_condition::WARN_LEVEL_WARN, ER_SIGNAL_WARN);
133  }
134  else if ((sqlstate[0] == '0') && (sqlstate[1] == '2'))
135  {
136  /* SQLSTATE class "02": not found. */
137  assign_defaults(cond, set_defaults,
138  Sql_condition::WARN_LEVEL_ERROR, ER_SIGNAL_NOT_FOUND);
139  }
140  else
141  {
142  /* other SQLSTATE classes : error. */
143  assign_defaults(cond, set_defaults,
144  Sql_condition::WARN_LEVEL_ERROR, ER_SIGNAL_EXCEPTION);
145  }
146 }
147 
148 static bool assign_fixed_string(MEM_ROOT *mem_root,
149  CHARSET_INFO *dst_cs,
150  size_t max_char,
151  String *dst,
152  const String* src)
153 {
154  bool truncated;
155  size_t numchars;
156  const CHARSET_INFO *src_cs;
157  const char* src_str;
158  const char* src_end;
159  size_t src_len;
160  size_t to_copy;
161  char* dst_str;
162  size_t dst_len;
163  size_t dst_copied;
164  uint32 dummy_offset;
165 
166  src_str= src->ptr();
167  if (src_str == NULL)
168  {
169  dst->set((const char*) NULL, 0, dst_cs);
170  return false;
171  }
172 
173  src_cs= src->charset();
174  src_len= src->length();
175  src_end= src_str + src_len;
176  numchars= src_cs->cset->numchars(src_cs, src_str, src_end);
177 
178  if (numchars <= max_char)
179  {
180  to_copy= src->length();
181  truncated= false;
182  }
183  else
184  {
185  numchars= max_char;
186  to_copy= dst_cs->cset->charpos(dst_cs, src_str, src_end, numchars);
187  truncated= true;
188  }
189 
190  if (String::needs_conversion(to_copy, src_cs, dst_cs, & dummy_offset))
191  {
192  dst_len= numchars * dst_cs->mbmaxlen;
193  dst_str= (char*) alloc_root(mem_root, dst_len + 1);
194  if (dst_str)
195  {
196  const char* well_formed_error_pos;
197  const char* cannot_convert_error_pos;
198  const char* from_end_pos;
199 
200  dst_copied= well_formed_copy_nchars(dst_cs, dst_str, dst_len,
201  src_cs, src_str, src_len,
202  numchars,
203  & well_formed_error_pos,
204  & cannot_convert_error_pos,
205  & from_end_pos);
206  DBUG_ASSERT(dst_copied <= dst_len);
207  dst_len= dst_copied; /* In case the copy truncated the data */
208  dst_str[dst_copied]= '\0';
209  }
210  }
211  else
212  {
213  dst_len= to_copy;
214  dst_str= (char*) alloc_root(mem_root, dst_len + 1);
215  if (dst_str)
216  {
217  memcpy(dst_str, src_str, to_copy);
218  dst_str[to_copy]= '\0';
219  }
220  }
221  dst->set(dst_str, dst_len, dst_cs);
222 
223  return truncated;
224 }
225 
226 static int assign_condition_item(MEM_ROOT *mem_root, const char* name, THD *thd,
227  Item *set, String *ci)
228 {
229  char str_buff[(64+1)*4]; /* Room for a null terminated UTF8 String 64 */
230  String str_value(str_buff, sizeof(str_buff), & my_charset_utf8_bin);
231  String *str;
232  bool truncated;
233 
234  DBUG_ENTER("assign_condition_item");
235 
236  if (set->is_null())
237  {
238  thd->raise_error_printf(ER_WRONG_VALUE_FOR_VAR, name, "NULL");
239  DBUG_RETURN(1);
240  }
241 
242  str= set->val_str(& str_value);
243  truncated= assign_fixed_string(mem_root, & my_charset_utf8_bin, 64, ci, str);
244  if (truncated)
245  {
246  if (thd->is_strict_mode())
247  {
248  thd->raise_error_printf(ER_COND_ITEM_TOO_LONG, name);
249  DBUG_RETURN(1);
250  }
251 
252  thd->raise_warning_printf(WARN_COND_ITEM_TRUNCATED, name);
253  }
254 
255  DBUG_RETURN(0);
256 }
257 
258 
260 {
261  struct cond_item_map
262  {
263  enum enum_diag_condition_item_name m_item;
264  String Sql_condition::*m_member;
265  };
266 
267  static cond_item_map map[]=
268  {
269  { DIAG_CLASS_ORIGIN, & Sql_condition::m_class_origin },
270  { DIAG_SUBCLASS_ORIGIN, & Sql_condition::m_subclass_origin },
271  { DIAG_CONSTRAINT_CATALOG, & Sql_condition::m_constraint_catalog },
272  { DIAG_CONSTRAINT_SCHEMA, & Sql_condition::m_constraint_schema },
273  { DIAG_CONSTRAINT_NAME, & Sql_condition::m_constraint_name },
274  { DIAG_CATALOG_NAME, & Sql_condition::m_catalog_name },
275  { DIAG_SCHEMA_NAME, & Sql_condition::m_schema_name },
276  { DIAG_TABLE_NAME, & Sql_condition::m_table_name },
277  { DIAG_COLUMN_NAME, & Sql_condition::m_column_name },
278  { DIAG_CURSOR_NAME, & Sql_condition::m_cursor_name }
279  };
280 
281  Item *set;
282  String str_value;
283  String *str;
284  int i;
285  uint j;
286  int result= 1;
287  enum enum_diag_condition_item_name item_enum;
288  String *member;
289  const LEX_STRING *name;
290 
291  DBUG_ENTER("Sql_cmd_common_signal::eval_signal_informations");
292 
293  for (i= FIRST_DIAG_SET_PROPERTY;
294  i <= LAST_DIAG_SET_PROPERTY;
295  i++)
296  {
297  set= m_set_signal_information.m_item[i];
298  if (set)
299  {
300  if (! set->fixed)
301  {
302  if (set->fix_fields(thd, & set))
303  goto end;
304  m_set_signal_information.m_item[i]= set;
305  }
306  }
307  }
308 
309  /*
310  Generically assign all the UTF8 String 64 condition items
311  described in the map.
312  */
313  for (j= 0; j < array_elements(map); j++)
314  {
315  item_enum= map[j].m_item;
316  set= m_set_signal_information.m_item[item_enum];
317  if (set != NULL)
318  {
319  member= & (cond->* map[j].m_member);
320  name= & Diag_condition_item_names[item_enum];
321  if (assign_condition_item(cond->m_mem_root, name->str, thd, set, member))
322  goto end;
323  }
324  }
325 
326  /*
327  Assign the remaining attributes.
328  */
329 
330  set= m_set_signal_information.m_item[DIAG_MESSAGE_TEXT];
331  if (set != NULL)
332  {
333  if (set->is_null())
334  {
335  thd->raise_error_printf(ER_WRONG_VALUE_FOR_VAR,
336  "MESSAGE_TEXT", "NULL");
337  goto end;
338  }
339  /*
340  Enforce that SET MESSAGE_TEXT = <value> evaluates the value
341  as VARCHAR(128) CHARACTER SET UTF8.
342  */
343  bool truncated;
344  String utf8_text;
345  str= set->val_str(& str_value);
346  truncated= assign_fixed_string(thd->mem_root, & my_charset_utf8_bin, 128,
347  & utf8_text, str);
348  if (truncated)
349  {
350  if (thd->is_strict_mode())
351  {
352  thd->raise_error_printf(ER_COND_ITEM_TOO_LONG,
353  "MESSAGE_TEXT");
354  goto end;
355  }
356 
357  thd->raise_warning_printf(WARN_COND_ITEM_TRUNCATED,
358  "MESSAGE_TEXT");
359  }
360 
361  /*
362  See the comments
363  "Design notes about Sql_condition::m_message_text."
364  in file sql_error.cc
365  */
366  String converted_text;
367  converted_text.set_charset(error_message_charset_info);
368  converted_text.append(utf8_text.ptr(), utf8_text.length(),
369  utf8_text.charset());
370  cond->set_builtin_message_text(converted_text.c_ptr_safe());
371  }
372 
373  set= m_set_signal_information.m_item[DIAG_MYSQL_ERRNO];
374  if (set != NULL)
375  {
376  if (set->is_null())
377  {
378  thd->raise_error_printf(ER_WRONG_VALUE_FOR_VAR,
379  "MYSQL_ERRNO", "NULL");
380  goto end;
381  }
382  longlong code= set->val_int();
383  if ((code <= 0) || (code > MAX_MYSQL_ERRNO))
384  {
385  str= set->val_str(& str_value);
386  thd->raise_error_printf(ER_WRONG_VALUE_FOR_VAR,
387  "MYSQL_ERRNO", str->c_ptr_safe());
388  goto end;
389  }
390  cond->m_sql_errno= (int) code;
391  }
392 
393  /*
394  The various item->val_xxx() methods don't return an error code,
395  but flag thd in case of failure.
396  */
397  if (! thd->is_error())
398  result= 0;
399 
400 end:
401  for (i= FIRST_DIAG_SET_PROPERTY;
402  i <= LAST_DIAG_SET_PROPERTY;
403  i++)
404  {
405  set= m_set_signal_information.m_item[i];
406  if (set)
407  {
408  if (set->fixed)
409  set->cleanup();
410  }
411  }
412 
413  DBUG_RETURN(result);
414 }
415 
417 {
418  bool result= TRUE;
419 
420  DBUG_ENTER("Sql_cmd_common_signal::raise_condition");
421 
422  DBUG_ASSERT(thd->lex->query_tables == NULL);
423 
424  eval_defaults(thd, cond);
425  if (eval_signal_informations(thd, cond))
426  DBUG_RETURN(result);
427 
428  /* SIGNAL should not signal WARN_LEVEL_NOTE */
429  DBUG_ASSERT((cond->m_level == Sql_condition::WARN_LEVEL_WARN) ||
430  (cond->m_level == Sql_condition::WARN_LEVEL_ERROR));
431 
432  Sql_condition *raised= NULL;
433  raised= thd->raise_condition(cond->get_sql_errno(),
434  cond->get_sqlstate(),
435  cond->get_level(),
436  cond->get_message_text());
437  if (raised)
438  raised->copy_opt_attributes(cond);
439 
440  if (cond->m_level == Sql_condition::WARN_LEVEL_WARN)
441  {
442  my_ok(thd);
443  result= FALSE;
444  }
445 
446  DBUG_RETURN(result);
447 }
448 
450 {
451  bool result= TRUE;
452  Sql_condition cond(thd->mem_root);
453 
454  DBUG_ENTER("Sql_cmd_signal::execute");
455 
456  /*
457  WL#2110 SIGNAL specification says:
458 
459  When SIGNAL is executed, it has five effects, in the following order:
460 
461  (1) First, the diagnostics area is completely cleared. So if the
462  SIGNAL is in a DECLARE HANDLER then any pending errors or warnings
463  are gone. So is 'row count'.
464 
465  This has roots in the SQL standard specification for SIGNAL.
466  */
467 
468  thd->get_stmt_da()->reset_diagnostics_area();
469  thd->set_row_count_func(0);
470  thd->get_stmt_da()->clear_warning_info(thd->query_id);
471 
472  result= raise_condition(thd, &cond);
473 
474  DBUG_RETURN(result);
475 }
476 
477 
489 {
490  Diagnostics_area *da= thd->get_stmt_da();
491  const sp_rcontext::Sql_condition_info *signaled;
492 
493  DBUG_ENTER("Sql_cmd_resignal::execute");
494 
495  // This is a way to force sql_conditions from the current Warning_info to be
496  // passed to the caller's Warning_info.
497  da->set_warning_info_id(thd->query_id);
498 
499  if (! thd->sp_runtime_ctx ||
500  ! (signaled= thd->sp_runtime_ctx->raised_condition()))
501  {
502  thd->raise_error(ER_RESIGNAL_WITHOUT_ACTIVE_HANDLER);
503  DBUG_RETURN(true);
504  }
505 
506  Sql_condition signaled_err(thd->mem_root);
507  signaled_err.set(signaled->sql_errno,
508  signaled->sql_state,
509  signaled->level,
510  signaled->message);
511 
512 
513  if (m_cond) // RESIGNAL with signal_value.
514  {
515  query_cache_abort(&thd->query_cache_tls);
516 
517  /* Keep handled conditions. */
518  da->unmark_sql_conditions_from_removal();
519 
520  /* Check if the old condition still exists. */
521  if (da->has_sql_condition(signaled->message, strlen(signaled->message)))
522  {
523  /* Make room for the new RESIGNAL condition. */
524  da->reserve_space(thd, 1);
525  }
526  else
527  {
528  /* Make room for old condition + the new RESIGNAL condition. */
529  da->reserve_space(thd, 2);
530 
531  da->push_warning(thd, &signaled_err);
532  }
533  }
534 
535  DBUG_RETURN(raise_condition(thd, &signaled_err));
536 }