X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/1dee6b399299241ffef19a61717bcb18d7a855d5..69659fd770f615210efac4b4fa741b3ad6223616:/src/common/dbtable.cpp diff --git a/src/common/dbtable.cpp b/src/common/dbtable.cpp index 7ec54cbc70..ac9981425e 100644 --- a/src/common/dbtable.cpp +++ b/src/common/dbtable.cpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////// -// Name: dbtable.cpp +// Name: src/common/dbtable.cpp // Purpose: Implementation of the wxDbTable class. // Author: Doug Card // Modified by: George Tasker @@ -8,77 +8,66 @@ // Created: 9.96 // RCS-ID: $Id$ // Copyright: (c) 1996 Remstar International, Inc. -// Licence: wxWindows licence, plus: -// Notice: This class library and its intellectual design are free of charge for use, -// modification, enhancement, debugging under the following conditions: -// 1) These classes may only be used as part of the implementation of a -// wxWindows-based application -// 2) All enhancements and bug fixes are to be submitted back to the wxWindows -// user groups free of all charges for use with the wxWindows library. -// 3) These classes may not be distributed as part of any other class library, -// DLL, text (written or electronic), other than a complete distribution of -// the wxWindows GUI development toolkit. +// Licence: wxWindows licence /////////////////////////////////////////////////////////////////////////////// -/* -// SYNOPSIS START -// SYNOPSIS STOP -*/ -#ifdef __GNUG__ - #pragma implementation "dbtable.h" -#endif - #include "wx/wxprec.h" #ifdef __BORLANDC__ #pragma hdrstop #endif -#ifdef DBDEBUG_CONSOLE - #include "iostream.h" - #include "wx/ioswrap.h" -#endif +#if wxUSE_ODBC #ifndef WX_PRECOMP - #include "wx/string.h" #include "wx/object.h" #include "wx/list.h" + #include "wx/string.h" #include "wx/utils.h" - #if wxUSE_GUI - #include "wx/msgdlg.h" - #endif #include "wx/log.h" + #include "wx/crt.h" #endif -#include "wx/filefn.h" -#if wxUSE_ODBC +#ifdef DBDEBUG_CONSOLE + #include "wx/ioswrap.h" +#endif + +#include "wx/filefn.h" #include #include #include -//#include #include "wx/dbtable.h" -#ifdef __UNIX__ -// The HPUX preprocessor lines below were commented out on 8/20/97 -// because macros.h currently redefines DEBUG and is unneeded. -// # ifdef HPUX -// # include -// # endif -# ifdef LINUX -# include -# endif +// FIXME-UTF8: get rid of this after switching to Unicode-only builds: +#if wxUSE_UNICODE + #define WXSQLCAST(s) ((SQLTCHAR FAR *)(wchar_t*)(s).wchar_str()) +#else + #define WXSQLCAST(s) ((SQLTCHAR FAR *)(char*)(s).char_str()) #endif ULONG lastTableID = 0; #ifdef __WXDEBUG__ + #include "wx/thread.h" + wxList TablesInUse; + wxCriticalSection csTablesInUse; #endif +void csstrncpyt(wxChar *target, const wxChar *source, int n) +{ + while ( (*target++ = *source++) != '\0' && --n != 0 ) + ; + + *target = '\0'; +} + + + /********** wxDbColDef::wxDbColDef() Constructor **********/ wxDbColDef::wxDbColDef() { @@ -93,14 +82,15 @@ bool wxDbColDef::Initialize() SqlCtype = SQL_C_LONG; PtrDataObj = NULL; SzDataObj = 0; - KeyField = FALSE; - Updateable = FALSE; - InsertAllowed = FALSE; - DerivedCol = FALSE; + KeyField = false; + Updateable = false; + InsertAllowed = false; + DerivedCol = false; CbValue = 0; - Null = FALSE; + Null = false; + CbValueCol = 0; - return TRUE; + return true; } // wxDbColDef::Initialize() @@ -113,17 +103,6 @@ wxDbTable::wxDbTable(wxDb *pwxDb, const wxString &tblName, const UWORD numColumn } // wxDbTable::wxDbTable() -/***** DEPRECATED: use wxDbTable::wxDbTable() format above *****/ -wxDbTable::wxDbTable(wxDb *pwxDb, const wxString &tblName, const UWORD numColumns, - const wxChar *qryTblName, bool qryOnly, const wxString &tblPath) -{ - wxString tempQryTblName; - tempQryTblName = qryTblName; - if (!initialize(pwxDb, tblName, numColumns, tempQryTblName, qryOnly, tblPath)) - cleanup(); -} // wxDbTable::wxDbTable() - - /********** wxDbTable::~wxDbTable() **********/ wxDbTable::~wxDbTable() { @@ -148,39 +127,50 @@ bool wxDbTable::initialize(wxDb *pwxDb, const wxString &tblName, const UWORD num hstmtInternal = 0; colDefs = 0; tableID = 0; - noCols = numColumns; // Number of cols in the table + m_numCols = numColumns; // Number of columns in the table where.Empty(); // Where clause orderBy.Empty(); // Order By clause from.Empty(); // From clause - selectForUpdate = FALSE; // SELECT ... FOR UPDATE; Indicates whether to include the FOR UPDATE phrase + selectForUpdate = false; // SELECT ... FOR UPDATE; Indicates whether to include the FOR UPDATE phrase queryOnly = qryOnly; - insertable = TRUE; + insertable = true; tablePath.Empty(); tableName.Empty(); queryTableName.Empty(); - wxASSERT(tblName.Length()); + wxASSERT(tblName.length()); wxASSERT(pDb); if (!pDb) - return FALSE; + return false; tableName = tblName; // Table Name - if (tblPath.Length()) + if ((pDb->Dbms() == dbmsORACLE) || + (pDb->Dbms() == dbmsFIREBIRD) || + (pDb->Dbms() == dbmsINTERBASE)) + tableName = tableName.Upper(); + + if (tblPath.length()) tablePath = tblPath; // Table Path - used for dBase files else tablePath.Empty(); - if (qryTblName.Length()) // Name of the table/view to query + if (qryTblName.length()) // Name of the table/view to query queryTableName = qryTblName; else queryTableName = tblName; + if ((pDb->Dbms() == dbmsORACLE) || + (pDb->Dbms() == dbmsFIREBIRD) || + (pDb->Dbms() == dbmsINTERBASE)) + queryTableName = queryTableName.Upper(); + pDb->incrementTableCount(); wxString s; tableID = ++lastTableID; - s.Printf(wxT("wxDbTable constructor (%-20s) tableID:[%6lu] pDb:[%p]"), tblName.c_str(), tableID, pDb); + s.Printf(wxT("wxDbTable constructor (%-20s) tableID:[%6lu] pDb:[%p]"), + tblName.c_str(), tableID, wx_static_cast(void*, pDb)); #ifdef __WXDEBUG__ wxTablesInUse *tableInUse; @@ -188,7 +178,10 @@ bool wxDbTable::initialize(wxDb *pwxDb, const wxString &tblName, const UWORD num tableInUse->tableName = tblName; tableInUse->tableID = tableID; tableInUse->pDb = pDb; - TablesInUse.Append(tableInUse); + { + wxCriticalSectionLocker lock(csTablesInUse); + TablesInUse.Append(tableInUse); + } #endif pDb->WriteSqlLog(s); @@ -198,8 +191,8 @@ bool wxDbTable::initialize(wxDb *pwxDb, const wxString &tblName, const UWORD num hdbc = pDb->GetHDBC(); // Allocate space for column definitions - if (noCols) - colDefs = new wxDbColDef[noCols]; // Points to the first column definition + if (m_numCols) + colDefs = new wxDbColDef[m_numCols]; // Points to the first column definition // Allocate statement handles for the table if (!queryOnly) @@ -260,7 +253,7 @@ bool wxDbTable::initialize(wxDb *pwxDb, const wxString &tblName, const UWORD num { // Should never happen pDb->GetNextError(henv, hdbc, hstmtInternal); - return FALSE; + return false; } } } @@ -289,11 +282,11 @@ bool wxDbTable::initialize(wxDb *pwxDb, const wxString &tblName, const UWORD num } // Make the default cursor the active cursor - hstmtDefault = GetNewCursor(FALSE,FALSE); + hstmtDefault = GetNewCursor(false,false); wxASSERT(hstmtDefault); hstmt = *hstmtDefault; - return TRUE; + return true; } // wxDbTable::initialize() @@ -303,28 +296,31 @@ void wxDbTable::cleanup() wxString s; if (pDb) { - s.Printf(wxT("wxDbTable destructor (%-20s) tableID:[%6lu] pDb:[%p]"), tableName.c_str(), tableID, pDb); + s.Printf(wxT("wxDbTable destructor (%-20s) tableID:[%6lu] pDb:[%p]"), + tableName.c_str(), tableID, wx_static_cast(void*, pDb)); pDb->WriteSqlLog(s); } #ifdef __WXDEBUG__ if (tableID) { - TablesInUse.DeleteContents(TRUE); - bool found = FALSE; + bool found = false; - wxNode *pNode; - pNode = TablesInUse.First(); - while (pNode && !found) + wxList::compatibility_iterator pNode; { - if (((wxTablesInUse *)pNode->Data())->tableID == tableID) + wxCriticalSectionLocker lock(csTablesInUse); + pNode = TablesInUse.GetFirst(); + while (!found && pNode) { - found = TRUE; - if (!TablesInUse.DeleteNode(pNode)) - wxLogDebug (s,wxT("Unable to delete node!")); + if (((wxTablesInUse *)pNode->GetData())->tableID == tableID) + { + found = true; + delete (wxTablesInUse *)pNode->GetData(); + TablesInUse.Erase(pNode); + } + else + pNode = pNode->GetNext(); } - else - pNode = pNode->Next(); } if (!found) { @@ -399,23 +395,64 @@ ODBC 3.0 says to use this form /***************************** PRIVATE FUNCTIONS *****************************/ +void wxDbTable::setCbValueForColumn(int columnIndex) +{ + switch(colDefs[columnIndex].DbDataType) + { + case DB_DATA_TYPE_VARCHAR: + case DB_DATA_TYPE_MEMO: + if (colDefs[columnIndex].Null) + colDefs[columnIndex].CbValue = SQL_NULL_DATA; + else + colDefs[columnIndex].CbValue = SQL_NTS; + break; + case DB_DATA_TYPE_INTEGER: + if (colDefs[columnIndex].Null) + colDefs[columnIndex].CbValue = SQL_NULL_DATA; + else + colDefs[columnIndex].CbValue = 0; + break; + case DB_DATA_TYPE_FLOAT: + if (colDefs[columnIndex].Null) + colDefs[columnIndex].CbValue = SQL_NULL_DATA; + else + colDefs[columnIndex].CbValue = 0; + break; + case DB_DATA_TYPE_DATE: + if (colDefs[columnIndex].Null) + colDefs[columnIndex].CbValue = SQL_NULL_DATA; + else + colDefs[columnIndex].CbValue = 0; + break; + case DB_DATA_TYPE_BLOB: + if (colDefs[columnIndex].Null) + colDefs[columnIndex].CbValue = SQL_NULL_DATA; + else + if (colDefs[columnIndex].SqlCtype == SQL_C_WXCHAR) + colDefs[columnIndex].CbValue = SQL_NTS; + else + colDefs[columnIndex].CbValue = SQL_LEN_DATA_AT_EXEC(colDefs[columnIndex].SzDataObj); + break; + } +} + /********** wxDbTable::bindParams() **********/ bool wxDbTable::bindParams(bool forUpdate) { wxASSERT(!queryOnly); if (queryOnly) - return(FALSE); + return false; SWORD fSqlType = 0; - UDWORD precision = 0; + SDWORD precision = 0; SWORD scale = 0; // Bind each column of the table that should be bound // to a parameter marker int i; - UWORD colNo; + UWORD colNumber; - for (i=0, colNo=1; i < noCols; i++) + for (i=0, colNumber=1; i < m_numCols; i++) { if (forUpdate) { @@ -434,19 +471,16 @@ bool wxDbTable::bindParams(bool forUpdate) fSqlType = pDb->GetTypeInfVarchar().FsqlType; precision = colDefs[i].SzDataObj; scale = 0; - if (colDefs[i].Null) - colDefs[i].CbValue = SQL_NULL_DATA; - else - colDefs[i].CbValue = SQL_NTS; + break; + case DB_DATA_TYPE_MEMO: + fSqlType = pDb->GetTypeInfMemo().FsqlType; + precision = colDefs[i].SzDataObj; + scale = 0; break; case DB_DATA_TYPE_INTEGER: fSqlType = pDb->GetTypeInfInteger().FsqlType; precision = pDb->GetTypeInfInteger().Precision; scale = 0; - if (colDefs[i].Null) - colDefs[i].CbValue = SQL_NULL_DATA; - else - colDefs[i].CbValue = 0; break; case DB_DATA_TYPE_FLOAT: fSqlType = pDb->GetTypeInfFloat().FsqlType; @@ -457,33 +491,24 @@ bool wxDbTable::bindParams(bool forUpdate) // I check for this here and set the scale = precision. //if (scale < 0) // scale = (short) precision; - if (colDefs[i].Null) - colDefs[i].CbValue = SQL_NULL_DATA; - else - colDefs[i].CbValue = 0; break; case DB_DATA_TYPE_DATE: fSqlType = pDb->GetTypeInfDate().FsqlType; precision = pDb->GetTypeInfDate().Precision; scale = 0; - if (colDefs[i].Null) - colDefs[i].CbValue = SQL_NULL_DATA; - else - colDefs[i].CbValue = 0; break; case DB_DATA_TYPE_BLOB: fSqlType = pDb->GetTypeInfBlob().FsqlType; - precision = 50000; + precision = colDefs[i].SzDataObj; scale = 0; - if (colDefs[i].Null) - colDefs[i].CbValue = SQL_NULL_DATA; - else - colDefs[i].CbValue = SQL_LEN_DATA_AT_EXEC(colDefs[i].SzDataObj); break; } + + setCbValueForColumn(i); + if (forUpdate) { - if (SQLBindParameter(hstmtUpdate, colNo++, SQL_PARAM_INPUT, colDefs[i].SqlCtype, + if (SQLBindParameter(hstmtUpdate, colNumber++, SQL_PARAM_INPUT, colDefs[i].SqlCtype, fSqlType, precision, scale, (UCHAR*) colDefs[i].PtrDataObj, precision+1, &colDefs[i].CbValue) != SQL_SUCCESS) { @@ -492,9 +517,9 @@ bool wxDbTable::bindParams(bool forUpdate) } else { - if (SQLBindParameter(hstmtInsert, colNo++, SQL_PARAM_INPUT, colDefs[i].SqlCtype, + if (SQLBindParameter(hstmtInsert, colNumber++, SQL_PARAM_INPUT, colDefs[i].SqlCtype, fSqlType, precision, scale, (UCHAR*) colDefs[i].PtrDataObj, - precision+1,&colDefs[i].CbValue) != SQL_SUCCESS) + precision+1, &colDefs[i].CbValue) != SQL_SUCCESS) { return(pDb->DispAllErrors(henv, hdbc, hstmtInsert)); } @@ -502,7 +527,7 @@ bool wxDbTable::bindParams(bool forUpdate) } // Completed successfully - return(TRUE); + return true; } // wxDbTable::bindParams() @@ -510,14 +535,14 @@ bool wxDbTable::bindParams(bool forUpdate) /********** wxDbTable::bindInsertParams() **********/ bool wxDbTable::bindInsertParams(void) { - return bindParams(FALSE); + return bindParams(false); } // wxDbTable::bindInsertParams() /********** wxDbTable::bindUpdateParams() **********/ bool wxDbTable::bindUpdateParams(void) { - return bindParams(TRUE); + return bindParams(true); } // wxDbTable::bindUpdateParams() @@ -526,18 +551,15 @@ bool wxDbTable::bindCols(HSTMT cursor) { // Bind each column of the table to a memory address for fetching data UWORD i; - for (i = 0; i < noCols; i++) + for (i = 0; i < m_numCols; i++) { if (SQLBindCol(cursor, (UWORD)(i+1), colDefs[i].SqlCtype, (UCHAR*) colDefs[i].PtrDataObj, - colDefs[i].SzDataObj, &colDefs[i].CbValue ) != SQL_SUCCESS) - { + colDefs[i].SzDataObj, &colDefs[i].CbValueCol ) != SQL_SUCCESS) return (pDb->DispAllErrors(henv, hdbc, cursor)); - } } // Completed successfully - return(TRUE); - + return true; } // wxDbTable::bindCols() @@ -549,14 +571,14 @@ bool wxDbTable::getRec(UWORD fetchType) if (!pDb->FwdOnlyCursors()) { // Fetch the NEXT, PREV, FIRST or LAST record, depending on fetchType - UDWORD cRowsFetched; + SQLULEN cRowsFetched; UWORD rowStatus; retcode = SQLExtendedFetch(hstmt, fetchType, 0, &cRowsFetched, &rowStatus); if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) { if (retcode == SQL_NO_DATA_FOUND) - return(FALSE); + return false; else return(pDb->DispAllErrors(henv, hdbc, hstmt)); } @@ -565,8 +587,8 @@ bool wxDbTable::getRec(UWORD fetchType) // Set the Null member variable to indicate the Null state // of each column just read in. int i; - for (i = 0; i < noCols; i++) - colDefs[i].Null = (colDefs[i].CbValue == SQL_NULL_DATA); + for (i = 0; i < m_numCols; i++) + colDefs[i].Null = (colDefs[i].CbValueCol == SQL_NULL_DATA); } } else @@ -576,7 +598,7 @@ bool wxDbTable::getRec(UWORD fetchType) if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) { if (retcode == SQL_NO_DATA_FOUND) - return(FALSE); + return false; else return(pDb->DispAllErrors(henv, hdbc, hstmt)); } @@ -585,13 +607,13 @@ bool wxDbTable::getRec(UWORD fetchType) // Set the Null member variable to indicate the Null state // of each column just read in. int i; - for (i = 0; i < noCols; i++) - colDefs[i].Null = (colDefs[i].CbValue == SQL_NULL_DATA); + for (i = 0; i < m_numCols; i++) + colDefs[i].Null = (colDefs[i].CbValueCol == SQL_NULL_DATA); } } // Completed successfully - return(TRUE); + return true; } // wxDbTable::getRec() @@ -602,14 +624,14 @@ bool wxDbTable::execDelete(const wxString &pSqlStmt) RETCODE retcode; // Execute the DELETE statement - retcode = SQLExecDirect(hstmtDelete, (UCHAR FAR *) pSqlStmt.c_str(), SQL_NTS); + retcode = SQLExecDirect(hstmtDelete, WXSQLCAST(pSqlStmt), SQL_NTS); if (retcode == SQL_SUCCESS || retcode == SQL_NO_DATA_FOUND || retcode == SQL_SUCCESS_WITH_INFO) { // Record deleted successfully - return(TRUE); + return true; } // Problem deleting record @@ -624,14 +646,46 @@ bool wxDbTable::execUpdate(const wxString &pSqlStmt) RETCODE retcode; // Execute the UPDATE statement - retcode = SQLExecDirect(hstmtUpdate, (UCHAR FAR *) pSqlStmt.c_str(), SQL_NTS); + retcode = SQLExecDirect(hstmtUpdate, WXSQLCAST(pSqlStmt), SQL_NTS); if (retcode == SQL_SUCCESS || retcode == SQL_NO_DATA_FOUND || retcode == SQL_SUCCESS_WITH_INFO) { // Record updated successfully - return(TRUE); + return true; + } + else if (retcode == SQL_NEED_DATA) + { + PTR pParmID; + retcode = SQLParamData(hstmtUpdate, &pParmID); + while (retcode == SQL_NEED_DATA) + { + // Find the parameter + int i; + for (i=0; i < m_numCols; i++) + { + if (colDefs[i].PtrDataObj == pParmID) + { + // We found it. Store the parameter. + retcode = SQLPutData(hstmtUpdate, pParmID, colDefs[i].SzDataObj); + if (retcode != SQL_SUCCESS) + { + pDb->DispNextError(); + return pDb->DispAllErrors(henv, hdbc, hstmtUpdate); + } + break; + } + } + retcode = SQLParamData(hstmtUpdate, &pParmID); + } + if (retcode == SQL_SUCCESS || + retcode == SQL_NO_DATA_FOUND || + retcode == SQL_SUCCESS_WITH_INFO) + { + // Record updated successfully + return true; + } } // Problem updating record @@ -649,7 +703,7 @@ bool wxDbTable::query(int queryType, bool forUpdate, bool distinct, const wxStri // The user may wish to select for update, but the DBMS may not be capable selectForUpdate = CanSelectForUpdate(); else - selectForUpdate = FALSE; + selectForUpdate = false; // Set the SQL SELECT string if (queryType != DB_SELECT_STATEMENT) // A select statement was not passed in, @@ -660,16 +714,16 @@ bool wxDbTable::query(int queryType, bool forUpdate, bool distinct, const wxStri // Make sure the cursor is closed first if (!CloseCursor(hstmt)) - return(FALSE); + return false; // Execute the SQL SELECT statement int retcode; - retcode = SQLExecDirect(hstmt, (UCHAR FAR *) (queryType == DB_SELECT_STATEMENT ? pSqlStmt.c_str() : sqlStmt.c_str()), SQL_NTS); + retcode = SQLExecDirect(hstmt, (queryType == DB_SELECT_STATEMENT ? WXSQLCAST(pSqlStmt) : WXSQLCAST(sqlStmt)), SQL_NTS); if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) return(pDb->DispAllErrors(henv, hdbc, hstmt)); // Completed successfully - return(TRUE); + return true; } // wxDbTable::query() @@ -681,28 +735,36 @@ bool wxDbTable::query(int queryType, bool forUpdate, bool distinct, const wxStri bool wxDbTable::Open(bool checkPrivileges, bool checkTableExists) { if (!pDb) - return FALSE; + return false; int i; wxString sqlStmt; wxString s; -// int NumKeyCols=0; // Calculate the maximum size of the concatenated // keys for use with wxDbGrid m_keysize = 0; - for (i=0; i < noCols; i++) + for (i=0; i < m_numCols; i++) { if (colDefs[i].KeyField) { -// NumKeyCols++; m_keysize += colDefs[i].SzDataObj; } } s.Empty(); + + bool exists = true; + if (checkTableExists) + { + if (pDb->Dbms() == dbmsPOSTGRES) + exists = pDb->TableExists(tableName, NULL, tablePath); + else + exists = pDb->TableExists(tableName, pDb->GetUsername(), tablePath); + } + // Verify that the table exists in the database - if (checkTableExists && !pDb->TableExists(tableName, pDb->GetUsername(), tablePath)) + if (!exists) { s = wxT("Table/view does not exist in the database"); if ( *(pDb->dbInf.accessibleTables) == wxT('Y')) @@ -713,21 +775,22 @@ bool wxDbTable::Open(bool checkPrivileges, bool checkTableExists) else if (checkPrivileges) { // Verify the user has rights to access the table. - // Shortcut boolean evaluation to optimize out call to - // TablePrivileges - // - // Unfortunately this optimization doesn't seem to be - // reliable! - if (// *(pDb->dbInf.accessibleTables) == 'N' && - !pDb->TablePrivileges(tableName,wxT("SELECT"), pDb->GetUsername(), pDb->GetUsername(), tablePath)) - s = wxT("Current logged in user does not have sufficient privileges to access this table.\n"); + bool hasPrivs wxDUMMY_INITIALIZE(true); + + if (pDb->Dbms() == dbmsPOSTGRES) + hasPrivs = pDb->TablePrivileges(tableName, wxT("SELECT"), pDb->GetUsername(), NULL, tablePath); + else + hasPrivs = pDb->TablePrivileges(tableName, wxT("SELECT"), pDb->GetUsername(), pDb->GetUsername(), tablePath); + + if (!hasPrivs) + s = wxT("Connecting user does not have sufficient privileges to access this table.\n"); } - if (!s.IsEmpty()) + if (!s.empty()) { wxString p; - if (!tablePath.IsEmpty()) + if (!tablePath.empty()) p.Printf(wxT("Error opening '%s/%s'.\n"),tablePath.c_str(),tableName.c_str()); else p.Printf(wxT("Error opening '%s'.\n"), tableName.c_str()); @@ -735,7 +798,7 @@ bool wxDbTable::Open(bool checkPrivileges, bool checkTableExists) p += s; pDb->LogError(p.GetData()); - return(FALSE); + return false; } // Bind the member variables for field exchange between @@ -743,50 +806,50 @@ bool wxDbTable::Open(bool checkPrivileges, bool checkTableExists) if (!queryOnly) { if (!bindInsertParams()) // Inserts - return(FALSE); + return false; if (!bindUpdateParams()) // Updates - return(FALSE); + return false; } if (!bindCols(*hstmtDefault)) // Selects - return(FALSE); + return false; if (!bindCols(hstmtInternal)) // Internal use only - return(FALSE); + return false; /* * Do NOT bind the hstmtCount cursor!!! */ // Build an insert statement using parameter markers - if (!queryOnly && noCols > 0) + if (!queryOnly && m_numCols > 0) { - bool needComma = FALSE; - sqlStmt.Printf(wxT("INSERT INTO %s ("), pDb->SQLTableName(tableName.c_str())); - for (i = 0; i < noCols; i++) + bool needComma = false; + sqlStmt.Printf(wxT("INSERT INTO %s ("), + pDb->SQLTableName(tableName.c_str()).c_str()); + for (i = 0; i < m_numCols; i++) { if (! colDefs[i].InsertAllowed) continue; if (needComma) sqlStmt += wxT(","); sqlStmt += pDb->SQLColumnName(colDefs[i].ColName); -// sqlStmt += colDefs[i].ColName; - needComma = TRUE; + needComma = true; } - needComma = FALSE; + needComma = false; sqlStmt += wxT(") VALUES ("); int insertableCount = 0; - for (i = 0; i < noCols; i++) + for (i = 0; i < m_numCols; i++) { if (! colDefs[i].InsertAllowed) continue; if (needComma) sqlStmt += wxT(","); sqlStmt += wxT("?"); - needComma = TRUE; + needComma = true; insertableCount++; } sqlStmt += wxT(")"); @@ -794,15 +857,15 @@ bool wxDbTable::Open(bool checkPrivileges, bool checkTableExists) // Prepare the insert statement for execution if (insertableCount) { - if (SQLPrepare(hstmtInsert, (UCHAR FAR *) sqlStmt.c_str(), SQL_NTS) != SQL_SUCCESS) + if (SQLPrepare(hstmtInsert, WXSQLCAST(sqlStmt), SQL_NTS) != SQL_SUCCESS) return(pDb->DispAllErrors(henv, hdbc, hstmtInsert)); } else - insertable= FALSE; + insertable = false; } // Completed successfully - return(TRUE); + return true; } // wxDbTable::Open() @@ -821,7 +884,7 @@ bool wxDbTable::QueryBySqlStmt(const wxString &pSqlStmt) { pDb->WriteSqlLog(pSqlStmt); - return(query(DB_SELECT_STATEMENT, FALSE, FALSE, pSqlStmt)); + return(query(DB_SELECT_STATEMENT, false, false, pSqlStmt)); } // wxDbTable::QueryBySqlStmt() @@ -850,7 +913,7 @@ bool wxDbTable::GetPrev(void) if (pDb->FwdOnlyCursors()) { wxFAIL_MSG(wxT("GetPrev()::Backward scrolling cursors are not enabled for this instance of wxDbTable")); - return FALSE; + return false; } else return(getRec(SQL_FETCH_PRIOR)); @@ -864,7 +927,7 @@ bool wxDbTable::operator--(int) if (pDb->FwdOnlyCursors()) { wxFAIL_MSG(wxT("operator--:Backward scrolling cursors are not enabled for this instance of wxDbTable")); - return FALSE; + return false; } else return(getRec(SQL_FETCH_PRIOR)); @@ -878,7 +941,7 @@ bool wxDbTable::GetFirst(void) if (pDb->FwdOnlyCursors()) { wxFAIL_MSG(wxT("GetFirst():Backward scrolling cursors are not enabled for this instance of wxDbTable")); - return FALSE; + return false; } else return(getRec(SQL_FETCH_FIRST)); @@ -892,7 +955,7 @@ bool wxDbTable::GetLast(void) if (pDb->FwdOnlyCursors()) { wxFAIL_MSG(wxT("GetLast()::Backward scrolling cursors are not enabled for this instance of wxDbTable")); - return FALSE; + return false; } else return(getRec(SQL_FETCH_LAST)); @@ -913,13 +976,15 @@ void wxDbTable::BuildDeleteStmt(wxString &pSqlStmt, int typeOfDel, const wxStrin // Handle the case of DeleteWhere() and the where clause is blank. It should // delete all records from the database in this case. - if (typeOfDel == DB_DEL_WHERE && (pWhereClause.Length() == 0)) + if (typeOfDel == DB_DEL_WHERE && (pWhereClause.length() == 0)) { - pSqlStmt.Printf(wxT("DELETE FROM %s"), pDb->SQLTableName(tableName.c_str())); + pSqlStmt.Printf(wxT("DELETE FROM %s"), + pDb->SQLTableName(tableName.c_str()).c_str()); return; } - pSqlStmt.Printf(wxT("DELETE FROM %s WHERE "), pDb->SQLTableName(tableName.c_str())); + pSqlStmt.Printf(wxT("DELETE FROM %s WHERE "), + pDb->SQLTableName(tableName.c_str()).c_str()); // Append the WHERE clause to the SQL DELETE statement switch(typeOfDel) @@ -928,15 +993,15 @@ void wxDbTable::BuildDeleteStmt(wxString &pSqlStmt, int typeOfDel, const wxStrin // If the datasource supports the ROWID column, build // the where on ROWID for efficiency purposes. // e.g. DELETE FROM PARTS WHERE ROWID = '111.222.333' - if (CanUpdByROWID()) + if (CanUpdateByROWID()) { - SDWORD cb; + SQLLEN cb; wxChar rowid[wxDB_ROWID_LEN+1]; // Get the ROWID value. If not successful retreiving the ROWID, // simply fall down through the code and build the WHERE clause // based on the key fields. - if (SQLGetData(hstmt, (UWORD)(noCols+1), SQL_C_CHAR, (UCHAR*) rowid, wxDB_ROWID_LEN, &cb) == SQL_SUCCESS) + if (SQLGetData(hstmt, (UWORD)(m_numCols+1), SQL_C_WXCHAR, (UCHAR*) rowid, sizeof(rowid), &cb) == SQL_SUCCESS) { pSqlStmt += wxT("ROWID = '"); pSqlStmt += rowid; @@ -985,42 +1050,41 @@ void wxDbTable::BuildSelectStmt(wxString &pSqlStmt, int typeOfSelect, bool disti // Was a FROM clause specified to join tables to the base table? // Available for ::Query() only!!! - bool appendFromClause = FALSE; + bool appendFromClause = false; #if wxODBC_BACKWARD_COMPATABILITY if (typeOfSelect == DB_SELECT_WHERE && from && wxStrlen(from)) - appendFromClause = TRUE; + appendFromClause = true; #else - if (typeOfSelect == DB_SELECT_WHERE && from.Length()) - appendFromClause = TRUE; + if (typeOfSelect == DB_SELECT_WHERE && from.length()) + appendFromClause = true; #endif // Add the column list int i; - for (i = 0; i < noCols; i++) + wxString tStr; + for (i = 0; i < m_numCols; i++) { + tStr = colDefs[i].ColName; // If joining tables, the base table column names must be qualified to avoid ambiguity - if (appendFromClause || pDb->Dbms() == dbmsACCESS) + if ((appendFromClause || pDb->Dbms() == dbmsACCESS) && tStr.Find(wxT('.')) == wxNOT_FOUND) { pSqlStmt += pDb->SQLTableName(queryTableName.c_str()); -// pSqlStmt += queryTableName; pSqlStmt += wxT("."); } pSqlStmt += pDb->SQLColumnName(colDefs[i].ColName); -// pSqlStmt += colDefs[i].ColName; - if (i + 1 < noCols) + if (i + 1 < m_numCols) pSqlStmt += wxT(","); } // If the datasource supports ROWID, get this column as well. Exception: Don't retrieve // the ROWID if querying distinct records. The rowid will always be unique. - if (!distinct && CanUpdByROWID()) + if (!distinct && CanUpdateByROWID()) { // If joining tables, the base table column names must be qualified to avoid ambiguity if (appendFromClause || pDb->Dbms() == dbmsACCESS) { pSqlStmt += wxT(","); pSqlStmt += pDb->SQLTableName(queryTableName); -// pSqlStmt += queryTableName; pSqlStmt += wxT(".ROWID"); } else @@ -1051,7 +1115,7 @@ void wxDbTable::BuildSelectStmt(wxString &pSqlStmt, int typeOfSelect, bool disti #if wxODBC_BACKWARD_COMPATABILITY if (where && wxStrlen(where)) // May not want a where clause!!! #else - if (where.Length()) // May not want a where clause!!! + if (where.length()) // May not want a where clause!!! #endif { pSqlStmt += wxT(" WHERE "); @@ -1060,7 +1124,7 @@ void wxDbTable::BuildSelectStmt(wxString &pSqlStmt, int typeOfSelect, bool disti break; case DB_SELECT_KEYFIELDS: BuildWhereClause(whereClause, DB_WHERE_KEYFIELDS); - if (whereClause.Length()) + if (whereClause.length()) { pSqlStmt += wxT(" WHERE "); pSqlStmt += whereClause; @@ -1068,7 +1132,7 @@ void wxDbTable::BuildSelectStmt(wxString &pSqlStmt, int typeOfSelect, bool disti break; case DB_SELECT_MATCHING: BuildWhereClause(whereClause, DB_WHERE_MATCHING); - if (whereClause.Length()) + if (whereClause.length()) { pSqlStmt += wxT(" WHERE "); pSqlStmt += whereClause; @@ -1080,7 +1144,7 @@ void wxDbTable::BuildSelectStmt(wxString &pSqlStmt, int typeOfSelect, bool disti #if wxODBC_BACKWARD_COMPATABILITY if (orderBy && wxStrlen(orderBy)) #else - if (orderBy.Length()) + if (orderBy.length()) #endif { pSqlStmt += wxT(" ORDER BY "); @@ -1106,7 +1170,7 @@ void wxDbTable::BuildSelectStmt(wxChar *pSqlStmt, int typeOfSelect, bool distinc /********** wxDbTable::BuildUpdateStmt() **********/ -void wxDbTable::BuildUpdateStmt(wxString &pSqlStmt, int typeOfUpd, const wxString &pWhereClause) +void wxDbTable::BuildUpdateStmt(wxString &pSqlStmt, int typeOfUpdate, const wxString &pWhereClause) { wxASSERT(!queryOnly); if (queryOnly) @@ -1115,13 +1179,14 @@ void wxDbTable::BuildUpdateStmt(wxString &pSqlStmt, int typeOfUpd, const wxStrin wxString whereClause; whereClause.Empty(); - bool firstColumn = TRUE; + bool firstColumn = true; - pSqlStmt.Printf(wxT("UPDATE %s SET "), pDb->SQLTableName(tableName.Upper().c_str())); + pSqlStmt.Printf(wxT("UPDATE %s SET "), + pDb->SQLTableName(tableName.c_str()).c_str()); // Append a list of columns to be updated int i; - for (i = 0; i < noCols; i++) + for (i = 0; i < m_numCols; i++) { // Only append Updateable columns if (colDefs[i].Updateable) @@ -1129,7 +1194,7 @@ void wxDbTable::BuildUpdateStmt(wxString &pSqlStmt, int typeOfUpd, const wxStrin if (!firstColumn) pSqlStmt += wxT(","); else - firstColumn = FALSE; + firstColumn = false; pSqlStmt += pDb->SQLColumnName(colDefs[i].ColName); // pSqlStmt += colDefs[i].ColName; @@ -1139,21 +1204,21 @@ void wxDbTable::BuildUpdateStmt(wxString &pSqlStmt, int typeOfUpd, const wxStrin // Append the WHERE clause to the SQL UPDATE statement pSqlStmt += wxT(" WHERE "); - switch(typeOfUpd) + switch(typeOfUpdate) { case DB_UPD_KEYFIELDS: // If the datasource supports the ROWID column, build // the where on ROWID for efficiency purposes. // e.g. UPDATE PARTS SET Col1 = ?, Col2 = ? WHERE ROWID = '111.222.333' - if (CanUpdByROWID()) + if (CanUpdateByROWID()) { - SDWORD cb; + SQLLEN cb; wxChar rowid[wxDB_ROWID_LEN+1]; // Get the ROWID value. If not successful retreiving the ROWID, // simply fall down through the code and build the WHERE clause // based on the key fields. - if (SQLGetData(hstmt, (UWORD)(noCols+1), SQL_C_CHAR, (UCHAR*) rowid, wxDB_ROWID_LEN, &cb) == SQL_SUCCESS) + if (SQLGetData(hstmt, (UWORD)(m_numCols+1), SQL_C_WXCHAR, (UCHAR*) rowid, sizeof(rowid), &cb) == SQL_SUCCESS) { pSqlStmt += wxT("ROWID = '"); pSqlStmt += rowid; @@ -1174,10 +1239,10 @@ void wxDbTable::BuildUpdateStmt(wxString &pSqlStmt, int typeOfUpd, const wxStrin /***** DEPRECATED: use wxDbTable::BuildUpdateStmt(wxString &....) form *****/ -void wxDbTable::BuildUpdateStmt(wxChar *pSqlStmt, int typeOfUpd, const wxString &pWhereClause) +void wxDbTable::BuildUpdateStmt(wxChar *pSqlStmt, int typeOfUpdate, const wxString &pWhereClause) { wxString tempSqlStmt; - BuildUpdateStmt(tempSqlStmt, typeOfUpd, pWhereClause); + BuildUpdateStmt(tempSqlStmt, typeOfUpdate, pWhereClause); wxStrcpy(pSqlStmt, tempSqlStmt); } // BuildUpdateStmt() @@ -1190,60 +1255,77 @@ void wxDbTable::BuildWhereClause(wxString &pWhereClause, int typeOfWhere, * They are not included as part of the where clause. */ { - bool moreThanOneColumn = FALSE; + bool moreThanOneColumn = false; wxString colValue; // Loop through the columns building a where clause as you go - int i; - for (i = 0; i < noCols; i++) + int colNumber; + for (colNumber = 0; colNumber < m_numCols; colNumber++) { // Determine if this column should be included in the WHERE clause - if ((typeOfWhere == DB_WHERE_KEYFIELDS && colDefs[i].KeyField) || - (typeOfWhere == DB_WHERE_MATCHING && (!IsColNull(i)))) + if ((typeOfWhere == DB_WHERE_KEYFIELDS && colDefs[colNumber].KeyField) || + (typeOfWhere == DB_WHERE_MATCHING && (!IsColNull((UWORD)colNumber)))) { // Skip over timestamp columns - if (colDefs[i].SqlCtype == SQL_C_TIMESTAMP) + if (colDefs[colNumber].SqlCtype == SQL_C_TIMESTAMP) continue; // If there is more than 1 column, join them with the keyword "AND" if (moreThanOneColumn) pWhereClause += wxT(" AND "); else - moreThanOneColumn = TRUE; + moreThanOneColumn = true; + // Concatenate where phrase for the column - if (qualTableName.Length()) + wxString tStr = colDefs[colNumber].ColName; + + if (qualTableName.length() && tStr.Find(wxT('.')) == wxNOT_FOUND) { pWhereClause += pDb->SQLTableName(qualTableName); -// pWhereClause += qualTableName; pWhereClause += wxT("."); } - pWhereClause += pDb->SQLColumnName(colDefs[i].ColName); -// pWhereClause += colDefs[i].ColName; - if (useLikeComparison && (colDefs[i].SqlCtype == SQL_C_CHAR)) + pWhereClause += pDb->SQLColumnName(colDefs[colNumber].ColName); + + if (useLikeComparison && (colDefs[colNumber].SqlCtype == SQL_C_WXCHAR)) pWhereClause += wxT(" LIKE "); else pWhereClause += wxT(" = "); - switch(colDefs[i].SqlCtype) + + switch(colDefs[colNumber].SqlCtype) { case SQL_C_CHAR: - colValue.Printf(wxT("'%s'"), (UCHAR FAR *) colDefs[i].PtrDataObj); +#ifdef SQL_C_WCHAR + case SQL_C_WCHAR: +#endif + //case SQL_C_WXCHAR: SQL_C_WXCHAR is covered by either SQL_C_CHAR or SQL_C_WCHAR + colValue.Printf(wxT("'%s'"), GetDb()->EscapeSqlChars((wxChar *)colDefs[colNumber].PtrDataObj).c_str()); break; + case SQL_C_SHORT: case SQL_C_SSHORT: - colValue.Printf(wxT("%hi"), *((SWORD *) colDefs[i].PtrDataObj)); + colValue.Printf(wxT("%hi"), *((SWORD *) colDefs[colNumber].PtrDataObj)); break; case SQL_C_USHORT: - colValue.Printf(wxT("%hu"), *((UWORD *) colDefs[i].PtrDataObj)); + colValue.Printf(wxT("%hu"), *((UWORD *) colDefs[colNumber].PtrDataObj)); break; + case SQL_C_LONG: case SQL_C_SLONG: - colValue.Printf(wxT("%li"), *((SDWORD *) colDefs[i].PtrDataObj)); + colValue.Printf(wxT("%li"), *((SDWORD *) colDefs[colNumber].PtrDataObj)); break; case SQL_C_ULONG: - colValue.Printf(wxT("%lu"), *((UDWORD *) colDefs[i].PtrDataObj)); + colValue.Printf(wxT("%lu"), *((UDWORD *) colDefs[colNumber].PtrDataObj)); break; case SQL_C_FLOAT: - colValue.Printf(wxT("%.6f"), *((SFLOAT *) colDefs[i].PtrDataObj)); + colValue.Printf(wxT("%.6f"), *((SFLOAT *) colDefs[colNumber].PtrDataObj)); break; case SQL_C_DOUBLE: - colValue.Printf(wxT("%.6f"), *((SDOUBLE *) colDefs[i].PtrDataObj)); + colValue.Printf(wxT("%.6f"), *((SDOUBLE *) colDefs[colNumber].PtrDataObj)); + break; + default: + { + wxString strMsg; + strMsg.Printf(wxT("wxDbTable::bindParams(): Unknown column type for colDefs %d colName %s"), + colNumber,colDefs[colNumber].ColName); + wxFAIL_MSG(strMsg.c_str()); + } break; } pWhereClause += colValue; @@ -1286,7 +1368,7 @@ bool wxDbTable::CloseCursor(HSTMT cursor) return(pDb->DispAllErrors(henv, hdbc, cursor)); // Completed successfully - return(TRUE); + return true; } // wxDbTable::CloseCursor() @@ -1295,7 +1377,7 @@ bool wxDbTable::CloseCursor(HSTMT cursor) bool wxDbTable::CreateTable(bool attemptDrop) { if (!pDb) - return FALSE; + return false; int i, j; wxString sqlStmt; @@ -1306,11 +1388,11 @@ bool wxDbTable::CreateTable(bool attemptDrop) // Drop table first if (attemptDrop && !DropTable()) - return FALSE; + return false; // Create the table #ifdef DBDEBUG_CONSOLE - for (i = 0; i < noCols; i++) + for (i = 0; i < m_numCols; i++) { // Exclude derived columns since they are NOT part of the base table if (colDefs[i].DerivedCol) @@ -1319,7 +1401,10 @@ bool wxDbTable::CreateTable(bool attemptDrop) switch(colDefs[i].DbDataType) { case DB_DATA_TYPE_VARCHAR: - cout << pDb->GetTypeInfVarchar().TypeName << wxT("(") << colDefs[i].SzDataObj << wxT(")"); + cout << pDb->GetTypeInfVarchar().TypeName << wxT("(") << (int)(colDefs[i].SzDataObj / sizeof(wxChar)) << wxT(")"); + break; + case DB_DATA_TYPE_MEMO: + cout << pDb->GetTypeInfMemo().TypeName; break; case DB_DATA_TYPE_INTEGER: cout << pDb->GetTypeInfInteger().TypeName; @@ -1339,11 +1424,12 @@ bool wxDbTable::CreateTable(bool attemptDrop) #endif // Build a CREATE TABLE string from the colDefs structure. - bool needComma = FALSE; + bool needComma = false; - sqlStmt.Printf(wxT("CREATE TABLE %s ("), pDb->SQLTableName(tableName.c_str())); + sqlStmt.Printf(wxT("CREATE TABLE %s ("), + pDb->SQLTableName(tableName.c_str()).c_str()); - for (i = 0; i < noCols; i++) + for (i = 0; i < m_numCols; i++) { // Exclude derived columns since they are NOT part of the base table if (colDefs[i].DerivedCol) @@ -1361,6 +1447,9 @@ bool wxDbTable::CreateTable(bool attemptDrop) case DB_DATA_TYPE_VARCHAR: sqlStmt += pDb->GetTypeInfVarchar().TypeName; break; + case DB_DATA_TYPE_MEMO: + sqlStmt += pDb->GetTypeInfMemo().TypeName; + break; case DB_DATA_TYPE_INTEGER: sqlStmt += pDb->GetTypeInfInteger().TypeName; break; @@ -1375,11 +1464,12 @@ bool wxDbTable::CreateTable(bool attemptDrop) break; } // For varchars, append the size of the string - if (colDefs[i].DbDataType == DB_DATA_TYPE_VARCHAR)// || + if (colDefs[i].DbDataType == DB_DATA_TYPE_VARCHAR && + (pDb->Dbms() != dbmsMY_SQL || pDb->GetTypeInfVarchar().TypeName != _T("text")))// || // colDefs[i].DbDataType == DB_DATA_TYPE_BLOB) { wxString s; - s.Printf(wxT("(%d)"), colDefs[i].SzDataObj); + s.Printf(wxT("(%d)"), (int)(colDefs[i].SzDataObj / sizeof(wxChar))); sqlStmt += s; } @@ -1387,6 +1477,7 @@ bool wxDbTable::CreateTable(bool attemptDrop) pDb->Dbms() == dbmsMY_SQL || pDb->Dbms() == dbmsSYBASE_ASE || pDb->Dbms() == dbmsINTERBASE || + pDb->Dbms() == dbmsFIREBIRD || pDb->Dbms() == dbmsMS_SQL_SERVER) { if (colDefs[i].KeyField) @@ -1395,10 +1486,10 @@ bool wxDbTable::CreateTable(bool attemptDrop) } } - needComma = TRUE; + needComma = true; } // If there is a primary key defined, include it in the create statement - for (i = j = 0; i < noCols; i++) + for (i = j = 0; i < m_numCols; i++) { if (colDefs[i].KeyField) { @@ -1406,7 +1497,8 @@ bool wxDbTable::CreateTable(bool attemptDrop) break; } } - if (j && pDb->Dbms() != dbmsDBASE) // Found a keyfield + if ( j && (pDb->Dbms() != dbmsDBASE) + && (pDb->Dbms() != dbmsXBASE_SEQUITER) ) // Found a keyfield { switch (pDb->Dbms()) { @@ -1415,6 +1507,7 @@ bool wxDbTable::CreateTable(bool attemptDrop) case dbmsSYBASE_ASA: case dbmsSYBASE_ASE: case dbmsMY_SQL: + case dbmsFIREBIRD: { // MySQL goes out on this one. We also declare the relevant key NON NULL above sqlStmt += wxT(",PRIMARY KEY ("); @@ -1426,7 +1519,7 @@ bool wxDbTable::CreateTable(bool attemptDrop) // DB2 is limited to 18 characters for index names if (pDb->Dbms() == dbmsDB2) { - wxASSERT_MSG((tableName && wxStrlen(tableName) <= 13), wxT("DB2 table/index names must be no longer than 13 characters in length.\n\nTruncating table name to 13 characters.")); + wxASSERT_MSG(!tableName.empty() && tableName.length() <= 13, wxT("DB2 table/index names must be no longer than 13 characters in length.\n\nTruncating table name to 13 characters.")); sqlStmt += pDb->SQLTableName(tableName.substr(0, 13).c_str()); // sqlStmt += tableName.substr(0, 13); } @@ -1440,14 +1533,21 @@ bool wxDbTable::CreateTable(bool attemptDrop) } // List column name(s) of column(s) comprising the primary key - for (i = j = 0; i < noCols; i++) + for (i = j = 0; i < m_numCols; i++) { if (colDefs[i].KeyField) { if (j++) // Multi part key, comma separate names sqlStmt += wxT(","); sqlStmt += pDb->SQLColumnName(colDefs[i].ColName); -// sqlStmt += colDefs[i].ColName; + + if (pDb->Dbms() == dbmsMY_SQL && + colDefs[i].DbDataType == DB_DATA_TYPE_VARCHAR) + { + wxString s; + s.Printf(wxT("(%d)"), (int)(colDefs[i].SzDataObj / sizeof(wxChar))); + sqlStmt += s; + } } } sqlStmt += wxT(")"); @@ -1472,23 +1572,23 @@ bool wxDbTable::CreateTable(bool attemptDrop) #endif // Execute the CREATE TABLE statement - RETCODE retcode = SQLExecDirect(hstmt, (UCHAR FAR *) sqlStmt.c_str(), SQL_NTS); + RETCODE retcode = SQLExecDirect(hstmt, WXSQLCAST(sqlStmt), SQL_NTS); if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) { pDb->DispAllErrors(henv, hdbc, hstmt); pDb->RollbackTrans(); CloseCursor(hstmt); - return(FALSE); + return false; } // Commit the transaction and close the cursor if (!pDb->CommitTrans()) - return(FALSE); + return false; if (!CloseCursor(hstmt)) - return(FALSE); + return false; // Database table created successfully - return(TRUE); + return true; } // wxDbTable::CreateTable() @@ -1496,14 +1596,15 @@ bool wxDbTable::CreateTable(bool attemptDrop) /********** wxDbTable::DropTable() **********/ bool wxDbTable::DropTable() { - // NOTE: This function returns TRUE if the Table does not exist, but + // NOTE: This function returns true if the Table 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 wxString sqlStmt; - sqlStmt.Printf(wxT("DROP TABLE %s"), pDb->SQLTableName(tableName.c_str())); + sqlStmt.Printf(wxT("DROP TABLE %s"), + pDb->SQLTableName(tableName.c_str()).c_str()); pDb->WriteSqlLog(sqlStmt); @@ -1511,7 +1612,7 @@ bool wxDbTable::DropTable() cout << endl << sqlStmt.c_str() << endl; #endif - RETCODE retcode = SQLExecDirect(hstmt, (UCHAR FAR *) sqlStmt.c_str(), SQL_NTS); + RETCODE retcode = SQLExecDirect(hstmt, WXSQLCAST(sqlStmt), SQL_NTS); if (retcode != SQL_SUCCESS) { // Check for "Base table not found" error and ignore @@ -1529,30 +1630,30 @@ bool wxDbTable::DropTable() pDb->DispAllErrors(henv, hdbc, hstmt); pDb->RollbackTrans(); // CloseCursor(hstmt); - return(FALSE); + return false; } } } // Commit the transaction and close the cursor if (! pDb->CommitTrans()) - return(FALSE); + return false; if (! CloseCursor(hstmt)) - return(FALSE); + return false; - return(TRUE); + return true; } // wxDbTable::DropTable() /********** wxDbTable::CreateIndex() **********/ -bool wxDbTable::CreateIndex(const wxString &idxName, bool unique, UWORD noIdxCols, - wxDbIdxDef *pIdxDefs, bool attemptDrop) +bool wxDbTable::CreateIndex(const wxString &indexName, bool unique, UWORD numIndexColumns, + wxDbIdxDef *pIndexDefs, bool attemptDrop) { wxString sqlStmt; // Drop the index first - if (attemptDrop && !DropIndex(idxName)) - return (FALSE); + if (attemptDrop && !DropIndex(indexName)) + return false; // MySQL (and possibly Sybase ASE?? - gt) require that any columns which are used as portions // of an index have the columns defined as "NOT NULL". During initial table creation though, @@ -1566,47 +1667,50 @@ bool wxDbTable::CreateIndex(const wxString &idxName, bool unique, UWORD noIdxCol { wxString sqlStmt; int i; - bool ok = TRUE; - for (i = 0; i < noIdxCols && ok; i++) + bool ok = true; + for (i = 0; i < numIndexColumns && ok; i++) { int j = 0; - bool found = FALSE; + bool found = false; // Find the column definition that has the ColName that matches the // index column name. We need to do this to get the DB_DATA_TYPE of // the index column, as MySQL's syntax for the ALTER column requires // this information - while (!found && (j < this->noCols)) + while (!found && (j < this->m_numCols)) { - if (wxStrcmp(colDefs[j].ColName,pIdxDefs[i].ColName) == 0) - found = TRUE; + if (wxStrcmp(colDefs[j].ColName,pIndexDefs[i].ColName) == 0) + found = true; if (!found) j++; } if (found) { - ok = pDb->ModifyColumn(tableName, pIdxDefs[i].ColName, - colDefs[j].DbDataType, colDefs[j].SzDataObj, + ok = pDb->ModifyColumn(tableName, pIndexDefs[i].ColName, + colDefs[j].DbDataType, (int)(colDefs[j].SzDataObj / sizeof(wxChar)), wxT("NOT NULL")); if (!ok) { + #if 0 + // retcode is not used wxODBC_ERRORS retcode; // Oracle returns a DB_ERR_GENERAL_ERROR if the column is already // defined to be NOT NULL, but reportedly MySQL doesn't mind. // This line is just here for debug checking of the value retcode = (wxODBC_ERRORS)pDb->DB_STATUS; + #endif } } else - ok = FALSE; + ok = false; } if (ok) pDb->CommitTrans(); else { pDb->RollbackTrans(); - return(FALSE); + return false; } } @@ -1616,7 +1720,7 @@ bool wxDbTable::CreateIndex(const wxString &idxName, bool unique, UWORD noIdxCol sqlStmt += wxT("UNIQUE "); sqlStmt += wxT("INDEX "); - sqlStmt += pDb->SQLTableName(idxName); + sqlStmt += pDb->SQLTableName(indexName); sqlStmt += wxT(" ON "); sqlStmt += pDb->SQLTableName(tableName); @@ -1625,24 +1729,45 @@ bool wxDbTable::CreateIndex(const wxString &idxName, bool unique, UWORD noIdxCol // Append list of columns making up index int i; - for (i = 0; i < noIdxCols; i++) + for (i = 0; i < numIndexColumns; i++) { - sqlStmt += pDb->SQLColumnName(pIdxDefs[i].ColName); -// sqlStmt += pIdxDefs[i].ColName; + sqlStmt += pDb->SQLColumnName(pIndexDefs[i].ColName); +// sqlStmt += pIndexDefs[i].ColName; + + // MySQL requires a key length on VARCHAR keys + if ( pDb->Dbms() == dbmsMY_SQL ) + { + // Find the details on this column + int j; + for ( j = 0; j < m_numCols; ++j ) + { + if ( wxStrcmp( pIndexDefs[i].ColName, colDefs[j].ColName ) == 0 ) + { + break; + } + } + if ( colDefs[j].DbDataType == DB_DATA_TYPE_VARCHAR) + { + wxString s; + s.Printf(wxT("(%d)"), (int)(colDefs[i].SzDataObj / sizeof(wxChar))); + sqlStmt += s; + } + } // Postgres and SQL Server 7 do not support the ASC/DESC keywords for index columns - if (!((pDb->Dbms() == dbmsMS_SQL_SERVER) && (strncmp(pDb->dbInf.dbmsVer,"07",2)==0)) && + if (!((pDb->Dbms() == dbmsMS_SQL_SERVER) && (wxStrncmp(pDb->dbInf.dbmsVer,_T("07"),2)==0)) && + !(pDb->Dbms() == dbmsFIREBIRD) && !(pDb->Dbms() == dbmsPOSTGRES)) { - if (pIdxDefs[i].Ascending) + if (pIndexDefs[i].Ascending) sqlStmt += wxT(" ASC"); else sqlStmt += wxT(" DESC"); } else - wxASSERT_MSG(pIdxDefs[i].Ascending, "Datasource does not support DESCending index columns"); + wxASSERT_MSG(pIndexDefs[i].Ascending, _T("Datasource does not support DESCending index columns")); - if ((i + 1) < noIdxCols) + if ((i + 1) < numIndexColumns) sqlStmt += wxT(","); } @@ -1656,30 +1781,31 @@ bool wxDbTable::CreateIndex(const wxString &idxName, bool unique, UWORD noIdxCol #endif // Execute the CREATE INDEX statement - if (SQLExecDirect(hstmt, (UCHAR FAR *) sqlStmt.c_str(), SQL_NTS) != SQL_SUCCESS) + RETCODE retcode = SQLExecDirect(hstmt, WXSQLCAST(sqlStmt), SQL_NTS); + if (retcode != SQL_SUCCESS) { pDb->DispAllErrors(henv, hdbc, hstmt); pDb->RollbackTrans(); CloseCursor(hstmt); - return(FALSE); + return false; } // Commit the transaction and close the cursor if (! pDb->CommitTrans()) - return(FALSE); + return false; if (! CloseCursor(hstmt)) - return(FALSE); + return false; // Index Created Successfully - return(TRUE); + return true; } // wxDbTable::CreateIndex() /********** wxDbTable::DropIndex() **********/ -bool wxDbTable::DropIndex(const wxString &idxName) +bool wxDbTable::DropIndex(const wxString &indexName) { - // NOTE: This function returns TRUE if the Index does not exist, but + // NOTE: This function returns true if the Index 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 @@ -1688,20 +1814,26 @@ bool wxDbTable::DropIndex(const wxString &idxName) if (pDb->Dbms() == dbmsACCESS || pDb->Dbms() == dbmsMY_SQL || pDb->Dbms() == dbmsDBASE /*|| Paradox needs this syntax too when we add support*/) - sqlStmt.Printf(wxT("DROP INDEX %s ON %s"),pDb->SQLTableName(idxName.c_str()), pDb->SQLTableName(tableName.c_str())); + sqlStmt.Printf(wxT("DROP INDEX %s ON %s"), + pDb->SQLTableName(indexName.c_str()).c_str(), + pDb->SQLTableName(tableName.c_str()).c_str()); else if ((pDb->Dbms() == dbmsMS_SQL_SERVER) || - (pDb->Dbms() == dbmsSYBASE_ASE)) - sqlStmt.Printf(wxT("DROP INDEX %s.%s"), pDb->SQLTableName(tableName.c_str()), pDb->SQLTableName(idxName.c_str())); + (pDb->Dbms() == dbmsSYBASE_ASE) || + (pDb->Dbms() == dbmsXBASE_SEQUITER)) + sqlStmt.Printf(wxT("DROP INDEX %s.%s"), + pDb->SQLTableName(tableName.c_str()).c_str(), + pDb->SQLTableName(indexName.c_str()).c_str()); else - sqlStmt.Printf(wxT("DROP INDEX %s"),pDb->SQLTableName(idxName.c_str())); + sqlStmt.Printf(wxT("DROP INDEX %s"), + pDb->SQLTableName(indexName.c_str()).c_str()); pDb->WriteSqlLog(sqlStmt); #ifdef DBDEBUG_CONSOLE cout << endl << sqlStmt.c_str() << endl; #endif - - if (SQLExecDirect(hstmt, (UCHAR FAR *) sqlStmt.c_str(), SQL_NTS) != SQL_SUCCESS) + RETCODE retcode = SQLExecDirect(hstmt, WXSQLCAST(sqlStmt), SQL_NTS); + if (retcode != SQL_SUCCESS) { // Check for "Index not found" error and ignore pDb->GetNextError(henv, hdbc, hstmt); @@ -1711,7 +1843,9 @@ bool wxDbTable::DropIndex(const wxString &idxName) if (!((pDb->Dbms() == dbmsSYBASE_ASA && !wxStrcmp(pDb->sqlState,wxT("42000"))) || // v5.x (and lower?) (pDb->Dbms() == dbmsSYBASE_ASE && !wxStrcmp(pDb->sqlState,wxT("37000"))) || (pDb->Dbms() == dbmsMS_SQL_SERVER && !wxStrcmp(pDb->sqlState,wxT("S1000"))) || - (pDb->Dbms() == dbmsINTERBASE && !wxStrcmp(pDb->sqlState,wxT("S1000"))) || + (pDb->Dbms() == dbmsINTERBASE && !wxStrcmp(pDb->sqlState,wxT("S1000"))) || + (pDb->Dbms() == dbmsMAXDB && !wxStrcmp(pDb->sqlState,wxT("S1000"))) || + (pDb->Dbms() == dbmsFIREBIRD && !wxStrcmp(pDb->sqlState,wxT("HY000"))) || (pDb->Dbms() == dbmsSYBASE_ASE && !wxStrcmp(pDb->sqlState,wxT("S0002"))) || // Base table not found (pDb->Dbms() == dbmsMY_SQL && !wxStrcmp(pDb->sqlState,wxT("42S12"))) || // tested by Christopher Ludwik Marino-Cebulski using v3.23.21beta (pDb->Dbms() == dbmsPOSTGRES && !wxStrcmp(pDb->sqlState,wxT("08S01"))) @@ -1721,48 +1855,48 @@ bool wxDbTable::DropIndex(const wxString &idxName) pDb->DispAllErrors(henv, hdbc, hstmt); pDb->RollbackTrans(); CloseCursor(hstmt); - return(FALSE); + return false; } } } // Commit the transaction and close the cursor if (! pDb->CommitTrans()) - return(FALSE); + return false; if (! CloseCursor(hstmt)) - return(FALSE); + return false; - return(TRUE); + return true; } // wxDbTable::DropIndex() /********** wxDbTable::SetOrderByColNums() **********/ bool wxDbTable::SetOrderByColNums(UWORD first, ... ) { - int colNo = first; // using 'int' to be able to look for wxDB_NO_MORE_COLUN_NUMBERS + int colNumber = first; // using 'int' to be able to look for wxDB_NO_MORE_COLUN_NUMBERS va_list argptr; - bool abort = FALSE; + bool abort = false; wxString tempStr; va_start(argptr, first); /* Initialize variable arguments. */ - while (!abort && (colNo != wxDB_NO_MORE_COLUMN_NUMBERS)) + while (!abort && (colNumber != wxDB_NO_MORE_COLUMN_NUMBERS)) { // Make sure the passed in column number // is within the valid range of columns // - // Valid columns are 0 thru noCols-1 - if (colNo >= noCols || colNo < 0) + // Valid columns are 0 thru m_numCols-1 + if (colNumber >= m_numCols || colNumber < 0) { - abort = TRUE; + abort = true; continue; } - if (colNo != first) + if (colNumber != first) tempStr += wxT(","); - tempStr += colDefs[colNo].ColName; - colNo = va_arg (argptr, int); + tempStr += colDefs[colNumber].ColName; + colNumber = va_arg (argptr, int); } va_end (argptr); /* Reset variable arguments. */ @@ -1783,8 +1917,9 @@ int wxDbTable::Insert(void) // Insert the record by executing the already prepared insert statement RETCODE retcode; - retcode=SQLExecute(hstmtInsert); - if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) + retcode = SQLExecute(hstmtInsert); + if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO && + retcode != SQL_NEED_DATA) { // Check to see if integrity constraint was violated pDb->GetNextError(henv, hdbc, hstmtInsert); @@ -1797,6 +1932,40 @@ int wxDbTable::Insert(void) return(DB_FAILURE); } } + if (retcode == SQL_NEED_DATA) + { + PTR pParmID; + retcode = SQLParamData(hstmtInsert, &pParmID); + while (retcode == SQL_NEED_DATA) + { + // Find the parameter + int i; + for (i=0; i < m_numCols; i++) + { + if (colDefs[i].PtrDataObj == pParmID) + { + // We found it. Store the parameter. + retcode = SQLPutData(hstmtInsert, pParmID, colDefs[i].SzDataObj); + if (retcode != SQL_SUCCESS) + { + pDb->DispNextError(); + pDb->DispAllErrors(henv, hdbc, hstmtInsert); + return(DB_FAILURE); + } + break; + } + } + retcode = SQLParamData(hstmtInsert, &pParmID); + if (retcode != SQL_SUCCESS && + retcode != SQL_SUCCESS_WITH_INFO) + { + // record was not inserted + pDb->DispNextError(); + pDb->DispAllErrors(henv, hdbc, hstmtInsert); + return(DB_FAILURE); + } + } + } // Record inserted into the datasource successfully return(DB_SUCCESS); @@ -1809,7 +1978,7 @@ bool wxDbTable::Update(void) { wxASSERT(!queryOnly); if (queryOnly) - return(FALSE); + return false; wxString sqlStmt; @@ -1833,7 +2002,7 @@ bool wxDbTable::Update(const wxString &pSqlStmt) { wxASSERT(!queryOnly); if (queryOnly) - return(FALSE); + return false; pDb->WriteSqlLog(pSqlStmt); @@ -1847,7 +2016,7 @@ bool wxDbTable::UpdateWhere(const wxString &pWhereClause) { wxASSERT(!queryOnly); if (queryOnly) - return(FALSE); + return false; wxString sqlStmt; @@ -1871,7 +2040,7 @@ bool wxDbTable::Delete(void) { wxASSERT(!queryOnly); if (queryOnly) - return(FALSE); + return false; wxString sqlStmt; sqlStmt.Empty(); @@ -1892,7 +2061,7 @@ bool wxDbTable::DeleteWhere(const wxString &pWhereClause) { wxASSERT(!queryOnly); if (queryOnly) - return(FALSE); + return false; wxString sqlStmt; sqlStmt.Empty(); @@ -1913,7 +2082,7 @@ bool wxDbTable::DeleteMatching(void) { wxASSERT(!queryOnly); if (queryOnly) - return(FALSE); + return false; wxString sqlStmt; sqlStmt.Empty(); @@ -1930,40 +2099,42 @@ bool wxDbTable::DeleteMatching(void) /********** wxDbTable::IsColNull() **********/ -bool wxDbTable::IsColNull(UWORD colNo) const +bool wxDbTable::IsColNull(UWORD colNumber) const { /* - This logic is just not right. It would indicate TRUE + This logic is just not right. It would indicate true if a numeric field were set to a value of 0. - switch(colDefs[colNo].SqlCtype) + switch(colDefs[colNumber].SqlCtype) { case SQL_C_CHAR: - return(((UCHAR FAR *) colDefs[colNo].PtrDataObj)[0] == 0); + case SQL_C_WCHAR: + //case SQL_C_WXCHAR: SQL_C_WXCHAR is covered by either SQL_C_CHAR or SQL_C_WCHAR + return(((UCHAR FAR *) colDefs[colNumber].PtrDataObj)[0] == 0); case SQL_C_SSHORT: - return(( *((SWORD *) colDefs[colNo].PtrDataObj)) == 0); + return(( *((SWORD *) colDefs[colNumber].PtrDataObj)) == 0); case SQL_C_USHORT: - return(( *((UWORD*) colDefs[colNo].PtrDataObj)) == 0); + return(( *((UWORD*) colDefs[colNumber].PtrDataObj)) == 0); case SQL_C_SLONG: - return(( *((SDWORD *) colDefs[colNo].PtrDataObj)) == 0); + return(( *((SDWORD *) colDefs[colNumber].PtrDataObj)) == 0); case SQL_C_ULONG: - return(( *((UDWORD *) colDefs[colNo].PtrDataObj)) == 0); + return(( *((UDWORD *) colDefs[colNumber].PtrDataObj)) == 0); case SQL_C_FLOAT: - return(( *((SFLOAT *) colDefs[colNo].PtrDataObj)) == 0); + return(( *((SFLOAT *) colDefs[colNumber].PtrDataObj)) == 0); case SQL_C_DOUBLE: - return((*((SDOUBLE *) colDefs[colNo].PtrDataObj)) == 0); + return((*((SDOUBLE *) colDefs[colNumber].PtrDataObj)) == 0); case SQL_C_TIMESTAMP: TIMESTAMP_STRUCT *pDt; - pDt = (TIMESTAMP_STRUCT *) colDefs[colNo].PtrDataObj; + pDt = (TIMESTAMP_STRUCT *) colDefs[colNumber].PtrDataObj; if (pDt->year == 0 && pDt->month == 0 && pDt->day == 0) - return(TRUE); + return true; else - return(FALSE); + return false; default: - return(TRUE); + return true; } */ - return (colDefs[colNo].Null); + return (colDefs[colNumber].Null); } // wxDbTable::IsColNull() @@ -1971,80 +2142,85 @@ bool wxDbTable::IsColNull(UWORD colNo) const bool wxDbTable::CanSelectForUpdate(void) { if (queryOnly) - return FALSE; + return false; if (pDb->Dbms() == dbmsMY_SQL) - return FALSE; + return false; if ((pDb->Dbms() == dbmsORACLE) || (pDb->dbInf.posStmts & SQL_PS_SELECT_FOR_UPDATE)) - return(TRUE); + return true; else - return(FALSE); + return false; } // wxDbTable::CanSelectForUpdate() -/********** wxDbTable::CanUpdByROWID() **********/ -bool wxDbTable::CanUpdByROWID(void) +/********** wxDbTable::CanUpdateByROWID() **********/ +bool wxDbTable::CanUpdateByROWID(void) { /* - * NOTE: Returning FALSE for now until this can be debugged, + * NOTE: Returning false for now until this can be debugged, * as the ROWID is not getting updated correctly */ - return FALSE; + return false; /* if (pDb->Dbms() == dbmsORACLE) - return(TRUE); + return true; else - return(FALSE); + return false; */ -} // wxDbTable::CanUpdByROWID() +} // wxDbTable::CanUpdateByROWID() /********** wxDbTable::IsCursorClosedOnCommit() **********/ bool wxDbTable::IsCursorClosedOnCommit(void) { if (pDb->dbInf.cursorCommitBehavior == SQL_CB_PRESERVE) - return(FALSE); + return false; else - return(TRUE); + return true; } // wxDbTable::IsCursorClosedOnCommit() /********** wxDbTable::ClearMemberVar() **********/ -void wxDbTable::ClearMemberVar(UWORD colNo, bool setToNull) +void wxDbTable::ClearMemberVar(UWORD colNumber, bool setToNull) { - wxASSERT(colNo < noCols); + wxASSERT(colNumber < m_numCols); - switch(colDefs[colNo].SqlCtype) + switch(colDefs[colNumber].SqlCtype) { case SQL_C_CHAR: - ((UCHAR FAR *) colDefs[colNo].PtrDataObj)[0] = 0; +#ifdef SQL_C_WCHAR + case SQL_C_WCHAR: +#endif + //case SQL_C_WXCHAR: SQL_C_WXCHAR is covered by either SQL_C_CHAR or SQL_C_WCHAR + ((UCHAR FAR *) colDefs[colNumber].PtrDataObj)[0] = 0; break; case SQL_C_SSHORT: - *((SWORD *) colDefs[colNo].PtrDataObj) = 0; + *((SWORD *) colDefs[colNumber].PtrDataObj) = 0; break; case SQL_C_USHORT: - *((UWORD*) colDefs[colNo].PtrDataObj) = 0; + *((UWORD*) colDefs[colNumber].PtrDataObj) = 0; break; + case SQL_C_LONG: case SQL_C_SLONG: - *((SDWORD *) colDefs[colNo].PtrDataObj) = 0; + *((SDWORD *) colDefs[colNumber].PtrDataObj) = 0; break; case SQL_C_ULONG: - *((UDWORD *) colDefs[colNo].PtrDataObj) = 0; + *((UDWORD *) colDefs[colNumber].PtrDataObj) = 0; break; case SQL_C_FLOAT: - *((SFLOAT *) colDefs[colNo].PtrDataObj) = 0.0f; + *((SFLOAT *) colDefs[colNumber].PtrDataObj) = 0.0f; break; case SQL_C_DOUBLE: - *((SDOUBLE *) colDefs[colNo].PtrDataObj) = 0.0f; + *((SDOUBLE *) colDefs[colNumber].PtrDataObj) = 0.0f; break; case SQL_C_TIMESTAMP: TIMESTAMP_STRUCT *pDt; - pDt = (TIMESTAMP_STRUCT *) colDefs[colNo].PtrDataObj; + pDt = (TIMESTAMP_STRUCT *) colDefs[colNumber].PtrDataObj; pDt->year = 0; pDt->month = 0; pDt->day = 0; @@ -2053,10 +2229,24 @@ void wxDbTable::ClearMemberVar(UWORD colNo, bool setToNull) pDt->second = 0; pDt->fraction = 0; break; + case SQL_C_DATE: + DATE_STRUCT *pDtd; + pDtd = (DATE_STRUCT *) colDefs[colNumber].PtrDataObj; + pDtd->year = 0; + pDtd->month = 0; + pDtd->day = 0; + break; + case SQL_C_TIME: + TIME_STRUCT *pDtt; + pDtt = (TIME_STRUCT *) colDefs[colNumber].PtrDataObj; + pDtt->hour = 0; + pDtt->minute = 0; + pDtt->second = 0; + break; } if (setToNull) - SetColNull(colNo); + SetColNull(colNumber); } // wxDbTable::ClearMemberVar() @@ -2066,8 +2256,8 @@ void wxDbTable::ClearMemberVars(bool setToNull) int i; // Loop through the columns setting each member variable to zero - for (i=0; i < noCols; i++) - ClearMemberVar(i,setToNull); + for (i=0; i < m_numCols; i++) + ClearMemberVar((UWORD)i,setToNull); } // wxDbTable::ClearMemberVars() @@ -2085,30 +2275,38 @@ bool wxDbTable::SetQueryTimeout(UDWORD nSeconds) return(pDb->DispAllErrors(henv, hdbc, hstmtInternal)); // Completed Successfully - return(TRUE); + return true; } // wxDbTable::SetQueryTimeout() /********** wxDbTable::SetColDefs() **********/ -void wxDbTable::SetColDefs(UWORD index, const wxString &fieldName, int dataType, void *pData, - SWORD cType, int size, bool keyField, bool upd, - bool insAllow, bool derivedCol) +bool wxDbTable::SetColDefs(UWORD index, const wxString &fieldName, int dataType, void *pData, + SWORD cType, int size, bool keyField, bool updateable, + bool insertAllowed, bool derivedColumn) { + wxString tmpStr; + + if (index >= m_numCols) // Columns numbers are zero based.... + { + tmpStr.Printf(wxT("Specified column index (%d) exceeds the maximum number of columns (%d) registered for this table definition. Column definition not added."), index, m_numCols); + wxFAIL_MSG(tmpStr); + wxLogDebug(tmpStr); + return false; + } + if (!colDefs) // May happen if the database connection fails - return; + return false; - if (fieldName.Length() > (unsigned int) DB_MAX_COLUMN_NAME_LEN) + if (fieldName.length() > (unsigned int) DB_MAX_COLUMN_NAME_LEN) { wxStrncpy(colDefs[index].ColName, fieldName, DB_MAX_COLUMN_NAME_LEN); - colDefs[index].ColName[DB_MAX_COLUMN_NAME_LEN] = 0; + colDefs[index].ColName[DB_MAX_COLUMN_NAME_LEN] = 0; // Prevent buffer overrun -#ifdef __WXDEBUG__ - wxString tmpMsg; - tmpMsg.Printf(_T("Column name '%s' is too long. Truncated to '%s'."), + tmpStr.Printf(wxT("Column name '%s' is too long. Truncated to '%s'."), fieldName.c_str(),colDefs[index].ColName); - wxFAIL_MSG(tmpMsg); -#endif // __WXDEBUG__ + wxFAIL_MSG(tmpStr); + wxLogDebug(tmpStr); } else wxStrcpy(colDefs[index].ColName, fieldName); @@ -2116,22 +2314,24 @@ void wxDbTable::SetColDefs(UWORD index, const wxString &fieldName, int dataType, colDefs[index].DbDataType = dataType; colDefs[index].PtrDataObj = pData; colDefs[index].SqlCtype = cType; - colDefs[index].SzDataObj = size; + colDefs[index].SzDataObj = size; //TODO: glt ??? * sizeof(wxChar) ??? colDefs[index].KeyField = keyField; - colDefs[index].DerivedCol = derivedCol; + colDefs[index].DerivedCol = derivedColumn; // Derived columns by definition would NOT be "Insertable" or "Updateable" - if (derivedCol) + if (derivedColumn) { - colDefs[index].Updateable = FALSE; - colDefs[index].InsertAllowed = FALSE; + colDefs[index].Updateable = false; + colDefs[index].InsertAllowed = false; } else { - colDefs[index].Updateable = upd; - colDefs[index].InsertAllowed = insAllow; + colDefs[index].Updateable = updateable; + colDefs[index].InsertAllowed = insertAllowed; } - colDefs[index].Null = FALSE; + colDefs[index].Null = false; + + return true; } // wxDbTable::SetColDefs() @@ -2154,13 +2354,18 @@ wxDbColDataPtr* wxDbTable::SetColDefs(wxDbColInf *pColInfs, UWORD numCols) switch (pColInfs[index].dbDataType) { case DB_DATA_TYPE_VARCHAR: - pColDataPtrs[index].PtrDataObj = new wxChar[pColInfs[index].bufferLength+1]; - pColDataPtrs[index].SzDataObj = pColInfs[index].columnSize; - pColDataPtrs[index].SqlCtype = SQL_C_CHAR; + pColDataPtrs[index].PtrDataObj = new wxChar[pColInfs[index].bufferSize+(1*sizeof(wxChar))]; + pColDataPtrs[index].SzDataObj = pColInfs[index].bufferSize+(1*sizeof(wxChar)); + pColDataPtrs[index].SqlCtype = SQL_C_WXCHAR; + break; + case DB_DATA_TYPE_MEMO: + pColDataPtrs[index].PtrDataObj = new wxChar[pColInfs[index].bufferSize+(1*sizeof(wxChar))]; + pColDataPtrs[index].SzDataObj = pColInfs[index].bufferSize+(1*sizeof(wxChar)); + pColDataPtrs[index].SqlCtype = SQL_C_WXCHAR; break; case DB_DATA_TYPE_INTEGER: // Can be long or short - if (pColInfs[index].bufferLength == sizeof(long)) + if (pColInfs[index].bufferSize == sizeof(long)) { pColDataPtrs[index].PtrDataObj = new long; pColDataPtrs[index].SzDataObj = sizeof(long); @@ -2175,7 +2380,7 @@ wxDbColDataPtr* wxDbTable::SetColDefs(wxDbColInf *pColInfs, UWORD numCols) break; case DB_DATA_TYPE_FLOAT: // Can be float or double - if (pColInfs[index].bufferLength == sizeof(float)) + if (pColInfs[index].bufferSize == sizeof(float)) { pColDataPtrs[index].PtrDataObj = new float; pColDataPtrs[index].SzDataObj = sizeof(float); @@ -2236,7 +2441,7 @@ ULONG wxDbTable::Count(const wxString &args) { ULONG count; wxString sqlStmt; - SDWORD cb; + SQLLEN cb; // Build a "SELECT COUNT(*) FROM queryTableName [WHERE whereClause]" SQL Statement sqlStmt = wxT("SELECT COUNT("); @@ -2247,7 +2452,7 @@ ULONG wxDbTable::Count(const wxString &args) #if wxODBC_BACKWARD_COMPATABILITY if (from && wxStrlen(from)) #else - if (from.Length()) + if (from.length()) #endif sqlStmt += from; @@ -2255,7 +2460,7 @@ ULONG wxDbTable::Count(const wxString &args) #if wxODBC_BACKWARD_COMPATABILITY if (where && wxStrlen(where)) #else - if (where.Length()) + if (where.length()) #endif { sqlStmt += wxT(" WHERE "); @@ -2267,14 +2472,14 @@ ULONG wxDbTable::Count(const wxString &args) // Initialize the Count cursor if it's not already initialized if (!hstmtCount) { - hstmtCount = GetNewCursor(FALSE,FALSE); + hstmtCount = GetNewCursor(false,false); wxASSERT(hstmtCount); if (!hstmtCount) return(0); } // Execute the SQL statement - if (SQLExecDirect(*hstmtCount, (UCHAR FAR *) sqlStmt.c_str(), SQL_NTS) != SQL_SUCCESS) + if (SQLExecDirect(*hstmtCount, WXSQLCAST(sqlStmt), SQL_NTS) != SQL_SUCCESS) { pDb->DispAllErrors(henv, hdbc, *hstmtCount); return(0); @@ -2307,15 +2512,15 @@ ULONG wxDbTable::Count(const wxString &args) /********** wxDbTable::Refresh() **********/ bool wxDbTable::Refresh(void) { - bool result = TRUE; + bool result = true; // Switch to the internal cursor so any active cursors are not corrupted HSTMT currCursor = GetCursor(); hstmt = hstmtInternal; #if wxODBC_BACKWARD_COMPATABILITY // Save the where and order by clauses - char *saveWhere = where; - char *saveOrderBy = orderBy; + wxChar *saveWhere = where; + wxChar *saveOrderBy = orderBy; #else wxString saveWhere = where; wxString saveOrderBy = orderBy; @@ -2325,15 +2530,15 @@ bool wxDbTable::Refresh(void) wxString whereClause; whereClause.Empty(); - if (CanUpdByROWID()) + if (CanUpdateByROWID()) { - SDWORD cb; - wxChar rowid[wxDB_ROWID_LEN+1]; + SQLLEN cb; + wxChar rowid[wxDB_ROWID_LEN+1]; // Get the ROWID value. If not successful retreiving the ROWID, // simply fall down through the code and build the WHERE clause // based on the key fields. - if (SQLGetData(hstmt, (UWORD)(noCols+1), SQL_C_CHAR, (UCHAR*) rowid, wxDB_ROWID_LEN, &cb) == SQL_SUCCESS) + if (SQLGetData(hstmt, (UWORD)(m_numCols+1), SQL_C_WXCHAR, (UCHAR*) rowid, sizeof(rowid), &cb) == SQL_SUCCESS) { whereClause += pDb->SQLTableName(queryTableName); // whereClause += queryTableName; @@ -2351,10 +2556,10 @@ bool wxDbTable::Refresh(void) where = whereClause; orderBy.Empty(); if (!Query()) - result = FALSE; + result = false; if (result && !GetNext()) - result = FALSE; + result = false; // Switch back to original cursor SetCursor(&currCursor); @@ -2373,17 +2578,20 @@ bool wxDbTable::Refresh(void) /********** wxDbTable::SetColNull() **********/ -bool wxDbTable::SetColNull(UWORD colNo, bool set) +bool wxDbTable::SetColNull(UWORD colNumber, bool set) { - if (colNo < noCols) + if (colNumber < m_numCols) { - colDefs[colNo].Null = set; + colDefs[colNumber].Null = set; if (set) // Blank out the values in the member variable - ClearMemberVar(colNo,FALSE); // Must call with FALSE, or infinite recursion will happen - return(TRUE); + ClearMemberVar(colNumber, false); // Must call with false here, or infinite recursion will happen + + setCbValueForColumn(colNumber); + + return true; } else - return(FALSE); + return false; } // wxDbTable::SetColNull() @@ -2391,22 +2599,25 @@ bool wxDbTable::SetColNull(UWORD colNo, bool set) /********** wxDbTable::SetColNull() **********/ bool wxDbTable::SetColNull(const wxString &colName, bool set) { - int i; - for (i = 0; i < noCols; i++) + int colNumber; + for (colNumber = 0; colNumber < m_numCols; colNumber++) { - if (!wxStricmp(colName, colDefs[i].ColName)) + if (!wxStricmp(colName, colDefs[colNumber].ColName)) break; } - if (i < noCols) + if (colNumber < m_numCols) { - colDefs[i].Null = set; + colDefs[colNumber].Null = set; if (set) // Blank out the values in the member variable - ClearMemberVar(i,FALSE); // Must call with FALSE, or infinite recursion will happen - return(TRUE); + ClearMemberVar((UWORD)colNumber,false); // Must call with false here, or infinite recursion will happen + + setCbValueForColumn(colNumber); + + return true; } else - return(FALSE); + return false; } // wxDbTable::SetColNull() @@ -2453,7 +2664,7 @@ HSTMT *wxDbTable::GetNewCursor(bool setCursor, bool bindColumns) /********** wxDbTable::DeleteCursor() **********/ bool wxDbTable::DeleteCursor(HSTMT *hstmtDel) { - bool result = TRUE; + bool result = true; if (!hstmtDel) // Cursor already deleted return(result); @@ -2466,7 +2677,7 @@ ODBC 3.0 says to use this form if (SQLFreeStmt(*hstmtDel, SQL_DROP) != SQL_SUCCESS) { pDb->DispAllErrors(henv, hdbc); - result = FALSE; + result = false; } delete hstmtDel; @@ -2483,7 +2694,7 @@ void wxDbTable::SetRowMode(const rowmode_t rowmode) { if (!m_hstmtGridQuery) { - m_hstmtGridQuery = GetNewCursor(FALSE,FALSE); + m_hstmtGridQuery = GetNewCursor(false,false); if (!bindCols(*m_hstmtGridQuery)) return; } @@ -2498,53 +2709,61 @@ void wxDbTable::SetRowMode(const rowmode_t rowmode) SetCursor(hstmtDefault); break; default: - assert(0); + wxASSERT(0); } } // wxDbTable::SetRowMode() -wxVariant wxDbTable::GetCol(const int colNo) const +wxVariant wxDbTable::GetColumn(const int colNumber) const { wxVariant val; - if ((colNo < noCols) && (!IsColNull(colNo))) + if ((colNumber < m_numCols) && (!IsColNull((UWORD)colNumber))) { - switch (colDefs[colNo].SqlCtype) + switch (colDefs[colNumber].SqlCtype) { +#if wxUSE_UNICODE + #if defined(SQL_WCHAR) + case SQL_WCHAR: + #endif + #if defined(SQL_WVARCHAR) + case SQL_WVARCHAR: + #endif +#endif case SQL_CHAR: case SQL_VARCHAR: - val = (wxChar *)(colDefs[colNo].PtrDataObj); + val = (wxChar *)(colDefs[colNumber].PtrDataObj); break; case SQL_C_LONG: case SQL_C_SLONG: - val = *(long *)(colDefs[colNo].PtrDataObj); + val = *(long *)(colDefs[colNumber].PtrDataObj); break; case SQL_C_SHORT: case SQL_C_SSHORT: - val = (long int )(*(short *)(colDefs[colNo].PtrDataObj)); + val = (long int )(*(short *)(colDefs[colNumber].PtrDataObj)); break; case SQL_C_ULONG: - val = (long)(*(unsigned long *)(colDefs[colNo].PtrDataObj)); + val = (long)(*(unsigned long *)(colDefs[colNumber].PtrDataObj)); break; case SQL_C_TINYINT: - val = (long)(*(char *)(colDefs[colNo].PtrDataObj)); + val = (long)(*(wxChar *)(colDefs[colNumber].PtrDataObj)); break; case SQL_C_UTINYINT: - val = (long)(*(unsigned char *)(colDefs[colNo].PtrDataObj)); + val = (long)(*(wxChar *)(colDefs[colNumber].PtrDataObj)); break; case SQL_C_USHORT: - val = (long)(*(UWORD *)(colDefs[colNo].PtrDataObj)); + val = (long)(*(UWORD *)(colDefs[colNumber].PtrDataObj)); break; case SQL_C_DATE: - val = (DATE_STRUCT *)(colDefs[colNo].PtrDataObj); + val = (DATE_STRUCT *)(colDefs[colNumber].PtrDataObj); break; case SQL_C_TIME: - val = (TIME_STRUCT *)(colDefs[colNo].PtrDataObj); + val = (TIME_STRUCT *)(colDefs[colNumber].PtrDataObj); break; case SQL_C_TIMESTAMP: - val = (TIMESTAMP_STRUCT *)(colDefs[colNo].PtrDataObj); + val = (TIMESTAMP_STRUCT *)(colDefs[colNumber].PtrDataObj); break; case SQL_C_DOUBLE: - val = *(double *)(colDefs[colNo].PtrDataObj); + val = *(double *)(colDefs[colNumber].PtrDataObj); break; default: assert(0); @@ -2554,75 +2773,75 @@ wxVariant wxDbTable::GetCol(const int colNo) const } // wxDbTable::GetCol() -void csstrncpyt(char *s, const char *t, int n) -{ - while ((*s++ = *t++) && --n) - {}; - - *s = '\0'; -} - -void wxDbTable::SetCol(const int colNo, const wxVariant val) +void wxDbTable::SetColumn(const int colNumber, const wxVariant val) { //FIXME: Add proper wxDateTime support to wxVariant.. wxDateTime dateval; - SetColNull(colNo, val.IsNull()); + SetColNull((UWORD)colNumber, val.IsNull()); if (!val.IsNull()) { - if ((colDefs[colNo].SqlCtype == SQL_C_DATE) - || (colDefs[colNo].SqlCtype == SQL_C_TIME) - || (colDefs[colNo].SqlCtype == SQL_C_TIMESTAMP)) + if ((colDefs[colNumber].SqlCtype == SQL_C_DATE) + || (colDefs[colNumber].SqlCtype == SQL_C_TIME) + || (colDefs[colNumber].SqlCtype == SQL_C_TIMESTAMP)) { //Returns null if invalid! if (!dateval.ParseDate(val.GetString())) - SetColNull(colNo, TRUE); + SetColNull((UWORD)colNumber, true); } - switch (colDefs[colNo].SqlCtype) + switch (colDefs[colNumber].SqlCtype) { +#if wxUSE_UNICODE + #if defined(SQL_WCHAR) + case SQL_WCHAR: + #endif + #if defined(SQL_WVARCHAR) + case SQL_WVARCHAR: + #endif +#endif case SQL_CHAR: case SQL_VARCHAR: - csstrncpyt((char *)(colDefs[colNo].PtrDataObj), + csstrncpyt((wxChar *)(colDefs[colNumber].PtrDataObj), val.GetString().c_str(), - colDefs[colNo].SzDataObj-1); + colDefs[colNumber].SzDataObj-1); //TODO: glt ??? * sizeof(wxChar) ??? break; case SQL_C_LONG: case SQL_C_SLONG: - *(long *)(colDefs[colNo].PtrDataObj) = val; + *(long *)(colDefs[colNumber].PtrDataObj) = val; break; case SQL_C_SHORT: case SQL_C_SSHORT: - *(short *)(colDefs[colNo].PtrDataObj) = val.GetLong(); + *(short *)(colDefs[colNumber].PtrDataObj) = (short)val.GetLong(); break; case SQL_C_ULONG: - *(unsigned long *)(colDefs[colNo].PtrDataObj) = val.GetLong(); + *(unsigned long *)(colDefs[colNumber].PtrDataObj) = val.GetLong(); break; case SQL_C_TINYINT: - *(char *)(colDefs[colNo].PtrDataObj) = val.GetChar(); + *(wxChar *)(colDefs[colNumber].PtrDataObj) = val.GetChar(); break; case SQL_C_UTINYINT: - *(unsigned char *)(colDefs[colNo].PtrDataObj) = val.GetChar(); + *(wxChar *)(colDefs[colNumber].PtrDataObj) = val.GetChar(); break; case SQL_C_USHORT: - *(unsigned short *)(colDefs[colNo].PtrDataObj) = val.GetLong(); + *(unsigned short *)(colDefs[colNumber].PtrDataObj) = (unsigned short)val.GetLong(); break; //FIXME: Add proper wxDateTime support to wxVariant.. case SQL_C_DATE: { DATE_STRUCT *dataptr = - (DATE_STRUCT *)colDefs[colNo].PtrDataObj; + (DATE_STRUCT *)colDefs[colNumber].PtrDataObj; - dataptr->year = dateval.GetYear(); - dataptr->month = dateval.GetMonth()+1; - dataptr->day = dateval.GetDay(); + dataptr->year = (SWORD)dateval.GetYear(); + dataptr->month = (UWORD)(dateval.GetMonth()+1); + dataptr->day = (UWORD)dateval.GetDay(); } break; case SQL_C_TIME: { TIME_STRUCT *dataptr = - (TIME_STRUCT *)colDefs[colNo].PtrDataObj; + (TIME_STRUCT *)colDefs[colNumber].PtrDataObj; dataptr->hour = dateval.GetHour(); dataptr->minute = dateval.GetMinute(); @@ -2632,10 +2851,10 @@ void wxDbTable::SetCol(const int colNo, const wxVariant val) case SQL_C_TIMESTAMP: { TIMESTAMP_STRUCT *dataptr = - (TIMESTAMP_STRUCT *)colDefs[colNo].PtrDataObj; - dataptr->year = dateval.GetYear(); - dataptr->month = dateval.GetMonth()+1; - dataptr->day = dateval.GetDay(); + (TIMESTAMP_STRUCT *)colDefs[colNumber].PtrDataObj; + dataptr->year = (SWORD)dateval.GetYear(); + dataptr->month = (UWORD)(dateval.GetMonth()+1); + dataptr->day = (UWORD)dateval.GetDay(); dataptr->hour = dateval.GetHour(); dataptr->minute = dateval.GetMinute(); @@ -2643,7 +2862,7 @@ void wxDbTable::SetCol(const int colNo, const wxVariant val) } break; case SQL_C_DOUBLE: - *(double *)(colDefs[colNo].PtrDataObj) = val; + *(double *)(colDefs[colNumber].PtrDataObj) = val; break; default: assert(0); @@ -2661,7 +2880,7 @@ GenericKey wxDbTable::GetKey() blkptr = (wxChar *) blk; int i; - for (i=0; i < noCols; i++) + for (i=0; i < m_numCols; i++) { if (colDefs[i].KeyField) { @@ -2686,11 +2905,11 @@ void wxDbTable::SetKey(const GenericKey& k) blkptr = (wxChar *)blk; int i; - for (i=0; i < noCols; i++) + for (i=0; i < m_numCols; i++) { if (colDefs[i].KeyField) { - SetColNull(i, FALSE); + SetColNull((UWORD)i, false); memcpy(colDefs[i].PtrDataObj, blkptr, colDefs[i].SzDataObj); blkptr += colDefs[i].SzDataObj; } @@ -2699,4 +2918,3 @@ void wxDbTable::SetKey(const GenericKey& k) #endif // wxUSE_ODBC -