Chinaunix首页 | 论坛 | 博客
  • 博客访问: 531185
  • 博文数量: 576
  • 博客积分: 40000
  • 博客等级: 大将
  • 技术积分: 5020
  • 用 户 组: 普通用户
  • 注册时间: 2008-10-13 14:47
文章分类

全部博文(576)

文章存档

2011年(1)

2008年(575)

我的朋友

分类:

2008-10-14 14:53:40

问题的提出:
一般我们要根据数据库的纪录变化时,进行某种操作。我们习惯的操作方式是在程序中不停的查询表,判断是否有新纪录。这样耗费的资源就很高,如何提高这种效率,我想在表中创建触发器,在触发器中调用外部动态连接库通过消息或事件通知应用程序就可实现。而master的存储过程中最好能调用外部的动态连接库,我们在触发器中调用master的存储过程即可。

大小:14K

说明:VC6需要安装较新的Platform SDK才能顺利编译本代码,VC.Net可以直接编译本代码。另外还需要连接Opends60.lib
为了使没有较新Platform SDK的朋友也能编译本例子,已经将VC.Net中的Srv.h和Opends60.lib放到压缩包中

程序实现:
我们来实现一个存储过程中调用外部的dll(storeproc.dll)的函数SetFileName和addLine。

存储过程如下(需放到master库中):
CREATE PROCEDURE sp_testdll AS

exec sp_addextendedproc 'SetFileName', 'storeproc.dll'	--声明函数
exec sp_addextendedproc 'addLine', 'storeproc.dll'		

declare @szFileName varchar(200)					
declare @szText varchar(200)
declare @rt int

Select @szFileName = 'c:\welcome.txt'

EXEC @rt = SetFileName @szFileName	--调用SetFileName函数,参数为--szFileName;
if @rt = 0
begin
select @szText = 'welcome 01'
Exec @rt = addLine @szText					--调用addLine
select @szText = 'welcome 02'
Exec @rt = addLine @szText

end
exec sp_dropextendedproc 'SetFileName'
exec sp_dropextendedproc 'addLine'

dbcc SetFileName(free)
dbcc addLine(free)
动态连接库的实现:这种动态连接库和普通的有所不同。该动态连接库要放入SQL的执行目录下,或直接放到Window的System32目录下,并重起SQL-Server
#include 
#include 			//要加入这个.h文件

#define XP_NOERROR      0
#define XP_ERROR        1

#ifndef _DEBUG
#define _DEBUG
#endif

char szFileName[MAX_PATH+1];

void WriteInfo(const char * str);

extern "C" SRVRETCODE WINAPI SetFileName(SRV_PROC* pSrvProc)
{
	WriteInfo("SetFileName start");
	int paramCount = srv_rpcparams(pSrvProc);
	if (paramCount != 1){
		WriteInfo("Param Err start");
		return XP_ERROR;
	}

	BYTE		bType;
	unsigned long	cbMaxLen;
	unsigned long	cbActualLen;
	BOOL		fNull;

	int ret = srv_paraminfo(pSrvProc, 1, &bType, &cbMaxLen, &cbActualLen,
		        NULL, &fNull);
	if (cbActualLen){
		ZeroMemory(szFileName, MAX_PATH+1);
		memcpy(szFileName, srv_paramdata(pSrvProc, 1), cbActualLen);
		WriteInfo("Set filename ok");
		return (XP_NOERROR);
	}
	else {
		WriteInfo("Set filename param failed");
		return XP_ERROR;
	}
}

extern "C" SRVRETCODE WINAPI addLine(SRV_PROC* pSrvProc)
{
	WriteInfo("addline start");
	int paramCount = srv_rpcparams(pSrvProc);
	if (paramCount != 1){
		WriteInfo("addline param err");
		return XP_ERROR;
	}

	BYTE        	bType;
	unsigned long	cbMaxLen;
	unsigned long	cbActualLen;
	BOOL		fNull;
	bool		rt = false;

	int ret = srv_paraminfo(pSrvProc, 1, &bType, &cbMaxLen, &cbActualLen,
		        NULL, &fNull);

	if (cbActualLen){
		int n;
		char srt[3] = {0x0d, 0x0a, 0};

		char * c = new char[cbActualLen + 3];
		if (!c)return XP_ERROR;

		ZeroMemory(c, cbActualLen + 3);
		memcpy(c, srv_paramdata(pSrvProc, 1), cbActualLen);
		memcpy(c+cbActualLen, srt, 3);

		HANDLE hf = CreateFile(szFileName, GENERIC_WRITE, FILE_SHARE_WRITE|FILE_SHARE_READ, NULL, 
			          OPEN_ALWAYS, 0, NULL);
		if (hf == INVALID_HANDLE_VALUE){
			WriteInfo("addline create file err ");
			delete []c;
			return XP_ERROR;
		}

		WriteInfo("addline create file ok ");
		DWORD dwWt;
		n = strlen(c);
		SetFilePointer(hf, 0, NULL, FILE_END);
		if (WriteFile(hf, c, n, &dwWt, NULL) && dwWt == n)
		{
			WriteInfo("addline write file ok ");
			rt = true;
		}
		delete []c;
		CloseHandle(hf);
	}
	return rt ? XP_NOERROR:XP_ERROR;
}

inline void WriteInfo(const char * str){
    #ifdef _DEBUG
	char srt[3] = {0x0d, 0x0a, 0};
	HANDLE hf = CreateFile("c:\\storeproc.log", GENERIC_WRITE, FILE_SHARE_WRITE|FILE_SHARE_READ, NULL, 
			          OPEN_ALWAYS, 0, NULL);
	if (hf != INVALID_HANDLE_VALUE){
		SetFilePointer(hf, 0, NULL, FILE_END);
		DWORD dwWt;
		WriteFile(hf, str, strlen(str), &dwWt, NULL);
		WriteFile(hf, srt, strlen(srt), &dwWt, NULL);
		CloseHandle(hf);
	}
	else {
		MessageBox(NULL, "Write info err", "Message", MB_OK|MB_ICONINFORMATION);
	}
	#endif
}

BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpReserved)
{
	return TRUE;
}
编译完成后,把动态链接库放到WINNT/System32目录下,启动SQL Server。我们可以打开SQL Server Query Analyzer调用存储过程sp_testdll以测试其运行是否正确。

具体可参考SQL-Server的在线帮助。
笔者环境:win2000 professional + SQL-Server7.0(2000也可)
VC6.0+SP5+Platform SDK 20001.8

VC知识库测试环境:win2000 professional + SQL-Server 7.0 + VC.Net
--------------------next---------------------

是不是只能用  SAMPLE DLL  用MFC 的总出错 ( windcao 发表于 2003-12-27 17:01:00)
 

有错误提示但是也正常了,不知道为何??


( feifei2001 发表于 2003-1-9 18:34:00)
 
Cannot add rows to sysdepends for the current stored procedure because it depends on the missing object 'SetFileName'. The stored procedure will still be created.
Cannot add rows to sysdepends for the current stored procedure because it depends on the missing object 'addLine'. The stored procedure will still be created.
Cannot add rows to sysdepends for the current stored procedure because it depends on the missing object 'addLine'. The stored procedure will still be created.
( feifei2001 发表于 2003-1-9 18:32:00)
 
请问这是什么错?:--------------------Configuration: StoreProc - Win32 Release--------------------
Compiling...
main.cpp
E:\qh_fwk\vc\th_unis\down_src\在存储过程中调用外部的动态连接库\main.cpp(29) : error C2065: 'srv_paraminfo' : undeclared identifier
Error executing cl.exe.

StoreProc.dll - 1 error(s), 0 warning(s)
-------------------------------------------------

This fault is caused by using a wrong included head file , which is located in the second line of main.cpp.

#include 
it shoud be substituted by the following line:
#include "srv_net.h"
 

( richard chang 发表于 2002-8-30 10:41:00)
 
--------------------Configuration: StoreProc - Win32 Release--------------------
Compiling...
main.cpp
E:\qh_fwk\vc\th_unis\down_src\在存储过程中调用外部的动态连接库\main.cpp(29) : error C2065: 'srv_paraminfo' : undeclared identifier
Error executing cl.exe.

StoreProc.dll - 1 error(s), 0 warning(s)


( 请问这是什么错? 发表于 2002-6-7 10:14:00)
 
请教一个问题:
我创建了一个trigger,调用sp_testdll,想触发执行该存储过程,但是出了下面的一些错误信息提示,并不象你在文章中提到的可以调用。请问是什么原因?

服务器: 消息 15002,级别 16,状态 1,过程 sp_addextendedproc,行 12
不能在事务内部执行过程 'sp_addextendedproc'。
服务器: 消息 15002,级别 16,状态 1,过程 sp_addextendedproc,行 12
不能在事务内部执行过程 'sp_addextendedproc'。
服务器: 消息 2812,级别 16,状态 62,行 12
未能找到存储过程 'SetFileName'。
语句已终止。
( running 发表于 2002-4-12 0:57:00)
 
.......................................................

--------------------next---------------------

阅读(371) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~