X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/1454d4e6599bbd18086cdf0cf1b06c2b9004fe3a..ed7c11abc829a8f7becc92ee438866e36f2216fe:/src/common/dbtable.cpp diff --git a/src/common/dbtable.cpp b/src/common/dbtable.cpp index 107779f0b9..e56bedcc25 100644 --- a/src/common/dbtable.cpp +++ b/src/common/dbtable.cpp @@ -8,16 +8,7 @@ // 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 /////////////////////////////////////////////////////////////////////////////// /* @@ -25,63 +16,41 @@ // SYNOPSIS STOP */ -// Use this line for wxWindows v1.x -//#include "wx_ver.h" -// Use this line for wxWindows v2.x +#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) + #pragma implementation "dbtable.h" +#endif + #include "wx/wxprec.h" -#include "wx/version.h" -#if wxMAJOR_VERSION == 2 - #ifdef __GNUG__ - #pragma implementation "dbtable.h" - #endif +#ifdef __BORLANDC__ + #pragma hdrstop #endif #ifdef DBDEBUG_CONSOLE - #include "wx/ioswrap.h" +#if wxUSE_IOSTREAMH + #include +#else + #include #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" - #include "wx/msgdlg.h" - #include "wx/log.h" - #endif - #include "wx/filefn.h" + #include "wx/ioswrap.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 +#ifndef WX_PRECOMP + #include "wx/string.h" + #include "wx/object.h" + #include "wx/list.h" + #include "wx/utils.h" + #include "wx/log.h" #endif - +#include "wx/filefn.h" #if wxUSE_ODBC #include #include #include -//#include -#if wxMAJOR_VERSION == 1 - #include "table.h" -#elif wxMAJOR_VERSION == 2 - #include "wx/dbtable.h" -#endif +#include "wx/dbtable.h" #ifdef __UNIX__ // The HPUX preprocessor lines below were commented out on 8/20/97 @@ -102,6 +71,16 @@ ULONG lastTableID = 0; #endif +void csstrncpyt(wxChar *target, const wxChar *source, int n) +{ + while ( (*target++ = *source++) != '\0' && --n ) + ; + + *target = '\0'; +} + + + /********** wxDbColDef::wxDbColDef() Constructor **********/ wxDbColDef::wxDbColDef() { @@ -116,33 +95,33 @@ 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; - return TRUE; + return true; } // wxDbColDef::Initialize() /********** wxDbTable::wxDbTable() Constructor **********/ -wxDbTable::wxDbTable(wxDb *pwxDb, const wxString &tblName, const int nCols, +wxDbTable::wxDbTable(wxDb *pwxDb, const wxString &tblName, const UWORD numColumns, const wxString &qryTblName, bool qryOnly, const wxString &tblPath) { - if (!initialize(pwxDb, tblName, nCols, qryTblName, qryOnly, tblPath)) + if (!initialize(pwxDb, tblName, numColumns, qryTblName, qryOnly, tblPath)) cleanup(); } // wxDbTable::wxDbTable() /***** DEPRECATED: use wxDbTable::wxDbTable() format above *****/ -wxDbTable::wxDbTable(wxDb *pwxDb, const wxString &tblName, const int nCols, +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, nCols, tempQryTblName, qryOnly, tblPath)) + if (!initialize(pwxDb, tblName, numColumns, tempQryTblName, qryOnly, tblPath)) cleanup(); } // wxDbTable::wxDbTable() @@ -154,7 +133,7 @@ wxDbTable::~wxDbTable() } // wxDbTable::~wxDbTable() -bool wxDbTable::initialize(wxDb *pwxDb, const wxString &tblName, const int nCols, +bool wxDbTable::initialize(wxDb *pwxDb, const wxString &tblName, const UWORD numColumns, const wxString &qryTblName, bool qryOnly, const wxString &tblPath) { // Initializing member variables @@ -162,6 +141,7 @@ bool wxDbTable::initialize(wxDb *pwxDb, const wxString &tblName, const int nCols henv = 0; hdbc = 0; hstmt = 0; + m_hstmtGridQuery = 0; hstmtDefault = 0; // Initialized below hstmtCount = 0; // Initialized first time it is needed hstmtInsert = 0; @@ -170,13 +150,13 @@ bool wxDbTable::initialize(wxDb *pwxDb, const wxString &tblName, const int nCols hstmtInternal = 0; colDefs = 0; tableID = 0; - noCols = nCols; // No. of cols in the table + noCols = numColumns; // Number of cols 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(); @@ -185,25 +165,25 @@ bool wxDbTable::initialize(wxDb *pwxDb, const wxString &tblName, const int nCols wxASSERT(pDb); if (!pDb) - return FALSE; + return false; tableName = tblName; // Table Name if (tblPath.Length()) tablePath = tblPath; // Table Path - used for dBase files else tablePath.Empty(); - + if (qryTblName.Length()) // Name of the table/view to query queryTableName = qryTblName; else queryTableName = tblName; - + pDb->incrementTableCount(); - + wxString s; tableID = ++lastTableID; s.Printf(wxT("wxDbTable constructor (%-20s) tableID:[%6lu] pDb:[%p]"), tblName.c_str(), tableID, pDb); - + #ifdef __WXDEBUG__ wxTablesInUse *tableInUse; tableInUse = new wxTablesInUse(); @@ -212,17 +192,17 @@ bool wxDbTable::initialize(wxDb *pwxDb, const wxString &tblName, const int nCols tableInUse->pDb = pDb; TablesInUse.Append(tableInUse); #endif - + pDb->WriteSqlLog(s); - + // Grab the HENV and HDBC from the wxDb object henv = pDb->GetHENV(); hdbc = pDb->GetHDBC(); - + // Allocate space for column definitions if (noCols) colDefs = new wxDbColDef[noCols]; // Points to the first column definition - + // Allocate statement handles for the table if (!queryOnly) { @@ -239,12 +219,12 @@ bool wxDbTable::initialize(wxDb *pwxDb, const wxString &tblName, const int nCols // Allocate a separate statement handle for internal use if (SQLAllocStmt(hdbc, &hstmtInternal) != SQL_SUCCESS) pDb->DispAllErrors(henv, hdbc); - + // Set the cursor type for the statement handles cursorType = SQL_CURSOR_STATIC; - + if (SQLSetStmtOption(hstmtInternal, SQL_CURSOR_TYPE, cursorType) != SQL_SUCCESS) - { + { // Check to see if cursor type is supported pDb->GetNextError(henv, hdbc, hstmtInternal); if (! wxStrcmp(pDb->sqlState, wxT("01S02"))) // Option Value Changed @@ -282,7 +262,7 @@ bool wxDbTable::initialize(wxDb *pwxDb, const wxString &tblName, const int nCols { // Should never happen pDb->GetNextError(henv, hdbc, hstmtInternal); - return FALSE; + return false; } } } @@ -296,7 +276,7 @@ bool wxDbTable::initialize(wxDb *pwxDb, const wxString &tblName, const int nCols else cout << wxT("Cursor Type set to STATIC") << endl << endl; #endif - + if (!queryOnly) { // Set the cursor type for the INSERT statement handle @@ -309,13 +289,13 @@ bool wxDbTable::initialize(wxDb *pwxDb, const wxString &tblName, const int nCols if (SQLSetStmtOption(hstmtUpdate, SQL_CURSOR_TYPE, SQL_CURSOR_FORWARD_ONLY) != SQL_SUCCESS) pDb->DispAllErrors(henv, hdbc, hstmtUpdate); } - + // 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() @@ -332,26 +312,25 @@ void wxDbTable::cleanup() #ifdef __WXDEBUG__ if (tableID) { - TablesInUse.DeleteContents(TRUE); - bool found = FALSE; + bool found = false; - wxNode *pNode; - pNode = TablesInUse.First(); + wxList::compatibility_iterator pNode; + pNode = TablesInUse.GetFirst(); while (pNode && !found) { - if (((wxTablesInUse *)pNode->Data())->tableID == tableID) + if (((wxTablesInUse *)pNode->GetData())->tableID == tableID) { - found = TRUE; - if (!TablesInUse.DeleteNode(pNode)) - wxLogDebug (s,wxT("Unable to delete node!")); + found = true; + delete (wxTablesInUse *)pNode->GetData(); + TablesInUse.Erase(pNode); } else - pNode = pNode->Next(); + pNode = pNode->GetNext(); } if (!found) { wxString msg; - msg.Printf(wxT("Unable to find the tableID in the linked\nlist of tables in use.\n\n%s"),s); + msg.Printf(wxT("Unable to find the tableID in the linked\nlist of tables in use.\n\n%s"),s.c_str()); wxLogDebug (msg,wxT("NOTICE...")); } } @@ -411,36 +390,82 @@ ODBC 3.0 says to use this form if (hstmtCount) DeleteCursor(hstmtCount); + + if (m_hstmtGridQuery) + DeleteCursor(m_hstmtGridQuery); + } // wxDbTable::cleanup() /***************************** PRIVATE FUNCTIONS *****************************/ -/********** wxDbTable::bindUpdateParams() **********/ +void wxDbTable::setCbValueForColumn(int columnIndex) +{ + switch(colDefs[columnIndex].DbDataType) + { + case DB_DATA_TYPE_VARCHAR: + 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_CHAR) + 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,colNo; - for (i = 0, colNo = 1; i < noCols; i++) + int i; + UWORD colNo; + + for (i=0, colNo=1; i < noCols; i++) { if (forUpdate) { - if (! colDefs[i].Updateable) + if (!colDefs[i].Updateable) continue; } else { - if (! colDefs[i].InsertAllowed) + if (!colDefs[i].InsertAllowed) continue; } @@ -450,57 +475,40 @@ 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_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; precision = pDb->GetTypeInfFloat().Precision; - scale = pDb->GetTypeInfFloat().MaximumScale; + scale = pDb->GetTypeInfFloat().MaximumScale; // SQL Sybase Anywhere v5.5 returned a negative number for the // MaxScale. This caused ODBC to kick out an error on ibscale. // 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, - fSqlType, precision, scale, (UCHAR*) colDefs[i].PtrDataObj, + fSqlType, precision, scale, (UCHAR*) colDefs[i].PtrDataObj, precision+1, &colDefs[i].CbValue) != SQL_SUCCESS) { return(pDb->DispAllErrors(henv, hdbc, hstmtUpdate)); @@ -509,16 +517,16 @@ bool wxDbTable::bindParams(bool forUpdate) else { if (SQLBindParameter(hstmtInsert, colNo++, SQL_PARAM_INPUT, colDefs[i].SqlCtype, - fSqlType, precision, scale, (UCHAR*) colDefs[i].PtrDataObj, - precision+1,&colDefs[i].CbValue) != SQL_SUCCESS) + fSqlType, precision, scale, (UCHAR*) colDefs[i].PtrDataObj, + precision+1, &colDefs[i].CbValue) != SQL_SUCCESS) { return(pDb->DispAllErrors(henv, hdbc, hstmtInsert)); } } } - + // Completed successfully - return(TRUE); + return true; } // wxDbTable::bindParams() @@ -526,36 +534,34 @@ 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() /********** wxDbTable::bindCols() **********/ bool wxDbTable::bindCols(HSTMT cursor) { -//RG-NULL static SDWORD cb; - + static SDWORD cb; + // Bind each column of the table to a memory address for fetching data - int i; + UWORD i; for (i = 0; i < noCols; i++) { - if (SQLBindCol(cursor, i+1, colDefs[i].SqlCtype, (UCHAR*) colDefs[i].PtrDataObj, -//RG-NULL colDefs[i].SzDataObj, &cb) != SQL_SUCCESS) - colDefs[i].SzDataObj, &colDefs[i].CbValue ) != SQL_SUCCESS) - { + cb = colDefs[i].CbValue; + if (SQLBindCol(cursor, (UWORD)(i+1), colDefs[i].SqlCtype, (UCHAR*) colDefs[i].PtrDataObj, + colDefs[i].SzDataObj, &cb ) != SQL_SUCCESS) return (pDb->DispAllErrors(henv, hdbc, cursor)); - } } // Completed successfully - return(TRUE); + return true; } // wxDbTable::bindCols() @@ -572,10 +578,10 @@ bool wxDbTable::getRec(UWORD fetchType) UWORD rowStatus; retcode = SQLExtendedFetch(hstmt, fetchType, 0, &cRowsFetched, &rowStatus); - if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) + 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)); } @@ -595,7 +601,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)); } @@ -610,7 +616,7 @@ bool wxDbTable::getRec(UWORD fetchType) } // Completed successfully - return(TRUE); + return true; } // wxDbTable::getRec() @@ -618,12 +624,21 @@ bool wxDbTable::getRec(UWORD fetchType) /********** wxDbTable::execDelete() **********/ bool wxDbTable::execDelete(const wxString &pSqlStmt) { + RETCODE retcode; + // Execute the DELETE statement - if (SQLExecDirect(hstmtDelete, (UCHAR FAR *) pSqlStmt.c_str(), SQL_NTS) != SQL_SUCCESS) - return(pDb->DispAllErrors(henv, hdbc, hstmtDelete)); + retcode = SQLExecDirect(hstmtDelete, (SQLTCHAR FAR *) pSqlStmt.c_str(), SQL_NTS); + + if (retcode == SQL_SUCCESS || + retcode == SQL_NO_DATA_FOUND || + retcode == SQL_SUCCESS_WITH_INFO) + { + // Record deleted successfully + return true; + } - // Record deleted successfully - return(TRUE); + // Problem deleting record + return(pDb->DispAllErrors(henv, hdbc, hstmtDelete)); } // wxDbTable::execDelete() @@ -631,12 +646,53 @@ bool wxDbTable::execDelete(const wxString &pSqlStmt) /********** wxDbTable::execUpdate() **********/ bool wxDbTable::execUpdate(const wxString &pSqlStmt) { + RETCODE retcode; + // Execute the UPDATE statement - if (SQLExecDirect(hstmtUpdate, (UCHAR FAR *) pSqlStmt.c_str(), SQL_NTS) != SQL_SUCCESS) - return(pDb->DispAllErrors(henv, hdbc, hstmtUpdate)); + retcode = SQLExecDirect(hstmtUpdate, (SQLTCHAR FAR *) pSqlStmt.c_str(), SQL_NTS); + + if (retcode == SQL_SUCCESS || + retcode == SQL_NO_DATA_FOUND || + retcode == SQL_SUCCESS_WITH_INFO) + { + // Record updated successfully + 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 < noCols; 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; + } + } - // Record deleted successfully - return(TRUE); + // Problem updating record + return(pDb->DispAllErrors(henv, hdbc, hstmtUpdate)); } // wxDbTable::execUpdate() @@ -650,7 +706,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, @@ -658,34 +714,19 @@ bool wxDbTable::query(int queryType, bool forUpdate, bool distinct, const wxStri BuildSelectStmt(sqlStmt, queryType, distinct); pDb->WriteSqlLog(sqlStmt); } -/* - This is the block of code that got added during the 2.2.1 merge with - the 2.2 main branch that somehow got added here when it should not have. - gt - - else - wxStrcpy(sqlStmt, pSqlStmt); - SQLFreeStmt(hstmt, SQL_CLOSE); - if (SQLExecDirect(hstmt, (UCHAR FAR *) sqlStmt, SQL_NTS) == SQL_SUCCESS) - return(TRUE); - else - { - pDb->DispAllErrors(henv, hdbc, hstmt); - return(FALSE); - } -*/ // 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); + int retcode; + retcode = SQLExecDirect(hstmt, (SQLTCHAR FAR *) (queryType == DB_SELECT_STATEMENT ? pSqlStmt.c_str() : sqlStmt.c_str()), 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() @@ -697,15 +738,28 @@ 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++) + { + if (colDefs[i].KeyField) + { +// NumKeyCols++; + m_keysize += colDefs[i].SzDataObj; + } + } s.Empty(); // Verify that the table exists in the database - if (checkTableExists && !pDb->TableExists(tableName,/*pDb->GetUsername()*/NULL,tablePath)) + if (checkTableExists && !pDb->TableExists(tableName, pDb->GetUsername(), tablePath)) { s = wxT("Table/view does not exist in the database"); if ( *(pDb->dbInf.accessibleTables) == wxT('Y')) @@ -716,13 +770,13 @@ 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 + // 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"),NULL,pDb->GetUsername(),tablePath)) + 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"); } @@ -738,7 +792,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 @@ -746,17 +800,17 @@ 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!!! @@ -765,18 +819,20 @@ bool wxDbTable::Open(bool checkPrivileges, bool checkTableExists) // Build an insert statement using parameter markers if (!queryOnly && noCols > 0) { - bool needComma = FALSE; - sqlStmt.Printf(wxT("INSERT INTO %s ("), tableName.c_str()); + bool needComma = false; + sqlStmt.Printf(wxT("INSERT INTO %s ("), + pDb->SQLTableName(tableName.c_str()).c_str()); for (i = 0; i < noCols; i++) { if (! colDefs[i].InsertAllowed) continue; if (needComma) sqlStmt += wxT(","); - sqlStmt += colDefs[i].ColName; - needComma = TRUE; + sqlStmt += pDb->SQLColumnName(colDefs[i].ColName); +// sqlStmt += colDefs[i].ColName; + needComma = true; } - needComma = FALSE; + needComma = false; sqlStmt += wxT(") VALUES ("); int insertableCount = 0; @@ -788,23 +844,23 @@ bool wxDbTable::Open(bool checkPrivileges, bool checkTableExists) if (needComma) sqlStmt += wxT(","); sqlStmt += wxT("?"); - needComma = TRUE; + needComma = true; insertableCount++; } sqlStmt += wxT(")"); - + // Prepare the insert statement for execution - if (insertableCount) + if (insertableCount) { - if (SQLPrepare(hstmtInsert, (UCHAR FAR *) sqlStmt.c_str(), SQL_NTS) != SQL_SUCCESS) + if (SQLPrepare(hstmtInsert, (SQLTCHAR FAR *) sqlStmt.c_str(), SQL_NTS) != SQL_SUCCESS) return(pDb->DispAllErrors(henv, hdbc, hstmtInsert)); } - else - insertable= FALSE; + else + insertable = false; } - + // Completed successfully - return(TRUE); + return true; } // wxDbTable::Open() @@ -823,7 +879,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() @@ -852,7 +908,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)); @@ -866,7 +922,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)); @@ -880,7 +936,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)); @@ -894,9 +950,9 @@ 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 + else return(getRec(SQL_FETCH_LAST)); } // wxDbTable::GetLast() @@ -917,11 +973,13 @@ void wxDbTable::BuildDeleteStmt(wxString &pSqlStmt, int typeOfDel, const wxStrin // delete all records from the database in this case. if (typeOfDel == DB_DEL_WHERE && (pWhereClause.Length() == 0)) { - pSqlStmt.Printf(wxT("DELETE FROM %s"), tableName.c_str()); + pSqlStmt.Printf(wxT("DELETE FROM %s"), + pDb->SQLTableName(tableName.c_str()).c_str()); return; } - pSqlStmt.Printf(wxT("DELETE FROM %s WHERE "), 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) @@ -938,7 +996,7 @@ void wxDbTable::BuildDeleteStmt(wxString &pSqlStmt, int typeOfDel, const wxStrin // 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, noCols+1, SQL_C_CHAR, (UCHAR*) rowid, wxDB_ROWID_LEN, &cb) == SQL_SUCCESS) + if (SQLGetData(hstmt, (UWORD)(noCols+1), SQL_C_CHAR, (UCHAR*) rowid, wxDB_ROWID_LEN, &cb) == SQL_SUCCESS) { pSqlStmt += wxT("ROWID = '"); pSqlStmt += rowid; @@ -987,26 +1045,28 @@ 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; + appendFromClause = true; #endif // Add the column list int i; + wxString tStr; for (i = 0; i < noCols; i++) { + tStr = colDefs[i].ColName; // If joining tables, the base table column names must be qualified to avoid ambiguity - if (appendFromClause) + if ((appendFromClause || pDb->Dbms() == dbmsACCESS) && tStr.Find(wxT('.')) == wxNOT_FOUND) { - pSqlStmt += queryTableName; + pSqlStmt += pDb->SQLTableName(queryTableName.c_str()); pSqlStmt += wxT("."); } - pSqlStmt += colDefs[i].ColName; + pSqlStmt += pDb->SQLColumnName(colDefs[i].ColName); if (i + 1 < noCols) pSqlStmt += wxT(","); } @@ -1016,10 +1076,11 @@ void wxDbTable::BuildSelectStmt(wxString &pSqlStmt, int typeOfSelect, bool disti if (!distinct && CanUpdByROWID()) { // If joining tables, the base table column names must be qualified to avoid ambiguity - if (appendFromClause) + if (appendFromClause || pDb->Dbms() == dbmsACCESS) { pSqlStmt += wxT(","); - pSqlStmt += queryTableName; + pSqlStmt += pDb->SQLTableName(queryTableName); +// pSqlStmt += queryTableName; pSqlStmt += wxT(".ROWID"); } else @@ -1028,7 +1089,8 @@ void wxDbTable::BuildSelectStmt(wxString &pSqlStmt, int typeOfSelect, bool disti // Append the FROM tablename portion pSqlStmt += wxT(" FROM "); - pSqlStmt += queryTableName; + pSqlStmt += pDb->SQLTableName(queryTableName); +// pSqlStmt += queryTableName; // Sybase uses the HOLDLOCK keyword to lock a record during query. // The HOLDLOCK keyword follows the table name in the from clause. @@ -1113,9 +1175,10 @@ 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 "), tableName.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; @@ -1124,11 +1187,13 @@ void wxDbTable::BuildUpdateStmt(wxString &pSqlStmt, int typeOfUpd, const wxStrin // Only append Updateable columns if (colDefs[i].Updateable) { - if (! firstColumn) + if (!firstColumn) pSqlStmt += wxT(","); else - firstColumn = FALSE; - pSqlStmt += colDefs[i].ColName; + firstColumn = false; + + pSqlStmt += pDb->SQLColumnName(colDefs[i].ColName); +// pSqlStmt += colDefs[i].ColName; pSqlStmt += wxT(" = ?"); } } @@ -1149,7 +1214,7 @@ void wxDbTable::BuildUpdateStmt(wxString &pSqlStmt, int typeOfUpd, const wxStrin // 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, noCols+1, SQL_C_CHAR, (UCHAR*) rowid, wxDB_ROWID_LEN, &cb) == SQL_SUCCESS) + if (SQLGetData(hstmt, (UWORD)(noCols+1), SQL_C_CHAR, (UCHAR*) rowid, wxDB_ROWID_LEN, &cb) == SQL_SUCCESS) { pSqlStmt += wxT("ROWID = '"); pSqlStmt += rowid; @@ -1186,58 +1251,73 @@ 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 colNo; + for (colNo = 0; colNo < noCols; colNo++) { // 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[colNo].KeyField) || + (typeOfWhere == DB_WHERE_MATCHING && (!IsColNull(colNo)))) { // Skip over timestamp columns - if (colDefs[i].SqlCtype == SQL_C_TIMESTAMP) + if (colDefs[colNo].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[colNo].ColName; + + if (qualTableName.Length() && tStr.Find(wxT('.')) == wxNOT_FOUND) { - pWhereClause += qualTableName; + pWhereClause += pDb->SQLTableName(qualTableName); pWhereClause += wxT("."); } - pWhereClause += colDefs[i].ColName; - if (useLikeComparison && (colDefs[i].SqlCtype == SQL_C_CHAR)) + pWhereClause += pDb->SQLColumnName(colDefs[colNo].ColName); + + if (useLikeComparison && (colDefs[colNo].SqlCtype == SQL_C_CHAR)) pWhereClause += wxT(" LIKE "); else pWhereClause += wxT(" = "); - switch(colDefs[i].SqlCtype) + + switch(colDefs[colNo].SqlCtype) { case SQL_C_CHAR: - colValue.Printf(wxT("'%s'"), (UCHAR FAR *) colDefs[i].PtrDataObj); + colValue.Printf(wxT("'%s'"), (UCHAR FAR *) colDefs[colNo].PtrDataObj); break; + case SQL_C_SHORT: case SQL_C_SSHORT: - colValue.Printf(wxT("%hi"), *((SWORD *) colDefs[i].PtrDataObj)); + colValue.Printf(wxT("%hi"), *((SWORD *) colDefs[colNo].PtrDataObj)); break; case SQL_C_USHORT: - colValue.Printf(wxT("%hu"), *((UWORD *) colDefs[i].PtrDataObj)); + colValue.Printf(wxT("%hu"), *((UWORD *) colDefs[colNo].PtrDataObj)); break; + case SQL_C_LONG: case SQL_C_SLONG: - colValue.Printf(wxT("%li"), *((SDWORD *) colDefs[i].PtrDataObj)); + colValue.Printf(wxT("%li"), *((SDWORD *) colDefs[colNo].PtrDataObj)); break; case SQL_C_ULONG: - colValue.Printf(wxT("%lu"), *((UDWORD *) colDefs[i].PtrDataObj)); + colValue.Printf(wxT("%lu"), *((UDWORD *) colDefs[colNo].PtrDataObj)); break; case SQL_C_FLOAT: - colValue.Printf(wxT("%.6f"), *((SFLOAT *) colDefs[i].PtrDataObj)); + colValue.Printf(wxT("%.6f"), *((SFLOAT *) colDefs[colNo].PtrDataObj)); break; case SQL_C_DOUBLE: - colValue.Printf(wxT("%.6f"), *((SDOUBLE *) colDefs[i].PtrDataObj)); + colValue.Printf(wxT("%.6f"), *((SDOUBLE *) colDefs[colNo].PtrDataObj)); + break; + default: + { + wxString strMsg; + strMsg.Printf(wxT("wxDbTable::bindParams(): Unknown column type for colDefs %d colName %s"), + colNo,colDefs[colNo].ColName); + wxFAIL_MSG(strMsg.c_str()); + } break; } pWhereClause += colValue; @@ -1280,7 +1360,7 @@ bool wxDbTable::CloseCursor(HSTMT cursor) return(pDb->DispAllErrors(henv, hdbc, cursor)); // Completed successfully - return(TRUE); + return true; } // wxDbTable::CloseCursor() @@ -1289,7 +1369,7 @@ bool wxDbTable::CloseCursor(HSTMT cursor) bool wxDbTable::CreateTable(bool attemptDrop) { if (!pDb) - return FALSE; + return false; int i, j; wxString sqlStmt; @@ -1300,7 +1380,7 @@ bool wxDbTable::CreateTable(bool attemptDrop) // Drop table first if (attemptDrop && !DropTable()) - return FALSE; + return false; // Create the table #ifdef DBDEBUG_CONSOLE @@ -1313,19 +1393,19 @@ bool wxDbTable::CreateTable(bool attemptDrop) switch(colDefs[i].DbDataType) { case DB_DATA_TYPE_VARCHAR: - cout << pDb->typeInfVarchar.TypeName << wxT("(") << colDefs[i].SzDataObj << wxT(")"); + cout << pDb->GetTypeInfVarchar().TypeName << wxT("(") << colDefs[i].SzDataObj << wxT(")"); break; case DB_DATA_TYPE_INTEGER: - cout << pDb->typeInfInteger.TypeName; + cout << pDb->GetTypeInfInteger().TypeName; break; case DB_DATA_TYPE_FLOAT: - cout << pDb->typeInfFloat.TypeName; + cout << pDb->GetTypeInfFloat().TypeName; break; case DB_DATA_TYPE_DATE: - cout << pDb->typeInfDate.TypeName; + cout << pDb->GetTypeInfDate().TypeName; break; case DB_DATA_TYPE_BLOB: - cout << pDb->typeInfBlob.TypeName; + cout << pDb->GetTypeInfBlob().TypeName; break; } cout << endl; @@ -1333,8 +1413,10 @@ bool wxDbTable::CreateTable(bool attemptDrop) #endif // Build a CREATE TABLE string from the colDefs structure. - bool needComma = FALSE; - sqlStmt.Printf(wxT("CREATE TABLE %s ("), tableName.c_str()); + bool needComma = false; + + sqlStmt.Printf(wxT("CREATE TABLE %s ("), + pDb->SQLTableName(tableName.c_str()).c_str()); for (i = 0; i < noCols; i++) { @@ -1345,7 +1427,8 @@ bool wxDbTable::CreateTable(bool attemptDrop) if (needComma) sqlStmt += wxT(","); // Column Name - sqlStmt += colDefs[i].ColName; + sqlStmt += pDb->SQLColumnName(colDefs[i].ColName); +// sqlStmt += colDefs[i].ColName; sqlStmt += wxT(" "); // Column Type switch(colDefs[i].DbDataType) @@ -1367,7 +1450,8 @@ 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; @@ -1378,6 +1462,7 @@ bool wxDbTable::CreateTable(bool attemptDrop) if (pDb->Dbms() == dbmsDB2 || pDb->Dbms() == dbmsMY_SQL || pDb->Dbms() == dbmsSYBASE_ASE || + pDb->Dbms() == dbmsINTERBASE || pDb->Dbms() == dbmsMS_SQL_SERVER) { if (colDefs[i].KeyField) @@ -1385,8 +1470,8 @@ bool wxDbTable::CreateTable(bool attemptDrop) sqlStmt += wxT(" NOT NULL"); } } - - needComma = TRUE; + + needComma = true; } // If there is a primary key defined, include it in the create statement for (i = j = 0; i < noCols; i++) @@ -1397,18 +1482,38 @@ 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 { - if (pDb->Dbms() != dbmsMY_SQL) - { - sqlStmt += wxT(",CONSTRAINT "); - sqlStmt += tableName; - sqlStmt += wxT("_PIDX PRIMARY KEY ("); - } - else + switch (pDb->Dbms()) { - /* MySQL goes out on this one. We also declare the relevant key NON NULL above */ - sqlStmt += wxT(", PRIMARY KEY ("); + case dbmsACCESS: + case dbmsINFORMIX: + case dbmsSYBASE_ASA: + case dbmsSYBASE_ASE: + case dbmsMY_SQL: + { + // MySQL goes out on this one. We also declare the relevant key NON NULL above + sqlStmt += wxT(",PRIMARY KEY ("); + break; + } + default: + { + sqlStmt += wxT(",CONSTRAINT "); + // 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.")); + sqlStmt += pDb->SQLTableName(tableName.substr(0, 13).c_str()); +// sqlStmt += tableName.substr(0, 13); + } + else + sqlStmt += pDb->SQLTableName(tableName.c_str()); +// sqlStmt += tableName; + + sqlStmt += wxT("_PIDX PRIMARY KEY ("); + break; + } } // List column name(s) of column(s) comprising the primary key @@ -1418,10 +1523,28 @@ bool wxDbTable::CreateTable(bool attemptDrop) { if (j++) // Multi part key, comma separate names sqlStmt += wxT(","); - sqlStmt += colDefs[i].ColName; + sqlStmt += pDb->SQLColumnName(colDefs[i].ColName); + + if (pDb->Dbms() == dbmsMY_SQL && + colDefs[i].DbDataType == DB_DATA_TYPE_VARCHAR) + { + wxString s; + s.Printf(wxT("(%d)"), colDefs[i].SzDataObj); + sqlStmt += s; + } } } - sqlStmt += wxT(")"); + sqlStmt += wxT(")"); + + if (pDb->Dbms() == dbmsINFORMIX || + pDb->Dbms() == dbmsSYBASE_ASA || + pDb->Dbms() == dbmsSYBASE_ASE) + { + sqlStmt += wxT(" CONSTRAINT "); + sqlStmt += pDb->SQLTableName(tableName); +// sqlStmt += tableName; + sqlStmt += wxT("_PIDX"); + } } // Append the closing parentheses for the create table statement sqlStmt += wxT(")"); @@ -1433,23 +1556,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, (SQLTCHAR FAR *) sqlStmt.c_str(), 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() @@ -1457,14 +1580,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"), tableName.c_str()); + sqlStmt.Printf(wxT("DROP TABLE %s"), + pDb->SQLTableName(tableName.c_str()).c_str()); pDb->WriteSqlLog(sqlStmt); @@ -1472,45 +1596,48 @@ bool wxDbTable::DropTable() cout << endl << sqlStmt.c_str() << endl; #endif - if (SQLExecDirect(hstmt, (UCHAR FAR *) sqlStmt.c_str(), SQL_NTS) != SQL_SUCCESS) + RETCODE retcode = SQLExecDirect(hstmt, (SQLTCHAR FAR *) sqlStmt.c_str(), SQL_NTS); + if (retcode != SQL_SUCCESS) { // Check for "Base table not found" error and ignore - pDb->GetNextError(henv, hdbc, hstmt); - if (wxStrcmp(pDb->sqlState, wxT("S0002")) && - wxStrcmp(pDb->sqlState, wxT("S1000"))) // "Base table not found" - { + pDb->GetNextError(henv, hdbc, hstmt); + if (wxStrcmp(pDb->sqlState, wxT("S0002")) /*&& + wxStrcmp(pDb->sqlState, wxT("S1000"))*/) // "Base table not found" + { // Check for product specific error codes - if (!((pDb->Dbms() == dbmsSYBASE_ASA && !wxStrcmp(pDb->sqlState,wxT("42000"))) || // 5.x (and lower?) - (pDb->Dbms() == dbmsSYBASE_ASE && !wxStrcmp(pDb->sqlState,wxT("37000"))) || - (pDb->Dbms() == dbmsPOSTGRES && !wxStrcmp(pDb->sqlState,wxT("08S01"))))) + if (!((pDb->Dbms() == dbmsSYBASE_ASA && !wxStrcmp(pDb->sqlState,wxT("42000"))) || // 5.x (and lower?) + (pDb->Dbms() == dbmsSYBASE_ASE && !wxStrcmp(pDb->sqlState,wxT("37000"))) || + (pDb->Dbms() == dbmsPERVASIVE_SQL && !wxStrcmp(pDb->sqlState,wxT("S1000"))) || // Returns an S1000 then an S0002 + (pDb->Dbms() == dbmsPOSTGRES && !wxStrcmp(pDb->sqlState,wxT("08S01"))))) { pDb->DispNextError(); pDb->DispAllErrors(henv, hdbc, hstmt); pDb->RollbackTrans(); - CloseCursor(hstmt); - return(FALSE); +// CloseCursor(hstmt); + 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, int noIdxCols, wxDbIdxDef *pIdxDefs, bool attemptDrop) +bool wxDbTable::CreateIndex(const wxString &idxName, bool unique, UWORD noIdxCols, + wxDbIdxDef *pIdxDefs, bool attemptDrop) { wxString sqlStmt; // Drop the index first if (attemptDrop && !DropIndex(idxName)) - return (FALSE); + 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, @@ -1524,11 +1651,11 @@ bool wxDbTable::CreateIndex(const wxString &idxName, bool unique, int noIdxCols, { wxString sqlStmt; int i; - bool ok = TRUE; + bool ok = true; for (i = 0; i < noIdxCols && 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 @@ -1536,11 +1663,11 @@ bool wxDbTable::CreateIndex(const wxString &idxName, bool unique, int noIdxCols, while (!found && (j < this->noCols)) { if (wxStrcmp(colDefs[j].ColName,pIdxDefs[i].ColName) == 0) - found = TRUE; + found = true; if (!found) j++; } - + if (found) { ok = pDb->ModifyColumn(tableName, pIdxDefs[i].ColName, @@ -1549,54 +1676,84 @@ bool wxDbTable::CreateIndex(const wxString &idxName, bool unique, int noIdxCols, 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; } } - + // Build a CREATE INDEX statement sqlStmt = wxT("CREATE "); if (unique) sqlStmt += wxT("UNIQUE "); - + sqlStmt += wxT("INDEX "); - sqlStmt += idxName; + sqlStmt += pDb->SQLTableName(idxName); sqlStmt += wxT(" ON "); - sqlStmt += tableName; + + sqlStmt += pDb->SQLTableName(tableName); +// sqlStmt += tableName; sqlStmt += wxT(" ("); - + // Append list of columns making up index int i; for (i = 0; i < noIdxCols; i++) { - sqlStmt += pIdxDefs[i].ColName; - /* Postgres doesn't cope with ASC */ - if (pDb->Dbms() != dbmsPOSTGRES) + sqlStmt += pDb->SQLColumnName(pIdxDefs[i].ColName); +// sqlStmt += pIdxDefs[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 < noCols; ++j ) + { + if ( wxStrcmp( pIdxDefs[i].ColName, colDefs[j].ColName ) == 0 ) + { + break; + } + } + if ( colDefs[j].DbDataType == DB_DATA_TYPE_VARCHAR) + { + wxString s; + s.Printf(wxT("(%d)"), colDefs[i].SzDataObj); + sqlStmt += s; + } + } + + // Postgres and SQL Server 7 do not support the ASC/DESC keywords for index columns + if (!((pDb->Dbms() == dbmsMS_SQL_SERVER) && (wxStrncmp(pDb->dbInf.dbmsVer,_T("07"),2)==0)) && + !(pDb->Dbms() == dbmsPOSTGRES)) { if (pIdxDefs[i].Ascending) sqlStmt += wxT(" ASC"); else sqlStmt += wxT(" DESC"); } + else + wxASSERT_MSG(pIdxDefs[i].Ascending, _T("Datasource does not support DESCending index columns")); if ((i + 1) < noIdxCols) sqlStmt += wxT(","); } - + // Append closing parentheses sqlStmt += wxT(")"); @@ -1607,22 +1764,22 @@ bool wxDbTable::CreateIndex(const wxString &idxName, bool unique, int noIdxCols, #endif // Execute the CREATE INDEX statement - if (SQLExecDirect(hstmt, (UCHAR FAR *) sqlStmt.c_str(), SQL_NTS) != SQL_SUCCESS) + if (SQLExecDirect(hstmt, (SQLTCHAR FAR *) sqlStmt.c_str(), SQL_NTS) != 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() @@ -1630,20 +1787,27 @@ bool wxDbTable::CreateIndex(const wxString &idxName, bool unique, int noIdxCols, /********** wxDbTable::DropIndex() **********/ bool wxDbTable::DropIndex(const wxString &idxName) { - // 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 + // below for any other databases when those databases are defined // to handle this situation consistently wxString sqlStmt; - if (pDb->Dbms() == dbmsACCESS || pDb->Dbms() == dbmsMY_SQL) - sqlStmt.Printf(wxT("DROP INDEX %s ON %s"),idxName.c_str(), tableName.c_str()); + 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()).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"),tableName.c_str(), 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(idxName.c_str()).c_str()); else - sqlStmt.Printf(wxT("DROP INDEX %s"),idxName.c_str()); + sqlStmt.Printf(wxT("DROP INDEX %s"), + pDb->SQLTableName(idxName.c_str()).c_str()); pDb->WriteSqlLog(sqlStmt); @@ -1651,7 +1815,7 @@ bool wxDbTable::DropIndex(const wxString &idxName) cout << endl << sqlStmt.c_str() << endl; #endif - if (SQLExecDirect(hstmt, (UCHAR FAR *) sqlStmt.c_str(), SQL_NTS) != SQL_SUCCESS) + if (SQLExecDirect(hstmt, (SQLTCHAR FAR *) sqlStmt.c_str(), SQL_NTS) != SQL_SUCCESS) { // Check for "Index not found" error and ignore pDb->GetNextError(henv, hdbc, hstmt); @@ -1661,6 +1825,7 @@ 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() == 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"))) @@ -1670,28 +1835,28 @@ 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(int first, ... ) +bool wxDbTable::SetOrderByColNums(UWORD first, ... ) { - int colNo = first; + int colNo = 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. */ @@ -1703,7 +1868,7 @@ bool wxDbTable::SetOrderByColNums(int first, ... ) // Valid columns are 0 thru noCols-1 if (colNo >= noCols || colNo < 0) { - abort = TRUE; + abort = true; continue; } @@ -1733,7 +1898,8 @@ 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) + 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); @@ -1746,6 +1912,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 < noCols; 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); @@ -1758,7 +1958,7 @@ bool wxDbTable::Update(void) { wxASSERT(!queryOnly); if (queryOnly) - return(FALSE); + return false; wxString sqlStmt; @@ -1782,7 +1982,7 @@ bool wxDbTable::Update(const wxString &pSqlStmt) { wxASSERT(!queryOnly); if (queryOnly) - return(FALSE); + return false; pDb->WriteSqlLog(pSqlStmt); @@ -1796,7 +1996,7 @@ bool wxDbTable::UpdateWhere(const wxString &pWhereClause) { wxASSERT(!queryOnly); if (queryOnly) - return(FALSE); + return false; wxString sqlStmt; @@ -1820,7 +2020,7 @@ bool wxDbTable::Delete(void) { wxASSERT(!queryOnly); if (queryOnly) - return(FALSE); + return false; wxString sqlStmt; sqlStmt.Empty(); @@ -1841,7 +2041,7 @@ bool wxDbTable::DeleteWhere(const wxString &pWhereClause) { wxASSERT(!queryOnly); if (queryOnly) - return(FALSE); + return false; wxString sqlStmt; sqlStmt.Empty(); @@ -1862,7 +2062,7 @@ bool wxDbTable::DeleteMatching(void) { wxASSERT(!queryOnly); if (queryOnly) - return(FALSE); + return false; wxString sqlStmt; sqlStmt.Empty(); @@ -1879,10 +2079,10 @@ bool wxDbTable::DeleteMatching(void) /********** wxDbTable::IsColNull() **********/ -bool wxDbTable::IsColNull(int colNo) +bool wxDbTable::IsColNull(UWORD colNo) 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) @@ -1905,11 +2105,11 @@ bool wxDbTable::IsColNull(int colNo) TIMESTAMP_STRUCT *pDt; pDt = (TIMESTAMP_STRUCT *) colDefs[colNo].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); @@ -1920,16 +2120,16 @@ bool wxDbTable::IsColNull(int colNo) 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() @@ -1938,16 +2138,16 @@ bool wxDbTable::CanSelectForUpdate(void) bool wxDbTable::CanUpdByROWID(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() @@ -1955,16 +2155,16 @@ bool wxDbTable::CanUpdByROWID(void) 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(int colNo, bool setToNull) +void wxDbTable::ClearMemberVar(UWORD colNo, bool setToNull) { wxASSERT(colNo < noCols); @@ -1979,6 +2179,7 @@ void wxDbTable::ClearMemberVar(int colNo, bool setToNull) case SQL_C_USHORT: *((UWORD*) colDefs[colNo].PtrDataObj) = 0; break; + case SQL_C_LONG: case SQL_C_SLONG: *((SDWORD *) colDefs[colNo].PtrDataObj) = 0; break; @@ -2034,23 +2235,33 @@ bool wxDbTable::SetQueryTimeout(UDWORD nSeconds) return(pDb->DispAllErrors(henv, hdbc, hstmtInternal)); // Completed Successfully - return(TRUE); + return true; } // wxDbTable::SetQueryTimeout() /********** wxDbTable::SetColDefs() **********/ -void wxDbTable::SetColDefs(int index, const wxString &fieldName, int dataType, void *pData, - int cType, int size, bool keyField, bool upd, +void wxDbTable::SetColDefs(UWORD index, const wxString &fieldName, int dataType, void *pData, + SWORD cType, int size, bool keyField, bool upd, bool insAllow, bool derivedCol) { + wxASSERT_MSG( index < noCols, + _T("Specified column index exceeds the maximum number of columns for this table.") ); + if (!colDefs) // May happen if the database connection fails return; if (fieldName.Length() > (unsigned int) DB_MAX_COLUMN_NAME_LEN) { - wxStrncpy (colDefs[index].ColName, fieldName, DB_MAX_COLUMN_NAME_LEN); + wxStrncpy(colDefs[index].ColName, fieldName, DB_MAX_COLUMN_NAME_LEN); colDefs[index].ColName[DB_MAX_COLUMN_NAME_LEN] = 0; + +#ifdef __WXDEBUG__ + wxString tmpMsg; + tmpMsg.Printf(_T("Column name '%s' is too long. Truncated to '%s'."), + fieldName.c_str(),colDefs[index].ColName); + wxFAIL_MSG(tmpMsg); +#endif // __WXDEBUG__ } else wxStrcpy(colDefs[index].ColName, fieldName); @@ -2064,8 +2275,8 @@ void wxDbTable::SetColDefs(int index, const wxString &fieldName, int dataType, v // Derived columns by definition would NOT be "Insertable" or "Updateable" if (derivedCol) { - colDefs[index].Updateable = FALSE; - colDefs[index].InsertAllowed = FALSE; + colDefs[index].Updateable = false; + colDefs[index].InsertAllowed = false; } else { @@ -2073,21 +2284,21 @@ void wxDbTable::SetColDefs(int index, const wxString &fieldName, int dataType, v colDefs[index].InsertAllowed = insAllow; } - colDefs[index].Null = FALSE; - + colDefs[index].Null = false; + } // wxDbTable::SetColDefs() /********** wxDbTable::SetColDefs() **********/ -wxDbColDataPtr* wxDbTable::SetColDefs(wxDbColInf *pColInfs, ULONG numCols) +wxDbColDataPtr* wxDbTable::SetColDefs(wxDbColInf *pColInfs, UWORD numCols) { wxASSERT(pColInfs); wxDbColDataPtr *pColDataPtrs = NULL; if (pColInfs) { - ULONG index; - + UWORD index; + pColDataPtrs = new wxDbColDataPtr[numCols+1]; for (index = 0; index < numCols; index++) @@ -2128,7 +2339,7 @@ wxDbColDataPtr* wxDbTable::SetColDefs(wxDbColInf *pColInfs, ULONG numCols) pColDataPtrs[index].PtrDataObj = new double; pColDataPtrs[index].SzDataObj = sizeof(double); pColDataPtrs[index].SqlCtype = SQL_C_DOUBLE; - } + } break; case DB_DATA_TYPE_DATE: pColDataPtrs[index].PtrDataObj = new TIMESTAMP_STRUCT; @@ -2136,8 +2347,7 @@ wxDbColDataPtr* wxDbTable::SetColDefs(wxDbColInf *pColInfs, ULONG numCols) pColDataPtrs[index].SqlCtype = SQL_C_TIMESTAMP; break; case DB_DATA_TYPE_BLOB: - int notSupportedYet = 0; - wxASSERT_MSG(notSupportedYet, wxT("This form of ::SetColDefs() cannot be used with BLOB columns")); + wxFAIL_MSG(wxT("This form of ::SetColDefs() cannot be used with BLOB columns")); pColDataPtrs[index].PtrDataObj = /*BLOB ADDITION NEEDED*/NULL; pColDataPtrs[index].SzDataObj = /*BLOB ADDITION NEEDED*/sizeof(void *); pColDataPtrs[index].SqlCtype = SQL_VARBINARY; @@ -2147,7 +2357,7 @@ wxDbColDataPtr* wxDbTable::SetColDefs(wxDbColInf *pColInfs, ULONG numCols) SetColDefs (index,pColInfs[index].colName,pColInfs[index].dbDataType, pColDataPtrs[index].PtrDataObj, pColDataPtrs[index].SqlCtype, pColDataPtrs[index].SzDataObj); else { - // Unable to build all the column definitions, as either one of + // Unable to build all the column definitions, as either one of // the calls to "new" failed above, or there was a BLOB field // to have a column definition for. If BLOBs are to be used, // the other form of ::SetColDefs() must be used, as it is impossible @@ -2185,7 +2395,8 @@ ULONG wxDbTable::Count(const wxString &args) sqlStmt = wxT("SELECT COUNT("); sqlStmt += args; sqlStmt += wxT(") FROM "); - sqlStmt += queryTableName; + sqlStmt += pDb->SQLTableName(queryTableName); +// sqlStmt += queryTableName; #if wxODBC_BACKWARD_COMPATABILITY if (from && wxStrlen(from)) #else @@ -2209,14 +2420,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, (SQLTCHAR FAR *) sqlStmt.c_str(), SQL_NTS) != SQL_SUCCESS) { pDb->DispAllErrors(henv, hdbc, *hstmtCount); return(0); @@ -2230,7 +2441,7 @@ ULONG wxDbTable::Count(const wxString &args) } // Obtain the result - if (SQLGetData(*hstmtCount, 1, SQL_C_ULONG, &count, sizeof(count), &cb) != SQL_SUCCESS) + if (SQLGetData(*hstmtCount, (UWORD)1, SQL_C_ULONG, &count, sizeof(count), &cb) != SQL_SUCCESS) { pDb->DispAllErrors(henv, hdbc, *hstmtCount); return(0); @@ -2249,15 +2460,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; @@ -2275,9 +2486,10 @@ bool wxDbTable::Refresh(void) // 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, noCols+1, SQL_C_CHAR, (UCHAR*) rowid, wxDB_ROWID_LEN, &cb) == SQL_SUCCESS) + if (SQLGetData(hstmt, (UWORD)(noCols+1), SQL_C_CHAR, (UCHAR*) rowid, wxDB_ROWID_LEN, &cb) == SQL_SUCCESS) { - whereClause += queryTableName; + whereClause += pDb->SQLTableName(queryTableName); +// whereClause += queryTableName; whereClause += wxT(".ROWID = '"); whereClause += rowid; whereClause += wxT("'"); @@ -2292,10 +2504,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); @@ -2313,41 +2525,47 @@ bool wxDbTable::Refresh(void) } // wxDbTable::Refresh() -/********** wxDbTable::SetColNull(int colNo, bool set) **********/ -bool wxDbTable::SetColNull(int colNo, bool set) +/********** wxDbTable::SetColNull() **********/ +bool wxDbTable::SetColNull(UWORD colNo, bool set) { if (colNo < noCols) { colDefs[colNo].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(colNo, false); // Must call with false here, or infinite recursion will happen + + setCbValueForColumn(colNo); + + return true; } else - return(FALSE); + return false; } // wxDbTable::SetColNull() -/********** wxDbTable::SetColNull(const wxString &colName, bool set) **********/ +/********** wxDbTable::SetColNull() **********/ bool wxDbTable::SetColNull(const wxString &colName, bool set) { - int i; - for (i = 0; i < noCols; i++) + int colNo; + for (colNo = 0; colNo < noCols; colNo++) { - if (!wxStricmp(colName, colDefs[i].ColName)) + if (!wxStricmp(colName, colDefs[colNo].ColName)) break; } - if (i < noCols) + if (colNo < noCols) { - colDefs[i].Null = set; + colDefs[colNo].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(colNo,false); // Must call with false here, or infinite recursion will happen + + setCbValueForColumn(colNo); + + return true; } else - return(FALSE); + return false; } // wxDbTable::SetColNull() @@ -2376,7 +2594,7 @@ HSTMT *wxDbTable::GetNewCursor(bool setCursor, bool bindColumns) if (bindColumns) { - if(!bindCols(*newHSTMT)) + if (!bindCols(*newHSTMT)) { delete newHSTMT; return(0); @@ -2394,7 +2612,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); @@ -2402,12 +2620,12 @@ bool wxDbTable::DeleteCursor(HSTMT *hstmtDel) /* ODBC 3.0 says to use this form if (SQLFreeHandle(*hstmtDel, SQL_DROP) != SQL_SUCCESS) - + */ if (SQLFreeStmt(*hstmtDel, SQL_DROP) != SQL_SUCCESS) { pDb->DispAllErrors(henv, hdbc); - result = FALSE; + result = false; } delete hstmtDel; @@ -2416,5 +2634,220 @@ ODBC 3.0 says to use this form } // wxDbTable::DeleteCursor() +////////////////////////////////////////////////////////////// +// wxDbGrid support functions +////////////////////////////////////////////////////////////// + +void wxDbTable::SetRowMode(const rowmode_t rowmode) +{ + if (!m_hstmtGridQuery) + { + m_hstmtGridQuery = GetNewCursor(false,false); + if (!bindCols(*m_hstmtGridQuery)) + return; + } + + m_rowmode = rowmode; + switch (m_rowmode) + { + case WX_ROW_MODE_QUERY: + SetCursor(m_hstmtGridQuery); + break; + case WX_ROW_MODE_INDIVIDUAL: + SetCursor(hstmtDefault); + break; + default: + wxASSERT(0); + } +} // wxDbTable::SetRowMode() + + +wxVariant wxDbTable::GetCol(const int colNo) const +{ + wxVariant val; + if ((colNo < noCols) && (!IsColNull(colNo))) + { + switch (colDefs[colNo].SqlCtype) + { + case SQL_CHAR: + case SQL_VARCHAR: + val = (wxChar *)(colDefs[colNo].PtrDataObj); + break; + case SQL_C_LONG: + case SQL_C_SLONG: + val = *(long *)(colDefs[colNo].PtrDataObj); + break; + case SQL_C_SHORT: + case SQL_C_SSHORT: + val = (long int )(*(short *)(colDefs[colNo].PtrDataObj)); + break; + case SQL_C_ULONG: + val = (long)(*(unsigned long *)(colDefs[colNo].PtrDataObj)); + break; + case SQL_C_TINYINT: + val = (long)(*(wxChar *)(colDefs[colNo].PtrDataObj)); + break; + case SQL_C_UTINYINT: + val = (long)(*(wxChar *)(colDefs[colNo].PtrDataObj)); + break; + case SQL_C_USHORT: + val = (long)(*(UWORD *)(colDefs[colNo].PtrDataObj)); + break; + case SQL_C_DATE: + val = (DATE_STRUCT *)(colDefs[colNo].PtrDataObj); + break; + case SQL_C_TIME: + val = (TIME_STRUCT *)(colDefs[colNo].PtrDataObj); + break; + case SQL_C_TIMESTAMP: + val = (TIMESTAMP_STRUCT *)(colDefs[colNo].PtrDataObj); + break; + case SQL_C_DOUBLE: + val = *(double *)(colDefs[colNo].PtrDataObj); + break; + default: + assert(0); + } + } + return val; +} // wxDbTable::GetCol() + + +void wxDbTable::SetCol(const int colNo, const wxVariant val) +{ + //FIXME: Add proper wxDateTime support to wxVariant.. + wxDateTime dateval; + + SetColNull(colNo, val.IsNull()); + + if (!val.IsNull()) + { + if ((colDefs[colNo].SqlCtype == SQL_C_DATE) + || (colDefs[colNo].SqlCtype == SQL_C_TIME) + || (colDefs[colNo].SqlCtype == SQL_C_TIMESTAMP)) + { + //Returns null if invalid! + if (!dateval.ParseDate(val.GetString())) + SetColNull(colNo, true); + } + + switch (colDefs[colNo].SqlCtype) + { + case SQL_CHAR: + case SQL_VARCHAR: + csstrncpyt((wxChar *)(colDefs[colNo].PtrDataObj), + val.GetString().c_str(), + colDefs[colNo].SzDataObj-1); + break; + case SQL_C_LONG: + case SQL_C_SLONG: + *(long *)(colDefs[colNo].PtrDataObj) = val; + break; + case SQL_C_SHORT: + case SQL_C_SSHORT: + *(short *)(colDefs[colNo].PtrDataObj) = val.GetLong(); + break; + case SQL_C_ULONG: + *(unsigned long *)(colDefs[colNo].PtrDataObj) = val.GetLong(); + break; + case SQL_C_TINYINT: + *(wxChar *)(colDefs[colNo].PtrDataObj) = val.GetChar(); + break; + case SQL_C_UTINYINT: + *(wxChar *)(colDefs[colNo].PtrDataObj) = val.GetChar(); + break; + case SQL_C_USHORT: + *(unsigned short *)(colDefs[colNo].PtrDataObj) = val.GetLong(); + break; + //FIXME: Add proper wxDateTime support to wxVariant.. + case SQL_C_DATE: + { + DATE_STRUCT *dataptr = + (DATE_STRUCT *)colDefs[colNo].PtrDataObj; + + dataptr->year = dateval.GetYear(); + dataptr->month = dateval.GetMonth()+1; + dataptr->day = dateval.GetDay(); + } + break; + case SQL_C_TIME: + { + TIME_STRUCT *dataptr = + (TIME_STRUCT *)colDefs[colNo].PtrDataObj; + + dataptr->hour = dateval.GetHour(); + dataptr->minute = dateval.GetMinute(); + dataptr->second = dateval.GetSecond(); + } + break; + 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(); + + dataptr->hour = dateval.GetHour(); + dataptr->minute = dateval.GetMinute(); + dataptr->second = dateval.GetSecond(); + } + break; + case SQL_C_DOUBLE: + *(double *)(colDefs[colNo].PtrDataObj) = val; + break; + default: + assert(0); + } // switch + } // if (!val.IsNull()) +} // wxDbTable::SetCol() + + +GenericKey wxDbTable::GetKey() +{ + void *blk; + wxChar *blkptr; + + blk = malloc(m_keysize); + blkptr = (wxChar *) blk; + + int i; + for (i=0; i < noCols; i++) + { + if (colDefs[i].KeyField) + { + memcpy(blkptr,colDefs[i].PtrDataObj, colDefs[i].SzDataObj); + blkptr += colDefs[i].SzDataObj; + } + } + + GenericKey k = GenericKey(blk, m_keysize); + free(blk); + + return k; +} // wxDbTable::GetKey() + + +void wxDbTable::SetKey(const GenericKey& k) +{ + void *blk; + wxChar *blkptr; + + blk = k.GetBlk(); + blkptr = (wxChar *)blk; + + int i; + for (i=0; i < noCols; i++) + { + if (colDefs[i].KeyField) + { + SetColNull(i, false); + memcpy(colDefs[i].PtrDataObj, blkptr, colDefs[i].SzDataObj); + blkptr += colDefs[i].SzDataObj; + } + } +} // wxDbTable::SetKey() + + #endif // wxUSE_ODBC