Существует ли “вы уверены” для выполнения хранимой процедуры?:)
-
23-09-2019 - |
Вопрос
У меня есть хранимая процедура, которая выполняет много операций удаления.Сотни тысяч записей.Он не будет доступен для запуска из приложения, но все же я обеспокоен тем, что один из моих клиентов случайно запускает его (ранее у меня были проблемы из-за их "любопытства"): D
ДА.есть резервные копии и тому подобное, но я тут подумал ....не для того , чтобы напугать их ...есть ли способ спросить пользователя "вы уверены?" перед его выполнением?:) спасибо
Решение
Я предполагаю, что у вас мог бы быть параметр с именем "подтверждение", который требует передачи определенной строки (например, g, "Я знаю, что я делаю"), если она не задана или установлена неправильно, просто вернитесь из процедуры без выполнения основного кода.Не совсем то, что вы хотели, но это вариант.
например - (непроверенный и, вероятно, ужасный синтаксис)
CREATE PROCEDURE dbo.mySproc (
@Confirmation Varchar(100)
) AS
BEGIN
if(@Confirmation <> 'I know what I am doing')
BEGIN
return;
END
DELETE from table_name where condition
END
Другие советы
Короче говоря, нет.
Теория гласит, что любой, у кого есть разрешения на поиск и возможность запуска хранимой процедуры, должен быть разрешен.Было бы лучше ограничить разрешения, чтобы у тех, у кого избыточное любопытство, не было разрешений для запуска этого.
Другим, менее безопасным вариантом было бы потребовать заранее определенный секрет, который необходимо передать в качестве параметра - конечно, они могли бы просто отключить хранимую процедуру, чтобы найти секрет...
Конечно, другим моментом было бы:Если это невозможно вызвать, зачем его включать?В конце концов, когда вы приступаете к выполнению задач типа admin, вы можете записать инструкции в виде файла, который вы сможете безопасно хранить на своем компьютере
используйте многоуровневый целенаправленный подход:
1) контролировать безопасность выполнения, например:
GRANT EXECUTE ON [dbo].[yourProcedure] TO [userxyz]
2) используйте действительно описательное / пугающее название процедуры, например
CREATE PROCEDURE Will_Delete_All_Your_Data ...
3) поместите большой бросающийся в глаза комментарий в начале хранимой процедуры
--NOTE, will delete all of your data--
--NOTE, will delete all of your data--
--NOTE, will delete all of your data--
--NOTE, will delete all of your data--
--NOTE, will delete all of your data--
4) заставить пользователя ввести запутанный специальный код доступа:
CREATE PROCEDURE Will_Delete_All_Your_Data
(
@SpecialCode varchar(30)
)
IF @SpecialCode!=CHAR(83)+CHAR(112)+CHAR(101)+CHAR(99)+CHAR(105)+CHAR(97)+CHAR(108)+CHAR(67)+CHAR(111)+CHAR(100)+CHAR(101)
BEGIN
RETURN 999
END
...
К вашему сведению, специальный код должен быть "SpecialCode", иначе будет сбит ВОЗВРАТ 999.
Вы можете добавить @reallyReallyReallyDelete
параметр для sproc, который будет служить мерой безопасности:если он установлен на YesYesYes
фактически зафиксирует транзакцию.
Вы могли бы использовать битовый ввод, называемый @UserKnowsWhatTheyAreDoing
и проверьте, верно ли это перед выполнением.Если значение равно false, выведите понятное сообщение и корректно завершите процедуру
Для процедуры может потребоваться аргумент с определенным значением, например 'Yes I know what I'm doing'
.Или он может искать строку в специальной таблице с аналогичным подтверждением и недавней меткой времени.
Вот еще один подход, который, я думаю, подходит для конкретного случая, когда процедура должна вызываться пользователем напрямую, а не из приложения.
Я должен сказать, что это создает меньше проблем для пользователя и больше (возможно, непропорционально) для разработчика по сравнению с большинством других предложений.Вы сами решаете, подходит ли это вам.
В любом случае, поехали.
Сначала вы создаете специальную таблицу, CriticalCalls
, для регистрации вызовов критически важных процедур.Таблица имела бы структуру, подобную этой:
SPID int,
ProcName sysname,
CallTime datetime
По сути, идея заключается в том, что критический SP должен быть вызван дважды:сначала он регистрирует свой вызов и сообщает пользователю повторить вызов в течение определенного интервала времени в качестве подтверждения своего намерения, а при втором вызове, если он сделан соответствующим образом, он фактически приступает к выполнению своей задачи.
Таким образом, начальная часть каждой критической процедуры будет иметь такую логику:
IF NOT EXISTS (
SELECT *
FROM CriticalCalls
WHERE SPID = @@SPID AND ProcName = @ThisProcName
AND GETDATE() - CallTime BETWEEN @LowerCallTimeLimit AND @UpperCallTimeLimit
/* the actual test for the time interval might be somewhat different */
) BEGIN
... /* upsert CriticalCalls with the current time stamp */
PRINT 'To proceed, please call this procedure again within...';
RETURN;
END;
DELETE FROM CriticalCalls WHERE SPID = @@SPID AND ProcName = @ThisProcName;
... /* proceed with your critical task */
На самом деле, я думаю, было бы лучше использовать выделенный SP (с именем CheckCriticalCalls
ниже) для всех манипуляций с CriticalCalls
, включая все необходимые модификации. CheckCriticalCalls
получит имя процедуры, подлежащей проверке, и вернет своего рода флаг, показывающий, должна ли указанная процедура выполнять свою реальную работу.
Так что это может выглядеть примерно так:
EXECUTE @result = CheckCriticalCalls 'ThisProcedureName';
IF @result = -1 BEGIN
PRINT 'Call me again';
RETURN;
END;
... /* go on with the task */
Идея установки нижнего предела интервала заключается просто в том, чтобы пользователь не мог дважды автоматически вызывать критическую процедуру, т. е.выполнив два идентичных EXECUTE...
линии в одной партии.Верхний предел, конечно, необходим для того, чтобы 1) убедиться, что пользователь подтверждает свое самое недавнее намерение выполнить критическую операцию;2) предотвратить выполнение, если существующая запись в CriticalCalls
на самом деле он остался там с прошлой сессии с тем же SPID.
Так что, в принципе, интервал от 1-2 секунд до полуминуты показался бы мне вполне естественным.Вместо этого вы могли бы выбрать другие цифры.
Вам действительно нужно удалять их из базы данных?Если я смогу позволить себе дополнительное пространство, я поставлю флаг "Удалено" в своих таблицах и последний обновленный столбец.Таким образом, если запись случайно удалена, по крайней мере, я обычно могу отследить ее и восстановить довольно легко.Просто мысль.