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