Управляемая рекурсия
От: Аноним  
Дата: 16.01.11 02:41
Оценка:
Есть таблица, на которую повешен триггер. И этот триггер меняет данные той же таблицы. И, соответственно, происходит рекурсия.

Каждый экземпляр триггера знает (по определенным правилам), должен ли он быть последним в цепочке. И, если да, надо отключить вызов следующего триггера, инициированного текущим. Проблема, как я ее вижу, в том, что если вводить состояния (стоп-флаг, например), то это все может накрыться тазиком, поскольку сервер многопоточный. Например, один клиент поменял таблицу, произошел вызов триггера, который понял, что должен стать концевым, и выставил стоп-флаг. В этот момент другой клиент меняет таблицу, вызывается независимый триггер, начало новой цепочки, который по-любому должен отработать. Однако, видя стоп-флаг, он сбрасывает его и прекращает работу. Тут начинает выполняться рекурсивный триггер, опа — стоп-флаг сброшен, цепочка не прервалась.

Я про рекурсию триггеров знаю мало, если напишете "учи матчасть" — дайте уже сразу ссылки на эту матчасть, пока видел только банальщину, типа, как включить и/или поменять лимит вложенности. Я даже не знаю, вызовется ли рекурсивный триггер сразу после изменения данных, или даст первому триггеру довыполняться до конца.
Re: Управляемая рекурсия
От: Sinix  
Дата: 16.01.11 06:19
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Есть таблица, на которую повешен триггер. И этот триггер меняет данные той же таблицы. И, соответственно, происходит рекурсия.


Истользовать instead-of триггер.
Re[2]: Управляемая рекурсия
От: Аноним  
Дата: 16.01.11 09:56
Оценка:
Здравствуйте, Sinix, Вы писали:

А>>Есть таблица, на которую повешен триггер. И этот триггер меняет данные той же таблицы. И, соответственно, происходит рекурсия.

S>Истользовать instead-of триггер.

Туплю, что ли, но не могу сообразитть, как тут поможет instead-of триггер.
Re: Управляемая рекурсия
От: Lloyd Россия  
Дата: 16.01.11 09:59
Оценка: 1 (1)
Здравствуйте, Аноним, Вы писали:

А>Я про рекурсию триггеров знаю мало, если напишете "учи матчасть" — дайте уже сразу ссылки на эту матчасть, пока видел только банальщину, типа, как включить и/или поменять лимит вложенности. Я даже не знаю, вызовется ли рекурсивный триггер сразу после изменения данных, или даст первому триггеру довыполняться до конца.


Зачем вы себе жизнь портите? Не надо сложную логику пихать в триггера.
Re[2]: Управляемая рекурсия
От: Аноним  
Дата: 16.01.11 10:06
Оценка:
Здравствуйте, Lloyd, Вы писали:

А>>Я про рекурсию триггеров знаю мало, если напишете "учи матчасть" — дайте уже сразу ссылки на эту матчасть, пока видел только банальщину, типа, как включить и/или поменять лимит вложенности. Я даже не знаю, вызовется ли рекурсивный триггер сразу после изменения данных, или даст первому триггеру довыполняться до конца.


L>Зачем вы себе жизнь портите? Не надо сложную логику пихать в триггера.


Конченные пользователи хотят "data modification rules" and "data modification rule chains" respectively.
Re[3]: Управляемая рекурсия
От: Lloyd Россия  
Дата: 16.01.11 10:09
Оценка:
Здравствуйте, Аноним, Вы писали:

L>>Зачем вы себе жизнь портите? Не надо сложную логику пихать в триггера.


А>Конченные пользователи хотят "data modification rules" and "data modification rule chains" respectively.


Это очень круто, что вы умеете по-английски, но где связь с необходимостью реализовывать этого в триггерах?
Re[4]: Управляемая рекурсия
От: Аноним  
Дата: 16.01.11 10:59
Оценка:
Здравствуйте, Lloyd, Вы писали:

L>>>Зачем вы себе жизнь портите? Не надо сложную логику пихать в триггера.


А>>Конченные пользователи хотят "data modification rules" and "data modification rule chains" respectively.


L>Это очень круто, что вы умеете по-английски, но где связь с необходимостью реализовывать этого в триггерах?


"Data modification rule" соответствует триггер, "data modification rule chain" — цепочка триггеров.
Re[5]: Управляемая рекурсия
От: Lloyd Россия  
Дата: 16.01.11 11:08
Оценка: +1
Здравствуйте, Аноним, Вы писали:

А>>>Конченные пользователи хотят "data modification rules" and "data modification rule chains" respectively.


L>>Это очень круто, что вы умеете по-английски, но где связь с необходимостью реализовывать этого в триггерах?


А>"Data modification rule" соответствует триггер, "data modification rule chain" — цепочка триггеров.


Конечные пользователи не хотят этого, они даже названий таких не знают.
Re[6]: Управляемая рекурсия
От: Аноним  
Дата: 16.01.11 12:49
Оценка:
Здравствуйте, Lloyd, Вы писали:

А>>>>Конченные пользователи хотят "data modification rules" and "data modification rule chains" respectively.

L>>>Это очень круто, что вы умеете по-английски, но где связь с необходимостью реализовывать этого в триггерах?
А>>"Data modification rule" соответствует триггер, "data modification rule chain" — цепочка триггеров.
L>Конечные пользователи не хотят этого, они даже названий таких не знают.

Вам, конечно, виднее. Ай лав рсдн.
Re[7]: Управляемая рекурсия
От: Lloyd Россия  
Дата: 16.01.11 13:04
Оценка:
Здравствуйте, Аноним, Вы писали:

L>>Конечные пользователи не хотят этого, они даже названий таких не знают.


А>Вам, конечно, виднее.


Однозначно виднее. 90% "закавыристых" вопросов, задаваемых тут — из-за неправильно выбраного способа решения задачи.

А>Ай лав рсдн.


Просто напишите, какую задачу вы пытаетесь решить.
Re[7]: Управляемая рекурсия
От: PepperPuh  
Дата: 16.01.11 13:10
Оценка: +1
А>Вам, конечно, виднее. Ай лав рсдн.

Тут Lloyd прав настолько, что и малейшая ирония в вашем посте должна быть исключена. Лучше сразу ставить (3) и продолжить работу по новому.
Re[8]: Управляемая рекурсия
От: Аноним  
Дата: 16.01.11 16:23
Оценка:
Здравствуйте, Lloyd, Вы писали:

L>>>Конечные пользователи не хотят этого, они даже названий таких не знают.

А>>Вам, конечно, виднее.

L>Однозначно виднее. 90% "закавыристых" вопросов, задаваемых тут — из-за неправильно выбраного способа решения задачи.


L>Просто напишите, какую задачу вы пытаетесь решить.


Позвольте усомниться. Вот мой предыдущий вопрос — http://rsdn.ru/forum/db/4111120.flat.aspx#4111120
Автор:
Дата: 11.01.11
. Заставили рассказать, как давно беспокоит, а также про дядю, который пил запоем в Вологде, а ответа так нифига и не дали. Я сам потом нашел:

http://www.sommarskog.se/arrays-in-sql-2005.html
http://www.sommarskog.se/arrays-in-sql-2008.html

Я понимаю, что тут мне никто ничем не обязан, но сужу по себе: я если вижу вопрос на форуме (не про БД, конечно — я в них как одно животное в одном фрукте) и знаю ответ, сразу отвечаю, а если не знаю — прохожу мимо. Если человек в явном виде не выражает сомнений в корректности вопроса, значит, знает, что делает, не дурак.

Ладно, рассказываю.

Есть готовый продукт, есть готовая БД. Менять нельзя. И в этой БД есть таблица с колонками A,B,C,D,G... (A..D — вещественного типа, G — guid). Конечный пользователь видит данные в виде Excel'еподобного интерфейса. В интерфейсе записи Gруппируются, т.е. разбиваются по Gруппам с одним и тем же G на... мммм... листы, на каждом из которых присутствуют только колонки A, B, C и D.

У пользователя есть возможность устанавливать зависимости A..D друг от друга. То есть, он может ввести в интерфейсе формулу D = (A * 5 — 8) / .333, после чего D станет read-only и будет вычисляться при каждом изменении A той же записи в пределах группы, для которой установлена зависимость.

Стоит задача — не меняя БД и продукта (триггер добавить можно, хранимку — можно, а менять таблицы нельзя), реализовать зависимости за пределами группы. Соответственно, пишем второй GUI, в котором можно вводить зависимости типа [D первого листа (т.е. для записей с G=guid1)] = ([A второго листа (т.е. запись с G=guid2 + дополнительное условие для поиска записи)] * 5 — 8) / .333. На каждую формулу создается триггер, который делает SET. Соответственно, второй лист превращается в справочник, из колонки A специфицированной условием записи которого данные подставляются в колонку D всех записей первого листа. Пользователи от радости ссут кипятком в потолок — не надо больше копипастить. Однако, спустя какое-то время пользователи захотели использовать один из листов не просто как справочник, а как справочник-конвертер. То есть, А первого листа ушло в ячейку A второго листа, посчиталось там с учетом справочных данных в ячейку D и — Surprise! — вернулось обратно в A первого листа. Выглядит это так: ввели в ячейку A число, нажали Apply, число поменялось на расчетное (слава богу, софтец когда что-то отправляет в базу, потом перечитывает значения). То есть, это deadlock. На первый взгляд кажется, что его надо рвать по признаку, было ли A изменено юзером или триггером. Однако, это не так: за кулисами работают ДВЕ формулы, одна из которых должна работать всегда, а вторая — только если данные поменялись юзером (не другим триггером). Напоминаю, что менять в софте ничего нельзя, можно только в БД. Логично к каждой формуле в GUI-2 присобачить чекбокс "конец цепочки", и пусть юзер сам следит за своими дедлоками. Моей надстройке все равно не известно, когда его рвать.

Ну что, теперь можно вернуться к изначальному вопросу?
Re[9]: Управляемая рекурсия
От: Lloyd Россия  
Дата: 16.01.11 18:49
Оценка: +1
Здравствуйте, Аноним, Вы писали:

А>Я понимаю, что тут мне никто ничем не обязан, но сужу по себе: я если вижу вопрос на форуме (не про БД, конечно — я в них как одно животное в одном фрукте) и знаю ответ, сразу отвечаю, а если не знаю — прохожу мимо. Если человек в явном виде не выражает сомнений в корректности вопроса, значит, знает, что делает, не дурак.


Это от неопытности, бывает.

А>Ладно, рассказываю.


А>Есть готовый продукт, есть готовая БД. Менять нельзя. И в этой БД есть таблица с колонками A,B,C,D,G... (A..D — вещественного типа, G — guid). Конечный пользователь видит данные в виде Excel'еподобного интерфейса. В интерфейсе записи Gруппируются, т.е. разбиваются по Gруппам с одним и тем же G на... мммм... листы, на каждом из которых присутствуют только колонки A, B, C и D.


А>У пользователя есть возможность устанавливать зависимости A..D друг от друга. То есть, он может ввести в интерфейсе формулу D = (A * 5 — 8) / .333, после чего D станет read-only и будет вычисляться при каждом изменении A той же записи в пределах группы, для которой установлена зависимость.


А>Стоит задача — не меняя БД и продукта (триггер добавить можно, хранимку — можно, а менять таблицы нельзя), реализовать зависимости за пределами группы. Соответственно, пишем второй GUI, в котором можно вводить зависимости типа [D первого листа (т.е. для записей с G=guid1)] = ([A второго листа (т.е. запись с G=guid2 + дополнительное условие для поиска записи)] * 5 — 8) / .333. На каждую формулу создается триггер, который делает SET. Соответственно, второй лист превращается в справочник, из колонки A специфицированной условием записи которого данные подставляются в колонку D всех записей первого листа. Пользователи от радости ссут кипятком в потолок — не надо больше копипастить. Однако, спустя какое-то время пользователи захотели использовать один из листов не просто как справочник, а как справочник-конвертер. То есть, А первого листа ушло в ячейку A второго листа, посчиталось там с учетом справочных данных в ячейку D и — Surprise! — вернулось обратно в A первого листа. Выглядит это так: ввели в ячейку A число, нажали Apply, число поменялось на расчетное (слава богу, софтец когда что-то отправляет в базу, потом перечитывает значения). То есть, это deadlock. На первый взгляд кажется, что его надо рвать по признаку, было ли A изменено юзером или триггером. Однако, это не так: за кулисами работают ДВЕ формулы, одна из которых должна работать всегда, а вторая — только если данные поменялись юзером (не другим триггером). Напоминаю, что менять в софте ничего нельзя, можно только в БД. Логично к каждой формуле в GUI-2 присобачить чекбокс "конец цепочки", и пусть юзер сам следит за своими дедлоками. Моей надстройке все равно не известно, когда его рвать.


А>Ну что, теперь можно вернуться к изначальному вопросу?


Уже лучше. Причем правильный ответ уже был: INSTEAD OF триггер.
Теперь подробнее. Твою исходную таблицу заменяешь на вьюху ровно с такой же схемой, что и исходная таблица + создаешь таблицу для хранения данных. На вьюху вешаешь триггеры на все операции и транслируешь их в соответствующие операции над таблицей для хранения. Т.о. получаешь, что для внешнего мира поведение базы данных никак не поменялось.
Но теперь у тебя есть способ отличить операции, сделанные приложением от операций, от сделанных изнутри триггеров: первые будут вызваны изутри триггера на вьюхе, вторых — изнутри триггеров на таблице. Как ты разрулишь дальнейшее — уже дело техники.
Re: Управляемая рекурсия
От: Sergei MO Россия  
Дата: 16.01.11 20:31
Оценка: +1
Здравствуйте, Аноним, Вы писали:

MSSQL?

А>Каждый экземпляр триггера знает (по определенным правилам), должен ли он быть последним в цепочке. И, если да, надо отключить вызов следующего триггера, инициированного текущим.


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

А>Проблема, как я ее вижу, в том, что если вводить состояния (стоп-флаг, например), то это все может накрыться тазиком, поскольку сервер многопоточный. Например, один клиент поменял таблицу, произошел вызов триггера, который понял, что должен стать концевым, и выставил стоп-флаг. В этот момент другой клиент меняет таблицу, вызывается независимый триггер, начало новой цепочки, который по-любому должен отработать. Однако, видя стоп-флаг, он сбрасывает его и прекращает работу. Тут начинает выполняться рекурсивный триггер, опа — стоп-флаг сброшен, цепочка не прервалась.


Многопоточность здесь вообще не при чём. Разделение работы разных пользователей производится с помощью транзакций и соответствующего уровня изоляции. В случае MSSQL описанный вами сценарий с поочерёдным изменением стоп-флага невозможен, если каждый клиент будет производить все свои изменения в одной транзакции.


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

Сейчас вы обходите граф зависимостей в глубину, используя рекурсивный алгоритм. Этот алгоритм можно заменить на нерекурсивный алгоритм обхода в ширину, реализованный в instead-of триггере. Т.е. при первом изменении записи пользователем вызывается этот триггер, а все изменения, которые он вносит сам, не приводят к его рекурсивному вызову. При этом весь алгоритм работает в одном контексте, поэтому отслеживать посещённые вершины можно в обычной табличной переменной.
Re: Управляемая рекурсия
От: rm822 Россия  
Дата: 16.01.11 23:26
Оценка:
Однако, видя стоп-флаг, он сбрасывает его и прекращает работу. Тут начинает выполняться рекурсивный триггер, опа — стоп-флаг сброшен, цепочка не прервалась.
технологически нет никаких сложностей с управлением флагами, создаешь таблицу (лучше временную) и в качестве ключа для своих флагов используешь ид транзакции(внутри триггера она будет открыта)

если конечно речь идет про MSSQL
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re: Управляемая рекурсия
От: Softwarer http://softwarer.ru
Дата: 21.01.11 19:02
Оценка:
Здравствуйте, Аноним, Вы писали:

А> то это все может накрыться тазиком, поскольку сервер многопоточный. Например, один клиент поменял таблицу, произошел вызов триггера, который понял, что должен стать концевым, и выставил стоп-флаг. В этот момент другой клиент меняет таблицу, вызывается независимый триггер, начало новой цепочки,


Хорошо, что Вы об этом думаете, но ещё лучше, что об этом подумали до Вас. СУБД поддерживают так называемую изоляцию данных, которая, если вкратце, заключается в том, что каждый пользователь думает, что он — единственный. Поиск по этим словам даст прорву информации, в том числе о том, каким образом изоляция реализуется в используемой Вами СУБД. Например, в Oracle "стоп-флаг" может быть сделан пакетной переменной, и никто не увидит чужого флага.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.