37.4. Déclarations
Toutes les variables utilisées dans un bloc doivent être déclarées
dans la section déclaration du bloc. La seule exception est que la
variable de boucle d'une boucle FOR
effectuant une itération sur des valeurs entières est automatiquement
déclarée comme variable entière.
Les variables PL/pgSQL peuvent être
de n'importe quel type de données tels que integer, varchar et
char.
Quelques exemples de déclarations de variables :
id_utilisateur integer;
quantité numeric(5);
url varchar;
ma_ligne nom_table%ROWTYPE;
mon_champ nom_table.nom_colonne%TYPE;
une_ligne RECORD;
La syntaxe générale d'une déclaration de variable est :
nom [ CONSTANT ] type [ NOT NULL ] [ { DEFAULT | := } expression ];
La clause DEFAULT, si indiquée, spécifie la
valeur initiale assignée à la variable quand on entre dans le bloc.
Si la clause DEFAULT n'est pas indiquée, la
variable est initialisée à la valeur SQL NULL. L'option CONSTANT empêche l'assignation de la variable, de
sorte que sa valeur reste constante pour la durée du bloc. Si
NOT NULL est spécifié, l'assignement d'une
valeur NULL aboutira à une erreur d'exécution. Les valeurs par défaut
de toutes les variables déclarées NOT NULL
doivent être spécifiées non NULL.
La valeur par défaut est évaluée à chaque entrée du bloc. Ainsi, par
exemple, l'assignation de now() à une
variable de type timestamp donnera à la
variable l'heure de l'appel de la fonction courante, et non l'heure
au moment où la fonction a été précompilée.
Exemples :
quantité integer DEFAULT 32;
url varchar := 'http://mysite.com';
id_utilisateur CONSTANT integer := 10;
37.4.1. Alias de paramètres de fonctions
Les paramètres passés aux fonctions sont nommés par les
identifiants $1, $2, etc. Éventuellement, des alias peuvent être
déclarés pour les noms de paramètres de type $
n
afin
d'améliorer la lisibilité. L'alias ou l'identifiant numérique
peuvent être utilisés indifféremment pour se référer à la valeur du
paramètre.
Il existe deux façons de créer un alias. La façon préférée est de
donner un nom au paramètre dans la commande
CREATE FUNCTION
, par exemple :
CREATE FUNCTION taxe_ventes(sous_total real) RETURNS real AS $$
BEGIN
RETURN sous_total * 0.06;
END;
L'autre façon, la seule disponible pour les versions antérieures de
PostgreSQL™ 8.0, est de
déclarer explicitement un alias en utilisant la syntaxe de
déclaration
nom ALIAS FOR $n;
Le même exemple dans ce style ressemble à
CREATE FUNCTION taxe_ventes(real) RETURNS real AS $$
DECLARE
sous_total ALIAS FOR $1;
BEGIN
RETURN sous_total * 0.06;
END;
$$ LANGUAGE plpgsql;
Quelques exemples de plus :
CREATE FUNCTION instr(varchar, integer) RETURNS integer AS $$
DECLARE
v_string ALIAS FOR $1;
index ALIAS FOR $2;
BEGIN
-- quelques traitements utilisant ici v_string et index
END;
$$ LANGUAGE plpgsql;
CREATE FUNCTION concat_champs_selectionnes(in_t un_nom_de_table) RETURNS text AS $$
BEGIN
RETURN in_t.f1 || in_t.f3 || in_t.f5 || in_t.f7;
END;
$$ LANGUAGE plpgsql;
Quand une fonction PL/pgSQL est
déclarée avec des paramètres en sortie, ces derniers se voient
attribués les noms $
n
et des alias optionnels de la
même façon que les paramètres en entrée. Un paramètre en sortie est
réellement une variable qui commence avec la valeur NULL ; il
devrait se voir attribuer une valeur lors de l'exécution de la
fonction. La valeur finale du paramètre est ce qui est renvoyée.
Par exemple, l'exemple sales-tax aurait pu être écrit de cette
façon :
CREATE FUNCTION taxe_ventes(sous_total real, OUT taxe real) AS $$
BEGIN
taxe := sous_total * 0.06;
END;
$$ LANGUAGE plpgsql;
Notez que nous avons omis RETURNS real --
nous aurions pu l'inclure mais cela aurait été redondant.
Les paramètres en sortie sont encore plus utiles lors du retour de
plusieurs valeurs. Un exemple trivial est :
CREATE FUNCTION somme_n_produits(x int, y int, OUT somme int, OUT produit int) AS $$
BEGIN
somme := x + y;
produit := x * y;
END;
$$ LANGUAGE plpgsql;
D'après ce qui a été vu dans la Section 33.4.3,
« Fonctions avec des paramètres en sortie », ceci
crée réellement un type d'enregistrement anonyme pour les résultats
de la fonction. Si une clause RETURNS est
donnée, elle doit spécifier RETURNS
record.
Lorsque le type de retour d'une fonction PL/pgSQL est déclaré comme type polymorphe
(anyelement ou anyarray), un paramètre spécial $0 est créé. Son type de donnée est le type effectif
de retour de la fonction, déduit d'après les types d'entrée (voir
la Section 33.2.5,
« Types et fonctions polymorphes »). Ceci permet à la
fonction d'accéder à son type de retour réel comme on le voit ici
avec la Section 37.4.2, « Copie de
types ». $0 est initialisé à NULL
et peut être modifié par la fonction, de sorte qu'il peut être
utilisé pour contenir la variable de retour si besoin est, bien que
cela ne soit pas requis. On peut aussi donner un alias à $0. Par exemple, cette fonction s'exécute comme un
opérateur + pour n'importe quel type de
données.
CREATE FUNCTION ajoute_trois_valeurs(v1 anyelement, v2 anyelement, v3 anyelement)
RETURNS anyelement AS $$
DECLARE
resultat ALIAS FOR $0;
BEGIN
resultat := v1 + v2 + v3;
RETURN resultat;
END;
$$ LANGUAGE plpgsql;
Le même effet peut être obtenu en déclarant un ou plusieurs
paramètres en sortie comme anyelement ou
anyarray. Dans ce cas, le paramètre
spécial $0 n'est pas utilisé ; les
paramètres en sortie servent ce même but. Par exemple :
CREATE FUNCTION ajoute_trois_valeurs(v1 anyelement, v2 anyelement, v3 anyelement,
OUT somme anyelement)
AS $$
BEGIN
somme := v1 + v2 + v3;
END;
$$ LANGUAGE plpgsql;
variable%TYPE
%TYPE fournit le type de données d'une
variable ou d'une colonne de table. Vous pouvez l'utiliser pour
déclarer des variables qui contiendront des valeurs de bases de
données. Par exemple, disons que vous avez une colonne nommée
id_utilisateur dans votre table utilisateurs. Pour déclarer une variable du même
type de données que utilisateurs.id_utilisateur, vous pouvez écrire :
id_utilisateur utilisateurs.id_utilisateur%TYPE;
En utilisant %TYPE vous n'avez pas besoin
de connaître le type de données de la structure à laquelle vous
faites référence et, plus important, si le type de données de
l'objet référencé change dans le futur (par exemple : vous changez
le type de id_utilisateur de integer à real), vous
pouvez ne pas avoir besoin de changer votre définition de fonction.
%TYPE est particulièrement utile dans le
cas de fonctions polymorphes puisque les types de données
nécessaires aux variables internes peuvent changer d'un appel à
l'autre. Des variables appropriées peuvent être créées en
appliquant %TYPE aux arguments de la
fonction ou à la variable fictive de résultat.
nom nom_table%ROWTYPE;
nom nom_type_composite;
Une variable de type composite est appelée variable ligne (ou variable row-type). Une telle variable peut contenir une
ligne entière de résultat de requête
SELECT
ou
FOR
, du moment que l'ensemble de
colonnes de la requête correspond au type déclaré de la variable.
Les champs individuels de la valeur row sont accessibles en
utilisant la notation pointée, par exemple varligne.champ.
Une variable ligne peut être déclarée de façon à avoir le même type
que les lignes d'une table ou vue existante, en utilisant la
notation
nom_table
%ROWTYPE ou elle peut être déclarée en donnant un
nom de type composite (chaque table ayant un type de données
associé du même nom, il importe peu dans PostgreSQL™ que vous écriviez %ROWTYPE ou pas. Cependant la forme utilisant
%ROWTYPE est plus portable).
Les paramètres d'une fonction peuvent être des types composites
(lignes complètes de tables). En ce cas, l'identifiant
correspondant $
n
sera une variable ligne à partir
de laquelle les champs peuvent être sélectionnés, par exemple
$1.id_utilisateur.
Seules les colonnes définies par l'utilisateur d'une ligne de table
sont accessibles dans une variable de type ligne, et non l'OID ou
d'autres colonnes systèmes (parce que la ligne pourrait être issue
d'une vue). Les champs du type ligne héritent des tailles des
champs de la table ou de leur précision pour les types de données
tels que char(
n
).
Voici un exemple d'utilisation des types composites. table1 et table2 sont des tables ayant au moins les
champs mentionnés :
CREATE FUNCTION assemble_champs(t_ligne table1) RETURNS text AS $$
DECLARE
t2_ligne table2%ROWTYPE;
BEGIN
SELECT * INTO t2_ligne FROM table2 WHERE ... ;
RETURN t_ligne.f1 || t2_ligne.f3 || t_ligne.f5 || t2_ligne.f7;
END;
$$ LANGUAGE plpgsql;
SELECT assemble_champs(t.*) FROM table1 t WHERE ... ;
nom RECORD;
Les variables record sont similaires aux variables de type ligne
mais n'ont pas de structure prédéfinie. Elles empruntent la
structure effective de type ligne de la ligne à laquelle elles sont
assignées durant une commande
SELECT
or
FOR
. La sous-structure d'une
variable record peut changer à chaque fois qu'on l'assigne. Une
conséquence de cela est que jusqu'à ce qu'elle ait été assignée,
elle n'a pas de sous-structure, et toutes les tentatives pour
accéder à un de ses champs entraîneront une erreur d'exécution.
Notez que RECORD n'est pas un vrai type de
données mais seulement un paramètre fictif (placeholder). Il faut
aussi réaliser que lorsqu'une fonction PL/pgSQL est déclarée renvoyer un type
record, il ne s'agit pas tout à fait du
même concept qu'une variable record, même si une telle fonction
peut aussi utiliser une variable record pour contenir son résultat.
Dans les deux cas la structure réelle de la ligne n'est pas connue
quand la fonction est écrite mais, dans le cas d'une fonction
renvoyant un type record, la structure
réelle est déterminée quand la requête appelante est analysée,
alors qu'une variable record peut changer sa structure de ligne à
la volée.
RENAME ancien nom TO nouveau nom;
En utilisant la déclaration RENAME, vous
pouvez changer le nom d'une variable, d'un record ou d'un row
(ligne). C'est particulièrement utile si NEW ou OLD doivent être
référencés par un autre nom dans une procédure déclencheur. Voir
aussi ALIAS.
Exemples :
RENAME id TO id_utilisateur;
RENAME cette_var TO cette_autre_var;
Note
RENAME semble ne pas fonctionner dans
PostgreSQL™ 7.3. Cette
correction est de faible priorité, ALIAS couvrant la plupart des utilisations
pratiques de RENAME.