[Trad] [svn:pgfr] r1351 - in traduc/tags: . tv840rc1

admin at listes.postgresql.fr admin at listes.postgresql.fr
Mar 23 Juin 18:25:46 CEST 2009


Author: gleu
Date: 2009-06-23 18:25:46 +0200 (Tue, 23 Jun 2009)
New Revision: 1351

Added:
   traduc/tags/tv840rc1/
   traduc/tags/tv840rc1/nls.xml
   traduc/tags/tv840rc1/xfunc.xml
Removed:
   traduc/tags/tv840rc1/nls.xml
   traduc/tags/tv840rc1/xfunc.xml
Log:
Ajout du tag de la 8.4 RC 1.



Property changes on: traduc/tags/tv840rc1
___________________________________________________________________
Added: svn:mergeinfo
   + 

Deleted: traduc/tags/tv840rc1/nls.xml
===================================================================
--- traduc/trunk/postgresql/nls.xml	2009-06-22 07:28:54 UTC (rev 1349)
+++ traduc/tags/tv840rc1/nls.xml	2009-06-23 16:25:46 UTC (rev 1351)
@@ -1,533 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-15"?>
-<!-- Dernière modification
-     le       $Date$
-     par      $Author$
-     révision $Revision$ -->
-
-<chapter id="nls">
- <chapterinfo>
-  <author>
-   <firstname>Peter</firstname>
-   <surname>Eisentraut</surname>
-  </author>
- </chapterinfo>
-
- <title>Support natif des langues</title>
-
- <sect1 id="nls-translator">
-  <title>Pour le traducteur</title>
-
-  <para>
-   Les programmes <productname>PostgreSQL</productname> (serveur et client) peuvent afficher
-   leur message dans la langue préférée de l'utilisateur &mdash; si les messages ont été traduits.
-   Créer et maintenir les ensembles de messages traduits nécessite l'aide de
-   personnes parlant leur propre langue et souhaitant contribuer à 
-   <productname>PostgreSQL</productname>. Il n'est nul besoin d'être un développeur
-   pour cela. Cette section explique comment apporter son aide.
-  </para>
-
-  <sect2>
-   <title>Prérequis</title>
-
-   <para>
-    Les compétences dans sa langue d'un traducteur ne seront pas jugées &mdash; cette
-    section concerne uniquement les outils logiciels. Théoriquement, seul un
-    éditeur de texte est nécessaire. Mais ceci n'est vrai que dans le cas très
-    improbable où un traducteur ne souhaiterait pas tester ses traductions des
-    messages. Lors de la configuration des sources, il faudra s'assurer d'utiliser l'option
-    <option>--enable-nls</option>. Ceci assurera également la présence de la
-    bibliothèque <application>libintl</application> et du programme
-    <filename>msgfmt</filename> dont tous les utilisateurs finaux ont indéniablement
-    besoin. Pour tester son travail, il sera utile de suivre les parties pertinentes
-    des instructions d'installation.
-   </para>
-
-   <para>
-    Pour commencer un nouvel effort de traduction ou pour faire un assemblage de
-    catalogues de messages (décrit ci-après), il faudra installer respectivement
-    les programmes <filename>xgettext</filename> et <filename>msgmerge</filename>
-    dans une implémentation compatible GNU. Il est prévu dans le futur que
-    <filename>xgettext</filename> ne soit plus nécessaire lorsqu'une distribution
-    empaquetée des sources est utilisée (en travaillant à partir du CVS, il
-    sera toujours utile). <application>GNU Gettext 0.10.36</application> ou ultérieure est
-     actuellement recommandé.
-   </para>
-
-   <para>
-    Toute implémentation locale de gettext devrait être disponible avec sa
-    propre documentation. Une partie en est certainement dupliquée dans ce qui suit
-    mais des détails complémentaires y sont certainement disponibles.
-   </para>
-  </sect2>
-
-  <sect2>
-   <title>Concepts</title>
-
-   <para>
-    Les couples de messages originaux (anglais) et de leurs (possibles)
-    traductions sont conservés dans les <firstterm>catalogues de
-    messages</firstterm>, un pour chaque programme (bien que des programmes liés
-    puissent partager un catalogue de messages) et pour chaque langue cible. Il
-    existe deux formats de fichiers pour les catalogues de messages&nbsp;: le
-    premier est le fichier <quote>PO</quote> (pour "Portable Object" ou Objet Portable), 
-    qui est un
-    fichier texte muni d'une syntaxe spéciale et que les traducteurs éditent. Le
-    second est un fichier <quote>MO</quote> (pour "Machine Object" ou Objet Machine), 
-    qui est un
-    fichier binaire engendré à partir du fichier PO respectif et qui est utilisé
-    lorsque le programme internationalisé est exécuté. Les traducteurs ne
-    s'occupent pas des fichiers MO&nbsp;; en fait, quasiment personne ne s'en occupe.
-   </para>
-
-   <para>
-    L'extension du fichier de catalogue de messages est, sans surprise, soit
-    <filename>.po</filename>, soit <filename>.mo</filename>. Le nom de base est
-    soit le nom du programme qu'il accompagne soit la langue utilisée dans le
-    fichier, suivant la situation. Ceci peut s'avérer être une source de
-    confusion. Des exemples sont <filename>psql.po</filename> (fichier PO pour
-    psql) ou <filename>fr.mo</filename> (fichier MO en français).
-   </para>
-
-   <para>
-    Le format du fichier PO est illustré ici&nbsp;:
-<programlisting># commentaire
-
-msgid "chaîne originale"
-msgstr "chaîne traduite"
-
-msgid "encore une originale"
-msgstr "encore une de traduite"
-"les chaînes peuvent être sur plusieurs lignes, comme ceci"
-
-...
-</programlisting>
-    Les chaînes msgid sont extraites des sources du programme. (Elles n'ont pas
-    besoin de l'être mais c'est le moyen le plus commun). Les lignes msgstr sont
-    initialement vides puis complétées avec les chaînes traduites. Les chaînes
-    peuvent contenir des caractères d'échappement de style C et peuvent être sur
-    plusieurs lignes comme le montre l'exemple ci-dessus (la ligne suivante
-    doit démarrer au début de la ligne).
-   </para>
-
-   <para>
-    Le caractère # introduit un commentaire. Si une espace fine suit 
-    immédiatement le caractère #, c'est qu'il s'agit là d'un commentaire maintenu par le 
-    traducteur. On trouve aussi des commentaires automatiques qui n'ont pas d'espace
-    fine suivant immédiatement le caractère #. Ils sont maintenus par les différents outils
-    qui opèrent sur les fichiers PO et ont pour but d'aider le traducteur.
-<programlisting>#. commentaire automatique
-#: fichier.c:1023
-#, drapeau, drapeau
-</programlisting>
-    Les commentaires du style #. sont extraits du fichier source où le message
-    est utilisé. Il est possible que le développeur ait ajouté des informations
-    pour le traducteur, telles que l'alignement attendu. Le commentaire #:
-    indique l'emplacement exact où le message est utilisé dans le source. Le
-    traducteur n'a pas besoin de regarder le source du programme, mais il peut
-    le faire s'il subsiste un doute sur l'exactitude d'une traduction. Le commentaire #,
-    contient des drapeaux décrivant le message d'une certaine façon. Il existe
-    actuellement deux drapeaux&nbsp;: <literal>fuzzy</literal> est positionné si le
-    message risque d'être rendu obsolète par des changements dans les
-    sources. Le traducteur peut alors vérifier ceci et supprimer ce drapeau.
-    Notez que les messages <quote>fuzzy</quote> ne sont pas accessibles à
-    l'utilisateur final. L'autre drapeau est <literal>c-format</literal>
-    indiquant que le message utilise le format de la fonction C
-    <function>printf</function>. Ceci signifie que la traduction devrait aussi
-    être de ce format avec le même nombre et le même type de paramètres fictifs. Il
-    existe des outils qui vérifient que le message est une chaîne au format
-    printf et valident le drapeau c-format en conséquence.
-<!-- which key off the c-format flags -->
-   </para>
-  </sect2>
-
-  <sect2>
-   <title>Créer et maintenir des catalogues de messages</title>
-
-   <para>
-    OK, alors comment faire pour créer un catalogue de messages
-    <quote>vide</quote>&nbsp;? Tout d'abord, se placer dans le répertoire contenant
-    le programme dont on souhaite traduire les messages. S'il existe un
-    fichier <filename>nls.mk</filename>, alors ce programme est préparé pour la
-    traduction.
-   </para>
-
-   <para>
-    S'il y a déjà des fichiers <filename>.po</filename>, alors quelqu'un a
-    déjà réalisé des travaux de traduction. Les fichiers sont nommés 
-    <filename><replaceable>langue</replaceable>.po</filename>, où
-    <replaceable>langue</replaceable> est le code de langue sur deux
-    caractères  (en minuscules) tel que défini par l'<ulink
-    url="http://lcweb.loc.gov/standards/iso639-2/englangn.html">
-    ISO 639-1, le code du pays composé de deux lettres en minuscule</ulink>,
-    c'est-à-dire <filename>fr.po</filename> pour
-    le français. S'il existe réellement un besoin pour plus d'une
-    traduction par langue, alors les fichiers peuvent être renommés
-    <filename><replaceable>langue</replaceable>_<replaceable>region</replaceable>.po</filename>
-    où <replaceable>region</replaceable> est le code de langue sur deux
-    caractères (en majuscules), tel que défini par l'<ulink
-    url="http://www.din.de/gremien/nas/nabd/iso3166ma/codlstp1/en_listp1.html">ISO 3166-1,
-    le code du payes sur deux lettres en majuscule</ulink>,
-    c'est-à-dire <filename>pt_BR.po</filename> pour le portugais du Brésil. Si vous
-    trouvez la langue que vous souhaitez, vous pouvez commencer à travailler
-    sur ce fichier.
-   </para>
-
-   <para>
-    Pour commencer une nouvelle traduction, il faudra préalablement exécuter la
-    commande&nbsp;:
-<programlisting>gmake init-po
-</programlisting>
-    Ceci créera un fichier
-    <filename><replaceable>nomprog</replaceable>.pot</filename>.
-    (<filename>.pot</filename> pour le distinguer des fichiers PO qui sont
-    <quote>en production</quote>. Le <literal>T</literal> signifie
-    <quote>template</quote> (NdT&nbsp;: modèle en anglais).
-    On copiera ce fichier sous le nom
-    <filename><replaceable>langue</replaceable>.po</filename>. On peut alors l'éditer.
-    Pour faire savoir qu'une nouvelle langue est disponible, il faut également éditer
-    le fichier <filename>nls.mk</filename> et y ajouter le code de la langue (ou de
-    la langue et du pays) avec une ligne ressemblant à ceci&nbsp;:
-<programlisting>AVAIL_LANGUAGES := de fr
-</programlisting>
-    (d'autres langues peuvent apparaître, bien entendu).
-   </para>
-
-   <para>
-    À mesure que le programme ou la bibliothèque change, des messages peuvent
-    être modifiés ou ajoutés par les développeurs. Dans ce cas, il n'est pas nécessaire
-    de tout recommencer depuis le début. À la place, on lancera la commande&nbsp;:
-<programlisting>gmake update-po
-</programlisting>
-    qui créera un nouveau catalogue de messages vides (le fichier pot avec
-    lequel la traduction a été initiée) et le fusionnera avec les fichiers PO existants.
-    Si l'algorithme de fusion a une incertitude sur un message particulier,
-    il le marquera <quote>fuzzy</quote> comme expliqué ci-dessus. Le nouveau
-    fichier PO est sauvegardé avec l'extension <filename>.po.new</filename>.
-   </para>
-  </sect2>
-
-  <sect2>
-   <title>Éditer les fichiers PO</title>
-
-   <para>
-    Les fichiers PO sont éditables avec un éditeur de texte standard. Le traducteur
-    doit seulement modifier l'emplacement entre les guillemets après la
-    directive msgstr, peut ajouter des commentaires et modifier le drapeau fuzzy
-    (NdA&nbsp;: Il existe, ce qui n'est pas surprenant, un mode PO pour Emacs, que je trouve assez
-    utile).
-   </para>
-
-   <para>
-    Les fichiers PO n'ont pas besoin d'être entièrement remplis. Le logiciel
-    retournera automatiquement à la chaîne originale si une traduction n'est pas
-    disponible ou est laissée vide. Soumettre des traductions incomplètes pour les
-    inclure dans l'arborescence des sources n'est pas un problème&nbsp;; cela permet à d'autres
-    personnes de récupérer le travail commencé pour le continuer. Néanmoins,
-    les traducteurs sont encouragés à donner une haute priorité à la suppression
-    des entrées fuzzy après avoir fait une fusion. Les entrées fuzzy ne
-    seront pas installées&nbsp;; elles servent seulement de référence à ce qui
-    pourrait être une bonne traduction.
-   </para>
-
-   <para>
-    Certaines choses sont à garder à l'esprit lors de l'édition des
-    traductions&nbsp;:
-    <itemizedlist>
-     <listitem>
-      <para>
-       S'assurer que si la chaîne originale se termine par un retour chariot, la
-       traduction le fasse bien aussi. De même pour les tabulations, etc.
-      </para>
-     </listitem>
-
-     <listitem>
-      <para>
-       Si la chaîne originale est une chaîne au format <function>printf</function>, la
-       traduction doit l'être aussi. La traduction doit également avoir les
-       même spécificateurs de format et dans le même ordre. Quelques fois, les
-       règles naturelles de la langue rendent cela impossible ou tout au moins
-       difficile. Dans ce cas, il est possible de modifier les spécificateurs de format
-       de la façon suivante&nbsp;:
-<programlisting>msgstr "Die Datei %2$s hat %1$u Zeichen."
-</programlisting>
-       Le premier paramètre fictif sera alors utilisé par le deuxième argument de la
-       liste. Le <literal><replaceable>chiffre</replaceable>$</literal> a
-       besoin de suivre immédiatement le %, avant tout autre manipulateur de
-       format (cette fonctionnalité existe réellement dans la famille des
-       fonctions <function>printf</function>, mais elle est peu connue, n'ayant
-       que peu d'utilité en dehors de l'internationalisation des messages).
-      </para>
-     </listitem>
-
-     <listitem>
-      <para>
-       Si la chaîne originale contient une erreur linguistique, on pourra la rapporter
-       (ou la corriger soi-même dans le source du programme) et la traduire
-       normalement. La chaîne corrigée peut être fusionnée lorsque les
-       programmes sources auront été mis à jour. Si la chaîne originale contient
-       une erreur factuelle, on la rapportera (ou la corrigera soi-même) mais on
-       ne la traduira pas. À la place, on marquera la chaîne avec un commentaire
-       dans le fichier PO.
-      </para>
-     </listitem>
-
-     <listitem>
-      <para>
-       Maintenir le style et le ton de la chaîne originale. En particulier, les
-       messages qui ne sont pas des phrases (<literal>cannot
-       open file %s</literal>, soit <literal>ne peut pas ouvrir le fichier
-       %s</literal>) ne devraient probablement pas commencer avec une lettre
-       capitale (si votre langue distingue la casse des lettres) ou finir avec
-       un point (si votre langue utilise des marques de ponctuation). Lire <xref
-       linkend="error-style-guide"/> peut aider.
-      </para>
-     </listitem>
-
-     <listitem>
-      <para>
-       Lorsque la signification d'un message n'est pas connue ou s'il est ambigü,
-       on pourra demander sa signification sur la liste de diffusion des développeurs.
-       Il est possible qu'un anglophone puisse aussi ne pas le comprendre ou le
-       trouver ambigü. Il est alors préférable d'améliorer le message.
-      </para>
-     </listitem>
-
-    </itemizedlist>
-   </para>
-  </sect2>
-
- </sect1>
-
-
- <sect1 id="nls-programmer">
-  <title>Pour le développeur</title>
-
-  <sect2 id="nls-mechanics">
-   <title>Mécaniques</title>
-
-  <para>
-   Cette section explique comment implémenter le support natif d'une langue dans
-   un programme ou dans une bibliothèque qui fait partie de la distribution
-   <productname>PostgreSQL</productname>. Actuellement, cela s'applique uniquement aux
-   programmes C.
-  </para>
-
-  <procedure>
-   <title>Ajouter le support NLS à un programme</title>
-
-   <step>
-    <para>
-     Le code suivant est inséré dans la séquence initiale du programme&nbsp;:
-<programlisting>#ifdef ENABLE_NLS
-#include &lt;locale.h&gt;
-#endif
-
-...
-
-#ifdef ENABLE_NLS
-setlocale(LC_ALL, "");
-bindtextdomain("<replaceable>nomprog</replaceable>", LOCALEDIR);
-textdomain("<replaceable>nomprog</replaceable>");
-#endif
-</programlisting>
-     (<replaceable>nomprog</replaceable> peut être choisi tout à fait librement).
-    </para>
-   </step>
-
-   <step>
-    <para>
-     Partout où un message candidat à la traduction est trouvé,
-     un appel à <function>gettext()</function> doit être inséré.
-     Par exemple&nbsp;:
-<programlisting>fprintf(stderr, "panic level %d\n", lvl);
-</programlisting>
-     devra être changé avec&nbsp;:
-<programlisting>fprintf(stderr, gettext("panic level %d\n"), lvl);
-</programlisting>
-     (<symbol>gettext</symbol> est défini comme une opération nulle si NLS
-     n'est pas configuré).
-    </para>
-
-    <para>
-     Cela peut engendrer du fouillis. Un raccourci habituel consiste à
-     utiliser&nbsp;:
-<programlisting>#define _(x) gettext(x)
-</programlisting>
-     Une autre solution est envisageable si le programme effectue la plupart de ses
-     communications via une fonction ou un nombre restreint de fonctions, telle
-     <function>ereport()</function> pour le moteur. Le fonctionnement interne de
-     cette fonction peut alors être modifiée pour qu'elle appelle
-     <function>gettext</function> pour toutes les chaînes en entrée.
-    </para>
-   </step>
-
-   <step>
-    <para>
-     Un fichier <filename>nls.mk</filename> est ajouté dans le répertoire des
-     sources du programme. Ce fichier sera lu comme un makefile. Les affectations
-     des variables suivantes doivent être réalisées ici&nbsp;:
-
-     <variablelist>
-      <varlistentry>
-       <term><varname>CATALOG_NAME</varname></term>
-
-       <listitem>
-        <para>
-         Le nom du programme tel que fourni lors de l'appel à
-         <function>textdomain()</function>.
-        </para>
-       </listitem>
-      </varlistentry>
-
-      <varlistentry>
-       <term><varname>AVAIL_LANGUAGES</varname></term>
-
-       <listitem>
-        <para>
-         Liste des traductions fournies &mdash; initialement vide.
-        </para>
-       </listitem>
-      </varlistentry>
-
-      <varlistentry>
-       <term><varname>GETTEXT_FILES</varname></term>
-
-       <listitem>
-        <para>
-         Liste des fichiers contenant les chaînes traduisibles, c'est-à-dire
-         celles marquées avec <function>gettext</function> ou avec une 
-         solution alternative. Il se peut que cette liste inclut pratiquement
-         tous les fichiers sources du programme. Si cette liste est trop longue,
-         le premier <quote>fichier</quote> peut être remplacé par un <literal>+</literal>
-         et le deuxième mot représenter un fichier contenant un nom de fichier par
-         ligne.
-        </para>
-       </listitem>
-      </varlistentry>
-
-      <varlistentry>
-       <term><varname>GETTEXT_TRIGGERS</varname></term>
-
-       <listitem>
-        <para>
-         Les outils qui engendrent des catalogues de messages pour les
-         traducteurs ont besoin de connaître les appels de
-         fonction contenant des chaînes à traduire. Par défaut, seuls les appels
-         à <function>gettext()</function> sont reconnus. Si <function>_</function>
-         ou d'autres identifiants sont utilisés, il est nécessaire de les lister ici.
-         Si la chaîne traduisible n'est pas le premier argument,
-         l'élément a besoin d'être de la forme <literal>func:2</literal> (pour
-         le second argument).
-         Si vous avez une fonction qui supporte les messages au format pluriel,
-	 l'élément ressemblera à <literal>func:1,2</literal>
-         (identifiant les arguments singulier et pluriel du message).
-        </para>
-       </listitem>
-      </varlistentry>
-     </variablelist>
-    </para>
-   </step>
-
-  </procedure>
-
-  <para>
-   Le système de construction s'occupera automatiquement de construire et
-   installer les catalogues de messages.
-  </para>
-  </sect2>
-
-  <sect2 id="nls-guidelines">
-   <title>Guide d'écriture des messages</title>
-
-  <para>
-   Voici quelques lignes de conduite pour l'écriture de messages facilement
-   traduisibles.
-
-   <itemizedlist>
-    <listitem>
-     <para>
-      Ne pas construire de phrases à l'exécution, telles que&nbsp;:
-<programlisting>printf("Files were %s.\n", flag ? "copied" : "removed");
-</programlisting>
-      L'ordre des mots d'une phrase peut être différent dans d'autres langues.
-      De plus, même si <function>gettext()</function> est correctement appelé sur chaque fragment,
-      il pourrait être difficile de traduire séparément les fragments. Il est
-      préférable de dupliquer un peu de code de façon à ce que chaque message à
-      traduire forme un tout cohérent. Seuls les nombres, noms de fichiers et
-      autres variables d'exécution devraient être insérés au moment de
-      l'exécution dans le texte d'un message.
-     </para>
-    </listitem>
-
-    <listitem>
-     <para>
-      Pour des raisons similaires, ceci ne fonctionnera pas&nbsp;:
-<programlisting>printf("copied %d file%s", n, n!=1 ? "s" : "");
-</programlisting>
-      parce que cette forme présume de la façon dont la forme plurielle est obtenue.
-      L'idée de résoudre ce cas de la façon suivante&nbsp;:
-<programlisting>if (n==1)
-    printf("copied 1 file");
-else
-    printf("copied %d files", n):
-</programlisting>
-      sera source de déception. Certaines langues ont plus de deux formes avec
-      des règles particulières. Il est souvent préférable de concevoir le
-      message de façon à éviter le problème, par exemple ainsi&snbp;:
-<programlisting>printf("number of copied files: %d", n);
-</programlisting>
-     </para>
-
-     <para>
-      Si vous voulez vraiment construire un message correctement pluralisé,
-      il existe un support pour cela, mais il est un peu étrange. Quand vous
-      générez un message d'erreur primaire ou détaillé dans
-      <function>ereport()</function>, vous pouvez écrire quelque-chose comme
-      ceci&nbsp;:
-<programlisting>
-errmsg_plural("copied %d file",
-              "copied %d files",
-              n,
-              n)
-</programlisting>
-      Le premier argument est le chaîne dans le format approprié pour la forme
-      au singulier en anglais, le second est le format de chaîne approprié pour
-      la forme plurielle en anglais, et le troisième est la valeur entière
-      déterminant la forme à utiliser. Des arguments additionnels sont formatés
-      suivant la chaîne de formatage comme d'habitude. (Habituellement, la
-      valeur de contrôle de la pluralisation sera aussi une des valeurs à
-      formater, donc elle sera écrite deux fois.) En anglais, cela n'importe
-      que si <replaceable>n</replaceable> est égale à 1 ou est différent de 1,
-      mais dans d'autres langues, il pourrait y avoir plusieurs formes de
-      pluriel. Le traducteur voit les deux formes anglaises comme un groupe
-      et a l'opportunité de fournir des chaînes de substitution supplémentaires,
-      la bonne étant sélectionnée suivant la valeur à l'exécution de
-      <replaceable>n</replaceable>.
-     </para>
-
-     <para>
-      Si vous avez besoin de pluraliser un message qui ne va pas directement à
-      <function>errmsg</function> ou <function>errdetail</function>, vous devez
-      utiliser la fonction sous-jacente <function>ngettext</function>. Voir la
-      documentation gettext.
-     </para>
-    </listitem>
-
-    <listitem>
-     <para>
-      Lorsque quelque chose doit être communiqué au traducteur, telle que la façon
-      dont un message doit être aligné avec quelque autre sortie, on pourra faire
-      précéder l'occurrence de la chaîne d'un commentaire commençant par
-      <literal>translator</literal>, par exemple&nbsp;:
-<programlisting>/* translator: This message is not what it seems to be. */
-</programlisting>
-      Ces commentaires sont copiés dans les catalogues de messages de façon à
-      ce que les traducteurs les voient.
-     </para>
-    </listitem>
-   </itemizedlist>
-  </para>
-  </sect2>
- </sect1>
-
-</chapter>

Copied: traduc/tags/tv840rc1/nls.xml (from rev 1350, traduc/trunk/postgresql/nls.xml)
===================================================================
--- traduc/tags/tv840rc1/nls.xml	                        (rev 0)
+++ traduc/tags/tv840rc1/nls.xml	2009-06-23 16:25:46 UTC (rev 1351)
@@ -0,0 +1,533 @@
+<?xml version="1.0" encoding="ISO-8859-15"?>
+<!-- Dernière modification
+     le       $Date$
+     par      $Author$
+     révision $Revision$ -->
+
+<chapter id="nls">
+ <chapterinfo>
+  <author>
+   <firstname>Peter</firstname>
+   <surname>Eisentraut</surname>
+  </author>
+ </chapterinfo>
+
+ <title>Support natif des langues</title>
+
+ <sect1 id="nls-translator">
+  <title>Pour le traducteur</title>
+
+  <para>
+   Les programmes <productname>PostgreSQL</productname> (serveur et client) peuvent afficher
+   leur message dans la langue préférée de l'utilisateur &mdash; si les messages ont été traduits.
+   Créer et maintenir les ensembles de messages traduits nécessite l'aide de
+   personnes parlant leur propre langue et souhaitant contribuer à 
+   <productname>PostgreSQL</productname>. Il n'est nul besoin d'être un développeur
+   pour cela. Cette section explique comment apporter son aide.
+  </para>
+
+  <sect2>
+   <title>Prérequis</title>
+
+   <para>
+    Les compétences dans sa langue d'un traducteur ne seront pas jugées &mdash; cette
+    section concerne uniquement les outils logiciels. Théoriquement, seul un
+    éditeur de texte est nécessaire. Mais ceci n'est vrai que dans le cas très
+    improbable où un traducteur ne souhaiterait pas tester ses traductions des
+    messages. Lors de la configuration des sources, il faudra s'assurer d'utiliser l'option
+    <option>--enable-nls</option>. Ceci assurera également la présence de la
+    bibliothèque <application>libintl</application> et du programme
+    <filename>msgfmt</filename> dont tous les utilisateurs finaux ont indéniablement
+    besoin. Pour tester son travail, il sera utile de suivre les parties pertinentes
+    des instructions d'installation.
+   </para>
+
+   <para>
+    Pour commencer un nouvel effort de traduction ou pour faire un assemblage de
+    catalogues de messages (décrit ci-après), il faudra installer respectivement
+    les programmes <filename>xgettext</filename> et <filename>msgmerge</filename>
+    dans une implémentation compatible GNU. Il est prévu dans le futur que
+    <filename>xgettext</filename> ne soit plus nécessaire lorsqu'une distribution
+    empaquetée des sources est utilisée (en travaillant à partir du CVS, il
+    sera toujours utile). <application>GNU Gettext 0.10.36</application> ou ultérieure est
+     actuellement recommandé.
+   </para>
+
+   <para>
+    Toute implémentation locale de gettext devrait être disponible avec sa
+    propre documentation. Une partie en est certainement dupliquée dans ce qui suit
+    mais des détails complémentaires y sont certainement disponibles.
+   </para>
+  </sect2>
+
+  <sect2>
+   <title>Concepts</title>
+
+   <para>
+    Les couples de messages originaux (anglais) et de leurs (possibles)
+    traductions sont conservés dans les <firstterm>catalogues de
+    messages</firstterm>, un pour chaque programme (bien que des programmes liés
+    puissent partager un catalogue de messages) et pour chaque langue cible. Il
+    existe deux formats de fichiers pour les catalogues de messages&nbsp;: le
+    premier est le fichier <quote>PO</quote> (pour "Portable Object" ou Objet Portable), 
+    qui est un
+    fichier texte muni d'une syntaxe spéciale et que les traducteurs éditent. Le
+    second est un fichier <quote>MO</quote> (pour "Machine Object" ou Objet Machine), 
+    qui est un
+    fichier binaire engendré à partir du fichier PO respectif et qui est utilisé
+    lorsque le programme internationalisé est exécuté. Les traducteurs ne
+    s'occupent pas des fichiers MO&nbsp;; en fait, quasiment personne ne s'en occupe.
+   </para>
+
+   <para>
+    L'extension du fichier de catalogue de messages est, sans surprise, soit
+    <filename>.po</filename>, soit <filename>.mo</filename>. Le nom de base est
+    soit le nom du programme qu'il accompagne soit la langue utilisée dans le
+    fichier, suivant la situation. Ceci peut s'avérer être une source de
+    confusion. Des exemples sont <filename>psql.po</filename> (fichier PO pour
+    psql) ou <filename>fr.mo</filename> (fichier MO en français).
+   </para>
+
+   <para>
+    Le format du fichier PO est illustré ici&nbsp;:
+<programlisting># commentaire
+
+msgid "chaîne originale"
+msgstr "chaîne traduite"
+
+msgid "encore une originale"
+msgstr "encore une de traduite"
+"les chaînes peuvent être sur plusieurs lignes, comme ceci"
+
+...
+</programlisting>
+    Les chaînes msgid sont extraites des sources du programme. (Elles n'ont pas
+    besoin de l'être mais c'est le moyen le plus commun). Les lignes msgstr sont
+    initialement vides puis complétées avec les chaînes traduites. Les chaînes
+    peuvent contenir des caractères d'échappement de style C et peuvent être sur
+    plusieurs lignes comme le montre l'exemple ci-dessus (la ligne suivante
+    doit démarrer au début de la ligne).
+   </para>
+
+   <para>
+    Le caractère # introduit un commentaire. Si une espace fine suit 
+    immédiatement le caractère #, c'est qu'il s'agit là d'un commentaire maintenu par le 
+    traducteur. On trouve aussi des commentaires automatiques qui n'ont pas d'espace
+    fine suivant immédiatement le caractère #. Ils sont maintenus par les différents outils
+    qui opèrent sur les fichiers PO et ont pour but d'aider le traducteur.
+<programlisting>#. commentaire automatique
+#: fichier.c:1023
+#, drapeau, drapeau
+</programlisting>
+    Les commentaires du style #. sont extraits du fichier source où le message
+    est utilisé. Il est possible que le développeur ait ajouté des informations
+    pour le traducteur, telles que l'alignement attendu. Le commentaire #:
+    indique l'emplacement exact où le message est utilisé dans le source. Le
+    traducteur n'a pas besoin de regarder le source du programme, mais il peut
+    le faire s'il subsiste un doute sur l'exactitude d'une traduction. Le commentaire #,
+    contient des drapeaux décrivant le message d'une certaine façon. Il existe
+    actuellement deux drapeaux&nbsp;: <literal>fuzzy</literal> est positionné si le
+    message risque d'être rendu obsolète par des changements dans les
+    sources. Le traducteur peut alors vérifier ceci et supprimer ce drapeau.
+    Notez que les messages <quote>fuzzy</quote> ne sont pas accessibles à
+    l'utilisateur final. L'autre drapeau est <literal>c-format</literal>
+    indiquant que le message utilise le format de la fonction C
+    <function>printf</function>. Ceci signifie que la traduction devrait aussi
+    être de ce format avec le même nombre et le même type de paramètres fictifs. Il
+    existe des outils qui vérifient que le message est une chaîne au format
+    printf et valident le drapeau c-format en conséquence.
+<!-- which key off the c-format flags -->
+   </para>
+  </sect2>
+
+  <sect2>
+   <title>Créer et maintenir des catalogues de messages</title>
+
+   <para>
+    OK, alors comment faire pour créer un catalogue de messages
+    <quote>vide</quote>&nbsp;? Tout d'abord, se placer dans le répertoire contenant
+    le programme dont on souhaite traduire les messages. S'il existe un
+    fichier <filename>nls.mk</filename>, alors ce programme est préparé pour la
+    traduction.
+   </para>
+
+   <para>
+    S'il y a déjà des fichiers <filename>.po</filename>, alors quelqu'un a
+    déjà réalisé des travaux de traduction. Les fichiers sont nommés 
+    <filename><replaceable>langue</replaceable>.po</filename>, où
+    <replaceable>langue</replaceable> est le code de langue sur deux
+    caractères  (en minuscules) tel que défini par l'<ulink
+    url="http://lcweb.loc.gov/standards/iso639-2/englangn.html">
+    ISO 639-1, le code du pays composé de deux lettres en minuscule</ulink>,
+    c'est-à-dire <filename>fr.po</filename> pour
+    le français. S'il existe réellement un besoin pour plus d'une
+    traduction par langue, alors les fichiers peuvent être renommés
+    <filename><replaceable>langue</replaceable>_<replaceable>region</replaceable>.po</filename>
+    où <replaceable>region</replaceable> est le code de langue sur deux
+    caractères (en majuscules), tel que défini par l'<ulink
+    url="http://www.din.de/gremien/nas/nabd/iso3166ma/codlstp1/en_listp1.html">ISO 3166-1,
+    le code du payes sur deux lettres en majuscule</ulink>,
+    c'est-à-dire <filename>pt_BR.po</filename> pour le portugais du Brésil. Si vous
+    trouvez la langue que vous souhaitez, vous pouvez commencer à travailler
+    sur ce fichier.
+   </para>
+
+   <para>
+    Pour commencer une nouvelle traduction, il faudra préalablement exécuter la
+    commande&nbsp;:
+<programlisting>gmake init-po
+</programlisting>
+    Ceci créera un fichier
+    <filename><replaceable>nomprog</replaceable>.pot</filename>.
+    (<filename>.pot</filename> pour le distinguer des fichiers PO qui sont
+    <quote>en production</quote>. Le <literal>T</literal> signifie
+    <quote>template</quote> (NdT&nbsp;: modèle en anglais).
+    On copiera ce fichier sous le nom
+    <filename><replaceable>langue</replaceable>.po</filename>. On peut alors l'éditer.
+    Pour faire savoir qu'une nouvelle langue est disponible, il faut également éditer
+    le fichier <filename>nls.mk</filename> et y ajouter le code de la langue (ou de
+    la langue et du pays) avec une ligne ressemblant à ceci&nbsp;:
+<programlisting>AVAIL_LANGUAGES := de fr
+</programlisting>
+    (d'autres langues peuvent apparaître, bien entendu).
+   </para>
+
+   <para>
+    À mesure que le programme ou la bibliothèque change, des messages peuvent
+    être modifiés ou ajoutés par les développeurs. Dans ce cas, il n'est pas nécessaire
+    de tout recommencer depuis le début. À la place, on lancera la commande&nbsp;:
+<programlisting>gmake update-po
+</programlisting>
+    qui créera un nouveau catalogue de messages vides (le fichier pot avec
+    lequel la traduction a été initiée) et le fusionnera avec les fichiers PO existants.
+    Si l'algorithme de fusion a une incertitude sur un message particulier,
+    il le marquera <quote>fuzzy</quote> comme expliqué ci-dessus. Le nouveau
+    fichier PO est sauvegardé avec l'extension <filename>.po.new</filename>.
+   </para>
+  </sect2>
+
+  <sect2>
+   <title>Éditer les fichiers PO</title>
+
+   <para>
+    Les fichiers PO sont éditables avec un éditeur de texte standard. Le traducteur
+    doit seulement modifier l'emplacement entre les guillemets après la
+    directive msgstr, peut ajouter des commentaires et modifier le drapeau fuzzy
+    (NdA&nbsp;: Il existe, ce qui n'est pas surprenant, un mode PO pour Emacs, que je trouve assez
+    utile).
+   </para>
+
+   <para>
+    Les fichiers PO n'ont pas besoin d'être entièrement remplis. Le logiciel
+    retournera automatiquement à la chaîne originale si une traduction n'est pas
+    disponible ou est laissée vide. Soumettre des traductions incomplètes pour les
+    inclure dans l'arborescence des sources n'est pas un problème&nbsp;; cela permet à d'autres
+    personnes de récupérer le travail commencé pour le continuer. Néanmoins,
+    les traducteurs sont encouragés à donner une haute priorité à la suppression
+    des entrées fuzzy après avoir fait une fusion. Les entrées fuzzy ne
+    seront pas installées&nbsp;; elles servent seulement de référence à ce qui
+    pourrait être une bonne traduction.
+   </para>
+
+   <para>
+    Certaines choses sont à garder à l'esprit lors de l'édition des
+    traductions&nbsp;:
+    <itemizedlist>
+     <listitem>
+      <para>
+       S'assurer que si la chaîne originale se termine par un retour chariot, la
+       traduction le fasse bien aussi. De même pour les tabulations, etc.
+      </para>
+     </listitem>
+
+     <listitem>
+      <para>
+       Si la chaîne originale est une chaîne au format <function>printf</function>, la
+       traduction doit l'être aussi. La traduction doit également avoir les
+       même spécificateurs de format et dans le même ordre. Quelques fois, les
+       règles naturelles de la langue rendent cela impossible ou tout au moins
+       difficile. Dans ce cas, il est possible de modifier les spécificateurs de format
+       de la façon suivante&nbsp;:
+<programlisting>msgstr "Die Datei %2$s hat %1$u Zeichen."
+</programlisting>
+       Le premier paramètre fictif sera alors utilisé par le deuxième argument de la
+       liste. Le <literal><replaceable>chiffre</replaceable>$</literal> a
+       besoin de suivre immédiatement le %, avant tout autre manipulateur de
+       format (cette fonctionnalité existe réellement dans la famille des
+       fonctions <function>printf</function>, mais elle est peu connue, n'ayant
+       que peu d'utilité en dehors de l'internationalisation des messages).
+      </para>
+     </listitem>
+
+     <listitem>
+      <para>
+       Si la chaîne originale contient une erreur linguistique, on pourra la rapporter
+       (ou la corriger soi-même dans le source du programme) et la traduire
+       normalement. La chaîne corrigée peut être fusionnée lorsque les
+       programmes sources auront été mis à jour. Si la chaîne originale contient
+       une erreur factuelle, on la rapportera (ou la corrigera soi-même) mais on
+       ne la traduira pas. À la place, on marquera la chaîne avec un commentaire
+       dans le fichier PO.
+      </para>
+     </listitem>
+
+     <listitem>
+      <para>
+       Maintenir le style et le ton de la chaîne originale. En particulier, les
+       messages qui ne sont pas des phrases (<literal>cannot
+       open file %s</literal>, soit <literal>ne peut pas ouvrir le fichier
+       %s</literal>) ne devraient probablement pas commencer avec une lettre
+       capitale (si votre langue distingue la casse des lettres) ou finir avec
+       un point (si votre langue utilise des marques de ponctuation). Lire <xref
+       linkend="error-style-guide"/> peut aider.
+      </para>
+     </listitem>
+
+     <listitem>
+      <para>
+       Lorsque la signification d'un message n'est pas connue ou s'il est ambigü,
+       on pourra demander sa signification sur la liste de diffusion des développeurs.
+       Il est possible qu'un anglophone puisse aussi ne pas le comprendre ou le
+       trouver ambigü. Il est alors préférable d'améliorer le message.
+      </para>
+     </listitem>
+
+    </itemizedlist>
+   </para>
+  </sect2>
+
+ </sect1>
+
+
+ <sect1 id="nls-programmer">
+  <title>Pour le développeur</title>
+
+  <sect2 id="nls-mechanics">
+   <title>Mécaniques</title>
+
+  <para>
+   Cette section explique comment implémenter le support natif d'une langue dans
+   un programme ou dans une bibliothèque qui fait partie de la distribution
+   <productname>PostgreSQL</productname>. Actuellement, cela s'applique uniquement aux
+   programmes C.
+  </para>
+
+  <procedure>
+   <title>Ajouter le support NLS à un programme</title>
+
+   <step>
+    <para>
+     Le code suivant est inséré dans la séquence initiale du programme&nbsp;:
+<programlisting>#ifdef ENABLE_NLS
+#include &lt;locale.h&gt;
+#endif
+
+...
+
+#ifdef ENABLE_NLS
+setlocale(LC_ALL, "");
+bindtextdomain("<replaceable>nomprog</replaceable>", LOCALEDIR);
+textdomain("<replaceable>nomprog</replaceable>");
+#endif
+</programlisting>
+     (<replaceable>nomprog</replaceable> peut être choisi tout à fait librement).
+    </para>
+   </step>
+
+   <step>
+    <para>
+     Partout où un message candidat à la traduction est trouvé,
+     un appel à <function>gettext()</function> doit être inséré.
+     Par exemple&nbsp;:
+<programlisting>fprintf(stderr, "panic level %d\n", lvl);
+</programlisting>
+     devra être changé avec&nbsp;:
+<programlisting>fprintf(stderr, gettext("panic level %d\n"), lvl);
+</programlisting>
+     (<symbol>gettext</symbol> est défini comme une opération nulle si NLS
+     n'est pas configuré).
+    </para>
+
+    <para>
+     Cela peut engendrer du fouillis. Un raccourci habituel consiste à
+     utiliser&nbsp;:
+<programlisting>#define _(x) gettext(x)
+</programlisting>
+     Une autre solution est envisageable si le programme effectue la plupart de ses
+     communications via une fonction ou un nombre restreint de fonctions, telle
+     <function>ereport()</function> pour le moteur. Le fonctionnement interne de
+     cette fonction peut alors être modifiée pour qu'elle appelle
+     <function>gettext</function> pour toutes les chaînes en entrée.
+    </para>
+   </step>
+
+   <step>
+    <para>
+     Un fichier <filename>nls.mk</filename> est ajouté dans le répertoire des
+     sources du programme. Ce fichier sera lu comme un makefile. Les affectations
+     des variables suivantes doivent être réalisées ici&nbsp;:
+
+     <variablelist>
+      <varlistentry>
+       <term><varname>CATALOG_NAME</varname></term>
+
+       <listitem>
+        <para>
+         Le nom du programme tel que fourni lors de l'appel à
+         <function>textdomain()</function>.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term><varname>AVAIL_LANGUAGES</varname></term>
+
+       <listitem>
+        <para>
+         Liste des traductions fournies &mdash; initialement vide.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term><varname>GETTEXT_FILES</varname></term>
+
+       <listitem>
+        <para>
+         Liste des fichiers contenant les chaînes traduisibles, c'est-à-dire
+         celles marquées avec <function>gettext</function> ou avec une 
+         solution alternative. Il se peut que cette liste inclut pratiquement
+         tous les fichiers sources du programme. Si cette liste est trop longue,
+         le premier <quote>fichier</quote> peut être remplacé par un <literal>+</literal>
+         et le deuxième mot représenter un fichier contenant un nom de fichier par
+         ligne.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term><varname>GETTEXT_TRIGGERS</varname></term>
+
+       <listitem>
+        <para>
+         Les outils qui engendrent des catalogues de messages pour les
+         traducteurs ont besoin de connaître les appels de
+         fonction contenant des chaînes à traduire. Par défaut, seuls les appels
+         à <function>gettext()</function> sont reconnus. Si <function>_</function>
+         ou d'autres identifiants sont utilisés, il est nécessaire de les lister ici.
+         Si la chaîne traduisible n'est pas le premier argument,
+         l'élément a besoin d'être de la forme <literal>func:2</literal> (pour
+         le second argument).
+         Si vous avez une fonction qui supporte les messages au format pluriel,
+	 l'élément ressemblera à <literal>func:1,2</literal>
+         (identifiant les arguments singulier et pluriel du message).
+        </para>
+       </listitem>
+      </varlistentry>
+     </variablelist>
+    </para>
+   </step>
+
+  </procedure>
+
+  <para>
+   Le système de construction s'occupera automatiquement de construire et
+   installer les catalogues de messages.
+  </para>
+  </sect2>
+
+  <sect2 id="nls-guidelines">
+   <title>Guide d'écriture des messages</title>
+
+  <para>
+   Voici quelques lignes de conduite pour l'écriture de messages facilement
+   traduisibles.
+
+   <itemizedlist>
+    <listitem>
+     <para>
+      Ne pas construire de phrases à l'exécution, telles que&nbsp;:
+<programlisting>printf("Files were %s.\n", flag ? "copied" : "removed");
+</programlisting>
+      L'ordre des mots d'une phrase peut être différent dans d'autres langues.
+      De plus, même si <function>gettext()</function> est correctement appelé sur chaque fragment,
+      il pourrait être difficile de traduire séparément les fragments. Il est
+      préférable de dupliquer un peu de code de façon à ce que chaque message à
+      traduire forme un tout cohérent. Seuls les nombres, noms de fichiers et
+      autres variables d'exécution devraient être insérés au moment de
+      l'exécution dans le texte d'un message.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Pour des raisons similaires, ceci ne fonctionnera pas&nbsp;:
+<programlisting>printf("copied %d file%s", n, n!=1 ? "s" : "");
+</programlisting>
+      parce que cette forme présume de la façon dont la forme plurielle est obtenue.
+      L'idée de résoudre ce cas de la façon suivante&nbsp;:
+<programlisting>if (n==1)
+    printf("copied 1 file");
+else
+    printf("copied %d files", n):
+</programlisting>
+      sera source de déception. Certaines langues ont plus de deux formes avec
+      des règles particulières. Il est souvent préférable de concevoir le
+      message de façon à éviter le problème, par exemple ainsi&nbsp;:
+<programlisting>printf("number of copied files: %d", n);
+</programlisting>
+     </para>
+
+     <para>
+      Si vous voulez vraiment construire un message correctement pluralisé,
+      il existe un support pour cela, mais il est un peu étrange. Quand vous
+      générez un message d'erreur primaire ou détaillé dans
+      <function>ereport()</function>, vous pouvez écrire quelque-chose comme
+      ceci&nbsp;:
+<programlisting>
+errmsg_plural("copied %d file",
+              "copied %d files",
+              n,
+              n)
+</programlisting>
+      Le premier argument est le chaîne dans le format approprié pour la forme
+      au singulier en anglais, le second est le format de chaîne approprié pour
+      la forme plurielle en anglais, et le troisième est la valeur entière
+      déterminant la forme à utiliser. Des arguments additionnels sont formatés
+      suivant la chaîne de formatage comme d'habitude. (Habituellement, la
+      valeur de contrôle de la pluralisation sera aussi une des valeurs à
+      formater, donc elle sera écrite deux fois.) En anglais, cela n'importe
+      que si <replaceable>n</replaceable> est égale à 1 ou est différent de 1,
+      mais dans d'autres langues, il pourrait y avoir plusieurs formes de
+      pluriel. Le traducteur voit les deux formes anglaises comme un groupe
+      et a l'opportunité de fournir des chaînes de substitution supplémentaires,
+      la bonne étant sélectionnée suivant la valeur à l'exécution de
+      <replaceable>n</replaceable>.
+     </para>
+
+     <para>
+      Si vous avez besoin de pluraliser un message qui ne va pas directement à
+      <function>errmsg</function> ou <function>errdetail</function>, vous devez
+      utiliser la fonction sous-jacente <function>ngettext</function>. Voir la
+      documentation gettext.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Lorsque quelque chose doit être communiqué au traducteur, telle que la façon
+      dont un message doit être aligné avec quelque autre sortie, on pourra faire
+      précéder l'occurrence de la chaîne d'un commentaire commençant par
+      <literal>translator</literal>, par exemple&nbsp;:
+<programlisting>/* translator: This message is not what it seems to be. */
+</programlisting>
+      Ces commentaires sont copiés dans les catalogues de messages de façon à
+      ce que les traducteurs les voient.
+     </para>
+    </listitem>
+   </itemizedlist>
+  </para>
+  </sect2>
+ </sect1>
+
+</chapter>

Deleted: traduc/tags/tv840rc1/xfunc.xml
===================================================================
--- traduc/trunk/postgresql/xfunc.xml	2009-06-22 07:28:54 UTC (rev 1349)
+++ traduc/tags/tv840rc1/xfunc.xml	2009-06-23 16:25:46 UTC (rev 1351)
@@ -1,3268 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-15"?>
-<!-- Dernière modification
-     le       $Date$
-     par      $Author$
-     révision $Revision$ -->
-
- <sect1 id="xfunc">
-  <title>Fonctions utilisateur</title>
-
-  <indexterm zone="xfunc">
-   <primary>fonction</primary>
-   <secondary>utilisateur</secondary>
-  </indexterm>
-
-  <para>
-   <productname>PostgreSQL</productname> propose quatre types de
-    fonctions&nbsp;:
-
-   <itemizedlist>
-    <listitem>
-     <para>
-      fonctions en langage de requête (fonctions écrites en <acronym>SQL</acronym>,
-      <xref linkend="xfunc-sql"/>)
-     </para>
-    </listitem>
-    <listitem>
-     <para>
-      fonctions en langage procédural (fonctions écrites, par exemple, en
-      <application>PL/pgSQL</application> ou <application>PL/Tcl</application>,
-      <xref linkend="xfunc-pl"/>)
-     </para>
-    </listitem>
-    <listitem>
-     <para>
-      fonctions internes (<xref linkend="xfunc-internal"/>)
-     </para>
-    </listitem>
-    <listitem>
-     <para>
-      fonctions en langage C (<xref linkend="xfunc-c"/>)
-     </para>
-    </listitem>
-   </itemizedlist>
-  </para>
-
-  <para>
-   Chaque type de fonction peut accepter comme arguments (paramètres) des types
-   de base, des types composites ou une combinaison de ceux-ci. De plus, chaque
-   sorte de fonction peut renvoyer un type de base ou un type composite. Les
-   fonctions pourraient aussi être définies pour renvoyer des ensembles de valeurs
-   de base ou de valeurs composites.
-  </para>
-
-  <para>
-   De nombreuses sortes de fonctions peuvent accepter ou renvoyer certains
-   pseudo-types (comme les types polymorphes) mais avec des fonctionnalités
-   variées.
-   Consultez la description de chaque type de fonction pour plus de détails.
-  </para>
-
-  <para>
-   Il est plus facile de définir des fonctions <acronym>SQL</acronym> aussi
-   allons-nous commencer par celles-ci. La plupart des concepts présentés pour
-   les fonctions <acronym>SQL</acronym> seront aussi gérés par les autres types
-   de fonctions.
-  </para>
-
-  <para>
-   Lors de  la lecture de ce chapitre, il peut être utile de consulter la page
-   de référence de la commande <xref linkend="sql-createfunction"
-   endterm="sql-createfunction-title"/> pour mieux
-   comprendre les exemples. Quelques exemples extraits de ce chapitre peuvent 
-   être trouvés dans les fichiers <filename>funcs.sql</filename> et
-   <filename>funcs.c</filename> du répertoire du tutoriel de la distribution
-   source de <productname>PostgreSQL</productname>.
-  </para>
-
-  </sect1>
-
-  <sect1 id="xfunc-sql">
-   <title>Fonctions en langage de requêtes (<acronym>SQL</acronym>)</title>
-
-   <indexterm zone="xfunc-sql">
-    <primary>fonction</primary>
-    <secondary>définie par l'utilisateur</secondary>
-    <tertiary>en SQL</tertiary>
-   </indexterm>
-
-   <para>
-    Les fonctions SQL exécutent une liste arbitraire d'instructions SQL et
-    renvoient le résultat de la dernière requête de cette liste. Dans le cas
-    d'un résultat simple (pas d'ensemble), la première ligne du résultat de la
-    dernière requête sera renvoyée (gardez à l'esprit que <quote>la première
-    ligne</quote> d'un résultat multiligne n'est pas bien définie à moins
-    d'utiliser <literal>ORDER BY</literal>). Si la dernière requête de la liste ne
-    renvoie aucune ligne, la valeur NULL est renvoyée.
-   </para>
-
-   <para>
-    Une fonction SQL peut être déclarée de façon à renvoyer un ensemble (set)
-    en spécifiant le type renvoyé par la fonction comme <literal>SETOF
-    <replaceable>un_type</replaceable></literal>, ou de façon équivalente en
-    la déclarant comme  <literal>RETURNS
-    TABLE(<replaceable>colonnes</replaceable>)</literal>. Dans ce
-    cas, toutes les lignes de la dernière requête sont renvoyées. Des détails
-    supplémentaires sont donnés plus loin dans ce chapitre.
-   </para>
-
-   <para>
-    Le corps d'une fonction SQL doit être constitué d'une liste d'une ou
-    de plusieurs instructions SQL séparées par des points-virgule. Un
-    point-virgule après la dernière instruction est optionnel. Sauf si la
-    fonction déclare renvoyer <type>void</type>, la dernière instruction doit
-    être un <command>SELECT</command> ou un <command>INSERT</command>,
-    <command>UPDATE</command> ou un <command>DELETE</command> qui a une clause
-    <literal>RETURNING</literal>.
-   </para>
-
-   <para>
-    Toute collection de commandes dans le langage <acronym>SQL</acronym> peut
-    être assemblée et définie comme une fonction. En plus des requêtes
-    <command>SELECT</command>, les commandes peuvent inclure des requêtes de
-    modification des données (<command>INSERT</command>,
-    <command>UPDATE</command> et <command>DELETE</command>) ainsi que
-    d'autres commandes SQL (la seule exception est que vous ne pouvez pas
-    placer de commandes <command>BEGIN</command>, <command>COMMIT</command>,
-    <command>ROLLBACK</command> ou <command>SAVEPOINT</command> dans une fonction
-    <acronym>SQL</acronym>). Néanmoins, la commande finale doit être un
-    <command>SELECT</command> ou doit avoir une clause <literal>RETURNING</literal>
-    qui renvoie ce qui a été spécifié comme type
-    de retour de la fonction. Autrement, si vous voulez définir une fonction
-    SQL qui réalise des actions mais n'a pas de valeur utile à renvoyer,
-    vous pouvez la définir comme renvoyant <type>void</type>. Par exemple, cette fonction supprime les 
-    lignes avec des salaires négatifs depuis la table <literal>emp</literal>&nbsp;:
-
-<screen>CREATE FUNCTION nettoie_emp() RETURNS void AS '
-    DELETE FROM emp WHERE salaire &lt; 0;
-' LANGUAGE SQL;
-  
-SELECT nettoie_emp();
-
-  nettoie_emp
-  -----------
-
-  (1 row)
-</screen>
-   </para>
-
-   <para>
-    La syntaxe de la commande <command>CREATE FUNCTION</command> 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 <xref linkend="sql-syntax-dollar-quoting"/>) pour cette constante.
-    Si vous choisissez d'utiliser la syntaxe habituelle avec des guillemets
-    simples, vous devez doubler les marques de guillemet simple
-    (<literal>'</literal>) et les antislashs (<literal>\</literal>), en supposant
-    que vous utilisez la syntaxe d'échappement de chaînes, utilisés dans le corps
-    de la fonction (voir la <xref linkend="sql-syntax-strings"/>).
-   </para>
-
-   <para>
-   Les arguments de la fonction SQL sont référencés dans le corps de la
-   fonction en utilisant la syntaxe suivante.
-   <literal>$<replaceable>n</replaceable></literal>:<literal>$1</literal> se réfère au premier argument,
-   <literal>$2</literal> au second et ainsi de suite. Si un argument est de type
-   composite, on utilisera la notation par point, par exemple
-   <literal>$1.name</literal>, pour accéder aux attributs de l'argument.
-   Les arguments peuvent seulement être utilisés comme valeurs des données, pas
-   comme des identifieurs. Du coup, par exemple, ceci est correct&nbsp;:
-<programlisting>INSERT INTO matable VALUES ($1);
-</programlisting>
-   mais ceci ne fonctionnera pas&nbsp;:
-<programlisting>INSERT INTO $1 VALUES (42);
-</programlisting>
-   </para>
-
-   <sect2 id="xfunc-sql-base-functions">
-    <title>Fonctions <acronym>SQL</acronym> sur les types de base</title>
-
-    <para>
-    La fonction <acronym>SQL</acronym> la plus simple possible n'a pas
-    d'argument et retourne un type de base tel que <type>integer</type>&nbsp;:
-<screen>CREATE FUNCTION un() RETURNS integer AS $$
-    SELECT 1 AS resultat;
-$$ LANGUAGE SQL;
-
--- Autre syntaxe pour les chaînes littérales :
-CREATE FUNCTION un() RETURNS integer AS '
-    SELECT 1 AS resultat;
-' LANGUAGE SQL;
-
-SELECT un();
-
- un
-----
-  1
-</screen>
-    </para>
-
-    <para>
-    Notez que nous avons défini un alias de colonne avec le nom
-    <literal>resultat</literal> dans le corps de la fonction pour se référer au
-    résultat de la fonction mais cet alias n'est pas visible hors de la
-    fonction. En effet, le résultat est nommé <literal>un</literal> au lieu de
-    <literal>resultat</literal>.
-    </para>
-
-    <para>
-    Il est presque aussi facile de définir des fonctions SQL acceptant des types
-    de base comme arguments. Dans l'exemple suivant, remarquez comment nous
-    faisons référence aux arguments dans le corps de la fonction avec  
-    <literal>$1</literal> et <literal>$2</literal>.
-
-<screen>CREATE FUNCTION ajoute(integer, integer) RETURNS integer AS $$
-    SELECT $1 + $2;
-$$ LANGUAGE SQL;
-
-SELECT ajoute(1, 2) AS reponse;
-
- reponse
----------
-      3
-</screen>
-    </para>
-
-    <para>
-    Voici une fonction plus utile, qui pourrait être utilisée pour débiter un
-    compte bancaire&nbsp;:
-
-<programlisting>CREATE FUNCTION tf1 (integer, numeric) RETURNS integer AS $$
-    UPDATE banque
-        SET balance = balance - $2
-        WHERE no_compte = $1;
-    SELECT 1;
-$$ LANGUAGE SQL;
-</programlisting>
-
-    Un utilisateur pourrait exécuter cette fonction pour débiter le compte 17 de
-    100&nbsp;000&nbsp;euros ainsi&nbsp;:
-<programlisting>SELECT tf1(17, 100.000);</programlisting>
-    </para>
-    
-    <para>
-    Dans la pratique, on préférera vraisemblablement un résultat plus utile que
-    la constante 1. Une définition plus probable est&nbsp;:
-
-<programlisting>CREATE FUNCTION tf1 (integer, numeric) RETURNS numeric AS $$
-    UPDATE banque
-        SET balance = balance - $2
-        WHERE no_compte = $1;
-    SELECT balance FROM banque WHERE no_compte = $1;
-$$ LANGUAGE SQL;
-</programlisting>
-
-     qui ajuste le solde et renvoie sa nouvelle valeur.
-     La même chose peut se faire en une commande en utilisant la clause
-     <literal>RETURNING</literal>&nbsp;:
-
-<programlisting>
-CREATE FUNCTION tf1 (integer, numeric) RETURNS numeric AS $$
-    UPDATE banque
-        SET balance = balance - $2
-        WHERE no_compte = $1
-    RETURNING balance;
-$$ LANGUAGE SQL;
-</programlisting>
-    </para>
-
-   </sect2>
-
-   <sect2>
-    <title>Fonctions <acronym>SQL</acronym> sur les types composites</title>
-
-    <para>
-    Quand nous écrivons une fonction avec des arguments de type composite,
-    nous devons non seulement spécifier l'argument utilisé (comme nous
-    l'avons fait précédemment avec <literal>$1</literal> et <literal>$2</literal>),
-    mais aussi spécifier l'attribut désiré de cet argument (champ). Par
-    exemple, supposons que 
-    <type>emp</type> soit le nom d'une table contenant des données sur les
-    employés et donc également le nom du type composite correspondant à chaque
-    ligne de la table. Voici une fonction <function>double_salaire</function>
-    qui calcule ce que serait le salaire de quelqu'un s'il était doublé&nbsp;:
-
-<screen>CREATE TABLE emp (
-    nom         text,
-    salaire     numeric,
-    age         integer,
-    cubicle     point
-);
-
-CREATE FUNCTION double_salaire(emp) RETURNS numeric AS $$
-    SELECT $1.salaire * 2 AS salaire;
-$$ LANGUAGE SQL;
-
-SELECT nom, double_salaire(emp.*) AS reve
-    FROM emp
-    WHERE emp.cubicle ~= point '(2,1)';
-
- name | reve
-------+-------
- Bill |  8400
-</screen>
-    </para>
-
-    <para>
-     Notez l'utilisation de la syntaxe <literal>$1.salaire</literal> pour
-     sélectionner un champ dans la valeur de la ligne argument. Notez également
-     comment la commande <command>SELECT</command> utilise <literal>*</literal> pour
-     sélectionner la ligne courante entière de la table comme une valeur composite
-     (<literal>emp</literal>). La ligne de la table peut aussi être référencée en
-     utilisant seulement le nom de la table ainsi&nbsp;:
-<screen>SELECT nom, double_salaire(emp) AS reve
-    FROM emp
-    WHERE emp.cubicle ~= point '(2,1)';
-</screen>
-     mais cette utilisation est obsolète car elle est facilement obscure.
-    </para>
-
-    <para>
-	 Quelque fois, il est pratique de construire une valeur d'argument
-	 composite en direct. Ceci peut se faire avec la construction 
-	 <literal>ROW</literal>. Par exemple, nous pouvons ajuster les données passées
-	 à la fonction&nbsp;:
-<screen>SELECT nom, double_salaire(ROW(nom, salaire*1.1, age, cubicle)) AS reve
-	FROM emp;
-</screen>
-    </para>
-
-    <para>
-    Il est aussi possible de construire une fonction qui renvoie un type
-    composite. Voici un exemple de fonction renvoyant une seule ligne de type
-    <type>emp</type>&nbsp;:
-
-<programlisting>CREATE FUNCTION nouvel_emp() RETURNS emp AS $$
-    SELECT text 'Aucun' AS nom,
-        1000.0 AS salaire,
-        25 AS age,
-        point '(2,2)' AS cubicle;
-$$ LANGUAGE SQL;
-</programlisting>
-
-    Dans cet exemple, nous avons spécifié chacun des attributs avec une valeur
-    constante, mais un quelconque calcul aurait pu être substitué à ces
-    valeurs. 
-    </para>
-
-    <para>
-    Notez deux aspects importants à propos de la définition de fonction&nbsp;:
-
-     <itemizedlist>
-      <listitem>
-       <para>
-       L'ordre de la liste du SELECT doit être exactement le même que celui
-       dans lequel les colonnes apparaissent dans la table associée au type
-       composite (donner des noms aux colonnes dans le corps de la fonction,
-       comme nous l'avons 
-       fait dans l'exemple, n'a aucune interaction avec le système).
-       </para>
-      </listitem>
-      <listitem>
-       <para>
-	Vous devez transtyper les expressions pour concorder avec la définition
-       du type composite ou bien vous aurez l'erreur suivante&nbsp;:
-<screen><computeroutput>ERROR:  function declared to return emp returns varchar instead of text at column 1</computeroutput></screen>
-       </para>
-      </listitem>
-     </itemizedlist>
-    </para>     
-
-    <para>
-      Un autre façon de définir la même fonction est&nbsp;:
-
-      <programlisting>CREATE FUNCTION nouveau_emp() RETURNS emp AS $$
-    SELECT ROW('Aucun', 1000.0, 25, '(2,2)')::emp;
-$$ LANGUAGE SQL;</programlisting>
-
-      Ici, nous écrivons un <command>SELECT</command> qui renvoie seulement une
-      colonne du bon type composite. Ceci n'est pas vraiment meilleur dans
-      cette situation mais c'est une alternative pratique dans certains cas
-      &mdash; par exemple, si nous avons besoin de calculer le résultat en
-      appelant une autre fonction qui renvoie la valeur composite désirée.
-    </para>     
-
-    <para>
-      Nous pourrions appeler cette fonction directement de deux façons&nbsp;:
-
-  <screen>SELECT nouveau_emp();
-
-        nouveau_emp
---------------------------
- (None,1000.0,25,"(2,2)")
-
-SELECT * FROM nouveau_emp();
-
-  nom  | salaire | age | cubicle
--------+---------+-----+---------
- Aucun |  1000.0 |  25 | (2,2)
-  </screen>
-
-      La deuxième façon est décrite plus complètement dans la <xref
-      linkend="xfunc-sql-table-functions"/>.
-  </para>
-
-  <para>
-    Quand vous utilisez une fonction qui renvoie un type composite, vous
-    pourriez vouloir seulement un champ (attribut) depuis ce résultat. Vous
-    pouvez le faire avec cette syntaxe&nbsp;:
-
-<screen>SELECT (nouveau_emp()).nom;
-
- nom
-------
- None
-</screen>
-
-    Les parenthèses supplémentaires sont nécessaires pour éviter une erreur de
-    l'analyseur. Si vous essayez de le faire sans, vous obtiendrez quelque chose
-    comme ceci&nbsp;:
-    <screen>SELECT nouveau_emp().nom;
-ERROR:  syntax error at or near "."
-LINE 1: SELECT nouveau_emp().nom;
-                            ^
-</screen>
-    </para>
-
-    <para>
-    Une autre option est d'utiliser la notation fonctionnelle pour extraire un
-    attribut. Une manière simple d'expliquer cela est de dire que nous pouvons
-    échanger les notations <literal>attribut(table)</literal> et
-    <literal>table.attribut</literal>.
-
-<screen>SELECT nom(nouveau_emp());
-
- name
-------
- None
-</screen>
-
-<screen>-- C'est la même chose que
--- SELECT emp.nom AS leplusjeune FROM emp WHERE emp.age &lt; 30;
-
-SELECT nom(emp) AS leplusjeune FROM emp WHERE age(emp) &lt; 30;
-
- leplusjeune
--------------
- Sam
- Andy
-</screen>
-    </para>
-
-    <tip>
-    <para>
-     L'équivalence entre la notation fonctionnelle et la notation d'attribut
-     rend possible l'utilisation de fonctions sur des types composites pour
-     émuler les <quote>champs calculés</quote>.
-     <indexterm>
-      <primary>champ calculé</primary>
-     </indexterm>
-     <indexterm>
-      <primary>field</primary>
-      <secondary>computed</secondary>
-     </indexterm>
-     Par exemple, en utilisant la définition précédente pour
-     <literal>double_salaire(emp)</literal>, nous pouvons écrire
-<screen>SELECT emp.nom, emp.double_salaire FROM emp;
-</screen>
-
-     Une application utilisant ceci n'aurait pas besoin d'être consciente
-     directement que <literal>double_salaire</literal> n'est pas une vraie colonne
-     de la table (vous pouvez aussi émuler les champs calculés avec des
-     vues).
-    </para>
-    </tip>
-
-    <para>
-     Une autre façon d'utiliser une fonction renvoyant un type composite est
-     de l'appeler comme une fonction de table, comme décrit dans la <xref
-     linkend="xfunc-sql-table-functions"/>.
-    </para>
-   </sect2>
-
-   <sect2 id="xfunc-output-parameters">
-    <title>Fonctions <acronym>SQL</acronym> avec des paramètres en sortie</title>
-
-   <indexterm>
-    <primary>fonction</primary>
-    <secondary>paramètre en sortie</secondary>
-   </indexterm>
-
-    <para>
-     Une autre façon de décrire les résultats d'une fonction est de la
-     définir avec des <firstterm>paramètres en sortie</firstterm> comme dans cet
-     exemple&nbsp;:
-
-<screen>CREATE FUNCTION ajoute (IN x int, IN y int, OUT sum int)
-AS 'SELECT $1 + $2'
-LANGUAGE SQL;
-
-SELECT ajoute(3,7);
- ajoute
---------
-     10
-(1 row)
-</screen>
-
-     Ceci n'est pas vraiment différent de la version d'<literal>ajoute</literal>
-     montrée dans la <xref linkend="xfunc-sql-base-functions"/>. La vraie valeur
-     des paramètres en sortie est qu'ils fournissent une façon agréable de
-     définir des fonctions qui renvoient plusieurs colonnes. Par exemple,
-
-<screen>CREATE FUNCTION ajoute_n_produit (x int, y int, OUT sum int, OUT product int)
-AS 'SELECT $1 + $2, $1 * $2'
-LANGUAGE SQL;
-
- SELECT * FROM sum_n_product(11,42);
- sum | product
------+---------
-  53 |     462
-(1 row)
-</screen>
-
-     Ce qui est arrivé ici est que nous avons créé un type composite anonyme
-     pour le résultat de la fonction. L'exemple ci-dessus a le même résultat
-     final que
-
-<screen>CREATE TYPE produit_ajoute AS (somme int, produit int);
-
-CREATE FUNCTION ajoute_n_produit (int, int) RETURNS produit_ajoute
-AS 'SELECT $1 + $2, $1 * $2'
-LANGUAGE SQL;
-</screen>
-
-     mais ne pas avoir à s'embêter avec la définition séparée du type
-     composite est souvent agréable.
-    </para>
-
-    <para>
-     Notez que les paramètres en sortie ne sont pas inclus dans la liste
-     d'arguments lors de l'appel d'une fonction de ce type en SQL. Ceci
-     parce que <productname>PostgreSQL</productname> considère seulement les
-     paramètres en entrée pour définir la signature d'appel de la fonction.
-     Cela signifie aussi que seuls les paramètres en entrée sont importants
-     lors de références de la fonction pour des buts comme sa suppression.
-     Nous pouvons supprimer la fonction ci-dessus avec l'un des deux appels
-     ci-dessous&nbsp;:
-
-<screen>DROP FUNCTION ajoute_n_produit (x int, y int, OUT somme int, OUT produit int);
-DROP FUNCTION ajoute_n_produit (int, int);
-</screen>
-    </para>
-
-    <para>
-     Les paramètres peuvent être marqués comme <literal>IN</literal> (par défaut),
-     <literal>OUT</literal> ou <literal>INOUT</literal> ou
-     <literal>VARIADIC</literal>.
-     Un paramètre <literal>INOUT</literal>
-     sert à la fois de paramètre en entrée (il fait partie de la liste
-     d'arguments en appel) et comme paramètre de sortie (il fait partie du
-     type d'enregistrement résultat).
-     <literal>VARIADIC</literal> parameters are input parameters, but are treated
-     specially as described next.
-    </para>
-   </sect2>
-
-   <sect2 id="xfunc-sql-variadic-functions">
-    <title>Fonctions <acronym>SQL</acronym> avec un nombre variables d'arguments</title>
-
-    <indexterm>
-     <primary>fonction</primary>
-     <secondary>variadic</secondary>
-    </indexterm>
-
-    <indexterm>
-     <primary>fonction variadic</primary>
-    </indexterm>
-
-    <para>
-     Les fonctions <acronym>SQL</acronym> peuvent accepter un nombre variable
-     d'arguments à condition que tous les arguments <quote>optionnels</quote>
-     sont du même type. Les arguments optionnels seront passés à la fonction
-     sous forme d'un tableau. La fonction est déclarée en marquant le dernier
-     paramètre comme <literal>VARIADIC</literal>&nbsp;; ce paramètre doit être
-     déclaré de type tableau. Par exemple&nbsp;:
-
-<screen>
-CREATE FUNCTION mleast(VARIADIC numeric[]) RETURNS numeric AS $$
-    SELECT min($1[i]) FROM generate_subscripts($1, 1) g(i);
-$$ LANGUAGE SQL;
-
-SELECT mleast(10, -1, 5, 4.4);
- mleast 
---------
-     -1
-(1 row)
-</screen>
-
-     En fait, tous les arguments à la position ou après la position de
-     l'argument <literal>VARIADIC</literal> sont emballés dans un tableau à
-     une dimension, comme si vous aviez écrit
-
-<screen>
-SELECT mleast(ARRAY[10, -1, 5, 4.4]);    -- doesn't work
-</screen>
-
-     Vous ne pouvez pas vraiment écrire cela, ou tout du moins cela ne
-     correspondra pas à la définition de la fonction. Un paramètre marqué
-     <literal>VARIADIC</literal> correspond à une ou plusieurs occurrences
-     de son type d'élément, et non pas de son propre type.
-    </para>
-
-    <para>
-     Sometimes it is useful to be able to pass an already-constructed array
-     to a variadic function; this is particularly handy when one variadic
-     function wants to pass on its array parameter to another one.  You can
-     do that by specifying <literal>VARIADIC</literal> in the call:
-
-<screen>
-SELECT mleast(VARIADIC ARRAY[10, -1, 5, 4.4]);
-</screen>
-
-     This prevents expansion of the function's variadic parameter into its
-     element type, thereby allowing the array argument value to match
-     normally.  <literal>VARIADIC</literal> can only be attached to the last
-     actual argument of a function call.
-    </para>
-   </sect2>
-
-   <sect2 id="xfunc-sql-parameter-defaults">
-    <title>Fonctions SQL <acronym>SQL</acronym> avec des valeurs par défaut
-     pour les arguments</title>
-
-    <indexterm>
-     <primary>fonction</primary>
-     <secondary>valeurs par défaut pour les arguments</secondary>
-    </indexterm>
-
-    <para>
-     Les fonctions peuvent être déclarées avec des valeurs par défaut pour
-     certains des paramètres en entrée ou pour tous. Les valeurs par défaut
-     sont insérées quand la fonction est appelée avec moins d'arguments que
-     à priori nécessaires. Comme les arguments peuvent seulement être omis
-     à partir de la fin de la liste des arguments, tous les paramètres après
-     un paramètres disposant d'une valeur par défaut disposeront eux-aussi
-     d'une valeur par défaut.
-    </para>
-
-    <para>
-     Par exemple&nbsp;:
-<screen>
-CREATE FUNCTION foo(a int, b int DEFAULT 2, c int DEFAULT 3)
-RETURNS int
-LANGUAGE SQL
-AS $$
-    SELECT $1 + $2 + $3;
-$$;
-
-SELECT foo(10, 20, 30);
- foo 
------
-  60
-(1 row)
-
-SELECT foo(10, 20);
- foo 
------
-  33
-(1 row)
-
-SELECT foo(10);
- foo 
------
-  15
-(1 row)
-
-SELECT foo();  -- échec car il n'y a pas de valeur par défaut pour le premier argument
-ERROR:  function foo() does not exist
-</screen>
-     Le signe <literal>=</literal> peut aussi être utilisé à la place du mot clé
-     <literal>DEFAULT</literal>,
-    </para>
-   </sect2>
-
-   <sect2 id="xfunc-sql-table-functions">
-    <title>Fonctions <acronym>SQL</acronym> comme sources de table</title>
-
-    <para>
-    Toutes les fonctions SQL peuvent être utilisées dans la clause
-    <literal>FROM</literal> d'une requête mais ceci est particulièrement utile pour les
-    fonctions renvoyant des types composite. Si la fonction est définie pour
-    renvoyer un type de base, la fonction table produit une table d'une seule
-    colonne. Si la fonction est définie pour renvoyer un type composite, la
-    fonction  table produit une colonne pour chaque attribut du type composite.
-   </para>
-
-    <para>
-     Voici un exemple&nbsp;:
-
-<screen>CREATE TABLE foo (fooid int, foosousid int, foonom text);
-INSERT INTO foo VALUES (1, 1, 'Joe');
-INSERT INTO foo VALUES (1, 2, 'Ed');
-INSERT INTO foo VALUES (2, 1, 'Mary');
-
-CREATE FUNCTION recupfoo(int) RETURNS foo AS $$
-    SELECT * FROM foo WHERE fooid = $1;
-$$ LANGUAGE SQL;
-
-SELECT *, upper(foonom) FROM recupfoo(1) AS t1;
-
- fooid | foosubid | foonom | upper
--------+----------+--------+-------
-     1 |        1 | Joe    | JOE
-(1 row)
-</screen>
-
-    Comme le montre cet exemple, nous pouvons travailler avec les colonnes du
-    résultat de la fonction comme s'il s'agissait des colonnes d'une table
-    normale.
-</para>
-
-    <para>
-    Notez que nous n'obtenons qu'une ligne comme résultat de la fonction. Ceci
-    parce que nous n'avons pas utilisé l'instruction <literal>SETOF</literal>. Cette
-    instruction est décrite dans la prochaine section.
-    </para>
-   </sect2>
-
-   <sect2 id="xfunc-sql-functions-returning-set">
-    <title>Fonctions <acronym>SQL</acronym> renvoyant un ensemble </title>
-
-    <indexterm>
-     <primary>fonction</primary>
-     <secondary>avec SETOF</secondary>
-    </indexterm>
-
-    <para>
-     Quand une fonction SQL est déclarée renvoyer un <literal>SETOF
-     <replaceable>un_type</replaceable></literal>, la requête finale de
-     la fonction est complètement exécutée et chaque ligne extraite est renvoyée
-     en tant qu'élément de l'ensemble résultat.
-    </para>
-    
-    <para>
-     Cette caractéristique est normalement utilisée lors de l'appel d'une
-     fonction dans une clause <literal>FROM</literal>. Dans ce cas, chaque ligne
-     renvoyée par la fonction devient une ligne de la table vue par la requête.
-     Par exemple, supposons que la table <literal>foo</literal> ait le même contenu que
-     précédemment et écrivons&nbsp;:
-
-<programlisting>CREATE FUNCTION recupfoo(int) RETURNS SETOF foo AS $$
-    SELECT * FROM foo WHERE fooid = $1;
-$$ LANGUAGE SQL;
-
-SELECT * FROM recupfoo(1) AS t1;
-</programlisting>
-
-     Alors nous obtenons&nbsp;:
-<screen> fooid | foosousid | foonom
--------+-----------+--------
-     1 |         1 | Joe
-     1 |         2 | Ed
-(2 rows)
-</screen>
-    </para>
-
-    <para>
-     Il est aussi possible de renvoyer plusieurs lignes avec les colonnes
-     définies par des paramètres en sortie, comme ceci&nbsp;:
-
-<programlisting>
-CREATE FUNCTION sum_n_product_with_tab (x int, OUT sum int, OUT product int) RETURNS SETOF record AS $$
-    SELECT $1 + tab.y, tab.y * tab.y FROM tab;
-$$ LANGUAGE SQL;
-</programlisting>
-
-     Le point clé ici est que vous devez écrire <literal>RETURNS SETOF
-     record</literal> pour indiquer que la fonction renvoie plusieurs lignes
-     et non pas une seule. S'il n'y a qu'un paramètre en sortie, indiquez le
-     type de paramètre plutôt que <type>record</type>.
-    </para>
-
-    <para>
-     Actuellement, les fonctions renvoyant des ensembles peuvent aussi être
-     appelées dans la liste du select d'une requête. Pour chaque ligne générée
-     par la requête, la fonction renvoyant un ensemble est appelée et une ligne
-     est générée pour chaque élément de l'ensemble résultat. Notez cependant que
-     cette fonctionnalité est déconseillée et pourra être supprimée dans une
-     version future. Voici un exemple de fonction renvoyant un ensemble à
-     partir de la liste d'un SELECT&nbsp;:
-
-<screen>CREATE FUNCTION listeenfant(text) RETURNS SETOF text AS $$
-    SELECT nom FROM noeuds WHERE parent = $1
-$$ LANGUAGE SQL;
-
-SELECT * FROM noeuds;
-   nom        | parent
---------------+--------
- Haut         |
- Enfant1      | Haut
- Enfant2      | Haut
- Enfant3      | Haut
- Sous-Enfant1 | Enfant1
- Sous-Enfant2 | Enfant1
-(6 rows)
-
-SELECT listeenfant('Haut');
- listeenfant
---------------
- Enfant1
- Enfant2
- Enfant3
-(3 rows)
-
-SELECT nom, listeenfant(nom) FROM noeuds;
-  nom    | listeenfant
----------+--------------
- Haut    | Enfant1
- Haut    | Enfant2
- Haut    | Enfant3
- Enfant1 | Sous-Enfant1
- Enfant1 | Sous-Enfant2
-(5 rows)
-</screen>
-
-     Notez, dans le dernier <command>SELECT</command>, qu'aucune ligne n'est
-     renvoyée pour <literal>Enfant2</literal>, <literal>Enfant3</literal>, etc. C'est parce
-     que la fonction <function>listeenfant</function> renvoie un ensemble vide
-     pour ces arguments et ainsi aucune ligne n'est générée.
-    </para>
-
-    <note>
-     <para>
-      Si la dernière commande d'une fonction est <command>INSERT</command>,
-      <command>UPDATE</command> ou <command>DELETE</command> avec une clause
-      <literal>RETURNING</literal>, cette commande sera toujours exécutée
-      jusqu'à sa fin, même si la fonction n'est pas déclarée avec
-      <literal>SETOF</literal> ou que la requête appelante ne renvoie pas toutes
-      les lignes résultats. Toutes les lignes supplémentaires produites par la
-      clause <literal>RETURNING</literal> sont silencieusement abandonnées mais
-      les modifications de table sont pris en compte (et sont toutes terminées
-      avant que la fonction ne se termine).
-     </para>
-    </note>
-   </sect2>
-
-   <sect2 id="xfunc-sql-functions-returning-table">
-    <title>Fonctions <acronym>SQL</acronym> renvoyant <literal>TABLE</literal></title>
-
-    <indexterm>
-     <primary>fonction</primary>
-     <secondary>RETURNS TABLE</secondary>
-    </indexterm>
-
-    <para>
-     Il existe une autre façon de déclarer une fonction comme renvoyant un
-     ensemble de données. Cela passe par la syntaxe <literal>RETURNS
-     TABLE(<replaceable>colonnes</replaceable>)</literal>. C'est équivalent
-     à utiliser un ou plusieurs paramètres <literal>OUT</literal> et à marquer
-     la fonction comme renvoyant un <literal>SETOF record</literal> (ou
-     <literal>SETOF</literal> d'un type simple en sortie, comme approprié).
-     Cette notation est indiquée dans les versions récentes du standard SQL
-     et, du coup, devrait être plus portable que <literal>SETOF</literal>.
-    </para>
-
-    <para>
-     L'exemple précédent, sum-and-product, peut se faire aussi de la façon
-     suivante&nbsp;:
-
-<programlisting>
-CREATE FUNCTION sum_n_product_with_tab (x int) RETURNS TABLE(sum int, product int) AS $$
-    SELECT $1 + tab.y, $1 * tab.y FROM tab;
-$$ LANGUAGE SQL;
-</programlisting>
-
-     Il n'est pas autorisé d'utiliser explicitement des paramètres
-     <literal>OUT</literal> ou <literal>INOUT</literal> avec la notation
-     <literal>RETURNS TABLE</literal> &mdash; vous devez indiquer toutes les
-     colonnes en sortie dans la liste <literal>TABLE</literal>.
- </para>
-    </sect2>
-
-   <sect2>
-    <title>Fonctions <acronym>SQL</acronym> polymorphes</title>
-
-    <para>
-     Les fonctions <acronym>SQL</acronym> peuvent être déclarées pour accepter
-     et renvoyer les types <quote>polymorphe</quote> <type>anyelement</type>,
-     <type>anyarray</type>, <type>anynonarray</type> et <type>anyenum</type>.
-     Voir la <xref linkend="extend-types-polymorphic"/> pour une
-     explication plus approfondie. Voici une fonction polymorphe
-     <function>cree_tableau</function> qui construit un tableau à partir de
-     deux éléments de type arbitraire&nbsp;:
-
-<screen>CREATE FUNCTION cree_tableau(anyelement, anyelement) RETURNS anyarray AS $$
-    SELECT ARRAY[$1, $2];
-$$ LANGUAGE SQL;
-SELECT cree_tableau(1, 2) AS tableau_entier, cree_tableau('a'::text, 'b') AS
-tableau_texte;
-
- tableau_entier | tableau_texte
-----------------+---------------
- {1,2}          | {a,b}
-(1 row)
-</screen>
-    </para>
-
-    <para>
-     Notez l'utilisation du transtypage <literal>'a'::text</literal> pour
-     spécifier le type <type>text</type> de l'argument. Ceci est nécessaire si
-     l'argument est une chaîne de caractères car, autrement, il serait traité
-     comme un type  <type>unknown</type>, et un tableau de type
-     <type>unknown</type> n'est pas un type valide. Sans le transtypage, vous
-     obtiendrez ce genre d'erreur&nbsp;:
-
-<screen><computeroutput>ERROR:  could not determine polymorphic type because input is UNKNOWN</computeroutput></screen>
-    </para>
-
-    <para>
-     Il est permis d'avoir des arguments polymorphes avec un type de renvoi
-     fixe, mais non l'inverse. Par exemple&nbsp;:
-
-<screen>CREATE FUNCTION est_plus_grand(anyelement, anyelement) RETURNS bool AS $$
-    SELECT $1 &gt; $2;
-$$ LANGUAGE SQL;
-
-SELECT est_plus_grand(1, 2);
- est_plus_grand
-----------------
- f
-(1 row)
-
-CREATE FUNCTION fonction_invalide() RETURNS anyelement AS $$
-    SELECT 1;
-$$ LANGUAGE SQL;
-ERROR:  cannot determine result datatype
-DETAIL:  A function returning a polymorphic type must have at least one
-polymorphic argument.
-</screen>
-    </para>
-
-    <para>
-     Le polymorphisme peut être utilisé avec les fonctions qui ont des
-     arguments en sortie. Par exemple&nbsp;:
-<screen>CREATE FUNCTION dup (f1 anyelement, OUT f2 anyelement, OUT f3 anyarray)
-AS 'select $1, array[$1,$1]' LANGUAGE SQL;
-
-SELECT * FROM dup(22);
- f2 |   f3
-----+---------
- 22 | {22,22}
-(1 row)
-</screen>
-    </para>
-
-    <para>
-     Le polymorphisme peut aussi être utilisé avec des fonctions variadic.
-     Par exemple&nbsp;:
-<screen>
-CREATE FUNCTION anyleast (VARIADIC anyarray) RETURNS anyelement AS $$
-    SELECT min($1[i]) FROM generate_subscripts($1, 1) g(i);
-$$ LANGUAGE SQL;
-
-SELECT anyleast(10, -1, 5, 4);
- anyleast 
-----------
-       -1
-(1 row)
-
-SELECT anyleast('abc'::text, 'def');
- anyleast 
-----------
- abc
-(1 row)
-
-CREATE FUNCTION concat(text, VARIADIC anyarray) RETURNS text AS $$
-    SELECT array_to_string($2, $1);
-$$ LANGUAGE SQL;
-
-SELECT concat('|', 1, 4, 2);
- concat 
---------
- 1|4|2
-(1 row)
-</screen>
-    </para>
-   </sect2>
-  </sect1>
-
-  <sect1 id="xfunc-overload">
-    <title>Surcharge des fonctions</title>
-    
-    <indexterm zone="xfunc-overload">
-      <primary>surcharge</primary>
-      <secondary>fonctions</secondary>
-    </indexterm>
-    
-    <para>
-      Plusieurs fonctions peuvent être définies avec le même nom SQL à condition
-      que les arguments soient différents. En d'autres termes, les noms de
-      fonction peuvent être <firstterm>surchargés</firstterm>. Quand une
-      requête est exécutée, le serveur déterminera la fonction à appeler à
-      partir des types de données des arguments et du nombre d'arguments. La
-      surcharge peut aussi être utilisée pour simuler des fonctions avec un
-      nombre variable d'arguments jusqu'à un nombre maximum fini.
-    </para>
-    
-    <para>
-      Lors de la création d'une famille de fonctions surchargées, vous devriez
-      être attentif à ne pas créer d'ambiguïtés. Par exemple, avec les
-      fonctions&nbsp;:
-      <programlisting>CREATE FUNCTION test(int, real) RETURNS ...
-CREATE FUNCTION test(smallint, double precision) RETURNS ...</programlisting>
-      Savoir quelle fonction sera appelée avec une entrée triviale comme
-      <literal>test(1, 1.5)</literal> n'est pas immédiatement clair. Les
-      règles de résolution actuellement implémentées sont décrites dans le
-      <xref linkend="typeconv"/> mais il est déconseillé de concevoir un
-      système qui serait basé subtilement sur ce comportement.
-      </para>
-      
-      <para>
-        Une fonction qui prend un seul argument d'un type composite devrait
-        généralement ne pas avoir le même nom que tout attribut (champ) de
-        ce type. Rappellez-vous que <literal>attribut(table)</literal> est
-        considéré comme équivalent à <literal>table.attribut</literal>. Dans
-        le cas où il existe une ambiguïté entre une fonction sur un type
-        composite et sur un attribut d'un type composite, l'attribut sera
-        toujours utilisé. Il est possible de contourner ce choix en
-        qualifiant le nom de la fonction avec celui du schéma (c'est-à-dire
-        <literal>schema.fonction(table)</literal>) mais il est préférable
-        d'éviter le problème en ne choisissant aucun nom conflictuel.
-      </para>
-      
-      <para>
-       Un autre conflit possible se trouve entre les fonctions variadic et les
-       autres. En fait, il est possible de créer à la fois
-       <literal>foo(numeric)</literal> et <literal>foo(VARIADIC numeric[])</literal>.
-       Dans ce cas, il n'est pas simple de savoir lequel sera sélectionné lors
-       d'un appel avec un seul argument numérique, par exemple
-       <literal>foo(10.1)</literal>. La règle est que la fonction apparaissant
-       plsu tôt dans le chemin des schémas est utilisé. De même, si les deux
-       fonctions sont dans le même schéma, la non variadic est préféré.
-      </para>
-   
-      <para>
-        Lors de la surcharge de fonctions en langage C, il existe une
-        contrainte supplémentaire&nbsp;: le nom C de chaque fonction dans la
-        famille des fonctions surchargées doit être différent des noms C de
-        toutes les autres fonctions, soit internes soit chargées dynamiquement
-        Si cette règle est violée, le comportement n'est pas portable. Vous
-        pourriez obtenir une erreur de l'éditeur de lien ou une des fonctions
-        sera appelée (habituellement l'interne). L'autre forme de clause
-        <literal>AS</literal> pour la commande SQL <command>CREATE
-        FUNCTION</command> découple le nom de la fonction SQL à partir du 
-        nom de la fonction dans le code source C. Par exemple&nbsp;:
-<programlisting>CREATE FUNCTION test(int) RETURNS int
-    AS '<replaceable>filename</replaceable>', 'test_1arg'
-LANGUAGE C;
-CREATE FUNCTION test(int, int) RETURNS int
-    AS '<replaceable>filename</replaceable>', 'test_2arg'
-LANGUAGE C;
-</programlisting>
-        Les noms des fonctions C reflètent ici une des nombreuses conventions
-        possibles.
-      </para>
-  </sect1>
-
-  <sect1 id="xfunc-volatility">
-    <title>Catégories de volatilité des fonctions</title>
-  
-    <indexterm zone="xfunc-volatility">
-      <primary>volatilité</primary>
-      <secondary>fonctions</secondary>
-    </indexterm>
-    <indexterm zone="xfunc-volatility">
-      <primary>VOLATILE</primary>
-    </indexterm>
-    <indexterm zone="xfunc-volatility">
-      <primary>STABLE</primary>
-    </indexterm>
-    <indexterm zone="xfunc-volatility">
-      <primary>IMMUTABLE</primary>
-    </indexterm>
-  
-  <para>
-    Chaque fonction a une classification de volatilité
-    (<firstterm>volatility</firstterm>) comprenant
-    <literal>VOLATILE</literal>, <literal>STABLE</literal> ou <literal>IMMUTABLE</literal>.
-    <literal>VOLATILE</literal> est la valeur par défaut si la commande
-    <xref linkend="sql-createfunction" endterm="sql-createfunction-title"/> ne
-    spécifie pas de catégorie. La catégorie de volatilité est une promesse
-    à l'optimiseur sur le comportement de la fonction&nbsp;:
-
-  <itemizedlist>
-    <listitem>
-    <para>
-      Une fonction <literal>VOLATILE</literal> peut tout faire, y compris modifier
-      la base de données. Elle peut renvoyer différents
-      résultats sur des appels successifs avec les mêmes arguments.
-      L'optimiseur ne fait aucune supposition sur le comportement de telles
-      fonctions. Une requête utilisant une fonction volatile ré-évaluera la
-      fonction à chaque ligne où sa valeur est nécessaire.
-    </para>
-    </listitem>
-    <listitem>
-    <para>
-      Une fonction <literal>STABLE</literal> ne peut pas modifier la base de
-      données et est garantie de renvoyer les mêmes résultats si elle est
-      appelée avec les mêmes arguments pour toutes les lignes à l'intérieur
-      d'une même instruction. Cette catégorie permet à l'optimiseur d'optimiser
-      plusieurs appels de la fonction dans une seule requête. En particulier,
-      vous pouvez utiliser en toute sécurité une expression contenant une
-      telle fonction dans une condition de parcours d'index (car un parcours
-      d'index évaluera la valeur de la comparaison une seule fois, pas une
-      fois pour chaque ligne, utiliser une fonction <literal>VOLATILE</literal> dans
-      une condition de parcours d'index n'est pas valide).
-    </para>
-    </listitem>
-    <listitem>
-    <para>
-      Une fonction <literal>IMMUTABLE</literal> ne peut pas modifier la base de
-      données et est garantie de toujours renvoyer les mêmes résultats si
-      elle est appelée avec les mêmes arguments. Cette catégorie permet à 
-      l'optimiseur de pré-évaluer la fonction quand une requête l'appelle
-      avec des arguments constants. Par exemple, une requête comme
-      <literal>SELECT ... WHERE x = 2 + 2</literal> peut être simplifiée pour
-      obtenir <literal>SELECT ... WHERE x = 4</literal> car la fonction sous-jacente
-      de l'opérateur d'addition est indiquée <literal>IMMUTABLE</literal>.
-    </para>
-    </listitem>
-  </itemizedlist>
-
-  </para>
-
-  <para>
-    Pour une meilleure optimisation des résultats, vous devez mettre un label
-    sur les fonctions avec la catégorie la plus volatile valide pour elles.
-  </para>
-
-  <para>
-    Toute fonction avec des effets de bord <emphasis>doit</emphasis> être indiquée
-    comme <literal>VOLATILE</literal>, de façon à ce que les appels ne puissent pas
-    être optimisés. Même une fonction sans effets de bord doit être indiquée
-    comme <literal>VOLATILE</literal> si sa valeur peut changer à l'intérieur
-    d'une seule requête&nbsp;; quelques exemples sont <literal>random()</literal>,
-    <literal>currval()</literal>, <literal>timeofday()</literal>.
-  </para>
-
-   <para>
-    Un autre exemple important est que la famille de fonctions
-    <function>current_timestamp</function> est qualifiée comme
-    <literal>STABLE</literal> car leurs valeurs ne changent pas à l'intérieur
-    d'une transaction.
-   </para>
-
-  <para>
-    Il y a relativement peu de différences entre les catégories 
-    <literal>STABLE</literal> et <literal>IMMUTABLE</literal> en considérant les requêtes
-    interactives qui sont planifiées et immédiatement exécutées&nbsp;: il 
-    importe peu que la fonction soit exécutée une fois lors de la
-    planification ou une fois au lancement de l'exécution de la requête mais
-    cela fait une grosse différence si le plan est sauvegardé et utilisé plus
-    tard. Placer un label <literal>IMMUTABLE</literal> sur une fonction quand elle
-    ne l'est pas vraiment pourrait avoir comme conséquence de la considérer
-    prématurément comme une constante lors de la planification et résulterait en une valeur
-    erronée lors d'une utilisation ultérieure de ce plan d'exécution. 
-    C'est un danger qui arrive lors de l'utilisattion d'instructions préparées
-    ou avec l'utilisation de langages de fonctions mettant les plans d'exécutions
-    en cache (comme
-    <application>PL/pgSQL</application>).
-  </para>
-
-   <para>
-    Pour les fonctions écrites en SQL ou dans tout autre langage de procédure
-    standard, la catégorie de volatibilité détermine une deuxième propriété
-    importante, à savoir la visibilité de toute modification de données
-    effectuées par la commande SQL qui a appelé la fonction. Une fonction
-    <literal>VOLATILE</literal> verra les changements, une fonction
-    <literal>STABLE</literal> ou <literal>IMMUTABLE</literal> ne les verra pas.
-    Ce comportement est implantée en utilisant le comportement par images de
-    MVCC (voir <xref linkend="mvcc"/>)&nbsp;: les fonctions
-    <literal>STABLE</literal> et <literal>IMMUTABLE</literal> utilisent une
-    image établie au lancement de la requête appelante alors que les fonctions
-    <literal>VOLATILE</literal> obtiennent une image fraiche au début de chaque
-    requête qu'elles exécutent.
-   </para>
-
-   <note>
-    <para>
-     Les fonctions écrites en C peuvent gérer les images de la façon qu'elles
-     le souhaitent, mais il est préférable de coder les fonctions C de la même
-     façon.
-    </para>
-   </note>
-
-  <para>
-    À cause du comportement à base d'images, une fonction contenant seulement des commandes
-    <command>SELECT</command> peut être indiquée <literal>STABLE</literal> en toute sécurité
-    même s'il sélectionne des données à partir de tables qui pourraient
-    avoir subi des modifications entre temps par des requêtes concurrentes.
-    <productname>PostgreSQL</productname> exécutera toutes les commandes d'une fonction
-    <literal>STABLE</literal> en utilisant l'image établie par la requête appelante et
-    n'aura qu'une vision figée de la base de données au cours de la requête.
-  </para>
-
-  <para>
-    Ce même comportement d'images est utilisé pour les commandes
-    <command>SELECT</command> à l'intérieur de fonctions <literal>IMMUTABLE</literal>. Il
-    est généralement déconseillé de sélectionner des tables de la base de
-    données à l'intérieur de fonctions <literal>IMMUTABLE</literal> car
-    l'immutabilité sera rompue si le contenu de la table change. Néanmoins,
-    <productname>PostgreSQL</productname> ne vous force pas à ne pas le faire.
-  </para>
-
-  <para>
-    Une erreur commune est de placer un label sur une fonction
-    <literal>IMMUTABLE</literal> quand son résultat dépend d'un paramètre de
-    configuration. Par exemple, une fonction qui manipule des types date/heure
-    pourrait bien avoir des résultats dépendant du paramètre
-    <xref linkend="guc-timezone"/>. Pour être sécurisées, de telles
-    fonctions devraient avoir le label <literal>STABLE</literal> à la place.
-  </para>
-
-  <note>
-    <para>
-      Avant <productname>PostgreSQL</productname> version 8.0, le prérequis
-      que les fonctions <literal>STABLE</literal> et
-      <literal>IMMUTABLE</literal> ne pouvaient pas modifier la base de données
-      n'était pas contraint par le système. Les versions 8.0 et ultérieures le
-      contraignent en
-      réclamant que les fonctions SQL et les fonctions de langages de
-      procédures de ces catégories ne contiennent pas de commandes SQL autre
-      que <command>SELECT</command> (ceci n'a pas été complètement testé car de
-      telles fonctions pourraient toujours appeler des fonctions
-      <literal>VOLATILE</literal> qui modifient la base de données. Si vous le
-      faites, vous trouverez que la fonction <literal>STABLE</literal> ou
-      <literal>IMMUTABLE</literal> n'est pas au courant des modifications
-      effectuées sur la base de données par la fonction appelée, car elles
-      sont cachées depuis son image).
-    </para>
-  </note>
-  </sect1>
-
-  <sect1 id="xfunc-pl">
-   <title>Fonctions en langage de procédures</title>
-
-   <para>
-    <productname>PostgreSQL</productname> autorise l'écriture de fonctions
-    définies par l'utilisateur dans d'autres langages que SQL et C. Ces autres
-    langages sont appelés des <firstterm>langages de procédure</firstterm>
-    (<acronym>PL</acronym>). Les langages de procédures ne sont pas compilés dans le
-    serveur <productname>PostgreSQL</productname>&nbsp;; ils sont fournis comme
-    des modules chargeables. Voir le <xref linkend="xplang"/> et les chapitres
-    suivants pour plus d'informations.
-   </para>
-
-   <para>
-    Il y a actuellement quatre langages de procédures disponibles dans la
-    distribution <productname>PostgreSQL</productname> standard&nbsp;:
-     <application>PL/pgSQL</application>, <application>PL/Tcl</application>,
-     <application>PL/Perl</application> et <application>PL/Python</application>.
- 
-    Référez-vous au <xref linkend="xplang"/> pour plus d'informations. D'autres
-    langages peuvent être définis par les utilisateurs. Les bases du
-    développement d'un nouveau langage de procédures sont traitées dans le <xref
-    linkend="plhandler"/>.
-   </para> 
- 
- </sect1>
- 
- <sect1 id="xfunc-internal">
-   <title>Fonctions internes</title>
-
-   <indexterm zone="xfunc-internal"><primary>fonction</primary><secondary>interne</secondary></indexterm>
-
-   <para>
-    Les fonctions internes sont des fonctions écrites en C qui ont été liées de
-    façon statique dans le serveur <productname>PostgreSQL</productname>. Le
-    <quote>corps</quote> de la définition de la fonction spécifie le nom en 
-    langage C de la fonction, qui n'est pas obligatoirement le même que le nom
-    déclaré pour l'utilisation en SQL (pour des raisons de rétro compatibilité,
-    un corps vide est accepté pour signifier que le nom de la fonction en
-    langage C est le même que le nom SQL).
-
-   </para>
-
-   <para>
-    Normalement, toutes les fonctions internes présentes dans le serveur sont
-    déclarées pendant l'initialisation du groupe de base de données
-    (<command>initdb</command>) mais un utilisateur peut utiliser la commande  
-    <command>CREATE FUNCTION</command> pour créer des noms d'alias
-    supplémentaires pour une fonction interne. Les fonctions internes sont
-    déclarées dans la commande <command>CREATE FUNCTION</command> avec le nom
-    de langage <literal>internal</literal>. Par exemple, pour créer un alias
-    de la fonction <function>sqrt</function>&nbsp;:
-
-<programlisting>CREATE FUNCTION racine_carree(double precision) RETURNS double precision    AS
-'dsqrt'    
-LANGUAGE internal    STRICT;
-</programlisting>
-
-    (la plupart des fonctions internes doivent être déclarées
-    <quote>STRICT</quote>)
-   </para>
-
-   <note>
-    <para>
-     Toutes les fonctions <quote>prédéfinies</quote> ne sont pas internes (au
-     sens explicité ci-dessus). Quelques fonctions prédéfinies sont écrites en
-     SQL.
-    </para>
-   </note>
-  </sect1>
-
-  <sect1 id="xfunc-c">
-   <title>Fonctions en langage C</title>
-
-   <indexterm zone="xfunc-c">
-    <primary>fonction</primary>
-    <secondary>définie par l'utilisateur</secondary>
-    <tertiary>en C</tertiary>
-   </indexterm>
-
-   <para>
-    Les fonctions définies par l'utilisateur peuvent être écrites en C (ou dans
-    un langage pouvant être rendu compatible avec C, comme le C++). Ces fonctions
-    sont compilées en objets dynamiques chargeables (encore appelés
-    bibliothèques partagées) et sont chargées par le serveur à la demande. Cette
-    caractéristique de chargement dynamique est ce qui distingue les fonctions
-    en <quote>langage C</quote> des fonctions <quote>internes</quote> &mdash; les véritables
-    conventions de codage sont essentiellement les mêmes pour les deux (c'est
-    pourquoi la bibliothèque standard de fonctions internes est une source
-    abondante d'exemples de code pour les fonctions C définies par
-    l'utilisateur).
-  </para>
-  
-  <para>
-    Deux différentes conventions d'appel sont actuellement en usage pour les
-    fonctions C. La plus récente, <quote>version 1</quote>,
-    est indiquée en écrivant une macro d'appel
-    <literal>PG_FUNCTION_INFO_V1()</literal> comme illustré ci-après. L'absence
-    d'une telle macro indique une fonction écrite selon l'ancien style
-    (<quote>version 0</quote>). Le nom de langage spécifié dans la commande 
-    <command>CREATE FUNCTION</command> est <literal>C</literal> dans les deux
-    cas. Les fonctions suivant l'ancien style sont maintenant déconseillées en
-    raison de problèmes de portabilité et d'un manque de fonctionnalité mais
-    elles sont encore supportées pour des raisons de compatibilité.
- </para>  
- 
-  <sect2 id="xfunc-c-dynload">
-   <title>Chargement dynamique</title>
-
-   <indexterm zone="xfunc-c-dynload">
-    <primary>dynamic loading</primary>
-   </indexterm>
-   
-   <para>
-    La première fois qu'une fonction définie par l'utilisateur dans un fichier
-    objet particulier chargeable est appelée dans une session, le chargeur
-    dynamique charge ce fichier objet en mémoire de telle sorte que la fonction 
-    peut être appelée. La commande <command>CREATE FUNCTION</command> pour une
-    fonction en C définie par l'utilisateur doit par conséquent spécifier deux
-    éléments d'information pour la fonction&nbsp;: le nom du fichier objet
-    chargeable et le nom en C (lien symbolique) de la fonction spécifique à
-    appeler à l'intérieur de ce fichier objet. Si le nom en C n'est pas
-    explicitement spécifié, il est supposé être le même que le nom de la
-    fonction SQL. 
-  </para> 
-  
-  <para>
-    L'algorithme suivant, basé sur le nom donné dans la commande
-    <command>CREATE FUNCTION</command>, est utilisé pour localiser le fichier
-    objet partagé&nbsp;:
-
-    <orderedlist>
-     <listitem>
-      <para>
-       Si le nom est un chemin absolu, le fichier est chargé.
-      </para>
-     </listitem>
-
-     <listitem>
-      <para>
-       Si le nom commence par la chaîne <literal>$libdir</literal>, cette chaîne
-       est remplacée par le nom du répertoire de la bibliothèque du paquetage
-       <productname>PostgreSQL</productname>, qui est déterminé au moment de la 
-       compilation. <indexterm><primary>$libdir</primary></indexterm>
-      </para>
-     </listitem>
-
-     <listitem>
-      <para>
-       Si le nom ne contient pas de partie répertoire, le fichier est recherché
-       par le chemin spécifié dans la variable de configuration
-       <xref linkend="guc-dynamic-library-path"/>.
-       <indexterm><primary>dynamic_library_path</primary></indexterm>
-      </para>
-     </listitem>
-
-     <listitem>
-      <para>
-       Dans les autres cas, (nom de fichier non trouvé dans le chemin ou ne
-       contenant pas de partie répertoire non absolu), le chargeur dynamique
-       essaiera d'utiliser le nom donné, ce qui échouera très vraisemblablement
-       (dépendre du répertoire de travail en cours n'est pas fiable).
-      </para>
-     </listitem>
-    </orderedlist>
-
-    Si cette séquence ne fonctionne pas, l'extension pour les noms de fichier
-    des bibliothèques partagées spécifique à la plateforme (souvent
-    <filename>.so</filename>) est ajoutée au nom attribué et la séquence est à
-    nouveau tentée. En cas de nouvel échec, le chargement échoue. 
- </para>
-
-   <para>
-    Il est recommandé de localiser les bibliothèques partagées soit relativement
-    à <literal>$libdir</literal> ou via le chemin dynamique des bibliothèques.
-    Ceci simplifie les mises à jour de versions si la nouvelle installation est
-    à un emplacement différent. Le répertoire actuel représenté par
-    <literal>$libdir</literal> est trouvable avec la commande
-    <literal>pg_config --pkglibdir</literal>.
-   </para>
-
-    <para>
-     L'identifiant utilisateur sous lequel fonctionne le serveur
-     <productname>PostgreSQL</productname> doit pouvoir suivre le chemin
-     jusqu'au fichier que vous essayez de charger. Une erreur fréquente revient
-     à définir le fichier ou un répertoire supérieur comme non lisible et/ou
-     non exécutable par l'utilisateur <systemitem>postgres</systemitem>.
-    </para>
-
-   <para>
-    Dans tous les cas, le nom de fichier donné dans la commande <command>CREATE
-    FUNCTION</command> est enregistré littéralement dans les catalogues
-    systèmes, de sorte que, si le fichier doit être à nouveau chargé, la même 
-    procédure sera appliquée.
- </para>
-
-   <note>
-    <para>
-     <productname>PostgreSQL</productname> ne compilera pas une fonction C
-     automatiquement. Le fichier objet doit être compilé avant d'être référencé
-     dans une commande <command>CREATE FUNCTION</command>. Voir la <xref
-    linkend="dfunc"/> pour des informations complémentaires. 
-   </para>
-   </note>
-
-   <indexterm zone="xfunc-c-dynload">
-    <primary>bloc magique</primary>
-   </indexterm>
-
-   <para>
-    Pour s'assurer qu'un fichier objet chargeable dynamiquement n'est pas chargé
-    dans un serveur incompatible, <productname>PostgreSQL</productname> vérifie
-    que le fichier contient un <quote>bloc magique</quote> avec un contenu
-    approprié. Ceci permet au serveur de détecter les incompatibilités évidentes
-    comme du code compilet pour une version majeure différente de
-    <productname>PostgreSQL</productname>. Un bloc magique est requis à partir de
-    <productname>PostgreSQL</productname> 8.2. Pour inclure un bloc magique,
-    écrivez ceci dans un (et seulement un) des fichiers source du module, après
-    avoir inclus l'en-tête <filename>fmgr.h</filename>&nbsp;:
-
-<programlisting>#ifdef PG_MODULE_MAGIC
-PG_MODULE_MAGIC;
-#endif
-</programlisting>
-
-    Le test <literal>#ifdef</literal> peut être omis si le code n'a pas besoin
-    d'être compilé avec des versions de <productname>PostgreSQL</productname>
-    antérieures à la 8.2.
-   </para>
-
-   <para>
-    Après avoir été utilisé pour la première fois, un fichier objet chargé
-    dynamiquement est conservé en mémoire. Les futurs appels de fonction(s) dans
-    ce fichier pendant la même session provoqueront seulement une légère
-    surcharge due à la consultation d'une table de symboles. Si vous devez
-    forcer le chargement d'un fichier objet, par exemple après une
-    recompilation, utilisez la commande <xref
-    linkend="sql-load" endterm="sql-load-title"/> ou commencez une
-    nouvelle session.  
-  </para>
-
-   <indexterm zone="xfunc-c-dynload">
-    <primary>_PG_init</primary>
-   </indexterm>
-   <indexterm zone="xfunc-c-dynload">
-    <primary>_PG_fini</primary>
-   </indexterm>
-   <indexterm zone="xfunc-c-dynload">
-    <primary>fonction d'initialisation de la bibliothèque</primary>
-   </indexterm>
-   <indexterm zone="xfunc-c-dynload">
-    <primary>fonction de terminaison de la bibliothèque</primary>
-   </indexterm>
-
-   <para>
-    De façon optionnelle, un fichier chargé dynamiquement peut contenir des
-    fonctions d'initialisation et de terminaison. Si le fichier inclut une
-    fonction nommée <function>_PG_init</function>, cette fonction sera appelée
-    immédiatement après le chargement du fichier. La fonction ne reçoit
-    aucun paramètre et doit renvoyer void. Si le fichier inclut une fonction
-    nommée <function>_PG_fini</function>, cette fonction sera appelée tout juste
-    avant le déchargement du fichier. De la même façon, la fonction ne reçoit
-    aucun paramètre et doit renvoyer void. Notez que <function>_PG_fini</function>
-    sera seulement appelée lors du déchargement du fichier, pas au moment de la
-    fin du processus. (Actuellement, un déchargement n'intervient que dans le
-    contexte d'un re-chargement du fichier suite à la commande explicite
-    <command>LOAD</command>.)
-   </para>
-
-  </sect2>
-
-   <sect2 id="xfunc-c-basetype">
-    <title>Types de base dans les fonctions en langage C</title>
-
-    <indexterm zone="xfunc-c-basetype">
-     <primary>type de données</primary>
-     <secondary>organisation interne</secondary>
-    </indexterm>
-
-    <para>
-     Pour savoir comment écrire des fonctions en langage C, vous devez savoir 
-     comment <productname>PostgreSQL</productname> représente en interne les
-     types de données de base et comment elles peuvent être passés vers et
-     depuis les fonctions. En interne, <productname>PostgreSQL</productname>
-     considère un type de base comme un <quote>blob de mémoire</quote>. Les
-     fonctions que vous définissez sur un type définissent à leur tour la façon
-     que <productname>PostgreSQL</productname> opère sur lui. C'est-à-dire
-     que <productname>PostgreSQL</productname> ne fera que conserver et retrouver
-     les données sur le disque et utilisera votre fonction pour entrer, traiter
-     et restituer les données.
-    </para>
-    
-    <para>
-     Les types de base peuvent avoir un des trois formats internes
-     suivants&nbsp;:
-     <itemizedlist>
-      <listitem>
-       <para>
-	passage par valeur, longueur fixe&nbsp;;
-       </para>
-      </listitem>
-      <listitem>
-       <para>
-	passage par référence, longueur fixe&nbsp;;
-       </para>
-      </listitem>
-      <listitem>
-       <para>
-	passage par référence, longueur variable.
-       </para>
-      </listitem>
-     </itemizedlist>
-    </para>
-
-    <para>
-     Les types par valeur peuvent seulement avoir une longueur de 1, 2 ou 4
-     octets (également 8 octets si <literal>sizeof(Datum)</literal> est de huit
-     octets sur votre machine). Vous devriez être attentif lors de la
-     définition de vos types de sorte à qu'ils aient la même taille sur toutes
-     les architectures. Par exemple, le type <literal>long</literal> est
-     dangereux car il a une taille de quatre octets sur certaines machines et
-     huit octets sur d'autres, alors que le type <type>int</type> est de quatre
-     octets sur la plupart des machines Unix. Une implémentation raisonnable du
-     type <type>int4</type> sur une machine Unix pourrait être
- 
- <programlisting>/* entier sur quatre octets, passé par valeur */
-typedef int int4;
-</programlisting>
-
-    </para>
-
-    <para>
-     D'autre part, les types à longueur fixe d'une taille quelconque peuvent
-     être passés par référence. Par exemple, voici l'implémentation d'un type
-     <productname>PostgreSQL</productname>&nbsp;:
-
-<programlisting>/* structure de 16 octets, passée par référence */
-typedef struct
-{
-    double  x, y;
-} Point;
-</programlisting>
-
-     Seuls des pointeurs vers de tels types peuvent être utilisés en les passant
-     dans et hors des fonctions <productname>PostgreSQL</productname>. Pour
-     renvoyer une valeur d'un tel type, allouez la quantité appropriée de
-     mémoire avec <literal>palloc</literal>, remplissez la mémoire allouée et
-     renvoyez un pointeur vers elle (de plus, si vous souhaitez seulement
-     renvoyer la même valeur qu'un de vos arguments en entrée qui se trouve du
-     même type, vous pouvez passer le <literal>palloc</literal>
-     supplémentaire et simplement renvoyer le pointeur vers la valeur en
-     entrée).
-    </para>
-
-    <para>
-     Enfin, tous les types à longueur variable doivent aussi être passés par
-     référence. Tous les types à longueur variable doivent commencer avec un
-     champ d'une longueur d'exactement quatre octets et toutes les données
-     devant être stockées dans ce type doivent être localisées dans la mémoire à
-     la suite immédiate de ce champ longueur. Le champ longueur contient la
-     longueur totale de la structure, c'est-à-dire incluant la longueur du
-     champ longueur lui-même.
-    </para>
-
-    <warning>
-     <para>
-      Ne <emphasis>jamais</emphasis> modifier le contenu d'une valeur en entrée passée
-      par référence. Si vous le faites, il y a de forts risques pour que
-      vous réussissiez à corrompre les données sur disque car le pointeur que
-      vous avez reçu pourrait bien pointer directement vers un tampon disque.
-      La seule exception à cette règle est expliquée dans la <xref
-      linkend="xaggr"/>.
-     </para>
-    </warning>
-
-    <para>
-     Comme exemple, nous pouvons définir le type <type>text</type> comme
-     ceci&nbsp;:
-
-<programlisting>typedef struct {
-    int4 length;
-    char data[1];
-} text;
-</programlisting>
-
-     Il est évident que le champ déclaré ici n'est pas assez long pour contenir
-     toutes les chaînes possibles. Comme il est impossible de déclarer une
-     structure de taille variable en <acronym>C</acronym>, nous nous appuyons
-     sur le fait que le compilateur  <acronym>C</acronym> ne vérifie pas la
-     plage des indices de tableau. Nous allouons juste la quantité d'espace
-     nécessaire et ensuite nous accédons au tableau comme s'il avait été déclaré
-     avec la bonne longueur (c'est une astuce courante que vous pouvez trouver
-     dans beaucoup de manuels de C).
-    </para>
-    
-    <para>
-     En manipulant les types à longueur variable, nous devons être attentifs à
-     allouer la quantité correcte de mémoire et à fixer correctement le champ
-     longueur. Par exemple, si nous voulons stocker 40 octets dans une structure
-     <structname>text</structname>, nous devrions utiliser un fragment de code comme
-     celui-ci&nbsp;:
-
-<programlisting><![CDATA[#include "postgres.h"
-...
-char buffer[40]; /* notre donnée source */
-...
-text *destination = (text *) palloc(VARHDRSZ + 40);
-destination->length = VARHDRSZ + 40;
-memcpy(destination->data, buffer, 40);
-...
-]]></programlisting>
-
-     <literal>VARHDRSZ</literal> est équivalent à <literal>sizeof(int4)</literal> mais
-     est considéré comme une meilleure tournure de référence à la taille de
-     l'overhead pour un type à longueur variable.
-    </para>
-
-    <para>
-     Le <xref linkend="xfunc-c-type-table"/> spécifie la correspondance entre
-     les types C et les types SQL quand on écrit une fonction en langage C
-     utilisant les types internes de <productname>PostgreSQL</productname>. La colonne
-     <quote>Défini dans</quote> donne le fichier d'en-tête devant être inclus
-     pour accéder à la définition du type (la définition effective peut se
-     trouver dans un fichier différent inclus dans le fichier indiqué. Il
-     est recommandé que les utilisateurs s'en tiennent à l'interface définie).
-     Notez que vous devriez toujours inclure <filename>postgres.h</filename> en
-     premier dans tout fichier source car il déclare un grand nombre d'éléments
-     dont vous aurez besoin de toute façon. 
-    </para>
-    
-    <table tocentry="1" id="xfunc-c-type-table">
-      <title>Équivalence des types C et des types SQL intégrés</title>
-      <tgroup cols="3">
-       <colspec colnum="1" colwidth="0.7*"/>
-       <colspec colnum="2" colwidth="0.5*"/>
-       <colspec colnum="3" colwidth="1.8*"/>
-       <thead>
-	<row>
-	 <entry>
-	  Type SQL
-	 </entry>
-	 <entry>
-	  Type C
-	 </entry>
-	 <entry>
-	  Défini dans
-	 </entry>
-	</row>
-       </thead>
-       <tbody>
-	<row>
-	 <entry><type>abstime</type></entry>
-	 <entry><type>AbsoluteTime</type></entry>
-	 <entry><filename>utils/nabstime.h</filename></entry>
-	</row>
-	<row>
-	 <entry><type>boolean</type></entry>
-	 <entry><type>bool</type></entry>
-	 <entry><filename>postgres.h</filename> (intégration au
-	  compilateur)</entry>
-	</row>
-	<row>
-	 <entry><type>box</type></entry>
-	 <entry><type>BOX*</type></entry>
-	 <entry><filename>utils/geo_decls.h</filename></entry>
-	</row>
-	<row>
-	 <entry><type>bytea</type></entry>
-	 <entry><type>bytea*</type></entry>
-	 <entry><filename>postgres.h</filename></entry>
-	</row>
-	<row>
-	 <entry><type>"char"</type></entry>
-	 <entry><type>char</type></entry>
-	 <entry>(intégré au compilateur)</entry>
-	</row>
-	<row>
-	 <entry><type>character</type></entry>
-	 <entry><type>BpChar*</type></entry>
-	 <entry><filename>postgres.h</filename></entry>
-	</row>
-	<row>
-	 <entry><type>cid</type></entry>
-	 <entry><type>CommandId</type></entry>
-	 <entry><filename>postgres.h</filename></entry>
-	</row>
-	<row>
-	 <entry><type>date</type></entry>
-	 <entry><type>DateADT</type></entry>
-	 <entry><filename>utils/date.h</filename></entry>
-	</row>
-	<row>
-	 <entry><type>smallint</type> (<type>int2</type>)</entry>
-	 <entry><type>int2</type> or <type>int16</type></entry>
-	 <entry><filename>postgres.h</filename></entry>
-	</row>
-	<row>
-	 <entry><type>int2vector</type></entry>
-	 <entry><type>int2vector*</type></entry>
-	 <entry><filename>postgres.h</filename></entry>
-	</row>
-	<row>
-	 <entry><type>integer</type> (<type>int4</type>)</entry>
-	 <entry><type>int4</type> or <type>int32</type></entry>
-	 <entry><filename>postgres.h</filename></entry>
-	</row>
-	<row>
-	 <entry><type>real</type> (<type>float4</type>)</entry>
-	 <entry><type>float4*</type></entry>
-	<entry><filename>postgres.h</filename></entry>
-	</row>
-	<row>
-	 <entry><type>double precision</type> (<type>float8</type>)</entry>
-	 <entry><type>float8*</type></entry>
-	 <entry><filename>postgres.h</filename></entry>
-	</row>
-	<row>
-	 <entry><type>interval</type></entry>
-	 <entry><type>Interval*</type></entry>
-	 <entry><filename>utils/timestamp.h</filename></entry>
-	</row>
-	<row>
-	 <entry><type>lseg</type></entry>
-	 <entry><type>LSEG*</type></entry>
-	 <entry><filename>utils/geo_decls.h</filename></entry>
-	</row>
-	<row>
-	 <entry><type>name</type></entry>
-	 <entry><type>Name</type></entry>
-	 <entry><filename>postgres.h</filename></entry>
-	</row>
-	<row>
-	 <entry><type>oid</type></entry>
-	 <entry><type>Oid</type></entry>
-	 <entry><filename>postgres.h</filename></entry>
-	</row>
-	<row>
-	 <entry><type>oidvector</type></entry>
-	 <entry><type>oidvector*</type></entry>
-	 <entry><filename>postgres.h</filename></entry>
-	</row>
-	<row>
-	 <entry><type>path</type></entry>
-	 <entry><type>PATH*</type></entry>
-	 <entry><filename>utils/geo_decls.h</filename></entry>
-	</row>
-	<row>
-	 <entry><type>point</type></entry>
-	 <entry><type>POINT*</type></entry>
-	 <entry><filename>utils/geo_decls.h</filename></entry>
-	</row>
-	<row>
-	 <entry><type>regproc</type></entry>
-	 <entry><type>regproc</type></entry>
-	 <entry><filename>postgres.h</filename></entry>
-	</row>
-	<row>
-	 <entry><type>reltime</type></entry>
-	 <entry><type>RelativeTime</type></entry>
-	 <entry><filename>utils/nabstime.h</filename></entry>
-	</row>
-	<row>
-	 <entry><type>text</type></entry>
-	 <entry><type>text*</type></entry>
-	 <entry><filename>postgres.h</filename></entry>
-	</row>
-	<row>
-	 <entry><type>tid</type></entry>
-	 <entry><type>ItemPointer</type></entry>
-	 <entry><filename>storage/itemptr.h</filename></entry>
-	</row>
-	<row>
-	 <entry><type>time</type></entry>
-	 <entry><type>TimeADT</type></entry>
-	 <entry><filename>utils/date.h</filename></entry>
-	</row>
-	<row>
-	 <entry><type>time with time zone</type></entry>
-	 <entry><type>TimeTzADT</type></entry>
-	 <entry><filename>utils/date.h</filename></entry>
-	</row>
-	<row>
-	 <entry><type>timestamp</type></entry>
-	 <entry><type>Timestamp*</type></entry>
-	 <entry><filename>utils/timestamp.h</filename></entry>
-	</row>
-	<row>
-	 <entry><type>tinterval</type></entry>
-	 <entry><type>TimeInterval</type></entry>
-	 <entry><filename>utils/nabstime.h</filename></entry>
-	</row>
-	<row>
-	 <entry><type>varchar</type></entry>
-	 <entry><type>VarChar*</type></entry>
-	 <entry><filename>postgres.h</filename></entry>
-	</row>
-	<row>
-	 <entry><type>xid</type></entry>
-	 <entry><type>TransactionId</type></entry>
-	 <entry><filename>postgres.h</filename></entry>
-	</row>
-       </tbody>
-      </tgroup>
-     </table>
-
-    <para>
-     Maintenant que nous avons passé en revue toutes les structures possibles
-     pour les types de base, nous pouvons donner quelques exemples de vraies
-     fonctions.
- </para>
-   </sect2>
-
-   <sect2>
-    <title>Conventions d'appel de la version 0</title>
-
-    <para>
-     Nous présentons l'<quote>ancien style</quote> de convention d'appel en
-     premier &mdash; bien que cette approche soit maintenant déconseillée, elle est
-     plus facile à maîtriser au début. Dans la méthode version-0, les arguments
-     et résultats de la fonction C sont simplement déclarés dans le style C
-     normal mais en faisant attention à utiliser la représentation C de chaque
-     type de données SQL comme montré ci-dessus.
-    </para>
-
-    <para>
-     Voici quelques exemples&nbsp;:
-
-<programlisting><![CDATA[#include "postgres.h"
-#include <string.h>
-
-/* par valeur */
-         
-int
-add_one(int arg)
-{
-    return arg + 1;
-}
-
-/* par référence, taille fixe */
-
-float8 *
-add_one_float8(float8 *arg)
-{
-    float8    *result = (float8 *) palloc(sizeof(float8));
-
-    *result = *arg + 1.0;
-       
-    return result;
-}
-
-Point *
-makepoint(Point *pointx, Point *pointy)
-{
-    Point     *new_point = (Point *) palloc(sizeof(Point));
-
-    new_point->x = pointx->x;
-    new_point->y = pointy->y;
-       
-    return new_point;
-}
-
-/* par référence, taille variable */
-
-text *
-copytext(text *t)
-{
-    /*
-     * VARSIZE est la taille totale de la structure en octets.
-     */
-    text *new_t = (text *) palloc(VARSIZE(t));
-    SET_VARSIZE(new_t, VARSIZE(t));
-    /*
-     * VARDATA est un pointeur sur la région de données de la structure.
-     */
-    memcpy((void *) VARDATA(new_t), /* destination */
-           (void *) VARDATA(t),     /* source */
-           VARSIZE(t) - VARHDRSZ);  /* nombre d'octets */
-    return new_t;
-}
-
-text *
-concat_text(text *arg1, text *arg2)
-{
-    int32 new_text_size = VARSIZE(arg1) + VARSIZE(arg2) - VARHDRSZ;
-    text *new_text = (text *) palloc(new_text_size);
-
-    SET_VARSIZE(new_text, new_text_size);
-    memcpy(VARDATA(new_text), VARDATA(arg1), VARSIZE(arg1) - VARHDRSZ);
-    memcpy(VARDATA(new_text) + (VARSIZE(arg1) - VARHDRSZ),
-           VARDATA(arg2), VARSIZE(arg2) - VARHDRSZ);
-    return new_text;
-}
-]]></programlisting>
-    </para>
-
-    <para>
-     En supposant que le code ci-dessus ait été écrit dans le fichier
-     <filename>funcs.c</filename> et compilé en objet partagé, nous pourrions
-     définir les fonctions pour <productname>PostgreSQL</productname> avec des
-     commandes comme ceci&nbsp;:
-     
-<programlisting>CREATE FUNCTION add_one(integer) RETURNS integer
-     AS '<replaceable>DIRECTORY</replaceable>/funcs', 'add_one'
-     LANGUAGE C STRICT;
-
--- notez la surcharge du nom de la fonction SQL "add_one"
-CREATE FUNCTION add_one(double precision) RETURNS double precision
-     AS '<replaceable>DIRECTORY</replaceable>/funcs', 'add_one_float8'
-     LANGUAGE C STRICT;
-
-CREATE FUNCTION makepoint(point, point) RETURNS point
-     AS '<replaceable>DIRECTORY</replaceable>/funcs', 'makepoint'
-     LANGUAGE C STRICT;
-                         
-CREATE FUNCTION copytext(text) RETURNS text
-     AS '<replaceable>DIRECTORY</replaceable>/funcs', 'copytext'
-     LANGUAGE C STRICT;
-
-CREATE FUNCTION concat_text(text, text) RETURNS text
-     AS '<replaceable>DIRECTORY</replaceable>/funcs', 'concat_text'
-     LANGUAGE C STRICT;
-</programlisting>
-    </para>
-
-    <para>
-     Ici, <replaceable>DIRECTORY</replaceable> représente le répertoire
-     contenant le fichier de la bibliothèque partagée (par exemple le répertoire
-     du tutoriel de <productname>PostgreSQL</productname>, qui contient le code
-     des exemples utilisés dans cette section). (Un meilleur style aurait été
-     d'écrire seulement <literal>'funcs'</literal> dans la clause <literal>AS</literal>, après
-     avoir ajouté <replaceable>DIRECTORY</replaceable> au chemin de recherche.
-     Dans tous les cas, nous pouvons omettre l'extension spécifique au système
-     pour les bibliothèques partagées, communément <literal>.so</literal> ou    
-     <literal>.sl</literal>.) 
-    </para>
-
-    <para>
-     Remarquez que nous avons spécifié la fonction comme <quote>STRICT</quote>, 
-     ce qui signifie que le système devra automatiquement supposer un résultat 
-     NULL si n'importe quelle valeur d'entrée est NULL. Ainsi, nous évitons
-     d'avoir à vérifier l'existence d'entrées NULL dans le code de la fonction.
-     Sinon, nous aurions dû contrôler explicitement les valeurs NULL en testant
-     un pointeur NULL pour chaque argument passé par référence (pour les
-     arguments passés par valeur, nous n'aurions même aucun moyen de contrôle&nbsp;!).
-    </para>
-
-    <para>
-     Bien que cette convention d'appel soit simple à utiliser, elle n'est pas
-     très portable&nbsp;; sur certaines architectures,  il y a des problèmes
-     pour passer de cette manière des types de données plus petits
-     que <type>int</type>. De plus, il n'y a pas de moyen simple de renvoyer un
-     résultat NULL, ni de traiter des arguments NULL autrement qu'en rendant la
-     fonction strict. La convention version-1, présentée ci-après, permet de
-     surmonter ces objections.
-    </para>
-    
-   </sect2>
-   
-   <sect2>
-    <title>Conventions d'appel de la version 1</title>
-
-    <para>
-     La convention d'appel version-1 repose sur des macros pour supprimer la
-     plus grande partie de la complexité du passage d'arguments et de résultats.
-     La déclaration C d'une fonction en version-1 est toujours&nbsp;:
-
-<programlisting>Datum nom_fonction(PG_FUNCTION_ARGS)
-</programlisting>
-
-     De plus, la macro d'appel&nbsp;:
-<programlisting>PG_FUNCTION_INFO_V1(nom_fonction);
-</programlisting>
-     doit apparaître dans le même fichier source (par convention, elle est
-     écrite juste avant la fonction elle-même). Cette macro n'est pas nécessaire
-     pour les fonctions <literal>internal</literal> puisque <productname>PostgreSQL</productname> 
-     assume que toutes les fonctions internes utilisent la convention version-1.
-     Elle est toutefois requise pour les fonctions chargées dynamiquement.
-    </para>
-
-    <para>
-     Dans une fonction version-1, chaque argument existant est traité par une
-     macro <function>PG_GETARG_<replaceable>xxx</replaceable>()</function> 
-     correspondant au type de donnée de l'argument et le résultat est renvoyé
-     par une macro
-     <function>PG_RETURN_<replaceable>xxx</replaceable>()</function>
-     correspondant au type renvoyé. 
-     <function>PG_GETARG_<replaceable>xxx</replaceable>()</function>
-     prend comme argument le nombre d'arguments de la fonction à parcourir, le
-     compteur commençant à 0.
-     <function>PG_RETURN_<replaceable>xxx</replaceable>()</function> prend comme
-     argument la valeur effective à renvoyer. 
-    </para>
-
-    <para>
-     Voici la même fonction que précédemment, codée en style version-1
-     
-<programlisting><![CDATA[#include "postgres.h"
-#include <string.h>
-#include "fmgr.h"
-
-/* par valeur */
-
-PG_FUNCTION_INFO_V1(add_one);
-         
-Datum
-add_one(PG_FUNCTION_ARGS)
-{
-    int32   arg = PG_GETARG_INT32(0);
-
-    PG_RETURN_INT32(arg + 1);
-}
-
-/* par référence, longueur fixe */
-
-PG_FUNCTION_INFO_V1(add_one_float8);
-
-Datum
-add_one_float8(PG_FUNCTION_ARGS)
-{
-    /* La macro pour FLOAT8 cache sa nature de passage par référence. */
-    float8   arg = PG_GETARG_FLOAT8(0);
-
-    PG_RETURN_FLOAT8(arg + 1.0);
-}
-
-PG_FUNCTION_INFO_V1(makepoint);
-
-Datum
-makepoint(PG_FUNCTION_ARGS)
-{
-    /* Ici, la nature de passage par référence de Point n'est pas cachée. */
-    Point     *pointx = PG_GETARG_POINT_P(0);
-    Point     *pointy = PG_GETARG_POINT_P(1);
-    Point     *new_point = (Point *) palloc(sizeof(Point));
-
-    new_point->x = pointx->x;
-    new_point->y = pointy->y;
-       
-    PG_RETURN_POINT_P(new_point);
-}
-
-/* par référence, longueur variable */
-
-PG_FUNCTION_INFO_V1(copytext);
-
-Datum
-copytext(PG_FUNCTION_ARGS)
-{
-    text     *t = PG_GETARG_TEXT_P(0);
-    /*
-     * VARSIZE est la longueur totale de la structure en octets.
-     */
-    text     *new_t = (text *) palloc(VARSIZE(t));
-    SET_VARSIZE(new_t, VARSIZE(t));
-    /*
-     * VARDATA est un pointeur vers la région de données de la structure.
-     */
-    memcpy((void *) VARDATA(new_t), /* destination */
-           (void *) VARDATA(t),     /* source */
-           VARSIZE(t) - VARHDRSZ);    /* nombre d'octets */
-    PG_RETURN_TEXT_P(new_t);
-}
-
-PG_FUNCTION_INFO_V1(concat_text);
-
-Datum
-concat_text(PG_FUNCTION_ARGS)
-{
-    text  *arg1 = PG_GETARG_TEXT_P(0);
-    text  *arg2 = PG_GETARG_TEXT_P(1);
-    int32 new_text_size = VARSIZE(arg1) + VARSIZE(arg2) - VARHDRSZ;
-    text *new_text = (text *) palloc(new_text_size);
-
-    SET_VARSIZE(new_text, new_text_size);
-    memcpy(VARDATA(new_text), VARDATA(arg1), VARSIZE(arg1) - VARHDRSZ);
-    memcpy(VARDATA(new_text) + (VARSIZE(arg1) - VARHDRSZ),
-           VARDATA(arg2), VARSIZE(arg2) - VARHDRSZ);
-    PG_RETURN_TEXT_P(new_text);
-}
-]]></programlisting>
-    </para>
-
-    <para>
-     Les commandes <command>CREATE FUNCTION</command> sont les mêmes que pour
-     leurs équivalents dans la version-0.
-    </para>
-        
-    <para>
-     Au premier coup d'&oelig;il, les conventions de codage de la version-1 peuvent
-     sembler inutilement obscures. Pourtant, elles offrent nombre
-     d'améliorations car les macros peuvent cacher les détails superflus. Un
-     exemple est donné par la fonction  <function>add_one_float8</function> où nous
-     n'avons plus besoin de prêter attention au fait que le type
-     <type>float8</type> est passé par référence. Un autre exemple de
-     simplification est donné par les macros pour les types à longueur variable
-     <literal>GETARG</literal> qui permettent un traitement plus efficace des valeurs 
-     <quote>toasted</quote> (compressées ou hors-ligne).  
-    </para>
-    
-    <para>
-     Une des grandes améliorations dans les fonctions version-1 est le meilleur
-     traitement des entrées et des résultats NULL. La macro  
-     <function>PG_ARGISNULL(<replaceable>n</replaceable>)</function> permet à une fonction
-     de tester si chaque entrée est NULL (évidemment, ceci n'est nécessaire que
-     pour les fonctions déclarées non <quote>STRICT</quote>). Comme avec les macros
-     <function>PG_GETARG_<replaceable>xxx</replaceable>()</function>, les
-     arguments en entrée sont comptés à partir de zéro. Notez qu'on doit se
-     garder d'exécuter
-     <function>PG_GETARG_<replaceable>xxx</replaceable>()</function> jusqu'à 
-     ce qu'on ait vérifié que l'argument n'est pas NULL. Pour renvoyer un
-     résultat NULL, exécutez la fonction
-     <function>PG_RETURN_NULL()</function>&nbsp;; ceci convient aussi bien dans
-     les fonctions STRICT que non STRICT.
-    </para>
-    
-    <para>  
-     Les autres options proposées dans l'interface de nouveau style sont deux
-     variantes des macros 
-     <function>PG_GETARG_<replaceable>xxx</replaceable>()</function>. La
-     première d'entre elles,
-     <function>PG_GETARG_<replaceable>xxx</replaceable>_COPY()</function>,  
-     garantit le renvoi d'une copie de l'argument spécifié où nous pouvons
-     écrire en toute sécurité (les macros normales peuvent parfois renvoyer 
-     un pointeur vers une valeur physiquement mise en mémoire dans une table qui
-     ne doit pas être modifiée. En utilisant les macros
-     <function>PG_GETARG_<replaceable>xxx</replaceable>_COPY()</function>, on
-     garantit l'écriture du résultat). La seconde variante se compose des macros
-     <function>PG_GETARG_<replaceable>xxx</replaceable>_SLICE()</function>
-     qui prennent trois arguments. Le premier est le nombre d'arguments de la
-     fonction (comme ci-dessus). Le second et le troisième sont le décalage et
-     la longueur du segment qui doit être renvoyé. Les décalages sont comptés à
-     partir de zéro et une longueur négative demande le renvoi du reste de la
-     valeur. Ces macros procurent un accès plus efficace à des parties de
-     valeurs à grande dimension dans le cas où elles ont un type de stockage en
-     mémoire <quote>external</quote> (le type de stockage d'une colonne peut
-     être spécifié en utilisant <literal>ALTER TABLE
-     <replaceable>nom_table</replaceable> ALTER COLUMN
-     <replaceable>nom_colonne</replaceable> SET STORAGE
-     <replaceable>typestockage</replaceable></literal>.
-     <replaceable>typestockage</replaceable> est un type parmi
-     <literal>plain</literal>, <literal>external</literal>, <literal>extended</literal> ou
-     <literal>main</literal>).
-    </para>
-
-    <para> 
-     Enfin, les conventions d'appels de la version-1 rendent possible le renvoi
-     de résultats d'ensemble (<xref linkend="xfunc-c-return-set"/>),
-     l'implémentation de fonctions déclencheurs (<xref
-     linkend="triggers"/>) et d'opérateurs d'appel de langage procédural (<xref
-     linkend="plhandler"/>). Le code version-1 est aussi plus portable que celui
-     de version-0 car il ne contrevient pas aux restrictions du protocole
-     d'appel de fonction en C standard. Pour plus de détails, voir
-     <filename>src/backend/utils/fmgr/README</filename> dans les fichiers 
-     sources de la distribution.
-    </para>
-     
-   </sect2>
-
-   <sect2>
-    <title>Écriture du code</title>
-
-    <para>
-     Avant de nous intéresser à des sujets plus avancés, nous devons discuter de
-     quelques règles de codage des fonctions en langage C de
-     <productname>PostgreSQL</productname>.  Bien qu'il soit possible de charger
-     des fonctions écrites dans des langages autre que le C dans
-     <productname>PostgreSQL</productname>, c'est habituellement difficile
-     (quand c'est possible) parce que les autres langages comme C++, FORTRAN ou
-     Pascal ne suivent pas fréquemment les mêmes conventions de nommage que le
-     C. C'est-à-dire que les autres langages ne passent pas les arguments et ne 
-     renvoient pas les valeurs entre fonctions de la même manière. Pour cette
-     raison, nous supposerons que nos fonctions en langage C sont réellement
-     écrites en C.
- </para>
-    <para>
-     Les règles de base pour l'écriture de fonctions C sont les suivantes&nbsp;:
-
-     <itemizedlist>
-      <listitem>
-       <para>
-        Utilisez <literal>pg_config
-        --includedir-server</literal><indexterm><primary>pg_config</primary><secondary>
-        avec des fonctions C définies par l'utilisateur</secondary></indexterm> pour découvrir où
-        sont installés les fichiers d'en-tête du serveur
-        <productname>PostgreSQL</productname> sur votre système (ou sur le système de vos
-        utilisateurs).
-       </para>
-      </listitem>
-
-      <listitem>
-       <para>
-        Compilez et liez votre code de façon à ce qu'il soit chargé dynamiquement
-	dans <productname>PostgreSQL</productname>, ce qui requiert des informations
-	spéciales. Voir <xref linkend="dfunc"/> pour une explication détaillée
-	sur la façon de le faire pour votre système d'exploitation spécifique.
-       </para>
-      </listitem>
-
-      <listitem>
-       <para>
-        Rappelez-vous to définir un <quote>bloc magique</quote> pour votre
-	bibliothèque partagée, comme décrit dans <xref linkend="xfunc-c-dynload"/>.
-       </para>
-      </listitem>
-
-      <listitem>
-       <para>
-        Quand vous allouez de la mémoire, utilisez les fonctions 
-        <productname>PostgreSQL</productname>
-        <function>palloc</function><indexterm><primary>palloc</primary></indexterm> et
-        <function>pfree</function><indexterm><primary>pfree</primary></indexterm>
-        au lieu des fonctions correspondantes <function>malloc</function> et
-        <function>free</function> de la bibliothèque C. La mémoire allouée par
-        <function>palloc</function> sera libérée automatiquement à la fin de
-        chaque transaction, empêchant des débordements de mémoire. 
-       </para>
-      </listitem>
-
-      <listitem>
-       <para>
-        Remettez toujours à zéro les octets de vos structures en utilisant
-        <function>memset</function>. Sinon, il est difficile de supporter les
-        index ou les jointures de découpage car vous devez retenir seulement
-        les bits significatifs de votre structure de donnée pour calculer un
-        découpage. Même si vous initialisez tous les champs de votre structure,
-        il peut y avoir des remplissages d'alignement (trous dans la structure)
-        pouvant contenir des valeurs parasites.
-       </para>
-      </listitem>
-
-      <listitem>
-       <para>
-        La plupart des types internes <productname>PostgreSQL</productname>
-        sont déclarés dans <filename>postgres.h</filename> alors que les
-        interfaces de gestion des fonctions
-        (<symbol>PG_FUNCTION_ARGS</symbol>, etc.) sont dans 
-        <filename>fmgr.h</filename>. Du coup, vous aurez besoin d'inclure au
-        moins ces deux fichiers. Pour des raisons de portabilité, il vaut
-        mieux inclure <filename>postgres.h</filename> <emphasis>en premier</emphasis>
-        avant tout autre fichier d'en-tête système ou utilisateur. En incluant
-        <filename>postgres.h</filename>, il incluera également
-        <filename>elog.h</filename> et <filename>palloc.h</filename> pour vous.
-       </para>
-      </listitem>
-
-      <listitem>
-       <para>
-        Les noms de symboles définis dans les objets ne doivent pas entrer en
-        conflit entre eux ou avec les symboles définis dans les exécutables du
-        serveur <productname>PostgreSQL</productname>. Vous aurez à renommer vos
-        fonctions ou variables si vous recevez un message d'erreur à cet effet.
-       </para>
-      </listitem>
-     </itemizedlist>
-    </para>
-   </sect2>
-
-&dfunc;
-
-<sect2 id="xfunc-c-pgxs">
-  <title>Infrastructure de construction d'extensions</title>
-
-  <indexterm zone="xfunc-c-pgxs">
-    <primary>pgxs</primary>
-  </indexterm>
-
-  <para>
-    Si vous pensez distribuer vos modules d'extension
-    <productname>PostgreSQL</productname>, configurer un système de construction
-    portable peut être assez compliqué. Du coup, l'installation de
-    <productname>PostgreSQL</productname> fournit une infrastructure de construction pour
-    les extensions, appelée <acronym>PGXS</acronym>, pour que les modules
-    d'extension simples puissent être construit simplement avec un serveur
-    déjà installé. Notez que cette infrastructure n'a pas pour but d'être un
-    ensemble de travail universel pouvant être utilisé pour construire tous
-    les logiciels s'interfaçant avec <productname>PostgreSQL</productname>&nbsp;; il
-    automatise simplement les règles de construction communes pour les modules
-    simples d'extension du serveur. Pour des paquetages plus complexes, vous
-    aurez besoin d'écrire votre propre système de construction.
-  </para>
-
-  <para>
-    Pour utiliser l'infrastructure de votre extension, vous devez écrire un
-    simple fichier makefile. Dans ce fichier, vous devez configurer quelques
-    variables et inclure enfin le makefile global <acronym>PGXS</acronym>.
-    Voici un exemple qui construit un module d'extension nommé
-    <literal>isbn_issn</literal> consistant en une bibliothèque partagée, un
-    script SQL et un fichier texte de documentation&nbsp;:
-<programlisting>MODULES = isbn_issn
-DATA_built = isbn_issn.sql
-DOCS = README.isbn_issn
-    
-PG_CONFIG := pg_config
-PGXS := $(shell $(PG_CONFIG) --pgxs)
-include $(PGXS)
-</programlisting>
-    Les trois dernières lignes devraient toujours être identiques. Plus tôt
-    dans le fichier, vous affectez des variables ou ajoutez vos propres règles
-    pour <application>make</application>.
-  </para>
-
-  <para>
-    Les variables suivantes peuvent être configurées&nbsp;:
-  
-  <variablelist>
-    <varlistentry>
-      <term><varname>MODULES</varname></term>
-      <listitem>
-        <para>
-          liste des objets partagés à construire à partir du fichier source
-          de même base (ne pas inclure le suffixe dans cette liste)
-        </para>
-      </listitem>
-    </varlistentry>
-    
-    <varlistentry>
-      <term><varname>DATA</varname></term>
-      <listitem>
-        <para>
-          fichiers spécifiques à installer dans
-          <literal><replaceable>prefix</replaceable>/share/contrib</literal>
-        </para>
-      </listitem>
-    </varlistentry>
-    
-    <varlistentry>
-      <term><varname>DATA_built</varname></term>
-      <listitem>
-        <para>
-          fichiers spécifiques à installer dans
-          <literal><replaceable>prefix</replaceable>/share/contrib</literal>
-          qui ont besoin d'être construit au début
-        </para>
-      </listitem>
-    </varlistentry>
-    
-    <varlistentry>
-      <term><varname>DOCS</varname></term>
-      <listitem>
-        <para>
-          fichiers spécifiques à installer dans
-          <literal><replaceable>prefix</replaceable>/doc/contrib</literal>
-        </para>
-      </listitem>
-    </varlistentry>
-    
-    <varlistentry>
-      <term><varname>SCRIPTS</varname></term>
-      <listitem>
-        <para>
-          fichiers script (pas des binaires) à installer dans
-          <literal><replaceable>prefix</replaceable>/bin</literal>
-        </para>
-      </listitem>
-    </varlistentry>
-    
-    <varlistentry>
-      <term><varname>SCRIPTS_built</varname></term>
-      <listitem>
-        <para>
-          fichiers script (pas des binaires) à installer dans
-          <literal><replaceable>prefix</replaceable>/bin</literal>
-          qui ont besoin d'être construit au début
-        </para>
-      </listitem>
-    </varlistentry>
-    
-    <varlistentry>
-      <term><varname>REGRESS</varname></term>
-      <listitem>
-        <para>
-          liste des cas de tests de regression (sans suffixe), voir ci-dessous
-        </para>
-      </listitem>
-    </varlistentry>
-  </variablelist>
-  
-    ou au moins un parmi ces deux-là&nbsp;:
-  
-  <variablelist>
-    <varlistentry>
-      <term><varname>PROGRAM</varname></term>
-      <listitem>
-        <para>
-          un programme binaire à construire (liste des fichiers objets dans
-          <varname>OBJS</varname>)
-        </para>
-      </listitem>
-    </varlistentry>
-    
-    <varlistentry>
-      <term><varname>MODULE_big</varname></term>
-      <listitem>
-        <para>
-          un objet partagé à construire (liste des fichiers objets dans
-          <varname>OBJS</varname>)
-        </para>
-      </listitem>
-    </varlistentry>
-  </variablelist>
-  
-    Ce qui suit peut être configuré&nbsp;:
-  
-  <variablelist>
-    
-    <varlistentry>
-      <term><varname>EXTRA_CLEAN</varname></term>
-      <listitem>
-        <para>
-          fichiers supplémentaires à supprimer dans <literal>make
-          clean</literal>
-        </para>
-      </listitem>
-    </varlistentry>
-    
-    <varlistentry>
-      <term><varname>PG_CPPFLAGS</varname></term>
-      <listitem>
-        <para>
-          sera ajouté à <varname>CPPFLAGS</varname>
-        </para>
-      </listitem>
-    </varlistentry>
-    
-    <varlistentry>
-      <term><varname>PG_LIBS</varname></term>
-      <listitem>
-        <para>
-          sera ajouté à la ligne de liens <varname>PROGRAM</varname>
-        </para>
-      </listitem>
-    </varlistentry>
-    
-    <varlistentry>
-      <term><varname>SHLIB_LINK</varname></term>
-      <listitem>
-        <para>
-          sera ajouté à la ligne de lien <varname>MODULE_big</varname>
-        </para>
-      </listitem>
-    </varlistentry>
-
-     <varlistentry>
-      <term><varname>PG_CONFIG</varname></term>
-      <listitem>
-       <para>
-        chemin vers le programme <application>pg_config</application> indiquant
-        l'installation de <productname>PostgreSQL</productname> qui sert à la
-	construction (généralement <literal>pg_config</literal> pour utiliser
-	le premier programme trouvé dans la variable d'environnement
-        <varname>PATH</varname>)
-       </para>
-      </listitem>
-     </varlistentry>
-  </variablelist>
-
-  </para>
-
-  <para>
-    Nommez ce fichier <literal>Makefile</literal> et placez le dans le répertoire
-    qui contient votre extension. Ensuite, vous pouvez lancer la compilation
-    avec <literal>make</literal>, et plus tard <literal>make
-    install</literal> pour installer votre module. Par défaut, l'extension est
-    compilée et installée pour l'installation de
-    <productname>PostgreSQL</productname> qui correspond au premier programme
-    <command>pg_config</command> trouvée dans votre chemin. Vous pouvez utiliser
-    utiliser une autre installation en configurant <varname>PG_CONFIG</varname>
-    pour qu'il pointe vers le bon <command>pg_config</command>, soit dans le
-    fichier Makefile soit sur la ligne de commande de <literal>make</literal>.
-  </para>
-  
-   <caution>
-    <para>
-     Modifier <varname>PG_CONFIG</varname> fonctionne seulement en construisant
-     à partir d'une installation <productname>PostgreSQL</productname> 8.3 ou
-     ultérieure. Les anciennes versions ne l'utilisent pas&nbsp;; vous devez
-     donc modifier votre variable <varname>PATH</varname> pour sélectionner
-     la bonne installation.
-    </para>
-   </caution>
-
-   <para>
-    Les scripts listés dans la variable <varname>REGRESS</varname> sont utilisés
-    pour les tests de régression de votre module, tout comme <literal>make
-    installcheck</literal> est utilisé pour votre serveur
-    <productname>PostgreSQL</productname>. Pour que ceci fonctionne, vous avez
-    besoin d'avoir un sous-répertoire nommé <literal>sql/</literal> dans le
-    répertoire de votre extension, à l'intérieur duquel vous placez un fichier
-    pour chaque groupe de tests que vous voulez exécuter. Les fichiers doivent
-    avoir l'extension <literal>.sql</literal>, qui ne seront pas inclus dans la
-    liste <varname>REGRESS</varname> dans le Makefile. Pour chaque test, il doit
-    exister un fichier contenant le résultat attendu dans un sous-répertoire nommé
-    <literal>expected/</literal>, avec l'extension <literal>.out</literal>. Les
-    tests sont exécutés via <literal>make installcheck</literal>, et le résultat sera
-    comparé aux fichiers attendus. Les différences seront écrites dans le fichier
-    <literal>regression.diffs</literal> dans un format <command>diff -c</command>.
-    Notez qu'essayer d'exécuter un test à qui il manque le fichier sera rapporté
-    comme un <quote>problème</quote>, donc assurez-vous que vous avez bien tous les
-    fichiers attendus.
-   </para>
-
-   <tip>
-    <para>
-     La façon la plus simple de créer les fichiers attendus est de créer des
-     fichiers vides, puis de vérifier avec précaution les fichiers résultants
-     après un test d'exécution (à trouver dans un répertoire
-     <literal>results/</literal>), et les copier dans
-     <literal>expected/</literal> s'ils correspondent à votre souhait suite aux
-     tests.
-    </para>
-   </tip>
-  </sect2>
-
-
-   <sect2>
-    <title>Arguments de type composite</title>
-    
-    <para>
-     Les types composites n'ont pas une organisation fixe comme les structures
-     en C. Des instances d'un type composite peuvent contenir des champs NULL.
-     De plus, les types composites faisant partie d'une hiérarchie d'héritage
-     peuvent avoir des champs différents des autres membres de la même
-     hiérarchie. En conséquence, <productname>PostgreSQL</productname> propose
-     une interface de fonction pour accéder depuis le C aux champs des types 
-     composites. 
-    </para>
-
-    <para>
-     Supposons que nous voulions écrire une fonction pour répondre à la requête&nbsp;:
-<programlisting>SELECT nom, c_surpaye(emp, 1500) AS surpaye
-    FROM emp
-    WHERE nom = 'Bill' OR nom = 'Sam';
-</programlisting>
-
-     En utilisant les conventions d'appel de la version 0, nous pouvons définir
-     <function>c_surpaye</function> comme&nbsp;:
-     
-<programlisting><![CDATA[#include "postgres.h"
-#include "executor/executor.h"  /* pour GetAttributeByName() */
-
-bool
-c_surpaye(HeapTupleHeader *t, /* la ligne courante d'emp */
-           int32 limite)
-{
-    bool isNULL;
-    int32 salaire;
-
-    salaire = DatumGetInt32(GetAttributeByName(t, "salaire", &isNULL));
-    if (isNULL)
-        return false;
-    return salaire > limite;
-}
-]]></programlisting>
-
-     Dans le codage version-1, le code ci-dessus devient&nbsp;:
-
-<programlisting><![CDATA[#include "postgres.h"
-#include "executor/executor.h"  /* pour GetAttributeByName() */
-
-PG_FUNCTION_INFO_V1(c_overpaid);
-
-Datum
-c_overpaid(PG_FUNCTION_ARGS)
-{
-    HeapTupleHeader  *t = (HeapTupleHeader *) PG_GETARG_HEAPTUPLEHEADER(0);
-    int32            limite = PG_GETARG_INT32(1);
-    bool isNULL;
-    Datum salaire;
-
-    salaire = GetAttributeByName(t, "salaire", &isNULL);
-    if (isNULL)
-        PG_RETURN_BOOL(false);
-    /* Autrement, nous pourrions préférer de lancer PG_RETURN_NULL() pour un
-       salaire NULL.
-    */
-
-    PG_RETURN_BOOL(DatumGetInt32(salaire) > limite);
-}
-]]></programlisting>
-    </para>
-
-    <para>
-     <function>GetAttributeByName</function> est la fonction système
-     <productname>PostgreSQL</productname> qui renvoie les attributs depuis une
-     colonne spécifiée. Elle a trois arguments&nbsp;: l'argument de type
-     <type>HeapTupleHeader</type> passé à la fonction, le nom de l'attribut
-     recherché et un paramètre de retour qui indique si l'attribut est NULL.  
-     <function>GetAttributeByName</function> renvoie une valeur de type
-     <type>Datum</type> que vous pouvez convertir dans un type voulu en
-     utilisant la macro appropriée
-     <function>DatumGet<replaceable>XXX</replaceable>()</function>. Notez que
-     la valeur de retour est insignifiante si le commutateur NULL est
-     positionné&nbsp;; il faut toujours vérifier le commutateur NULL avant de commencer
-     à faire quelque chose avec le résultat.
-    </para> 
-    
-    <para>
-     Il y a aussi <function>GetAttributeByNum</function>, qui sélectionne
-     l'attribut cible par le numéro de colonne au lieu de son nom.
-    </para>
-    
-    <para> 
-     La commande suivante déclare la fonction <function>c_surpaye</function>
-     en SQL&nbsp;:
-
-<programlisting>CREATE FUNCTION c_surpaye(emp, integer) RETURNS boolean
-    AS '<replaceable>DIRECTORY</replaceable>/funcs', 'c_surpaye'
-    LANGUAGE C STRICT;
-</programlisting>
-
-     Notez que nous avons utilisé <literal>STRICT</literal> pour que nous n'ayons pas à
-     vérifier si les arguments en entrée sont NULL.
-    </para>
-   </sect2>
-
-   <sect2>
-    <title>Renvoi de lignes (types composites)</title>
-     
-    <para>
-     Pour renvoyer une ligne ou une valeur de type composite à partir d'une
-     fonction en langage C, vous pouvez utiliser une API spéciale qui fournit
-     les macros et les fonctions dissimulant en grande partie la complexité
-     liée à la construction de types de données composites. Pour utiliser cette
-     API, le fichier source doit inclure&nbsp;:
- <programlisting>#include "funcapi.h"</programlisting>
-    </para>
-
-    <para>
-	 Il existe deux façons de construire une valeur de données composites 
-	 (autrement dit un <quote>tuple</quote>)&nbsp;: vous pouvez le construire à
-	 partir d'un tableau de valeurs Datum ou à partir d'un tableau de
-	 chaînes C qui peuvent passer dans les fonctions de conversion des types
-	 de données du tuple. Quelque soit le cas, vous avez d'abord besoin
-	 d'obtenir et de construire un descripteur <structname>TupleDesc</structname> pour
-	 la structure du tuple. En travaillant avec des Datums, vous passez le
-     <structname>TupleDesc</structname> à <function>BlessTupleDesc</function>, puis vous appelez
-     <function>heap_form_tuple</function> pour chaque ligne. En travaillant avec des
-     chaînes C, vous passez <structname>TupleDesc</structname> à
-     <function>TupleDescGetAttInMetadata</function>, puis vous appelez
-     <function>BuildTupleFromCStrings</function> pour chaque ligne. Dans le cas d'une
-     fonction renvoyant un ensemble de tuple, les étapes de configuration
-     peuvent toutes être entreprises une fois lors du premier appel à la
-     fonction.
-    </para>
-
-    <para>
-     Plusieurs fonctions d'aide sont disponibles pour configurer le
-     <structname>TupleDesc</structname> requis. La façon recommandée de le faire dans la 
-     plupart des fonctions renvoyant des valeurs composites est d'appeler&nbsp;:
-<programlisting>TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo,
-                                   Oid *resultTypeId,
-                                   TupleDesc *resultTupleDesc)
-</programlisting>
-     en passant la même structure <literal>fcinfo</literal> que celle passée à la
-     fonction appelante (ceci requiert bien sûr que vous utilisez les
-     conventions d'appel version-1). <varname>resultTypeId</varname> peut être
-     spécifié comme <literal>NULL</literal> ou comme l'adresse d'une variable locale
-     pour recevoir l'OID du type de résultat de la fonction.
-     <varname>resultTupleDesc</varname> devrait être l'adresse d'une variable
-     <structname>TupleDesc</structname> locale. Vérifiez que le résultat est
-     <literal>TYPEFUNC_COMPOSITE</literal>&nbsp;; dans ce cas,
-     <varname>resultTupleDesc</varname> a été rempli avec le
-     <structname>TupleDesc</structname> requis (si ce n'est pas le cas, vous pouvez
-     rapporter une erreur pour une <quote>fonction renvoyant un enregistrement
-     appelé dans un contexte qui ne peut pas accepter ce type
-     enregistrement</quote>).
-    </para>
-
-    <tip>
-     <para>
-      <function>get_call_result_type</function> peut résoudre le vrai type du
-      résultat d'une fonction polymorphique&nbsp;; donc, il est utile pour les
-      fonctions qui renvoient des résultats scalaires polymorphiques, pas
-      seulement les fonctions qui renvoient des types composites. Le résultat
-      <varname>resultTypeId</varname> est principalement utile pour les fonctions
-      renvoyant des scalaires polymorphiques.
-     </para>
-    </tip>
-
-    <note>
-     <para>
-      <function>get_call_result_type</function> a une fonction cousine
-      <function>get_expr_result_type</function>, qui peut être utilisée pour résoudre
-      le tupe attendu en sortie en un appel de fonction représenté par
-      un arbre d'expressions. Ceci peut être utilisé pour tenter de déterminer
-      le type de résultat sans entrer dans la fonction elle-même. Il existe
-      aussi <function>get_func_result_type</function>, qui peut seulement être utilisée
-      quand l'OID de la fonction est disponible. Néanmoins, ces fonctions ne
-      sont pas capables de gérer les fonctions déclarées renvoyer des
-      enregistrements (<structname>record</structname>).
-      <function>get_func_result_type</function> ne peut pas résoudre les types
-      polymorphiques, donc vous devriez utiliser de préférence
-      <function>get_call_result_type</function>.
-     </para>
-    </note>
-
-    <para>
-     Les fonctions anciennes, et maintenant obsolètes, qui permettent d'obtenir des
-     <structname>TupleDesc</structname> sont&nbsp;:
-<programlisting>TupleDesc RelationNameGetTupleDesc(const char *relname)
-</programlisting>
-    pour obtenir un <structname>TupleDesc</structname> pour le type de ligne d'une
-    relation nommée ou&nbsp;:
-<programlisting>TupleDesc TypeGetTupleDesc(Oid typeoid, List *colaliases)
-</programlisting>
-     pour obtenir une <structname>TupleDesc</structname> basée sur l'OID d'un type. Ceci
-     peut être utilisé pour obtenir un <structname>TupleDesc</structname> soit pour un
-     type de base, soit pour un type composite. Néanmoins, cela ne fonctionnera
-     pas pour une fonction qui renvoie <structname>record</structname> et cela ne résoudra
-     pas les types polymorphiques.
-    </para>
-
-    <para>
-	 Une fois que vous avez un <structname>TupleDesc</structname>, appelez&nbsp;:
-<programlisting>TupleDesc BlessTupleDesc(TupleDesc tupdesc)
-</programlisting>
-     si vous pensez travailler avec des Datums ou&nbsp;:
-<programlisting>AttInMetadata *TupleDescGetAttInMetadata(TupleDesc tupdesc)
-</programlisting>
-     si vous pensez travailler avec des chaînes C. Si vous écrivez une
-     fonction renvoyant un ensemble, vous pouvez sauvegarder les résultats
-     de ces fonctions dans la structure dans le
-     <structname>FuncCallContext</structname> &mdash; utilisez le champ
-     <structfield>tuple_desc</structfield> ou <structfield>attinmeta</structfield> respectivement.
-    </para>
-
-    <para>
-	 Lorsque vous fonctionnez avec des Datums, utilisez&nbsp;:
-<programlisting>HeapTuple heap_form_tuple(TupleDesc tupdesc, Datum *values, bool *isnull)
-</programlisting>
-	 pour construire une donnée utilisateur <structname>HeapTuple</structname> indiquée
-	 dans le format Datum.
-    </para>
-
-    <para>
-	 Lorsque vous travaillez avec des chaînes C, utilisez&nbsp;:
-<programlisting>HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
-</programlisting>
-	 pour construire une donnée utilisateur <structname>HeapTuple</structname> indiquée
-	 dans le format des chaînes C. <literal>values</literal> est un tableau de
-	 chaîne C, une pour chaque attribut de la ligne renvoyée. Chaque chaîne
-	 C doit être de la forme attendue par la fonction d'entrée du type de
-	 donnée de l'attribut. Afin de renvoyer une valeur NULL pour un des
-	 attributs, le pointeur correspondant dans le tableau de valeurs
-	 (<parameter>values</parameter>) doit être fixé à <symbol>NULL</symbol>. Cette fonction
-	 demandera à être appelée pour chaque ligne que vous renvoyez.
-    </para>
-
-    <para>
-     Une fois que vous avez construit un tuple devant être renvoyé par votre
-     fonction, vous devez le convertir en type <type>Datum</type>. Utilisez&nbsp;:
-<programlisting>HeapTupleGetDatum(HeapTuple tuple)
-</programlisting>
-     pour convertir un type <type>HeapTuple</type> en un Datum valide.
-     Ce <type>Datum</type> peut être renvoyé directement si vous envisagez de
-     renvoyer juste une simple ligne ou bien il peut être utilisé pour renvoyer
-     la valeur courante dans une fonction renvoyant un ensemble.
-  </para>
-
-    <para>
-     Un exemple figure dans la section suivante.
-    </para>
-
-   </sect2>
-
-   <sect2 id="xfunc-c-return-set">
-    <title>Renvoi d'ensembles</title>
-
-    <para>
-     Il existe aussi une API spéciale procurant le moyen de renvoyer des
-     ensembles (lignes multiples) depuis une fonction en langage C. Une fonction
-     renvoyant un ensemble doit suivre les conventions d'appel de la version-1. 
-     Aussi, les fichiers source doivent inclure l'en-tête
-     <filename>funcapi.h</filename>, comme ci-dessus.
-    </para>
-
-    <para>
-     Une fonction renvoyant un ensemble (<acronym>SRF</acronym> : <quote>set
-     returning function</quote>) est appelée une fois pour chaque élément
-     qu'elle renvoie. La <acronym>SRF</acronym> doit donc sauvegarder suffisamment
-     l'état pour se rappeler ce qu'elle était en train de faire et renvoyer le
-     prochain élément à chaque appel. La structure
-     <structname>FuncCallContext</structname> est offerte pour assister le contrôle de ce
-     processus. À l'intérieur d'une fonction,
-     <literal>fcinfo-&gt;flinfo-&gt;fn_extra</literal> est utilisée pour conserver un
-     pointeur vers <structname>FuncCallContext</structname> au cours des appels
-     successifs.
-
-<programlisting>typedef struct
-{
-    /*
-     * Number of times we've been called before
-     * 
-     * call_cntr is initialized to 0 for you by SRF_FIRSTCALL_INIT(), and
-     * incremented for you every time SRF_RETURN_NEXT() is called.
-     */
-    uint32 call_cntr;
-
-    /*
-     * OPTIONAL maximum number of calls
-     *
-     * max_calls is here for convenience only and setting it is optional.
-     * If not set, you must provide alternative means to know when the
-     * function is done.
-     */
-    uint32 max_calls;
-
-    /*
-     * OPTIONAL pointer to result slot
-     * 
-     * This is obsolete and only present for backwards compatibility, viz,
-     * user-defined SRFs that use the deprecated TupleDescGetSlot().
-     */
-    TupleTableSlot *slot;
-
-    /*
-     * OPTIONAL pointer to miscellaneous user-provided context information
-     * 
-     * user_fctx is for use as a pointer to your own data to retain
-     * arbitrary context information between calls of your function.
-     */
-    void *user_fctx;
-
-    /*
-     * OPTIONAL pointer to struct containing attribute type input metadata
-     * 
-     * attinmeta is for use when returning tuples (i.e., composite data types)
-     * and is not used when returning base data types. It is only needed
-     * if you intend to use BuildTupleFromCStrings() to create the return
-     * tuple.
-     */
-    AttInMetadata *attinmeta;
-
-    /*
-     * memory context used for structures that must live for multiple calls
-     *
-     * multi_call_memory_ctx is set by SRF_FIRSTCALL_INIT() for you, and used
-     * by SRF_RETURN_DONE() for cleanup. It is the most appropriate memory
-     * context for any memory that is to be reused across multiple calls
-     * of the SRF.
-     */
-    MemoryContext multi_call_memory_ctx;
-    
-    /*
-    * OPTIONAL pointer to struct containing tuple description
-    *
-    * tuple_desc is for use when returning tuples (i.e. composite data types)
-    * and is only needed if you are going to build the tuples with
-    * heap_form_tuple() rather than with BuildTupleFromCStrings().  Note that
-    * the TupleDesc pointer stored here should usually have been run through
-    * BlessTupleDesc() first.
-    */
-    TupleDesc tuple_desc;
-    
-} FuncCallContext;
-</programlisting>
-    </para>
-
-    <para>
-     Une <acronym>SRF</acronym> utilise plusieurs fonctions et macros qui manipulent
-     automatiquement la structure <structname>FuncCallContext</structname> (et s'attendent
-     à la trouver via <literal>fn_extra</literal>). Utilisez&nbsp;:
-<programlisting>SRF_IS_FIRSTCALL()
-</programlisting>
-     pour déterminer si votre fonction est appelée pour la première fois. Au
-     premier appel, utilisez&nbsp;:
-<programlisting>SRF_FIRSTCALL_INIT()
-</programlisting>
-     pour initialiser la structure <structname>FuncCallContext</structname>. À chaque
-     appel de fonction, y compris le premier, utilisez&nbsp;:
-<programlisting>SRF_PERCALL_SETUP()
-</programlisting>
-     pour une mise à jour correcte en vue de l'utilisation de
-     <structname>FuncCallContext</structname> et pour nettoyer toutes les données
-     renvoyées précédemment et conservées depuis le dernier passage de la
-     fonction.
-    </para>
-
-    <para>
-     Si votre fonction a des données à renvoyer, utilisez&nbsp;:
-<programlisting>SRF_RETURN_NEXT(funcctx, result)
-</programlisting>
-     pour les renvoyer à l'appelant. (<literal>result</literal> doit être de type
-     <type>Datum</type>, soit une valeur simple, soit un tuple préparé comme décrit
-     ci-dessus.) Enfin, quand votre fonction a fini de renvoyer des données,
-     utilisez&nbsp;:
-<programlisting>SRF_RETURN_DONE(funcctx)
-</programlisting>
-     pour nettoyer et terminer la <acronym>SRF</acronym>.
-    </para>
-
-    <para>
-     Lors de l'appel de la <acronym>SRF</acronym>, le contexte mémoire courant est un
-     contexte transitoire qui est effacé entre les appels. Cela signifie que
-     vous n'avez pas besoin d'appeler <function>pfree</function> sur tout ce que vous
-     avez alloué en utilisant <function>palloc</function>&nbsp;; ce sera supprimé de
-     toute façon. Toutefois, si vous voulez allouer des structures de données
-     devant persister tout au long des appels, vous avez besoin de les conserver
-     quelque part. Le contexte mémoire référencé par
-     <structfield>multi_call_memory_ctx</structfield> est un endroit approprié pour toute
-     donnée devant survivre jusqu'à l'achèvement de la fonction <acronym>SRF</acronym>.
-     Dans la plupart des cas, cela signifie que vous devrez basculer vers
-     <structfield>multi_call_memory_ctx</structfield> au moment de la préparation du
-     premier appel.
- </para>  
-   <para>
-     Voici un exemple complet de pseudo-code&nbsp;:
-<programlisting>Datum
-my_set_returning_function(PG_FUNCTION_ARGS)
-{
-    FuncCallContext  *funcctx;
-    Datum             result;
-    MemoryContext     oldcontext;
-    <replaceable>further declarations as needed</replaceable>
-
-    if (SRF_IS_FIRSTCALL())
-    {
-        funcctx = SRF_FIRSTCALL_INIT();
-        oldcontext = MemoryContextSwitchTo(funcctx-&gt;multi_call_memory_ctx);
-        /* One-time setup code appears here: */
-        <replaceable>user code</replaceable>
-        <replaceable>if returning composite</replaceable>
-            <replaceable>build TupleDesc, and perhaps AttInMetadata</replaceable>
-        <replaceable>endif returning composite</replaceable>
-        <replaceable>user code</replaceable>
-        MemoryContextSwitchTo(oldcontext);
-    }
-
-    /* Each-time setup code appears here: */
-    <replaceable>user code</replaceable>
-    funcctx = SRF_PERCALL_SETUP();
-    <replaceable>user code</replaceable>
-
-    /* this is just one way we might test whether we are done: */
-    if (funcctx-&gt;call_cntr &lt; funcctx-&gt;max_calls)
-    {
-        /* Here we want to return another item: */
-        <replaceable>user code</replaceable>
-        <replaceable>obtain result Datum</replaceable>
-        SRF_RETURN_NEXT(funcctx, result);
-    }
-    else
-    {
-        /* Here we are done returning items and just need to clean up: */
-        <replaceable>user code</replaceable>
-        SRF_RETURN_DONE(funcctx);
-    }
-}
-</programlisting>
-    </para>
-
-    <para>
-     Et voici un exemple complet d'une simple <acronym>SRF</acronym> retournant un
-     type composite&nbsp;:
-     <programlisting><![CDATA[PG_FUNCTION_INFO_V1(retcomposite);
-
-Datum
-retcomposite(PG_FUNCTION_ARGS)
-{
-    FuncCallContext     *funcctx;
-    int                  call_cntr;
-    int                  max_calls;
-    TupleDesc            tupdesc;
-    AttInMetadata       *attinmeta;
-
-     /* stuff done only on the first call of the function */
-     if (SRF_IS_FIRSTCALL())
-     {
-        MemoryContext	oldcontext;
-
-        /* create a function context for cross-call persistence */
-        funcctx = SRF_FIRSTCALL_INIT();
-
-        /* switch to memory context appropriate for multiple function calls */
-        oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
-
-        /* total number of tuples to be returned */
-        funcctx->max_calls = PG_GETARG_UINT32(0);
-
-        /* Build a tuple descriptor for our result type */
-        if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
-            ereport(ERROR,
-                    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                     errmsg("function returning record called in context "
-                            "that cannot accept type record")));
-
-        /*
-         * generate attribute metadata needed later to produce tuples from raw
-         * C strings
-         */
-        attinmeta = TupleDescGetAttInMetadata(tupdesc);
-        funcctx->attinmeta = attinmeta;
-
-        MemoryContextSwitchTo(oldcontext);
-    }
-
-    /* stuff done on every call of the function */
-    funcctx = SRF_PERCALL_SETUP();
-
-    call_cntr = funcctx->call_cntr;
-    max_calls = funcctx->max_calls;
-    attinmeta = funcctx->attinmeta;
- 
-    if (call_cntr < max_calls)    /* do when there is more left to send */
-    {
-        char       **values;
-        HeapTuple    tuple;
-        Datum        result;
-
-        /*
-	* Prepare a values array for building the returned tuple.
-         * This should be an array of C strings which will
-         * be processed later by the type input functions.
-         */
-        values = (char **) palloc(3 * sizeof(char *));
-        values[0] = (char *) palloc(16 * sizeof(char));
-        values[1] = (char *) palloc(16 * sizeof(char));
-        values[2] = (char *) palloc(16 * sizeof(char));
-
-        snprintf(values[0], 16, "%d", 1 * PG_GETARG_INT32(1));
-        snprintf(values[1], 16, "%d", 2 * PG_GETARG_INT32(1));
-        snprintf(values[2], 16, "%d", 3 * PG_GETARG_INT32(1));
-
-        /* build a tuple */
-        tuple = BuildTupleFromCStrings(attinmeta, values);
-
-        /* make the tuple into a datum */
-        result = HeapTupleGetDatum(tuple);
-
-        /* clean up (this is not really necessary) */
-        pfree(values[0]);
-        pfree(values[1]);
-        pfree(values[2]);
-        pfree(values);
-
-        SRF_RETURN_NEXT(funcctx, result);
-    }
-    else    /* do when there is no more left */
-    {
-        SRF_RETURN_DONE(funcctx);
-    }
-}
-]]></programlisting>
-
-     Voici une façon de déclarer cette fonction en SQL&nbsp;:
-     
-<programlisting>CREATE TYPE __retcomposite AS (f1 integer, f2 integer, f3 integer);
-
-CREATE OR REPLACE FUNCTION retcomposite(integer, integer)
-    RETURNS SETOF __retcomposite
-    AS '<replaceable>filename</replaceable>', 'retcomposite'
-    LANGUAGE C IMMUTABLE STRICT;
-</programlisting>
-     Une façon différente de le faire est d'utiliser des paramètres OUT&nbsp;:
-<programlisting>CREATE OR REPLACE FUNCTION retcomposite(IN integer, IN integer,
-    OUT f1 integer, OUT f2 integer, OUT f3 integer)
-    RETURNS SETOF record
-    AS '<replaceable>filename</replaceable>', 'retcomposite'
-    LANGUAGE C IMMUTABLE STRICT;
-</programlisting>
-     Notez que dans cette méthode le type en sortie de la fonction est du type
-     <structname>record</structname> anonyme.
-    </para>
-
-    <para>
-     Le répertoire <filename>contrib/tablefunc</filename> situé dans les fichiers source
-     de la distribution contient d'autres exemples de fonctions renvoyant des
-     ensembles.</para>
-   </sect2>
-
-   <sect2>
-    <title>Arguments polymorphes et types renvoyés</title>
-
-    <para>
-     Les fonctions en langage C peuvent être déclarées pour accepter et renvoyer
-     les types <quote>polymorphes</quote> <type>anyelement</type>,
-	 <type>anyarray</type>, <type>anynonarray</type> et <type>anyenum</type>. Voir la <xref linkend="extend-types-polymorphic"/> pour une
-     explication plus détaillée des fonctions polymorphes. Si les types des
-     arguments ou du renvoi de la fonction sont définis comme polymorphes,
-     l'auteur de la fonction ne peut pas savoir à l'avance quel type de données
-     sera appelé ou bien quel type doit être renvoyé. Il y a deux routines
-     offertes par <filename>fmgr.h</filename>  qui permettent à une fonction en
-     version-1 de découvrir les types de données effectifs de ses arguments et
-     le type qu'elle doit renvoyer. Ces routines s'appellent 
-     <literal>get_fn_expr_rettype(FmgrInfo *flinfo)</literal> et 
-     <literal>get_fn_expr_argtype(FmgrInfo *flinfo, int argnum)</literal>. Elles
-     renvoient l'OID du type du résultat ou de l'argument ou InvalidOID si
-     l'information n'est pas disponible. L'accès à la structure
-     <literal>flinfo</literal> se fait normalement avec
-     <literal>fcinfo-&gt;flinfo</literal>. Le paramètre <literal>argnum</literal> est basé à
-     partir de zéro. <function>get_call_result_type</function> peut aussi être utilisé
-     comme alternative à <function>get_fn_expr_rettype</function>.
-    </para>
-    
-    <para>
-     Par exemple, supposons que nous voulions écrire une fonction qui accepte un
-     argument de n'importe quel type et qui renvoie un tableau uni-dimensionnel
-     de ce type&nbsp;:
-
-<programlisting>PG_FUNCTION_INFO_V1(make_array);
-Datum
-make_array(PG_FUNCTION_ARGS)
-{
-    ArrayType  *result;
-    Oid         element_type = get_fn_expr_argtype(fcinfo-&gt;flinfo, 0);
-    Datum       element;
-    bool        isnull;
-    int16       typlen;
-    bool        typbyval;
-    char        typalign;
-    int         ndims;
-    int         dims[MAXDIM];
-    int         lbs[MAXDIM];
-
-    if (!OidIsValid(element_type))
-        elog(ERROR, "could not determine data type of input");
-
-    /* get the provided element, being careful in case it's NULL */
-    isnull = PG_ARGISNULL(0);
-    if (isnull)
-        element = (Datum) 0;
-    else
-        element = PG_GETARG_DATUM(0);
-
-    /* we have one dimension */
-    ndims = 1;
-    /* and one element */
-    dims[0] = 1;
-    /* and lower bound is 1 */
-    lbs[0] = 1;
-
-    /* get required info about the element type */
-    get_typlenbyvalalign(element_type, &amp;typlen, &amp;typbyval,
-&amp;typalign);
-
-    /* now build the array */
-    result = construct_md_array(&amp;element, &amp;isnull, ndims, dims, lbs,
-                                element_type, typlen, typbyval, typalign);
-
-    PG_RETURN_ARRAYTYPE_P(result);
-}
-</programlisting>
-    </para>
-
-    <para>
-     La commande suivante déclare la fonction <function>make_array</function> en
-     SQL&nbsp;:
-
-<programlisting>CREATE FUNCTION make_array(anyelement) 
-    RETURNS anyarray
-    AS '<replaceable>DIRECTORY</replaceable>/funcs', 'make_array'
-    LANGUAGE 'C' IMMUTABLE;
-</programlisting>
-
-     Notez l'utilisation de STRICT&nbsp;; ceci est primordial car le code ne se
-     préoccupe pas de tester une entrée NULL.
-    </para>
-
-    <para>
-     Il existe une variante du polymorphisme qui est seulement disponible pour
-     les fonctions en langage C&nbsp;: elles peuvent être déclarées prendre des
-     paramètres de type <literal>"any"</literal>. (Notez que ce nom de type doit
-     être placé entre des guillemets doubles car il s'agit d'un mot SQL réservé.)
-     Ceci fonctionne comme <type>anyelement</type> sauf qu'il ne contraint pas
-     les différents arguments <literal>"any"</literal> à être du même type, pas
-     plus qu'ils n'aident à déterminer le type de résultat de la fonction. Une
-     fonction en langage C peut aussi déclarer son paramètre final ainsi&nbsp;:
-     <literal>VARIADIC "any"</literal>.  Cela correspondra à un ou plusieurs
-     arguments réels de tout type (pas nécessairement le même type). Ces
-     arguments ne seront <emphasis>pas</emphasis> placés dans un tableau
-     comme c'est le cas pour les fonctions variadic normales&nbsp;; ils seront
-     passés séparément à la fonction. La macro <function>PG_NARGS()</function>
-     et les méthodes décrites ci-dessus doivent être utilisées pour déterminer
-     le nombre d'arguments réels et leur type lors de l'utilisation de cette
-     fonctionnalité.
-    </para>
-   </sect2>
-
-   <sect2>
-    <title>Mémoire partagée et LWLocks</title>
-
-    <para>
-     Les modules peuvent réserver des LWLocks et allouer de la mémoire partagée
-     au lancement du serveur. La bibliothèque partagée du module doit être
-     préchargée en l'ajoutant <xref
-     linkend="guc-shared-preload-libraries"/><indexterm><primary>shared-preload-libraries</primary></indexterm>.
-     La mémoire partagée est réservée en appelant&nbsp;:
-<programlisting>void RequestAddinShmemSpace(int size)
-</programlisting>
-     à partir de votre fonction <function>_PG_init</function>.
-    </para>
-    <para>
-     Les LWLocks sont réservés en appelant&nbsp;:
-<programlisting>
-void RequestAddinLWLocks(int n)
-</programlisting>
-     à partir de <function>_PG_init</function>.
-    </para>	
-    <para>
-     Pour éviter des cas rares possibles, chaque moteur devrait utiliser la
-     fonction <function>AddinShmemInitLock</function> lors de la connexion et
-     de l'initialisation de la mémoire partagée, comme indiquée ci-dessous&nbsp;:
-<programlisting>
-        static mystruct *ptr = NULL;
-
-        if (!ptr)
-        {
-                bool    found;
-
-                LWLockAcquire(AddinShmemInitLock, LW_EXCLUSIVE);
-                ptr = ShmemInitStruct("my struct name", size, &amp;found);
-                if (!ptr)
-                        elog(ERROR, "out of shared memory");
-                if (!found)
-                {
-                        initialize contents of shmem area;
-                        acquire any requested LWLocks using:
-                        ptr->mylockid = LWLockAssign();
-                }
-                LWLockRelease(AddinShmemInitLock);
-        }
-</programlisting>
-    </para>
-   </sect2>
-
-  </sect1>

Copied: traduc/tags/tv840rc1/xfunc.xml (from rev 1350, traduc/trunk/postgresql/xfunc.xml)
===================================================================
--- traduc/tags/tv840rc1/xfunc.xml	                        (rev 0)
+++ traduc/tags/tv840rc1/xfunc.xml	2009-06-23 16:25:46 UTC (rev 1351)
@@ -0,0 +1,3268 @@
+<?xml version="1.0" encoding="ISO-8859-15"?>
+<!-- Dernière modification
+     le       $Date$
+     par      $Author$
+     révision $Revision$ -->
+
+ <sect1 id="xfunc">
+  <title>Fonctions utilisateur</title>
+
+  <indexterm zone="xfunc">
+   <primary>fonction</primary>
+   <secondary>utilisateur</secondary>
+  </indexterm>
+
+  <para>
+   <productname>PostgreSQL</productname> propose quatre types de
+    fonctions&nbsp;:
+
+   <itemizedlist>
+    <listitem>
+     <para>
+      fonctions en langage de requête (fonctions écrites en <acronym>SQL</acronym>,
+      <xref linkend="xfunc-sql"/>)
+     </para>
+    </listitem>
+    <listitem>
+     <para>
+      fonctions en langage procédural (fonctions écrites, par exemple, en
+      <application>PL/pgSQL</application> ou <application>PL/Tcl</application>,
+      <xref linkend="xfunc-pl"/>)
+     </para>
+    </listitem>
+    <listitem>
+     <para>
+      fonctions internes (<xref linkend="xfunc-internal"/>)
+     </para>
+    </listitem>
+    <listitem>
+     <para>
+      fonctions en langage C (<xref linkend="xfunc-c"/>)
+     </para>
+    </listitem>
+   </itemizedlist>
+  </para>
+
+  <para>
+   Chaque type de fonction peut accepter comme arguments (paramètres) des types
+   de base, des types composites ou une combinaison de ceux-ci. De plus, chaque
+   sorte de fonction peut renvoyer un type de base ou un type composite. Les
+   fonctions pourraient aussi être définies pour renvoyer des ensembles de valeurs
+   de base ou de valeurs composites.
+  </para>
+
+  <para>
+   De nombreuses sortes de fonctions peuvent accepter ou renvoyer certains
+   pseudo-types (comme les types polymorphes) mais avec des fonctionnalités
+   variées.
+   Consultez la description de chaque type de fonction pour plus de détails.
+  </para>
+
+  <para>
+   Il est plus facile de définir des fonctions <acronym>SQL</acronym> aussi
+   allons-nous commencer par celles-ci. La plupart des concepts présentés pour
+   les fonctions <acronym>SQL</acronym> seront aussi gérés par les autres types
+   de fonctions.
+  </para>
+
+  <para>
+   Lors de  la lecture de ce chapitre, il peut être utile de consulter la page
+   de référence de la commande <xref linkend="sql-createfunction"
+   endterm="sql-createfunction-title"/> pour mieux
+   comprendre les exemples. Quelques exemples extraits de ce chapitre peuvent 
+   être trouvés dans les fichiers <filename>funcs.sql</filename> et
+   <filename>funcs.c</filename> du répertoire du tutoriel de la distribution
+   source de <productname>PostgreSQL</productname>.
+  </para>
+
+  </sect1>
+
+  <sect1 id="xfunc-sql">
+   <title>Fonctions en langage de requêtes (<acronym>SQL</acronym>)</title>
+
+   <indexterm zone="xfunc-sql">
+    <primary>fonction</primary>
+    <secondary>définie par l'utilisateur</secondary>
+    <tertiary>en SQL</tertiary>
+   </indexterm>
+
+   <para>
+    Les fonctions SQL exécutent une liste arbitraire d'instructions SQL et
+    renvoient le résultat de la dernière requête de cette liste. Dans le cas
+    d'un résultat simple (pas d'ensemble), la première ligne du résultat de la
+    dernière requête sera renvoyée (gardez à l'esprit que <quote>la première
+    ligne</quote> d'un résultat multiligne n'est pas bien définie à moins
+    d'utiliser <literal>ORDER BY</literal>). Si la dernière requête de la liste ne
+    renvoie aucune ligne, la valeur NULL est renvoyée.
+   </para>
+
+   <para>
+    Une fonction SQL peut être déclarée de façon à renvoyer un ensemble (set)
+    en spécifiant le type renvoyé par la fonction comme <literal>SETOF
+    <replaceable>un_type</replaceable></literal>, ou de façon équivalente en
+    la déclarant comme  <literal>RETURNS
+    TABLE(<replaceable>colonnes</replaceable>)</literal>. Dans ce
+    cas, toutes les lignes de la dernière requête sont renvoyées. Des détails
+    supplémentaires sont donnés plus loin dans ce chapitre.
+   </para>
+
+   <para>
+    Le corps d'une fonction SQL doit être constitué d'une liste d'une ou
+    de plusieurs instructions SQL séparées par des points-virgule. Un
+    point-virgule après la dernière instruction est optionnel. Sauf si la
+    fonction déclare renvoyer <type>void</type>, la dernière instruction doit
+    être un <command>SELECT</command> ou un <command>INSERT</command>,
+    <command>UPDATE</command> ou un <command>DELETE</command> qui a une clause
+    <literal>RETURNING</literal>.
+   </para>
+
+   <para>
+    Toute collection de commandes dans le langage <acronym>SQL</acronym> peut
+    être assemblée et définie comme une fonction. En plus des requêtes
+    <command>SELECT</command>, les commandes peuvent inclure des requêtes de
+    modification des données (<command>INSERT</command>,
+    <command>UPDATE</command> et <command>DELETE</command>) ainsi que
+    d'autres commandes SQL (la seule exception est que vous ne pouvez pas
+    placer de commandes <command>BEGIN</command>, <command>COMMIT</command>,
+    <command>ROLLBACK</command> ou <command>SAVEPOINT</command> dans une fonction
+    <acronym>SQL</acronym>). Néanmoins, la commande finale doit être un
+    <command>SELECT</command> ou doit avoir une clause <literal>RETURNING</literal>
+    qui renvoie ce qui a été spécifié comme type
+    de retour de la fonction. Autrement, si vous voulez définir une fonction
+    SQL qui réalise des actions mais n'a pas de valeur utile à renvoyer,
+    vous pouvez la définir comme renvoyant <type>void</type>. Par exemple, cette fonction supprime les 
+    lignes avec des salaires négatifs depuis la table <literal>emp</literal>&nbsp;:
+
+<screen>CREATE FUNCTION nettoie_emp() RETURNS void AS '
+    DELETE FROM emp WHERE salaire &lt; 0;
+' LANGUAGE SQL;
+  
+SELECT nettoie_emp();
+
+  nettoie_emp
+  -----------
+
+  (1 row)
+</screen>
+   </para>
+
+   <para>
+    La syntaxe de la commande <command>CREATE FUNCTION</command> 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 <xref linkend="sql-syntax-dollar-quoting"/>) pour cette constante.
+    Si vous choisissez d'utiliser la syntaxe habituelle avec des guillemets
+    simples, vous devez doubler les marques de guillemet simple
+    (<literal>'</literal>) et les antislashs (<literal>\</literal>), en supposant
+    que vous utilisez la syntaxe d'échappement de chaînes, utilisés dans le corps
+    de la fonction (voir la <xref linkend="sql-syntax-strings"/>).
+   </para>
+
+   <para>
+   Les arguments de la fonction SQL sont référencés dans le corps de la
+   fonction en utilisant la syntaxe suivante.
+   <literal>$<replaceable>n</replaceable></literal>:<literal>$1</literal> se réfère au premier argument,
+   <literal>$2</literal> au second et ainsi de suite. Si un argument est de type
+   composite, on utilisera la notation par point, par exemple
+   <literal>$1.name</literal>, pour accéder aux attributs de l'argument.
+   Les arguments peuvent seulement être utilisés comme valeurs des données, pas
+   comme des identifieurs. Du coup, par exemple, ceci est correct&nbsp;:
+<programlisting>INSERT INTO matable VALUES ($1);
+</programlisting>
+   mais ceci ne fonctionnera pas&nbsp;:
+<programlisting>INSERT INTO $1 VALUES (42);
+</programlisting>
+   </para>
+
+   <sect2 id="xfunc-sql-base-functions">
+    <title>Fonctions <acronym>SQL</acronym> sur les types de base</title>
+
+    <para>
+    La fonction <acronym>SQL</acronym> la plus simple possible n'a pas
+    d'argument et retourne un type de base tel que <type>integer</type>&nbsp;:
+<screen>CREATE FUNCTION un() RETURNS integer AS $$
+    SELECT 1 AS resultat;
+$$ LANGUAGE SQL;
+
+-- Autre syntaxe pour les chaînes littérales :
+CREATE FUNCTION un() RETURNS integer AS '
+    SELECT 1 AS resultat;
+' LANGUAGE SQL;
+
+SELECT un();
+
+ un
+----
+  1
+</screen>
+    </para>
+
+    <para>
+    Notez que nous avons défini un alias de colonne avec le nom
+    <literal>resultat</literal> dans le corps de la fonction pour se référer au
+    résultat de la fonction mais cet alias n'est pas visible hors de la
+    fonction. En effet, le résultat est nommé <literal>un</literal> au lieu de
+    <literal>resultat</literal>.
+    </para>
+
+    <para>
+    Il est presque aussi facile de définir des fonctions SQL acceptant des types
+    de base comme arguments. Dans l'exemple suivant, remarquez comment nous
+    faisons référence aux arguments dans le corps de la fonction avec  
+    <literal>$1</literal> et <literal>$2</literal>.
+
+<screen>CREATE FUNCTION ajoute(integer, integer) RETURNS integer AS $$
+    SELECT $1 + $2;
+$$ LANGUAGE SQL;
+
+SELECT ajoute(1, 2) AS reponse;
+
+ reponse
+---------
+      3
+</screen>
+    </para>
+
+    <para>
+    Voici une fonction plus utile, qui pourrait être utilisée pour débiter un
+    compte bancaire&nbsp;:
+
+<programlisting>CREATE FUNCTION tf1 (integer, numeric) RETURNS integer AS $$
+    UPDATE banque
+        SET balance = balance - $2
+        WHERE no_compte = $1;
+    SELECT 1;
+$$ LANGUAGE SQL;
+</programlisting>
+
+    Un utilisateur pourrait exécuter cette fonction pour débiter le compte 17 de
+    100&nbsp;000&nbsp;euros ainsi&nbsp;:
+<programlisting>SELECT tf1(17, 100.000);</programlisting>
+    </para>
+    
+    <para>
+    Dans la pratique, on préférera vraisemblablement un résultat plus utile que
+    la constante 1. Une définition plus probable est&nbsp;:
+
+<programlisting>CREATE FUNCTION tf1 (integer, numeric) RETURNS numeric AS $$
+    UPDATE banque
+        SET balance = balance - $2
+        WHERE no_compte = $1;
+    SELECT balance FROM banque WHERE no_compte = $1;
+$$ LANGUAGE SQL;
+</programlisting>
+
+     qui ajuste le solde et renvoie sa nouvelle valeur.
+     La même chose peut se faire en une commande en utilisant la clause
+     <literal>RETURNING</literal>&nbsp;:
+
+<programlisting>
+CREATE FUNCTION tf1 (integer, numeric) RETURNS numeric AS $$
+    UPDATE banque
+        SET balance = balance - $2
+        WHERE no_compte = $1
+    RETURNING balance;
+$$ LANGUAGE SQL;
+</programlisting>
+    </para>
+
+   </sect2>
+
+   <sect2>
+    <title>Fonctions <acronym>SQL</acronym> sur les types composites</title>
+
+    <para>
+    Quand nous écrivons une fonction avec des arguments de type composite,
+    nous devons non seulement spécifier l'argument utilisé (comme nous
+    l'avons fait précédemment avec <literal>$1</literal> et <literal>$2</literal>),
+    mais aussi spécifier l'attribut désiré de cet argument (champ). Par
+    exemple, supposons que 
+    <type>emp</type> soit le nom d'une table contenant des données sur les
+    employés et donc également le nom du type composite correspondant à chaque
+    ligne de la table. Voici une fonction <function>double_salaire</function>
+    qui calcule ce que serait le salaire de quelqu'un s'il était doublé&nbsp;:
+
+<screen>CREATE TABLE emp (
+    nom         text,
+    salaire     numeric,
+    age         integer,
+    cubicle     point
+);
+
+CREATE FUNCTION double_salaire(emp) RETURNS numeric AS $$
+    SELECT $1.salaire * 2 AS salaire;
+$$ LANGUAGE SQL;
+
+SELECT nom, double_salaire(emp.*) AS reve
+    FROM emp
+    WHERE emp.cubicle ~= point '(2,1)';
+
+ name | reve
+------+-------
+ Bill |  8400
+</screen>
+    </para>
+
+    <para>
+     Notez l'utilisation de la syntaxe <literal>$1.salaire</literal> pour
+     sélectionner un champ dans la valeur de la ligne argument. Notez également
+     comment la commande <command>SELECT</command> utilise <literal>*</literal> pour
+     sélectionner la ligne courante entière de la table comme une valeur composite
+     (<literal>emp</literal>). La ligne de la table peut aussi être référencée en
+     utilisant seulement le nom de la table ainsi&nbsp;:
+<screen>SELECT nom, double_salaire(emp) AS reve
+    FROM emp
+    WHERE emp.cubicle ~= point '(2,1)';
+</screen>
+     mais cette utilisation est obsolète car elle est facilement obscure.
+    </para>
+
+    <para>
+	 Quelque fois, il est pratique de construire une valeur d'argument
+	 composite en direct. Ceci peut se faire avec la construction 
+	 <literal>ROW</literal>. Par exemple, nous pouvons ajuster les données passées
+	 à la fonction&nbsp;:
+<screen>SELECT nom, double_salaire(ROW(nom, salaire*1.1, age, cubicle)) AS reve
+	FROM emp;
+</screen>
+    </para>
+
+    <para>
+    Il est aussi possible de construire une fonction qui renvoie un type
+    composite. Voici un exemple de fonction renvoyant une seule ligne de type
+    <type>emp</type>&nbsp;:
+
+<programlisting>CREATE FUNCTION nouvel_emp() RETURNS emp AS $$
+    SELECT text 'Aucun' AS nom,
+        1000.0 AS salaire,
+        25 AS age,
+        point '(2,2)' AS cubicle;
+$$ LANGUAGE SQL;
+</programlisting>
+
+    Dans cet exemple, nous avons spécifié chacun des attributs avec une valeur
+    constante, mais un quelconque calcul aurait pu être substitué à ces
+    valeurs. 
+    </para>
+
+    <para>
+    Notez deux aspects importants à propos de la définition de fonction&nbsp;:
+
+     <itemizedlist>
+      <listitem>
+       <para>
+       L'ordre de la liste du SELECT doit être exactement le même que celui
+       dans lequel les colonnes apparaissent dans la table associée au type
+       composite (donner des noms aux colonnes dans le corps de la fonction,
+       comme nous l'avons 
+       fait dans l'exemple, n'a aucune interaction avec le système).
+       </para>
+      </listitem>
+      <listitem>
+       <para>
+	Vous devez transtyper les expressions pour concorder avec la définition
+       du type composite ou bien vous aurez l'erreur suivante&nbsp;:
+<screen><computeroutput>ERROR:  function declared to return emp returns varchar instead of text at column 1</computeroutput></screen>
+       </para>
+      </listitem>
+     </itemizedlist>
+    </para>     
+
+    <para>
+      Un autre façon de définir la même fonction est&nbsp;:
+
+      <programlisting>CREATE FUNCTION nouveau_emp() RETURNS emp AS $$
+    SELECT ROW('Aucun', 1000.0, 25, '(2,2)')::emp;
+$$ LANGUAGE SQL;</programlisting>
+
+      Ici, nous écrivons un <command>SELECT</command> qui renvoie seulement une
+      colonne du bon type composite. Ceci n'est pas vraiment meilleur dans
+      cette situation mais c'est une alternative pratique dans certains cas
+      &mdash; par exemple, si nous avons besoin de calculer le résultat en
+      appelant une autre fonction qui renvoie la valeur composite désirée.
+    </para>     
+
+    <para>
+      Nous pourrions appeler cette fonction directement de deux façons&nbsp;:
+
+  <screen>SELECT nouveau_emp();
+
+        nouveau_emp
+--------------------------
+ (None,1000.0,25,"(2,2)")
+
+SELECT * FROM nouveau_emp();
+
+  nom  | salaire | age | cubicle
+-------+---------+-----+---------
+ Aucun |  1000.0 |  25 | (2,2)
+  </screen>
+
+      La deuxième façon est décrite plus complètement dans la <xref
+      linkend="xfunc-sql-table-functions"/>.
+  </para>
+
+  <para>
+    Quand vous utilisez une fonction qui renvoie un type composite, vous
+    pourriez vouloir seulement un champ (attribut) depuis ce résultat. Vous
+    pouvez le faire avec cette syntaxe&nbsp;:
+
+<screen>SELECT (nouveau_emp()).nom;
+
+ nom
+------
+ None
+</screen>
+
+    Les parenthèses supplémentaires sont nécessaires pour éviter une erreur de
+    l'analyseur. Si vous essayez de le faire sans, vous obtiendrez quelque chose
+    comme ceci&nbsp;:
+    <screen>SELECT nouveau_emp().nom;
+ERROR:  syntax error at or near "."
+LINE 1: SELECT nouveau_emp().nom;
+                            ^
+</screen>
+    </para>
+
+    <para>
+    Une autre option est d'utiliser la notation fonctionnelle pour extraire un
+    attribut. Une manière simple d'expliquer cela est de dire que nous pouvons
+    échanger les notations <literal>attribut(table)</literal> et
+    <literal>table.attribut</literal>.
+
+<screen>SELECT nom(nouveau_emp());
+
+ name
+------
+ None
+</screen>
+
+<screen>-- C'est la même chose que
+-- SELECT emp.nom AS leplusjeune FROM emp WHERE emp.age &lt; 30;
+
+SELECT nom(emp) AS leplusjeune FROM emp WHERE age(emp) &lt; 30;
+
+ leplusjeune
+-------------
+ Sam
+ Andy
+</screen>
+    </para>
+
+    <tip>
+    <para>
+     L'équivalence entre la notation fonctionnelle et la notation d'attribut
+     rend possible l'utilisation de fonctions sur des types composites pour
+     émuler les <quote>champs calculés</quote>.
+     <indexterm>
+      <primary>champ calculé</primary>
+     </indexterm>
+     <indexterm>
+      <primary>field</primary>
+      <secondary>computed</secondary>
+     </indexterm>
+     Par exemple, en utilisant la définition précédente pour
+     <literal>double_salaire(emp)</literal>, nous pouvons écrire
+<screen>SELECT emp.nom, emp.double_salaire FROM emp;
+</screen>
+
+     Une application utilisant ceci n'aurait pas besoin d'être consciente
+     directement que <literal>double_salaire</literal> n'est pas une vraie colonne
+     de la table (vous pouvez aussi émuler les champs calculés avec des
+     vues).
+    </para>
+    </tip>
+
+    <para>
+     Une autre façon d'utiliser une fonction renvoyant un type composite est
+     de l'appeler comme une fonction de table, comme décrit dans la <xref
+     linkend="xfunc-sql-table-functions"/>.
+    </para>
+   </sect2>
+
+   <sect2 id="xfunc-output-parameters">
+    <title>Fonctions <acronym>SQL</acronym> avec des paramètres en sortie</title>
+
+   <indexterm>
+    <primary>fonction</primary>
+    <secondary>paramètre en sortie</secondary>
+   </indexterm>
+
+    <para>
+     Une autre façon de décrire les résultats d'une fonction est de la
+     définir avec des <firstterm>paramètres en sortie</firstterm> comme dans cet
+     exemple&nbsp;:
+
+<screen>CREATE FUNCTION ajoute (IN x int, IN y int, OUT sum int)
+AS 'SELECT $1 + $2'
+LANGUAGE SQL;
+
+SELECT ajoute(3,7);
+ ajoute
+--------
+     10
+(1 row)
+</screen>
+
+     Ceci n'est pas vraiment différent de la version d'<literal>ajoute</literal>
+     montrée dans la <xref linkend="xfunc-sql-base-functions"/>. La vraie valeur
+     des paramètres en sortie est qu'ils fournissent une façon agréable de
+     définir des fonctions qui renvoient plusieurs colonnes. Par exemple,
+
+<screen>CREATE FUNCTION ajoute_n_produit (x int, y int, OUT sum int, OUT product int)
+AS 'SELECT $1 + $2, $1 * $2'
+LANGUAGE SQL;
+
+ SELECT * FROM sum_n_product(11,42);
+ sum | product
+-----+---------
+  53 |     462
+(1 row)
+</screen>
+
+     Ce qui est arrivé ici est que nous avons créé un type composite anonyme
+     pour le résultat de la fonction. L'exemple ci-dessus a le même résultat
+     final que
+
+<screen>CREATE TYPE produit_ajoute AS (somme int, produit int);
+
+CREATE FUNCTION ajoute_n_produit (int, int) RETURNS produit_ajoute
+AS 'SELECT $1 + $2, $1 * $2'
+LANGUAGE SQL;
+</screen>
+
+     mais ne pas avoir à s'embêter avec la définition séparée du type
+     composite est souvent agréable.
+    </para>
+
+    <para>
+     Notez que les paramètres en sortie ne sont pas inclus dans la liste
+     d'arguments lors de l'appel d'une fonction de ce type en SQL. Ceci
+     parce que <productname>PostgreSQL</productname> considère seulement les
+     paramètres en entrée pour définir la signature d'appel de la fonction.
+     Cela signifie aussi que seuls les paramètres en entrée sont importants
+     lors de références de la fonction pour des buts comme sa suppression.
+     Nous pouvons supprimer la fonction ci-dessus avec l'un des deux appels
+     ci-dessous&nbsp;:
+
+<screen>DROP FUNCTION ajoute_n_produit (x int, y int, OUT somme int, OUT produit int);
+DROP FUNCTION ajoute_n_produit (int, int);
+</screen>
+    </para>
+
+    <para>
+     Les paramètres peuvent être marqués comme <literal>IN</literal> (par défaut),
+     <literal>OUT</literal> ou <literal>INOUT</literal> ou
+     <literal>VARIADIC</literal>.
+     Un paramètre <literal>INOUT</literal>
+     sert à la fois de paramètre en entrée (il fait partie de la liste
+     d'arguments en appel) et comme paramètre de sortie (il fait partie du
+     type d'enregistrement résultat). Les paramètres
+     <literal>VARIADIC</literal> sont des paramètres en entrées, mais sont
+     traités spécifiquement comme indiqué ci-dessous.
+    </para>
+   </sect2>
+
+   <sect2 id="xfunc-sql-variadic-functions">
+    <title>Fonctions <acronym>SQL</acronym> avec un nombre variables d'arguments</title>
+
+    <indexterm>
+     <primary>fonction</primary>
+     <secondary>variadic</secondary>
+    </indexterm>
+
+    <indexterm>
+     <primary>fonction variadic</primary>
+    </indexterm>
+
+    <para>
+     Les fonctions <acronym>SQL</acronym> peuvent accepter un nombre variable
+     d'arguments à condition que tous les arguments <quote>optionnels</quote>
+     sont du même type. Les arguments optionnels seront passés à la fonction
+     sous forme d'un tableau. La fonction est déclarée en marquant le dernier
+     paramètre comme <literal>VARIADIC</literal>&nbsp;; ce paramètre doit être
+     déclaré de type tableau. Par exemple&nbsp;:
+
+<screen>
+CREATE FUNCTION mleast(VARIADIC numeric[]) RETURNS numeric AS $$
+    SELECT min($1[i]) FROM generate_subscripts($1, 1) g(i);
+$$ LANGUAGE SQL;
+
+SELECT mleast(10, -1, 5, 4.4);
+ mleast 
+--------
+     -1
+(1 row)
+</screen>
+
+     En fait, tous les arguments à la position ou après la position de
+     l'argument <literal>VARIADIC</literal> sont emballés dans un tableau à
+     une dimension, comme si vous aviez écrit
+
+<screen>
+SELECT mleast(ARRAY[10, -1, 5, 4.4]);    -- doesn't work
+</screen>
+
+     Vous ne pouvez pas vraiment écrire cela, ou tout du moins cela ne
+     correspondra pas à la définition de la fonction. Un paramètre marqué
+     <literal>VARIADIC</literal> correspond à une ou plusieurs occurrences
+     de son type d'élément, et non pas de son propre type.
+    </para>
+
+    <para>
+     Sometimes it is useful to be able to pass an already-constructed array
+     to a variadic function; this is particularly handy when one variadic
+     function wants to pass on its array parameter to another one.  You can
+     do that by specifying <literal>VARIADIC</literal> in the call:
+
+<screen>
+SELECT mleast(VARIADIC ARRAY[10, -1, 5, 4.4]);
+</screen>
+
+     This prevents expansion of the function's variadic parameter into its
+     element type, thereby allowing the array argument value to match
+     normally.  <literal>VARIADIC</literal> can only be attached to the last
+     actual argument of a function call.
+    </para>
+   </sect2>
+
+   <sect2 id="xfunc-sql-parameter-defaults">
+    <title>Fonctions SQL <acronym>SQL</acronym> avec des valeurs par défaut
+     pour les arguments</title>
+
+    <indexterm>
+     <primary>fonction</primary>
+     <secondary>valeurs par défaut pour les arguments</secondary>
+    </indexterm>
+
+    <para>
+     Les fonctions peuvent être déclarées avec des valeurs par défaut pour
+     certains des paramètres en entrée ou pour tous. Les valeurs par défaut
+     sont insérées quand la fonction est appelée avec moins d'arguments que
+     à priori nécessaires. Comme les arguments peuvent seulement être omis
+     à partir de la fin de la liste des arguments, tous les paramètres après
+     un paramètres disposant d'une valeur par défaut disposeront eux-aussi
+     d'une valeur par défaut.
+    </para>
+
+    <para>
+     Par exemple&nbsp;:
+<screen>
+CREATE FUNCTION foo(a int, b int DEFAULT 2, c int DEFAULT 3)
+RETURNS int
+LANGUAGE SQL
+AS $$
+    SELECT $1 + $2 + $3;
+$$;
+
+SELECT foo(10, 20, 30);
+ foo 
+-----
+  60
+(1 row)
+
+SELECT foo(10, 20);
+ foo 
+-----
+  33
+(1 row)
+
+SELECT foo(10);
+ foo 
+-----
+  15
+(1 row)
+
+SELECT foo();  -- échec car il n'y a pas de valeur par défaut pour le premier argument
+ERROR:  function foo() does not exist
+</screen>
+     Le signe <literal>=</literal> peut aussi être utilisé à la place du mot clé
+     <literal>DEFAULT</literal>,
+    </para>
+   </sect2>
+
+   <sect2 id="xfunc-sql-table-functions">
+    <title>Fonctions <acronym>SQL</acronym> comme sources de table</title>
+
+    <para>
+    Toutes les fonctions SQL peuvent être utilisées dans la clause
+    <literal>FROM</literal> d'une requête mais ceci est particulièrement utile pour les
+    fonctions renvoyant des types composite. Si la fonction est définie pour
+    renvoyer un type de base, la fonction table produit une table d'une seule
+    colonne. Si la fonction est définie pour renvoyer un type composite, la
+    fonction  table produit une colonne pour chaque attribut du type composite.
+   </para>
+
+    <para>
+     Voici un exemple&nbsp;:
+
+<screen>CREATE TABLE foo (fooid int, foosousid int, foonom text);
+INSERT INTO foo VALUES (1, 1, 'Joe');
+INSERT INTO foo VALUES (1, 2, 'Ed');
+INSERT INTO foo VALUES (2, 1, 'Mary');
+
+CREATE FUNCTION recupfoo(int) RETURNS foo AS $$
+    SELECT * FROM foo WHERE fooid = $1;
+$$ LANGUAGE SQL;
+
+SELECT *, upper(foonom) FROM recupfoo(1) AS t1;
+
+ fooid | foosubid | foonom | upper
+-------+----------+--------+-------
+     1 |        1 | Joe    | JOE
+(1 row)
+</screen>
+
+    Comme le montre cet exemple, nous pouvons travailler avec les colonnes du
+    résultat de la fonction comme s'il s'agissait des colonnes d'une table
+    normale.
+</para>
+
+    <para>
+    Notez que nous n'obtenons qu'une ligne comme résultat de la fonction. Ceci
+    parce que nous n'avons pas utilisé l'instruction <literal>SETOF</literal>. Cette
+    instruction est décrite dans la prochaine section.
+    </para>
+   </sect2>
+
+   <sect2 id="xfunc-sql-functions-returning-set">
+    <title>Fonctions <acronym>SQL</acronym> renvoyant un ensemble </title>
+
+    <indexterm>
+     <primary>fonction</primary>
+     <secondary>avec SETOF</secondary>
+    </indexterm>
+
+    <para>
+     Quand une fonction SQL est déclarée renvoyer un <literal>SETOF
+     <replaceable>un_type</replaceable></literal>, la requête finale de
+     la fonction est complètement exécutée et chaque ligne extraite est renvoyée
+     en tant qu'élément de l'ensemble résultat.
+    </para>
+    
+    <para>
+     Cette caractéristique est normalement utilisée lors de l'appel d'une
+     fonction dans une clause <literal>FROM</literal>. Dans ce cas, chaque ligne
+     renvoyée par la fonction devient une ligne de la table vue par la requête.
+     Par exemple, supposons que la table <literal>foo</literal> ait le même contenu que
+     précédemment et écrivons&nbsp;:
+
+<programlisting>CREATE FUNCTION recupfoo(int) RETURNS SETOF foo AS $$
+    SELECT * FROM foo WHERE fooid = $1;
+$$ LANGUAGE SQL;
+
+SELECT * FROM recupfoo(1) AS t1;
+</programlisting>
+
+     Alors nous obtenons&nbsp;:
+<screen> fooid | foosousid | foonom
+-------+-----------+--------
+     1 |         1 | Joe
+     1 |         2 | Ed
+(2 rows)
+</screen>
+    </para>
+
+    <para>
+     Il est aussi possible de renvoyer plusieurs lignes avec les colonnes
+     définies par des paramètres en sortie, comme ceci&nbsp;:
+
+<programlisting>
+CREATE FUNCTION sum_n_product_with_tab (x int, OUT sum int, OUT product int) RETURNS SETOF record AS $$
+    SELECT $1 + tab.y, tab.y * tab.y FROM tab;
+$$ LANGUAGE SQL;
+</programlisting>
+
+     Le point clé ici est que vous devez écrire <literal>RETURNS SETOF
+     record</literal> pour indiquer que la fonction renvoie plusieurs lignes
+     et non pas une seule. S'il n'y a qu'un paramètre en sortie, indiquez le
+     type de paramètre plutôt que <type>record</type>.
+    </para>
+
+    <para>
+     Actuellement, les fonctions renvoyant des ensembles peuvent aussi être
+     appelées dans la liste du select d'une requête. Pour chaque ligne générée
+     par la requête, la fonction renvoyant un ensemble est appelée et une ligne
+     est générée pour chaque élément de l'ensemble résultat. Notez cependant que
+     cette fonctionnalité est déconseillée et pourra être supprimée dans une
+     version future. Voici un exemple de fonction renvoyant un ensemble à
+     partir de la liste d'un SELECT&nbsp;:
+
+<screen>CREATE FUNCTION listeenfant(text) RETURNS SETOF text AS $$
+    SELECT nom FROM noeuds WHERE parent = $1
+$$ LANGUAGE SQL;
+
+SELECT * FROM noeuds;
+   nom        | parent
+--------------+--------
+ Haut         |
+ Enfant1      | Haut
+ Enfant2      | Haut
+ Enfant3      | Haut
+ Sous-Enfant1 | Enfant1
+ Sous-Enfant2 | Enfant1
+(6 rows)
+
+SELECT listeenfant('Haut');
+ listeenfant
+--------------
+ Enfant1
+ Enfant2
+ Enfant3
+(3 rows)
+
+SELECT nom, listeenfant(nom) FROM noeuds;
+  nom    | listeenfant
+---------+--------------
+ Haut    | Enfant1
+ Haut    | Enfant2
+ Haut    | Enfant3
+ Enfant1 | Sous-Enfant1
+ Enfant1 | Sous-Enfant2
+(5 rows)
+</screen>
+
+     Notez, dans le dernier <command>SELECT</command>, qu'aucune ligne n'est
+     renvoyée pour <literal>Enfant2</literal>, <literal>Enfant3</literal>, etc. C'est parce
+     que la fonction <function>listeenfant</function> renvoie un ensemble vide
+     pour ces arguments et ainsi aucune ligne n'est générée.
+    </para>
+
+    <note>
+     <para>
+      Si la dernière commande d'une fonction est <command>INSERT</command>,
+      <command>UPDATE</command> ou <command>DELETE</command> avec une clause
+      <literal>RETURNING</literal>, cette commande sera toujours exécutée
+      jusqu'à sa fin, même si la fonction n'est pas déclarée avec
+      <literal>SETOF</literal> ou que la requête appelante ne renvoie pas toutes
+      les lignes résultats. Toutes les lignes supplémentaires produites par la
+      clause <literal>RETURNING</literal> sont silencieusement abandonnées mais
+      les modifications de table sont pris en compte (et sont toutes terminées
+      avant que la fonction ne se termine).
+     </para>
+    </note>
+   </sect2>
+
+   <sect2 id="xfunc-sql-functions-returning-table">
+    <title>Fonctions <acronym>SQL</acronym> renvoyant <literal>TABLE</literal></title>
+
+    <indexterm>
+     <primary>fonction</primary>
+     <secondary>RETURNS TABLE</secondary>
+    </indexterm>
+
+    <para>
+     Il existe une autre façon de déclarer une fonction comme renvoyant un
+     ensemble de données. Cela passe par la syntaxe <literal>RETURNS
+     TABLE(<replaceable>colonnes</replaceable>)</literal>. C'est équivalent
+     à utiliser un ou plusieurs paramètres <literal>OUT</literal> et à marquer
+     la fonction comme renvoyant un <literal>SETOF record</literal> (ou
+     <literal>SETOF</literal> d'un type simple en sortie, comme approprié).
+     Cette notation est indiquée dans les versions récentes du standard SQL
+     et, du coup, devrait être plus portable que <literal>SETOF</literal>.
+    </para>
+
+    <para>
+     L'exemple précédent, sum-and-product, peut se faire aussi de la façon
+     suivante&nbsp;:
+
+<programlisting>
+CREATE FUNCTION sum_n_product_with_tab (x int) RETURNS TABLE(sum int, product int) AS $$
+    SELECT $1 + tab.y, $1 * tab.y FROM tab;
+$$ LANGUAGE SQL;
+</programlisting>
+
+     Il n'est pas autorisé d'utiliser explicitement des paramètres
+     <literal>OUT</literal> ou <literal>INOUT</literal> avec la notation
+     <literal>RETURNS TABLE</literal> &mdash; vous devez indiquer toutes les
+     colonnes en sortie dans la liste <literal>TABLE</literal>.
+ </para>
+    </sect2>
+
+   <sect2>
+    <title>Fonctions <acronym>SQL</acronym> polymorphes</title>
+
+    <para>
+     Les fonctions <acronym>SQL</acronym> peuvent être déclarées pour accepter
+     et renvoyer les types <quote>polymorphe</quote> <type>anyelement</type>,
+     <type>anyarray</type>, <type>anynonarray</type> et <type>anyenum</type>.
+     Voir la <xref linkend="extend-types-polymorphic"/> pour une
+     explication plus approfondie. Voici une fonction polymorphe
+     <function>cree_tableau</function> qui construit un tableau à partir de
+     deux éléments de type arbitraire&nbsp;:
+
+<screen>CREATE FUNCTION cree_tableau(anyelement, anyelement) RETURNS anyarray AS $$
+    SELECT ARRAY[$1, $2];
+$$ LANGUAGE SQL;
+SELECT cree_tableau(1, 2) AS tableau_entier, cree_tableau('a'::text, 'b') AS
+tableau_texte;
+
+ tableau_entier | tableau_texte
+----------------+---------------
+ {1,2}          | {a,b}
+(1 row)
+</screen>
+    </para>
+
+    <para>
+     Notez l'utilisation du transtypage <literal>'a'::text</literal> pour
+     spécifier le type <type>text</type> de l'argument. Ceci est nécessaire si
+     l'argument est une chaîne de caractères car, autrement, il serait traité
+     comme un type  <type>unknown</type>, et un tableau de type
+     <type>unknown</type> n'est pas un type valide. Sans le transtypage, vous
+     obtiendrez ce genre d'erreur&nbsp;:
+
+<screen><computeroutput>ERROR:  could not determine polymorphic type because input is UNKNOWN</computeroutput></screen>
+    </para>
+
+    <para>
+     Il est permis d'avoir des arguments polymorphes avec un type de renvoi
+     fixe, mais non l'inverse. Par exemple&nbsp;:
+
+<screen>CREATE FUNCTION est_plus_grand(anyelement, anyelement) RETURNS bool AS $$
+    SELECT $1 &gt; $2;
+$$ LANGUAGE SQL;
+
+SELECT est_plus_grand(1, 2);
+ est_plus_grand
+----------------
+ f
+(1 row)
+
+CREATE FUNCTION fonction_invalide() RETURNS anyelement AS $$
+    SELECT 1;
+$$ LANGUAGE SQL;
+ERROR:  cannot determine result datatype
+DETAIL:  A function returning a polymorphic type must have at least one
+polymorphic argument.
+</screen>
+    </para>
+
+    <para>
+     Le polymorphisme peut être utilisé avec les fonctions qui ont des
+     arguments en sortie. Par exemple&nbsp;:
+<screen>CREATE FUNCTION dup (f1 anyelement, OUT f2 anyelement, OUT f3 anyarray)
+AS 'select $1, array[$1,$1]' LANGUAGE SQL;
+
+SELECT * FROM dup(22);
+ f2 |   f3
+----+---------
+ 22 | {22,22}
+(1 row)
+</screen>
+    </para>
+
+    <para>
+     Le polymorphisme peut aussi être utilisé avec des fonctions variadic.
+     Par exemple&nbsp;:
+<screen>
+CREATE FUNCTION anyleast (VARIADIC anyarray) RETURNS anyelement AS $$
+    SELECT min($1[i]) FROM generate_subscripts($1, 1) g(i);
+$$ LANGUAGE SQL;
+
+SELECT anyleast(10, -1, 5, 4);
+ anyleast 
+----------
+       -1
+(1 row)
+
+SELECT anyleast('abc'::text, 'def');
+ anyleast 
+----------
+ abc
+(1 row)
+
+CREATE FUNCTION concat(text, VARIADIC anyarray) RETURNS text AS $$
+    SELECT array_to_string($2, $1);
+$$ LANGUAGE SQL;
+
+SELECT concat('|', 1, 4, 2);
+ concat 
+--------
+ 1|4|2
+(1 row)
+</screen>
+    </para>
+   </sect2>
+  </sect1>
+
+  <sect1 id="xfunc-overload">
+    <title>Surcharge des fonctions</title>
+    
+    <indexterm zone="xfunc-overload">
+      <primary>surcharge</primary>
+      <secondary>fonctions</secondary>
+    </indexterm>
+    
+    <para>
+      Plusieurs fonctions peuvent être définies avec le même nom SQL à condition
+      que les arguments soient différents. En d'autres termes, les noms de
+      fonction peuvent être <firstterm>surchargés</firstterm>. Quand une
+      requête est exécutée, le serveur déterminera la fonction à appeler à
+      partir des types de données des arguments et du nombre d'arguments. La
+      surcharge peut aussi être utilisée pour simuler des fonctions avec un
+      nombre variable d'arguments jusqu'à un nombre maximum fini.
+    </para>
+    
+    <para>
+      Lors de la création d'une famille de fonctions surchargées, vous devriez
+      être attentif à ne pas créer d'ambiguïtés. Par exemple, avec les
+      fonctions&nbsp;:
+      <programlisting>CREATE FUNCTION test(int, real) RETURNS ...
+CREATE FUNCTION test(smallint, double precision) RETURNS ...</programlisting>
+      Savoir quelle fonction sera appelée avec une entrée triviale comme
+      <literal>test(1, 1.5)</literal> n'est pas immédiatement clair. Les
+      règles de résolution actuellement implémentées sont décrites dans le
+      <xref linkend="typeconv"/> mais il est déconseillé de concevoir un
+      système qui serait basé subtilement sur ce comportement.
+      </para>
+      
+      <para>
+        Une fonction qui prend un seul argument d'un type composite devrait
+        généralement ne pas avoir le même nom que tout attribut (champ) de
+        ce type. Rappellez-vous que <literal>attribut(table)</literal> est
+        considéré comme équivalent à <literal>table.attribut</literal>. Dans
+        le cas où il existe une ambiguïté entre une fonction sur un type
+        composite et sur un attribut d'un type composite, l'attribut sera
+        toujours utilisé. Il est possible de contourner ce choix en
+        qualifiant le nom de la fonction avec celui du schéma (c'est-à-dire
+        <literal>schema.fonction(table)</literal>) mais il est préférable
+        d'éviter le problème en ne choisissant aucun nom conflictuel.
+      </para>
+      
+      <para>
+       Un autre conflit possible se trouve entre les fonctions variadic et les
+       autres. En fait, il est possible de créer à la fois
+       <literal>foo(numeric)</literal> et <literal>foo(VARIADIC numeric[])</literal>.
+       Dans ce cas, il n'est pas simple de savoir lequel sera sélectionné lors
+       d'un appel avec un seul argument numérique, par exemple
+       <literal>foo(10.1)</literal>. La règle est que la fonction apparaissant
+       plsu tôt dans le chemin des schémas est utilisé. De même, si les deux
+       fonctions sont dans le même schéma, la non variadic est préféré.
+      </para>
+   
+      <para>
+        Lors de la surcharge de fonctions en langage C, il existe une
+        contrainte supplémentaire&nbsp;: le nom C de chaque fonction dans la
+        famille des fonctions surchargées doit être différent des noms C de
+        toutes les autres fonctions, soit internes soit chargées dynamiquement
+        Si cette règle est violée, le comportement n'est pas portable. Vous
+        pourriez obtenir une erreur de l'éditeur de lien ou une des fonctions
+        sera appelée (habituellement l'interne). L'autre forme de clause
+        <literal>AS</literal> pour la commande SQL <command>CREATE
+        FUNCTION</command> découple le nom de la fonction SQL à partir du 
+        nom de la fonction dans le code source C. Par exemple&nbsp;:
+<programlisting>CREATE FUNCTION test(int) RETURNS int
+    AS '<replaceable>filename</replaceable>', 'test_1arg'
+LANGUAGE C;
+CREATE FUNCTION test(int, int) RETURNS int
+    AS '<replaceable>filename</replaceable>', 'test_2arg'
+LANGUAGE C;
+</programlisting>
+        Les noms des fonctions C reflètent ici une des nombreuses conventions
+        possibles.
+      </para>
+  </sect1>
+
+  <sect1 id="xfunc-volatility">
+    <title>Catégories de volatilité des fonctions</title>
+  
+    <indexterm zone="xfunc-volatility">
+      <primary>volatilité</primary>
+      <secondary>fonctions</secondary>
+    </indexterm>
+    <indexterm zone="xfunc-volatility">
+      <primary>VOLATILE</primary>
+    </indexterm>
+    <indexterm zone="xfunc-volatility">
+      <primary>STABLE</primary>
+    </indexterm>
+    <indexterm zone="xfunc-volatility">
+      <primary>IMMUTABLE</primary>
+    </indexterm>
+  
+  <para>
+    Chaque fonction a une classification de volatilité
+    (<firstterm>volatility</firstterm>) comprenant
+    <literal>VOLATILE</literal>, <literal>STABLE</literal> ou <literal>IMMUTABLE</literal>.
+    <literal>VOLATILE</literal> est la valeur par défaut si la commande
+    <xref linkend="sql-createfunction" endterm="sql-createfunction-title"/> ne
+    spécifie pas de catégorie. La catégorie de volatilité est une promesse
+    à l'optimiseur sur le comportement de la fonction&nbsp;:
+
+  <itemizedlist>
+    <listitem>
+    <para>
+      Une fonction <literal>VOLATILE</literal> peut tout faire, y compris modifier
+      la base de données. Elle peut renvoyer différents
+      résultats sur des appels successifs avec les mêmes arguments.
+      L'optimiseur ne fait aucune supposition sur le comportement de telles
+      fonctions. Une requête utilisant une fonction volatile ré-évaluera la
+      fonction à chaque ligne où sa valeur est nécessaire.
+    </para>
+    </listitem>
+    <listitem>
+    <para>
+      Une fonction <literal>STABLE</literal> ne peut pas modifier la base de
+      données et est garantie de renvoyer les mêmes résultats si elle est
+      appelée avec les mêmes arguments pour toutes les lignes à l'intérieur
+      d'une même instruction. Cette catégorie permet à l'optimiseur d'optimiser
+      plusieurs appels de la fonction dans une seule requête. En particulier,
+      vous pouvez utiliser en toute sécurité une expression contenant une
+      telle fonction dans une condition de parcours d'index (car un parcours
+      d'index évaluera la valeur de la comparaison une seule fois, pas une
+      fois pour chaque ligne, utiliser une fonction <literal>VOLATILE</literal> dans
+      une condition de parcours d'index n'est pas valide).
+    </para>
+    </listitem>
+    <listitem>
+    <para>
+      Une fonction <literal>IMMUTABLE</literal> ne peut pas modifier la base de
+      données et est garantie de toujours renvoyer les mêmes résultats si
+      elle est appelée avec les mêmes arguments. Cette catégorie permet à 
+      l'optimiseur de pré-évaluer la fonction quand une requête l'appelle
+      avec des arguments constants. Par exemple, une requête comme
+      <literal>SELECT ... WHERE x = 2 + 2</literal> peut être simplifiée pour
+      obtenir <literal>SELECT ... WHERE x = 4</literal> car la fonction sous-jacente
+      de l'opérateur d'addition est indiquée <literal>IMMUTABLE</literal>.
+    </para>
+    </listitem>
+  </itemizedlist>
+
+  </para>
+
+  <para>
+    Pour une meilleure optimisation des résultats, vous devez mettre un label
+    sur les fonctions avec la catégorie la plus volatile valide pour elles.
+  </para>
+
+  <para>
+    Toute fonction avec des effets de bord <emphasis>doit</emphasis> être indiquée
+    comme <literal>VOLATILE</literal>, de façon à ce que les appels ne puissent pas
+    être optimisés. Même une fonction sans effets de bord doit être indiquée
+    comme <literal>VOLATILE</literal> si sa valeur peut changer à l'intérieur
+    d'une seule requête&nbsp;; quelques exemples sont <literal>random()</literal>,
+    <literal>currval()</literal>, <literal>timeofday()</literal>.
+  </para>
+
+   <para>
+    Un autre exemple important est que la famille de fonctions
+    <function>current_timestamp</function> est qualifiée comme
+    <literal>STABLE</literal> car leurs valeurs ne changent pas à l'intérieur
+    d'une transaction.
+   </para>
+
+  <para>
+    Il y a relativement peu de différences entre les catégories 
+    <literal>STABLE</literal> et <literal>IMMUTABLE</literal> en considérant les requêtes
+    interactives qui sont planifiées et immédiatement exécutées&nbsp;: il 
+    importe peu que la fonction soit exécutée une fois lors de la
+    planification ou une fois au lancement de l'exécution de la requête mais
+    cela fait une grosse différence si le plan est sauvegardé et utilisé plus
+    tard. Placer un label <literal>IMMUTABLE</literal> sur une fonction quand elle
+    ne l'est pas vraiment pourrait avoir comme conséquence de la considérer
+    prématurément comme une constante lors de la planification et résulterait en une valeur
+    erronée lors d'une utilisation ultérieure de ce plan d'exécution. 
+    C'est un danger qui arrive lors de l'utilisattion d'instructions préparées
+    ou avec l'utilisation de langages de fonctions mettant les plans d'exécutions
+    en cache (comme
+    <application>PL/pgSQL</application>).
+  </para>
+
+   <para>
+    Pour les fonctions écrites en SQL ou dans tout autre langage de procédure
+    standard, la catégorie de volatibilité détermine une deuxième propriété
+    importante, à savoir la visibilité de toute modification de données
+    effectuées par la commande SQL qui a appelé la fonction. Une fonction
+    <literal>VOLATILE</literal> verra les changements, une fonction
+    <literal>STABLE</literal> ou <literal>IMMUTABLE</literal> ne les verra pas.
+    Ce comportement est implantée en utilisant le comportement par images de
+    MVCC (voir <xref linkend="mvcc"/>)&nbsp;: les fonctions
+    <literal>STABLE</literal> et <literal>IMMUTABLE</literal> utilisent une
+    image établie au lancement de la requête appelante alors que les fonctions
+    <literal>VOLATILE</literal> obtiennent une image fraiche au début de chaque
+    requête qu'elles exécutent.
+   </para>
+
+   <note>
+    <para>
+     Les fonctions écrites en C peuvent gérer les images de la façon qu'elles
+     le souhaitent, mais il est préférable de coder les fonctions C de la même
+     façon.
+    </para>
+   </note>
+
+  <para>
+    À cause du comportement à base d'images, une fonction contenant seulement des commandes
+    <command>SELECT</command> peut être indiquée <literal>STABLE</literal> en toute sécurité
+    même s'il sélectionne des données à partir de tables qui pourraient
+    avoir subi des modifications entre temps par des requêtes concurrentes.
+    <productname>PostgreSQL</productname> exécutera toutes les commandes d'une fonction
+    <literal>STABLE</literal> en utilisant l'image établie par la requête appelante et
+    n'aura qu'une vision figée de la base de données au cours de la requête.
+  </para>
+
+  <para>
+    Ce même comportement d'images est utilisé pour les commandes
+    <command>SELECT</command> à l'intérieur de fonctions <literal>IMMUTABLE</literal>. Il
+    est généralement déconseillé de sélectionner des tables de la base de
+    données à l'intérieur de fonctions <literal>IMMUTABLE</literal> car
+    l'immutabilité sera rompue si le contenu de la table change. Néanmoins,
+    <productname>PostgreSQL</productname> ne vous force pas à ne pas le faire.
+  </para>
+
+  <para>
+    Une erreur commune est de placer un label sur une fonction
+    <literal>IMMUTABLE</literal> quand son résultat dépend d'un paramètre de
+    configuration. Par exemple, une fonction qui manipule des types date/heure
+    pourrait bien avoir des résultats dépendant du paramètre
+    <xref linkend="guc-timezone"/>. Pour être sécurisées, de telles
+    fonctions devraient avoir le label <literal>STABLE</literal> à la place.
+  </para>
+
+  <note>
+    <para>
+      Avant <productname>PostgreSQL</productname> version 8.0, le prérequis
+      que les fonctions <literal>STABLE</literal> et
+      <literal>IMMUTABLE</literal> ne pouvaient pas modifier la base de données
+      n'était pas contraint par le système. Les versions 8.0 et ultérieures le
+      contraignent en
+      réclamant que les fonctions SQL et les fonctions de langages de
+      procédures de ces catégories ne contiennent pas de commandes SQL autre
+      que <command>SELECT</command> (ceci n'a pas été complètement testé car de
+      telles fonctions pourraient toujours appeler des fonctions
+      <literal>VOLATILE</literal> qui modifient la base de données. Si vous le
+      faites, vous trouverez que la fonction <literal>STABLE</literal> ou
+      <literal>IMMUTABLE</literal> n'est pas au courant des modifications
+      effectuées sur la base de données par la fonction appelée, car elles
+      sont cachées depuis son image).
+    </para>
+  </note>
+  </sect1>
+
+  <sect1 id="xfunc-pl">
+   <title>Fonctions en langage de procédures</title>
+
+   <para>
+    <productname>PostgreSQL</productname> autorise l'écriture de fonctions
+    définies par l'utilisateur dans d'autres langages que SQL et C. Ces autres
+    langages sont appelés des <firstterm>langages de procédure</firstterm>
+    (<acronym>PL</acronym>). Les langages de procédures ne sont pas compilés dans le
+    serveur <productname>PostgreSQL</productname>&nbsp;; ils sont fournis comme
+    des modules chargeables. Voir le <xref linkend="xplang"/> et les chapitres
+    suivants pour plus d'informations.
+   </para>
+
+   <para>
+    Il y a actuellement quatre langages de procédures disponibles dans la
+    distribution <productname>PostgreSQL</productname> standard&nbsp;:
+     <application>PL/pgSQL</application>, <application>PL/Tcl</application>,
+     <application>PL/Perl</application> et <application>PL/Python</application>.
+ 
+    Référez-vous au <xref linkend="xplang"/> pour plus d'informations. D'autres
+    langages peuvent être définis par les utilisateurs. Les bases du
+    développement d'un nouveau langage de procédures sont traitées dans le <xref
+    linkend="plhandler"/>.
+   </para> 
+ 
+ </sect1>
+ 
+ <sect1 id="xfunc-internal">
+   <title>Fonctions internes</title>
+
+   <indexterm zone="xfunc-internal"><primary>fonction</primary><secondary>interne</secondary></indexterm>
+
+   <para>
+    Les fonctions internes sont des fonctions écrites en C qui ont été liées de
+    façon statique dans le serveur <productname>PostgreSQL</productname>. Le
+    <quote>corps</quote> de la définition de la fonction spécifie le nom en 
+    langage C de la fonction, qui n'est pas obligatoirement le même que le nom
+    déclaré pour l'utilisation en SQL (pour des raisons de rétro compatibilité,
+    un corps vide est accepté pour signifier que le nom de la fonction en
+    langage C est le même que le nom SQL).
+
+   </para>
+
+   <para>
+    Normalement, toutes les fonctions internes présentes dans le serveur sont
+    déclarées pendant l'initialisation du groupe de base de données
+    (<command>initdb</command>) mais un utilisateur peut utiliser la commande  
+    <command>CREATE FUNCTION</command> pour créer des noms d'alias
+    supplémentaires pour une fonction interne. Les fonctions internes sont
+    déclarées dans la commande <command>CREATE FUNCTION</command> avec le nom
+    de langage <literal>internal</literal>. Par exemple, pour créer un alias
+    de la fonction <function>sqrt</function>&nbsp;:
+
+<programlisting>CREATE FUNCTION racine_carree(double precision) RETURNS double precision    AS
+'dsqrt'    
+LANGUAGE internal    STRICT;
+</programlisting>
+
+    (la plupart des fonctions internes doivent être déclarées
+    <quote>STRICT</quote>)
+   </para>
+
+   <note>
+    <para>
+     Toutes les fonctions <quote>prédéfinies</quote> ne sont pas internes (au
+     sens explicité ci-dessus). Quelques fonctions prédéfinies sont écrites en
+     SQL.
+    </para>
+   </note>
+  </sect1>
+
+  <sect1 id="xfunc-c">
+   <title>Fonctions en langage C</title>
+
+   <indexterm zone="xfunc-c">
+    <primary>fonction</primary>
+    <secondary>définie par l'utilisateur</secondary>
+    <tertiary>en C</tertiary>
+   </indexterm>
+
+   <para>
+    Les fonctions définies par l'utilisateur peuvent être écrites en C (ou dans
+    un langage pouvant être rendu compatible avec C, comme le C++). Ces fonctions
+    sont compilées en objets dynamiques chargeables (encore appelés
+    bibliothèques partagées) et sont chargées par le serveur à la demande. Cette
+    caractéristique de chargement dynamique est ce qui distingue les fonctions
+    en <quote>langage C</quote> des fonctions <quote>internes</quote> &mdash; les véritables
+    conventions de codage sont essentiellement les mêmes pour les deux (c'est
+    pourquoi la bibliothèque standard de fonctions internes est une source
+    abondante d'exemples de code pour les fonctions C définies par
+    l'utilisateur).
+  </para>
+  
+  <para>
+    Deux différentes conventions d'appel sont actuellement en usage pour les
+    fonctions C. La plus récente, <quote>version 1</quote>,
+    est indiquée en écrivant une macro d'appel
+    <literal>PG_FUNCTION_INFO_V1()</literal> comme illustré ci-après. L'absence
+    d'une telle macro indique une fonction écrite selon l'ancien style
+    (<quote>version 0</quote>). Le nom de langage spécifié dans la commande 
+    <command>CREATE FUNCTION</command> est <literal>C</literal> dans les deux
+    cas. Les fonctions suivant l'ancien style sont maintenant déconseillées en
+    raison de problèmes de portabilité et d'un manque de fonctionnalité mais
+    elles sont encore supportées pour des raisons de compatibilité.
+ </para>  
+ 
+  <sect2 id="xfunc-c-dynload">
+   <title>Chargement dynamique</title>
+
+   <indexterm zone="xfunc-c-dynload">
+    <primary>dynamic loading</primary>
+   </indexterm>
+   
+   <para>
+    La première fois qu'une fonction définie par l'utilisateur dans un fichier
+    objet particulier chargeable est appelée dans une session, le chargeur
+    dynamique charge ce fichier objet en mémoire de telle sorte que la fonction 
+    peut être appelée. La commande <command>CREATE FUNCTION</command> pour une
+    fonction en C définie par l'utilisateur doit par conséquent spécifier deux
+    éléments d'information pour la fonction&nbsp;: le nom du fichier objet
+    chargeable et le nom en C (lien symbolique) de la fonction spécifique à
+    appeler à l'intérieur de ce fichier objet. Si le nom en C n'est pas
+    explicitement spécifié, il est supposé être le même que le nom de la
+    fonction SQL. 
+  </para> 
+  
+  <para>
+    L'algorithme suivant, basé sur le nom donné dans la commande
+    <command>CREATE FUNCTION</command>, est utilisé pour localiser le fichier
+    objet partagé&nbsp;:
+
+    <orderedlist>
+     <listitem>
+      <para>
+       Si le nom est un chemin absolu, le fichier est chargé.
+      </para>
+     </listitem>
+
+     <listitem>
+      <para>
+       Si le nom commence par la chaîne <literal>$libdir</literal>, cette chaîne
+       est remplacée par le nom du répertoire de la bibliothèque du paquetage
+       <productname>PostgreSQL</productname>, qui est déterminé au moment de la 
+       compilation. <indexterm><primary>$libdir</primary></indexterm>
+      </para>
+     </listitem>
+
+     <listitem>
+      <para>
+       Si le nom ne contient pas de partie répertoire, le fichier est recherché
+       par le chemin spécifié dans la variable de configuration
+       <xref linkend="guc-dynamic-library-path"/>.
+       <indexterm><primary>dynamic_library_path</primary></indexterm>
+      </para>
+     </listitem>
+
+     <listitem>
+      <para>
+       Dans les autres cas, (nom de fichier non trouvé dans le chemin ou ne
+       contenant pas de partie répertoire non absolu), le chargeur dynamique
+       essaiera d'utiliser le nom donné, ce qui échouera très vraisemblablement
+       (dépendre du répertoire de travail en cours n'est pas fiable).
+      </para>
+     </listitem>
+    </orderedlist>
+
+    Si cette séquence ne fonctionne pas, l'extension pour les noms de fichier
+    des bibliothèques partagées spécifique à la plateforme (souvent
+    <filename>.so</filename>) est ajoutée au nom attribué et la séquence est à
+    nouveau tentée. En cas de nouvel échec, le chargement échoue. 
+ </para>
+
+   <para>
+    Il est recommandé de localiser les bibliothèques partagées soit relativement
+    à <literal>$libdir</literal> ou via le chemin dynamique des bibliothèques.
+    Ceci simplifie les mises à jour de versions si la nouvelle installation est
+    à un emplacement différent. Le répertoire actuel représenté par
+    <literal>$libdir</literal> est trouvable avec la commande
+    <literal>pg_config --pkglibdir</literal>.
+   </para>
+
+    <para>
+     L'identifiant utilisateur sous lequel fonctionne le serveur
+     <productname>PostgreSQL</productname> doit pouvoir suivre le chemin
+     jusqu'au fichier que vous essayez de charger. Une erreur fréquente revient
+     à définir le fichier ou un répertoire supérieur comme non lisible et/ou
+     non exécutable par l'utilisateur <systemitem>postgres</systemitem>.
+    </para>
+
+   <para>
+    Dans tous les cas, le nom de fichier donné dans la commande <command>CREATE
+    FUNCTION</command> est enregistré littéralement dans les catalogues
+    systèmes, de sorte que, si le fichier doit être à nouveau chargé, la même 
+    procédure sera appliquée.
+ </para>
+
+   <note>
+    <para>
+     <productname>PostgreSQL</productname> ne compilera pas une fonction C
+     automatiquement. Le fichier objet doit être compilé avant d'être référencé
+     dans une commande <command>CREATE FUNCTION</command>. Voir la <xref
+    linkend="dfunc"/> pour des informations complémentaires. 
+   </para>
+   </note>
+
+   <indexterm zone="xfunc-c-dynload">
+    <primary>bloc magique</primary>
+   </indexterm>
+
+   <para>
+    Pour s'assurer qu'un fichier objet chargeable dynamiquement n'est pas chargé
+    dans un serveur incompatible, <productname>PostgreSQL</productname> vérifie
+    que le fichier contient un <quote>bloc magique</quote> avec un contenu
+    approprié. Ceci permet au serveur de détecter les incompatibilités évidentes
+    comme du code compilet pour une version majeure différente de
+    <productname>PostgreSQL</productname>. Un bloc magique est requis à partir de
+    <productname>PostgreSQL</productname> 8.2. Pour inclure un bloc magique,
+    écrivez ceci dans un (et seulement un) des fichiers source du module, après
+    avoir inclus l'en-tête <filename>fmgr.h</filename>&nbsp;:
+
+<programlisting>#ifdef PG_MODULE_MAGIC
+PG_MODULE_MAGIC;
+#endif
+</programlisting>
+
+    Le test <literal>#ifdef</literal> peut être omis si le code n'a pas besoin
+    d'être compilé avec des versions de <productname>PostgreSQL</productname>
+    antérieures à la 8.2.
+   </para>
+
+   <para>
+    Après avoir été utilisé pour la première fois, un fichier objet chargé
+    dynamiquement est conservé en mémoire. Les futurs appels de fonction(s) dans
+    ce fichier pendant la même session provoqueront seulement une légère
+    surcharge due à la consultation d'une table de symboles. Si vous devez
+    forcer le chargement d'un fichier objet, par exemple après une
+    recompilation, utilisez la commande <xref
+    linkend="sql-load" endterm="sql-load-title"/> ou commencez une
+    nouvelle session.  
+  </para>
+
+   <indexterm zone="xfunc-c-dynload">
+    <primary>_PG_init</primary>
+   </indexterm>
+   <indexterm zone="xfunc-c-dynload">
+    <primary>_PG_fini</primary>
+   </indexterm>
+   <indexterm zone="xfunc-c-dynload">
+    <primary>fonction d'initialisation de la bibliothèque</primary>
+   </indexterm>
+   <indexterm zone="xfunc-c-dynload">
+    <primary>fonction de terminaison de la bibliothèque</primary>
+   </indexterm>
+
+   <para>
+    De façon optionnelle, un fichier chargé dynamiquement peut contenir des
+    fonctions d'initialisation et de terminaison. Si le fichier inclut une
+    fonction nommée <function>_PG_init</function>, cette fonction sera appelée
+    immédiatement après le chargement du fichier. La fonction ne reçoit
+    aucun paramètre et doit renvoyer void. Si le fichier inclut une fonction
+    nommée <function>_PG_fini</function>, cette fonction sera appelée tout juste
+    avant le déchargement du fichier. De la même façon, la fonction ne reçoit
+    aucun paramètre et doit renvoyer void. Notez que <function>_PG_fini</function>
+    sera seulement appelée lors du déchargement du fichier, pas au moment de la
+    fin du processus. (Actuellement, un déchargement n'intervient que dans le
+    contexte d'un re-chargement du fichier suite à la commande explicite
+    <command>LOAD</command>.)
+   </para>
+
+  </sect2>
+
+   <sect2 id="xfunc-c-basetype">
+    <title>Types de base dans les fonctions en langage C</title>
+
+    <indexterm zone="xfunc-c-basetype">
+     <primary>type de données</primary>
+     <secondary>organisation interne</secondary>
+    </indexterm>
+
+    <para>
+     Pour savoir comment écrire des fonctions en langage C, vous devez savoir 
+     comment <productname>PostgreSQL</productname> représente en interne les
+     types de données de base et comment elles peuvent être passés vers et
+     depuis les fonctions. En interne, <productname>PostgreSQL</productname>
+     considère un type de base comme un <quote>blob de mémoire</quote>. Les
+     fonctions que vous définissez sur un type définissent à leur tour la façon
+     que <productname>PostgreSQL</productname> opère sur lui. C'est-à-dire
+     que <productname>PostgreSQL</productname> ne fera que conserver et retrouver
+     les données sur le disque et utilisera votre fonction pour entrer, traiter
+     et restituer les données.
+    </para>
+    
+    <para>
+     Les types de base peuvent avoir un des trois formats internes
+     suivants&nbsp;:
+     <itemizedlist>
+      <listitem>
+       <para>
+	passage par valeur, longueur fixe&nbsp;;
+       </para>
+      </listitem>
+      <listitem>
+       <para>
+	passage par référence, longueur fixe&nbsp;;
+       </para>
+      </listitem>
+      <listitem>
+       <para>
+	passage par référence, longueur variable.
+       </para>
+      </listitem>
+     </itemizedlist>
+    </para>
+
+    <para>
+     Les types par valeur peuvent seulement avoir une longueur de 1, 2 ou 4
+     octets (également 8 octets si <literal>sizeof(Datum)</literal> est de huit
+     octets sur votre machine). Vous devriez être attentif lors de la
+     définition de vos types de sorte à qu'ils aient la même taille sur toutes
+     les architectures. Par exemple, le type <literal>long</literal> est
+     dangereux car il a une taille de quatre octets sur certaines machines et
+     huit octets sur d'autres, alors que le type <type>int</type> est de quatre
+     octets sur la plupart des machines Unix. Une implémentation raisonnable du
+     type <type>int4</type> sur une machine Unix pourrait être
+ 
+ <programlisting>/* entier sur quatre octets, passé par valeur */
+typedef int int4;
+</programlisting>
+
+    </para>
+
+    <para>
+     D'autre part, les types à longueur fixe d'une taille quelconque peuvent
+     être passés par référence. Par exemple, voici l'implémentation d'un type
+     <productname>PostgreSQL</productname>&nbsp;:
+
+<programlisting>/* structure de 16 octets, passée par référence */
+typedef struct
+{
+    double  x, y;
+} Point;
+</programlisting>
+
+     Seuls des pointeurs vers de tels types peuvent être utilisés en les passant
+     dans et hors des fonctions <productname>PostgreSQL</productname>. Pour
+     renvoyer une valeur d'un tel type, allouez la quantité appropriée de
+     mémoire avec <literal>palloc</literal>, remplissez la mémoire allouée et
+     renvoyez un pointeur vers elle (de plus, si vous souhaitez seulement
+     renvoyer la même valeur qu'un de vos arguments en entrée qui se trouve du
+     même type, vous pouvez passer le <literal>palloc</literal>
+     supplémentaire et simplement renvoyer le pointeur vers la valeur en
+     entrée).
+    </para>
+
+    <para>
+     Enfin, tous les types à longueur variable doivent aussi être passés par
+     référence. Tous les types à longueur variable doivent commencer avec un
+     champ d'une longueur d'exactement quatre octets et toutes les données
+     devant être stockées dans ce type doivent être localisées dans la mémoire à
+     la suite immédiate de ce champ longueur. Le champ longueur contient la
+     longueur totale de la structure, c'est-à-dire incluant la longueur du
+     champ longueur lui-même.
+    </para>
+
+    <warning>
+     <para>
+      Ne <emphasis>jamais</emphasis> modifier le contenu d'une valeur en entrée passée
+      par référence. Si vous le faites, il y a de forts risques pour que
+      vous réussissiez à corrompre les données sur disque car le pointeur que
+      vous avez reçu pourrait bien pointer directement vers un tampon disque.
+      La seule exception à cette règle est expliquée dans la <xref
+      linkend="xaggr"/>.
+     </para>
+    </warning>
+
+    <para>
+     Comme exemple, nous pouvons définir le type <type>text</type> comme
+     ceci&nbsp;:
+
+<programlisting>typedef struct {
+    int4 length;
+    char data[1];
+} text;
+</programlisting>
+
+     Il est évident que le champ déclaré ici n'est pas assez long pour contenir
+     toutes les chaînes possibles. Comme il est impossible de déclarer une
+     structure de taille variable en <acronym>C</acronym>, nous nous appuyons
+     sur le fait que le compilateur  <acronym>C</acronym> ne vérifie pas la
+     plage des indices de tableau. Nous allouons juste la quantité d'espace
+     nécessaire et ensuite nous accédons au tableau comme s'il avait été déclaré
+     avec la bonne longueur (c'est une astuce courante que vous pouvez trouver
+     dans beaucoup de manuels de C).
+    </para>
+    
+    <para>
+     En manipulant les types à longueur variable, nous devons être attentifs à
+     allouer la quantité correcte de mémoire et à fixer correctement le champ
+     longueur. Par exemple, si nous voulons stocker 40 octets dans une structure
+     <structname>text</structname>, nous devrions utiliser un fragment de code comme
+     celui-ci&nbsp;:
+
+<programlisting><![CDATA[#include "postgres.h"
+...
+char buffer[40]; /* notre donnée source */
+...
+text *destination = (text *) palloc(VARHDRSZ + 40);
+destination->length = VARHDRSZ + 40;
+memcpy(destination->data, buffer, 40);
+...
+]]></programlisting>
+
+     <literal>VARHDRSZ</literal> est équivalent à <literal>sizeof(int4)</literal> mais
+     est considéré comme une meilleure tournure de référence à la taille de
+     l'overhead pour un type à longueur variable.
+    </para>
+
+    <para>
+     Le <xref linkend="xfunc-c-type-table"/> spécifie la correspondance entre
+     les types C et les types SQL quand on écrit une fonction en langage C
+     utilisant les types internes de <productname>PostgreSQL</productname>. La colonne
+     <quote>Défini dans</quote> donne le fichier d'en-tête devant être inclus
+     pour accéder à la définition du type (la définition effective peut se
+     trouver dans un fichier différent inclus dans le fichier indiqué. Il
+     est recommandé que les utilisateurs s'en tiennent à l'interface définie).
+     Notez que vous devriez toujours inclure <filename>postgres.h</filename> en
+     premier dans tout fichier source car il déclare un grand nombre d'éléments
+     dont vous aurez besoin de toute façon. 
+    </para>
+    
+    <table tocentry="1" id="xfunc-c-type-table">
+      <title>Équivalence des types C et des types SQL intégrés</title>
+      <tgroup cols="3">
+       <colspec colnum="1" colwidth="0.7*"/>
+       <colspec colnum="2" colwidth="0.5*"/>
+       <colspec colnum="3" colwidth="1.8*"/>
+       <thead>
+	<row>
+	 <entry>
+	  Type SQL
+	 </entry>
+	 <entry>
+	  Type C
+	 </entry>
+	 <entry>
+	  Défini dans
+	 </entry>
+	</row>
+       </thead>
+       <tbody>
+	<row>
+	 <entry><type>abstime</type></entry>
+	 <entry><type>AbsoluteTime</type></entry>
+	 <entry><filename>utils/nabstime.h</filename></entry>
+	</row>
+	<row>
+	 <entry><type>boolean</type></entry>
+	 <entry><type>bool</type></entry>
+	 <entry><filename>postgres.h</filename> (intégration au
+	  compilateur)</entry>
+	</row>
+	<row>
+	 <entry><type>box</type></entry>
+	 <entry><type>BOX*</type></entry>
+	 <entry><filename>utils/geo_decls.h</filename></entry>
+	</row>
+	<row>
+	 <entry><type>bytea</type></entry>
+	 <entry><type>bytea*</type></entry>
+	 <entry><filename>postgres.h</filename></entry>
+	</row>
+	<row>
+	 <entry><type>"char"</type></entry>
+	 <entry><type>char</type></entry>
+	 <entry>(intégré au compilateur)</entry>
+	</row>
+	<row>
+	 <entry><type>character</type></entry>
+	 <entry><type>BpChar*</type></entry>
+	 <entry><filename>postgres.h</filename></entry>
+	</row>
+	<row>
+	 <entry><type>cid</type></entry>
+	 <entry><type>CommandId</type></entry>
+	 <entry><filename>postgres.h</filename></entry>
+	</row>
+	<row>
+	 <entry><type>date</type></entry>
+	 <entry><type>DateADT</type></entry>
+	 <entry><filename>utils/date.h</filename></entry>
+	</row>
+	<row>
+	 <entry><type>smallint</type> (<type>int2</type>)</entry>
+	 <entry><type>int2</type> or <type>int16</type></entry>
+	 <entry><filename>postgres.h</filename></entry>
+	</row>
+	<row>
+	 <entry><type>int2vector</type></entry>
+	 <entry><type>int2vector*</type></entry>
+	 <entry><filename>postgres.h</filename></entry>
+	</row>
+	<row>
+	 <entry><type>integer</type> (<type>int4</type>)</entry>
+	 <entry><type>int4</type> or <type>int32</type></entry>
+	 <entry><filename>postgres.h</filename></entry>
+	</row>
+	<row>
+	 <entry><type>real</type> (<type>float4</type>)</entry>
+	 <entry><type>float4*</type></entry>
+	<entry><filename>postgres.h</filename></entry>
+	</row>
+	<row>
+	 <entry><type>double precision</type> (<type>float8</type>)</entry>
+	 <entry><type>float8*</type></entry>
+	 <entry><filename>postgres.h</filename></entry>
+	</row>
+	<row>
+	 <entry><type>interval</type></entry>
+	 <entry><type>Interval*</type></entry>
+	 <entry><filename>utils/timestamp.h</filename></entry>
+	</row>
+	<row>
+	 <entry><type>lseg</type></entry>
+	 <entry><type>LSEG*</type></entry>
+	 <entry><filename>utils/geo_decls.h</filename></entry>
+	</row>
+	<row>
+	 <entry><type>name</type></entry>
+	 <entry><type>Name</type></entry>
+	 <entry><filename>postgres.h</filename></entry>
+	</row>
+	<row>
+	 <entry><type>oid</type></entry>
+	 <entry><type>Oid</type></entry>
+	 <entry><filename>postgres.h</filename></entry>
+	</row>
+	<row>
+	 <entry><type>oidvector</type></entry>
+	 <entry><type>oidvector*</type></entry>
+	 <entry><filename>postgres.h</filename></entry>
+	</row>
+	<row>
+	 <entry><type>path</type></entry>
+	 <entry><type>PATH*</type></entry>
+	 <entry><filename>utils/geo_decls.h</filename></entry>
+	</row>
+	<row>
+	 <entry><type>point</type></entry>
+	 <entry><type>POINT*</type></entry>
+	 <entry><filename>utils/geo_decls.h</filename></entry>
+	</row>
+	<row>
+	 <entry><type>regproc</type></entry>
+	 <entry><type>regproc</type></entry>
+	 <entry><filename>postgres.h</filename></entry>
+	</row>
+	<row>
+	 <entry><type>reltime</type></entry>
+	 <entry><type>RelativeTime</type></entry>
+	 <entry><filename>utils/nabstime.h</filename></entry>
+	</row>
+	<row>
+	 <entry><type>text</type></entry>
+	 <entry><type>text*</type></entry>
+	 <entry><filename>postgres.h</filename></entry>
+	</row>
+	<row>
+	 <entry><type>tid</type></entry>
+	 <entry><type>ItemPointer</type></entry>
+	 <entry><filename>storage/itemptr.h</filename></entry>
+	</row>
+	<row>
+	 <entry><type>time</type></entry>
+	 <entry><type>TimeADT</type></entry>
+	 <entry><filename>utils/date.h</filename></entry>
+	</row>
+	<row>
+	 <entry><type>time with time zone</type></entry>
+	 <entry><type>TimeTzADT</type></entry>
+	 <entry><filename>utils/date.h</filename></entry>
+	</row>
+	<row>
+	 <entry><type>timestamp</type></entry>
+	 <entry><type>Timestamp*</type></entry>
+	 <entry><filename>utils/timestamp.h</filename></entry>
+	</row>
+	<row>
+	 <entry><type>tinterval</type></entry>
+	 <entry><type>TimeInterval</type></entry>
+	 <entry><filename>utils/nabstime.h</filename></entry>
+	</row>
+	<row>
+	 <entry><type>varchar</type></entry>
+	 <entry><type>VarChar*</type></entry>
+	 <entry><filename>postgres.h</filename></entry>
+	</row>
+	<row>
+	 <entry><type>xid</type></entry>
+	 <entry><type>TransactionId</type></entry>
+	 <entry><filename>postgres.h</filename></entry>
+	</row>
+       </tbody>
+      </tgroup>
+     </table>
+
+    <para>
+     Maintenant que nous avons passé en revue toutes les structures possibles
+     pour les types de base, nous pouvons donner quelques exemples de vraies
+     fonctions.
+ </para>
+   </sect2>
+
+   <sect2>
+    <title>Conventions d'appel de la version 0</title>
+
+    <para>
+     Nous présentons l'<quote>ancien style</quote> de convention d'appel en
+     premier &mdash; bien que cette approche soit maintenant déconseillée, elle est
+     plus facile à maîtriser au début. Dans la méthode version-0, les arguments
+     et résultats de la fonction C sont simplement déclarés dans le style C
+     normal mais en faisant attention à utiliser la représentation C de chaque
+     type de données SQL comme montré ci-dessus.
+    </para>
+
+    <para>
+     Voici quelques exemples&nbsp;:
+
+<programlisting><![CDATA[#include "postgres.h"
+#include <string.h>
+
+/* par valeur */
+         
+int
+add_one(int arg)
+{
+    return arg + 1;
+}
+
+/* par référence, taille fixe */
+
+float8 *
+add_one_float8(float8 *arg)
+{
+    float8    *result = (float8 *) palloc(sizeof(float8));
+
+    *result = *arg + 1.0;
+       
+    return result;
+}
+
+Point *
+makepoint(Point *pointx, Point *pointy)
+{
+    Point     *new_point = (Point *) palloc(sizeof(Point));
+
+    new_point->x = pointx->x;
+    new_point->y = pointy->y;
+       
+    return new_point;
+}
+
+/* par référence, taille variable */
+
+text *
+copytext(text *t)
+{
+    /*
+     * VARSIZE est la taille totale de la structure en octets.
+     */
+    text *new_t = (text *) palloc(VARSIZE(t));
+    SET_VARSIZE(new_t, VARSIZE(t));
+    /*
+     * VARDATA est un pointeur sur la région de données de la structure.
+     */
+    memcpy((void *) VARDATA(new_t), /* destination */
+           (void *) VARDATA(t),     /* source */
+           VARSIZE(t) - VARHDRSZ);  /* nombre d'octets */
+    return new_t;
+}
+
+text *
+concat_text(text *arg1, text *arg2)
+{
+    int32 new_text_size = VARSIZE(arg1) + VARSIZE(arg2) - VARHDRSZ;
+    text *new_text = (text *) palloc(new_text_size);
+
+    SET_VARSIZE(new_text, new_text_size);
+    memcpy(VARDATA(new_text), VARDATA(arg1), VARSIZE(arg1) - VARHDRSZ);
+    memcpy(VARDATA(new_text) + (VARSIZE(arg1) - VARHDRSZ),
+           VARDATA(arg2), VARSIZE(arg2) - VARHDRSZ);
+    return new_text;
+}
+]]></programlisting>
+    </para>
+
+    <para>
+     En supposant que le code ci-dessus ait été écrit dans le fichier
+     <filename>funcs.c</filename> et compilé en objet partagé, nous pourrions
+     définir les fonctions pour <productname>PostgreSQL</productname> avec des
+     commandes comme ceci&nbsp;:
+     
+<programlisting>CREATE FUNCTION add_one(integer) RETURNS integer
+     AS '<replaceable>DIRECTORY</replaceable>/funcs', 'add_one'
+     LANGUAGE C STRICT;
+
+-- notez la surcharge du nom de la fonction SQL "add_one"
+CREATE FUNCTION add_one(double precision) RETURNS double precision
+     AS '<replaceable>DIRECTORY</replaceable>/funcs', 'add_one_float8'
+     LANGUAGE C STRICT;
+
+CREATE FUNCTION makepoint(point, point) RETURNS point
+     AS '<replaceable>DIRECTORY</replaceable>/funcs', 'makepoint'
+     LANGUAGE C STRICT;
+                         
+CREATE FUNCTION copytext(text) RETURNS text
+     AS '<replaceable>DIRECTORY</replaceable>/funcs', 'copytext'
+     LANGUAGE C STRICT;
+
+CREATE FUNCTION concat_text(text, text) RETURNS text
+     AS '<replaceable>DIRECTORY</replaceable>/funcs', 'concat_text'
+     LANGUAGE C STRICT;
+</programlisting>
+    </para>
+
+    <para>
+     Ici, <replaceable>DIRECTORY</replaceable> représente le répertoire
+     contenant le fichier de la bibliothèque partagée (par exemple le répertoire
+     du tutoriel de <productname>PostgreSQL</productname>, qui contient le code
+     des exemples utilisés dans cette section). (Un meilleur style aurait été
+     d'écrire seulement <literal>'funcs'</literal> dans la clause <literal>AS</literal>, après
+     avoir ajouté <replaceable>DIRECTORY</replaceable> au chemin de recherche.
+     Dans tous les cas, nous pouvons omettre l'extension spécifique au système
+     pour les bibliothèques partagées, communément <literal>.so</literal> ou    
+     <literal>.sl</literal>.) 
+    </para>
+
+    <para>
+     Remarquez que nous avons spécifié la fonction comme <quote>STRICT</quote>, 
+     ce qui signifie que le système devra automatiquement supposer un résultat 
+     NULL si n'importe quelle valeur d'entrée est NULL. Ainsi, nous évitons
+     d'avoir à vérifier l'existence d'entrées NULL dans le code de la fonction.
+     Sinon, nous aurions dû contrôler explicitement les valeurs NULL en testant
+     un pointeur NULL pour chaque argument passé par référence (pour les
+     arguments passés par valeur, nous n'aurions même aucun moyen de contrôle&nbsp;!).
+    </para>
+
+    <para>
+     Bien que cette convention d'appel soit simple à utiliser, elle n'est pas
+     très portable&nbsp;; sur certaines architectures,  il y a des problèmes
+     pour passer de cette manière des types de données plus petits
+     que <type>int</type>. De plus, il n'y a pas de moyen simple de renvoyer un
+     résultat NULL, ni de traiter des arguments NULL autrement qu'en rendant la
+     fonction strict. La convention version-1, présentée ci-après, permet de
+     surmonter ces objections.
+    </para>
+    
+   </sect2>
+   
+   <sect2>
+    <title>Conventions d'appel de la version 1</title>
+
+    <para>
+     La convention d'appel version-1 repose sur des macros pour supprimer la
+     plus grande partie de la complexité du passage d'arguments et de résultats.
+     La déclaration C d'une fonction en version-1 est toujours&nbsp;:
+
+<programlisting>Datum nom_fonction(PG_FUNCTION_ARGS)
+</programlisting>
+
+     De plus, la macro d'appel&nbsp;:
+<programlisting>PG_FUNCTION_INFO_V1(nom_fonction);
+</programlisting>
+     doit apparaître dans le même fichier source (par convention, elle est
+     écrite juste avant la fonction elle-même). Cette macro n'est pas nécessaire
+     pour les fonctions <literal>internal</literal> puisque <productname>PostgreSQL</productname> 
+     assume que toutes les fonctions internes utilisent la convention version-1.
+     Elle est toutefois requise pour les fonctions chargées dynamiquement.
+    </para>
+
+    <para>
+     Dans une fonction version-1, chaque argument existant est traité par une
+     macro <function>PG_GETARG_<replaceable>xxx</replaceable>()</function> 
+     correspondant au type de donnée de l'argument et le résultat est renvoyé
+     par une macro
+     <function>PG_RETURN_<replaceable>xxx</replaceable>()</function>
+     correspondant au type renvoyé. 
+     <function>PG_GETARG_<replaceable>xxx</replaceable>()</function>
+     prend comme argument le nombre d'arguments de la fonction à parcourir, le
+     compteur commençant à 0.
+     <function>PG_RETURN_<replaceable>xxx</replaceable>()</function> prend comme
+     argument la valeur effective à renvoyer. 
+    </para>
+
+    <para>
+     Voici la même fonction que précédemment, codée en style version-1
+     
+<programlisting><![CDATA[#include "postgres.h"
+#include <string.h>
+#include "fmgr.h"
+
+/* par valeur */
+
+PG_FUNCTION_INFO_V1(add_one);
+         
+Datum
+add_one(PG_FUNCTION_ARGS)
+{
+    int32   arg = PG_GETARG_INT32(0);
+
+    PG_RETURN_INT32(arg + 1);
+}
+
+/* par référence, longueur fixe */
+
+PG_FUNCTION_INFO_V1(add_one_float8);
+
+Datum
+add_one_float8(PG_FUNCTION_ARGS)
+{
+    /* La macro pour FLOAT8 cache sa nature de passage par référence. */
+    float8   arg = PG_GETARG_FLOAT8(0);
+
+    PG_RETURN_FLOAT8(arg + 1.0);
+}
+
+PG_FUNCTION_INFO_V1(makepoint);
+
+Datum
+makepoint(PG_FUNCTION_ARGS)
+{
+    /* Ici, la nature de passage par référence de Point n'est pas cachée. */
+    Point     *pointx = PG_GETARG_POINT_P(0);
+    Point     *pointy = PG_GETARG_POINT_P(1);
+    Point     *new_point = (Point *) palloc(sizeof(Point));
+
+    new_point->x = pointx->x;
+    new_point->y = pointy->y;
+       
+    PG_RETURN_POINT_P(new_point);
+}
+
+/* par référence, longueur variable */
+
+PG_FUNCTION_INFO_V1(copytext);
+
+Datum
+copytext(PG_FUNCTION_ARGS)
+{
+    text     *t = PG_GETARG_TEXT_P(0);
+    /*
+     * VARSIZE est la longueur totale de la structure en octets.
+     */
+    text     *new_t = (text *) palloc(VARSIZE(t));
+    SET_VARSIZE(new_t, VARSIZE(t));
+    /*
+     * VARDATA est un pointeur vers la région de données de la structure.
+     */
+    memcpy((void *) VARDATA(new_t), /* destination */
+           (void *) VARDATA(t),     /* source */
+           VARSIZE(t) - VARHDRSZ);    /* nombre d'octets */
+    PG_RETURN_TEXT_P(new_t);
+}
+
+PG_FUNCTION_INFO_V1(concat_text);
+
+Datum
+concat_text(PG_FUNCTION_ARGS)
+{
+    text  *arg1 = PG_GETARG_TEXT_P(0);
+    text  *arg2 = PG_GETARG_TEXT_P(1);
+    int32 new_text_size = VARSIZE(arg1) + VARSIZE(arg2) - VARHDRSZ;
+    text *new_text = (text *) palloc(new_text_size);
+
+    SET_VARSIZE(new_text, new_text_size);
+    memcpy(VARDATA(new_text), VARDATA(arg1), VARSIZE(arg1) - VARHDRSZ);
+    memcpy(VARDATA(new_text) + (VARSIZE(arg1) - VARHDRSZ),
+           VARDATA(arg2), VARSIZE(arg2) - VARHDRSZ);
+    PG_RETURN_TEXT_P(new_text);
+}
+]]></programlisting>
+    </para>
+
+    <para>
+     Les commandes <command>CREATE FUNCTION</command> sont les mêmes que pour
+     leurs équivalents dans la version-0.
+    </para>
+        
+    <para>
+     Au premier coup d'&oelig;il, les conventions de codage de la version-1 peuvent
+     sembler inutilement obscures. Pourtant, elles offrent nombre
+     d'améliorations car les macros peuvent cacher les détails superflus. Un
+     exemple est donné par la fonction  <function>add_one_float8</function> où nous
+     n'avons plus besoin de prêter attention au fait que le type
+     <type>float8</type> est passé par référence. Un autre exemple de
+     simplification est donné par les macros pour les types à longueur variable
+     <literal>GETARG</literal> qui permettent un traitement plus efficace des valeurs 
+     <quote>toasted</quote> (compressées ou hors-ligne).  
+    </para>
+    
+    <para>
+     Une des grandes améliorations dans les fonctions version-1 est le meilleur
+     traitement des entrées et des résultats NULL. La macro  
+     <function>PG_ARGISNULL(<replaceable>n</replaceable>)</function> permet à une fonction
+     de tester si chaque entrée est NULL (évidemment, ceci n'est nécessaire que
+     pour les fonctions déclarées non <quote>STRICT</quote>). Comme avec les macros
+     <function>PG_GETARG_<replaceable>xxx</replaceable>()</function>, les
+     arguments en entrée sont comptés à partir de zéro. Notez qu'on doit se
+     garder d'exécuter
+     <function>PG_GETARG_<replaceable>xxx</replaceable>()</function> jusqu'à 
+     ce qu'on ait vérifié que l'argument n'est pas NULL. Pour renvoyer un
+     résultat NULL, exécutez la fonction
+     <function>PG_RETURN_NULL()</function>&nbsp;; ceci convient aussi bien dans
+     les fonctions STRICT que non STRICT.
+    </para>
+    
+    <para>  
+     Les autres options proposées dans l'interface de nouveau style sont deux
+     variantes des macros 
+     <function>PG_GETARG_<replaceable>xxx</replaceable>()</function>. La
+     première d'entre elles,
+     <function>PG_GETARG_<replaceable>xxx</replaceable>_COPY()</function>,  
+     garantit le renvoi d'une copie de l'argument spécifié où nous pouvons
+     écrire en toute sécurité (les macros normales peuvent parfois renvoyer 
+     un pointeur vers une valeur physiquement mise en mémoire dans une table qui
+     ne doit pas être modifiée. En utilisant les macros
+     <function>PG_GETARG_<replaceable>xxx</replaceable>_COPY()</function>, on
+     garantit l'écriture du résultat). La seconde variante se compose des macros
+     <function>PG_GETARG_<replaceable>xxx</replaceable>_SLICE()</function>
+     qui prennent trois arguments. Le premier est le nombre d'arguments de la
+     fonction (comme ci-dessus). Le second et le troisième sont le décalage et
+     la longueur du segment qui doit être renvoyé. Les décalages sont comptés à
+     partir de zéro et une longueur négative demande le renvoi du reste de la
+     valeur. Ces macros procurent un accès plus efficace à des parties de
+     valeurs à grande dimension dans le cas où elles ont un type de stockage en
+     mémoire <quote>external</quote> (le type de stockage d'une colonne peut
+     être spécifié en utilisant <literal>ALTER TABLE
+     <replaceable>nom_table</replaceable> ALTER COLUMN
+     <replaceable>nom_colonne</replaceable> SET STORAGE
+     <replaceable>typestockage</replaceable></literal>.
+     <replaceable>typestockage</replaceable> est un type parmi
+     <literal>plain</literal>, <literal>external</literal>, <literal>extended</literal> ou
+     <literal>main</literal>).
+    </para>
+
+    <para> 
+     Enfin, les conventions d'appels de la version-1 rendent possible le renvoi
+     de résultats d'ensemble (<xref linkend="xfunc-c-return-set"/>),
+     l'implémentation de fonctions déclencheurs (<xref
+     linkend="triggers"/>) et d'opérateurs d'appel de langage procédural (<xref
+     linkend="plhandler"/>). Le code version-1 est aussi plus portable que celui
+     de version-0 car il ne contrevient pas aux restrictions du protocole
+     d'appel de fonction en C standard. Pour plus de détails, voir
+     <filename>src/backend/utils/fmgr/README</filename> dans les fichiers 
+     sources de la distribution.
+    </para>
+     
+   </sect2>
+
+   <sect2>
+    <title>Écriture du code</title>
+
+    <para>
+     Avant de nous intéresser à des sujets plus avancés, nous devons discuter de
+     quelques règles de codage des fonctions en langage C de
+     <productname>PostgreSQL</productname>.  Bien qu'il soit possible de charger
+     des fonctions écrites dans des langages autre que le C dans
+     <productname>PostgreSQL</productname>, c'est habituellement difficile
+     (quand c'est possible) parce que les autres langages comme C++, FORTRAN ou
+     Pascal ne suivent pas fréquemment les mêmes conventions de nommage que le
+     C. C'est-à-dire que les autres langages ne passent pas les arguments et ne 
+     renvoient pas les valeurs entre fonctions de la même manière. Pour cette
+     raison, nous supposerons que nos fonctions en langage C sont réellement
+     écrites en C.
+ </para>
+    <para>
+     Les règles de base pour l'écriture de fonctions C sont les suivantes&nbsp;:
+
+     <itemizedlist>
+      <listitem>
+       <para>
+        Utilisez <literal>pg_config
+        --includedir-server</literal><indexterm><primary>pg_config</primary><secondary>
+        avec des fonctions C définies par l'utilisateur</secondary></indexterm> pour découvrir où
+        sont installés les fichiers d'en-tête du serveur
+        <productname>PostgreSQL</productname> sur votre système (ou sur le système de vos
+        utilisateurs).
+       </para>
+      </listitem>
+
+      <listitem>
+       <para>
+        Compilez et liez votre code de façon à ce qu'il soit chargé dynamiquement
+	dans <productname>PostgreSQL</productname>, ce qui requiert des informations
+	spéciales. Voir <xref linkend="dfunc"/> pour une explication détaillée
+	sur la façon de le faire pour votre système d'exploitation spécifique.
+       </para>
+      </listitem>
+
+      <listitem>
+       <para>
+        Rappelez-vous to définir un <quote>bloc magique</quote> pour votre
+	bibliothèque partagée, comme décrit dans <xref linkend="xfunc-c-dynload"/>.
+       </para>
+      </listitem>
+
+      <listitem>
+       <para>
+        Quand vous allouez de la mémoire, utilisez les fonctions 
+        <productname>PostgreSQL</productname>
+        <function>palloc</function><indexterm><primary>palloc</primary></indexterm> et
+        <function>pfree</function><indexterm><primary>pfree</primary></indexterm>
+        au lieu des fonctions correspondantes <function>malloc</function> et
+        <function>free</function> de la bibliothèque C. La mémoire allouée par
+        <function>palloc</function> sera libérée automatiquement à la fin de
+        chaque transaction, empêchant des débordements de mémoire. 
+       </para>
+      </listitem>
+
+      <listitem>
+       <para>
+        Remettez toujours à zéro les octets de vos structures en utilisant
+        <function>memset</function>. Sinon, il est difficile de supporter les
+        index ou les jointures de découpage car vous devez retenir seulement
+        les bits significatifs de votre structure de donnée pour calculer un
+        découpage. Même si vous initialisez tous les champs de votre structure,
+        il peut y avoir des remplissages d'alignement (trous dans la structure)
+        pouvant contenir des valeurs parasites.
+       </para>
+      </listitem>
+
+      <listitem>
+       <para>
+        La plupart des types internes <productname>PostgreSQL</productname>
+        sont déclarés dans <filename>postgres.h</filename> alors que les
+        interfaces de gestion des fonctions
+        (<symbol>PG_FUNCTION_ARGS</symbol>, etc.) sont dans 
+        <filename>fmgr.h</filename>. Du coup, vous aurez besoin d'inclure au
+        moins ces deux fichiers. Pour des raisons de portabilité, il vaut
+        mieux inclure <filename>postgres.h</filename> <emphasis>en premier</emphasis>
+        avant tout autre fichier d'en-tête système ou utilisateur. En incluant
+        <filename>postgres.h</filename>, il incluera également
+        <filename>elog.h</filename> et <filename>palloc.h</filename> pour vous.
+       </para>
+      </listitem>
+
+      <listitem>
+       <para>
+        Les noms de symboles définis dans les objets ne doivent pas entrer en
+        conflit entre eux ou avec les symboles définis dans les exécutables du
+        serveur <productname>PostgreSQL</productname>. Vous aurez à renommer vos
+        fonctions ou variables si vous recevez un message d'erreur à cet effet.
+       </para>
+      </listitem>
+     </itemizedlist>
+    </para>
+   </sect2>
+
+&dfunc;
+
+<sect2 id="xfunc-c-pgxs">
+  <title>Infrastructure de construction d'extensions</title>
+
+  <indexterm zone="xfunc-c-pgxs">
+    <primary>pgxs</primary>
+  </indexterm>
+
+  <para>
+    Si vous pensez distribuer vos modules d'extension
+    <productname>PostgreSQL</productname>, configurer un système de construction
+    portable peut être assez compliqué. Du coup, l'installation de
+    <productname>PostgreSQL</productname> fournit une infrastructure de construction pour
+    les extensions, appelée <acronym>PGXS</acronym>, pour que les modules
+    d'extension simples puissent être construit simplement avec un serveur
+    déjà installé. Notez que cette infrastructure n'a pas pour but d'être un
+    ensemble de travail universel pouvant être utilisé pour construire tous
+    les logiciels s'interfaçant avec <productname>PostgreSQL</productname>&nbsp;; il
+    automatise simplement les règles de construction communes pour les modules
+    simples d'extension du serveur. Pour des paquetages plus complexes, vous
+    aurez besoin d'écrire votre propre système de construction.
+  </para>
+
+  <para>
+    Pour utiliser l'infrastructure de votre extension, vous devez écrire un
+    simple fichier makefile. Dans ce fichier, vous devez configurer quelques
+    variables et inclure enfin le makefile global <acronym>PGXS</acronym>.
+    Voici un exemple qui construit un module d'extension nommé
+    <literal>isbn_issn</literal> consistant en une bibliothèque partagée, un
+    script SQL et un fichier texte de documentation&nbsp;:
+<programlisting>MODULES = isbn_issn
+DATA_built = isbn_issn.sql
+DOCS = README.isbn_issn
+    
+PG_CONFIG := pg_config
+PGXS := $(shell $(PG_CONFIG) --pgxs)
+include $(PGXS)
+</programlisting>
+    Les trois dernières lignes devraient toujours être identiques. Plus tôt
+    dans le fichier, vous affectez des variables ou ajoutez vos propres règles
+    pour <application>make</application>.
+  </para>
+
+  <para>
+    Les variables suivantes peuvent être configurées&nbsp;:
+  
+  <variablelist>
+    <varlistentry>
+      <term><varname>MODULES</varname></term>
+      <listitem>
+        <para>
+          liste des objets partagés à construire à partir du fichier source
+          de même base (ne pas inclure le suffixe dans cette liste)
+        </para>
+      </listitem>
+    </varlistentry>
+    
+    <varlistentry>
+      <term><varname>DATA</varname></term>
+      <listitem>
+        <para>
+          fichiers spécifiques à installer dans
+          <literal><replaceable>prefix</replaceable>/share/contrib</literal>
+        </para>
+      </listitem>
+    </varlistentry>
+    
+    <varlistentry>
+      <term><varname>DATA_built</varname></term>
+      <listitem>
+        <para>
+          fichiers spécifiques à installer dans
+          <literal><replaceable>prefix</replaceable>/share/contrib</literal>
+          qui ont besoin d'être construit au début
+        </para>
+      </listitem>
+    </varlistentry>
+    
+    <varlistentry>
+      <term><varname>DOCS</varname></term>
+      <listitem>
+        <para>
+          fichiers spécifiques à installer dans
+          <literal><replaceable>prefix</replaceable>/doc/contrib</literal>
+        </para>
+      </listitem>
+    </varlistentry>
+    
+    <varlistentry>
+      <term><varname>SCRIPTS</varname></term>
+      <listitem>
+        <para>
+          fichiers script (pas des binaires) à installer dans
+          <literal><replaceable>prefix</replaceable>/bin</literal>
+        </para>
+      </listitem>
+    </varlistentry>
+    
+    <varlistentry>
+      <term><varname>SCRIPTS_built</varname></term>
+      <listitem>
+        <para>
+          fichiers script (pas des binaires) à installer dans
+          <literal><replaceable>prefix</replaceable>/bin</literal>
+          qui ont besoin d'être construit au début
+        </para>
+      </listitem>
+    </varlistentry>
+    
+    <varlistentry>
+      <term><varname>REGRESS</varname></term>
+      <listitem>
+        <para>
+          liste des cas de tests de regression (sans suffixe), voir ci-dessous
+        </para>
+      </listitem>
+    </varlistentry>
+  </variablelist>
+  
+    ou au moins un parmi ces deux-là&nbsp;:
+  
+  <variablelist>
+    <varlistentry>
+      <term><varname>PROGRAM</varname></term>
+      <listitem>
+        <para>
+          un programme binaire à construire (liste des fichiers objets dans
+          <varname>OBJS</varname>)
+        </para>
+      </listitem>
+    </varlistentry>
+    
+    <varlistentry>
+      <term><varname>MODULE_big</varname></term>
+      <listitem>
+        <para>
+          un objet partagé à construire (liste des fichiers objets dans
+          <varname>OBJS</varname>)
+        </para>
+      </listitem>
+    </varlistentry>
+  </variablelist>
+  
+    Ce qui suit peut être configuré&nbsp;:
+  
+  <variablelist>
+    
+    <varlistentry>
+      <term><varname>EXTRA_CLEAN</varname></term>
+      <listitem>
+        <para>
+          fichiers supplémentaires à supprimer dans <literal>make
+          clean</literal>
+        </para>
+      </listitem>
+    </varlistentry>
+    
+    <varlistentry>
+      <term><varname>PG_CPPFLAGS</varname></term>
+      <listitem>
+        <para>
+          sera ajouté à <varname>CPPFLAGS</varname>
+        </para>
+      </listitem>
+    </varlistentry>
+    
+    <varlistentry>
+      <term><varname>PG_LIBS</varname></term>
+      <listitem>
+        <para>
+          sera ajouté à la ligne de liens <varname>PROGRAM</varname>
+        </para>
+      </listitem>
+    </varlistentry>
+    
+    <varlistentry>
+      <term><varname>SHLIB_LINK</varname></term>
+      <listitem>
+        <para>
+          sera ajouté à la ligne de lien <varname>MODULE_big</varname>
+        </para>
+      </listitem>
+    </varlistentry>
+
+     <varlistentry>
+      <term><varname>PG_CONFIG</varname></term>
+      <listitem>
+       <para>
+        chemin vers le programme <application>pg_config</application> indiquant
+        l'installation de <productname>PostgreSQL</productname> qui sert à la
+	construction (généralement <literal>pg_config</literal> pour utiliser
+	le premier programme trouvé dans la variable d'environnement
+        <varname>PATH</varname>)
+       </para>
+      </listitem>
+     </varlistentry>
+  </variablelist>
+
+  </para>
+
+  <para>
+    Nommez ce fichier <literal>Makefile</literal> et placez le dans le répertoire
+    qui contient votre extension. Ensuite, vous pouvez lancer la compilation
+    avec <literal>make</literal>, et plus tard <literal>make
+    install</literal> pour installer votre module. Par défaut, l'extension est
+    compilée et installée pour l'installation de
+    <productname>PostgreSQL</productname> qui correspond au premier programme
+    <command>pg_config</command> trouvée dans votre chemin. Vous pouvez utiliser
+    utiliser une autre installation en configurant <varname>PG_CONFIG</varname>
+    pour qu'il pointe vers le bon <command>pg_config</command>, soit dans le
+    fichier Makefile soit sur la ligne de commande de <literal>make</literal>.
+  </para>
+  
+   <caution>
+    <para>
+     Modifier <varname>PG_CONFIG</varname> fonctionne seulement en construisant
+     à partir d'une installation <productname>PostgreSQL</productname> 8.3 ou
+     ultérieure. Les anciennes versions ne l'utilisent pas&nbsp;; vous devez
+     donc modifier votre variable <varname>PATH</varname> pour sélectionner
+     la bonne installation.
+    </para>
+   </caution>
+
+   <para>
+    Les scripts listés dans la variable <varname>REGRESS</varname> sont utilisés
+    pour les tests de régression de votre module, tout comme <literal>make
+    installcheck</literal> est utilisé pour votre serveur
+    <productname>PostgreSQL</productname>. Pour que ceci fonctionne, vous avez
+    besoin d'avoir un sous-répertoire nommé <literal>sql/</literal> dans le
+    répertoire de votre extension, à l'intérieur duquel vous placez un fichier
+    pour chaque groupe de tests que vous voulez exécuter. Les fichiers doivent
+    avoir l'extension <literal>.sql</literal>, qui ne seront pas inclus dans la
+    liste <varname>REGRESS</varname> dans le Makefile. Pour chaque test, il doit
+    exister un fichier contenant le résultat attendu dans un sous-répertoire nommé
+    <literal>expected/</literal>, avec l'extension <literal>.out</literal>. Les
+    tests sont exécutés via <literal>make installcheck</literal>, et le résultat sera
+    comparé aux fichiers attendus. Les différences seront écrites dans le fichier
+    <literal>regression.diffs</literal> dans un format <command>diff -c</command>.
+    Notez qu'essayer d'exécuter un test à qui il manque le fichier sera rapporté
+    comme un <quote>problème</quote>, donc assurez-vous que vous avez bien tous les
+    fichiers attendus.
+   </para>
+
+   <tip>
+    <para>
+     La façon la plus simple de créer les fichiers attendus est de créer des
+     fichiers vides, puis de vérifier avec précaution les fichiers résultants
+     après un test d'exécution (à trouver dans un répertoire
+     <literal>results/</literal>), et les copier dans
+     <literal>expected/</literal> s'ils correspondent à votre souhait suite aux
+     tests.
+    </para>
+   </tip>
+  </sect2>
+
+
+   <sect2>
+    <title>Arguments de type composite</title>
+    
+    <para>
+     Les types composites n'ont pas une organisation fixe comme les structures
+     en C. Des instances d'un type composite peuvent contenir des champs NULL.
+     De plus, les types composites faisant partie d'une hiérarchie d'héritage
+     peuvent avoir des champs différents des autres membres de la même
+     hiérarchie. En conséquence, <productname>PostgreSQL</productname> propose
+     une interface de fonction pour accéder depuis le C aux champs des types 
+     composites. 
+    </para>
+
+    <para>
+     Supposons que nous voulions écrire une fonction pour répondre à la requête&nbsp;:
+<programlisting>SELECT nom, c_surpaye(emp, 1500) AS surpaye
+    FROM emp
+    WHERE nom = 'Bill' OR nom = 'Sam';
+</programlisting>
+
+     En utilisant les conventions d'appel de la version 0, nous pouvons définir
+     <function>c_surpaye</function> comme&nbsp;:
+     
+<programlisting><![CDATA[#include "postgres.h"
+#include "executor/executor.h"  /* pour GetAttributeByName() */
+
+bool
+c_surpaye(HeapTupleHeader *t, /* la ligne courante d'emp */
+           int32 limite)
+{
+    bool isNULL;
+    int32 salaire;
+
+    salaire = DatumGetInt32(GetAttributeByName(t, "salaire", &isNULL));
+    if (isNULL)
+        return false;
+    return salaire > limite;
+}
+]]></programlisting>
+
+     Dans le codage version-1, le code ci-dessus devient&nbsp;:
+
+<programlisting><![CDATA[#include "postgres.h"
+#include "executor/executor.h"  /* pour GetAttributeByName() */
+
+PG_FUNCTION_INFO_V1(c_overpaid);
+
+Datum
+c_overpaid(PG_FUNCTION_ARGS)
+{
+    HeapTupleHeader  *t = (HeapTupleHeader *) PG_GETARG_HEAPTUPLEHEADER(0);
+    int32            limite = PG_GETARG_INT32(1);
+    bool isNULL;
+    Datum salaire;
+
+    salaire = GetAttributeByName(t, "salaire", &isNULL);
+    if (isNULL)
+        PG_RETURN_BOOL(false);
+    /* Autrement, nous pourrions préférer de lancer PG_RETURN_NULL() pour un
+       salaire NULL.
+    */
+
+    PG_RETURN_BOOL(DatumGetInt32(salaire) > limite);
+}
+]]></programlisting>
+    </para>
+
+    <para>
+     <function>GetAttributeByName</function> est la fonction système
+     <productname>PostgreSQL</productname> qui renvoie les attributs depuis une
+     colonne spécifiée. Elle a trois arguments&nbsp;: l'argument de type
+     <type>HeapTupleHeader</type> passé à la fonction, le nom de l'attribut
+     recherché et un paramètre de retour qui indique si l'attribut est NULL.  
+     <function>GetAttributeByName</function> renvoie une valeur de type
+     <type>Datum</type> que vous pouvez convertir dans un type voulu en
+     utilisant la macro appropriée
+     <function>DatumGet<replaceable>XXX</replaceable>()</function>. Notez que
+     la valeur de retour est insignifiante si le commutateur NULL est
+     positionné&nbsp;; il faut toujours vérifier le commutateur NULL avant de commencer
+     à faire quelque chose avec le résultat.
+    </para> 
+    
+    <para>
+     Il y a aussi <function>GetAttributeByNum</function>, qui sélectionne
+     l'attribut cible par le numéro de colonne au lieu de son nom.
+    </para>
+    
+    <para> 
+     La commande suivante déclare la fonction <function>c_surpaye</function>
+     en SQL&nbsp;:
+
+<programlisting>CREATE FUNCTION c_surpaye(emp, integer) RETURNS boolean
+    AS '<replaceable>DIRECTORY</replaceable>/funcs', 'c_surpaye'
+    LANGUAGE C STRICT;
+</programlisting>
+
+     Notez que nous avons utilisé <literal>STRICT</literal> pour que nous n'ayons pas à
+     vérifier si les arguments en entrée sont NULL.
+    </para>
+   </sect2>
+
+   <sect2>
+    <title>Renvoi de lignes (types composites)</title>
+     
+    <para>
+     Pour renvoyer une ligne ou une valeur de type composite à partir d'une
+     fonction en langage C, vous pouvez utiliser une API spéciale qui fournit
+     les macros et les fonctions dissimulant en grande partie la complexité
+     liée à la construction de types de données composites. Pour utiliser cette
+     API, le fichier source doit inclure&nbsp;:
+ <programlisting>#include "funcapi.h"</programlisting>
+    </para>
+
+    <para>
+	 Il existe deux façons de construire une valeur de données composites 
+	 (autrement dit un <quote>tuple</quote>)&nbsp;: vous pouvez le construire à
+	 partir d'un tableau de valeurs Datum ou à partir d'un tableau de
+	 chaînes C qui peuvent passer dans les fonctions de conversion des types
+	 de données du tuple. Quelque soit le cas, vous avez d'abord besoin
+	 d'obtenir et de construire un descripteur <structname>TupleDesc</structname> pour
+	 la structure du tuple. En travaillant avec des Datums, vous passez le
+     <structname>TupleDesc</structname> à <function>BlessTupleDesc</function>, puis vous appelez
+     <function>heap_form_tuple</function> pour chaque ligne. En travaillant avec des
+     chaînes C, vous passez <structname>TupleDesc</structname> à
+     <function>TupleDescGetAttInMetadata</function>, puis vous appelez
+     <function>BuildTupleFromCStrings</function> pour chaque ligne. Dans le cas d'une
+     fonction renvoyant un ensemble de tuple, les étapes de configuration
+     peuvent toutes être entreprises une fois lors du premier appel à la
+     fonction.
+    </para>
+
+    <para>
+     Plusieurs fonctions d'aide sont disponibles pour configurer le
+     <structname>TupleDesc</structname> requis. La façon recommandée de le faire dans la 
+     plupart des fonctions renvoyant des valeurs composites est d'appeler&nbsp;:
+<programlisting>TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo,
+                                   Oid *resultTypeId,
+                                   TupleDesc *resultTupleDesc)
+</programlisting>
+     en passant la même structure <literal>fcinfo</literal> que celle passée à la
+     fonction appelante (ceci requiert bien sûr que vous utilisez les
+     conventions d'appel version-1). <varname>resultTypeId</varname> peut être
+     spécifié comme <literal>NULL</literal> ou comme l'adresse d'une variable locale
+     pour recevoir l'OID du type de résultat de la fonction.
+     <varname>resultTupleDesc</varname> devrait être l'adresse d'une variable
+     <structname>TupleDesc</structname> locale. Vérifiez que le résultat est
+     <literal>TYPEFUNC_COMPOSITE</literal>&nbsp;; dans ce cas,
+     <varname>resultTupleDesc</varname> a été rempli avec le
+     <structname>TupleDesc</structname> requis (si ce n'est pas le cas, vous pouvez
+     rapporter une erreur pour une <quote>fonction renvoyant un enregistrement
+     appelé dans un contexte qui ne peut pas accepter ce type
+     enregistrement</quote>).
+    </para>
+
+    <tip>
+     <para>
+      <function>get_call_result_type</function> peut résoudre le vrai type du
+      résultat d'une fonction polymorphique&nbsp;; donc, il est utile pour les
+      fonctions qui renvoient des résultats scalaires polymorphiques, pas
+      seulement les fonctions qui renvoient des types composites. Le résultat
+      <varname>resultTypeId</varname> est principalement utile pour les fonctions
+      renvoyant des scalaires polymorphiques.
+     </para>
+    </tip>
+
+    <note>
+     <para>
+      <function>get_call_result_type</function> a une fonction cousine
+      <function>get_expr_result_type</function>, qui peut être utilisée pour résoudre
+      le tupe attendu en sortie en un appel de fonction représenté par
+      un arbre d'expressions. Ceci peut être utilisé pour tenter de déterminer
+      le type de résultat sans entrer dans la fonction elle-même. Il existe
+      aussi <function>get_func_result_type</function>, qui peut seulement être utilisée
+      quand l'OID de la fonction est disponible. Néanmoins, ces fonctions ne
+      sont pas capables de gérer les fonctions déclarées renvoyer des
+      enregistrements (<structname>record</structname>).
+      <function>get_func_result_type</function> ne peut pas résoudre les types
+      polymorphiques, donc vous devriez utiliser de préférence
+      <function>get_call_result_type</function>.
+     </para>
+    </note>
+
+    <para>
+     Les fonctions anciennes, et maintenant obsolètes, qui permettent d'obtenir des
+     <structname>TupleDesc</structname> sont&nbsp;:
+<programlisting>TupleDesc RelationNameGetTupleDesc(const char *relname)
+</programlisting>
+    pour obtenir un <structname>TupleDesc</structname> pour le type de ligne d'une
+    relation nommée ou&nbsp;:
+<programlisting>TupleDesc TypeGetTupleDesc(Oid typeoid, List *colaliases)
+</programlisting>
+     pour obtenir une <structname>TupleDesc</structname> basée sur l'OID d'un type. Ceci
+     peut être utilisé pour obtenir un <structname>TupleDesc</structname> soit pour un
+     type de base, soit pour un type composite. Néanmoins, cela ne fonctionnera
+     pas pour une fonction qui renvoie <structname>record</structname> et cela ne résoudra
+     pas les types polymorphiques.
+    </para>
+
+    <para>
+	 Une fois que vous avez un <structname>TupleDesc</structname>, appelez&nbsp;:
+<programlisting>TupleDesc BlessTupleDesc(TupleDesc tupdesc)
+</programlisting>
+     si vous pensez travailler avec des Datums ou&nbsp;:
+<programlisting>AttInMetadata *TupleDescGetAttInMetadata(TupleDesc tupdesc)
+</programlisting>
+     si vous pensez travailler avec des chaînes C. Si vous écrivez une
+     fonction renvoyant un ensemble, vous pouvez sauvegarder les résultats
+     de ces fonctions dans la structure dans le
+     <structname>FuncCallContext</structname> &mdash; utilisez le champ
+     <structfield>tuple_desc</structfield> ou <structfield>attinmeta</structfield> respectivement.
+    </para>
+
+    <para>
+	 Lorsque vous fonctionnez avec des Datums, utilisez&nbsp;:
+<programlisting>HeapTuple heap_form_tuple(TupleDesc tupdesc, Datum *values, bool *isnull)
+</programlisting>
+	 pour construire une donnée utilisateur <structname>HeapTuple</structname> indiquée
+	 dans le format Datum.
+    </para>
+
+    <para>
+	 Lorsque vous travaillez avec des chaînes C, utilisez&nbsp;:
+<programlisting>HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
+</programlisting>
+	 pour construire une donnée utilisateur <structname>HeapTuple</structname> indiquée
+	 dans le format des chaînes C. <literal>values</literal> est un tableau de
+	 chaîne C, une pour chaque attribut de la ligne renvoyée. Chaque chaîne
+	 C doit être de la forme attendue par la fonction d'entrée du type de
+	 donnée de l'attribut. Afin de renvoyer une valeur NULL pour un des
+	 attributs, le pointeur correspondant dans le tableau de valeurs
+	 (<parameter>values</parameter>) doit être fixé à <symbol>NULL</symbol>. Cette fonction
+	 demandera à être appelée pour chaque ligne que vous renvoyez.
+    </para>
+
+    <para>
+     Une fois que vous avez construit un tuple devant être renvoyé par votre
+     fonction, vous devez le convertir en type <type>Datum</type>. Utilisez&nbsp;:
+<programlisting>HeapTupleGetDatum(HeapTuple tuple)
+</programlisting>
+     pour convertir un type <type>HeapTuple</type> en un Datum valide.
+     Ce <type>Datum</type> peut être renvoyé directement si vous envisagez de
+     renvoyer juste une simple ligne ou bien il peut être utilisé pour renvoyer
+     la valeur courante dans une fonction renvoyant un ensemble.
+  </para>
+
+    <para>
+     Un exemple figure dans la section suivante.
+    </para>
+
+   </sect2>
+
+   <sect2 id="xfunc-c-return-set">
+    <title>Renvoi d'ensembles</title>
+
+    <para>
+     Il existe aussi une API spéciale procurant le moyen de renvoyer des
+     ensembles (lignes multiples) depuis une fonction en langage C. Une fonction
+     renvoyant un ensemble doit suivre les conventions d'appel de la version-1. 
+     Aussi, les fichiers source doivent inclure l'en-tête
+     <filename>funcapi.h</filename>, comme ci-dessus.
+    </para>
+
+    <para>
+     Une fonction renvoyant un ensemble (<acronym>SRF</acronym> : <quote>set
+     returning function</quote>) est appelée une fois pour chaque élément
+     qu'elle renvoie. La <acronym>SRF</acronym> doit donc sauvegarder suffisamment
+     l'état pour se rappeler ce qu'elle était en train de faire et renvoyer le
+     prochain élément à chaque appel. La structure
+     <structname>FuncCallContext</structname> est offerte pour assister le contrôle de ce
+     processus. À l'intérieur d'une fonction,
+     <literal>fcinfo-&gt;flinfo-&gt;fn_extra</literal> est utilisée pour conserver un
+     pointeur vers <structname>FuncCallContext</structname> au cours des appels
+     successifs.
+
+<programlisting>typedef struct
+{
+    /*
+     * Number of times we've been called before
+     * 
+     * call_cntr is initialized to 0 for you by SRF_FIRSTCALL_INIT(), and
+     * incremented for you every time SRF_RETURN_NEXT() is called.
+     */
+    uint32 call_cntr;
+
+    /*
+     * OPTIONAL maximum number of calls
+     *
+     * max_calls is here for convenience only and setting it is optional.
+     * If not set, you must provide alternative means to know when the
+     * function is done.
+     */
+    uint32 max_calls;
+
+    /*
+     * OPTIONAL pointer to result slot
+     * 
+     * This is obsolete and only present for backwards compatibility, viz,
+     * user-defined SRFs that use the deprecated TupleDescGetSlot().
+     */
+    TupleTableSlot *slot;
+
+    /*
+     * OPTIONAL pointer to miscellaneous user-provided context information
+     * 
+     * user_fctx is for use as a pointer to your own data to retain
+     * arbitrary context information between calls of your function.
+     */
+    void *user_fctx;
+
+    /*
+     * OPTIONAL pointer to struct containing attribute type input metadata
+     * 
+     * attinmeta is for use when returning tuples (i.e., composite data types)
+     * and is not used when returning base data types. It is only needed
+     * if you intend to use BuildTupleFromCStrings() to create the return
+     * tuple.
+     */
+    AttInMetadata *attinmeta;
+
+    /*
+     * memory context used for structures that must live for multiple calls
+     *
+     * multi_call_memory_ctx is set by SRF_FIRSTCALL_INIT() for you, and used
+     * by SRF_RETURN_DONE() for cleanup. It is the most appropriate memory
+     * context for any memory that is to be reused across multiple calls
+     * of the SRF.
+     */
+    MemoryContext multi_call_memory_ctx;
+    
+    /*
+    * OPTIONAL pointer to struct containing tuple description
+    *
+    * tuple_desc is for use when returning tuples (i.e. composite data types)
+    * and is only needed if you are going to build the tuples with
+    * heap_form_tuple() rather than with BuildTupleFromCStrings().  Note that
+    * the TupleDesc pointer stored here should usually have been run through
+    * BlessTupleDesc() first.
+    */
+    TupleDesc tuple_desc;
+    
+} FuncCallContext;
+</programlisting>
+    </para>
+
+    <para>
+     Une <acronym>SRF</acronym> utilise plusieurs fonctions et macros qui manipulent
+     automatiquement la structure <structname>FuncCallContext</structname> (et s'attendent
+     à la trouver via <literal>fn_extra</literal>). Utilisez&nbsp;:
+<programlisting>SRF_IS_FIRSTCALL()
+</programlisting>
+     pour déterminer si votre fonction est appelée pour la première fois. Au
+     premier appel, utilisez&nbsp;:
+<programlisting>SRF_FIRSTCALL_INIT()
+</programlisting>
+     pour initialiser la structure <structname>FuncCallContext</structname>. À chaque
+     appel de fonction, y compris le premier, utilisez&nbsp;:
+<programlisting>SRF_PERCALL_SETUP()
+</programlisting>
+     pour une mise à jour correcte en vue de l'utilisation de
+     <structname>FuncCallContext</structname> et pour nettoyer toutes les données
+     renvoyées précédemment et conservées depuis le dernier passage de la
+     fonction.
+    </para>
+
+    <para>
+     Si votre fonction a des données à renvoyer, utilisez&nbsp;:
+<programlisting>SRF_RETURN_NEXT(funcctx, result)
+</programlisting>
+     pour les renvoyer à l'appelant. (<literal>result</literal> doit être de type
+     <type>Datum</type>, soit une valeur simple, soit un tuple préparé comme décrit
+     ci-dessus.) Enfin, quand votre fonction a fini de renvoyer des données,
+     utilisez&nbsp;:
+<programlisting>SRF_RETURN_DONE(funcctx)
+</programlisting>
+     pour nettoyer et terminer la <acronym>SRF</acronym>.
+    </para>
+
+    <para>
+     Lors de l'appel de la <acronym>SRF</acronym>, le contexte mémoire courant est un
+     contexte transitoire qui est effacé entre les appels. Cela signifie que
+     vous n'avez pas besoin d'appeler <function>pfree</function> sur tout ce que vous
+     avez alloué en utilisant <function>palloc</function>&nbsp;; ce sera supprimé de
+     toute façon. Toutefois, si vous voulez allouer des structures de données
+     devant persister tout au long des appels, vous avez besoin de les conserver
+     quelque part. Le contexte mémoire référencé par
+     <structfield>multi_call_memory_ctx</structfield> est un endroit approprié pour toute
+     donnée devant survivre jusqu'à l'achèvement de la fonction <acronym>SRF</acronym>.
+     Dans la plupart des cas, cela signifie que vous devrez basculer vers
+     <structfield>multi_call_memory_ctx</structfield> au moment de la préparation du
+     premier appel.
+ </para>  
+   <para>
+     Voici un exemple complet de pseudo-code&nbsp;:
+<programlisting>Datum
+my_set_returning_function(PG_FUNCTION_ARGS)
+{
+    FuncCallContext  *funcctx;
+    Datum             result;
+    MemoryContext     oldcontext;
+    <replaceable>further declarations as needed</replaceable>
+
+    if (SRF_IS_FIRSTCALL())
+    {
+        funcctx = SRF_FIRSTCALL_INIT();
+        oldcontext = MemoryContextSwitchTo(funcctx-&gt;multi_call_memory_ctx);
+        /* One-time setup code appears here: */
+        <replaceable>user code</replaceable>
+        <replaceable>if returning composite</replaceable>
+            <replaceable>build TupleDesc, and perhaps AttInMetadata</replaceable>
+        <replaceable>endif returning composite</replaceable>
+        <replaceable>user code</replaceable>
+        MemoryContextSwitchTo(oldcontext);
+    }
+
+    /* Each-time setup code appears here: */
+    <replaceable>user code</replaceable>
+    funcctx = SRF_PERCALL_SETUP();
+    <replaceable>user code</replaceable>
+
+    /* this is just one way we might test whether we are done: */
+    if (funcctx-&gt;call_cntr &lt; funcctx-&gt;max_calls)
+    {
+        /* Here we want to return another item: */
+        <replaceable>user code</replaceable>
+        <replaceable>obtain result Datum</replaceable>
+        SRF_RETURN_NEXT(funcctx, result);
+    }
+    else
+    {
+        /* Here we are done returning items and just need to clean up: */
+        <replaceable>user code</replaceable>
+        SRF_RETURN_DONE(funcctx);
+    }
+}
+</programlisting>
+    </para>
+
+    <para>
+     Et voici un exemple complet d'une simple <acronym>SRF</acronym> retournant un
+     type composite&nbsp;:
+     <programlisting><![CDATA[PG_FUNCTION_INFO_V1(retcomposite);
+
+Datum
+retcomposite(PG_FUNCTION_ARGS)
+{
+    FuncCallContext     *funcctx;
+    int                  call_cntr;
+    int                  max_calls;
+    TupleDesc            tupdesc;
+    AttInMetadata       *attinmeta;
+
+     /* stuff done only on the first call of the function */
+     if (SRF_IS_FIRSTCALL())
+     {
+        MemoryContext	oldcontext;
+
+        /* create a function context for cross-call persistence */
+        funcctx = SRF_FIRSTCALL_INIT();
+
+        /* switch to memory context appropriate for multiple function calls */
+        oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
+
+        /* total number of tuples to be returned */
+        funcctx->max_calls = PG_GETARG_UINT32(0);
+
+        /* Build a tuple descriptor for our result type */
+        if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+            ereport(ERROR,
+                    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                     errmsg("function returning record called in context "
+                            "that cannot accept type record")));
+
+        /*
+         * generate attribute metadata needed later to produce tuples from raw
+         * C strings
+         */
+        attinmeta = TupleDescGetAttInMetadata(tupdesc);
+        funcctx->attinmeta = attinmeta;
+
+        MemoryContextSwitchTo(oldcontext);
+    }
+
+    /* stuff done on every call of the function */
+    funcctx = SRF_PERCALL_SETUP();
+
+    call_cntr = funcctx->call_cntr;
+    max_calls = funcctx->max_calls;
+    attinmeta = funcctx->attinmeta;
+ 
+    if (call_cntr < max_calls)    /* do when there is more left to send */
+    {
+        char       **values;
+        HeapTuple    tuple;
+        Datum        result;
+
+        /*
+	* Prepare a values array for building the returned tuple.
+         * This should be an array of C strings which will
+         * be processed later by the type input functions.
+         */
+        values = (char **) palloc(3 * sizeof(char *));
+        values[0] = (char *) palloc(16 * sizeof(char));
+        values[1] = (char *) palloc(16 * sizeof(char));
+        values[2] = (char *) palloc(16 * sizeof(char));
+
+        snprintf(values[0], 16, "%d", 1 * PG_GETARG_INT32(1));
+        snprintf(values[1], 16, "%d", 2 * PG_GETARG_INT32(1));
+        snprintf(values[2], 16, "%d", 3 * PG_GETARG_INT32(1));
+
+        /* build a tuple */
+        tuple = BuildTupleFromCStrings(attinmeta, values);
+
+        /* make the tuple into a datum */
+        result = HeapTupleGetDatum(tuple);
+
+        /* clean up (this is not really necessary) */
+        pfree(values[0]);
+        pfree(values[1]);
+        pfree(values[2]);
+        pfree(values);
+
+        SRF_RETURN_NEXT(funcctx, result);
+    }
+    else    /* do when there is no more left */
+    {
+        SRF_RETURN_DONE(funcctx);
+    }
+}
+]]></programlisting>
+
+     Voici une façon de déclarer cette fonction en SQL&nbsp;:
+     
+<programlisting>CREATE TYPE __retcomposite AS (f1 integer, f2 integer, f3 integer);
+
+CREATE OR REPLACE FUNCTION retcomposite(integer, integer)
+    RETURNS SETOF __retcomposite
+    AS '<replaceable>filename</replaceable>', 'retcomposite'
+    LANGUAGE C IMMUTABLE STRICT;
+</programlisting>
+     Une façon différente de le faire est d'utiliser des paramètres OUT&nbsp;:
+<programlisting>CREATE OR REPLACE FUNCTION retcomposite(IN integer, IN integer,
+    OUT f1 integer, OUT f2 integer, OUT f3 integer)
+    RETURNS SETOF record
+    AS '<replaceable>filename</replaceable>', 'retcomposite'
+    LANGUAGE C IMMUTABLE STRICT;
+</programlisting>
+     Notez que dans cette méthode le type en sortie de la fonction est du type
+     <structname>record</structname> anonyme.
+    </para>
+
+    <para>
+     Le répertoire <filename>contrib/tablefunc</filename> situé dans les fichiers source
+     de la distribution contient d'autres exemples de fonctions renvoyant des
+     ensembles.</para>
+   </sect2>
+
+   <sect2>
+    <title>Arguments polymorphes et types renvoyés</title>
+
+    <para>
+     Les fonctions en langage C peuvent être déclarées pour accepter et renvoyer
+     les types <quote>polymorphes</quote> <type>anyelement</type>,
+	 <type>anyarray</type>, <type>anynonarray</type> et <type>anyenum</type>. Voir la <xref linkend="extend-types-polymorphic"/> pour une
+     explication plus détaillée des fonctions polymorphes. Si les types des
+     arguments ou du renvoi de la fonction sont définis comme polymorphes,
+     l'auteur de la fonction ne peut pas savoir à l'avance quel type de données
+     sera appelé ou bien quel type doit être renvoyé. Il y a deux routines
+     offertes par <filename>fmgr.h</filename>  qui permettent à une fonction en
+     version-1 de découvrir les types de données effectifs de ses arguments et
+     le type qu'elle doit renvoyer. Ces routines s'appellent 
+     <literal>get_fn_expr_rettype(FmgrInfo *flinfo)</literal> et 
+     <literal>get_fn_expr_argtype(FmgrInfo *flinfo, int argnum)</literal>. Elles
+     renvoient l'OID du type du résultat ou de l'argument ou InvalidOID si
+     l'information n'est pas disponible. L'accès à la structure
+     <literal>flinfo</literal> se fait normalement avec
+     <literal>fcinfo-&gt;flinfo</literal>. Le paramètre <literal>argnum</literal> est basé à
+     partir de zéro. <function>get_call_result_type</function> peut aussi être utilisé
+     comme alternative à <function>get_fn_expr_rettype</function>.
+    </para>
+    
+    <para>
+     Par exemple, supposons que nous voulions écrire une fonction qui accepte un
+     argument de n'importe quel type et qui renvoie un tableau uni-dimensionnel
+     de ce type&nbsp;:
+
+<programlisting>PG_FUNCTION_INFO_V1(make_array);
+Datum
+make_array(PG_FUNCTION_ARGS)
+{
+    ArrayType  *result;
+    Oid         element_type = get_fn_expr_argtype(fcinfo-&gt;flinfo, 0);
+    Datum       element;
+    bool        isnull;
+    int16       typlen;
+    bool        typbyval;
+    char        typalign;
+    int         ndims;
+    int         dims[MAXDIM];
+    int         lbs[MAXDIM];
+
+    if (!OidIsValid(element_type))
+        elog(ERROR, "could not determine data type of input");
+
+    /* get the provided element, being careful in case it's NULL */
+    isnull = PG_ARGISNULL(0);
+    if (isnull)
+        element = (Datum) 0;
+    else
+        element = PG_GETARG_DATUM(0);
+
+    /* we have one dimension */
+    ndims = 1;
+    /* and one element */
+    dims[0] = 1;
+    /* and lower bound is 1 */
+    lbs[0] = 1;
+
+    /* get required info about the element type */
+    get_typlenbyvalalign(element_type, &amp;typlen, &amp;typbyval,
+&amp;typalign);
+
+    /* now build the array */
+    result = construct_md_array(&amp;element, &amp;isnull, ndims, dims, lbs,
+                                element_type, typlen, typbyval, typalign);
+
+    PG_RETURN_ARRAYTYPE_P(result);
+}
+</programlisting>
+    </para>
+
+    <para>
+     La commande suivante déclare la fonction <function>make_array</function> en
+     SQL&nbsp;:
+
+<programlisting>CREATE FUNCTION make_array(anyelement) 
+    RETURNS anyarray
+    AS '<replaceable>DIRECTORY</replaceable>/funcs', 'make_array'
+    LANGUAGE 'C' IMMUTABLE;
+</programlisting>
+
+     Notez l'utilisation de STRICT&nbsp;; ceci est primordial car le code ne se
+     préoccupe pas de tester une entrée NULL.
+    </para>
+
+    <para>
+     Il existe une variante du polymorphisme qui est seulement disponible pour
+     les fonctions en langage C&nbsp;: elles peuvent être déclarées prendre des
+     paramètres de type <literal>"any"</literal>. (Notez que ce nom de type doit
+     être placé entre des guillemets doubles car il s'agit d'un mot SQL réservé.)
+     Ceci fonctionne comme <type>anyelement</type> sauf qu'il ne contraint pas
+     les différents arguments <literal>"any"</literal> à être du même type, pas
+     plus qu'ils n'aident à déterminer le type de résultat de la fonction. Une
+     fonction en langage C peut aussi déclarer son paramètre final ainsi&nbsp;:
+     <literal>VARIADIC "any"</literal>.  Cela correspondra à un ou plusieurs
+     arguments réels de tout type (pas nécessairement le même type). Ces
+     arguments ne seront <emphasis>pas</emphasis> placés dans un tableau
+     comme c'est le cas pour les fonctions variadic normales&nbsp;; ils seront
+     passés séparément à la fonction. La macro <function>PG_NARGS()</function>
+     et les méthodes décrites ci-dessus doivent être utilisées pour déterminer
+     le nombre d'arguments réels et leur type lors de l'utilisation de cette
+     fonctionnalité.
+    </para>
+   </sect2>
+
+   <sect2>
+    <title>Mémoire partagée et LWLocks</title>
+
+    <para>
+     Les modules peuvent réserver des LWLocks et allouer de la mémoire partagée
+     au lancement du serveur. La bibliothèque partagée du module doit être
+     préchargée en l'ajoutant <xref
+     linkend="guc-shared-preload-libraries"/><indexterm><primary>shared-preload-libraries</primary></indexterm>.
+     La mémoire partagée est réservée en appelant&nbsp;:
+<programlisting>void RequestAddinShmemSpace(int size)
+</programlisting>
+     à partir de votre fonction <function>_PG_init</function>.
+    </para>
+    <para>
+     Les LWLocks sont réservés en appelant&nbsp;:
+<programlisting>
+void RequestAddinLWLocks(int n)
+</programlisting>
+     à partir de <function>_PG_init</function>.
+    </para>	
+    <para>
+     Pour éviter des cas rares possibles, chaque moteur devrait utiliser la
+     fonction <function>AddinShmemInitLock</function> lors de la connexion et
+     de l'initialisation de la mémoire partagée, comme indiquée ci-dessous&nbsp;:
+<programlisting>
+        static mystruct *ptr = NULL;
+
+        if (!ptr)
+        {
+                bool    found;
+
+                LWLockAcquire(AddinShmemInitLock, LW_EXCLUSIVE);
+                ptr = ShmemInitStruct("my struct name", size, &amp;found);
+                if (!ptr)
+                        elog(ERROR, "out of shared memory");
+                if (!found)
+                {
+                        initialize contents of shmem area;
+                        acquire any requested LWLocks using:
+                        ptr->mylockid = LWLockAssign();
+                }
+                LWLockRelease(AddinShmemInitLock);
+        }
+</programlisting>
+    </para>
+   </sect2>
+
+  </sect1>



Plus d'informations sur la liste de diffusion Trad