Added support for dBase, PostGres, MySQL, Access, MS SQL Server.
Added QUERY_ONLY data connection types. SQL logging code addded. Cleaned up handling compilation under both 1.6x and 2.x. Added debug code to warn when connections were not released on program termination. MS-VC6 corrections due to larger memory buffers required. Parameter added to not require CreateView() and CreateTable() to drop the view or table first. DropView() function added. Database UserIDs can now be passed to functions that need them. SQLUnbind() called where needed now to prevent resource leaks. TableExists() function now handles dBase files. Dbms() function added to determine which database the program is currently running against. Comments have been added to the Dbms() function to indicate issues specific to different data sources. Dynamic cursor support added (no longer creates 5-7 cursors for every wxTable instance). wxTable dtor is now virtual. Parameter added to not require CreateIndex() and CreateTable() to drop the view or table first. DropIndex() and DropTable() functions added. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@3868 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
134
include/wx/db.h
134
include/wx/db.h
@@ -5,8 +5,15 @@
|
|||||||
// source such as opening and closing the data source.
|
// source such as opening and closing the data source.
|
||||||
// Author: Doug Card
|
// Author: Doug Card
|
||||||
// Modified by:
|
// Modified by:
|
||||||
// Mods: Dec, 1998: Added support for SQL statement logging and database
|
// Mods: Dec, 1998:
|
||||||
// cataloging
|
// -Added support for SQL statement logging and database cataloging
|
||||||
|
// April, 1999
|
||||||
|
// -Added QUERY_ONLY mode support to reduce default number of cursors
|
||||||
|
// -Added additional SQL logging code
|
||||||
|
// -Added DEBUG-ONLY tracking of Ctable objects to detect orphaned DB connections
|
||||||
|
// -Set ODBC option to only read committed writes to the DB so all
|
||||||
|
// databases operate the same in that respect
|
||||||
|
//
|
||||||
// Created: 9.96
|
// Created: 9.96
|
||||||
// RCS-ID: $Id$
|
// RCS-ID: $Id$
|
||||||
// Copyright: (c) 1996 Remstar International, Inc.
|
// Copyright: (c) 1996 Remstar International, Inc.
|
||||||
@@ -31,39 +38,70 @@
|
|||||||
#ifndef DB_DOT_H
|
#ifndef DB_DOT_H
|
||||||
#define DB_DOT_H
|
#define DB_DOT_H
|
||||||
|
|
||||||
|
// Use this line for wxWindows v1.x
|
||||||
|
//#include "wx_ver.h"
|
||||||
|
// Use this line for wxWindows v2.x
|
||||||
|
#include "wx/version.h"
|
||||||
|
|
||||||
|
#if wxMAJOR_VERSION == 2
|
||||||
#ifdef __GNUG__
|
#ifdef __GNUG__
|
||||||
#pragma interface "db.h"
|
#pragma interface "db.h"
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(__WXMSW__) || defined(WIN32)
|
#if defined(wx_msw) || defined(__WXMSW__) || defined(WIN32)
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef _IODBC_
|
||||||
#ifdef __WXGTK__
|
#if wxMAJOR_VERSION == 2
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "../../src/iodbc/isql.h"
|
#include "../../src/iodbc/isql.h"
|
||||||
#include "../../src/iodbc/isqlext.h"
|
#include "../../src/iodbc/isqlext.h"
|
||||||
|
}
|
||||||
|
#else // version == 1
|
||||||
|
extern "C" {
|
||||||
|
#include "iodbc.h"
|
||||||
|
#include "isqlext.h"
|
||||||
|
}
|
||||||
|
#endif
|
||||||
typedef float SFLOAT;
|
typedef float SFLOAT;
|
||||||
typedef double SDOUBLE;
|
typedef double SDOUBLE;
|
||||||
typedef unsigned int UINT;
|
typedef unsigned int UINT;
|
||||||
#define ULONG UDWORD
|
#define ULONG UDWORD
|
||||||
|
#else // msw
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#define ODBCVER 0x0250
|
#define ODBCVER 0x0250
|
||||||
#include <sql.h>
|
#include <sql.h>
|
||||||
#include <sqlext.h>
|
#include <sqlext.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __UNIX__
|
||||||
|
# ifndef strnicmp
|
||||||
|
# define strnicmp strncasecmp
|
||||||
|
# endif
|
||||||
|
# ifndef stricmp
|
||||||
|
# define stricmp strcasecmp
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# include <io.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
enum enumDummy {enumDum1};
|
enum enumDummy {enumDum1};
|
||||||
|
|
||||||
#define SQL_C_BOOLEAN (sizeof(int) == 2 ? SQL_C_USHORT : SQL_C_ULONG)
|
#define SQL_C_BOOLEAN(datatype) (sizeof(datatype) == 1 ? SQL_C_UTINYINT : (sizeof(datatype) == 2 ? SQL_C_USHORT : SQL_C_ULONG))
|
||||||
#define SQL_C_ENUM (sizeof(enumDummy) == 2 ? SQL_C_USHORT : SQL_C_ULONG) //glt 2-21-97
|
// #define SQL_C_BOOLEAN (sizeof(Bool) == 2 ? SQL_C_USHORT : SQL_C_ULONG)
|
||||||
|
|
||||||
|
#define SQL_C_ENUM (sizeof(enumDummy) == 2 ? SQL_C_USHORT : SQL_C_ULONG)
|
||||||
|
|
||||||
|
#ifndef TRUE
|
||||||
|
#define TRUE 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef FALSE
|
||||||
|
#define FALSE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const int DB_PATH_MAX = 254;
|
||||||
|
|
||||||
// Database Globals
|
// Database Globals
|
||||||
const int DB_TYPE_NAME_LEN = 40;
|
const int DB_TYPE_NAME_LEN = 40;
|
||||||
@@ -94,13 +132,6 @@ const int DB_DEL_MATCHING = 3;
|
|||||||
const int DB_WHERE_KEYFIELDS = 1;
|
const int DB_WHERE_KEYFIELDS = 1;
|
||||||
const int DB_WHERE_MATCHING = 2;
|
const int DB_WHERE_MATCHING = 2;
|
||||||
|
|
||||||
const int DB_CURSOR0 = 0;
|
|
||||||
const int DB_CURSOR1 = 1;
|
|
||||||
const int DB_CURSOR2 = 2;
|
|
||||||
//const int DB_CURSOR3 = 3;
|
|
||||||
//const int DB_CURSOR4 = 4;
|
|
||||||
//const int DB_CURSOR5 = 5;
|
|
||||||
|
|
||||||
const int DB_GRANT_SELECT = 1;
|
const int DB_GRANT_SELECT = 1;
|
||||||
const int DB_GRANT_INSERT = 2;
|
const int DB_GRANT_INSERT = 2;
|
||||||
const int DB_GRANT_UPDATE = 4;
|
const int DB_GRANT_UPDATE = 4;
|
||||||
@@ -208,8 +239,14 @@ struct DbStuff
|
|||||||
{
|
{
|
||||||
HENV Henv;
|
HENV Henv;
|
||||||
char Dsn[SQL_MAX_DSN_LENGTH+1]; // Data Source Name
|
char Dsn[SQL_MAX_DSN_LENGTH+1]; // Data Source Name
|
||||||
char Uid[20]; // User ID
|
char Uid[20+1]; // User ID
|
||||||
char AuthStr[20]; // Authorization string (password)
|
char AuthStr[20+1]; // Authorization string (password)
|
||||||
|
|
||||||
|
char description[SQL_MAX_DSN_LENGTH+1]; // Not sure what the max length is
|
||||||
|
char fileType[SQL_MAX_DSN_LENGTH+1]; // Not sure what the max length is
|
||||||
|
|
||||||
|
// Optionals needed for some databases like dBase
|
||||||
|
char defaultDir[DB_PATH_MAX]; // Directory that db file resides in
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
@@ -236,6 +273,30 @@ enum sqlLog
|
|||||||
sqlLogON
|
sqlLogON
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum dbms
|
||||||
|
{
|
||||||
|
dbmsUNIDENTIFIED,
|
||||||
|
dbmsORACLE,
|
||||||
|
dbmsSYBASE_ASA, // Adaptive Server Anywhere
|
||||||
|
dbmsSYBASE_ASE, // Adaptive Server Enterprise
|
||||||
|
dbmsMS_SQL_SERVER,
|
||||||
|
dbmsMY_SQL,
|
||||||
|
dbmsPOSTGRES,
|
||||||
|
dbmsACCESS,
|
||||||
|
dbmsDBASE
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef enum dbms DBMS;
|
||||||
|
|
||||||
|
// The wxDB::errorList is copied to this variable when the wxDB object
|
||||||
|
// is closed. This way, the error list is still available after the
|
||||||
|
// database object is closed. This is necessary if the database
|
||||||
|
// connection fails so the calling application can show the operator
|
||||||
|
// why the connection failed. Note: as each wxDB object is closed, it
|
||||||
|
// will overwrite the errors of the previously destroyed wxDB object in
|
||||||
|
// this variable.
|
||||||
|
extern char DBerrorList[DB_MAX_ERROR_HISTORY][DB_MAX_ERROR_MSG_LEN];
|
||||||
|
|
||||||
class WXDLLEXPORT wxDB
|
class WXDLLEXPORT wxDB
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
@@ -261,7 +322,7 @@ public:
|
|||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
char dbmsName[40]; // Name of the dbms product
|
char dbmsName[40]; // Name of the dbms product
|
||||||
char dbmsVer[40]; // Version # of the dbms product
|
char dbmsVer[64]; // Version # of the dbms product
|
||||||
char driverName[40]; // Driver name
|
char driverName[40]; // Driver name
|
||||||
char odbcVer[60]; // ODBC version of the driver
|
char odbcVer[60]; // ODBC version of the driver
|
||||||
char drvMgrOdbcVer[60]; // ODBC version of the driver manager
|
char drvMgrOdbcVer[60]; // ODBC version of the driver manager
|
||||||
@@ -308,6 +369,9 @@ public:
|
|||||||
//Error reporting mode
|
//Error reporting mode
|
||||||
bool silent;
|
bool silent;
|
||||||
|
|
||||||
|
// Number of Ctable objects connected to this db object
|
||||||
|
unsigned int nTables;
|
||||||
|
|
||||||
// Inf. about logical data types VARCHAR, INTEGER, FLOAT and DATE.
|
// Inf. about logical data types VARCHAR, INTEGER, FLOAT and DATE.
|
||||||
// This inf. is obtained from the ODBC driver by use of the
|
// This inf. is obtained from the ODBC driver by use of the
|
||||||
// SQLGetTypeInfo() function. The key piece of inf. is the
|
// SQLGetTypeInfo() function. The key piece of inf. is the
|
||||||
@@ -324,12 +388,15 @@ public:
|
|||||||
bool DispAllErrors(HENV aHenv, HDBC aHdbc = SQL_NULL_HDBC, HSTMT aHstmt = SQL_NULL_HSTMT);
|
bool DispAllErrors(HENV aHenv, HDBC aHdbc = SQL_NULL_HDBC, HSTMT aHstmt = SQL_NULL_HSTMT);
|
||||||
bool GetNextError(HENV aHenv, HDBC aHdbc = SQL_NULL_HDBC, HSTMT aHstmt = SQL_NULL_HSTMT);
|
bool GetNextError(HENV aHenv, HDBC aHdbc = SQL_NULL_HDBC, HSTMT aHstmt = SQL_NULL_HSTMT);
|
||||||
void DispNextError(void);
|
void DispNextError(void);
|
||||||
bool CreateView(char *viewName, char *colList, char *pSqlStmt);
|
bool CreateView(char *viewName, char *colList, char *pSqlStmt, bool attemptDrop=TRUE);
|
||||||
|
bool DropView(char *viewName);
|
||||||
bool ExecSql(char *pSqlStmt);
|
bool ExecSql(char *pSqlStmt);
|
||||||
|
bool GetNext(void);
|
||||||
|
bool GetData(UWORD colNo, SWORD cType, PTR pData, SDWORD maxLen, SDWORD FAR *cbReturned);
|
||||||
bool Grant(int privileges, char *tableName, char *userList = "PUBLIC");
|
bool Grant(int privileges, char *tableName, char *userList = "PUBLIC");
|
||||||
int TranslateSqlState(char *SQLState);
|
int TranslateSqlState(char *SQLState);
|
||||||
bool Catalog(char *userID, char *fileName = "Catalog.txt");
|
bool Catalog(char *userID, char *fileName = "Catalog.txt");
|
||||||
CcolInf *GetColumns(char *tableName[]);
|
CcolInf *GetColumns(char *tableName[], char *userID=NULL);
|
||||||
char *GetDatabaseName(void) {return dbInf.dbmsName;}
|
char *GetDatabaseName(void) {return dbInf.dbmsName;}
|
||||||
char *GetDataSource(void) {return dsn;}
|
char *GetDataSource(void) {return dsn;}
|
||||||
char *GetUsername(void) {return uid;}
|
char *GetUsername(void) {return uid;}
|
||||||
@@ -338,10 +405,11 @@ public:
|
|||||||
HENV GetHENV(void) {return henv;}
|
HENV GetHENV(void) {return henv;}
|
||||||
HDBC GetHDBC(void) {return hdbc;}
|
HDBC GetHDBC(void) {return hdbc;}
|
||||||
HSTMT GetHSTMT(void) {return hstmt;}
|
HSTMT GetHSTMT(void) {return hstmt;}
|
||||||
bool TableExists(char *tableName); // Table name can refer to a table, view, alias or synonym
|
bool TableExists(char *tableName, char *userID=NULL, char *path=NULL); // Table name can refer to a table, view, alias or synonym
|
||||||
void LogError(char *errMsg, char *SQLState = 0) {logError(errMsg, SQLState);}
|
void LogError(char *errMsg, char *SQLState = 0) {logError(errMsg, SQLState);}
|
||||||
bool SqlLog(enum sqlLog state, char *filename = "sqllog.txt", bool append = FALSE);
|
bool SqlLog(enum sqlLog state, char *filename = "sqllog.txt", bool append = FALSE);
|
||||||
bool WriteSqlLog(char *logMsg);
|
bool WriteSqlLog(char *logMsg);
|
||||||
|
DBMS Dbms(void);
|
||||||
|
|
||||||
}; // wxDB
|
}; // wxDB
|
||||||
|
|
||||||
@@ -359,6 +427,17 @@ struct DbList
|
|||||||
DbList *PtrNext; // Pointer to next item in the list
|
DbList *PtrNext; // Pointer to next item in the list
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#if __WXDEBUG__ > 0
|
||||||
|
class CstructTablesInUse : public wxObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
const char *tableName;
|
||||||
|
ULONG tableID;
|
||||||
|
class wxDB *pDb;
|
||||||
|
}; // CstructTablesInUse
|
||||||
|
#endif
|
||||||
|
|
||||||
// The following routines allow a user to get new database connections, free them
|
// The following routines allow a user to get new database connections, free them
|
||||||
// for other code segments to use, or close all of them when the application has
|
// for other code segments to use, or close all of them when the application has
|
||||||
// completed.
|
// completed.
|
||||||
@@ -368,6 +447,9 @@ bool WXDLLEXPORT FreeDbConnection(wxDB *pDb);
|
|||||||
void WXDLLEXPORT CloseDbConnections(void);
|
void WXDLLEXPORT CloseDbConnections(void);
|
||||||
int WXDLLEXPORT NumberDbConnectionsInUse(void);
|
int WXDLLEXPORT NumberDbConnectionsInUse(void);
|
||||||
|
|
||||||
|
// This function sets the sql log state for all open wxDB objects
|
||||||
|
bool SqlLog(enum sqlLog state, char *filename = "sqllog.txt");
|
||||||
|
|
||||||
// This routine allows you to query a driver manager
|
// This routine allows you to query a driver manager
|
||||||
// for a list of available datasources. Call this routine
|
// for a list of available datasources. Call this routine
|
||||||
// the first time using SQL_FETCH_FIRST. Continue to call it
|
// the first time using SQL_FETCH_FIRST. Continue to call it
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// Name: table.h
|
// Name: dbtable.h
|
||||||
// Purpose: Declaration of the wxTable class.
|
// Purpose: Declaration of the wxTable class.
|
||||||
// Author: Doug Card
|
// Author: Doug Card
|
||||||
// Modified by:
|
// Modified by:
|
||||||
@@ -23,16 +23,30 @@
|
|||||||
// SYNOPSIS STOP
|
// SYNOPSIS STOP
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef TABLE_DOT_H
|
#ifndef DBTABLE_DOT_H
|
||||||
#define TABLE_DOT_H
|
#define DBTABLE_DOT_H
|
||||||
|
|
||||||
|
// Use this line for wxWindows v1.x
|
||||||
|
//#include "wx_ver.h"
|
||||||
|
// Use this line for wxWindows v2.x
|
||||||
|
#include "wx/version.h"
|
||||||
|
|
||||||
|
#if wxMAJOR_VERSION == 2
|
||||||
#ifdef __GNUG__
|
#ifdef __GNUG__
|
||||||
#pragma interface "dbtable.h"
|
#pragma interface "dbtable.h"
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if wxMAJOR_VERSION == 2
|
||||||
#include "wx/db.h"
|
#include "wx/db.h"
|
||||||
|
#else
|
||||||
|
#include "db.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
const int ROWID_LEN = 24; // 18 is the max, 24 is in case it gets larger
|
const int ROWID_LEN = 24; // 18 is the max, 24 is in case it gets larger
|
||||||
|
const int DEFAULT_CURSOR = 0;
|
||||||
|
const bool QUERY_ONLY = TRUE;
|
||||||
|
const bool DISABLE_VIEW = TRUE;
|
||||||
|
|
||||||
// The following class is used to define a column of a table.
|
// The following class is used to define a column of a table.
|
||||||
// The wxTable constructor will dynamically allocate as many of
|
// The wxTable constructor will dynamically allocate as many of
|
||||||
@@ -46,7 +60,7 @@ const int ROWID_LEN = 24; // 18 is the max, 24 is in case it gets larger
|
|||||||
class WXDLLEXPORT CcolDef
|
class WXDLLEXPORT CcolDef
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
char ColName[DB_MAX_COLUMN_NAME_LEN+1]; // Column Name glt 4/19/97 added one for the null terminator
|
char ColName[DB_MAX_COLUMN_NAME_LEN+1]; // Column Name
|
||||||
int DbDataType; // Logical Data Type; e.g. DB_DATA_TYPE_INTEGER
|
int DbDataType; // Logical Data Type; e.g. DB_DATA_TYPE_INTEGER
|
||||||
int SqlCtype; // C data type; e.g. SQL_C_LONG
|
int SqlCtype; // C data type; e.g. SQL_C_LONG
|
||||||
void *PtrDataObj; // Address of the data object
|
void *PtrDataObj; // Address of the data object
|
||||||
@@ -56,13 +70,14 @@ public:
|
|||||||
bool InsertAllowed; // Specifies whether this column should be included in an INSERT statement
|
bool InsertAllowed; // Specifies whether this column should be included in an INSERT statement
|
||||||
bool DerivedCol; // Specifies whether this column is a derived value
|
bool DerivedCol; // Specifies whether this column is a derived value
|
||||||
SDWORD CbValue; // Internal use only!!!
|
SDWORD CbValue; // Internal use only!!!
|
||||||
|
bool Null; // NOT FULLY IMPLEMENTED - Allows NULL values in Inserts and Updates
|
||||||
}; // CcolDef
|
}; // CcolDef
|
||||||
|
|
||||||
// This structure is used when creating secondary indexes.
|
// This structure is used when creating secondary indexes.
|
||||||
class WXDLLEXPORT CidxDef
|
class WXDLLEXPORT CidxDef
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
char ColName[DB_MAX_COLUMN_NAME_LEN+1]; // Column Name glt 4/19/97 added one for the null terminator
|
char ColName[DB_MAX_COLUMN_NAME_LEN+1];
|
||||||
bool Ascending;
|
bool Ascending;
|
||||||
}; // CidxDef
|
}; // CidxDef
|
||||||
|
|
||||||
@@ -70,8 +85,10 @@ class WXDLLEXPORT wxTable
|
|||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
ULONG tableID; // Used for debugging. This can help to match up mismatched constructors/destructors
|
||||||
|
|
||||||
// Private member variables
|
// Private member variables
|
||||||
int currCursorNo;
|
UDWORD cursorType;
|
||||||
|
|
||||||
// Private member functions
|
// Private member functions
|
||||||
bool bindInsertParams(void);
|
bool bindInsertParams(void);
|
||||||
@@ -91,17 +108,20 @@ public:
|
|||||||
HENV henv; // ODBC Environment handle
|
HENV henv; // ODBC Environment handle
|
||||||
HDBC hdbc; // ODBC DB Connection handle
|
HDBC hdbc; // ODBC DB Connection handle
|
||||||
HSTMT hstmt; // ODBC Statement handle
|
HSTMT hstmt; // ODBC Statement handle
|
||||||
// HSTMT c0, c1, c2, c3, c4, c5; // Cursors 0 through 5
|
HSTMT *hstmtDefault; // Default cursor
|
||||||
HSTMT c0, c1, c2; // Limited to Cursors 0 through 2 for now
|
|
||||||
HSTMT hstmtInsert; // ODBC Statement handle used specifically for inserts
|
HSTMT hstmtInsert; // ODBC Statement handle used specifically for inserts
|
||||||
HSTMT hstmtDelete; // ODBC Statement handle used specifically for deletes
|
HSTMT hstmtDelete; // ODBC Statement handle used specifically for deletes
|
||||||
HSTMT hstmtUpdate; // ODBC Statement handle used specifically for updates
|
HSTMT hstmtUpdate; // ODBC Statement handle used specifically for updates
|
||||||
HSTMT hstmtCount; // ODBC Statement handle used specifically for COUNT(*)
|
HSTMT hstmtInternal; // ODBC Statement handle used internally only
|
||||||
|
HSTMT *hstmtCount; // ODBC Statement handle used by Count() function (No binding of columns)
|
||||||
|
|
||||||
// Table Inf.
|
// Table Inf.
|
||||||
char tableName[DB_MAX_TABLE_NAME_LEN+1]; // Table name
|
char tableName[DB_MAX_TABLE_NAME_LEN+1]; // Table name
|
||||||
char queryTableName[DB_MAX_TABLE_NAME_LEN+1]; // Query Table Name
|
char queryTableName[DB_MAX_TABLE_NAME_LEN+1]; // Query Table Name
|
||||||
int noCols; // # of columns in the table
|
int noCols; // # of columns in the table
|
||||||
|
bool queryOnly; // Query Only, no inserts, updates or deletes
|
||||||
|
|
||||||
|
char tablePath[DB_PATH_MAX]; // needed for dBase tables
|
||||||
|
|
||||||
// Column Definitions
|
// Column Definitions
|
||||||
CcolDef *colDefs; // Array of CcolDef structures
|
CcolDef *colDefs; // Array of CcolDef structures
|
||||||
@@ -109,17 +129,20 @@ public:
|
|||||||
// Where, Order By and From clauses
|
// Where, Order By and From clauses
|
||||||
char *where; // Standard SQL where clause, minus the word WHERE
|
char *where; // Standard SQL where clause, minus the word WHERE
|
||||||
char *orderBy; // Standard SQL order by clause, minus the ORDER BY
|
char *orderBy; // Standard SQL order by clause, minus the ORDER BY
|
||||||
char *from; // Allows for joins in a Ctable::Query(). Format: ",tbl,tbl..."
|
char *from; // Allows for joins in a wxTable::Query(). Format: ",tbl,tbl..."
|
||||||
|
|
||||||
// Flags
|
// Flags
|
||||||
bool selectForUpdate;
|
bool selectForUpdate;
|
||||||
|
|
||||||
// Public member functions
|
// Public member functions
|
||||||
wxTable(wxDB *pwxDB, const char *tblName, const int nCols, const char *qryTblName = 0);
|
wxTable(wxDB *pwxDB, const char *tblName, const int nCols,
|
||||||
|
const char *qryTblName = 0, bool qryOnly = !QUERY_ONLY, char *tblPath=NULL);
|
||||||
virtual ~wxTable();
|
virtual ~wxTable();
|
||||||
bool Open(void);
|
bool Open(void);
|
||||||
bool CreateTable(void);
|
bool CreateTable(bool attemptDrop=TRUE);
|
||||||
bool CreateIndex(char * idxName, bool unique, int noIdxCols, CidxDef *pIdxDefs);
|
bool DropTable(void);
|
||||||
|
bool CreateIndex(char * idxName, bool unique, int noIdxCols, CidxDef *pIdxDefs, bool attemptDrop=TRUE);
|
||||||
|
bool DropIndex(char * idxName);
|
||||||
bool CloseCursor(HSTMT cursor);
|
bool CloseCursor(HSTMT cursor);
|
||||||
int Insert(void);
|
int Insert(void);
|
||||||
bool Update(void);
|
bool Update(void);
|
||||||
@@ -154,11 +177,19 @@ public:
|
|||||||
void SetColDefs (int index, char *fieldName, int dataType, void *pData, int cType,
|
void SetColDefs (int index, char *fieldName, int dataType, void *pData, int cType,
|
||||||
int size, bool keyField = FALSE, bool upd = TRUE,
|
int size, bool keyField = FALSE, bool upd = TRUE,
|
||||||
bool insAllow = TRUE, bool derivedCol = FALSE);
|
bool insAllow = TRUE, bool derivedCol = FALSE);
|
||||||
bool SetCursor(int cursorNo = DB_CURSOR0);
|
HSTMT *NewCursor(bool setCursor = FALSE, bool bindColumns = TRUE);
|
||||||
int GetCursor(void) { return(currCursorNo); }
|
bool DeleteCursor(HSTMT *hstmtDel);
|
||||||
|
void SetCursor(HSTMT *hstmtActivate = (void **) DEFAULT_CURSOR);
|
||||||
|
HSTMT GetCursor(void) { return(hstmt); }
|
||||||
ULONG Count(void);
|
ULONG Count(void);
|
||||||
int DB_STATUS(void) { return(pDb->DB_STATUS); }
|
int DB_STATUS(void) { return(pDb->DB_STATUS); }
|
||||||
bool Refresh(void);
|
bool Refresh(void);
|
||||||
|
bool SetNull(int colNo);
|
||||||
|
bool SetNull(char *colName);
|
||||||
|
|
||||||
|
#if __WXDEBUG__ > 0
|
||||||
|
ULONG GetTableID() { return tableID; };
|
||||||
|
#endif
|
||||||
|
|
||||||
}; // wxTable
|
}; // wxTable
|
||||||
|
|
||||||
|
@@ -5,8 +5,14 @@
|
|||||||
// source such as opening and closing the data source.
|
// source such as opening and closing the data source.
|
||||||
// Author: Doug Card
|
// Author: Doug Card
|
||||||
// Modified by:
|
// Modified by:
|
||||||
// Mods: Dec, 1998: Added support for SQL statement logging and database
|
// Mods: Dec, 1998:
|
||||||
// cataloging
|
// -Added support for SQL statement logging and database cataloging
|
||||||
|
// Mods: April, 1999
|
||||||
|
// -Added QUERY_ONLY mode support to reduce default number of cursors
|
||||||
|
// -Added additional SQL logging code
|
||||||
|
// -Added DEBUG-ONLY tracking of wxTable objects to detect orphaned DB connections
|
||||||
|
// -Set ODBC option to only read committed writes to the DB so all
|
||||||
|
// databases operate the same in that respect
|
||||||
// Created: 9.96
|
// Created: 9.96
|
||||||
// RCS-ID: $Id$
|
// RCS-ID: $Id$
|
||||||
// Copyright: (c) 1996 Remstar International, Inc.
|
// Copyright: (c) 1996 Remstar International, Inc.
|
||||||
@@ -22,30 +28,47 @@
|
|||||||
// the wxWindows GUI development toolkit.
|
// the wxWindows GUI development toolkit.
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#ifdef __GNUG__
|
|
||||||
#pragma implementation "db.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// SYNOPSIS START
|
// SYNOPSIS START
|
||||||
// SYNOPSIS STOP
|
// SYNOPSIS STOP
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
// Use this line for wxWindows v1.x
|
||||||
|
//#include "wx_ver.h"
|
||||||
|
// Use this line for wxWindows v2.x
|
||||||
|
#include "wx/version.h"
|
||||||
|
#include "wx/wxprec.h"
|
||||||
|
|
||||||
|
#if wxMAJOR_VERSION == 2
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma implementation "db.h"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef DBDEBUG_CONSOLE
|
#ifdef DBDEBUG_CONSOLE
|
||||||
#include <iostream.h>
|
#include <iostream.h>
|
||||||
#endif
|
#endif
|
||||||
*/
|
|
||||||
|
|
||||||
#include "wx/wxprec.h"
|
|
||||||
|
|
||||||
#ifdef __BORLANDC__
|
#ifdef __BORLANDC__
|
||||||
#pragma hdrstop
|
#pragma hdrstop
|
||||||
#endif //__BORLANDC__
|
#endif //__BORLANDC__
|
||||||
|
|
||||||
|
#if wxMAJOR_VERSION == 2
|
||||||
#ifndef WX_PRECOMP
|
#ifndef WX_PRECOMP
|
||||||
#include "wx/string.h"
|
#include "wx/string.h"
|
||||||
#endif //WX_PRECOMP
|
#endif //WX_PRECOMP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if wxMAJOR_VERSION == 1
|
||||||
|
# if defined(wx_msw) || defined(wx_x)
|
||||||
|
# ifdef WX_PRECOMP
|
||||||
|
# include "wx_prec.h"
|
||||||
|
# else
|
||||||
|
# include "wx.h"
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
# define wxUSE_ODBC 1
|
||||||
|
#endif
|
||||||
|
|
||||||
#if wxUSE_ODBC
|
#if wxUSE_ODBC
|
||||||
|
|
||||||
@@ -54,10 +77,32 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#if wxMAJOR_VERSION == 1
|
||||||
|
#include "db.h"
|
||||||
|
#elif wxMAJOR_VERSION == 2
|
||||||
#include "wx/db.h"
|
#include "wx/db.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
DbList* WXDLLEXPORT PtrBegDbList = 0;
|
DbList* WXDLLEXPORT PtrBegDbList = 0;
|
||||||
|
|
||||||
|
#if __WXDEBUG__ > 0
|
||||||
|
extern wxList TablesInUse;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// SQL Log defaults to be used by GetDbConnection
|
||||||
|
enum sqlLog SQLLOGstate = sqlLogOFF;
|
||||||
|
|
||||||
|
char SQLLOGfn[DB_PATH_MAX+1] = "sqllog.txt";
|
||||||
|
|
||||||
|
// The wxDB::errorList is copied to this variable when the wxDB object
|
||||||
|
// is closed. This way, the error list is still available after the
|
||||||
|
// database object is closed. This is necessary if the database
|
||||||
|
// connection fails so the calling application can show the operator
|
||||||
|
// why the connection failed. Note: as each wxDB object is closed, it
|
||||||
|
// will overwrite the errors of the previously destroyed wxDB object in
|
||||||
|
// this variable.
|
||||||
|
char DBerrorList[DB_MAX_ERROR_HISTORY][DB_MAX_ERROR_MSG_LEN];
|
||||||
|
|
||||||
/********** wxDB Constructor **********/
|
/********** wxDB Constructor **********/
|
||||||
wxDB::wxDB(HENV &aHenv)
|
wxDB::wxDB(HENV &aHenv)
|
||||||
{
|
{
|
||||||
@@ -65,6 +110,7 @@ wxDB::wxDB(HENV &aHenv)
|
|||||||
|
|
||||||
fpSqlLog = 0; // Sql Log file pointer
|
fpSqlLog = 0; // Sql Log file pointer
|
||||||
sqlLogState = sqlLogOFF; // By default, logging is turned off
|
sqlLogState = sqlLogOFF; // By default, logging is turned off
|
||||||
|
nTables = 0;
|
||||||
|
|
||||||
strcpy(sqlState,"");
|
strcpy(sqlState,"");
|
||||||
strcpy(errorMsg,"");
|
strcpy(errorMsg,"");
|
||||||
@@ -123,10 +169,10 @@ bool wxDB::Open(char *Dsn, char *Uid, char *AuthStr)
|
|||||||
uid = Uid;
|
uid = Uid;
|
||||||
authStr = AuthStr;
|
authStr = AuthStr;
|
||||||
|
|
||||||
#ifndef FWD_ONLY_CURSORS
|
|
||||||
|
|
||||||
RETCODE retcode;
|
RETCODE retcode;
|
||||||
|
|
||||||
|
#ifndef FWD_ONLY_CURSORS
|
||||||
|
|
||||||
// Specify that the ODBC cursor library be used, if needed. This must be
|
// Specify that the ODBC cursor library be used, if needed. This must be
|
||||||
// specified before the connection is made.
|
// specified before the connection is made.
|
||||||
retcode = SQLSetConnectOption(hdbc, SQL_ODBC_CURSORS, SQL_CUR_USE_IF_NEEDED);
|
retcode = SQLSetConnectOption(hdbc, SQL_ODBC_CURSORS, SQL_CUR_USE_IF_NEEDED);
|
||||||
@@ -141,11 +187,21 @@ bool wxDB::Open(char *Dsn, char *Uid, char *AuthStr)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Connect to the data source
|
// Connect to the data source
|
||||||
if (SQLConnect(hdbc, (UCHAR FAR *) Dsn, SQL_NTS,
|
retcode = SQLConnect(hdbc, (UCHAR FAR *) Dsn, SQL_NTS,
|
||||||
(UCHAR FAR *) Uid, SQL_NTS,
|
(UCHAR FAR *) Uid, SQL_NTS,
|
||||||
(UCHAR FAR *) AuthStr, SQL_NTS) != SQL_SUCCESS)
|
(UCHAR FAR *) AuthStr,SQL_NTS);
|
||||||
|
if (retcode == SQL_SUCCESS_WITH_INFO)
|
||||||
|
DispAllErrors(henv, hdbc);
|
||||||
|
else if (retcode != SQL_SUCCESS)
|
||||||
return(DispAllErrors(henv, hdbc));
|
return(DispAllErrors(henv, hdbc));
|
||||||
|
|
||||||
|
/*
|
||||||
|
If using Intersolv branded ODBC drivers, this is the place where you would substitute
|
||||||
|
your branded driver license information
|
||||||
|
|
||||||
|
SQLSetConnectOption(hdbc, 1041, (UDWORD) "");
|
||||||
|
SQLSetConnectOption(hdbc, 1042, (UDWORD) "");
|
||||||
|
*/
|
||||||
// Mark database as open
|
// Mark database as open
|
||||||
dbIsOpen = TRUE;
|
dbIsOpen = TRUE;
|
||||||
|
|
||||||
@@ -193,7 +249,7 @@ bool wxDB::Open(char *Dsn, char *Uid, char *AuthStr)
|
|||||||
// =====================================================================
|
// =====================================================================
|
||||||
// Results from a Microsoft Access 7.0 db, using a driver from Microsoft
|
// Results from a Microsoft Access 7.0 db, using a driver from Microsoft
|
||||||
//
|
//
|
||||||
// SQL_VARCHAR type name = 'TEXT(', Precision = 255
|
// SQL_VARCHAR type name = 'TEXT', Precision = 255
|
||||||
// SQL_TIMESTAMP type name = 'DATETIME'
|
// SQL_TIMESTAMP type name = 'DATETIME'
|
||||||
// SQL_DECIMAL SQL_NO_DATA_FOUND
|
// SQL_DECIMAL SQL_NO_DATA_FOUND
|
||||||
// SQL_NUMERIC type name = 'CURRENCY', Precision = 19
|
// SQL_NUMERIC type name = 'CURRENCY', Precision = 19
|
||||||
@@ -241,10 +297,20 @@ bool wxDB::Open(char *Dsn, char *Uid, char *AuthStr)
|
|||||||
typeInfInteger.FsqlType = SQL_INTEGER;
|
typeInfInteger.FsqlType = SQL_INTEGER;
|
||||||
|
|
||||||
// Date/Time
|
// Date/Time
|
||||||
|
if (Dbms() != dbmsDBASE)
|
||||||
|
{
|
||||||
if (! getDataTypeInfo(SQL_TIMESTAMP, typeInfDate))
|
if (! getDataTypeInfo(SQL_TIMESTAMP, typeInfDate))
|
||||||
return(FALSE);
|
return(FALSE);
|
||||||
else
|
else
|
||||||
typeInfDate.FsqlType = SQL_TIMESTAMP;
|
typeInfDate.FsqlType = SQL_TIMESTAMP;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (! getDataTypeInfo(SQL_DATE, typeInfDate))
|
||||||
|
return(FALSE);
|
||||||
|
else
|
||||||
|
typeInfDate.FsqlType = SQL_DATE;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DBDEBUG_CONSOLE
|
#ifdef DBDEBUG_CONSOLE
|
||||||
cout << "VARCHAR DATA TYPE: " << typeInfVarchar.TypeName << endl;
|
cout << "VARCHAR DATA TYPE: " << typeInfVarchar.TypeName << endl;
|
||||||
@@ -309,8 +375,9 @@ bool wxDB::setConnectionOptions(void)
|
|||||||
bool wxDB::getDbInfo(void)
|
bool wxDB::getDbInfo(void)
|
||||||
{
|
{
|
||||||
SWORD cb;
|
SWORD cb;
|
||||||
|
RETCODE retcode;
|
||||||
|
|
||||||
if (SQLGetInfo(hdbc, SQL_SERVER_NAME, (UCHAR*) dbInf.serverName, 40, &cb) != SQL_SUCCESS)
|
if (SQLGetInfo(hdbc, SQL_SERVER_NAME, (UCHAR*) dbInf.serverName, 80, &cb) != SQL_SUCCESS)
|
||||||
return(DispAllErrors(henv, hdbc));
|
return(DispAllErrors(henv, hdbc));
|
||||||
|
|
||||||
if (SQLGetInfo(hdbc, SQL_DATABASE_NAME, (UCHAR*) dbInf.databaseName, 128, &cb) != SQL_SUCCESS)
|
if (SQLGetInfo(hdbc, SQL_DATABASE_NAME, (UCHAR*) dbInf.databaseName, 128, &cb) != SQL_SUCCESS)
|
||||||
@@ -319,7 +386,11 @@ bool wxDB::getDbInfo(void)
|
|||||||
if (SQLGetInfo(hdbc, SQL_DBMS_NAME, (UCHAR*) dbInf.dbmsName, 40, &cb) != SQL_SUCCESS)
|
if (SQLGetInfo(hdbc, SQL_DBMS_NAME, (UCHAR*) dbInf.dbmsName, 40, &cb) != SQL_SUCCESS)
|
||||||
return(DispAllErrors(henv, hdbc));
|
return(DispAllErrors(henv, hdbc));
|
||||||
|
|
||||||
if (SQLGetInfo(hdbc, SQL_DBMS_VER, (UCHAR*) dbInf.dbmsVer, 40, &cb) != SQL_SUCCESS)
|
// 16-Mar-1999
|
||||||
|
// After upgrading to MSVC6, the original 20 char buffer below was insufficient,
|
||||||
|
// causing database connectivity to fail in some cases.
|
||||||
|
retcode = SQLGetInfo(hdbc, SQL_DBMS_VER, (UCHAR*) dbInf.dbmsVer, 64, &cb);
|
||||||
|
if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO )
|
||||||
return(DispAllErrors(henv, hdbc));
|
return(DispAllErrors(henv, hdbc));
|
||||||
|
|
||||||
if (SQLGetInfo(hdbc, SQL_ACTIVE_CONNECTIONS, (UCHAR*) &dbInf.maxConnections, sizeof(dbInf.maxConnections), &cb) != SQL_SUCCESS)
|
if (SQLGetInfo(hdbc, SQL_ACTIVE_CONNECTIONS, (UCHAR*) &dbInf.maxConnections, sizeof(dbInf.maxConnections), &cb) != SQL_SUCCESS)
|
||||||
@@ -334,7 +405,8 @@ bool wxDB::getDbInfo(void)
|
|||||||
if (SQLGetInfo(hdbc, SQL_DRIVER_ODBC_VER, (UCHAR*) dbInf.odbcVer, 60, &cb) == SQL_ERROR)
|
if (SQLGetInfo(hdbc, SQL_DRIVER_ODBC_VER, (UCHAR*) dbInf.odbcVer, 60, &cb) == SQL_ERROR)
|
||||||
return(DispAllErrors(henv, hdbc));
|
return(DispAllErrors(henv, hdbc));
|
||||||
|
|
||||||
if (SQLGetInfo(hdbc, SQL_ODBC_VER, (UCHAR*) dbInf.drvMgrOdbcVer, 60, &cb) == SQL_ERROR)
|
retcode = SQLGetInfo(hdbc, SQL_ODBC_VER, (UCHAR*) dbInf.drvMgrOdbcVer, 60, &cb);
|
||||||
|
if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
|
||||||
return(DispAllErrors(henv, hdbc));
|
return(DispAllErrors(henv, hdbc));
|
||||||
|
|
||||||
if (SQLGetInfo(hdbc, SQL_DRIVER_VER, (UCHAR*) dbInf.driverVer, 60, &cb) == SQL_ERROR)
|
if (SQLGetInfo(hdbc, SQL_DRIVER_VER, (UCHAR*) dbInf.driverVer, 60, &cb) == SQL_ERROR)
|
||||||
@@ -635,8 +707,14 @@ bool wxDB::getDataTypeInfo(SWORD fSqlType, SqlTypeInfo &structSQLTypeInfo)
|
|||||||
return(DispAllErrors(henv, hdbc, hstmt));
|
return(DispAllErrors(henv, hdbc, hstmt));
|
||||||
// if (SQLGetData(hstmt, 14, SQL_C_SHORT, (UCHAR*) &structSQLTypeInfo.MinimumScale, 0, &cbRet) != SQL_SUCCESS)
|
// if (SQLGetData(hstmt, 14, SQL_C_SHORT, (UCHAR*) &structSQLTypeInfo.MinimumScale, 0, &cbRet) != SQL_SUCCESS)
|
||||||
// return(DispAllErrors(henv, hdbc, hstmt));
|
// return(DispAllErrors(henv, hdbc, hstmt));
|
||||||
|
|
||||||
|
//#ifdef __UNIX__ // BJO : IODBC knows about 5, not 15...
|
||||||
|
// if (SQLGetData(hstmt, 5, SQL_C_SHORT,(UCHAR*) &structSQLTypeInfo.MaximumScale, 0, &cbRet) != SQL_SUCCESS)
|
||||||
|
// return(DispAllErrors(henv, hdbc, hstmt));
|
||||||
|
//#else
|
||||||
if (SQLGetData(hstmt, 15, SQL_C_SHORT,(UCHAR*) &structSQLTypeInfo.MaximumScale, 0, &cbRet) != SQL_SUCCESS)
|
if (SQLGetData(hstmt, 15, SQL_C_SHORT,(UCHAR*) &structSQLTypeInfo.MaximumScale, 0, &cbRet) != SQL_SUCCESS)
|
||||||
return(DispAllErrors(henv, hdbc, hstmt));
|
return(DispAllErrors(henv, hdbc, hstmt));
|
||||||
|
//#endif
|
||||||
|
|
||||||
if (structSQLTypeInfo.MaximumScale < 0)
|
if (structSQLTypeInfo.MaximumScale < 0)
|
||||||
structSQLTypeInfo.MaximumScale = 0;
|
structSQLTypeInfo.MaximumScale = 0;
|
||||||
@@ -657,7 +735,7 @@ void wxDB::Close(void)
|
|||||||
if (fpSqlLog)
|
if (fpSqlLog)
|
||||||
{
|
{
|
||||||
fclose(fpSqlLog);
|
fclose(fpSqlLog);
|
||||||
fpSqlLog = 0; //glt
|
fpSqlLog = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Free statement handle
|
// Free statement handle
|
||||||
@@ -675,14 +753,43 @@ void wxDB::Close(void)
|
|||||||
if (SQLFreeConnect(hdbc) != SQL_SUCCESS)
|
if (SQLFreeConnect(hdbc) != SQL_SUCCESS)
|
||||||
DispAllErrors(henv, hdbc);
|
DispAllErrors(henv, hdbc);
|
||||||
|
|
||||||
|
// There should be zero Ctable objects still connected to this db object
|
||||||
|
assert(nTables == 0);
|
||||||
|
|
||||||
|
#if __WXDEBUG__ > 0
|
||||||
|
CstructTablesInUse *tiu;
|
||||||
|
wxNode *pNode;
|
||||||
|
pNode = TablesInUse.First();
|
||||||
|
char s[80];
|
||||||
|
char s2[80];
|
||||||
|
while (pNode)
|
||||||
|
{
|
||||||
|
tiu = (CstructTablesInUse *)pNode->Data();
|
||||||
|
if (tiu->pDb == this)
|
||||||
|
{
|
||||||
|
sprintf(s, "(%-20s) tableID:[%6lu] pDb:[%lu]", tiu->tableName,tiu->tableID,tiu->pDb);
|
||||||
|
sprintf(s2,"Orphaned found using pDb:[%lu]",this);
|
||||||
|
wxMessageBox (s,s2);
|
||||||
|
}
|
||||||
|
pNode = pNode->Next();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Copy the error messages to a global variable
|
||||||
|
for (int i = 0; i < DB_MAX_ERROR_HISTORY; i++)
|
||||||
|
strcpy(DBerrorList[i],errorList[i]);
|
||||||
|
|
||||||
} // wxDB::Close()
|
} // wxDB::Close()
|
||||||
|
|
||||||
/********** wxDB::CommitTrans() **********/
|
/********** wxDB::CommitTrans() **********/
|
||||||
bool wxDB::CommitTrans(void)
|
bool wxDB::CommitTrans(void)
|
||||||
|
{
|
||||||
|
if (this)
|
||||||
{
|
{
|
||||||
// Commit the transaction
|
// Commit the transaction
|
||||||
if (SQLTransact(henv, hdbc, SQL_COMMIT) != SQL_SUCCESS)
|
if (SQLTransact(henv, hdbc, SQL_COMMIT) != SQL_SUCCESS)
|
||||||
return(DispAllErrors(henv, hdbc));
|
return(DispAllErrors(henv, hdbc));
|
||||||
|
}
|
||||||
|
|
||||||
// Completed successfully
|
// Completed successfully
|
||||||
return(TRUE);
|
return(TRUE);
|
||||||
@@ -719,9 +826,13 @@ bool wxDB::DispAllErrors(HENV aHenv, HDBC aHdbc, HSTMT aHstmt)
|
|||||||
getchar();
|
getchar();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __WXDEBUG__
|
||||||
|
wxMessageBox(odbcErrMsg);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
return(FALSE); // This function alway's returns false.
|
return(FALSE); // This function always returns false.
|
||||||
|
|
||||||
} // wxDB::DispAllErrors()
|
} // wxDB::DispAllErrors()
|
||||||
|
|
||||||
@@ -765,7 +876,8 @@ void wxDB::logError(char *errMsg, char *SQLState)
|
|||||||
|
|
||||||
if (++pLast == DB_MAX_ERROR_HISTORY)
|
if (++pLast == DB_MAX_ERROR_HISTORY)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < DB_MAX_ERROR_HISTORY; i++)
|
int i;
|
||||||
|
for (i = 0; i < DB_MAX_ERROR_HISTORY; i++)
|
||||||
strcpy(errorList[i], errorList[i+1]);
|
strcpy(errorList[i], errorList[i+1]);
|
||||||
pLast--;
|
pLast--;
|
||||||
}
|
}
|
||||||
@@ -776,6 +888,9 @@ void wxDB::logError(char *errMsg, char *SQLState)
|
|||||||
if ((dbStatus = TranslateSqlState(SQLState)) != DB_ERR_FUNCTION_SEQUENCE_ERROR)
|
if ((dbStatus = TranslateSqlState(SQLState)) != DB_ERR_FUNCTION_SEQUENCE_ERROR)
|
||||||
DB_STATUS = dbStatus;
|
DB_STATUS = dbStatus;
|
||||||
|
|
||||||
|
// Add the errmsg to the sql log
|
||||||
|
WriteSqlLog(errMsg);
|
||||||
|
|
||||||
} // wxDB::logError()
|
} // wxDB::logError()
|
||||||
|
|
||||||
/**********wxDB::TranslateSqlState() **********/
|
/**********wxDB::TranslateSqlState() **********/
|
||||||
@@ -979,14 +1094,14 @@ bool wxDB::Grant(int privileges, char *tableName, char *userList)
|
|||||||
int c = 0;
|
int c = 0;
|
||||||
if (privileges & DB_GRANT_SELECT)
|
if (privileges & DB_GRANT_SELECT)
|
||||||
{
|
{
|
||||||
strcat(sqlStmt, "SELECT(");
|
strcat(sqlStmt, "SELECT");
|
||||||
c++;
|
c++;
|
||||||
}
|
}
|
||||||
if (privileges & DB_GRANT_INSERT)
|
if (privileges & DB_GRANT_INSERT)
|
||||||
{
|
{
|
||||||
if (c++)
|
if (c++)
|
||||||
strcat(sqlStmt, ", ");
|
strcat(sqlStmt, ", ");
|
||||||
strcat(sqlStmt, "INSERT(");
|
strcat(sqlStmt, "INSERT");
|
||||||
}
|
}
|
||||||
if (privileges & DB_GRANT_UPDATE)
|
if (privileges & DB_GRANT_UPDATE)
|
||||||
{
|
{
|
||||||
@@ -1018,33 +1133,13 @@ bool wxDB::Grant(int privileges, char *tableName, char *userList)
|
|||||||
} // wxDB::Grant()
|
} // wxDB::Grant()
|
||||||
|
|
||||||
/********** wxDB::CreateView() **********/
|
/********** wxDB::CreateView() **********/
|
||||||
bool wxDB::CreateView(char *viewName, char *colList, char *pSqlStmt)
|
bool wxDB::CreateView(char *viewName, char *colList, char *pSqlStmt, bool attemptDrop)
|
||||||
{
|
{
|
||||||
char sqlStmt[DB_MAX_STATEMENT_LEN];
|
char sqlStmt[DB_MAX_STATEMENT_LEN];
|
||||||
|
|
||||||
// Drop the view first
|
// Drop the view first
|
||||||
sprintf(sqlStmt, "DROP VIEW %s", viewName);
|
if (attemptDrop && !DropView(viewName))
|
||||||
if (SQLExecDirect(hstmt, (UCHAR FAR *) sqlStmt, SQL_NTS) != SQL_SUCCESS)
|
return FALSE;
|
||||||
{
|
|
||||||
// Check for sqlState = S0002, "Table or view not found".
|
|
||||||
// Ignore this error, bomb out on any other error.
|
|
||||||
// SQL Sybase Anwhere v5.5 returns an access violation error here
|
|
||||||
// (sqlstate = 42000) rather than an S0002.
|
|
||||||
GetNextError(henv, hdbc, hstmt);
|
|
||||||
if (strcmp(sqlState, "S0002") && strcmp(sqlState, "42000"))
|
|
||||||
{
|
|
||||||
DispNextError();
|
|
||||||
DispAllErrors(henv, hdbc, hstmt);
|
|
||||||
RollbackTrans();
|
|
||||||
return(FALSE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
WriteSqlLog(sqlStmt);
|
|
||||||
|
|
||||||
#ifdef DBDEBUG_CONSOLE
|
|
||||||
cout << endl << sqlStmt << endl;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Build the create view statement
|
// Build the create view statement
|
||||||
strcpy(sqlStmt, "CREATE VIEW ");
|
strcpy(sqlStmt, "CREATE VIEW ");
|
||||||
@@ -1070,9 +1165,54 @@ bool wxDB::CreateView(char *viewName, char *colList, char *pSqlStmt)
|
|||||||
|
|
||||||
} // wxDB::CreateView()
|
} // wxDB::CreateView()
|
||||||
|
|
||||||
|
/********** wxDB::DropView() **********/
|
||||||
|
bool wxDB::DropView(char *viewName)
|
||||||
|
{
|
||||||
|
// NOTE: This function returns TRUE if the View does not exist, but
|
||||||
|
// only for identified databases. Code will need to be added
|
||||||
|
// below for any other databases when those databases are defined
|
||||||
|
// to handle this situation consistently
|
||||||
|
|
||||||
|
char sqlStmt[DB_MAX_STATEMENT_LEN];
|
||||||
|
|
||||||
|
sprintf(sqlStmt, "DROP VIEW %s", viewName);
|
||||||
|
|
||||||
|
WriteSqlLog(sqlStmt);
|
||||||
|
|
||||||
|
#ifdef DBDEBUG_CONSOLE
|
||||||
|
cout << endl << sqlStmt << endl;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (SQLExecDirect(hstmt, (UCHAR FAR *) sqlStmt, SQL_NTS) != SQL_SUCCESS)
|
||||||
|
{
|
||||||
|
// Check for "Base table not found" error and ignore
|
||||||
|
GetNextError(henv, hdbc, hstmt);
|
||||||
|
if (strcmp(sqlState,"S0002")) // "Base table not found"
|
||||||
|
{
|
||||||
|
// Check for product specific error codes
|
||||||
|
if (!((Dbms() == dbmsSYBASE_ASA && !strcmp(sqlState,"42000")))) // 5.x (and lower?)
|
||||||
|
{
|
||||||
|
DispNextError();
|
||||||
|
DispAllErrors(henv, hdbc, hstmt);
|
||||||
|
RollbackTrans();
|
||||||
|
return(FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Commit the transaction
|
||||||
|
if (! CommitTrans())
|
||||||
|
return(FALSE);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
} // wxDB::DropView()
|
||||||
|
|
||||||
|
|
||||||
/********** wxDB::ExecSql() **********/
|
/********** wxDB::ExecSql() **********/
|
||||||
bool wxDB::ExecSql(char *pSqlStmt)
|
bool wxDB::ExecSql(char *pSqlStmt)
|
||||||
{
|
{
|
||||||
|
SQLFreeStmt(hstmt, SQL_CLOSE);
|
||||||
if (SQLExecDirect(hstmt, (UCHAR FAR *) pSqlStmt, SQL_NTS) == SQL_SUCCESS)
|
if (SQLExecDirect(hstmt, (UCHAR FAR *) pSqlStmt, SQL_NTS) == SQL_SUCCESS)
|
||||||
return(TRUE);
|
return(TRUE);
|
||||||
else
|
else
|
||||||
@@ -1083,6 +1223,35 @@ bool wxDB::ExecSql(char *pSqlStmt)
|
|||||||
|
|
||||||
} // wxDB::ExecSql()
|
} // wxDB::ExecSql()
|
||||||
|
|
||||||
|
/********** wxDB::GetNext() **********/
|
||||||
|
bool wxDB::GetNext(void)
|
||||||
|
{
|
||||||
|
if (SQLFetch(hstmt) == SQL_SUCCESS)
|
||||||
|
return(TRUE);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DispAllErrors(henv, hdbc, hstmt);
|
||||||
|
return(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // wxDB::GetNext()
|
||||||
|
|
||||||
|
/********** wxDB::GetData() **********/
|
||||||
|
bool wxDB::GetData(UWORD colNo, SWORD cType, PTR pData, SDWORD maxLen, SDWORD FAR *cbReturned)
|
||||||
|
{
|
||||||
|
assert(pData);
|
||||||
|
assert(cbReturned);
|
||||||
|
|
||||||
|
if (SQLGetData(hstmt, colNo, cType, pData, maxLen, cbReturned) == SQL_SUCCESS)
|
||||||
|
return(TRUE);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DispAllErrors(henv, hdbc, hstmt);
|
||||||
|
return(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // wxDB::GetData()
|
||||||
|
|
||||||
/********** wxDB::GetColumns() **********/
|
/********** wxDB::GetColumns() **********/
|
||||||
/*
|
/*
|
||||||
* 1) The last array element of the tableName[] argument must be zero (null).
|
* 1) The last array element of the tableName[] argument must be zero (null).
|
||||||
@@ -1092,7 +1261,7 @@ bool wxDB::ExecSql(char *pSqlStmt)
|
|||||||
* CALLING FUNCTION IS RESPONSIBLE FOR DELETING THE MEMORY RETURNED WHEN IT
|
* CALLING FUNCTION IS RESPONSIBLE FOR DELETING THE MEMORY RETURNED WHEN IT
|
||||||
* IS FINISHED WITH IT. i.e.
|
* IS FINISHED WITH IT. i.e.
|
||||||
*
|
*
|
||||||
* CcolInf *colInf = pDb->GetColumns(tableList);
|
* CcolInf *colInf = pDb->GetColumns(tableList, userID);
|
||||||
* if (colInf)
|
* if (colInf)
|
||||||
* {
|
* {
|
||||||
* // Use the column inf
|
* // Use the column inf
|
||||||
@@ -1101,7 +1270,7 @@ bool wxDB::ExecSql(char *pSqlStmt)
|
|||||||
* delete [] colInf;
|
* delete [] colInf;
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
CcolInf *wxDB::GetColumns(char *tableName[])
|
CcolInf *wxDB::GetColumns(char *tableName[], char *userID)
|
||||||
{
|
{
|
||||||
UINT noCols = 0;
|
UINT noCols = 0;
|
||||||
UINT colNo = 0;
|
UINT colNo = 0;
|
||||||
@@ -1111,11 +1280,32 @@ CcolInf *wxDB::GetColumns(char *tableName[])
|
|||||||
char tblName[DB_MAX_TABLE_NAME_LEN+1];
|
char tblName[DB_MAX_TABLE_NAME_LEN+1];
|
||||||
char colName[DB_MAX_COLUMN_NAME_LEN+1];
|
char colName[DB_MAX_COLUMN_NAME_LEN+1];
|
||||||
SWORD sqlDataType;
|
SWORD sqlDataType;
|
||||||
|
char userIdUC[80+1];
|
||||||
|
char tableNameUC[DB_MAX_TABLE_NAME_LEN+1];
|
||||||
|
|
||||||
|
if (!userID || !strlen(userID))
|
||||||
|
userID = uid;
|
||||||
|
|
||||||
|
// dBase does not use user names, and some drivers fail if you try to pass one
|
||||||
|
if (Dbms() == dbmsDBASE)
|
||||||
|
userID = "";
|
||||||
|
|
||||||
|
// Oracle user names may only be in uppercase, so force
|
||||||
|
// the name to uppercase
|
||||||
|
if (Dbms() == dbmsORACLE)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
for (char *p = userID; *p; p++)
|
||||||
|
userIdUC[i++] = toupper(*p);
|
||||||
|
userIdUC[i] = 0;
|
||||||
|
userID = userIdUC;
|
||||||
|
}
|
||||||
|
|
||||||
// Pass 1 - Determine how many columns there are.
|
// Pass 1 - Determine how many columns there are.
|
||||||
// Pass 2 - Allocate the CcolInf array and fill in
|
// Pass 2 - Allocate the CcolInf array and fill in
|
||||||
// the array with the column information.
|
// the array with the column information.
|
||||||
for (int pass = 1; pass <= 2; pass++)
|
int pass;
|
||||||
|
for (pass = 1; pass <= 2; pass++)
|
||||||
{
|
{
|
||||||
if (pass == 2)
|
if (pass == 2)
|
||||||
{
|
{
|
||||||
@@ -1131,19 +1321,50 @@ CcolInf *wxDB::GetColumns(char *tableName[])
|
|||||||
colInf[noCols].sqlDataType = 0;
|
colInf[noCols].sqlDataType = 0;
|
||||||
}
|
}
|
||||||
// Loop through each table name
|
// Loop through each table name
|
||||||
for (int tbl = 0; tableName[tbl]; tbl++)
|
int tbl;
|
||||||
|
for (tbl = 0; tableName[tbl]; tbl++)
|
||||||
{
|
{
|
||||||
|
// Oracle table names are uppercase only, so force
|
||||||
|
// the name to uppercase just in case programmer forgot to do this
|
||||||
|
if (Dbms() == dbmsORACLE)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
for (char *p = tableName[tbl]; *p; p++)
|
||||||
|
tableNameUC[i++] = toupper(*p);
|
||||||
|
tableNameUC[i] = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
sprintf(tableNameUC,tableName[tbl]);
|
||||||
|
|
||||||
SQLFreeStmt(hstmt, SQL_CLOSE);
|
SQLFreeStmt(hstmt, SQL_CLOSE);
|
||||||
|
|
||||||
|
// MySQL and Access cannot accept a user name when looking up column names, so we
|
||||||
|
// use the call below that leaves out the user name
|
||||||
|
if (strcmp(userID,"") &&
|
||||||
|
Dbms() != dbmsMY_SQL &&
|
||||||
|
Dbms() != dbmsACCESS)
|
||||||
|
{
|
||||||
retcode = SQLColumns(hstmt,
|
retcode = SQLColumns(hstmt,
|
||||||
NULL, 0, // All qualifiers
|
NULL, 0, // All qualifiers
|
||||||
NULL, 0, // All owners
|
(UCHAR *) userID, SQL_NTS, // Owner
|
||||||
(UCHAR *) tableName[tbl], SQL_NTS,
|
(UCHAR *) tableNameUC, SQL_NTS,
|
||||||
NULL, 0); // All columns
|
NULL, 0); // All columns
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
retcode = SQLColumns(hstmt,
|
||||||
|
NULL, 0, // All qualifiers
|
||||||
|
NULL, 0, // Owner
|
||||||
|
(UCHAR *) tableNameUC, SQL_NTS,
|
||||||
|
NULL, 0); // All columns
|
||||||
|
}
|
||||||
if (retcode != SQL_SUCCESS)
|
if (retcode != SQL_SUCCESS)
|
||||||
{ // Error occured, abort
|
{ // Error occured, abort
|
||||||
DispAllErrors(henv, hdbc, hstmt);
|
DispAllErrors(henv, hdbc, hstmt);
|
||||||
if (colInf)
|
if (colInf)
|
||||||
delete [] colInf;
|
delete [] colInf;
|
||||||
|
SQLFreeStmt(hstmt, SQL_UNBIND);
|
||||||
|
SQLFreeStmt(hstmt, SQL_CLOSE);
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
SQLBindCol(hstmt, 3, SQL_C_CHAR, (UCHAR*) tblName, DB_MAX_TABLE_NAME_LEN+1, &cb);
|
SQLBindCol(hstmt, 3, SQL_C_CHAR, (UCHAR*) tblName, DB_MAX_TABLE_NAME_LEN+1, &cb);
|
||||||
@@ -1169,11 +1390,14 @@ CcolInf *wxDB::GetColumns(char *tableName[])
|
|||||||
DispAllErrors(henv, hdbc, hstmt);
|
DispAllErrors(henv, hdbc, hstmt);
|
||||||
if (colInf)
|
if (colInf)
|
||||||
delete [] colInf;
|
delete [] colInf;
|
||||||
|
SQLFreeStmt(hstmt, SQL_UNBIND);
|
||||||
|
SQLFreeStmt(hstmt, SQL_CLOSE);
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SQLFreeStmt(hstmt, SQL_UNBIND);
|
||||||
SQLFreeStmt(hstmt, SQL_CLOSE);
|
SQLFreeStmt(hstmt, SQL_CLOSE);
|
||||||
return colInf;
|
return colInf;
|
||||||
|
|
||||||
@@ -1183,7 +1407,6 @@ CcolInf *wxDB::GetColumns(char *tableName[])
|
|||||||
/********** wxDB::Catalog() **********/
|
/********** wxDB::Catalog() **********/
|
||||||
bool wxDB::Catalog(char *userID, char *fileName)
|
bool wxDB::Catalog(char *userID, char *fileName)
|
||||||
{
|
{
|
||||||
assert(userID && strlen(userID));
|
|
||||||
assert(fileName && strlen(fileName));
|
assert(fileName && strlen(fileName));
|
||||||
|
|
||||||
RETCODE retcode;
|
RETCODE retcode;
|
||||||
@@ -1192,7 +1415,7 @@ bool wxDB::Catalog(char *userID, char *fileName)
|
|||||||
char tblNameSave[DB_MAX_TABLE_NAME_LEN+1];
|
char tblNameSave[DB_MAX_TABLE_NAME_LEN+1];
|
||||||
char colName[DB_MAX_COLUMN_NAME_LEN+1];
|
char colName[DB_MAX_COLUMN_NAME_LEN+1];
|
||||||
SWORD sqlDataType;
|
SWORD sqlDataType;
|
||||||
char typeName[16];
|
char typeName[30+1];
|
||||||
SWORD precision, length;
|
SWORD precision, length;
|
||||||
|
|
||||||
FILE *fp = fopen(fileName,"wt");
|
FILE *fp = fopen(fileName,"wt");
|
||||||
@@ -1201,17 +1424,37 @@ bool wxDB::Catalog(char *userID, char *fileName)
|
|||||||
|
|
||||||
SQLFreeStmt(hstmt, SQL_CLOSE);
|
SQLFreeStmt(hstmt, SQL_CLOSE);
|
||||||
|
|
||||||
|
if (!userID || !strlen(userID))
|
||||||
|
userID = uid;
|
||||||
|
|
||||||
|
char userIdUC[80+1];
|
||||||
|
// Oracle user names may only be in uppercase, so force
|
||||||
|
// the name to uppercase
|
||||||
|
if (Dbms() == dbmsORACLE)
|
||||||
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
char userIdUC[81];
|
|
||||||
for (char *p = userID; *p; p++)
|
for (char *p = userID; *p; p++)
|
||||||
userIdUC[i++] = toupper(*p);
|
userIdUC[i++] = toupper(*p);
|
||||||
userIdUC[i] = 0;
|
userIdUC[i] = 0;
|
||||||
|
userID = userIdUC;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(userID,""))
|
||||||
|
{
|
||||||
retcode = SQLColumns(hstmt,
|
retcode = SQLColumns(hstmt,
|
||||||
NULL, 0, // All qualifiers
|
NULL, 0, // All qualifiers
|
||||||
(UCHAR *) userIdUC, SQL_NTS, // User specified
|
(UCHAR *) userID, SQL_NTS, // User specified
|
||||||
NULL, 0, // All tables
|
NULL, 0, // All tables
|
||||||
NULL, 0); // All columns
|
NULL, 0); // All columns
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
retcode = SQLColumns(hstmt,
|
||||||
|
NULL, 0, // All qualifiers
|
||||||
|
NULL, 0, // User specified
|
||||||
|
NULL, 0, // All tables
|
||||||
|
NULL, 0); // All columns
|
||||||
|
}
|
||||||
if (retcode != SQL_SUCCESS)
|
if (retcode != SQL_SUCCESS)
|
||||||
{
|
{
|
||||||
DispAllErrors(henv, hdbc, hstmt);
|
DispAllErrors(henv, hdbc, hstmt);
|
||||||
@@ -1222,7 +1465,7 @@ bool wxDB::Catalog(char *userID, char *fileName)
|
|||||||
SQLBindCol(hstmt, 3, SQL_C_CHAR, (UCHAR*) tblName, DB_MAX_TABLE_NAME_LEN+1, &cb);
|
SQLBindCol(hstmt, 3, SQL_C_CHAR, (UCHAR*) tblName, DB_MAX_TABLE_NAME_LEN+1, &cb);
|
||||||
SQLBindCol(hstmt, 4, SQL_C_CHAR, (UCHAR*) colName, DB_MAX_COLUMN_NAME_LEN+1, &cb);
|
SQLBindCol(hstmt, 4, SQL_C_CHAR, (UCHAR*) colName, DB_MAX_COLUMN_NAME_LEN+1, &cb);
|
||||||
SQLBindCol(hstmt, 5, SQL_C_SSHORT, (UCHAR*) &sqlDataType, 0, &cb);
|
SQLBindCol(hstmt, 5, SQL_C_SSHORT, (UCHAR*) &sqlDataType, 0, &cb);
|
||||||
SQLBindCol(hstmt, 6, SQL_C_CHAR, (UCHAR*) typeName, 16, &cb);
|
SQLBindCol(hstmt, 6, SQL_C_CHAR, (UCHAR*) typeName, sizeof(typeName), &cb);
|
||||||
SQLBindCol(hstmt, 7, SQL_C_SSHORT, (UCHAR*) &precision, 0, &cb);
|
SQLBindCol(hstmt, 7, SQL_C_SSHORT, (UCHAR*) &precision, 0, &cb);
|
||||||
SQLBindCol(hstmt, 8, SQL_C_SSHORT, (UCHAR*) &length, 0, &cb);
|
SQLBindCol(hstmt, 8, SQL_C_SSHORT, (UCHAR*) &length, 0, &cb);
|
||||||
|
|
||||||
@@ -1255,6 +1498,8 @@ bool wxDB::Catalog(char *userID, char *fileName)
|
|||||||
tblName, colName, sqlDataType, typeName, precision, length);
|
tblName, colName, sqlDataType, typeName, precision, length);
|
||||||
if (fputs(outStr, fp) == EOF)
|
if (fputs(outStr, fp) == EOF)
|
||||||
{
|
{
|
||||||
|
SQLFreeStmt(hstmt, SQL_UNBIND);
|
||||||
|
SQLFreeStmt(hstmt, SQL_CLOSE);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
return(FALSE);
|
return(FALSE);
|
||||||
}
|
}
|
||||||
@@ -1262,15 +1507,13 @@ bool wxDB::Catalog(char *userID, char *fileName)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (retcode != SQL_NO_DATA_FOUND)
|
if (retcode != SQL_NO_DATA_FOUND)
|
||||||
{
|
|
||||||
DispAllErrors(henv, hdbc, hstmt);
|
DispAllErrors(henv, hdbc, hstmt);
|
||||||
fclose(fp);
|
|
||||||
return(FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
SQLFreeStmt(hstmt, SQL_UNBIND);
|
||||||
SQLFreeStmt(hstmt, SQL_CLOSE);
|
SQLFreeStmt(hstmt, SQL_CLOSE);
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
return(TRUE);
|
return(retcode == SQL_NO_DATA_FOUND);
|
||||||
|
|
||||||
} // wxDB::Catalog()
|
} // wxDB::Catalog()
|
||||||
|
|
||||||
@@ -1279,20 +1522,78 @@ bool wxDB::Catalog(char *userID, char *fileName)
|
|||||||
// if the object exists in the database. This function does not indicate
|
// if the object exists in the database. This function does not indicate
|
||||||
// whether or not the user has privleges to query or perform other functions
|
// whether or not the user has privleges to query or perform other functions
|
||||||
// on the table.
|
// on the table.
|
||||||
bool wxDB::TableExists(char *tableName)
|
bool wxDB::TableExists(char *tableName, char *userID, char *tablePath)
|
||||||
{
|
{
|
||||||
assert(tableName && strlen(tableName));
|
assert(tableName && strlen(tableName));
|
||||||
|
|
||||||
|
if (Dbms() == dbmsDBASE)
|
||||||
|
{
|
||||||
|
wxString dbName;
|
||||||
|
if (tablePath && strlen(tablePath))
|
||||||
|
dbName.sprintf("%s/%s.dbf",tablePath,tableName);
|
||||||
|
else
|
||||||
|
dbName.sprintf("%s.dbf",tableName);
|
||||||
|
bool glt;
|
||||||
|
glt = wxFileExists(dbName.GetData());
|
||||||
|
return glt;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!userID || !strlen(userID))
|
||||||
|
userID = uid;
|
||||||
|
|
||||||
|
char userIdUC[80+1];
|
||||||
|
// Oracle user names may only be in uppercase, so force
|
||||||
|
// the name to uppercase
|
||||||
|
if (Dbms() == dbmsORACLE)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
for (char *p = userID; *p; p++)
|
||||||
|
userIdUC[i++] = toupper(*p);
|
||||||
|
userIdUC[i] = 0;
|
||||||
|
userID = userIdUC;
|
||||||
|
}
|
||||||
|
|
||||||
|
char tableNameUC[DB_MAX_TABLE_NAME_LEN+1];
|
||||||
|
// Oracle table names are uppercase only, so force
|
||||||
|
// the name to uppercase just in case programmer forgot to do this
|
||||||
|
if (Dbms() == dbmsORACLE)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
for (char *p = tableName; *p; p++)
|
||||||
|
tableNameUC[i++] = toupper(*p);
|
||||||
|
tableNameUC[i] = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
sprintf(tableNameUC,tableName);
|
||||||
|
|
||||||
SQLFreeStmt(hstmt, SQL_CLOSE);
|
SQLFreeStmt(hstmt, SQL_CLOSE);
|
||||||
RETCODE retcode = SQLTables(hstmt,
|
RETCODE retcode;
|
||||||
|
|
||||||
|
// MySQL and Access cannot accept a user name when looking up table names, so we
|
||||||
|
// use the call below that leaves out the user name
|
||||||
|
if (strcmp(userID,"") &&
|
||||||
|
Dbms() != dbmsMY_SQL &&
|
||||||
|
Dbms() != dbmsACCESS)
|
||||||
|
{
|
||||||
|
retcode = SQLTables(hstmt,
|
||||||
|
NULL, 0, // All qualifiers
|
||||||
|
(UCHAR *) userID, SQL_NTS, // All owners
|
||||||
|
(UCHAR FAR *)tableNameUC, SQL_NTS,
|
||||||
|
NULL, 0); // All table types
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
retcode = SQLTables(hstmt,
|
||||||
NULL, 0, // All qualifiers
|
NULL, 0, // All qualifiers
|
||||||
NULL, 0, // All owners
|
NULL, 0, // All owners
|
||||||
(UCHAR FAR *)tableName, SQL_NTS,
|
(UCHAR FAR *)tableNameUC, SQL_NTS,
|
||||||
NULL, 0); // All table types
|
NULL, 0); // All table types
|
||||||
|
}
|
||||||
if (retcode != SQL_SUCCESS)
|
if (retcode != SQL_SUCCESS)
|
||||||
return(DispAllErrors(henv, hdbc, hstmt));
|
return(DispAllErrors(henv, hdbc, hstmt));
|
||||||
|
|
||||||
if (SQLFetch(hstmt) != SQL_SUCCESS)
|
retcode = SQLFetch(hstmt);
|
||||||
|
if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
|
||||||
{
|
{
|
||||||
SQLFreeStmt(hstmt, SQL_CLOSE);
|
SQLFreeStmt(hstmt, SQL_CLOSE);
|
||||||
return(DispAllErrors(henv, hdbc, hstmt));
|
return(DispAllErrors(henv, hdbc, hstmt));
|
||||||
@@ -1352,6 +1653,73 @@ bool wxDB::WriteSqlLog(char *logMsg)
|
|||||||
} // wxDB::WriteSqlLog()
|
} // wxDB::WriteSqlLog()
|
||||||
|
|
||||||
|
|
||||||
|
/********** wxDB::Dbms() **********/
|
||||||
|
/*
|
||||||
|
* Be aware that not all database engines use the exact same syntax, and not
|
||||||
|
* every ODBC compliant database is compliant to the same level of compliancy.
|
||||||
|
* Some manufacturers support the minimum Level 1 compliancy, and others up
|
||||||
|
* through Level 3. Others support subsets of features for levels above 1.
|
||||||
|
*
|
||||||
|
* If you find an inconsistency between the wxDB class and a specific database
|
||||||
|
* engine, and an identifier to this section, and special handle the database in
|
||||||
|
* the area where behavior is non-conforming with the other databases.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* NOTES ABOUT ISSUES SPECIFIC TO EACH DATABASE ENGINE
|
||||||
|
* ---------------------------------------------------
|
||||||
|
*
|
||||||
|
* ORACLE
|
||||||
|
* - Currently the only database supported by the class to support VIEWS
|
||||||
|
*
|
||||||
|
* DBASE
|
||||||
|
* - Does not support the SQL_TIMESTAMP structure
|
||||||
|
* - Supports only one cursor and one connect (apparently? with Microsoft driver only?)
|
||||||
|
* - Does not automatically create the primary index if the 'keyField' param of SetColDef
|
||||||
|
* is TRUE. The user must create ALL indexes from their program.
|
||||||
|
* - Table names can only be 8 characters long
|
||||||
|
* - Column names can only be 10 characters long
|
||||||
|
*
|
||||||
|
* SYBASE (all)
|
||||||
|
* - To lock a record during QUERY functions, the reserved word 'HOLDLOCK' must be added
|
||||||
|
* after every table name involved in the query/join if that tables matching record(s)
|
||||||
|
* are to be locked
|
||||||
|
* - Ignores the keywords 'FOR UPDATE'. Use the HOLDLOCK functionality described above
|
||||||
|
*
|
||||||
|
* SYBASE (Enterprise)
|
||||||
|
* - If a column is part of the Primary Key, the column cannot be NULL
|
||||||
|
*
|
||||||
|
* MY_SQL
|
||||||
|
* - If a column is part of the Primary Key, the column cannot be NULL
|
||||||
|
* - Cannot support selecting for update [::CanSelectForUpdate()]. Always returns FALSE
|
||||||
|
*
|
||||||
|
* POSTGRES
|
||||||
|
* - Does not support the keywords 'ASC' or 'DESC' as of release v6.5.0
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
DBMS wxDB::Dbms(void)
|
||||||
|
{
|
||||||
|
if (!strnicmp(dbInf.dbmsName,"Oracle",6))
|
||||||
|
return(dbmsORACLE);
|
||||||
|
if (!stricmp(dbInf.dbmsName,"Adaptive Server Anywhere"))
|
||||||
|
return(dbmsSYBASE_ASA);
|
||||||
|
if (!stricmp(dbInf.dbmsName,"SQL Server")) // Sybase Adaptive Server Enterprise
|
||||||
|
return(dbmsSYBASE_ASE);
|
||||||
|
if (!stricmp(dbInf.dbmsName,"Microsoft SQL Server"))
|
||||||
|
return(dbmsMS_SQL_SERVER);
|
||||||
|
if (!stricmp(dbInf.dbmsName,"MySQL"))
|
||||||
|
return(dbmsMY_SQL);
|
||||||
|
if (!stricmp(dbInf.dbmsName,"PostgresSQL")) // v6.5.0
|
||||||
|
return(dbmsPOSTGRES);
|
||||||
|
if (!stricmp(dbInf.dbmsName,"ACCESS"))
|
||||||
|
return(dbmsACCESS);
|
||||||
|
if (!strnicmp(dbInf.dbmsName,"DBASE",5))
|
||||||
|
return(dbmsDBASE);
|
||||||
|
return(dbmsUNIDENTIFIED);
|
||||||
|
|
||||||
|
} // wxDB::Dbms()
|
||||||
|
|
||||||
|
|
||||||
/********** GetDbConnection() **********/
|
/********** GetDbConnection() **********/
|
||||||
wxDB* WXDLLEXPORT GetDbConnection(DbStuff *pDbStuff)
|
wxDB* WXDLLEXPORT GetDbConnection(DbStuff *pDbStuff)
|
||||||
{
|
{
|
||||||
@@ -1396,7 +1764,10 @@ wxDB* WXDLLEXPORT GetDbConnection(DbStuff *pDbStuff)
|
|||||||
|
|
||||||
// Connect to the datasource
|
// Connect to the datasource
|
||||||
if (pList->PtrDb->Open(pDbStuff->Dsn, pDbStuff->Uid, pDbStuff->AuthStr))
|
if (pList->PtrDb->Open(pDbStuff->Dsn, pDbStuff->Uid, pDbStuff->AuthStr))
|
||||||
|
{
|
||||||
|
pList->PtrDb->SqlLog(SQLLOGstate,SQLLOGfn,TRUE);
|
||||||
return(pList->PtrDb);
|
return(pList->PtrDb);
|
||||||
|
}
|
||||||
else // Unable to connect, destroy list item
|
else // Unable to connect, destroy list item
|
||||||
{
|
{
|
||||||
if (pList->PtrPrev)
|
if (pList->PtrPrev)
|
||||||
@@ -1466,6 +1837,26 @@ int WXDLLEXPORT NumberDbConnectionsInUse(void)
|
|||||||
|
|
||||||
} // NumberDbConnectionsInUse()
|
} // NumberDbConnectionsInUse()
|
||||||
|
|
||||||
|
/********** SqlLog() **********/
|
||||||
|
bool SqlLog(enum sqlLog state, char *filename)
|
||||||
|
{
|
||||||
|
bool append = FALSE;
|
||||||
|
DbList *pList;
|
||||||
|
|
||||||
|
for (pList = PtrBegDbList; pList; pList = pList->PtrNext)
|
||||||
|
{
|
||||||
|
if (!pList->PtrDb->SqlLog(state,filename,append))
|
||||||
|
return(FALSE);
|
||||||
|
append = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
SQLLOGstate = state;
|
||||||
|
strcpy(SQLLOGfn,filename);
|
||||||
|
|
||||||
|
return(TRUE);
|
||||||
|
|
||||||
|
} // SqlLog()
|
||||||
|
|
||||||
/********** GetDataSource() **********/
|
/********** GetDataSource() **********/
|
||||||
bool GetDataSource(HENV henv, char *Dsn, SWORD DsnMax, char *DsDesc, SWORD DsDescMax,
|
bool GetDataSource(HENV henv, char *Dsn, SWORD DsnMax, char *DsDesc, SWORD DsDescMax,
|
||||||
UWORD direction)
|
UWORD direction)
|
||||||
|
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user