]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/dbtable.cpp
Misc. Dialog Editor/resource bugs fixed
[wxWidgets.git] / src / common / dbtable.cpp
index 1113157d9028ab6076be760c361598f033d41673..f73f17089dd9da080cb13237d388ed64c9626df0 100644 (file)
@@ -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
 #include <stdlib.h>
 #include <string.h>
 #include <assert.h>
+
 #if   wxMAJOR_VERSION == 1
        #include "table.h"
 #elif wxMAJOR_VERSION == 2
        #include "wx/dbtable.h"
 #endif
 
-#ifdef __MWERKS__
-#ifdef __WXMSW__
-#define stricmp _stricmp
-#define strnicmp _strnicmp
-#else
-int strcasecmp(const char *str_1, const char *str_2) ;
-int strncasecmp(const char *str_1, const char *str_2, size_t maxchar) ;
-#define stricmp strcasecmp
-#define strnicmp strncasecmp
-#endif
-#endif
-
 #ifdef __UNIX__
 // The HPUX preprocessor lines below were commented out on 8/20/97
 // because macros.h currently redefines DEBUG and is unneeded.
@@ -114,12 +104,12 @@ ULONG lastTableID = 0;
 
 /********** 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;
@@ -129,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;
 
@@ -173,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)
@@ -252,6 +241,7 @@ wxTable::wxTable(wxDB *pwxDB, const char *tblName, const int nCols,
 
 }  // wxTable::wxTable()
 
+
 /********** wxTable::~wxTable() **********/
 wxTable::~wxTable()
 {
@@ -321,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)
 {
@@ -331,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);
        }
@@ -366,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);
 
@@ -395,6 +648,7 @@ bool wxTable::Open(void)
 
 }  // wxTable::Open()
 
+
 /********** wxTable::Query() **********/
 bool wxTable::Query(bool forUpdate, bool distinct)
 {
@@ -403,6 +657,7 @@ bool wxTable::Query(bool forUpdate, bool distinct)
 
 }  // wxTable::Query()
 
+
 /********** wxTable::QueryBySqlStmt() **********/
 bool wxTable::QueryBySqlStmt(char *pSqlStmt)
 {
@@ -412,6 +667,7 @@ bool wxTable::QueryBySqlStmt(char *pSqlStmt)
 
 }  // wxTable::QueryBySqlStmt()
 
+
 /********** wxTable::QueryMatching() **********/
 bool wxTable::QueryMatching(bool forUpdate, bool distinct)
 {
@@ -420,6 +676,7 @@ bool wxTable::QueryMatching(bool forUpdate, bool distinct)
 
 }  // wxTable::QueryMatching()
 
+
 /********** wxTable::QueryOnKeyFields() **********/
 bool wxTable::QueryOnKeyFields(bool forUpdate, bool distinct)
 {
@@ -428,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)
@@ -471,303 +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;
-
-#if !wxODBC_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)
-   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));
-       }
-#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)
@@ -780,6 +876,7 @@ bool wxTable::CloseCursor(HSTMT cursor)
 
 }  // wxTable::CloseCursor()
 
+
 /********** wxTable::CreateTable() **********/
 bool wxTable::CreateTable(bool attemptDrop)
 {
@@ -834,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");
                        }
                }
                
@@ -884,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
@@ -900,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);
 
@@ -916,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();
@@ -935,6 +1033,7 @@ bool wxTable::CreateTable(bool attemptDrop)
 
 } // wxTable::CreateTable()
 
+
 /********** wxTable::DropTable() **********/
 bool wxTable::DropTable()
 {
@@ -982,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];
 
@@ -992,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);
 
@@ -1049,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
@@ -1102,6 +1203,7 @@ bool wxTable::DropIndex(char * idxName)
        return(TRUE);
 }  // wxTable::DropIndex()
 
+
 /********** wxTable::Insert() **********/
 int wxTable::Insert(void)
 {
@@ -1133,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)
@@ -1169,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)
@@ -1192,6 +1297,7 @@ bool wxTable::UpdateWhere(char *pWhereClause)
 
 }  // wxTable::UpdateWhere()
 
+
 /********** wxTable::Delete() **********/
 bool wxTable::Delete(void)
 {
@@ -1211,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)
@@ -1230,6 +1337,7 @@ bool wxTable::DeleteWhere(char *pWhereClause)
 
 }  // wxTable::DeleteWhere()
 
+
 /********** wxTable::DeleteMatching() **********/
 bool wxTable::DeleteMatching(void)
 {
@@ -1249,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)
@@ -1294,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:
@@ -1320,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)
@@ -1351,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;
@@ -1376,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];
@@ -1422,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:
@@ -1457,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)
 {
@@ -1492,9 +1577,9 @@ bool wxTable::IsColNull(int colNo)
        default:
                return(TRUE);
        }
-
 }  // wxTable::IsColNull()
 
+
 /********** wxTable::CanSelectForUpdate() **********/
 bool wxTable::CanSelectForUpdate(void)
 {
@@ -1508,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)
@@ -1523,6 +1610,7 @@ bool wxTable::CanUpdByROWID(void)
 
 }  // wxTable::CanUpdByROWID()
 
+
 /********** wxTable::IsCursorClosedOnCommit() **********/
 bool wxTable::IsCursorClosedOnCommit(void)
 {
@@ -1533,6 +1621,7 @@ bool wxTable::IsCursorClosedOnCommit(void)
 
 }  // wxTable::IsCursorClosedOnCommit()
 
+
 /********** wxTable::ClearMemberVars() **********/
 void wxTable::ClearMemberVars(void)
 {
@@ -1579,6 +1668,7 @@ void wxTable::ClearMemberVars(void)
 
 }  // wxTable::ClearMemberVars()
 
+
 /********** wxTable::SetQueryTimeout() **********/
 bool wxTable::SetQueryTimeout(UDWORD nSeconds)
 {
@@ -1596,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;
@@ -1634,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)
 {
@@ -1644,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);
@@ -1706,6 +1897,7 @@ ULONG wxTable::Count(void)
 
 }  // wxTable::Count()
 
+
 /********** wxTable::Refresh() **********/
 bool wxTable::Refresh(void)
 {
@@ -1722,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;
@@ -1733,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
@@ -1768,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)
@@ -1776,10 +1969,11 @@ 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++)
@@ -1795,6 +1989,7 @@ bool wxTable::SetNull(char *colName)
 
 }  // wxTable::SetNull(char *colName)
 
+
 /********** wxTable::NewCursor() **********/
 HSTMT *wxTable::NewCursor(bool setCursor, bool bindColumns)
 {
@@ -1831,7 +2026,8 @@ HSTMT *wxTable::NewCursor(bool setCursor, bool bindColumns)
 
        return(newHSTMT);
 
-}   // wxTable::NewCursor()
+}      // wxTable::NewCursor()
+
 
 /********** wxTable::DeleteCursor() **********/
 bool wxTable::DeleteCursor(HSTMT *hstmtDel)