Ми з тобою зараз як секретні агенти — наші функції та процедури виконують місії: обробляють дані, роблять обчислення або просто творять магію всередині бази. Але як дізнатися, якщо щось піде не так? Як зрозуміти, на якому етапі зламалась "масажна ванночка для даних"? Тут на допомогу приходять логування та обробка помилок.
Пам’ятаєш, ми вже починали знайомитись із тим, як у PostgreSQL та PL/pgSQL можна "спілкуватися" і вести логи:
RAISE NOTICE: спокійний, дружній тон — "Гей, тут все ок, але, може, захочеш глянути на це".RAISE WARNING: тон трохи гучніше — "Ой, тут щось дивне, може, зазирни".RAISE EXCEPTION: панічна сирена — "СТОП! Алгоритм у біді! Ми зупинили виконання, щоб все не пішло шкереберть".
Кожен із цих рівнів має своє призначення, і важливо правильно обирати, який із них використовувати.
Ось як ці повідомлення виглядають у коді:
DO $$
BEGIN
-- Рівень NOTICE (все нормально, просто повідомлення)
RAISE NOTICE 'Просто повідомлення: почалась обробка даних';
-- Рівень WARNING (щось підозріле)
RAISE WARNING 'Попередження: формат даних у стовпці може бути некоректним';
-- Рівень EXCEPTION (критична помилка)
RAISE EXCEPTION 'Помилка: вхідне значення недопустиме!';
END $$;
Коли використовувати:
RAISE NOTICE— для відладки та спокійного виводу інформації.RAISE WARNING— щоб попередити про потенційно некоректні дані.RAISE EXCEPTION— коли трапляються критичні помилки, через які виконання функції треба зупинити.
Обробка помилок з RAISE EXCEPTION
RAISE EXCEPTION — це твій стоп-кран. Якщо щось іде не так, ти зможеш зупинити виконання функції й повідомити про помилку.
Нагадаю, базове використання виглядає так:
RAISE EXCEPTION 'Твоє повідомлення про помилку';
Але щоб зробити повідомлення більш інформативними, можна використовувати змінні:
DECLARE
input_value INTEGER;
BEGIN
input_value := NULL;
IF input_value IS NULL THEN
RAISE EXCEPTION 'Помилка: вхідне значення NULL. Очікувалось значення INTEGER';
END IF;
END;
Форматування повідомлень
Ти можеш підставляти змінні прямо в текст повідомлення:
DECLARE
var1 TEXT := 'Дані';
var2 INTEGER := 42;
BEGIN
RAISE EXCEPTION 'Помилка при обробці % з ID %', var1, var2;
END;
Вивід: Помилка при обробці Дані з ID 42.
Приклад: валідація даних
Уяви, що у тебе є процедура, яка приймає вік людини. Якщо вік від’ємний, логічно викликати помилку:
CREATE OR REPLACE FUNCTION validate_age(age INTEGER)
RETURNS VOID AS $$
BEGIN
IF age < 0 THEN
RAISE EXCEPTION 'Вік не може бути від’ємним: %', age;
END IF;
END;
$$ LANGUAGE plpgsql;
-- Виклик функції
SELECT validate_age(-5); -- Викличе помилку
Інформування з RAISE NOTICE
Якщо RAISE EXCEPTION — це сирена, то RAISE NOTICE — це дружнє поплескування по плечу. За допомогою цього рівня можна додавати коментарі для розуміння того, що відбувається всередині функції.
Коли використовувати RAISE NOTICE:
- Вивід відладочної інформації (наприклад, поточний стан змінних).
- Повідомлення про початок виконання етапу або результат обчислень.
Приклад: інформаційні повідомлення
CREATE OR REPLACE FUNCTION calculate_discount(price NUMERIC, discount_rate NUMERIC)
RETURNS NUMERIC AS $$
DECLARE
final_price NUMERIC;
BEGIN
RAISE NOTICE 'Ціна перед знижкою: %', price;
RAISE NOTICE 'Ставка знижки: %', discount_rate;
final_price := price - (price * discount_rate);
RAISE NOTICE 'Підсумкова ціна: %', final_price;
RETURN final_price;
END;
$$ LANGUAGE plpgsql;
-- Виклик функції
SELECT calculate_discount(100, 0.2);
-- Виведе:
-- NOTICE: Ціна перед знижкою: 100
-- NOTICE: Ставка знижки: 0.2
-- NOTICE: Підсумкова ціна: 80
Практичне застосування: планування та логування
Припустимо, у тебе є складна процедура обробки даних, і ти хочеш знати, на якому етапі вона зараз знаходиться:
CREATE OR REPLACE FUNCTION process_data_step_by_step()
RETURNS VOID AS $$
BEGIN
RAISE NOTICE 'Крок 1: Підготовка даних';
-- Твоя логіка для першого етапу
RAISE NOTICE 'Крок 2: Валідація даних';
-- Твоя логіка для другого етапу
RAISE NOTICE 'Крок 3: Збереження даних';
-- Твоя логіка для третього етапу
END;
$$ LANGUAGE plpgsql;
-- Виклик функції
SELECT process_data_step_by_step();
-- У логах відобразиться покрокове виконання
Наведемо ще один приклад. Давай уявимо магазин, який пропонує знижки тільки для замовлень вище певної суми:
CREATE OR REPLACE FUNCTION apply_discount(order_amount NUMERIC)
RETURNS NUMERIC AS $$
BEGIN
IF order_amount < 50 THEN
RAISE EXCEPTION 'Помилка: сума замовлення має бути не менше 50, поточна сума: %', order_amount;
END IF;
RETURN order_amount * 0.9; -- Застосовуємо 10% знижку
END;
$$ LANGUAGE plpgsql;
-- Виклик функції
SELECT apply_discount(30); -- Помилка: сума замовлення має бути не менше 50
Типові помилки
Помилка 1: логування повідомлень без параметрів.
Виглядає неінформативно, особливо у великих процедурах:
RAISE NOTICE 'Сталася помилка'; -- Чому? Де? Як?
Рекомендація: завжди додавай контекст:
RAISE NOTICE 'Помилка у функції process_data(): вхідне значення: %', input_value;
Помилка 2: використання RAISE EXCEPTION там, де достатньо RAISE WARNING.
Якщо ти перестараєшся з виключеннями, код буде перериватися з будь-якого приводу, що ускладнить обробку даних.
Порада: використовуй рівні логування свідомо. Для відладки обирай NOTICE, а для критичних моментів — EXCEPTION.
Помилка 3: відсутність логування взагалі.
Це як шукати ключі у темній кімнаті. Без логів відладка складних процесів стає майже неможливою.
Порада: додавай RAISE NOTICE на ключових етапах виконання функції, особливо якщо вона велика і складна.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ