Here is an example Extended Stored
Procedure (xp) using SQL Servers Open Data Services (ODS). Some really great
stuff. Why? Because it allows you to use a math library like CEPHES or GSL and
return values right back into T-SQL. If you compile with Jacob Navia's compiler
(LCC) you have easy access to math libraries. Visual Studio, no such luck. In
Visual Studio though, you have an easy framework for xp's to use. In LCC you
have to find the SQL Server opends60.lib file and convert it for use with LCC
and also you need to find the srv.h file and copy it into the header files
folder. There are a few other things also. It isn't tough but it is a little
more than copying and pasting like in Visual Studio. LCC has great
documentation so it is very worthwhile taking a look at. And did I also mention
that it has a math library!
An xp written in C has performance
advantages over the newer Common Language Runtime (CLR) bound languages and you
have access to difficult to write math functions. This allows you to access
functions from T-SQL that are not already present, return the values into a
stored procedure which then makes it easy to hook a UI to the results for easy
analysis.
The students t function is an
interesting function to take a look at. You can find the source code on the
internet if you search for the CEPHES math library. It is a difficult function
to write and benefits from the performance of C code. By taking a look at this function you also gain an appreciation
and insight of some excellent programming. Complementary to W. S. Gosset
Here is a simple example for Visual
Studio but without the intended function call to students t function.
Open Visual Studio. Go to File>New>Project,
pick C++ and in the dialog box pick Extended Stored Procedure dll. In the
name field enter xp_StudentsTest. Change the path to one that works for you.
Click OK. Click Finish. Now in the Solution Explorer on the right hand side
of the screen click on the proc.cpp file. Delete all of the text from this
file and copy the entire C file text from below into it. Go to the Build menu
and click Build Solution. This will build a bunch of files in the xp_StudentsTest
directory. In the Debug folder there will be a file called xp_StudentsTest.dll.
Select this and copy it in to the Binn folder under your SQL Server install
directory. I have two Binn folders on my install. Copy the dll into the Binn
folder under the directory labeled MSSQL&<NameOfServer>. Now open
the SQL script(text below) in Query Analyzer and run it!
OK, here are some warnings. There isn't
much error handling in the xp for the sake of simplicity. Once you drop the xp
stop the SQL Server service and then delete the dll. To debug C code is a
little tricky here. I just have some simple return messages. Also you don't have to compile under the
debug setting. I used Version 7 of Visual Studio and also SQL Server 2000 on a
Windows 2000 Server. If you use a different version of Visual Studio the dialog
boxes might be different. Good luck and please use a test computer!
By
C. Eric Cashon
--SQL
Script for Query Analyzer.
USE
master
GO
sp_addextendedproc
'xp_students_t', 'xp_StudentsTest.dll'
GO
DECLARE
@Number1 float
DECLARE
@Number2 int
DECLARE
@Number3 float
SET
@Number2 = 3
SET
@Number3 = 34.89723
--Student's
t prototype from LCC statistics library.
--long
double students_t(int df, long double t)
--This
example does not return this value!!!
--It
shows how it can be done. All it does is multiply
--two
input values together.
EXEC
xp_students_t @Number1 OUTPUT,
@Number2, @Number3
PRINT
@Number1
PRINT
@Number2
PRINT
@Number3
GO
--sp_dropextendedproc
'xp_students_t'
//C
code text for Visual Studio.
#include
<stdafx.h>
#include
<windows.h>
#include
<srv.h>
//Return
codes
#define
XP_NOERROR 0
#define
XP_ERROR 1
#ifdef
__cplusplus
extern
"C" {
#endif
RETCODE
__declspec(dllexport) xp_students_t(SRV_PROC *srvproc);
#ifdef
__cplusplus
}
#endif
void
printError (SRV_PROC *pSrvProc, CHAR* szErrorMsg);
ULONG
__declspec(dllexport) __GetXpVersion()
{
return ODS_VERSION;
}
//Export
the sample function.
SRVRETCODE
__declspec(dllexport) xp_students_t
(
SRV_PROC* pSrvProc
)
{
int nParams;
int nParam = 1;
SRVRETCODE rc = XP_NOERROR;
double dOutput1;
double * pOutput1;
int * pInput1;
double * pInput2;
// Need two input arguments for Students t
function and one output.
nParams = srv_rpcparams(pSrvProc);
if (nParams != 3)
{
printError
(pSrvProc, "1 failed...");
rc = XP_ERROR;
}
// Make sure first parameter is
a return (OUTPUT) parameter
if ((srv_paramstatus(pSrvProc, 1) &
SRV_PARAMRETURN) == FAIL)
{
printError
(pSrvProc, "2 failed...");
rc = XP_ERROR;
}
//Get a pointer to the 2nd argument.
if (rc == XP_NOERROR)
{
pInput1 = ((int*)srv_paramdata(pSrvProc,
2));
}
//Get a pointer to the 3rd argument.
if (rc == XP_NOERROR)
{
pInput2 =
((double*)srv_paramdata(pSrvProc, 3));
}
//Math library function location. For an
example multiply
//the two input values together. This is
where the students t
//function would be.
if (rc == XP_NOERROR)
{
dOutput1 = ((float)*pInput1)* (*pInput2);
pOutput1 =
&dOutput1;
}
// Set the output parameter
if (rc == XP_NOERROR)
{
//Send the output back to T-SQL.
if (FAIL == srv_paramset(pSrvProc, 1,
pOutput1, sizeof(dOutput1)))
{
printError (pSrvProc, "3
failed...");
return (XP_ERROR);
}
}
// Indicate that we're done.
if (rc == XP_NOERROR)
{
srv_senddone(pSrvProc, (SRV_DONE_COUNT
| SRV_DONE_MORE), 0, 0);
}
else if (rc == XP_ERROR)
{
printError (pSrvProc, "XP
encountered an error.");
}
return (rc);
}
//Send
error message to client. Useful for basic debugging.
void
printError (SRV_PROC *pSrvProc, CHAR* pErrorMsg)
{
srv_sendmsg(pSrvProc, SRV_MSG_ERROR,
XP_ERROR, SRV_INFO, 1,
NULL, 0, (DBUSMALLINT) __LINE__,
pErrorMsg,
SRV_NULLTERM);
srv_senddone(pSrvProc, (SRV_DONE_ERROR |
SRV_DONE_MORE), 0, 0);
}