PERFORM nel mondo PostgreSQL è tipo quell’eroe silenzioso e tosto che arriva, fa il suo lavoro e sparisce, senza lasciare tracce sotto forma di dati restituiti. Questo comando si usa quando vuoi eseguire una query SQL dentro una funzione PL/pgSQL, ma non ti interessa gestire o salvare il risultato. Il compito principale di PERFORM è lanciare una query per far succedere qualcosa, tipo modificare dati o chiamare un’altra funzione, non per ottenere un risultato.
PERFORM si usa quando il risultato della query non ci serve. Diversamente da un normale SELECT, che si aspetta che tu faccia qualcosa con il risultato, PERFORM semplicemente lancia la query e va avanti senza dire nulla. È super comodo se chiami una funzione solo per l’effetto che ha, non per quello che restituisce. Tipo, per scrivere qualcosa nei log. Questo approccio rende il codice più semplice e chiaro: meno roba inutile, più senso.
Esempi di utilizzo di PERFORM
Chiamata di funzioni
Vediamo un esempio reale. Immagina di avere una funzione log_action che scrive info sulle azioni dell’utente nei log. Questa funzione non restituisce nulla, e vogliamo solo che venga eseguita. Ecco come si fa con PERFORM:
CREATE OR REPLACE FUNCTION log_action(user_id INT, action TEXT) RETURNS VOID AS $$
BEGIN
INSERT INTO logs (user_id, action, log_time)
VALUES (user_id, action, NOW());
END;
$$ LANGUAGE plpgsql;
-- Poi usiamo PERFORM per chiamare questa funzione:
PERFORM log_action(5, 'Utente ha effettuato l\'accesso');
Cosa succede qui? Il comando PERFORM chiama la funzione log_action, che aggiunge una riga nella tabella logs. Occhio: il risultato della funzione viene ignorato. La usiamo solo per il suo effetto, non per i valori che restituisce.
Aggiornamento dei dati
A volte PERFORM è utile quando devi eseguire una query che modifica dati senza interessarti del risultato. Per esempio, aggiorniamo lo stato di un ordine nella tabella orders.
CREATE OR REPLACE FUNCTION update_order_status(order_id INT, new_status TEXT) RETURNS VOID AS $$
BEGIN
UPDATE orders
SET status = new_status
WHERE id = order_id;
END;
$$ LANGUAGE plpgsql;
-- Usiamo PERFORM per chiamare questa funzione:
PERFORM update_order_status(101, 'Spedito');
Qui update_order_status aggiorna lo stato dell’ordine con id 101. Non ci interessa il risultato della query SQL dentro la funzione, quindi PERFORM è perfetto.
Esecuzione di operazioni di supporto
A volte le funzioni contengono mini-operazioni, una sorta di logica "di supporto" che aiuta a completare un processo complesso. Supponiamo di voler svuotare la cache dopo aver aggiornato una tabella:
CREATE OR REPLACE FUNCTION clear_cache() RETURNS VOID AS $$
BEGIN
DELETE FROM cache_table;
END;
$$ LANGUAGE plpgsql;
-- La chiamiamo in un’altra funzione:
CREATE OR REPLACE FUNCTION update_product(product_id INT, new_price NUMERIC) RETURNS VOID AS $$
BEGIN
UPDATE products
SET price = new_price
WHERE id = product_id;
-- Svuotiamo la cache dopo aver cambiato i dati:
PERFORM clear_cache();
END;
$$ LANGUAGE plpgsql;
Ecco la magia: puoi eseguire azioni in sequenza usando PERFORM per chiamare funzioni di cui non ti interessa il risultato.
Esercizi pratici
Vediamo qualche esempio di come PERFORM può semplificare la vita a chi sviluppa.
Esempio 1: logging delle fasi di una procedura
Supponiamo di avere una procedura complessa per gestire i pagamenti, e vogliamo tracciare ogni fase scrivendola nei log. Possiamo definire una funzione log_stage per registrare le info, e poi usare PERFORM:
CREATE OR REPLACE FUNCTION log_stage(stage_name TEXT) RETURNS VOID AS $$
BEGIN
INSERT INTO process_logs(stage, log_time)
VALUES (stage_name, NOW());
END;
$$ LANGUAGE plpgsql;
-- Ecco un esempio di procedura:
CREATE OR REPLACE FUNCTION process_payment(payment_id INT) RETURNS VOID AS $$
BEGIN
-- Logging dell'inizio
PERFORM log_stage('Inizio elaborazione pagamento');
-- Prima fase
UPDATE payments
SET status = 'In elaborazione'
WHERE id = payment_id;
PERFORM log_stage('Stato pagamento aggiornato');
-- Fase finale
UPDATE payments
SET status = 'Completato'
WHERE id = payment_id;
PERFORM log_stage('Pagamento completato');
END;
$$ LANGUAGE plpgsql;
Qui log_stage viene chiamata tramite PERFORM per registrare lo stato di avanzamento ad ogni fase della procedura. Così il codice è più facile da debuggare.
Esempio 2: attivazione delle notifiche
Immagina di avere un sistema di notifiche e di dover inviare una notifica dopo ogni azione importante. PERFORM può essere usato per chiamare la funzione che se ne occupa:
CREATE OR REPLACE FUNCTION send_notification(user_id INT, message TEXT) RETURNS VOID AS $$
BEGIN
INSERT INTO notifications (user_id, message, created_at)
VALUES (user_id, message, NOW());
END;
$$ LANGUAGE plpgsql;
-- Usiamo nella procedura:
CREATE OR REPLACE FUNCTION complete_task(task_id INT) RETURNS VOID AS $$
DECLARE
user_id INT;
BEGIN
-- Prendiamo l'autore del task
SELECT assigned_to INTO user_id
FROM tasks
WHERE id = task_id;
-- Completiamo il task
UPDATE tasks
SET status = 'Completato'
WHERE id = task_id;
-- Inviamo la notifica
PERFORM send_notification(user_id, 'Il tuo task è stato completato');
END;
$$ LANGUAGE plpgsql;
Qui PERFORM ti permette di concentrarti solo sull’effetto collaterale — inviare la notifica — ignorando il risultato della funzione.
Consigli utili ed errori tipici
Quando usi PERFORM, ricorda alcune cose. Per esempio, PERFORM non controlla se la query ha restituito dati. Quindi, se il risultato della funzione o della query SQL è importante per la logica, meglio usare SELECT INTO. Guarda qui:
-- Possibile errore
PERFORM some_function_that_must_return_value();
-- Corretto
SELECT some_function_that_must_return_value() INTO some_variable;
Un altro errore comune è usare PERFORM dove invece serve davvero il risultato della query, tipo per validare dati. In questi casi, ovviamente, meglio prendere il risultato e controllarlo.
Nei progetti reali il comando PERFORM aiuta a rendere funzioni e procedure più semplici, leggibili e facili da debuggare. Insieme al logging (RAISE NOTICE) e alle funzioni diagnostiche integrate di PostgreSQL, come current_query(), diventa uno strumento importante per creare sistemi affidabili, gestibili e chiari.
GO TO FULL VERSION