为MSSQL添加扩展存储过程

MSSQL添加扩展存储过程
--地宝原创,转贴请注明出自微软BI开拓者www.windbi.com

MSSQL中的sysprocesses中的hostname可以获取连接客户端的机器名,
net_address可以获取连接的客户端的网卡(或者ARP代理)Mac地址,
虽说可以通过Pinghostname的方法来获取IP地址,也可以通过建立好的
局域网Mac地址表来反查到IP地址,但我们是否能够通过任意一个局域网
IP地址来查询到hostnamemac地址呢?

MSSQL看来很难做到这一点。是否能通过曲线救国的方式来实现呢?
这是能够做到的,那就是使用vc中的Extended Stored Proc Wizard来创
建一个扩展存储过程(好像回到了过去,用vb调用vcdll ^_^)。


具体创建方法如下:

打开vc选择File->New,在对话框中选择Projects,在项目列表中选择
Extended Stored Proc Wizard,输入Project Name后,点击finishVC++
就会自动的为你创建出一个模版。


仔细看看模版是不是很简单呀!

实际上写 Extended Proc 很简单,主要就是就是这么几个函数:

1)srv_sendmsg 用来显示sql执行后的消息

2)srv_describe  用来设置描述行

3)srv_setcoldata srv_setcollen 用来显示数据行

4)srv_sendrow 将生产的数据行发送出去

5)srv_senddone 显示执行sql后所返回的数据行数


在若扩展存储涉及参数输入问题,则需注意这么几个函数

1)srv_rpcparams 返回输入参数中的个数

2)srv_paraminfo 获取输入参数的类型,如参数的长度,参数的数据类型等

3)srv_paramdata获取输入参数的数值
介绍完这些,我们就开始完成这个扩展存储过程了。以下是详细代码:

/*根据指定的IP地址返回网卡的Mac地址*/

#include <stdafx.h>
#include "stdio.h"
#include "stdlib.h"
#include "Winsock2.h"
#include "iphlpapi.h"
 
#pragma comment ( lib, "ws2_32.lib" )
#pragma comment ( lib, "Iphlpapi.lib" )
 
#define XP_NOERROR              0
#define XP_ERROR                1
#define MAXCOLNAME25
#define MAXNAME255
#define MAXTEXT255

#ifdef __cplusplus
extern "C" {
#endif

RETCODE __declspec(dllexport) xp_proc5(SRV_PROC *srvproc);

#ifdef __cplusplus
}
#endif

RETCODE __declspec(dllexport) xp_proc5(SRV_PROC *srvproc)
{

    DBSMALLINT i = 0;
    DBCHAR colname[MAXCOLNAME];

DBCHAR spText[MAXTEXT];

DBCHAR spIP[MAXTEXT];

DBCHAR spHostName[MAXTEXT];

DBCHAR spMac[18];

DBCHAR szFileName[MAX_PATH+1];


struct hostent *remoteHostent;

int numberOfHost = 1;

int nArgs = srv_rpcparams(srvproc);//检测参数个数

if (nArgs=1)

{

//初始化SOCKET

WSADATA wsaData;

int iRet =WSAStartup(MAKEWORD(2,1), &wsaData);

if ( iRet != 0 )

exit( 0 );

}


BYTE          bType;

unsigned long  cbMaxLen;

unsigned long  cbActualLen;

BOOL          fNull;


intret=srv_paraminfo(srvproc,1,&bType,&cbMaxLen,&cbActualLen,NULL,&fNull);


if (cbActualLen){

ZeroMemory(szFileName, MAX_PATH+1);

memcpy(szFileName, srv_paramdata(srvproc,1), cbActualLen);

}

else{

return XP_ERROR;

}


int nRemoteAddr=inet_addr((constchar*)szFileName);

_snprintf(spText, MAXTEXT, "%s 示例扩展存储过程", szFileName);

srv_sendmsg(

srvproc,

SRV_MSG_INFO,

0,

(DBTINYINT)0,

(DBTINYINT)0,

NULL,

0,

0,

spText,

SRV_NULLTERM);


remoteHostent= (structhostent*)malloc( sizeof(struct hostent ));

struct in_addr sa;

for ( int i = 0; i < numberOfHost;i ++ )

{

//获取远程机器名

sa.s_addr = nRemoteAddr;

_snprintf(spIP,MAXTEXT,"%s\0",inet_ntoa( sa ) );//输出IP地址

remoteHostent = gethostbyaddr((char*)&nRemoteAddr,4, AF_INET );

if ( remoteHostent )

_snprintf(spHostName,MAXTEXT,"%s\0",remoteHostent->h_name);

else

_snprintf(spHostName,5,"null");



//发送ARP查询包获得远程MAC地址


unsigned char macAddress[6];


ULONG macAddLen = 6;



iRet=SendARP(nRemoteAddr,(unsigned long)NULL,(PULONG)&macAddress, &macAddLen);

if ( iRet == NO_ERROR )

{



sprintf(spMac,"%02X-%02X-%02X-%02X-%02X-%02X",
macAddress[0],macAddress[1],macAddress[2],macAddress[3],macAddress[4],macAddress[5]);
}
else

sprintf(spMac,"null");

nRemoteAddr = htonl( ntohl(nRemoteAddr ) + 1 );
}
}


//设置列名称
    _snprintf(colname, MAXCOLNAME, "IP");
    srv_describe(srvproc, 1, colname, SRV_NULLTERM, SRVCHAR, MAXTEXT,SRVCHAR, 0, NULL);

    _snprintf(colname, MAXCOLNAME, "HOSTNAME");
    srv_describe(srvproc, 2, colname, SRV_NULLTERM, SRVCHAR, MAXNAME,SRVCHAR, 0, NULL);

    _snprintf(colname, MAXTEXT, "MAC");
    srv_describe(srvproc, 3, colname, SRV_NULLTERM, SRVCHAR, MAXTEXT,SRVCHAR, 0, NULL);

    //读进数据

srv_setcoldata(srvproc, 1, spIP);
    srv_setcollen(srvproc, 1, static_cast<int>(strlen(spIP)));

srv_setcoldata(srvproc, 2,spHostName);
    srv_setcollen(srvproc, 2,static_cast<int>(strlen(spHostName)));

srv_setcoldata(srvproc, 3, spMac);
    srv_setcollen(srvproc, 3, static_cast<int>(strlen(spMac)));


// 发送整行
    srv_sendrow(srvproc);


// 现在返回已处理的行数

srv_senddone(srvproc,SRV_DONE_MORE | SRV_DONE_COUNT, (DBUSMALLINT)0, (DBINT)i);


return XP_NOERROR ;
}

=============================
当我们编译完后,怎样添加到mssql中呢?使用sp_addextendedproc
sp_addextendedproc 'xp_proc5','dllpath'

调用方法:
xp_proc5 '10.50.80.22' --10.50.80.22为输入参数
返回效果:

IP            HOSTNAME          MAC
--------------------------------------------------------
10.50.80.22  sunshine          00-80-C8-EE-11-03   

卸载的方法:
sp_dropextendedproc 'xp_proc5'

当扩展存储在SQLServer中执行时,它要装入内存,会一直驻留在内存中,
直到SQL Server关闭,或者你用DBCC xp_proc5(Free)来释放。
==============================
最后,想获取更多的有关编写扩展存储的信息,你可以到
msdn中查询 “extendedstored procedures”
最后编辑suntt 最后编辑于 2007-05-25 14:56:45