- •Работа №4 функции, определенные пользователем
- •1Типы функций PostgreSql
- •2ХранимыЕ процедурЫ
- •2.1Создание хранимых процедур
- •2.2Использование параметров в хранимых процедурах
- •Входные параметры
- •Выходные параметры
- •Задания для самостоятельной работы
- •II. Pl/pgSql-функции
- •2.3 Создание pl/pgSql-функции
- •Объявления переменных
- •Операторы управления программой
- •2.4 Обработка ошибок в pl/pgSql-функциях
- •3Триггеры
- •Задания для самостоятельной работы
- •Контрольное задание
- •Контрольные вопросы
2.4 Обработка ошибок в pl/pgSql-функциях
Ошибки, возникающие при выполнении команд в блоке, отслеживаются с помощью предложения EXCEPTION, синтаксис котрого имеет вид:
BEGIN
… ; -- тело блока
EXCEPTION
WHEN условие [ OR условие ... ] THEN
обработчик_исключения
[ WHEN условие [ OR условие... ] THEN
обработчик_исключения
... ]
END;
Если возникает ошибка, то выполнение команд в блоке прерывается и управление передается в раздел EXCEPTION, где производится поиск первого из условий, удовлетворяющих возникшей ошибке, и запускается соответствующий обработчик. После чего управление передается следующей после END команде. Если ни одно из условий не удовлетворяет ошибке, обработка исключения передается первому из объемлющих блоков, в котором есть раздел EXCEPTION. Если такого блока нет, выполнение функции останавливается и выводится сообщение об ошибке. Список кодов ошибок приведен в документации к PostgreSQL в Приложении А.
Для отслеживания ошибок при выполнении команд SQL в PostgreSQL можно использовать специальную системную переменную FOUND типа boolean. Эта переменная является локальной и меняет исходное значение false на true в следующих случаях:
SELECT, UPDATE, INSERT, DELETE если хотя бы одна строка включается в результат, т.е. выбирается, модифицируется, вставляется или удаляется;
FOR если выполняется хотя бы одна итерация цикла;
RETURN QUERY, RETURN QUERY EXECUTE если запрос возвращает хотя бы одну строку.
Примеры
/* Добавление строки в таблицу Доставка БД BookShop */
DROP TABLE "Доставка";
CREATE TABLE "Доставка"
( "Заказ" bigint NOT NULL,
"Курьер" character varying(40) DEFAULT 'foo'::character varying,
"Дата_время" timestamp without time zone DEFAULT now(),
"Доставлен" boolean DEFAULT false,
CONSTRAINT "PK_delivery" PRIMARY KEY ("Заказ") );
CREATE FUNCTION insert_delivery( order_id bigint, courier character varying, date_time timestamp without time zone)
RETURNS VOID AS
$$ BEGIN
INSERT INTO “Доставка” ("Заказ", "Курьер" , "Дата_время") VALUES ($1,$2,$3);
RETURN;
/* нарушение ограничения уникальности для первичного ключа*/
EXCEPTION WHEN unique_violation THEN
LOOP
UPDATE “Доставка” SET "Курьер" = $2, "Дата_время" = $3
WHERE "Заказ" = $1;
IF FOUND THEN RETURN;
END LOOP;
END; $$
LANGUAGE plpgsql;
В PostgreSQL не предусмотрен специальный отладчик процедурных функций, поэтому для отладки в таких случаях обычно используют операторы вывода сообщений об ошибках и переменные состояния.
3Триггеры
Триггеры – это специальный тип функций, которые выполняются автоматически при выполнении инструкций языка манипулирования данными (INSERT, UPDATE, DELETE). Триггеры обычно используются для внесения каскадных изменений в связанные таблицы или для выполнения сложных ограничений, которые нельзя реализовать стандартными средствами SQL.
Триггеры делятся на два вида: триггеры (FOR EACH ROW), вызываемые для каждой из строк, участвующих в операции, и триггеры (FOR EACH STATEMENT), которые вызываются один раз для каждой операции. Триггеры также могут вызываться до (before-триггеры) начала выполнения операции и после (after-триггеры).
Триггеры создаются с помощью команды CREATE TRIGGER, в которой указывается, какая функция будет выполняться при вызове триггера. Эти функции могут создаваться на любом из поддерживаемых процедурных языков, например, на PL/pgSQL. Они должны быть определены без параметров и с возвращаемым значением типа trigger. Когда такая функция запускается на исполнение, в ее основном блоке (блок самого верхнего уровня) создаются несколько переменных, в которых фиксируются параметры соответствующего триггера, и две буферные переменные:
NEW переменная типа RECORD, в которой содержится новая строка для INSERT/UPDATE-триггеров типа FOR EACH ROW или значение NULL для триггеров типа FOR EACH STATEMENT и для INSERT/UPDATE-триггеров типа FOR EACH ROW;
OLD переменная типа RECORD, в которой содержится старая строка для UPDATE/DELETE-триггеров типа FOR EACH ROW или значение NULL для триггеров типа FOR EACH STATEMENT и для INSERT-триггеров типа FOR EACH ROW.
Примеры:
/* Создаем таблицу */
CREATE TABLE emp (
a text NOT NULL,
b integer NOT NULL CHECK (b>0),
last_date timestamp,
last_user text );
/* Создаем триггерную функцию */
CREATE FUNCTION stamp() RETURNS trigger AS
$stamp$
BEGIN
-- Проверка a= null и b= null и b>0'
IF NEW.a IS NULL THEN
RAISE EXCEPTION 'a не может бать null !';
END IF;
IF NEW.b IS NULL THEN
RAISE EXCEPTION ' b не может бать null ! ', NEW.a;
END IF;
IF NEW.b < 0 THEN
RAISE EXCEPTION ‘ b = % должно быть положительным !', NEW.b;
END IF;
-- Заносим в таблицу текущее время и текущего пользователя
NEW.last_date := current_timestamp;
NEW.last_user := current_user;
RETURN NEW;
END;
$stamp$ LANGUAGE plpgsql;
/ * Создаем тригер */
CREATE TRIGGER stamp BEFORE INSERT OR UPDATE ON emp
FOR EACH ROW EXECUTE PROCEDURE stamp();