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