home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / dbutil.zip / BUFOP.ZIP / COMPSQL.CPP < prev    next >
Text File  |  1993-10-09  |  11KB  |  317 lines

  1. #include "compsql.hpp"
  2. #include <istring.hpp>
  3. #include <Itime.hpp>
  4. #include "gensql.hpp"
  5. #include <fstream.h>
  6. #include <iset.h>
  7. #include "hostvars.hpp"         // host variables
  8. #include <sqlaprep.h>
  9. #include <sql.h>
  10. #include <stdlib.h>
  11.  
  12. /***********************************************************************
  13. *  Precompiler services
  14. *   Initial tasks
  15. *    create package ID string - gen into new source program
  16. *      build option array - set up envirionment
  17. *
  18. *     SQL tasks
  19. *    prepare sql statement
  20. *      build token array
  21. *      build compile statement
  22. *      generate error messages
  23. *    send task array to code generator
  24. *    
  25. ***********************************************************************/
  26.  
  27.  
  28. //
  29. // INTERNAL STATIC VARIABLES used for precompiler services
  30. //
  31.  
  32. static sqla_tasks * taskArray;
  33. static sqla_tokens * tokenArray;
  34.  sqlca      mysqlca;
  35.  char  progIDLabel[] ="_PROGID";    // needed by runtime servies
  36.  
  37. extern ofstream monitor;     // monitor output file name from compsql.h
  38.  
  39. static unsigned char * pbuff1, * pbuff2, *pbuff3;
  40. static unsigned short sectionNbr;
  41.  
  42.  
  43. // these const apply to this implementation only - these are not the
  44. // DB/2 max amounts.  As these are just best guess numbers they can be
  45. // changed if needed - or, made dynamic based on actual need
  46. //
  47.  
  48. const int MAX_TASK = 500;       // max number of tasks that can be in task array
  49. const int MAX_TOKENS = 300;       // max number of host variables in one statement
  50. const int MAX_OPTIONS = 15;     // max number of options for precompiler
  51.  
  52.  
  53.  
  54. //
  55. //                This set is a set of characters that terminate a host variable
  56. //               sure wish C++ had built in set functions like Mod2
  57. //
  58. typedef ISet<char> charset;
  59. charset termChars;                    // SQL terminating char
  60. charset prefixChars;                          // chars that terminate a prefix
  61.  
  62.  
  63. /****************************************************************
  64. * PROCEDURE InitSQLStuff
  65. *  allocate the needed data structures and
  66. *  initialize the sets required for processing
  67. *****************************************************************/
  68.  
  69. void initSQLStuff()
  70.  
  71. {
  72. //    pSQLCA = new sqlca;
  73.     pbuff1 = new unsigned char(128);
  74.     pbuff2 = new unsigned char(128);
  75.     pbuff3 = new unsigned char(128);
  76.     taskArray = (sqla_tasks *) calloc( (sizeof(sqla_tasks::sqla_tasks_header) +
  77.                         (MAX_TASK)*sizeof(sqla_tasks::sqla_task)),1);
  78.     taskArray->header.allocated = MAX_TASK;
  79.  
  80.  
  81.     tokenArray = (sqla_tokens *) calloc( (sizeof(sqla_tokens:: sqla_tokens_header) +
  82.                          (MAX_TOKENS)*sizeof(sqla_tokens::sqla_token)),1);
  83.     tokenArray->header.allocated = MAX_TOKENS;
  84.  
  85.                                            
  86.     termChars.add(':');
  87.     termChars.add(',');
  88.     termChars.add(' ');
  89.     termChars.add('(');
  90.     termChars.add(')');
  91.     termChars.add('=');
  92.      prefixChars.add('.');  // structOrClass.varname
  93.      prefixChars.add('*');  //  * varname
  94.      prefixChars.add('>');  // structOrClass->varname
  95. }
  96.  
  97.  
  98. /*==================================================================
  99. *  FUNCTION  SQLError
  100. *   this function will report the sql error along with
  101. *   the known state of variables from the variable array
  102. *
  103. *====================================================================*/
  104.  
  105. void dumpTokenArray(ofstream & out)    // debug stuff
  106. {   out << "\nToken Array  used: " << tokenArray->header.used << "\n";
  107.   Variable V;
  108.     for (int j=0;j<tokenArray->header.used ;j++ ) {
  109.        V = getVarByID(tokenArray->token[j].id);
  110.        out << tokenArray->token[j].use << "  " << V
  111.                << "\n";
  112.   } /* endfor */                                       
  113. }
  114.  
  115.  
  116. static int errorcnt = 0;
  117.  
  118. void SQLError(int LineNbr,ofstream & out, Boolean full)
  119. { char  buffer[256];
  120.  
  121.  
  122.    sqlaintp ( buffer,              /* buffer for message text */
  123.               255,                 /* buffer size */
  124.               60,                  /* line width */
  125.               &mysqlca );          /* SQLCA */
  126.   if (full) {
  127.       out << "\n* * * * Precompiler Error: " << mysqlca.sqlcode;
  128.       out << "At source line: " << LineNbr << "\n";
  129.       out << buffer << "\n" << "Variables used: \n";
  130.       out << "* * * * * * All Variables * * * * *";
  131.       dumpTokenArray(out);
  132.       out.flush();              // in case we die someplace, all output to disk
  133.   }
  134.  
  135. }  /* end SQL Error */
  136.  
  137.  
  138.  
  139. void MSQLError(int lineNbr){
  140.    SQLError(lineNbr,monitor,false);
  141.  }
  142.  
  143.  
  144. void monitorMessage(IString const & msg)
  145. {  ITime t;
  146.    t.now;
  147.    monitor << t << " " << msg << "\n";
  148. }
  149.  
  150.  
  151.  
  152. /***************************************************************************
  153. * PROCEDURE IsSQL
  154. *
  155. *  this routine will examine the input string for a valid SQL statement
  156. *  Special care is given  to BEGIN DECLARE and END DECLARE statements
  157. *  facilitate the including of multiple header files, each with their own
  158. *  BEGIN/END sections.
  159. *    Only the first BEGIN DECLARE SECTION statement is processed
  160. *     the subsequent BEGIN/END declare sections only toggle a boolean
  161. *     the first NON-BEGIN/END declare SQL statement will
  162. *     trigger an  END DECLARE for the precompiler services
  163. *
  164. *  If the statement is an SQL statement
  165. *  some initial cleanup is done
  166. *   N O T E 
  167. *    the statemet can not be processed yet as this only detects the begining
  168. *    of an SQL statement, and some rudementary SQL commands.
  169. *    The statement could be several lines long 
  170. *      must be built by the input file handler
  171. ***************************************************************************/
  172.  
  173. Boolean IsSQL(IString const & theStr)   // checks if the statement is an SQL command
  174. {
  175.    if (theStr.isLike("*EXEC *SQL *"))
  176.       return true;
  177.       else return false;
  178.  
  179. } // end isSQL
  180.  
  181.  
  182.  
  183. static char blanks[30];
  184.  
  185. char * makeBlanks(int nbrBlanks)
  186. {
  187.   for (int j = 0;j < nbrBlanks ;j++ ) {
  188.      blanks[j] = ' ';
  189.   } /* endfor */
  190.   blanks[nbrBlanks] = '\0';
  191.   return &blanks[0];
  192. }
  193.  
  194. /*******************************************************************
  195. * PROCEDURE PrepareStmt
  196. *prepare an sql statement for compilation
  197. *  This routine is given the complete SQL statement
  198. *
  199. *  This routine will remove host variables from the input statement
  200. *  and fill the variable array.
  201. *  It must detect variable prefixes of *, "." or ->
  202. *  to support structures, classes and pointers.
  203. *   structNameorclass-> varname, * varname) pass the varname and keep
  204. *   the prefix part to append for code gen
  205. *  A host variable is terminated by either a blank or ',' or ':'
  206. *  (in the case of a nul indicator variable)
  207. *  A varname is reccognized the :varname or :varname :nulind_name
  208. *  if there is a nul indicator, then add one to the varname type
  209. *  (N O T E - the nul indicator does not have to be declared in SQL Declare )
  210. *
  211. *********************************************************************/
  212.  
  213. void prepareSQL(IString & theStmt, ofstream & fout, int lineNbr)
  214. {
  215.  
  216. int index = 1;
  217. IString thePrefix = "", theToken= "";
  218.  
  219. int nbrTokens = 0;
  220.  char theChar;
  221.  char shortStr[2] = "";
  222.  
  223.  
  224.   tokenArray->header.used = 0;
  225.   shortStr[1] = '\0';
  226.   theStmt = theStmt.change(";","");       // get rid of SQL terminator char
  227.   theStmt =theStmt + " ";            // add one byte for compiler
  228.  
  229.   theStmt = theStmt.change("\n"," ");      // get rid of CRLF stuff
  230.   theStmt =theStmt.change("\t"," ");      // make tab a space  theStmt.change("  "," ");      // make only single space between words
  231.   theStmt =theStmt.removeWords(1,2);      // remove "EXEC SQL" from statement
  232.   index = theStmt.indexOf(":",index);
  233.  
  234. /*****  
  235. *   get the number of tokens in the sql statement
  236. *  (A host Variable (token) is identified as a substring withing
  237. *  the statement that begins with ":"
  238. *  W A R N I N G - this thing will fail if the statement has
  239. *  a colon in quotes (e.g.  WHERE Var = ":mystring" )
  240. *  the above is legal SQL but I can't handle it yet
  241. *  My personal use will never need this but.....
  242. ***************************/
  243.  
  244.   while (index > 0) {          // there is a token
  245.      tokenArray->token[tokenArray->header.used++].use =index;
  246.      index++;                 // gota point past the current :
  247.      index = theStmt.indexOf(":",index);
  248.    } /* endwhile */  
  249.     for (int j=0;j<tokenArray->header.used ;j++ ) {  // for each token
  250.       int t = tokenArray->token[j].use;
  251.       int k = t;
  252.       while (! termChars.contains(theStmt[k+1]) ) {  // create token
  253.          k++;
  254.       } /* endwhile   get length of token*/
  255.       theToken = theStmt.subString(t+1,k-t);        // isolate the token
  256.       theStmt = theStmt.change(theToken,
  257.                                makeBlanks(theToken.length()),t,1); 
  258.                                          // get rid of the token in the statement
  259. /********************** 
  260. *  if a prefix is found, isolate it from the variable so
  261. *  we can find the variable
  262. *  then restore it when we do the SetV Function call
  263. *  to give the correct address
  264. ***************************/
  265.  
  266.       IString tmp1 = theToken;
  267.       int pos = 0;
  268.       pos = max(pos,theToken.indexOf('*'));     // for for pointer
  269.       pos = max(pos,theToken.indexOf('>'));     // look for ->
  270.       pos = max(pos,theToken.indexOf('.'));     // for for dot operator
  271.       if (pos > 0) {
  272.          theToken.insert(" ",pos);
  273.          thePrefix = theToken.word(1);      // keep the prefix
  274.          theToken.removeWords(1,1);           // but remove from token
  275.          } else {thePrefix = "";}
  276.       Variable * V = getVarByName(theToken);
  277.       V->setPrefix(thePrefix);
  278.       tokenArray->token[j].id = V->getID();
  279.       theToken = "";
  280.  
  281.  
  282.     } /* endfor */
  283.  
  284. /****************************************************************** 
  285. *  the statement is now ready for compiling
  286. *  the tokens have been removed and placed in the token array
  287. *  all non-printable stuff is changed to white space
  288. *  compile the statement and generate the code);
  289. *******************************************************************/
  290.   unsigned short stmttype;
  291.   unsigned short len = theStmt.length() -1;
  292.   sqlacmpl     (&len,    /* SQL statement text length */
  293.                 theStmt,     /* SQL statement text */
  294.                 (unsigned short *) &lineNbr,    /* source line number */
  295.                 taskArray, /* task array */
  296.                 tokenArray,/* token id array */
  297.                 §ionNbr,    /* section number */
  298.                 &stmttype,    /* type of SQL statement */
  299.                 pbuff1,     /* 128 byte string buffer 1 */
  300.                 pbuff2,     /* 128 byte string buffer 2 */
  301.                 pbuff3,     /* 128 byte string buffer 3 */
  302.                 NULL,              /* reserved */
  303.                 &mysqlca);     /* SQLCA */
  304.  
  305.   if (mysqlca.sqlcode < 0) {        //error in the statement
  306.     SQLError(lineNbr,fout,true);
  307.     SQLError(lineNbr,monitor,true);
  308.   } else {                          // everything spiffy jets
  309.   genSQL(fout, taskArray,tokenArray,sectionNbr,theStmt,stmttype);
  310.   }
  311.  
  312. } // end of prepare statement
  313.  
  314.  
  315.  
  316.  
  317.