MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
sql_error.cc
1 /* Copyright (c) 2002, 2013, 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 /**********************************************************************
17 This file contains the implementation of error and warnings related
18 
19  - Whenever an error or warning occurred, it pushes it to a warning list
20  that the user can retrieve with SHOW WARNINGS or SHOW ERRORS.
21 
22  - For each statement, we return the number of warnings generated from this
23  command. Note that this can be different from @@warning_count as
24  we reset the warning list only for questions that uses a table.
25  This is done to allow on to do:
26  INSERT ...;
27  SELECT @@warning_count;
28  SHOW WARNINGS;
29  (If we would reset after each command, we could not retrieve the number
30  of warnings)
31 
32  - When client requests the information using SHOW command, then
33  server processes from this list and returns back in the form of
34  resultset.
35 
36  Supported syntaxes:
37 
38  SHOW [COUNT(*)] ERRORS [LIMIT [offset,] rows]
39  SHOW [COUNT(*)] WARNINGS [LIMIT [offset,] rows]
40  SELECT @@warning_count, @@error_count;
41 
42 ***********************************************************************/
43 
44 #include "sql_priv.h"
45 #include "unireg.h"
46 #include "sql_error.h"
47 #include "sp_rcontext.h"
48 
49 using std::min;
50 using std::max;
51 
52 /*
53  Design notes about Sql_condition::m_message_text.
54 
55  The member Sql_condition::m_message_text contains the text associated with
56  an error, warning or note (which are all SQL 'conditions')
57 
58  Producer of Sql_condition::m_message_text:
59  ----------------------------------------
60 
61  (#1) the server implementation itself, when invoking functions like
62  my_error() or push_warning()
63 
64  (#2) user code in stored programs, when using the SIGNAL statement.
65 
66  (#3) user code in stored programs, when using the RESIGNAL statement.
67 
68  When invoking my_error(), the error number and message is typically
69  provided like this:
70  - my_error(ER_WRONG_DB_NAME, MYF(0), ...);
71  - my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
72 
73  In both cases, the message is retrieved from ER(ER_XXX), which in turn
74  is read from the resource file errmsg.sys at server startup.
75  The strings stored in the errmsg.sys file are expressed in the character set
76  that corresponds to the server --language start option
77  (see error_message_charset_info).
78 
79  When executing:
80  - a SIGNAL statement,
81  - a RESIGNAL statement,
82  the message text is provided by the user logic, and is expressed in UTF8.
83 
84  Storage of Sql_condition::m_message_text:
85  ---------------------------------------
86 
87  (#4) The class Sql_condition is used to hold the message text member.
88  This class represents a single SQL condition.
89 
90  (#5) The class Warning_info represents a SQL condition area, and contains
91  a collection of SQL conditions in the Warning_info::m_warn_list
92 
93  Consumer of Sql_condition::m_message_text:
94  ----------------------------------------
95 
96  (#6) The statements SHOW WARNINGS and SHOW ERRORS display the content of
97  the warning list.
98 
99  (#7) The GET DIAGNOSTICS statement reads the content of:
100  - the top level statement condition area (when executed in a query),
101  - a sub statement (when executed in a stored program)
102  and return the data stored in a Sql_condition.
103 
104  (#8) The RESIGNAL statement reads the Sql_condition caught by an exception
105  handler, to raise a new or modified condition (in #3).
106 
107  The big picture
108  ---------------
109  --------------
110  | ^
111  V |
112  my_error(#1) SIGNAL(#2) RESIGNAL(#3) |
113  |(#A) |(#B) |(#C) |
114  | | | |
115  ----------------------------|---------------------------- |
116  | |
117  V |
118  Sql_condition(#4) |
119  | |
120  | |
121  V |
122  Warning_info(#5) |
123  | |
124  ----------------------------------------------------- |
125  | | | |
126  | | | |
127  | | | |
128  V V V |
129  SHOW WARNINGS(#6) GET DIAGNOSTICS(#7) RESIGNAL(#8) |
130  | | | | |
131  | -------- | V |
132  | | | --------------
133  V | |
134  Connectors | |
135  | | |
136  -------------------------
137  |
138  V
139  Client application
140 
141  Current implementation status
142  -----------------------------
143 
144  (#1) (my_error) produces data in the 'error_message_charset_info' CHARSET
145 
146  (#2) and (#3) (SIGNAL, RESIGNAL) produces data internally in UTF8
147 
148  (#6) (SHOW WARNINGS) produces data in the 'error_message_charset_info' CHARSET
149 
150  (#7) (GET DIAGNOSTICS) is implemented.
151 
152  (#8) (RESIGNAL) produces data internally in UTF8 (see #3)
153 
154  As a result, the design choice for (#4) and (#5) is to store data in
155  the 'error_message_charset_info' CHARSET, to minimize impact on the code base.
156  This is implemented by using 'String Sql_condition::m_message_text'.
157 
158  The UTF8 -> error_message_charset_info conversion is implemented in
159  Sql_cmd_common_signal::eval_signal_informations() (for path #B and #C).
160 
161  Future work
162  -----------
163 
164  - Change (#1) (my_error) to generate errors in UTF8.
165  See WL#751 (Recoding of error messages)
166 
167  - Change (#4 and #5) to store message text in UTF8 natively.
168  In practice, this means changing the type of the message text to
169  '<UTF8 String 128 class> Sql_condition::m_message_text', and is a direct
170  consequence of WL#751.
171 */
172 
173 Sql_condition::Sql_condition()
174  : Sql_alloc(),
175  m_class_origin((const char*) NULL, 0, & my_charset_utf8_bin),
176  m_subclass_origin((const char*) NULL, 0, & my_charset_utf8_bin),
177  m_constraint_catalog((const char*) NULL, 0, & my_charset_utf8_bin),
178  m_constraint_schema((const char*) NULL, 0, & my_charset_utf8_bin),
179  m_constraint_name((const char*) NULL, 0, & my_charset_utf8_bin),
180  m_catalog_name((const char*) NULL, 0, & my_charset_utf8_bin),
181  m_schema_name((const char*) NULL, 0, & my_charset_utf8_bin),
182  m_table_name((const char*) NULL, 0, & my_charset_utf8_bin),
183  m_column_name((const char*) NULL, 0, & my_charset_utf8_bin),
184  m_cursor_name((const char*) NULL, 0, & my_charset_utf8_bin),
185  m_message_text(),
186  m_sql_errno(0),
187  m_level(Sql_condition::WARN_LEVEL_ERROR),
188  m_mem_root(NULL)
189 {
190  memset(m_returned_sqlstate, 0, sizeof(m_returned_sqlstate));
191 }
192 
193 void Sql_condition::init(MEM_ROOT *mem_root)
194 {
195  DBUG_ASSERT(mem_root != NULL);
196  DBUG_ASSERT(m_mem_root == NULL);
197  m_mem_root= mem_root;
198 }
199 
200 void Sql_condition::clear()
201 {
202  m_class_origin.length(0);
203  m_subclass_origin.length(0);
204  m_constraint_catalog.length(0);
205  m_constraint_schema.length(0);
206  m_constraint_name.length(0);
207  m_catalog_name.length(0);
208  m_schema_name.length(0);
209  m_table_name.length(0);
210  m_column_name.length(0);
211  m_cursor_name.length(0);
212  m_message_text.length(0);
213  m_sql_errno= 0;
214  m_level= Sql_condition::WARN_LEVEL_ERROR;
215 }
216 
217 Sql_condition::Sql_condition(MEM_ROOT *mem_root)
218  : Sql_alloc(),
219  m_class_origin((const char*) NULL, 0, & my_charset_utf8_bin),
220  m_subclass_origin((const char*) NULL, 0, & my_charset_utf8_bin),
221  m_constraint_catalog((const char*) NULL, 0, & my_charset_utf8_bin),
222  m_constraint_schema((const char*) NULL, 0, & my_charset_utf8_bin),
223  m_constraint_name((const char*) NULL, 0, & my_charset_utf8_bin),
224  m_catalog_name((const char*) NULL, 0, & my_charset_utf8_bin),
225  m_schema_name((const char*) NULL, 0, & my_charset_utf8_bin),
226  m_table_name((const char*) NULL, 0, & my_charset_utf8_bin),
227  m_column_name((const char*) NULL, 0, & my_charset_utf8_bin),
228  m_cursor_name((const char*) NULL, 0, & my_charset_utf8_bin),
229  m_message_text(),
230  m_sql_errno(0),
231  m_level(Sql_condition::WARN_LEVEL_ERROR),
232  m_mem_root(mem_root)
233 {
234  DBUG_ASSERT(mem_root != NULL);
235  memset(m_returned_sqlstate, 0, sizeof(m_returned_sqlstate));
236 }
237 
238 static void copy_string(MEM_ROOT *mem_root, String* dst, const String* src)
239 {
240  size_t len= src->length();
241  if (len)
242  {
243  char* copy= (char*) alloc_root(mem_root, len + 1);
244  if (copy)
245  {
246  memcpy(copy, src->ptr(), len);
247  copy[len]= '\0';
248  dst->set(copy, len, src->charset());
249  }
250  }
251  else
252  dst->length(0);
253 }
254 
255 void
256 Sql_condition::copy_opt_attributes(const Sql_condition *cond)
257 {
258  DBUG_ASSERT(this != cond);
259  copy_string(m_mem_root, & m_class_origin, & cond->m_class_origin);
260  copy_string(m_mem_root, & m_subclass_origin, & cond->m_subclass_origin);
261  copy_string(m_mem_root, & m_constraint_catalog, & cond->m_constraint_catalog);
262  copy_string(m_mem_root, & m_constraint_schema, & cond->m_constraint_schema);
263  copy_string(m_mem_root, & m_constraint_name, & cond->m_constraint_name);
264  copy_string(m_mem_root, & m_catalog_name, & cond->m_catalog_name);
265  copy_string(m_mem_root, & m_schema_name, & cond->m_schema_name);
266  copy_string(m_mem_root, & m_table_name, & cond->m_table_name);
267  copy_string(m_mem_root, & m_column_name, & cond->m_column_name);
268  copy_string(m_mem_root, & m_cursor_name, & cond->m_cursor_name);
269 }
270 
271 void
272 Sql_condition::set(uint sql_errno, const char* sqlstate,
273  Sql_condition::enum_warning_level level, const char* msg)
274 {
275  DBUG_ASSERT(sql_errno != 0);
276  DBUG_ASSERT(sqlstate != NULL);
277  DBUG_ASSERT(msg != NULL);
278 
279  m_sql_errno= sql_errno;
280  memcpy(m_returned_sqlstate, sqlstate, SQLSTATE_LENGTH);
281  m_returned_sqlstate[SQLSTATE_LENGTH]= '\0';
282 
283  set_class_origins();
284  set_builtin_message_text(msg);
285  m_level= level;
286 }
287 
288 void
289 Sql_condition::set_builtin_message_text(const char* str)
290 {
291  /*
292  See the comments
293  "Design notes about Sql_condition::m_message_text."
294  */
295  const char* copy;
296 
297  copy= strdup_root(m_mem_root, str);
298  m_message_text.set(copy, strlen(copy), error_message_charset_info);
299  DBUG_ASSERT(! m_message_text.is_alloced());
300 }
301 
302 const char*
304 {
305  return m_message_text.ptr();
306 }
307 
308 int
310 {
311  return m_message_text.length();
312 }
313 
314 void
315 Sql_condition::set_sqlstate(const char* sqlstate)
316 {
317  memcpy(m_returned_sqlstate, sqlstate, SQLSTATE_LENGTH);
318  m_returned_sqlstate[SQLSTATE_LENGTH]= '\0';
319 }
320 
321 static LEX_CSTRING sqlstate_origin[]= {
322  { STRING_WITH_LEN("ISO 9075") },
323  { STRING_WITH_LEN("MySQL") }
324 };
325 
326 void Sql_condition::set_class_origins()
327 {
328  char cls[2];
329 
330  /* Let CLASS = the first two letters of RETURNED_SQLSTATE. */
331  cls[0]= m_returned_sqlstate[0];
332  cls[1]= m_returned_sqlstate[1];
333 
334  /* Only digits and upper case latin letter are allowed. */
335  DBUG_ASSERT(my_isdigit(&my_charset_latin1, cls[0]) ||
336  my_isupper(&my_charset_latin1, cls[0]));
337 
338  DBUG_ASSERT(my_isdigit(&my_charset_latin1, cls[1]) ||
339  my_isupper(&my_charset_latin1, cls[1]));
340 
341  /*
342  If CLASS[1] is any of: 0 1 2 3 4 A B C D E F G H
343  and CLASS[2] is any of: 0-9 A-Z,
344  then let CLASS_ORIGIN = 'ISO 9075'. Otherwise 'MySQL'.
345 
346  Let SUBCLASS = the next three letters of RETURNED_SQLSTATE.
347  If CLASS_ORIGIN = 'ISO 9075' or SUBCLASS = '000',
348  then let SUBCLASS_ORIGIN = 'ISO 9075'. Otherwise 'MySQL'.
349  */
350  if (((cls[0] >= '0' && cls[0] <= '4') || (cls[0] >= 'A' && cls[0] <= 'H')) &&
351  ((cls[1] >= '0' && cls[1] <= '9') || (cls[1] >= 'A' && cls[1] <= 'Z')))
352  {
353  // ISO 9075
354  m_class_origin.set_ascii(sqlstate_origin[0].str,
355  sqlstate_origin[0].length);
356  // ISO 9075
357  m_subclass_origin.set_ascii(sqlstate_origin[0].str,
358  sqlstate_origin[0].length);
359  }
360  else
361  {
362  // MySQL
363  m_class_origin.set_ascii(sqlstate_origin[1].str, sqlstate_origin[1].length);
364  if (!memcmp(m_returned_sqlstate + 2, STRING_WITH_LEN("000")))
365  // ISO 9075
366  m_subclass_origin.set_ascii(sqlstate_origin[0].str,
367  sqlstate_origin[0].length);
368  else
369  // MySQL
370  m_subclass_origin.set_ascii(sqlstate_origin[1].str,
371  sqlstate_origin[1].length);
372  }
373 }
374 
375 Diagnostics_area::Diagnostics_area()
376  : m_main_wi(0, false)
377 {
378  push_warning_info(&m_main_wi);
379 
380  reset_diagnostics_area();
381 }
382 
383 Diagnostics_area::Diagnostics_area(ulonglong warning_info_id,
384  bool allow_unlimited_warnings)
385  : m_main_wi(warning_info_id, allow_unlimited_warnings)
386 {
387  push_warning_info(&m_main_wi);
388 
389  reset_diagnostics_area();
390 }
391 
398 void
400 {
401  DBUG_ENTER("reset_diagnostics_area");
402 #ifdef DBUG_OFF
403  set_overwrite_status(false);
405  m_message[0]= '\0';
406  m_sql_errno= 0;
407  m_affected_rows= 0;
408  m_last_insert_id= 0;
409  m_statement_warn_count= 0;
410 #endif
411  get_warning_info()->clear_error_condition();
412  set_is_sent(false);
414  m_status= DA_EMPTY;
415  DBUG_VOID_RETURN;
416 }
417 
418 
424 void
425 Diagnostics_area::set_ok_status(ulonglong affected_rows,
426  ulonglong last_insert_id,
427  const char *message)
428 {
429  DBUG_ENTER("set_ok_status");
430  DBUG_ASSERT(! is_set());
431  /*
432  In production, refuse to overwrite an error or a custom response
433  with an OK packet.
434  */
435  if (is_error() || is_disabled())
436  return;
437 
438  m_statement_warn_count= current_statement_warn_count();
439  m_affected_rows= affected_rows;
440  m_last_insert_id= last_insert_id;
441  if (message)
442  strmake(m_message, message, sizeof(m_message) - 1);
443  else
444  m_message[0]= '\0';
445  m_status= DA_OK;
446  DBUG_VOID_RETURN;
447 }
448 
449 
454 void
456 {
457  DBUG_ENTER("set_eof_status");
458  /* Only allowed to report eof if has not yet reported an error */
459  DBUG_ASSERT(! is_set());
460  /*
461  In production, refuse to overwrite an error or a custom response
462  with an EOF packet.
463  */
464  if (is_error() || is_disabled())
465  return;
466 
467  /*
468  If inside a stored procedure, do not return the total
469  number of warnings, since they are not available to the client
470  anyway.
471  */
472  m_statement_warn_count= (thd->sp_runtime_ctx ?
473  0 :
474  current_statement_warn_count());
475 
476  m_status= DA_EOF;
477  DBUG_VOID_RETURN;
478 }
479 
488 void
490 {
491  set_error_status(sql_errno,
492  ER(sql_errno),
493  mysql_errno_to_sqlstate(sql_errno),
494  NULL);
495 }
496 
509 void
511  const char *message,
512  const char *sqlstate,
513  const Sql_condition *error_condition)
514 {
515  DBUG_ENTER("set_error_status");
516  /*
517  Only allowed to report error if has not yet reported a success
518  The only exception is when we flush the message to the client,
519  an error can happen during the flush.
520  */
521  DBUG_ASSERT(! is_set() || m_can_overwrite_status);
522 
523  // message must be set properly by the caller.
524  DBUG_ASSERT(message);
525 
526  // sqlstate must be set properly by the caller.
527  DBUG_ASSERT(sqlstate);
528 
529 #ifdef DBUG_OFF
530  /*
531  In production, refuse to overwrite a custom response with an
532  ERROR packet.
533  */
534  if (is_disabled())
535  return;
536 #endif
537 
538  m_sql_errno= sql_errno;
539  memcpy(m_sqlstate, sqlstate, SQLSTATE_LENGTH);
540  m_sqlstate[SQLSTATE_LENGTH]= '\0';
541  strmake(m_message, message, sizeof(m_message)-1);
542 
543  get_warning_info()->set_error_condition(error_condition);
544 
545  m_status= DA_ERROR;
546  DBUG_VOID_RETURN;
547 }
548 
549 
558 void
560 {
561  DBUG_ASSERT(! is_set());
562  m_status= DA_DISABLED;
563 }
564 
565 Warning_info::Warning_info(ulonglong warn_id_arg, bool allow_unlimited_warnings)
566  :m_current_statement_warn_count(0),
567  m_current_row_for_warning(1),
568  m_warn_id(warn_id_arg),
569  m_error_condition(NULL),
570  m_allow_unlimited_warnings(allow_unlimited_warnings),
571  m_read_only(FALSE)
572 {
573  /* Initialize sub structures */
574  init_sql_alloc(&m_warn_root, WARN_ALLOC_BLOCK_SIZE, WARN_ALLOC_PREALLOC_SIZE);
575  m_warn_list.empty();
576  memset(m_warn_count, 0, sizeof(m_warn_count));
577 }
578 
579 Warning_info::~Warning_info()
580 {
581  free_root(&m_warn_root,MYF(0));
582 }
583 
584 
585 bool Warning_info::has_sql_condition(const char *message_str,
586  ulong message_length) const
587 {
589  const Sql_condition *err;
590 
591  while ((err= it++))
592  {
593  if (strncmp(message_str, err->get_message_text(), message_length) == 0)
594  return true;
595  }
596 
597  return false;
598 }
599 
600 
601 void Warning_info::clear(ulonglong new_id)
602 {
603  id(new_id);
604  m_warn_list.empty();
605  m_marked_sql_conditions.empty();
606  free_root(&m_warn_root, MYF(0));
607  memset(m_warn_count, 0, sizeof(m_warn_count));
608  m_current_statement_warn_count= 0;
609  m_current_row_for_warning= 1; /* Start counting from the first row */
610  clear_error_condition();
611 }
612 
613 
614 void Warning_info::append_warning_info(THD *thd, const Warning_info *source)
615 {
616  const Sql_condition *err;
617  Diagnostics_area::Sql_condition_iterator it(source->m_warn_list);
618  const Sql_condition *src_error_condition = source->get_error_condition();
619 
620  while ((err= it++))
621  {
622  // Do not use ::push_warning() to avoid invocation of THD-internal-handlers.
623  Sql_condition *new_error= Warning_info::push_warning(thd, err);
624 
625  if (src_error_condition && src_error_condition == err)
626  set_error_condition(new_error);
627 
628  if (source->is_marked_for_removal(err))
629  mark_condition_for_removal(new_error);
630  }
631 }
632 
633 
644  const Warning_info *src_wi)
645 {
646  Sql_condition_iterator it(src_wi->m_warn_list);
647  const Sql_condition *cond;
648  Warning_info *wi= get_warning_info();
649 
650  while ((cond= it++))
651  {
652  if (cond->get_level() == Sql_condition::WARN_LEVEL_ERROR)
653  continue;
654 
655  Sql_condition *new_condition= wi->push_warning(thd, cond);
656 
657  if (src_wi->is_marked_for_removal(cond))
658  wi->mark_condition_for_removal(new_condition);
659  }
660 }
661 
662 
663 void Warning_info::mark_sql_conditions_for_removal()
664 {
665  Sql_condition_list::Iterator it(m_warn_list);
666  Sql_condition *cond;
667 
668  while ((cond= it++))
669  mark_condition_for_removal(cond);
670 }
671 
672 
673 void Warning_info::remove_marked_sql_conditions()
674 {
675  List_iterator_fast<Sql_condition> it(m_marked_sql_conditions);
676  Sql_condition *cond;
677 
678  while ((cond= it++))
679  {
680  m_warn_list.remove(cond);
681  m_warn_count[cond->get_level()]--;
682  m_current_statement_warn_count--;
683  if (cond == m_error_condition)
684  m_error_condition= NULL;
685  }
686 
687  m_marked_sql_conditions.empty();
688 }
689 
690 
691 bool Warning_info::is_marked_for_removal(const Sql_condition *cond) const
692 {
694  const_cast<List<Sql_condition>&> (m_marked_sql_conditions));
695  Sql_condition *c;
696 
697  while ((c= it++))
698  {
699  if (c == cond)
700  return true;
701  }
702 
703  return false;
704 }
705 
706 
707 void Warning_info::reserve_space(THD *thd, uint count)
708 {
709  while (m_warn_list.elements() &&
710  (m_warn_list.elements() + count) > thd->variables.max_error_count)
711  m_warn_list.remove(m_warn_list.front());
712 }
713 
714 Sql_condition *Warning_info::push_warning(THD *thd,
715  uint sql_errno, const char* sqlstate,
716  Sql_condition::enum_warning_level level,
717  const char *msg)
718 {
719  Sql_condition *cond= NULL;
720 
721  if (! m_read_only)
722  {
723  if (m_allow_unlimited_warnings ||
724  m_warn_list.elements() < thd->variables.max_error_count)
725  {
726  cond= new (& m_warn_root) Sql_condition(& m_warn_root);
727  if (cond)
728  {
729  cond->set(sql_errno, sqlstate, level, msg);
730  m_warn_list.push_back(cond);
731  }
732  }
733  m_warn_count[(uint) level]++;
734  }
735 
736  m_current_statement_warn_count++;
737  return cond;
738 }
739 
740 Sql_condition *Warning_info::push_warning(THD *thd, const Sql_condition *sql_condition)
741 {
742  Sql_condition *new_condition= push_warning(thd,
743  sql_condition->get_sql_errno(),
744  sql_condition->get_sqlstate(),
745  sql_condition->get_level(),
746  sql_condition->get_message_text());
747 
748  if (new_condition)
749  new_condition->copy_opt_attributes(sql_condition);
750 
751  return new_condition;
752 }
753 
754 /*
755  Push the warning to error list if there is still room in the list
756 
757  SYNOPSIS
758  push_warning()
759  thd Thread handle
760  level Severity of warning (note, warning)
761  code Error number
762  msg Clear error message
763 */
764 
765 void push_warning(THD *thd, Sql_condition::enum_warning_level level,
766  uint code, const char *msg)
767 {
768  DBUG_ENTER("push_warning");
769  DBUG_PRINT("enter", ("code: %d, msg: %s", code, msg));
770 
771  /*
772  Calling push_warning/push_warning_printf with a level of
773  WARN_LEVEL_ERROR *is* a bug. Either use my_printf_error(),
774  my_error(), or WARN_LEVEL_WARN.
775  */
776  DBUG_ASSERT(level != Sql_condition::WARN_LEVEL_ERROR);
777 
778  if (level == Sql_condition::WARN_LEVEL_ERROR)
779  level= Sql_condition::WARN_LEVEL_WARN;
780 
781  (void) thd->raise_condition(code, NULL, level, msg);
782 
783  DBUG_VOID_RETURN;
784 }
785 
786 
787 /*
788  Push the warning to error list if there is still room in the list
789 
790  SYNOPSIS
791  push_warning_printf()
792  thd Thread handle
793  level Severity of warning (note, warning)
794  code Error number
795  msg Clear error message
796 */
797 
798 void push_warning_printf(THD *thd, Sql_condition::enum_warning_level level,
799  uint code, const char *format, ...)
800 {
801  va_list args;
802  char warning[MYSQL_ERRMSG_SIZE];
803  DBUG_ENTER("push_warning_printf");
804  DBUG_PRINT("enter",("warning: %u", code));
805 
806  DBUG_ASSERT(code != 0);
807  DBUG_ASSERT(format != NULL);
808 
809  va_start(args,format);
810  my_vsnprintf_ex(&my_charset_utf8_general_ci, warning,
811  sizeof(warning), format, args);
812  va_end(args);
813  push_warning(thd, level, code, warning);
814  DBUG_VOID_RETURN;
815 }
816 
817 
818 /*
819  Send all notes, errors or warnings to the client in a result set
820 
821  SYNOPSIS
822  mysqld_show_warnings()
823  thd Thread handler
824  levels_to_show Bitmap for which levels to show
825 
826  DESCRIPTION
827  Takes into account the current LIMIT
828 
829  RETURN VALUES
830  FALSE ok
831  TRUE Error sending data to client
832 */
833 
834 const LEX_STRING warning_level_names[]=
835 {
836  { C_STRING_WITH_LEN("Note") },
837  { C_STRING_WITH_LEN("Warning") },
838  { C_STRING_WITH_LEN("Error") },
839  { C_STRING_WITH_LEN("?") }
840 };
841 
842 bool mysqld_show_warnings(THD *thd, ulong levels_to_show)
843 {
844  List<Item> field_list;
845  DBUG_ENTER("mysqld_show_warnings");
846 
847  DBUG_ASSERT(thd->get_stmt_da()->is_warning_info_read_only());
848 
849  field_list.push_back(new Item_empty_string("Level", 7));
850  field_list.push_back(new Item_return_int("Code",4, MYSQL_TYPE_LONG));
851  field_list.push_back(new Item_empty_string("Message",MYSQL_ERRMSG_SIZE));
852 
853  if (thd->protocol->send_result_set_metadata(&field_list,
854  Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
855  DBUG_RETURN(TRUE);
856 
857  const Sql_condition *err;
858  SELECT_LEX *sel= &thd->lex->select_lex;
859  SELECT_LEX_UNIT *unit= &thd->lex->unit;
860  ulonglong idx= 0;
861  Protocol *protocol=thd->protocol;
862 
863  unit->set_limit(sel);
864 
866  thd->get_stmt_da()->sql_conditions();
867  while ((err= it++))
868  {
869  /* Skip levels that the user is not interested in */
870  if (!(levels_to_show & ((ulong) 1 << err->get_level())))
871  continue;
872  if (++idx <= unit->offset_limit_cnt)
873  continue;
874  if (idx > unit->select_limit_cnt)
875  break;
876  protocol->prepare_for_resend();
877  protocol->store(warning_level_names[err->get_level()].str,
878  warning_level_names[err->get_level()].length,
879  system_charset_info);
880  protocol->store((uint32) err->get_sql_errno());
881  protocol->store(err->get_message_text(),
883  system_charset_info);
884  if (protocol->write())
885  DBUG_RETURN(TRUE);
886  }
887  my_eof(thd);
888 
889  thd->get_stmt_da()->set_warning_info_read_only(FALSE);
890 
891  DBUG_RETURN(FALSE);
892 }
893 
894 
895 ErrConvString::ErrConvString(double nr)
896 {
897  // enough to print '-[digits].E+###'
898  DBUG_ASSERT(sizeof(err_buffer) > DBL_DIG + 8);
899  buf_length= my_gcvt(nr, MY_GCVT_ARG_DOUBLE,
900  sizeof(err_buffer) - 1, err_buffer, NULL);
901 }
902 
903 
904 
905 ErrConvString::ErrConvString(const my_decimal *nr)
906 {
907  int len= sizeof(err_buffer);
908  (void) decimal2string((decimal_t *) nr, err_buffer, &len, 0, 0, 0);
909  buf_length= (uint) len;
910 }
911 
912 
913 ErrConvString::ErrConvString(const struct st_mysql_time *ltime, uint dec)
914 {
915  buf_length= my_TIME_to_str(ltime, err_buffer,
916  MY_MIN(dec, DATETIME_MAX_DECIMALS));
917 }
918 
919 
933 uint err_conv(char *buff, size_t to_length, const char *from,
934  size_t from_length, const CHARSET_INFO *from_cs)
935 {
936  char *to= buff;
937  const char *from_start= from;
938  size_t res;
939 
940  DBUG_ASSERT(to_length > 0);
941  to_length--;
942  if (from_cs == &my_charset_bin)
943  {
944  uchar char_code;
945  res= 0;
946  while (1)
947  {
948  if ((uint)(from - from_start) >= from_length ||
949  res >= to_length)
950  {
951  *to= 0;
952  break;
953  }
954 
955  char_code= ((uchar) *from);
956  if (char_code >= 0x20 && char_code <= 0x7E)
957  {
958  *to++= char_code;
959  from++;
960  res++;
961  }
962  else
963  {
964  if (res + 4 >= to_length)
965  {
966  *to= 0;
967  break;
968  }
969  res+= my_snprintf(to, 5, "\\x%02X", (uint) char_code);
970  to+=4;
971  from++;
972  }
973  }
974  }
975  else
976  {
977  uint errors;
978  res= copy_and_convert(to, to_length, system_charset_info,
979  from, from_length, from_cs, &errors);
980  to+= res;
981  *to= 0;
982  }
983  return to - buff;
984 }
985 
986 
1002 uint32 convert_error_message(char *to, uint32 to_length,
1003  const CHARSET_INFO *to_cs,
1004  const char *from, uint32 from_length,
1005  const CHARSET_INFO *from_cs, uint *errors)
1006 {
1007  int cnvres;
1008  my_wc_t wc;
1009  const uchar *from_end= (const uchar*) from+from_length;
1010  char *to_start= to;
1011  uchar *to_end;
1012  my_charset_conv_mb_wc mb_wc= from_cs->cset->mb_wc;
1013  my_charset_conv_wc_mb wc_mb;
1014  uint error_count= 0;
1015  uint length;
1016 
1017  DBUG_ASSERT(to_length > 0);
1018  /* Make room for the null terminator. */
1019  to_length--;
1020  to_end= (uchar*) (to + to_length);
1021 
1022  if (!to_cs || from_cs == to_cs || to_cs == &my_charset_bin)
1023  {
1024  length= MY_MIN(to_length, from_length);
1025  memmove(to, from, length);
1026  to[length]= 0;
1027  return length;
1028  }
1029 
1030  wc_mb= to_cs->cset->wc_mb;
1031  while (1)
1032  {
1033  if ((cnvres= (*mb_wc)(from_cs, &wc, (uchar*) from, from_end)) > 0)
1034  {
1035  if (!wc)
1036  break;
1037  from+= cnvres;
1038  }
1039  else if (cnvres == MY_CS_ILSEQ)
1040  {
1041  wc= (ulong) (uchar) *from;
1042  from+=1;
1043  }
1044  else
1045  break;
1046 
1047  if ((cnvres= (*wc_mb)(to_cs, wc, (uchar*) to, to_end)) > 0)
1048  to+= cnvres;
1049  else if (cnvres == MY_CS_ILUNI)
1050  {
1051  length= (wc <= 0xFFFF) ? 6/* '\1234' format*/ : 9 /* '\+123456' format*/;
1052  if ((uchar*)(to + length) >= to_end)
1053  break;
1054  cnvres= my_snprintf(to, 9,
1055  (wc <= 0xFFFF) ? "\\%04X" : "\\+%06X", (uint) wc);
1056  to+= cnvres;
1057  }
1058  else
1059  break;
1060  }
1061 
1062  *to= 0;
1063  *errors= error_count;
1064  return (uint32) (to - to_start);
1065 }
1066 
1067 
1079 bool is_sqlstate_valid(const LEX_STRING *sqlstate)
1080 {
1081  if (sqlstate->length != 5)
1082  return false;
1083 
1084  for (int i= 0 ; i < 5 ; ++i)
1085  {
1086  char c = sqlstate->str[i];
1087 
1088  if ((c < '0' || '9' < c) &&
1089  (c < 'A' || 'Z' < c))
1090  return false;
1091  }
1092 
1093  return true;
1094 }