1 | /* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. |
2 | Copyright (c) 2017, MariaDB Corporation. |
3 | |
4 | This program is free software; you can redistribute it and/or modify |
5 | it under the terms of the GNU General Public License as published by |
6 | the Free Software Foundation; version 2 of the License. |
7 | |
8 | This program is distributed in the hope that it will be useful, |
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | GNU General Public License for more details. |
12 | |
13 | You should have received a copy of the GNU General Public License |
14 | along with this program; if not, write to the Free Software |
15 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ |
16 | |
17 | #ifndef SQL_ERROR_H |
18 | #define SQL_ERROR_H |
19 | |
20 | #include "sql_list.h" /* Sql_alloc, MEM_ROOT, list */ |
21 | #include "m_string.h" /* LEX_STRING */ |
22 | #include "sql_string.h" /* String */ |
23 | #include "sql_plist.h" /* I_P_List */ |
24 | #include "mysql_com.h" /* MYSQL_ERRMSG_SIZE */ |
25 | #include "my_time.h" /* MYSQL_TIME */ |
26 | #include "decimal.h" |
27 | |
28 | class THD; |
29 | class my_decimal; |
30 | class sp_condition_value; |
31 | |
32 | /////////////////////////////////////////////////////////////////////////// |
33 | |
34 | class Sql_state |
35 | { |
36 | protected: |
37 | /** |
38 | This member is always NUL terminated. |
39 | */ |
40 | char m_sqlstate[SQLSTATE_LENGTH + 1]; |
41 | public: |
42 | Sql_state() |
43 | { |
44 | memset(m_sqlstate, 0, sizeof(m_sqlstate)); |
45 | } |
46 | |
47 | Sql_state(const char *sqlstate) |
48 | { |
49 | set_sqlstate(sqlstate); |
50 | } |
51 | |
52 | const char* get_sqlstate() const |
53 | { return m_sqlstate; } |
54 | |
55 | void set_sqlstate(const Sql_state *other) |
56 | { |
57 | *this= *other; |
58 | } |
59 | void set_sqlstate(const char *sqlstate) |
60 | { |
61 | memcpy(m_sqlstate, sqlstate, SQLSTATE_LENGTH); |
62 | m_sqlstate[SQLSTATE_LENGTH]= '\0'; |
63 | } |
64 | bool eq(const Sql_state *other) const |
65 | { |
66 | return strcmp(m_sqlstate, other->m_sqlstate) == 0; |
67 | } |
68 | |
69 | bool has_sql_state() const { return m_sqlstate[0] != '\0'; } |
70 | |
71 | /** |
72 | Checks if this SQL state defines a WARNING condition. |
73 | Note: m_sqlstate must contain a valid SQL-state. |
74 | |
75 | @retval true if this SQL state defines a WARNING condition. |
76 | @retval false otherwise. |
77 | */ |
78 | inline bool is_warning() const |
79 | { return m_sqlstate[0] == '0' && m_sqlstate[1] == '1'; } |
80 | |
81 | |
82 | /** |
83 | Checks if this SQL state defines a NOT FOUND condition. |
84 | Note: m_sqlstate must contain a valid SQL-state. |
85 | |
86 | @retval true if this SQL state defines a NOT FOUND condition. |
87 | @retval false otherwise. |
88 | */ |
89 | inline bool is_not_found() const |
90 | { return m_sqlstate[0] == '0' && m_sqlstate[1] == '2'; } |
91 | |
92 | |
93 | /** |
94 | Checks if this SQL state defines an EXCEPTION condition. |
95 | Note: m_sqlstate must contain a valid SQL-state. |
96 | |
97 | @retval true if this SQL state defines an EXCEPTION condition. |
98 | @retval false otherwise. |
99 | */ |
100 | inline bool is_exception() const |
101 | { return m_sqlstate[0] != '0' || m_sqlstate[1] > '2'; } |
102 | |
103 | }; |
104 | |
105 | |
106 | class Sql_state_errno: public Sql_state |
107 | { |
108 | protected: |
109 | /** |
110 | MySQL extension, MYSQL_ERRNO condition item. |
111 | SQL error number. One of ER_ codes from share/errmsg.txt. |
112 | Set by set_error_status. |
113 | */ |
114 | uint m_sql_errno; |
115 | |
116 | public: |
117 | Sql_state_errno() |
118 | :m_sql_errno(0) |
119 | { } |
120 | Sql_state_errno(uint sql_errno) |
121 | :m_sql_errno(sql_errno) |
122 | { } |
123 | Sql_state_errno(uint sql_errno, const char *sql_state) |
124 | :Sql_state(sql_state), |
125 | m_sql_errno(sql_errno) |
126 | { } |
127 | /** |
128 | Get the SQL_ERRNO of this condition. |
129 | @return the sql error number condition item. |
130 | */ |
131 | uint get_sql_errno() const |
132 | { return m_sql_errno; } |
133 | |
134 | void set(uint sql_errno, const char *sqlstate) |
135 | { |
136 | m_sql_errno= sql_errno; |
137 | set_sqlstate(sqlstate); |
138 | } |
139 | void clear() |
140 | { |
141 | m_sql_errno= 0; |
142 | } |
143 | }; |
144 | |
145 | |
146 | class Sql_state_errno_level: public Sql_state_errno |
147 | { |
148 | public: |
149 | /* |
150 | Enumeration value describing the severity of the error. |
151 | |
152 | Note that these enumeration values must correspond to the indices |
153 | of the sql_print_message_handlers array. |
154 | */ |
155 | enum enum_warning_level |
156 | { WARN_LEVEL_NOTE, WARN_LEVEL_WARN, WARN_LEVEL_ERROR, WARN_LEVEL_END}; |
157 | |
158 | protected: |
159 | /** Severity (error, warning, note) of this condition. */ |
160 | enum_warning_level m_level; |
161 | |
162 | void assign_defaults(const Sql_state_errno *value); |
163 | |
164 | public: |
165 | /** |
166 | Get the error level of this condition. |
167 | @return the error level condition item. |
168 | */ |
169 | enum_warning_level get_level() const |
170 | { return m_level; } |
171 | |
172 | Sql_state_errno_level() |
173 | :m_level(WARN_LEVEL_ERROR) |
174 | { } |
175 | |
176 | Sql_state_errno_level(uint sqlerrno, const char* sqlstate, |
177 | enum_warning_level level) |
178 | :Sql_state_errno(sqlerrno, sqlstate), |
179 | m_level(level) |
180 | { } |
181 | Sql_state_errno_level(const Sql_state_errno &state_errno, |
182 | enum_warning_level level) |
183 | :Sql_state_errno(state_errno), |
184 | m_level(level) |
185 | { } |
186 | void clear() |
187 | { |
188 | m_level= WARN_LEVEL_ERROR; |
189 | Sql_state_errno::clear(); |
190 | } |
191 | }; |
192 | |
193 | |
194 | /* |
195 | class Sql_user_condition_identity. |
196 | Instances of this class uniquely idetify user defined conditions (EXCEPTION). |
197 | |
198 | SET sql_mode=ORACLE; |
199 | CREATE PROCEDURE p1 |
200 | AS |
201 | a EXCEPTION; |
202 | BEGIN |
203 | RAISE a; |
204 | EXCEPTION |
205 | WHEN a THEN NULL; |
206 | END; |
207 | |
208 | Currently a user defined condition is identified by a pointer to |
209 | its parse time sp_condition_value instance. This can change when |
210 | we add packages. See MDEV-10591. |
211 | */ |
212 | class Sql_user_condition_identity |
213 | { |
214 | protected: |
215 | const sp_condition_value *m_user_condition_value; |
216 | public: |
217 | Sql_user_condition_identity() |
218 | :m_user_condition_value(NULL) |
219 | { } |
220 | Sql_user_condition_identity(const sp_condition_value *value) |
221 | :m_user_condition_value(value) |
222 | { } |
223 | const sp_condition_value *get_user_condition_value() const |
224 | { return m_user_condition_value; } |
225 | |
226 | void set(const Sql_user_condition_identity &identity) |
227 | { |
228 | *this= identity; |
229 | } |
230 | void clear() |
231 | { |
232 | m_user_condition_value= NULL; |
233 | } |
234 | }; |
235 | |
236 | |
237 | /** |
238 | class Sql_condition_identity. |
239 | Instances of this class uniquely identify conditions |
240 | (including user-defined exceptions for sql_mode=ORACLE) |
241 | and store everything that is needed for handler search |
242 | purposes in sp_pcontext::find_handler(). |
243 | */ |
244 | class Sql_condition_identity: public Sql_state_errno_level, |
245 | public Sql_user_condition_identity |
246 | { |
247 | public: |
248 | Sql_condition_identity() |
249 | { } |
250 | Sql_condition_identity(const Sql_state_errno_level &st, |
251 | const Sql_user_condition_identity &ucid) |
252 | :Sql_state_errno_level(st), |
253 | Sql_user_condition_identity(ucid) |
254 | { } |
255 | Sql_condition_identity(const Sql_state_errno &st, |
256 | enum_warning_level level, |
257 | const Sql_user_condition_identity &ucid) |
258 | :Sql_state_errno_level(st, level), |
259 | Sql_user_condition_identity(ucid) |
260 | { } |
261 | Sql_condition_identity(uint sqlerrno, |
262 | const char* sqlstate, |
263 | enum_warning_level level, |
264 | const Sql_user_condition_identity &ucid) |
265 | :Sql_state_errno_level(sqlerrno, sqlstate, level), |
266 | Sql_user_condition_identity(ucid) |
267 | { } |
268 | void clear() |
269 | { |
270 | Sql_state_errno_level::clear(); |
271 | Sql_user_condition_identity::clear(); |
272 | } |
273 | }; |
274 | |
275 | |
276 | class Sql_condition_items |
277 | { |
278 | protected: |
279 | /** SQL CLASS_ORIGIN condition item. */ |
280 | String m_class_origin; |
281 | |
282 | /** SQL SUBCLASS_ORIGIN condition item. */ |
283 | String m_subclass_origin; |
284 | |
285 | /** SQL CONSTRAINT_CATALOG condition item. */ |
286 | String m_constraint_catalog; |
287 | |
288 | /** SQL CONSTRAINT_SCHEMA condition item. */ |
289 | String m_constraint_schema; |
290 | |
291 | /** SQL CONSTRAINT_NAME condition item. */ |
292 | String m_constraint_name; |
293 | |
294 | /** SQL CATALOG_NAME condition item. */ |
295 | String m_catalog_name; |
296 | |
297 | /** SQL SCHEMA_NAME condition item. */ |
298 | String m_schema_name; |
299 | |
300 | /** SQL TABLE_NAME condition item. */ |
301 | String m_table_name; |
302 | |
303 | /** SQL COLUMN_NAME condition item. */ |
304 | String m_column_name; |
305 | |
306 | /** SQL CURSOR_NAME condition item. */ |
307 | String m_cursor_name; |
308 | |
309 | Sql_condition_items() |
310 | :m_class_origin((const char*) NULL, 0, & my_charset_utf8_bin), |
311 | m_subclass_origin((const char*) NULL, 0, & my_charset_utf8_bin), |
312 | m_constraint_catalog((const char*) NULL, 0, & my_charset_utf8_bin), |
313 | m_constraint_schema((const char*) NULL, 0, & my_charset_utf8_bin), |
314 | m_constraint_name((const char*) NULL, 0, & my_charset_utf8_bin), |
315 | m_catalog_name((const char*) NULL, 0, & my_charset_utf8_bin), |
316 | m_schema_name((const char*) NULL, 0, & my_charset_utf8_bin), |
317 | m_table_name((const char*) NULL, 0, & my_charset_utf8_bin), |
318 | m_column_name((const char*) NULL, 0, & my_charset_utf8_bin), |
319 | m_cursor_name((const char*) NULL, 0, & my_charset_utf8_bin) |
320 | { } |
321 | |
322 | void clear() |
323 | { |
324 | m_class_origin.length(0); |
325 | m_subclass_origin.length(0); |
326 | m_constraint_catalog.length(0); |
327 | m_constraint_schema.length(0); |
328 | m_constraint_name.length(0); |
329 | m_catalog_name.length(0); |
330 | m_schema_name.length(0); |
331 | m_table_name.length(0); |
332 | m_column_name.length(0); |
333 | m_cursor_name.length(0); |
334 | } |
335 | }; |
336 | |
337 | |
338 | /** |
339 | Representation of a SQL condition. |
340 | A SQL condition can be a completion condition (note, warning), |
341 | or an exception condition (error, not found). |
342 | */ |
343 | class Sql_condition : public Sql_alloc, |
344 | public Sql_condition_identity, |
345 | public Sql_condition_items |
346 | { |
347 | public: |
348 | |
349 | /** |
350 | Convert a bitmask consisting of MYSQL_TIME_{NOTE|WARN}_XXX bits |
351 | to WARN_LEVEL_XXX |
352 | */ |
353 | static enum_warning_level time_warn_level(uint warnings) |
354 | { |
355 | return MYSQL_TIME_WARN_HAVE_WARNINGS(warnings) ? |
356 | WARN_LEVEL_WARN : WARN_LEVEL_NOTE; |
357 | } |
358 | |
359 | /** |
360 | Get the MESSAGE_TEXT of this condition. |
361 | @return the message text. |
362 | */ |
363 | const char* get_message_text() const; |
364 | |
365 | /** |
366 | Get the MESSAGE_OCTET_LENGTH of this condition. |
367 | @return the length in bytes of the message text. |
368 | */ |
369 | int get_message_octet_length() const; |
370 | |
371 | private: |
372 | /* |
373 | The interface of Sql_condition is mostly private, by design, |
374 | so that only the following code: |
375 | - various raise_error() or raise_warning() methods in class THD, |
376 | - the implementation of SIGNAL / RESIGNAL / GET DIAGNOSTICS |
377 | - catch / re-throw of SQL conditions in stored procedures (sp_rcontext) |
378 | is allowed to create / modify a SQL condition. |
379 | Enforcing this policy prevents confusion, since the only public |
380 | interface available to the rest of the server implementation |
381 | is the interface offered by the THD methods (THD::raise_error()), |
382 | which should be used. |
383 | */ |
384 | friend class THD; |
385 | friend class Warning_info; |
386 | friend class Sql_cmd_common_signal; |
387 | friend class Sql_cmd_signal; |
388 | friend class Sql_cmd_resignal; |
389 | friend class sp_rcontext; |
390 | friend class Condition_information_item; |
391 | |
392 | /** |
393 | Default constructor. |
394 | This constructor is usefull when allocating arrays. |
395 | Note that the init() method should be called to complete the Sql_condition. |
396 | */ |
397 | Sql_condition() |
398 | :m_mem_root(NULL) |
399 | { } |
400 | |
401 | /** |
402 | Complete the Sql_condition initialisation. |
403 | @param mem_root The memory root to use for the condition items |
404 | of this condition |
405 | */ |
406 | void init(MEM_ROOT *mem_root) |
407 | { |
408 | DBUG_ASSERT(mem_root != NULL); |
409 | DBUG_ASSERT(m_mem_root == NULL); |
410 | m_mem_root= mem_root; |
411 | } |
412 | |
413 | /** |
414 | Constructor. |
415 | @param mem_root The memory root to use for the condition items |
416 | of this condition |
417 | */ |
418 | Sql_condition(MEM_ROOT *mem_root) |
419 | :m_mem_root(mem_root) |
420 | { |
421 | DBUG_ASSERT(mem_root != NULL); |
422 | } |
423 | |
424 | Sql_condition(MEM_ROOT *mem_root, const Sql_user_condition_identity &ucid) |
425 | :Sql_condition_identity(Sql_state_errno_level(), ucid), |
426 | m_mem_root(mem_root) |
427 | { |
428 | DBUG_ASSERT(mem_root != NULL); |
429 | } |
430 | /** |
431 | Constructor for a fixed message text. |
432 | @param mem_root - memory root |
433 | @param value - the error number and the sql state for this condition |
434 | @param level - the error level for this condition |
435 | @param msg - the message text for this condition |
436 | */ |
437 | Sql_condition(MEM_ROOT *mem_root, |
438 | const Sql_condition_identity &value, |
439 | const char *msg) |
440 | :Sql_condition_identity(value), |
441 | m_mem_root(mem_root) |
442 | { |
443 | DBUG_ASSERT(mem_root != NULL); |
444 | DBUG_ASSERT(value.get_sql_errno() != 0); |
445 | DBUG_ASSERT(msg != NULL); |
446 | set_builtin_message_text(msg); |
447 | } |
448 | |
449 | /** Destructor. */ |
450 | ~Sql_condition() |
451 | {} |
452 | |
453 | /** |
454 | Copy optional condition items attributes. |
455 | @param cond the condition to copy. |
456 | */ |
457 | void copy_opt_attributes(const Sql_condition *cond); |
458 | |
459 | /** |
460 | Set the condition message test. |
461 | @param str Message text, expressed in the character set derived from |
462 | the server --language option |
463 | */ |
464 | void set_builtin_message_text(const char* str); |
465 | |
466 | /** Set the CLASS_ORIGIN of this condition. */ |
467 | void set_class_origin(); |
468 | |
469 | /** Set the SUBCLASS_ORIGIN of this condition. */ |
470 | void set_subclass_origin(); |
471 | |
472 | /** |
473 | Assign the condition items 'MYSQL_ERRNO', 'level' and 'MESSAGE_TEXT' |
474 | default values of a condition. |
475 | @param thd - current thread, to access to localized error messages |
476 | @param from - copy condition items from here (can be NULL) |
477 | */ |
478 | void assign_defaults(THD *thd, const Sql_state_errno *from); |
479 | |
480 | /** |
481 | Clear this SQL condition. |
482 | */ |
483 | void clear() |
484 | { |
485 | Sql_condition_identity::clear(); |
486 | Sql_condition_items::clear(); |
487 | m_message_text.length(0); |
488 | } |
489 | |
490 | private: |
491 | /** Message text, expressed in the character set implied by --language. */ |
492 | String m_message_text; |
493 | |
494 | /** Pointers for participating in the list of conditions. */ |
495 | Sql_condition *next_in_wi; |
496 | Sql_condition **prev_in_wi; |
497 | |
498 | /** Memory root to use to hold condition item values. */ |
499 | MEM_ROOT *m_mem_root; |
500 | }; |
501 | |
502 | /////////////////////////////////////////////////////////////////////////// |
503 | |
504 | /** |
505 | Information about warnings of the current connection. |
506 | */ |
507 | class Warning_info |
508 | { |
509 | /** The type of the counted and doubly linked list of conditions. */ |
510 | typedef I_P_List<Sql_condition, |
511 | I_P_List_adapter<Sql_condition, |
512 | &Sql_condition::next_in_wi, |
513 | &Sql_condition::prev_in_wi>, |
514 | I_P_List_counter, |
515 | I_P_List_fast_push_back<Sql_condition> > |
516 | Sql_condition_list; |
517 | |
518 | /** A memory root to allocate warnings and errors */ |
519 | MEM_ROOT m_warn_root; |
520 | |
521 | /** List of warnings of all severities (levels). */ |
522 | Sql_condition_list m_warn_list; |
523 | |
524 | /** A break down of the number of warnings per severity (level). */ |
525 | uint m_warn_count[(uint) Sql_condition::WARN_LEVEL_END]; |
526 | |
527 | /** |
528 | The number of warnings of the current statement. Warning_info |
529 | life cycle differs from statement life cycle -- it may span |
530 | multiple statements. In that case we get |
531 | m_current_statement_warn_count 0, whereas m_warn_list is not empty. |
532 | */ |
533 | uint m_current_statement_warn_count; |
534 | |
535 | /* |
536 | Row counter, to print in errors and warnings. Not increased in |
537 | create_sort_index(); may differ from examined_row_count. |
538 | */ |
539 | ulong m_current_row_for_warning; |
540 | |
541 | /** Used to optionally clear warnings only once per statement. */ |
542 | ulonglong m_warn_id; |
543 | |
544 | /** |
545 | A pointer to an element of m_warn_list. It determines SQL-condition |
546 | instance which corresponds to the error state in Diagnostics_area. |
547 | |
548 | This is needed for properly processing SQL-conditions in SQL-handlers. |
549 | When an SQL-handler is found for the current error state in Diagnostics_area, |
550 | this pointer is needed to remove the corresponding SQL-condition from the |
551 | Warning_info list. |
552 | |
553 | @note m_error_condition might be NULL in the following cases: |
554 | - Diagnostics_area set to fatal error state (like OOM); |
555 | - Max number of Warning_info elements has been reached (thus, there is |
556 | no corresponding SQL-condition object in Warning_info). |
557 | */ |
558 | const Sql_condition *m_error_condition; |
559 | |
560 | /** Indicates if push_warning() allows unlimited number of warnings. */ |
561 | bool m_allow_unlimited_warnings; |
562 | bool initialized; /* Set to 1 if init() has been called */ |
563 | |
564 | /** Read only status. */ |
565 | bool m_read_only; |
566 | |
567 | /** Pointers for participating in the stack of Warning_info objects. */ |
568 | Warning_info *m_next_in_da; |
569 | Warning_info **m_prev_in_da; |
570 | |
571 | List<Sql_condition> m_marked_sql_conditions; |
572 | |
573 | public: |
574 | Warning_info(ulonglong warn_id_arg, bool allow_unlimited_warnings, |
575 | bool initialized); |
576 | ~Warning_info(); |
577 | /* Allocate memory for structures */ |
578 | void init(); |
579 | void free_memory(); |
580 | |
581 | private: |
582 | Warning_info(const Warning_info &rhs); /* Not implemented */ |
583 | Warning_info& operator=(const Warning_info &rhs); /* Not implemented */ |
584 | |
585 | /** |
586 | Checks if Warning_info contains SQL-condition with the given message. |
587 | |
588 | @param message_str Message string. |
589 | @param message_length Length of message string. |
590 | |
591 | @return true if the Warning_info contains an SQL-condition with the given |
592 | message. |
593 | */ |
594 | bool has_sql_condition(const char *message_str, size_t message_length) const; |
595 | |
596 | /** |
597 | Reset the warning information. Clear all warnings, |
598 | the number of warnings, reset current row counter |
599 | to point to the first row. |
600 | |
601 | @param new_id new Warning_info id. |
602 | */ |
603 | void clear(ulonglong new_id); |
604 | |
605 | /** |
606 | Only clear warning info if haven't yet done that already |
607 | for the current query. Allows to be issued at any time |
608 | during the query, without risk of clearing some warnings |
609 | that have been generated by the current statement. |
610 | |
611 | @todo: This is a sign of sloppy coding. Instead we need to |
612 | designate one place in a statement life cycle where we call |
613 | Warning_info::clear(). |
614 | |
615 | @param query_id Current query id. |
616 | */ |
617 | void opt_clear(ulonglong query_id) |
618 | { |
619 | if (query_id != m_warn_id) |
620 | clear(query_id); |
621 | } |
622 | |
623 | /** |
624 | Concatenate the list of warnings. |
625 | |
626 | It's considered tolerable to lose an SQL-condition in case of OOM-error, |
627 | or if the number of SQL-conditions in the Warning_info reached top limit. |
628 | |
629 | @param thd Thread context. |
630 | @param source Warning_info object to copy SQL-conditions from. |
631 | */ |
632 | void append_warning_info(THD *thd, const Warning_info *source); |
633 | |
634 | /** |
635 | Reset between two COM_ commands. Warnings are preserved |
636 | between commands, but statement_warn_count indicates |
637 | the number of warnings of this particular statement only. |
638 | */ |
639 | void reset_for_next_command() |
640 | { m_current_statement_warn_count= 0; } |
641 | |
642 | /** |
643 | Mark active SQL-conditions for later removal. |
644 | This is done to simulate stacked DAs for HANDLER statements. |
645 | */ |
646 | void mark_sql_conditions_for_removal(); |
647 | |
648 | /** |
649 | Unmark SQL-conditions, which were marked for later removal. |
650 | This is done to simulate stacked DAs for HANDLER statements. |
651 | */ |
652 | void unmark_sql_conditions_from_removal() |
653 | { m_marked_sql_conditions.empty(); } |
654 | |
655 | /** |
656 | Remove SQL-conditions that are marked for deletion. |
657 | This is done to simulate stacked DAs for HANDLER statements. |
658 | */ |
659 | void remove_marked_sql_conditions(); |
660 | |
661 | /** |
662 | Check if the given SQL-condition is marked for removal in this Warning_info |
663 | instance. |
664 | |
665 | @param cond the SQL-condition. |
666 | |
667 | @retval true if the given SQL-condition is marked for removal in this |
668 | Warning_info instance. |
669 | @retval false otherwise. |
670 | */ |
671 | bool is_marked_for_removal(const Sql_condition *cond) const; |
672 | |
673 | /** |
674 | Mark a single SQL-condition for removal (add the given SQL-condition to the |
675 | removal list of this Warning_info instance). |
676 | */ |
677 | void mark_condition_for_removal(Sql_condition *cond) |
678 | { m_marked_sql_conditions.push_back(cond, &m_warn_root); } |
679 | |
680 | /** |
681 | Used for @@warning_count system variable, which prints |
682 | the number of rows returned by SHOW WARNINGS. |
683 | */ |
684 | ulong warn_count() const |
685 | { |
686 | /* |
687 | This may be higher than warn_list.elements() if we have |
688 | had more warnings than thd->variables.max_error_count. |
689 | */ |
690 | return (m_warn_count[(uint) Sql_condition::WARN_LEVEL_NOTE] + |
691 | m_warn_count[(uint) Sql_condition::WARN_LEVEL_ERROR] + |
692 | m_warn_count[(uint) Sql_condition::WARN_LEVEL_WARN]); |
693 | } |
694 | |
695 | /** |
696 | The number of errors, or number of rows returned by SHOW ERRORS, |
697 | also the value of session variable @@error_count. |
698 | */ |
699 | ulong error_count() const |
700 | { return m_warn_count[(uint) Sql_condition::WARN_LEVEL_ERROR]; } |
701 | |
702 | /** |
703 | The number of conditions (errors, warnings and notes) in the list. |
704 | */ |
705 | uint cond_count() const |
706 | { |
707 | return m_warn_list.elements(); |
708 | } |
709 | |
710 | /** Id of the warning information area. */ |
711 | ulonglong id() const { return m_warn_id; } |
712 | |
713 | /** Set id of the warning information area. */ |
714 | void id(ulonglong id_arg) { m_warn_id= id_arg; } |
715 | |
716 | /** Do we have any errors and warnings that we can *show*? */ |
717 | bool is_empty() const { return m_warn_list.is_empty(); } |
718 | |
719 | /** Increment the current row counter to point at the next row. */ |
720 | void inc_current_row_for_warning() { m_current_row_for_warning++; } |
721 | |
722 | /** Reset the current row counter. Start counting from the first row. */ |
723 | void reset_current_row_for_warning() { m_current_row_for_warning= 1; } |
724 | |
725 | /** Return the current counter value. */ |
726 | ulong current_row_for_warning() const { return m_current_row_for_warning; } |
727 | |
728 | /** Return the number of warnings thrown by the current statement. */ |
729 | ulong current_statement_warn_count() const |
730 | { return m_current_statement_warn_count; } |
731 | |
732 | /** Make sure there is room for the given number of conditions. */ |
733 | void reserve_space(THD *thd, uint count); |
734 | |
735 | /** |
736 | Add a new SQL-condition to the current list and increment the respective |
737 | counters. |
738 | |
739 | @param thd Thread context. |
740 | @param identity SQL-condition identity |
741 | @param msg SQL-condition message. |
742 | |
743 | @return a pointer to the added SQL-condition. |
744 | */ |
745 | Sql_condition *push_warning(THD *thd, |
746 | const Sql_condition_identity *identity, |
747 | const char* msg); |
748 | |
749 | /** |
750 | Add a new SQL-condition to the current list and increment the respective |
751 | counters. |
752 | |
753 | @param thd Thread context. |
754 | @param sql_condition SQL-condition to copy values from. |
755 | |
756 | @return a pointer to the added SQL-condition. |
757 | */ |
758 | Sql_condition *push_warning(THD *thd, const Sql_condition *sql_condition); |
759 | |
760 | /** |
761 | Set the read only status for this statement area. |
762 | This is a privileged operation, reserved for the implementation of |
763 | diagnostics related statements, to enforce that the statement area is |
764 | left untouched during execution. |
765 | The diagnostics statements are: |
766 | - SHOW WARNINGS |
767 | - SHOW ERRORS |
768 | - GET DIAGNOSTICS |
769 | @param read_only the read only property to set. |
770 | */ |
771 | void set_read_only(bool read_only_arg) |
772 | { m_read_only= read_only_arg; } |
773 | |
774 | /** |
775 | Read only status. |
776 | @return the read only property. |
777 | */ |
778 | bool is_read_only() const |
779 | { return m_read_only; } |
780 | |
781 | /** |
782 | @return SQL-condition, which corresponds to the error state in |
783 | Diagnostics_area. |
784 | |
785 | @see m_error_condition. |
786 | */ |
787 | const Sql_condition *get_error_condition() const |
788 | { return m_error_condition; } |
789 | |
790 | /** |
791 | Set SQL-condition, which corresponds to the error state in Diagnostics_area. |
792 | |
793 | @see m_error_condition. |
794 | */ |
795 | void set_error_condition(const Sql_condition *error_condition) |
796 | { m_error_condition= error_condition; } |
797 | |
798 | /** |
799 | Reset SQL-condition, which corresponds to the error state in |
800 | Diagnostics_area. |
801 | |
802 | @see m_error_condition. |
803 | */ |
804 | void clear_error_condition() |
805 | { m_error_condition= NULL; } |
806 | |
807 | // for: |
808 | // - m_next_in_da / m_prev_in_da |
809 | // - is_marked_for_removal() |
810 | friend class Diagnostics_area; |
811 | }; |
812 | |
813 | |
814 | extern char *err_conv(char *buff, uint to_length, const char *from, |
815 | uint from_length, CHARSET_INFO *from_cs); |
816 | |
817 | class ErrConv |
818 | { |
819 | protected: |
820 | mutable char err_buffer[MYSQL_ERRMSG_SIZE]; |
821 | public: |
822 | ErrConv() {} |
823 | virtual ~ErrConv() {} |
824 | virtual const char *ptr() const = 0; |
825 | }; |
826 | |
827 | class ErrConvString : public ErrConv |
828 | { |
829 | const char *str; |
830 | size_t len; |
831 | CHARSET_INFO *cs; |
832 | public: |
833 | ErrConvString(const char *str_arg, size_t len_arg, CHARSET_INFO *cs_arg) |
834 | : ErrConv(), str(str_arg), len(len_arg), cs(cs_arg) {} |
835 | ErrConvString(const char *str_arg, CHARSET_INFO *cs_arg) |
836 | : ErrConv(), str(str_arg), len(strlen(str_arg)), cs(cs_arg) {} |
837 | ErrConvString(const String *s) |
838 | : ErrConv(), str(s->ptr()), len(s->length()), cs(s->charset()) {} |
839 | const char *ptr() const |
840 | { |
841 | DBUG_ASSERT(len < UINT_MAX32); |
842 | return err_conv(err_buffer, (uint) sizeof(err_buffer), str, (uint) len, cs); |
843 | } |
844 | }; |
845 | |
846 | class ErrConvInteger : public ErrConv |
847 | { |
848 | longlong m_value; |
849 | bool m_unsigned; |
850 | public: |
851 | ErrConvInteger(longlong num_arg, bool unsigned_flag= false) : |
852 | ErrConv(), m_value(num_arg), m_unsigned(unsigned_flag) {} |
853 | const char *ptr() const |
854 | { |
855 | return m_unsigned ? ullstr(m_value, err_buffer) : |
856 | llstr(m_value, err_buffer); |
857 | } |
858 | }; |
859 | |
860 | class ErrConvDouble: public ErrConv |
861 | { |
862 | double num; |
863 | public: |
864 | ErrConvDouble(double num_arg) : ErrConv(), num(num_arg) {} |
865 | const char *ptr() const |
866 | { |
867 | my_gcvt(num, MY_GCVT_ARG_DOUBLE, sizeof(err_buffer), err_buffer, 0); |
868 | return err_buffer; |
869 | } |
870 | }; |
871 | |
872 | class ErrConvTime : public ErrConv |
873 | { |
874 | const MYSQL_TIME *ltime; |
875 | public: |
876 | ErrConvTime(const MYSQL_TIME *ltime_arg) : ErrConv(), ltime(ltime_arg) {} |
877 | const char *ptr() const |
878 | { |
879 | my_TIME_to_str(ltime, err_buffer, AUTO_SEC_PART_DIGITS); |
880 | return err_buffer; |
881 | } |
882 | }; |
883 | |
884 | class ErrConvDecimal : public ErrConv |
885 | { |
886 | const decimal_t *d; |
887 | public: |
888 | ErrConvDecimal(const decimal_t *d_arg) : ErrConv(), d(d_arg) {} |
889 | const char *ptr() const |
890 | { |
891 | int len= sizeof(err_buffer); |
892 | decimal2string(d, err_buffer, &len, 0, 0, ' '); |
893 | return err_buffer; |
894 | } |
895 | }; |
896 | |
897 | /////////////////////////////////////////////////////////////////////////// |
898 | |
899 | /** |
900 | Stores status of the currently executed statement. |
901 | Cleared at the beginning of the statement, and then |
902 | can hold either OK, ERROR, or EOF status. |
903 | Can not be assigned twice per statement. |
904 | */ |
905 | |
906 | class Diagnostics_area: public Sql_state_errno, |
907 | public Sql_user_condition_identity |
908 | { |
909 | private: |
910 | /** The type of the counted and doubly linked list of conditions. */ |
911 | typedef I_P_List<Warning_info, |
912 | I_P_List_adapter<Warning_info, |
913 | &Warning_info::m_next_in_da, |
914 | &Warning_info::m_prev_in_da>, |
915 | I_P_List_counter, |
916 | I_P_List_fast_push_back<Warning_info> > |
917 | Warning_info_list; |
918 | |
919 | public: |
920 | /** Const iterator used to iterate through the warning list. */ |
921 | typedef Warning_info::Sql_condition_list::Const_Iterator |
922 | Sql_condition_iterator; |
923 | |
924 | enum enum_diagnostics_status |
925 | { |
926 | /** The area is cleared at start of a statement. */ |
927 | DA_EMPTY= 0, |
928 | /** Set whenever one calls my_ok(). */ |
929 | DA_OK, |
930 | /** Set whenever one calls my_eof(). */ |
931 | DA_EOF, |
932 | /** Set whenever one calls my_ok() in PS bulk mode. */ |
933 | DA_OK_BULK, |
934 | /** Set whenever one calls my_error() or my_message(). */ |
935 | DA_ERROR, |
936 | /** Set in case of a custom response, such as one from COM_STMT_PREPARE. */ |
937 | DA_DISABLED |
938 | }; |
939 | |
940 | void set_overwrite_status(bool can_overwrite_status) |
941 | { m_can_overwrite_status= can_overwrite_status; } |
942 | |
943 | /** True if status information is sent to the client. */ |
944 | bool is_sent() const { return m_is_sent; } |
945 | |
946 | void set_is_sent(bool is_sent_arg) { m_is_sent= is_sent_arg; } |
947 | |
948 | void set_ok_status(ulonglong affected_rows, |
949 | ulonglong last_insert_id, |
950 | const char *message); |
951 | |
952 | void set_eof_status(THD *thd); |
953 | |
954 | void set_error_status(uint sql_errno); |
955 | |
956 | void set_error_status(uint sql_errno, |
957 | const char *message, |
958 | const char *sqlstate, |
959 | const Sql_user_condition_identity &ucid, |
960 | const Sql_condition *error_condition); |
961 | |
962 | void set_error_status(uint sql_errno, |
963 | const char *message, |
964 | const char *sqlstate, |
965 | const Sql_condition *error_condition) |
966 | { |
967 | set_error_status(sql_errno, message, sqlstate, |
968 | Sql_user_condition_identity(), |
969 | error_condition); |
970 | } |
971 | |
972 | void disable_status(); |
973 | |
974 | void reset_diagnostics_area(); |
975 | |
976 | bool is_set() const { return m_status != DA_EMPTY; } |
977 | |
978 | bool is_error() const { return m_status == DA_ERROR; } |
979 | |
980 | bool is_eof() const { return m_status == DA_EOF; } |
981 | |
982 | bool is_ok() const { return m_status == DA_OK; } |
983 | |
984 | bool is_disabled() const { return m_status == DA_DISABLED; } |
985 | |
986 | void set_bulk_execution(bool bulk) { is_bulk_execution= bulk; } |
987 | |
988 | bool is_bulk_op() const { return is_bulk_execution; } |
989 | |
990 | enum_diagnostics_status status() const { return m_status; } |
991 | |
992 | const char *message() const |
993 | { DBUG_ASSERT(m_status == DA_ERROR || m_status == DA_OK || |
994 | m_status == DA_OK_BULK); return m_message; } |
995 | |
996 | bool skip_flush() const |
997 | { |
998 | DBUG_ASSERT(m_status == DA_OK || m_status == DA_OK_BULK); |
999 | return m_skip_flush; |
1000 | } |
1001 | |
1002 | void set_skip_flush() |
1003 | { m_skip_flush= TRUE; } |
1004 | |
1005 | uint sql_errno() const |
1006 | { |
1007 | DBUG_ASSERT(m_status == DA_ERROR); |
1008 | return Sql_state_errno::get_sql_errno(); |
1009 | } |
1010 | |
1011 | const char* get_sqlstate() const |
1012 | { DBUG_ASSERT(m_status == DA_ERROR); return Sql_state::get_sqlstate(); } |
1013 | |
1014 | ulonglong affected_rows() const |
1015 | { |
1016 | DBUG_ASSERT(m_status == DA_OK || m_status == DA_OK_BULK); |
1017 | return m_affected_rows; |
1018 | } |
1019 | |
1020 | ulonglong last_insert_id() const |
1021 | { |
1022 | DBUG_ASSERT(m_status == DA_OK || m_status == DA_OK_BULK); |
1023 | return m_last_insert_id; |
1024 | } |
1025 | |
1026 | uint statement_warn_count() const |
1027 | { |
1028 | DBUG_ASSERT(m_status == DA_OK || m_status == DA_OK_BULK || |
1029 | m_status == DA_EOF); |
1030 | return m_statement_warn_count; |
1031 | } |
1032 | |
1033 | /** |
1034 | Get the current errno, state and id of the user defined condition |
1035 | and return them as Sql_condition_identity. |
1036 | */ |
1037 | Sql_condition_identity get_error_condition_identity() const |
1038 | { |
1039 | DBUG_ASSERT(m_status == DA_ERROR); |
1040 | return Sql_condition_identity(*this /*Sql_state_errno*/, |
1041 | Sql_condition::WARN_LEVEL_ERROR, |
1042 | *this /*Sql_user_condition_identity*/); |
1043 | } |
1044 | |
1045 | /* Used to count any warnings pushed after calling set_ok_status(). */ |
1046 | void increment_warning() |
1047 | { |
1048 | if (m_status != DA_EMPTY) |
1049 | m_statement_warn_count++; |
1050 | } |
1051 | |
1052 | Diagnostics_area(bool initialize); |
1053 | Diagnostics_area(ulonglong warning_info_id, bool allow_unlimited_warnings, |
1054 | bool initialize); |
1055 | void init() { m_main_wi.init() ; } |
1056 | void free_memory() { m_main_wi.free_memory() ; } |
1057 | |
1058 | void push_warning_info(Warning_info *wi) |
1059 | { m_wi_stack.push_front(wi); } |
1060 | |
1061 | void pop_warning_info() |
1062 | { |
1063 | DBUG_ASSERT(m_wi_stack.elements() > 0); |
1064 | m_wi_stack.remove(m_wi_stack.front()); |
1065 | } |
1066 | |
1067 | void set_warning_info_id(ulonglong id) |
1068 | { get_warning_info()->id(id); } |
1069 | |
1070 | ulonglong warning_info_id() const |
1071 | { return get_warning_info()->id(); } |
1072 | |
1073 | /** |
1074 | Compare given current warning info and current warning info |
1075 | and see if they are different. They will be different if |
1076 | warnings have been generated or statements that use tables |
1077 | have been executed. This is checked by comparing m_warn_id. |
1078 | |
1079 | @param wi Warning info to compare with current Warning info. |
1080 | |
1081 | @return false if they are equal, true if they are not. |
1082 | */ |
1083 | bool warning_info_changed(const Warning_info *wi) const |
1084 | { return get_warning_info()->id() != wi->id(); } |
1085 | |
1086 | bool is_warning_info_empty() const |
1087 | { return get_warning_info()->is_empty(); } |
1088 | |
1089 | ulong current_statement_warn_count() const |
1090 | { return get_warning_info()->current_statement_warn_count(); } |
1091 | |
1092 | bool has_sql_condition(const char *message_str, size_t message_length) const |
1093 | { return get_warning_info()->has_sql_condition(message_str, message_length); } |
1094 | |
1095 | void reset_for_next_command() |
1096 | { get_warning_info()->reset_for_next_command(); } |
1097 | |
1098 | void clear_warning_info(ulonglong id) |
1099 | { get_warning_info()->clear(id); } |
1100 | |
1101 | void opt_clear_warning_info(ulonglong query_id) |
1102 | { get_warning_info()->opt_clear(query_id); } |
1103 | |
1104 | ulong current_row_for_warning() const |
1105 | { return get_warning_info()->current_row_for_warning(); } |
1106 | |
1107 | void inc_current_row_for_warning() |
1108 | { get_warning_info()->inc_current_row_for_warning(); } |
1109 | |
1110 | void reset_current_row_for_warning() |
1111 | { get_warning_info()->reset_current_row_for_warning(); } |
1112 | |
1113 | bool is_warning_info_read_only() const |
1114 | { return get_warning_info()->is_read_only(); } |
1115 | |
1116 | void set_warning_info_read_only(bool read_only_arg) |
1117 | { get_warning_info()->set_read_only(read_only_arg); } |
1118 | |
1119 | ulong error_count() const |
1120 | { return get_warning_info()->error_count(); } |
1121 | |
1122 | ulong warn_count() const |
1123 | { return get_warning_info()->warn_count(); } |
1124 | |
1125 | uint cond_count() const |
1126 | { return get_warning_info()->cond_count(); } |
1127 | |
1128 | Sql_condition_iterator sql_conditions() const |
1129 | { return get_warning_info()->m_warn_list; } |
1130 | |
1131 | void reserve_space(THD *thd, uint count) |
1132 | { get_warning_info()->reserve_space(thd, count); } |
1133 | |
1134 | Sql_condition *push_warning(THD *thd, const Sql_condition *sql_condition) |
1135 | { return get_warning_info()->push_warning(thd, sql_condition); } |
1136 | |
1137 | Sql_condition *push_warning(THD *thd, |
1138 | uint sql_errno_arg, |
1139 | const char* sqlstate, |
1140 | Sql_condition::enum_warning_level level, |
1141 | const Sql_user_condition_identity &ucid, |
1142 | const char* msg) |
1143 | { |
1144 | Sql_condition_identity tmp(sql_errno_arg, sqlstate, level, ucid); |
1145 | return get_warning_info()->push_warning(thd, &tmp, msg); |
1146 | } |
1147 | |
1148 | Sql_condition *push_warning(THD *thd, |
1149 | uint sqlerrno, |
1150 | const char* sqlstate, |
1151 | Sql_condition::enum_warning_level level, |
1152 | const char* msg) |
1153 | { |
1154 | return push_warning(thd, sqlerrno, sqlstate, level, |
1155 | Sql_user_condition_identity(), msg); |
1156 | } |
1157 | void mark_sql_conditions_for_removal() |
1158 | { get_warning_info()->mark_sql_conditions_for_removal(); } |
1159 | |
1160 | void unmark_sql_conditions_from_removal() |
1161 | { get_warning_info()->unmark_sql_conditions_from_removal(); } |
1162 | |
1163 | void remove_marked_sql_conditions() |
1164 | { get_warning_info()->remove_marked_sql_conditions(); } |
1165 | |
1166 | const Sql_condition *get_error_condition() const |
1167 | { return get_warning_info()->get_error_condition(); } |
1168 | |
1169 | void copy_sql_conditions_to_wi(THD *thd, Warning_info *dst_wi) const |
1170 | { dst_wi->append_warning_info(thd, get_warning_info()); } |
1171 | |
1172 | void copy_sql_conditions_from_wi(THD *thd, const Warning_info *src_wi) |
1173 | { get_warning_info()->append_warning_info(thd, src_wi); } |
1174 | |
1175 | void copy_non_errors_from_wi(THD *thd, const Warning_info *src_wi); |
1176 | |
1177 | private: |
1178 | Warning_info *get_warning_info() { return m_wi_stack.front(); } |
1179 | |
1180 | const Warning_info *get_warning_info() const { return m_wi_stack.front(); } |
1181 | |
1182 | private: |
1183 | /** True if status information is sent to the client. */ |
1184 | bool m_is_sent; |
1185 | |
1186 | /** Set to make set_error_status after set_{ok,eof}_status possible. */ |
1187 | bool m_can_overwrite_status; |
1188 | |
1189 | /** Skip flushing network buffer after writing OK (for COM_MULTI) */ |
1190 | bool m_skip_flush; |
1191 | |
1192 | /** Message buffer. Can be used by OK or ERROR status. */ |
1193 | char m_message[MYSQL_ERRMSG_SIZE]; |
1194 | |
1195 | /** |
1196 | The number of rows affected by the last statement. This is |
1197 | semantically close to thd->m_row_count_func, but has a different |
1198 | life cycle. thd->m_row_count_func stores the value returned by |
1199 | function ROW_COUNT() and is cleared only by statements that |
1200 | update its value, such as INSERT, UPDATE, DELETE and few others. |
1201 | This member is cleared at the beginning of the next statement. |
1202 | |
1203 | We could possibly merge the two, but life cycle of thd->m_row_count_func |
1204 | can not be changed. |
1205 | */ |
1206 | ulonglong m_affected_rows; |
1207 | |
1208 | /** |
1209 | Similarly to the previous member, this is a replacement of |
1210 | thd->first_successful_insert_id_in_prev_stmt, which is used |
1211 | to implement LAST_INSERT_ID(). |
1212 | */ |
1213 | |
1214 | ulonglong m_last_insert_id; |
1215 | /** |
1216 | Number of warnings of this last statement. May differ from |
1217 | the number of warnings returned by SHOW WARNINGS e.g. in case |
1218 | the statement doesn't clear the warnings, and doesn't generate |
1219 | them. |
1220 | */ |
1221 | uint m_statement_warn_count; |
1222 | |
1223 | enum_diagnostics_status m_status; |
1224 | |
1225 | my_bool is_bulk_execution; |
1226 | |
1227 | Warning_info m_main_wi; |
1228 | |
1229 | Warning_info_list m_wi_stack; |
1230 | }; |
1231 | |
1232 | /////////////////////////////////////////////////////////////////////////// |
1233 | |
1234 | |
1235 | void push_warning(THD *thd, Sql_condition::enum_warning_level level, |
1236 | uint code, const char *msg); |
1237 | |
1238 | void push_warning_printf(THD *thd, Sql_condition::enum_warning_level level, |
1239 | uint code, const char *format, ...); |
1240 | |
1241 | bool mysqld_show_warnings(THD *thd, ulong levels_to_show); |
1242 | |
1243 | size_t convert_error_message(char *to, size_t to_length, |
1244 | CHARSET_INFO *to_cs, |
1245 | const char *from, size_t from_length, |
1246 | CHARSET_INFO *from_cs, uint *errors); |
1247 | |
1248 | extern const LEX_CSTRING warning_level_names[]; |
1249 | |
1250 | bool is_sqlstate_valid(const LEX_CSTRING *sqlstate); |
1251 | /** |
1252 | Checks if the specified SQL-state-string defines COMPLETION condition. |
1253 | This function assumes that the given string contains a valid SQL-state. |
1254 | |
1255 | @param s the condition SQLSTATE. |
1256 | |
1257 | @retval true if the given string defines COMPLETION condition. |
1258 | @retval false otherwise. |
1259 | */ |
1260 | inline bool is_sqlstate_completion(const char *s) |
1261 | { return s[0] == '0' && s[1] == '0'; } |
1262 | |
1263 | |
1264 | #endif // SQL_ERROR_H |
1265 | |