home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
dbutil.zip
/
BUFOP.ZIP
/
COMPSQL.CPP
< prev
next >
Wrap
Text File
|
1993-10-09
|
11KB
|
317 lines
#include "compsql.hpp"
#include <istring.hpp>
#include <Itime.hpp>
#include "gensql.hpp"
#include <fstream.h>
#include <iset.h>
#include "hostvars.hpp" // host variables
#include <sqlaprep.h>
#include <sql.h>
#include <stdlib.h>
/***********************************************************************
* Precompiler services
* Initial tasks
* create package ID string - gen into new source program
* build option array - set up envirionment
*
* SQL tasks
* prepare sql statement
* build token array
* build compile statement
* generate error messages
* send task array to code generator
*
***********************************************************************/
//
// INTERNAL STATIC VARIABLES used for precompiler services
//
static sqla_tasks * taskArray;
static sqla_tokens * tokenArray;
sqlca mysqlca;
char progIDLabel[] ="_PROGID"; // needed by runtime servies
extern ofstream monitor; // monitor output file name from compsql.h
static unsigned char * pbuff1, * pbuff2, *pbuff3;
static unsigned short sectionNbr;
// these const apply to this implementation only - these are not the
// DB/2 max amounts. As these are just best guess numbers they can be
// changed if needed - or, made dynamic based on actual need
//
const int MAX_TASK = 500; // max number of tasks that can be in task array
const int MAX_TOKENS = 300; // max number of host variables in one statement
const int MAX_OPTIONS = 15; // max number of options for precompiler
//
// This set is a set of characters that terminate a host variable
// sure wish C++ had built in set functions like Mod2
//
typedef ISet<char> charset;
charset termChars; // SQL terminating char
charset prefixChars; // chars that terminate a prefix
/****************************************************************
* PROCEDURE InitSQLStuff
* allocate the needed data structures and
* initialize the sets required for processing
*****************************************************************/
void initSQLStuff()
{
// pSQLCA = new sqlca;
pbuff1 = new unsigned char(128);
pbuff2 = new unsigned char(128);
pbuff3 = new unsigned char(128);
taskArray = (sqla_tasks *) calloc( (sizeof(sqla_tasks::sqla_tasks_header) +
(MAX_TASK)*sizeof(sqla_tasks::sqla_task)),1);
taskArray->header.allocated = MAX_TASK;
tokenArray = (sqla_tokens *) calloc( (sizeof(sqla_tokens:: sqla_tokens_header) +
(MAX_TOKENS)*sizeof(sqla_tokens::sqla_token)),1);
tokenArray->header.allocated = MAX_TOKENS;
termChars.add(':');
termChars.add(',');
termChars.add(' ');
termChars.add('(');
termChars.add(')');
termChars.add('=');
prefixChars.add('.'); // structOrClass.varname
prefixChars.add('*'); // * varname
prefixChars.add('>'); // structOrClass->varname
}
/*==================================================================
* FUNCTION SQLError
* this function will report the sql error along with
* the known state of variables from the variable array
*
*====================================================================*/
void dumpTokenArray(ofstream & out) // debug stuff
{ out << "\nToken Array used: " << tokenArray->header.used << "\n";
Variable V;
for (int j=0;j<tokenArray->header.used ;j++ ) {
V = getVarByID(tokenArray->token[j].id);
out << tokenArray->token[j].use << " " << V
<< "\n";
} /* endfor */
}
static int errorcnt = 0;
void SQLError(int LineNbr,ofstream & out, Boolean full)
{ char buffer[256];
sqlaintp ( buffer, /* buffer for message text */
255, /* buffer size */
60, /* line width */
&mysqlca ); /* SQLCA */
if (full) {
out << "\n* * * * Precompiler Error: " << mysqlca.sqlcode;
out << "At source line: " << LineNbr << "\n";
out << buffer << "\n" << "Variables used: \n";
out << "* * * * * * All Variables * * * * *";
dumpTokenArray(out);
out.flush(); // in case we die someplace, all output to disk
}
} /* end SQL Error */
void MSQLError(int lineNbr){
SQLError(lineNbr,monitor,false);
}
void monitorMessage(IString const & msg)
{ ITime t;
t.now;
monitor << t << " " << msg << "\n";
}
/***************************************************************************
* PROCEDURE IsSQL
*
* this routine will examine the input string for a valid SQL statement
* Special care is given to BEGIN DECLARE and END DECLARE statements
* facilitate the including of multiple header files, each with their own
* BEGIN/END sections.
* Only the first BEGIN DECLARE SECTION statement is processed
* the subsequent BEGIN/END declare sections only toggle a boolean
* the first NON-BEGIN/END declare SQL statement will
* trigger an END DECLARE for the precompiler services
*
* If the statement is an SQL statement
* some initial cleanup is done
* N O T E
* the statemet can not be processed yet as this only detects the begining
* of an SQL statement, and some rudementary SQL commands.
* The statement could be several lines long
* must be built by the input file handler
***************************************************************************/
Boolean IsSQL(IString const & theStr) // checks if the statement is an SQL command
{
if (theStr.isLike("*EXEC *SQL *"))
return true;
else return false;
} // end isSQL
static char blanks[30];
char * makeBlanks(int nbrBlanks)
{
for (int j = 0;j < nbrBlanks ;j++ ) {
blanks[j] = ' ';
} /* endfor */
blanks[nbrBlanks] = '\0';
return &blanks[0];
}
/*******************************************************************
* PROCEDURE PrepareStmt
*prepare an sql statement for compilation
* This routine is given the complete SQL statement
*
* This routine will remove host variables from the input statement
* and fill the variable array.
* It must detect variable prefixes of *, "." or ->
* to support structures, classes and pointers.
* structNameorclass-> varname, * varname) pass the varname and keep
* the prefix part to append for code gen
* A host variable is terminated by either a blank or ',' or ':'
* (in the case of a nul indicator variable)
* A varname is reccognized the :varname or :varname :nulind_name
* if there is a nul indicator, then add one to the varname type
* (N O T E - the nul indicator does not have to be declared in SQL Declare )
*
*********************************************************************/
void prepareSQL(IString & theStmt, ofstream & fout, int lineNbr)
{
int index = 1;
IString thePrefix = "", theToken= "";
int nbrTokens = 0;
char theChar;
char shortStr[2] = "";
tokenArray->header.used = 0;
shortStr[1] = '\0';
theStmt = theStmt.change(";",""); // get rid of SQL terminator char
theStmt =theStmt + " "; // add one byte for compiler
theStmt = theStmt.change("\n"," "); // get rid of CRLF stuff
theStmt =theStmt.change("\t"," "); // make tab a space theStmt.change(" "," "); // make only single space between words
theStmt =theStmt.removeWords(1,2); // remove "EXEC SQL" from statement
index = theStmt.indexOf(":",index);
/*****
* get the number of tokens in the sql statement
* (A host Variable (token) is identified as a substring withing
* the statement that begins with ":"
* W A R N I N G - this thing will fail if the statement has
* a colon in quotes (e.g. WHERE Var = ":mystring" )
* the above is legal SQL but I can't handle it yet
* My personal use will never need this but.....
***************************/
while (index > 0) { // there is a token
tokenArray->token[tokenArray->header.used++].use =index;
index++; // gota point past the current :
index = theStmt.indexOf(":",index);
} /* endwhile */
for (int j=0;j<tokenArray->header.used ;j++ ) { // for each token
int t = tokenArray->token[j].use;
int k = t;
while (! termChars.contains(theStmt[k+1]) ) { // create token
k++;
} /* endwhile get length of token*/
theToken = theStmt.subString(t+1,k-t); // isolate the token
theStmt = theStmt.change(theToken,
makeBlanks(theToken.length()),t,1);
// get rid of the token in the statement
/**********************
* if a prefix is found, isolate it from the variable so
* we can find the variable
* then restore it when we do the SetV Function call
* to give the correct address
***************************/
IString tmp1 = theToken;
int pos = 0;
pos = max(pos,theToken.indexOf('*')); // for for pointer
pos = max(pos,theToken.indexOf('>')); // look for ->
pos = max(pos,theToken.indexOf('.')); // for for dot operator
if (pos > 0) {
theToken.insert(" ",pos);
thePrefix = theToken.word(1); // keep the prefix
theToken.removeWords(1,1); // but remove from token
} else {thePrefix = "";}
Variable * V = getVarByName(theToken);
V->setPrefix(thePrefix);
tokenArray->token[j].id = V->getID();
theToken = "";
} /* endfor */
/******************************************************************
* the statement is now ready for compiling
* the tokens have been removed and placed in the token array
* all non-printable stuff is changed to white space
* compile the statement and generate the code);
*******************************************************************/
unsigned short stmttype;
unsigned short len = theStmt.length() -1;
sqlacmpl (&len, /* SQL statement text length */
theStmt, /* SQL statement text */
(unsigned short *) &lineNbr, /* source line number */
taskArray, /* task array */
tokenArray,/* token id array */
§ionNbr, /* section number */
&stmttype, /* type of SQL statement */
pbuff1, /* 128 byte string buffer 1 */
pbuff2, /* 128 byte string buffer 2 */
pbuff3, /* 128 byte string buffer 3 */
NULL, /* reserved */
&mysqlca); /* SQLCA */
if (mysqlca.sqlcode < 0) { //error in the statement
SQLError(lineNbr,fout,true);
SQLError(lineNbr,monitor,true);
} else { // everything spiffy jets
genSQL(fout, taskArray,tokenArray,sectionNbr,theStmt,stmttype);
}
} // end of prepare statement