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

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

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

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

Для обеспечения целостности всей структуры базы данных, Tantor SE гарантирует, что вы не можете удалить объекты, от которых зависят другие объекты. Например, попытка удалить таблицу products, рассмотренную в Раздел 5.4.5, при условии, что от нее зависит таблица orders, приведет к появлению сообщения об ошибке, подобного следующему:

DROP TABLE products;

ERROR:  cannot drop table products because other objects depend on it
DETAIL:  constraint orders_product_no_fkey on table orders depends on table products
HINT:  Use DROP ... CASCADE to drop the dependent objects too.

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

DROP TABLE products CASCADE;

и все зависимые объекты будут удалены, а также все объекты, которые зависят от них, рекурсивно. В этом случае он не удаляет таблицу orders, он только удаляет ограничение внешнего ключа. Он останавливается, потому что ничто не зависит от ограничения внешнего ключа. (Если вы хотите проверить, что DROP ... CASCADE сделает, запустите DROP без CASCADE и прочитайте вывод DETAIL).

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

Примечание

Согласно стандарту SQL, в команде DROP требуется указать либо RESTRICT, либо CASCADE. Ни одна система управления базами данных на самом деле не принуждает к соблюдению этого правила, но поведение по умолчанию может быть либо RESTRICT, либо CASCADE в зависимости от системы.

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

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

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;

(См. Раздел 36.5 для объяснения функций SQL-языка). Tantor SE будет знать, что функция get_color_note зависит от типа rainbow: удаление типа приведет к удалению функции, потому что ее аргументный тип больше не будет определен. Но Tantor SE не будет считать, что функция get_color_note зависит от таблицы my_colors, и поэтому не удалит функцию, если таблица будет удалена. Хотя есть недостатки такого подхода, есть и преимущества. Функция все еще будет действительна в некотором смысле, если таблица отсутствует, хотя ее выполнение вызовет ошибку; создание новой таблицы с тем же именем позволит функции снова работать.

С другой стороны, для функции или процедуры на языке SQL, тело которой написано в стиле стандарта SQL, тело анализируется во время определения функции и все зависимости, распознанные парсером, сохраняются. Таким образом, если мы напишем функцию выше как

CREATE FUNCTION get_color_note (rainbow) RETURNS text
BEGIN ATOMIC
  SELECT note FROM my_colors WHERE color = $1;
END;

тогда зависимость функции от таблицы my_colors будет известна и принудительно применена командой DROP.