You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

539 lines
16 KiB

Auto-merge from mysql-trunk-bugfixing. ****** This patch fixes the following bugs: - Bug#5889: Exit handler for a warning doesn't hide the warning in trigger - Bug#9857: Stored procedures: handler for sqlwarning ignored - Bug#23032: Handlers declared in a SP do not handle warnings generated in sub-SP - Bug#36185: Incorrect precedence for warning and exception handlers The problem was in the way warnings/errors during stored routine execution were handled. Prior to this patch the logic was as follows: - when a warning/an error happens: if we're executing a stored routine, and there is a handler for that warning/error, remember the handler, ignore the warning/error and continue execution. - after a stored routine instruction is executed: check for a remembered handler and activate one (if any). This logic caused several problems: - if one instruction generates several warnings (errors) it's impossible to choose the right handler -- a handler for the first generated condition was chosen and remembered for activation. - mess with handling conditions in scopes different from the current one. - not putting generated warnings/errors into Warning Info (Diagnostic Area) is against The Standard. The patch changes the logic as follows: - Diagnostic Area is cleared on the beginning of each statement that either is able to generate warnings, or is able to work with tables. - at the end of a stored routine instruction, Diagnostic Area is left intact. - Diagnostic Area is checked after each stored routine instruction. If an instruction generates several condition, it's now possible to take a look at all of them and determine an appropriate handler.
16 years ago
  1. /* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
  2. This program is free software; you can redistribute it and/or modify
  3. it under the terms of the GNU General Public License as published by
  4. the Free Software Foundation; version 2 of the License.
  5. This program is distributed in the hope that it will be useful,
  6. but WITHOUT ANY WARRANTY; without even the implied warranty of
  7. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  8. GNU General Public License for more details.
  9. You should have received a copy of the GNU General Public License
  10. along with this program; if not, write to the Free Software
  11. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
  12. #ifndef SQL_ERROR_H
  13. #define SQL_ERROR_H
  14. #include "sql_list.h" /* Sql_alloc, MEM_ROOT */
  15. #include "m_string.h" /* LEX_STRING */
  16. #include "sql_string.h" /* String */
  17. #include "mysql_com.h" /* MYSQL_ERRMSG_SIZE */
  18. class THD;
  19. /**
  20. Stores status of the currently executed statement.
  21. Cleared at the beginning of the statement, and then
  22. can hold either OK, ERROR, or EOF status.
  23. Can not be assigned twice per statement.
  24. */
  25. class Diagnostics_area
  26. {
  27. public:
  28. enum enum_diagnostics_status
  29. {
  30. /** The area is cleared at start of a statement. */
  31. DA_EMPTY= 0,
  32. /** Set whenever one calls my_ok(). */
  33. DA_OK,
  34. /** Set whenever one calls my_eof(). */
  35. DA_EOF,
  36. /** Set whenever one calls my_error() or my_message(). */
  37. DA_ERROR,
  38. /** Set in case of a custom response, such as one from COM_STMT_PREPARE. */
  39. DA_DISABLED
  40. };
  41. /** True if status information is sent to the client. */
  42. bool is_sent;
  43. /** Set to make set_error_status after set_{ok,eof}_status possible. */
  44. bool can_overwrite_status;
  45. void set_ok_status(THD *thd, ulonglong affected_rows_arg,
  46. ulonglong last_insert_id_arg,
  47. const char *message);
  48. void set_eof_status(THD *thd);
  49. void set_error_status(THD *thd, uint sql_errno_arg, const char *message_arg,
  50. const char *sqlstate);
  51. void disable_status();
  52. void reset_diagnostics_area();
  53. bool is_set() const { return m_status != DA_EMPTY; }
  54. bool is_error() const { return m_status == DA_ERROR; }
  55. bool is_eof() const { return m_status == DA_EOF; }
  56. bool is_ok() const { return m_status == DA_OK; }
  57. bool is_disabled() const { return m_status == DA_DISABLED; }
  58. enum_diagnostics_status status() const { return m_status; }
  59. const char *message() const
  60. { DBUG_ASSERT(m_status == DA_ERROR || m_status == DA_OK); return m_message; }
  61. uint sql_errno() const
  62. { DBUG_ASSERT(m_status == DA_ERROR); return m_sql_errno; }
  63. const char* get_sqlstate() const
  64. { DBUG_ASSERT(m_status == DA_ERROR); return m_sqlstate; }
  65. ulonglong affected_rows() const
  66. { DBUG_ASSERT(m_status == DA_OK); return m_affected_rows; }
  67. ulonglong last_insert_id() const
  68. { DBUG_ASSERT(m_status == DA_OK); return m_last_insert_id; }
  69. uint statement_warn_count() const
  70. {
  71. DBUG_ASSERT(m_status == DA_OK || m_status == DA_EOF);
  72. return m_statement_warn_count;
  73. }
  74. Diagnostics_area() { reset_diagnostics_area(); }
  75. private:
  76. /** Message buffer. Can be used by OK or ERROR status. */
  77. char m_message[MYSQL_ERRMSG_SIZE];
  78. /**
  79. SQL error number. One of ER_ codes from share/errmsg.txt.
  80. Set by set_error_status.
  81. */
  82. uint m_sql_errno;
  83. char m_sqlstate[SQLSTATE_LENGTH+1];
  84. /**
  85. The number of rows affected by the last statement. This is
  86. semantically close to thd->row_count_func, but has a different
  87. life cycle. thd->row_count_func stores the value returned by
  88. function ROW_COUNT() and is cleared only by statements that
  89. update its value, such as INSERT, UPDATE, DELETE and few others.
  90. This member is cleared at the beginning of the next statement.
  91. We could possibly merge the two, but life cycle of thd->row_count_func
  92. can not be changed.
  93. */
  94. ulonglong m_affected_rows;
  95. /**
  96. Similarly to the previous member, this is a replacement of
  97. thd->first_successful_insert_id_in_prev_stmt, which is used
  98. to implement LAST_INSERT_ID().
  99. */
  100. ulonglong m_last_insert_id;
  101. /**
  102. Number of warnings of this last statement. May differ from
  103. the number of warnings returned by SHOW WARNINGS e.g. in case
  104. the statement doesn't clear the warnings, and doesn't generate
  105. them.
  106. */
  107. uint m_statement_warn_count;
  108. enum_diagnostics_status m_status;
  109. };
  110. ///////////////////////////////////////////////////////////////////////////
  111. /**
  112. Representation of a SQL condition.
  113. A SQL condition can be a completion condition (note, warning),
  114. or an exception condition (error, not found).
  115. @note This class is named MYSQL_ERROR instead of SQL_condition for
  116. historical reasons, to facilitate merging code with previous releases.
  117. */
  118. class MYSQL_ERROR : public Sql_alloc
  119. {
  120. public:
  121. /*
  122. Enumeration value describing the severity of the error.
  123. Note that these enumeration values must correspond to the indices
  124. of the sql_print_message_handlers array.
  125. */
  126. enum enum_warning_level
  127. { WARN_LEVEL_NOTE, WARN_LEVEL_WARN, WARN_LEVEL_ERROR, WARN_LEVEL_END};
  128. /**
  129. Get the MESSAGE_TEXT of this condition.
  130. @return the message text.
  131. */
  132. const char* get_message_text() const;
  133. /**
  134. Get the MESSAGE_OCTET_LENGTH of this condition.
  135. @return the length in bytes of the message text.
  136. */
  137. int get_message_octet_length() const;
  138. /**
  139. Get the SQLSTATE of this condition.
  140. @return the sql state.
  141. */
  142. const char* get_sqlstate() const
  143. { return m_returned_sqlstate; }
  144. /**
  145. Get the SQL_ERRNO of this condition.
  146. @return the sql error number condition item.
  147. */
  148. uint get_sql_errno() const
  149. { return m_sql_errno; }
  150. /**
  151. Get the error level of this condition.
  152. @return the error level condition item.
  153. */
  154. MYSQL_ERROR::enum_warning_level get_level() const
  155. { return m_level; }
  156. private:
  157. /*
  158. The interface of MYSQL_ERROR is mostly private, by design,
  159. so that only the following code:
  160. - various raise_error() or raise_warning() methods in class THD,
  161. - the implementation of SIGNAL / RESIGNAL
  162. - catch / re-throw of SQL conditions in stored procedures (sp_rcontext)
  163. is allowed to create / modify a SQL condition.
  164. Enforcing this policy prevents confusion, since the only public
  165. interface available to the rest of the server implementation
  166. is the interface offered by the THD methods (THD::raise_error()),
  167. which should be used.
  168. */
  169. friend class THD;
  170. friend class Warning_info;
  171. friend class Signal_common;
  172. friend class Signal_statement;
  173. friend class Resignal_statement;
  174. friend class sp_rcontext;
  175. /**
  176. Default constructor.
  177. This constructor is usefull when allocating arrays.
  178. Note that the init() method should be called to complete the MYSQL_ERROR.
  179. */
  180. MYSQL_ERROR();
  181. /**
  182. Complete the MYSQL_ERROR initialisation.
  183. @param mem_root The memory root to use for the condition items
  184. of this condition
  185. */
  186. void init(MEM_ROOT *mem_root);
  187. /**
  188. Constructor.
  189. @param mem_root The memory root to use for the condition items
  190. of this condition
  191. */
  192. MYSQL_ERROR(MEM_ROOT *mem_root);
  193. /** Destructor. */
  194. ~MYSQL_ERROR()
  195. {}
  196. /**
  197. Copy optional condition items attributes.
  198. @param cond the condition to copy.
  199. */
  200. void copy_opt_attributes(const MYSQL_ERROR *cond);
  201. /**
  202. Set this condition area with a fixed message text.
  203. @param thd the current thread.
  204. @param code the error number for this condition.
  205. @param str the message text for this condition.
  206. @param level the error level for this condition.
  207. @param MyFlags additional flags.
  208. */
  209. void set(uint sql_errno, const char* sqlstate,
  210. MYSQL_ERROR::enum_warning_level level,
  211. const char* msg);
  212. /**
  213. Set the condition message test.
  214. @param str Message text, expressed in the character set derived from
  215. the server --language option
  216. */
  217. void set_builtin_message_text(const char* str);
  218. /** Set the SQLSTATE of this condition. */
  219. void set_sqlstate(const char* sqlstate);
  220. /**
  221. Clear this SQL condition.
  222. */
  223. void clear();
  224. private:
  225. /** SQL CLASS_ORIGIN condition item. */
  226. String m_class_origin;
  227. /** SQL SUBCLASS_ORIGIN condition item. */
  228. String m_subclass_origin;
  229. /** SQL CONSTRAINT_CATALOG condition item. */
  230. String m_constraint_catalog;
  231. /** SQL CONSTRAINT_SCHEMA condition item. */
  232. String m_constraint_schema;
  233. /** SQL CONSTRAINT_NAME condition item. */
  234. String m_constraint_name;
  235. /** SQL CATALOG_NAME condition item. */
  236. String m_catalog_name;
  237. /** SQL SCHEMA_NAME condition item. */
  238. String m_schema_name;
  239. /** SQL TABLE_NAME condition item. */
  240. String m_table_name;
  241. /** SQL COLUMN_NAME condition item. */
  242. String m_column_name;
  243. /** SQL CURSOR_NAME condition item. */
  244. String m_cursor_name;
  245. /** Message text, expressed in the character set implied by --language. */
  246. String m_message_text;
  247. /** MySQL extension, MYSQL_ERRNO condition item. */
  248. uint m_sql_errno;
  249. /**
  250. SQL RETURNED_SQLSTATE condition item.
  251. This member is always NUL terminated.
  252. */
  253. char m_returned_sqlstate[SQLSTATE_LENGTH+1];
  254. /** Severity (error, warning, note) of this condition. */
  255. MYSQL_ERROR::enum_warning_level m_level;
  256. /** Memory root to use to hold condition item values. */
  257. MEM_ROOT *m_mem_root;
  258. };
  259. ///////////////////////////////////////////////////////////////////////////
  260. /**
  261. Information about warnings of the current connection.
  262. */
  263. class Warning_info
  264. {
  265. /** A memory root to allocate warnings and errors */
  266. MEM_ROOT m_warn_root;
  267. /** List of warnings of all severities (levels). */
  268. List <MYSQL_ERROR> m_warn_list;
  269. /** A break down of the number of warnings per severity (level). */
  270. uint m_warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_END];
  271. /**
  272. The number of warnings of the current statement. Warning_info
  273. life cycle differs from statement life cycle -- it may span
  274. multiple statements. In that case we get
  275. m_statement_warn_count 0, whereas m_warn_list is not empty.
  276. */
  277. uint m_statement_warn_count;
  278. /*
  279. Row counter, to print in errors and warnings. Not increased in
  280. create_sort_index(); may differ from examined_row_count.
  281. */
  282. ulong m_current_row_for_warning;
  283. /** Used to optionally clear warnings only once per statement. */
  284. ulonglong m_warn_id;
  285. /** Indicates if push_warning() allows unlimited number of warnings. */
  286. bool m_allow_unlimited_warnings;
  287. private:
  288. Warning_info(const Warning_info &rhs); /* Not implemented */
  289. Warning_info& operator=(const Warning_info &rhs); /* Not implemented */
  290. public:
  291. Warning_info(ulonglong warn_id_arg, bool allow_unlimited_warnings);
  292. ~Warning_info();
  293. /**
  294. Reset the warning information. Clear all warnings,
  295. the number of warnings, reset current row counter
  296. to point to the first row.
  297. */
  298. void clear_warning_info(ulonglong warn_id_arg);
  299. /**
  300. Only clear warning info if haven't yet done that already
  301. for the current query. Allows to be issued at any time
  302. during the query, without risk of clearing some warnings
  303. that have been generated by the current statement.
  304. @todo: This is a sign of sloppy coding. Instead we need to
  305. designate one place in a statement life cycle where we call
  306. clear_warning_info().
  307. */
  308. void opt_clear_warning_info(ulonglong query_id)
  309. {
  310. if (query_id != m_warn_id)
  311. clear_warning_info(query_id);
  312. }
  313. void append_warning_info(THD *thd, Warning_info *source)
  314. {
  315. append_warnings(thd, & source->warn_list());
  316. }
  317. /**
  318. Concatenate the list of warnings.
  319. It's considered tolerable to lose a warning.
  320. */
  321. void append_warnings(THD *thd, List<MYSQL_ERROR> *src)
  322. {
  323. MYSQL_ERROR *err;
  324. List_iterator_fast<MYSQL_ERROR> it(*src);
  325. /*
  326. Don't use ::push_warning() to avoid invocation of condition
  327. handlers or escalation of warnings to errors.
  328. */
  329. while ((err= it++))
  330. Warning_info::push_warning(thd, err);
  331. }
  332. /**
  333. Conditional merge of related warning information areas.
  334. */
  335. void merge_with_routine_info(THD *thd, Warning_info *source);
  336. /**
  337. Reset between two COM_ commands. Warnings are preserved
  338. between commands, but statement_warn_count indicates
  339. the number of warnings of this particular statement only.
  340. */
  341. void reset_for_next_command() { m_statement_warn_count= 0; }
  342. /**
  343. Used for @@warning_count system variable, which prints
  344. the number of rows returned by SHOW WARNINGS.
  345. */
  346. ulong warn_count() const
  347. {
  348. /*
  349. This may be higher than warn_list.elements if we have
  350. had more warnings than thd->variables.max_error_count.
  351. */
  352. return (m_warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_NOTE] +
  353. m_warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_ERROR] +
  354. m_warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_WARN]);
  355. }
  356. /**
  357. This is for iteration purposes. We return a non-constant reference
  358. since List doesn't have constant iterators.
  359. */
  360. List<MYSQL_ERROR> &warn_list() { return m_warn_list; }
  361. /**
  362. The number of errors, or number of rows returned by SHOW ERRORS,
  363. also the value of session variable @@error_count.
  364. */
  365. ulong error_count() const
  366. {
  367. return m_warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_ERROR];
  368. }
  369. /** Id of the warning information area. */
  370. ulonglong warn_id() const { return m_warn_id; }
  371. /** Do we have any errors and warnings that we can *show*? */
  372. bool is_empty() const { return m_warn_list.elements == 0; }
  373. /** Increment the current row counter to point at the next row. */
  374. void inc_current_row_for_warning() { m_current_row_for_warning++; }
  375. /** Reset the current row counter. Start counting from the first row. */
  376. void reset_current_row_for_warning() { m_current_row_for_warning= 1; }
  377. /** Return the current counter value. */
  378. ulong current_row_for_warning() const { return m_current_row_for_warning; }
  379. ulong statement_warn_count() const { return m_statement_warn_count; }
  380. /** Add a new condition to the current list. */
  381. MYSQL_ERROR *push_warning(THD *thd,
  382. uint sql_errno, const char* sqlstate,
  383. MYSQL_ERROR::enum_warning_level level,
  384. const char* msg);
  385. /** Add a new condition to the current list. */
  386. MYSQL_ERROR *push_warning(THD *thd, const MYSQL_ERROR *sql_condition);
  387. /**
  388. Set the read only status for this statement area.
  389. This is a privileged operation, reserved for the implementation of
  390. diagnostics related statements, to enforce that the statement area is
  391. left untouched during execution.
  392. The diagnostics statements are:
  393. - SHOW WARNINGS
  394. - SHOW ERRORS
  395. - GET DIAGNOSTICS
  396. @param read_only the read only property to set
  397. */
  398. void set_read_only(bool read_only)
  399. { m_read_only= read_only; }
  400. /**
  401. Read only status.
  402. @return the read only property
  403. */
  404. bool is_read_only() const
  405. { return m_read_only; }
  406. private:
  407. /** Read only status. */
  408. bool m_read_only;
  409. friend class Resignal_statement;
  410. };
  411. extern char *err_conv(char *buff, uint to_length, const char *from,
  412. uint from_length, CHARSET_INFO *from_cs);
  413. class ErrConvString
  414. {
  415. char err_buffer[MYSQL_ERRMSG_SIZE];
  416. public:
  417. ErrConvString(String *str)
  418. {
  419. (void) err_conv(err_buffer, sizeof(err_buffer), str->ptr(),
  420. str->length(), str->charset());
  421. }
  422. ErrConvString(const char *str, CHARSET_INFO* cs)
  423. {
  424. (void) err_conv(err_buffer, sizeof(err_buffer),
  425. str, strlen(str), cs);
  426. }
  427. ErrConvString(const char *str, uint length, CHARSET_INFO* cs)
  428. {
  429. (void) err_conv(err_buffer, sizeof(err_buffer),
  430. str, length, cs);
  431. }
  432. ~ErrConvString() { };
  433. char *ptr() { return err_buffer; }
  434. };
  435. void push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level,
  436. uint code, const char *msg);
  437. void push_warning_printf(THD *thd, MYSQL_ERROR::enum_warning_level level,
  438. uint code, const char *format, ...);
  439. bool mysqld_show_warnings(THD *thd, ulong levels_to_show);
  440. uint32 convert_error_message(char *to, uint32 to_length, CHARSET_INFO *to_cs,
  441. const char *from, uint32 from_length,
  442. CHARSET_INFO *from_cs, uint *errors);
  443. extern const LEX_STRING warning_level_names[];
  444. #endif // SQL_ERROR_H