用 C++ 编写扩展存储过程






4.50/5 (21投票s)
2004年10月15日
4分钟阅读

156019

1938
用 C++ 为 SQL Server 编写扩展存储过程。
引言
本文演示了如何使用 C++ 编写 SQL Server 扩展存储过程。Visual Studio 2003 企业版提供了一个用于创建扩展存储过程的向导,但在本文中,我将展示如何在不使用向导的情况下轻松创建它们。
背景
扩展存储过程是运行在 SQL Server 地址空间内的 DLL。它们像 SQL Server 中的其他存储过程一样被访问,但首先必须在 SQL Server 中注册它们。
可以使用 sp_addextendedproc
存储过程来注册扩展存储过程。该过程接受要注册的扩展过程的名称以及托管它的 DLL 的名称。
exec sp_addextendedproc 'xp_example', 'xp_example.dll'
要删除扩展存储过程,请使用 sp_dropextendedproc
过程,并将要删除的过程的名称传递给它。
exec sp_dropextendedproc 'xp_example'
创建扩展存储过程
要在 Visual Studio 中创建扩展存储过程,您需要先创建一个标准的 DLL 项目。使用“新建项目”向导,创建一个 Win32 应用程序 C++ 项目,并将输出指定为 DLL。为了使 DLL 能够正确构建,您需要链接 opends60.lib 库。创建托管扩展存储过程的 DLL 就这么简单!您可以看到向导实际上并没有做什么。
所有扩展存储过程都具有相同的 C 签名,以便 SQL Server 可以正确执行它们。下面显示了此签名,它是 SQL Server 调用过程的入口点。
RETCODE __declspec(dllexport) xp_example(SRV_PROC *srvproc)
将参数传递给过程
编写扩展过程时首先要做的事情之一是检查从客户端传递的参数数量是否正确。下面展示了执行此操作的方法。
// Check that there are the correct number of parameters. if ( srv_rpcparams(srvproc) != 1 ) { // If there is not exactly one parameter, send an error to the client. _snprintf(spText, MAXTEXT, "ERROR. You need to pass one parameter."); srv_sendmsg( srvproc, SRV_MSG_INFO, 0,(DBTINYINT)0, (DBTINYINT)0,NULL,0,0,spText,SRV_NULLTERM); // Signal the client that we are finished. srv_senddone(srvproc, SRV_DONE_ERROR, (DBUSMALLINT)0, (DBINT)0); return XP_ERROR; }
要检查参数数量,我们调用 srv_rpcparams
方法。在此示例中,我们期望一个参数,因此如果传递的参数数量不正确,我们需要标记一个错误并停止执行该过程。
如果参数数量不正确,则使用 srv_sendmsg
方法将文本字符串发送回客户端。在此简单示例中,将返回一个带有简单消息的字符串。
发送消息后,我们需要向客户端指示存储过程已完成执行。这是使用 srv_senddone
方法完成的。您可以看到此函数的第二个参数是 SRV_DONE_ERROR
,它指示正在向客户端返回错误。最后,我们从方法中返回 XP_ERROR
。
现在我们知道了参数数量正确,我们需要获取有关它们的them信息。这是使用 srv_paraminfo
方法完成的。
// Get the info about the parameter. // Note pass NULL for the pbData parameter to get // information rather than the parameter itself. srv_paraminfo(srvproc, 1, &bType, &uMaxLen, &uLen, NULL, &bNull); // Create some memory to get the parameter in to. BYTE* Data = new BYTE[uLen]; memset(Data, '\0', uLen); // Get the parameter srv_paraminfo(srvproc, 1, &bType, &uMaxLen, &uLen, Data, &bNull);
此方法被调用两次。第一次调用将 NULL
作为 pbData
参数传递。这会导致返回保存参数所需的缓冲区大小,而不会返回参数本身。第一次调用后,会创建一个缓冲区,然后再次调用该方法。这次,参数被返回到变量 Data
中。
在结果集中创建列
要为 SQL 结果集定义列,请使用 srv_describe
方法。此方法指定列的类型(在此示例中为 SRVINT4
和 SRVCHAR
)以及列的长度(对于 char
列为 MAXTEXT
)。
// Define column 1 _snprintf(colname, MAXCOLNAME, "ID"); srv_describe(srvproc, 1, colname, SRV_NULLTERM, SRVINT4, sizeof(DBSMALLINT), SRVINT2, sizeof(DBSMALLINT), 0); // Define column 2 _snprintf(colname, MAXCOLNAME, "Hello World"); srv_describe(srvproc, 2, colname, SRV_NULLTERM, SRVCHAR, MAXTEXT, SRVCHAR, 0, NULL);
将结果返回给客户端
最后,该返回行给客户端了。如下所示,这是使用 srv_setcoldata
、srv_setcollen
和 srv_sendrow
方法完成的。
使用 srv_setcoldata
初始化每个列。最后,当所有列都定义好后,使用 srv_sendrow
方法将行发送到客户端。
// Generate "numRows" output rows. for ( long i = 1; i <= numRows; i++ ) { // Set the first column to be the count. srv_setcoldata(srvproc, 1, &i); // Set the second column to be a text string int ColLength = _snprintf(spText, MAXTEXT, "Hello from the extended stored procedure. %d", i); srv_setcoldata(srvproc, 2, spText); srv_setcollen(srvproc, 2, ColLength); // Send the row back to the client srv_sendrow(srvproc); }
结束过程
为了通知 SQL Server 处理已完成并将结果返回给客户端,我们调用 srv_senddone
方法,尽管这次我们传递的参数是 SRV_DONE_MORE|SRV_DONE_COUNT
,表示没有发生错误且执行已完成。最后一个参数指定返回给客户端的行数。
// Tell the client we're done and return the number of rows returned. srv_senddone(srvproc, SRV_DONE_MORE | SRV_DONE_COUNT, (DBUSMALLINT)0, (DBINT)i);
运行示例
要运行示例,请编译示例代码以创建名为 xp_example.dll 的 DLL,然后将此 DLL 复制到 SQL Server 的 MSSQL/Binn 目录中。以 sa
身份登录 SQL Server,并通过执行 exec sp_addextendedproc 'xp_example', 'xp_example.dll'
来注册存储过程。
然后,您可以通过执行 exec xp_example 5
来测试代码。这将生成如下所示的结果。