X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/f6bcfd974ef26faf6f91a62cac09827e09463fd1..937afade13326376cf1d3071057d069041172daa:/src/common/dbtable.cpp diff --git a/src/common/dbtable.cpp b/src/common/dbtable.cpp index 9daf02fcb7..de3b913141 100644 --- a/src/common/dbtable.cpp +++ b/src/common/dbtable.cpp @@ -3,11 +3,8 @@ // Purpose: Implementation of the wxDbTable class. // Author: Doug Card // Modified by: George Tasker -// Mods: April 1999 -// -Dynamic cursor support - Only one predefined cursor, as many others as -// you need may be created on demand -// -Reduced number of active cursors significantly -// -Query-Only wxDbTable objects +// Bart Jourquin +// Mark Johnson // Created: 9.96 // RCS-ID: $Id$ // Copyright: (c) 1996 Remstar International, Inc. @@ -35,9 +32,9 @@ #include "wx/version.h" #if wxMAJOR_VERSION == 2 -# ifdef __GNUG__ -# pragma implementation "dbtable.h" -# endif + #ifdef __GNUG__ + #pragma implementation "dbtable.h" + #endif #endif #ifdef DBDEBUG_CONSOLE @@ -128,27 +125,32 @@ wxDbTable::wxDbTable(wxDb *pwxDb, const char *tblName, const int nCols, selectForUpdate = FALSE; // SELECT ... FOR UPDATE; Indicates whether to include the FOR UPDATE phrase queryOnly = qryOnly; insertable = TRUE; + wxStrcpy(tablePath,""); + wxStrcpy(tableName,""); + wxStrcpy(queryTableName,""); assert (tblName); wxStrcpy(tableName, tblName); // Table Name if (tblPath) wxStrcpy(tablePath, tblPath); // Table Path - used for dBase files - + else + tablePath[0] = 0; + if (qryTblName) // Name of the table/view to query wxStrcpy(queryTableName, qryTblName); else wxStrcpy(queryTableName, tblName); - + if (!pDb) return; - + pDb->incrementTableCount(); - + wxString s; tableID = ++lastTableID; s.sprintf("wxDbTable constructor (%-20s) tableID:[%6lu] pDb:[%p]", tblName,tableID,pDb); - + #ifdef __WXDEBUG__ wxTablesInUse *tableInUse; tableInUse = new wxTablesInUse(); @@ -157,17 +159,17 @@ wxDbTable::wxDbTable(wxDb *pwxDb, const char *tblName, const int nCols, tableInUse->pDb = pDb; TablesInUse.Append(tableInUse); #endif - + pDb->WriteSqlLog(s.c_str()); - + // 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 defintion - + // Allocate statement handles for the table if (!queryOnly) { @@ -184,62 +186,64 @@ wxDbTable::wxDbTable(wxDb *pwxDb, const char *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, "01S02")) // Option Value Changed - { - + { // Datasource does not support static cursors. Driver // will substitute a cursor type. Call SQLGetStmtOption() // to determine which cursor type was selected. if (SQLGetStmtOption(hstmtInternal, SQL_CURSOR_TYPE, &cursorType) != SQL_SUCCESS) - pDb->DispAllErrors(henv, hdbc, hstmtInternal); + pDb->DispAllErrors(henv, hdbc, hstmtInternal); #ifdef DBDEBUG_CONSOLE cout << "Static cursor changed to: "; switch(cursorType) - { - case SQL_CURSOR_FORWARD_ONLY: - cout << "Forward Only"; break; - case SQL_CURSOR_STATIC: - cout << "Static"; break; - case SQL_CURSOR_KEYSET_DRIVEN: - cout << "Keyset Driven"; break; - case SQL_CURSOR_DYNAMIC: - cout << "Dynamic"; break; - } + { + case SQL_CURSOR_FORWARD_ONLY: + cout << "Forward Only"; + break; + case SQL_CURSOR_STATIC: + cout << "Static"; + break; + case SQL_CURSOR_KEYSET_DRIVEN: + cout << "Keyset Driven"; + break; + case SQL_CURSOR_DYNAMIC: + cout << "Dynamic"; + break; + } cout << endl << endl; #endif - - // BJO20000425 - if (pDb->FwdOnlyCursors() && cursorType != SQL_CURSOR_FORWARD_ONLY) - { - // Force the use of a forward only cursor... - cursorType = SQL_CURSOR_FORWARD_ONLY; - if (SQLSetStmtOption(hstmtInternal, SQL_CURSOR_TYPE, cursorType) != SQL_SUCCESS) - { - // Should never happen - pDb->GetNextError(henv, hdbc, hstmtInternal); - return; - } - } - } - else - { + // BJO20000425 + if (pDb->FwdOnlyCursors() && cursorType != SQL_CURSOR_FORWARD_ONLY) + { + // Force the use of a forward only cursor... + cursorType = SQL_CURSOR_FORWARD_ONLY; + if (SQLSetStmtOption(hstmtInternal, SQL_CURSOR_TYPE, cursorType) != SQL_SUCCESS) + { + // Should never happen + pDb->GetNextError(henv, hdbc, hstmtInternal); + return; + } + } + } + else + { pDb->DispNextError(); pDb->DispAllErrors(henv, hdbc, hstmtInternal); - } + } } #ifdef DBDEBUG_CONSOLE else cout << "Cursor Type set to STATIC" << endl << endl; #endif - + if (!queryOnly) { // Set the cursor type for the INSERT statement handle @@ -252,12 +256,12 @@ wxDbTable::wxDbTable(wxDb *pwxDb, const char *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); assert(hstmtDefault); hstmt = *hstmtDefault; - + } // wxDbTable::wxDbTable() @@ -320,8 +324,8 @@ wxDbTable::~wxDbTable() if (hstmtUpdate) if (SQLFreeStmt(hstmtUpdate, SQL_DROP) != SQL_SUCCESS) pDb->DispAllErrors(henv, hdbc); - } + if (hstmtInternal) if (SQLFreeStmt(hstmtInternal, SQL_DROP) != SQL_SUCCESS) pDb->DispAllErrors(henv, hdbc); @@ -333,7 +337,6 @@ wxDbTable::~wxDbTable() if (hstmtCount) DeleteCursor(hstmtCount); - } // wxDbTable::~wxDbTable() @@ -361,48 +364,62 @@ bool wxDbTable::bindInsertParams(void) continue; switch(colDefs[i].DbDataType) { - - case DB_DATA_TYPE_VARCHAR: - fSqlType = pDb->GetTypeInfVarchar().FsqlType; - precision = colDefs[i].SzDataObj; - scale = 0; - colDefs[i].CbValue = SQL_NTS; - break; - case DB_DATA_TYPE_INTEGER: - fSqlType = pDb->GetTypeInfInteger().FsqlType; - precision = pDb->GetTypeInfInteger().Precision; - scale = 0; - colDefs[i].CbValue = 0; - break; - case DB_DATA_TYPE_FLOAT: - fSqlType = pDb->GetTypeInfFloat().FsqlType; - precision = pDb->GetTypeInfFloat().Precision; - 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; - colDefs[i].CbValue = 0; - break; - case DB_DATA_TYPE_DATE: - fSqlType = pDb->GetTypeInfDate().FsqlType; - precision = pDb->GetTypeInfDate().Precision; - scale = 0; - colDefs[i].CbValue = 0; - break; + case DB_DATA_TYPE_VARCHAR: + 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; + // 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; } // Null values - if (colDefs[i].Null) +//RG-NULL +//RG-NULL if (colDefs[i].Null) +//RG-NULL { +//RG-NULL colDefs[i].CbValue = SQL_NULL_DATA; +//RG-NULL colDefs[i].Null = FALSE; +//RG-NULL } + + if (SQLBindParameter(hstmtInsert, colNo++, SQL_PARAM_INPUT, colDefs[i].SqlCtype, + fSqlType, precision, scale, (UCHAR*) colDefs[i].PtrDataObj, + precision+1,&colDefs[i].CbValue) != SQL_SUCCESS) { - colDefs[i].CbValue = SQL_NULL_DATA; - colDefs[i].Null = FALSE; + return(pDb->DispAllErrors(henv, hdbc, hstmtInsert)); } - - if (SQLBindParameter(hstmtInsert, colNo++, SQL_PARAM_INPUT, colDefs[i].SqlCtype, - fSqlType, precision, scale, (UCHAR*) colDefs[i].PtrDataObj, - precision+1,&colDefs[i].CbValue) != SQL_SUCCESS) - return(pDb->DispAllErrors(henv, hdbc, hstmtInsert)); } // Completed successfully @@ -417,7 +434,7 @@ bool wxDbTable::bindUpdateParams(void) assert(!queryOnly); if (queryOnly) return(FALSE); - + SWORD fSqlType = 0; UDWORD precision = 0; SWORD scale = 0; @@ -430,43 +447,57 @@ bool wxDbTable::bindUpdateParams(void) continue; switch(colDefs[i].DbDataType) { - case DB_DATA_TYPE_VARCHAR: - fSqlType = pDb->GetTypeInfVarchar().FsqlType; - precision = colDefs[i].SzDataObj; - scale = 0; - colDefs[i].CbValue = SQL_NTS; - break; - case DB_DATA_TYPE_INTEGER: - fSqlType = pDb->GetTypeInfInteger().FsqlType; - precision = pDb->GetTypeInfInteger().Precision; - scale = 0; - colDefs[i].CbValue = 0; - break; - case DB_DATA_TYPE_FLOAT: - fSqlType = pDb->GetTypeInfFloat().FsqlType; - precision = pDb->GetTypeInfFloat().Precision; - 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; - colDefs[i].CbValue = 0; - break; - case DB_DATA_TYPE_DATE: - fSqlType = pDb->GetTypeInfDate().FsqlType; - precision = pDb->GetTypeInfDate().Precision; - scale = 0; - colDefs[i].CbValue = 0; - break; + case DB_DATA_TYPE_VARCHAR: + 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; + // 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; + } + + if (SQLBindParameter(hstmtUpdate, colNo++, SQL_PARAM_INPUT, colDefs[i].SqlCtype, + fSqlType, precision, scale, (UCHAR*) colDefs[i].PtrDataObj, + precision+1, &colDefs[i].CbValue) != SQL_SUCCESS) + { + return(pDb->DispAllErrors(henv, hdbc, hstmtUpdate)); } - - if (SQLBindParameter(hstmtUpdate, colNo++, SQL_PARAM_INPUT, colDefs[i].SqlCtype, - fSqlType, precision, scale, (UCHAR*) colDefs[i].PtrDataObj, - precision+1, &colDefs[i].CbValue) != SQL_SUCCESS) - return(pDb->DispAllErrors(henv, hdbc, hstmtUpdate)); } - + // Completed successfully return(TRUE); @@ -476,16 +507,19 @@ bool wxDbTable::bindUpdateParams(void) /********** wxDbTable::bindCols() **********/ bool wxDbTable::bindCols(HSTMT cursor) { - static SDWORD cb; +//RG-NULL static SDWORD cb; // Bind each column of the table to a memory address for fetching data int i; for (i = 0; i < noCols; i++) - { - if (SQLBindCol(cursor, i+1, colDefs[i].SqlCtype, (UCHAR*) colDefs[i].PtrDataObj, - colDefs[i].SzDataObj, &cb) != SQL_SUCCESS) - return (pDb->DispAllErrors(henv, hdbc, cursor)); - } + { + 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) + { + return (pDb->DispAllErrors(henv, hdbc, cursor)); + } + } // Completed successfully return(TRUE); @@ -506,10 +540,20 @@ bool wxDbTable::getRec(UWORD fetchType) retcode = SQLExtendedFetch(hstmt, fetchType, 0, &cRowsFetched, &rowStatus); if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) + { if (retcode == SQL_NO_DATA_FOUND) return(FALSE); else return(pDb->DispAllErrors(henv, hdbc, hstmt)); + } + else + { + // 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); + } } else { @@ -522,6 +566,14 @@ bool wxDbTable::getRec(UWORD fetchType) else return(pDb->DispAllErrors(henv, hdbc, hstmt)); } + else + { + // 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); + } } // Completed successfully @@ -559,23 +611,8 @@ bool wxDbTable::execUpdate(const char *pSqlStmt) /********** wxDbTable::query() **********/ bool wxDbTable::query(int queryType, bool forUpdate, bool distinct, const char *pSqlStmt) { - - - -/* SQLFreeStmt(hstmt, SQL_CLOSE); - if (SQLExecDirect(hstmt, (UCHAR FAR *) pSqlStmt, SQL_NTS) == SQL_SUCCESS) - return(TRUE); - else - { - pDb->DispAllErrors(henv, hdbc, hstmt); - return(FALSE); - } -*/ - - char sqlStmt[DB_MAX_STATEMENT_LEN]; - // Set the selectForUpdate member variable if (forUpdate) // The user may wish to select for update, but the DBMS may not be capable selectForUpdate = CanSelectForUpdate(); @@ -584,29 +621,35 @@ bool wxDbTable::query(int queryType, bool forUpdate, bool distinct, const char * // Set the SQL SELECT string if (queryType != DB_SELECT_STATEMENT) // A select statement was not passed in, - { // so generate a select statement. + { // so generate a select statement. BuildSelectStmt(sqlStmt, queryType, distinct); pDb->WriteSqlLog(sqlStmt); - } else wxStrcpy(sqlStmt, pSqlStmt); + } +/* + 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); + return(TRUE); else - { + { pDb->DispAllErrors(henv, hdbc, hstmt); return(FALSE); - } - + } +*/ // Make sure the cursor is closed first - if (! CloseCursor(hstmt)) - return(FALSE); + if (!CloseCursor(hstmt)) + return(FALSE); // Execute the SQL SELECT statement int retcode; retcode = SQLExecDirect(hstmt, (UCHAR FAR *) (queryType == DB_SELECT_STATEMENT ? pSqlStmt : sqlStmt), SQL_NTS); if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) - return(pDb->DispAllErrors(henv, hdbc, hstmt)); + return(pDb->DispAllErrors(henv, hdbc, hstmt)); // Completed successfully return(TRUE); @@ -618,26 +661,50 @@ bool wxDbTable::query(int queryType, bool forUpdate, bool distinct, const char * /********** wxDbTable::Open() **********/ -bool wxDbTable::Open(void) +bool wxDbTable::Open(bool checkPrivileges) { if (!pDb) return FALSE; + int i; wxString sqlStmt; + wxString s; + s = ""; // Verify that the table exists in the database - if (!pDb->TableExists(tableName,pDb->GetUsername(),tablePath)) + if (!pDb->TableExists(tableName,/*pDb->GetUsername()*/NULL,tablePath)) { - wxString s; - if (wxStrcmp(tablePath,"")) - s.sprintf(wxT("Error opening '%s/%s'.\n"),tablePath,tableName); + s = "Table/view does not exist in the database"; + if ( *(pDb->dbInf.accessibleTables) == 'Y') + s += ", or you have no permissions.\n"; else - s.sprintf(wxT("Error opening '%s'.\n"), tableName); - if (!pDb->TableExists(tableName,NULL,tablePath)) - s += wxT("Table/view does not exist in the database.\n"); + s += ".\n"; + } + 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,"SELECT",NULL,pDb->GetUsername(),tablePath)) + s = "Current logged in user does not have sufficient privileges to access this table.\n"; + } + + if (!s.IsEmpty()) + { + wxString p; + + if (wxStrcmp(tablePath,"")) + p.sprintf("Error opening '%s/%s'.\n",tablePath,tableName); else - s += wxT("Current logged in user does not have sufficient privileges to access this table.\n"); - pDb->LogError(s.c_str()); + p.sprintf("Error opening '%s'.\n", tableName); + + p += s; + pDb->LogError(p.GetData()); + return(FALSE); } @@ -645,21 +712,20 @@ bool wxDbTable::Open(void) // the wxDbTable object and the ODBC record. if (!queryOnly) { - if (!bindInsertParams()) // Inserts return(FALSE); if (!bindUpdateParams()) // Updates return(FALSE); - } + if (!bindCols(*hstmtDefault)) // Selects return(FALSE); - + if (!bindCols(hstmtInternal)) // Internal use only return(FALSE); - - /* + + /* * Do NOT bind the hstmtCount cursor!!! */ @@ -680,7 +746,7 @@ bool wxDbTable::Open(void) needComma = FALSE; sqlStmt += ") VALUES ("; - int insertableCount = 0; + int insertableCount = 0; for (i = 0; i < noCols; i++) { @@ -690,19 +756,17 @@ bool wxDbTable::Open(void) sqlStmt += ","; sqlStmt += "?"; needComma = TRUE; - insertableCount++; + insertableCount++; } sqlStmt += ")"; - -// pDb->WriteSqlLog(sqlStmt); - + // Prepare the insert statement for execution if (insertableCount) - { + { if (SQLPrepare(hstmtInsert, (UCHAR FAR *) sqlStmt.c_str(), SQL_NTS) != SQL_SUCCESS) return(pDb->DispAllErrors(henv, hdbc, hstmtInsert)); } - else + else insertable= FALSE; } @@ -759,6 +823,7 @@ bool wxDbTable::GetPrev(void) } else return(getRec(SQL_FETCH_PRIOR)); + } // wxDbTable::GetPrev() @@ -772,6 +837,7 @@ bool wxDbTable::operator--(int) } else return(getRec(SQL_FETCH_PRIOR)); + } // wxDbTable::operator-- @@ -785,6 +851,7 @@ bool wxDbTable::GetFirst(void) } else return(getRec(SQL_FETCH_FIRST)); + } // wxDbTable::GetFirst() @@ -798,6 +865,7 @@ bool wxDbTable::GetLast(void) } else return(getRec(SQL_FETCH_LAST)); + } // wxDbTable::GetLast() @@ -875,40 +943,40 @@ void wxDbTable::BuildSelectStmt(char *pSqlStmt, int typeOfSelect, bool distinct) // or build a where clause. The typeOfSelect determines this. switch(typeOfSelect) { - case DB_SELECT_WHERE: + case DB_SELECT_WHERE: #if wxODBC_BACKWARD_COMPATABILITY - if (where && wxStrlen(where)) // May not want a where clause!!! + 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 - { - wxStrcat(pSqlStmt, " WHERE "); - wxStrcat(pSqlStmt, where); - } - break; - case DB_SELECT_KEYFIELDS: - BuildWhereClause(whereClause, DB_WHERE_KEYFIELDS); - if (wxStrlen(whereClause)) - { - wxStrcat(pSqlStmt, " WHERE "); - wxStrcat(pSqlStmt, whereClause); - } - break; - case DB_SELECT_MATCHING: - BuildWhereClause(whereClause, DB_WHERE_MATCHING); - if (wxStrlen(whereClause)) - { - wxStrcat(pSqlStmt, " WHERE "); - wxStrcat(pSqlStmt, whereClause); - } - break; + { + wxStrcat(pSqlStmt, " WHERE "); + wxStrcat(pSqlStmt, where); + } + break; + case DB_SELECT_KEYFIELDS: + BuildWhereClause(whereClause, DB_WHERE_KEYFIELDS); + if (wxStrlen(whereClause)) + { + wxStrcat(pSqlStmt, " WHERE "); + wxStrcat(pSqlStmt, whereClause); + } + break; + case DB_SELECT_MATCHING: + BuildWhereClause(whereClause, DB_WHERE_MATCHING); + if (wxStrlen(whereClause)) + { + wxStrcat(pSqlStmt, " WHERE "); + wxStrcat(pSqlStmt, whereClause); + } + break; } // Append the ORDER BY clause #if wxODBC_BACKWARD_COMPATABILITY if (orderBy && wxStrlen(orderBy)) #else - if (orderBy.Length()) + if (orderBy.Length()) #endif { wxStrcat(pSqlStmt, " ORDER BY "); @@ -960,7 +1028,6 @@ bool wxDbTable::CreateTable(bool attemptDrop) return FALSE; int i, j; -// char sqlStmt[DB_MAX_STATEMENT_LEN]; wxString sqlStmt; #ifdef DBDEBUG_CONSOLE @@ -1009,7 +1076,7 @@ bool wxDbTable::CreateTable(bool attemptDrop) continue; // Comma Delimiter if (needComma) - sqlStmt += ","; + sqlStmt += ","; // Column Name sqlStmt += colDefs[i].ColName; sqlStmt += " "; @@ -1017,13 +1084,17 @@ bool wxDbTable::CreateTable(bool attemptDrop) switch(colDefs[i].DbDataType) { case DB_DATA_TYPE_VARCHAR: - sqlStmt += pDb->GetTypeInfVarchar().TypeName; break; + sqlStmt += pDb->GetTypeInfVarchar().TypeName; + break; case DB_DATA_TYPE_INTEGER: - sqlStmt += pDb->GetTypeInfInteger().TypeName; break; + sqlStmt += pDb->GetTypeInfInteger().TypeName; + break; case DB_DATA_TYPE_FLOAT: - sqlStmt += pDb->GetTypeInfFloat().TypeName; break; + sqlStmt += pDb->GetTypeInfFloat().TypeName; + break; case DB_DATA_TYPE_DATE: - sqlStmt += pDb->GetTypeInfDate().TypeName; break; + sqlStmt += pDb->GetTypeInfDate().TypeName; + break; } // For varchars, append the size of the string if (colDefs[i].DbDataType == DB_DATA_TYPE_VARCHAR) @@ -1036,7 +1107,10 @@ bool wxDbTable::CreateTable(bool attemptDrop) sqlStmt += s.c_str(); } - if (pDb->Dbms() == dbmsSYBASE_ASE || pDb->Dbms() == dbmsMY_SQL) + if (pDb->Dbms() == dbmsDB2 || + pDb->Dbms() == dbmsMY_SQL || + pDb->Dbms() == dbmsSYBASE_ASE || + pDb->Dbms() == dbmsMS_SQL_SERVER) { if (colDefs[i].KeyField) { @@ -1101,9 +1175,9 @@ bool wxDbTable::CreateTable(bool attemptDrop) } // Commit the transaction and close the cursor - if (! pDb->CommitTrans()) + if (!pDb->CommitTrans()) return(FALSE); - if (! CloseCursor(hstmt)) + if (!CloseCursor(hstmt)) return(FALSE); // Database table created successfully @@ -1133,13 +1207,13 @@ bool wxDbTable::DropTable() if (SQLExecDirect(hstmt, (UCHAR FAR *) sqlStmt.c_str(), SQL_NTS) != SQL_SUCCESS) { // Check for "Base table not found" error and ignore - pDb->GetNextError(henv, hdbc, hstmt); + pDb->GetNextError(henv, hdbc, hstmt); if (wxStrcmp(pDb->sqlState,"S0002") && wxStrcmp(pDb->sqlState, "S1000")) // "Base table not found" - { + { // Check for product specific error codes - if (!((pDb->Dbms() == dbmsSYBASE_ASA && !wxStrcmp(pDb->sqlState,"42000")) || // 5.x (and lower?) - (pDb->Dbms() == dbmsSYBASE_ASE && !wxStrcmp(pDb->sqlState,"37000")) || - (pDb->Dbms() == dbmsPOSTGRES && !wxStrcmp(pDb->sqlState,"08S01")))) + if (!((pDb->Dbms() == dbmsSYBASE_ASA && !wxStrcmp(pDb->sqlState,"42000")) || // 5.x (and lower?) + (pDb->Dbms() == dbmsSYBASE_ASE && !wxStrcmp(pDb->sqlState,"37000")) || + (pDb->Dbms() == dbmsPOSTGRES && !wxStrcmp(pDb->sqlState,"08S01")))) { pDb->DispNextError(); pDb->DispAllErrors(henv, hdbc, hstmt); @@ -1163,24 +1237,104 @@ bool wxDbTable::DropTable() /********** wxDbTable::CreateIndex() **********/ bool wxDbTable::CreateIndex(const char * idxName, bool unique, int noIdxCols, wxDbIdxDef *pIdxDefs, bool attemptDrop) { -// char sqlStmt[DB_MAX_STATEMENT_LEN]; wxString sqlStmt; // Drop the index first if (attemptDrop && !DropIndex(idxName)) 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, + // it may not be known which columns are necessarily going to be part of an index (e.g. the + // table was created, then months later you determine that an additional index while + // give better performance, so you want to add an index). + // + // The following block of code will modify the column definition to make the column be + // defined with the "NOT NULL" qualifier. + if (pDb->Dbms() == dbmsMY_SQL) + { + wxString sqlStmt; + int i; + bool ok = TRUE; + for (i = 0; i < noIdxCols && ok; i++) + { + int j = 0; + 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)) + { + if (wxStrcmp(colDefs[j].ColName,pIdxDefs[i].ColName) == 0) + found = TRUE; + if (!found) + j++; + } + + if (found) + { + wxString typeNameAndSize; + + switch(colDefs[j].DbDataType) + { + case DB_DATA_TYPE_VARCHAR: + typeNameAndSize = pDb->GetTypeInfVarchar().TypeName; + break; + case DB_DATA_TYPE_INTEGER: + typeNameAndSize = pDb->GetTypeInfInteger().TypeName; + break; + case DB_DATA_TYPE_FLOAT: + typeNameAndSize = pDb->GetTypeInfFloat().TypeName; + break; + case DB_DATA_TYPE_DATE: + typeNameAndSize = pDb->GetTypeInfDate().TypeName; + break; + } + + // For varchars, append the size of the string + if (colDefs[j].DbDataType == DB_DATA_TYPE_VARCHAR) + { + wxString s; + s.sprintf("(%d)", colDefs[i].SzDataObj); + typeNameAndSize += s.c_str(); + } + + sqlStmt.sprintf("ALTER TABLE %s MODIFY %s %s NOT NULL",tableName,pIdxDefs[i].ColName,typeNameAndSize.c_str()); + ok = pDb->ExecSql(sqlStmt.c_str()); + + if (!ok) + { + 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; + } + } + else + ok = FALSE; + } + if (ok) + pDb->CommitTrans(); + else + { + pDb->RollbackTrans(); + return(FALSE); + } + } + // Build a CREATE INDEX statement sqlStmt = "CREATE "; if (unique) sqlStmt += "UNIQUE "; - + sqlStmt += "INDEX "; sqlStmt += idxName; sqlStmt += " ON "; sqlStmt += tableName; sqlStmt += " ("; - + // Append list of columns making up index int i; for (i = 0; i < noIdxCols; i++) @@ -1239,9 +1393,10 @@ bool wxDbTable::DropIndex(const char * idxName) wxString sqlStmt; - if (pDb->Dbms() == dbmsACCESS) + if (pDb->Dbms() == dbmsACCESS || pDb->Dbms() == dbmsMY_SQL) sqlStmt.sprintf("DROP INDEX %s ON %s",idxName,tableName); - else if (pDb->Dbms() == dbmsSYBASE_ASE) + else if ((pDb->Dbms() == dbmsMS_SQL_SERVER) || + (pDb->Dbms() == dbmsSYBASE_ASE)) sqlStmt.sprintf("DROP INDEX %s.%s",tableName,idxName); else sqlStmt.sprintf("DROP INDEX %s",idxName); @@ -1259,13 +1414,13 @@ bool wxDbTable::DropIndex(const char * idxName) if (wxStrcmp(pDb->sqlState,"S0012")) // "Index not found" { // Check for product specific error codes - if (!((pDb->Dbms() == dbmsSYBASE_ASA && !wxStrcmp(pDb->sqlState,"42000")) || // v5.x (and lower?) - (pDb->Dbms() == dbmsSYBASE_ASE && !wxStrcmp(pDb->sqlState,"37000")) || - (pDb->Dbms() == dbmsMS_SQL_SERVER && !wxStrcmp(pDb->sqlState,"S1000")) || - (pDb->Dbms() == dbmsSYBASE_ASE && !wxStrcmp(pDb->sqlState,"S0002")) || // Base table not found - (pDb->Dbms() == dbmsMY_SQL && !wxStrcmp(pDb->sqlState,"42S02")) || // untested - (pDb->Dbms() == dbmsPOSTGRES && !wxStrcmp(pDb->sqlState,"08S01")) - )) + if (!((pDb->Dbms() == dbmsSYBASE_ASA && !wxStrcmp(pDb->sqlState,"42000")) || // v5.x (and lower?) + (pDb->Dbms() == dbmsSYBASE_ASE && !wxStrcmp(pDb->sqlState,"37000")) || + (pDb->Dbms() == dbmsMS_SQL_SERVER && !wxStrcmp(pDb->sqlState,"S1000")) || + (pDb->Dbms() == dbmsSYBASE_ASE && !wxStrcmp(pDb->sqlState,"S0002")) || // Base table not found + (pDb->Dbms() == dbmsMY_SQL && !wxStrcmp(pDb->sqlState,"42S12")) || // tested by Christopher Ludwik Marino-Cebulski using v3.23.21beta + (pDb->Dbms() == dbmsPOSTGRES && !wxStrcmp(pDb->sqlState,"08S01")) + )) { pDb->DispNextError(); pDb->DispAllErrors(henv, hdbc, hstmt); @@ -1286,6 +1441,42 @@ bool wxDbTable::DropIndex(const char * idxName) } // wxDbTable::DropIndex() +/********** wxDbTable::SetOrderByColNums() **********/ +bool wxDbTable::SetOrderByColNums(int first, ... ) +{ + int colNo = first; + va_list argptr; + + bool abort = FALSE; + wxString tempStr; + + va_start(argptr, first); /* Initialize variable arguments. */ + while (!abort && (colNo != 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) + { + abort = TRUE; + continue; + } + + if (colNo != first) + tempStr += ","; + + tempStr += colDefs[colNo].ColName; + colNo = va_arg (argptr, int); + } + va_end (argptr); /* Reset variable arguments. */ + + SetOrderByClause(tempStr.c_str()); + + return (!abort); +} // wxDbTable::SetOrderByColNums() + + /********** wxDbTable::Insert() **********/ int wxDbTable::Insert(void) { @@ -1473,34 +1664,34 @@ void wxDbTable::BuildUpdateStmt(char *pSqlStmt, int typeOfUpd, const char *pWher wxStrcat(pSqlStmt, " WHERE "); switch(typeOfUpd) { - 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()) - { - SDWORD cb; - char rowid[wxDB_ROWID_LEN]; - - // 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) + 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()) { - wxStrcat(pSqlStmt, "ROWID = '"); - wxStrcat(pSqlStmt, rowid); - wxStrcat(pSqlStmt, "'"); - break; + SDWORD cb; + char rowid[wxDB_ROWID_LEN]; + + // 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) + { + wxStrcat(pSqlStmt, "ROWID = '"); + wxStrcat(pSqlStmt, rowid); + wxStrcat(pSqlStmt, "'"); + break; + } } - } - // Unable to delete by ROWID, so build a WHERE - // clause based on the keyfields. - BuildWhereClause(whereClause, DB_WHERE_KEYFIELDS); - wxStrcat(pSqlStmt, whereClause); - break; - case DB_UPD_WHERE: - wxStrcat(pSqlStmt, pWhereClause); - break; + // Unable to delete by ROWID, so build a WHERE + // clause based on the keyfields. + BuildWhereClause(whereClause, DB_WHERE_KEYFIELDS); + wxStrcat(pSqlStmt, whereClause); + break; + case DB_UPD_WHERE: + wxStrcat(pSqlStmt, pWhereClause); + break; } } // BuildUpdateStmt() @@ -1529,38 +1720,38 @@ void wxDbTable::BuildDeleteStmt(char *pSqlStmt, int typeOfDel, const char *pWher // Append the WHERE clause to the SQL DELETE statement switch(typeOfDel) { - case DB_DEL_KEYFIELDS: - // 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()) - { - SDWORD cb; - char rowid[wxDB_ROWID_LEN]; - - // 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) + case DB_DEL_KEYFIELDS: + // 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()) { - wxStrcat(pSqlStmt, "ROWID = '"); - wxStrcat(pSqlStmt, rowid); - wxStrcat(pSqlStmt, "'"); - break; + SDWORD cb; + char rowid[wxDB_ROWID_LEN]; + + // 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) + { + wxStrcat(pSqlStmt, "ROWID = '"); + wxStrcat(pSqlStmt, rowid); + wxStrcat(pSqlStmt, "'"); + break; + } } - } - // Unable to delete by ROWID, so build a WHERE - // clause based on the keyfields. - BuildWhereClause(whereClause, DB_WHERE_KEYFIELDS); - wxStrcat(pSqlStmt, whereClause); - break; - case DB_DEL_WHERE: - wxStrcat(pSqlStmt, pWhereClause); - break; - case DB_DEL_MATCHING: - BuildWhereClause(whereClause, DB_WHERE_MATCHING); - wxStrcat(pSqlStmt, whereClause); - break; + // Unable to delete by ROWID, so build a WHERE + // clause based on the keyfields. + BuildWhereClause(whereClause, DB_WHERE_KEYFIELDS); + wxStrcat(pSqlStmt, whereClause); + break; + case DB_DEL_WHERE: + wxStrcat(pSqlStmt, pWhereClause); + break; + case DB_DEL_MATCHING: + BuildWhereClause(whereClause, DB_WHERE_MATCHING); + wxStrcat(pSqlStmt, whereClause); + break; } } // BuildDeleteStmt() @@ -1583,7 +1774,7 @@ void wxDbTable::BuildWhereClause(char *pWhereClause, int typeOfWhere, { // 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)))) + (typeOfWhere == DB_WHERE_MATCHING && (!IsColNull(i)))) { // Skip over timestamp columns if (colDefs[i].SqlCtype == SQL_C_TIMESTAMP) @@ -1606,27 +1797,27 @@ void wxDbTable::BuildWhereClause(char *pWhereClause, int typeOfWhere, wxStrcat(pWhereClause, " = "); switch(colDefs[i].SqlCtype) { - case SQL_C_CHAR: - sprintf(colValue, "'%s'", (UCHAR FAR *) colDefs[i].PtrDataObj); - break; - case SQL_C_SSHORT: - sprintf(colValue, "%hi", *((SWORD *) colDefs[i].PtrDataObj)); - break; - case SQL_C_USHORT: - sprintf(colValue, "%hu", *((UWORD *) colDefs[i].PtrDataObj)); - break; - case SQL_C_SLONG: - sprintf(colValue, "%li", *((SDWORD *) colDefs[i].PtrDataObj)); - break; - case SQL_C_ULONG: - sprintf(colValue, "%lu", *((UDWORD *) colDefs[i].PtrDataObj)); - break; - case SQL_C_FLOAT: - sprintf(colValue, "%.6f", *((SFLOAT *) colDefs[i].PtrDataObj)); - break; - case SQL_C_DOUBLE: - sprintf(colValue, "%.6f", *((SDOUBLE *) colDefs[i].PtrDataObj)); - break; + case SQL_C_CHAR: + sprintf(colValue, "'%s'", (UCHAR FAR *) colDefs[i].PtrDataObj); + break; + case SQL_C_SSHORT: + sprintf(colValue, "%hi", *((SWORD *) colDefs[i].PtrDataObj)); + break; + case SQL_C_USHORT: + sprintf(colValue, "%hu", *((UWORD *) colDefs[i].PtrDataObj)); + break; + case SQL_C_SLONG: + sprintf(colValue, "%li", *((SDWORD *) colDefs[i].PtrDataObj)); + break; + case SQL_C_ULONG: + sprintf(colValue, "%lu", *((UDWORD *) colDefs[i].PtrDataObj)); + break; + case SQL_C_FLOAT: + sprintf(colValue, "%.6f", *((SFLOAT *) colDefs[i].PtrDataObj)); + break; + case SQL_C_DOUBLE: + sprintf(colValue, "%.6f", *((SDOUBLE *) colDefs[i].PtrDataObj)); + break; } wxStrcat(pWhereClause, colValue); } @@ -1637,42 +1828,52 @@ void wxDbTable::BuildWhereClause(char *pWhereClause, int typeOfWhere, /********** wxDbTable::IsColNull() **********/ bool wxDbTable::IsColNull(int colNo) { +/* + 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) { - case SQL_C_CHAR: - return(((UCHAR FAR *) colDefs[colNo].PtrDataObj)[0] == 0); - case SQL_C_SSHORT: - return(( *((SWORD *) colDefs[colNo].PtrDataObj)) == 0); - case SQL_C_USHORT: - return(( *((UWORD*) colDefs[colNo].PtrDataObj)) == 0); - case SQL_C_SLONG: - return(( *((SDWORD *) colDefs[colNo].PtrDataObj)) == 0); - case SQL_C_ULONG: - return(( *((UDWORD *) colDefs[colNo].PtrDataObj)) == 0); - case SQL_C_FLOAT: - return(( *((SFLOAT *) colDefs[colNo].PtrDataObj)) == 0); - case SQL_C_DOUBLE: - return((*((SDOUBLE *) colDefs[colNo].PtrDataObj)) == 0); - case SQL_C_TIMESTAMP: - TIMESTAMP_STRUCT *pDt; - pDt = (TIMESTAMP_STRUCT *) colDefs[colNo].PtrDataObj; - if (pDt->year == 0 && pDt->month == 0 && pDt->day == 0) + case SQL_C_CHAR: + return(((UCHAR FAR *) colDefs[colNo].PtrDataObj)[0] == 0); + case SQL_C_SSHORT: + return(( *((SWORD *) colDefs[colNo].PtrDataObj)) == 0); + case SQL_C_USHORT: + return(( *((UWORD*) colDefs[colNo].PtrDataObj)) == 0); + case SQL_C_SLONG: + return(( *((SDWORD *) colDefs[colNo].PtrDataObj)) == 0); + case SQL_C_ULONG: + return(( *((UDWORD *) colDefs[colNo].PtrDataObj)) == 0); + case SQL_C_FLOAT: + return(( *((SFLOAT *) colDefs[colNo].PtrDataObj)) == 0); + case SQL_C_DOUBLE: + return((*((SDOUBLE *) colDefs[colNo].PtrDataObj)) == 0); + case SQL_C_TIMESTAMP: + TIMESTAMP_STRUCT *pDt; + pDt = (TIMESTAMP_STRUCT *) colDefs[colNo].PtrDataObj; + if (pDt->year == 0 && pDt->month == 0 && pDt->day == 0) + return(TRUE); + else + return(FALSE); + default: return(TRUE); - else - return(FALSE); - default: - return(TRUE); } +*/ + return (colDefs[colNo].Null); } // wxDbTable::IsColNull() /********** wxDbTable::CanSelectForUpdate() **********/ bool wxDbTable::CanSelectForUpdate(void) { + if (queryOnly) + return FALSE; + if (pDb->Dbms() == dbmsMY_SQL) return FALSE; - if (pDb->dbInf.posStmts & SQL_PS_SELECT_FOR_UPDATE) + if ((pDb->Dbms() == dbmsORACLE) || + (pDb->dbInf.posStmts & SQL_PS_SELECT_FOR_UPDATE)) return(TRUE); else return(FALSE); @@ -1708,39 +1909,38 @@ bool wxDbTable::IsCursorClosedOnCommit(void) } // wxDbTable::IsCursorClosedOnCommit() -/********** wxDbTable::ClearMemberVars() **********/ -void wxDbTable::ClearMemberVars(void) + +/********** wxDbTable::ClearMemberVar() **********/ +void wxDbTable::ClearMemberVar(int colNo, bool setToNull) { - // Loop through the columns setting each member variable to zero - int i; - for (i = 0; i < noCols; i++) + assert(colNo < noCols); + + switch(colDefs[colNo].SqlCtype) { - switch(colDefs[i].SqlCtype) - { case SQL_C_CHAR: - ((UCHAR FAR *) colDefs[i].PtrDataObj)[0] = 0; + ((UCHAR FAR *) colDefs[colNo].PtrDataObj)[0] = 0; break; case SQL_C_SSHORT: - *((SWORD *) colDefs[i].PtrDataObj) = 0; + *((SWORD *) colDefs[colNo].PtrDataObj) = 0; break; case SQL_C_USHORT: - *((UWORD*) colDefs[i].PtrDataObj) = 0; + *((UWORD*) colDefs[colNo].PtrDataObj) = 0; break; case SQL_C_SLONG: - *((SDWORD *) colDefs[i].PtrDataObj) = 0; + *((SDWORD *) colDefs[colNo].PtrDataObj) = 0; break; case SQL_C_ULONG: - *((UDWORD *) colDefs[i].PtrDataObj) = 0; + *((UDWORD *) colDefs[colNo].PtrDataObj) = 0; break; case SQL_C_FLOAT: - *((SFLOAT *) colDefs[i].PtrDataObj) = 0.0f; + *((SFLOAT *) colDefs[colNo].PtrDataObj) = 0.0f; break; case SQL_C_DOUBLE: - *((SDOUBLE *) colDefs[i].PtrDataObj) = 0.0f; + *((SDOUBLE *) colDefs[colNo].PtrDataObj) = 0.0f; break; case SQL_C_TIMESTAMP: TIMESTAMP_STRUCT *pDt; - pDt = (TIMESTAMP_STRUCT *) colDefs[i].PtrDataObj; + pDt = (TIMESTAMP_STRUCT *) colDefs[colNo].PtrDataObj; pDt->year = 0; pDt->month = 0; pDt->day = 0; @@ -1749,10 +1949,22 @@ void wxDbTable::ClearMemberVars(void) pDt->second = 0; pDt->fraction = 0; break; - - } } + if (setToNull) + SetColNull(colNo); +} // wxDbTable::ClearMemberVar() + + +/********** wxDbTable::ClearMemberVars() **********/ +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); + } // wxDbTable::ClearMemberVars() @@ -1775,9 +1987,9 @@ bool wxDbTable::SetQueryTimeout(UDWORD nSeconds) /********** wxDbTable::SetColDefs() **********/ -void wxDbTable::SetColDefs (int index, const char *fieldName, int dataType, void *pData, - int cType, int size, bool keyField, bool upd, - bool insAllow, bool derivedCol) +void wxDbTable::SetColDefs(int index, const char *fieldName, int dataType, void *pData, + int cType, int size, bool keyField, bool upd, + bool insAllow, bool derivedCol) { if (!colDefs) // May happen if the database connection fails return; @@ -1813,8 +2025,8 @@ void wxDbTable::SetColDefs (int index, const char *fieldName, int dataType, void } // wxDbTable::SetColDefs() -/********** wxDbTable::SetColDef() **********/ -wxDbColDataPtr* wxDbTable::SetColDefs (wxDbColInf *pColInfs, ULONG numCols) +/********** wxDbTable::SetColDefs() **********/ +wxDbColDataPtr* wxDbTable::SetColDefs(wxDbColInf *pColInfs, ULONG numCols) { assert(pColInfs); wxDbColDataPtr *pColDataPtrs = NULL; @@ -1822,7 +2034,6 @@ wxDbColDataPtr* wxDbTable::SetColDefs (wxDbColInf *pColInfs, ULONG numCols) if (pColInfs) { ULONG index; - pColDataPtrs = new wxDbColDataPtr[numCols+1]; @@ -1832,14 +2043,11 @@ wxDbColDataPtr* wxDbTable::SetColDefs (wxDbColInf *pColInfs, ULONG numCols) switch (pColInfs[index].dbDataType) { case DB_DATA_TYPE_VARCHAR: - { pColDataPtrs[index].PtrDataObj = new char[pColInfs[index].bufferLength+1]; pColDataPtrs[index].SzDataObj = pColInfs[index].columnSize; pColDataPtrs[index].SqlCtype = SQL_C_CHAR; break; - } case DB_DATA_TYPE_INTEGER: - { // Can be long or short if (pColInfs[index].bufferLength == sizeof(long)) { @@ -1854,9 +2062,7 @@ wxDbColDataPtr* wxDbTable::SetColDefs (wxDbColInf *pColInfs, ULONG numCols) pColDataPtrs[index].SqlCtype = SQL_C_SSHORT; } break; - } case DB_DATA_TYPE_FLOAT: - { // Can be float or double if (pColInfs[index].bufferLength == sizeof(float)) { @@ -1871,21 +2077,19 @@ wxDbColDataPtr* wxDbTable::SetColDefs (wxDbColInf *pColInfs, ULONG numCols) pColDataPtrs[index].SqlCtype = SQL_C_DOUBLE; } break; - } case DB_DATA_TYPE_DATE: - { pColDataPtrs[index].PtrDataObj = new TIMESTAMP_STRUCT; pColDataPtrs[index].SzDataObj = sizeof(TIMESTAMP_STRUCT); pColDataPtrs[index].SqlCtype = SQL_C_TIMESTAMP; break; - } } - - SetColDefs (index,pColInfs[index].colName,pColInfs[index].dbDataType, pColDataPtrs[index].PtrDataObj, pColDataPtrs[index].SqlCtype, pColDataPtrs[index].SzDataObj); + SetColDefs (index,pColInfs[index].colName,pColInfs[index].dbDataType, pColDataPtrs[index].PtrDataObj, pColDataPtrs[index].SqlCtype, pColDataPtrs[index].SzDataObj); } } + return (pColDataPtrs); -} // wxDbTable::SetColDef() + +} // wxDbTable::SetColDefs() /********** wxDbTable::SetCursor() **********/ @@ -1902,7 +2106,7 @@ void wxDbTable::SetCursor(HSTMT *hstmtActivate) /********** wxDbTable::Count(const char *) **********/ ULONG wxDbTable::Count(const char *args) { - ULONG l; + ULONG count; wxString sqlStmt; SDWORD cb; @@ -1955,7 +2159,7 @@ ULONG wxDbTable::Count(const char *args) } // Obtain the result - if (SQLGetData(*hstmtCount, 1, SQL_C_ULONG, &l, sizeof(l), &cb) != SQL_SUCCESS) + if (SQLGetData(*hstmtCount, 1, SQL_C_ULONG, &count, sizeof(count), &cb) != SQL_SUCCESS) { pDb->DispAllErrors(henv, hdbc, *hstmtCount); return(0); @@ -1966,7 +2170,7 @@ ULONG wxDbTable::Count(const char *args) pDb->DispAllErrors(henv, hdbc, *hstmtCount); // Return the record count - return(l); + return(count); } // wxDbTable::Count() @@ -2037,19 +2241,24 @@ bool wxDbTable::Refresh(void) } // wxDbTable::Refresh() -/********** wxDbTable::SetNull(int colNo) **********/ -bool wxDbTable::SetNull(int colNo) +/********** wxDbTable::SetColNull(int colNo, bool set) **********/ +bool wxDbTable::SetColNull(int colNo, bool set) { if (colNo < noCols) - return(colDefs[colNo].Null = TRUE); + { + 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); + } else return(FALSE); -} // wxDbTable::SetNull(int colNo) +} // wxDbTable::SetColNull(int colNo) -/********** wxDbTable::SetNull(char *colName) **********/ -bool wxDbTable::SetNull(const char *colName) +/********** wxDbTable::SetColNull(char *colName, bool set) **********/ +bool wxDbTable::SetColNull(const char *colName, bool set) { int i; for (i = 0; i < noCols; i++) @@ -2059,11 +2268,16 @@ bool wxDbTable::SetNull(const char *colName) } if (i < noCols) - return(colDefs[i].Null = TRUE); + { + colDefs[i].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); + } else return(FALSE); -} // wxDbTable::SetNull(char *colName) +} // wxDbTable::SetColNull(char *colName) /********** wxDbTable::GetNewCursor() **********/