35.8. Curseurs

Plut�t que d'ex�cuter la totalit� d'une requ�te � la fois, il est possible de cr�er un curseur qui encapsule la requ�te, puis en lit le r�sultat quelques lignes � la fois. Une des raisons pour faire de la sorte est d'�viter les surcharges de m�moire quand le r�sultat contient un grand nombre de lignes (cependant, les utilisateurs PL/pgSQL n'ont g�n�ralement pas besoin de se pr�occuper de cela puisque les boucles FOR utilisent automatiquement un curseur en interne pour �viter les probl�mes de m�moire). Un usage plus int�ressant est de renvoyer une r�f�rence � un curseur qu'elle a cr��, permettant � l'appelant de lire les lignes. Ceci fournit un moyen efficace de renvoyer de grands ensembles de lignes � partir des fonctions.

35.8.1. D�claration de variables curseur

Tous les acc�s aux curseurs dans PL/pgSQL se font par les variables curseur, qui sont toujours du type de donn�es sp�cial refcursor. Un des moyens de cr�er une variable curseur est de simplement la d�clarer comme une variable de type refcursor. Un autre moyen est d'utiliser la syntaxe de d�claration de curseur qui est en g�n�ral :

nom CURSOR [ ( arguments ) ] FOR requ�te ;

(FOR peut �tre remplac� par IS pour la compatibilit� avec Oracle). arguments, si sp�cifi�, est une liste de paires de nom type-de-donn�e qui d�finit les noms devant �tre remplac�s par les valeurs des param�tres dans la requ�te donn�e. La valeur effective � substituer pour ces noms sera sp�cifi�e plus tard lors de l'ouverture du curseur.

Quelques exemples :

DECLARE
    curs1 refcursor;
    curs2 CURSOR FOR SELECT * FROM tenk1;
    curs3 CURSOR (key integer) IS SELECT * FROM tenk1 WHERE unique1 = key;

Ces variables sont toutes trois du type de donn�es refcursor, mais la premi�re peut �tre utilis�es avec n'importe quelle requ�te, alors que la seconde a une requ�te compl�tement sp�cifi�e qui lui est d�j� li�e, et la derni�re est li�e � une requ�te param�tr�e. (key sera remplac�e par un param�tre de valeur enti�re lors de l'ouverture du curseur.) La variable curs1 est dite non li�e puisqu'elle n'est pas li�e a une requ�te particuli�re.

35.8.2. Ouverture De Curseurs

Avant qu'un curseur puisse �tre utilis� pour rapatrier des lignes, il doit �tre ouvert. (C'est l'action �quivalente de la commande SQL DECLARE CURSOR.) PL/pgSQL a trois formes pour l'instruction OPEN, dont deux utilisent des variables curseur non li�es et les autres utilisent une variable curseur li�e.

35.8.2.1. OPEN FOR SELECT

OPEN curseur_non_li� FOR SELECT ...;

La variable curseur est ouverte et re�oit la requ�te sp�cifi�e � ex�cuter. Le curseur ne peut pas �tre d�j� ouvert, et il doit avoir �t� d�clar� comme curseur non li�. (c'est � dire comme une simple variable refcursor). La requ�te SELECT est trait�e de la m�me fa�on que les autres instructionsSELECT dans PL/pgSQL : les noms de variables PL/pgSQL sont remplac�s, et le plan de requ�te est mis en cache pour une possible r�utilisation.

Exemple :

OPEN curs1 FOR SELECT * FROM foo WHERE key = mykey;

35.8.2.2. OPEN FOR EXECUTE

OPEN curseur_non_li� FOR EXECUTE cha�ne_requ�te;

La variable curseur est ouverte et re�oit la requ�te sp�cifi�e � ex�cuter. Le curseur ne peut pas �tre d�j� ouvert et il doit avoir �t� d�clar� comme curseur non-li� (c'est-�-dire comme une simple variable refcursor. La requ�te est sp�cifi�e comme une expression cha�ne de la m�me fa�on que dans une commande EXECUTE. Comme d'habitude, ceci donne assez de flexibilit� pour que la requ�te puisse changer d'une ex�cution � l'autre.

Exemple :

OPEN curs1 FOR EXECUTE 'SELECT * FROM ' || quote_ident($1);

35.8.2.3. Ouverture d'un curseur li�

OPEN curseur_li� [ ( arguments ) ];

Cette forme d'OPEN est utilis�e pour ouvrir une variable curseur � laquelle la requ�te est li�e au moment de la d�claration. Le curseur ne peut pas �tre d�j� ouvert. Une liste des expressions arguments doit appara�tre si et seulement si le curseur a �t� d�clar� comme acceptant des arguments. Ces valeurs seront remplac�es dans la requ�te. Le plan de requ�te pour un curseur li� est toujours consid�r� comme pouvant �tre mis en cache ; il n'y a pas d'�quivalent de la commande EXECUTE dans ce cas.

Exemples :

OPEN curs2;
OPEN curs3(42);

35.8.3. Utilisation des Curseurs

Une fois qu'un curseur a �t� ouvert, il peut �tre manipul� gr�ce aux instructions d�crites ci-dessous.

Ces manipulations n'ont pas besoin de se d�rouler dans la m�me fonction que celle qui a ouvert le curseur. Vous pouvez renvoyer une valeur refcursor � partir d'une fonction et laisser l'appelant op�rer sur le curseur (d'un point de vue interne, une valeur refcursor est simplement la cha�ne de caract�res du nom d'un portail contenant la requ�te active pour le curseur. Ce nom peut �tre pass� � d'autres, assign� � d'autres variables refcursor et ainsi de suite, sans d�ranger le portail).

Tous les portails sont implicitement ferm�s � la fin de la transaction. C'est pourquoi une valeur refcursor est utilisable pour r�f�rencer un curseur ouvert seulement jusqu'� la fin de la transaction.

35.8.3.1. FETCH

FETCH curseur INTO cible;

FETCH rapatrie le rang suivant depuis le curseur dans une cible, qui peut �tre une variable ligne, une variable record ou une liste de simples variables s�par�es d'une virgule, exactement comme SELECT INTO. Comme pour SELECT INTO, la variable sp�ciale FOUND peut �tre v�rifi�e pour voir si une ligne a �t� obtenue ou pas.

Exemple :

FETCH curs1 INTO var_ligne;
FETCH curs2 INTO foo, bar, baz;

35.8.3.2. CLOSE

CLOSE curseur;

CLOSE ferme le portail sous-tendant un curseur ouvert. Ceci peut �tre utilis� pour lib�rer des ressources avant la fin de la transaction ou de lib�rer la variable curseur pour pouvoir la r�ouvrir.

Exemple :

CLOSE curs1;

35.8.3.3. Renvoi de curseurs

Les fonctions PL/pgSQL peuvent renvoyer des curseurs � l'appelant. Ceci est utile pour renvoyer plusieurs lignes ou colonnes, sp�cialement avec des ensembles de r�sultats tr�s grands. Pour cela, la fonction ouvre le curseur et renvoie le nom du curseur � l'appelant (ou simplement ouvre le curseur en utilisant un nom de portail sp�cifi� par ou autrement connu par l'appelant). L'appelant peut alors r�cup�rer les lignes � partir du curseur. Le curseur peut �tre ferm� par l'appelant ou il sera ferm� automatiquement � la fin de la transaction.

Le nom du portail utilis� pour un curseur peut �tre sp�cifi� par le d�veloppeur ou peut �tre g�n�r� automatiquement. Pour sp�cifier un nom de portail, affectez simplement une cha�ne � la variable refcursor avant de l'ouvrir. La valeur de la variable refcursor sera utilis�e par OPEN comme nom du portail sous-jacent. N�anmoins, si la variable refcursor est NULL, OPEN g�n�re automatiquement un nom qui n'entre pas en conflit avec tout portail existant et l'affecte � la variable refcursor.

Note�: Une variable curseur avec limites est initialis�e avec la valeur de la cha�ne repr�sentant son nom, de fa�on � ce que le nom du portail soit identique au nom de la variable curseur, sauf si le d�veloppeur le surcharge par affectation avant d'ouvrir le curseur. Mais, une variable curseur sans limite aura par d�faut la valeur NULL, dont il recevra un nom unique g�n�r� automatiquement sauf s'il est surcharg�.

L'exemple suivant montre une fa�on de fournir un nom de curseur par l'appelant :

CREATE TABLE test (col text);
INSERT INTO test VALUES ('123');

CREATE FUNCTION fonction_reference(refcursor) RETURNS refcursor AS '
BEGIN
    OPEN $1 FOR SELECT col FROM test;
    RETURN $1;
END;
' LANGUAGE plpgsql;

BEGIN;
SELECT fonction_reference('curseur_fonction');
FETCH ALL IN curseur_fonction;
COMMIT;

L'exemple suivant utilise la g�n�ration automatique du nom du curseur :

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

BEGIN;
SELECT fonction_reference2();

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

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

L'exemple suivant montre une fa�on de renvoyer plusieurs curseurs � une seule fonction :

CREATE FUNCTION ma_fonction(refcursor, refcursor) RETURNS SETOF refcursor AS $$
BEGIN
    OPEN $1 FOR SELECT * FROM table_1;
    RETURN NEXT $1;
    OPEN $2 FOR SELECT * FROM table_2;
    RETURN NEXT $2;
    RETURN;
END;
$$ LANGUAGE plpgsql;

-- doit �tre dans une transaction pour utiliser les curseurs.
BEGIN;

SELECT * FROM ma_fonction('a', 'b');

FETCH ALL FROM a;
FETCH ALL FROM b;
COMMIT;