]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/dbtable.cpp
Rework the wxCusor ctor taking wx stock number to provide as many cursors as
[wxWidgets.git] / src / common / dbtable.cpp
index f32954f688ffa9e63d981c733255e1a21ce6aaba..ac9981425e04ce32a4ce0a5abb091628d593f85b 100644 (file)
@@ -1,5 +1,5 @@
 ///////////////////////////////////////////////////////////////////////////////
-// Name:        dbtable.cpp
+// Name:        src/common/dbtable.cpp
 // Purpose:     Implementation of the wxDbTable class.
 // Author:      Doug Card
 // Modified by: George Tasker
 // Licence:     wxWindows licence
 ///////////////////////////////////////////////////////////////////////////////
 
-/*
-// SYNOPSIS START
-// SYNOPSIS STOP
-*/
-
 #include  "wx/wxprec.h"
 
 #ifdef __BORLANDC__
     #pragma hdrstop
 #endif
 
-#ifdef DBDEBUG_CONSOLE
-#if wxUSE_IOSTREAMH
-    #include <iostream.h>
-#else
-    #include <iostream>
-#endif
-    #include "wx/ioswrap.h"
-#endif
+#if wxUSE_ODBC
 
 #ifndef WX_PRECOMP
-    #include "wx/string.h"
     #include "wx/object.h"
     #include "wx/list.h"
+    #include "wx/string.h"
     #include "wx/utils.h"
     #include "wx/log.h"
+    #include "wx/crt.h"
 #endif
-#include "wx/filefn.h"
 
-#if wxUSE_ODBC
+#ifdef DBDEBUG_CONSOLE
+    #include "wx/ioswrap.h"
+#endif
+
+#include "wx/filefn.h"
 
 #include <stdio.h>
 #include <stdlib.h>
 
 #include "wx/dbtable.h"
 
-#ifdef __UNIX__
-// The HPUX preprocessor lines below were commented out on 8/20/97
-// because macros.h currently redefines DEBUG and is unneeded.
-// #  ifdef HPUX
-// #    include <macros.h>
-// #  endif
-#  ifdef LINUX
-#    include <sys/minmax.h>
-#  endif
+// FIXME-UTF8: get rid of this after switching to Unicode-only builds:
+#if wxUSE_UNICODE
+    #define WXSQLCAST(s) ((SQLTCHAR FAR *)(wchar_t*)(s).wchar_str())
+#else
+    #define WXSQLCAST(s) ((SQLTCHAR FAR *)(char*)(s).char_str())
 #endif
 
 ULONG lastTableID = 0;
 
 
 #ifdef __WXDEBUG__
+    #include "wx/thread.h"
+
     wxList TablesInUse;
+    wxCriticalSection csTablesInUse;
 #endif
 
 
 void csstrncpyt(wxChar *target, const wxChar *source, int n)
 {
-    while ( (*target++ = *source++) != '\0' && --n )
+    while ( (*target++ = *source++) != '\0' && --n != 0 )
         ;
 
     *target = '\0';
@@ -97,6 +88,7 @@ bool wxDbColDef::Initialize()
     DerivedCol      = false;
     CbValue         = 0;
     Null            = false;
+    CbValueCol      = 0;
 
     return true;
 }  // wxDbColDef::Initialize()
@@ -111,19 +103,6 @@ wxDbTable::wxDbTable(wxDb *pwxDb, const wxString &tblName, const UWORD numColumn
 }  // wxDbTable::wxDbTable()
 
 
-/***** DEPRECATED: use wxDbTable::wxDbTable() format above *****/
-#if WXWIN_COMPATIBILITY_2_4
-wxDbTable::wxDbTable(wxDb *pwxDb, const wxString &tblName, const UWORD numColumns,
-                    const wxChar *qryTblName, bool qryOnly, const wxString &tblPath)
-{
-    wxString tempQryTblName;
-    tempQryTblName = qryTblName;
-    if (!initialize(pwxDb, tblName, numColumns, tempQryTblName, qryOnly, tblPath))
-        cleanup();
-}  // wxDbTable::wxDbTable()
-#endif // WXWIN_COMPATIBILITY_2_4
-
-
 /********** wxDbTable::~wxDbTable() **********/
 wxDbTable::~wxDbTable()
 {
@@ -159,7 +138,7 @@ bool wxDbTable::initialize(wxDb *pwxDb, const wxString &tblName, const UWORD num
     tableName.Empty();
     queryTableName.Empty();
 
-    wxASSERT(tblName.Length());
+    wxASSERT(tblName.length());
     wxASSERT(pDb);
 
     if (!pDb)
@@ -171,12 +150,12 @@ bool wxDbTable::initialize(wxDb *pwxDb, const wxString &tblName, const UWORD num
         (pDb->Dbms() == dbmsINTERBASE))
         tableName = tableName.Upper();
 
-    if (tblPath.Length())
+    if (tblPath.length())
         tablePath = tblPath;                    // Table Path - used for dBase files
     else
         tablePath.Empty();
 
-    if (qryTblName.Length())                    // Name of the table/view to query
+    if (qryTblName.length())                    // Name of the table/view to query
         queryTableName = qryTblName;
     else
         queryTableName = tblName;
@@ -190,7 +169,8 @@ bool wxDbTable::initialize(wxDb *pwxDb, const wxString &tblName, const UWORD num
 
     wxString s;
     tableID = ++lastTableID;
-    s.Printf(wxT("wxDbTable constructor (%-20s) tableID:[%6lu] pDb:[%p]"), tblName.c_str(), tableID, pDb);
+    s.Printf(wxT("wxDbTable constructor (%-20s) tableID:[%6lu] pDb:[%p]"),
+             tblName.c_str(), tableID, wx_static_cast(void*, pDb));
 
 #ifdef __WXDEBUG__
     wxTablesInUse *tableInUse;
@@ -198,7 +178,10 @@ bool wxDbTable::initialize(wxDb *pwxDb, const wxString &tblName, const UWORD num
     tableInUse->tableName = tblName;
     tableInUse->tableID   = tableID;
     tableInUse->pDb       = pDb;
-    TablesInUse.Append(tableInUse);
+    {
+        wxCriticalSectionLocker lock(csTablesInUse);
+        TablesInUse.Append(tableInUse);
+    }
 #endif
 
     pDb->WriteSqlLog(s);
@@ -313,7 +296,8 @@ void wxDbTable::cleanup()
     wxString s;
     if (pDb)
     {
-        s.Printf(wxT("wxDbTable destructor (%-20s) tableID:[%6lu] pDb:[%p]"), tableName.c_str(), tableID, pDb);
+        s.Printf(wxT("wxDbTable destructor (%-20s) tableID:[%6lu] pDb:[%p]"),
+                 tableName.c_str(), tableID, wx_static_cast(void*, pDb));
         pDb->WriteSqlLog(s);
     }
 
@@ -323,17 +307,20 @@ void wxDbTable::cleanup()
         bool found = false;
 
         wxList::compatibility_iterator pNode;
-        pNode = TablesInUse.GetFirst();
-        while (pNode && !found)
         {
-            if (((wxTablesInUse *)pNode->GetData())->tableID == tableID)
+            wxCriticalSectionLocker lock(csTablesInUse);
+            pNode = TablesInUse.GetFirst();
+            while (!found && pNode)
             {
-                found = true;
-                delete (wxTablesInUse *)pNode->GetData();
-                TablesInUse.Erase(pNode);
+                if (((wxTablesInUse *)pNode->GetData())->tableID == tableID)
+                {
+                    found = true;
+                    delete (wxTablesInUse *)pNode->GetData();
+                    TablesInUse.Erase(pNode);
+                }
+                else
+                    pNode = pNode->GetNext();
             }
-            else
-                pNode = pNode->GetNext();
         }
         if (!found)
         {
@@ -413,6 +400,7 @@ void wxDbTable::setCbValueForColumn(int columnIndex)
     switch(colDefs[columnIndex].DbDataType)
     {
         case DB_DATA_TYPE_VARCHAR:
+        case DB_DATA_TYPE_MEMO:
             if (colDefs[columnIndex].Null)
                 colDefs[columnIndex].CbValue = SQL_NULL_DATA;
             else
@@ -484,6 +472,11 @@ bool wxDbTable::bindParams(bool forUpdate)
                 precision = colDefs[i].SzDataObj;
                 scale = 0;
                 break;
+            case DB_DATA_TYPE_MEMO:
+                fSqlType = pDb->GetTypeInfMemo().FsqlType;
+                precision = colDefs[i].SzDataObj;
+                scale = 0;
+                break;
             case DB_DATA_TYPE_INTEGER:
                 fSqlType = pDb->GetTypeInfInteger().FsqlType;
                 precision = pDb->GetTypeInfInteger().Precision;
@@ -556,21 +549,17 @@ bool wxDbTable::bindUpdateParams(void)
 /********** wxDbTable::bindCols() **********/
 bool wxDbTable::bindCols(HSTMT cursor)
 {
-    static SQLLEN cb;
-
     // Bind each column of the table to a memory address for fetching data
     UWORD i;
     for (i = 0; i < m_numCols; i++)
     {
-        cb = colDefs[i].CbValue;
         if (SQLBindCol(cursor, (UWORD)(i+1), colDefs[i].SqlCtype, (UCHAR*) colDefs[i].PtrDataObj,
-                       colDefs[i].SzDataObj, &cb ) != SQL_SUCCESS)
+                       colDefs[i].SzDataObj, &colDefs[i].CbValueCol ) != SQL_SUCCESS)
           return (pDb->DispAllErrors(henv, hdbc, cursor));
     }
 
     // Completed successfully
     return true;
-
 }  // wxDbTable::bindCols()
 
 
@@ -599,7 +588,7 @@ bool wxDbTable::getRec(UWORD fetchType)
             // of each column just read in.
             int i;
             for (i = 0; i < m_numCols; i++)
-                colDefs[i].Null = (colDefs[i].CbValue == SQL_NULL_DATA);
+                colDefs[i].Null = (colDefs[i].CbValueCol == SQL_NULL_DATA);
         }
     }
     else
@@ -619,7 +608,7 @@ bool wxDbTable::getRec(UWORD fetchType)
             // of each column just read in.
             int i;
             for (i = 0; i < m_numCols; i++)
-                colDefs[i].Null = (colDefs[i].CbValue == SQL_NULL_DATA);
+                colDefs[i].Null = (colDefs[i].CbValueCol == SQL_NULL_DATA);
         }
     }
 
@@ -635,7 +624,7 @@ bool wxDbTable::execDelete(const wxString &pSqlStmt)
     RETCODE retcode;
 
     // Execute the DELETE statement
-    retcode = SQLExecDirect(hstmtDelete, (SQLTCHAR FAR *) pSqlStmt.c_str(), SQL_NTS);
+    retcode = SQLExecDirect(hstmtDelete, WXSQLCAST(pSqlStmt), SQL_NTS);
 
     if (retcode == SQL_SUCCESS ||
         retcode == SQL_NO_DATA_FOUND ||
@@ -657,7 +646,7 @@ bool wxDbTable::execUpdate(const wxString &pSqlStmt)
     RETCODE retcode;
 
     // Execute the UPDATE statement
-    retcode = SQLExecDirect(hstmtUpdate, (SQLTCHAR FAR *) pSqlStmt.c_str(), SQL_NTS);
+    retcode = SQLExecDirect(hstmtUpdate, WXSQLCAST(pSqlStmt), SQL_NTS);
 
     if (retcode == SQL_SUCCESS ||
         retcode == SQL_NO_DATA_FOUND ||
@@ -729,7 +718,7 @@ bool wxDbTable::query(int queryType, bool forUpdate, bool distinct, const wxStri
 
     // Execute the SQL SELECT statement
     int retcode;
-    retcode = SQLExecDirect(hstmt, (SQLTCHAR FAR *) (queryType == DB_SELECT_STATEMENT ? pSqlStmt.c_str() : sqlStmt.c_str()), SQL_NTS);
+    retcode = SQLExecDirect(hstmt, (queryType == DB_SELECT_STATEMENT ? WXSQLCAST(pSqlStmt) : WXSQLCAST(sqlStmt)), SQL_NTS);
     if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
         return(pDb->DispAllErrors(henv, hdbc, hstmt));
 
@@ -868,7 +857,7 @@ bool wxDbTable::Open(bool checkPrivileges, bool checkTableExists)
         // Prepare the insert statement for execution
         if (insertableCount)
         {
-            if (SQLPrepare(hstmtInsert, (SQLTCHAR FAR *) sqlStmt.c_str(), SQL_NTS) != SQL_SUCCESS)
+            if (SQLPrepare(hstmtInsert, WXSQLCAST(sqlStmt), SQL_NTS) != SQL_SUCCESS)
                 return(pDb->DispAllErrors(henv, hdbc, hstmtInsert));
         }
         else
@@ -987,7 +976,7 @@ void wxDbTable::BuildDeleteStmt(wxString &pSqlStmt, int typeOfDel, const wxStrin
 
     // Handle the case of DeleteWhere() and the where clause is blank.  It should
     // delete all records from the database in this case.
-    if (typeOfDel == DB_DEL_WHERE && (pWhereClause.Length() == 0))
+    if (typeOfDel == DB_DEL_WHERE && (pWhereClause.length() == 0))
     {
         pSqlStmt.Printf(wxT("DELETE FROM %s"),
                         pDb->SQLTableName(tableName.c_str()).c_str());
@@ -1066,7 +1055,7 @@ void wxDbTable::BuildSelectStmt(wxString &pSqlStmt, int typeOfSelect, bool disti
     if (typeOfSelect == DB_SELECT_WHERE && from && wxStrlen(from))
         appendFromClause = true;
 #else
-    if (typeOfSelect == DB_SELECT_WHERE && from.Length())
+    if (typeOfSelect == DB_SELECT_WHERE && from.length())
         appendFromClause = true;
 #endif
 
@@ -1126,7 +1115,7 @@ void wxDbTable::BuildSelectStmt(wxString &pSqlStmt, int typeOfSelect, bool disti
 #if wxODBC_BACKWARD_COMPATABILITY
             if (where && wxStrlen(where))   // May not want a where clause!!!
 #else
-            if (where.Length())   // May not want a where clause!!!
+            if (where.length())   // May not want a where clause!!!
 #endif
             {
                 pSqlStmt += wxT(" WHERE ");
@@ -1135,7 +1124,7 @@ void wxDbTable::BuildSelectStmt(wxString &pSqlStmt, int typeOfSelect, bool disti
             break;
         case DB_SELECT_KEYFIELDS:
             BuildWhereClause(whereClause, DB_WHERE_KEYFIELDS);
-            if (whereClause.Length())
+            if (whereClause.length())
             {
                 pSqlStmt += wxT(" WHERE ");
                 pSqlStmt += whereClause;
@@ -1143,7 +1132,7 @@ void wxDbTable::BuildSelectStmt(wxString &pSqlStmt, int typeOfSelect, bool disti
             break;
         case DB_SELECT_MATCHING:
             BuildWhereClause(whereClause, DB_WHERE_MATCHING);
-            if (whereClause.Length())
+            if (whereClause.length())
             {
                 pSqlStmt += wxT(" WHERE ");
                 pSqlStmt += whereClause;
@@ -1155,7 +1144,7 @@ void wxDbTable::BuildSelectStmt(wxString &pSqlStmt, int typeOfSelect, bool disti
 #if wxODBC_BACKWARD_COMPATABILITY
     if (orderBy && wxStrlen(orderBy))
 #else
-    if (orderBy.Length())
+    if (orderBy.length())
 #endif
     {
         pSqlStmt += wxT(" ORDER BY ");
@@ -1289,7 +1278,7 @@ void wxDbTable::BuildWhereClause(wxString &pWhereClause, int typeOfWhere,
             // Concatenate where phrase for the column
             wxString tStr = colDefs[colNumber].ColName;
 
-            if (qualTableName.Length() && tStr.Find(wxT('.')) == wxNOT_FOUND)
+            if (qualTableName.length() && tStr.Find(wxT('.')) == wxNOT_FOUND)
             {
                 pWhereClause += pDb->SQLTableName(qualTableName);
                 pWhereClause += wxT(".");
@@ -1308,7 +1297,7 @@ void wxDbTable::BuildWhereClause(wxString &pWhereClause, int typeOfWhere,
                 case SQL_C_WCHAR:
 #endif
                 //case SQL_C_WXCHAR:  SQL_C_WXCHAR is covered by either SQL_C_CHAR or SQL_C_WCHAR
-                    colValue.Printf(wxT("'%s'"), (UCHAR FAR *) colDefs[colNumber].PtrDataObj);
+                    colValue.Printf(wxT("'%s'"), GetDb()->EscapeSqlChars((wxChar *)colDefs[colNumber].PtrDataObj).c_str());
                     break;
                 case SQL_C_SHORT:
                 case SQL_C_SSHORT:
@@ -1414,6 +1403,9 @@ bool wxDbTable::CreateTable(bool attemptDrop)
             case DB_DATA_TYPE_VARCHAR:
                 cout << pDb->GetTypeInfVarchar().TypeName << wxT("(") << (int)(colDefs[i].SzDataObj / sizeof(wxChar)) << wxT(")");
                 break;
+            case DB_DATA_TYPE_MEMO:
+                cout << pDb->GetTypeInfMemo().TypeName;
+                break;
             case DB_DATA_TYPE_INTEGER:
                 cout << pDb->GetTypeInfInteger().TypeName;
                 break;
@@ -1455,6 +1447,9 @@ bool wxDbTable::CreateTable(bool attemptDrop)
             case DB_DATA_TYPE_VARCHAR:
                 sqlStmt += pDb->GetTypeInfVarchar().TypeName;
                 break;
+            case DB_DATA_TYPE_MEMO:
+                sqlStmt += pDb->GetTypeInfMemo().TypeName;
+                break;
             case DB_DATA_TYPE_INTEGER:
                 sqlStmt += pDb->GetTypeInfInteger().TypeName;
                 break;
@@ -1524,7 +1519,7 @@ bool wxDbTable::CreateTable(bool attemptDrop)
                 //  DB2 is limited to 18 characters for index names
                 if (pDb->Dbms() == dbmsDB2)
                 {
-                    wxASSERT_MSG((tableName && wxStrlen(tableName) <= 13), wxT("DB2 table/index names must be no longer than 13 characters in length.\n\nTruncating table name to 13 characters."));
+                    wxASSERT_MSG(!tableName.empty() && tableName.length() <= 13, wxT("DB2 table/index names must be no longer than 13 characters in length.\n\nTruncating table name to 13 characters."));
                     sqlStmt += pDb->SQLTableName(tableName.substr(0, 13).c_str());
 //                    sqlStmt += tableName.substr(0, 13);
                 }
@@ -1577,7 +1572,7 @@ bool wxDbTable::CreateTable(bool attemptDrop)
 #endif
 
     // Execute the CREATE TABLE statement
-    RETCODE retcode = SQLExecDirect(hstmt, (SQLTCHAR FAR *) sqlStmt.c_str(), SQL_NTS);
+    RETCODE retcode = SQLExecDirect(hstmt, WXSQLCAST(sqlStmt), SQL_NTS);
     if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
     {
         pDb->DispAllErrors(henv, hdbc, hstmt);
@@ -1617,7 +1612,7 @@ bool wxDbTable::DropTable()
     cout << endl << sqlStmt.c_str() << endl;
 #endif
 
-    RETCODE retcode = SQLExecDirect(hstmt, (SQLTCHAR FAR *) sqlStmt.c_str(), SQL_NTS);
+    RETCODE retcode = SQLExecDirect(hstmt, WXSQLCAST(sqlStmt), SQL_NTS);
     if (retcode != SQL_SUCCESS)
     {
         // Check for "Base table not found" error and ignore
@@ -1786,7 +1781,7 @@ bool wxDbTable::CreateIndex(const wxString &indexName, bool unique, UWORD numInd
 #endif
 
     // Execute the CREATE INDEX statement
-    RETCODE retcode = SQLExecDirect(hstmt, (SQLTCHAR FAR *) sqlStmt.c_str(), SQL_NTS);
+    RETCODE retcode = SQLExecDirect(hstmt, WXSQLCAST(sqlStmt), SQL_NTS);
     if (retcode != SQL_SUCCESS)
     {
         pDb->DispAllErrors(henv, hdbc, hstmt);
@@ -1837,7 +1832,7 @@ bool wxDbTable::DropIndex(const wxString &indexName)
 #ifdef DBDEBUG_CONSOLE
     cout << endl << sqlStmt.c_str() << endl;
 #endif
-    RETCODE retcode = SQLExecDirect(hstmt, (SQLTCHAR FAR *) sqlStmt.c_str(), SQL_NTS);
+    RETCODE retcode = SQLExecDirect(hstmt, WXSQLCAST(sqlStmt), SQL_NTS);
     if (retcode != SQL_SUCCESS)
     {
         // Check for "Index not found" error and ignore
@@ -2234,6 +2229,20 @@ void wxDbTable::ClearMemberVar(UWORD colNumber, bool setToNull)
             pDt->second = 0;
             pDt->fraction = 0;
             break;
+        case SQL_C_DATE:
+            DATE_STRUCT *pDtd;
+            pDtd = (DATE_STRUCT *) colDefs[colNumber].PtrDataObj;
+            pDtd->year = 0;
+            pDtd->month = 0;
+            pDtd->day = 0;
+            break;
+        case SQL_C_TIME:
+            TIME_STRUCT *pDtt;
+            pDtt = (TIME_STRUCT *) colDefs[colNumber].PtrDataObj;
+            pDtt->hour = 0;
+            pDtt->minute = 0;
+            pDtt->second = 0;
+            break;
     }
 
     if (setToNull)
@@ -2289,7 +2298,7 @@ bool wxDbTable::SetColDefs(UWORD index, const wxString &fieldName, int dataType,
     if (!colDefs)  // May happen if the database connection fails
         return false;
 
-    if (fieldName.Length() > (unsigned int) DB_MAX_COLUMN_NAME_LEN)
+    if (fieldName.length() > (unsigned int) DB_MAX_COLUMN_NAME_LEN)
     {
         wxStrncpy(colDefs[index].ColName, fieldName, DB_MAX_COLUMN_NAME_LEN);
         colDefs[index].ColName[DB_MAX_COLUMN_NAME_LEN] = 0;  // Prevent buffer overrun
@@ -2349,6 +2358,11 @@ wxDbColDataPtr* wxDbTable::SetColDefs(wxDbColInf *pColInfs, UWORD numCols)
                    pColDataPtrs[index].SzDataObj  = pColInfs[index].bufferSize+(1*sizeof(wxChar));
                    pColDataPtrs[index].SqlCtype   = SQL_C_WXCHAR;
                    break;
+                case DB_DATA_TYPE_MEMO:
+                   pColDataPtrs[index].PtrDataObj = new wxChar[pColInfs[index].bufferSize+(1*sizeof(wxChar))];
+                   pColDataPtrs[index].SzDataObj  = pColInfs[index].bufferSize+(1*sizeof(wxChar));
+                   pColDataPtrs[index].SqlCtype   = SQL_C_WXCHAR;
+                   break;
                 case DB_DATA_TYPE_INTEGER:
                     // Can be long or short
                     if (pColInfs[index].bufferSize == sizeof(long))
@@ -2438,7 +2452,7 @@ ULONG wxDbTable::Count(const wxString &args)
 #if wxODBC_BACKWARD_COMPATABILITY
     if (from && wxStrlen(from))
 #else
-    if (from.Length())
+    if (from.length())
 #endif
         sqlStmt += from;
 
@@ -2446,7 +2460,7 @@ ULONG wxDbTable::Count(const wxString &args)
 #if wxODBC_BACKWARD_COMPATABILITY
     if (where && wxStrlen(where))
 #else
-    if (where.Length())
+    if (where.length())
 #endif
     {
         sqlStmt += wxT(" WHERE ");
@@ -2465,7 +2479,7 @@ ULONG wxDbTable::Count(const wxString &args)
     }
 
     // Execute the SQL statement
-    if (SQLExecDirect(*hstmtCount, (SQLTCHAR FAR *) sqlStmt.c_str(), SQL_NTS) != SQL_SUCCESS)
+    if (SQLExecDirect(*hstmtCount, WXSQLCAST(sqlStmt), SQL_NTS) != SQL_SUCCESS)
     {
         pDb->DispAllErrors(henv, hdbc, *hstmtCount);
         return(0);
@@ -2904,4 +2918,3 @@ void wxDbTable::SetKey(const GenericKey& k)
 
 
 #endif  // wxUSE_ODBC
-