2010-11-26 36 views
1

Ceci est vraiment dérivé de my earlier question today.Appel de la procédure stockée dans la boucle foreach - première exécution seulement

J'ai créé une procédure stockée dans ma base de données que je voulais appeler plusieurs fois de suite à partir de PHP.
Disons que ceci est ma procédure:

CREATE PROCEDURE PROC_1(
    IN param1 VARCHAR(255), 
    IN param2 VARCHAR(255)) 
BEGIN 
    DECLARE ok INT; 
    DECLARE success, failure VARCHAR(255); 

    /* several SELECT, IF ... THEN, INSERT and UPDATE operations which then SET ok var to 0 or 1 */ 
    IF ok = 1 THEN 
    SET success = 'Everything went well'; 
    SELECT success; 
    LEAVE; 
    ELSE 
    SET failure = 'Problem description'; 
    SELECT failure; 
    LEAVE;  
    END IF; 
END 

Je l'ai fait de cette façon (version courte):

$calls = array(
    "CALL PROC_1('param1', 'param2')", 
    "CALL PROC_1('param3', 'param4')", 
    "CALL PROC_1('param5', 'param6')", 
); 

// assuming I'm already connected to DB with $link 
foreach ($calls as $i => $call) 
{ 
    echo $i . ': '; 
    $result = mysql_query($call); 
    $ok = ($result === FALSE) ? FALSE : TRUE; 
    var_dump($ok); 

    if ($result !== FALSE) 
     mysql_free_result($result); 
} 

Les premiers travaux d'itération comme prévu, mais quoi que ce soit après le retour FALSE.
Pourquoi est-ce?

Essayé mysqli juste au cas où, mais obtenir exactement le même résultat:

0: bool(true) 
1: bool(false) 
2: bool(false) 

Ce qui est intéressant, je l'ai vérifié les journaux MySQL (journalisation configuré pour journaliser toutes les requêtes) et seule la première requête obtient jamais au serveur . Les requêtes suivantes ne parviennent jamais au serveur.

PS. Je cours PHP 5.3.2 et Apache 2.2.17.


MISE À JOUR

Selon la suggestion de Shakti Singh J'ai vérifié $link état avant interrogation de la base. J'ai remarqué qu'il ya une erreur depuis la deuxième itération voici donc la sortie avec l'erreur:

ERROR: (0) 
0: bool(true) 
ERROR: (0) 

ERROR: (0) 
1: bool(false) 
ERROR: (2014) Commands out of sync; you can't run this command now 

ERROR: (2014) Commands out of sync; you can't run this command now 
2: bool(false) 
ERROR: (2014) Commands out of sync; you can't run this command now 

En outre, cela apparaît dans l'erreur MySQL journal:

101126 15:46:28 [Warning] Aborted connection 129 to db: 'db1' user: 'root' host: 'localhost' (Got an error reading communication packets) 
+0

Pouvez-vous var_dump ($ link) en dessous de l'écho $ i. ':'; –

+0

C'était un bon conseil Shakti. Montre un peu plus sur le problème maintenant. Détails dans la question mise à jour –

+1

Une procédure stockée peut renvoyer plusieurs jeux de résultats et renvoie toujours un jeu de résultats supplémentaire qui ne contient aucune donnée mais les informations d'erreur/d'avertissement globales concernant l'appel de procédure en plus de tous les jeux de résultats renvoyés explicitement. - http://forums.mysql.com/read.php?52,228296,228347#msg-228347 – ajreal

Répondre

2

En PHP, lorsque nous appelons une procédure stockée dans une boucle, il suffit de l'exécuter une fois. Cela se produit lorsque la procédure stockée renvoie un jeu de résultats. J'ai fait face au même problème. J'ai eu une procédure stockée pour mettre à jour les enregistrements de table.

DELIMITER $$ 

DROP PROCEDURE IF EXISTS `espritkm`.`update_notification`$$ 
CREATE DEFINER=`root`@`localhost` PROCEDURE `update_notification`(item_id_val VARCHAR(11),item_source_val VARCHAR(50),item_type_id_val INT(50),item_type_val VARCHAR(50),created_at_val BIGINT(11),pivot_user_id_val VARCHAR(256),pivot_item_type_val VARCHAR(64),pivot_owner_type_val VARCHAR(64),pivot_owner_id_val INT(11),user_id_val VARCHAR(64), OUT row_effect VARCHAR(11)) 
Begin 
    Declare item_count INT(10); 
    SET @SQL1 = CONCAT('select count(*) into @item_count from item_notifications where item_id = ''', item_id_val, '''');                     PREPARE S1 FROM @SQL1;                    EXECUTE S1;                     DEALLOCATE PREPARE S1;  
    IF @item_count = 0 THEN 
     SET @SQL2 = CONCAT('INSERT INTO item_notifications (item_id,item_source,item_type_id,item_type,created_at,pivot_user_id,pivot_item_type,pivot_owner_type,pivot_owner_id,user_id) value(''',item_id_val,''',''',item_source_val,''',''',item_type_id_val,''',''',item_type_val,''',''',created_at_val,''',''',pivot_user_id_val,''',''',pivot_item_type_val,''',''',pivot_owner_type_val,''',''',pivot_owner_id_val,''',''',user_id_val,''')');  
PREPARE S2 FROM @SQL2;                     EXECUTE S2;                      DEALLOCATE PREPARE S2;  
     SET row_effect= "Insert";  
    ELSE    
     SET row_effect= "Update";  

    SET @SQL3 = CONCAT('UPDATE item_notifications SET viewer_id = ''',user_id_val,''' WHERE item_id = ''' ,item_id_val,'''') ;  
     PREPARE S3 FROM @SQL3;                     EXECUTE S3;                     DEALLOCATE PREPARE S3;  

    END IF; 
    SELECT row_effect; 
END$$ 

DELIMITER ; 

Et cela était censé être exécuté pour 1000 + lignes, mais exécuté pour un seul enregistrement.

Il ne prend pas en charge dans le cas où votre SP retourner un ensemble de données. Il suffit d'éliminer la variable OUT, ou toute instruction select (juste pour toute référence de résultat), et cela fonctionnera bien.