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 / dblib / c / sqlexamp / sqlexamp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-04-03  |  14.2 KB  |  388 lines

  1. /* SQLEXAMP.C - Copyright (c) 1990 - 1995 by Craig Henry.  This program may
  2. ** be freely distributed and copied, without charge.  However, any attempt to
  3. ** charge for this program will be considered a copyright infringement and
  4. ** will be prosecuted to the fullest extent.
  5. **
  6. ** This program provides a simple example of logging onto a SQL Server,
  7. ** sending down commands, retrieving metadata, and result rows.  Formatting
  8. ** and printing those results on the console.
  9. **
  10. */
  11.  
  12. #if defined(DBNTWIN32)
  13. #include <windows.h>
  14. #endif
  15.  
  16. #include "stdio.h"        // include standard header
  17. #include "sqlfront.h"        // include dblib macro/manifest defines
  18. #include "sqldb.h"        // include dblib datatype, prottypes, etc
  19. #include "string.h"        // include for string functions
  20. #include "malloc.h"        // include for malloc and free
  21.  
  22.  
  23. // prototypes for internal functions
  24. extern int DetermineRowSize(DBPROCESS *,int);
  25. extern RETCODE PrintHeaders(DBPROCESS *);
  26. extern RETCODE PrintRow(DBPROCESS *);
  27.  
  28. /*
  29. ** DetermineRowSize(DBPROCESS *,int)
  30. **
  31. ** This function returns either the size of all columns in the row, converted
  32. ** to character data (SQLCHAR) with one space between each column, or
  33. ** if col is non-zero, the length of the input column converted to string.
  34. ** It is used to build the header strings, and each row of data, and is
  35. ** called to allocate the memory needed for each row, and determine how
  36. ** much of that space is to be used for each column
  37. */
  38. int DetermineRowSize(dbproc,col)
  39. DBPROCESS *dbproc;        // The SQL Server connection structure
  40. int col;            // column size to get, 0 for all
  41. {
  42.     int x,cols;            // counters
  43.     int length=0;        // total length of column(row).
  44.     int namelength;        // length of name of column
  45.     int prlength;        // printable length
  46.     char *name;            // pointer to column name
  47.     if(!col)                // get number of columns
  48.        cols = dbnumcols(dbproc);
  49.     // count from 1 to numcols if col is 0, else x will = col only
  50.     for(x=((col) ? col : 1);x<=((col) ? col : cols);x++)
  51.     {
  52.         switch(dbcoltype(dbproc,x))    // get column type, determine SQLCHAR
  53.         {                // converted length
  54.         case SQLNUMERIC:
  55.         case SQLDECIMAL:
  56.             {
  57.             DBCOL Col;
  58.                 dbcolinfo(dbproc,CI_REGULAR,x,0,&Col);
  59.                 prlength = Col.Precision + 2;
  60.             }
  61.             break;
  62.  
  63.         case SQLBIT:        // The PR... values are found in the
  64.             prlength = PRBIT;    // SQLDB.H header file.
  65.             break;
  66.         case SQLINT1:
  67.                prlength = PRINT1;
  68.             break;
  69.         case SQLINT2:
  70.               prlength = PRINT2;
  71.             break;
  72.         case SQLINT4:
  73.             prlength = PRINT4;
  74.             break;
  75.         case SQLFLT8:
  76.             prlength = PRFLT8;
  77.             break;
  78.         case SQLDATETIME:
  79.             prlength = PRDATETIME;
  80.             break;
  81.         case SQLMONEY:
  82.             prlength = PRMONEY;
  83.             break;
  84.             case SQLVARBINARY :        // VARBINARY IMAGE, and BINARY
  85.             case SQLBINARY:        // convert to 2 times length
  86.             case SQLIMAGE:
  87.                 prlength = dbcollen(dbproc,x)*2;
  88.                 break;
  89.         default :
  90.             prlength = dbcollen(dbproc,x);     // other types are maximum of
  91.             break;                 // actual column length
  92.         }
  93.         name = (char *)dbcolname(dbproc,x);         // names may be longer than
  94.         namelength =  (name) ? strlen(name) : 0; // column so use name len if
  95.         if(prlength<namelength)             // longer of two.
  96.            length+=namelength+1;         // add one for space between
  97.         else                     // columns
  98.            length+=prlength+1;
  99.     }
  100.     return length;            // return the length of the
  101.                         // field
  102. }
  103. /*
  104. ** RETCODE PrintHeaders(DBPROCESS *)
  105. **
  106. ** This function builds the string that contains the names of each column,
  107. ** and a string containing '=' as a separator line.  It does this by finding
  108. ** the print size of each column, allocating a buffer to hold all column names
  109. ** plus one space between each column name, then copying that name into the
  110. ** appropriate location into the buffer.  Finally the two lines are
  111. ** printed.
  112. */
  113. RETCODE PrintHeaders(dbproc)
  114. DBPROCESS *dbproc;        // The SQL Server connection structure pointer
  115. {
  116.     int x,cols,size;        // counters
  117.     char *header;        // pointer for separator buffer
  118.     char *colnames;        // pointer for column name buffer
  119.     char *colname;        // scratch pointers
  120.     char *ptr,*hptr;
  121.     size = DetermineRowSize(dbproc,0);    // get size of buffers
  122.     ptr = colnames = malloc(size+1);     // get name buffer
  123.     hptr = header = malloc(size+1);     // get separator buf
  124.     memset (header,' ',size);        // set buffers to all spaces
  125.     memset (colnames,' ',size);
  126.     cols = dbnumcols(dbproc);    // get number of columns
  127.     for(x=1;x<=cols;x++)    // loop on all columns
  128.     {
  129.         size = DetermineRowSize(dbproc,x);     // get size of this column
  130.         colname = (char *)dbcolname(dbproc,x);        // get column name
  131.         strncpy(ptr,colname,strlen(colname));    // copy name
  132.         memset(hptr,'=',size-1);            // set ='s in separator line
  133.         hptr+=size;                // move to next position
  134.         ptr+=size;                // move to next position
  135.     }
  136.     *ptr = '\0';            // null term both strings
  137.     *hptr = '\0';
  138.     printf("%s\n",colnames);        // print both strings
  139.     printf("%s\n",header);
  140.     free(colnames);            // free both buffers
  141.     free(header);
  142.     return SUCCEED;            // done
  143. }
  144. /*
  145. ** RETCODE PrintRow(DBPROCESS *)
  146. **
  147. ** This function prints out one row.  dbnextrow() must be called to fetch the
  148. ** row to print.  This routine could be used to print the current row as
  149. ** many times as wanted, as the current row data is always available until
  150. ** dbnextrow() is called to fetch the next row.  This routine works like
  151. ** PrintHeaders above, but each column's data is obtained instead of a row
  152. ** name, and converted to a string.  It is then set into the buffer.
  153. */
  154. RETCODE PrintRow(dbproc)
  155. DBPROCESS *dbproc;        // SQL Server connection structure
  156. {
  157.     int x,cols,size,datasize,colwidth,coltype;    // counters
  158.     char *datavals;        // data buffer pointer
  159.     char *data;            // column data pointer
  160.     char *ptr;            // scratch pointer
  161.      colwidth = DetermineRowSize(dbproc,0);
  162.     ptr = datavals = malloc(colwidth+1); // get buffer
  163.     cols = dbnumcols(dbproc);    // get number of columns
  164.     for(x=1;x<=cols;x++)    // do all columns
  165.     {
  166.            coltype = dbcoltype(dbproc,x);
  167.         size = DetermineRowSize(dbproc,x); // determine size of this column
  168.         memset(ptr,' ',size);        // set it to spaces
  169.         data = (char *)dbdata(dbproc,x);    // get pointer to column's data
  170.         if(data == (BYTE *)NULL)    // if NULL, use "NULL"
  171.         {
  172.             strncpy(ptr,"NULL",4);    // set NULL into buffer
  173.             ptr += size;        // point past this column in output buf
  174.         }
  175.         else                // else have data, so convert to char
  176.         {
  177.             datasize = dbconvert(dbproc,coltype,data,dbdatlen(dbproc,x),
  178.                 SQLCHAR,ptr,(DBINT)size-1);
  179.                 if (datasize < size && (coltype == SQLNUMERIC || coltype == SQLDECIMAL || coltype == SQLINT1 ||
  180.                     coltype == SQLINT2 || coltype == SQLINT4 || coltype == SQLFLT8 || coltype == SQLFLT4))
  181.                     {
  182.                     memmove(ptr+size-1-datasize,ptr,datasize);
  183.                     memset(ptr,' ',size-1-datasize);
  184.                     }
  185.             ptr+=size;
  186.         }
  187.     }
  188.     *ptr = '\0';            // null term string
  189.     printf("%s\n",datavals);        // print row
  190.     free(datavals);            // free buffer
  191.     return SUCCEED;            // done
  192. }
  193.  
  194. /*
  195. **
  196. ** The below main is a mini isql interpreter and as such is only
  197. ** used for demonstration purposes.  Command line args include the Server
  198. ** name as arg 1, User ID as arg 2, assumes the password is null.
  199. ** This routine requests opens the connection after obtaining the login record
  200. ** and filling it with the necessary info.  Once the connection is established
  201. ** it accpets command input, set's it into the dbproc.  On "go" it executes
  202. ** the command against the server, processes each results set and then returns
  203. ** to accepting command input.  If "quit" or "exit" is input the program
  204. ** is terminated.  This interpreter will not process COMPUTE statements,
  205. ** and will not work with commands that return text/image data.
  206. */
  207. int main(argc, argv)
  208. int argc;
  209. char *argv[];
  210. {
  211.     LOGINREC *login;        // login rec pointer
  212.     DBPROCESS *dbproc;        // SQL Server connection structure pointer
  213.  
  214.     char cmd[150];        // command buffer
  215.     char server[30];        // server name buffer
  216.     int x=1;            // command line counter
  217.     STATUS retc;        // return code
  218.     const char * sqlversion;        // pointer for version string
  219.     int err_handler(DBPROCESS*, int, int, int, char*, char*);
  220.     int msg_handler(DBPROCESS*, DBINT, int, int, char*);
  221.  
  222.     *server = '\0';        // null start these two buffers
  223.     *cmd = '\0';
  224.  
  225.     if(argc == 1)        // if no server name, request it
  226.     {
  227.     printf("Enter Server Name: ");
  228.     gets(server);
  229.     }
  230.     else            // else it was input as first arg
  231.        strcpy(server,argv[1]);
  232.     if(argc < 2)        // if no login id, request it
  233.     {
  234.        printf("Enter User Name: ");
  235.        gets(cmd);
  236.     }
  237.     else            // otherwise it was input as second arg.
  238.        strcpy(cmd,argv[2]);
  239.  
  240.     // check to see if communications layer was loaded (DOS ONLY)
  241.     if((sqlversion = dbinit()) == (BYTE *)NULL)
  242.     {
  243.        // DOS TSR (DBNMPIPE.EXE) is not loaded, don't bother going any farther
  244.        printf("Error in DB-Library initialization, exiting\n");
  245.        return 1;
  246.     }
  247.     else
  248.        printf("DB-Library version: %s\n",sqlversion); // print dblib version
  249.  
  250.     dbsettime(30);        // set timeouts to 30 seconds
  251.     
  252.     // set error/msg handlers for this program
  253.     dbmsghandle((DBMSGHANDLE_PROC)msg_handler);
  254.     dberrhandle((DBERRHANDLE_PROC)err_handler);
  255.     
  256.     login = dblogin();        // get a login rec
  257.  
  258.     DBSETLUSER(login,cmd);        // set login id
  259.     DBSETLHOST(login,"SQL EXAMPLE");    // set host name for sp_who
  260.     DBSETLVERSION(login, DBVER60);
  261.  
  262.     // open connection to requested server.  Pass null server name for local
  263.     // connection, if name not entered.
  264.     if((dbproc = dbopen(login,(*server) ? server : (char *)NULL)) == (DBPROCESS *)NULL)
  265.     {
  266.         // no one answered, so couldn't connect or error occurred
  267.     printf("Login failed\n");
  268.     return 1;
  269.     }
  270.     else
  271.     {
  272.         // loop on command input until quit or exit appears in first 4 bytes.
  273.     while((strnicmp(cmd,"quit",4) != 0) && (strnicmp(cmd,"exit",4)!=0))
  274.     {
  275.        printf("%d> ",x++);        // print command prompt
  276.        gets(cmd);            // get command
  277.        if(strnicmp(cmd,"go",2) == 0)    // is it go
  278.        {
  279.           if(dbsqlexec(dbproc) == FAIL)    // execute command
  280.               {
  281.                  // problem occurred, just try another command
  282.                  printf("Error in executing command batch!\n");
  283.                  x = 1;
  284.                  continue;
  285.               }
  286.               // command executed correctly, get results information
  287.           while((retc = dbresults(dbproc)) != NO_MORE_RESULTS)
  288.           {
  289.          if (retc == FAIL)    // if error get out of loop
  290.              break;
  291.          // headers and data could be printed here with only two
  292.                  // function calls, dbprhead(dbproc), and dbprrow(dbproc),
  293.                  // which would output the headers, and all the data to
  294.                  // standard output.  However, that isn't very informative
  295.                  // toward understanding how this data is obtained and
  296.                  // processed, so I do it the hard way, one column at a time.
  297.  
  298.                  PrintHeaders(dbproc);        // print header data
  299.  
  300.                  // loop on each row, until all read
  301.                  while((retc= dbnextrow(dbproc))!=NO_MORE_ROWS)
  302.                  {
  303.                     if(retc == FAIL)        // if fail, then clear
  304.                     {                // connection completely, just
  305.                        dbcancel(dbproc);    // in case.
  306.                        break;
  307.                     }
  308.                     else
  309.                         PrintRow(dbproc);    // else print the current row
  310.                  }
  311.          if(DBCOUNT(dbproc) == 1L)    // print the row count
  312.               printf("(1 row effected)\n");
  313.           else
  314.               printf("(%ld rows effected)\n",DBCOUNT(dbproc));
  315.  
  316.           } // end while(dbresults())
  317.  
  318.               x = 1;            // reset command line counter
  319.        }
  320.        else
  321.        {
  322.           strcat(cmd," ");        // go not detected, so put space
  323.           dbcmd(dbproc,cmd);    // between each command and set in
  324.        }                // dbproc.
  325.  
  326.         } // end while()
  327.  
  328.         dbclose(dbproc);        // quit/exit input, close connection
  329.  
  330.         // print adios and exit.
  331.         printf("SQL Server Connection to %s closed, bye bye.\n",server);
  332.     return 0;
  333.      }
  334. }
  335. /*
  336. ** msg_handler(char *buffer, long len);
  337. **
  338. ** This routine is a local isql message handler call back function that
  339. ** is invoked whenever the SQL Server is sending a message back to
  340. ** the program.
  341. **
  342. */
  343. int msg_handler(dbproc, Msg, State, Severity, Message)
  344. DBPROCESS *dbproc;        // SQL Server connection structure
  345. DBINT Msg;            // SQL Server message number
  346. int State;            // State of the message
  347. int Severity;            // Severity of the message
  348. char *Message;            // The message itself (read only)
  349. {
  350.     printf("Message No.: %ld, Msg. State: %d, Msg. Severity: %d\n",
  351.     Msg,State,Severity);
  352.     if(Message != NULL)
  353.        printf("%s\n",Message);
  354.     return (0);
  355. }
  356.  
  357. /*
  358. ** err_handler(char *buffer, long len);
  359. **
  360. ** This routine is a local error handler called by dblib if an internal
  361. ** error occurs, also to notify when a server message has been sent, which is
  362. ** obtained through the above message handler.
  363. **
  364. */
  365. int err_handler(dbproc, Severity,dberr, oserr, errstr, oserrstr)
  366. DBPROCESS *dbproc;        // SQL Server connection structure
  367. int Severity;            // Severity of Dblib error
  368. int dberr;            // dblib error, all dblib errors start at 10000
  369. int oserr;            // OS error from, C runtime
  370. char *errstr;            // dblib error string
  371. char *oserrstr;            // OS error string (if any)
  372. {
  373.  
  374.     printf("DB-LIBRARY Error - Severity: %d, Error No: %d, OS Error No: %d\n",
  375.        Severity, dberr, oserr);
  376.     if(errstr != NULL)
  377.        printf("%s\n",errstr);
  378.     if(oserrstr != NULL)
  379.        printf("%s\n",oserrstr);
  380.     return INT_CANCEL;
  381. }
  382.  
  383. /*****************************************************************************/
  384. /*======================== E N D - O F - F I L E ============================*/
  385. /*****************************************************************************/
  386.  
  387.  
  388.