Archives de catégorie : Développement

Configuration MySQL – quelques astuces

Paramètre Max Packet Size pour les grosses requêtes

Il faut augmenter la valeur du paramètre max_allowed_packet dans le fichier de configuration de MySQL pour permettre de gérer les grosses requêtes : principalement pour les tables qui contiennent des BLOB et CLOB qui peuvent être volumineux.

Méthodes

Éditer le fichier my.ini

Ajouter ce qui suit dans la section [mysqld] du fichier de configuration

#Max packetlength to send/receive from to server.
max_allowed_packet=8M

Utiliser l’interface graphique MySQL Administrator

Modifier le paramètre dans l’interface graphique comme dans la capture d’écran suivant :

MySQL : modification du paramètre "max_packet_size"
MySQL : modification du paramètre "max_packet_size"

Importer une base de Windows à Linux

La gestion des noms de tables est configurée différemment par défaut sous Windows ou Linux :

  • Sous Windows il ne tient pas compte de la casse,
  • Sous Linux il en tient compte.

Le passage du contenu d’une base de données d’un OS à un autre peut donc être problématique, principalement dans le sens Windows -> Linux. En effet, faire le dump depuis Windows va minimiser tous les noms de tables. Et si jamais le code source de votre application référence les tables avec des majuscules, cela peut posser des soucis. Surtout qu’il n’est pas toujours possible de re-écrire le code pour n’utiliser que des noms de tables en minuscules. Voici les solutions que j’utilise dans ces cas-là.

Choix 1 : Modifier la configuration du MySQL sous Linux

Pour importer une base MySQL depuis une machine Windows vers une machine Linux, il est possible de configurer le serveur MySQL sous Linux avec le paramètre lower_case_table_names à 1. Pour cela, éditer le fichier my.ini et placer dans la section [mysqld] la ligne suivante :

set-variable = lower_case_table_names=1

Voir la documentation MySQL pour plus de détails sur ce sujet.

Choix 2 : Transformer le fichier de dump

Si il n’est pas possible de modifier la configuration du serveur MySQL sous linux, il reste la solution – beaucoup plus sport – qui consiste à modifier le fichier de dump. En fait, il va falloir diviser le dump en deux fichiers :

Le premier fichier qui ne contient que la structure de la base :  dump.struct.sql Il peut être créé avec la commande suivante :

 mysqldump -hHOSTNAME -uUSER -p -d DBNAME > dump.struct.sql

Le deuxième fichier qui ne contient que les données de la base : dump.data.sql Il peut être créé avec la commande suivante (–hex-blob pour exporter les binaires en hexadécimal et –extended-insert=false pour avoir une commande INSERT par enregistrement) :

 mysqldump -hHOSTNAME -uUSER -p --hex-blob --extended-insert=false -t DBNAME > dump.data.sql

Il va ensuite falloir transformer ces fichiers pour que les noms des tables soient en majuscules :

Pour le fichier dump.struct.sql

C’est l’opération la plus simple. Utilisez la commande ‘tr‘ comme suit :

$ cat dump.struct.sql | tr '[:lower:]' '[:upper:]' > dump.struct.upper.sql

Et importer le fichier dump.struct.upper.sql résultant dans la base.

Pour le fichier dump.data.sql

Là c’est un peu plus compliqué, car on ne veut pas tout mettre en majuscules, car ce fichier contient aussi les données des différentes tables de notre base.

Note : il est à rapeller que le fichier dump.data.sql ne contient qu’une ligne de données – ie un INSERT – par enregistrement de chaque table.

Utiliser la commande ‘awk‘ pour modifier les commandes ‘INSERT INTO‘ et ‘LOCK TABLE‘ comme suit – chaque commande awk doit être sur une seule ligne :

$ awk '$1 == "LOCK" || $1 == "INSERT" { $3 = toupper($3) ; print $0 };
 $1 != "INSERT" && $1 != "LOCK" {print $0}; ' dump.data.sql > dump.data.upper.sql

En fonction de la structure du fichier d’import des données, il se peut que le nom des tables soit utilisé dans d’autres commandes, comme par exemple des commandes pour ignorer les intégrités référentielles : ALTER TABLE `une_table` DISABLE KEYS. Il faut dans ce cas se baser sur les scripts ci-dessus pour créer un nouveau qui corrigera ce problème.

Il n’y a plus qu’à importer le fichier dump.data.upper.sql dans la base MySQL.

Greasemonkey et chaque site devient mien

Greasemonkey est une extension à Mozilla Firefox qui permet de définir des Javascript personnels qui ne sont appliqués qu’à certains sites. Cela permet de les personnaliser à nos besoins.
J’ai donc eu l’idée d’utiliser et tester ce plugin pour faciliter l’utilisation d’un site que je consulte régulièrement, à savoir LinuxFR. En effet, les commentaires des articles sont présentés sous forme d’une arborescence. Si la première branche d’un commentaire est assez facile à suivre, il est plus ardu de rattacher les commentaires suivants à celui auquel ils répondent.

Nom de code : PAPA

Je vais donc essayer de construire un script pour Greasemonkey qui va me permettre à partir de n’importe quel commentaire de retrouver facilement celui auquel il se rattache. Son père. Ce projet s’appellera donc provisoirement PAPA en attendant d’avoir plus d’inspiration.

Références

Pour commencer, voici quelques url qui peuvent être utiles pour faire des user scripts avec Greasemonkey :
–  « Writing User Scripts », explication rapide sur la création de scripts Greasemonkey,
–  « Gecko DOM Reference »
–  Une liste de User scripts alimentée par un wiki,
–  Le site UserScripts qui veut proposer un outil plus poussé pour catégoriser les différents scripts.
–  Une présentation en français sur le site du Journal du net dans la section développeurs.
À noter : Les utilisateurs d’Internet Explorer peuvent aussi utiliser les user scripts à l’aide de l’extension turnabout. La version 8 du navigateur Opera semble aussi pourvoir supporter les scripts utilisateurs.
À noter encore : Utiliser GreaseMonkey peut causer quelques soucis avec les pages utilisant déjà du javascript, voir ce témoignage [1].

Principes

Une fois la page d’un article de LinuxFR chargée, le script va s’éxécuter. Il va ainsi parcourir l’arbre DOM de cette page et modifier le bloc contenant le titre de chaque commentaire en ajoutant un lien “Masquer“. Ceci ne sera fait que pour les commentaires qui ne sont pas le premier fils d’un commentaire de niveau supérieur [2]. Quand on cliquera sur ce lien, tous les commentaires précédents de même niveau seront masqués. On pourra donc facilement accéder au commentaire père pour suivre le fil de discussion.
Donc en images, voici ce que cela donne. On lit le fil d’un commentaire et on arrive au bout d’une branche. Le commentaire suivant est donc une réponse à un texte qui apparait bien plus haut dans l’arborescence. Il n’est pas toujours facile à retrouver, surtout dans un arbre à trolls.

Avant masquage

En cliquant sur le lien Masquer que l’on apercoit en bas de la page je vais me retrouver positionné sur le commentaire père – pour ainsi savoir sur quoi porte la réponse suivante – et les éléments intermédiaires seront masqués, comme ceci :

Aprés masquage

En cliquant sur Afficher on revient à la normal.

Installation du user script PAPA

Si vous voulez l’utiliser, il suffit d’installer l’extension Greasemonkey, de redémarrer Mozilla Firefox [3] et de “cliquer droit” sur ce lien. Dans le menu contextuelle qui apparait, il faut choisir « Install User Script ».

Menu contextuel sur un lien {.user.js}

Le code du script

Ci-dessous le code du script que j’ai réalisé.

// ==UserScript==
// @name          LinuxFR papa
// @namespace     /papa
// @description          [en] : This user script adds action links to each comment in comments tree
//                of Linuxfr.org website in order to improve navigability. With this
//                script you are able to find easily the parent of a comment and
//                hide (or display) a part of this tree.
//
//                [fr] : Ce "user script" ajoute des liens actifs à chaque commentaire dans
//                l'arbre des commentaires du site Linuxfr.org dans le but d'améliorer l'expérience
//                de navigation. Avec ce script vous êtes capable de trouver facilement le père d'un
//                commentaire et de cacher (ou d'afficher) une partie de cet arbre.
// @include       http://linuxfr.org/*
// @exclude       http://linuxfr.org/my/
// ==/UserScript==
// Notes:
//   version 0.4 - 02/12/2005 - correction suite a modification dans le code html de LinuxFR : Le script ne
//                              s'exécutait plus. Apparement il y a eu des changements dans les pages, et le
//                              onload ne s'exécutait pas, donc le script ne pouvait pas se dérouler. J'ai donc
//                              supprimer l'attachement du script à onload.
//   version 0.3 - 17/08/2005 - ajout licence GPL
//                            - modification de la description
//                            - ajout d'une traduction en anglais
//
//   version 0.2 - 05/06/2005 - quand on clique sur "Masquer" on est positionné sur le commentaire parent
//                            - un seul lien "Masquer" ou "Afficher" est visible. En fonction de ce qui est
//                              possible pour un commentaire, soit l'un soit l'autre est visible.
//
//   version 0.1 - 04/06/2005 - premiere version.
//
//   auteur  : Bruno ARLIGUY
//
//   licence : GPL license - http://www.gnu.org/copyleft/gpl.html

(function()
{
        //Listener positionné sur chaque lien "Masquer" quand on le "clique".
        // On va masquer le lien "Masquer", afficher le lien "Afficher" et ensuite
        // parcourir tous les commentaires précédents (ie previousSibling) et les masquer
        //
        // param e : l'évènement reçu par l'objet auquel est associé ce listener
        function hideSibling(e)
        {
                //masquer le lien "masquer"
                e.target.style.display = 'none';
                //afficher le lien "afficher"
                e.target.nextSibling.style.display = 'block';
                //masquer les commentaires précédents
                var currentComment = e.target.parentNode.parentNode.parentNode.parentNode;
                if (currentComment)
                {
                        for (var sibling = currentComment.previousSibling; sibling.nodeName == 'UL'; sibling = sibling.previousSibling)
                        {
                                sibling.style.display = 'none';
                        }
                }
        }

        //Listener positionné sur chaque lien "Afficher" quand on le "clique".
        // On va masquer le lien "Afficher", afficher le lien "Masquer" et ensuite
        // parcourir tous les commentaires précédents (ie previousSibling) et les afficher
        //
        // Attention : ceci va re-afficher tous les commentaires précédents de même niveau,
        // même si ils n'ont pas été cachés en activant le lien "cacher" correspondant au lien
        // "afficher" actuellement actif. Il faut donc repositionner les liens "Afficher" et "Masquer"
        // de ces commentaires, car certains pourraient être innapropriés.
        //
        // param e : l'évènement reçu par l'objet auquel est associé ce listener
        function showSibling(e)
        {
                //masquer le lien "afficher"
                e.target.style.display = 'none';
                //afficher le lien "masquer"
                e.target.previousSibling.style.display = 'block';
                //afficher les commentaires précédents
                var currentComment = e.target.parentNode.parentNode.parentNode.parentNode;
                var papaBlock      = null;
                if (currentComment)
                {
                        for (var sibling = currentComment.previousSibling; sibling.nodeName == 'UL'; sibling = sibling.previousSibling)
                        {
                                sibling.style.display = 'block';
                                papaBlock = document.evaluate("./li/h1/div", sibling, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
                                if (papaBlock != null)
                                {
                                        papaBlock.childNodes[0].style.display = 'block';
                                        papaBlock.childNodes[1].style.display = 'none';
                                }
                        }
                }
        }

        //Construit un block (div) qui contient les liens "Masquer" et "Afficher" pour l'UL passé en paramètre.
        //
        // param ul : un objet qui doit représenter un UL correspondant à
        //            un commentaire (ie répond au xpath //ul[@class='commentsul'])
        function getPapaBlock(ul)
        {
                var namedLink  = ul.firstChild.childNodes[1];
                var parentLink = ul.parentNode.childNodes[1];
                var id         = namedLink.name;
                var div        = document.createElement("div");
                var aHide      = document.createElement("a");
                var aShow      = document.createElement("a");

                //
                div.setAttribute("id", "pn" + namedLink.name);
                div.setAttribute("class", "pn");
                div.setAttribute("style", "float: right;");

                //Faire pointer le lien masquant sur le commentaire parent.
                aHide.setAttribute("href", "#" + parentLink.name);
                aHide.setAttribute("id", "hide" + namedLink.name);
                aHide.setAttribute("class", "pn");
                aHide.addEventListener("click", hideSibling, false);

                aShow.setAttribute("href", "#" + namedLink.name);
                aShow.setAttribute("id", "show" + namedLink.name);
                aShow.setAttribute("class", "pn");
                aShow.setAttribute("style", "display: none");
                aShow.addEventListener("click", showSibling, false);

                div.appendChild(aHide);
                div.appendChild(aShow);

                aHide.appendChild(document.createTextNode("- Masquer"));
                aShow.appendChild(document.createTextNode("+ Afficher"));

                return div;
        }

                try
                {
                        // Recupérer tous les UL de classe "commentsul". Pour chacun, ajouter un bloc dans sa barre de titre.
                        // Ce bloc contiendra deux liens : "Masquer" et "Afficher". Chaque lien appellera un script
                        // qui appliquera l'action correspondante (masquer ou afficher) sur tous les "previousSibling" du
                        // commentaire associé. Le lien en lui même consistera à appeler la même page en la positionnant sur :
                        //    - le lien nommé correspondant au commentaire parent si l'utilisateur a cliqué sur "Masquer"
                        //    - le lien nommé correspondant au commentaire si l'utilisateur a cliqué sur "Afficher".
                        // les liens nommés sont ceux de la forme <a name="580185"></a> et qui sont les "childNodes[1]" de chaque //ul[@class='commentsul'].
                        var elements = document.evaluate("//ul[@class='commentsul']", document, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
                        var uls = new Array();
                        var ul  = null;
                        //tranferer les éléments trouvés dans un tableau.
                        for (var i = 0; ul = elements.iterateNext(); i++)
                        {
                                uls[i] = ul;
                        }

                        var before = null;
                        var previous = null;
                        for (var i = 0; i < uls.length; i++)
                        {
                                previous = uls[i].previousSibling;
                                while (previous.nodeName == "#text")
                                {
                                        previous = previous.previousSibling;
                                }

                                if (previous.nodeName == "UL")
                                {
                                        //Selectionner le premier H1 à partir du premier enfant de cet UL. J'utilise une expression xPath car
                                        // apparement le Html de LinuxFR a tendance à évoluer. Donc un accés relatif comme avant (avec des numéros
                                        // d'index dans les enfants, par exemple uls[i].firstChild.childNodes[5]) rendait le code trop dépendant des
                                        // modifications du code.
                                        before = document.evaluate("./h1", uls[i].firstChild, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue.firstChild;
                                        before.parentNode.insertBefore(getPapaBlock(uls[i]), before);
                                }
                        }
                }
                catch (ex)
                {
                        GM_log(ex);
                }
})();
[1] Ce n’est pas un avis négatif sur l’utilisation de GreaseMonkey, juste qu’il faut faire attention à ce que l’on fait avec
[2] désolé, je n’ai pas réussi à expliquer ceci plus simplement
[3] Oui oui, il faut arrêter FireFox - toutes les instances lancées sous le même profil - et le relancer