// SYNOPSIS START
// SYNOPSIS STOP
*/
+#ifdef __GNUG__
+ #pragma implementation "db.h"
+#endif
#include "wx/wxprec.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__
- #pragma implementation "db.h"
- #endif
+#ifdef __BORLANDC__
+ #pragma hdrstop
#endif
#ifdef DBDEBUG_CONSOLE
#include "wx/ioswrap.h"
#endif
-#ifdef __BORLANDC__
- #pragma hdrstop
-#endif //__BORLANDC__
-
-#if wxMAJOR_VERSION == 2
- #ifndef WX_PRECOMP
- #include "wx/string.h"
- #include "wx/object.h"
- #include "wx/list.h"
- #include "wx/utils.h"
+#ifndef WX_PRECOMP
+ #include "wx/string.h"
+ #include "wx/object.h"
+ #include "wx/list.h"
+ #include "wx/utils.h"
+ #if wxUSE_GUI
#include "wx/msgdlg.h"
- #include "wx/log.h"
#endif
- #include "wx/filefn.h"
- #include "wx/wxchar.h"
-#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
+ #include "wx/log.h"
#endif
+#include "wx/filefn.h"
+#include "wx/wxchar.h"
#if wxUSE_ODBC
#include <stdlib.h>
#include <ctype.h>
-#if wxMAJOR_VERSION == 1
- #include "db.h"
-#elif wxMAJOR_VERSION == 2
- #include "wx/db.h"
-#endif
+#include "wx/db.h"
WXDLLEXPORT_DATA(wxDbList*) PtrBegDbList = 0;
// connection
wxChar DBerrorList[DB_MAX_ERROR_HISTORY][DB_MAX_ERROR_MSG_LEN];
+
// This type defines the return row-struct form
// SQLTablePrivileges, and is used by wxDB::TablePrivileges.
typedef struct
s_Field = wxT("%02d/%02d/%04d %02d:%02d:%02d.%03d");
}
break;
- case DB_DATA_TYPE_BLOB:
+ case DB_DATA_TYPE_BLOB:
s_Field.Printf(wxT("Unable to format(%d)-SQL(%d)"),dbDataType,sqlDataType); //
- break;
+ break;
default:
s_Field.Printf(wxT("Unknown Format(%d)-SQL(%d)"),dbDataType,sqlDataType); //
break;
} // wxDbInf::Initialize()
-/********** wxDb Constructors **********/
+/********** wxDb Constructor **********/
wxDb::wxDb(const HENV &aHenv, bool FwdOnlyCursors)
{
// Copy the HENV into the db class
} // wxDb::wxDb()
+/********** wxDb Destructor **********/
+wxDb::~wxDb()
+{
+ wxASSERT_MSG(!IsCached(),wxT("Cached connections must not be manually deleted, use\nwxDbFreeConnection() or wxDbCloseConnections()."));
+
+ if (IsOpen())
+ {
+ Close();
+ }
+} // wxDb destructor
+
+
+
/********** PRIVATE! wxDb::initialize PRIVATE! **********/
/********** wxDb::initialize() **********/
void wxDb::initialize()
// Mark database as not open as of yet
dbIsOpen = FALSE;
+ dbIsCached = FALSE;
} // wxDb::initialize()
UserID.Empty();
// dBase does not use user names, and some drivers fail if you try to pass one
- if (Dbms() == dbmsDBASE)
+ if ( Dbms() == dbmsDBASE
+ || Dbms() == dbmsXBASE_SEQUITER )
UserID.Empty();
// Oracle user names may only be in uppercase, so force
/********** wxDb::Open() **********/
-bool wxDb::Open(const wxString &Dsn, const wxString &Uid, const wxString &AuthStr)
+bool wxDb::Open(const wxString &Dsn, const wxString &Uid, const wxString &AuthStr, bool failOnDataTypeUnsupported)
{
wxASSERT(Dsn.Length());
dsn = Dsn;
(UCHAR FAR *) uid.c_str(), SQL_NTS,
(UCHAR FAR *) authStr.c_str(), SQL_NTS);
-/*
- if (retcode == SQL_SUCCESS_WITH_INFO)
- DispAllErrors(henv, hdbc);
- else if (retcode != SQL_SUCCESS)
- return(DispAllErrors(henv, hdbc));
-
- if (retcode == SQL_ERROR)
- return(DispAllErrors(henv, hdbc));
-*/
- if ((retcode != SQL_SUCCESS) &&
+ if ((retcode != SQL_SUCCESS) &&
(retcode != SQL_SUCCESS_WITH_INFO))
- return(DispAllErrors(henv, hdbc));
+ return(DispAllErrors(henv, hdbc));
/*
If using Intersolv branded ODBC drivers, this is the place where you would substitute
if (!getDataTypeInfo(SQL_FLOAT,typeInfFloat))
if (!getDataTypeInfo(SQL_DECIMAL,typeInfFloat))
if (!getDataTypeInfo(SQL_NUMERIC,typeInfFloat))
- return(FALSE);
+ {
+ if (failOnDataTypeUnsupported)
+ return(FALSE);
+ }
else
typeInfFloat.FsqlType = SQL_NUMERIC;
else
// If SQL_INTEGER is not supported, use the floating point
// data type to store integers as well as floats
if (!getDataTypeInfo(typeInfFloat.FsqlType, typeInfInteger))
- return(FALSE);
+ {
+ if (failOnDataTypeUnsupported)
+ return(FALSE);
+ }
else
typeInfInteger.FsqlType = typeInfFloat.FsqlType;
}
typeInfInteger.FsqlType = SQL_INTEGER;
// Date/Time
- if (Dbms() != dbmsDBASE)
- {
- if (! getDataTypeInfo(SQL_TIMESTAMP,typeInfDate))
- return(FALSE);
- else
- typeInfDate.FsqlType = SQL_TIMESTAMP;
- }
- else
+ if (!getDataTypeInfo(SQL_TIMESTAMP,typeInfDate))
{
if (!getDataTypeInfo(SQL_DATE,typeInfDate))
- return(FALSE);
+ {
+#ifdef SQL_DATETIME
+ if (getDataTypeInfo(SQL_DATETIME,typeInfDate))
+ {
+ typeInfDate.FsqlType = SQL_TIME;
+ }
+ else
+#endif // SQL_DATETIME defined
+ {
+ if (failOnDataTypeUnsupported)
+ return(FALSE);
+ }
+ }
else
typeInfDate.FsqlType = SQL_DATE;
}
+ else
+ typeInfDate.FsqlType = SQL_TIMESTAMP;
+
if (!getDataTypeInfo(SQL_LONGVARBINARY, typeInfBlob))
{
if (!getDataTypeInfo(SQL_VARBINARY,typeInfBlob))
- return(FALSE);
+ {
+ if (failOnDataTypeUnsupported)
+ return(FALSE);
+ }
else
typeInfBlob.FsqlType = SQL_VARBINARY;
}
(UCHAR FAR *) uid.c_str(), SQL_NTS,
(UCHAR FAR *) authStr.c_str(), SQL_NTS);
- if (retcode == SQL_ERROR)
- return(DispAllErrors(henv, hdbc));
+ if (retcode == SQL_ERROR)
+ return(DispAllErrors(henv, hdbc));
/*
If using Intersolv branded ODBC drivers, this is the place where you would substitute
SQLSetConnectOption(hdbc, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF);
SQLSetConnectOption(hdbc, SQL_OPT_TRACE, SQL_OPT_TRACE_OFF);
-// SQLSetConnectOption(hdbc, SQL_TXN_ISOLATION, SQL_TXN_READ_COMMITTED); // No dirty reads
+// SQLSetConnectOption(hdbc, SQL_TXN_ISOLATION, SQL_TXN_READ_COMMITTED); // No dirty reads
// By default, MS Sql Server closes cursors on commit and rollback. The following
// call to SQLSetConnectOption() is needed to force SQL Server to preserve cursors
// Get information about the data type specified
if (SQLGetTypeInfo(hstmt, fSqlType) != SQL_SUCCESS)
return(DispAllErrors(henv, hdbc, hstmt));
+
// Fetch the record
- if ((retcode = SQLFetch(hstmt)) != SQL_SUCCESS)
+ retcode = SQLFetch(hstmt);
+ if (retcode != SQL_SUCCESS)
{
#ifdef DBDEBUG_CONSOLE
if (retcode == SQL_NO_DATA_FOUND)
}
wxChar typeName[DB_TYPE_NAME_LEN+1];
+
// Obtain columns from the record
if (SQLGetData(hstmt, 1, SQL_C_CHAR, (UCHAR*) typeName, DB_TYPE_NAME_LEN, &cbRet) != SQL_SUCCESS)
return(DispAllErrors(henv, hdbc, hstmt));
{
s.Printf(wxT("(%-20s) tableID:[%6lu] pDb:[%p]"), tiu->tableName,tiu->tableID,tiu->pDb);
s2.Printf(wxT("Orphaned found using pDb:[%p]"),this);
- wxLogDebug (s,s2);
+ wxLogDebug (s.c_str(),s2.c_str());
}
pNode = pNode->Next();
}
for (i = 0; i < DB_MAX_ERROR_HISTORY; i++)
wxStrcpy(DBerrorList[i], errorList[i]);
- dbmsType = dbmsUNIDENTIFIED;
+ dbmsType = dbmsUNIDENTIFIED;
dbIsOpen = FALSE;
} // wxDb::Close()
}
}
- return(FALSE); // This function always returns false.
+ return(FALSE); // This function always returns FALSE.
} // wxDb::DispAllErrors()
}
sqlStmt += wxT(" ON ");
- sqlStmt += tableName;
+ sqlStmt += SQLTableName(tableName);
sqlStmt += wxT(" TO ");
sqlStmt += userList;
}
// Commit the transaction
- if (! CommitTrans())
+ if (!CommitTrans())
return(FALSE);
return TRUE;
* to avoid undesired unbinding of columns.
*/
{
- UWORD noCols = 0;
- UWORD colNo = 0;
+ UWORD noCols = 0;
+ UWORD colNo = 0;
wxDbColInf *colInf = 0;
RETCODE retcode;
// Build a generic SELECT statement which returns 0 rows
wxString Stmt;
- Stmt.Printf(wxT("select * from %s where 0=1"), tableName);
+ Stmt.Printf(wxT("select * from \"%s\" where 0=1"), tableName);
// Execute query
if (SQLExecDirect(hstmt, (UCHAR FAR *) Stmt.c_str(), SQL_NTS) != SQL_SUCCESS)
/********** wxDb::GetColumnCount() **********/
-UWORD wxDb::GetColumnCount(const wxString &tableName, const wxChar *userID)
+int wxDb::GetColumnCount(const wxString &tableName, const wxChar *userID)
/*
* Returns a count of how many columns are in a table.
* If an error occurs in computing the number of columns
wxChar colName[DB_MAX_COLUMN_NAME_LEN+1];
SWORD sqlDataType;
wxChar typeName[30+1];
- SWORD precision, length;
+ SDWORD precision, length;
FILE *fp = fopen(fileName.c_str(),wxT("wt"));
if (fp == NULL)
if (!UserID.IsEmpty() &&
Dbms() != dbmsMY_SQL &&
Dbms() != dbmsACCESS &&
+ Dbms() != dbmsINTERBASE &&
Dbms() != dbmsMS_SQL_SERVER)
{
retcode = SQLColumns(hstmt,
tblNameSave.Empty();
int cnt = 0;
- while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS)
+ while (TRUE)
{
+ retcode = SQLFetch(hstmt);
+ if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
+ break;
+
if (wxStrcmp(tblName, tblNameSave.c_str()))
{
if (cnt)
tblNameSave = tblName;
}
- GetData(3,SQL_C_CHAR, (UCHAR *)tblName, DB_MAX_TABLE_NAME_LEN+1, &cb);
- GetData(4,SQL_C_CHAR, (UCHAR *)colName, DB_MAX_COLUMN_NAME_LEN+1,&cb);
- GetData(5,SQL_C_SSHORT,(UCHAR *)&sqlDataType,0, &cb);
- GetData(6,SQL_C_CHAR, (UCHAR *)typeName, sizeof(typeName), &cb);
- GetData(7,SQL_C_SSHORT,(UCHAR *)&precision, 0, &cb);
- GetData(8,SQL_C_SSHORT,(UCHAR *)&length, 0, &cb);
+ GetData(3,SQL_C_CHAR, (UCHAR *) tblName, DB_MAX_TABLE_NAME_LEN+1, &cb);
+ GetData(4,SQL_C_CHAR, (UCHAR *) colName, DB_MAX_COLUMN_NAME_LEN+1,&cb);
+ GetData(5,SQL_C_SSHORT,(UCHAR *)&sqlDataType, 0, &cb);
+ GetData(6,SQL_C_CHAR, (UCHAR *) typeName, sizeof(typeName), &cb);
+ GetData(7,SQL_C_SLONG, (UCHAR *)&precision, 0, &cb);
+ GetData(8,SQL_C_SLONG, (UCHAR *)&length, 0, &cb);
- outStr.Printf(wxT("%-32s %-32s (%04d)%-15s %9d %9d\n"),
+ outStr.Printf(wxT("%-32s %-32s (%04d)%-15s %9ld %9ld\n"),
tblName, colName, sqlDataType, typeName, precision, length);
if (fputs(outStr.c_str(), fp) == EOF)
{
bool wxDb::TableExists(const wxString &tableName, const wxChar *userID, const wxString &tablePath)
/*
- * Table name can refer to a table, view, alias or synonym. Returns true
+ * Table name can refer to a table, view, alias or synonym. Returns TRUE
* 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
* on the table.
Dbms() != dbmsACCESS &&
Dbms() != dbmsMS_SQL_SERVER &&
Dbms() != dbmsDB2 &&
+ Dbms() != dbmsINTERBASE &&
Dbms() != dbmsPERVASIVE_SQL)
{
retcode = SQLTables(hstmt,
} // wxDb::TablePrivileges
+const wxString wxDb::SQLTableName(const wxChar *tableName)
+{
+ wxString TableName;
+
+ if (Dbms() == dbmsACCESS)
+ TableName = '"';
+ TableName += tableName;
+ if (Dbms() == dbmsACCESS)
+ TableName += '"';
+
+ return TableName;
+} // wxDb::SQLTableName()
+
+
+const wxString wxDb::SQLColumnName(const wxChar *colName)
+{
+ wxString ColName;
+
+ if (Dbms() == dbmsACCESS)
+ ColName = '"';
+ ColName += colName;
+ if (Dbms() == dbmsACCESS)
+ ColName += '"';
+
+ return ColName;
+} // wxDb::SQLColumnName()
+
+
/********** wxDb::SetSqlLogging() **********/
bool wxDb::SetSqlLogging(wxDbSqlLogState state, const wxString &filename, bool append)
{
*
* PERVASIVE SQL
*
+ * INTERBASE
+ * - Columns that are part of primary keys must be defined as being NOT NULL
+ * when they are created. Some code is added in ::CreateIndex to try to adjust the
+ * column definition if it is not defined correctly, but it is experimental
*/
{
// Should only need to do this once for each new database connection
{
if (!wxStrncmp(dbInf.driverName, wxT("oplodbc"), 7) ||
!wxStrncmp(dbInf.driverName, wxT("OLOD"), 4))
- return ((wxDBMS)(dbmsMS_SQL_SERVER));
- else
- return ((wxDBMS)(dbmsType = dbmsSYBASE_ASE));
+ return ((wxDBMS)(dbmsMS_SQL_SERVER));
+ else
+ return ((wxDBMS)(dbmsType = dbmsSYBASE_ASE));
}
if (!wxStricmp(dbInf.dbmsName,wxT("Microsoft SQL Server")))
return((wxDBMS)(dbmsType = dbmsPOSTGRES));
baseName[9] = 0;
- if (!wxStricmp(dbInf.dbmsName,wxT("Pervasive")))
- return((wxDBMS)(dbmsType = dbmsPERVASIVE_SQL));
+ if (!wxStricmp(dbInf.dbmsName,wxT("Pervasive")))
+ return((wxDBMS)(dbmsType = dbmsPERVASIVE_SQL));
baseName[8] = 0;
if (!wxStricmp(baseName,wxT("Informix")))
if (!wxStricmp(baseName,wxT("DBASE")))
return((wxDBMS)(dbmsType = dbmsDBASE));
+ if (!wxStricmp(baseName,wxT("xBase")))
+ return((wxDBMS)(dbmsType = dbmsXBASE_SEQUITER));
+
+ if (!wxStricmp(baseName,wxT("MySQL")))
+ return((wxDBMS)(dbmsType = dbmsMY_SQL));
+
baseName[3] = 0;
if (!wxStricmp(baseName,wxT("DB2")))
return((wxDBMS)(dbmsType = dbmsDBASE));
return FALSE;
wxString dataTypeName;
- wxString sqlStmt;
+ wxString sqlStmt;
wxString alterSlashModify;
- switch(dataType)
- {
- case DB_DATA_TYPE_VARCHAR :
- dataTypeName = typeInfVarchar.TypeName;
- break;
- case DB_DATA_TYPE_INTEGER :
- dataTypeName = typeInfInteger.TypeName;
- break;
- case DB_DATA_TYPE_FLOAT :
- dataTypeName = typeInfFloat.TypeName;
- break;
- case DB_DATA_TYPE_DATE :
- dataTypeName = typeInfDate.TypeName;
- break;
- case DB_DATA_TYPE_BLOB :
- dataTypeName = typeInfBlob.TypeName;
- break;
- default:
- return FALSE;
- }
-
- // Set the modify or alter syntax depending on the type of database connected to
- switch (Dbms())
- {
- case dbmsORACLE :
- alterSlashModify = "MODIFY";
- break;
- case dbmsMS_SQL_SERVER :
- alterSlashModify = "ALTER COLUMN";
- break;
- case dbmsUNIDENTIFIED :
+ switch(dataType)
+ {
+ case DB_DATA_TYPE_VARCHAR :
+ dataTypeName = typeInfVarchar.TypeName;
+ break;
+ case DB_DATA_TYPE_INTEGER :
+ dataTypeName = typeInfInteger.TypeName;
+ break;
+ case DB_DATA_TYPE_FLOAT :
+ dataTypeName = typeInfFloat.TypeName;
+ break;
+ case DB_DATA_TYPE_DATE :
+ dataTypeName = typeInfDate.TypeName;
+ break;
+ case DB_DATA_TYPE_BLOB :
+ dataTypeName = typeInfBlob.TypeName;
+ break;
+ default:
+ return FALSE;
+ }
+
+ // Set the modify or alter syntax depending on the type of database connected to
+ switch (Dbms())
+ {
+ case dbmsORACLE :
+ alterSlashModify = "MODIFY";
+ break;
+ case dbmsMS_SQL_SERVER :
+ alterSlashModify = "ALTER COLUMN";
+ break;
+ case dbmsUNIDENTIFIED :
return FALSE;
- case dbmsSYBASE_ASA :
- case dbmsSYBASE_ASE :
- case dbmsMY_SQL :
- case dbmsPOSTGRES :
- case dbmsACCESS :
- case dbmsDBASE :
- default :
- alterSlashModify = "MODIFY";
- break;
- }
-
- // create the SQL statement
- sqlStmt.Printf(wxT("ALTER TABLE %s %s %s %s"), tableName.c_str(), alterSlashModify.c_str(),
- columnName.c_str(), dataTypeName.c_str());
+ case dbmsSYBASE_ASA :
+ case dbmsSYBASE_ASE :
+ case dbmsMY_SQL :
+ case dbmsPOSTGRES :
+ case dbmsACCESS :
+ case dbmsDBASE :
+ case dbmsXBASE_SEQUITER :
+ default :
+ alterSlashModify = "MODIFY";
+ break;
+ }
+
+ // create the SQL statement
+ if ( Dbms() == dbmsMY_SQL )
+ {
+ sqlStmt.Printf(wxT("ALTER TABLE %s %s %s %s"), tableName.c_str(), alterSlashModify.c_str(),
+ columnName.c_str(), dataTypeName.c_str());
+ }
+ else
+ {
+ sqlStmt.Printf(wxT("ALTER TABLE \"%s\" \"%s\" \"%s\" %s"), tableName.c_str(), alterSlashModify.c_str(),
+ columnName.c_str(), dataTypeName.c_str());
+ }
// For varchars only, append the size of the column
- if (dataType == DB_DATA_TYPE_VARCHAR)
+ if (dataType == DB_DATA_TYPE_VARCHAR &&
+ (Dbms() != dbmsMY_SQL || dataTypeName != "text"))
{
wxString s;
- s.Printf(wxT("(%d)"), columnLength);
+ s.Printf(wxT("(%lu)"), columnLength);
sqlStmt += s;
}
sqlStmt += optionalParam;
}
- return ExecSql(sqlStmt);
+ return ExecSql(sqlStmt);
} // wxDb::ModifyColumn()
// Initialize new node in the linked list
pList->PtrNext = 0;
pList->Free = FALSE;
- pList->Dsn = pDbConfig->GetDsn(); //glt - will this assignment work?
+ pList->Dsn = pDbConfig->GetDsn();
pList->Uid = pDbConfig->GetUserID();
pList->AuthStr = pDbConfig->GetPassword();
// Connect to the datasource
if (opened)
{
+ pList->PtrDb->setCached(TRUE); // Prevent a user from deleting a cached connection
pList->PtrDb->SetSqlLogging(SQLLOGstate,SQLLOGfn,TRUE);
return(pList->PtrDb);
}
pNext = pList->PtrNext; // Save the pointer to next
pList->PtrDb->CommitTrans(); // Commit any open transactions on wxDb object
pList->PtrDb->Close(); // Close the wxDb object
+ pList->PtrDb->setCached(FALSE); // Allows deletion of the wxDb instance
delete pList->PtrDb; // Deletes the wxDb object
delete pList; // Deletes the linked list object
}
} // wxDbConnectionsInUse()
+
+/********** wxDbLogExtendedErrorMsg() **********/
+// DEBUG ONLY function
+const wxChar* WXDLLEXPORT wxDbLogExtendedErrorMsg(const wxChar *userText,
+ wxDb *pDb,
+ const wxChar *ErrFile,
+ int ErrLine)
+{
+ static wxString msg;
+ msg = userText;
+
+ wxString tStr;
+
+ if (ErrFile || ErrLine)
+ {
+ msg += wxT("File: ");
+ msg += ErrFile;
+ msg += wxT(" Line: ");
+ tStr.Printf(wxT("%d"),ErrLine);
+ msg += tStr.c_str();
+ msg += wxT("\n");
+ }
+
+ msg.Append (wxT("\nODBC errors:\n"));
+ msg += wxT("\n");
+
+ // Display errors for this connection
+ int i;
+ for (i = 0; i < DB_MAX_ERROR_HISTORY; i++)
+ {
+ if (pDb->errorList[i])
+ {
+ msg.Append(pDb->errorList[i]);
+ if (wxStrcmp(pDb->errorList[i],wxT("")) != 0)
+ msg.Append(wxT("\n"));
+ // Clear the errmsg buffer so the next error will not
+ // end up showing the previous error that have occurred
+ wxStrcpy(pDb->errorList[i],wxT(""));
+ }
+ }
+ msg += wxT("\n");
+
+ wxLogDebug(msg.c_str());
+
+ return msg.c_str();
+} // wxDbLogExtendedErrorMsg()
+
+
/********** wxDbSqlLog() **********/
bool wxDbSqlLog(wxDbSqlLogState state, const wxChar *filename)
{