查找SQL函数的调用者

时间:2010-06-28 14:16:16

标签: sql sql-server tsql

我想从SQL Server 2005数据库中删除一个SQL函数,但首先我要确保没有人调用它。我已经使用“查看依赖项”功能从数据库中删除对它的任何引用。但是,可能有Web应用程序或SSIS包使用它。

我的想法是让函数在每次调用时在审计表中插入一条记录。但是,除非我也知道呼叫者,否则这将是有限的价值。有没有办法确定谁调用了这个函数?

7 个答案:

答案 0 :(得分:4)

您可以从extended stored procedures致电function

一些例子是:

  • xp_cmdshell的
  • xp_regwrite
  • xp_logevent

如果您拥有正确的权限,理论上您可以从函数中调用扩展存储过程,并将APP_NAME()和ORIGINAL_LOGIN()等信息存储在平面文件或注册表项中。

另一种选择是从scratch构建扩展存储过程。

如果这一切都太麻烦,我会遵循SQL Profiler的早期建议或server side tracing

下面是使用扩展存储过程的示例。这使用xp_logevent记录Windows应用程序日志中的每个函数调用实例。

此方法的一个警告是,如果函数应用于SELECT查询中的列,则将为返回的每一行调用该函数。这意味着您可以快速填写日志。

代码:

USE [master]
GO

/* A security risk but will get the job done easily */
GRANT EXECUTE ON xp_logevent TO PUBLIC
GO

/* Test database */
USE [Sandbox]
GO

/* Test function which always returns 1 */
CREATE FUNCTION ufx_Function() RETURNS INT
AS 
BEGIN 

  DECLARE 
    @msg VARCHAR(4000),
    @login SYSNAME,
    @app SYSNAME

  /* Gather critical information */    
  SET @login = ORIGINAL_LOGIN()
  SET @app = APP_NAME()
  SET @msg = 'The function ufx_Function was executed by ' 
    + @login + ' using the application ' + @app

  /* Log this event */
  EXEC master.dbo.xp_logevent 60000, @msg, warning

  /* Resume normal function */
  RETURN 1
END
GO

/* Test */
SELECT dbo.ufx_Function()

答案 1 :(得分:3)

尝试此搜索代码:

--declare and set a value of @SearchValue to be your function name
SELECT DISTINCT
    s.name+'.'+o.name AS Object_Name,o.type_desc
    FROM sys.sql_modules        m
        INNER JOIN sys.objects  o ON m.object_id=o.object_id
        INNER JOIN sys.schemas  s ON o.schema_id=s.schema_id
    WHERE m.definition Like '%'+@SearchValue+'%'
    ORDER BY 1

要在运行时查找调用方,您可以尝试使用CONTEXT_INFO

--in the code chain doing the suspected function call:
    DECLARE @CONTEXT_INFO  varbinary(128)
           ,@Info  varchar(128)
    SET @Info='????'
    SET @CONTEXT_INFO =CONVERT(varbinary(128),'InfoForFunction='+ISNULL(@Info,'')+REPLICATE(' ',128))
    SET CONTEXT_INFO @CONTEXT_INFO

    --after the suspected function call

    SET CONTEXT_INFO 0x0  --reset CONTEXT_INFO


--here is the portion to put in the function:
    DECLARE @Info           varchar(128)
           ,@sCONTEXT_INFO  varchar(128)
    SET @sCONTEXT_INFO=CONVERT(varchar(128),CONTEXT_INFO())

    IF LEFT(@sCONTEXT_INFO,15)='InfoForFunction='
    BEGIN
        SET @Info=RIGHT(RTRIM(@sCONTEXT_INFO),LEN(RTRIM(@sCONTEXT_INFO))-15)
    END

    --use the @Info
    SELECT @Info,@sCONTEXT_INFO

如果你在不同的地方在@CONTEXT_INFO中添加不同的值,你可以缩小调用该函数的人的范围,并在找到之前优化该值。

答案 2 :(得分:2)

取决于您当前的安全模型。我们使用连接池与一个SQL帐户。每个应用程序都有自己的帐户来连接数据库。如果是这样的话。然后,您可以执行Sql Profiler会话以查找该函数的调用者。无论哪个帐户调用该函数都将直接与一个应用程序相关。

这对我们处理Sql流量的方式起作用;我希望它能为你做同样的事。

答案 3 :(得分:2)

您可以尝试使用APP_NAME()和USER_NAME()。它不会给你详细信息(如SSIS包名称),但它可能有所帮助。

答案 4 :(得分:1)

另一个不那么优雅的方法是通过源代码grep -R [functionname] *。根据代码的数量,这可能是可行的,也可能是不可行的。

这样做的好处就是工作即使只使用非常的部分,这对你的审计表的想法来说也是个大问题。

答案 5 :(得分:1)

这将帮助您查找是否在数据库中的任何位置调用此方法。

select object_name(id) from sys.syscomments where text like '%**<FunctionName>**%'

答案 6 :(得分:1)

您可以在探查器中运行跟踪,以查看该函数是否被调用一周(或您认为是安全窗口的任何内容)。

我认为如果启用即席查询,您也可以使用OPENROWSET来调用记录到表的SP。