_A GENERIC SQL CLASS LIBRARY_ by Ken North [LISTING ONE] /////////////////////////////////////////////////// // FILE NAME: dbObject.h TITLE: database class // AUTHOR: Ken North Resource Group, Inc. // 2604B El Camino Real, #351 // copyright(c)1992 Carlsbad, CA 92008 /////////////////////////////////////////////////// #ifndef __DBOBJECT_H #define __DBOBJECT_H class dbObject { int ReferenceTotal; protected: public: dbObject(); virtual ~dbObject(); virtual void IncrementRefs(); virtual int DecrementRefs(); }; #endif [LISTING TWO] /////////////////////////////////////////////////// // FILE NAME: dbObject.cpp TITLE: base class // AUTHOR: Ken North Resource Group, Inc. // 2604B El Camino Real, #351 // copyright(c)1992 Carlsbad, CA 92008 /////////////////////////////////////////////////// // SYNOPSIS: // implementation of dbObject class /////////////////////////////////////////////////// #undef DEBUG #undef DEBUG1 #include #include #include "sql.h" #include "sqlext.h" #include "sqldefs.h" #include "dbobject.h" //////////////////////////////////////////////////// // FUNCTION NAME: dbObject // SYNOPSIS: // define dbObject, SQL base class constructor //////////////////////////////////////////////////// dbObject :: dbObject() { ReferenceTotal = 1; // referenced by self } /////////////////////////////////////////////////// // FUNCTION NAME: ~dbObject // define dbObject, SQL data base class destructor /////////////////////////////////////////////////// dbObject :: ~dbObject() { // this is a point where error handler should be // invoked if the reference total > 1 or < 0 // systemError(); } //////////////////////////////////////////////////////////////////////// // FUNCTION NAME: IncrementRefs -- increment object reference total //////////////////////////////////////////////////////////////////////// void dbObject :: IncrementRefs() { ReferenceTotal++; } ////////////////////////////////////////////////////////////////////////// // FUNCTION NAME: IncrementRefs -- increment object reference total ////////////////////////////////////////////////////////////////////////// int dbObject :: DecrementRefs() { // if the reference total < 0 // { // systemError(); // } return(--ReferenceTotal); } [LISTING THREE] /////////////////////////////////////////////////// // FILE NAME: database.cpp TITLE: data base class // AUTHOR: Ken North Resource Group, Inc. // 2604B El Camino Real, #351 // copyright(c)1992 Carlsbad, CA 92008 // SYNOPSIS: implementation of database class /////////////////////////////////////////////////// #undef DEBUG #undef DEBUG1 #include #include #include "sql.h" #include "sqlext.h" #include "gendefs.h" #include "sqldefs.h" #include "dbobject.h" #include "sqldb.h" #ifndef __RGSTRING_H #include "rgstring.h" #endif HDBC dbDataBase::ODBCLinkHandle[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; int dbDataBase::nDefinedSources = 0; int dbDataBase::ActiveLinks = 0; char dbDataBase::DataSourceList[] = "None"; UCHAR dbDataBase::ODBCLinkList[] = "None"; /* standard return code for calls */ extern char ErrStat; /* large / huge model */ extern char MemModel; //////////////////////////////////////////////////// // FUNCTION NAME: dbDataBase // SYNOPSIS: dbDataBase class constructor //////////////////////////////////////////////////// dbDataBase::dbDataBase(HENV AppEnv) : dbObject() { // save application environment handle henv = AppEnv; // initialize status and error info StatusReturned = SQL_SUCCESS; InitODBCErrorInfo(); } /////////////////////////////////////////////////////////// // FUNCTION NAME: ~DataBase -- DataBase class destructor ////////////////////////////////////////////////////////// dbDataBase :: ~dbDataBase() { } ////////////////////////////////////////////////////////////////////////// // FUNCTION NAME: InitODBCErrorInfo -- initialize ODBC error information ////////////////////////////////////////////////////////////////////////// void dbDataBase::InitODBCErrorInfo() { err.ErrStatus = 0; err.ErrorMsgLength = 0; err.ErrorMsgMax = 0; err.NativeError = 0; memset(err.szSQLState,'\x0', sizeof(err.szSQLState)); memset(err.ErrorMsg,'\x0', sizeof(err.ErrorMsg)); } /*************************************************** * FUNCTION NAME: MatchLinkName * SYNOPSIS: scan the active link list (ODBCLinkList) to find * the link that matches the selected link name * (from disconnect dialog box) *****************************************************/ int dbDataBase::MatchLinkName(UCHAR *LinkToDrop) { int tdx; /* link index */ int toff; /* link offset */ UCHAR NameToTest[LINK_NAME_LEN+1]; /* string position to begin search */ unsigned short StartPos=0; /* position found: result of the search */ unsigned short SearchResult; for (tdx=0;tdx < ActiveLinks;tdx++) { toff = tdx * LINK_NAME_LEN; memset(NameToTest,'\x0',LINK_NAME_LEN+1); substr_n((char *)ODBCLinkList, (char *)NameToTest, toff, LINK_NAME_LEN ) ; SearchResult = left_srch((char *)NameToTest, (char *)LinkToDrop, StartPos); if (ErrStat == SUCCESS) { return tdx; } } return OOPS; } [LISTING FOUR] //////////////////////////////////////////////////// // FILE NAME: connect.h TITLE: SQL connection // AUTHOR: Ken North Resource Group, Inc. // 2604B El Camino Real, #351 // copyright(c)1992 Carlsbad, CA 92008 //////////////////////////////////////////////////// #ifndef __CONNECT_H #define __CONNECT_H #ifndef __SQLDB_H #include "sqldb.h" #endif #ifndef __DATASOUR_H #include "datasour.h" #endif #ifndef __DBPROFIL_H #include "dbprofil.h" #endif #ifndef __ODERROR_H #include "oderror.h" #endif #ifndef __DSINFO_H #include "DSInfo.h" /* data source information */ #endif /* Connection is a child of data source */ class dbConnection : public dbDataSource { protected: HENV henv; POINTER cstr; public: RETCODE Status; RETCODE ErrStatus; HDBC hdbc; UCHAR far *conec; static UCHAR ConnectionString[CONECLEN]; static UCHAR szConnStrOut[CONECLEN]; /* the next two variables are used for situations */ /* where a connection's values are subsets of a */ /* data source's values */ SDWORD ConnTableCount; /* number of tables for this connection */ char ConnTableList[DS_TABLE_LIST_LEN]; dbConnection(HENV); virtual ~dbConnection(); HDBC AllocateConnection(void); POINTER BuildBrowseConnectString(char *); virtual POINTER BuildConnectString(char *); RETCODE BrowseConnect(); virtual RETCODE Connect(UCHAR *, UCHAR *); virtual int Disconnect(UCHAR *); RETCODE DriverConnect(UCHAR *); void InitConnData(void); void dbConnection::GetErrorInfo(void); RETCODE PASCAL ProfileDataSource(DataSourceInfo *); }; #endif [LISTING FIVE] /////////////////////////////////////////////////////////////////// // FILE NAME: connect.cpp TITLE: database connection // AUTHOR: Ken North Resource Group, Inc. // 2604B El Camino Real, #351 // copyright(c)1992 Carlsbad, CA 92008 /////////////////////////////////////////////////////////////////// // SYNOPSIS: implementation of SQL connection class /////////////////////////////////////////////////////////////////// #include #include #include #include #include #include "sql.h" #include "sqlext.h" #include "sqldefs.h" #include "gendefs.h" #include "sqldb.h" #include "dboption.h" #include "oderror.h" #ifndef __DATASOUR_H #include "datasour.h" #endif #ifndef __DSINFO_H #include "DSInfo.h" /* data source information */ #endif #include "connect.h" UCHAR dbConnection::ConnectionString[]="None"; UCHAR dbConnection::szConnStrOut[]=""; /* constructor for dbConnection class */ dbConnection::dbConnection(HENV AppEnv) : dbDataSource(AppEnv) { henv = AppEnv; /* save environment handle */ InitODBCErrorInfo(); Status = SQL_SUCCESS; } /////////////////////////////////////////////////////////////////// // FUNCTION NAME: ~dbConnection // SYNOPSIS: destructor for dbConnection /////////////////////////////////////////////////////////////////// dbConnection::~dbConnection() { } /////////////////////////////////////////////////////////////////// // FUNCTION NAME: AllocateConnection // SYNOPSIS: allocates a connection handle /////////////////////////////////////////////////////////////////// HDBC dbConnection::AllocateConnection() { /* get connection handle */ Status = SQLAllocConnect(henv, &hdbc); if (Status != SQL_SUCCESS) { return NULL; }; return hdbc; } /////////////////////////////////////////////////////////////////// // FUNCTION NAME: Connect // SYNOPSIS: connect to SQL data source /////////////////////////////////////////////////////////////////// RETCODE dbConnection::Connect(UCHAR *Userid, UCHAR *Password) { SWORD cbConnStrOut; memset(ConnectionString,'\x0',sizeof(ConnectionString)); memset(szConnStrOut,'\x0',sizeof(szConnStrOut)); strcpy((char *)ConnectionString,"DSN="); strncat((char *)ConnectionString,(char *)TrimmedDSName, strlen((char *)TrimmedDSName)); /* ODBC driver connect */ Status = SQLDriverConnect (hdbc, NULL, ConnectionString, SQL_NTS, szConnStrOut, CONECLEN, &cbConnStrOut, SQL_DRIVER_COMPLETE); if (Status != SQL_SUCCESS) { /* ODBC connect */ Status = SQLConnect (hdbc, DSName, SQL_NTS, Userid, SQL_NTS, Password, SQL_NTS); if (Status != SQL_SUCCESS) { err.ErrorMsgMax = SQL_MAX_MESSAGE_LENGTH - 1; ErrStatus = SQLError(henv, hdbc, SQL_NULL_HSTMT, &err.szSQLState[0], &err.NativeError, &err.ErrorMsg[0], err.ErrorMsgMax, &err.ErrorMsgLength); } } ODBCLinkHandle[ActiveLinks] = hdbc; /* add handle to active list */ if (ActiveLinks < 1) { strncpy((char *)ODBCLinkList,(char *)DSName, SQL_MAX_DSN_LENGTH); } else { strncat((char *)ODBCLinkList,(char *)DSName,sizeof(DSName)); } ActiveLinks++; return Status; } /////////////////////////////////////////////////////////////////// // FUNCTION NAME: BuildConnectString // SYNOPSIS: build connection string for ODBC driver // return far pointer to connection string /////////////////////////////////////////////////////////////////// POINTER dbConnection::BuildConnectString(char *str) { UCHAR far *conec; conec = (UCHAR far *) malloc(CONECLEN); movedata(FP_SEG(str), FP_OFF(str), FP_SEG(conec), FP_OFF(conec), 1+strlen(str)); return conec; } /////////////////////////////////////////////////////////////////// // FUNCTION NAME: Disconnect // SYNOPSIS: terminate the SQL connection /////////////////////////////////////////////////////////////////// int dbConnection::Disconnect(UCHAR *LinkToDrop) { int i; int j; int nLink; /* index to hdbc to drop */ int offset; HDBC ConnHandle; nLink = MatchLinkName(LinkToDrop); if (nLink < 0) { return OOPS; } ConnHandle = ODBCLinkHandle[nLink]; /* ODBC disconnect */ Status = SQLDisconnect(ConnHandle); if (Status) return Status; /* compress the list of active links and active handles */ for (i=nLink; i < ActiveLinks;i++) { ODBCLinkHandle[i] = ODBCLinkHandle[i+1]; } offset = nLink * LINK_NAME_LEN; j = offset; while ( ODBCLinkList[j+LINK_NAME_LEN] != '\0') { ODBCLinkList[j] = ODBCLinkList[j+LINK_NAME_LEN]; j++; } ODBCLinkList[j] = '\0'; --ActiveLinks; /* free conn handle */ Status = SQLFreeConnect(ConnHandle); if (Status) return Status; return SQL_SUCCESS; } /////////////////////////////////////////////////////////////////// // FUNCTION NAME: ProfileDataSource // SYNOPSIS: information about driver and data source /////////////////////////////////////////////////////////////////// RETCODE PASCAL dbConnection::ProfileDataSource( DataSourceInfo *inf ) { /* implementation of error handling is left to the user, since */ /* the user interface may vary. Using QuickWin or EasyWin, you can */ /* use printf statements. If you are writing a typical Windows app, */ /* you can use MessageBox or BWCCMessageBox to display errors */ Status = SQL_SUCCESS; Status = SQLGetInfo(hdbc, SQL_DRIVER_NAME, &inf->DriverName, sizeof(inf->DriverName), NULL); if (Status != SQL_SUCCESS) { GetErrorInfo(); } Status = SQL_SUCCESS; Status = SQLGetInfo(hdbc, SQL_ACTIVE_STATEMENTS, (PTR)&inf->ActiveStatements, sizeof(inf->ActiveStatements), NULL); if (Status != SQL_SUCCESS) { GetErrorInfo(); } Status = SQL_SUCCESS; Status = SQLGetInfo(hdbc, SQL_ACTIVE_CONNECTIONS, (PTR)&inf->ActiveConnections, sizeof(inf->ActiveConnections), NULL); if (Status != SQL_SUCCESS) { GetErrorInfo(); } Status = SQL_SUCCESS; Status = SQLGetInfo(hdbc, SQL_DRIVER_VER, &inf->DriverVersion, sizeof(inf->DriverVersion), NULL); if (Status != SQL_SUCCESS) { GetErrorInfo(); } Status = SQL_SUCCESS; Status = SQLGetInfo(hdbc, SQL_SERVER_NAME, &inf->ServerName, sizeof(inf->ServerName), NULL); if (Status != SQL_SUCCESS) { GetErrorInfo(); } Status = SQL_SUCCESS; Status = SQLGetInfo(hdbc, SQL_USER_NAME, &inf->UserName, sizeof(inf->UserName), NULL); if (Status != SQL_SUCCESS) { GetErrorInfo(); } Status = SQL_SUCCESS; Status = SQLGetInfo(hdbc, SQL_ODBC_API_CONFORMANCE, (PTR)&inf->ODBC_API_Level, sizeof(inf->ODBC_API_Level), NULL); if (Status != SQL_SUCCESS) { GetErrorInfo(); } Status = SQL_SUCCESS; Status = SQLGetInfo(hdbc, SQL_ODBC_SAG_CLI_CONFORMANCE, (PTR)&inf->ODBC_SAG_Level, sizeof(inf->ODBC_SAG_Level), NULL); if (Status != SQL_SUCCESS) { GetErrorInfo(); } Status = SQL_SUCCESS; Status = SQLGetInfo(hdbc, SQL_ODBC_SQL_CONFORMANCE, (PTR)&inf->ODBC_SQL_Level, sizeof(inf->ODBC_SQL_Level), NULL); if (Status != SQL_SUCCESS) { GetErrorInfo(); } Status = SQL_SUCCESS; Status = SQLGetInfo(hdbc, SQL_DATABASE_NAME, &inf->DatabaseName, sizeof(inf->DatabaseName), NULL); if (Status != SQL_SUCCESS) { GetErrorInfo(); } Status = SQL_SUCCESS; Status = SQLGetInfo(hdbc, SQL_DBMS_NAME, &inf->DBMSName, sizeof(inf->DBMSName), NULL); if (Status != SQL_SUCCESS) { GetErrorInfo(); } Status = SQL_SUCCESS; Status = SQLGetInfo(hdbc, SQL_DBMS_VER, &inf->DBMSVersion, sizeof(inf->DBMSVersion), NULL); if (Status != SQL_SUCCESS) { GetErrorInfo(); } /* IEF ? */ Status = SQL_SUCCESS; Status = SQLGetInfo(hdbc, SQL_ODBC_SQL_OPT_IEF, &inf->IEFSupport, sizeof(inf->IEFSupport), NULL); if (Status != SQL_SUCCESS) { GetErrorInfo(); } /* Support Procedures ? */ Status = SQL_SUCCESS; Status = SQLGetInfo(hdbc, SQL_PROCEDURES, &inf->Procedures, sizeof(inf->Procedures), NULL); if (Status != SQL_SUCCESS) { GetErrorInfo(); } /* detect changes in rows between fetches ? */ Status = SQL_SUCCESS; Status = SQLGetInfo(hdbc, SQL_ROW_UPDATES, &inf->RowUpdates, sizeof(inf->RowUpdates), NULL); if (Status != SQL_SUCCESS) { GetErrorInfo(); } /* all tables accessible */ Status = SQL_SUCCESS; Status = SQLGetInfo(hdbc, SQL_ACCESSIBLE_TABLES, &inf->AccessibleTables, sizeof(inf->AccessibleTables), NULL); if (Status != SQL_SUCCESS) { GetErrorInfo(); } if(inf->AccessibleProcedures[0] == 'Y') { /* all procedures accessible */ Status = SQL_SUCCESS; Status = SQLGetInfo(hdbc, SQL_ACCESSIBLE_PROCEDURES, &inf->AccessibleProcedures, sizeof(inf->AccessibleProcedures), NULL); if (Status != SQL_SUCCESS) { GetErrorInfo(); } } Status = SQL_SUCCESS; Status = SQLGetInfo(hdbc, SQL_CONCAT_NULL_BEHAVIOR, (PTR)&inf->ConcatNullBehavior, sizeof(inf->ConcatNullBehavior), NULL); if (Status != SQL_SUCCESS) { GetErrorInfo(); } Status = SQL_SUCCESS; Status = SQLGetInfo(hdbc, SQL_CURSOR_COMMIT_BEHAVIOR, (PTR)&inf->CursorCommitBehavior, sizeof(inf->CursorCommitBehavior), NULL); if (Status != SQL_SUCCESS) { GetErrorInfo(); } Status = SQL_SUCCESS; Status = SQLGetInfo(hdbc, SQL_CURSOR_ROLLBACK_BEHAVIOR, (PTR)&inf->CursorRollbackBehavior, sizeof(inf->CursorRollbackBehavior), NULL); if (Status != SQL_SUCCESS) { GetErrorInfo(); } Status = SQL_SUCCESS; Status = SQLGetInfo(hdbc, SQL_DATA_SOURCE_READ_ONLY, &inf->DSReadOnly, sizeof(inf->DSReadOnly), NULL); if (Status != SQL_SUCCESS) { GetErrorInfo(); } Status = SQL_SUCCESS; Status = SQLGetInfo(hdbc, SQL_MAX_COLUMN_NAME_LEN, (PTR)&inf->MaxColNameLen, sizeof(inf->MaxColNameLen), NULL); if (Status != SQL_SUCCESS) { GetErrorInfo(); } Status = SQL_SUCCESS; Status = SQLGetInfo(hdbc, SQL_MAX_CURSOR_NAME_LEN, (PTR)&inf->MaxCursorNameLen, sizeof(inf->MaxCursorNameLen), NULL); if (Status != SQL_SUCCESS) { GetErrorInfo(); } Status = SQL_SUCCESS; Status = SQLGetInfo(hdbc, SQL_MAX_OWNER_NAME_LEN, (PTR)&inf->MaxOwnerNameLen, sizeof(inf->MaxOwnerNameLen), NULL); if (Status != SQL_SUCCESS) { GetErrorInfo(); } Status = SQL_SUCCESS; Status = SQLGetInfo(hdbc, SQL_MAX_PROCEDURE_NAME_LEN, (PTR)&inf->MaxProcedureNameLen, sizeof(inf->MaxProcedureNameLen), NULL); if (Status != SQL_SUCCESS) { GetErrorInfo(); } Status = SQL_SUCCESS; Status = SQLGetInfo(hdbc, SQL_MAX_QUALIFIER_NAME_LEN, (PTR)&inf->MaxQualifierNameLen, sizeof(inf->MaxQualifierNameLen), NULL); if (Status != SQL_SUCCESS) { GetErrorInfo(); } Status = SQL_SUCCESS; Status = SQLGetInfo(hdbc, SQL_MAX_TABLE_NAME_LEN, (PTR)&inf->MaxTableNameLen, sizeof(inf->MaxTableNameLen), NULL); if (Status != SQL_SUCCESS) { GetErrorInfo(); } Status = SQL_SUCCESS; Status = SQLGetInfo(hdbc, SQL_MULT_RESULT_SETS, &inf->MultipleResultSets, sizeof(inf->MultipleResultSets), NULL); if (Status != SQL_SUCCESS) { GetErrorInfo(); } Status = SQL_SUCCESS; Status = SQLGetInfo(hdbc, SQL_MULTIPLE_ACTIVE_TXN, &inf->MultipleActiveTransactions, sizeof(inf->MultipleActiveTransactions), NULL); if (Status != SQL_SUCCESS) { GetErrorInfo(); } Status = SQL_SUCCESS; Status = SQLGetInfo(hdbc, SQL_OUTER_JOINS, &inf->OuterJoins, sizeof(inf->OuterJoins), NULL); if (Status != SQL_SUCCESS) { GetErrorInfo(); } Status = SQL_SUCCESS; Status = SQLGetInfo(hdbc, SQL_OWNER_TERM, &inf->OwnerTerm, sizeof(inf->OwnerTerm), NULL); if (Status != SQL_SUCCESS) { GetErrorInfo(); } Status = SQL_SUCCESS; Status = SQLGetInfo(hdbc, SQL_PROCEDURE_TERM, &inf->ProcTerm, sizeof(inf->ProcTerm), NULL); if (Status != SQL_SUCCESS) { GetErrorInfo(); } Status = SQL_SUCCESS; Status = SQLGetInfo(hdbc, SQL_QUALIFIER_TERM, &inf->QualifierTerm, sizeof(inf->QualifierTerm), NULL); if (Status != SQL_SUCCESS) { GetErrorInfo(); } Status = SQL_SUCCESS; Status = SQLGetInfo(hdbc, SQL_EXPRESSIONS_IN_ORDERBY, &inf->OrderBy, sizeof(inf->OrderBy), NULL); if (Status != SQL_SUCCESS) { GetErrorInfo(); } Status = SQL_SUCCESS; Status = SQLGetInfo(hdbc, SQL_TXN_CAPABLE, (PTR)&inf->TransCapable, sizeof(inf->TransCapable), NULL); if (Status != SQL_SUCCESS) { GetErrorInfo(); } if (Status != SQL_SUCCESS) return Status; return(SQL_SUCCESS); } /////////////////////////////////////////////////////////////////// // FUNCTION NAME: GetErrorInfo // SYNOPSIS: check SQLError info /////////////////////////////////////////////////////////////////// void dbConnection::GetErrorInfo() { /* implementation of error handling is left to the user, since */ /* the user interface may vary. Using QuickWin or EasyWin, you can */ /* use printf statements. If you are writing a typical Windows app, */ /* you can use MessageBox or BWCCMessageBox to display errors */ err.ErrorMsgMax = SQL_MAX_MESSAGE_LENGTH - 1; ErrStatus = SQLError(henv, hdbc, SQL_NULL_HSTMT, &err.szSQLState[0], &err.NativeError, &err.ErrorMsg[0], err.ErrorMsgMax, &err.ErrorMsgLength); } /////////////////////////////////////////////////// // FUNCTION NAME: InitConnData // SYNOPSIS: initialize conn data /////////////////////////////////////////////////// void dbConnection::InitConnData() { Status = 0; ErrStatus = 0; cstr = NULL; ConnTableCount = 0; memset(ConnectionString,'\x0',sizeof(ConnectionString)); memset(ConnTableList,'\x0',sizeof(ConnTableList)); } [LISTING SIX] /////////////////////////////////////////////////// // FILE NAME: request.h TITLE: SQL request // AUTHOR: Ken North Resource Group, Inc. // 2604B El Camino Real, #351 // copyright(c)1992 Carlsbad, CA 92008 /////////////////////////////////////////////////// #ifndef __REQUEST_H #define __REQUEST_H #ifndef __CONNECT_H #include "connect.h" #endif #ifndef __DBOPTION_H #include "dboption.h" #endif #ifndef __RQOPTION_H #include "rqoption.h" #endif #ifndef __TABLESET_H #include "tableset.h" #endif // dbRequest is a child of dbConnection class dbRequest : public dbConnection { protected: UCHAR Statement[MAXSQL]; UCHAR *stmt; RETCODE Status; // exceeds max statement length for d.b. driver BOOL ExceedsMax; HENV henv; HSTMT hAStmt; CURNAME ACursor; /* for named cursors */ UCHAR CursorName[CURSOR_NAME_LEN]; public: UCHAR far *stptr; HSTMT hstmt; DataBaseOptions *dbopt; // options for this database RequestOptions OptionInfo; // options for this request dbRequest(HENV, HDBC, DataBaseOptions *, UCHAR *); virtual ~dbRequest(); virtual HSTMT AllocateStatement(HDBC); virtual POINTER BuildRequest(BOOL); virtual RETCODE ExecuteStatement(POINTER); virtual SWORD FindNumberOfColumns(HSTMT); virtual CURNAME GetCursorforRequest(HDBC); SDWORD GetTableList(char *); void InitTableResultSet(TableResultSet *); virtual int TerminateStatement(HSTMT); }; #endif [LISTING SEVEN] ///////////////////////////////////////////////////////////////////// // FILE NAME: request.cpp TITLE: SQL request // AUTHOR: Ken North Resource Group, Inc. // 2604B El Camino Real, #351 // copyright(c)1992 Carlsbad, CA 92008 ///////////////////////////////////////////////////////////////////// // SYNOPSIS: SQL request class ///////////////////////////////////////////////////////////////////// #include #include #include #include #include #include #include "sql.h" #include "sqlext.h" #include "gendefs.h" #include "sqldefs.h" #include "sqldb.h" #include "connect.h" #include "dboption.h" /* database options */ #ifndef __ODERROR_H #include "oderror.h" #endif #ifndef __RGSTRING_H #include "rgstring.h" #endif #include "request.h" extern char ErrStat; /* return code for string calls */ extern char MemModel; /* large / huge model */ /* Constructor for the 'Request' class: */ dbRequest :: dbRequest( HENV envhandle, HDBC connhandle, DataBaseOptions *opt, UCHAR *SQLstring ) : dbConnection(envhandle) { // save SQL string and options dbopt = opt; strcpy((char *)Statement,(char *)SQLstring); stmt = &Statement[0]; // set request environment handle henv = envhandle; // set request connection handle hdbc = connhandle; } ///////////////////////////////////////////////////////////////////// // FUNCTION NAME: ~dbRequest // SYNOPSIS: destructor ///////////////////////////////////////////////////////////////////// dbRequest::~dbRequest() { free(stptr); } ///////////////////////////////////////////////////////////////////// // FUNCTION NAME: BuildRequest // SYNOPSIS: prepare an SQL request ///////////////////////////////////////////////////////////////////// POINTER dbRequest::BuildRequest( BOOL ExceedsMax ) { if (dbopt->AllocStmtHandle) { hAStmt = AllocateStatement(hdbc); } if (OptionInfo.UseCursor) { ACursor = GetCursorforRequest(hdbc); } stptr = (UCHAR far *) malloc(MAXSQL); movedata(FP_SEG(stmt), FP_OFF(stmt), FP_SEG(stptr), FP_OFF(stptr), 1+strlen((char *)stmt)); return stptr; } ///////////////////////////////////////////////////////////////////// // FUNCTION NAME: ExecuteStatement // SYNOPSIS: executes a direct or prepared request ///////////////////////////////////////////////////////////////////// RETCODE dbRequest::ExecuteStatement( POINTER stptr ) { Status = SQLExecDirect (hAStmt, stptr, SQL_NTS ); if (Status != SQL_SUCCESS) { return Status; }; return SQL_SUCCESS; } ///////////////////////////////////////////////////////////////////// // FUNCTION NAME: FindNumberOfColumns // SYNOPSIS: get the number of columns in the request ///////////////////////////////////////////////////////////////////// SWORD dbRequest::FindNumberOfColumns( HSTMT hstmt ) { SWORD n; Status = SQLNumResultCols (hAStmt, &n); if (Status != SQL_SUCCESS) { return Status; }; return n; } ///////////////////////////////////////////////////////////////////// // FUNCTION NAME: GetTableList // SYNOPSIS: get the tables for this SQL data source ///////////////////////////////////////////////////////////////////// SDWORD dbRequest::GetTableList(char *TableList) { SDWORD nTables=0; SDWORD QualifierLength; SDWORD OwnerLength; SDWORD NameLength; SDWORD TypeLength; SDWORD RemarksLength; UCHAR FAR *szTableQualifier=NULL; SWORD cbTableQualifier=0; UCHAR FAR *szTableOwner=NULL; SWORD cbTableOwner=0; UCHAR FAR *szTableName=NULL; SWORD cbTableName=0; UCHAR FAR *szTableType=NULL; SWORD cbTableType=0; TableResultSet *rset; char NameString[TABLE_NAME_LEN+1]; rset = new(TableResultSet); if(!rset) return NO_MEMORY; InitTableResultSet(rset); Status = SQL_SUCCESS; ErrStatus = 0; Status = SQLTables( hstmt, szTableQualifier, cbTableQualifier, szTableOwner, cbTableOwner, szTableName, cbTableName, szTableType, cbTableType); if(Status == SQL_ERROR) { err.ErrorMsgMax = SQL_MAX_MESSAGE_LENGTH - 1; ErrStatus = SQLError(henv, hdbc, SQL_NULL_HSTMT, &err.szSQLState[0], &err.NativeError, &err.ErrorMsg[0], err.ErrorMsgMax, &err.ErrorMsgLength); if (ErrStatus < 1) return Status; } Status = SQL_SUCCESS; Status=SQLBindCol(hstmt, 1, SQL_C_CHAR, &rset->TABLE_QUALIFIER, sizeof(rset->TABLE_QUALIFIER), &QualifierLength); if(Status == SQL_ERROR) { err.ErrorMsgMax = SQL_MAX_MESSAGE_LENGTH - 1; ErrStatus = SQLError(henv, hdbc, SQL_NULL_HSTMT, &err.szSQLState[0], &err.NativeError, &err.ErrorMsg[0], err.ErrorMsgMax, &err.ErrorMsgLength); if (ErrStatus < 1) return Status; } Status = SQL_SUCCESS; ErrStatus = 0; Status=SQLBindCol(hstmt, 2, SQL_C_CHAR, &rset->TABLE_OWNER, sizeof(rset->TABLE_OWNER), &OwnerLength); if(Status == SQL_ERROR) { err.ErrorMsgMax = SQL_MAX_MESSAGE_LENGTH - 1; ErrStatus = SQLError(henv, hdbc, SQL_NULL_HSTMT, &err.szSQLState[0], &err.NativeError, &err.ErrorMsg[0], err.ErrorMsgMax, &err.ErrorMsgLength); if (ErrStatus < 1) return Status; } Status = SQL_SUCCESS; ErrStatus = 0; Status=SQLBindCol(hstmt, 3, SQL_C_CHAR, &rset->TABLE_NAME, sizeof(rset->TABLE_NAME), &NameLength); if(Status == SQL_ERROR) { err.ErrorMsgMax = SQL_MAX_MESSAGE_LENGTH - 1; ErrStatus = SQLError(henv, hdbc, SQL_NULL_HSTMT, &err.szSQLState[0], &err.NativeError, &err.ErrorMsg[0], err.ErrorMsgMax, &err.ErrorMsgLength); if (ErrStatus < 1) return Status; } Status = SQL_SUCCESS; ErrStatus = 0; Status=SQLBindCol(hstmt, 4, SQL_C_CHAR, &rset->TABLE_TYPE, sizeof(rset->TABLE_TYPE), &TypeLength); if(Status == SQL_ERROR) { err.ErrorMsgMax = SQL_MAX_MESSAGE_LENGTH - 1; ErrStatus = SQLError(henv, hdbc, SQL_NULL_HSTMT, &err.szSQLState[0], &err.NativeError, &err.ErrorMsg[0], err.ErrorMsgMax, &err.ErrorMsgLength); if (ErrStatus < 1) return Status; } Status = SQL_SUCCESS; ErrStatus = 0; Status=SQLBindCol(hstmt, 5, SQL_C_CHAR, &rset->REMARKS, sizeof(rset->REMARKS), &RemarksLength); if(Status == SQL_ERROR) { err.ErrorMsgMax = SQL_MAX_MESSAGE_LENGTH - 1; ErrStatus = SQLError(henv, hdbc, SQL_NULL_HSTMT, &err.szSQLState[0], &err.NativeError, &err.ErrorMsg[0], err.ErrorMsgMax, &err.ErrorMsgLength); if (ErrStatus < 1) return Status; } /* Loop to fetch data for SQLTables */ while (Status != SQL_NO_DATA_FOUND) { InitTableResultSet(rset); Status = SQL_SUCCESS; ErrStatus = 0; Status = SQLFetch(hstmt); if(Status == SQL_ERROR) { err.ErrorMsgMax = SQL_MAX_MESSAGE_LENGTH - 1; ErrStatus = SQLError(henv, hdbc, SQL_NULL_HSTMT, &err.szSQLState[0], &err.NativeError, &err.ErrorMsg[0], err.ErrorMsgMax, &err.ErrorMsgLength); if (ErrStatus < 1) return Status; } strcpy(NameString,(char *)rset->TABLE_NAME); right_fill(NameString,SPACE,TABLE_NAME_LEN); strncat(TableList,NameString,TABLE_NAME_LEN); nTables++; } return nTables; } ///////////////////////////////////////////////////////////////////// // FUNCTION NAME: InitTableResultSet // SYNOPSIS: initialize result set for GetTables ///////////////////////////////////////////////////////////////////// void dbRequest::InitTableResultSet(TableResultSet *rs) { memset(rs->TABLE_QUALIFIER,'\x0',sizeof(rs->TABLE_QUALIFIER)); memset(rs->TABLE_OWNER,'\x0',sizeof(rs->TABLE_OWNER)); memset(rs->TABLE_NAME,'\x0',sizeof(rs->TABLE_NAME)); memset(rs->TABLE_TYPE,'\x0',sizeof(rs->TABLE_TYPE)); memset(rs->REMARKS,'\x0',sizeof(rs->REMARKS)); } ///////////////////////////////////////////////////////////////////// // FUNCTION NAME: TerminateStatement // SYNOPSIS: terminate the statement ///////////////////////////////////////////////////////////////////// RETCODE dbRequest::TerminateStatement(HSTMT hstmt) { Status = SQLFreeStmt(hstmt, SQL_DROP); if (Status) return Status; else return SQL_SUCCESS; } ///////////////////////////////////////////////////////////////////// // FUNCTION NAME: AllocateStatement // SYNOPSIS: allocates a statement handle ///////////////////////////////////////////////////////////////////// HSTMT dbRequest::AllocateStatement(HDBC hdbc) { Status = SQLAllocStmt(hdbc, &hstmt); if (Status != SQL_SUCCESS) { return NULL; }; return hstmt; } ///////////////////////////////////////////////////////////////////// // FUNCTION NAME: GetCursorforRequest // SYNOPSIS: gets a cursor for this request ///////////////////////////////////////////////////////////////////// CURNAME dbRequest::GetCursorforRequest(HDBC hdbc) { return NULL; } [LISTING EIGHT] ///////////////////////////////////////////////////////////////////// // FILE NAME: column.h TITLE: SQL column class // AUTHOR: Ken North Resource Group, Inc. // 2604B El Camino Real, #351 // copyright(c)1992 Carlsbad, CA 92008 ///////////////////////////////////////////////////////////////////// #ifndef __COLUMN_H #define __COLUMN_H #ifndef __DBOPTION_H #include "dboption.h" #endif #ifndef __REQUEST_H #include "request.h" #endif #ifndef __COLDESC_H #include "coldesc.h" #endif /* 'dbColumn' is a child of 'dbRequest' */ class dbColumn : public dbRequest { protected: HSTMT hstmt; public: RETCODE Status; /* column info for this request */ ColumnDesc ColumnInfo[MAXFIELD]; dbColumn(HENV, HDBC, DataBaseOptions *, HSTMT, UCHAR *, UWORD); virtual ~dbColumn(); virtual int Describe(UWORD, ColumnDesc *); virtual char * DecodeODBCDataType(SWORD); }; #endif [LISTING NINE] ///////////////////////////////////////////////////////////////////// // FILE NAME: column.cpp TITLE: database column // AUTHOR: Ken North Resource Group, Inc. // 2604B El Camino Real, #351 // copyright(c)1992 Carlsbad, CA 92008 // ///////////////////////////////////////////////////////////////////// // SYNOPSIS: implementation of SQL column class ///////////////////////////////////////////////////////////////////// #include #include #include #include #include #include #include "sql.h" #include "sqlext.h" #include "sqldefs.h" #include "sqldb.h" #include "connect.h" #include "dboption.h" #include "rqoption.h" #include "request.h" #include "column.h" /* Constructor for the 'dbColumn' class: */ dbColumn :: dbColumn( HENV envhandle, HDBC connhandle, DataBaseOptions *opt, HSTMT hStatement, UCHAR *SQLstring, UWORD ColumnPosition ) : dbRequest( envhandle, connhandle, opt, SQLstring) { hstmt = hStatement; } ///////////////////////////////////////////////////////////////////// // FUNCTION NAME: ~dbColumn // SYNOPSIS: destructor for dbColumn ///////////////////////////////////////////////////////////////////// dbColumn::~dbColumn() { } ///////////////////////////////////////////////////////////////////// // FUNCTION NAME: Describe // SYNOPSIS: get a column description ///////////////////////////////////////////////////////////////////// RETCODE dbColumn::Describe( UWORD ColumnPosition, ColumnDesc *fi) { UCHAR FAR *col; SWORD NameBufLen=NAMELENGTH; SWORD ncount; /* get the column name, type, width, etc. */ Status = SQLDescribeCol ( hstmt, ColumnPosition, &fi->Name[0], NameBufLen, &ncount, &fi->DataType, &fi->Precision, &fi->Scale, &fi->Nullable); if (Status != SQL_SUCCESS) { return Status; } return SQL_SUCCESS; } ///////////////////////////////////////////////////////////////////// // FUNCTION NAME: DecodeODBCDataType // SYNOPSIS: return description of data type ///////////////////////////////////////////////////////////////////// char *dbColumn::DecodeODBCDataType(SWORD DataType) { static char Type[20]; strcpy((char *)Type,"Unknown"); if (DataType == SQL_CHAR) strcpy((char *)Type,"character"); if (DataType == SQL_VARCHAR) strcpy((char *)Type,"variable len char"); if (DataType == SQL_LONGVARCHAR) strcpy((char *)Type,"long variable char"); if (DataType == SQL_DECIMAL) strcpy((char *)Type,"decimal"); if (DataType == SQL_NUMERIC) strcpy((char *)Type,"numeric"); if (DataType == SQL_BIT) strcpy((char *)Type,"bit"); if (DataType == SQL_TINYINT) strcpy((char *)Type,"tiny integer"); if (DataType == SQL_SMALLINT) strcpy((char *)Type,"small integer"); if (DataType == SQL_INTEGER) strcpy((char *)Type,"integer"); if (DataType == SQL_BIGINT) strcpy((char *)Type,"big integer"); if (DataType == SQL_REAL) strcpy((char *)Type,"real"); if (DataType == SQL_FLOAT) strcpy((char *)Type,"float"); if (DataType == SQL_DOUBLE) strcpy((char *)Type,"double"); if (DataType == SQL_BINARY) strcpy((char *)Type,"binary"); if (DataType == SQL_VARBINARY) strcpy((char *)Type,"variable binary"); if (DataType == SQL_LONGVARBINARY) strcpy((char *)Type,"long variable binary"); if (DataType == SQL_DATE) strcpy((char *)Type,"date"); if (DataType == SQL_TIME) strcpy((char *)Type,"time"); if (DataType == SQL_TIMESTAMP) strcpy((char *)Type,"timestamp"); return Type; } [LISTING TEN] /////////////////////////////////////////////////// // FILE NAME: blob.h TITLE: SQL blob class // AUTHOR: Ken North Resource Group, Inc. // 2604B El Camino Real, #351 // copyright(c)1992 Carlsbad, CA 92008 /////////////////////////////////////////////////// #ifndef __BLOB_H #define __BLOB_H #ifndef __DBOPTION_H #include "dboption.h" #endif #ifndef __REQUEST_H #include "request.h" #endif /* 'dbBlob' is a child of 'dbRequest' */ class dbBlob : public dbRequest { protected: HSTMT hstmt; public: RETCODE Status; dbBlob(HENV, HDBC, DataBaseOptions *, HSTMT, UCHAR *); virtual ~dbBlob(); }; #endif [LISTING ELEVEN] /////////////////////////////////////////////////// // FILE NAME: blob.cpp TITLE: database blob // AUTHOR: Ken North Resource Group, Inc. // 2604B El Camino Real, #351 // copyright(c)1992 Carlsbad, CA 92008 // SYNOPSIS: implementation of SQL blob class /////////////////////////////////////////////////// #include #include #include #include #include #include #include "sql.h" #include "sqlext.h" #include "sqldefs.h" #include "sqldb.h" #include "connect.h" #include "dboption.h" #include "rqoption.h" #include "request.h" #include "blob.h" /* Constructor for the 'dbBLOB' class: */ dbBlob :: dbBlob( HENV envhandle, HDBC connhandle, DataBaseOptions *opt, HSTMT hStatement, UCHAR *SQLstring) : dbRequest( envhandle, connhandle, opt, SQLstring) { hstmt = hStatement; } /////////////////////////////////////////////////// // FUNCTION NAME: ~dbBLOB // SYNOPSIS: destructor for dbBLOB /////////////////////////////////////////////////// dbBlob::~dbBlob() { } [LISTING TWELVE] /////////////////////////////////////////////////////////////////// // FILE NAME: SQLstruc.cpp TITLE: SQL data dictionary // AUTHOR: Ken North Resource Group, Inc., 2604B El Camino Real, #351 // copyright(c)1992 Carlsbad, CA 92008 // SYNOPSIS: display dictionary (structure) info for SQL table /////////////////////////////////////////////////////////////////// #include #include #include #include #include #include "qeapi.h" #ifndef __QEDEFS_H #include "qedefs.h" /* QELIB definitions */ #endif #ifndef __SQLDB_H #include "sqldb.h" /* database class */ #endif #ifndef __CONNECT_H #include "connect.h" #endif #ifndef __RQOPTION_H #include "rqoption.h" /* request options */ #endif #ifndef __DATASRC_H #include "datasrc.h" /* data source */ #endif #ifndef __REQUEST_H #include "request.h" #endif #ifndef __COLUMN_H #include "column.h" #endif #ifndef __BLOB_H #include "blob.h" #endif #ifndef __COLDESC_H #include "coldesc.h" /* column or field description */ #endif #include "sqlstruc.h" static char DBDriver [9]; static char DBDictPath[80]; static char DBTable[31]; static char DBUserid[31]; static char DBPassword[PASSWORDLEN]; static char SQLString[MAXSQL]; static char FldName[DISPLAYLEN+1]; char *driver; char *table; char *dict; char *userid; char *password; ColumnDesc *fi; void main (int argc, char *argv[]) { dbDataBase *db; dbConnection *connection; dbRequest *request; dbColumn *column; dbBlob *BLOB; HSTMT hstmt; POINTER statement; // exceeds max SQL stmt. length BOOL ExceedsMax=FALSE; int nColumns; /* number of columns */ int ColumnPosition; int ColumnCount; int flen; /* string length of field name */ int i; /* blank fill loop index */ int TotalLength; /* sum of field lengths */ char *ColumnDataType; memset(DBDriver,'\x0',sizeof(DBDriver)); memset(DBDictPath,'\x0',sizeof(DBDictPath)); memset(DBTable,'\x0',sizeof(DBTable)); memset(DBUserid,'\x0',sizeof(DBUserid)); memset(DBPassword,'\x0',sizeof(DBPassword)); memset(SQLString,'\x0',sizeof(SQLString)); /* point to strings */ table = &DBTable[0]; dict = &DBDictPath[0]; driver = &DBDriver[0]; userid = &DBUserid[0]; password = &DBPassword[0]; /* data source includes a driver and path */ /* Using ODBC, data source info is in a file */ /* For this example, prompt for relevant info */ DataSource source; memset(source.DBDictPath,'\x0',sizeof(source.DBDictPath)); memset(source.DBDataPath,'\x0',sizeof(source.DBDataPath)); memset(source.DBDriver,'\x0',sizeof(source.DBDriver)); memset(source.DBUserid,'\x0',sizeof(source.DBUserid)); memset(source.DBDataBase,'\x0',sizeof(source.DBDataBase)); memset(source.DBServer,'\x0',sizeof(source.DBServer)); db = new(dbDataBase); db->StatusReturned = SQL_SUCCESS; /* define options for this database */ db->Options.AllocConnHandle = FALSE; db->Options.AllocEnvHandle = FALSE; db->Options.AllocStmtHandle = FALSE; db->Options.UseCursor = FALSE; db->opt = &db->Options; /* point to database options */ GetArgs(argc,argv[1],argv[2],argv[3], table,dict,driver); /* make selection of database type */ strcpy (source.DBDriver, driver); /* for dBASE and Paradox databases, the table structure */ /* or dictionary info is in the same directory as data */ strcpy (source.DBDictPath, DBDictPath); strcpy (source.DBDataPath, DBDictPath); /*****************************/ /* connect to datasource */ /*****************************/ connection = new(dbConnection); connection->hdbc = connection->Connect( source, password ); if ((connection->hdbc == NOHANDLE)) { printf ("\n ERROR %d: Unable to connect to %s", connection->hdbc, source.DBDriver); exit (1); } /*****************************/ /* statement / request */ /*****************************/ strcpy(SQLString,"SELECT * FROM "); strcat(SQLString,source.DBDataPath); /* terminate the SQL string */ SQLString[strlen(SQLString)] = '\x5c'; strcat(SQLString,DBTable); request = new dbRequest(connection->hdbc, db->opt, SQLString); /* define options for this request */ request->OptionInfo.UseDirectExec = TRUE; request->OptionInfo.UseNamedCursor = FALSE; request->OptionInfo.UseTransaction = FALSE; /* build a valid SQL request/statement string */ /* Note: statement length may be an issue in some */ /* SQL libraries */ statement = request->BuildRequest(ExceedsMax); request->hstmt = request->ExecuteStatement(statement); nColumns = request->FindNumberOfColumns(request->hstmt); ColumnPosition = 0; ColumnCount = 0; TotalLength = 0; column = new dbColumn( connection->hdbc, db->opt, request->hstmt, SQLString, ColumnPosition); /************************/ /* get description */ /************************/ printf ("\nStructure for table: %s\n", DBTable); printf ("Field Field Name Type Width Dec\n"); db->StatusReturned = SQL_SUCCESS; do { /* point to column descriptor */ fi = &column->ColumnInfo[ColumnPosition]; db->StatusReturned = SQL_SUCCESS; db->StatusReturned = column->Describe(ColumnPosition+1, fi); if ((db->StatusReturned != SQL_SUCCESS)) { if (db->StatusReturned == ENDFILE) { break; } else { printf ("\n ERROR: getting column data for %s\n", SQLString); exit (1); } }; ColumnCount++; /* update field count */ TotalLength += column->ColumnInfo[ColumnPosition].Length; /* data type is specific to the SQL library */ ColumnDataType = column->DecodeQEDataType(fi->DataType); strcpy(FldName,fi->Name); flen = strlen(fi->Name); for ( i=flen; i < DISPLAYLEN; i++ ); { FldName[i]='\x20'; } FldName[DISPLAYLEN]='\x0'; printf ("\n %3d %20.20s %12.12s %5d %2d", ColumnCount, FldName, ColumnDataType, fi->Length, fi->Scale); ColumnPosition++; } while (ColumnPosition < nColumns); printf ("\nTotal: %d\n",TotalLength); // terminate request db->StatusReturned = request->TerminateStatement(request->hstmt); /************************/ /* disconnect */ /************************/ db->StatusReturned = connection->Disconnect(); if ((db->StatusReturned != SQL_SUCCESS)) { printf ("\n ERROR %d: Disconnecting from %s", db->StatusReturned, source.DBDriver); exit (1); } } /************************************************** * FUNCTION NAME: GetArgs * AUTHOR: Ken North * SYNOPSIS: get table name and dictionary path from command line or user ***************************************************/ void GetArgs(int argc, char *arg1, char *arg2, char *arg3, char *table, char *dict, char *driver) { static char name [80]; if (argc > 1) { memset(name,'\x0',sizeof(name)); if (*arg1 == '?') { printf("\n Usage: SQLSTRUC table \ dictionarypath\n"); printf ("\n SQLSTRUC SQL \ data definitions\n"); printf(" (Requires QELIB DLL\ or QExxx.DLL)\n\n"); printf (" To display a data dictionary screen, \ type:\n"); printf (" SQLSTRUC table dictpath driver| \ MORE\n\n"); printf (" To list to a file, type:\n"); printf (" SQLSTRUC table dictpath driver> \ listfile\n\n\n"); exit(1); } strcpy (name, arg1); strupr (name); /* translate to upper case */ strcpy(table,name) ; /* copy name to table */ memset(name,'\x0',sizeof(name)); } if (argc > 2) { strcpy (name, arg2); strupr (name); /* translate to upper case */ strcpy(dict,name) ; memset(name,'\x0',sizeof(name)); } if (argc > 3) { strcpy (name, arg3); strupr (name); /* translate to upper case */ strcpy(driver,name) ; } if (argc < 2) { printf ("Table name ? "); gets (name); strupr (name); /* translate to upper case */ strcpy(table,name) ; memset(name,'\x0',sizeof(name)); /* zero name */ printf ("Dictionary pathname ? "); gets (name); strupr (name); strcpy(dict,name) ; memset(name,'\x0',sizeof(name)); /* zero name */ printf ("Database driver ? "); gets (name); strupr (name); strcpy(driver,name) ; } }