Oggi analizziamo gli errori tipici che si fanno quando si creano funzioni, perché succedono e come risolverli. Solo facendo debug si diventa veri maestri del mestiere — il coding! Let's debug it!
Creare funzioni, soprattutto quando si inizia a studiare PL/pgSQL, può sembrare una roba complicata. Anche i dev più esperti su PostgreSQL ci cascano ogni tanto. Vediamoli uno per uno.
1. Dimenticare la parola chiave RETURNS
PL/pgSQL è super rigido su come descrivi le funzioni. Uno degli errori più comuni è dimenticare di specificare il tipo di dato che la funzione deve restituire. Guarda qui:
-- Errore: manca la parola chiave RETURNS
CREATE FUNCTION incorrect_function() AS $$
BEGIN
RETURN 1;
END;
$$ LANGUAGE plpgsql;
PostgreSQL non capisce cosa dovrebbe restituire questa funzione. RETURNS è obbligatorio e serve a dire che tipo di dato torna (tipo RETURNS INT, RETURNS TEXT o anche RETURNS VOID).
Soluzione: aggiungi la parola chiave RETURNS con il tipo di dato:
CREATE FUNCTION correct_function() RETURNS INT AS $$
BEGIN
RETURN 1;
END;
$$ LANGUAGE plpgsql;
2. Restituire un risultato senza RETURN
Chi inizia spesso si dimentica che in PL/pgSQL, per restituire qualcosa, bisogna usare proprio l’operatore RETURN. Ecco un esempio:
-- Errore: manca RETURN
CREATE FUNCTION missing_return() RETURNS TEXT AS $$
BEGIN
'Ciao, Mondo!'; -- Solo una stringa, ma non restituita
END;
$$ LANGUAGE plpgsql;
Qui la stringa 'Ciao, Mondo!' è solo scritta, ma non viene restituita. PostgreSQL lo vede come un risultato non raggiunto e lancia errore.
Soluzione: aggiungi l’operatore RETURN esplicitamente:
CREATE FUNCTION fixed_return() RETURNS TEXT AS $$
BEGIN
RETURN 'Ciao, Mondo!';
END;
$$ LANGUAGE plpgsql;
3. Provare a scrivere dati in una variabile non dichiarata
In PL/pgSQL, prima di usare una variabile, la devi dichiarare nel blocco DECLARE. Tipo così:
-- Errore: variabile my_var non dichiarata
CREATE FUNCTION missing_variable() RETURNS VOID AS $$
BEGIN
my_var := 'Ciao, Mondo!';
END;
$$ LANGUAGE plpgsql;
PostgreSQL non sa che esiste la variabile my_var, perché non è stata dichiarata nel blocco DECLARE.
Soluzione: dichiara sempre le variabili in DECLARE:
CREATE FUNCTION declared_variable() RETURNS VOID AS $$
DECLARE
my_var TEXT;
BEGIN
my_var := 'Ciao, Mondo!';
END;
$$ LANGUAGE plpgsql;
4. Uso sbagliato del tipo di ritorno VOID
Il tipo VOID vuol dire che la funzione non restituisce niente. A volte si prova a usare RETURN in funzioni con tipo VOID, e questo crea errori:
-- Errore: RETURN in funzione con VOID
CREATE FUNCTION void_example() RETURNS VOID AS $$
BEGIN
RETURN 1; -- Restituire un valore non va bene
END;
$$ LANGUAGE plpgsql;
Le funzioni con tipo di ritorno VOID non devono restituire valori. Puoi usare RETURN, ma senza valore.
Soluzione: o togli RETURN, oppure lascialo senza valore:
CREATE FUNCTION correct_void() RETURNS VOID AS $$
BEGIN
-- Facciamo solo delle azioni
RAISE NOTICE 'Questa funzione non restituisce niente';
RETURN; -- Fine funzione
END;
$$ LANGUAGE plpgsql;
5. Uso sbagliato di RAISE per il debug
Per fare debug in PL/pgSQL si usa spesso RAISE NOTICE. Ma se sbagli formato o variabili, arrivano errori.
Esempio:
-- Errore: formato sbagliato
CREATE FUNCTION debug_example() RETURNS VOID AS $$
BEGIN
RAISE NOTICE 'Il valore è %'; -- Variabile mancante
END;
$$ LANGUAGE plpgsql;
L’operatore RAISE si aspetta che dopo % ci sia una variabile o un valore. Se lasci % da solo, PostgreSQL non sa che fare.
Soluzione: assicurati che variabili o valori siano messi giusti:
CREATE FUNCTION fixed_debug() RETURNS VOID AS $$
DECLARE
my_var TEXT := 'PostgreSQL';
BEGIN
RAISE NOTICE 'Il valore è %', my_var; -- Variabile inserita
END;
$$ LANGUAGE plpgsql;
6. Problemi con nomi di variabili e colonne
Se il nome di una variabile è uguale a quello di una colonna, possono succedere cose strane. Tipo così:
-- Errore: conflitto tra nome variabile e colonna
CREATE FUNCTION name_conflict() RETURNS TEXT AS $$
DECLARE
name TEXT;
BEGIN
SELECT name INTO name FROM students LIMIT 1; -- Quale name viene usato?
RETURN name;
END;
$$ LANGUAGE plpgsql;
PL/pgSQL dà priorità alle variabili rispetto ai nomi delle colonne se coincidono.
Soluzione: usa alias per le tabelle o evita nomi uguali.
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. Esecuzione sbagliata di query nei cicli
Gli errori capitano spesso quando si prova a fare query SQL dentro i cicli. Tipo così:
-- Errore: query sbagliata dentro il ciclo
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... Pericolo! Concatenare stringhe per le query SQL è una brutta pratica. Così rischi vulnerabilità.
Per risolvere, usa i parametri:
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. Errori con i tipi di dati
Esempio di errore:
-- Errore: tipi di dati non corrispondenti
CREATE FUNCTION type_error() RETURNS INT AS $$
DECLARE
my_var TEXT := 'non_un_numero';
BEGIN
RETURN my_var; -- Errore restituendo testo invece di INT
END;
$$ LANGUAGE plpgsql;
PostgreSQL si aspetta INT, ma riceve TEXT. I tipi di dati devono sempre combaciare.
Come risolvere? Assicurati che i tipi siano giusti, oppure fai una conversione esplicita:
CREATE FUNCTION type_correct() RETURNS INT AS $$
DECLARE
my_var TEXT := '42';
BEGIN
RETURN my_var::INT; -- Conversione da testo a numero
END;
$$ LANGUAGE plpgsql;
Best practice e consigli
- Dividi le funzioni complesse in più piccole. Così il debug e i test sono più facili.
- Usa i commenti dentro le funzioni per spiegare le parti complicate.
- Testa sempre le funzioni su pochi dati prima di usarle sulle tabelle vere.
- Fai debug con
RAISE NOTICE, così capisci cosa succede passo passo. - Evita le SQL-injection: usa i parametri nelle query.
-- Uso di RAISE per il debug
DO $$
DECLARE
total_students INT;
BEGIN
SELECT COUNT(*) INTO total_students FROM students;
RAISE NOTICE 'Studenti totali: %', total_students; -- Messaggio di debug
END;
$$;
Questi consigli ti risparmieranno un sacco di mal di testa e ti faranno evitare per sempre le "trappole" di PL/pgSQL!
GO TO FULL VERSION