Bonjour,

Je suis sous Oracle 10gR2.
J'ai un problème avec un bout de code en PL/SQL qui plante avec l'erreur ORA-01002 : fetch out of sequence.
Après recherche, il apparaitrait que cette erreur se produit dans un des 3 cas suivant :
  1. Fetch d'un curseur alors que toutes les lignes ont été lues
  2. Commit à l'intérieur d'une boucle FOR LOOP sur un curseur ouvert en mode FOR UPDATE
  3. Re-bind de variable d'une requête SQL et fetch sans rééxecuter la requête
Le code a l'aspect suivant: (dans un package)
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
 
PROCEDURE MAPROC IS
CURSOR C1 IS
  SELECT ...
  FROM TABLE_DES_VOYAGES M
  WHERE M.KEY = MaVariableKey
  AND EXISTS (SELECT 1 FROM TABLE_DES_TRAVAUX T WHERE T.KEY = M.KEY AND T.STATUS <> 'X')
  FOR UPDATE;
R1 C1%ROWTYPE;
CURSOR C2 IS
   SELECT ...
   FROM TABLE_DES_TRAVAUX 
   WHERE KEY = R1.KEY
   FOR UPDATE;
CURSOR C3 IS
   SELECT ...
   FROM TABLE_QUELCONQUE
   WHERE << condition >>;
R3 C3%ROWTYPE;
BEGIN
   FOR FORTDV IN C1 LOOP 
       R1.KEY = FORTDV.KEY;
       UPDATE TABLE_DES_VOYAGES
       SET CHAMP = Calcul
       WHERE CURRENT OF C1;
 
       PROC_INSERT_TEMP; -- procédure autonome
 
       OPEN C3;
       LOOP
           FETCH C3 INTO R3;
           EXIT WHEN C3%NOTFOUND;
           -- calcul sur R3
       END LOOP;
       CLOSE C3;
 
       FOR R2 IN C2 LOOP
           UPDATE TABLE_DES_TRAVAUX
           SET CHAMP = Calcul
           WHERE CURRENT OF C2;
       END LOOP;
   END LOOP;
EXCEPTION ...
END;
La procédure PROC_INSERT_TEMP est une procédure autonome (PRAGMA AUTONOMOUS_TRANSACTION) qui fait une insertion dans une table et un commit.

A la vue du code, j'ai d'abord cherché la présence d'un COMMIT qui agirait dans un des 2 FOR LOOP. Malheureusement, le seul présent est dans la procédure autonome, et j'ai effectué plusieurs tests qui m'ont montré que dans ce cas, il n'y a pas d'erreur.

J'ai ensuite envisagé une erreur sur le fetch du curseur C3, mais là aussi, des tests m'ont montré que j'ai beau faire plus de fetch que le curseur a de lignes, je ne tombe pas en erreur. Tout au plus, ma variable receptrice vaut NULL et j'ai C3%FOUND = FALSE.

Donc, à ce stade, je suis bloqué aux constatations suivantes :
  1. Le cas du fetch alors que toutes les lignes ont déjà été lues ne semble pas être le problème (d'ailleurs, je n'arrive pas à reproduire cette erreur)
  2. Le cas du commit dans une boucle FOR LOOP avec un curseur FOR UPDATE n'est pas le problème de manière quasiment certaine
  3. J'avoue ne pas comprendre ce que veut dire le rebind ? D'ailleurs, je remets la définition en anglais au cas où ma traduction soit hasardeuse : Rebinding any placeholders in the SQL statement, then issuing a fetch before reexecuting the statement
Je ne peux hélas pas débugger ce bout de code, ni rejouer le package car cela se passe en production. Avez-vous des idées sur le problème ?