X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/47765ba2b8bc04fdc00257dcba45dcdb34c451e4..30b5fc118f6fa8bad8cd3692ca42c164aa5007f9:/src/common/dbtable.cpp diff --git a/src/common/dbtable.cpp b/src/common/dbtable.cpp index f5bc7f5b29..f73f17089d 100644 --- a/src/common/dbtable.cpp +++ b/src/common/dbtable.cpp @@ -2,6 +2,7 @@ // Name: dbtable.cpp // Purpose: Implementation of the wxTable 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 @@ -40,17 +41,22 @@ #endif #ifdef DBDEBUG_CONSOLE -# include + #include #endif #ifdef __BORLANDC__ - #pragma hdrstop + #pragma hdrstop #endif //__BORLANDC__ #if wxMAJOR_VERSION == 2 -# ifndef WX_PRECOMP -# include -# endif //WX_PRECOMP + #ifndef WX_PRECOMP + #include "wx/string.h" + #include "wx/object.h" + #include "wx/list.h" + #include "wx/utils.h" + #include "wx/msgdlg.h" + #endif + #include "wx/filefn.h" #endif #if wxMAJOR_VERSION == 1 @@ -70,6 +76,7 @@ #include #include #include + #if wxMAJOR_VERSION == 1 #include "table.h" #elif wxMAJOR_VERSION == 2 @@ -90,19 +97,19 @@ ULONG lastTableID = 0; -#if __WXDEBUG__ > 0 +#ifdef __WXDEBUG__ wxList TablesInUse; #endif /********** wxTable::wxTable() **********/ wxTable::wxTable(wxDB *pwxDB, const char *tblName, const int nCols, - const char *qryTblName, bool qryOnly, char *tblPath) + const char *qryTblName, bool qryOnly, const char *tblPath) { pDb = pwxDB; // Pointer to the wxDB object - henv = 0; - hdbc = 0; - hstmt = 0; + henv = 0; + hdbc = 0; + hstmt = 0; hstmtDefault = 0; // Initialized below hstmtCount = 0; // Initialized first time it is needed hstmtInsert = 0; @@ -112,24 +119,23 @@ wxTable::wxTable(wxDB *pwxDB, const char *tblName, const int nCols, colDefs = 0; tableID = 0; noCols = nCols; // No. of cols in the table - where = 0; // Where clause + where = 0; // Where clause orderBy = 0; // Order By clause - from = 0; // From clause - selectForUpdate = FALSE; // SELECT ... FOR UPDATE; Indicates whether to include the FOR UPDATE phrase + from = 0; // From clause + selectForUpdate = FALSE; // SELECT ... FOR UPDATE; Indicates whether to include the FOR UPDATE phrase queryOnly = qryOnly; assert (tblName); - strcpy(tableName, tblName); // Table Name + wxStrcpy(tableName, tblName); // Table Name if (tblPath) - strcpy(tablePath, tblPath); // Table Path - used for dBase files + wxStrcpy(tablePath, tblPath); // Table Path - used for dBase files if (qryTblName) // Name of the table/view to query - strcpy(queryTableName, qryTblName); + wxStrcpy(queryTableName, qryTblName); else - strcpy(queryTableName, tblName); + wxStrcpy(queryTableName, tblName); -// assert(pDb); // Assert is placed after table name is assigned for error reporting reasons if (!pDb) return; @@ -139,7 +145,7 @@ wxTable::wxTable(wxDB *pwxDB, const char *tblName, const int nCols, tableID = ++lastTableID; sprintf(s, "wxTable constructor (%-20s) tableID:[%6lu] pDb:[%p]", tblName,tableID,pDb); -#if __WXDEBUG__ > 0 +#ifdef __WXDEBUG__ CstructTablesInUse *tableInUse; tableInUse = new CstructTablesInUse(); tableInUse->tableName = tblName; @@ -156,7 +162,7 @@ wxTable::wxTable(wxDB *pwxDB, const char *tblName, const int nCols, // Allocate space for column definitions if (noCols) - colDefs = new CcolDef[noCols]; // Points to the first column defintion + colDefs = new wxColDef[noCols]; // Points to the first column defintion // Allocate statement handles for the table if (!queryOnly) @@ -181,7 +187,7 @@ wxTable::wxTable(wxDB *pwxDB, const char *tblName, const int nCols, { // Check to see if cursor type is supported pDb->GetNextError(henv, hdbc, hstmtInternal); - if (! strcmp(pDb->sqlState, "01S02")) // Option Value Changed + if (! wxStrcmp(pDb->sqlState, "01S02")) // Option Value Changed { // Datasource does not support static cursors. Driver // will substitute a cursor type. Call SQLGetStmtOption() @@ -235,6 +241,7 @@ wxTable::wxTable(wxDB *pwxDB, const char *tblName, const int nCols, } // wxTable::wxTable() + /********** wxTable::~wxTable() **********/ wxTable::~wxTable() { @@ -245,8 +252,7 @@ wxTable::~wxTable() pDb->WriteSqlLog(s); } -#ifndef PROGRAM_FP4UPG -#if __WXDEBUG__ > 0 +#ifdef __WXDEBUG__ if (tableID) { bool found = FALSE; @@ -271,7 +277,7 @@ wxTable::~wxTable() } } #endif -#endif + // Decrement the wxDB table count if (pDb) pDb->nTables--; @@ -305,6 +311,262 @@ wxTable::~wxTable() } // wxTable::~wxTable() + + +/***************************** PRIVATE FUNCTIONS *****************************/ + + + +/********** wxTable::bindInsertParams() **********/ +bool wxTable::bindInsertParams(void) +{ + assert(!queryOnly); + if (queryOnly) + return(FALSE); + + SWORD fSqlType = 0; + UDWORD precision = 0; + SWORD scale = 0; + + // Bind each column (that can be inserted) of the table to a parameter marker + int i,colNo; + for (i = 0, colNo = 1; i < noCols; i++) + { + if (! colDefs[i].InsertAllowed) + continue; + switch(colDefs[i].DbDataType) + { + case DB_DATA_TYPE_VARCHAR: + fSqlType = pDb->typeInfVarchar.FsqlType; + precision = colDefs[i].SzDataObj; + scale = 0; + colDefs[i].CbValue = SQL_NTS; + break; + case DB_DATA_TYPE_INTEGER: + fSqlType = pDb->typeInfInteger.FsqlType; + precision = pDb->typeInfInteger.Precision; + scale = 0; + colDefs[i].CbValue = 0; + break; + case DB_DATA_TYPE_FLOAT: + fSqlType = pDb->typeInfFloat.FsqlType; + precision = pDb->typeInfFloat.Precision; + scale = pDb->typeInfFloat.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->typeInfDate.FsqlType; + precision = pDb->typeInfDate.Precision; + scale = 0; + colDefs[i].CbValue = 0; + break; + } + // Null values + if (colDefs[i].Null) + { + colDefs[i].CbValue = SQL_NULL_DATA; + colDefs[i].Null = FALSE; + } + 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 + return(TRUE); + +} // wxTable::bindInsertParams() + + +/********** wxTable::bindUpdateParams() **********/ +bool wxTable::bindUpdateParams(void) +{ + assert(!queryOnly); + if (queryOnly) + return(FALSE); + + SWORD fSqlType = 0; + UDWORD precision = 0; + SWORD scale = 0; + + // Bind each UPDATEABLE column of the table to a parameter marker + int i,colNo; + for (i = 0, colNo = 1; i < noCols; i++) + { + if (! colDefs[i].Updateable) + continue; + switch(colDefs[i].DbDataType) + { + case DB_DATA_TYPE_VARCHAR: + fSqlType = pDb->typeInfVarchar.FsqlType; + precision = colDefs[i].SzDataObj; + scale = 0; + colDefs[i].CbValue = SQL_NTS; + break; + case DB_DATA_TYPE_INTEGER: + fSqlType = pDb->typeInfInteger.FsqlType; + precision = pDb->typeInfInteger.Precision; + scale = 0; + colDefs[i].CbValue = 0; + break; + case DB_DATA_TYPE_FLOAT: + fSqlType = pDb->typeInfFloat.FsqlType; + precision = pDb->typeInfFloat.Precision; + scale = pDb->typeInfFloat.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->typeInfDate.FsqlType; + precision = pDb->typeInfDate.Precision; + scale = 0; + 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)); + } + + // Completed successfully + return(TRUE); + +} // wxTable::bindUpdateParams() + + +/********** wxTable::bindCols() **********/ +bool wxTable::bindCols(HSTMT cursor) +{ + 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)); + } + + // Completed successfully + return(TRUE); + +} // wxTable::bindCols() + + +/********** wxTable::getRec() **********/ +bool wxTable::getRec(UWORD fetchType) +{ + RETCODE retcode; + + if (!pDb->FwdOnlyCursors()) + { + // Fetch the NEXT, PREV, FIRST or LAST record, depending on fetchType + UDWORD cRowsFetched; + UWORD rowStatus; + + retcode = SQLExtendedFetch(hstmt, fetchType, 0, &cRowsFetched, &rowStatus); + if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) + if (retcode == SQL_NO_DATA_FOUND) + return(FALSE); + else + return(pDb->DispAllErrors(henv, hdbc, hstmt)); + } + else + { + // Fetch the next record from the record set + retcode = SQLFetch(hstmt); + if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) + { + if (retcode == SQL_NO_DATA_FOUND) + return(FALSE); + else + return(pDb->DispAllErrors(henv, hdbc, hstmt)); + } + } + + // Completed successfully + return(TRUE); + +} // wxTable::getRec() + + +/********** wxTable::execDelete() **********/ +bool wxTable::execDelete(const char *pSqlStmt) +{ + // Execute the DELETE statement + if (SQLExecDirect(hstmtDelete, (UCHAR FAR *) pSqlStmt, SQL_NTS) != SQL_SUCCESS) + return(pDb->DispAllErrors(henv, hdbc, hstmtDelete)); + + // Record deleted successfully + return(TRUE); + +} // wxTable::execDelete() + + +/********** wxTable::execUpdate() **********/ +bool wxTable::execUpdate(const char *pSqlStmt) +{ + // Execute the UPDATE statement + if (SQLExecDirect(hstmtUpdate, (UCHAR FAR *) pSqlStmt, SQL_NTS) != SQL_SUCCESS) + return(pDb->DispAllErrors(henv, hdbc, hstmtUpdate)); + + // Record deleted successfully + return(TRUE); + +} // wxTable::execUpdate() + + +/********** wxTable::query() **********/ +bool wxTable::query(int queryType, bool forUpdate, bool distinct, char *pSqlStmt) +{ + 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(); + else + selectForUpdate = FALSE; + + // Set the SQL SELECT string + if (queryType != DB_SELECT_STATEMENT) // A select statement was not passed in, + { // so generate a select statement. + GetSelectStmt(sqlStmt, queryType, distinct); + pDb->WriteSqlLog(sqlStmt); + } + + // Make sure the cursor is closed first + 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)); + + // Completed successfully + return(TRUE); + +} // wxTable::query() + + +/***************************** PUBLIC FUNCTIONS *****************************/ + + /********** wxTable::Open() **********/ bool wxTable::Open(void) { @@ -315,10 +577,17 @@ bool wxTable::Open(void) char sqlStmt[DB_MAX_STATEMENT_LEN]; // Verify that the table exists in the database - if (!pDb->TableExists(tableName,NULL,tablePath)) + if (!pDb->TableExists(tableName,pDb->GetUsername(),tablePath)) { - char s[128]; - sprintf(s, "Error opening '%s', table/view does not exist in the database.", tableName); + char s[250]; + if (wxStrcmp(tablePath,"")) + sprintf(s, "Error opening '%s/%s'.\n",tablePath,tableName); + else + sprintf(s, "Error opening '%s'.\n", tableName); + if (!pDb->TableExists(tableName,NULL,tablePath)) + wxStrcat(s,"Table/view does not exist in the database.\n"); + else + wxStrcat(s,"Current logged in user does not have sufficient privileges to access this table.\n"); pDb->LogError(s); return(FALSE); } @@ -350,22 +619,22 @@ bool wxTable::Open(void) if (! colDefs[i].InsertAllowed) continue; if (needComma) - strcat(sqlStmt, ","); - strcat(sqlStmt, colDefs[i].ColName); + wxStrcat(sqlStmt, ","); + wxStrcat(sqlStmt, colDefs[i].ColName); needComma = TRUE; } needComma = FALSE; - strcat(sqlStmt, ") VALUES ("); + wxStrcat(sqlStmt, ") VALUES ("); for (i = 0; i < noCols; i++) { if (! colDefs[i].InsertAllowed) continue; if (needComma) - strcat(sqlStmt, ","); - strcat(sqlStmt, "?"); + wxStrcat(sqlStmt, ","); + wxStrcat(sqlStmt, "?"); needComma = TRUE; } - strcat(sqlStmt, ")"); + wxStrcat(sqlStmt, ")"); // pDb->WriteSqlLog(sqlStmt); @@ -379,6 +648,7 @@ bool wxTable::Open(void) } // wxTable::Open() + /********** wxTable::Query() **********/ bool wxTable::Query(bool forUpdate, bool distinct) { @@ -387,6 +657,7 @@ bool wxTable::Query(bool forUpdate, bool distinct) } // wxTable::Query() + /********** wxTable::QueryBySqlStmt() **********/ bool wxTable::QueryBySqlStmt(char *pSqlStmt) { @@ -396,6 +667,7 @@ bool wxTable::QueryBySqlStmt(char *pSqlStmt) } // wxTable::QueryBySqlStmt() + /********** wxTable::QueryMatching() **********/ bool wxTable::QueryMatching(bool forUpdate, bool distinct) { @@ -404,6 +676,7 @@ bool wxTable::QueryMatching(bool forUpdate, bool distinct) } // wxTable::QueryMatching() + /********** wxTable::QueryOnKeyFields() **********/ bool wxTable::QueryOnKeyFields(bool forUpdate, bool distinct) { @@ -412,40 +685,58 @@ bool wxTable::QueryOnKeyFields(bool forUpdate, bool distinct) } // wxTable::QueryOnKeyFields() -/********** wxTable::query() **********/ -bool wxTable::query(int queryType, bool forUpdate, bool distinct, char *pSqlStmt) -{ - 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(); +/********** wxTable::GetPrev() **********/ +bool wxTable::GetPrev(void) +{ + if (pDb->FwdOnlyCursors()) + { + wxFAIL_MSG(wxT("GetPrev()::Backward scrolling cursors are not enabled for this instance of wxTable")); + return FALSE; + } else - selectForUpdate = FALSE; + return(getRec(SQL_FETCH_PRIOR)); +} // wxTable::GetPrev() - // Set the SQL SELECT string - if (queryType != DB_SELECT_STATEMENT) // A select statement was not passed in, - { // so generate a select statement. - GetSelectStmt(sqlStmt, queryType, distinct); - pDb->WriteSqlLog(sqlStmt); + +/********** wxTable::operator-- **********/ +bool wxTable::operator--(int) +{ + if (pDb->FwdOnlyCursors()) + { + wxFAIL_MSG(wxT("operator--:Backward scrolling cursors are not enabled for this instance of wxTable")); + return FALSE; } + else + return(getRec(SQL_FETCH_PRIOR)); +} // wxTable::operator-- - // Make sure the cursor is closed first - if (! CloseCursor(hstmt)) - return(FALSE); - // Execute the SQL SELECT statement - int retcode; +/********** wxTable::GetFirst() **********/ +bool wxTable::GetFirst(void) +{ + if (pDb->FwdOnlyCursors()) + { + wxFAIL_MSG(wxT("GetFirst():Backward scrolling cursors are not enabled for this instance of wxTable")); + return FALSE; + } + else + return(getRec(SQL_FETCH_FIRST)); +} // wxTable::GetFirst() - 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)); - // Completed successfully - return(TRUE); +/********** wxTable::GetLast() **********/ +bool wxTable::GetLast(void) +{ + if (pDb->FwdOnlyCursors()) + { + wxFAIL_MSG(wxT("GetLast()::Backward scrolling cursors are not enabled for this instance of wxTable")); + return FALSE; + } + else + return(getRec(SQL_FETCH_LAST)); +} // wxTable::GetLast() -} // wxTable::query() /********** wxTable::GetSelectStmt() **********/ void wxTable::GetSelectStmt(char *pSqlStmt, int typeOfSelect, bool distinct) @@ -455,299 +746,124 @@ void wxTable::GetSelectStmt(char *pSqlStmt, int typeOfSelect, bool distinct) whereClause[0] = 0; // Build a select statement to query the database - strcpy(pSqlStmt, "SELECT "); + wxStrcpy(pSqlStmt, "SELECT "); // SELECT DISTINCT values only? if (distinct) - strcat(pSqlStmt, "DISTINCT "); + wxStrcat(pSqlStmt, "DISTINCT "); // Was a FROM clause specified to join tables to the base table? // Available for ::Query() only!!! bool appendFromClause = FALSE; - if (typeOfSelect == DB_SELECT_WHERE && from && strlen(from)) + if (typeOfSelect == DB_SELECT_WHERE && from && wxStrlen(from)) appendFromClause = TRUE; // Add the column list int i; for (i = 0; i < noCols; i++) - { - // If joining tables, the base table column names must be qualified to avoid ambiguity - if (appendFromClause) - { - strcat(pSqlStmt, queryTableName); - strcat(pSqlStmt, "."); - } - strcat(pSqlStmt, colDefs[i].ColName); - if (i + 1 < noCols) - strcat(pSqlStmt, ","); - } - - // If the datasource supports ROWID, get this column as well. Exception: Don't retrieve - // the ROWID if querying distinct records. The rowid will always be unique. - if (!distinct && CanUpdByROWID()) - { - // If joining tables, the base table column names must be qualified to avoid ambiguity - if (appendFromClause) - { - strcat(pSqlStmt, ","); - strcat(pSqlStmt, queryTableName); - strcat(pSqlStmt, ".ROWID"); - } - else - strcat(pSqlStmt, ",ROWID"); - } - - // Append the FROM tablename portion - strcat(pSqlStmt, " FROM "); - strcat(pSqlStmt, queryTableName); - - // Sybase uses the HOLDLOCK keyword to lock a record during query. - // The HOLDLOCK keyword follows the table name in the from clause. - // Each table in the from clause must specify HOLDLOCK or - // NOHOLDLOCK (the default). Note: The "FOR UPDATE" clause - // is parsed but ignored in SYBASE Transact-SQL. - if (selectForUpdate && (pDb->Dbms() == dbmsSYBASE_ASA || pDb->Dbms() == dbmsSYBASE_ASE)) - strcat(pSqlStmt, " HOLDLOCK"); - - if (appendFromClause) - strcat(pSqlStmt, from); - - // Append the WHERE clause. Either append the where clause for the class - // or build a where clause. The typeOfSelect determines this. - switch(typeOfSelect) - { - case DB_SELECT_WHERE: - if (where && strlen(where)) // May not want a where clause!!! - { - strcat(pSqlStmt, " WHERE "); - strcat(pSqlStmt, where); - } - break; - case DB_SELECT_KEYFIELDS: - GetWhereClause(whereClause, DB_WHERE_KEYFIELDS); - if (strlen(whereClause)) - { - strcat(pSqlStmt, " WHERE "); - strcat(pSqlStmt, whereClause); - } - break; - case DB_SELECT_MATCHING: - GetWhereClause(whereClause, DB_WHERE_MATCHING); - if (strlen(whereClause)) - { - strcat(pSqlStmt, " WHERE "); - strcat(pSqlStmt, whereClause); - } - break; - } - - // Append the ORDER BY clause - if (orderBy && strlen(orderBy)) - { - strcat(pSqlStmt, " ORDER BY "); - strcat(pSqlStmt, orderBy); - } - - // SELECT FOR UPDATE if told to do so and the datasource is capable. Sybase - // parses the FOR UPDATE clause but ignores it. See the comment above on the - // HOLDLOCK for Sybase. - if (selectForUpdate && CanSelectForUpdate()) - strcat(pSqlStmt, " FOR UPDATE"); - -} // wxTable::GetSelectStmt() - -/********** wxTable::getRec() **********/ -bool wxTable::getRec(UWORD fetchType) -{ - RETCODE retcode; - -#ifndef FWD_ONLY_CURSORS - // Fetch the NEXT, PREV, FIRST or LAST record, depending on fetchType - UDWORD cRowsFetched; - UWORD rowStatus; - if ((retcode = SQLExtendedFetch(hstmt, fetchType, 0, &cRowsFetched, &rowStatus)) != SQL_SUCCESS) - if (retcode == SQL_NO_DATA_FOUND) - return(FALSE); - else - return(pDb->DispAllErrors(henv, hdbc, hstmt)); -#else - // Fetch the next record from the record set - - retcode = SQLFetch(hstmt); - if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) - { - if (retcode == SQL_NO_DATA_FOUND) - return(FALSE); - else - return(pDb->DispAllErrors(henv, hdbc, hstmt)); - } -#endif - - // Completed successfully - return(TRUE); - -} // wxTable::getRec() - -/********** wxTable::GetRowNum() **********/ -UWORD wxTable::GetRowNum(void) -{ - UDWORD rowNum; - - if (SQLGetStmtOption(hstmt, SQL_ROW_NUMBER, (UCHAR*) &rowNum) != SQL_SUCCESS) - { - pDb->DispAllErrors(henv, hdbc, hstmt); - return(0); - } - - // Completed successfully - return((UWORD) rowNum); - -} // wxTable::GetRowNum() - -/********** wxTable::bindInsertParams() **********/ -bool wxTable::bindInsertParams(void) -{ - assert(!queryOnly); - if (queryOnly) - return(FALSE); - - SWORD fSqlType = 0; - UDWORD precision = 0; - SWORD scale = 0; - - // Bind each column (that can be inserted) of the table to a parameter marker - int i; - for (i = 0; i < noCols; i++) - { - if (! colDefs[i].InsertAllowed) - continue; - switch(colDefs[i].DbDataType) + { + // If joining tables, the base table column names must be qualified to avoid ambiguity + if (appendFromClause) { - case DB_DATA_TYPE_VARCHAR: - fSqlType = pDb->typeInfVarchar.FsqlType; - precision = colDefs[i].SzDataObj; - scale = 0; - colDefs[i].CbValue = SQL_NTS; - break; - case DB_DATA_TYPE_INTEGER: - fSqlType = pDb->typeInfInteger.FsqlType; - precision = pDb->typeInfInteger.Precision; - scale = 0; - colDefs[i].CbValue = 0; - break; - case DB_DATA_TYPE_FLOAT: - fSqlType = pDb->typeInfFloat.FsqlType; - precision = pDb->typeInfFloat.Precision; - scale = pDb->typeInfFloat.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->typeInfDate.FsqlType; - precision = pDb->typeInfDate.Precision; - scale = 0; - colDefs[i].CbValue = 0; - break; + wxStrcat(pSqlStmt, queryTableName); + wxStrcat(pSqlStmt, "."); } - // Null values - if (colDefs[i].Null) + wxStrcat(pSqlStmt, colDefs[i].ColName); + if (i + 1 < noCols) + wxStrcat(pSqlStmt, ","); + } + + // If the datasource supports ROWID, get this column as well. Exception: Don't retrieve + // the ROWID if querying distinct records. The rowid will always be unique. + if (!distinct && CanUpdByROWID()) + { + // If joining tables, the base table column names must be qualified to avoid ambiguity + if (appendFromClause) { - colDefs[i].CbValue = SQL_NULL_DATA; - colDefs[i].Null = FALSE; + wxStrcat(pSqlStmt, ","); + wxStrcat(pSqlStmt, queryTableName); + wxStrcat(pSqlStmt, ".ROWID"); } - if (SQLBindParameter(hstmtInsert, i+1, 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)); + else + wxStrcat(pSqlStmt, ",ROWID"); } - // Completed successfully - return(TRUE); + // Append the FROM tablename portion + wxStrcat(pSqlStmt, " FROM "); + wxStrcat(pSqlStmt, queryTableName); -} // wxTable::bindInsertParams() + // Sybase uses the HOLDLOCK keyword to lock a record during query. + // The HOLDLOCK keyword follows the table name in the from clause. + // Each table in the from clause must specify HOLDLOCK or + // NOHOLDLOCK (the default). Note: The "FOR UPDATE" clause + // is parsed but ignored in SYBASE Transact-SQL. + if (selectForUpdate && (pDb->Dbms() == dbmsSYBASE_ASA || pDb->Dbms() == dbmsSYBASE_ASE)) + wxStrcat(pSqlStmt, " HOLDLOCK"); -/********** wxTable::bindUpdateParams() **********/ -bool wxTable::bindUpdateParams(void) -{ - assert(!queryOnly); - if (queryOnly) - return(FALSE); + if (appendFromClause) + wxStrcat(pSqlStmt, from); - SWORD fSqlType = 0; - UDWORD precision = 0; - SWORD scale = 0; - - // Bind each UPDATEABLE column of the table to a parameter marker - int i,colNo; - for (i = 0, colNo = 1; i < noCols; i++) + // Append the WHERE clause. Either append the where clause for the class + // or build a where clause. The typeOfSelect determines this. + switch(typeOfSelect) { - if (! colDefs[i].Updateable) - continue; - switch(colDefs[i].DbDataType) + case DB_SELECT_WHERE: + if (where && wxStrlen(where)) // May not want a where clause!!! { - case DB_DATA_TYPE_VARCHAR: - fSqlType = pDb->typeInfVarchar.FsqlType; - precision = colDefs[i].SzDataObj; - scale = 0; - colDefs[i].CbValue = SQL_NTS; - break; - case DB_DATA_TYPE_INTEGER: - fSqlType = pDb->typeInfInteger.FsqlType; - precision = pDb->typeInfInteger.Precision; - scale = 0; - colDefs[i].CbValue = 0; - break; - case DB_DATA_TYPE_FLOAT: - fSqlType = pDb->typeInfFloat.FsqlType; - precision = pDb->typeInfFloat.Precision; - scale = pDb->typeInfFloat.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->typeInfDate.FsqlType; - precision = pDb->typeInfDate.Precision; - scale = 0; - colDefs[i].CbValue = 0; - break; + wxStrcat(pSqlStmt, " WHERE "); + wxStrcat(pSqlStmt, where); } - 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)); + break; + case DB_SELECT_KEYFIELDS: + GetWhereClause(whereClause, DB_WHERE_KEYFIELDS); + if (wxStrlen(whereClause)) + { + wxStrcat(pSqlStmt, " WHERE "); + wxStrcat(pSqlStmt, whereClause); + } + break; + case DB_SELECT_MATCHING: + GetWhereClause(whereClause, DB_WHERE_MATCHING); + if (wxStrlen(whereClause)) + { + wxStrcat(pSqlStmt, " WHERE "); + wxStrcat(pSqlStmt, whereClause); + } + break; } - // Completed successfully - return(TRUE); + // Append the ORDER BY clause + if (orderBy && wxStrlen(orderBy)) + { + wxStrcat(pSqlStmt, " ORDER BY "); + wxStrcat(pSqlStmt, orderBy); + } -} // wxTable::bindUpdateParams() + // SELECT FOR UPDATE if told to do so and the datasource is capable. Sybase + // parses the FOR UPDATE clause but ignores it. See the comment above on the + // HOLDLOCK for Sybase. + if (selectForUpdate && CanSelectForUpdate()) + wxStrcat(pSqlStmt, " FOR UPDATE"); -/********** wxTable::bindCols() **********/ -bool wxTable::bindCols(HSTMT cursor) +} // wxTable::GetSelectStmt() + + +/********** wxTable::GetRowNum() **********/ +UWORD wxTable::GetRowNum(void) { - static SDWORD cb; - - // Bind each column of the table to a memory address for fetching data - int i; - for (i = 0; i < noCols; i++) + UDWORD rowNum; + + if (SQLGetStmtOption(hstmt, SQL_ROW_NUMBER, (UCHAR*) &rowNum) != SQL_SUCCESS) { - if (SQLBindCol(cursor, i+1, colDefs[i].SqlCtype, (UCHAR*) colDefs[i].PtrDataObj, - colDefs[i].SzDataObj, &cb) != SQL_SUCCESS) - return(pDb->DispAllErrors(henv, hdbc, cursor)); + pDb->DispAllErrors(henv, hdbc, hstmt); + return(0); } // Completed successfully - return(TRUE); + return((UWORD) rowNum); + +} // wxTable::GetRowNum() -} // wxTable::bindCols() /********** wxTable::CloseCursor() **********/ bool wxTable::CloseCursor(HSTMT cursor) @@ -760,6 +876,7 @@ bool wxTable::CloseCursor(HSTMT cursor) } // wxTable::CloseCursor() + /********** wxTable::CreateTable() **********/ bool wxTable::CreateTable(bool attemptDrop) { @@ -814,38 +931,38 @@ bool wxTable::CreateTable(bool attemptDrop) continue; // Comma Delimiter if (needComma) - strcat(sqlStmt, ","); + wxStrcat(sqlStmt, ","); // Column Name - strcat(sqlStmt, colDefs[i].ColName); - strcat(sqlStmt, " "); + wxStrcat(sqlStmt, colDefs[i].ColName); + wxStrcat(sqlStmt, " "); // Column Type switch(colDefs[i].DbDataType) { case DB_DATA_TYPE_VARCHAR: - strcat(sqlStmt, pDb->typeInfVarchar.TypeName); break; + wxStrcat(sqlStmt, pDb->typeInfVarchar.TypeName); break; case DB_DATA_TYPE_INTEGER: - strcat(sqlStmt, pDb->typeInfInteger.TypeName); break; + wxStrcat(sqlStmt, pDb->typeInfInteger.TypeName); break; case DB_DATA_TYPE_FLOAT: - strcat(sqlStmt, pDb->typeInfFloat.TypeName); break; + wxStrcat(sqlStmt, pDb->typeInfFloat.TypeName); break; case DB_DATA_TYPE_DATE: - strcat(sqlStmt, pDb->typeInfDate.TypeName); break; + wxStrcat(sqlStmt, pDb->typeInfDate.TypeName); break; } // For varchars, append the size of the string if (colDefs[i].DbDataType == DB_DATA_TYPE_VARCHAR) { char s[10]; - // strcat(sqlStmt, "("); - // strcat(sqlStmt, itoa(colDefs[i].SzDataObj, s, 10)); - // strcat(sqlStmt, ")"); + // wxStrcat(sqlStmt, "("); + // wxStrcat(sqlStmt, itoa(colDefs[i].SzDataObj, s, 10)); + // wxStrcat(sqlStmt, ")"); sprintf(s, "(%d)", colDefs[i].SzDataObj); - strcat(sqlStmt, s); + wxStrcat(sqlStmt, s); } - + if (pDb->Dbms() == dbmsSYBASE_ASE || pDb->Dbms() == dbmsMY_SQL) { if (colDefs[i].KeyField) { - strcat(sqlStmt, " NOT NULL"); + wxStrcat(sqlStmt, " NOT NULL"); } } @@ -864,14 +981,14 @@ bool wxTable::CreateTable(bool attemptDrop) { if (pDb->Dbms() != dbmsMY_SQL) { - strcat(sqlStmt, ",CONSTRAINT "); - strcat(sqlStmt, tableName); - strcat(sqlStmt, "_PIDX PRIMARY KEY ("); + wxStrcat(sqlStmt, ",CONSTRAINT "); + wxStrcat(sqlStmt, tableName); + wxStrcat(sqlStmt, "_PIDX PRIMARY KEY ("); } else { /* MySQL goes out on this one. We also declare the relevant key NON NULL above */ - strcat(sqlStmt, ", PRIMARY KEY ("); + wxStrcat(sqlStmt, ", PRIMARY KEY ("); } // List column name(s) of column(s) comprising the primary key @@ -880,14 +997,14 @@ bool wxTable::CreateTable(bool attemptDrop) if (colDefs[i].KeyField) { if (j++) // Multi part key, comma separate names - strcat(sqlStmt, ","); - strcat(sqlStmt, colDefs[i].ColName); + wxStrcat(sqlStmt, ","); + wxStrcat(sqlStmt, colDefs[i].ColName); } } - strcat(sqlStmt, ")"); + wxStrcat(sqlStmt, ")"); } // Append the closing parentheses for the create table statement - strcat(sqlStmt, ")"); + wxStrcat(sqlStmt, ")"); pDb->WriteSqlLog(sqlStmt); @@ -896,7 +1013,8 @@ bool wxTable::CreateTable(bool attemptDrop) #endif // Execute the CREATE TABLE statement - if (SQLExecDirect(hstmt, (UCHAR FAR *) sqlStmt, SQL_NTS) != SQL_SUCCESS) + RETCODE retcode = SQLExecDirect(hstmt, (UCHAR FAR *) sqlStmt, SQL_NTS); + if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) { pDb->DispAllErrors(henv, hdbc, hstmt); pDb->RollbackTrans(); @@ -915,6 +1033,7 @@ bool wxTable::CreateTable(bool attemptDrop) } // wxTable::CreateTable() + /********** wxTable::DropTable() **********/ bool wxTable::DropTable() { @@ -937,12 +1056,12 @@ bool wxTable::DropTable() { // Check for "Base table not found" error and ignore pDb->GetNextError(henv, hdbc, hstmt); - if (strcmp(pDb->sqlState,"S0002")) // "Base table not found" + if (wxStrcmp(pDb->sqlState,"S0002")) // "Base table not found" { // Check for product specific error codes - if (!((pDb->Dbms() == dbmsSYBASE_ASA && !strcmp(pDb->sqlState,"42000")) || // 5.x (and lower?) - (pDb->Dbms() == dbmsMY_SQL && !strcmp(pDb->sqlState,"S1000")) || // untested - (pDb->Dbms() == dbmsPOSTGRES && !strcmp(pDb->sqlState,"08S01")))) // untested + if (!((pDb->Dbms() == dbmsSYBASE_ASA && !wxStrcmp(pDb->sqlState,"42000")) || // 5.x (and lower?) + (pDb->Dbms() == dbmsMY_SQL && !wxStrcmp(pDb->sqlState,"S1000")) || // untested + (pDb->Dbms() == dbmsPOSTGRES && !wxStrcmp(pDb->sqlState,"08S01")))) // untested { pDb->DispNextError(); pDb->DispAllErrors(henv, hdbc, hstmt); @@ -962,8 +1081,9 @@ bool wxTable::DropTable() return(TRUE); } // wxTable::DropTable() + /********** wxTable::CreateIndex() **********/ -bool wxTable::CreateIndex(char * idxName, bool unique, int noIdxCols, CidxDef *pIdxDefs, bool attemptDrop) +bool wxTable::CreateIndex(const char * idxName, bool unique, int noIdxCols, CidxDef *pIdxDefs, bool attemptDrop) { char sqlStmt[DB_MAX_STATEMENT_LEN]; @@ -972,36 +1092,36 @@ bool wxTable::CreateIndex(char * idxName, bool unique, int noIdxCols, CidxDef *p return (FALSE); // Build a CREATE INDEX statement - strcpy(sqlStmt, "CREATE "); + wxStrcpy(sqlStmt, "CREATE "); if (unique) - strcat(sqlStmt, "UNIQUE "); + wxStrcat(sqlStmt, "UNIQUE "); - strcat(sqlStmt, "INDEX "); - strcat(sqlStmt, idxName); - strcat(sqlStmt, " ON "); - strcat(sqlStmt, tableName); - strcat(sqlStmt, " ("); + wxStrcat(sqlStmt, "INDEX "); + wxStrcat(sqlStmt, idxName); + wxStrcat(sqlStmt, " ON "); + wxStrcat(sqlStmt, tableName); + wxStrcat(sqlStmt, " ("); // Append list of columns making up index int i; for (i = 0; i < noIdxCols; i++) { - strcat(sqlStmt, pIdxDefs[i].ColName); + wxStrcat(sqlStmt, pIdxDefs[i].ColName); /* Postgres doesn't cope with ASC */ if (pDb->Dbms() != dbmsPOSTGRES) { if (pIdxDefs[i].Ascending) - strcat(sqlStmt, " ASC"); + wxStrcat(sqlStmt, " ASC"); else - strcat(sqlStmt, " DESC"); + wxStrcat(sqlStmt, " DESC"); } if ((i + 1) < noIdxCols) - strcat(sqlStmt, ","); + wxStrcat(sqlStmt, ","); } // Append closing parentheses - strcat(sqlStmt, ")"); + wxStrcat(sqlStmt, ")"); pDb->WriteSqlLog(sqlStmt); @@ -1029,8 +1149,9 @@ bool wxTable::CreateIndex(char * idxName, bool unique, int noIdxCols, CidxDef *p } // wxTable::CreateIndex() + /********** wxTable::DropIndex() **********/ -bool wxTable::DropIndex(char * idxName) +bool wxTable::DropIndex(const char * idxName) { // NOTE: This function returns TRUE if the Index does not exist, but // only for identified databases. Code will need to be added @@ -1056,12 +1177,12 @@ bool wxTable::DropIndex(char * idxName) { // Check for "Index not found" error and ignore pDb->GetNextError(henv, hdbc, hstmt); - if (strcmp(pDb->sqlState,"S0012")) // "Index not found" + if (wxStrcmp(pDb->sqlState,"S0012")) // "Index not found" { // Check for product specific error codes - if (!((pDb->Dbms() == dbmsSYBASE_ASA && !strcmp(pDb->sqlState,"42000")) || // v5.x (and lower?) - (pDb->Dbms() == dbmsSYBASE_ASE && !strcmp(pDb->sqlState,"S0002")) || // Base table not found - (pDb->Dbms() == dbmsMY_SQL && !strcmp(pDb->sqlState,"42S02")) // untested + if (!((pDb->Dbms() == dbmsSYBASE_ASA && !wxStrcmp(pDb->sqlState,"42000")) || // v5.x (and lower?) + (pDb->Dbms() == dbmsSYBASE_ASE && !wxStrcmp(pDb->sqlState,"S0002")) || // Base table not found + (pDb->Dbms() == dbmsMY_SQL && !wxStrcmp(pDb->sqlState,"42S02")) // untested )) { pDb->DispNextError(); @@ -1082,6 +1203,7 @@ bool wxTable::DropIndex(char * idxName) return(TRUE); } // wxTable::DropIndex() + /********** wxTable::Insert() **********/ int wxTable::Insert(void) { @@ -1098,7 +1220,7 @@ int wxTable::Insert(void) { // Check to see if integrity constraint was violated pDb->GetNextError(henv, hdbc, hstmtInsert); - if (! strcmp(pDb->sqlState, "23000")) // Integrity constraint violated + if (! wxStrcmp(pDb->sqlState, "23000")) // Integrity constraint violated return(DB_ERR_INTEGRITY_CONSTRAINT_VIOL); else { @@ -1113,18 +1235,6 @@ int wxTable::Insert(void) } // wxTable::Insert() -/********** wxTable::Update(pSqlStmt) **********/ -bool wxTable::Update(char *pSqlStmt) -{ - assert(!queryOnly); - if (queryOnly) - return(FALSE); - - pDb->WriteSqlLog(pSqlStmt); - - return(execUpdate(pSqlStmt)); - -} // wxTable::Update(pSqlStmt) /********** wxTable::Update() **********/ bool wxTable::Update(void) @@ -1149,8 +1259,23 @@ bool wxTable::Update(void) } // wxTable::Update() + +/********** wxTable::Update(pSqlStmt) **********/ +bool wxTable::Update(const char *pSqlStmt) +{ + assert(!queryOnly); + if (queryOnly) + return(FALSE); + + pDb->WriteSqlLog(pSqlStmt); + + return(execUpdate(pSqlStmt)); + +} // wxTable::Update(pSqlStmt) + + /********** wxTable::UpdateWhere() **********/ -bool wxTable::UpdateWhere(char *pWhereClause) +bool wxTable::UpdateWhere(const char *pWhereClause) { assert(!queryOnly); if (queryOnly) @@ -1172,6 +1297,7 @@ bool wxTable::UpdateWhere(char *pWhereClause) } // wxTable::UpdateWhere() + /********** wxTable::Delete() **********/ bool wxTable::Delete(void) { @@ -1191,8 +1317,9 @@ bool wxTable::Delete(void) } // wxTable::Delete() + /********** wxTable::DeleteWhere() **********/ -bool wxTable::DeleteWhere(char *pWhereClause) +bool wxTable::DeleteWhere(const char *pWhereClause) { assert(!queryOnly); if (queryOnly) @@ -1210,6 +1337,7 @@ bool wxTable::DeleteWhere(char *pWhereClause) } // wxTable::DeleteWhere() + /********** wxTable::DeleteMatching() **********/ bool wxTable::DeleteMatching(void) { @@ -1229,32 +1357,9 @@ bool wxTable::DeleteMatching(void) } // wxTable::DeleteMatching() -/********** wxTable::execDelete() **********/ -bool wxTable::execDelete(char *pSqlStmt) -{ - // Execute the DELETE statement - if (SQLExecDirect(hstmtDelete, (UCHAR FAR *) pSqlStmt, SQL_NTS) != SQL_SUCCESS) - return(pDb->DispAllErrors(henv, hdbc, hstmtDelete)); - - // Record deleted successfully - return(TRUE); - -} // wxTable::execDelete() - -/********** wxTable::execUpdate() **********/ -bool wxTable::execUpdate(char *pSqlStmt) -{ - // Execute the UPDATE statement - if (SQLExecDirect(hstmtUpdate, (UCHAR FAR *) pSqlStmt, SQL_NTS) != SQL_SUCCESS) - return(pDb->DispAllErrors(henv, hdbc, hstmtUpdate)); - - // Record deleted successfully - return(TRUE); - -} // wxTable::execUpdate() /********** wxTable::GetUpdateStmt() **********/ -void wxTable::GetUpdateStmt(char *pSqlStmt, int typeOfUpd, char *pWhereClause) +void wxTable::GetUpdateStmt(char *pSqlStmt, int typeOfUpd, const char *pWhereClause) { assert(!queryOnly); if (queryOnly) @@ -1274,16 +1379,16 @@ void wxTable::GetUpdateStmt(char *pSqlStmt, int typeOfUpd, char *pWhereClause) if (colDefs[i].Updateable) { if (! firstColumn) - strcat(pSqlStmt, ","); + wxStrcat(pSqlStmt, ","); else firstColumn = FALSE; - strcat(pSqlStmt, colDefs[i].ColName); - strcat(pSqlStmt, " = ?"); + wxStrcat(pSqlStmt, colDefs[i].ColName); + wxStrcat(pSqlStmt, " = ?"); } } // Append the WHERE clause to the SQL UPDATE statement - strcat(pSqlStmt, " WHERE "); + wxStrcat(pSqlStmt, " WHERE "); switch(typeOfUpd) { case DB_UPD_KEYFIELDS: @@ -1300,26 +1405,26 @@ void wxTable::GetUpdateStmt(char *pSqlStmt, int typeOfUpd, char *pWhereClause) // based on the key fields. if (SQLGetData(hstmt, noCols+1, SQL_C_CHAR, (UCHAR*) rowid, ROWID_LEN, &cb) == SQL_SUCCESS) { - strcat(pSqlStmt, "ROWID = '"); - strcat(pSqlStmt, rowid); - strcat(pSqlStmt, "'"); + wxStrcat(pSqlStmt, "ROWID = '"); + wxStrcat(pSqlStmt, rowid); + wxStrcat(pSqlStmt, "'"); break; } } // Unable to delete by ROWID, so build a WHERE // clause based on the keyfields. GetWhereClause(whereClause, DB_WHERE_KEYFIELDS); - strcat(pSqlStmt, whereClause); + wxStrcat(pSqlStmt, whereClause); break; case DB_UPD_WHERE: - strcat(pSqlStmt, pWhereClause); + wxStrcat(pSqlStmt, pWhereClause); break; } - } // GetUpdateStmt() + /********** wxTable::GetDeleteStmt() **********/ -void wxTable::GetDeleteStmt(char *pSqlStmt, int typeOfDel, char *pWhereClause) +void wxTable::GetDeleteStmt(char *pSqlStmt, int typeOfDel, const char *pWhereClause) { assert(!queryOnly); if (queryOnly) @@ -1331,7 +1436,7 @@ void wxTable::GetDeleteStmt(char *pSqlStmt, int typeOfDel, char *pWhereClause) // Handle the case of DeleteWhere() and the where clause is blank. It should // delete all records from the database in this case. - if (typeOfDel == DB_DEL_WHERE && (pWhereClause == 0 || strlen(pWhereClause) == 0)) + if (typeOfDel == DB_DEL_WHERE && (pWhereClause == 0 || wxStrlen(pWhereClause) == 0)) { sprintf(pSqlStmt, "DELETE FROM %s", tableName); return; @@ -1356,35 +1461,35 @@ void wxTable::GetDeleteStmt(char *pSqlStmt, int typeOfDel, char *pWhereClause) // based on the key fields. if (SQLGetData(hstmt, noCols+1, SQL_C_CHAR, (UCHAR*) rowid, ROWID_LEN, &cb) == SQL_SUCCESS) { - strcat(pSqlStmt, "ROWID = '"); - strcat(pSqlStmt, rowid); - strcat(pSqlStmt, "'"); + wxStrcat(pSqlStmt, "ROWID = '"); + wxStrcat(pSqlStmt, rowid); + wxStrcat(pSqlStmt, "'"); break; } } // Unable to delete by ROWID, so build a WHERE // clause based on the keyfields. GetWhereClause(whereClause, DB_WHERE_KEYFIELDS); - strcat(pSqlStmt, whereClause); + wxStrcat(pSqlStmt, whereClause); break; case DB_DEL_WHERE: - strcat(pSqlStmt, pWhereClause); + wxStrcat(pSqlStmt, pWhereClause); break; case DB_DEL_MATCHING: GetWhereClause(whereClause, DB_WHERE_MATCHING); - strcat(pSqlStmt, whereClause); + wxStrcat(pSqlStmt, whereClause); break; } } // GetDeleteStmt() + /********** wxTable::GetWhereClause() **********/ +void wxTable::GetWhereClause(char *pWhereClause, int typeOfWhere, const char *qualTableName) /* * Note: GetWhereClause() currently ignores timestamp columns. * They are not included as part of the where clause. */ - -void wxTable::GetWhereClause(char *pWhereClause, int typeOfWhere, char *qualTableName) { bool moreThanOneColumn = FALSE; char colValue[255]; @@ -1402,17 +1507,17 @@ void wxTable::GetWhereClause(char *pWhereClause, int typeOfWhere, char *qualTabl continue; // If there is more than 1 column, join them with the keyword "AND" if (moreThanOneColumn) - strcat(pWhereClause, " AND "); + wxStrcat(pWhereClause, " AND "); else moreThanOneColumn = TRUE; // Concatenate where phrase for the column - if (qualTableName && strlen(qualTableName)) + if (qualTableName && wxStrlen(qualTableName)) { - strcat(pWhereClause, qualTableName); - strcat(pWhereClause, "."); + wxStrcat(pWhereClause, qualTableName); + wxStrcat(pWhereClause, "."); } - strcat(pWhereClause, colDefs[i].ColName); - strcat(pWhereClause, " = "); + wxStrcat(pWhereClause, colDefs[i].ColName); + wxStrcat(pWhereClause, " = "); switch(colDefs[i].SqlCtype) { case SQL_C_CHAR: @@ -1437,12 +1542,12 @@ void wxTable::GetWhereClause(char *pWhereClause, int typeOfWhere, char *qualTabl sprintf(colValue, "%.6f", *((SDOUBLE *) colDefs[i].PtrDataObj)); break; } - strcat(pWhereClause, colValue); + wxStrcat(pWhereClause, colValue); } } - } // wxTable::GetWhereClause() + /********** wxTable::IsColNull() **********/ bool wxTable::IsColNull(int colNo) { @@ -1472,9 +1577,9 @@ bool wxTable::IsColNull(int colNo) default: return(TRUE); } - } // wxTable::IsColNull() + /********** wxTable::CanSelectForUpdate() **********/ bool wxTable::CanSelectForUpdate(void) { @@ -1488,12 +1593,14 @@ bool wxTable::CanSelectForUpdate(void) } // wxTable::CanSelectForUpdate() + /********** wxTable::CanUpdByROWID() **********/ bool wxTable::CanUpdByROWID(void) { - -//NOTE: Returning FALSE for now until this can be debugged, -// as the ROWID is not getting updated correctly +/* + * NOTE: Returning FALSE for now until this can be debugged, + * as the ROWID is not getting updated correctly + */ return FALSE; if (pDb->Dbms() == dbmsORACLE) @@ -1503,6 +1610,7 @@ bool wxTable::CanUpdByROWID(void) } // wxTable::CanUpdByROWID() + /********** wxTable::IsCursorClosedOnCommit() **********/ bool wxTable::IsCursorClosedOnCommit(void) { @@ -1513,6 +1621,7 @@ bool wxTable::IsCursorClosedOnCommit(void) } // wxTable::IsCursorClosedOnCommit() + /********** wxTable::ClearMemberVars() **********/ void wxTable::ClearMemberVars(void) { @@ -1559,6 +1668,7 @@ void wxTable::ClearMemberVars(void) } // wxTable::ClearMemberVars() + /********** wxTable::SetQueryTimeout() **********/ bool wxTable::SetQueryTimeout(UDWORD nSeconds) { @@ -1576,21 +1686,22 @@ bool wxTable::SetQueryTimeout(UDWORD nSeconds) } // wxTable::SetQueryTimeout() + /********** wxTable::SetColDefs() **********/ -void wxTable::SetColDefs (int index, char *fieldName, int dataType, void *pData, +void wxTable::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; - if (strlen(fieldName) > (unsigned int) DB_MAX_COLUMN_NAME_LEN) + if (wxStrlen(fieldName) > (unsigned int) DB_MAX_COLUMN_NAME_LEN) { - strncpy (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; } else - strcpy(colDefs[index].ColName, fieldName); + wxStrcpy(colDefs[index].ColName, fieldName); colDefs[index].DbDataType = dataType; colDefs[index].PtrDataObj = pData; @@ -1614,6 +1725,103 @@ void wxTable::SetColDefs (int index, char *fieldName, int dataType, void *pData, } // wxTable::SetColDefs() + +/********** wxTable::SetColDef() **********/ +// BJO20000121 : changed prototype in order to return proper pointer on wxColDataPtr's array +//bool wxTable::SetColDefs(wxColInf *pColInfs, ULONG numCols, wxColDataPtr *pColDataPtrs) +wxColDataPtr* wxTable::SetColDefs (wxColInf *pColInfs, ULONG numCols) +{ + assert(pColInfs); + wxColDataPtr *pColDataPtrs; + + if (pColInfs) + { + ULONG index; + + + pColDataPtrs = new wxColDataPtr[numCols+1]; + + for (index = 0; index < numCols; index++) + { +/* + wxString title,msg; + title.sprintf("Catalog: %s, Schema: %s, Table name: %s",pColInfs[index].catalog,pColInfs[index].schema,pColInfs[index].tableName); + msg.sprintf("Column name: %s\nData type: %04d\nType name: %s\nColumn size: %d\nBuffer len: %d\nDecimals:%d\nRadix: %d\nNullable: %d\nRemarks: %s", + pColInfs[index].colName,pColInfs[index].sqlDataType,pColInfs[index].typeName,pColInfs[index].columnSize,pColInfs[index].bufferLength,pColInfs[index].decimalDigits,pColInfs[index].numPrecRadix,pColInfs[index].nullable,pColInfs[index].remarks); + msg += " \nDB_DATA_TYPE: "; + switch(pColInfs[index].dbDataType) + { + case DB_DATA_TYPE_VARCHAR: + msg += pDb->typeInfVarchar.TypeName; break; + case DB_DATA_TYPE_INTEGER: + msg += pDb->typeInfInteger.TypeName; break; + case DB_DATA_TYPE_FLOAT: + msg += pDb->typeInfFloat.TypeName; break; + case DB_DATA_TYPE_DATE: + msg += pDb->typeInfDate.TypeName; break; + } + wxMessageBox(msg.GetData(),title.GetData()); +*/ + // Process the fields + switch (pColInfs[index].dbDataType) + { + case DB_DATA_TYPE_VARCHAR: + { + pColDataPtrs[index].PtrDataObj = new char[pColInfs[index].bufferLength+1]; + pColDataPtrs[index].SzDataObj = pColInfs[index].bufferLength; + pColDataPtrs[index].SqlCtype = SQL_C_CHAR; + break; + } + case DB_DATA_TYPE_INTEGER: + { + // Can be long or short + if (pColInfs[index].bufferLength == sizeof(long)) + { + pColDataPtrs[index].PtrDataObj = new long; + pColDataPtrs[index].SzDataObj = sizeof(long); + pColDataPtrs[index].SqlCtype = SQL_C_SLONG; + } + else + { + pColDataPtrs[index].PtrDataObj = new short; + pColDataPtrs[index].SzDataObj = sizeof(short); + pColDataPtrs[index].SqlCtype = SQL_C_SSHORT; + } + break; + } + case DB_DATA_TYPE_FLOAT: + { + // Can be float or double + if (pColInfs[index].bufferLength == sizeof(float)) + { + pColDataPtrs[index].PtrDataObj = new float; + pColDataPtrs[index].SzDataObj = sizeof(float); + pColDataPtrs[index].SqlCtype = SQL_C_FLOAT; + } + else + { + 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; + 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); + } + } + return (pColDataPtrs); +} // wxTable::SetColDef() + + /********** wxTable::SetCursor() **********/ void wxTable::SetCursor(HSTMT *hstmtActivate) { @@ -1624,25 +1832,28 @@ void wxTable::SetCursor(HSTMT *hstmtActivate) } // wxTable::SetCursor() -/********** wxTable::Count() **********/ -ULONG wxTable::Count(void) + +/********** wxTable::Count(const char *) **********/ +ULONG wxTable::Count(const char *args) { ULONG l; char sqlStmt[DB_MAX_STATEMENT_LEN]; SDWORD cb; // Build a "SELECT COUNT(*) FROM queryTableName [WHERE whereClause]" SQL Statement - strcpy(sqlStmt, "SELECT COUNT(*) FROM "); - strcat(sqlStmt, queryTableName); + wxStrcpy(sqlStmt, "SELECT COUNT("); + wxStrcat(sqlStmt, args); + wxStrcat(sqlStmt, ") FROM "); + wxStrcat(sqlStmt, queryTableName); - if (from && strlen(from)) - strcat(sqlStmt, from); + if (from && wxStrlen(from)) + wxStrcat(sqlStmt, from); // Add the where clause if one is provided - if (where && strlen(where)) + if (where && wxStrlen(where)) { - strcat(sqlStmt, " WHERE "); - strcat(sqlStmt, where); + wxStrcat(sqlStmt, " WHERE "); + wxStrcat(sqlStmt, where); } pDb->WriteSqlLog(sqlStmt); @@ -1686,6 +1897,7 @@ ULONG wxTable::Count(void) } // wxTable::Count() + /********** wxTable::Refresh() **********/ bool wxTable::Refresh(void) { @@ -1702,7 +1914,7 @@ bool wxTable::Refresh(void) // Build a where clause to refetch the record with. Try and use the // ROWID if it's available, ow use the key fields. char whereClause[DB_MAX_WHERE_CLAUSE_LEN+1]; - strcpy(whereClause, ""); + wxStrcpy(whereClause, ""); if (CanUpdByROWID()) { SDWORD cb; @@ -1713,15 +1925,15 @@ bool wxTable::Refresh(void) // based on the key fields. if (SQLGetData(hstmt, noCols+1, SQL_C_CHAR, (UCHAR*) rowid, ROWID_LEN, &cb) == SQL_SUCCESS) { - strcat(whereClause, queryTableName); - strcat(whereClause, ".ROWID = '"); - strcat(whereClause, rowid); - strcat(whereClause, "'"); + wxStrcat(whereClause, queryTableName); + wxStrcat(whereClause, ".ROWID = '"); + wxStrcat(whereClause, rowid); + wxStrcat(whereClause, "'"); } } // If unable to use the ROWID, build a where clause from the keyfields - if (strlen(whereClause) == 0) + if (wxStrlen(whereClause) == 0) GetWhereClause(whereClause, DB_WHERE_KEYFIELDS, queryTableName); // Requery the record @@ -1748,7 +1960,8 @@ bool wxTable::Refresh(void) } // wxTable::Refresh() -/********** wxTable::SetNull(UINT colNo) **********/ + +/********** wxTable::SetNull(int colNo) **********/ bool wxTable::SetNull(int colNo) { if (colNo < noCols) @@ -1756,15 +1969,16 @@ bool wxTable::SetNull(int colNo) else return(FALSE); -} // wxTable::SetNull(UINT colNo) +} // wxTable::SetNull(int colNo) + /********** wxTable::SetNull(char *colName) **********/ -bool wxTable::SetNull(char *colName) +bool wxTable::SetNull(const char *colName) { int i; for (i = 0; i < noCols; i++) { - if (!stricmp(colName, colDefs[i].ColName)) + if (!wxStricmp(colName, colDefs[i].ColName)) break; } @@ -1775,6 +1989,7 @@ bool wxTable::SetNull(char *colName) } // wxTable::SetNull(char *colName) + /********** wxTable::NewCursor() **********/ HSTMT *wxTable::NewCursor(bool setCursor, bool bindColumns) { @@ -1811,7 +2026,8 @@ HSTMT *wxTable::NewCursor(bool setCursor, bool bindColumns) return(newHSTMT); -} // wxTable::NewCursor() +} // wxTable::NewCursor() + /********** wxTable::DeleteCursor() **********/ bool wxTable::DeleteCursor(HSTMT *hstmtDel)