PostgreSQLLa base de données la plus sophistiquée au monde.

33.9. Utiliser les aires de descripteur

Une aire de descripteur SQL est une méthode plus sophistiquée pour traiter les résultats d'une instruction SELECT, FETCH ou DESCRIBE. Une aire de descripteur SQL groupe les données d'une ligne avec les éléments des méta-données en une seule structure de données. Les méta-données sont particulièrement utiles lors de l'exécution de requêtes SQL dynamiques, où la nature des colonnes résultantes pourrait ne pas être connue à l'avance. PostgreSQL fournit deux moyens pour utiliser les aires de descripteur : les aires nommées de descripteur SQL et la structure C SQLDA.

33.9.1. Aires nommées de descripteur SQL

Une aire nommée de descripteur SQL consiste en un en-tête contenant des informations concernant le descripteur entier et un ou plusieurs éléments aires de descripteur, chacun décrivant une colonne de la ligne de résultat.

Avant de pouvoir utiliser une aire de descripteur SQL, vous devez en allouer une :

EXEC SQL ALLOCATE DESCRIPTOR identifier;

L'identifiant sert en tant que « nom de variable » de l'aire de descripteur. Quand vous n'avez plus besoin du descripteur, vous pouvez le libérer :

EXEC SQL DEALLOCATE DESCRIPTOR identifier;

Pour utiliser une aire de descripteur, spécifiez-la en tant que cible de stockage dans une clause INTO au lieu de liter les variables hôtes :

EXEC SQL FETCH NEXT FROM mycursor INTO SQL DESCRIPTOR mydesc;

Si l'ensemble de résultats est vide, l'aire de descripeteur contiendra malgré tout les méta-données de la requête, autrement dit les noms des champs.

Pour des requêtes préparées pas encore exécutées, l'instruction DESCRIBE peut être utilisée pour obtenir les méta-données sur l'ensemble de résultats :

 
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, donc l'utilisation de DESCRIPTOR et SQL DESCRIPTOR produisaient des aires nommées de descripteur SQL. Maintenant, le mot-clé est obligatoire. Omettre ce mot-clé produit des aires de descripteur SQLDA, voir Section 33.9.2, « Aires de descripteur SQLDA ».

Dans les instructions DESCRIBE et FETCH, les mot-clés INTO et USING peuvent être utilisés de façon similaire : l'ensemble de résultat et les méta-données sont placés dans une aire de descripteur.

Maintenant, comment sortir les données de l'aire de descripteur ? l'aire des descripteur est en quelque sorte une structure avec des champs nommés. Pour récupérer la valeur d'un champ à partir d'un en-tête et pour stocker cette valeur dans une variable hôte, utilisez la commande suivante :

EXEC SQL GET DESCRIPTOR name :hostvar = field;

Actuellement, il existe un seul champ d'en-tête défini : COUNT, qui indique le nombre d'éléments existant dans l'aire de descripteur (autrement dit, le nombre de colonnes contenues dans le résultat). La variable hôte doit être de type entier. Pour obtenir un champ à partir de cet élément aire de descripteur, utilisez la commande suivante :

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

num peut être un entier constant ou une variable hôte contenant un entier. Les champs possibles sont :

CARDINALITY (integer)

nombre de lignes dans l'ensemble de résultat

DATA

élément de données actuel (du coup, le type de données de ce champ dépend de la requête)

DATETIME_INTERVAL_CODE (integer)

?

DATETIME_INTERVAL_PRECISION (integer)

non implémenté

INDICATOR (integer)

un indicateur précisant une valeur NULL ou un tronquage de la valeur

KEY_MEMBER (integer)

non implémenté

LENGTH (integer)

longueur du champ en caractères

NAME (string)

nom de la colonne

NULLABLE (integer)

non implémenté

OCTET_LENGTH (integer)

longueur de la représentation en caractères du datum en octets

PRECISION (integer)

précision (pour le type numeric)

RETURNED_LENGTH (integer)

longueur du datum en caractères

RETURNED_OCTET_LENGTH (integer)

longueur de la représentation en caractères du datum en octets

SCALE (integer)

échelle (pour le type numeric)

TYPE (integer)

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

Dans les instructions EXECUTE, DECLARE et OPEN, l'effet des mot-clés INTO et USING est différent. Une aire de descripteur peut aussi être construite manuellement pour fournir les paramètres en entrée pour une requête ou un curseur. USING SQL DESCRIPTOR name est la façon de passer les paramètres en entrée pour une requête avec paramètres. L'instruction pour construire une aire nommée de descripteur SQL se trouve ci-dessous :

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

PostgreSQL accepte de récupérer plus d'un enregistrement avec une instruction FETCH. Stocker les données dans des variables hôtes dans ce cas suppose que la variable est un tableau. 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.9.2. Aires de descripteur SQLDA

Une aire de descripteur SQLDA est une structure C qui peut aussi être utilisée pour obtenir l'ensemble de résultats et les méta-données d'une requête. Une structure conserve un enregistrement de l'ensemble de résultat.

EXEC SQL include sqlda.h;
sqlda_t         *mysqlda;

EXEC SQL FETCH 3 FROM mycursor INTO DESCRIPTOR mysqlda;

Notez que le mot-clé SQL est omis. Les paragraphes sur les cas d'utilisation des mot-clés INTO et USING dans Section 33.9.1, « Aires nommées de descripteur SQL » s'appliquent aussi ici avec un ajout. Dans une instruction DESCRIBE, le mot-clé DESCRIPTOR peut être complètement omis si le mot-clé INTO est utilisé :

EXEC SQL DESCRIBE prepared_statement INTO mysqlda;

La structure de SQLDA est :

#define NAMEDATALEN 64

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

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

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

typedef struct sqlvar_struct    sqlvar_t;
typedef struct sqlda_struct     sqlda_t;

Les données allouées pour une structure SQLDA sont variables car elles dépendent du nombre de champs dans l'ensemble du résultat et dépendent aussi de la longueur des valeurs des données de type chaîne de caractères dans un enregistrement. Les champs individuels de la structure SQLDA sont :

sqldaid

Il contient la chaîne constante "SQLDA ".

sqldabc

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

sqln

Il contient le nombre de paramètres en entrée pour une requête avec paramètres lorsqu'elle est passée via OPEN, DECLARE ou EXECUTE en utilisant le mot-clé USING. Dans le cas où elle est passée en sortie des instructions SELECT, EXECUTE ou FETCH, sa valeur est identique à celle de l'instruction sqld.

sqld

Il contient le nombre de champs dans l'ensemble de résultats.

desc_next

Si la requête renvoie plus d'un enregistrement, plusieurs structures SQLDA liées sont renvoyées et desc_next contient un pointeur vers la prochaine entrée dans la liste.

sqlvar

C'est le tableau de champs de l'ensemble des résultats. Les champs disponibles sont les suivants :

sqltype

Il contient l'identifiant du type pour le champ. Pour les valeurs, voir enum ECPGttype dans ecpgtype.h.

sqllen

Il contient la longueur binaire du champ. Par exemple, quatre octets pour ECPGt_int.

sqldata

(char *)sqldata pointe vers les données.

sqlind

(char *)sqlind pointe vers l'indicateur NULL pour les données. 0 signifie NOT NULL, -1 signifie NULL.

sqlname

struct sqlname sqlname contient le nom d'un champ dans une structure :

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

sqlname.length contient la longueur du nom du champ.

data

sqlname.data contient le nom réel du champ.