Код: Выделить всё
CREATE TABLE hierarchy (
parent INTEGER,
child INTEGER,
PRIMARY KEY(parent, child)
);
Однако, согласно разделу 5 документации SQLite о предложении With, его нельзя использовать внутри TRIGGER. Таким образом, я переместил With в функцию, определенную в C++, то есть LookForCycles, которая вызывается из TRIGGER.
Код: Выделить всё
CREATE TRIGGER prevent_cycles_insert
BEFORE INSERT ON hierarchy
FOR EACH ROW
BEGIN
SELECT
CASE
WHEN lookForCycles(NEW.parent, NEW.child) = 1 THEN
RAISE(ABORT, 'Cycle detected in INSERT INTO hierarchy!')
END;
END;
CREATE TRIGGER prevent_cycles_update
BEFORE UPDATE ON hierarchy
FOR EACH ROW
BEGIN
SELECT
CASE
WHEN lookForCycles(NEW.parent, NEW.child) = 1 THEN
RAISE(ABORT, 'Cycle detected in UPDATE hierarchy!')
END;
END;
Код: Выделить всё
lookForCyclesКод: Выделить всё
WITH RECURSIVE ancestors(node) AS(
SELECT ?
UNION ALL
SELECT h.parent
FROM hierarchy h
JOIN ancestors a ON h.child = a.node
)
SELECT 1 FROM ancestors WHERE node = ?;
Меня беспокоит то, что даже если предложение With используется в совершенно другом контексте, чем TRIGGER, как он вызывается из функции C++, я не знаю, работает ли он сейчас, но не гарантируется, что он будет делать то же самое во всех случаях. Если бы кто-то, обладающий большими знаниями о SQLite, мог бы сказать мне, как мне следует это делать, было бы здорово!
Две аннотации:
- Я знаю, что могу реализовать это с помощью рекурсивных TRIGGER, и я уже думал о возможном алгоритме, но я бы предпочел избежать этого варианта, поскольку он, вероятно, потребует использования временной таблицы и будет намного сложнее, чем просто использование With.
- По какой-то причине это тоже работает, хотя я использую FOR непосредственно внутри TRIGGER:
Код: Выделить всё
CREATE TRIGGER prevent_cycles BEFORE INSERT ON hierarchy FOR EACH ROW BEGIN WITH RECURSIVE ancestors(node) AS ( SELECT NEW.parent UNION ALL SELECT h.parent FROM hierarchy h JOIN ancestors a ON h.child = a.node ) SELECT CASE WHEN EXISTS ( SELECT 1 FROM ancestors WHERE node = NEW.child ) THEN RAISE(ABORT, 'Cycle detected!') END; END;
Подробнее здесь: https://stackoverflow.com/questions/798 ... t-uses-the
Мобильная версия