How to recursively call a procedure when there is a deadlock? - mysql

I have jobs "stored procedures" runs over night. Every now and then I run into a deadlock. I want to write a code that will execute the same procedure after 15 minutes up to 3 time if a deadlock is found.
Assume the time now is 10AM. Then run it at 10AM, if a deadlock found, call the job again at 10:15AM, then at 10:30AM "if dead locked", then 10:45AM "if dead locked." If the last run dead locked then terminate the job completely.
Here is What I have done.
DECLARE totalTrys INT DEFAULT 0;
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
GET DIAGNOSTICS CONDITION 1
#err_num = MYSQL_ERRNO;
if(#err_num = 1213 AND totalTrys < 4) THEN
SET totalTrys = totalTrys + 1;
SELECT SLEEP(900);
CALL guardi.prod_update_guardi_accounts();
END IF;
END;
Is this a valid approach? is there a better way other than eliminating deadlocks all together?

I would keep everything in the procedure: Then all code related to this behaviour is at one location. Also: Would the deadlock not follow the execution of you CALL statement instead of proceed? If is proceeds, it is probably already solved, and we are then waiting for nothing. Also transactions following a deadlock, would just be executed after the deadlock is resolved.
My approach with your code would be:
CREATE PROCEDURE manageAccounts()
BEGIN
DECLARE totalTrys INT DEFAULT 0;
DECLARE EXIT HANDLER FOR SQLEXCEPTION
GET DIAGNOSTICS CONDITION 1
#err_num = MYSQL_ERRNO;
CALL guardi.prod_update_guardi_accounts();
WHILE(#err_num = 1213 AND totalTrys < 4) DO
SET totalTrys = totalTrys + 1;
SELECT SLEEP(900);
CALL guardi.prod_update_guardi_accounts();
END WHILE;
END;
You will have to test this: Untested, so typos are not impossible.

Related

basic cursor mysql with loop

I've been trying to create a cursor but for some reason i keep getting an error saying theres something wrong with the syntax.
what im asking is for a basic cursor that i can use with a loop so that i can call a function for each row. literally a mysql equivelent of php foreach loop
function functionName ($commentId){
$i = 0;
foreach (commentId as value) {
//inside here we would do whatever function we would like but for this example i just want a basic increment to keep things simple and easy to understand
$i++;
}
echo $i;}
functionName(76);
i understand php is a little bit different as i would first need to select the rows using a mysql query and have the $commentId variable equal to the but i was just using this as an example to make this question as clear as i can make it.
here is my example that keeps failing
DELIMITER $$
create function functionName(commentOn int(11)) returns int
BEGIN
DECLARE done INT DEFAULT FALSE;
declare var int;
declare anotherVar int;
set var = 0;
set anotherVar = 0;
DECLARE cur1 CURSOR FOR SELECT id FROM comments where `commentOnComment` = commentOn;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cur1;
read_loop: LOOP
FETCH cur1 INTO anotherVar;
set var = var + 1;
IF done THEN
LEAVE read_loop;
END IF;
END LOOP;
CLOSE cur1;
return var;
END; $$
DELIMITER ;
select functionName(76);
to explain what this example is in a little more detail, there is a table full of comments, the comment id and the id of the comment the user commented on (commentOnComment). and in the end i want to loop through all of the comments and select all where the commentOnComment equals the id of the comment the user commented on so that i can see how much replies each comment has i will change the increment to a select count(*) from comments where commentOnComment = commentOn; the commentOn parameter will be the id of the comment. But for the answer shown for this question i just want an increment to keep it simple and easy for myself and other people to understand.
Thanks to P.Salmon i was able to get a basic cursor with loop working, it was just the order of my code that was the problem. Im very greatfull as a little mistake like this would have taken me forever to figure out especially with the fact that i had never done a working cursor before.
here is the code for a basic cursor that does a function for each row in a table, in this example it increments the value of a variable by 1.
DELIMITER $$
create function functionName(commentOn int(11)) returns int
BEGIN
DECLARE done INT DEFAULT FALSE;
declare var int;
declare anotherVar int;
DECLARE cur1 CURSOR FOR SELECT id FROM comments where `commentOnComment` = commentOn;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
set var = 0;
set anotherVar = 0;
OPEN cur1;
read_loop: LOOP
FETCH cur1 INTO anotherVar;
IF done THEN
LEAVE read_loop;
END IF;
/*comment here is the area where you can add whatever insert, update, select or any
type of function you would like for each row. This is literally mysql's version of
php's foreach loop*/
set var = var + 1;
END LOOP;
CLOSE cur1;
return var;
END; $$
DELIMITER ;
as you can see its very similar to the question i just needed to change the order of my code. a simple select functionName(id); will give you the output, the id can be any number, in this example it would be the id of the row.
I am also curious as to why many people viewed this question but didnt answer, consequentially causing me to have to answer myself? if P.Salmon didnt comment and tell me the problem i would still be stuck. i tried to be as clear as i could, was it difficult to understand? was the question too hard for most people? feedback would be highly appreciated as it will help me in my future questions.

MySql Procedure GOTO Statement

I want to use goto statement in Mysql stored procedure in such manner that I execute my cursor whenever condition become true once again.
This is a sample code only, I just looking for goto statement
BLOCK_BACKLOG:begin
declare backlgId, oldCOR, oldATR,oldCourse,oldATR,isFormFilled,nextParentId int;
declare backlogNoMoreRow boolean default false;
Label : TestLineStart
declare backlogCur cursor for select bcklg.id,cor.id,atr.id,cr.id,atr.obtainedMarks,atr.isFormFilled,atr.parentRegistration_id
from train bcklg,bus cor,fliet atr,fair co,distance cr
where bcklg.courseofferingregistration_id=cor.id and cor.academictermregistration_id=atr.id and cor.courseoffering_id=co.id and co.course_id=cr.id
and bcklg.isDeleted is false and atr.id=parentId;
declare continue handler for not found set backlogNoMoreRow=true;
open backlogCur;
LOOP_BACKLOG: loop
fetch backlogCur into backlgId, oldCOR, oldATR,oldCourse,oldATRMarks,isFormFilled,nextParentId;
if backlogNoMoreRow then
close backlogCur;
leave LOOP_BACKLOG;
end if;
if isFormFilled==0 then
parentId=nextParentId;
GOTO TestLineStart;
end if;
You can use a LOOP on the outer block based on the value for variable isFormFilled.
Following change may help you.
-- Label : TestLineStart
TestLineStart: LOOP
-- other part of your SP as it is
and make following change:
if isFormFilled==0 then
parentId=nextParentId;
-- GOTO TestLineStart;
else
leave TestLineStart;
end if;
You have to close all loop statements properly.

FFT implementation in Verilog : Error using nested for loop

This post is related to the my previous post related to FFT.
FFT implemetation in Verilog: Assigning Wire input to Register type array
I want to assign output of first stage to input of second stage of FFT butterfly modules. I have to re-order the output of first stage according to input of second stage. Here is my code to implement the swapping.
always# (posedge y_ndd[0] or posedge J)
begin
if(J==1'b1)
begin
for (idx=0; idx<N/2; idx=idx+1)
begin
IN[2*idx] <= X[idx*2*X_WDTH+: 2*X_WDTH];
IN[2*idx+1] <= X[(idx+N/2)*2*X_WDTH+: 2*X_WDTH];
end
end
else
begin
level=level+1;
modulecount=0;
for(jj=0;jj<N;jj=jj+(2**(level+1)))
begin
for (jx=jj; jx<jj+(2**level); jx=jx+1)//jj+(2**level)
begin
IN[modulecount] <=OUT[jx];
IN[modulecount+1] <=OUT[jx+(2**level)];
modulecount=modulecount+1;
end
end
end
end
When I synthesize this, It gives 2 errors.
ERROR:Xst:891 - "Network.v" line 161: For Statement is only supported when the new step evaluation is constant increment or decrement of the loop variable.
ERROR:Xst:2634 - "Network.v" line 161: For loop stop condition should depend on loop variable or be static.
Can't we use non-constant increment and non-static stop coditions?
If that so, how we handle this.
Any help is appreciated.
Thanks in advance.
Synthesis tools unroll loops in order to synthesize the circuit. Therefore, only loops that iterate a constant number of times, whose constant is known at compile/elaboration time are synthetisable.
When the stop value is not known, you can assume a maximum number of iterations and use that as the stop condition. Then add the original stop condition as a conditional statement inside the loop:
for (jx=jj; jx < MAX_LOOP_ITERATION; jx=jx+1)//jj+(2**level)
begin
if (jx<jj+(2**level)) // <---------- Add stop condition here
begin
IN[modulecount] <=OUT[jx];
IN[modulecount+1] <=OUT[jx+(2**level)];
modulecount=modulecount+1;
end
end
If N is not a constant, the outer loop should also be fixed using a similar conditional statement. You also need to fix the increment value and each time add a constant value. Use a conditional statement to check if jj==jj+(2**(level+1))
Obviously, you need to be careful as a high max number may increase your worst case delay and the minimum clock cycle time.
//ll,level,K has to be declare.
always# (posedge y_ndd[0] or posedge J)
begin
if(J==1'b1)
begin
for (idx=0; idx<N/2; idx=idx+1)
begin
IN[2*idx] <= X[idx*2*X_WDTH+: 2*X_WDTH];
IN[2*idx+1] <= X[(idx+N/2)*2*X_WDTH+: 2*X_WDTH];
end
end
else
begin
ll=ll+1;
modulecount=0;
for(level=0;level<K;level=level+1) //K time you need to execute
begin
if(ll==level)
begin
for(jj=0;jj<N;jj=jj+(2**(level+1)))
begin
for (jx=jj; jx<jj+(2**level); jx=jx+1)
begin
IN[modulecount] <=OUT[jx];
IN[modulecount+1] <=OUT[jx+(2**level)];
modulecount=modulecount+1;
end
end
end
end
//ll=ll+1;
end
end
You can try this. It has to work. But problem is outer loop will execute K times.

Warning 1329 no data fetched

delimiter ;;
create procedure cd3(out var int)
begin
declare finished int default 0;
declare cur cursor for select id from a;
declare continue handler for not found set finished=1;
open cur;
curloop:loop
fetch cur into var;
if finished then
leave curloop;
end if;
end loop curloop;
close cur;
end;;
call cd3(#var);
This is a warning provided by MySQL. They can be a bit confusing, i suggest you read up on it: See http://dev.mysql.com/doc/refman/5./en/show-warnings.html
I would use this approach instead
declare v_var VARCHAR(200); <-- if that whats it expected to be
open cur;
-- create a loop
repeat_cur: LOOP
FETCH cur INTO var;
-- checks if it is done
if finished then
LEAVE repeat_cur;
end if;
// DO THE WORK
END LOOP;
close cur;
Im not sure since var is a expected out parameter. You can declare var as a variable and work with it, otherwise just skip the declare line i wrote.
Check out this page: How to get rid of "Error 1329: No data - zero rows fetched, selected, or processed" , he had the same problem, and was solved by adding a simple select statement into var.
If above doesnt work, try adding this before the end of the loop.
SELECT 'var' INTO var;

Multiple handlers conflicting

I have nested cursor loops, and I wanted to catch error 1329, no data fetch, on the outer loop. How can I do this?
I tried to add a second CONTINUE HANDLER for this outer loop cursor but it catches nested loop errors (not wanted), and it ends up not triggering the nested handler.
I have this:
DECLARE cur1 CURSOR FOR select data, valor_split, valor_div from tbl1 where data >= primeira_mov and id_papel = idpapel order by data DESC;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
DECLARE CONTINUE HANDLER FOR 1329 BEGIN
SET nodata_issue = 1;
SET dateof_issue = datasplit;
END;
Any ideas on how can I solve this?
Set a flag to 1 when you enter the inner loop, set it to 0 when you leave it.
Then:
DECLARE CONTINUE HANDLER FOR 1329 BEGIN
IF flag_innerloop = 0 THEN do_something;
ELSE do_something_else;
END;