WL#5928: Most statements should clear the diagnostic area
Affects: Server-5.7
—
Status: Complete
According to the SQL standard, the first diagnostics area should be emptied at the beginning of the execution of anythat is not an . Currently, MySQL clears the diagnostic area as follows (start quote): * When the server starts executing a statement after parsing it, it clears the diagnostics area for nondiagnostic statements that use tables. Diagnostic statements are SHOW WARNINGS, SHOW ERRORS, and GET DIAGNOSTICS. * If a statement raises a condition, the diagnostics area is cleared of conditions that belong to earlier statements. The exception is that conditions raised by GET DIAGNOSTICS and RESIGNAL are added to the diagnostics area without clearing it. Thus, even a statement that does not normally clear the diagnostics area when it begins executing clears it if the statement raises a condition. Quoted from http://dev.mysql.com/doc/refman/5.6/en/diagnostics-area.html#diagnostics-area- populating This worklog is about changing MySQL to follow the SQL standard with respect to clearing the diagnostic area. This means that: 1) We will also clear the diagnostic area for non-diagnostic statments that does not use tables. 2) Clearing the diagnostic area should be done at one well-defined point during statement execution. User Documentation ================== http://dev.mysql.com/doc/refman/5.7/en/show-warnings.html http://dev.mysql.com/doc/refman/5.7/en/diagnostics-area.html#diagnostics-area- populating http://dev.mysql.com/doc/relnotes/mysql/5.7/en/news-5-7-2.html
REQUIREMENTS Func-Req (1.1) If an exception condition is raised during parsing, it must become the sole contents of the diagnostics area, and an error status must be sent. Func-Req (1.2) If parsing completes successfully and a diagnostics statement is detected, it shall return data of the diagnostics area describing the command executed in the previous cycle. Func-Req (1.3) In all other cases, the diagnostics area shall be cleared, and the command executed. Func-Req (1.4) During TRIGGER excution, Warnings shall be suppressed, whereas exceptions are thrown (SQL 2008, Foundation, 15.19 k). Func-Req (1.5) After the execution of a STORED PROCEDURE, the diagnostics area shall reflect the execution of the last (non-diagnostics) procedure statement (e.g. the sole statement in the routine body, the last statement before the END of the outmost compound statement, etc.). Func-Req (1.6) After the execution of a STORED FUNCTION, the diagnostics area shall reflect the execution of the last (non-diagnostics) procedure statement (the RETURN statement). Func-Req (1.6.1) The caller (e.g. SELECT ...) of a STORED FUNCTION may however aggregate the conditions from all stored functions it calls: if f1() throws a warning, SELECT f1(),f1(),f1(); SHOW WARNINGS; will show a list of three warnings. This is implementation-defined. Func-Req (1.7) If the result set for a SELECT can be returned from the QUERY CACHE, it must still clear the diagnostics area. The diagnostics area will not be populated with any conditions generated in the original execution. DISCUSSION [See below in Low level design for relevant excerpts from the SQL standard and nomenclature.] The MySQL Reference Manual says for SHOW WARNINGS: "Statements that do not use tables and do not generate messages have no effect on the message list." http://dev.mysql.com/doc/refman/5.6/en/show-warnings.html And it says for the error_count system variable: "The number of errors that resulted from the last statement that generated messages." http://dev.mysql.com/doc/refman/5.6/en/server-system-variables.html And it says for the warning_count system variable: "The number of errors, warnings, and notes that resulted from the last statement that generated messages." http://dev.mysql.com/doc/refman/5.6/en/server-system-variables.html Example: mysql> DROP TABLE no_such_table; ERROR 1051 (42S02): Unknown table 'test.no_such_table' mysql> CREATE EVENT e ON SCHEDULE EVERY 1 SECOND DO DELETE FROM t; Query OK, 0 rows affected (0.35 sec) mysql> SHOW ERRORS; +-------+------+------------------------------------+ | Level | Code | Message | +-------+------+------------------------------------+ | Error | 1051 | Unknown table 'test.no_such_table' | +-------+------+------------------------------------+ 1 row in set (0.00 sec) In this example SHOW ERRORS is showing the results of the DROP TABLE statement, not the CREATE EVENT statement, because the CREATE EVENT statement was successful and did not "use" a table. Terminology ----------- The word "used" in the quote from the manual means "actually used" not "effectively used" There's effective use of tables when one needs a privilege, or drops a database, or repeats a cached query, or refers to a table in CREATE EVENT, etc. That doesn't matter -- it's not actual use.) The "message list" is sometimes called the "warning stack". It is analogous to one diagnostics stack in standard SQL but its content and behaviour are not as in standard SQL. What the change would be ------------------------ Generally speaking, after the change, all statements that can say "okay" will say "okay". This means the message list will be cleared, SHOW ERRORS and SHOW WARNINGS would return an empty set, and GET DIAGNOSTICS would show a completion condition. Actually, not quite "all" statements. We exclude: * Statements that aren't executed. Our current examples are DECLARE condition DECLARE handler (Not DECLARE variable, which is capable of causing errors) * Diagnostics statements. Our current examples are SHOW ERRORS SHOW WARNINGS GET DIAGNOSTICS SHOW COUNT(*) ERRORS SHOW COUNT(*) WARNINGS * SELECT @@error_count | @@warning_count will be supported for the time being in that SELECT @@warning_count will return the same result as SHOW COUNT(*) WARNINGS, and SELECT @@error_count will reflect SHOW COUNT(*) ERRORS. However, as these are, in a manner of speaking, "diagnostics variables" but SELECT etc. are not diagnostics statements, SHOW COUNT(*) ... are repeatable, whereas SELECT @@warning_count | @@error_count are NOT repeatable -- they will give correct results when issued as the first non-diagnostics statement after the statement whose diagnostics we're interested in; it will however then clear the diagnostics area (and populate it with any conditions that may arise during its own execution). At this point, any diagnostics statements or non-diagnostics statements querying these "diagnostics variables" will pertain to the results of the SELECT: DROP TABLE non_existent; SHOW WARNINGS; # will give warnings SHOW WARNINGS; # will still give the warnings about non-existent table GET DIAGNOSTICS @n = number; GET DIAGNOSTICS ... SELECT @@warning_count; # this will still render "1" ("no such table"), but the DA will be # cleared due to SELECT not being a diagnostics statement. If any # conditions are raised during this SELECT, we will now see THOSE # conditions instead of "no such table", otherwise, an empty list: SHOW WARNINGS; @@error_count and @@warning_count are MySQL specific extensions support for which may be dropped at a later date. * As a special case, if f() throws one warning, we now support that SELECT f(), f(), f(); will result in a condition list containing three warnings: As all these warnings are raised within the scope of the same statement (e.g. SELECT), they are accumulated. * The standard requires that diagnostics statements are not preparable (Foundation 2007, 4.33.7). Trying to prepare GET DIAGNOSTICS ... will fail (as it already did) with ER_UNSUPPORTED_PS; additionally, SHOW [COUNT(*)] ERRORS|WARNINGS and use of @@error_count | @@warning_count are now unsupported in prepared statements. * As a general rule, if one is interested in the conditions raised by a statement, one is required to query them right away (preferably using the GET DIAGNOSTICS interface), as any later statements will clear the diagnostics area (except in the few cases enumerated above, as per the standard -- essentially, diagnostics statements, and some statements that are not executed (i.e. used at define-time of a stored program, not at runtime)). These rules also hold within compound statements (whether in handlers or otherwise); a compound statement is not "one statement" in the sense that any enclosing block would see the accumulated warnings raised by all statements in the enclosed compound statement. If a warning is not handled, it will be cleared by the next non-diagnostics statement in the compound statement; only warnings raised by the last statement in the block will be seen by the next statement outside the block. If an error is not handled, execution of the compound statement will be aborted, and the next statement outside the block will see the error. Any unhandled error/warning conditions "seen outside the block" shall fire any appropriate handlers there. Understanding this behavior is key to correct use of DECLARE HANDLER. Why keep the behaviour? ----------------------- The only known reason for keeping the behaviour is the fear that we'd break an existing application that wants to know the result from a significant earlier statement. Why change the behaviour? ------------------------- Three bug reports have comments mentioning the "use tables and generate messages" rule: BUG#35296 CREATE EVENT does not clear warnings. Reporter: Paul DuBois. BUG#43012 Bad error message handling in "drop database". Reporter: Jorgen Loland. BUG#49634 Cached queries do not clear warnings. Reporter: Daniel Nichter. Although they were declared "not a bug" or else not really fixed, their existence shows that even MySQL employees expect to see cleared message lists after successful non-message-generating statements. Also, clearing message lists would be closer to standard SQL. mysql_error() and mysql_errno() ------------------------------- The MySQL Reference Manual says for mysql_error() in the API: "If a function didn't fail, the return value of mysql_error() may be the previous error or an empty string to indicate no error. A rule of thumb is that all functions that have to ask the server for information reset mysql_error() if they succeed." http://dev.mysql.com/doc/refman/5.6/en/mysql-error.html In 2003 Georg Richter posted a bug report about this behaviour: BUG#706 mysql_fetch_row doesn't reset errorcode. But Monty Widenius declared it "not a bug" and explained "This is not a bug. The intention is that mysql_error() and mysql_errno() are only well defined if you get an error for the previous statement. (A bit like 'errno' in C)." Peter thought this is a similar case. Davi didn't. We won't directly do anything about it.
1 DIRECT INVOCATION 1.01 - At the start of interactive processing ("the cycle"), a temporary diagnostics area is pushed to the stack. 1.02 - Then, the parser is run. 1.03 - Based on whether a diagnostics statement is detected, the parser will flag for preservation of the previous cycle's diagnostics area, so when a diagnostics statement is actually executed later, it will have the necessary data to describe the previous command. 1.04 - After parsing, the parsing-DA is popped. 1.05 - If any conditions are raised during parsing, the main DA shall be cleared and populated with the conditions raised during parsing. (SQL 2008 Foundation 22.1 5) 1.06 - If any exception conditions were raised during parsing, the cycle ends here. 1.07 - If no conditions were raised during parsing, and the detected statement is not diagnost, the DA shall be cleared. (SQL 2008 Foundation 22.1 6b v) 1.08 - If no conditions were raised during parsing, and the detected statement is a diagnostics statement, the DA remains unmodified at this stage, so the statement has the necessary data to return diagnostics pertaining to the statement executed in the previous cycle. (SQL 2008 Foundation 23.1 2 a) 1.09 - The statement will be executed, possibly adding new conditions to the diagnostics area. This specifically means that a non diagnostics statement will start populating the DA (SQL 2008 Foundation 22.1 10), whereas a diagnostics statement will not modify the DA describing the previous statement's execution unless an exception condition is raised while executing the diagnostics statement. (SQL 2008 Foundation 23.1 3) 1.10 - OK/EOF/Error is sent to the client. 1.11 - The cycle ends. 2 STORED PROGRAMS 2.01 Instructions used in stored programs may fall into one of three classes each: 2.01.1 SP-statements that preserve the DA (requiring for it not be cleared pre-execution) 2.01.2 SP-statements that require the DA to be cleared pre-execution 2.01.3 SQL-statements that require the DA to be cleared pre-execution, but that are executed through stages 1.07 - 1.10, so any clearing of the DA may be deferred to the mechanisms already in place there. 3 QUERY CACHE 3.01 As the query cache bypasses normal parsing/execution (and DA clearing), the DA needs to be cleared explicitly on cache hits. Once the query cache identifies the current statement as potentially cacheable (QC is activated, query is a SELECT, doesn't have SQL_NO_CACHE, etc.), the diagnostics area will therefore be cleared. This is safe as at this point the statement is known not to be a diagnostics statement. As the QC has three callers (SP, PS, interactive), the clearing of the diagnostics area happens in send_result_to_client(). ad 1.03 - flagging diagnostics statements Parser shall set lex->keep_diagnostics, which shall default to false, to true for statements which must not clear the DA. sql/sql_lex.cc: lex_start() shall set the default, lex->keep_diagnostics= false; sql/sql_lex.h: add bool keep_diagnostics; to struct LEX: public Query_tables_list, somewhat similar to bool contains_plaintext_password sql/sql_yacc.yy: eligible commands set lex->keep_diagnostics= true; at this point, that's DECLARE COND, DECLARE HANDLER, GET DIAGNOSTICS, COUNT (*) WARNINGS, COUNT (*) ERRORS, SHOW WARNINGS, SHOW ERRORS, and CALL. The inclusion of CALL in this list is pending further updates. BEGIN...END is part of the sp_block_content rule, which itself gets wrapped in sp_[un]labeled_block. TABLE OF CHANGES TO NON-INTERACTIVE STATEMENTS, AND THEIR JUSTIFICATION IN THE SQL STANDARD Compound: new behavior: does NOT count as "one statement" in that the warnings of the individual statements are not accumulated; each sub statement of the compound clears the DA in the regular way; if an error occurs, we either error out of the compound, in which case the DA is there for the caller, or we ignore the error and the DA will be cleared when the next stmt is executed. Standard: SQL 2008, Foundation, 4.30 SF: new behavior: after SF, DA will be set with results of last non diag stmt (as per the standard), i.e. RETURN. merge conditions from all called SF. old behavior: suppression not requested by caller, warnings may or may not survive depending on the vagaries of the current DA clearing. where: sp_head.cc: execute_function->execute(thd, TRUE); Standard: Foundation, 4.30 (DA reflects last stmt) Standard doesn't seem to forbid adding conditions of ALL called SF to current caller (e.g. SELECT) SP: new behavior: DA reflects last (non-diag) stmt only old behavior: suppression not requested by caller, warnings may or may not survive depending on the vagaries of the current DA clearing. where: sp_head.cc: execute_procedure->execute(thd, TRUE) Standard: Foundation, 4.30 (DA reflects last stmt) Trigger: new behavior: warnings are suppressed old behavior: warnings are suppressed where: sp_head.cc: execute_trigger->execute(thd, FALSE) Standard: SQL 2008, Foundation, 15.19 k) - failing exceptions bubble up NOMENCLATURE AND REQUIREMENT IN THE SQL STANDARD OF 2008, AND ASSUMPTIONS PERTAINING THERETO from SQL Standard, "Foundation" 4.29.2 Status parameters [ERR] "If a condition is raised that causes a statement to have no effect other than that associated with raising the condition (that is, not a completion condition), then the condition is said to be an 'exception condition' or 'exception.'" [WARN/OK] "If a condition is raised that permits a statement to have an effect other than that associated with raising the condition (corresponding to an SQLSTATE class value of successful completion, warning, or no data), then the condition is said to be a 'completion condition.' [...] The completion condition 'no data' has special significance and is used to indicate an empty result." [NOTE / INFORMATION] "The completion condition 'successful completion' is defined to indicate a completion condition that does not correspond to warning or no data. This includes conditions in which the SQLSTATE subclass provides implementation-defined information of a non-cautionary nature." "For the purpose of choosing status parameter values to be returned, exception conditions for transaction rollback have precedence over exception conditions for statement failure. Similarly, the completion condition no data has precedence over the completion condition warning, which has precedence over the completion condition successful completion. All exception conditions have precedence over all completion conditions. The values assigned to SQLSTATE shall obey these precedence requirements." 4.30 Diagnostics area "The ordering of the information about conditions placed into a diagnostics area is implementationdependent, except that the first condition area in a diagnostics area always corresponds to the condition specified by the SQLSTATE value." [We violate that last bit, but that's a documented issue and not something we'll have to resolve here.] "A statement information item gives information about the *innermost* SQL-statement that is being executed when a condition is raised. A condition information item gives information about the condition itself." [If warnings are generated at various points of stored program execution, the caller will NOT see them, as each new non-diagnostics statement will clear the diagnostics area. After stored program execution, the DA will therefore not contain the sum of all warnings thrown; the stored program call is not treated as one (compound) statement in that respect. The diagnostics area found after execution is that of the last non-diagnostics statement executed, with any non exceptional conditions, i.e. warnings, thrown by any diagnostics statements following said last non-diagnostics statement appended to the diagnostics area.] "At the beginning of the execution of anythat is not an , the first diagnostics area is emptied. An implementation places information about a completion condition or an exception condition reported by SQLSTATE into a vacant condition area in this diagnostics area. If other conditions are raised, the extent to which these cause further condition areas to become occupied is implementation-defined." 13.5 Format - OPEN, FETCH, CLOSE are SQL procedure statements - PREPARE, EXECUTE, DEALLOCATE are SQL dynamic statements, and therefore SQL procedure statements - CALL and RETURN are SQL control statements, and therefore SQL procedure statements General rules, 11 "If S is not an , then diagnostics information resulting from the execution of S is placed into the first diagnostics area, causing the first condition area in the first diagnostics area to become occupied. Whether any other condition areas become occupied is implementation-defined." 15.19 Execution of triggers General rules, 5 k) If the execution of TSS is not successful, then an exception condition is raised: triggered action exception. The exception condition that caused TSS to fail is raised. NOTE 430 Raising the exception condition that caused TSS to fail enters the exception information into the diagnostics area that was pushed prior to the execution of TSS. 20.13 General rules 3, "Exception condition or completion condition information resulting from the PREPARE or EXECUTE is reflected in the diagnostics area." 22.1 General rules 5) If S does not conform to the Format, Syntax Rules, and Access Rules for a , then an exception condition is raised: syntax error or access rule violation. 6b v) "The first diagnostics area is emptied." (before execution) 10) Diagnostics information resulting from the execution of S is placed into the first diagnostics area, causing the first condition area in the first diagnostics area to become occupied. NOTE 473 The method of accessing the diagnostics information is implementation-defined, but does not alter the contents of the diagnostics area. 23.1 23.1 2 a) NOTE 474 The itself may return information via the SQLSTATE parameter, but does not modify the previous contents of DA. 3) If is specified, then let N be the value of . If N is less than 1 (one) or greater than the number of occupied condition areas in DA, then an exception condition is raised: invalid condition number. 24.1 SQLSTATE "If multiple completion conditions: warning or multiple exception conditions, including implementation-defined exception conditions, are raised, then it is implementation-dependent which of the corresponding SQLSTATE values is returned in the SQLSTATE status parameter, provided that the precedence rules in Subclause 4.29.2, "Status parameters", are obeyed. Any number of applicable conditions values in addition to the one returned in the SQLSTATE status parameter, may be returned in the diagnostics area." PSM 2007 4.10.9 Compound statements A compound statement allows a sequence of SQL-statements to be considered as a single SQL-statement. A compound statement also defines a local scope in which SQL-variables, condition handlers, and standing SQLserver cursors can be declared. PSM 14.1 ::= [ ] BEGIN [ [ NOT ] ATOMIC ] [ ] [ ] [ ] [ ] END [ ] General Rules 2) The SQL variables, standing SQL-server cursors, and handlers specified in the , , and the of CS are created in an implementation-dependent order. 3) c) If the execution of [a statement] Si [within the current compound statement] terminates with exception conditions or completion conditions other than successful completion, then: i) The following is effectively executed without further Syntax Rule checking: RESIGNAL ii) If there are unhandled exception conditions at the completion of the execution of a handler (if any), then the execution of CS is terminated immediately. PSM 14.4 "The following SQL-statement is effectively executed: SET = ; NULL if not otherwise stated" [This implies clearing the DA.] PSM 14.2 2) Let CS be the simply containing HD. 3) When H is *activated*: a) If H is activated in an atomic execution context and the condition raised is a transaction rollback with any subcondition, then the following is effectively executed: RESIGNAL NOTE 20 If a condition results in an implicit rollback (See Subclause 4.35.5, "Implicit rollbacks", in [ISO9075-2]) in an atomic execution context, the transaction has been effectively rolled back by the time the Handler body is executed. If any transaction initiating statement is executed following this, it would require a transaction to be initiated in an atomic execution context, which is not valid. Therefore, the condition is effectively resignaled to an outer non-atomic execution context. b) Case: i) If HD specifies CONTINUE, then: 1) The General Rules of Subclause 23.2, "Pushing and popping the diagnostics area stack", in [ISO9075-2], are applied with PUSH as OPERATION and the diagnostics area stack as STACK. 2) HA is executed. 3) Case: A) If there is an unhandled condition other than successful completion at the completion of HA, then: I) The General Rules of Subclause 23.2, "Pushing and popping the diagnostics area stack", in [ISO9075-2], are applied with PUSH as OPERATION and the diagnostics area stack as STACK. II) The following is effectively executed: RESIGNAL B) Otherwise: I) The General Rules of Subclause 23.2, "Pushing and popping the diagnostics area stack", in [ISO9075-2], are applied with POP as OPERATION and the diagnostics area stack as STACK. II) HA completes with completion condition successful completion and the SQLsession continues as it would have done if execution of the innermost executing statement that raised the condition had completed. ii) If HD specifies EXIT, then: 1) The General Rules of Subclause 23.2, "Pushing and popping the diagnostics area stack", in [ISO9075-2], are applied with PUSH as OPERATION and the diagnostics area stack as STACK. 2) HA is executed. 3) For every open standing SQL-server cursor CR declared in the of CS, the General Rules of Subclause 15.4, "Effect of closing a cursor", in [ISO9075-2], are applied with CR as CURSOR and SAVE as DISPOSITION. 4) Case: A) If there is an unhandled condition other than successful completion at the completion of HA, then: I) The General Rules of Subclause 23.2, "Pushing and popping the diagnostics area stack", in [ISO9075-2], are applied with PUSH as OPERATION and the diagnostics area stack as STACK. II) The following is effectively executed: RESIGNAL B) Otherwise: I) The General Rules of Subclause 23.2, "Pushing and popping the diagnostics area stack", in [ISO9075-2], are applied with POP as OPERATION and the diagnostics area stack as STACK. II) HA completes with completion condition successful completion and the SQLsession continues as it would have done if execution of CS had completed. iii) If HD specifies UNDO, then: 1) The General Rules of Subclause 23.2, "Pushing and popping the diagnostics area stack", in [ISO9075-2], are applied with PUSH as OPERATION and the diagnostics area stack as STACK. 2) All changes made to SQL-data or schemas by the execution of SQL-statements contained in the of CS and any s triggered by the execution of any such statements are canceled. 3) For every open standing SQL-server cursor CR declared in the of CS, the General Rules of Subclause 15.4, "Effect of closing a cursor", in [ISO9075-2], are applied with CR as CURSOR and SAVE as DISPOSITION. 4) HA is executed. 5) Case: A) If there is an unhandled condition other than successful completion at the completion of HA, then: I) The General Rules of Subclause 23.2, "Pushing and popping the diagnostics area stack", in [ISO9075-2], are applied with PUSH as OPERATION and the diagnostics area stack as STACK. II) The following is effectively executed: RESIGNAL B) Otherwise: I) The General Rules of Subclause 23.2, "Pushing and popping the diagnostics area stack", in [ISO9075-2], are applied with POP as OPERATION and the diagnostics area stack as STACK. II) HA completes with completion condition successful completion and the SQLsession continues as it would have done if execution of CS had completed.
Copyright (c) 2000, 2024, Oracle Corporation and/or its affiliates. All rights reserved.