home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / dbmsg / sql / ods / xp / xp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-04-03  |  30.6 KB  |  1,053 lines

  1. // This is an example of an extended procedure DLL built with Open Data
  2. // Services. The functions within the DLL can be invoked by using the extended
  3. //    stored procedures support in SQL Server.  To register the functions 
  4. // and allow all users to use them run the ISQL script INSTXP.SQL.
  5. //
  6. // For further information on Open Data Services refer to the Microsoft Open 
  7. // Data Services Programmer's Reference.
  8. //
  9. //  The extended procedures implemented in this DLL are:
  10. //
  11. //  XP_PROCLIST    Returns all this DLL's extended stored procedures and 
  12. //                    their usuage.
  13. //
  14. //     XP_DISKLIST    Returns a row for each defined drive containing its name 
  15. //                    and the amount of disk space available.
  16. //
  17. //  XP_DISKFREE   Returns the amount of space available on a given drive.
  18. //             The value is placed into the defined return parameter of
  19. //             the stored procedure.
  20. //
  21. //  XP_SCAN_XBASE    Reads an xBase file and sends it to the client as if it 
  22. //                    were a SQL Server query result set (the equivalent of a 
  23. //                    'SELECT * FROM tablename' SQL statement).
  24. //
  25. //  XP_ECHO        Used to demo the handling of output parameters in
  26. //                    extended procedures.
  27. //
  28. //  XP_TRACE    Used to show the installation and removal of pre-handlers
  29. //                    for language and rpc events. The pre-handlers installed
  30. //                    just print langauge and rpc events to the console in
  31. //                    readable form.  Start SQL Server at the command line
  32. //                    to see the output.
  33. //
  34.  
  35. #include <stdlib.h>
  36. #include <stdio.h>
  37. #include <string.h>
  38. #include <ctype.h>
  39. #include <windows.h>
  40. #include <srv.h>
  41. #include <time.h>
  42.  
  43. // Miscellaneous defines
  44. //
  45. #define  XP_NOERROR        0
  46. #define  XP_ERROR        1
  47.  
  48. #define  MAXNAME       31    // Maximum extended procedure name length
  49. #define  MAXLEN        80    // Maximum string length
  50. #define  COMMAND_PARAM    1    // Command Parameter
  51. #define  OUTPUT_PARAM    2    // Command Parameter
  52.  
  53. // Extended procedure error codes
  54. //
  55. #define  SRV_MAXERROR           20000
  56. #define  XP_PROCLIST_ERROR      SRV_MAXERROR + 1
  57. #define  CMDSHELL_ERROR         SRV_MAXERROR + 2
  58. #define  DISKLIST_ERROR         SRV_MAXERROR + 3
  59. #define  SCAN_XBASE_ERROR       SRV_MAXERROR + 4
  60. #define  TRACE_ERROR              SRV_MAXERROR + 6
  61.  
  62. // Standard error macro for reporting API errors
  63. //
  64. #define SETERROR( api, retstring)               \
  65.     sprintf(retstring,"%s: Error %d from %s on line %d\n",  \
  66.         __FILE__, GetLastError(), api, __LINE__);
  67.  
  68. // SCAN_XBASE defines
  69. //
  70. #define XBASE_HDR_SIZE          32
  71. #define XBASE_MAX_COLUMNS         128
  72. #define XBASE_BUF_SIZE            2048
  73.  
  74. // function prototypes for xp_trace callbacks
  75. SRVRETCODE trace_lang(SRV_PROC *);
  76. SRVRETCODE trace_rpc(SRV_PROC *);
  77.  
  78. // Stored Procedure information structure.
  79. //
  80. typedef struct xp_info {
  81.     DBCHAR name[MAXNAME];       // Extended procedure name
  82.     DBCHAR usage[MAXLEN];           // Usage string
  83. } XP_INFO;
  84.  
  85. // Array of Extended Stored Procedures supported by this DLL.
  86. //
  87. XP_INFO Xps[] = 
  88. {
  89.     "xp_proclist",                    // Procedure name
  90.     "usage: xp_proclist",             // Procedure usage string
  91.  
  92.     "xp_disklist",
  93.     "usage: xp_disklist",
  94.  
  95.     "xp_diskfree",
  96.     "usage: xp_diskfree <[@drive =] drive letter> [,] <[@space =] free space>",
  97.  
  98.     "xp_scan_xbase",
  99.     "usage: xp_scan_xbase <xbase file name>",
  100.  
  101.     "xp_echo",
  102.     "usage: xp_echo @p1=<input> , @p2=<output-param> output",
  103.  
  104.     "xp_trace",
  105.     "usage: xp_trace <[@state=] 'on'|'off'> [, [@users=] NULL | 'all']",
  106. };
  107. #define Xpcnumber sizeof(Xps) / sizeof(XP_INFO)
  108.  
  109. //
  110. // PROCLIST
  111. //    Returns the usage for all defined stored procedures
  112. //
  113. // Parameters:
  114. //    srvproc - the handle to the client connection that got the SRV_CONNECT.
  115. //
  116. // Returns:
  117. //    XP_NOERROR
  118. //    XP_ERROR
  119. //
  120. // Side Effects:
  121. //    Returns a result set to client
  122. //
  123. SRVRETCODE xp_proclist(srvproc)
  124. SRV_PROC *srvproc;
  125. {
  126.     int paramnum;
  127.     DBCHAR colname1[MAXNAME];
  128.     DBCHAR colname2[MAXNAME];
  129.     int i;
  130.  
  131.     // Get number of parameters
  132.     //
  133.     paramnum = srv_rpcparams(srvproc);
  134.  
  135.     // Check number of parameters
  136.     //
  137.     if (paramnum != -1) {
  138.         // Send error message and return
  139.         //
  140.         srv_sendmsg(srvproc, SRV_MSG_ERROR, XP_PROCLIST_ERROR, SRV_INFO, (DBTINYINT)0,
  141.                     NULL, 0, 0, "Error executing extended stored procedure: Invalid Parameter",
  142.                     SRV_NULLTERM);
  143.            // A SRV_DONE_MORE instead of a SRV_DONE_FINAL must complete the
  144.            // result set of an Extended Stored Procedure.
  145.            //
  146.         srv_senddone(srvproc, (SRV_DONE_ERROR | SRV_DONE_MORE), 0, 0);
  147.     return(XP_ERROR);
  148.     }
  149.  
  150.     sprintf(colname1, "spname");
  151.     srv_describe(srvproc, 1, colname1, SRV_NULLTERM, SRVCHAR, MAXNAME,
  152.                  SRVCHAR, 0, NULL);
  153.  
  154.     sprintf(colname2, "spusage");
  155.     srv_describe(srvproc, 2, colname2, SRV_NULLTERM, SRVCHAR, MAXLEN, SRVCHAR,
  156.                  0, NULL);
  157.  
  158.     // Return each XP handler as a row
  159.     //
  160.     for (i = 0; i < Xpcnumber; i++) {
  161.         srv_setcoldata(srvproc, 1, Xps[i].name);
  162.         srv_setcollen(srvproc, 1, strlen(Xps[i].name));
  163.  
  164.         srv_setcoldata(srvproc, 2, Xps[i].usage);
  165.         srv_setcollen(srvproc, 2, strlen(Xps[i].usage));
  166.  
  167.         srv_sendrow(srvproc);
  168.     }
  169.      // A SRV_DONE_MORE instead of a SRV_DONE_FINAL must complete the
  170.      // result set of an Extended Stored Procedure.
  171.      //
  172.     srv_senddone(srvproc, (SRV_DONE_COUNT | SRV_DONE_MORE), 0, i);
  173.  
  174.     return(XP_NOERROR);
  175. }
  176.  
  177. //
  178. // XP_ECHO
  179. //    Used to demo the handling of output parameters in extended procedures.
  180. //    The first parameter should be the input parameter and the second
  181. //    parameter should be the output.  The input parameter is placed in the
  182. //    output parameter and returned.
  183. //
  184. // Parameters:
  185. //    srvproc - the handle to the client connection that got the SRV_CONNECT.
  186. //
  187. // Returns:
  188. //    XP_NOERROR
  189. //    XP_ERROR
  190. //
  191. //
  192.  
  193. SRVRETCODE xp_echo(srvproc)
  194. SRV_PROC *srvproc;
  195. {
  196.     int paramnum;
  197.  
  198.     // Check number of parameters
  199.     //
  200.     if ((paramnum = srv_rpcparams(srvproc)) != 2) {
  201.         // Send error message and return
  202.         //
  203.         srv_sendmsg(srvproc, SRV_MSG_ERROR, CMDSHELL_ERROR, SRV_INFO, (DBTINYINT)0,
  204.             NULL, 0, 0, "Error executing extended stored procedure: Invalid # of Parameters",
  205.                     SRV_NULLTERM);
  206.          // A SRV_DONE_MORE instead of a SRV_DONE_FINAL must complete the
  207.          // result set of an Extended Stored Procedure.
  208.          //
  209.         srv_senddone(srvproc, (SRV_DONE_ERROR | SRV_DONE_MORE), 0, 0);
  210.     return(XP_ERROR);
  211.     }
  212.  
  213.     // Set output parameter to input parameter.
  214.     //
  215.  
  216.     srv_paramset(srvproc, 2, srv_paramdata(srvproc,1), srv_paramlen(srvproc,1));
  217.  
  218.     srv_senddone(srvproc, SRV_DONE_MORE, 0, 0);
  219.  
  220.     return(XP_NOERROR);
  221.  
  222. }
  223.  
  224. //
  225. // XP_DISKLIST
  226. //     Returns a row for each defined drive containing its name and the
  227. //     amount of disk space available.
  228. //
  229. // Parameters:
  230. //    srvproc - the handle to the client connection that got the SRV_CONNECT.
  231. //
  232. // Returns:
  233. //    XP_NOERROR
  234. //    XP_ERROR
  235. //
  236. // Side Effects:
  237. //     Returns a result set to client
  238. //
  239. SRVRETCODE xp_disklist(srvproc)
  240. SRV_PROC *srvproc;
  241. {
  242.     int paramnum;
  243.     DBCHAR colname1[MAXNAME];
  244.     DBCHAR colname2[MAXNAME];
  245.     DBCHAR drivename;
  246.     DBCHAR rootname[16];
  247.     int drivenum;
  248.     int secPerCluster;
  249.     int bytesPerSector;
  250.     int freeClusters;
  251.     int totalClusters;
  252.     int drivenums;
  253.     int space_remaining;
  254.     int i = 0;
  255.  
  256.     // Get number of parameters
  257.     //
  258.     paramnum = srv_rpcparams(srvproc);
  259.  
  260.     // Check number of parameters
  261.     //
  262.     if (paramnum != -1) {
  263.         // Send error message and return
  264.         //
  265.         srv_sendmsg(srvproc, SRV_MSG_ERROR, DISKLIST_ERROR, SRV_INFO, (DBTINYINT)0,
  266.                     NULL, 0, 0, "Error executing extended stored procedure: Invalid Parameter",
  267.                     SRV_NULLTERM);
  268.          // A SRV_DONE_MORE instead of a SRV_DONE_FINAL must complete the
  269.          // result set of an Extended Stored Procedure.
  270.          //
  271.         srv_senddone(srvproc, (SRV_DONE_ERROR | SRV_DONE_MORE), 0, 0);
  272.     return(XP_ERROR);
  273.     }
  274.     sprintf(colname1, "drive");
  275.     srv_describe(srvproc, 1, colname1, SRV_NULLTERM, SRVCHAR, 1, SRVCHAR, 1,
  276.                  (BYTE *)&drivename);
  277.  
  278.     sprintf(colname2, "bytes free");
  279.     srv_describe(srvproc, 2, colname2, SRV_NULLTERM, SRVINT4, 4, SRVINT4, 4,
  280.                  (BYTE *)&space_remaining);
  281.  
  282.     drivenums = GetLogicalDrives();
  283.  
  284.     drivenums >>= 2;        //Ignore drives A and B
  285.     for (drivename = 'C', drivenum = 3; drivename <= 'Z';
  286.          drivename++, drivenum++) {
  287.  
  288.         if (drivenums & 1) {
  289.             i++;
  290.             sprintf(rootname, "%c:\\", drivename);
  291.             GetDiskFreeSpace(rootname, &secPerCluster, &bytesPerSector,
  292.                              &freeClusters, &totalClusters);
  293.             space_remaining = secPerCluster * freeClusters * bytesPerSector;
  294.  
  295.             srv_sendrow(srvproc);
  296.         }
  297.         drivenums >>= 1;
  298.     }
  299.     // A SRV_DONE_MORE instead of a SRV_DONE_FINAL must complete the
  300.     // result set of an Extended Stored Procedure.
  301.     //
  302.     srv_senddone(srvproc, (SRV_DONE_COUNT | SRV_DONE_MORE), 0, i);
  303.     return(XP_NOERROR);
  304. }
  305.  
  306.  
  307. //
  308. // XP_DISKFREE
  309. //    Returns the amount of space available on a given drive. The value
  310. //     is placed into the defined return parameter of the stored procedure.
  311. //
  312. // Parameters:
  313. //    srvproc - the handle to the client connection that got the SRV_CONNECT.
  314. //
  315. // Returns:
  316. //    XP_NOERROR
  317. //    XP_ERROR
  318. //
  319. // Side Effects:
  320. //    Returns messages and/or a result set to client. Returns a value in the
  321. //     defined return parameter.
  322. //
  323. SRVRETCODE xp_diskfree(srvproc)
  324. SRV_PROC *srvproc;
  325. {
  326.     DBCHAR *drive;
  327.     DBCHAR colname1[MAXNAME];
  328.     DBCHAR colname2[MAXNAME];
  329.     DBINT paramlength;
  330.     DBCHAR rootname[16];
  331.     DBCHAR bErrorMsg[MAXLEN];
  332.  
  333.     int drivenum;
  334.     int drivenums;
  335.     int secPerCluster;
  336.     int bytesPerSector;
  337.     int freeClusters;
  338.     int totalClusters;
  339.     int space_remaining = -1;
  340.  
  341.     // Check number of parameters
  342.     //
  343.     if (srv_rpcparams(srvproc) > 0) {
  344.  
  345.     // Allocation local storage for drive name.
  346.     //
  347.     paramlength = srv_paramlen(srvproc, 1);
  348.     drive = (DBCHAR *)malloc(paramlength);
  349.     if (!drive) {
  350.  
  351.         SETERROR("Malloc", bErrorMsg);
  352.         srv_sendmsg(srvproc, SRV_MSG_ERROR, CMDSHELL_ERROR, SRV_INFO, (DBTINYINT)0,
  353.                NULL, 0, 0, bErrorMsg, SRV_NULLTERM);
  354.         // A SRV_DONE_MORE instead of a SRV_DONE_FINAL must complete the
  355.         // result set of an Extended Stored Procedure.
  356.         //
  357.         srv_senddone(srvproc, (SRV_DONE_ERROR | SRV_DONE_MORE), 0, 0);
  358.         return(XP_ERROR);
  359.     }
  360.  
  361.     // Fetch drive letter.
  362.     srv_bmove(srv_paramdata(srvproc, 1), drive, paramlength);
  363.     drive = strupr(drive);
  364.  
  365.     } else
  366.  
  367.     // Default drive is C.
  368.     drive = "C";
  369.  
  370.     drivenums = GetLogicalDrives();
  371.     drivenum = drive[0] - 'A' + 1;
  372.  
  373.     drivenums >>= drivenum - 1; //Ignore drives A and B
  374.     if (drivenums & 0x01) {
  375.  
  376.         sprintf(rootname, "%c:\\", drive[0]);
  377.         GetDiskFreeSpace(rootname, &secPerCluster, &bytesPerSector,
  378.                          &freeClusters, &totalClusters);
  379.  
  380.         space_remaining = secPerCluster * freeClusters * bytesPerSector;
  381.  
  382.     }
  383.  
  384.     // Process return values
  385.     //
  386.     if (srv_paramstatus(srvproc, 2) < 0 ) {
  387.     // Setup column heading
  388.     sprintf(colname1, "drive");
  389.     sprintf(colname2, "space");
  390.     srv_describe(srvproc, 1, colname1, SRV_NULLTERM, SRVCHAR, 1, SRVCHAR, 1,
  391.              (BYTE *)drive);
  392.     srv_describe(srvproc, 2, colname2, SRV_NULLTERM,
  393.              SRVINT4, sizeof(space_remaining), SRVINT4,
  394.              sizeof(space_remaining), &space_remaining);
  395.  
  396.     srv_sendrow(srvproc);
  397.     srv_senddone(srvproc, (SRV_DONE_COUNT | SRV_DONE_MORE), 0, 1);
  398.  
  399.    }
  400.     else {
  401.     srv_paramset(srvproc, 2, (BYTE *)&space_remaining, 4);
  402.     srv_senddone(srvproc, SRV_DONE_MORE, 0, 0);
  403.     }
  404.  
  405.     return(XP_NOERROR);
  406. }
  407.  
  408.  
  409.  
  410. //
  411. // XP_SCAN_XBASE
  412. //    Reads an xBase file and sends it to the client as if it were a SQL
  413. //    Server query result set (the equivalent of a 'SELECT * FROM
  414. //    tablename' SQL statement).
  415. //
  416. // Parameters:
  417. //    srvproc - the handle to the client connection that got the SRV_CONNECT.
  418. //
  419. // Returns:
  420. //    XP_NOERROR
  421. //    XP_ERROR
  422. //
  423. // Side Effects:
  424. //    Returns messages and/or a result set to client
  425. //
  426. SRVRETCODE xp_scan_xbase(srvproc)
  427. SRV_PROC *srvproc;
  428. {
  429.     int paramnum;
  430.     DBINT paramtype;
  431.     DBCHAR *filename;
  432.     FILE *xbasefile;
  433.     size_t count;
  434.     char buffer[XBASE_BUF_SIZE];
  435.     short numrecords;
  436.     short headerlength;
  437.     short recordlength;
  438.     short lengthlist[XBASE_MAX_COLUMNS];
  439.     int i;
  440.     short j;
  441.     short position;
  442.     short numcolumns;
  443.  
  444.     // Get number of parameters
  445.     //
  446.     paramnum = srv_rpcparams(srvproc);
  447.  
  448.     // Check number of parameters
  449.     //
  450.     if (paramnum != 1) {
  451.         // Send error message and return
  452.         //
  453.         srv_sendmsg(srvproc, SRV_MSG_ERROR, SCAN_XBASE_ERROR, SRV_INFO, (DBTINYINT)0,
  454.                     NULL, 0, 0, "Error executing extended stored procedure: Invalid Parameter",
  455.                     SRV_NULLTERM);
  456.          // A SRV_DONE_MORE instead of a SRV_DONE_FINAL must complete the
  457.          // result set of an Extended Stored Procedure.
  458.          //
  459.         srv_senddone(srvproc, (SRV_DONE_ERROR | SRV_DONE_MORE), 0, 0);
  460.     return(XP_ERROR);
  461.     }
  462.  
  463.     // Check parameters for correct type
  464.     //
  465.     paramtype = srv_paramtype(srvproc, paramnum);
  466.     if (paramtype != SRVVARCHAR) {
  467.         // Send error message and return
  468.         //
  469.         srv_sendmsg(srvproc, SRV_MSG_ERROR, SCAN_XBASE_ERROR, SRV_INFO, (DBTINYINT)0,
  470.                     NULL, 0, 0,
  471.                     "Error executing extended stored procedure: Invalid Parameter Type",
  472.                     SRV_NULLTERM);
  473.          // A SRV_DONE_MORE instead of a SRV_DONE_FINAL must complete the
  474.          // result set of an Extended Stored Procedure.
  475.          //
  476.         srv_senddone(srvproc, (SRV_DONE_ERROR | SRV_DONE_MORE), 0, 0);
  477.     return(XP_ERROR);
  478.     }
  479.     filename = srv_paramdata(srvproc, 1);
  480.  
  481.     // now read the database header info
  482.     //
  483.     if ((xbasefile = fopen(filename, "r")) == NULL) {
  484.         srv_sendmsg(srvproc, SRV_MSG_ERROR, SCAN_XBASE_ERROR, SRV_INFO, (DBTINYINT)0,
  485.                     NULL, 0, 0, "Error reading xBase file", SRV_NULLTERM);
  486.          // A SRV_DONE_MORE instead of a SRV_DONE_FINAL must complete the
  487.          // result set of an Extended Stored Procedure.
  488.          //
  489.         srv_senddone(srvproc, (SRV_DONE_ERROR | SRV_DONE_MORE), 0, 0);
  490.     return(XP_ERROR);
  491.     }
  492.     count = fread(buffer, XBASE_HDR_SIZE, 1, xbasefile);
  493.  
  494.     if (count == 0) {
  495.         srv_sendmsg(srvproc, SRV_MSG_ERROR, SCAN_XBASE_ERROR, SRV_INFO, (DBTINYINT)0,
  496.                     NULL, 0, 0, "Error reading xBase file", SRV_NULLTERM);
  497.          // A SRV_DONE_MORE instead of a SRV_DONE_FINAL must complete the
  498.          // result set of an Extended Stored Procedure.
  499.          //
  500.         srv_senddone(srvproc, (SRV_DONE_ERROR | SRV_DONE_MORE), 0, 0);
  501.         fclose(xbasefile);
  502.     return(XP_ERROR);
  503.     }
  504.     numrecords = *((short *)&buffer[4]);
  505.     headerlength = *((short *)&buffer[8]);
  506.     recordlength = *((short *)&buffer[10]);
  507.     numcolumns = (headerlength - 32 - 1) / 32;
  508.  
  509.     // now get the column header information
  510.     //
  511.     for (j = 0; j < numcolumns; j++) {
  512.         count = fread(buffer,
  513.         XBASE_HDR_SIZE,
  514.         1,
  515.         xbasefile);
  516.         if (count == 0) {
  517.             srv_sendmsg(srvproc, SRV_MSG_ERROR, SCAN_XBASE_ERROR, SRV_INFO, (DBTINYINT)0,
  518.                         NULL, 0, 0, "Error reading xBase file", SRV_NULLTERM);
  519.              // A SRV_DONE_MORE instead of a SRV_DONE_FINAL must complete the
  520.              // result set of an Extended Stored Procedure.
  521.              //
  522.             srv_senddone(srvproc, (SRV_DONE_ERROR | SRV_DONE_MORE), 0, 0);
  523.             fclose(xbasefile);
  524.         return(XP_ERROR);
  525.         }
  526.  
  527.         // we need to NULL terminate the column name (if it is a
  528.         // full 11 characters int)
  529.         //
  530.         buffer[11] = '\0';
  531.  
  532.         // now find our the column length for this data buffer
  533.         //
  534.         lengthlist[j] = (short)buffer[16];
  535.  
  536.         // now 'describe' this column
  537.         //
  538.         srv_describe(srvproc, j + 1,// column number
  539.                 buffer,     // pointer to column name
  540.                 SRV_NULLTERM,// column name is NULL terminated
  541.                 SRVCHAR,    // datatype is char (xBase numbers are ASCII
  542.                 lengthlist[j],// column length
  543.                 SRVCHAR,    // destination datatype is also char
  544.                 lengthlist[j],// destination column length
  545.                 NULL);      // pointer to where the data will be
  546.  
  547.     }
  548.     // now read the one byte 'column header seperator'
  549.     //
  550.     count = fread(buffer, 1, 1, xbasefile);
  551.     if (count == 0) {
  552.         srv_sendmsg(srvproc, SRV_MSG_ERROR, SCAN_XBASE_ERROR, SRV_INFO, (DBTINYINT)0,
  553.                     NULL, 0, 0, "Error reading xBase file", SRV_NULLTERM);
  554.          // A SRV_DONE_MORE instead of a SRV_DONE_FINAL must complete the
  555.          // result set of an Extended Stored Procedure.
  556.          //
  557.         srv_senddone(srvproc, (SRV_DONE_ERROR | SRV_DONE_MORE), 0, 0);
  558.         fclose(xbasefile);
  559.     return(XP_ERROR);
  560.     }
  561.     for (i = 0; i < numrecords; i++) {
  562.         count = fread(buffer, recordlength, 1, xbasefile);
  563.         if (count == 0 && !feof(xbasefile)) {
  564.             srv_sendmsg(srvproc, SRV_MSG_ERROR, SCAN_XBASE_ERROR, SRV_INFO, (DBTINYINT)0,
  565.                         NULL, 0, 0, "Error reading xBase file", SRV_NULLTERM);
  566.              // A SRV_DONE_MORE instead of a SRV_DONE_FINAL must complete the
  567.              // result set of an Extended Stored Procedure.
  568.              //
  569.             srv_senddone(srvproc, (SRV_DONE_ERROR | SRV_DONE_MORE), 0, 0);
  570.             fclose(xbasefile);
  571.         return(XP_ERROR);
  572.         }
  573.  
  574.         // check to see if this is a deleted row
  575.         //
  576.         if (buffer[0] == '*')
  577.             break;
  578.  
  579.         // Now set the length and data pointers for each column
  580.         for (j = 0, position = 1; j < numcolumns; j++) {
  581.             srv_setcollen(srvproc, j + 1, lengthlist[j]);
  582.             srv_setcoldata(srvproc, j + 1, &buffer[position]);
  583.             position += lengthlist[j];
  584.         }
  585.  
  586.         // send the row to the client.
  587.         //
  588.         srv_sendrow(srvproc);
  589.     }
  590.      // A SRV_DONE_MORE instead of a SRV_DONE_FINAL must complete the
  591.      // result set of an Extended Stored Procedure.
  592.      //
  593.     srv_senddone(srvproc, SRV_DONE_COUNT | SRV_DONE_MORE, 0, i);
  594.     fclose(xbasefile);
  595.     return(XP_NOERROR);
  596. }
  597.  
  598. //
  599. // XP_TRACE
  600. //    Used to demo the proc-specific pre-handlers in extended procedures.
  601. //    Parameter 1 is @state, "on" or "off" to install or remove.  
  602. //    Parameter 2 is @users, NULL to install pre-handlers on this
  603. //        srvproc only , or 'all' to install server-wide pre-handlers
  604. //
  605. // Parameters:
  606. //    srvproc - the handle to the client connection that got the SRV_CONNECT.
  607. //
  608. // Returns:
  609. //    XP_NOERROR
  610. //    XP_ERROR
  611. //
  612.  
  613. SRVRETCODE xp_trace(srvproc)
  614. SRV_PROC *srvproc;
  615. {
  616.     int      numparams;
  617.     DBCHAR * paramname;
  618.     int      i;
  619.     int      position;
  620.     int      len;
  621.     DBINT    paramtype;
  622.     DBINT    paramlength;
  623.     char state[4];
  624.     char users[4];
  625.     char timestr[9];
  626.     char *errmsg;
  627.     SRV_SERVER *server;
  628.     int    retcode;
  629.  
  630.     state[0] = '\0';
  631.     users[0] = '\0';
  632.  
  633.     // Check parameters
  634.     // Support both named and positional parameters
  635.     //
  636.     numparams = srv_rpcparams( srvproc );
  637.  
  638.     if ((numparams < 1) || (numparams > 2)) {
  639.         errmsg = "Error: Invalid number of Parameters";
  640.         goto ErrorExit;                    
  641.     }    
  642.  
  643.     for( i = 1; i <= numparams; i++ )
  644.     {
  645.         paramname = srv_paramname( srvproc, i, &len );
  646.  
  647.         if( len )
  648.         {
  649.             if( !stricmp(paramname, "@state") )
  650.                 position = 1;
  651.             else if( !stricmp(paramname, "@users") )
  652.                 position = 2;
  653.             else {
  654.                 srv_sendmsg( srvproc,SRV_MSG_ERROR,TRACE_ERROR,
  655.                              16,(DBTINYINT)1,NULL,0,0,"Invalid Parameter",SRV_NULLTERM );                
  656.                 return FAIL;
  657.             }
  658.         }
  659.         else
  660.             position = i;
  661.  
  662.         paramtype   = srv_paramtype( srvproc, i );
  663.         if ( (paramlength = srv_paramlen( srvproc, i )) > 3 )
  664.             {
  665.             errmsg = "Error:  Parameter value too long";
  666.             goto ErrorExit;
  667.             }            
  668.  
  669.         switch( position )
  670.         {
  671.         case 1: // @state
  672.             if( paramtype != SRVVARCHAR && paramtype != SRVNULL )
  673.             {
  674.                 errmsg = "Error:  Invalid @state parameter type, expecting varchar";
  675.                 goto ErrorExit;                    
  676.             }
  677.             srv_bmove(srv_paramdata(srvproc, i), state, paramlength);
  678.             state[paramlength] = '\0';
  679.             
  680.             break;
  681.  
  682.         case 2: // @users
  683.             if( paramtype != SRVVARCHAR && paramtype != SRVNULL )
  684.             {
  685.                 errmsg = "Error:  Invalid @users parameter type, expecting varchar";
  686.                 goto ErrorExit;                    
  687.             }
  688.  
  689.             srv_bmove(srv_paramdata(srvproc, i), users, paramlength);
  690.             users[paramlength] = '\0';
  691.             
  692.             if ( (stricmp(users,"all") != 0) && paramlength ) 
  693.             {
  694.                 errmsg = "Error:  Invalid @users parameter, must be 'all' or NULL";
  695.                 goto ErrorExit;                    
  696.             }
  697.             break;
  698.         } // switch( position )
  699.  
  700.     } // for( i = 1; i <= numparams; i++ )
  701.  
  702.     // check for required 1st parameter
  703.     if ( (stricmp(state,"on") != 0) && (stricmp(state,"off") != 0) ) 
  704.     {
  705.         errmsg = "Error:  Required @state parameter must be 'on' or 'off'";
  706.         goto ErrorExit;                    
  707.     }    
  708.     
  709.     if (!stricmp(state,"on") && !strlen(users)) {
  710.         // turn on trace for just this srvproc
  711.         srv_pre_handle(NULL,srvproc,SRV_LANGUAGE,trace_lang,FALSE);
  712.         retcode = srv_pre_handle(NULL,srvproc,SRV_RPC,trace_rpc,FALSE);
  713.         switch (retcode) {
  714.             case FAIL:
  715.                 errmsg = "Error installing pre-handlers";
  716.                 goto ErrorExit;                    
  717.             case SRV_DUPLICATE_HANDLER:
  718.                 errmsg = "Pre-handler already installed";
  719.                 goto ErrorExit;                    
  720.             default:                                                
  721.                 printf("%s  starting trace for KPID %s\n", _strtime(timestr),
  722.                                             srv_pfield(srvproc, SRV_SPID, NULL));
  723.         }
  724.     }        
  725.     else if (!stricmp(state,"off") && !strlen(users)) {
  726.         // set remove flag to true
  727.         srv_pre_handle(NULL,srvproc,SRV_LANGUAGE,trace_lang,TRUE);
  728.         retcode = srv_pre_handle(NULL,srvproc,SRV_RPC,trace_rpc,TRUE);
  729.         switch (retcode) {
  730.             case FAIL:
  731.                 errmsg = "Pre-handler not found";
  732.                 goto ErrorExit;                    
  733.             default:                                                
  734.                 printf("%s  stopping trace for KPID %s\n", _strtime(timestr),
  735.                                         srv_pfield(srvproc, SRV_SPID, NULL));
  736.         }
  737.     }    
  738.     else if (!stricmp(state,"on") && !stricmp(users, "all")) {
  739.         // turn on trace for all connections
  740.         server = SRV_GETSERVER(srvproc);
  741.         srv_pre_handle(server,NULL,SRV_LANGUAGE,trace_lang,FALSE);
  742.         retcode = srv_pre_handle(server,NULL,SRV_RPC,trace_rpc,FALSE);
  743.         switch (retcode) {
  744.             case FAIL:
  745.                 errmsg = "Error installing pre-handlers";
  746.                 goto ErrorExit;                    
  747.             case SRV_DUPLICATE_HANDLER:
  748.                 errmsg = "Pre-handler already installed";
  749.                 goto ErrorExit;                    
  750.             default:                                                
  751.                 printf("%s  starting trace for all connections \n", _strtime(timestr));            
  752.         }
  753.     }        
  754.     else if (!stricmp(state,"off") && !stricmp(users, "all")) {
  755.         // set remove flag to true
  756.         server = SRV_GETSERVER(srvproc);
  757.         srv_pre_handle(server,NULL,SRV_LANGUAGE,trace_lang,TRUE);
  758.         retcode = srv_pre_handle(server,NULL,SRV_RPC,trace_rpc,TRUE);
  759.         switch (retcode) {
  760.             case FAIL:
  761.                 errmsg = "Pre-handler not found";
  762.                 goto ErrorExit;                    
  763.             default:                                                
  764.                 printf("%s  stopping trace for all connections \n", _strtime(timestr));            
  765.         }
  766.     }    
  767.     else {
  768.         errmsg = "Error in xp_trace logic";
  769.         goto ErrorExit;                    
  770.     }    
  771.                 
  772.     return(XP_NOERROR);
  773.  
  774. ErrorExit:
  775. // Send error message and return
  776.     //
  777.     srv_sendmsg(srvproc, SRV_MSG_ERROR, TRACE_ERROR, SRV_INFO, (DBTINYINT)0,
  778.             NULL, 0, 0, errmsg, SRV_NULLTERM);
  779.          
  780.     srv_senddone(srvproc, (SRV_DONE_ERROR | SRV_DONE_MORE), 0, 0);
  781.         return(XP_ERROR);
  782.  
  783. }
  784. //****************************************************************************
  785. // trace_lang
  786. //      This is the pre-language handler routine to print language requests to 
  787. //        stdio
  788. //
  789. // Parameters:
  790. //    srvproc - a pointer to SRV_PROC stucture
  791. //
  792. // Returns:
  793. //    SRV_CONTINUE
  794. //
  795. // Side Effects:
  796. //
  797. //****************************************************************************
  798. SRVRETCODE trace_lang(srvproc)
  799. SRV_PROC *srvproc;
  800. {
  801.     char timestr[9];
  802.     DBCHAR *query;
  803.     int query_len;
  804.  
  805.     query= srv_langptr(srvproc);
  806.     query_len = srv_langlen(srvproc);
  807.  
  808.        //print the request
  809.     printf("%s  KPID %s lang:  %s\n", _strtime(timestr),
  810.         srv_pfield(srvproc, SRV_SPID, (int *)NULL),query);
  811.     if (query[query_len-1] != '\n')
  812.         printf("\n");
  813.     
  814.     return(SRV_CONTINUE);
  815. }
  816.  
  817. //****************************************************************************
  818. // trace_rpc
  819. //      This is the pre-rpc handler routine to print language requests to 
  820. //        stdio
  821. //
  822. // Parameters:
  823. //    srvproc - a pointer to SRV_PROC stucture
  824. //
  825. // Returns:
  826. //    SRV_CONTINUE
  827. //
  828. // Side Effects:
  829. //
  830. //****************************************************************************
  831. SRVRETCODE trace_rpc(srvproc)
  832. SRV_PROC *srvproc;
  833. {
  834.     int i;                  // Index variable
  835.     short params;
  836.     DBCHAR complete_rpc_name[4 * (MAXNAME + 1)]; //database.owner.name;#
  837.     DBCHAR *rpc_db;
  838.     DBCHAR *rpc_owner;
  839.     DBCHAR *rpc_name;
  840.     int rpc_number;
  841.     char rpc_number_char[17];
  842.     DBCHAR *rpc_paramname;
  843.     DBCHAR * rpc_paramstatus;
  844.     int rpc_paramtype;
  845.     DBINT rpc_parammaxlen;
  846.     DBINT rpc_paramlen;
  847.     void *rpc_paramdata;
  848.     char rpc_paramstr[256];
  849.     char timestr[9];
  850.     DBCHAR * rpc_typename;
  851.     DBCHAR sztypestr[20];
  852.     DBNUMERIC numeric;
  853.     
  854.  
  855.     // Construct full RPC name 
  856.     //
  857.     memset (complete_rpc_name, 0, sizeof(complete_rpc_name));
  858.     rpc_db = srv_rpcdb(srvproc, (int *)NULL);
  859.     rpc_owner = srv_rpcowner(srvproc, (int *)NULL);
  860.     rpc_name = srv_rpcname(srvproc, (int *)NULL);
  861.     rpc_number = srv_rpcnumber(srvproc);
  862.     
  863.     if (rpc_db != NULL) {
  864.         strcat(complete_rpc_name,rpc_db);
  865.         strcat(complete_rpc_name,".");
  866.     };
  867.     if (rpc_owner != NULL) {
  868.         strcat(complete_rpc_name,rpc_owner);
  869.         strcat(complete_rpc_name,".");
  870.     };
  871.     strcat(complete_rpc_name,rpc_name);
  872.     if (rpc_number > 0) {
  873.         strcat(complete_rpc_name,";");
  874.         _itoa(rpc_number,rpc_number_char,10);
  875.         strcat(complete_rpc_name, rpc_number_char);
  876.     };
  877.     
  878.     //start printing the request
  879.  
  880.     printf("%s  KPID %s rpc:  %s", _strtime(timestr),
  881.         srv_pfield(srvproc, SRV_SPID, (int *)NULL),complete_rpc_name);
  882.     
  883.     // Set up any RPC parameters.
  884.     //
  885.     params = srv_rpcparams(srvproc);
  886.  
  887.     for (i = 1; i <= params; i++) {
  888.  
  889.         rpc_paramname = srv_paramname(srvproc, i, (int *)NULL);
  890.         if (strlen(rpc_paramname) == 0) rpc_paramname = NULL;
  891.  
  892.         if ((BYTE)srv_paramstatus(srvproc, i) == SRV_PARAMRETURN)
  893.             rpc_paramstatus = "OUT";
  894.         else
  895.             rpc_paramstatus = " ";
  896.         
  897.         rpc_paramtype = srv_paramtype(srvproc, i);
  898.         rpc_parammaxlen = srv_parammaxlen(srvproc, i);
  899.         rpc_paramlen = srv_paramlen(srvproc, i);
  900.            rpc_paramdata = srv_paramdata(srvproc, i);              
  901.  
  902.         switch (rpc_paramtype) {
  903.             case SRVVARCHAR:
  904.                 sprintf(sztypestr, "%s(%d)","varchar",rpc_parammaxlen);
  905.                 break;
  906.             case SRVCHAR:
  907.                 sprintf(sztypestr, "%s(%d)","char",rpc_parammaxlen);
  908.                 break;
  909.             case SRVINTN:
  910.                 switch (rpc_paramlen) {
  911.                     case 1:
  912.                         rpc_typename = "tinyint";
  913.                         break;
  914.                     case 2:
  915.                         rpc_typename = "smallint";
  916.                         break;
  917.                     default:
  918.                         rpc_typename = "int";
  919.                         break;
  920.                 }
  921.                 sprintf(sztypestr, "%s null",rpc_typename);
  922.                 break;
  923.             case SRVINT1:
  924.                 sprintf(sztypestr, "tinyint");
  925.                 break;
  926.             case SRVINT2:
  927.                 sprintf(sztypestr, "smallint");
  928.                 break;
  929.             case SRVINT4:
  930.                 sprintf(sztypestr, "int");
  931.                 break;
  932.  
  933.             case SRVMONEYN:
  934.                 switch (rpc_paramlen) {
  935.                     case 4:
  936.                         rpc_typename = "smallmoney";
  937.                         break;
  938.                     default:
  939.                         rpc_typename = "money";
  940.                         break;
  941.                 }
  942.                 sprintf(sztypestr, "%s null",rpc_typename);
  943.                 break;
  944.             case SRVMONEY4:
  945.                 sprintf(sztypestr, "smallmoney");
  946.                 break;
  947.             case SRVMONEY:
  948.                 sprintf(sztypestr, "money");
  949.                 break;
  950.  
  951.             case SRVDATETIMN:
  952.                 switch (rpc_paramlen) {
  953.                     case 4:
  954.                         rpc_typename = "smalldatetime";
  955.                         break;
  956.                     default:
  957.                         rpc_typename = "datetime";
  958.                         break;
  959.                 }
  960.                 sprintf(sztypestr, "%s null",rpc_typename);
  961.                 break;
  962.             case SRVDATETIM4:
  963.                 sprintf(sztypestr, "smalldatetime");
  964.                 break;
  965.             case SRVDATETIME:
  966.                 sprintf(sztypestr, "datetime");
  967.                 break;
  968.  
  969.             case SRVFLTN:
  970.                 switch (rpc_paramlen) {
  971.                     case 4:
  972.                         rpc_typename = "real";
  973.                         break;
  974.                     default:
  975.                         rpc_typename = "float";
  976.                         break;
  977.                 }
  978.                 sprintf(sztypestr, "%s null",rpc_typename);
  979.                 break;
  980.             case SRVFLT4:
  981.                 sprintf(sztypestr, "real");
  982.                 break;
  983.             case SRVFLT8:
  984.                 sprintf(sztypestr, "float");
  985.                 break;
  986.  
  987.             case SRVNUMERIC:
  988.             case SRVNUMERICN:
  989.             case SRVDECIMAL:
  990.             case SRVDECIMALN:
  991.                 memset (&numeric, 0, sizeof(DBNUMERIC));
  992.                 memmove (&numeric, rpc_paramdata, rpc_paramlen);
  993.                 rpc_paramdata = &numeric;
  994.                 switch (rpc_paramtype) {
  995.                     case SRVNUMERIC:
  996.                     case SRVNUMERICN:
  997.                         rpc_typename = "numeric";
  998.                         break;
  999.                     case SRVDECIMAL:
  1000.                     case SRVDECIMALN:
  1001.                         rpc_typename = "decimal";
  1002.                         break;
  1003.                 }        
  1004.                 sprintf(sztypestr, "%s(%d,%d)",rpc_typename, numeric.precision, numeric.scale);
  1005.                 if (rpc_paramlen == 2) 
  1006.                     rpc_paramlen = 0;
  1007.                 break;
  1008.             case SRVTEXT:
  1009.                 sprintf(sztypestr, "text");
  1010.                 break;
  1011.             case SRVIMAGE:
  1012.                 sprintf(sztypestr, "image");
  1013.                 break;
  1014.  
  1015.             case SRVVARBINARY:
  1016.                 sprintf(sztypestr, "%s(%d)","varbinary",rpc_parammaxlen);
  1017.                 break;
  1018.             case SRVBINARY:
  1019.                 sprintf(sztypestr, "%s(%d)","binary",rpc_parammaxlen);
  1020.                 break;
  1021.             case SRVBIT:
  1022.                 sprintf(sztypestr, "bit");
  1023.                 break;
  1024.  
  1025.             case SRVNULL:
  1026.                 sprintf(sztypestr, "srvnull");
  1027.                 break;
  1028.  
  1029.             default:
  1030.                 sprintf(sztypestr, "unknown type");
  1031.                 break;
  1032.  
  1033.         } // end of switch (rpc_paramtype)
  1034.  
  1035.         if (rpc_paramlen > 0) {
  1036.             if (rpc_paramtype != SRVVARBINARY)  
  1037.                 srv_convert(srvproc,rpc_paramtype,rpc_paramdata,
  1038.                         rpc_paramlen,SRVCHAR,rpc_paramstr,-1);
  1039.             else
  1040.                 strcpy(rpc_paramstr,"<conversion not supported>");
  1041.         }
  1042.         else 
  1043.             strcpy(rpc_paramstr,"<null>");
  1044.  
  1045.  
  1046.         printf("\r\n   P%3d: %-10s %-15s %4s %s",i,rpc_paramname, sztypestr, rpc_paramstatus, rpc_paramstr);
  1047.         
  1048.     }
  1049.     printf("\n\n");
  1050.  
  1051.     return(SRV_CONTINUE);
  1052. }
  1053.