Go to the first, previous, next, last section, table of contents.


9 Etendre MySQL

9.1 Rouages de MySQL

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.3.4 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.7.1.1 Les listes de diffusions 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 vos patchs que vous voulez voir intégré au projet MySQL.

9.1.1 Threads MySQL

Le serveur MySQL crée les threads suivants :

mysqladmin processlist affiche uniquement les threads de connexion, ceux de INSERT DELAYED et ceux de réplication.

9.1.2 Suite de test de MySQL

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

9.1.2.1 Exécuter la suite de tests MySQL

Le système de tests est constituté 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 (eg. /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 9.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.

9.1.2.2 Améliorer la suite de tests MySQL

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.

9.1.2.3 Rapporter des bugs dans la suite de tests MySQL

Si votre versionn de MySQL ne passe pas un teste, vous devez faire ceci :

9.2 Ajouter des fonctions à MySQL

Il y a deux méthodes pour ajouter des fonctions à MySQL :

Chaque méthode a ses avantages et inconvénients :

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().

9.2.1 Syntaxe de CREATE FUNCTION/DROP FUNCTION

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 librairies 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 9.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.

9.2.2 Ajouter une nouvelle fonction définie par l'utilisateur (UDF)

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 plate-formes, (Linux inclus) vous pouvez charger une librairie 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 :
xxx_deinit() (optionnel)
La dés-initialisation de la fonction xxx(). Elle doit dés-allouer 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 dés-initialisation 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 dés-initialisation 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 :

All functions must be thread-safe (not just the main function, but the initialisation and deinitialisation functions as well). This means that you are not allowed to allocate any global or static variables that change! If you need memory, you should allocate it in xxx_init() and free it in xxx_deinit().

  1. Appeler xxx_init() pour laisser la fonction d'agrégat allouer la mémoire dont elle aura besoin pour stocker les résultats.
  2. Trier la table en accord avec la clause GROUP BY.
  3. Pour la première ligne dans un nouveau groupe, appeler la fonction xxx_reset().
  4. Pour chaque ligne appartenant à un même groupe, appeler la fonction xxx_add().
  5. 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.
  6. Répéter 3-5 tant que toutes les lignes n'ont pas été traitées.
  7. 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 dés-initialisation é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().

9.2.2.1 Fonctions utiliateur : appeler des fonctions simples

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 chî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, and 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 65K ou 16M; 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.

9.2.2.2 Appeler des fonctions utilisateurs pour les groupements

Voici une description des différentes fonctions que vous devez définir pour réaliser des calculs sur des regroupements, avec une fonction utilisateur :

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().

char *xxx_add(UDF_INIT *initid, UDF_ARGS *args,
              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.

La fonction xxx() doit être déclarée de manière identique à celle d'un fonction utilisateur simple. See section 9.2.2.1 Fonctions utiliateur : 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 9.2.2.3 Traitement des arguments.

La gestion de la valeur retournée par xxx() doit être identique à celle d'une fonction utilisateur classique. See section 9.2.2.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.

9.2.2.3 Traitement des arguments

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 avleur 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'initisalition 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 :
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).

9.2.2.4 Valeurs de retour et gestion d'erreurs.

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 calc à une taille de 255 bits. Si votre résultat dépasse ceci, ne vous inquietez 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 slot ptr de la structure UDF_INIT pour être ré-utilisée par les appels futurs de xxx(). See section 9.2.2.1 Fonctions utiliateur : 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;

9.2.2.5 Compiler et installer des fonctions utilisateurs

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 :

Un fichier dynamiquement chargeable 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. Compilier 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'. 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 librairie 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 librairie 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.

9.2.3 Ajouter de nouvelles fonctions natives

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 :

  1. Ajoutez une ligne dans `lex.h' qui définit le nom de la fonction dans le tableau sql_functions[].
  2. 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 préprocesseur 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 occurences de ATAN dans `sql_yacc.yy' pour voir comment cela se fait.
  3. Dans `item_func.h', déclarez une classe héritant de Item_num_func ou de Item_str_func, selon que vvotre fonction retourne une nombre ou un chaîne.
  4. 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().
  5. 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 mutexes).

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 :

9.3 Ajouter une nouvelle procédure à MySQL

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.

9.3.1 La procédure Analyse

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 :

SELECT ... FROM ... WHERE ... PROCEDURE ANALYSE([max elements,[max memory]])

9.3.2 Ecrire une procédure

Pour le moment, la seule documentation à ce sujet est constituée par les sources.

Vous pourrez trouver toutes les informations sur les procédures en examinant les fichiers suivants :


Go to the first, previous, next, last section, table of contents.