Vous n'êtes pas identifié(e).

#1 14/02/2012 18:09:17

mourad
Membre

Afficher résultat fonction avec libpq

Bonjour tout le monde,
j'ai crée une fonction

CREATE OR REPLACE FUNCTION "mabase"."get_the_results" (varchar) RETURNS "pg_catalog"."refcursor" AS
$body$
DECLARE
  CodeId ALIAS FOR $1;
  curRet REFCURSOR;
  SQL_QUERY varchar;
BEGIN
      SQL_QUERY := 'SELECT sp_code_sq_pk    ,      
             sp_gsp_code_fk   ,     
             A.CDF_NOM        AS STATUT_LABO ,          
             B.CDF_NOM        AS SP_LISTE    ,         
             sp_catc_code_fk  ,    
             sp_ceph_code_fk  ,   
             sp_cge_code_fk   ,     
             sp_pr_code_fk    ,      
             sp_type_spe      ,        
             sp_gref_fk       ,         
             sp_nom           ,           
             sp_nomcomp       ,         
             sp_ph            ,           
             sp_cipucd        ,         
             sp_datecr        ,        
             sp_datemj        ,          
             sp_nl            ,             
             sp_aphp          ,            
             sp_origine_gene  ,    
             sp_nomlong		  ,
             SP_CIPUCD13	  ,
		     SP_MONO_VIRTUELLE AS MONO_VIR      
      FROM   theriaque.SP_SPECIALITE,
             theriaque.CDF_CODIF A, 
             theriaque.CDF_CODIF B
      WHERE  SP_CDF_SLAB_CODE_FK = A.CDF_CODE_PK 
      AND    SP_CDF_LI_CODE_FK   = B.CDF_CODE_PK
      AND    A.CDF_NUMERO_PK     = ''15'' 
      AND    B.CDF_NUMERO_PK     = ''08''
      AND    SP_CODE_SQ_PK = CAST('||CodeId||' AS NUMERIC)';
open curRet FOR execute SQL_QUERY;
RETURN curRet;
end;

J'ai voulu afficher les résultats renvoyée par cette procédure depuis une petite application C++.
J'ai utilisé la librairie libpq, mais je n'arrive pas à afficher les résultats vu que lorsque je récupère les enregistrements renvoyés dans un CURSOR et puis j'essai de faire le parcours de ce curseur j'ai toujours le nom de la procédure qui est affiché avec comme valeur "unnamed portal".
Est ce que quelqu'un a une idée où se trouve mon problème et qu'est ce que je dois faire pour corriger ce problème ?
Merci d'avance pour votre aide.
Cordialement.

Hors ligne

#2 14/02/2012 18:21:56

rjuju
Administrateur

Re : Afficher résultat fonction avec libpq

Bonjour.
Je ne pense pas qu'un refcursor soit utilisable comme ça.
Pourquoi ne pas utiliser une fonction retournant un setof record ou une table, et même du coup utiliser une fonction sql et non pl/pgsql.
Ex :

CREATE OR REPLACE FUNCTION "mabase"."get_the_results" (varchar) RETURNS TABLE(sp_code_sq_pk integer, sp_gsp_code_fk integer, ....) AS
$BODY$
SELECT ...
FROM ...
WHERE ... AND SP_CODE_SQ_PK = CAST('||$1||' AS NUMERIC)';
$BODY$
  LANGUAGE sql VOLATILE;

Cela dit, il est encore plus simple de créer une vue que ce genre de fonction, si le but est de simplifier les requêtes coté c++.

Dernière modification par rjuju (14/02/2012 18:24:03)

Hors ligne

#3 14/02/2012 18:37:13

mourad
Membre

Re : Afficher résultat fonction avec libpq

Merci pour votre réponse.
En fait, j'ai effectué une migration de la procédure depuis SQL Server et l'outil que j'ai utilisé m'a généré cette fonction.

Je ne pense pas qu'un refcursor soit utilisable comme ça.

1. Est ce que je dois obligatoirement modifier le type de retour de la fonction ?
2. Si je change le type de retour, est ce que ça donne le résultat escompté ?

Cela dit, il est encore plus simple de créer une vue que ce genre de fonction, si le but est de simplifier les requêtes coté c++.

En fait, le but c'est d'appeler des fonctions PostgreSQL à l'aide de la librairie libpq.

Merci encore.
Cordialement.

Hors ligne

#4 14/02/2012 18:51:12

rjuju
Administrateur

Re : Afficher résultat fonction avec libpq

Si vous utilisez un type de retour "table", vous pourrez utiliser la fonction comme si vous utilisiez directement une requête "select" dans votre programme.

Si le but de votre fonction n'est que de faire un select, une procédure stockée en pl/pgsql n'est pas le meilleur choix. Votre procédure stockée doit-elle effectuer un traitement, ou quelle est la finalité ? Dans la majorité des cas un type de retour simple suffit (nombre d'enregistrement traités, code retour ...).

Hors ligne

#5 14/02/2012 19:13:11

mourad
Membre

Re : Afficher résultat fonction avec libpq

Effectivement, la fonction ne fait que du "Select".
Dans ce cas, je n'ai pas besoin de retourner quelque chose ?
Est ce que le type TABLE suffit ?

Merci encore.
Cordialement.

Hors ligne

#6 14/02/2012 19:22:19

rjuju
Administrateur

Re : Afficher résultat fonction avec libpq

Le type table suffit, mais vous impose de définir les noms et types de champs retournés. Il faut définir la fonction en langage sql et ne faire que le select dans le corps de la fonction.

Pourquoi ne pas utiliser le système des vues qui est beaucoup plus simple à mettre en place ?

Hors ligne

#7 14/02/2012 22:10:48

dverite
Membre

Re : Afficher résultat fonction avec libpq

mourad a écrit :

J'ai utilisé la librairie libpq, mais je n'arrive pas à afficher les résultats vu que lorsque je récupère les enregistrements renvoyés dans un CURSOR et puis j'essai de faire le parcours de ce curseur j'ai toujours le nom de la procédure qui est affiché avec comme valeur "unnamed portal".
Est ce que quelqu'un a une idée où se trouve mon problème et qu'est ce que je dois faire pour corriger ce problème ?
Merci d'avance pour votre aide.
Cordialement.

La représentation textuelle d'un refcursor, c'est son nom. Il se trouve que les noms générés par PG ressemblent à <unnamed portal N> mais ça n'a pas d'importance. Le programme C++ doit récupérer ce nom comme résultat de la fonction et le mettre dans la commande FETCH ALL FROM "mettre le nom ici".
Le programme C++ lui-même n'a pas à utiliser DECLARE name CURSOR FOR... car sinon ça fait double emploi avec le curseur déjà ouvert dans la fonction plgsql.

Hors ligne

#8 15/02/2012 12:03:17

mourad
Membre

Re : Afficher résultat fonction avec libpq

Bonjour,
Merci pour vos réponses.
En fait, il serait difficile pour moi maintenant de changer le type de retour de la fonction.  Je dois afficher les résultat depuis le refCursor retourné.

Le programme C++ doit récupérer ce nom comme résultat de la fonction et le mettre dans la commande FETCH ALL FROM "mettre le nom ici".

Si j'ai bien compris, je dois récupérer le nom du portal retourné et ensuite exécuter la requete "FETCH ALL FROM "nom_portal_récupéré".
Par la suite, je pourrais afficher les résultat contenus dans ce "portal".

Merci de votre aide.
Cordialement.

Hors ligne

#9 15/02/2012 12:15:19

rjuju
Administrateur

Re : Afficher résultat fonction avec libpq

Oui, il faut l'utiliser de cette façon, et être en transaction.

cf la doc postgresql (http://docs.postgresql.fr/9.1/plpgsql-c … #id5673972) :

CREATE FUNCTION fonction_reference2() RETURNS refcursor AS $$
DECLARE
    ref refcursor;
BEGIN
    OPEN ref FOR SELECT col FROM test;
    RETURN ref;
END;
$$ LANGUAGE plpgsql;

-- Il faut être dans une transaction pour utiliser les curseurs.
BEGIN;
SELECT fonction_reference2();

   fonction_reference2
--------------------------
 <unnamed cursor 1>
(1 row)

FETCH ALL IN "<unnamed cursor 1>";
COMMIT;

Hors ligne

#10 15/02/2012 12:40:10

mourad
Membre

Re : Afficher résultat fonction avec libpq

Merci de votre réponse. J'ai vraiment essayé mais toujours il y a un problème.
Voici le code que j'utilise :

// connexion à la base de données
pgsqlConn = ConnectDB(conninfo);

// Commencer une transaction
PGresult *res  = PQexec(conn, "BEGIN");

if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
	printf("Echec création transaction : %s", PQerrorMessage(conn));
        PQclear(res);
        CloseConn(conn);
}

// Initialiser le resultat
PQclear(res);

// récupérer nom curseur 
res = PQexec(conn, "SELECT get_the_results ('13183')");
if (PQresultStatus(res) != PGRES_COMMAND_OK)
 {
        printf("Echec récupération nom curseur : %s", PQerrorMessage(conn));
        PQclear(res);
        CloseConn(conn);
    }

	// récupérer nom curseur retourné
	char* curName = PQgetvalue(res, 0, 0);

// Clear result
    PQclear(res);

	// parcourir le curseur
	query = "";
	sprintf(query,"FETCH ALL IN \"%s\"", curName);
    res = PQexec(conn, query);

    if (PQresultStatus(res) != PGRES_TUPLES_OK)
    {
		printf("FETCH ALL failed : %s", PQerrorMessage(conn));
        PQclear(res);
        CloseConn(conn);
    }

    // récupérer le nombre des champs
    nFields = PQnfields(res);

	// Préparer l'entête avec le nom des colonnes
	printf("\nFetch employee record:");
	printf("\n********************************************************************\n");
    for (int i = 0; i < nFields; i++)
        printf("%-30s", PQfname(res, i));
    printf("\n********************************************************************\n");

    // afficher les enregistrements retournés
    for (int i = 0; i < PQntuples(res); i++)
    {
        for (int j = 0; j < nFields; j++)
            printf("%-30s", PQgetvalue(res, i, j));
        printf("\n");
    }
  
    PQclear(res);

    // fermer le curseur
    res = PQexec(conn, "CLOSE emprec");
    PQclear(res);

    // Fermer la transaction
    res = PQexec(conn, "END");

  // Effecer le resultat
    PQclear(res);

Le problème que la 1ère requete qui va me retourner le nom du curseur retourne une erreur mais qui n'est pas affichée.
Merci de voir ce bout de code et de me corriger.
Cordialement.

Hors ligne

#11 15/02/2012 13:10:17

rjuju
Administrateur

Re : Afficher résultat fonction avec libpq

Le programme à l'air correct à première vue.

Si vous avez un problème sur l'appel de la fonction get_the_results, vous devriez avoir un message "Echec récupération nom curseur ..." avec le message correspondant.

De plus une version précédente de votre programme vous affichait bien le nom du curseur "unnamed portal", le problème doit se situer ailleurs.

Vous pouvez voir ce que vous avez changé sur la partie get_the_results, ou faire des printf un peu partout pour voir si l'erreur ne vient pas d'ailleurs.

Hors ligne

#12 15/02/2012 13:39:36

mourad
Membre

Re : Afficher résultat fonction avec libpq

En fait, le résultat que j'ai récupéré ne provient d'une requete lancée dans le programme C mais plutot depuis un éditeur Postgres.
D'ailleur, depuis l'éditeur j'ai réussi à exécuter les commandes et afficher les données.
Par contre, lorsque j'exécute la requete "select get_the_result" depuis le programme C, aucune erreur n'est retourné et le PQresultStatus(res) est égal à 2.

Hors ligne

#13 15/02/2012 14:16:19

rjuju
Administrateur

Re : Afficher résultat fonction avec libpq

La valeur 2 signifie PGRES_TUPLES_OK, donc que la requête a bien été exécutée et que PGResult contient des données. PGRES_COMMAND_OK n'est valable que pour des instructions ne renvoyant pas de données (BEGIN par exemple).

Hors ligne

#14 15/02/2012 17:39:16

mourad
Membre

Re : Afficher résultat fonction avec libpq

Yes ! Merci pour votre aide.
En fait mon erreur si situait lors du parcours du résulat.
Je mets le code que j'ai utilisé et qui marche en espérant que ça servira pour autre personne.

/* Etablir la connecxion à base de données */
PGconn *ConnectDB(const char* conninfo)
{
	PGconn *conn = NULL;

	// Etablir la connecxion à base de données
	conn = PQconnectdb(conninfo);

	if (PQstatus(conn) != CONNECTION_OK)
    {
        printf("Connecxion à la base de données non établie !");
        CloseConn(conn);
    }

	printf("Connecxion à la base réussie - OK\n");

	return conn;
}
/* Récupérer les résultats de l'exécution de la procédure*/
void fetchResults(PGconn *conn, char query[])
{
	// Pour contenir le nombre des champs retournés
	int nFields;

	// Commencer une transaction
	PGresult *res  = PQexec(conn, "begin");

    if (PQresultStatus(res) != PGRES_COMMAND_OK)
    {
		printf("BEGIN command failed : %s", PQerrorMessage(conn));
        PQclear(res);
        CloseConn(conn);
    }

	printf("Transaction démarrée.....");

	// Initialiser le resultat
    PQclear(res);

    // récupérer le nom du curseur automatique (portal) contenant les résulats
    res = PQexec(conn, query);
    if (PQresultStatus(res) != PGRES_TUPLES_OK)
    {
		printf("Echec récupération nom curseur : %d - %s", PQerrorMessage(conn), PQresultStatus(res));
        PQclear(res);
        CloseConn(conn);
    }

	// récupérer nom curseur retourné
	char* cursorName = NULL;

	// récupérer le nombre des champs
    nFields = PQnfields(res);

	// Préparer l'entête avec le nom des colonnes
	printf("\Affichage nom du cuseur :");
	printf("\n********************************************************************\n");
    for (int i = 0; i < nFields; i++)
        printf("%-30s", PQfname(res, i));
    printf("\n********************************************************************\n");

    // afficher les enregistrements retournés
    for (int i = 0; i < PQntuples(res); i++)
    {
        for (int j = 0; j < nFields; j++)
		{
			cursorName = PQgetvalue(res, i, j);
            printf("%-30s", PQgetvalue(res, i, j));
		}
        printf("\n");
    }

	// récupérer les résultat contenus dans le curseur
	sprintf(query,"FETCH ALL IN \"%s\"", cursorName);
    res = PQexec(conn, query);

    if (PQresultStatus(res) != PGRES_TUPLES_OK)
    {
		printf("FETCH ALL failed : %s", PQerrorMessage(conn));
        PQclear(res);
        CloseConn(conn);
    }

    // récupérer le nombre des champs
    nFields = PQnfields(res);

	// Préparer l'entête avec le nom des colonnes
	printf("\nAffichage contenu du curseur :");
	printf("\n********************************************************************\n");
    for (int i = 0; i < nFields; i++)
        printf("%-30s", PQfname(res, i));
    printf("\n********************************************************************\n");

    // afficher les enregistrements retournés
    for (int i = 0; i < PQntuples(res); i++)
    {
        for (int j = 0; j < nFields; j++)
            printf("%-30s", PQgetvalue(res, i, j));
        printf("\n");
    }
  
    PQclear(res);

    // fermer le curseur
	sprintf(query,"CLOSE \"%s\"", cursorName);
    res = PQexec(conn, query);
    PQclear(res);

    // Fermer la transaction
    res = PQexec(conn, "END");

	// Effecer le resultat
    PQclear(res);

}
int main(int argc, char **argv)
{
	// déclaration et initialisation des variables
	PGconn *pgsqlConn = NULL;
    const char *conninfo = "host = '127.0.0.1' port = 5432 dbname = 'mabase' user = 'postgres' password = '*******'"; 
	
	// paramétrer la requete selon la procédure stockée et ses arguments
	char query[150] = "select theriaque.get_the_result(13183)";
	
	// connexion à la base de données
	pgsqlConn = ConnectDB(conninfo);
	
	// afficher les données
	fetchResults(pgsqlConn, query);

	// quitter
	printf("\nPress ENTER to remove all records & table.....\n");
	CloseConn(pgsqlConn);

	return 0;
}

Encorde merci pour aide et collaboration
Cordialement

Hors ligne

#15 15/02/2012 17:50:51

Marc Cousin
Membre

Re : Afficher résultat fonction avec libpq

Et merci à vous pour le code final. C'est effectivement le genre d'exemple qui pourra aider d'autres utilisateurs…


Marc.

Hors ligne

Pied de page des forums