Aller au contenu

MySQL/Débogage

Un livre de Wikilivres.

Comme vu précédemment dans la description de la base "mysql", il peut être utile d'activer les logs sur l'historique des requêtes lors du débogage d'une application qui utilise MySQL.

Gestion des exceptions

[modifier | modifier le wikicode]

En MySQL, les anomalies du type "division par zéro" ne renvoient pas d'erreur mais NULL.

Toutefois il est possible de lever des exceptions lors des manipulations de table, par exemple pour éviter qu'une liste d'insertions s'arrête au milieu à cause d'une contrainte d'unicité. L'exemple ci-dessous fonctionne sur une table InnoDB (et pas MyISAM)[1] :

ALTER TABLE `MaTable1` ADD UNIQUE(`id`);

INSERT INTO MaTable1 (id) VALUES('1');
START TRANSACTION;
      INSERT INTO MaTable1 (id) VALUES('2');
      INSERT INTO MaTable1 (id) VALUES('3');
      INSERT INTO MaTable1 (id) VALUES('1');
IF condition THEN
  COMMIT;
ELSE
  ROLLBACK;
END IF;

Ici une erreur surgit lors de la deuxième insertion d'un id=1. Selon une condition, on peut donc annuler les insertions de 2 et 3, ou bien les soumettre.

 Par défaut, MySQL est en autocommit, cela signifie qu'un COMMIT est automatiquement effectué après chaque opération (rendant inutile les ROLLBACK). Pour le désactiver, lancer SET autocommit = 0;

Logo

S'il y a plusieurs COMMIT avant un ROLLBACK (par exemple dans une boucle), ce dernier n'annulera que les opérations consécutives au dernier COMMIT.

A new statement was found, but no delimiter between it and the previous one

[modifier | modifier le wikicode]

Ajouter un ";".

Sinon avec "DELIMITER" : sans espace avant (donc consécutivement au retour chariot).

Access denied for user mon_compte@mon_hôte

[modifier | modifier le wikicode]
  • Vérifier le mot de passe du compte.
  • Vérifier que l'hôte du compte n'a pas été changé par une règle réseau.
    Si c'est le cas, tester en shell :
sudo mysql -h mon_hôte1 -u mon_compte
sudo mysql -h mon_hôte2 -u mon_compte
  • Sinon, recréer le droit avec :
GRANT ALL PRIVILEGES ON *.* TO 'mon_compte'@'mon_hôte2' IDENTIFIED BY PASSWORD 'mon_mot_de_passe_hashé';


Base table or view not found: 1146 Table 'xxx' doesn't exist" is not defined, use one of: 100, 200, 250, 300, 400, 500, 550, 600

[modifier | modifier le wikicode]

Une table temporaire n'est pas accessible, elle a peut-être été créée dans un autre thread : il faut la déplacer dans le même fichier.

BIGINT UNSIGNED value is out of range

[modifier | modifier le wikicode]

Se produit sur les opérations sur les grands nombres. On peut alors manipuler des nombres plus petits, par exemple en convertissant les octets en gigas dans le select.

Can't create table 'xxx' (errno: 150)

[modifier | modifier le wikicode]

Clé primaire invalide. Dans ce cas il vaut mieux séparer la création de la table puis l'ajout des contraintes en deux requêtes. Cela peut permettre par exemple de voir que les tables vers lesquelles pointent les contraintes doivent être créées avant ces dernières.

Can't connect to MySQL server

[modifier | modifier le wikicode]

Changer le paramètre "host".

Can't create federated table

[modifier | modifier le wikicode]

Le schéma de la table distante doit être le même que celui de la table locale.

Sinon, activer les logs sur le serveur distant pour voir le compte qui se connecte.

Can't create/write to file 'mon_dossier/mon_fichier.csv'

[modifier | modifier le wikicode]

Lors d'un SELECT INTO OUTFILE, si le compte du SGBD utilisé a les droits d'exportation (GRANT FILE ON .* TO 'mon_compte'@'%';), le problème est lié au compte MySQL de l'OS qui n'a pas accès au système de fichier. Comme généralement le compte "mysql" sur Linux n'a pas de shell, cela peut se confirmer ainsi :

su - -s /bin/bash mysql
touch mon_dossier/mon_fichier.csv

Si les droits manquent :

sudo chown -R mysql mon_dossier

Cannot add foreign key constraint

[modifier | modifier le wikicode]

Survient lors d'un "CREATE TABLE", et ce n'est pas lié à la valeur de foreign_key_checks.

En fait il ne faut pas créer de contrainte d'intégrité entre deux tables de moteur différent (ex : InnoDB vs MyISAM).

Cannot drop index 'UNIQ_XXX': needed in a foreign key constraint

[modifier | modifier le wikicode]

Il faut supprimer la clé étrangère avant l'index duquel elle dépend :

ALTER TABLE `maTable` DROP FOREIGN KEY `FK_XXX`;
ALTER TABLE `maTable` DROP INDEX `UNIQ_XXX`;

... check that it exists

[modifier | modifier le wikicode]

Ajouter IF EXISTS. Ex :

    DROP DATABASE IF EXISTS base_2;
    DROP TABLE IF EXISTS table_2;
    DROP TRIGGER IF EXISTS trigger_2;
    DROP EVENT IF EXISTS event_2;
 Sur MariaDB on peut aussi faire des IF EXISTS dans les ALTER TABLE. Ex :
    ALTER TABLE table_1 DROP IF EXISTS table_2_id;
    ALTER TABLE table_1 DROP FOREIGN KEY IF EXISTS table_1_ibfk_1;

Connection refused

[modifier | modifier le wikicode]

Si tous les utilisateurs de la base ont cette erreur, relancer le serveur MySQL.

Par contre, un utilisateur peut se loguer depuis PhpMyAdmin, ou en ligne de commande (mysql -u mon_user ma_base -p), mais pas depuis un DSN, si le serveur a un replica, vérifier sa configuration[2].

Data too long for column

[modifier | modifier le wikicode]

Si les données avec des caractères non ASCII étaient censées tenir dans le champ, on peut passer en mode strict : SET @@global.sql_mode= 'NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';

Toutefois cela ne préserve pas leur encodage Unicode. Le mieux est donc :

SET NAMES 'utf8';

Failed to open the referenced table

[modifier | modifier le wikicode]

Une clé étrangère tente d'être créée vers une table inexistante ou qui ne supporte pas les clés étrangères (ex : moteur MyISAM).

Foreign data src error

[modifier | modifier le wikicode]

Lors du create server, le compte renseigné n'existe pas.

Foreign key constraint is incorrectly formed

[modifier | modifier le wikicode]

Une clé étrangère n'est pas au même format que la colonne à laquelle elle fait référence. Par exemple si cette dernière n'existe pas ou si elle n'a pas le même type.

Got error 'invalid character range'

[modifier | modifier le wikicode]

L'utilisation de \- est parfois proscrite en regex (ou il faut l'échapper autrement ?).

Host 'example.com' is not allowed to connect to this MySQL server

[modifier | modifier le wikicode]

Dans le cas d'une connexion depuis un PC distant, le compte utilisé n'est pas autorisé. Il faut donc le configurer avec :

GRANT ALL PRIVILEGES ON *.* TO 'utilisateur'@'%' WITH GRANT OPTION;

au lieu ou en plus de :

GRANT ALL PRIVILEGES ON *.* TO 'utilisateur'@'localhost' WITH GRANT OPTION;

Illegal mix of collations

[modifier | modifier le wikicode]

Trois solutions :

  • ALTER TABLE pour changer la structure d'au moins une des deux tables jointes, pour uniformiser leur collation.
  • CAST(monChamp AS CHAR CHARACTER SET utf8).
  • CONVERT(monChamp USING utf8).

Invalid use of group function

[modifier | modifier le wikicode]
  • Dans le cas d'un SELECT, il conviendrait d'utiliser HAVING au lieu de WHERE pour modifier des enregistrements en fonction d'autres d'une sous-requête.
  • Pour un UPDATE ou un DELETE, les champs comparés par un IN ne sont peut-être pas du même type.

Integrity constraint violation: 1217 Cannot delete or update a parent row: a foreign key constraint fails

[modifier | modifier le wikicode]
  • En cas d'ajout de contrainte, il y a au moins un enregistrement qui ne peut pas être join avec la table cible.
  • En cas de suppression, il manque un "DROP FOREIGN KEY" avant un "DROP TABLE" ou un "DROP COLUMN". Pour les supprimer, l'utilisateur root n'a pas le droit de modifier directement directement la table "information_schema". Il faut donc exécuter les requêtes générées par la suivante :
SELECT concat('alter table ',table_schema,'.',table_name,' DROP FOREIGN KEY ',constraint_name,';')
FROM information_schema.table_constraints
WHERE constraint_type='FOREIGN KEY'
AND table_name='maTable';

La clé est trop longue. Longueur maximale: 1000

[modifier | modifier le wikicode]

Dans le cas d'un alter table général ou de plusieurs champs, décomposer la requête pour traiter les champs un par un afin d'isoler celui qui provoque l'erreur. Ensuite on peut la résoudre en réduisant la taille du varchar (ex : de 255 à 50 si possible).

Lock wait timeout exceeded; try restarting transaction

[modifier | modifier le wikicode]

Le serveur SQL est surchargé : exécuter les instructions une par une. Sinon :

 SET innodb_lock_wait_timeout = 120;

No such file or directory

[modifier | modifier le wikicode]

Remplacer "localhost" par 127.0.0.1.

Query execution was interrupted, max_execution_time exceeded

[modifier | modifier le wikicode]
SET GLOBAL MAX_EXECUTION_TIME = 1000; -- milisecondes

-- Dans MariaDB :
SET GLOBAL max_statement_time = 1; -- secondes

View ... references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them

[modifier | modifier le wikicode]

Temporairement on peut recréer la view sans "SQL SECURITY INVOKER".

Specified key was too long; max key length is 3072 bytes

[modifier | modifier le wikicode]

Se produit lors d'un ALTER vers un grand type comme "text". Exemple :

ALTER TABLE ma_table
CHANGE `mon_champ2` `mon_champ2` text COLLATE 'utf8_general_ci' NULL AFTER `mon_champ1`;

Solution :

ALTER TABLE ma_table
CHANGE `mon_champ2` `mon_champ2` varchar(1000) COLLATE 'utf8_general_ci' NULL AFTER `mon_champ1`;

Syntax error or access violation

[modifier | modifier le wikicode]

Utiliser phpMyAdmin pour trouver l'erreur de syntaxe.

Si cela survient après avoir collé une exportation de base, utiliser plutôt l'importation d'un .sql qui gère mieux les caractères d'échappement.

This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery'

[modifier | modifier le wikicode]

Remplacer les "IN" par des jointures, ou la sous-requête par une deuxième dont le résultat est stockée dans une table temporaire.

Too many tables (ou timeouts systématiques)

[modifier | modifier le wikicode]

Si des requêtes sont systématiquement en timeout, c'est peut-être que la limite de 61 jointures a été atteinte. Pour pallier cela, il est possible d'en remplacer certaines par des SELECT[3].

Type d'énoncé non reconnu

[modifier | modifier le wikicode]

Certains mots clés ne sont reconnus que dans les procédures stockées, ou doivent être précédés d'un SELECT.

Unexpected end of JSON text in argument 1 to function 'json_extract'

[modifier | modifier le wikicode]

Lever l'exception vide avec : if(x = "", null, json_extract(x, y)).

Unknown storage engine 'federated' mariadb

[modifier | modifier le wikicode]

Lancer "mysql" en shell puis taper :

install plugin federated soname 'ha_federated.so';

'utf8mb3' is deprecated and will be removed in a future release

[modifier | modifier le wikicode]

Pas besoin de changer chaque champ varchar ou text, il suffit de convertir la table :

ALTER TABLE ma_table CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;

You can't specify target table '...' for update in FROM clause

[modifier | modifier le wikicode]

Cela se produit quand on essaie de mettre à jour ou supprimer des lignes selon une sélection de ces mêmes lignes. En effet, il est impossible de mettre à jour une table pendant en même temps qu'elle une subit sous-requête. Par exemple, pour réinitialiser un mot de passe SPIP :

mysql> UPDATE spip_auteurs SET pass =
 (SELECT pass FROM spip_auteurs WHERE login='paul') where login='admin';
ERROR 1093 (HY000): You can't specify target table 'spip_auteurs' for update in FROM clause
  • Passer par des CREATE TEMPORARY TABLE (voire DECLARE si cela rentre dans une variable scalaire).
  • Sinon, il est possible de sélectionner les enregistrements à mettre à jour automatiquement en enveloppant la sous-requête dans une autre, grâce aux tables temporaires générées par les FROM[4].

You do not have the SUPER privilege and binary logging is enabled

[modifier | modifier le wikicode]
SET GLOBAL log_bin_trust_function_creators = 1;

Les résultats sont tronqués

[modifier | modifier le wikicode]

Cliquer sous la requête à exécuter dans "Options supplémentaires", puis "Textes complets".

Erreur : fonctionnalités relationnelles désactivées !

[modifier | modifier le wikicode]

Se produit dans le concepteur de diagramme de phpMyAdmin, il faut l'activer dans config.inc.php.