Vous n'êtes pas identifié(e).
Pages : 1
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
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)
Julien.
https://rjuju.github.io/
Hors ligne
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
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 ...).
Julien.
https://rjuju.github.io/
Hors ligne
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
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 ?
Julien.
https://rjuju.github.io/
Hors ligne
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.
@DanielVerite
http://blog-postgresql.verite.pro/
Hors ligne
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
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;
Julien.
https://rjuju.github.io/
Hors ligne
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
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.
Julien.
https://rjuju.github.io/
Hors ligne
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
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).
Julien.
https://rjuju.github.io/
Hors ligne
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
Et merci à vous pour le code final. C'est effectivement le genre d'exemple qui pourra aider d'autres utilisateurs…
Marc.
Hors ligne
Pages : 1