编程数据库引擎扩展存储过程

适用范围:SQL Server

重要

在 SQL Server的未来版本中将删除此功能。 请避免在新的开发工作中使用该功能,并着手修改当前还在使用该功能的应用程序。 请改用 CLR 集成

扩展存储过程的工作原理

扩展存储过程的工作流程是:

  1. 当客户端执行扩展存储过程时,请求以表格数据流(TDS)或简单对象访问协议(SOAP)格式从客户端应用程序传输到 SQL Server。

  2. SQL Server 搜索与扩展存储过程关联的 DLL,并加载 DLL(如果尚未加载)。

  3. SQL Server 调用请求的扩展存储过程(作为 DLL 中的函数实现)。

  4. 扩展存储过程通过扩展存储过程 API 传递结果集,并将参数返回给服务器。

过去,程序员使用开放式数据服务编写服务器应用程序,比如到非 SQL 服务器数据库环境的网关。 SQL Server 不支持 Open Data Services API 的过时部分。 SQL Server 仍支持的原始 Open Data Services API 的唯一部分是扩展存储过程函数,因此 API 已重命名为扩展存储过程 API。

随着分布式查询和 CLR 集成的出现,扩展存储过程 API 应用程序的需求已基本被取代。

如果已有网关应用程序,则无法使用 opends60.dll SQL Server 附带的应用程序来运行应用程序。 网关应用程序不再受支持。

扩展存储过程与 CLR 集成

CLR 集成提供了更可靠的替代方法,用于编写难以表达或无法在 Transact-SQL 中写入的服务器端逻辑。 在 SQL Server 的早期版本中,扩展存储过程(XP)提供了唯一可用于数据库应用程序开发人员编写此类代码的机制。

使用 CLR 集成时,以存储过程形式写入的逻辑通常更能表示为表值函数,从而允许函数构造的结果通过在子句中SELECTFROM嵌入它们来查询函数。

有关详细信息,请参阅 CLR 集成概述

扩展存储过程的执行特征

执行扩展存储过程具有以下特征:

  • 扩展存储过程函数在 SQL Server 的安全上下文下执行。

  • 扩展存储过程函数在 SQL Server 的进程空间中运行。

  • 与执行扩展存储过程关联的线程和用于客户端连接的线程相同。

重要

在将扩展存储过程添加到服务器并向其他用户授予执行权限之前,系统管理员应彻底检查每个扩展存储过程,以确保它不包含有害或恶意代码。

加载扩展存储过程 DLL 后,DLL 将保留在服务器的地址空间中,直到 SQL Server 停止或管理员使用 DBCC <DLL_name> (FREE)显式卸载 DLL。

可以使用语句从 Transact-SQL 执行扩展存储过程作为存储过程 EXECUTE

EXECUTE @retval = xp_extendedProcName @param1, @param2 OUTPUT;

参数

@ retval

返回值。

@ param1

一个输入参数。

@ param2

输入/输出参数。

注意

扩展存储过程提供性能增强和扩展 SQL Server 功能。 但是,由于扩展存储过程 DLL 和 SQL Server 共享相同的地址空间,问题过程可能会对 SQL Server 运行产生不利影响。 尽管扩展存储过程 DLL 引发的异常由 SQL Server 处理,但可能会损坏 SQL Server 数据区域。 作为安全预防措施,只有 SQL Server 系统管理员才能将扩展存储过程添加到 SQL Server。 应彻底测试这些过程,然后才能进行安装。

使用扩展存储过程 API 将结果集发送到服务器

将结果集发送到 SQL Server 时,扩展存储过程应调用相应的 API,如下所示:

  • srv_sendmsg函数可以按所有行之前或之后的任何顺序调用(如果有)。srv_sendrow 在发送 srv_senddone完成状态之前,所有消息都必须发送到客户端。

  • 对于发送到客户端的每一行,都会 srv_sendrow 调用该函数一次。 所有行都必须发送到客户端,然后发送任何消息、状态值或完成状态 srv_sendmsgsrv_status 参数 srv_pfieldsrv_senddone

  • 发送未定义 srv_describe 其所有列的行会导致应用程序引发信息性错误消息并返回到 FAIL 客户端。 在这种情况下,不会发送该行。

创建扩展存储过程

扩展存储过程是具有原型的 C/C++ 函数:

SRVRETCODE xp_extendedProcName (SRVPROC *);

使用前缀 xp_ 是可选的。 扩展存储过程名称在 Transact-SQL 语句中引用时区分大小写,而不考虑服务器上安装的代码页/排序顺序。 当您生成 DLL 时:

  • 如果需要入口点,请编写函数 DllMain

    此函数是可选的。 如果未在源代码中提供它,编译器将链接自己的版本,但不会返回 TRUE。 如果提供函数 DllMain ,当线程或进程附加到 DLL 或从 DLL 分离时,操作系统将调用此函数。

  • 必须导出从 DLL 外部调用的所有函数(所有扩展存储过程函数)。

    可以通过在文件的节.defEXPORTS列出函数的名称来导出函数,也可以为源代码__declspec(dllexport)中的函数名称加上前缀,Microsoft编译器扩展(__declspec()以两个下划线开头)。

创建扩展存储过程 DLL 时需要这些文件。

文件 说明
srv.h 扩展存储过程 API 头文件
opends60.lib 导入库 opends60.dll

若要创建扩展存储过程 DLL,请创建一个类型为动态链接库的项目。 有关创建 DLL 的详细信息,请参阅开发环境文档。

所有扩展存储过程 DLL 都应实现并导出以下函数:

__declspec(dllexport) ULONG __GetXpVersion()
{
   return ODS_VERSION;
}

__declspec(dllexport) 是特定于Microsoft的编译器扩展。 如果编译器不支持此指令,则应在 DEF 节下的 EXPORTS 文件中导出此函数。

当 SQL Server 以跟踪标志 -T260 启动或具有系统管理员权限的用户运行时 DBCC TRACEON (260),如果扩展存储过程 DLL 不支持 __GetXpVersion(),则会将以下警告消息打印到错误日志(__GetXpVersion() 以两个下划线开头)。

Error 8131: Extended stored procedure DLL '%' does not export __GetXpVersion().

如果扩展存储过程 DLL 导出 __GetXpVersion(),但函数返回的版本小于服务器所需的版本,则会显示一条警告消息,指出该函数返回的版本以及服务器预期的版本将输出到错误日志中。 如果收到此消息,则从中返回不正确的值 __GetXpVersion(),或者使用较旧版本的版本 srv.h进行编译。

注意

SetErrorMode不应在扩展存储过程中调用 Win32 函数。

长时间运行的扩展存储过程应定期调用 srv_got_attention ,以便在连接终止或批处理中止时,该过程可以终止自身。

若要调试扩展存储过程 DLL,请将其复制到 SQL Server \Binn 目录。 若要指定调试会话的可执行文件,请输入 SQL Server 可执行文件的路径和文件名(例如)。 C:\Program Files\Microsoft SQL Server\MSSQL16.MSSQLSERVER\MSSQL\Binn\sqlservr.exe 有关参数的信息 sqlservr ,请参阅 sqlservr 应用程序

将扩展存储过程添加到 SQL Server

包含扩展存储过程函数的 DLL 充当 SQL Server 的扩展。 若要安装 DLL,请将该文件复制到目录,例如包含标准 SQL Server DLL 文件(C:\Program Files\Microsoft SQL Server\MSSQL16.0.<x>\MSSQL\Binn 默认情况下)。

将扩展存储过程 DLL 复制到服务器后,SQL Server 系统管理员必须将每个扩展存储过程函数注册到 DLL 中的每个扩展存储过程函数。 这是使用系统存储过程完成的 sp_addextendedproc

重要

系统管理员应彻底查看扩展存储过程,以确保在将代码添加到服务器并向其他用户授予执行权限之前,它不包含有害或恶意代码。 验证所有用户的输入。 在验证用户输入之前不要连接用户输入。 绝对不要执行根据尚未验证的用户输入构造的命令。

第一个参数 sp_addextendedproc 指定函数的名称,第二个参数指定该函数所在的 DLL 的名称。 应指定 DLL 的完整路径。

注意

升级到 SQL Server 2005 (9.x) 或更高版本后,未注册到完整路径的现有 DLL 不起作用。 若要更正此问题,请使用 sp_dropextendedproc 取消注册 DLL,然后使用指定完整路径重新注册它 sp_addextendedproc,

sp_addextendedproc 中指定的函数名称必须与 DLL 中的函数名称完全相同,包括大小写。 例如,此命令将位于名为 xp_hello.dll 的 dll 中的函数xp_hello,注册为 SQL Server 扩展存储过程:

sp_addextendedproc 'xp_hello', 'c:\Program Files\Microsoft SQL Server\MSSQL13.0.MSSQLSERVER\MSSQL\Binn\xp_hello.dll';

如果指定的 sp_addextendedproc 函数名称与 DLL 中的函数名称不完全匹配,则新名称在 SQL Server 中注册,但该名称不可用。 例如,尽管 xp_Hello 注册为位于中的 xp_hello.dllSQL Server 扩展存储过程,但如果稍后用于 xp_Hello 调用函数,SQL Server 在 DLL 中找不到该函数。

-- Register the function (xp_hello) with an initial upper case
sp_addextendedproc 'xp_Hello', 'c:\xp_hello.dll';

-- Use the newly registered name to call the function
DECLARE @txt VARCHAR(33);
EXEC xp_Hello @txt OUTPUT;

下面是错误消息:

Server: Msg 17750, Level 16, State 1, Procedure xp_Hello, Line 1
Could not load the DLL xp_hello.dll, or one of the DLLs it references. Reason: 127(The specified procedure could not be found.).

如果指定 sp_addextendedproc 函数的名称与 DLL 中的函数名称完全匹配,并且 SQL Server 实例的排序规则不区分大小写,则用户可以使用名称中小写字母和大写字母的任意组合调用扩展存储过程。

-- Register the function (xp_hello)
sp_addextendedproc 'xp_hello', 'c:\xp_hello.dll';

-- The following example succeeds in calling xp_hello
DECLARE @txt VARCHAR(33);
EXEC xp_Hello @txt OUTPUT;

DECLARE @txt VARCHAR(33);
EXEC xp_HelLO @txt OUTPUT;

DECLARE @txt VARCHAR(33);
EXEC xp_HELLO @txt OUTPUT;

当 SQL Server 实例的排序规则区分大小写时,如果使用不同的大小写调用过程,则 SQL Server 无法调用扩展存储过程。 即使它注册的名称和排序规则与 DLL 中的函数完全相同,也是如此。

-- Register the function (xp_hello)
sp_addextendedproc 'xp_hello', 'c:\xp_hello.dll';

-- The following example results in an error
DECLARE @txt VARCHAR(33);
EXEC xp_HELLO @txt OUTPUT;

下面是错误消息:

Server: Msg 2812, Level 16, State 62, Line 1

无需停止并重启 SQL Server。

查询 SQL Server 中安装的扩展存储过程

经 SQL Server 身份验证的用户可以通过运行 sp_helpextendedproc 系统过程来显示当前定义的扩展存储过程和每个存储过程所属的 DLL 的名称。 例如,以下示例返回属于的 xp_hello DLL:

sp_helpextendedproc 'xp_hello';

如果在 sp_helpextendedproc 未指定扩展存储过程的情况下执行,则会显示所有扩展存储过程及其 DLL。

从 SQL Server 中删除扩展存储过程

若要在用户定义的扩展存储过程 DLL 中删除每个扩展存储过程函数,SQL Server 系统管理员必须运行 sp_dropextendedproc 系统存储过程,并指定函数的名称以及该函数所在的 DLL 的名称。 例如,此命令删除位于从 SQL Server 命名xp_hello.dll,的 DLL 中的函数xp_hello

sp_dropextendedproc 'xp_hello';

sp_dropextendedproc 不会删除系统扩展存储过程。 相反,系统管理员应拒绝EXECUTE对公共角色的扩展存储过程的权限。

卸载扩展存储过程 DLL

SQL Server 在调用 DLL 的其中一个函数后立即加载扩展存储过程 DLL。 DLL 将保持加载状态,直到服务器关闭或系统管理员使用该 DBCC 语句卸载它。 例如,此命令将卸载 xp_hello.dll,允许系统管理员将此文件的较新版本复制到目录,而无需关闭服务器:

DBCC xp_hello(FREE);