

Tous les appels de fonctions écrites dans un langage autre que celui de l'interface « version 1 » pour les langages compilés (ce qui inclut les fonctions dans les langages procéduraux utilisateur, les fonctions SQL), passent par une fonction spécifique au langage du gestionnaire d'appels. Le gestionnaire d'appels exécute la fonction de manière appropriée, par exemple en interprétant le code source fourni. Ce chapitre décrit l'écriture du gestionnaire d'appels d'un nouveau langage procédural.
  Le gestionnaire d'appel d'un langage procédural est une fonction
  « normale » qui doit être écrite dans un langage compilé tel que
  le C, en utilisant l'interface version-1, et enregistrée sous
  PostgreSQL comme une fonction sans argument
  et retournant le type language_handler. Ce pseudo-type spécial
  identifie la fonction comme gestionnaire d'appel et empêche son appel
  à partir des commandes SQL.
  Pour plus de détails sur les conventions d'appels et le chargement
  dynamique en langage C, voir Section 37.9.
 
  L'appel du gestionnaire d'appels est identique à celui de toute
  autre fonction : il reçoit un pointeur de structure
  FunctionCallInfoData qui contient les
  valeurs des arguments et d'autres informations de la fonction appelée.
  Il retourne un résultat Datum (et, initialise
  le champ isnull de la structure
  FunctionCallInfoData si un résultat SQL NULL doit
  être retourné). La différence entre un gestionnaire d'appels et une
  fonction ordinaire se situe au niveau du champ
  flinfo->fn_oid de la structure
  FunctionCallInfoData. Dans le cas du gestionnaire
  d'appels, il contiendra l'OID de la fonction à appeler, et non pas celui du
  gestionnaire d'appels lui-même.
  Le gestionnaire d'appels utilise ce champ pour déterminer la
  fonction à exécuter. De plus, la liste d'arguments passée a été dressée
  à partir de la déclaration de la fonction cible, et non pas en
  fonction du gestionnaire d'appels.
 
  C'est le gestionnaire d'appels qui récupère l'entrée de la
  fonction dans la table système pg_proc et
  analyse les types des arguments et de la valeur de retour de la fonction
  appelée. La clause AS de la commande
  CREATE FUNCTION se situe dans la
  colonne prosrc de
  pg_proc. Il s'agit généralement du texte source du
  langage procédural lui-même (comme pour PL/Tcl) mais, en théorie, cela
  peut être un chemin vers un fichier ou tout ce qui indique
  au gestionnaire d'appels les détails des actions à effectuer.
 
  Souvent, la même fonction est appelée plusieurs fois dans la même
  instruction SQL.
  L'utilisation du champ flinfo->fn_extra
  évite au gestionnaire d'appels de répéter la recherche des informations
  concernant la fonction appelée. Ce champ, initialement
  NULL, peut être configuré par le gestionnaire d'appels pour
  pointer sur l'information concernant la fonction appelée. Lors des appels
  suivants, si flinfo->fn_extra est différent
  de NULL, alors il peut être utilisé et l'étape de
  recherche d'information évitée. Le gestionnaire d'appels doit
  s'assurer que flinfo->fn_extra pointe sur une
  zone mémoire qui restera allouée au moins jusqu'à la fin de la requête en
  cours, car une structure de données FmgrInfo peut
  être conservée aussi longtemps. Cela peut-être obtenu par l'allocation
  des données supplémentaires dans le contexte mémoire spécifié par
  flinfo->fn_mcxt ; de telles données
  ont la même espérance de vie que FmgrInfo.
  Le gestionnaire peut également choisir d'utiliser un contexte mémoire de
  plus longue espérance de vie de façon à
  mettre en cache sur plusieurs
  requêtes les informations concernant les définitions des fonctions.
 
  Lorsqu'une fonction en langage procédural est appelée via un déclencheur,
  aucun argument ne lui est passé de façon traditionnelle mais le champ
  context de
  FunctionCallInfoData pointe sur une structure
  TriggerData. Il n'est pas
  NULL comme c'est le cas dans les appels de fonctions standard.
  Un gestionnaire de langage doit fournir les mécanismes pour que les
  fonctions de langages procéduraux obtiennent les informations du
  déclencheur.
 
Voici un modèle de gestionnaire de langage procédural écrit en C :
#include "postgres.h"
#include "executor/spi.h"
#include "commands/trigger.h"
#include "fmgr.h"
#include "access/heapam.h"
#include "utils/syscache.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif
PG_FUNCTION_INFO_V1(plsample_call_handler);
Datum
plsample_call_handler(PG_FUNCTION_ARGS)
{
    Datum          retval;
    if (CALLED_AS_TRIGGER(fcinfo))
    {
        /*
         * Appelé comme procédure de déclencheur
         */
        TriggerData    *trigdata = (TriggerData *) fcinfo->context;
        retval = ...
    }
    else
    {
        /*
         * Appelé en tant que fonction
         */
        retval = ...
    }
    return retval;
}
  Il suffit de remplacer les points de suspension par quelques milliers de lignes de codes pour compléter ce modèle.
Lorsque la fonction du gestionnaire est compilée dans un module chargeable (voir Section 37.9.5), les commandes suivantes enregistrent le langage procédural défini dans l'exemple :
CREATE FUNCTION plsample_call_handler() RETURNS language_handler
    AS 'nomfichier'
    LANGUAGE C;
CREATE LANGUAGE plsample
    HANDLER plsample_call_handler;
  
Bien que fournir un gestionnaire d'appels est suffisant pour créer un langage de procédures minimal, il existe deux autres fonctions qui peuvent être fournies pour faciliter l'utilisation du langage. Ce sont les fonctions de validation (validator) et de traitement en ligne (inline handler). Une fonction de validation peut être fournie pour activer une vérification spécifique au langage lors du CREATE FUNCTION. Une fonction de traitement en ligne sera utilisé pour supporter les blocs de code anonymes exécutés via la commande DO.
  Si une fonction de validation est fournie par un langage de procédures,
  elle doit être déclarée comme une fonction prenant un seul paramètre, de
  type oid. Le résultat de la validation est ignoré, donc elle
  peut renvoyer le type void. La fonction de validation sera
  appelée à la fin de la commande CREATE FUNCTION qui a
  créé ou mis à jour une fonction écrite dans ce langage. L'OID passé en
  argument est l'OID de la fonction, disponible dans le catalogue
  pg_proc. La fonction de validation doit récupérer
  cette ligne de la façon habituelle et réaliser les vérifications
  appropriées. Tout d'abord, elle appelle
  CheckFunctionValidatorAccess() pour diagnostiquer les
  appels explicites au validateur que l'utilisateur ne peut pas réaliser
  via CREATE FUNCTION.
  Les vérifications typiques incluent la vérification du
  support des types en arguments et en sortie, ainsi que la vérification
  syntaxique du corps de la requête pour ce langage. Si la fonction de
  validation est satisfait par la fonction, elle quitte sans erreur. Si, par
  contre, elle trouve une erreur, elle doit rapporter cette erreur au travers
  du mécanisme ereport() standard. Renvoyer une erreur
  forcera une annulation de la transaction et empêchera du même coup
  l'enregistrement de la fonction dont la définition est erronée.
 
  Les fonctions de validation devraient typiquement accepter le paramètre
  check_function_bodies : s'il est désactivé,
  alors tout vérification coûteuse ou spécifique au contexte devrait être
  abandonnée. Si le langage permet l'exécution de code à la compilation,
  le validateur doit supprimer les vérifications qui impliquerait une
  telle exécution. En particulier, ce paramètre est désactivé par
  pg_dump, pour qu'il puisse charger le langage
  de procédures sans avoir à s'inquiéter des effets de bord et des dépendances
  possibles dans le
  corps des procédures stockées avec d'autres objets de la base de données.
  (À cause de cela, le gestionnaire d'appels doit éviter de supposer que la
  fonction de validation a vérifié complètement la fonction. Le but d'avoir
  une fonction de validation n'est pas d'éviter au gestionnaire d'appels de
  faire des vérifications, mais plutôt de notifier immédiatement à
  l'utilisateur si des erreurs évidentes apparaissent dans la commande
  CREATE FUNCTION.)
  Bien que le choix de ce qui est à vérifier est laissé à la discrétion de la
  fonction de validation, il faut noter que le code de CREATE
   FUNCTION exécute seulement les clauses SET
  attachées à la fonction quand le paramètre
  check_function_bodies est activé. Du coup, les vérifications
  dont les résultats pourraient être affectés par les paramètres en question
  doivent être ignorées quand check_function_bodies est
  désactivé pour éviter de échecs erronés lors du chargement d'une sauvegarde.
 
  Si une fonction de traitement en ligne est fournie au langage de
  procédures, elle doit être déclarée comme une fonction acceptant un seul
  paramètre de type internal. Le résultat de la fonction de
  traitement en ligne est ignoré, donc elle peut renvoyer le type
  void. Elle sera appelée quand une instruction
  DO est exécutée pour ce langage. Le paramètre qui lui
  est fourni est un pointeur vers une structure
  InlineCodeBlock, structure contenant des
  informations sur les paramètres de l'instruction DO, en
  particulier le texte du bloc de code anonyme à exécuter. La fonction doit
  exécuter ce code.
 
  It est recommandé de placer toutes les déclarations de fonctions ainsi que
  la commande CREATE LANGUAGE dans une
  extension pour qu'une simple commande
  CREATE EXTENSION suffise à installer le langage. Voir
  Section 37.15 pour plus d'informations sur
  l'écriture d'extensions.
 
  Les langages procéduraux inclus dans la distribution standard sont de
  bons points de départ à l'écriture de son propre gestionnaire
  de langage. Les sources se trouvent dans le répertoire src/pl.
  La page de référence de CREATE LANGUAGE contient aussi
  certains détails utiles.