home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / cppsql.zip / SQLSRC.ZIP / SQLTAB.CPP < prev    next >
Text File  |  1992-09-18  |  35KB  |  1,250 lines

  1. // :H1 SQLTAB.CPP: START OF SPECIFICATIONS
  2. //----------------------------------------------------------------------
  3. //
  4. //  Module Name: SQLTAB.CPP
  5. //
  6. //  Description: SQL Table Interface.
  7. //
  8. //  Product Classification:
  9. //    IBM Internal Use Only
  10. //    (C) Copyright IBM Corp. 1992
  11. //
  12. //  Status: New
  13. //
  14. //  Initial Author: George L. Havens
  15. //
  16. //  Function: To provide an interface to tables for SQL databases.
  17. //
  18. //  Notes: None.
  19. //
  20. //  Dependencies: Requires PORTABLE.H include.
  21. //                This module requires SQL.C for the SQL C interface.
  22. //
  23. //  Restrictions: None.
  24. //
  25. //  Compiler: Zortech C++
  26. //
  27. // Change Activity -----------------------------------------------------
  28. //
  29. // $MOD(module) COMP(component) PROD(product): Description...
  30. //
  31. // FLAG  REASON  VERS  DATE  WHO   DESCRIPTION
  32. // ---- -------- ---- ------ ---   -----------
  33. //               V100 920224 GLH : Initial level
  34. //
  35. // END-OF-SPECIFICATIONS -----------------------------------------------
  36.  
  37. // Use the following define to create a test version.
  38. //#define TEST
  39.  
  40. // :H1 SYSTEM INCLUDE FILES.  SELECTIVITY USED WHERE POSSIBLE.
  41. #include "stdio.h"
  42. #include "stdlib.h"
  43. #include "stdarg.h"
  44. #include "string.h"
  45. #include "ctype.h"
  46. extern "C"
  47.   {
  48. #include "sqlda.h"
  49. #include "sql.h"
  50.   }
  51.  
  52. // :H1 USER-DEFINED INCLUDE FILES.  SELECTIVITY USED WHERE POSSIBLE.
  53. #include "portable.h"
  54. extern "C"
  55.   {
  56. #include "sqlc.h"
  57.   }
  58.  
  59. #ifdef TEST
  60. #include "sql.hpp"
  61. #endif
  62. #include "sqltab.hpp"
  63.  
  64. #define  MAX_COL_LEN         20     // maximum column name length
  65.  
  66.  
  67. // :H1 Table: Table Constructor
  68. //----------------------------------------------------------------------
  69. //
  70. //  Function Name: Table constructor
  71. //
  72. //  Purpose: This method will create an SQL table object.
  73. //
  74. //  Description: This method will create an SQL table object. It
  75. //               will create a SQLDA structure for the table
  76. //               format specified.
  77. //
  78. //  Input:
  79. //    name       Table name
  80. //    format     table format
  81. //               format must be a string using %d, %ld, or %#s
  82. //               where # is the string length not including the 0 terminator
  83. //    col        column names seperated by ','
  84. //  Output:
  85. //    none
  86. //
  87. //----------------------------------------------------------------------
  88.  
  89. Table::Table (const CHAR *name, const CHAR *format, const CHAR *col)
  90.   {
  91.    const CHAR  *ptr = format;
  92.    SHORT i;
  93.    SHORT len;
  94.  
  95.     // save table name
  96.     table = new CHAR [strlen (name) + 1];
  97.     strcpy (table, name);
  98.  
  99.     // save column names
  100.     columns = new CHAR [strlen (col) + 1];
  101.     strcpy (columns, col);
  102.  
  103.     // initialize number of columns
  104.     cols = 0;
  105.  
  106.     // initialize to database not searched
  107.     record_found = FALSE;
  108.  
  109.     // while % in format
  110.     while ( (ptr = strchr (ptr, '%')) != 0)
  111.       {
  112.         // update number of columns
  113.         cols++;
  114.  
  115.         // skip to next character
  116.         ptr++;
  117.       }
  118.  
  119.     // if no % in format
  120.     if (cols == 0)
  121.       {
  122.         // set no % in format
  123.         rc = SQLTAB_NO_PERCENT_ERROR;
  124.         id = SQLTAB_ID_1;
  125.         return;
  126.       }
  127.  
  128.     // create sqlda structure
  129.     var = (struct sqlda *)new CHAR [SQLDASIZE (cols)];
  130.     var->sqln = var->sqld = cols;
  131.  
  132.     // initialize format pointer
  133.     ptr = format;
  134.  
  135.     // for all columns
  136.     for (i = 0; i < cols; i++)
  137.       {
  138.         // if % not found in format
  139.         if ( (ptr = strchr (ptr, '%')) == 0)
  140.             break;
  141.  
  142.         // skip to character following %
  143.         ptr++;
  144.  
  145.         // if small integer format
  146.         if (*ptr == 'd')
  147.           {
  148.             // set up variable data area
  149.             var->sqlvar[i].sqltype = SQL_TYP_SMALL;
  150.             var->sqlvar[i].sqldata = 0;
  151.             var->sqlvar[i].sqllen = sizeof (SHORT);
  152.             var->sqlvar[i].sqlind = 0;
  153.           }
  154.         // else if long integer format
  155.         else if (*ptr == 'l' && *(ptr + 1) == 'd')
  156.           {
  157.             // set up variable data area
  158.             var->sqlvar[i].sqltype = SQL_TYP_INTEGER;
  159.             var->sqlvar[i].sqldata = 0;
  160.             var->sqlvar[i].sqllen = sizeof (LONG);
  161.             var->sqlvar[i].sqlind = 0;
  162.           }
  163.         // else if string format
  164.         else if (sscanf ((char*) ptr, "%ds", &len) == 1)
  165.           {
  166.             // set up variable data area
  167.             var->sqlvar[i].sqltype = SQL_TYP_CSTR;
  168.             var->sqlvar[i].sqldata = 0;
  169.             var->sqlvar[i].sqllen = len + 1;
  170.             var->sqlvar[i].sqlind = 0;
  171.           }
  172.         // else set error occurred
  173.         else
  174.           {
  175.             rc = SQLTAB_INVALID_FORMAT_STRING;
  176.             id = SQLTAB_ID_2;
  177.             break;
  178.           }
  179.       }
  180.  
  181.     // set no error occurred
  182.     rc = 0;
  183.   }
  184.  
  185. // :H1 Create: Create Table
  186. //----------------------------------------------------------------------
  187. //
  188. //  Function Name: Create
  189. //
  190. //  Purpose: This method will create an SQL table.
  191. //
  192. //  Description: This method will create an SQL table by using
  193. //               dynamic SQL.
  194. //
  195. //  Input:
  196. //    none
  197. //
  198. //  Output:
  199. //    return code 0 = successful, not 0 = error
  200. //
  201. //----------------------------------------------------------------------
  202.  
  203. Table::Create (VOID)
  204.   {
  205.    SHORT i;
  206.    CHAR  *statement = new CHAR [SQL_MAXCOLS * MAX_COL_LEN];
  207.    CHAR  *col_name;
  208.    SHORT  length;
  209.    CHAR  temp [20];
  210.    CHAR  *names;
  211.  
  212.     // build create table statement
  213.     strcpy (statement, "CREATE TABLE ");
  214.     strcat (statement, table);
  215.     strcat (statement, "(");
  216.  
  217.     // get copy of column names
  218.     names = strdup (columns);
  219.  
  220.     // get pointer to start of columns names
  221.     col_name = strtok (names, ",");
  222.  
  223.     // for all columns names
  224.     for (i = 0; i < cols && col_name != 0; i++)
  225.       {
  226.         // add column name to statement
  227.         strcat (statement, col_name);
  228.  
  229.         // switch on variable type
  230.         switch (var->sqlvar[i].sqltype)
  231.           {
  232.             case SQL_TYP_SMALL: // small integer format
  233.               // build create table string
  234.               strcat (statement, " SMALLINT");
  235.               break;
  236.  
  237.             case SQL_TYP_INTEGER: // long integer format
  238.               // build create table string
  239.               strcat (statement, " INTEGER");
  240.               break;
  241.  
  242.             case SQL_TYP_CSTR: // C string format
  243.               // build create table string
  244.               sprintf (temp, " VARCHAR(%d)", var->sqlvar[i].sqllen);
  245.               strcat (statement, temp);
  246.               break;
  247.           }
  248.  
  249.         // if not the last column
  250.         if (i < cols - 1)
  251.             strcat (statement, ",");
  252.         else
  253.             strcat (statement, ")");
  254.  
  255.         // get next column name
  256.         col_name = strtok (NULL, ",");
  257.       }
  258.  
  259.     // if all columns not processed
  260.     if (i < cols)
  261.       {
  262.         // free the create table statement
  263.         free (statement);
  264.  
  265.         // free the names string
  266.         free (names);
  267.  
  268.         // set error location
  269.         id = SQLTAB_ID_6;
  270.  
  271.         // set error return code
  272.         rc = SQLTAB_INVALID_NUMBER_OF_COLUMNS;
  273.  
  274.         return (rc);
  275.       }
  276.  
  277.     // if error creating table
  278.     if ( (rc = sql_dynamic (statement)) != 0)
  279.       {
  280.         // free the create table statement
  281.         free (statement);
  282.  
  283.         // free the names string
  284.         free (names);
  285.  
  286.         // set error location
  287.         id = SQLTAB_ID_3;
  288.  
  289.         return (rc);
  290.       }
  291.  
  292.     // free the create table statement
  293.     free (statement);
  294.  
  295.     // free the names string
  296.     free (names);
  297.  
  298.     return (0);
  299.   }
  300.  
  301. // :H1 Create: Insert Data
  302. //----------------------------------------------------------------------
  303. //
  304. //  Function Name: Insert
  305. //
  306. //  Purpose: This method will insert data into an SQL table.
  307. //
  308. //  Description: This method will insert a variable data into the
  309. //               table columns.
  310. //
  311. //  Input:
  312. //    num_cols   number of colums to insert (must match number of columns
  313. //               in the table description)
  314. //    variable data to be inserted
  315. //
  316. //  Output:
  317. //    return code 0 = successful, not 0 = error
  318. //
  319. //----------------------------------------------------------------------
  320.  
  321. SHORT Table::Insert (SHORT num_cols, ...)
  322.   {
  323.    SHORT i;
  324.    CHAR  *statement = new CHAR [SQL_MAXCOLS * 2 + 30];
  325.    va_list arg_ptr;
  326.  
  327.     // if invalid number of columns specified
  328.     if (num_cols != cols)
  329.       {
  330.         // free the insert table statement
  331.         free (statement);
  332.  
  333.         // set error location
  334.         id = SQLTAB_ID_13;
  335.  
  336.         // set error return code
  337.         rc = SQLTAB_INVALID_NUMBER_OF_COLUMNS;
  338.  
  339.         return (rc);
  340.       }
  341.  
  342.     // build insert table statement
  343.     sprintf (statement, "INSERT INTO %s VALUES(", table);
  344.  
  345.     // get pointer to start of variable list
  346.     va_start (arg_ptr, num_cols);
  347.  
  348.     // for all columns
  349.     for (i = 0; i < cols; i++)
  350.       {
  351.         // switch on variable type
  352.         switch (var->sqlvar[i].sqltype)
  353.           {
  354.             case SQL_TYP_SMALL: // small integer format
  355.               // put pointer to value in control block
  356.               var->sqlvar[i].sqldata  = (unsigned CHAR *)arg_ptr;
  357.  
  358.               // skip to next variable
  359.               va_arg (arg_ptr, SHORT);
  360.               break;
  361.  
  362.             case SQL_TYP_INTEGER: // long integer format
  363.               // put pointer to value in control block
  364.               var->sqlvar[i].sqldata  = (unsigned CHAR *)arg_ptr;
  365.  
  366.               // skip to next variable
  367.               va_arg (arg_ptr, LONG);
  368.               break;
  369.  
  370.             case SQL_TYP_CSTR: // C string format
  371.               // put pointer to value in control block and skip
  372.               // to next variable
  373.               var->sqlvar[i].sqldata  =
  374.                 (unsigned char *)va_arg (arg_ptr, CHAR *);
  375.               break;
  376.           }
  377.  
  378.         // if not the last column
  379.         if (i < cols - 1)
  380.             strcat (statement, "?,");
  381.         else
  382.             strcat (statement, "?)");
  383.       }
  384.  
  385.     // reset pointer to column list
  386.     va_end (arg_ptr);
  387.  
  388.     // if error inserting into table
  389.     if ( (rc = sql_desc (statement, var)) != 0)
  390.       {
  391.         // free the insert table statement
  392.         free (statement);
  393.  
  394.         // set error location
  395.         id = SQLTAB_ID_4;
  396.  
  397.         return (rc);
  398.       }
  399.  
  400.     // free the insert table statement
  401.     free (statement);
  402.  
  403.     return (0);
  404.   }
  405.  
  406. // :H1 Search: Table Search
  407. //----------------------------------------------------------------------
  408. //
  409. //  Function Name: Search
  410. //
  411. //  Purpose: This method will search an SQL table for a specified value(s).
  412. //
  413. //  Description: This method will search for a match on the specified
  414. //               value(s). This is done by building a SELECT record
  415. //               for the specified values. If multiple conditions
  416. //               are specified they are AND'ed together.
  417. //
  418. //  Input:
  419. //    initial    initial search with this format?
  420. //    format     table format
  421. //               format must be a string using %d, %ld, or %#s for
  422. //               fields to be searched and %*d, %*ld, and %*#s for
  423. //               those not being searched.
  424. //               # is the string length to search not including the
  425. //               0 terminator. If no fields to be searched are specified
  426. //               the next row will be returned.
  427. //
  428. //    variable   pointers where to store EVERY field in the row
  429. //    variable   data to be seached for match
  430. //  Output:
  431. //    return code 0 = successful, not 0 = error
  432. //
  433. //----------------------------------------------------------------------
  434. SHORT Table::Search (BOOLEAN initial, const CHAR *format, ...)
  435.   {
  436.    const CHAR  *ptr = format;
  437.    SHORT i;
  438.    SHORT len;
  439.    va_list arg_ptr;
  440.    CHAR  *statement;
  441.    CHAR  *col_name;
  442.    CHAR  temp[30];
  443.    CHAR  *names;
  444.    BOOLEAN first_search = TRUE;
  445.  
  446.     // get pointer to start of variable list
  447.     va_start (arg_ptr, format);
  448.  
  449.     // for all columns
  450.     for (i = 0; i < cols; i++)
  451.       {
  452.         // switch on variable type
  453.         switch (var->sqlvar[i].sqltype)
  454.           {
  455.             case SQL_TYP_SMALL: // small integer format
  456.               // get pointer to data and skip to next variable
  457.               var->sqlvar[i].sqldata = (unsigned char *)va_arg (arg_ptr, SHORT *);
  458.               break;
  459.  
  460.             case SQL_TYP_INTEGER: // long integer format
  461.               // get pointer to data and skip to next variable
  462.               var->sqlvar[i].sqldata = (unsigned char *)va_arg (arg_ptr, LONG *);
  463.               break;
  464.  
  465.             case SQL_TYP_CSTR: // C string format
  466.               // get pointer to data and skip to next variable
  467.               var->sqlvar[i].sqldata = (unsigned char *)va_arg (arg_ptr, CHAR **);
  468.               break;
  469.           }
  470.       }
  471.  
  472.     // if initial search
  473.     if (initial == TRUE)
  474.       {
  475.         // get memory for statement 
  476.         statement = new CHAR [SQL_MAXRECL];
  477.  
  478.         // get copy of column names
  479.         names = strdup (columns);
  480.  
  481.         // initialize pointer to format
  482.         ptr = format;
  483.      
  484.         // create search statement
  485.         sprintf (statement, "SELECT * FROM %s WHERE ", table);
  486.      
  487.         // get pointer to start of columns names
  488.         col_name = strtok (names, ",");
  489.      
  490.         // for all columns
  491.         for (i = 0; i < cols && col_name != 0; i++)
  492.           {
  493.             // if % not found in format
  494.             if ( (ptr = strchr (ptr, '%')) == 0)
  495.                 break;
  496.      
  497.             // skip to character following %
  498.             ptr++;
  499.      
  500.             // if skip this field
  501.             if (*ptr == '*')
  502.               {
  503.               }
  504.             else
  505.               {
  506.                 // if not the first search condition
  507.                 if (first_search == FALSE)
  508.                   {
  509.                     // add the AND condition to the statement
  510.                     strcat (statement, "AND ");
  511.                   }
  512.                 else
  513.                   {
  514.                     // set not the first search condition
  515.                     first_search = FALSE;
  516.                   }
  517.      
  518.                 // if small integer format
  519.                 if (*ptr == 'd')
  520.                   {
  521.                     // add variable to search
  522.                     strcat (statement, col_name);
  523.                     sprintf (temp, " = %d", va_arg (arg_ptr, SHORT));
  524.                     strcat (statement, temp);
  525.                   }
  526.                 // else if long integer format
  527.                 else if (*ptr == 'l' && *(ptr + 1) == 'd')
  528.                   {
  529.                     // add variable to search
  530.                     strcat (statement, col_name);
  531.                     sprintf (temp, " = %ld", va_arg (arg_ptr, LONG));
  532.                     strcat (statement, temp);
  533.                   }
  534.                 // else if string format
  535.                 else if (sscanf ((char*) ptr, "%ds", &len) == 1)
  536.                   {
  537.                     // if only part of the string is to be searched
  538.                     if (len < var->sqlvar[i].sqllen - 1)
  539.                       {
  540.                         // add variable to search
  541.                         strcat (statement, " SUBSTR (");
  542.                         strcat (statement, col_name);
  543.                         strcat (statement, ",1,");
  544.                         sprintf (temp, "%d)='",len);
  545.                         strcat (statement, temp);
  546.                         strcat (statement, va_arg (arg_ptr, CHAR *));
  547.                         strcat (statement, "'");
  548.                       }
  549.                     // else if invalid string length
  550.                     else if (len > var->sqlvar[i].sqllen - 1)
  551.                       {
  552.                         // free the create table statement
  553.                         free (statement);
  554.      
  555.                         // free the names string
  556.                         free (names);
  557.      
  558.                         // set error location
  559.                         id = SQLTAB_ID_8;
  560.      
  561.                         // set error return code
  562.                         rc = SQLTAB_INVALID_FORMAT_STRING;
  563.      
  564.                         return (rc);
  565.                       }
  566.                     else
  567.                       {
  568.                         // add variable to search
  569.                         strcat (statement, col_name);
  570.                         strcat (statement, " = '");
  571.                         strcat (statement, va_arg (arg_ptr, CHAR *));
  572.                         strcat (statement, "'");
  573.                       }
  574.                   }
  575.                 // else set error occurred
  576.                 else
  577.                   {
  578.                     // free the create table statement
  579.                     free (statement);
  580.      
  581.                     // free the names string
  582.                     free (names);
  583.      
  584.                     // set error location
  585.                     id = SQLTAB_ID_5;
  586.      
  587.                     // set error return code
  588.                     rc = SQLTAB_INVALID_FORMAT_STRING;
  589.      
  590.                     return (rc);
  591.                   }
  592.               }
  593.      
  594.             // get pointer to next of column name
  595.             col_name = strtok (NULL, ",");
  596.           }
  597.      
  598.         // if all columns not processed
  599.         if (i < cols)
  600.           {
  601.             // free the create table statement
  602.             free (statement);
  603.      
  604.             // free the names string
  605.             free (names);
  606.      
  607.             // set error location
  608.             id = SQLTAB_ID_7;
  609.      
  610.             // set error return code
  611.             rc = SQLTAB_INVALID_NUMBER_OF_COLUMNS;
  612.      
  613.             return (rc);
  614.           }
  615.      
  616.          if // no search arguments specified
  617.             (first_search == TRUE)
  618.              // create get any row statement
  619.              sprintf (statement, "SELECT * FROM %s", table);
  620.  
  621.         // get the row selected
  622.         rc =  sql_fetch (initial, statement, var);
  623.  
  624.         // free the create table statement
  625.         free (statement);
  626.  
  627.         // free the names string
  628.         free (names);
  629.       }
  630.     else
  631.       {
  632.         // get the row selected
  633.         rc =  sql_fetch (initial, 0, var);
  634.       }
  635.  
  636.     // if row  found
  637.     if (rc == 0)
  638.         // set record found
  639.         record_found = TRUE;
  640.     else
  641.       {
  642.         // set record not found
  643.         record_found = FALSE;
  644.  
  645.         // set error location
  646.         id = SQLTAB_ID_14;
  647.       }
  648.  
  649.     return (rc);
  650.   }
  651.  
  652. // :H1 Delete: Delete Row
  653. //----------------------------------------------------------------------
  654. //
  655. //  Function Name: Delete
  656. //
  657. //  Purpose: This method will search an SQL table for a specified value(s)
  658. //           and delete the rows found.
  659. //
  660. //  Description: This method will search for a match on the specified
  661. //               value(s). This is done by building a DELETE record
  662. //               for the specified values. If multiple conditions
  663. //               are specified they are AND'ed together.
  664. //
  665. //  Input:
  666. //    format     table format
  667. //               format must be a string using %d, %ld, or %#s for
  668. //               fields to be searched and %*d, %*ld, and %*#s for
  669. //               those not being searched.
  670. //               # is the string length to search not including the
  671. //               0 terminator. If no fields to be searched are specified
  672. //               all the rows will be deleted.
  673. //    variable   data to be seached for match
  674. //  Output:
  675. //    return code 0 = successful, not 0 = error
  676. //
  677. //----------------------------------------------------------------------
  678. SHORT Table::Delete (const CHAR *format, ...)
  679.   {
  680.    const CHAR  *ptr = format;
  681.    SHORT i;
  682.    SHORT len;
  683.    va_list arg_ptr;
  684.    CHAR  *statement = new CHAR [SQL_MAXRECL];
  685.    CHAR  *col_name;
  686.    CHAR  temp[30];
  687.    CHAR  *names;
  688.    BOOLEAN first_search = TRUE;
  689.  
  690.     // get copy of column names
  691.     names = strdup (columns);
  692.  
  693.     // get pointer to start of variable list
  694.     va_start (arg_ptr, format);
  695.  
  696.     // initialize pointer to format
  697.     ptr = format;
  698.  
  699.     // create delete statement
  700.     sprintf (statement, "DELETE FROM %s WHERE ", table);
  701.  
  702.     // get pointer to start of columns names
  703.     col_name = strtok (names, ",");
  704.  
  705.     // for all columns
  706.     for (i = 0; i < cols && col_name != 0; i++)
  707.       {
  708.         // if % not found in format
  709.         if ( (ptr = strchr (ptr, '%')) == 0)
  710.             break;
  711.  
  712.         // skip to character following %
  713.         ptr++;
  714.  
  715.         // if skip this field
  716.         if (*ptr == '*')
  717.           {
  718.           }
  719.         else
  720.           {
  721.             // if not the first condition
  722.             if (first_search == FALSE)
  723.               {
  724.                 // add the AND condition to the statement
  725.                 strcat (statement, "AND ");
  726.               }
  727.             else
  728.               {
  729.                 // set not the first condition
  730.                 first_search = FALSE;
  731.               }
  732.  
  733.             // if small integer format
  734.             if (*ptr == 'd')
  735.               {
  736.                 // add variable to search
  737.                 strcat (statement, col_name);
  738.                 sprintf (temp, " = %d", va_arg (arg_ptr, SHORT));
  739.                 strcat (statement, temp);
  740.               }
  741.             // else if long integer format
  742.             else if (*ptr == 'l' && *(ptr + 1) == 'd')
  743.               {
  744.                 // add variable to search
  745.                 strcat (statement, col_name);
  746.                 sprintf (temp, " = %ld", va_arg (arg_ptr, LONG));
  747.                 strcat (statement, temp);
  748.               }
  749.             // else if string format
  750.             else if (sscanf ((char*) ptr, "%ds", &len) == 1)
  751.               {
  752.                 // if only part of the string is to be searched
  753.                 if (len < var->sqlvar[i].sqllen - 1)
  754.                   {
  755.                     // add variable to search
  756.                     strcat (statement, " SUBSTR (");
  757.                     strcat (statement, col_name);
  758.                     strcat (statement, ",1,");
  759.                     sprintf (temp, "%d)='",len);
  760.                     strcat (statement, temp);
  761.                     strcat (statement, va_arg (arg_ptr, CHAR *));
  762.                     strcat (statement, "'");
  763.                   }
  764.                 // else if invalid string length
  765.                 else if (len > var->sqlvar[i].sqllen - 1)
  766.                   {
  767.                     // free the delete statement
  768.                     free (statement);
  769.  
  770.                     // free the names string
  771.                     free (names);
  772.  
  773.                     // set error location
  774.                     id = SQLTAB_ID_9;
  775.  
  776.                     // set error return code
  777.                     rc = SQLTAB_INVALID_FORMAT_STRING;
  778.  
  779.                     return (rc);
  780.                   }
  781.                 else
  782.                   {
  783.                     // add variable to search
  784.                     strcat (statement, col_name);
  785.                     strcat (statement, " = '");
  786.                     strcat (statement, va_arg (arg_ptr, CHAR *));
  787.                     strcat (statement, "'");
  788.                   }
  789.               }
  790.             // else set error occurred
  791.             else
  792.               {
  793.                 // free the delete statement
  794.                 free (statement);
  795.  
  796.                 // free the names string
  797.                 free (names);
  798.  
  799.                 // set error location
  800.                 id = SQLTAB_ID_10;
  801.  
  802.                 // set error return code
  803.                 rc = SQLTAB_INVALID_FORMAT_STRING;
  804.  
  805.                 return (rc);
  806.               }
  807.           }
  808.  
  809.         // get pointer to next of column name
  810.         col_name = strtok (NULL, ",");
  811.       }
  812.  
  813.     // if all columns not processed
  814.     if (i < cols)
  815.       {
  816.         // free the delete statement
  817.         free (statement);
  818.  
  819.         // free the names string
  820.         free (names);
  821.  
  822.         // set error location
  823.         id = SQLTAB_ID_11;
  824.  
  825.         // set error return code
  826.         rc = SQLTAB_INVALID_NUMBER_OF_COLUMNS;
  827.  
  828.         return (rc);
  829.       }
  830.  
  831.     if // no search arguments specified
  832.        (first_search == TRUE)
  833.         // create delete all rows statement
  834.         sprintf (statement, "DELETE FROM %s", table);
  835.  
  836.     // if get the row selected error
  837.     if ( (rc =  sql_dynamic (statement)) != 0)
  838.         // set error location
  839.         id = SQLTAB_ID_15;
  840.  
  841.     // free the delete statement
  842.     free (statement);
  843.  
  844.     // free the names string
  845.     free (names);
  846.  
  847.     return (rc);
  848.   }
  849.  
  850. // :H1 DeleteCurrent: Delete Current Row
  851. //----------------------------------------------------------------------
  852. //
  853. //  Function Name: DeleteCurrent
  854. //
  855. //  Purpose: This method will delete the current row found by using the
  856. //           search statement.
  857. //
  858. //  Description: This method will delete the current row that was found using
  859. //               the search statement. This is done by building a DELETE
  860. //               current record.
  861. //
  862. //  Input:
  863. //    none
  864. //
  865. //  Output:
  866. //    return code 0 = successful, not 0 = error
  867. //
  868. //----------------------------------------------------------------------
  869. SHORT Table::DeleteCurrent (VOID)
  870.   {
  871.    CHAR  *statement = new CHAR [SQL_MAXRECL];
  872.  
  873.     // if search record was not found using the search statement
  874.     if (record_found == FALSE)
  875.       {
  876.         // free the delete statement
  877.         free (statement);
  878.  
  879.         // set error location
  880.         id = SQLTAB_ID_12;
  881.  
  882.         // set error return code
  883.         rc = SQLTAB_NO_SEARCH_DONE;
  884.  
  885.         return (rc);
  886.       }
  887.  
  888.     // create delete statement
  889.     sprintf (statement, "DELETE FROM %s WHERE CURRENT OF", table);
  890.  
  891.     // if delete the current row error
  892.     if ( (rc =  sql_delete_row (statement)) != 0)
  893.         // set error location
  894.         id = SQLTAB_ID_16;
  895.  
  896.     // free the delete statement
  897.     free (statement);
  898.  
  899.     return (rc);
  900.   }
  901.  
  902. // :H1 Index: Index the database
  903. //----------------------------------------------------------------------
  904. //
  905. //  Function Name: Index 
  906. //
  907. //  Purpose: This method will create an index for the specified columns.  
  908. //
  909. //  Description: This method will create an index for the specified  
  910. //               columns using the SQL create index command. Only one index       
  911. //               can be created per table.
  912. //
  913. //  Input:
  914. //    format     table format
  915. //               format must be a string using %d, %ld, or %#s for
  916. //               fields to be searched and %*d, %*ld, and %*#s for
  917. //               those not being indexed.
  918. //               # is the string length to search not including the
  919. //               0 terminator. If no fields to be indexed are specified
  920. //               an error will be returned.
  921. //  Output:
  922. //    return code 0 = successful, not 0 = error
  923. //
  924. //----------------------------------------------------------------------
  925. SHORT Table::Index (const CHAR *format)
  926.   {
  927.    const CHAR  *ptr = format;
  928.    SHORT i;
  929.    CHAR  *statement = new CHAR [SQL_MAXRECL];
  930.    CHAR  *col_name;
  931.    CHAR  *names;
  932.    BOOLEAN first_col;
  933.  
  934.     // get copy of column names
  935.     names = strdup (columns);
  936.  
  937.     // initialize pointer to format
  938.     ptr = format;
  939.  
  940.     // create index statement
  941.     sprintf (statement, "CREATE INDEX %s ON %s (", table, table);
  942.  
  943.     // get pointer to start of columns names
  944.     col_name = strtok (names, ",");
  945.  
  946.     // for all columns
  947.     for (i = 0; i < cols && col_name != 0; i++)
  948.       {
  949.         // if % not found in format
  950.         if ( (ptr = strchr (ptr, '%')) == 0)
  951.             break;
  952.  
  953.         // skip to character following %
  954.         ptr++;
  955.  
  956.         // if skip this field
  957.         if (*ptr == '*')
  958.           {
  959.           }
  960.         else
  961.           {
  962.             // if not the first column   
  963.             if (first_col == FALSE)
  964.               {
  965.                 // add a , to separate the columns
  966.                 strcat (statement, ",");
  967.               }
  968.             else
  969.               {
  970.                 // set not the first column
  971.                 first_col = FALSE;
  972.               }
  973.  
  974.             // add variable to index
  975.             strcat (statement, col_name);
  976.           }    
  977.  
  978.         // get pointer to next of column name
  979.         col_name = strtok (NULL, ",");
  980.       }
  981.  
  982.     // add closing ( to statement
  983.     strcat (statement, ")");
  984.  
  985.     // if all columns not processed
  986.     if (i < cols)
  987.       {
  988.         // free the index statement
  989.         free (statement);
  990.  
  991.         // free the names string
  992.         free (names);
  993.  
  994.         // set error location
  995.         id = SQLTAB_ID_18;
  996.  
  997.         // set error return code
  998.         rc = SQLTAB_INVALID_NUMBER_OF_COLUMNS;
  999.  
  1000.         return (rc);
  1001.       }
  1002.  
  1003.     if // no index arguments specified
  1004.        (first_col == TRUE)
  1005.       {
  1006.         // free the index statement
  1007.         free (statement);
  1008.  
  1009.         // free the names string
  1010.         free (names);
  1011.  
  1012.         // set error location
  1013.         id = SQLTAB_ID_19;
  1014.  
  1015.         // set error return code
  1016.         rc = SQLTAB_INVALID_FORMAT_STRING;
  1017.  
  1018.         return (rc);
  1019.       }
  1020.  
  1021.     // if index selected column error
  1022.     if ( (rc =  sql_dynamic (statement)) != 0)
  1023.         // set error location
  1024.         id = SQLTAB_ID_20;
  1025.  
  1026.     // free the index statement
  1027.     free (statement);
  1028.  
  1029.     // free the names string
  1030.     free (names);
  1031.  
  1032.     return (rc);
  1033.   }
  1034.  
  1035. // :H1 ~Table: Table Destructor
  1036. //----------------------------------------------------------------------
  1037. //
  1038. //  Function Name: Table destructor
  1039. //
  1040. //  Purpose: This method will delete an table object.
  1041. //
  1042. //  Description: This method will delete the table object and
  1043. //               release the table name.
  1044. //
  1045. //  Input:
  1046. //    none
  1047. //
  1048. //  Output:
  1049. //    none
  1050. //
  1051. //----------------------------------------------------------------------
  1052. Table::~Table ()
  1053.   {
  1054.     // delete table name
  1055.     delete table;
  1056.   }
  1057.  
  1058.  
  1059. #ifdef TEST
  1060.  
  1061. SHORT _astart;   // for SD386 to find main
  1062.  
  1063. // This code is used to test the sql object.
  1064. VOID main ()
  1065.   {
  1066.    SHORT rc, id;
  1067.    SQL database ("test");       // create sql object
  1068.    Table table ("FORMAT", "%d %ld %4s", "SHORTVAR,LONGVAR,STRINGVAR");
  1069.    SHORT shortvar;
  1070.    LONG  longvar;
  1071.    CHAR  stringvar [5];
  1072.  
  1073.     printf ("Creating database...\n");
  1074.  
  1075.     // if error creating database
  1076.     if ( (rc = database.Create ("This is a test database")) != 0 )
  1077.       {
  1078.         printf ("Error creating database, rc = %d\n", rc);
  1079.         // if error opening database
  1080.         if ( (rc = database.Open ()) != 0 )
  1081.           {
  1082.             printf ("Error opening database, rc = %d\n", rc);
  1083.             exit (-1);
  1084.           }
  1085.        else
  1086.             printf ("Database opened...\n");
  1087.       }
  1088.     else
  1089.         printf ("Database created...\n");
  1090.  
  1091.     printf ("Creating table...\n");
  1092.  
  1093.     if ( (rc = table.Create ()) != 0 )
  1094.       {
  1095.         printf ("Error creating table, rc = %d\n", rc);
  1096.         database.Close ();
  1097.         exit (-1);
  1098.       }
  1099.     else
  1100.         printf ("Table created...\n");
  1101.  
  1102.     if ( (rc = table.Create ()) == 0 )
  1103.       {
  1104.         printf ("No error on 2nd table create, rc = %d\n", rc);
  1105.         database.Close ();
  1106.         exit (-1);
  1107.       }
  1108.  
  1109.     table.Error (rc, id);
  1110.  
  1111.     printf ("2nd create table rc = %d, id = %d\n", rc, id);
  1112.  
  1113.     printf ("Adding indexing\n");
  1114.     if ( (rc = table.Index ("%d %*ld %*4s")) != 0 )
  1115.       {
  1116.         printf ("Error creating index, rc = %d\n", rc);
  1117.         database.Close ();
  1118.         exit (-1);
  1119.       }
  1120.  
  1121.     if ( (rc = table.Index ("%*d %*ld %*4s")) == 0 )
  1122.       {
  1123.         printf ("Error creating index with no index specified, rc = %d\n", rc);
  1124.         database.Close ();
  1125.         exit (-1);
  1126.       }
  1127.  
  1128.     printf ("Inserting data...\n");
  1129.  
  1130.     if ( (rc = table.Insert (3, 1, 2L, "ABC" )) != 0 )
  1131.       {
  1132.         printf ("Error inserting data, rc = %d\n", rc);
  1133.         database.Close ();
  1134.         exit (-1);
  1135.       }
  1136.  
  1137.     if ( (rc = table.Insert (3, 3, 4L, "DEF")) != 0 )
  1138.       {
  1139.         printf ("Error inserting data, rc = %d\n", rc);
  1140.         database.Close ();
  1141.         exit (-1);
  1142.       }
  1143.  
  1144.     printf ("Data inserted...\n");
  1145.  
  1146.     if ( (rc = table.Insert (0, 1, 2)) != SQLTAB_INVALID_NUMBER_OF_COLUMNS)
  1147.       {
  1148.         printf ("Error on invalid number of columns, rc = %d\n", rc);
  1149.         database.Close ();
  1150.         exit (-1);
  1151.       }
  1152.  
  1153.     if ( (rc = table.Search (TRUE, "%d %*d %*4s",
  1154.                &shortvar, &longvar, &stringvar, 1)) != 0)
  1155.       {
  1156.         printf ("Error on table search, rc = %d\n", rc);
  1157.         database.Close ();
  1158.         exit (-1);
  1159.       }
  1160.  
  1161.     if (shortvar != 1 || longvar != 2 || (strcmp (stringvar, "ABC")!= 0))
  1162.       {
  1163.         printf ("Error on table search, incorrect record\n");
  1164.         database.Close ();
  1165.         exit (-1);
  1166.       }
  1167.  
  1168.     if ( (rc = table.Search (FALSE, "%d %*d %*4s",
  1169.                &shortvar, &longvar, &stringvar, 1)) == 0)
  1170.       {
  1171.         printf ("Error on table search, rc = %d\n", rc);
  1172.         database.Close ();
  1173.         exit (-1);
  1174.       }
  1175.  
  1176.     if ( (rc = table.Search (TRUE, "%*d %*d %2s",
  1177.                &shortvar, &longvar, &stringvar, "AB")) != 0)
  1178.       {
  1179.         printf ("Error on partial string search, rc = %d\n", rc);
  1180.         database.Close ();
  1181.         exit (-1);
  1182.       }
  1183.  
  1184.     if (shortvar != 1 || longvar != 2 || (strcmp (stringvar, "ABC")!= 0))
  1185.       {
  1186.         printf ("Error on partial string search, incorrect record\n");
  1187.         database.Close ();
  1188.         exit (-1);
  1189.       }
  1190.  
  1191.     if ( (rc = table.Search (TRUE, "%*d %*d %*2s",
  1192.                &shortvar, &longvar, &stringvar)) != 0)
  1193.       {
  1194.         printf ("Error on search for all rows, rc = %d\n", rc);
  1195.         database.Close ();
  1196.         exit (-1);
  1197.       }
  1198.  
  1199.     if (shortvar != 1 || longvar != 2 || (strcmp (stringvar, "ABC")!= 0))
  1200.       {
  1201.         printf ("Error on search for all rows, incorrect record\n");
  1202.         database.Close ();
  1203.         exit (-1);
  1204.       }
  1205.  
  1206.     if ( (rc = table.DeleteCurrent ()) != 0)
  1207.       {
  1208.         printf ("Error on delete current row, rc = %d\n", rc);
  1209.         database.Close ();
  1210.         exit (-1);
  1211.       }
  1212.  
  1213.     if ( (rc = table.Delete ("%d %*d %*4s", 3)) != 0)
  1214.       {
  1215.         printf ("Error on table row delete, rc = %d\n", rc);
  1216.         database.Close ();
  1217.         exit (-1);
  1218.       }
  1219.  
  1220.     if ( (rc = table.Commit ()) != 0 )
  1221.       {
  1222.         printf ("Error commiting data, rc = %d\n", rc);
  1223.         database.Close ();
  1224.         exit (-1);
  1225.       }
  1226.  
  1227.     if ( (rc = table.Insert (3, 5, 6L, "GHI")) != 0 )
  1228.       {
  1229.         printf ("Error inserting data, rc = %d\n", rc);
  1230.         database.Close ();
  1231.         exit (-1);
  1232.       }
  1233.  
  1234.     if ( (rc = table.Delete ("%*d %*d %*4s")) != 0)
  1235.       {
  1236.         printf ("Error on delete all rows, rc = %d\n", rc);
  1237.         database.Close ();
  1238.         exit (-1);
  1239.       }
  1240.  
  1241.     if ( (rc = database.Close ()) != 0)
  1242.       {
  1243.         printf ("Error on close database, rc = %d\n", rc);
  1244.         exit (-1);
  1245.       }
  1246.  
  1247.     printf ("Unit test completed successfully\n");
  1248.   }
  1249. #endif
  1250.