Table des matières
      Ce chapitre décrit un grand nombre de notions que vous devez
      connaître lorsque vous travaillez sur le code de MySQL. Si vous
      envisagez de contribuer au développement de MySQL, que vous
      voulez accéder à du code ultra récent, ou que vous souhaitez
      simplement vous tenir au courant du développement, suivez les
      instructions de la section
      Section 2.4.3, « Installer à partir de l'arbre source de développement ». Si vous êtes
      intéressés par les rouages internes de MySQL, il est recommandé
      de vous inscrire à notre liste de diffusion interne
      internals. Cette liste est relativement calme.
      Pour les détails d'inscription, voyez
      Section 1.4.1.1, « Les listes de diffusion de MySQL ». Tous les développeurs de MySQL AB
      sont sur la liste internals et nous aidons ceux
      qui travaillent sur le code de MySQL. Utilisez cette liste pour
      poser des questions sur le code, et partagez les correctifs que
      vous voulez voir intégré au projet MySQL.
    
Le serveur MySQL crée les threads suivants :
Le thread de connexion TCP/IP, qui gère toutes les demandes de connexion, et crée un nouveau thread dédié pour gérer l'identification et le traitement des requêtes SQL, pour chaque connexion.
Sur Windows NT, il y a un thread appelé gestionnaire de pipe, qui effectue le même travail que le thread de gestion des demandes de connexion, sur les demandes de connexion par pipe.
            Le threads de signal gère tous les signaux. Ce thread gère
            aussi normalement les alertes et les appels à
            process_alarm() pour forcer les délais
            d'expiration des connexions qui sont inactives.
          
            Si mysqld est compilé avec l'option
            -DUSE_ALARM_THREAD, un thread dédié aux
            alarmes est créé. Il est uniquement utilisé sur certains
            systèmes où il y a des problèmes avec la fonction
            sigwait() ou si vous voulez utiliser la
            fonction thr_alarm() dans des
            applications qui n'ont pas de thread dédié aux signaux.
          
            Lors de l'utilisation de l'option
            --flush_time=#, un thread dédié est
            créé pour vider les tables de la mémoire à intervalle
            régulier.
          
Chaque connexion a son propre thread dédié.
            Chaque table différente sur laquelle des INSERT
            DELAYED sont pratiquées re¸oit un thread.
          
            Si vous utilisez l'option --master-host, un
            thread de réplication sera démarré pour lire et appliquer
            les modifications du maître.
          
        mysqladmin processlist affiche uniquement les
        threads de connexion, ceux de INSERT DELAYED
        et ceux de réplication.
      
        Jusqu'à récemment, notre suite de test principale étaient
        basée sur des données propriétaires de client, et pour cette
        raison, il n'a jamais été publié. Le seul système de test
        public actuel est notre script crash-me, qui
        est un script Perl DBI/DBD qui se trouve dans
        le dossier sql-bench, et divers tests qui
        font parti du dossier tests. Le manque d'une
        suite de test publique et standardisée rend difficile à nos
        utilisateurs et nos développeurs les possibilités de tests de
        régressions. Pour corriger ce problème, nous avons créé un
        nouveau système de tests qui est inclus dans les distributions
        source et binaires, à partir de la version 3.23.29.
      
Le jeu de test actuel ne couvre pas toutes les situations en MySQL, mais il permet d'identifier les bogues les plus courants lors de requêtes SQL, les problèmes de bibliothèques et aussi les problèmes de réplication. Notre but final est de lui faire couvrir 100% du code. Nous apprécions les contributions à notre suite de test. Vous pouvez notamment fournir des test qui examine certaines fonctions critiques de votre système, et qui assureront que les futures versions de MySQL le prennent en compte.
          Le système de tests est constitué d'un interpréteur de
          langage de tests (mysqltest), un script
          Shell qui exécute tous les scripts
          (mysql-test-run), les cas de tests réels,
          écrits dans un langage spécial de tests, et leur résultats
          attendus. Pour exécuter ces tests sur votre système après
          une compilation, tapez make test ou
          mysql-test/mysql-test-run depuis la racine
          de la distribution. Si vous avez installé une distribution
          binaire, cd jusqu'au dossier d'installation
          (par exemple, /usr/local/mysql), et
          exécutez scripts/mysql-test-run. Tous les
          tests doivent réussir. Si ce n'est pas le cas, vous devriez
          essayer de trouver pourquoi, et faire un rapport de bogues à
          MySQL. See Section 27.1.2.3, « Rapporter des bugs dans la suite de tests MySQL ».
        
          Si vous avez une copie de mysqld qui
          fonctionne sur la machine où vous voulez faire des tests,
          vous n'avez pas à l'arrêter, tant qu'elle n'utilise pas les
          ports 9306 et 9307. Si
          l'un de ces ports est pris, vous devriez éditer le script
          mysql-test-run et changer les valeurs des
          ports des maîtres et esclaves, en les rempla¸ant par des
          ports libres.
        
          Vous pouvez exécuter des tests individuels avec
          mysql-test/mysql-test-run test_name.
        
          Si l'un des tests échoue, vous devriez tester
          mysql-test-run avec l'option
          --force pour vérifier si aucun autre test
          n'échoue.
        
          Vous pouvez utiliser le langage de
          mysqltest pour écrire vos propres cas de
          tests. Malheureusement, nous n'avons pas encore écrit une
          documentation complète pour ce logiciel, et nous prévoyons
          de le faire rapidement. Vous pouvez, toutefois, utiliser les
          cas de tests actuels comme exemples. Les points suivants
          devraient vous mettre le pied à l'étrier.
        
              Les tests sont situé dans
              mysql-test/t/*.test
            
              Un cas de tests est constitué de commandes terminées par
              un ;, et est similaire aux données
              d'entrées du client mysql. Une
              commande est par défaut une commande envoyée au serveur
              MySQL, à moins qu'il ne soit reconnu comme une commande
              interne (par exemple, sleep).
            
              Toutes les requêtes qui produisent des résultats, comme
              SELECT, SHOW,
              EXPLAIN, etc., doivent être
              précédées par @/path/to/result/file.
              Le fichier contient alors les résultats attendus. Un
              moyen simple pour générer le résultat du fichier est
              d'exécuter mysqltest -r <
              t/test-case-name.test depuis le dossier de tests
              mysql-test, puis d'éditer le fichier
              résultant, si nécessaire, pour ajuster le contenu. Dans
              ce cas, soyez très prudent lors de l'ajout ou la
              suppression de caractères invisibles : assurez vous de
              ne changer que du texte, ou d'effacer des lignes. Vous
              pouvez utiliser od -c pour vous assurer
              que votre éditeur n'a pas perturbé le fichier durant
              l'édition. Bien sur, nous espérons que vous n'aurez
              jamais a éditer le résultat du fichier
              mysqltest -r ca vous n'avez à faire
              cela que lorsque vous découvrez un bug.
            
              Pour être cohérent avec votre configuration, vous
              devriez placer les fichiers de résultats dans le dossier
              mysql-test/r et les nommer
              test_name.result. Si le test produit
              plus qu'un résultat, vous devez utiliser
              test_name.a.result,
              test_name.b.result, etc.
            
              Si une commande retourne une erreur, vous devez, sur la
              ligne de la commande, le spécifier avec --error
              error-number. Le numéro d'erreur peut être une
              liste d'erreurs possibles, séparées par des virgules
              ','.
            
              Si vous écrivez un test de réplication, vous devez, sur
              la première ligne du fichier de test, ajouter le code
              source include/master-slave.inc;. Pour
              passer entre le maître et l'esclave, utilisez
              connection master; et
              connection slave;. Si vous avez besoin
              d'utiliser une connexion alternative, vous pouvez utiliser
              connection master1; pour le maître, et
              connection slave1; pour l'esclave.
            
Si vous avez besoin d'une boucle, vous pouvez utiliser ceci :
let $1=1000;
while ($1)
{
 # votre requête ici
 dec $1;
}
              Pour faire une pause entre les requêtes, utilisez la
              commande sleep. Elle supporte les
              fraction de secondes, ce qui vous permet d'utiliser
              sleep 1.3;, pour attendre 1,3 secondes.
            
              Pour exécuter l'esclave avec des options additionnelles
              pour votre cas de tests, ajoutez les au format ligne de
              commande dans
              mysql-test/t/test_name-slave.opt. Pour
              le maître, ajoutez les dans
              mysql-test/t/test_name-master.opt.
            
Si vous avez une question sur la suite de tests, ou que vous avez un test à proposer, envoyez le par email à sur la liste interne. See Section 1.4.1.1, « Les listes de diffusion de MySQL ». Comme la liste n'accepte pas les attachements, vous devriez les placer sur le serveur FTP : ftp://support.mysql.com/pub/mysql/Incoming/
Si votre version de MySQL ne passe pas un teste, vous devez faire ceci :
              N'envoyez pas de rapport de bug avant d'avoir étudier au
              maximum les raisons possibles de l'échec! Lorsque vous le
              faîtes, utilisez le programme
              mysqlbug, pour que nous puissions
              obtenir un maximum d'informations sur votre système et la
              version de MySQL. See Section 1.4.1.3, « Comment rapporter un bogue ou un problème ».
            
              Assurez vous d'inclure le résultat de
              mysql-test-run, ainsi que le contenu de
              tous les fichiers .reject du dossier
              mysql-test/r.
            
Si un test de la suite échoue, vérifiez si le test échoue aussi en l'exécutant seul :
cd mysql-test mysql-test-run --local test-name
              Si cela échoue, alors vous devriez configurer MySQL avec
              --with-debug et exécuter
              mysql-test-run avec l'option
              --debug. Si cela échoue aussi, envoyez
              le fichier de trace
              var/tmp/master.trace à
              ftp://support.mysql.com/pub/mysql/secret pour que nous
              puissions l'examiner. N'oubliez pas d'inclure une
              description complète de votre système, ainsi que de la
              version de l'exécutable mysqld, et de
              sa compilation.
            
              Essayez d'exécuter mysql-test-run avec
              l'option --force pour voir si il n'y a
              pas d'autres tests qui échouent.
            
Si vous avez compilé MySQL vous-même, vérifiez notre manuel, ainsi que les notes de compilations pour votre plate-forme, ou bien, utilisez à la place un des exécutables que nous avons compilé pour vous, disponibles à http://www.mysql.com/downloads/. Toutes nos versions exécutables doivent passer la suite de tests.
              Si vous obtenez une erreur, comme Result length
              mismatch ou Result content
              mismatch, cela signifie que le résultat de la
              suite de tests n'a pas la taille attendue. Cela peut être
              un bug de MySQL, ou que votre version de MySQL fournit un
              résultat d'une autre taille, dans certaines
              circonstances.
            
              Les résultats de tests qui ont échoués sont placés
              dans un fichier avec le même nom de base que le fichier
              de test, et avec l'extension .reject.
              Si votre test échoue, faites un diff
              sur les deux fichiers. Si vous ne pouvez pas voir où ils
              diffèrent, examinez ces deux fichiers avec od
              -c, et vérifiez leur tailles respectives.
            
              Si un test échoue totalement, vous devriez vérifier les
              fichiers de log dans le dossier
              mysql-test/var/log, pour avoir des
              indices sur ce qui a échoué.
            
              Si vous avez compilé MySQL avec le débogage, vous pouvez
              essayer de le déboger en exécutant
              mysql-test-run avec
              --gdb et/ou --debug. See
              Section D.1.2, « Créer un fichier de tra¸age ».
            
              Si vous n'avez pas compilé MySQL pour le débogage, vous
              devriez essayer de le faire. Spécifiez simplement
              l'option --with-debug dans le script de
              configure! See
              Section 2.4, « Installation de MySQL avec une distribution source ».
            
Il y a deux méthodes pour ajouter des fonctions à MySQL :
          Vous pouvez ajouter la fonction grâce à l'interface de
          fonctions utilisateur (UDF). Les fonctions
          utilisateur sont ajoutées et supprimées dynamiquement avec
          les commandes CREATE FUNCTION et
          DROP FUNCTION. See
          Section 27.2.2, « Syntaxe de CREATE FUNCTION/DROP FUNCTION ».
        
          Vous pouvez ajouter une fonction sous la forme native
          (intégrée) d'une fonction MySQL. Les fonctions natives sont
          compilées dans mysqld et sont disponibles
          en permanence.
        
Chaque méthode a ses avantages et inconvénients :
Si vous écrivez une fonction utilisateur, vous devez installer le fichier objet en plus du serveur lui-même. Si vous compilez votre fonction dans le serveur, vous n'avez pas ce problème.
          Vous pouvez ajouter des UDF à une
          distribution binaire de MySQL. Les fonctions natives
          requièrent une modification de la distribution source.
        
Si vous mettez à jour votre distribution MySQL, vous pouvez continuer à utiliser vos fonctions précédemment installées. Pour les fonctions natives, vous devez refaire les modifications du code à chaque mise à jour.
      Quelque soit la méthode que vous utilisez pour ajouter de
      nouvelles fonctions, ces fonctions pourront être utilisées comme
      des fonctions natives telles que ABS() ou
      SOUNDEX().
    
L'interface MySQL pour créer des fonctions utilisateurs fournit les fonctionnalités et capacités suivantes :
Les fonctions peuvent retourner des chaînes, des entiers ou des nombre décimaux.
Vous pouvez définir des fonctions simples qui travaillent sur une ligne à la fois, ou bien des fonctions d'agrégation, qui travaillent sur plusieurs lignes à la fois.
Des informations fournies aux fonctions pour qu'elles puissent vérifier le nombre et le type des arguments qui leur sont passé.
Vous pouvez demander à MySQL de forcer certains arguments à certains types avant de les transmettre à votre fonction.
            Vous pouvez indiquer qu'une fonction retourne
            NULL ou qu'une erreur est survenue.
          
CREATE [AGGREGATE] FUNCTION nom_fonction RETURNS {STRING|REAL|INTEGER}
       SONAME nom_librairie_partagée
DROP FUNCTION nom_fonction
        Une fonction définie par un utilisateur
        (UDF) est une méthode pour intégrer une
        fonction qui fonctionne de la même fa¸on qu'une fonction
        native de MySQL, comme ABS() et
        CONCAT().
      
        AGGREGATE est une nouvelle option pour MySQL
        version 3.23. Une fonction AGGREGATE
        fonctionne exactement comme une fonction native comme
        SUM ou COUNT().
      
        CREATE FUNCTION enregistre le nom de la
        fonction, le type, et le nom des bibliothèques partagées dans
        la table mysql.func. Vous devez avoir les
        droits INSERT et DELETE
        dans la base mysql pour créer et supprimer
        les fonctions.
      
        Toutes les fonctions actives sont rechargées chaque fois que le
        serveur démarre, sauf si vous démarrez
        mysqld avec l'option
        --skip-grant-tables. Dans ce cas, l'utilisation
        des UDF n'est pas prise en compte et les UDFs
        ne sont pas disponibles. (Une fonction active est une fonction
        qui peut être chargée avec CREATE FUNCTION
        et supprimée par REMOVE FUNCTION).
      
        Concernant l'écriture des UDFs,
        Section 27.2, « Ajouter des fonctions à MySQL ». Pour que le mécanisme des
        fonctions UDF fonctionne, les fonctions
        doivent être écrites en C ou C++, votre système doit
        supporter le chargement dynamique et vous devez avoir compilé
        mysqld dynamiquement (pas statiquement).
      
        Notez que pour faire fonctionner AGGREGATE,
        vous devez avoir une table mysql.func qui
        contient la colonne type. Si ce n'est pas le
        cas, vous devez exécuter le script
        mysql_fix_privilege_table pour résoudre ce
        problème.
      
        Pour que le mécanisme UDF fonctionne, les
        fonctions doivent êtres écrites en C ou C++ et votre système
        doit supporter le chargement dynamique. Les sources de MySQL
        incluent un fichier sql/udf_example.cc qui
        définit 5 nouvelles fonctions. Consultez ce fichier pour voir
        comment marchent les conventions d'appels des
        UDF.
      
        Pour que mysqld puisse utiliser les fonctions
        UDF, vous devez configurer MySQL avec
        l'option --with-mysqld-ldflags=-rdynamic. La
        raison est que sur diverses plates-formes, (Linux inclus) vous
        pouvez charger une bibliothèque dynamique (avec
        dlopen()) depuis un programme statique lié,
        que vous pouvez obtenir si vous utilisez l'option
        --with-mysql-ldflags=-all-static. Si vous
        voulez utiliser une UDF qui nécessite un
        accès aux symboles de mysqld (comme
        l'exemple methaphone dans
        sql/udf_example.cc qui utilise
        default_charset_info), vous devez lier le
        programme avec -rdynamic (voir man
        dlopen).
      
        Pour chaque fonction que vous voulez utiliser dans SQL, vous
        devez définir les fonctions correspondantes en C (ou C++). Dans
        la discussion ci-dessous, le nom ``xxx'' est
        utilisé comme un exemple de nom de fonction. Pour faire la
        différence entre l'usage de SQL et de C/C++,
        XXX() (majuscules) indique l'appel d'une
        fonction SQL et xxx() (minuscules) indique
        l'appel d'une fonction C/C++.
      
        Les fonctions C/C++ que vous écrivez pour l'implémentation de
        l'interface de XXX() sont :
      
            xxx() (requis)
          
La fonction principale. C'est là où le résultat de la fonction est calculé. La correspondance entre le type de SQL et le type retourné par votre fonction C/C++ est affiché ci-dessous :
| SQL type | C/C++ type | 
STRING | char * | 
INTEGER | long long | 
REAL | double | 
            xxx_init() (optionnel)
          
            La fonction d'initialisation de xxx().
            Elle peut-être utilisée pour :
          
                Vérifier le nombre d'arguments de
                XXX().
              
Vérifier que les arguments correspondent aux types requis ou indiquer à MySQL de contraindre des arguments aux types que vous voulez quand la fonction principale est appelée.
Allouer la mémoire requise pour la fonction principale.
Spécifier la longueur maximale de la sortie.
                Spécifier (pour les fonctions REAL)
                le nombre maximal de décimales.
              
                Spécifier si le résultat peut-être
                NULL.
              
            xxx_deinit() (optionnel)
          
            La terminaison de la fonction xxx(). Elle
            doit libérer toute la mémoire allouée par
            l'initialisation de la fonction.
          
        Quand une requête SQL fait appel à XXX(),
        MySQL appelle l'initialisation de la fonction
        xxx_init(), pour laisser exécuter n'importe
        quelle action exigée, telle que la vérification d'arguments ou
        l'allocation de mémoire.
      
        Si xxx_init() retourne une erreur, la
        requête SQL est annulée avec un message d'erreur et la
        fonction principale et la fonction de terminaison ne sont pas
        appelées. Autrement, la fonction principale
        xxx() est appelée une fois pour chaque
        ligne. Après que toutes les lignes aient été traitées, la
        fonction de terminaison xxx_deinit() est
        appelée pour procéder aux nettoyages requis.
      
        Pour les fonctions d'agrégat (comme SUM()),
        vous pouvez également ajouter les fonctions suivantes :
      
            xxx_reset() (requise)
          
Remet la somme à zéro et insère l'argument en tant que valeur initiale pour un nouveau groupe.
            xxx_add() (requise)
          
Ajoute l'argument à l'ancienne somme.
        Quand vous utilisez les UDF d'agrégat, MySQL
        opère comme suit :
      
        Toutes les fonctions doivent être compatibles avec les threads
        (et non pas simplement la fonction principale, mais aussi les
        fonctions d'initialisation et de terminaison). Cela signifie que
        vous ne pouvez pas allouer de variables globales ou statiques.
        Si vous avez besoin de mémoire, allouez-la avec la fonction
        xxx_init() et libérez la avec
        xxx_deinit().
      
            Appeler xxx_init() pour laisser la
            fonction d'agrégat allouer la mémoire dont elle aura
            besoin pour stocker les résultats.
          
            Trier la table en accord avec la clause GROUP
            BY.
          
            Pour la première ligne dans un nouveau groupe, appeler la
            fonction xxx_reset().
          
            Pour chaque ligne appartenant à un même groupe, appeler la
            fonction xxx_add().
          
            Quand le groupe change ou lorsque la dernière ligne a été
            traitée, appeler xxx() pour obtenir le
            résultat de l'agrégat.
          
Répéter les étapes de 3 à 5 tant que toutes les lignes n'ont pas été traitées.
            Appeler xxx_deinit() pour libérer la
            mémoire allouée.
          
        Toutes les fonctions doivent être sûrs pour les threads (pas
        seulement la fonction principale, mais les fonctions
        d'initialisation et de terminaison également). Cela signifie
        que vous n'êtes pas autorisés à allouer une variable globale
        ou statique qui change ! Si vous avez besoin de mémoire, vous
        devez l'allouer avec la fonction xxx_init()
        et la libérer avec xxx_deinit().
      
          La fonction principale doit être déclarée comme illustrée
          ici. Notez que le type de retour et les paramètres
          diffèrent, suivant que vous voulez déclarer une fonction SQL
          XXX() qui retournera une
          STRING, un INTEGER ou un
          REAL dans la commande CREATE
          FUNCTION :
        
          Pour les fonctions de chaînes STRING :
        
char *xxx(UDF_INIT *initid, UDF_ARGS *args,
          char *result, unsigned long *length,
          char *is_null, char *error);
          Pour les fonctions d'entiers INTEGER :
        
long long xxx(UDF_INIT *initid, UDF_ARGS *args,
              char *is_null, char *error);
          Pour les fonctions de nombres à virgule flottante
          REAL :
        
double xxx(UDF_INIT *initid, UDF_ARGS *args,
              char *is_null, char *error);
Les fonctions d'initialisation et de terminaison sont déclarées comme ceci :
my_bool xxx_init(UDF_INIT *initid, UDF_ARGS *args, char *message); void xxx_deinit(UDF_INIT *initid);
          Le paramètre initid est passé aux trois
          fonctions. Il pointe sur une structure
          UDF_INIT qui est utilisée pour communiquer
          des informations entre les fonctions. Les membres de la
          structure UDF_INIT sont ceux qui sont
          listés ci-dessous. La fonction d'initialisation doit
          préparer les membres qu'elle veut, et notamment leur donner
          une valeur initiale (pour utiliser les valeurs par défaut,
          laissez le membre intact) :
        
              my_bool maybe_null
            
              xxx_init() doit remplacer
              maybe_null par 1 si
              xxx() peut retourner
              NULL. La valeur par défaut est
              1 si l'un des arguments n'est déclaré
              comme maybe_null.
            
              unsigned int decimals
            
              Le nombre de décimales. La valeur par défaut est le
              nombre maximum de décimales dans l'argument passé à la
              fonction. Par exemple, vis la fonction re¸oit
              1.34, 1.345 et
              1.3, ce nombre sera 3, car
              1.345 a 3 décimales.
            
              unsigned int max_length
            
              La taille maximale de la chaîne résultat. La valeur par
              défaut dépend du type de résultat de la fonction. Pour
              les fonctions de chaînes, la valeur par défaut est la
              taille du plus grand argument. Pour les fonctions
              entières, la valeur est de 21 chiffres. Pour les
              fonctions à nombre à virgule flottante, la valeur est de
              13, plus le nombre de décimales indiquées par
              initid->decimals. Pour les fonctions
              numériques, la taille inclut le signe et le séparateur
              décimal.
            
              Si vous voulez retourner un BLOB, vous
              devez donner à ce membre la valeur de 65 ko ou 16 Mo; cet
              espace mémoire ne sera pas alloué, mais utilisé pour
              décider quel type de colonne utiliser, si il y a un
              besoin de stockage temporaire.
            
              char *ptr
            
              Un pointeur que la fonction peut utiliser pour ses besoins
              propres. Par exemple, la fonction peut utiliser
              initid->ptr pour transférer de la
              mémoire allouée entre les trois fonctions. En
              xxx_init(), allouez de la mémoire, et
              assignez la à ce pointeur :
            
initid->ptr = allocated_memory;
              En xxx() et
              xxx_deinit(), utilisez
              initid->ptr pour exploiter ou
              supprimer la mémoire.
            
Voici une description des différentes fonctions que vous devez définir pour réaliser des calculs sur des regroupements, avec une fonction utilisateur :
Notez que ce qui suit n'est pas demandé ou utilisé par MySQL 4.1.1. Vous pouvez conserver cette définition pour assurer la compatibilité entre MySQL 4.0 et MySQL 4.1.1.
char *xxx_reset(UDF_INIT *initid, UDF_ARGS *args,
                char *is_null, char *error);
Cette fonction est appelée lorsque MySQL trouve la première ligne dans un nouveau groupe. Dans cette fonction, vous devez remettre à zéro des variables internes de sommaire, puis indique le nouvel argument comme premier membre du nouveau groupe.
          Dans de nombreuses situations, cela se fait en interne en
          remettant à zéro toutes les variables, et en appelant
          xxx_add().
        
Cette fonction n'est demandée que par MySQL 4.1.1 et plus récent :
char *xxx_clear(UDF_INIT *initid, char *is_null, char *error);
Cette fonction est appelée à chaque fois qu'une ligne qui appartient à un groupe est trouvée, hormis la première ligne. Durant cette fonction, vous devez ajouter les données dans votre variable interne de sommaire.
          Vous pouvez utiliser le pointeur error pour
          stocker un octet si quelque chose n'a pas fonctionné.
        
char *xxx_add(UDF_INIT *initid, UDF_ARGS *args,
              char *is_null, char *error);
          Cette fonction est appelée pour toutes les lignes du même
          groupe, hormis pour la première ligne. Dans cette dernière,
          vous devez ajouter la valeur dans UDF_ARGS
          pour vos variables internes.
        
          La fonction xxx() doit être déclarée de
          manière identique à celle d'un fonction utilisateur simple.
          See Section 27.2.3.1, « Fonctions utilisateur : appeler des fonctions simples ».
        
          Cette fonction est appelée lorsque toutes les lignes d'un
          groupe ont été traitées. Vous ne devez normalement pas
          accéder à la variable args ici, mais
          retourner votre valeur, à partir des valeurs du sommaire
          interne.
        
          Tous les traitements des arguments de
          xxx_reset() et xxx_add()
          doivent être fait d'une manière similaire à celle des
          fonctions UDF normales. See
          Section 27.2.3.3, « Traitement des arguments ».
        
          La gestion de la valeur retournée par
          xxx() doit être identique à celle d'une
          fonction utilisateur classique. See
          Section 27.2.3.4, « Valeurs de retour et gestion d'erreurs. ».
        
          Le pointeur argument de is_null et
          error sont les mêmes pour tous les appels
          de xxx_reset(),
          xxx_add() et xxx(). Vous
          pouvez utiliser ces valeur pour vous rappeler si vous avez
          rencontré une erreur, ou si la fonction
          xxx() doit retourner
          NULL. Notez que vous ne devez pas stocker
          de chaîne dans *error! C'est un conteneur
          d'un seul octet!
        
          is_null est remis à zéro pour chaque
          (avant d'appeler xxx_reset().
          error n'est jamais remis à zéro.
        
          Si isnull ou error sont
          modifiés après xxx(), alors MySQL va
          retourner NULL comme résultat de la
          fonction de groupement.
        
          Le paramètre args pointe sur une structure
          UDF_ARGS qui dispose des membre suivants :
        
              unsigned int arg_count
            
Le nombre d'arguments. Vérifiez cette valeur dans la fonction d'initialisation, si vous voulez que votre fonction soit appelée avec un nombre particulier d'arguments. Par exemple :
if (args->arg_count != 2)
{
    strcpy(message,"XXX() requires two arguments");
    return 1;
}
              enum Item_result *arg_type
            
              Le type de chaque argument. Les valeurs possibles pour
              chaque type sont STRING_RESULT,
              INT_RESULT et
              REAL_RESULT.
            
              Pour s'assurer que les arguments sont d'un type donné, et
              retourner une erreur dans le cas contraire, vérifiez le
              tableau arg_type durant la fonction
              d'initialisation. Par exemple :
            
if (args->arg_type[0] != STRING_RESULT ||
    args->arg_type[1] != INT_RESULT)
{
    strcpy(message,"XXX() requires a string and an integer");
    return 1;
}
              Comme alternative à l'imposition d'un type particulier
              pour les arguments des fonctions, vous pouvez utiliser la
              fonction pour qu'elle modifie le type des arguments et
              donne aux valeurs de arg_type le type
              que vous souhaitez. Cela fait que MYSQL va forcer les
              arguments à un type donnée, pour chaque appel de la
              fonction xxx(). Par exemple, pour
              forcer le type des deux premiers arguments en chaîne et
              entier, vous pouvez utiliser la fonction d'initialisation
              xxx_init() :
            
args->arg_type[0] = STRING_RESULT; args->arg_type[1] = INT_RESULT;
              char **args
            
              args->args communique les
              informations à la fonction d'initialisation, ainsi que la
              nature des arguments avec laquelle elle a été appelée.
              Pour un argument constant i,
              args->args[i] pointe sur la valeur
              de l'argument. Voir plus bas pour les instructions
              d'accès à cette valeur. Pour les valeurs non constantes,
              args->args[i] vaut
              0. Un argument constant est une
              expression qui utilise des constantes, comme
              3 ou 4*7-2 ou
              SIN(3.14). Un argument non-constant est
              une expression qui fait référence aux valeurs qui
              peuvent changer de ligne en ligne, par exemple des noms de
              colonnes ou des fonctions qui sont appelées avec des
              arguments non-constants.
            
              Pour chaque invocation de la fonction principale,
              args->args contient les arguments
              réels qui sont passés à la ligne qui sera traitée.
            
              Les fonctions peuvent faire référence à un argument
              i comme ceci :
            
                  Un argument de type STRING_RESULT
                  est donné sous la forme d'un pointeur de chaîne,
                  plus une longueur, pour permettre la gestion des
                  données binaires ou des données de taille
                  arbitraire. Le contenu des chaînes est disponible
                  avec l'expression args->args[i]
                  et la taille de la chaîne est
                  args->lengths[i]. Ne supposez
                  pas que les chaînes sont terminés par le caractère
                  nul.
                
                  Pour un argument de type
                  INT_RESULT, vous devez transtyper
                  la valeur args->args[i] en
                  valeur long long :
                
long long int_val; int_val = *((long long*) args->args[i]);
                  Pour un argument de type
                  REAL_RESULT, vous devez transtyper
                  la valeur args->args[i] en
                  valeur double :
                
double real_val; real_val = *((double*) args->args[i]);
              unsigned long *lengths
            
              Pour une fonction d'initialisation, le tableau
              lengths indique la taille maximale des
              chaînes pour chaque argument. Vous ne devez pas les
              modifier. Pour chaque appel de la fonction principale,
              lengths contient la taille réelle de
              toutes les chaînes arguments qui sont passé pour la
              ligne traitée. Pour les arguments de type
              INT_RESULT ou
              REAL_RESULT, lengths
              contient toujours la taille maximale de l'argument (comme
              pour la fonction d'initialisation).
            
          La fonction d'initialisation doit retourner
          0 si aucune erreur ne s'est produite et
          1 sinon. Si une erreur s'est produite,
          xxx_init() doit stocker un message se
          terminant par un NULL dans le paramètre
          message. Le message sera retourné au
          client. La taille du tampon du message est de
          MYSQL_ERRMSG_SIZE caractères, mais vous
          devez essayer de garder une taille de message inférieure à
          80 caractères, sinon, il remplit la largeur d'un écran de
          terminal standard.
        
          La valeur de retour de la fonction principale
          xxx() est la valeur de la fonction, pour
          les fonctions long long et
          double. Une fonction de chaîne de
          caractères doit retourner un pointeur vers le résultat et
          stocker la taille de la chaîne de caractères dans l'argument
          length.
        
Affectez cette valeur au contenu et à la longueur de la valeur retournée. Par exemple :
memcpy(result, "chaîne retournée", 16); *length = 16;
          Le tampon result qui est passé à la
          fonction a une taille de 255 bits. Si votre résultat dépasse
          ceci, ne vous inquiétez pas de l'allocation de mémoire pour
          ce résultat.
        
          Si votre fonction de chaînes de caractères a besoin de
          retourner une chaîne de caractères plus grande que 255 bits,
          vous devez allouer de l'espace pour cela avec
          malloc() dans votre fonction
          xxx_init(). Vous pouvez stocker la mémoire
          allouée dans le buffer ptr de la structure
          UDF_INIT pour être ré-utilisée par les
          appels futurs de xxx(). See
          Section 27.2.3.1, « Fonctions utilisateur : appeler des fonctions simples ».
        
          Pour indiquer une valeur de retour NULL
          dans la fonction principale, mettez is_null
          à 1 :
        
*is_null = 1;
          Pour indiquer une erreur retournée dans la fonction
          principale, mettez le paramètre error à
          1:
        
*error = 1;
          Si xxx() met *error à
          1 pour chaque ligne, la valeur de la
          fonction est NULL pour la ligne en question
          et pour chaque ligne suivante traitée par le processus dans
          lequel XXX() est invoqué.
          (xxx() ne sera même pas appelé pour les
          lignes suivantes.)
          Remarque : dans les versions
          antérieures à 3.22.10, vous devez définir
          *error et *is_null :
        
*error = 1; *is_null = 1;
          Les fichiers qui implémentent des fonctions utilisateurs
          doivent être compilés et installés sur le même hôte que
          celui du serveur. Ce processus est décrit plus bas, avec le
          fichier udf_example.cc qui est inclut
          dans les sources MySQL. Ce fichier contient les fonctions
          suivantes :
        
              metaphon() retourne la version
              métaphone de la chaîne en argument. C'est une technique
              proche du soundex, mais elle est bien plus optimisée pour
              l'anglais.
            
              myfunc_double() retourne la moyenne des
              codes ASCII des caractères de la chaîne passée en
              argument.
            
              myfunc_int() retourne la somme de
              tailles des arguments.
            
              sequence([const int]) retourne une
              séquence, commen¸ant à partir du nombre choisit ou 1,
              si aucun nombre n'a été fourni.
            
              lookup() retourne l'adresse IP
              numérique d'un hôte.
            
              reverse_lookup() retourne le nom
              d'hôte pour une adresse IP. Cette fonction peut être
              appelée avec une chaîne au format
              "xxx.xxx.xxx.xxx" ou quatre nombres.
            
Un fichier dynamiquement chargé doit être compilé sous la forme d'un objet partagé, grâce à une commande comme celle-ci :
shell> gcc -shared -o udf_example.so myfunc.cc
          Vous pouvez facilement trouver les options correctes pour la
          compilation en exécutant cette commande dans le dossier
          sql de votre installation source :
        
shell> make udf_example.o
          Vous devez exécuter une commande de compilation similaire à
          celle que le make affiche, sauf que vous
          devrez supprimer l'option -c près de la
          fin de la ligne, et ajouter -o
          udf_example.so à la fin de la ligne. Sur certains
          systèmes, vous devrez aussi supprimer -c
          de la commande).
        
          Une fois que vous compilez un objet partagés contenant des
          fonctions utilisateurs, vous devez les installer, et prévenir
          le serveur MYSQL. Compiler un objet partagé avec
          udf_example.cc produit un fichier qui
          s'appelle udf_example.so (le nom exact
          peut varier suivant la plate-forme). Copiez ce fichier dans
          l'un des dossiers utilisé par ld, tel que
          /usr/lib. Par exemple,
          /etc/ld.so.conf.
        
          Sur de nombreux systèmes, vous pouvez faire pointer la
          variable d'environnement LD_LIBRARY ou
          LD_LIBRARY_PATH pour qu'elle pointe dans le
          dossier où vous avez vos fichiers de fonctions. Le manuel de
          dlopen vous indiquera quelle variable
          utiliser sur votre système. Vous devriez indiquer cette
          valeur dans les options de démarrage de
          mysql.server et
          safe_mysqld, et redémarrer
          mysqld.
        
          Après que la bibliothèque ait été installée, indiquez à
          mysqld ces nouvelles fonctions avec ces
          commandes :
        
mysql>CREATE FUNCTION metaphon RETURNS STRING SONAME "udf_example.so";mysql>CREATE FUNCTION myfunc_double RETURNS REAL SONAME "udf_example.so";mysql>CREATE FUNCTION myfunc_int RETURNS INTEGER SONAME "udf_example.so";mysql>CREATE FUNCTION lookup RETURNS STRING SONAME "udf_example.so";mysql>CREATE FUNCTION reverse_lookup->RETURNS STRING SONAME "udf_example.so";mysql>CREATE AGGREGATE FUNCTION avgcost->RETURNS REAL SONAME "udf_example.so";
          Les fonctions peuvent être effacées plus tard avec
          DROP FUNCTION:
        
mysql>DROP FUNCTION metaphon;mysql>DROP FUNCTION myfunc_double;mysql>DROP FUNCTION myfunc_int;mysql>DROP FUNCTION lookup;mysql>DROP FUNCTION reverse_lookup;mysql>DROP FUNCTION avgcost;
          Les commandes CREATE FUNCTION et
          DROP FUNCTION modifient la table système
          func dans la base mysql.
          Le nom de la fonction, son type et le nom de la bibliothèque
          partagée sont alors sauvés dans la table. Vous devez avoir
          les droits de INSERT et
          DELETE dans la base
          mysql pour ajouter et effacer des
          fonctions.
        
          Vous ne devez pas utiliser la commande CREATE
          FUNCTION pour ajouter une fonction qui a déjà
          été créée. Si vous devez reinstaller une fonction, vous
          devez la supprimer avec la commande DROP
          FUNCTION puis la reinstaller avec CREATE
          FUNCTION. Vous devrez faire cela, par exemple, si
          vous recompilez une nouvelle version de votre fonction, pour
          que mysqld utilise cette nouvelle version.
          Sinon, le serveur va continuer à utiliser l'ancienne version.
        
          Les fonctions actives sont rechargées à chaque fois que le
          serveur démarre, à moins que vous ne démarriez le serveur
          mysqld avec l'option
          --skip-grant-tables. Dans ce cas,
          l'initialisation des fonctions utilisateurs sont ignorées, et
          ces fonctions sont inutilisables. Une fonction active doit
          avoir été créée avec CREATE FUNCTION et
          pas supprimée avec DROP FUNCTION.
        
MySQL prend les mesures suivantes pour éviter une utilisation abusive des fonctions utilisateurs.
          Vous devez avoir les droits de INSERT pour
          être capable d'utiliser la commande CREATE
          FUNCTION et le droit de DELETE
          pour être capable d'effacer une fonction (DROP
          FUNCTION. Ceci est nécessaire car ces commandes
          ajoutent et suppriment des lignes dans la table
          mysql.func.
        
          UDF doit avoir au moins un symbole défini, en plus du symbole
          xxx qui correspond à la fonction
          principale xxx(). Ces symboles auxiliaires
          correspondent aux fonctions xxx_init(),
          xxx_deinit(),
          xxx_reset(), xxx_clear()
          et xxx_add(). Depuis MySQL 4.0.24, 4.1.10a
          et 5.0.3, mysqld supporte l'option
          --allow-suspicious-udfs qui spécifie si les
          UDF qui n'ont qu'une fonction xxx peuvent
          être chargées. Par défaut, cette fonction est désactivée,
          ce qui empêche les fonctions de charger des fonctions depuis
          des objets partagés autres que les UDF légales. Si vous avez
          de vieilles fonctions UDF qui contiennent uniquement le
          symbole xxx qui ne peuvent pas être
          recompilées pour utiliser un symbole auxiliaire, il sera
          nécessaire d'utiliser l'option
          --allow-suspicious-udfs. Sinon, vous devrez
          vous passer de cette fonctionnalité.
        
          Les fichiers d'objet UDF ne peuvent pas être placés dans
          n'importe quel dossier. Ils doivent être placés dans un
          dossier système que le compilateur dynamique peut analyser.
          Pour assurer le fonctionnement de cette restriction, et
          éviter les attaques par spécification de chemins arbitraires
          en dehors de ceux que le compilateur dynamique peut atteindre,
          MySQL vérifie dans le nom de l'objet partagé spécifié dans
          la commande CREATE FUNCTION la présence de
          délimiteurs de dossiers. Depuis MySQL 4.0.24, 4.1.10a et
          5.0.3, MySQL vérifie aussi les délimiteurs de fichiers
          stockés dans la table mysql.func lorsque
          vous chargez les fonctions. Cela évite les tentatives de
          spécifications de chemins interdits, en manipulant
          directement les tables mysql.func. Pour
          plus de détails sur les UDF et le compilateur dynamique,
          voyez Section 27.2.3.5, « Compiler et installer des fonctions utilisateurs ».
        
La procédure pour ajouter une nouvelle fonction native est décrite ici. Notez que vous ne pouvez ajouter de fonctions natives à une distribution binaire car la procédure implique la modifications du code source de MySQL. Vous devez compiler MySQL vous-même à partir d'une distribution des sources. Notez aussi que si vous migrez vers une autre version de MySQL (par exemple, quand une nouvelle version est réalisée), vous devrez répéter la procédure avec la nouvelle version.
Pour ajouter une nouvelle fonction native à MySQL, suivez les étapes suivantes :
            Ajoutez une ligne dans lex.h qui
            définit le nom de la fonction dans le tableau
            sql_functions[].
          
            Si le prototype de la fonction est simple (elle prend zéro,
            un, deux ou trois arguments), vous devez spécifier dans
            lex.h SYM(FUNC_ARG#)
            (où # est le nombre d'arguments) en tant que second
            argument dans le tableau sql_functions[]
            et ajouter une fonction qui crée un objet fonction dans
            item_create.cc. Regardez
            "ABS" et
            create_funcs_abs() pour un exemple.
          
            Si le prototype de la fonction est compliqué (par exemple,
            elle prend un nombre variable d'arguments), vous devez
            ajouter deux lignes à sql_yacc.yy. Une
            qui indique le symbole preprocesseur que
            yacc doit définir (cela doit être
            ajouté au début du fichier). Puis définir les paramètres
            de la fonction et un ``item'' avec ces paramètres à la
            règle simple_expr. Pour un exemple,
            vérifiez toutes les occurrences de ATAN
            dans sql_yacc.yy pour voir comment cela
            se fait.
          
            Dans item_func.h, déclarez une classe
            héritant de Item_num_func ou de
            Item_str_func, selon que votre fonction
            retourne une nombre ou un chaîne.
          
            Dans le fichier item_func.cc, ajoutez
            l'une des déclaration suivantes, selon que vous définissez
            une fonction numérique ou de chaîne de caractères :
          
double Item_func_newname::val() longlong Item_func_newname::val_int() String *Item_func_newname::Str(String *str)
            Si vous héritez votre objet de l'un des éléments
            standards (comme Item_num_func) vous
            n'aurez probablement qu'à définir l'une des fonctions
            décrites ci-dessus et laisser l'objet parent prendre soin
            des autres fonctions. Par exemple, la classe
            Item_str_func définit une fonction
            val() qui exécute
            atof() sur la valeur retournée par
            ::str().
          
Vous devez aussi probablement définir la fonction objet suivante :
void Item_func_newname::fix_length_and_dec()
            Cette fonction doit au moins calculer
            max_length en se basant sur les arguments
            donnés. max_length est le nombre maximal
            de caractères que la fonction peut retourner. Cette
            fonction doit aussi définir maybe_null =
            0 si la fonction principale ne peut pas retourner
            une valeur NULL. La fonction peut
            vérifier si l'un de ses arguments peut retourner
            NULL en vérifiant la variable
            maybe_null des arguments. Vous pouvez
            regarder
            Item_func_mod::fix_length_and_dec pour
            avoir un exemple concret.
          
Toutes les fonctions doivent être sûres pour les threads (en d'autres termes, n'utilisez aucune variable statique ou globale dans la fonction sans les protéger avec mutex).
        Si vous voulez retourner NULL, à partir de
        ::val(), ::val_int() ou
        ::str() vous devez mettre
        null_value à 1 et retourner 0.
      
        Pour les fonctions de l'objet ::str(), il y a
        d'autres considérations à prendre en compte :
      
            L'argument String *str fournit un tampon
            de chaîne qui peut être utilisé pour contenir le
            résultat. (Pour plus d'informations à propos du type
            String, regardez le fichier
            sql_string.h.)
          
            La fonction ::str() doit retourner la
            chaîne contenant le résultat ou (char*)
            0 si celui-ci est NULL.
          
Aucune des fonctions de chaînes n'essaye d'allouer de mémoire tant que ce n'est pas nécessaire !
      Avec MySQL, vous pouvez définir une procédure en C++ qui accède
      et modifie les données dans la requête avant que celle-ci ne
      soit envoyée au client. La modification peut être faite ligne
      par ligne ou au niveau de GROUP BY.
    
Nous avons crée une procédure d'exemple avec la version 3.23 de MySQL pour vous montrer comment cela fonctionne.
      De plus, nous vous recommandons de jeter un oeil à
      mylua. Avec cela, vous pouvez utiliser le
      langage LUA pour charger une dynamiquement une procédure dans
      mysqld.
    
        analyse([max elements,[max memory]])
      
        Cette procédure est définie dans le fichier
        sql/sql_analyse.cc. Elle examine les
        résultats de vos requêtes et en retourne une analyse :
      
            max elements (256 par défaut) est le
            nombre maximal de valeurs distinctes que
            analyse retiendra par colonne. C'est
            utilisé par analyse pour vérifier si le
            type optimal de la colonne ne serait pas le type
            ENUM.
          
            max memory (8192 par défaut) est le
            maximum de mémoire que analyse doit
            allouer par colonne quand elle essaye de trouver toutes les
            valeurs distinctes.
          
SELECT ... FROM ... WHERE ... PROCEDURE ANALYSE([max elements,[max memory]])
This is a translation of the MySQL Reference Manual that can be found at dev.mysql.com. The original Reference Manual is in English, and this translation is not necessarily as up to date as the English version.