2016-05-12 2 views
1

J'essaie d'extraire des données à partir d'une variable de curseur ouverte dans une fonction stockée mais je reçois toujours un message d'erreur "fetch out of sequence".En utilisant Pro * C, comment chercher à partir d'un curseur ouvert dans la fonction stockée PL sans définir l'option 'sqlcheck = semantics'?

Voici la fonction stockée:

CREATE OR REPLACE FUNCTION test_function RETURN SYS_REFCURSOR AS 
    p_recordset SYS_REFCURSOR; 
BEGIN 
    OPEN p_recordset FOR SELECT '1' FROM DUAL UNION SELECT '2' FROM DUAL; 
    RETURN p_recordset; 
END TEST_FUNCTION; 

Et le code Pro * C:

int myfunction() 
{ 
    ... 
    EXEC SQL BEGIN DECLARE SECTION; 
    SQL_CURSOR sql_cursor_pl; 
    VARCHAR string_field[20]; 
    EXEC SQL END DECLARE SECTION; 

    EXEC SQL ALLOCATE :sql_cursor_pl; 

    // It is not possible to use embedded PL/SQL block as seen in other 
    // examples because it requieres a compilation time access to database 
    // that I don't have, so as far as I know I have to use EXEC SQL CALL 
    EXEC SQL CALL sch.test_function() INTO :sql_cursor_pl; 

    EXEC SQL WHENEVER NOT FOUND DO break; 

    //for (; ;) 
    while (sqlca.sqlcode == '\0') 
    { 
    EXEC SQL FETCH :sql_cursor_pl INTO :string_field; 
    ... 
    } 

    EXEC SQL CLOSE :sql_cursor_pl; 
    ... 
} 

La fonction stockée fonctionne très bien si je l'utilise dans un autre bloc PL comme celui ci-dessous, donc Je pense que le problème devrait être dans le code Pro * C.

DECLARE 
    mycursor sys_refcursor; 
    string_field VARCHAR(20) 
BEGIN 
    mycursor := sch.test_function(); 
    LOOP 
    FETCH mycursor INTO string_field; 
    EXIT WHEN mycursor%NOTFOUND; 
    DBMS_OUTPUT.PUT_LINE(string_field); 
    END LOOP; 
    CLOSE mycursor; 
END; 

Répondre

2

Je pense avoir trouvé le problème et une solution. Lorsque vous ouvrez un curseur dans un bloc PL/SQL, l'index du curseur commence à 0, mais les Pro * C commencent à partir de 1. Le problème est que Pro * C ne met pas à jour l'index du curseur, donc une solution pourrait être incrémenter manuellement comme ceci vu here.

... 
while (sqlca.sqlcode == '\0') 
{ 
    sql_cursor_pl.curocn++; 
    EXEC SQL FETCH :sql_cursor_pl INTO :string_field; 
    ... 
} 
... 
1

Le problème est dans la condition while qui est testée avant d'exécuter la commande FETCH.

Je résous habituellement ces boucles en utilisant la directive EXEC SQL WHENEVER NOT FOUND. Voici un exemple sur la façon de le faire:

while(1) 
{ 
    EXEC SQL WHENEVER NOT FOUND DO break; // Where a no data found occurs execute a C "break" instruction. 
    EXEC SQL FETCH :sql_cursor_pl INTO :string_field; 
    EXEC SQL WHENEVER NOT FOUND DO ???; // Restore desired behaviour. 

    ... 
} 

La première directive indique Pro * C/C++ pour exécuter un break si aucune donnée trouvée erreur se produit, cela signifie que la sortie de la boucle while. La deuxième directive est nécessaire pour restaurer le comportement souhaité (une pause est souhaitée ici dans le temps, mais dans le reste du code n'est probablement pas le meilleur choix).

+0

Merci pour votre réponse, mais mon code inclut également cette déclaration avant que la boucle comme il se doit, et je pense que le retour d'un curseur à partir d'une sélection qui récupère des valeurs constantes de double doit toujours retourner un curseur valide. –