Étendre un serveur MySQL/MariaDB avec des fonctions compilées – Partie 2/2

2.3 Installation

Une fois programmée, puis compilée, la fonction UDF se trouve sous la forme d’un binaire partagé (.so) qu’il est nécessaire de déposer à un endroit du système de fichiers où le serveur MySQL saura le trouver.

Ce chemin peut être différent selon les distributions, et surtout il peut être modifié par l’administrateur, dans la configuration de lancement du service.

La variable MySQL globale @@plugin_dir a pour rôle d’indiquer le chemin où le serveur obtient les binaires des UDF :

C’est à cet emplacement que vous déposerez votre binaire. Le fichier doit appartenir au compte sous lequel tourne le service, lui être accessible en lecture et en exécution. En outre pour des raisons évidentes de sécurité vous devrez veiller à ce qu’il ne soit pas modifiable par d’autres utilisateurs.

2.4 Déclaration

Une fois que le serveur MySQL est en mesure de trouver et d’exécuter votre binaire, il faut lui indiquer la ou les fonctions UDF qu’il fournit.

Le mot AGGREGATE n’est à indiquer que s’il s’agit d’une fonction d’agrégat. L’argument fourni après le mot SONAME est le nom du shared object relatif au chemin des plugins du serveur.

3. Pièges courants

3.1 Calculs et arrondis

À la lumière de la démonstration [5] faite dans GNU/Linux Magazine n°194 sur les difficultés liées au calcul à virgule flottante ou avec des très grands ou très petits nombres, la prudence s’impose dans les formules arithmétiques des fonctions UDF. Bien que les types double et long long laissent une bonne latitude concernant la précision ou la taille des nombres, la manipulation de valeurs potentiellement hétérogènes peut causer des inexactitudes difficiles à détecter.

Par exemple :

3.2 Mémoire

Une fois chargée en mémoire lors de la première utilisation d’une fonction UDF, la bibliothèque reste montée. Les fuites de mémoire occasionnées par du code UDF accompagnent toute la durée d’exécution du service MySQL, jusqu’à son redémarrage.

3.3 Encodage des chaînes de caractères

Les arguments textuels sont passés aux UDF sous forme de char *. L’inconvénient direct est que le contenu de ces chaînes varie selon l’encodage (charset) en vigueur lors de l’appel à la fonction UDF. Il n’existe pas de moyen simple d’identifier automatiquement (dès l’appel) l’encodage des paramètres. Des hypothèses doivent être faites (sous forme de convention d’appel à votre fonction, ou par un argument supplémentaire qui contiendrait le charset si c’est important pour votre traitement).

3.4 Mise au point

Il n’est pas rare de devoir effectuer plusieurs essais lors de la création d’une fonction UDF, or la mise au point n’est pas aisée, car le code s’exécute dans le contexte du service MySQL lui-même. Aussi, il est conseillé d’effectuer les tests dans un serveur de développement, voire un conteneur Docker [6] :

3.5 Sécurité

Le code présent dans une bibliothèque UDF peut exécuter tout ce qui est autorisé au compte du service MySQL, et peut être déclenché par un simple utilisateur de la base de données sur simple appel de la fonction. Il est donc important de veiller à ce que les droits du compte du service soient convenablement configurés. En outre, il convient de ne pas faire confiance d’emblée à un binaire UDF, qui pourrait effectuer des actions sensibles ou malveillantes (ou mal codées !) provoquant des dégâts même sous le compte limité du service MySQL (qui possède tout de même tous les fichiers de données de la base…).

Avant de la déployer, il est préférable de toujours compiler le source d’une fonction UDF, à partir d’un dépôt de confiance.

Conclusion

La criticité de l’aspect sécuritaire des UDF oblige généralement les hébergeurs de serveurs de bases de données dans le nuage à les proscrire, à juste titre.

À l’heure où les directions informatiques tendent à s’orienter vers l’infrastructure locative, de façon à s’affranchir des tâches de maintenance et de supervision des serveurs de bases de données, il est à prévoir que les UDF, qui nécessitent un accès administratif à l’hôte, disparaîtront progressivement des architectures applicatives. Par ailleurs, l’augmentation des puissances de calcul permettent le plus souvent d’envisager une solution programmatique au niveau de la couche de persistance des applications, en lieu et place d’une fonction compilée dans le SGBD, même pour ce qui est des agrégats.

Néanmoins, la connaissance de ces possibilités d’extension de MySQL/MariaDB et leurs points faibles, demeure recommandée pour savoir sécuriser un système ou faire les bons choix de conception d’un applicatif.

Notez qu’il existe un projet d’inventaire et de contributions open source de fonctions UDF utiles et populaires [7]. Vos besoins particuliers sont peut-être déjà couverts, et vous pourrez souhaiter contribuer à cette plateforme avec vos prochaines créations.

Références

[1] http://www.mathematik.uni-ulm.de/help/mysql-3.22.25/manual.html
[2] http://dev.mysql.com/doc/refman/5.7/en/adding-native-function.html
[3] http://dev.mysql.com/doc/refman/5.7/en/adding-udf.html
[4] https://github.com/mysql/mysql-server/blob/5.7/sql/udf_example.cc
[5] LANGRONET F., « Peut-on vraiment calculer avec un ordinateur », GNU/Linux Magazine n°194, pp 22-31
[6] https://hub.docker.com/_/mysql/
[7] http://www.mysqludf.org/

Retrouvez cet article (et bien d’autres) dans GNU/Linux Magazine n°203, disponible sur la boutique et sur la plateforme de lecture en ligne Connect !