home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
dbutil.zip
/
BUFOP.ZIP
/
GENSQL.CPP
< prev
next >
Wrap
Text File
|
1993-09-13
|
16KB
|
454 lines
#include "compsql.hpp"
#include <istring.hpp>
#include "files.hpp"
#include <fstream.h>
#include <iset.h>
#include "hostvars.hpp" // host variables
#include <sqlaprep.h>
#include <sql.h>
#include <stdlib.h>
extern sqlca mysqlca;
extern sqla_program_id progID;
Boolean optimize;
//
// On an SQL error, warning or not found - the goto labels
//
static IString NotFoundLabel="";
static IString WarningLabel ="";
static IString ErrorLabel = "";
/*********************************************************************
* Generate the source code for access to the database
* The generate instructions are in the task array
* (created by the precompiler services)
* Variables and usage is in the token array (usage filled in by
* precompiler services)
**********************************************************************/
/*********************************************************************
* Proto Types of internal functions to gen code
*********************************************************************/
void inputFile(IString const & Stmt, unsigned long );
static unsigned short nxtSQLDA=1,inputSQLDA=0, outputSQLDA=0;
void genConnect(char type, // exclusive or shared
IString const & stmt, // SQL statment with DB name in
unsigned long x, // offset to DBName & DBLen
ofstream & fout); // output file
void GenSetVArray(int nbrTokens,
unsigned short StmtID,
Boolean input,
ofstream & fout,
sqla_tokens * tokenArray);
void GenOnError(ofstream & fout);
void GenOnWarning(ofstream & fout);
void GenOnNotFound(ofstream & fout);
IString MakeLabel(IString & theLabel);
void GenIncludeSQLDA(ofstream & fout);
void GenIncludeSQLCA(ofstream & fout);
void GenSQLASets(int theID, ofstream & fout);
/************************************************************* */
/* G E N E R A T E C O D E TO I N T E R F A C E */
/* D B 2 / 2 */
/************************************************************** */
genSQL(ofstream & fout, sqla_tasks * taskArray, sqla_tokens * tokenArray,
unsigned short sectionNbr, IString const & Stmt, int stmttype)
{
int task;
//
// reset the sqlda ids for this call
//
inputSQLDA = 0;
outputSQLDA = 0;
for (int j=0;j<taskArray->header.used ;j++ ) {
switch (taskArray->task[j].func) {
case SQLA_START: fout << " sqlastrt(&sqla_program_id,NULL,&sqlca); \n";
break;
case SQLA_DECLARE:
if (taskArray->task[j].val == SQLA_BEGIN) {
setDeclare(true);
} else {
setDeclare(false);
} /* endif */
break;
case SQLA_INCLUDE:
if (taskArray->task[j].val == SQLA_SQLCA) {
GenIncludeSQLCA(fout);
} else {
GenIncludeSQLDA(fout);
} /* endif */
break;
case SQLA_ALLOC_INPUT: GenSetVArray(taskArray->task[j].val,sectionNbr,
true,fout,tokenArray);
break;
case SQLA_ALLOC_OUTPUT: GenSetVArray(taskArray->task[j].val,sectionNbr,
false,fout,tokenArray);
break;
case SQLA_SETS: GenSQLASets(taskArray->task[j].val, fout);
break;
case SQLA_USDA_INPUT: // TBD GenSQLDA(taskArray->task[j].value);
break;
case SQLA_USDA_OUTPUT: // TBDGenInputSQLDA(taskArray->task[j].value);
break;
case SQLA_CALL:
fout << " sqlacall("
<< taskArray->task[j].val << ", "
<< sectionNbr << ", "
<< inputSQLDA << ", "
<< outputSQLDA
<< ",NULL); \n";
break;
case SQLA_DEALLOC: /* not used */
break;
case SQLA_STOP: fout << " sqlastop(NULL); \n";
break;
case SQLA_SQLERROR: GenOnError(fout);
break;
case SQLA_SQLWARNING: GenOnWarning(fout);
break;
case SQLA_NOT_FOUND: GenOnNotFound(fout);
break;
case SQLA_CONNECT_EXCL: genConnect('X',Stmt,taskArray->task[j].val,fout);
break;
case SQLA_CONNECT_SHARE: genConnect('S',Stmt,taskArray->task[j].val,fout);
break;
case SQLA_CONNECT_RESET: fout << " _RC = sqlestpd(&sqlca); \n";// not used
break;
case SQLA_INC_TEXTFILE:
{inputFile(Stmt,taskArray->task[j].val);}
break;
} /* endswitch */
} /* endfor each task in task array*/
//-----------------------------------------------------------------------
// C H E C K F O R A W H E N E V E R S T M T
// a "whenever statement does not associate any tasks
// must pick up the info based on statement type
// N O T I C E
// do not support ":label" no colon in the label
//----------------------------------------------------------------------
if (stmttype == SQLA_TYPE_WHEN_NOT_FOUND ) {
NotFoundLabel = Stmt.word(Stmt.numWords()); // skip "whenever not found"
} else {
if (stmttype == SQLA_TYPE_WHEN_SQLERROR ) {
ErrorLabel = Stmt.word(Stmt.numWords()); // skip " whenever sqlwarning"
} else {
if (stmttype == SQLA_TYPE_WHEN_SQLWARNING ) {
WarningLabel = Stmt.word(Stmt.numWords()); // skip " whenever sqlerror "
} /* endif */
} /* endif */
} /* endif */
} /* end of gen code */
/***************************************************************************
* support functions for code generation
***************************************************************************/
void GenSetVArray(int nbrTokens,
unsigned short StmtID,
Boolean input,
ofstream & fout,
sqla_tokens * tokenArray)
{
short useSQLDA; // id of sqlda to use
Variable Var; // a variable objects
// -----------------------------------------------------------
if (input) {
inputSQLDA =nxtSQLDA++;
useSQLDA = inputSQLDA;
} else {
outputSQLDA = nxtSQLDA++;
useSQLDA = outputSQLDA;
} /* endif */
fout << " _RC = sqlaaloc(" << useSQLDA << ", " << nbrTokens << ","
<< StmtID << ",NULL);// allocate an sqlda \n";
//
// for each host variable used - gen setV code
//
// if the indicator is with Indicator, the next in the array
// will be the null indicator - get that and send the name
//
if (optimize) {
fout << "if (sqlca.code == 0) { \n"; // gen the optimization stuff
} /* endif*/
int index = 0;
int theID, theNullInd;
Variable theToken;
/***********************************************************************
* The token array has all tokens used For input only process the ones
* markeds for input, for output, only process the ones marked for output
************************************************************************/
if (input) {
for (int j = 0;j < tokenArray->header.used ;j++ ) {
theID = tokenArray->token[j].id;
switch (tokenArray->token[j].use) {
case SQLA_INPUT_HVAR : theToken = getVarByID(theID); // get the token
theToken.setV(useSQLDA,index,fout);
index++;
break;
case SQLA_INPUT_WITH_IND : theToken = getVarByID(theID);
theNullInd = tokenArray->token[j+1].id;
theToken.setVNull(useSQLDA,index,fout,theNullInd);
index++;
break;
case SQLA_INDICATOR: // do nothing - already done by withNull
break;
} /* endswitch */
} /* end for */
} else {
for (int j = 0;j < tokenArray->header.used ;j++ ) {
theID = tokenArray->token[j].id;
switch (tokenArray->token[j].use) {
case SQLA_OUTPUT_HVAR : theToken = getVarByID(theID); // get the token
theToken.setV(useSQLDA,index,fout);
index++;
break;
case SQLA_OUTPUT_WITH_IND: theToken = getVarByID(theID);
theNullInd = tokenArray->token[j+1].id;
theToken.setVNull(useSQLDA,index,fout,theNullInd);
index++;
break;
case SQLA_INDICATOR: // do nothing - already done by withNull
break;
} /* endswitch */
} /* end for */
} /* end if*/
if (optimize) {
fout << "} // end of optimize \n ";
} /* endif */
}
/**********************************************************************
* and EXEC SQL IMPORT
* was found in the input stream. Isolate the file name and
* make a recursive call to process file with the file name
**********************************************************************/
void inputFile(IString const & Stmt, unsigned long x)
{
sqla_return_token * p = (sqla_return_token *) &x;
IString FileName=Stmt.subString(p->offset,p->length);
FileName.translate("'","");
FileName.strip(' ');
processFile(FileName);
}
/************************************************************
*
* Generate call to connent the database
* in form of
* _rc =sqlestrd("dbname",use,&sqlca);
**************************************************************/
void genConnect(char type, // exclusive or shared
IString const & stmt, // SQL statment with DB name in
unsigned long x, // offset to DBName & DBLen
ofstream & fout) // output file
{
sqla_return_token * p = (sqla_return_token *) &x;
IString dbName = stmt.subString((p->offset)+1,p->length);
fout << "\n unsigned char dbname[]= \"" << dbName << "\";\n";
fout <<" _RC = sqlestrd(dbname, '" << type << "',&sqlca);\n";
}
//========================================================================
// an sqlca includes both the CA and the DA and....
// in this implementation generates the program ID sqla_program_id
// defines the ca to use in all DB calls
// defines the Booean _found
// one of these should be put into every program module that
// makes DB calls
//========================================================================
void GenIncludeSQLCA(ofstream & fout)
{
//unsigned short letter;
unsigned char * pProgID = (unsigned char *) &progID; // pointer to program ID
fout << "#include <sqlda.h> // sqlda structure \n"
<< "#include <sqlca.h> // sqlca structre \n"
<< "#include <sqlaprep.h> // api(s) for most calls \n"
<< "#include <sqlenv.h> // api(s) for start & stop db \n"
<< "sqlca sqlca; \n" // an instance of sqlca
<< "typedef int Boolean; \n"
<< "#define false 0\n"
<< "#define true 1 \n"
<< "Boolean _sqlfound = false;\n"
<< "Boolean _sqlerror = false;\n"
<< "Boolean _sqlwarn = false; \n"
<< "int _RC;\n"
<< "const unsigned char sqla_program_id[40] = {";
fout << hex;
fout.setf(ios::showbase);
for (int j=0;j<4 ;j++ ) { // print 4 lines of 10
fout << "\n ";
for (int k=j*10;k<(j+1)*10 ;k++ ) { // do 10 char
fout << short (pProgID[k]);
if (k < 39) {
fout <<",";
} /* endif */
} /* endfor */
} /* endfor */
fout << "};\n\n";
fout << dec; // change it back to decimal
}
//=================================================================
// an sqlda include only includes the file
// wow big deal. changed the including of the
// structure into the program to generating an include <sqlda.h>
// does the same thing but no so messy
// I don't know of any real use for this command.
//===================================================================
void GenIncludeSQLDA(ofstream & fout)
{ fout << "#include <sqlda.h>\n";
}
//------------------------------------------------------
// support for dynamic sql SQLASets
// the hostvar in the ID
// get the hostvar by the ID and generate SQLASETS
//-----------------------------------------------------------
void GenSQLASets(int theID, ofstream & fout)
{ IString VName,lenstr;
Variable V;
V = getVarByID(theID);
VName = V.getFullName();
if (VName.includes('&')) {
lenstr = VName.strip('&');
}else{
lenstr = VName;
} /* endif */
fout << " _RC = sqlasets(strlen( " << lenstr << "),"
<< VName << ",NULL);\n";
}
/***************************************************************
* A word about GOTOs (on error, warning, not found )
* I HATE Gotos but SQL uses them. So I cheat!
* If the goto label is of the patterm xxxx(x)
* I will call it as a function rather than a goto
* If the no found is _found I will gen code to
* set the boolean _found
* otherwise I'll just gen the go-old goto
*************************************************************/
void GenOnError(ofstream & fout){
const char SB[]=
" if (sqlca.sqlcode < 0) { \n"
" _sqlerror = true;\n"
" } else { \n"
" _sqlerror = false;\n"
" } /* endif */ \n";
const char GT[] =
" if (sqlca.sqlcode < 0) { \n";
if (ErrorLabel.includes("_sqlerror")) { // generate code to set boolean
fout << SB;
} else { fout << " " << MakeLabel(NotFoundLabel) << ";\n"
<< " }\n";
} /* endif */
}
void GenOnWarning(ofstream & fout){
const char SB[]=
" if (((sqlca.sqlcode > 0) && (sqlca.sqlcode !=100))) ||\n"
" ((sqlca.sqlcode ==0) && (sqlca.sqlwarn[0] == 'W'))){\n"
" _sqlwarn = true;\n"
" } else { \n"
" _sqlwarn = true;\n"
" } /* endif */ \n";
const char GT[] =
" if (sqlca.sqlcode == 100) { \n";
if (WarningLabel.includes("_sqlwarn")) { // generate code to set boolean
fout << SB;
} else { fout << " " << MakeLabel(NotFoundLabel) << ";\n"
<< " }\n";
} /* endif */
}
void GenOnNotFound(ofstream & fout){
const char SB[]=
" if (sqlca.sqlcode == 100) { \n"
" _sqlfound = false;\n"
" } else { \n"
" _sqlfound = true;\n"
" } /* endif */ \n";
const char GT[] =
" if (sqlca.sqlcode == 100) { \n";
if (NotFoundLabel.includes("_sqlfound")) { // generate code to set boolean
fout << SB;
} else { fout << " " << MakeLabel(NotFoundLabel) << ";\n"
<< " }\n";
} /* endif */
}
IString MakeLabel(IString & theLabel) {
if (theLabel.isLike("*(*)")) { // make it a function call
return theLabel+ ";\n";
} else {
return "goto " + theLabel;
} /* endif */
}