"Tonal" <[EMAIL PROTECTED]> сообщил/сообщила в
новостях следующее: news:[EMAIL PROTECTED]
>
...
> гарантировать, что в нашем дереве нет циклов так просто не получится...
:-(
...
Как так не получится?
Получается элементарными триггерами.
С 2002 года работает и не жужжит.
:-)
Наверное не очень красиво.
Но это писАлось очень давно, аж 6 лет назад.
CREATE TABLE DM_GR (
ID INTEGER NOT NULL,
PARENT_ID INTEGER,
NAME VARCHAR(63) COLLATE PXW_CYRL,
POSTSCRIB BLOB SUB_TYPE 1 SEGMENT SIZE 80
);
ALTER TABLE DM_GR ADD CONSTRAINT DM_GR_PK PRIMARY KEY (ID);
ALTER TABLE DM_GR ADD CONSTRAINT DM_GR_DM_GR FOREIGN KEY (PARENT_ID)
REFERENCES DM_GR (ID) ON DELETE NOACTION ON UPDATE CASCADE;
CREATE OR ALTER TRIGGER DM_GR_BIU20 FOR DM_GR
ACTIVE BEFORE INSERT OR UPDATE POSITION 20
AS
DECLARE VARIABLE ISCYRCLE INTEGER;
begin
/* Проверка на цикличность
(выбрасывает, если новый ID соответствует ID одного из предков) */
if (New.ID = New.Parent_ID) then
execute procedure err_showmessage('Узел не может содержать сам себя');
execute procedure DM_GR_Cyrc(New.Id,New.Parent_Id) returning_values
IsCyrcle;
if (IsCyrcle = 1) then
execute procedure err_showmessage('Узел не может содержать сам себя');
end
CREATE OR ALTER PROCEDURE DM_GR_CYRC(
ID INTEGER,
PARENT_ID INTEGER)
RETURNS (
RESULT INTEGER)
AS
DECLARE VARIABLE NEWPARENT_ID INTEGER;
begin
/* Проверка на цикличность.
Проверяет соответствует ли ID новой записи
ID одного из родителей старше первого.
Возвращает 0 или 1. */
for select DM_Gr.Parent_ID from DM_GR
where DM_GR.ID = :Parent_ID
into :NewParent_ID
do
begin
Result = 0;
if (:NewParent_ID = :ID) then
begin
Result = 1;
exit;
end
else execute procedure DM_GR_CYRC :ID, :NewParent_ID returning_values
:Result;
exit;
end
end
--
Галимов Артур Амирзянович.
"ФармМедСервис" (Сочи).