IdentifiantMot de passe
Loading...
Mot de passe oubli� ?Je m'inscris ! (gratuit)

33.7. Utiliser les Zones de Descripteur

Une zone de descripteur SQL (SQL Descriptor Area ou SQLDA) est une m�thode plus sophistiqu�e pour traiter le r�sultat d'un ordre SELECT, FETCH ou DESCRIBE. Une zone de descripteur SQL regroupe les donn�es d'un enregistrement avec ses m�tadonn�es dans une seule structure. Ces m�tadonn�es sont particuli�rement utiles quand on ex�cute des ordres SQL dynamiques, o�_la nature des colonnes r�sultat ne sont pas forc�ment connues � l'avance. PostgreSQL fournit deux fa�ons d'utiliser des Zones de Descripteur: les Zones de Descripteur SQL nomm�e et les structures C SQLDA.

33.7.1. Zones de Descripteur SQL nomm�es

Une zone descripteur SQL nomm� est compos�e d'un ent�te, qui contient des donn�es concernant l'ensemble du descripteur, et une ou plusieurs zones de descriptions d'objets, qui en fait d�crivent chaque colonne de l'enregistrement r�sultat.

Avant que vous puissiez utiliser une zone de descripteur SQL, vous devez en allouer une:

EXEC SQL ALLOCATE DESCRIPTOR identifiant;

L'identifiant sert de � nom de variable � de la zone de descripteur. La port�e de descripteur est QUOI?. Quand vous n'avez plus besoin du descripteur, vous devriez le d�sallouer:

EXEC SQL DEALLOCATE DESCRIPTOR identifiant;

Pour utiliser une zone de descripteur, sp�cifiez le comme cible de stockage dans une clause INTO, � la place d'une liste de variables h�tes:

EXEC SQL FETCH NEXT FROM mycursor INTO SQL DESCRIPTOR mydesc;

Si le jeu de donn�es retourn� est vide, la zone de descripteur contiendra tout de m�me les m�tadonn�es de la requ�te, c'est � dire les noms des champs.

Pour les requ�tes pr�par�es mais pas encore ex�cut�es, l'ordre DESCRIBE peut �tre utilis� pour r�cup�rer les m�tadonn�es du r�sultat:

EXEC SQL BEGIN DECLARE SECTION;
char *sql_stmt = "SELECT * FROM table1";
EXEC SQL END DECLARE SECTION;

EXEC SQL PREPARE stmt1 FROM :sql_stmt;
EXEC SQL DESCRIBE stmt1 INTO SQL DESCRIPTOR mydesc;

Avant PostgreSQL 9.0, le mot cl� SQL �tait optionnel, par cons�quent utiliser DESCRIPTOR et SQL DESCRIPTOR produisaent les m�mes zones de descripteur SQL. C'est maintenant obligatoire, et oublier le mot cl� SQL produit des zones de descripteurs SQLDA, voyez Section 33.7.2, � Zones de Descripteurs SQLDA �.

Dans les ordres DESCRIBE et FETCH, les mots-cl�s INTO et USING peuvent �tre utilis�s de fa�on similaire: ils produisent le jeu de donn�es et les m�tadonn�es de la zone de descripteur.

Maintenant, comment r�cup�rer les donn�es de la zone de descripteur? Vous pouvez voir la zone de descripteur comme une structure avec des champs nomm�s. Pour r�cup�rer la valeur d'un champ � partir de l'ent�te et le stocker dans une variable h�te, utilisez la commande suivante:

EXEC SQL GET DESCRIPTOR name :hostvar = field;

À l'heure actuelle, il n'y a qu'un seul champ d'ent�te d�fini: COUNT, qui dit combien il y a de zones de descripteurs d'objets (c'est � dire, combien de colonnes il y a dans le r�sultat). La variable h�te doit �tre de type integer. Pour r�cup�rer un champ de la zone de description d'objet, utilisez la commande suivante:

EXEC SQL GET DESCRIPTOR name VALUE num :hostvar = field;

num peut �tre un integer literal, ou une variable h�te contenant un integer. Les champs possibles sont:

CARDINALITY (integer)

nombres d'enregistrements dans le r�sultat

DATA

objet de donn�e proprement dit (par cons�quent, le type de donn�es de ce champ d�pend de la requ�te)

DATETIME_INTERVAL_CODE (integer)

Quand TYPE est 9, DATETIME_INTERVAL_CODE aura une valeur de 1 pour DATE, 2 pour TIME, 3 pour TIMESTAMP, 4 pour TIME WITH TIME ZONE, or 5 pour TIMESTAMP WITH TIME ZONE.

DATETIME_INTERVAL_PRECISION (integer)

non impl�ment�

INDICATOR (integer)

l'indicateur (indique une valeur null ou une troncature de valeur)

KEY_MEMBER (integer)

non impl�ment�

LENGTH (integer)

longueur de la donn�e en caract�res

NAME (string)

nom de la colonne

NULLABLE (integer)

non impl�ment�

OCTET_LENGTH (integer)

longueur de la repr�sentation caract�re de la donn�e en octets

PRECISION (integer)

pr�cision (pour les types numeric)

RETURNED_LENGTH (integer)

longueur de la donn�e en caract�res

RETURNED_OCTET_LENGTH (integer)

longueur de la repr�sentation caract�re de la donn�e en octets

SCALE (integer)

�chelle (pour le type numeric)

TYPE (integer)

code num�rique du type de donn�es de la colonne

Dans les ordres EXECUTE, DECLARE and OPEN, l'effet des mots cl�s INTO and USING est diff�rent. Une zone de descripteur peut aussi �tre construite manuellement pour fournir les param�tres d'entr� pour une requ�te ou un curseur et USING SQL DESCRIPTOR name est la fa�on de passer les param�tres d'entr�e � une requ�te param�tris�e. L'ordre pour construire une zone de descripteur SQL est ci-dessous:

EXEC SQL SET DESCRIPTOR name VALUE num field = :hostvar;

PostgreSQL supporte la r�cup�ration de plus d'un enregistrement dans un ordre FETCH et les variables h�tes dans ce cas doivent �tre des tableaux. Par exemple:

EXEC SQL BEGIN DECLARE SECTION;
int id[5];
EXEC SQL END DECLARE SECTION;

EXEC SQL FETCH 5 FROM mycursor INTO SQL DESCRIPTOR mydesc;

EXEC SQL GET DESCRIPTOR mydesc VALUE 1 :id = DATA;

33.7.2. Zones de Descripteurs SQLDA

Une zone de descripteur SQLDA est une structure C qui peut aussi �tre utilis� pour r�cup�rer les r�sultats et les m�tadonn�es d'une requ�te. Une structure stocke un enregistrement du jeu de r�sultat.

EXEC SQL include sqlda.h;
sqlda_t         *mysqlda;

EXEC SQL FETCH 3 FROM mycursor INTO DESCRIPTOR mysqlda;

Netez que le mot cl� SQL est omis. Les paragraphes qui parlent des cas d'utilisation de INTO and USING dans Section 33.7.1, � Zones de Descripteur SQL nomm�es � s'appliqent aussi ici, avec un point suppl�mentaire. Dans un ordre DESCRIBE le mot cl� DESCRIPTOR peut �tre compl�tement omis si le mot cl� INTO est utilis�:

EXEC SQL DESCRIBE prepared_statement INTO mysqlda;

Le d�roulement g�n�ral d'un programme qui utilise des SQLDA est:

  1. Pr�parer une requ�te, et d�clarer un curseur pour l'utiliser.

  2. D�clarer une SQLDA pour les lignes de r�sultat.

  3. D�clarer une SQLDA pour les param�tres d'entr�es, et les initialiser (allocation m�moire, positionnement des param�tres).

  4. Ouvrir un curseur avec la SQLDA d'entr�e.

  5. R�cup�rer les enregistrements du curseur, et les stocker dans une SQLDA de sortie.

  6. Lire les valeurs de la SQLDA de sortie vers les variables h�tes (avec conversion si n�cessaire).

  7. Fermer le curseur.

  8. Lib�rer la zone m�moire allou�e pour la SQLDA d'entr�e.

33.7.2.1. Structure de Donn�es SQLDA

Les SQLDA utilisent 3 types de structures de donn�es: sqlda_t, sqlvar_t, et struct sqlname.

[Astuce]

Astuce

La structure de la SQLDA de PostgreSQL est similaire � celle de DB2 Universal Database d'IBM, des informations techniques sur la SQLDA de DB2 peuvent donc aider � mieux comprendre celle de PostgreSQL.

33.7.2.1.1. Structure sqlda_t

Le type de structure sqlda_t est le type de la SQLDA proprement dit. Il contient un enregistrement. Et deux ou plus sqlda_t peuvent �tre connect�es par une liste cha�n�e par le pointeur du champ desc_next, repr�sentant par cons�quent une collection ordonn�e d'enregistrements. Par cons�quent, quand deux enregistrements ou plus sont r�cup�r�s, l'application peut les lire en suivant le pointeur desc_next dans chaque nœud sqlda_t.

La d�finition de sqlda_t est:

struct sqlda_struct
{
    char            sqldaid[8];
    long            sqldabc;
    short           sqln;
    short           sqld;
    struct sqlda_struct *desc_next;
    struct sqlvar_struct sqlvar[1];
};

typedef struct sqlda_struct sqlda_t;

La signification des champs est:

sqldaid

Elle contient la cha�ne litt�rale "SQLDA ".

sqldabc

Il contient la taille de l'espace allou� en octets.

sqln

Il content le nombre de param�tres d'entr�e pour une requ�te param�trique, dans le cas o� il est pass� � un ordre OPEN, DECLARE ou EXECUTE utilisant le mot cl� USING. Dans le cas o� il sert de sortie � un ordre SELECT, EXECUTE ou FETCH statements, sa valeur est la m�me que celle du champ sqld.

sqld

Il contient le nombre de champs du r�sultat.

desc_next

Si la requ�te retourne plus d'un enregistrement, plusieurs structures SQLDA cha�n�es sont retourn�es, et desc_next contient un pointeur vers l'�l�ment suivant (enregistrement) de la liste.

sqlvar

C'est le tableau des colonnes du r�sultat.

33.7.2.1.2. Structure de sqlvar_t

Le type structure sqlvar_t contient la valeur d'une colonne et les m�tadonn�es telles que son type et sa longueur. La d�finition du type est:

struct sqlvar_struct
{
    short          sqltype;
    short          sqllen;
    char          *sqldata;
    short         *sqlind;
    struct sqlname sqlname;
};

typedef struct sqlvar_struct sqlvar_t;

La signification des champs est:

sqltype

Contient l'identifiant de type du champ. Pour les valeurs, voyez enum ECPGttype dans ecpgtype.h.

sqllen

Contient la longueur binaire du champ, par exemple 4 octets pour ECPGt_int.

sqldata

Pointe vers la donn�e. Le format de la donn�e est d�crit dans Section 33.4.4, � Correspondance de Type �.

sqlind

Pointe vers l'indicateur de nullit�. 0 signifie non nul, -1 signifie nul. null.

sqlname

Le nom du champ.

33.7.2.1.3. Structure struct sqlname

Une structure struct sqlname contient un nom de colonne. Il est utilis� comme membre de la structure sqlvar_t. La d�finition de la structure est:

#define NAMEDATALEN 64

struct sqlname
{
        short           length;
        char            data[NAMEDATALEN];
};

La signification des champs est:

length

Contient la longueur du nom du champ.

data

Contient le nom du champ proprement dit.

33.7.2.2. R�cup�rer un jeu de donn�es au moyen d'une SQLDA

Les �tapes g�n�rales pour r�cup�rer un jeu de donn�es au moyen d'une SQLDA sont:

  1. D�clarer une structure sqlda_t pour recevoir le jeu de donn�es.

  2. Ex�cuter des commandes FETCH/EXECUTE/DESCRIBE pour traiter une requ�te en sp�cifiant la SQLDA d�clar�e.

  3. V�rifier le nombre d'enregistrements dans le r�sultat en inspectant sqln, un membre de la structure sqlda_t.

  4. R�cup�rer les valeurs de chaque colonne des membres sqlvar[0], sqlvar[1], etc., de la structure sqlda_t.

  5. Aller � l'enregistrement suivant (sqlda_t structure) en suivant le pointeur desc_next, un membre de la structure sqlda_t.

  6. R�p�ter l'�tape ci-dessus au besoin.

Voici un exemple de r�cup�ration d'un jeu de r�sultats au moyen d'une SQLDA.

Tout d'abord, d�clarer une structure sqlda_t pour recevoir le jeu de r�sultats.

sqlda_t *sqlda1;

Puis, sp�cifier la SQLDA dans une commande. Voici un exemple avec une commande FETCH.

EXEC SQL FETCH NEXT FROM cur1 INTO DESCRIPTOR sqlda1;

Faire une boucle suivant la liste cha�n�e pour r�cup�rer les enregistrements.

sqlda_t *cur_sqlda;

for (cur_sqlda = sqlda1;
     cur_sqlda != NULL;
     cur_sqlda = cur_sqlda->desc_next)
{
    ...
}

Dans la boucle, faire une autre boucle pour r�cup�rer chaque colonne de donn�es (sqlvar_t) de l'enregistrement.

for (i = 0; i < cur_sqlda->sqld; i++)
{
    sqlvar_t v = cur_sqlda->sqlvar[i];
    char *sqldata = v.sqldata;
    short sqllen  = v.sqllen;
    ...
}

Pour r�cup�rer une valeur de colonne, v�rifiez la valeur de sqltype. Puis, suivant le type de la colonne, basculez sur une fa�on appropri�e de copier les donn�es du champ sqlvar vers une variable h�te.

char var_buf[1024];

switch (v.sqltype)
{
    case ECPGt_char:
        memset(&var_buf, 0, sizeof(var_buf));
        memcpy(&var_buf, sqldata, (sizeof(var_buf) <= sqllen ? sizeof(var_buf) - 1 : sqllen));
        break;

    case ECPGt_int: /* integer */
        memcpy(&intval, sqldata, sqllen);
        snprintf(var_buf, sizeof(var_buf), "%d", intval);
        break;

    ...
}

33.7.2.3. Passer des Param�tres de Requ�te en Utilisant une SQLDA

La m�thode g�n�rale pour utiliser une SQLDA pour passer des param�tres d'entr�e � une requ�te pr�par�e sont:

  1. Cr�er une requ�te pr�par�e (prepared statement)

  2. D�clarer une structure sqlda_t comme SQLDA d'entr�e.

  3. Allouer une zone m�morie (comme structure sqlda_t) pour la SQLDA d'entr�e.

  4. Positionner (copier) les valeurs d'entr�e dans la m�moire alloupe.

  5. Ouvrir un curseur en sp�cifiant la SQLDA d'entr�e.

Voici un exemple.

D'abord, cr�er une requ�te pr�par�e.

EXEC SQL BEGIN DECLARE SECTION;
char query[1024] = "SELECT d.oid, * FROM pg_database d, pg_stat_database s WHERE d.oid = s.datid AND (d.datname = ? OR d.oid = ?)";
EXEC SQL END DECLARE SECTION;

EXEC SQL PREPARE stmt1 FROM :query;

Puis, allouer de la m�moire pour une SQLDA, et positionner le nombre de param�tres d'entrn�e dans sqln, une variable membre de la structure<sqlda_t>. Quand deux param�tres d'entr�e ou plus sont requis pour la requ�te pr�par�e, l'application doit allouer de la m�moire suppl�mentaire qui est calcul�e par (nombre de param�tres -1) * sizeof<sqlvar_t>. Les exemples affich�s ici allouent de l'espace m�moire pour deux param�tres d'entr�e.

sqlda_t *sqlda2;

sqlda2 = (sqlda_t *) malloc(sizeof(sqlda_t) + sizeof(sqlvar_t));
memset(sqlda2, 0, sizeof(sqlda_t) + sizeof(sqlvar_t));

sqlda2->sqln = 2; /* nombre de variables d'entr�e */

Apr�s l'allocation m�moire, stocker les valeurs des param�tres dans le tableausqlvar[]. (C'est le m�me tableau que celui qui est utilis� quand la SQLDA re�oit un jeu de r�sultats.) Dans cet exemple, les param�tres d'entr�e sont "postgres", de type cha�ne, et 1, de type integer.

sqlda2->sqlvar[0].sqltype = ECPGt_char;
sqlda2->sqlvar[0].sqldata = "postgres";
sqlda2->sqlvar[0].sqllen  = 8;

int intval = 1;
sqlda2->sqlvar[1].sqltype = ECPGt_int;
sqlda2->sqlvar[1].sqldata = (char *) &intval;
sqlda2->sqlvar[1].sqllen  = sizeof(intval);

En ouvrant un curseur et en sp�cifiant la SQLDA qui a �t� positionn� auparavant, les param�tres d'entr�e sont pass�s � la requ�te pr�par�e.

EXEC SQL OPEN cur1 USING DESCRIPTOR sqlda2;

Et pour finir, apr�s avoir utilis� les SQLDAs d'entr�e, la m�moire allou�e doit �tre lib�r�e explicitement, contrairement aux SQLDAs utilis� pour recevoir le r�sultat d'une requ�te.

free(sqlda2);

33.7.2.4. Une application de D�monstration Utilisant SQLDA

Voici un programme de d�monstration, qui montre comment r�cup�rer des statistiques d'acc�s des bases, sp�cifi�es par les param�tres d'entr�e, dans les catalogues syst�mes.

Cette application joint deux tables syst�mes, pg_database et pg_stat_database sur l'oid de la base, et r�cup�re et affiche aussi les statistiques des bases qui sont sp�cifi�es par deux param�tres d'entr�es (une base postgres et un OID 1).

Tout d'abord, d�clarer une SQLDA pour l'entr�e et une SQLDA pour la sortie.

EXEC SQL include sqlda.h;

sqlda_t *sqlda1; /* un descripteur de sortie */
sqlda_t *sqlda2; /* un descripteur d'entr�e  */

Puis, se connecter � la base, pr�parer une requ�te, et d�clarer un curseur pour la requ�te pr�par�e.

int
main(void)
{
    EXEC SQL BEGIN DECLARE SECTION;
    char query[1024] = "SELECT d.oid,* FROM pg_database d, pg_stat_database s WHERE d.oid=s.datid AND ( d.datname=? OR d.oid=? )";
    EXEC SQL END DECLARE SECTION;

    EXEC SQL CONNECT TO testdb AS con1 USER testuser;

    EXEC SQL PREPARE stmt1 FROM :query;
    EXEC SQL DECLARE cur1 CURSOR FOR stmt1;

Puis, mettre des valeurs dans la SQLDA d'entr�e pour les param�tres d'entr�e. Allouer de la m�moire pour la SQL d'entr�e, et positionner le nombre de param�tres d'entr�e dans sqln. Stocker le type, la valeur et la longueur de la valeur dans sqltype, sqldata et sqllen dans la structure sqlvar.

    /* Cr�er une structure SQLDA pour les param�tres d'entr�e. */
    sqlda2 = (sqlda_t *) malloc(sizeof(sqlda_t) + sizeof(sqlvar_t));
    memset(sqlda2, 0, sizeof(sqlda_t) + sizeof(sqlvar_t));
    sqlda2->sqln = 2; /* number of input variables */

    sqlda2->sqlvar[0].sqltype = ECPGt_char;
    sqlda2->sqlvar[0].sqldata = "postgres";
    sqlda2->sqlvar[0].sqllen  = 8;

    intval = 1;
    sqlda2->sqlvar[1].sqltype = ECPGt_int;
    sqlda2->sqlvar[1].sqldata = (char *)&intval;
    sqlda2->sqlvar[1].sqllen  = sizeof(intval);

Apr�s avoir positionn� la SQLDA d'entr�e, ouvrir un curseur avec la SQLDA d'entr�e.

    /* Ouvrir un curseur avec les param�tres d'entr�e. */
    EXEC SQL OPEN cur1 USING DESCRIPTOR sqlda2;

R�cup�rer les enregistrements dans la SQLDA de sortie � partir du curseur ouvert. (En g�n�ral, il faut appeler FETCH de fa�on r�p�t�e dans la boucle, pour r�cup�rer tous les enregistrements du jeu de donn�es.)

    while (1)
    {
        sqlda_t *cur_sqlda;

        /* Assigner le descripteur au curseur  */
        EXEC SQL FETCH NEXT FROM cur1 INTO DESCRIPTOR sqlda1;

Ensuite, r�cup�rer les enregistrements du FETCH de la SQLDA, en suivant la liste cha�n�e de la structure sqlda_t.

    for (cur_sqlda = sqlda1 ;
         cur_sqlda != NULL ;
         cur_sqlda = cur_sqlda->desc_next)
    {
        ...

Lire chaque colonne dans le premier enregistrement. Le nombre de colonnes est stock� dans sqld, les donn�es r�elles de la premi�re colonne sont stock�es dans sqlvar[0], tous deux membres de la structuresqlda_t.

        /* Afficher toutes les colonnes d'un enregistrement. */
        for (i = 0; i < sqlda1->sqld; i++)
        {
            sqlvar_t v = sqlda1->sqlvar[i];
            char *sqldata = v.sqldata;
            short sqllen  = v.sqllen;

            strncpy(name_buf, v.sqlname.data, v.sqlname.length);
            name_buf[v.sqlname.length] = '\0';

Maintenant, la donn�e de la colonne est stock�e dans la variable v. Copier toutes les donn�es dans les variables host, en inspectant v.sqltype pour conna�tre le type de la colonne.

            switch (v.sqltype) {
                int intval;
                double doubleval;
                unsigned long long int longlongval;

                case ECPGt_char:
                    memset(&var_buf, 0, sizeof(var_buf));
                    memcpy(&var_buf, sqldata, (sizeof(var_buf) <= sqllen ? sizeof(var_buf)-1 : sqllen));
                    break;

                case ECPGt_int: /* integer */
                    memcpy(&intval, sqldata, sqllen);
                    snprintf(var_buf, sizeof(var_buf), "%d", intval);
                    break;

                ...

                default:
                    ...
            }

            printf("%s = %s (type: %d)\n", name_buf, var_buf, v.sqltype);
        }

Fermer le curseur apr�s avoir trait� tous les enregistrements, et se d�connecter de la base de donn�es.

    EXEC SQL CLOSE cur1;
    EXEC SQL COMMIT;

    EXEC SQL DISCONNECT ALL;

Le programme dans son entier est visible dans Exemple 33.1, � Programme de D�monstration SQLDA �.

Exemple 33.1. Programme de D�monstration SQLDA

#include <stdlib.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

EXEC SQL include sqlda.h;

sqlda_t *sqlda1; /* descripteur pour la sortie */
sqlda_t *sqlda2; /* descripteur pour l'entr�e */

EXEC SQL WHENEVER NOT FOUND DO BREAK;
EXEC SQL WHENEVER SQLERROR STOP;

int
main(void)
{
    EXEC SQL BEGIN DECLARE SECTION;
    char query[1024] = "SELECT d.oid,* FROM pg_database d, pg_stat_database s WHERE d.oid=s.datid AND ( d.datname=? OR d.oid=? )";

    int intval;
    unsigned long long int longlongval;
    EXEC SQL END DECLARE SECTION;

    EXEC SQL CONNECT TO uptimedb AS con1 USER uptime;

    EXEC SQL PREPARE stmt1 FROM :query;
    EXEC SQL DECLARE cur1 CURSOR FOR stmt1;

    /* Cr�er une structure SQLDB pour let param�tres d'entr�e */
    sqlda2 = (sqlda_t *)malloc(sizeof(sqlda_t) + sizeof(sqlvar_t));
    memset(sqlda2, 0, sizeof(sqlda_t) + sizeof(sqlvar_t));
    sqlda2->sqln = 2; /* a number of input variables */

    sqlda2->sqlvar[0].sqltype = ECPGt_char;
    sqlda2->sqlvar[0].sqldata = "postgres";
    sqlda2->sqlvar[0].sqllen  = 8;

    intval = 1;
    sqlda2->sqlvar[1].sqltype = ECPGt_int;
    sqlda2->sqlvar[1].sqldata = (char *) &intval;
    sqlda2->sqlvar[1].sqllen  = sizeof(intval);

    /* Ouvrir un curseur avec les param�tres d'entr�e. */
    EXEC SQL OPEN cur1 USING DESCRIPTOR sqlda2;

    while (1)
    {
        sqlda_t *cur_sqlda;

        /* Assigner le descripteur au curseur  */
        EXEC SQL FETCH NEXT FROM cur1 INTO DESCRIPTOR sqlda1;

        for (cur_sqlda = sqlda1 ;
             cur_sqlda != NULL ;
             cur_sqlda = cur_sqlda->desc_next)
        {
            int i;
            char name_buf[1024];
            char var_buf[1024];

            /* Afficher toutes les colonnes d'un enregistrement. */
            for (i=0 ; i<cur_sqlda->sqld ; i++)
            {
                sqlvar_t v = cur_sqlda->sqlvar[i];
                char *sqldata = v.sqldata;
                short sqllen  = v.sqllen;

                strncpy(name_buf, v.sqlname.data, v.sqlname.length);
                name_buf[v.sqlname.length] = '\0';

                switch (v.sqltype)
                {
                    case ECPGt_char:
                        memset(&var_buf, 0, sizeof(var_buf));
                        memcpy(&var_buf, sqldata, (sizeof(var_buf)<=sqllen ? sizeof(var_buf)-1 : sqllen) );
                        break;

                    case ECPGt_int: /* integer */
                        memcpy(&intval, sqldata, sqllen);
                        snprintf(var_buf, sizeof(var_buf), "%d", intval);
                        break;

                    case ECPGt_long_long: /* bigint */
                        memcpy(&longlongval, sqldata, sqllen);
                        snprintf(var_buf, sizeof(var_buf), "%lld", longlongval);
                        break;

                    default:
                    {
                        int i;
                        memset(var_buf, 0, sizeof(var_buf));
                        for (i = 0; i < sqllen; i++)
                        {
                            char tmpbuf[16];
                            snprintf(tmpbuf, sizeof(tmpbuf), "%02x ", (unsigned char) sqldata[i]);
                            strncat(var_buf, tmpbuf, sizeof(var_buf));
                        }
                    }
                        break;
                }

                printf("%s = %s (type: %d)\n", name_buf, var_buf, v.sqltype);
            }

            printf("\n");
        }
    }

    EXEC SQL CLOSE cur1;
    EXEC SQL COMMIT;

    EXEC SQL DISCONNECT ALL;

    return 0;
}

L'exemple suivant devrait ressembler � quelque chose comme ce qui suit (des nombres seront diff�rents).

oid = 1 (type: 1)
datname = template1 (type: 1)
datdba = 10 (type: 1)
encoding = 0 (type: 5)
datistemplate = t (type: 1)
datallowconn = t (type: 1)
datconnlimit = -1 (type: 5)
datlastsysoid = 11510 (type: 1)
datfrozenxid = 379 (type: 1)
dattablespace = 1663 (type: 1)
datconfig =  (type: 1)
datacl = {=c/uptime,uptime=CTc/uptime} (type: 1)
datid = 1 (type: 1)
datname = template1 (type: 1)
numbackends = 0 (type: 5)
xact_commit = 113606 (type: 9)
xact_rollback = 0 (type: 9)
blks_read = 130 (type: 9)
blks_hit = 7341714 (type: 9)
tup_returned = 38262679 (type: 9)
tup_fetched = 1836281 (type: 9)
tup_inserted = 0 (type: 9)
tup_updated = 0 (type: 9)
tup_deleted = 0 (type: 9)

oid = 11511 (type: 1)
datname = postgres (type: 1)
datdba = 10 (type: 1)
encoding = 0 (type: 5)
datistemplate = f (type: 1)
datallowconn = t (type: 1)
datconnlimit = -1 (type: 5)
datlastsysoid = 11510 (type: 1)
datfrozenxid = 379 (type: 1)
dattablespace = 1663 (type: 1)
datconfig =  (type: 1)
datacl =  (type: 1)
datid = 11511 (type: 1)
datname = postgres (type: 1)
numbackends = 0 (type: 5)
xact_commit = 221069 (type: 9)
xact_rollback = 18 (type: 9)
blks_read = 1176 (type: 9)
blks_hit = 13943750 (type: 9)
tup_returned = 77410091 (type: 9)
tup_fetched = 3253694 (type: 9)
tup_inserted = 0 (type: 9)
tup_updated = 0 (type: 9)
tup_deleted = 0 (type: 9)