Страница 1 из 1
Хранимая процедура
Добавлено: 09 апр 2007, 17:24
santilaas
Хранимая процедура:
Firebird 1.5.3, FibPlus 5.2
Привет всем!!!
Вопрос такой:
есть хранимая процедура:
Код: Выделить всё
CREATE PROCEDURE GRANT_ROLE (
CMD VARCHAR(6),
ROLENAME VARCHAR(31),
USR VARCHAR(31))
AS
DECLARE VARIABLE EXESTUB VARCHAR(1024) = '';
begin
if (rolename = '') then rolename = null;
if (usr = '') then usr = null;
if ((rolename is null) or (usr is null)) then exit;
else
begin
if (cmd starting with 'g') then
exestub = 'grant ';
else
exestub = 'revoke ';
if (exestub = 'grant ') then
exestub = exestub || rolename || ' to ' || usr;
else
exestub = exestub || rolename || ' from ' || usr;
execute statement exestub;
end
end
- как Вы правильно поняли - она назначает или отбирает роль у пользователя.
Сама она работает (в том же IBExpert-е проверял), но проблема в другом:
- на форме есть 2 ДБГрида, связанные с датасетами (DataSetRole - мастер и DataSetUser - деталь) - так вот, при добавлении
пользователя, он у меня должен записаться в БД безопасности и в таблицу моей БД и здесь же должно выполниться назначение
роли (мастера) данному юзеру (детали). вызываю процедуру так (с помощью компонента pFIBStoredProc):
Код: Выделить всё
DM.StoredProc.SQL.Clear;
//1-ый способ:
//DM.StoredProc.SQL.Add('EXECUTE PROCEDURE GRANT_ROLE(''grant'',''' + DM.DSRoleNAME.AsString + ''', ''' + Edit.Text) + ''')');
//DM.StoredProc.ExecProc;
//или так:
// 2-ой способ:
DM.StoredProc.ExecProcedure('SPRole',['grant', DM.DSRoleNAME.AsString, Edit.Text)]);
- притом она все правильно срабатывает, но "гасит" (делает неактивными мои датасеты (см. выше)) - почему так происходит - может кто подскажет?
Заранее благодарен!
Добавлено: 09 апр 2007, 21:40
kdv
как Вы правильно поняли - она назначает или отбирает роль у пользователя.
вернее, включает пользователя в роль или исключает оттуда.
неясно только, зачем это мутить на сервере.
Код: Выделить всё
притом она все правильно срабатывает, но "гасит"
такие запросы надо в отдельной транзакции пускать. старт, ддл, коммит.
Добавлено: 10 апр 2007, 18:21
santilaas
неясно только, зачем это мутить на сервере.
- а что в плохого в том, что я из своего приложения могу раздавать права, ВКЛЮЧАТЬ (ИСКЛЮЧАТЬ) пользователя в роль?! Единственное может я это немного коряво делаю - вот поэтому и прошу помощи
Добавлено: 10 апр 2007, 23:20
kdv
что я из своего приложения
ты не понял. так или иначе это делается из приложения.
другое дело, почему тебе не нравится просто оператор grant, и ты решил городить для этого процедуру с execute statement.
Единственное может я это немного коряво делаю
про ddl в отдельных транзакциях я уже сказал.
Добавлено: 11 апр 2007, 18:26
santilaas
Помимо двух моих транзакций (на чтение из запись) завел еще одну:
попробовал написать так:
Код: Выделить всё
Tr_StoredProc.Active:=True;
Tr_StoredProc.StartTransaction;
DM.StoredProc.SQL.Clear;
DM.StoredProc.SQL.Add('EXECUTE PROCEDURE GRANT_ROLE('''',''' + DM.DSRoleNAME.AsString + ''', ''' + trim(Edit.Text) + ''')');
try
DM.StoredProc.ExecProc;
if Tr_StoredProc.InTransaction then Tr_StoredProc.CommitRetaining;
except
Tr_StoredProc.RollbackRetaining;
end;
но толку мало,
только после DM.DS_A_Role.FullRefresh; - все встает на свои места
почему я не сделал все это через транзакцию на запись - а потому что в рамках неё выполняются другие изменения БД,
а транзакция (которая для ХП) вызывается внутри этой транзакции - кстати вопрос:
- а если транзакция, скажем Tr_main, запущена и в рамках неё выполняется другая транзакция Tr_child, которая подтверждается как CommitRetaining, - то что будет с этой внутренней транзакцией после Rollback- а транзакции Tr_main ???
и еще вопрос: как мне отследить для моей процедуры - включила она пользователя в роль или нет, - чтобы сделать Rollback при необходимости: мне надо в самой процедуре это писать или как-то сделать это иначе?
почему тебе не нравится просто оператор grant
- почему же не нравится - я бы рад сделать, проще, если бы знал как -
kdv, может, если не трудно подскажешь как это сделать?! через Query или еще как?
Добавлено: 12 апр 2007, 02:14
kdv
Tr_StoredProc.Active:=True;
сколько раз говорить можно - свойство Active - ДЛЯ ТЫКАНЬЯ МЫШЬЮ В OBJECT INSPECTOR. Только.
www.ibase.ru/devinfo/ibx.htm
в результате имеем бред вида
Код: Выделить всё
Tr_StoredProc.Active:=True;
Tr_StoredProc.StartTransaction;
почему я не сделал все это через транзакцию на запись - а потому что в рамках неё выполняются другие изменения БД,
а транзакция (которая для ХП) вызывается внутри этой транзакции - кстати вопрос:
еще раз повторяю - изменения, выполненные операторами DDL, вступают в действие только по commit. И мешать их в транзации с DML КАТЕГОРИЧЕСКИ НЕЛЬЗЯ.
подтверждается как CommitRetaining
хочешь хреновые приложения - используй CommitRetaining дальше. я не знаю, сколько еще раз можно советовать одно и то же.
то что будет с этой внутренней транзакцией
нет никаких "вложенных" транзакций. В принципе. Транзакции всегда выполняются только "параллельно", т.е. независимо друг от друга, так, как они бы выполнялись из разных приложений с разных компьютеров.
включила она пользователя в роль или нет, - чтобы сделать Rollback при необходимости
не всем операторам ddl можно сделать rollback.
я бы рад сделать, проще, если бы знал как
ну так учись же. что ж ты советы игнорируешь? Если ты и дальше будешь писать так как тебе надо, а не так как тебе советуют, какой мне смысл дальше отвечать на твои вопросы???
Добавлено: 15 апр 2007, 19:26
santilaas
процитирую сам себя:
притом она все правильно срабатывает, но "гасит" (делает неактивными мои датасеты (см. выше)) - почему так происходит - может кто подскажет?
- потому что надо было у StoredProc поставить options-qoAutoCommit в False и указать для неё в качестве транзакции мою транзакцию на запись и тогда не надо было бы писать всю эту чепуху (т.е. мой предыдущий ответ)
почему тебе не нравится просто оператор grant, и ты решил городить для этого процедуру с execute statement.
- здесь я полностью согласен - сделал через Query (options-qoAutoCommit, Transaction = Tr_Write):
Код: Выделить всё
DM.Query_Grant.Close;
DM.Query_Grant.SQL.Clear;
DM.Query_Grant.SQL.Add('Grant ' + DM.DataSetRoleName.AsString + ' to ' + DM.DataSetUsersLOGIN.AsString);
DM.Query_Grant.ExecQuery;
- тут сразу вопрос- обязательно ли делать Close для Query в данном случае?
в результате имеем бред вида ...
- что я могу сказать - снова согласен
что ж ты советы игнорируешь?
- я исправляюсь по мере своих сил
Добавлено: 16 апр 2007, 02:01
CyberMax
Код: Выделить всё
DM.Query_Grant.Close;
DM.Query_Grant.SQL.Clear;
DM.Query_Grant.SQL.Add('Grant ' + DM.DataSetRoleName.AsString + ' to ' + DM.DataSetUsersLOGIN.AsString);
DM.Query_Grant.ExecQuery;
Наборы должны закрываться сразу же после использования (естественно, могут быть исключения). В итоге получается:
Код: Выделить всё
DM.Query_Grant.SQL.Clear;
DM.Query_Grant.SQL.Add('Grant ' + DM.DataSetRoleName.AsString + ' to ' + DM.DataSetUsersLOGIN.AsString);
DM.Query_Grant.ExecQuery;
DM.Query_Grant.Close;
Таким образом, твой вопрос сам собой отпадает.
Добавлено: 17 апр 2007, 18:01
santilaas
Все, теперь (по этому вопросу) мне все ясно - спасибо Вам, kdv и CyberMax, огромное