mysql nested cursor is already open - mysql

I have a sp with two nested cursors. The outer cursor is customers, and the inner cursor is periods.
when an error occurs in the inner cursor I want to rollback what has been done for the specific customer and proceed with the processing of the next customer. However when the inner cursor is executed for the next customer (after an exception has occurred) I get an "cursor is already open message"
The code looks like this:
DECLARE customers CURSOR FOR
select * from customers_table;
DECLARE CONTINUE HANDLER FOR NOT FOUND
SET no_more_customers = 1;
OPEN customers;
customers_cursor:
REPEAT
FETCH customers
INTO ....
IF no_more_customers = 1
THEN
close customers;
LEAVE customers_cursor;
END IF;
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
rollback;
END;
....... //do some stuff
BEGIN
DECLARE no_more_periods INT(1) DEFAULT 0;
DECLARE periods CURSOR FOR
SELECT ...
DECLARE CONTINUE HANDLER FOR NOT FOUND
SET no_more_periods = 1;
OPEN periods;
periods_cursor:
REPEAT
FETCH periods INTO...
IF no_more_periods = 1
THEN
close periods;
LEAVE periods_cursor;
END IF;
..... //do some stuff point 1
UNTIL no_more_periods = 1
END REPEAT periods_cursor;
end;
END;
UNTIL no_more_customers = 1
END REPEAT customers_cursor;
END;
Customer 1 runs and and exception occurs in //do some stuff point 1. Then customer 2 runs until the open periods statement is reached and that's when I get the "Cursor is already open".
Thanks a lot for your help.

I do not see any transactions or commits in your code. I would change the code to include the following:
Start a new transaction for each customer
Commit this transaction before starting on the next customer.
Close the periods cursor before performing a rollback.

thanks a lot for your help #JodyT .I am initiating a new block for each loop of the customer cursor (begin after the "if no_more_customer=1" block". Also i am doing "commit" before next customer. Unfortunately i cannot close periods cursor in the exception handler of this block (cursor periods not defined in this scope-compile time error).What i did to overcome the issue was to define an exception handler inside the inner loop (exactly after the continue handler of the periods cursor).In this handler i close periods and then raise exception to perform rollback in the outter exception handler

Related

Why does this MySQL stored procedure not seem to execute its exit handler?

I have read the documentation on Exit Handlers and have found useful code ideas in relevant SO questions here and here amongst other places.
Nevertheless, calling the stored procedure below appears to complete OK and returns a TRUE value for the parameter success. when I know it is definitely not completing OK, not least because there was a syntax error in the body SQL (it was referring to a field that did not exist).
So the exit handler should have kicked in and returned FALSE for parameter success.
Can anyone help me to understand why a transaction that fails does not return the correct value for the parameter? (I suspect it has something to do with where I set success to true)
The actual SQL inside the transaction is not important to this question so I haven't shown it. Just assume that it might or might not successfully complete the transaction. It is the success or failure of that transaction that I want to detect through the parameter
DELIMITER $$
CREATE PROCEDURE do_thing (OUT success BOOLEAN)
DETERMINISTIC
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN SET success := FALSE; ROLLBACK; END; # rollback on any error
DECLARE EXIT HANDLER FOR SQLWARNING BEGIN SET success := FALSE; ROLLBACK; END; # rollback on any warning
START TRANSACTION;
< SQL that might cause an error >
< in my case it was referring to a field that didn't exist>
COMMIT;
SET success := TRUE;
END$$
DELIMITER ;
SEE DBFIDDLE
The first part is a copy of your code, it throws an error....
The second part is corrected, both DECLARE EXIT are moved within the block.
The third part is an example where #success will be set to false.

Log errors on SQLException to table

I have stored procedures that are likes this overall:
BEGIN
DECLARE exit handler for sqlexception
BEGIN
SHOW ERRORS; # this shows a result set with the errors that occured
ROLLBACK; # this rollbacks all the magic i tried to to, making this whole stuff atomic, YAY!
insert into LogTest select 1,2; # this is just a test to make sure it would work
END;
START TRANSACTION;
# do some magic
COMMIT
END
Now, what i need to do is change the Handler to something like this, obviously semi-pseudocode:
DECLARE exit handler for sqlexception
BEGIN
ROLLBACK; # this rollbacks all the magic i tried to to, making this whole stuff atomic, YAY!
insert into LogTest # and this tells me what timey whimey hit the maelstorm
select now(),*,'some id', ... <some more stuff maybe?>
from (Show errors) as Errors
END;
Any one any experience/idea/knowledge?

How to do unlimited recursion in mysql?

I have a mysql stored procedure made it recursively, it always returned 499 rows max.
my stored procedure is moving in a tree (not a binary tree) and check the nodes if they have children and so on until it reached the leaves.
I don't know how can I convert my code into non-recursive way, I just want to ask for tow points:
how can I make an infinite recursive in mysql(mysql server version is 5.5)?
if that can't happened, how can I change my cod into non-recursive way?
CREATE PROCEDURE `get_citations`(in _pub_id int(10),in _lvl int,citation_count int)
BEGIN
DECLARE done INT DEFAULT FALSE;
declare p_id,c_count int;
declare _counter int default 1;
DECLARE cur1 CURSOR FOR SELECT pat_publn_id,cited_count from temp.a_citations
where pub_parent=_pub_id ;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
insert into a_citations
(pat_publn_id ,
publn_nr ,
publn_kind,
publn_auth,
publn_date,
cited_pat_publn_id,
cited_count,
pub_lvl,
pub_parent)
(select p.pat_publn_id,p.publn_nr,p.publn_kind,p.publn_auth,p.publn_date,c.cited_pat_publn_id,
(select count(*) as cnt FROM patstat1304.tls212_citation c2 where c2.cited_pat_publn_id=c.pat_publn_id) as cited_count,_lvl as pub_lvl,_pub_id as pub_parent
from patstat1304.tls212_citation c,patstat1304.tls211_pat_publn p
where c.pat_publn_id=p.pat_publn_id and c.cited_pat_publn_id=_pub_id);
commit;
OPEN cur1;
read_loop: LOOP
fetch cur1 into p_id,c_count;
IF (c_count !=0) then
call get_citations( p_id,_lvl+1,c_count);
commit;
END if;
IF done THEN
LEAVE read_loop;
END IF;
set _counter=_counter+1;
if(_counter=citation_count) then
LEAVE read_loop;
end if;
end loop;
CLOSE cur1;
END
MySQL can not execute stored procedures with a very deep nesting.
Very soon, error ER_STACK_OVERRUN_NEED_MORE will appear.
Increasing the thread stack to go further will not work either.
To change the recursive call to a non recursive one, consider something like this:
1) Create a table named publications_to_process, with the publication and search level.
2) To start the search, insert the original publication in this table, with level 1.
3) In a loop, fetch one publication, examine the citations, and add the publications listed in the publications_to_process, incrementing the level.
4) As a bonus, for cases like:
Pub_1 --> Pub_2 --> Pub_3,
Pub_1 --> Pub_3
there is no need to add Pub_3 again to the search if it has been processed already.
In other words, the publications are more likely to be a directed graph that a tree.
5) Either make the table temporary, or consider adding a PROCESSLIST_ID column, so that different sessions (having a different CONNECTION_ID()) do not step on each other, when executing this search in parallel.

1329 No data - zero rows fetched, selected, or processed

I have changed this stored procedure many times and still keep getting the same error. I know I am getting rows back because I tested the cursor select separately. I have read other similar issues on this site but I don't seem to have the same fix.
DECLARE iDone INTEGER(10) DEFAULT 0;
DECLARE userID INTEGER(10);
DECLARE creditRemaining INTEGER(10);
DECLARE column_cur CURSOR FOR
SELECT `userID`, `creditRemaining` FROM `access`
WHERE (`dateExpire`>=now() OR `isRenewed`=1) and `descriptionShort`='Subscription';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET iDone=1;
SET userID = 0;
SET creditRemaining = 0;
OPEN column_cur;
LOOP1: LOOP
FETCH column_cur INTO userID, creditRemaining;
IF iDone = 1
THEN
LEAVE LOOP1;
END IF;
-- SELECT userID, creditRemaining;
UPDATE `users` SET `saveCount`=creditRemaining, `searchCount`=6000 WHERE `ID`=userID;
END LOOP LOOP1;
CLOSE column_cur;
I think this is a duplicate of more, except for the fact you already have a HANDLER declared. In another Error 1329 question, this answer from #DanJGer pointed out a note in the 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.
That's likely the problem you're encountering.

Catch and continue in SQLServer

I have this sql procedure:
create procedure DELETE as
DECLARE VARIABLES
begin TRY
DECLARE CURSOR FOR SELECT ANYTHING
OPEN CURUPD
FETCH NEXT FROM CURUPD INTO VARIABLES
WHILE ##FETCH_STATUS = 0 BEGIN
UPDATE TABLE BASED SON VARIABLES
FETCH NEXT FROM CURUPD INTO VARIABLES
END
CLOSE CUR
DEALLOCATE CUR
end TRY
begin catch
DO NOT CARE ABOUT THE ERROR BUT CONTINUE UPDATE ON NEXT RECORD
end catch;
Is this possible?
Robert :-)
You would have to put the TRY/CATCH inside of the WHILE loop. The way you have it, you can't continue the WHILE loop, because it's already finished.
Try this code:
create procedure DELETE as
DECLARE VARIABLES
begin TRY
DECLARE CURSOR FOR SELECT ANYTHING
OPEN CURUPD
FETCH NEXT FROM CURUPD INTO VARIABLES
WHILE ##FETCH_STATUS = 0 BEGIN
UPDATE TABLE BASED SON VARIABLES
FETCH NEXT FROM CURUPD INTO VARIABLES
END
CLOSE CUR
DEALLOCATE CUR
end TRY
begin catch
FETCH NEXT FROM CURUPD INTO VARIABLES
continue
end catch;
some errors are not trappable and will abort the batch even with try and catch you could check XACT_STATE() and then determine what to do
Why do you need a cursor can't you do a SET based update?
Also your try is outside of the loop but you will still have the same problem, try updating an int colum,n with 'A'....BOOM!