Aujourd’hui, on va décortiquer les erreurs classiques quand tu crées des fonctions, pourquoi elles arrivent et comment les corriger. Parce que c’est en débuggant qu’on devient un vrai codeur — coding power ! Let's debug it !
Créer des fonctions, surtout quand tu débutes avec PL/pgSQL, ça peut sembler galère. Même les devs PostgreSQL expérimentés se prennent les pieds dans le tapis. On va les voir une par une.
1. Oublier le mot-clé RETURNS
PL/pgSQL est super strict sur la façon dont tu déclares tes fonctions. Une des erreurs les plus répandues, c’est d’oublier de préciser le type de données que la fonction doit renvoyer. Regarde :
-- Erreur : mot-clé RETURNS manquant
CREATE FUNCTION incorrect_function() AS $$
BEGIN
RETURN 1;
END;
$$ LANGUAGE plpgsql;
PostgreSQL ne peut pas deviner ce que ta fonction est censée retourner. RETURNS est obligatoire pour décrire le type de retour (genre RETURNS INT, RETURNS TEXT, ou même RETURNS VOID).
Correction : ajoute le mot-clé RETURNS avec le type de données :
CREATE FUNCTION correct_function() RETURNS INT AS $$
BEGIN
RETURN 1;
END;
$$ LANGUAGE plpgsql;
2. Retourner un résultat sans RETURN
Les débutants oublient souvent qu’en PL/pgSQL, pour renvoyer un résultat, il faut explicitement utiliser l’opérateur RETURN. Exemple :
-- Erreur : RETURN manquant
CREATE FUNCTION missing_return() RETURNS TEXT AS $$
BEGIN
'Hello, World!'; -- Juste une chaîne, mais pas renvoyée
END;
$$ LANGUAGE plpgsql;
Ici, la chaîne 'Hello, World!' est juste posée là, mais elle n’est pas renvoyée. PostgreSQL voit ça comme un résultat inatteignable et va râler.
Correction : mets un RETURN explicite :
CREATE FUNCTION fixed_return() RETURNS TEXT AS $$
BEGIN
RETURN 'Hello, World!';
END;
$$ LANGUAGE plpgsql;
3. Essayer d’assigner une valeur à une variable non déclarée
En PL/pgSQL, il faut déclarer ta variable dans le bloc DECLARE avant de l’utiliser. Exemple :
-- Erreur : variable my_var non déclarée
CREATE FUNCTION missing_variable() RETURNS VOID AS $$
BEGIN
my_var := 'Hello, World!';
END;
$$ LANGUAGE plpgsql;
PostgreSQL ne connaît pas la variable my_var car elle n’a pas été déclarée dans DECLARE.
Correction : déclare toujours tes variables dans DECLARE :
CREATE FUNCTION declared_variable() RETURNS VOID AS $$
DECLARE
my_var TEXT;
BEGIN
my_var := 'Hello, World!';
END;
$$ LANGUAGE plpgsql;
4. Mauvaise utilisation du type de retour VOID
Le type VOID veut dire que la fonction ne retourne rien. Parfois, on essaye quand même de faire un RETURN dans une fonction VOID, et ça plante :
-- Erreur : RETURN dans une fonction VOID
CREATE FUNCTION void_example() RETURNS VOID AS $$
BEGIN
RETURN 1; -- Retourner une valeur n’est pas permis
END;
$$ LANGUAGE plpgsql;
Les fonctions qui retournent VOID ne doivent pas renvoyer de valeur. Tu peux utiliser RETURN, mais sans rien après.
Correction : soit tu vires le RETURN, soit tu le laisses vide :
CREATE FUNCTION correct_void() RETURNS VOID AS $$
BEGIN
-- On fait juste des actions
RAISE NOTICE 'Cette fonction ne retourne rien';
RETURN; -- Fin de la fonction
END;
$$ LANGUAGE plpgsql;
5. Mauvaise utilisation de RAISE pour le debug
Pour débugger en PL/pgSQL, on utilise souvent RAISE NOTICE. Mais si tu te plantes dans le format ou les variables, ça coince.
Exemple :
-- Erreur : format incorrect
CREATE FUNCTION debug_example() RETURNS VOID AS $$
BEGIN
RAISE NOTICE 'La valeur est %'; -- Variable manquante
END;
$$ LANGUAGE plpgsql;
L’opérateur RAISE attend une variable ou une valeur après %. Si tu laisses % tout seul, PostgreSQL ne va pas aimer.
Correction : vérifie que tu passes bien une variable ou une valeur :
CREATE FUNCTION fixed_debug() RETURNS VOID AS $$
DECLARE
my_var TEXT := 'PostgreSQL';
BEGIN
RAISE NOTICE 'La valeur est %', my_var; -- Variable indiquée
END;
$$ LANGUAGE plpgsql;
6. Problèmes avec les noms de variables et de colonnes
Si le nom d’une variable est le même qu’une colonne, ça peut donner des résultats bizarres. Exemple :
-- Erreur : conflit de noms entre variable et colonne
CREATE FUNCTION name_conflict() RETURNS TEXT AS $$
DECLARE
name TEXT;
BEGIN
SELECT name INTO name FROM students LIMIT 1; -- Quel name est utilisé ?
RETURN name;
END;
$$ LANGUAGE plpgsql;
PL/pgSQL va préférer la variable si le nom est le même que la colonne.
Correction : utilise des alias pour les tables ou évite les doublons.
CREATE FUNCTION fixed_conflict() RETURNS TEXT AS $$
DECLARE
student_name TEXT;
BEGIN
SELECT s.name INTO student_name FROM students s LIMIT 1;
RETURN student_name;
END;
$$ LANGUAGE plpgsql;
7. Mauvaise exécution des requêtes dans une boucle
On fait souvent des erreurs quand on lance des requêtes SQL dans des boucles. Exemple :
-- Erreur : requête incorrecte dans la boucle
CREATE FUNCTION cycle_error() RETURNS VOID AS $$
BEGIN
FOR rec IN SELECT * FROM students LOOP
EXECUTE 'UPDATE students SET active = TRUE WHERE id = ' || rec.id;
END LOOP;
END;
$$ LANGUAGE plpgsql;
SQL-injection... Danger ! Faire de la concaténation de chaînes pour les requêtes SQL, c’est une mauvaise idée. Ça peut ouvrir des failles.
Pour corriger, utilise des paramètres :
CREATE FUNCTION safe_cycle() RETURNS VOID AS $$
BEGIN
FOR rec IN SELECT * FROM students LOOP
EXECUTE 'UPDATE students SET active = TRUE WHERE id = $1' USING rec.id;
END LOOP;
END;
$$ LANGUAGE plpgsql;
8. Erreurs de types de données
Exemple d’erreur :
-- Erreur : types de données incompatibles
CREATE FUNCTION type_error() RETURNS INT AS $$
DECLARE
my_var TEXT := 'not_a_number';
BEGIN
RETURN my_var; -- Erreur en renvoyant du texte au lieu d’un INT
END;
$$ LANGUAGE plpgsql;
PostgreSQL attend un INT, mais reçoit un TEXT. Les types de données sont vérifiés à fond.
Comment corriger ? Vérifie que les types correspondent, ou fais une conversion explicite :
CREATE FUNCTION type_correct() RETURNS INT AS $$
DECLARE
my_var TEXT := '42';
BEGIN
RETURN my_var::INT; -- Conversion du texte en nombre
END;
$$ LANGUAGE plpgsql;
Best practices et astuces
- Découpe les fonctions complexes en plus petites. Ça rend le debug et les tests plus simples.
- Commente dans tes fonctions pour expliquer les parties compliquées.
- Teste toujours tes fonctions sur des petites données avant de les lancer sur les vraies tables.
- Débugge avec
RAISE NOTICEpour suivre ce qui se passe. - Évite les SQL-injections : utilise des paramètres dans tes requêtes.
-- Utilisation de RAISE pour le debug
DO $$
DECLARE
total_students INT;
BEGIN
SELECT COUNT(*) INTO total_students FROM students;
RAISE NOTICE 'Nombre total d’étudiants : %', total_students; -- Message de debug
END;
$$;
Ces astuces vont t’éviter plein de prises de tête et t’aider à esquiver à jamais les "râteaux" de PL/pgSQL !
GO TO FULL VERSION