Некоторые из хранимых процедур, которые мы имеем, содержат условную логику, например:
Create Procedure dbo.DoSomething(Some Parameters)
As
...
If (Some Condition) Begin
Set @SomeVariable = SomeValue
End
...
Select ...
Когда такая хранимая процедура используется в качестве источника записей для формы MS Access, и пользователь пытается использовать встроенные функции сортировки / фильтрации формы, MS Access пытается выполнить хранимую процедуру в режиме FMTONLY (очевидно, для поиска для метаданных набора строк, предоставляемых хранимой процедурой).
Как большинство людей знают (теперь включая нас самих :-), когда FMTONLY включен, SQL Server игнорирует условные операторы. В приведенном ниже примере оператор Set @SomeVariable = SomeValue
выполняется независимо от того, истинно ли Some Condition
, что, очевидно, создает для нас некоторые проблемы.
-- EXAMPLE
-- -------
Create Procedure dbo.DoSomething(..., @vcSomeDate as VarChar(50), ...)
As
...
Declare @dtSomeDate As Datetime
If (IsDate(@vcSomeDateOrAgeInDays)) Begin
-- The next statement fails miserably when FMTONLY=ON
Set @dtSomeDate = @vcSomeDateOrAgeInDays
End Else Begin
...
End
...
Чтобы обойти эту проблему, мы «оборачиваем» условную логику (или любые другие фрагменты кода, затронутые FMTONLY) следующим образом:
Create Procedure dbo.DoSomething(Some Parameters)
As
...
-- HACK: Protection from unexpected FMTONLY mode
Declare @wasFmtonlyOn As Bit; If (0 = 1) Set @wasFmtonlyOn = 1; SET FMTONLY OFF
...
If (Some Condition) Begin
Set @SomeVariable = SomeValue
End
...
-- /HACK: Protection from unexpected FMTONLY mode
If (@wasFmtonlyOn = 1) SET FMTONLY ON
...
Select ...
(Это уродливое форматирование «кода защиты» в одну строку является преднамеренным: мы считаем, что хаки, необходимые для решения некоторых странных проблем, не заслуживают надлежащего форматирования; наоборот, мы считаем, что они должны вписываться в несколько строк код как можно.: -)
В любом случае, эта «защита» работает нормально, но она слишком многословна и не настолько инкапсулирована, как хотелось бы. Например, мы определенно предпочли бы скрыть реальную логику взлома - например, за скалярным UDF, например:
Create Procedure dbo.DoSomething(Some Parameters)
As
...
declare @wasFmtonlyOn as bit; set @wasFmtonlyOn = dbo.SetFmtonly(0)
...
If (Some Condition) Begin
Set @SomeVariable = SomeValue
End
...
dbo.SetFmtonly(@wasFmtonlyOn)
...
Select ...
К сожалению, это, похоже, не работает - ни со скалярными UDF, ни с другой хранимой процедурой. Похоже, FMTONLY предотвращает возврат любых данных из любого места. Итак, вот Главный вопрос :
Если вам также приходилось сталкиваться с этой проблемой (игнорирование условий SQL Server в режиме FMTONLY), смогли ли вы придумать лучший «защитный идиом», чем описанный выше?
Кстати, я до сих пор не понимаю одну вещь: эта проблема - ошибка или особенность в SQL Server 2005? И если это особенность, то что может быть хорошей причиной для этого?
Спасибо!