Pour créer une fonction dans le langage PL/Perl, utilisez la syntaxe standard CREATE FUNCTION :
CREATE FUNCTIONnom_fonction
(types-arguments
) RETURNStype-retour
-- attributs de fonction AS $$ # Corps de la fonction PL/Perl $$ LANGUAGE plperl;
Le corps de la fonction est du code Perl normal. En fait, le code supplémentaire PL/Perl l'emballe dans une sous-routine Perl. Une fonction PL/Perl est appelée dans un contexte scalaire, il ne peut donc pas retourner une liste. Vous pouvez retourner des valeurs non scalaire par référence comme indiqué ci-dessous.
Dans une procédure PL/Perl, toute valeur de retour du code Perl est ignorée.
PL/Perl peut aussi être utilisé au sein de blocs de procédures anonymes avec l'ordre DO :
DO $$ # PL/Perl code $$ LANGUAGE plperl;
Un bloc de procédure anonyme ne prend pas d'arguments et toute valeur retournée est ignorée. Ceci mis à part, il se comporte comme une fonction classique.
L'utilisation de sous-routines nommées est dangereux en Perl, spécialement
si elles font références à des variables lexicales dans la partie
englobante. Comme une fonction PL/Perl est englobée dans une sous-routine,
toute sous-routine nommée que vous y créez
sera englobée. En général, il est bien plus sûr de créer des sous-routines anonymes
que vous appellerez via un coderef. Pour de plus amples détails, voir
les entrées Variable "%s" will not stay shared
et
Variable "%s" is not available
dans le manuel
perldiag, ou
recherchez « perl nested named subroutine » sur internet.
La syntaxe de la commande CREATE FUNCTION
requiert que le
corps de la fonction soit écrit comme une constante de type chaîne. Il est
habituellement plus agréable d'utiliser les guillemets dollar (voir la Section 4.1.2.4) pour cette constante. Si vous
choisissez d'utiliser la syntaxe d'échappement des chaînes E''
,
vous devez doubler les marques de guillemets simples ('
)
et les antislashs (\
) utilisés dans le corps de la
fonction (voir la Section 4.1.2.1).
Les arguments et les résultats sont manipulés comme dans n'importe quel
routine Perl : les arguments sont passés au tableau
@_
et une valeur de retour
est indiquée par return
ou par la dernière expression
évaluée dans la fonction.
Par exemple, une fonction retournant le plus grand de deux entiers peut être définie comme suit :
CREATE FUNCTION perl_max (integer, integer) RETURNS integer AS $$ if ($_[0] > $_[1]) { return $_[0]; } return $_[1]; $$ LANGUAGE plperl;
Les arguments seront convertis de l'encodage de la base de données en UTF-8 pour être utilisé par PL/perl, puis converti de l'UTF-8 vers l'encodage de la base.
Si une valeur NULL en SQL est passée à une fonction,
cet argument apparaîtra comme « undefined » en Perl. La
fonction définie ci-dessus ne se comportera pas correctement avec des
arguments NULL (en fait, tout se passera comme s'ils avaient été des zéros).
Nous aurions pu ajouter STRICT
à la définition de la fonction
pour forcer PostgreSQL à faire quelque chose de
plus raisonnable : si une valeur NULL est passée en argument, la
fonction ne sera pas du tout appelée mais retournera automatiquement un
résultat NULL. D'une autre façon, nous aurions pu vérifier dans le corps de
la fonction la présence d'arguments NULL. Par exemple, supposons que nous
voulions que perl_max
avec un argument NULL et un autre
non NULL retourne une valeur non NULL plutôt qu'une valeur NULL, on aurait
écrit :
CREATE FUNCTION perl_max (integer, integer) RETURNS integer AS $$ my ($x, $y) = @_; if (not defined $x) { return undef if not defined $y; return $y; } return $x if not defined $y; return $x if $x > $y; return $y; $$ LANGUAGE plperl;
Comme le montre l'exemple ci-dessus, passer une valeur NULL en SQL à une fonction en PL/Perl retourne une valeur non définie. Et ceci, que la fonction soit déclarée stricte ou non.
Dans un argument de fonction, tout ce qui n'est pas une référence est une
chaîne qui est dans la représentation texte externe standard de
PostgreSQL pour ce type de données. Dans le cas
de types numériques ou texte, Perl fera ce qu'il faut et le programmeur
n'aura pas à s'en soucier. Néanmoins, dans d'autres cas, l'argument aura
besoin d'être converti dans une forme qui est plus utilisable que Perl.
Par exemple, la fonction decode_bytea
peut-être utilisée
pour convertir un argument de type
bytea
en données binaires non échappées.
De façon similaire, les valeurs renvoyées à
PostgreSQL doivent être dans le format textuel.
Par exemple,
la fonction encode_bytea
peut être utilisée
pour échapper des données binaires en retournant une valeur de type bytea
.
Un cas particulièrement important concerne les valeurs booléennes. Comme
indiqué à l'instant, le comportement par défaut des valeurs de type
bool
est qu'elles sont passées en tant que text à
l'interpréteur Perl, donc soit 't'
soit
'f'
. Ceci est problématique parce que Perl ne traite pas
'f'
comme un false ! Il est possible d'améliorer
les choses en utilisant une « transformation » (voir CREATE TRANSFORM). Des transformations intéressantes sont
fournies par l'extension bool_plperl
. Pour l'utiliser,
installez l'extension :
CREATE EXTENSION bool_plperl; -- or bool_plperlu for PL/PerlU
Puis utilisez l'attribut de fonction TRANSFORM
pour une
fonction PL/Perl qui prend ou renvoie une donnée de type bool
,
par exemple :
CREATE FUNCTION perl_and(bool, bool) RETURNS bool TRANSFORM FOR TYPE bool AS $$ my ($a, $b) = @_; return $a && $b; $$ LANGUAGE plperl;
Quand cette transformation est appliquée, les arguments bool
seront vues par Perl comme valant 1
ou vide, soit des
valeurs true ou false propres. Si le résultat de la fonction renvoie le
type bool
, il sera true ou false suivant comment Perl évaluera
la valeur retournée. Des transformations similaires sont aussi réalisées
pour les arguments de requêtes de type booléen et les résultats des
requêtes SPI réalisées à l'intérieur de la fonction (Section 45.3.1).
Perl peut renvoyer des tableaux PostgreSQL comme référence à des tableaux Perl. Voici un exemple :
CREATE OR REPLACE function renvoit_tableau() RETURNS text[][] AS $$ return [['a"b','c,d'],['e\\f','g']]; $$ LANGUAGE plperl; select renvoit_tableau();
Perl utilise les tableaux PostgreSQL comme des
objets PostgreSQL::InServer::ARRAY
. Cet objet sera traité comme une référence
de tableau ou comme une chaîne, permettant une compatibilité ascendante avec
le code Perl écrit pour les versions de PostgreSQL
antérieures à la 9.1. Par exemple :
CREATE OR REPLACE FUNCTION concat_array_elements(text[]) RETURNS TEXT AS $$ my $arg = shift; my $result = ""; return undef if (!defined $arg); # en tant que référence de tableau for (@$arg) { $result .= $_; } # en tant que chaîne $result .= $arg; return $result; $$ LANGUAGE plperl; SELECT concat_array_elements(ARRAY['PL','/','Perl']);
Les tableaux multi-dimensionnels sont représentés comme des références à des tableaux de reférence et de moindre dimension, d'une façon connue de chaque développeur Perl.
Les arguments de type composite sont passés à la fonction en tant que références d'un tableau de découpage, les clés du tableau de découpage étant les noms des attributs du type composé. Voici un exemple :
CREATE TABLE employe ( nom text, basesalaire integer, bonus integer ); CREATE FUNCTION empcomp(employe) RETURNS integer AS $$ my ($emp) = @_; return $emp->{basesalaire} + $emp->{bonus}; $$ LANGUAGE plperl; SELECT nom, empcomp(employe.*) FROM employe;
Une fonction PL/Perl peut renvoyer un résultat de type composite en utilisant la même approche : renvoyer une référence à un hachage qui a les attributs requis. Par exemple
CREATE TYPE testligneperl AS (f1 integer, f2 text, f3 text); CREATE OR REPLACE FUNCTION perl_ligne() RETURNS test_ligne_perl AS $$ return {f2 => 'hello', f1 => 1, f3 => 'world'}; $$ LANGUAGE plperl; SELECT * FROM perl_row();
Toute colonne dans le type de données déclaré du résultat qui n'est pas présente dans le hachage sera renvoyée NULL.
De façon similaire, les arguments en sortie des procédures peuvent être renvoyés sous la format d'une référence hash :
CREATE PROCEDURE perl_triple(INOUT a integer, INOUT b integer) AS $$ my ($a, $b) = @_; return {a => $a * 3, b => $b * 3}; $$ LANGUAGE plperl; CALL perl_triple(5, 10);
Les fonctions PL/Perl peuvent aussi renvoyer des ensembles de types
scalaires ou composites. Habituellement, vous voulez renvoyer une ligne à
la fois, à la fois pour améliorer le temps de démarrage et pour éviter
d'allonger la queue de l'ensemble des résultats en mémoire. Vous pouvez
faire ceci avec return_next
comme indiqué ci-dessous.
Notez qu'après le dernier return_next
, vous devez
placer soit return
soit (encore mieux) return
undef
.
CREATE OR REPLACE FUNCTION perl_set_int(int) RETURNS SETOF INTEGER AS $$ foreach (0..$_[0]) { return_next($_); } return undef; $$ LANGUAGE plperl; SELECT * FROM perl_set_int(5); CREATE OR REPLACE FUNCTION perl_set() RETURNS SETOF test_ligne_perl AS $$ return_next({ f1 => 1, f2 => 'Hello', f3 => 'World' }); return_next({ f1 => 2, f2 => 'Hello', f3 => 'PostgreSQL' }); return_next({ f1 => 3, f2 => 'Hello', f3 => 'PL/Perl' }); return undef; $$ LANGUAGE plperl;
Pour les petits ensembles de résultats, vous pouvez renvoyer une référence à un tableau contenant soit des scalaires, soit des références à des tableaux soit des références à des hachages de types simples, de types tableaux ou de types composites. Voici quelques exemples simples pour renvoyer l'ensemble complet du résultant en tant que référence de tableau :
CREATE OR REPLACE FUNCTION perl_set_int(int) RETURNS SETOF INTEGER AS $$ return [0..$_[0]]; $$ LANGUAGE plperl; SELECT * FROM perl_set_int(5); CREATE OR REPLACE FUNCTION perl_set() RETURNS SETOF testligneperl AS $$ return [ { f1 => 1, f2 => 'Bonjour', f3 => 'Monde' }, { f1 => 2, f2 => 'Bonjour', f3 => 'PostgreSQL' }, { f1 => 3, f2 => 'Bonjour', f3 => 'PL/Perl' } ]; $$ LANGUAGE plperl; SELECT * FROM perl_set();
Si vous souhaitez utiliser le pragma strict
dans votre code,
vous avez plusieurs options. Pour une utilisation temporaire globale vous pouvez positionner (SET
)
plperl.use_strict
à « true ». Ce paramètre affectera les
compilations suivantes de fonctions PL/Perl, mais
pas les fonctions déjà compilées dans la session en cours.
Pour une utilisation globale permanente, vous pouvez positionner plperl.use_strict
à « true » dans le fichier postgresql.conf
.
Pour une utilisation permanente dans des fonctions spécifiques, vous pouvez simplement placer:
use strict;
en haut du corps de la fonction.
Le pragma feature
est aussi disponible avec use
si votre version de Perl est 5.10.0 ou supérieur.