/* 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
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.
]]>// 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.
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;
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.
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.
Pourquoi ne pas utiliser le système des vues qui est beaucoup plus simple à mettre en place ?
]]>Merci encore.
Cordialement.
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 ...).
]]>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.
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++.
]]>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.