PERFORM в мире PostgreSQL — это такой суровый молчаливый герой, который приходит, делает своё дело и исчезает, не оставляя после себя никаких следов в виде возвращаемых данных. Эта команда используется, когда вы хотите выполнить SQL-запрос внутри функции PL/pgSQL, но вам не нужно обрабатывать или сохранять результат. Основная задача PERFORM — вызвать запрос, чтобы что-то произошло, например, модификация данных или вызов другой функции, а не получение результата.
PERFORM используется в тех случаях, когда результат запроса нам не нужен. В отличие от обычного SELECT, который ждёт, что вы что-то с этим результатом сделаете, PERFORM просто запускает запрос и молча идёт дальше. Это особенно удобно, если вы вызываете функцию ради её действия, а не ради того, что она вернёт. Например, чтобы записать что-то в лог. Такой подход делает код проще и понятнее: меньше лишнего, больше смысла.
Примеры использования PERFORM
Вызов функций
Давайте разберёмся с реальным примером. Представьте, что у нас есть функция log_action, которая записывает информацию о действиях пользователя в логи. Эта функция ничего не возвращает, и мы просто хотим, чтобы она сработала. Вот как это делается с 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;
-- Далее мы используем PERFORM для вызова этой функции:
PERFORM log_action(5, 'User logged in');
Что здесь происходит? Команда PERFORM вызывает функцию log_action, которая вносит запись в таблицу logs. Убедитесь, что вы понимаете: результат вызова функции игнорируется. Мы используем её исключительно из-за её эффекта, а не ради возвращения значений.
Обновление данных
Иногда PERFORM полезен, когда нужно выполнить запрос для изменения данных без заинтересованности в его результате. Например, обновим статус заказа в таблице 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;
-- Используем PERFORM для вызова этой функции:
PERFORM update_order_status(101, 'Shipped');
Здесь update_order_status обновляет статус заказа с идентификатором 101. Мы не интересуемся результатом SQL-запроса внутри функции, поэтому PERFORM — идеальный выбор.
Запуск вспомогательных операций
Иногда функции содержат мини-операции, сведённые к "вспомогательной" логике, которая помогает завершить сложный процесс. Допустим, мы хотим сбросить кэш после обновления таблицы:
CREATE OR REPLACE FUNCTION clear_cache() RETURNS VOID AS $$
BEGIN
DELETE FROM cache_table;
END;
$$ LANGUAGE plpgsql;
-- Вызываем её в другой функции:
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;
-- Сбрасываем кэш после изменения данных:
PERFORM clear_cache();
END;
$$ LANGUAGE plpgsql;
Вот в чём магия: вы можете последовательно выполнять действия, используя PERFORM для вызова функций, результат которых вам совершенно не нужен.
Практические задачи
Давайте разберём несколько примеров того, как PERFORM может облегчить жизнь разработчику.
Пример 1: логирование выполнения этапов процедуры
Допустим, у нас есть сложная процедура обработки платежей, и нам нужно отслеживать каждую её стадию, записывая это в лог. Мы можем определить функцию log_stage для записи информации, а затем использовать 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;
-- А вот пример процедуры:
CREATE OR REPLACE FUNCTION process_payment(payment_id INT) RETURNS VOID AS $$
BEGIN
-- Логирование начала
PERFORM log_stage('Start payment processing');
-- Выполняем первый этап
UPDATE payments
SET status = 'Processing'
WHERE id = payment_id;
PERFORM log_stage('Updated payment status');
-- Выполняем финальный этап
UPDATE payments
SET status = 'Completed'
WHERE id = payment_id;
PERFORM log_stage('Payment completed');
END;
$$ LANGUAGE plpgsql;
Здесь log_stage вызывается через PERFORM для записи состояния выполнения на каждом этапе процедуры. Это делает наш код легче для отладки.
Пример 2: активация уведомлений
Представьте, что у вас есть система уведомлений, и вам нужно отправлять уведомление после каждого важного действия. PERFORM может использоваться для вызова функции, отвечающей за это:
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;
-- Используем в процедуре:
CREATE OR REPLACE FUNCTION complete_task(task_id INT) RETURNS VOID AS $$
DECLARE
user_id INT;
BEGIN
-- Получаем автора задачи
SELECT assigned_to INTO user_id
FROM tasks
WHERE id = task_id;
-- Завершаем задачу
UPDATE tasks
SET status = 'Completed'
WHERE id = task_id;
-- Отправляем уведомление
PERFORM send_notification(user_id, 'Your task has been completed');
END;
$$ LANGUAGE plpgsql;
Здесь PERFORM позволяет сосредоточить внимание только на побочном эффекте — отправке уведомления, игнорируя результат выполнения функции.
Полезные советы и типичные ошибки
Когда вы используете PERFORM, важно помнить о некоторых особенностях. Например, PERFORM не проверяет, что запрос вернул данные. Это значит, что если результат функции или SQL-запроса важен для логики выполнения, лучше использовать SELECT INTO. Рассмотрим пример:
-- Потенциальная ошибка
PERFORM some_function_that_must_return_value();
-- Исправление
SELECT some_function_that_must_return_value() INTO some_variable;
Ещё одна частая ошибка — использование PERFORM там, где логически необходимо получить результат запроса, например, валидация данных. В таких случаях, конечно, лучше получать результат и проверять его.
В реальных проектах команда PERFORM помогает делать функции и процедуры проще, легче для чтения и отладки. В сочетании с логированием (RAISE NOTICE) и встроенными диагностическими функциями PostgreSQL, такими как current_query(), она становится важным инструментом для создания надёжных, управляемых и понятных систем.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ