mysql Query Return Code - mysql

I am Writing a MYSQL Stored Procedure. In that i know using HANDLER we can check the condition for SELECT STATEMENT.
DECLARE CONTINUE HANDLER FOR NOT FOUND
SET NO_MORE_ROWS = TRUE;
In DB2 we can check the return code using SQLCODE immediatly after the statement.
Please let me know how i need to handle the Duplicate Index, More than one Row, Cursor Problem, Data mismatch in Source variable against table fields. Is there a way in MYSQL.
Basically i want to know in MYSQL How to handle the below condition.
SELECT - NOT FOUND, MORE THAN ONE ROW, EXCEPTION, DATATYPE MISMATCH IN TO CONDITION
INSERT - DUPLICATE INDEX, DATATYPE MISMATCH, OTHER INERT FAILURE
UPDATE - NO DATA FOR UPDATE, UPDATE WHERE CONDITION NOT MET
DELETE - NOT DELETED BECAUSE OF FOREIGN KEY ISSUE.
CURSOR - CURSOR FAILURE
Thanks.

As documented under DECLARE ... HANDLER Syntax:
The condition_value for DECLARE ... HANDLER indicates the specific condition or class of conditions that activates the handler:
A MySQL error code (a number) or an SQLSTATE value (a 5-character string literal). You should not use MySQL error code 0 or SQLSTATE values that begin with '00', because those indicate success rather than an error condition. For a list of MySQL error codes and SQLSTATE values, see Section C.3, “Server Error Codes and Messages”.

Related

Is It Possible for a MYSQL Trigger to Return an Error Message if the Trigger Fails for Any Reason?

I am trying to create an after insert trigger in MySQL that writes the message "Insert Failed" to an error table called tbl_error if the trigger fails for any reason.
To solve this problem, I have attempted to use a combination of handlers and signal statements. None have worked.
DELIMITER $$
CREATE TRIGGER trig_statesout_afterinsert AFTER INSERT ON states
FOR EACH ROW
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
SIGNAL SQLSTATE VALUE '99999'
SET MESSAGE_TEXT = 'Insert Failed';
INSERT INTO tbl_error(ErrorMessage) Values ('Insert Failed');
END;
INSERT INTO statesout (states_id, state, cases, lastupdate)
SELECT s.states_id, s.state, s.cases, current_timestamp()
FROM states as s
WHERE s.states_id = NEW.states_id;
END $$
I attempted to return information from a diagnostic statement, but that didn't work either.
Because the documentation states that
For SQLEXCEPTION conditions, the stored program terminates at the
statement that raised the condition, as if there were an EXIT handler.
If the program was called by another stored program, the calling
program handles the condition using the handler selection rules
applied to its own handlers.
I split the update logic for the trigger into a separate stored procedure in case the issue was that the SQLEXCEPTION conditions cannot be in the calling object. It didn't work.
Some SO solutions suggest using a "trick" to call a nonexistent table, but the documentation says this is not necessary due to the SIGNAL statement:
Without SIGNAL, it is necessary to resort to workarounds such as
deliberately referring to a nonexistent table to cause a routine to
return an error.
In any case, those solutions only throw errors based on a specific condition, not for any condition.
What am I doing wrong? Is it impossible for a MYSQL trigger to return an error message if the trigger fails for any reason?
It's not possible to make any change to data if the trigger activates a SQLException.
If the trigger experiences any error, whether handled or not handled, then the INSERT that spawned the trigger is undone, as well as any SQL run by the trigger, and even any SQL run by triggers spawned by actions your trigger executes.
This is related to the idea of atomicity — either the whole action must succeed, or else no part of the action is saved. It's all or nothing.
If you want to log the error, you'll have to check for the error in your application, and then log the error as a separate action. You can't do it in the trigger body.

How do I require a mysql field?

I just discovered NOT NULL does not make a field required.
When creating a mysql table, how do I create a field that cannot contain null or blank (must have something in it)?
By default, MySQL accepts invalid values. You can set MySQL to strict mode to force valid values. This will reject a query that does not provide a value for a NOT NULL column as well as enforce integrity on all types of columns.
Update: MySQL 5.7 and above now have strict mode on by default. So it would not accept invalid values by default like previous versions.
http://dev.mysql.com/doc/refman/5.0/en/sql-mode.html#sql-mode-important
http://dev.mysql.com/doc/refman/5.0/en/sql-mode.html#sqlmode_strict_all_tables
Edit:
#Barranka and #RocketHazmat made good points in the comments. '' is not the same as null, so MySQL will allow that in a NOT NULL column. In that instance, you would have to resort to your code or a trigger.
In the code (PHP for example), this could be easy enough, running something like:
if (!strlen($value)) {
// Exclude value or use NULL in query
}
I think you should do two things:
Set the column to NOT NULL to force the input of a value
Use a trigger to validate the values.
Within the trigger you can cancel the operation if the desired column does not fulfill a required condition (for example, having zero-length).
This question and its answers address this second thing, and here is an example:
delimiter $$
CREATE TRIGGER `cancel_insert_if_empty`
BEFORE INSERT ON `your_table`
FOR EACH ROW
BEGIN
declare msg varchar(255);
if NEW.your_column is null or length(NEW.your_column) = 0 then
set msg = "You're doing something wrong! Now suffer the consequences";
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = msg;
end if;
END$$
delimiter ;
In this example, if you try to insert a null value or a zero-length string in your_column an error will rise and the insert will be canceled. Quoting from the reference manual:
MySQL handles errors during trigger execution as follows:
If a BEFORE trigger fails, the operation on the corresponding row is not performed.
A BEFORE trigger is activated by the attempt to insert or modify the row, regardless of whether the attempt subsequently succeeds.
An error during either a BEFORE or AFTER trigger results in failure of the entire statement that caused trigger invocation.
Of course, you can write a trigger to check the updates too.
Hope this helps.
You can set default value for that field: City varchar(40) DEFAULT 'Sandnes'

How to get exception message on stored procedure in MySQL 5.5

I'm using MySQL 5.5.To get the exception message on MySQL 5.6 is using GET DIAGNOSTIC function. Is there any similar function in MySQL 5.5 ,.? The project I'm working is already use MySQL version 5.5.
You could try using SHOW ERROR and SHOW WARNING. To see the last error or warning you could use it as:
SHOW ERRORS LIMIT 1 -- for SQL-state > 2
SHOW WARNINGS LIMIT 1 -- for SQL-state 1,2
In order to prevent listing each and every error, you can handle a class of SQL-errors like so:
SQLWARNING is shorthand for the class of SQLSTATE values that begin
with '01'.
NOT FOUND is shorthand for the class of SQLSTATE values that begin
with '02'. This is relevant only within the context of cursors and is
used to control what happens when a cursor reaches the end of a data
set. If no more rows are available, a No Data condition occurs with
SQLSTATE value 02000. To detect this condition, you can set up a
handler for it (or for a NOT FOUND condition). An example is shown in
Section 12.7.5, “Cursors”. This condition also occurs for SELECT ...
INTO var_list statements that retrieve no rows.
SQLEXCEPTION is shorthand for the class of SQLSTATE values that do not
begin with '00', '01', or '02'.
So to handle an exception, you need to only do:
DECLARE EXIT HANDLER FOR SQLSTATE SQLEXCEPTION .....;
Links:
http://dev.mysql.com/doc/refman/5.5/en/signal.html
http://dev.mysql.com/doc/refman/5.0/en/declare-handler.html

MySQL Stored Procedure Error Handling

I believe there is nothing currently available in MySQL that allows access to the SQLSTATE of the last executed statement within a MySQL stored procedure. This means that when a generic SQLException is raised within a stored procedure it is hard/impossible to derive the exact nature of the error.
Does anybody have a workaround for deriving the SQLSTATE of an error in a MySQL stored procedure that does not involve declaring a handler for every possible SQLSTATE?
For example - imagine that I am trying to return an error_status that goes beyond the generic "SQLException happened somewhere in this BEGIN....END block" in the following:
DELIMITER $$
CREATE PROCEDURE `myProcedure`(OUT o_error_status varchar(50))
MY_BLOCK: BEGIN
DECLARE EXIT handler for 1062 set o_error_status := "Duplicate entry in table";
DECLARE EXIT handler for 1048 set o_error_status := "Trying to populate a non-null column with null value";
-- declare handlers ad nauseum here....
DECLARE EXIT handler for sqlexception set o_error_status:= "Generic SQLException. You'll just have to figure out the SQLSTATE yourself...." ;
-- Procedure logic that might error to follow here...
END MY_BLOCK$$
Any tips?
PS I am running MySQL 5.1.49
I believe there is nothing currently available in MySQL that allows access to the SQLSTATE of the last executed statement within a MySQL stored procedure. This means that ... it is hard/impossible to derive the exact nature of the error.
Luckily that is not true.
SHOW ERRORS LIMIT 1 -- for SQL-state > 2
SHOW WARNINGS LIMIT 1 -- for SQL-state 1,2
Will show the last error or warning.
In order to prevent listing each and every error, you can handle a class of SQL-errors like so:
SQLWARNING is shorthand for the class of SQLSTATE values that begin with '01'.
NOT FOUND is shorthand for the class of SQLSTATE values that begin with '02'. This is relevant only within the context of cursors and is used to control what happens when a cursor reaches the end of a data set. If no more rows are available, a No Data condition occurs with SQLSTATE value 02000. To detect this condition, you can set up a handler for it (or for a NOT FOUND condition). An example is shown in Section 12.7.5, “Cursors”. This condition also occurs for SELECT ... INTO var_list statements that retrieve no rows.
SQLEXCEPTION is shorthand for the class of SQLSTATE values that do not begin with '00', '01', or '02'.
So to handle an exception, you need to only do:
DECLARE EXIT HANDLER FOR SQLSTATE SQLEXCEPTION .....;
Links:
http://dev.mysql.com/doc/refman/5.5/en/signal.html
http://dev.mysql.com/doc/refman/5.0/en/declare-handler.html
GET DIAGNOSTICS is available in 5.6.4
See
http://dev.mysql.com/doc/refman/5.6/en/get-diagnostics.html
I am doing the following workaround: using a SELECT to provocate an error. For example:
SELECT RAISE_ERROR_unable_to_update_basket;
This will result in the following error message (example):
ERROR 1054 (42S22): Unknown column 'RAISE_ERROR_unable_to_update_basket' in 'field list'
I am wrapping my call to a stored procedure in a try { ... } catch { ... } and now can handle this error. This will of course only work for provocating custom error messages from inside your stored procedure and will not handle any SQL or database errors, that might occur (because of duplicate-key entry). In the latter case, you might be able to workaround this using the solution of Johan.

'Return'/Abort mySql stored procedure

I want to abort/quit/return from a stored procedure when a condition is not met.
I'm not sure how to do it. Googling didn't help me much because:
The version of MySql on our servers is 5.1 (<5.5 and hence no signal sqlstate).
I don't want to put everything in if..then..else statements (there will be multiple levels of nesting in my case)
I don't want to call an_invalid_procedure to raise an exception.
Are there alternatives?
Something wrong with....
...
BEGIN
<do stuff>
IF (<your condition>) THEN
<do more stuff>
END IF;
END$$
What I do in such cases is to:
Create table called errors with one column containing textual error messages and UNIQUE index on it. I fill the table with errors I want to support.
When I need specific error to raised, I insert the error message into errors table. Since it's already there, I am violating a UNIQUE key so error is raised. In my application I can watch for MySQL error #1062 (that's the code for 'Duplicate value for key...' error and use regexp to extract my error message to show it to user/log it/whatever;