SQL Server 2005: «Защита» хранимых процедур из режима FMTONLY, используемого MS Access - PullRequest
0 голосов
/ 19 ноября 2008

Некоторые из хранимых процедур, которые мы имеем, содержат условную логику, например:

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? И если это особенность, то что может быть хорошей причиной для этого?

Спасибо!

1 Ответ

1 голос
/ 22 ноября 2008

Как насчет этого?

If (Some Condition) Begin
    Set @SomeVariable = SomeValue
ELSE
    Set @SomeVariable = @SomeVariable --or dummy/default value?
End

Ваш код возвращает 2 разных набора записей (столбцы и типы) на основе этой переменной? Если это так, вам придется разделить сохраненный процесс на 2

Кроме того, я нашел статью КБ , в которой объясняется, почему.

Edit: Измените ветку на встроенный код ...

Set @dtSomeDate = CASE WHEN ISDATE(@vcSomeDateOrAgeInDays) = 1 THEN @vcSomeDateOrAgeInDays ELSE NULL END
...