5.13. Отслеживание зависимостей

Когда вы создаёте сложные структуры баз данных, включающие множество таблиц с внешними ключами, представлениями, триггерами, функциями и т. п., вы неявно создаёте сеть зависимостей между объектами. Например, таблица с ограничением внешнего ключа зависит от таблицы, на которую она ссылается.

Для сохранения целостности структуры всей базы данных, PostgreSQL не позволяет удалять объекты, от которых зависят другие. Например, попытка удалить таблицу products (мы рассматривали её в Подразделе 5.3.5), от которой зависит таблица orders, приведёт к ошибке примерно такого содержания:

DROP TABLE products;

ОШИБКА:  удалить объект "таблица products" нельзя, так как от него зависят другие
ПОДРОБНОСТИ:  ограничение orders_product_no_fkey в отношении "таблица orders" зависит от объекта "таблица products"
ПОДСКАЗКА:  Для удаления зависимых объектов используйте DROP ... CASCADE.

Сообщение об ошибке даёт полезную подсказку: если вы не хотите заниматься ликвидацией зависимостей по отдельности, можно выполнить:

DROP TABLE products CASCADE;

и все зависимые объекты, а также объекты, зависящие от них, будут удалены рекурсивно. В этом случае таблица orders останется, а удалено будет только её ограничение внешнего ключа. Удаление не распространится на другие объекты, так как ни один объект не зависит от этого ограничения. (Если вы хотите проверить, что произойдёт при выполнении DROP ... CASCADE, запустите DROP без CASCADE и прочитайте ПОДРОБНОСТИ (DETAIL).)

Почти все команды DROP в PostgreSQL поддерживают указание CASCADE. Конечно, вид возможных зависимостей зависит от типа объекта. Вы также можете написать RESTRICT вместо CASCADE, чтобы включить поведение по умолчанию, когда объект можно удалить, только если от него не зависят никакие другие.

Примечание

Стандарт SQL требует явного указания RESTRICT или CASCADE в команде DROP. Но это требование на самом деле не выполняется ни в одной СУБД, при этом одни системы по умолчанию подразумевают RESTRICT, а другие — CASCADE.

Если в команде DROP перечисляются несколько объектов, CASCADE требуется указывать, только когда есть зависимости вне заданной группы. Например, в команде DROP TABLE tab1, tab2 при наличии внешнего ключа, ссылающегося на tab1 из tab2, можно не указывать CASCADE, чтобы она выполнилась успешно.

Для пользовательских функций PostgreSQL отслеживает зависимости, связанные с внешне видимыми свойствами функции, такими как типы аргументов и результата, но не зависимости, которые могут быть выявлены только при анализе тела функции. В качестве примера рассмотрите следующий сценарий:

CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow',
                             'green', 'blue', 'purple');

CREATE TABLE my_colors (color rainbow, note text);

CREATE FUNCTION get_color_note (rainbow) RETURNS text AS
  'SELECT note FROM my_colors WHERE color = $1'
  LANGUAGE SQL;

(Описание функций языка SQL можно найти в Разделе 37.4.) PostgreSQL будет понимать, что функция get_color_note зависит от типа rainbow: при удалении типа будет принудительно удалена функция, так как тип её аргумента оказывается неопределённым. Но PostgreSQL не будет учитывать зависимость get_color_note от таблицы my_colors и не удалит функцию при удалении таблицы. Но у этого подхода есть не только минус, но и плюс. В случае отсутствия таблицы эта функция останется рабочей в некотором смысле: хотя при попытке выполнить её возникнет ошибка, но при создании новой таблицы с тем же именем функция снова будет работать.