Sql server SQL Server 2005:;“保护”;MS Access使用的FMTONLY模式的存储过程
我们的一些存储过程包含条件逻辑,如下所示:Sql server SQL Server 2005:;“保护”;MS Access使用的FMTONLY模式的存储过程,sql-server,ms-access,stored-procedures,coding-style,Sql Server,Ms Access,Stored Procedures,Coding Style,我们的一些存储过程包含条件逻辑,如下所示: Create Procedure dbo.DoSomething(Some Parameters) As ... If (Some Condition) Begin Set @SomeVariable = SomeValue End ... Select ... Create Procedure dbo.DoSomething(Some Parameters) A
Create Procedure dbo.DoSomething(Some Parameters)
As
...
If (Some Condition) Begin
Set @SomeVariable = SomeValue
End
...
Select ...
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 ...
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 ...
当此类存储过程用作MS Access窗体的记录源,并且用户尝试使用窗体的内置排序/筛选功能时,MS Access将尝试以FMTONLY模式执行存储过程(显然,查找存储过程提供的行集的元数据)
正如大多数人所知(现在包括我们自己:-),当FMTONLY设置为ON时,SQLServer会忽略条件语句。在下面所示的示例中,执行Set@SomeVariable=SomeValue
语句,而不管某些条件是否为真,这显然给我们带来了一些麻烦
-- 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
...
If (Some Condition) Begin
Set @SomeVariable = SomeValue
End
...
Select ...
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 ...
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后面,如下所示:
Create Procedure dbo.DoSomething(Some Parameters)
As
...
If (Some Condition) Begin
Set @SomeVariable = SomeValue
End
...
Select ...
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 ...
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也不起作用,另一个存储过程也不起作用。看起来fmtony可以防止从任何地方返回任何数据。那么,主要问题来了:
如果您还必须处理这个问题(SQLServer在FMTONLY模式下忽略条件),您是否能够想出比上面描述的更好的“保护习惯用法”
顺便说一句,我仍然不明白一件事:这个问题是SQLServer2005中的一个bug还是一个特性?如果这是一个功能,那么什么可能是它的一个很好的理由呢
谢谢大家! 这个怎么样
If (Some Condition) Begin
Set @SomeVariable = SomeValue
ELSE
Set @SomeVariable = @SomeVariable --or dummy/default value?
End
您的代码是否基于此变量返回2个不同的记录集(列和类型)?
如果是这样,则必须将存储的进程拆分为2
此外,我还找到了一个解释原因的答案
编辑:
将分支更改为内联代码
Set @dtSomeDate = CASE WHEN ISDATE(@vcSomeDateOrAgeInDays) = 1 THEN @vcSomeDateOrAgeInDays ELSE NULL END
谢谢你的文章参考!虽然我没有看到它解释为什么在FMTONLY模式下忽略条件语句和分支语句,但它展示了一个很好的例子,说明了如何使用FMTONLY模式来破坏安全性。。。我想我没有理解我的观点:问题是FMTONLY=ON模式可能会导致执行不应该执行的语句;这可能导致例外情况。我将继续在我的问题中插入这种情况的一个具体例子……将@dtSomeDate=case设置为ISDATE(@vcSomeDateOrAgeInDays)=1,然后将@vcSomeDateOrAgeInDays设置为NULL END?@Yarik:你能用问题的形式表达这一点吗。SQL Server文档清楚地说明SET FMTONLY ON执行所有非条件语句,所以我不确定您的问题是什么?