SQL Server 2005: "Protecting" stored procedures from FMTONLY mode used by MS Access
In some stored procedures, we have conditional logic, for example:
Create Procedure dbo.DoSomething(Some Parameters)
As
...
If (Some Condition) Begin
Set @SomeVariable = SomeValue
End
...
Select ...
When such a stored procedure is used as a record source for an MS Access form and the user tries to use the built-in sort / filter functions of the form, MS Access tries to execute the stored procedure in FMTONLY mode (apparently hunting for the rowset metadata provided by the stored procedure).
As most people know (now including ourselves :-), when FMTONLY is ON, SQL Server ignores conditional statements. In the example below, the statement is executed regardless of whether the value is true, which obviously creates some problems for us. 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
...
To work around this problem, we "wrap" the conditional logic (or any other code fragments affected by FMTONLY) as follows:
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 ...
(This ugly one-line "security code" formatting is intentional: we think that the hacks needed to solve some strange problems don't deserve proper formatting, on the contrary, we think they should fit on multiple lines as soon as possible. :-)
In any case, this "protection" works fine, but it is a little too verbose and not as encapsulated as we would like. For example, we would definitely prefer to hide the actual hacking logic behind a scalar UDF like this:
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 ...
Unfortunately this doesn't seem to work - neither with scalar UDFs, nor with any other stored procedure. Looks like FMTONLY prevents any data from being returned from anywhere. So here's the main question :
If you also had to solve this problem (SQL Server ignores conditionals in FMTONLY mode), could you think of a better "security idiom" than the one described above?
By the way, I still don't understand one thing: is it a bug or a feature in SQL Server 2005? And if this is a feature, then what could it be a good reason for?
Thank!
source to share
How about this?
If (Some Condition) Begin
Set @SomeVariable = SomeValue
ELSE
Set @SomeVariable = @SomeVariable --or dummy/default value?
End
Does your code mean two different sets of records (columns and types) based on this variable? If so, you need to split the saved proc by 2
Also, I found an article in KB that explains why.
Edit: Change the branch to inline code ...
Set @dtSomeDate = CASE WHEN ISDATE(@vcSomeDateOrAgeInDays) = 1 THEN @vcSomeDateOrAgeInDays ELSE NULL END
source to share