0
votes

My triger It works normally but if i use procedur in the insert I'm getting the error

1442 - Can't update table 'stock' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.

bu if i use manuel insert into table panier Normal inserted does not show me the error :'(

i use it like that :

call temps;
call stock_panier(94,19,'tranche');
call panier_ins(22547153,6185,null,now());

my triger :

DELIMITER $$
CREATE TRIGGER  Stock_cal BEFORE INSERT on panier
FOR EACH ROW  BEGIN
  DECLARE is_exist INT;
    DECLARE is_exist1 INT;
      DECLARE is_exist2 INT;
            set is_exist = (select stock.qte_res_s from stock WHERE stock.code_s=new.code_s);
        set is_exist1 = new.qte_p;
        set is_exist2 = new.qte_p;
            if  (is_exist<is_exist1) OR (is_exist2<1) THEN
  SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '✘: Opération a été refusée.';    
                ELSE  
       UPDATE stock SET qte_res_s=qte_res_s-new.qte_p,qte_sor_s=qte_sor_s+new.qte_p WHERE  new.code_s=stock.code_s  ;
       END if;
      
END$$
DELIMITER ; 

my table temperer :

CREATE PROCEDURE `temps`()
BEGIN
call virifier_table_exist('panier_tm');
if (@table_exists)=0 THEN
    CREATE TEMPORARY TABLE `panier_tm` (
      `N_p` bigint(20) DEFAULT Null,
      `N`   bigint(20) DEFAULT null,
        `Code_barr` varchar(100) DEFAULT NULL,
        `Référence` varchar(40) DEFAULT NULL,
        `Désignation` varchar(40) DEFAULT NULL,
        `Prix_HT` varchar(20) DEFAULT NULL,
        `Fournisseur` varchar(30) DEFAULT NULL,
        `Magasin` varchar(10) DEFAULT NULL,
        `Qte_Vent` varchar(5) DEFAULT NULL,
        `code_s` bigint(20) DEFAULT NULL,
        `code_d` bigint(20) DEFAULT NULL,
        tva_p varchar(5) DEFAULT Null,
        type_ver varchar(15) DEFAULT null);
SET @row_number:=0;
else    
DROP TEMPORARY TABLE `panier_tm`;
    CREATE TEMPORARY TABLE `panier_tm` (
      `N_p` bigint(20) DEFAULT Null,
      `N`   bigint(20) DEFAULT null,
        `Code_barr` varchar(100) DEFAULT NULL,
        `Référence` varchar(40) DEFAULT NULL,
        `Désignation` varchar(40) DEFAULT NULL,
        `Prix_HT` varchar(20) DEFAULT NULL,
        `Fournisseur` varchar(30) DEFAULT NULL,
        `Magasin` varchar(10) DEFAULT NULL,
        `Qte_Vent` varchar(5) DEFAULT NULL,
        `code_s` bigint(20) DEFAULT NULL,
        `code_d` bigint(20) DEFAULT NULL,
         tva_p varchar(5) DEFAULT Null,
        type_ver varchar(15) DEFAULT null);
SET @row_number:=0;
        end if;
END$$
DELIMITER ;

my procedure :

drop PROCEDURE if EXISTS panier_ins ;
DELIMITER $$
CREATE PROCEDURE panier_ins (in code_cccp varchar(30), code_cl1 bigint(20),N_p1 bigint(20),dat date)
BEGIN
DECLARE code_faa varchar(20);
DECLARE  n_p2 bigint(20);
START TRANSACTION;
if (SELECT COUNT(Qte_Vent) from panier_tm tm2,stock WHERE tm2.code_s=stock.code_s and tm2.Qte_Vent>stock.qte_res_s and not EXISTS (select 1 from panier_vu vu2 where tm2.N_p=vu2.code_p and tm2.code_s=vu2.code_s ))>0 THEN 
SELECT "Veuillez vous assurer que le stock est terminé" AS message ;
ELSE 
set @count_n_p=(select COUNT(n_p) from panier_tm where n_p=n_p1);
set @n_p=(select n_p from panier_tm where n_p=n_p1);
       if (@n_p) is null OR  (@count_n_p)=0 THEN
     SET @n_p2=(SELECT MIN(t1.code_p+1) as id FROM panier t1 LEFT JOIN panier t2 On t1.code_p+1=t2.code_p Where t2.code_cl IS NULL);
           set @n_p2=if(@n_p2 = null,1,@n_p2);
           INSERT INTO `panier`(`code_p`, `n_p`, `code_s`, `code_cl`, `type_ver_p`, `date_p`, `qte_p`, `prix_p`, `tva_p`) SELECT @n_p2,tm1.n,stock.code_s,code_cl1,type_ver,dat,qte_vent,prix_ht,tva_p FROM `preduit`,`stock`,`panier_tm` tm1 WHERE    preduit.code_pr=stock.code_pr  and tm1.code_s=stock.code_s and  NOT EXISTS (select 1 from panier_vu vu1 where tm1.N_p=vu1.code_p and tm1.code_s=vu1.code_s);
    update panier_tm set N_p=@n_p2;
   set code_faa=(SELECT MIN(SUBSTRING(t1.code_fa, 6, length(t1.code_fa)-5)+1) as id FROM facture t1 LEFT JOIN facture t2 On SUBSTRING(t1.code_fa, 6, length(t1.code_fa)-5)+1=SUBSTRING(t2.code_fa, 6, length(t2.code_fa)-5) Where t2.code_fa IS NULL);
  set code_faa=  CONCAT( DATE_FORMAT(now(),"%Y"),"/",code_faa) ;
    INSERT INTO `facture`(`autot`, `code_fa`, `code_ccp`, `code_cl`, `code_p`, `date_fa`, `type_ver`) VALUES (null,code_faa,code_cccp,code_cl1,@n_p2,now(),typ);
   COMMIT ;
     ELSE
    START TRANSACTION;
           INSERT INTO `panier`(`code_p`, `n_p`, `code_s`, `code_cl`, `type_ver_p`, `date_p`, `qte_p`, `prix_p`, `tva_p`) SELECT tm1.n_p,tm1.n,stock.code_s,code_cl1,type_ver,dat,qte_vent,prix_ht,tva_p FROM `preduit`,`stock`,`panier_tm` tm1 WHERE preduit.code_pr=stock.code_pr and tm1.code_s=stock.code_s and  NOT EXISTS (select 1 from panier_vu vu1 where tm1.N_p=vu1.code_p and tm1.code_s=vu1.code_s);
         DELETE b FROM `panier` b LEFT JOIN panier_tm f ON  f.code_s = b.code_s and b.code_p=f.N_p WHERE code_p=n_p1 and f.N_p is null;
          UPDATE `panier` p1,panier_tm tms SET p1.`n_p`=tms.N_p,p1.`qte_p`=tms.Qte_Vent,p1.`prix_p`=tms.Prix_HT,`tva_p`=tva1 WHERE p1.code_p=N_p1 and p1.code_s=tms.code_s;
   COMMIT ;
     END if;
END IF;
END$$
DELIMITER ;
1
I can''t see nothing that could call this behaviuor. the only trigger Stock_cal thich updates stock, so as long you don't have a triggerf which calls on a procedure... - nbk
Unless there is another trigger on stock table or panier table that causes this error. - Shadow
problem in procedure not in trigger - Djallel Merzoug
i dont have trigger in stock table - Djallel Merzoug

1 Answers

0
votes

Your problem are the two inserts into panier that depend on stock, while you have an on insert-trigger on panier that modifies the table stock that the insert into panier depends on:

INSERT INTO `panier`(`code_p`, ...) SELECT @n_p2,tm1.n,stock.code_s, ...
FROM `preduit`,`stock`,`panier_tm` tm1 WHERE reduit.code_pr=stock.code_pr ...

INSERT INTO `panier`(`code_p`, ...) SELECT tm1.n_p,tm1.n,stock.code_s, ...
FROM `preduit`,`stock`,`panier_tm` tm1 WHERE preduit.code_pr=stock.code_pr ...

They both have the structure

INSERT INTO panier (...) SELECT ... FROM stock ...

which is not allowed if you have an insert trigger on panier which modifies stock. These inserts are the statement which invoked this stored function/trigger in which you can't update table 'stock'. MySQL is for technical reasons not able to do this.

The straight forward technical workaround for this is to create a temporary table in which you store the result of your SELECT ..., and then insert into panier from that temporary table, e.g. something like

 create temporary table tmp (...);
 insert into tmp (...) select ... from stock ...;
 insert into panier (...) select ... from tmp;
 drop table tmp;

The insert-trigger now doesn't modify any dependent tables anymore, since you only select from tmp.

In your procedure, this would look like

 create temporary table tmp (code_p bigint(20), n_p bigint(20), 
 ..., tva_p varchar(5)); 

 if (@n_p) is null OR  (@count_n_p)=0 THEN  
   ...
   insert into tmp (code_p, n_p, ...) 
   SELECT @n_p2,tm1.n,stock.code_s, ...
   FROM `preduit`,`stock`,`panier_tm` tm1 WHERE reduit.code_pr=stock.code_pr ...

   insert into panier (code_p, n_p, ...) select code_p, n_p, ... from tmp;
   ...
else  
   ...
   insert into tmp (code_p, n_p, ...) 
   SELECT tm1.n_p,tm1.n,stock.code_s, ...
   FROM `preduit`,`stock`,`panier_tm` tm1 WHERE preduit.code_pr=stock.code_pr ...

   insert into panier (code_p, n_p, ...) select code_p, n_p, ... from tmp;
   ...
end if; 
drop table tmp;

You can of course create the temporary table in your procedure temps.

It is also usually possible to redesign your procedure, triggers or logic so you do not need this, but that would probably be a larger endeavour.

And you should verify if that is actually the logic you want to apply, e.g. if you want to decide on the current state of stock which rows to insert, freeze this state (by putting it into the tmp-table) and then run the insert independently of how the stock-table changed during those inserts (e.g. if you would have inserted the 2nd row if you would have known what the first row changed in stock). I didn't check what your code is supposed to do, so this may or may not apply here, and may or may not be a problem here, but circular dependendies (and the error you get here because of it) can sometimes be a sign for an underlying problem.