35.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.

Voici 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;

35.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
END;
$$ LANGUAGE plpgsql;


CREATE FUNCTION concat_selected_fields(in_t tablename) RETURNS text AS $$
BEGIN
    RETURN in_t.f1 || in_t.f3 || in_t.f5 || in_t.f7;
END;
$$ LANGUAGE plpgsql;

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 31.2.1). Ceci permet à la fonction d'accéder à son type de retour réel comme on le voit ici avec la Section 35.4.2. $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;

35.4.2. Copie de types

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.

35.4.3. Types ligne

name table_name%ROWTYPE;
name composite_type_name;

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  :

CREATE FUNCTION merge_fields(t_row tablename) RETURNS text AS $$
DECLARE
    t2_row table2name%ROWTYPE;
BEGIN
    SELECT * INTO t2_row FROM table2name WHERE ... ;
    RETURN t_row.f1 || t2_row.f3 || t_row.f5 || t2_row.f7;
END;
$$ LANGUAGE plpgsql;

SELECT merge_fields(t.*) FROM tablename t WHERE ... ;

35.4.4. Types Record

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.

35.4.5. RENAME

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.