PERFORM en el mundo de PostgreSQL es como ese héroe silencioso y duro que llega, hace su trabajo y desaparece sin dejar rastro en forma de datos devueltos. Este comando se usa cuando quieres ejecutar una consulta SQL dentro de una función PL/pgSQL, pero no necesitas procesar ni guardar el resultado. El objetivo principal de PERFORM es lanzar la consulta para que pase algo, como modificar datos o llamar otra función, y no para obtener un resultado.
PERFORM se usa cuando el resultado de la consulta no nos interesa. A diferencia de un SELECT normal, que espera que hagas algo con el resultado, PERFORM simplemente ejecuta la consulta y sigue adelante en silencio. Esto es súper útil si llamas a una función solo por su efecto, no por lo que devuelve. Por ejemplo, para escribir algo en el log. Así el código es más simple y claro: menos cosas de relleno, más sentido.
Ejemplos de uso de PERFORM
Llamada a funciones
Vamos a ver un ejemplo real. Imagina que tienes una función log_action que guarda información sobre las acciones del usuario en los logs. Esta función no devuelve nada, y solo queremos que se ejecute. Así es como se hace 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;
-- Ahora usamos PERFORM para llamar a esta función:
PERFORM log_action(5, 'Usuario inició sesión');
¿Qué pasa aquí? El comando PERFORM llama a la función log_action, que mete un registro en la tabla logs. Ojo: el resultado de la función se ignora. La usamos solo por su efecto, no por lo que devuelve.
Actualización de datos
A veces PERFORM es útil cuando necesitas ejecutar una consulta para cambiar datos sin preocuparte por el resultado. Por ejemplo, vamos a actualizar el estado de un pedido en la tabla 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;
-- Usamos PERFORM para llamar a esta función:
PERFORM update_order_status(101, 'Enviado');
Aquí update_order_status actualiza el estado del pedido con id 101. No nos importa el resultado de la consulta SQL dentro de la función, así que PERFORM es la opción perfecta.
Ejecución de operaciones auxiliares
A veces las funciones tienen mini-operaciones, como lógica "auxiliar" que ayuda a terminar un proceso complicado. Por ejemplo, queremos limpiar la caché después de actualizar una tabla:
CREATE OR REPLACE FUNCTION clear_cache() RETURNS VOID AS $$
BEGIN
DELETE FROM cache_table;
END;
$$ LANGUAGE plpgsql;
-- La llamamos en otra función:
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;
-- Limpiamos la caché después de cambiar los datos:
PERFORM clear_cache();
END;
$$ LANGUAGE plpgsql;
Aquí está la magia: puedes ejecutar acciones en secuencia usando PERFORM para llamar funciones cuyo resultado no te importa para nada.
Ejercicios prácticos
Vamos a ver algunos ejemplos de cómo PERFORM puede hacerte la vida más fácil como desarrollador.
Ejemplo 1: loguear las etapas de una procedure
Imagina que tienes un procedure complicado para procesar pagos y necesitas registrar cada etapa en el log. Podemos definir una función log_stage para guardar la info y luego usar 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;
-- Y aquí va el procedure:
CREATE OR REPLACE FUNCTION process_payment(payment_id INT) RETURNS VOID AS $$
BEGIN
-- Loguear el inicio
PERFORM log_stage('Inicio del procesamiento de pago');
-- Primer paso
UPDATE payments
SET status = 'Procesando'
WHERE id = payment_id;
PERFORM log_stage('Estado del pago actualizado');
-- Paso final
UPDATE payments
SET status = 'Completado'
WHERE id = payment_id;
PERFORM log_stage('Pago completado');
END;
$$ LANGUAGE plpgsql;
Aquí log_stage se llama con PERFORM para guardar el estado de ejecución en cada etapa del procedure. Así el código es más fácil de depurar.
Ejemplo 2: activar notificaciones
Imagina que tienes un sistema de notificaciones y necesitas enviar una notificación después de cada acción importante. PERFORM puede usarse para llamar a la función encargada de eso:
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;
-- Usamos en el procedure:
CREATE OR REPLACE FUNCTION complete_task(task_id INT) RETURNS VOID AS $$
DECLARE
user_id INT;
BEGIN
-- Obtener el autor de la tarea
SELECT assigned_to INTO user_id
FROM tasks
WHERE id = task_id;
-- Completar la tarea
UPDATE tasks
SET status = 'Completada'
WHERE id = task_id;
-- Enviar notificación
PERFORM send_notification(user_id, 'Tu tarea ha sido completada');
END;
$$ LANGUAGE plpgsql;
Aquí PERFORM te permite centrarte solo en el efecto secundario —enviar la notificación— ignorando el resultado de la función.
Consejos útiles y errores típicos
Cuando uses PERFORM, hay que tener en cuenta algunas cosas. Por ejemplo, PERFORM no comprueba si la consulta devolvió datos. O sea, si el resultado de la función o consulta SQL es importante para la lógica, mejor usa SELECT INTO. Mira este ejemplo:
-- Error típico
PERFORM alguna_funcion_que_debe_devolver_valor();
-- Solución
SELECT alguna_funcion_que_debe_devolver_valor() INTO alguna_variable;
Otro error común es usar PERFORM donde realmente necesitas el resultado de la consulta, por ejemplo, para validar datos. En esos casos, claro, mejor obtener el resultado y comprobarlo.
En proyectos reales, el comando PERFORM ayuda a que las funciones y procedures sean más simples, fáciles de leer y de depurar. Si lo combinas con logs (RAISE NOTICE) y funciones de diagnóstico de PostgreSQL como current_query(), se vuelve una herramienta clave para crear sistemas fiables, controlables y claros.
GO TO FULL VERSION