2008-08-13
Скачать функции изменения типа ENUM "на лету":
dklab_postgresql_enum_2009-02-26.sql
Как установить
Это просто: скачайте, распакуйте и запустите как обычный SQL-скрипт. В вашей базе данных
появится новая схема с именем "enum"; она содержит все необходимые функции.
Постановка проблемы
Хорошо известно, что конструкции ALTER TYPE для удобного типа ENUM PostgreSQL 8.3 отсутствует
(а в 9.1 ALTER для ENUM не работает внутри транзакции). Таким образом, вы можете написать:
Листинг 1
|
CREATE TYPE my_enum AS ENUM('first', 'second'); |
но после этого не имеете возможности добавить новый элемент в данный ENUM, если на тип ссылается
некоторая таблица. И даже если на какой-то элемент my_enum нет внешних ссылок,
вы все равно не можете его удалить стандартными средствами.
В PostgreSQL 9.1+ существует оператор "ALTER TYPE my_enum ADD VALUE 'new_value'", однако он не работает
внутри транзакции, что делает его почти бессмысленным в системах миграции. Удаления элемента из ENUM-а
также не существует.
Примеры использования: enum_add() и enum_del()
Предлагаемое решение состоит из двух функций, которые позволяют добавлять и удалять элементы
в ENUM, производя при этом все необходимые проверки целостности базы данных.
Вот несколько примеров их использования.
-- Создаем тип ENUM и ссылающуюся на него таблицу.
CREATE TYPE my_enum AS ENUM('first', 'second');
CREATE TABLE my_table(id INTEGER, my my_enum);
-- Вставляем тестовые данные в таблицу.
INSERT INTO my_table(id, my) VALUES(1, 'second');
-- Добавляем новый элемент в ENUM "на лету".
SELECT enum.enum_add('my_enum', 'third');
-- Удаляем элемент из ENUM "на лету".
SELECT enum.enum_del('my_enum', 'first');
Видите, мы можем удалять элементы из my_enum, если на них отсутствуют ссылки
во всех таблицах базы данных. Давайте теперь посмотрим, что произойдет, если мы
попробуем удалить элемент 'second', на который ссылается строка таблицы my_table:
-- Удаляем элемент из ENUM "на лету".
SELECT enum.enum_del('my_enum', 'first');
! ERROR: Cannot delete the ENUM element my_enum.second: column public.my_table.my contains references
Итак, целостность базы данных не нарушается, когда мы удаляем элемент из ENUM.
|
Чтобы добиться максимальной производительности от enum_del() для типа ENUM,
вы должны создать во всех таблицах индексы на колонки, ссылающиеся на этот ENUM.
|
|
|
|