SQL continue handler is not triggered - sql

IBM i V7R1M0. I need to continue processing a statement whenever an error occurs and as far as I have read, such as from this:
https://dba.stackexchange.com/questions/88862/how-to-ignore-sql-errors-in-stored-procedure-not-handle
DECLARE CONTINUE HANDLER seems to be the answer, so
I have a very simple procedure that looks like this:
exec SQL create or replace procedure test_prod1
(in test2 decimal(1,0))
language sql modifies sql data
begin
declare continue handler for sqlexception
begin end;
update DUPEPF set INT2 = test2;
end;
As far as I can tell, this means whenever an error occurs (such as unique key violation) the SQL statement will simply continue, yet this isn't the case. The statement stops whenever a key violation appears and the next rows are not processed. I am confused as to why this is the case

Your continue handler is working...
Your procedure is ignoring the error thrown by the UPDATE statement and continuing. Except that there isn't anything else to do.
Just because your proc is ignoring the error, doesn't mean the DB can ignore the error inside of it's update statement processing.
EDIT
handlers change how your stored procedure or UDF handle errrors...think of them as a way to "catch" errors thrown by the DB. They don't prevent the DB from throwing those errors in the first place
Make sense?
In order to do what you're trying to do, you'd need to use your own cursor, something like so...
create or replace procedure test_prod1
(in test2 decimal(1,0))
language sql modifies sql data
begin
declare myInt integer;
DECLARE DUPLICATE_KEY CONDITION FOR SQLSTATE '23505';
DECLARE END_OF_TABLE CONDITION FOR SQLSTATE '02000';
declare test_cursor cursor for
select int2 from DUPEPP for update;
declare exit handler for END_OF_TABLE
close test_cursor;
declare continue handler for DUPLICATE_KEY
begin end;
open test_cursor;
fetch_loop:
LOOP
fetch next from test_cursor into myInt;
update dupepf set int2 = test2
where current of test_cursor;
END LOOP fetch_loop;
end;

Related

Teradata Dynamic Insert - Looped?

I'm doing something very similar to dnoeth's second comment on this question:
Insert Into table Teradata dynamic stored procedure SQL
I need to run it multiple times to loop the same insert statement but with different values for the "?" and I'm not sure how to go about that.
The dynamic value in my version is a date span. I can't run a massive insert without spooling out so I've broken the data into segments.
Thanks.
William,
As you are aware that you need to use cursor to iterate through each value you want to process.
For that purpose store dynamically created INSERT statement into a variable.
Final step: Use EXECUTE IMMEDIATE command to run insert statement stored in teradata variable
Here is the working sample that you may refer
REPLACE PROCEDURE td_user.sp_dynamic_insert( OUT proc_msg VARCHAR(5000) )
BEGIN
DECLARE lv_insert_txt VARCHAR(20000);
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
/* Error handling code if required */
END;
L0:
FOR insert_cursor AS select_list
CURSOR FOR
SELECT Col2
FROM test_1
DO
SET lv_insert_txt = 'INSERT INTO test_2(Col1,Col2) VALUES('||TRIM(insert_cursor.Col2)||','||TRIM(insert_cursor.Col2)||')';
EXECUTE IMMEDIATE lv_insert_txt;
END FOR L0;
SET proc_msg = 'Procedure completed successfully';
END;

performance anaysis (select in loop vs function call in loop )

i will like to ask a performance related question here my question is which approach is best
1 adding subquery in loop
declare
test varchar2(50);
FOR Lcntr IN 1..20
LOOP
update emp set empno='50' where empname=test;
END LOOP;
2 adding function call in loop or making the function of the above query and calling it in loop
declare
test varchar2(50);
FOR Lcntr IN 1..20
LOOP
temp:=update('argument');
END LOOP;
If your function update just call the same sql update, it dosen't matter are you call it directly of from stored function.
In common the best way is use one sql statement (update or merge) for update whole dataset what you need.
But you update are look like strange:
In first pl/sql block you declare variable test. And test is equal null. And after that you try update table by comparing with null - no any rows will be affected.
In second pl\sql block you declare variable test too, but use varable temp. It will raise error in compilation.

IBM SolidDB, fetching result fails due to no result en execute statement

In my stored procedures I'm doing a lot of:
EXEC SQL EXECUTE ...
EXEC SQL FETCH ...
However, I'm getting some errors (Error 23506: End of table in cursor) when the execute statement doesn't return anything and I'm trying to fetch the result.
Are there anyway to check if the result contains anything before trying to fetch it?
I've tried SQLSUCCESS and SQLROWCOUNT, but SQLSUCCESS only tells me if the statement doesn't fail, not if it returns anything, and SQLROWCOUNT apparently only works for inserts, updates and deletes. Not select statements.
This reference compares DB2 and SolidDB procedures.
In the section "Listing 15. SQLSUCCESS showing end of result set", the IBM reference shows this snippet.
EXEC SQL FETCH sel_tab;
WHILE SQLSUCCESS LOOP
EXEC SQL FETCH sel_tab;
END LOOP
It also says
When the FETCH cursor statement fails
and does not find another row to
retrieve, the value of SQLSUCCESS is
set to 0 and the WHILE LOOP ends.
That pretty much tells me that the WHILE loop shouldn't even be entered if that first EXEC SQL FETCH doesn't find a row. But you seem to be suggesting that isn't happening in your code.
Later, in "Table 7. solidDB SQLERROR of cursorname statement", it shows this code. (My annotations.)
"CREATE PROCEDURE tabs_in_schema (schema_nm
VARCHAR) RETURNS (nr_of_rows INTEGER)
BEGIN
DECLARE tab_nm VARCHAR;
EXEC SQL PREPARE sel_tab -- A SELECT statement
SELECT table_name FROM sys_tables
WHERE table_schema = ?;
EXEC SQL PREPARE ins_tab
INSERT INTO my_table (table_name,
schema) VALUES (?,?);
nr_of_rows := 0;
EXEC SQL EXECUTE sel_tab USING -- Executes the SELECT
(schema_nm)INTO (tab_nm);
EXEC SQL FETCH sel_tab; -- EXEC SQL FETCH first row
WHILE SQLSUCCESS LOOP -- Like listing 15
nr_of_rows := nr_of_rows + 1;
EXEC SQL EXECUTE ins_tab USING
(tab_nm, schema_nm);
IF SQLROWCOUNT <> 1 THEN
RETURN SQLERROR OF ins_tab;
END IF;
EXEC SQL FETCH sel_tab; -- FETCH subsequent rows
END LOOP
END";
I suppose you could execute something like
SELECT COUNT(your_column_name)
FROM your_table
WHERE ...;
COUNT() will always return at least one row as long as your query is valid. But that involves more round trips to the database. I think you're better off sticking to the idiom of trying to fetch a row, and trapping the error.

How to get rid of "Error 1329: No data - zero rows fetched, selected, or processed"

I have a stored procedure which does not need to return any values. It runs smoothly and without any problem. However, it outputs an error message after finishing its run:
Error: No data - zero rows fetched, selected, or processed
How can I get rid of this error message?
CREATE PROCEDURE `testing_proc`()
READS SQL DATA
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE l_name VARCHAR(20);
DECLARE my_cur CURSOR FOR
SELECT name FROM customer_tbl;
OPEN my_cur;
my_cur_loop:
LOOP FETCH my_cur INTO l_name;
IF done = 1 THEN
LEAVE my_cur_loop;
END IF;
INSERT INTO names_tbl VALUES(l_name);
END LOOP my_cur_loop;
CLOSE my_cur;
END
I guess you just forgot to include the following line in your post:
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
Your code is correct, but bug/strange behaviour of mysql causes the warning to appear even if it was handled. You can avoid that if you add a "dummy" statement to the end of your procedure that invovles a table and is successful, this will clear the warning. (See http://dev.mysql.com/doc/refman/5.5/en/show-warnings.html)
In your case:
SELECT name INTO l_name FROM customer_tbl LIMIT 1;
after the end of the loop.
On MySQL 5.5.13 the warning disappears, on Linux and Windows.
I commented on MySQL Bug 60840 and I hope they will fix it some time in the future...
You need to define a continue handler like:
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
So it would look like:
DECLARE done INT DEFAULT 0;
DECLARE l_name VARCHAR(20);
DECLARE my_cur CURSOR FOR
SELECT name FROM customer_tbl;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN my_cur;
my_cur_loop:
LOOP FETCH my_cur INTO l_name;
IF done = 1 THEN
LEAVE my_cur_loop;
END IF;
INSERT INTO names_tbl VALUES(l_name);
END LOOP my_cur_loop;
CLOSE my_cur;
I ran into this and pulled out my hair till I ran across this in the official mysql docs
Before MySQL 5.6.3, if a statement that generates a warning or error
causes a condition handler to be invoked, the handler may not clear
the diagnostic area. This might lead to the appearance that the
handler was not invoked. The following discussion demonstrates the
issue and provides a workaround.
Click the link and scroll to the bottom for details but the fix was to include a successful select INSIDE the CONTINUE HANDLER:
DECLARE CONTINUE HANDLER FOR NOT FOUND
BEGIN
SELECT 1 INTO #handler_invoked FROM (SELECT 1) AS t;
END;
I tried the solutions in here and none, including the continue handler worked for me. I still get the messages in the MySQL error log. I discovered this also with my "select ... into ..." which made sense, but I really thought the continue handler would work for the cursors. Either way I found using "found_rows()" to find out if any rows were returned worked perfectly. This mean that the simple "select into" statements have to be converted to cursors, but it isn't much work and does solve the problem.
DECLARE v_rowcount integer unsigned;
DECLARE cur_entries cursor for
select app_name, proc_name, error_code, sum(occurrences) occurrences
from that_table...;
open cur_entries;
set v_rowcount = found_rows();
if v_rowcount > 0 then
fetch cur_entries into v_app_name, v_proc_name, v_error_code, v_occurrences;
...
end if;
close cur_entries;
I wrote this up on my personal blog here: http://tinky2jed.wordpress.com/technical-stuff/mysql/mysql-no-data-zero-rows-fetched-how-to-code-for-it/
Normally this happens when you overshoot a cursor range, so checkout the loop conditions where the FETCH statement is
I don't know if this fixes the cursor issue, but I ran into this warning with a stored function and found that if you use:
RETURN (SELECT x From myTable...);
instead of
SELECT x into myVar...return myVar
I got this from this helpful doc:
http://bugs.mysql.com/bug.php?id=42834
I was getting the same error in my code, and I realized that I had not incremented my loop variable (using while loop) and hence, the loop was going infinite.
In your code too, you are not setting "done" to 1 anywhere, and I think the code is showing error because of that.
In the below code, instead of the variable "done", I have added a variable "count" that is initialized with the number of records in the table and is decremented after each insertion. The loop is terminated when count=0:
CREATE PROCEDURE `testing_proc`()
READS SQL DATA
BEGIN
DECLARE count INT;
DECLARE l_name VARCHAR(20);
SELECT count(*) into count from customer_tbl;
DECLARE my_cur CURSOR FOR
SELECT name FROM customer_tbl;
OPEN my_cur;
my_cur_loop:
LOOP FETCH my_cur INTO l_name;
INSERT INTO names_tbl VALUES(l_name);
SET count = count - 1;
IF count = 0 THEN
LEAVE my_cur_loop;
END IF;
END LOOP my_cur_loop;
CLOSE my_cur;
END
I hope this helps!

MySQL Syntax Error

When executing:
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
SELECT 1;
END;
DECLARE EXIT HANDLER FOR SQLWARNING
BEGIN
ROLLBACK;
SELECT 1;
END;
-- delete all users in the main profile table that are in the MaineU18 by email address
DELETE FROM ap_form_1 WHERE element_5 IN (SELECT email FROM MaineU18);
-- delete all users from the MaineU18 table
DELETE from MaineU18;
COMMIT;
END;
I get:
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'e1:
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK' at line 2
Any ideas? Thanks.
UPDATE 2:
I have tried putting the script into a PROCEDURE:
DELIMITER |
DROP PROCEDURE IF EXISTS temp_clapro|
CREATE PROCEDURE temp_clapro()
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION, SQLWARNING ROLLBACK;
SET AUTOCOMMIT=0;
-- delete all users in the main profile table that are in the MaineU18 by email address
DELETE FROM ap_form_1 WHERE element_5 IN (SELECT email FROM MaineU18);
-- delete all users from the MaineU18 table
DELETE from MaineU18;
COMMIT;
SET AUTOCOMMIT=1;
END
|
DELIMITER ;
CALL temp_clapro();
I am still having issues:
Query OK, 0 rows affected (0.00 sec)
Query OK, 0 rows affected (2.40 sec)
Query OK, 0 rows affected (2.40 sec)
Query OK, 0 rows affected (2.40 sec)
Query OK, 0 rows affected (2.40 sec)
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'END;
|
DELIMITER ;
CALL temp_clapro()' at line 1
UPDATE 3:
It seems that many of my problems are coming from the fact that I am running the script from a file using the "SOURCE" command. If I only have the DROP and CREATE commands in the file and run the DELIMITER and CALL commands outside the file, everything works without error.
Is there away to run this from a single script file?
You seem to be using BEGIN as the opening of a block of ad hoc statements, as one would do in SQL Server.
MySQL doesn't support this. You can DECLARE only in the body of a stored procedure or stored function or trigger.
http://dev.mysql.com/doc/refman/en/declare.html:
DECLARE is allowed only inside a BEGIN ... END compound statement and must be
at its start, before any other
statements.
http://dev.mysql.com/doc/refman/en/begin-end.html:
BEGIN ... END syntax is used for
writing compound statements, which can
appear within stored programs.
Re your comments and updated question: I don't know why it's failing. I just tried it myself and it worked fine. What version of MySQL are you using?
you're using semicolons with the procedure for statement delimiters, so you have to change the delimiter in your client. see http://dev.mysql.com/doc/refman/5.1/en/stored-programs-defining.html