]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/db.cpp
more efficient implementation of ToAscii/FromAscii in UTF8 build
[wxWidgets.git] / src / common / db.cpp
index 5d92d95366d15633aca8c5fbc0b31061fb20405b..7ca9dc47ae85db1c45dd18807ccba36958e05af6 100644 (file)
@@ -1,5 +1,5 @@
 ///////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////
-// Name:        db.cpp
+// Name:        src/common/db.cpp
 // Purpose:     Implementation of the wxDb class.  The wxDb class represents a connection
 //              to an ODBC data source.  The wxDb class allows operations on the data
 //              source such as opening and closing the data source.
 // Purpose:     Implementation of the wxDb class.  The wxDb class represents a connection
 //              to an ODBC data source.  The wxDb class allows operations on the data
 //              source such as opening and closing the data source.
 // Licence:     wxWindows licence
 ///////////////////////////////////////////////////////////////////////////////
 
 // Licence:     wxWindows licence
 ///////////////////////////////////////////////////////////////////////////////
 
-/*
-// SYNOPSIS START
-// SYNOPSIS STOP
-*/
-
 #include "wx/wxprec.h"
 
 #ifdef __BORLANDC__
     #pragma hdrstop
 #endif
 
 #include "wx/wxprec.h"
 
 #ifdef __BORLANDC__
     #pragma hdrstop
 #endif
 
-#ifdef DBDEBUG_CONSOLE
-    #include "wx/ioswrap.h"
-#endif
+#if wxUSE_ODBC
 
 #ifndef WX_PRECOMP
 
 #ifndef WX_PRECOMP
-    #include "wx/string.h"
     #include "wx/object.h"
     #include "wx/list.h"
     #include "wx/object.h"
     #include "wx/list.h"
+    #include "wx/string.h"
     #include "wx/utils.h"
     #include "wx/log.h"
     #include "wx/utils.h"
     #include "wx/log.h"
+    #include "wx/app.h"
+#endif
+
+#ifdef DBDEBUG_CONSOLE
+    #include "wx/ioswrap.h"
 #endif
 #endif
+
 #include "wx/filefn.h"
 #include "wx/wxchar.h"
 
 #include "wx/filefn.h"
 #include "wx/wxchar.h"
 
-#if wxUSE_ODBC
-
 #include <stdio.h>
 #include <string.h>
 #include <assert.h>
 #include <stdio.h>
 #include <string.h>
 #include <assert.h>
 
 #include "wx/db.h"
 
 
 #include "wx/db.h"
 
+// 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
+
 // DLL options compatibility check:
 // DLL options compatibility check:
-#include "wx/app.h"
 WX_CHECK_BUILD_OPTIONS("wxODBC")
 
 WXDLLIMPEXP_DATA_ODBC(wxDbList*) PtrBegDbList = 0;
 WX_CHECK_BUILD_OPTIONS("wxODBC")
 
 WXDLLIMPEXP_DATA_ODBC(wxDbList*) PtrBegDbList = 0;
@@ -66,7 +69,10 @@ wxChar const *SQL_LOG_FILENAME         = wxT("sqllog.txt");
 wxChar const *SQL_CATALOG_FILENAME     = wxT("catalog.txt");
 
 #ifdef __WXDEBUG__
 wxChar const *SQL_CATALOG_FILENAME     = wxT("catalog.txt");
 
 #ifdef __WXDEBUG__
+    #include "wx/thread.h"
+
     extern wxList TablesInUse;
     extern wxList TablesInUse;
+    extern wxCriticalSection csTablesInUse;
 #endif
 
 // SQL Log defaults to be used by GetDbConnection
 #endif
 
 // SQL Log defaults to be used by GetDbConnection
@@ -201,37 +207,37 @@ void wxDbConnectInf::FreeHenv()
 
 void wxDbConnectInf::SetDsn(const wxString &dsn)
 {
 
 void wxDbConnectInf::SetDsn(const wxString &dsn)
 {
-    wxASSERT(dsn.Length() < sizeof(Dsn));
+    wxASSERT(dsn.length() < WXSIZEOF(Dsn));
 
 
-    wxStrncpy(Dsn, dsn, sizeof(Dsn)-1);
-    Dsn[sizeof(Dsn)-1] = 0;  // Prevent buffer overrun
+    wxStrncpy(Dsn, dsn, WXSIZEOF(Dsn)-1);
+    Dsn[WXSIZEOF(Dsn)-1] = 0;  // Prevent buffer overrun
 }  // wxDbConnectInf::SetDsn()
 
 
 void wxDbConnectInf::SetUserID(const wxString &uid)
 {
 }  // wxDbConnectInf::SetDsn()
 
 
 void wxDbConnectInf::SetUserID(const wxString &uid)
 {
-    wxASSERT(uid.Length() < sizeof(Uid));
-    wxStrncpy(Uid, uid, sizeof(Uid)-1);
-    Uid[sizeof(Uid)-1] = 0;  // Prevent buffer overrun
+    wxASSERT(uid.length() < WXSIZEOF(Uid));
+    wxStrncpy(Uid, uid, WXSIZEOF(Uid)-1);
+    Uid[WXSIZEOF(Uid)-1] = 0;  // Prevent buffer overrun
 }  // wxDbConnectInf::SetUserID()
 
 
 void wxDbConnectInf::SetPassword(const wxString &password)
 {
 }  // wxDbConnectInf::SetUserID()
 
 
 void wxDbConnectInf::SetPassword(const wxString &password)
 {
-    wxASSERT(password.Length() < sizeof(AuthStr));
+    wxASSERT(password.length() < WXSIZEOF(AuthStr));
 
 
-    wxStrncpy(AuthStr, password, sizeof(AuthStr)-1);
-    AuthStr[sizeof(AuthStr)-1] = 0;  // Prevent buffer overrun
+    wxStrncpy(AuthStr, password, WXSIZEOF(AuthStr)-1);
+    AuthStr[WXSIZEOF(AuthStr)-1] = 0;  // Prevent buffer overrun
 }  // wxDbConnectInf::SetPassword()
 
 void wxDbConnectInf::SetConnectionStr(const wxString &connectStr)
 {
 }  // wxDbConnectInf::SetPassword()
 
 void wxDbConnectInf::SetConnectionStr(const wxString &connectStr)
 {
-    wxASSERT(connectStr.Length() < sizeof(ConnectionStr));
+    wxASSERT(connectStr.length() < WXSIZEOF(ConnectionStr));
 
     useConnectionStr = wxStrlen(connectStr) > 0;
 
 
     useConnectionStr = wxStrlen(connectStr) > 0;
 
-    wxStrncpy(ConnectionStr, connectStr, sizeof(ConnectionStr)-1);
-    ConnectionStr[sizeof(ConnectionStr)-1] = 0;  // Prevent buffer overrun
+    wxStrncpy(ConnectionStr, connectStr, WXSIZEOF(ConnectionStr)-1);
+    ConnectionStr[WXSIZEOF(ConnectionStr)-1] = 0;  // Prevent buffer overrun
 }  // wxDbConnectInf::SetConnectionStr()
 
 
 }  // wxDbConnectInf::SetConnectionStr()
 
 
@@ -287,7 +293,7 @@ int wxDbColFor::Format(int Nation, int dbDataType, SWORD sqlDataType,
         if ((i_sqlDataType == SQL_VARCHAR)
 #if wxUSE_UNICODE
     #if defined(SQL_WCHAR)
         if ((i_sqlDataType == SQL_VARCHAR)
 #if wxUSE_UNICODE
     #if defined(SQL_WCHAR)
-            || (i_sqlDataType == SQL_WCHAR) 
+            || (i_sqlDataType == SQL_WCHAR)
     #endif
     #if defined(SQL_WVARCHAR)
             || (i_sqlDataType == SQL_WVARCHAR)
     #endif
     #if defined(SQL_WVARCHAR)
             || (i_sqlDataType == SQL_WVARCHAR)
@@ -532,6 +538,12 @@ void wxDb::initialize()
     typeInfBlob.CaseSensitive = 0;
     typeInfBlob.MaximumScale  = 0;
 
     typeInfBlob.CaseSensitive = 0;
     typeInfBlob.MaximumScale  = 0;
 
+    typeInfMemo.TypeName.Empty();
+    typeInfMemo.FsqlType      = 0;
+    typeInfMemo.Precision     = 0;
+    typeInfMemo.CaseSensitive = 0;
+    typeInfMemo.MaximumScale  = 0;
+
     // Error reporting is turned OFF by default
     silent = true;
 
     // Error reporting is turned OFF by default
     silent = true;
 
@@ -555,7 +567,7 @@ void wxDb::initialize()
 //       immediately, as the value is not good after
 //       this function has left scope.
 //
 //       immediately, as the value is not good after
 //       this function has left scope.
 //
-const wxChar *wxDb::convertUserID(const wxChar *userID, wxString &UserID)
+void wxDb::convertUserID(const wxChar *userID, wxString &UserID)
 {
     if (userID)
     {
 {
     if (userID)
     {
@@ -577,8 +589,6 @@ const wxChar *wxDb::convertUserID(const wxChar *userID, wxString &UserID)
     if ((Dbms() == dbmsORACLE) ||
         (Dbms() == dbmsMAXDB))
         UserID = UserID.Upper();
     if ((Dbms() == dbmsORACLE) ||
         (Dbms() == dbmsMAXDB))
         UserID = UserID.Upper();
-
-    return UserID.c_str();
 }  // wxDb::convertUserID()
 
 
 }  // wxDb::convertUserID()
 
 
@@ -650,6 +660,16 @@ bool wxDb::determineDataTypes(bool failOnDataTypeUnsupported)
         SQL_VARBINARY
     };
 
         SQL_VARBINARY
     };
 
+    // These are the possible SQL types we check for use agains the datasource we are connected
+    // to for the purpose of determining which data type to use for the MEMO column types
+    // (a type which allow to store large strings; like VARCHAR just with a bigger precision)
+    //
+    // NOTE: The first type in this enumeration that is determined to be supported by the
+    //       datasource/driver is the one that will be used.
+    SWORD PossibleSqlMemoTypes[] = {
+        SQL_LONGVARCHAR,
+    };
+
 
     // Query the data source regarding data type information
 
 
     // Query the data source regarding data type information
 
@@ -756,6 +776,16 @@ bool wxDb::determineDataTypes(bool failOnDataTypeUnsupported)
     else if (failOnDataTypeUnsupported)
         return false;
 
     else if (failOnDataTypeUnsupported)
         return false;
 
+    // --------------- MEMO ---------------
+    for (iIndex = 0; iIndex < WXSIZEOF(PossibleSqlMemoTypes) &&
+                     !getDataTypeInfo(PossibleSqlMemoTypes[iIndex], typeInfMemo); ++iIndex)
+    {}
+
+    if (iIndex < WXSIZEOF(PossibleSqlMemoTypes))
+        typeInfMemo.FsqlType = PossibleSqlMemoTypes[iIndex];
+    else if (failOnDataTypeUnsupported)
+        return false;
+
     return true;
 }  // wxDb::determineDataTypes
 
     return true;
 }  // wxDb::determineDataTypes
 
@@ -790,6 +820,7 @@ bool wxDb::open(bool failOnDataTypeUnsupported)
     cout << wxT("FLOAT   DATA TYPE: ") << typeInfFloat.TypeName << endl;
     cout << wxT("DATE    DATA TYPE: ") << typeInfDate.TypeName << endl;
     cout << wxT("BLOB    DATA TYPE: ") << typeInfBlob.TypeName << endl;
     cout << wxT("FLOAT   DATA TYPE: ") << typeInfFloat.TypeName << endl;
     cout << wxT("DATE    DATA TYPE: ") << typeInfDate.TypeName << endl;
     cout << wxT("BLOB    DATA TYPE: ") << typeInfBlob.TypeName << endl;
+    cout << wxT("MEMO    DATA TYPE: ") << typeInfMemo.TypeName << endl;
     cout << endl;
 #endif
 
     cout << endl;
 #endif
 
@@ -799,15 +830,15 @@ bool wxDb::open(bool failOnDataTypeUnsupported)
 
 bool wxDb::Open(const wxString& inConnectStr, bool failOnDataTypeUnsupported)
 {
 
 bool wxDb::Open(const wxString& inConnectStr, bool failOnDataTypeUnsupported)
 {
-    wxASSERT(inConnectStr.Length());
+    wxASSERT(inConnectStr.length());
     return Open(inConnectStr, NULL, failOnDataTypeUnsupported);
 }
 
 bool wxDb::Open(const wxString& inConnectStr, SQLHWND parentWnd, bool failOnDataTypeUnsupported)
 {
     return Open(inConnectStr, NULL, failOnDataTypeUnsupported);
 }
 
 bool wxDb::Open(const wxString& inConnectStr, SQLHWND parentWnd, bool failOnDataTypeUnsupported)
 {
-    dsn        = wxT("");
-    uid        = wxT("");
-    authStr    = wxT("");
+    dsn        = wxEmptyString;
+    uid        = wxEmptyString;
+    authStr    = wxEmptyString;
 
     RETCODE retcode;
 
 
     RETCODE retcode;
 
@@ -833,9 +864,9 @@ bool wxDb::Open(const wxString& inConnectStr, SQLHWND parentWnd, bool failOnData
 
     inConnectionStr = inConnectStr;
 
 
     inConnectionStr = inConnectStr;
 
-    retcode = SQLDriverConnect(hdbc, parentWnd, (SQLTCHAR FAR *)inConnectionStr.c_str(),
-                        (SWORD)inConnectionStr.Length(), (SQLTCHAR FAR *)outConnectBuffer,
-                        sizeof(outConnectBuffer), &outConnectBufferLen, SQL_DRIVER_COMPLETE );
+    retcode = SQLDriverConnect(hdbc, parentWnd, WXSQLCAST(inConnectionStr),
+                        (SWORD)inConnectionStr.length(), (SQLTCHAR FAR *)outConnectBuffer,
+                        WXSIZEOF(outConnectBuffer), &outConnectBufferLen, SQL_DRIVER_COMPLETE );
 
     if ((retcode != SQL_SUCCESS) &&
         (retcode != SQL_SUCCESS_WITH_INFO))
 
     if ((retcode != SQL_SUCCESS) &&
         (retcode != SQL_SUCCESS_WITH_INFO))
@@ -851,13 +882,13 @@ bool wxDb::Open(const wxString& inConnectStr, SQLHWND parentWnd, bool failOnData
 /********** wxDb::Open() **********/
 bool wxDb::Open(const wxString &Dsn, const wxString &Uid, const wxString &AuthStr, bool failOnDataTypeUnsupported)
 {
 /********** wxDb::Open() **********/
 bool wxDb::Open(const wxString &Dsn, const wxString &Uid, const wxString &AuthStr, bool failOnDataTypeUnsupported)
 {
-    wxASSERT(Dsn.Length());
+    wxASSERT(!Dsn.empty());
     dsn        = Dsn;
     uid        = Uid;
     authStr    = AuthStr;
 
     dsn        = Dsn;
     uid        = Uid;
     authStr    = AuthStr;
 
-    inConnectionStr = wxT("");
-    outConnectionStr = wxT("");
+    inConnectionStr = wxEmptyString;
+    outConnectionStr = wxEmptyString;
 
     RETCODE retcode;
 
 
     RETCODE retcode;
 
@@ -878,9 +909,10 @@ bool wxDb::Open(const wxString &Dsn, const wxString &Uid, const wxString &AuthSt
     }
 
     // Connect to the data source
     }
 
     // Connect to the data source
-    retcode = SQLConnect(hdbc, (SQLTCHAR FAR *) dsn.c_str(), SQL_NTS,
-                         (SQLTCHAR FAR *) uid.c_str(), SQL_NTS,
-                         (SQLTCHAR FAR *) authStr.c_str(), SQL_NTS);
+    retcode = SQLConnect(hdbc,
+                         WXSQLCAST(dsn), SQL_NTS,
+                         WXSQLCAST(uid), SQL_NTS,
+                         WXSQLCAST(authStr), SQL_NTS);
 
     if ((retcode != SQL_SUCCESS) &&
         (retcode != SQL_SUCCESS_WITH_INFO))
 
     if ((retcode != SQL_SUCCESS) &&
         (retcode != SQL_SUCCESS_WITH_INFO))
@@ -897,7 +929,7 @@ bool wxDb::Open(wxDbConnectInf *dbConnectInf, bool failOnDataTypeUnsupported)
 
     // Use the connection string if one is present
     if (dbConnectInf->UseConnectionStr())
 
     // Use the connection string if one is present
     if (dbConnectInf->UseConnectionStr())
-        return Open(GetConnectionInStr(), failOnDataTypeUnsupported);
+        return Open(dbConnectInf->GetConnectionStr(), failOnDataTypeUnsupported);
     else
         return Open(dbConnectInf->GetDsn(), dbConnectInf->GetUserID(),
                     dbConnectInf->GetPassword(), failOnDataTypeUnsupported);
     else
         return Open(dbConnectInf->GetDsn(), dbConnectInf->GetUserID(),
                     dbConnectInf->GetPassword(), failOnDataTypeUnsupported);
@@ -938,9 +970,9 @@ bool wxDb::Open(wxDb *copyDb)
 
         inConnectionStr = copyDb->GetConnectionInStr();
 
 
         inConnectionStr = copyDb->GetConnectionInStr();
 
-        retcode = SQLDriverConnect(hdbc, NULL, (SQLTCHAR FAR *)inConnectionStr.c_str(),
-                            (SWORD)inConnectionStr.Length(), (SQLTCHAR FAR *)outConnectBuffer,
-                            sizeof(outConnectBuffer), &outConnectBufferLen, SQL_DRIVER_COMPLETE);
+        retcode = SQLDriverConnect(hdbc, NULL, WXSQLCAST(inConnectionStr),
+                            (SWORD)inConnectionStr.length(), (SQLTCHAR FAR *)outConnectBuffer,
+                            WXSIZEOF(outConnectBuffer), &outConnectBufferLen, SQL_DRIVER_COMPLETE);
 
         if ((retcode != SQL_SUCCESS) &&
             (retcode != SQL_SUCCESS_WITH_INFO))
 
         if ((retcode != SQL_SUCCESS) &&
             (retcode != SQL_SUCCESS_WITH_INFO))
@@ -953,9 +985,10 @@ bool wxDb::Open(wxDb *copyDb)
     else
     {
         // Connect to the data source
     else
     {
         // Connect to the data source
-        retcode = SQLConnect(hdbc, (SQLTCHAR FAR *) dsn.c_str(), SQL_NTS,
-                             (SQLTCHAR FAR *) uid.c_str(), SQL_NTS,
-                             (SQLTCHAR FAR *) authStr.c_str(), SQL_NTS);
+        retcode = SQLConnect(hdbc,
+                             WXSQLCAST(dsn), SQL_NTS,
+                             WXSQLCAST(uid), SQL_NTS,
+                             WXSQLCAST(authStr), SQL_NTS);
     }
 
     if ((retcode != SQL_SUCCESS) &&
     }
 
     if ((retcode != SQL_SUCCESS) &&
@@ -1050,12 +1083,20 @@ bool wxDb::Open(wxDb *copyDb)
     typeInfBlob.CaseSensitive    = copyDb->typeInfBlob.CaseSensitive;
     typeInfBlob.MaximumScale     = copyDb->typeInfBlob.MaximumScale;
 
     typeInfBlob.CaseSensitive    = copyDb->typeInfBlob.CaseSensitive;
     typeInfBlob.MaximumScale     = copyDb->typeInfBlob.MaximumScale;
 
+    // Memo
+    typeInfMemo.FsqlType         = copyDb->typeInfMemo.FsqlType;
+    typeInfMemo.TypeName         = copyDb->typeInfMemo.TypeName;
+    typeInfMemo.Precision        = copyDb->typeInfMemo.Precision;
+    typeInfMemo.CaseSensitive    = copyDb->typeInfMemo.CaseSensitive;
+    typeInfMemo.MaximumScale     = copyDb->typeInfMemo.MaximumScale;
+
 #ifdef DBDEBUG_CONSOLE
     cout << wxT("VARCHAR DATA TYPE: ") << typeInfVarchar.TypeName << endl;
     cout << wxT("INTEGER DATA TYPE: ") << typeInfInteger.TypeName << endl;
     cout << wxT("FLOAT   DATA TYPE: ") << typeInfFloat.TypeName << endl;
     cout << wxT("DATE    DATA TYPE: ") << typeInfDate.TypeName << endl;
     cout << wxT("BLOB    DATA TYPE: ") << typeInfBlob.TypeName << endl;
 #ifdef DBDEBUG_CONSOLE
     cout << wxT("VARCHAR DATA TYPE: ") << typeInfVarchar.TypeName << endl;
     cout << wxT("INTEGER DATA TYPE: ") << typeInfInteger.TypeName << endl;
     cout << wxT("FLOAT   DATA TYPE: ") << typeInfFloat.TypeName << endl;
     cout << wxT("DATE    DATA TYPE: ") << typeInfDate.TypeName << endl;
     cout << wxT("BLOB    DATA TYPE: ") << typeInfBlob.TypeName << endl;
+    cout << wxT("MEMO    DATA TYPE: ") << typeInfMemo.TypeName << endl;
     cout << endl;
 #endif
 
     cout << endl;
 #endif
 
@@ -1715,20 +1756,24 @@ void wxDb::Close(void)
     wxASSERT(nTables == 0);
 
 #ifdef __WXDEBUG__
     wxASSERT(nTables == 0);
 
 #ifdef __WXDEBUG__
-    wxTablesInUse *tiu;
-    wxList::compatibility_iterator pNode;
-    pNode = TablesInUse.GetFirst();
-    wxString s,s2;
-    while (pNode)
     {
     {
-        tiu = (wxTablesInUse *)pNode->GetData();
-        if (tiu->pDb == this)
+        wxCriticalSectionLocker lock(csTablesInUse);
+        wxTablesInUse *tiu;
+        wxList::compatibility_iterator pNode;
+        pNode = TablesInUse.GetFirst();
+        wxString s,s2;
+        while (pNode)
         {
         {
-            s.Printf(wxT("(%-20s)     tableID:[%6lu]     pDb:[%p]"), tiu->tableName,tiu->tableID,tiu->pDb);
-            s2.Printf(wxT("Orphaned table found using pDb:[%p]"),this);
-            wxLogDebug(s.c_str(),s2.c_str());
+            tiu = (wxTablesInUse *)pNode->GetData();
+            if (tiu->pDb == this)
+            {
+                s.Printf(wxT("(%-20s)     tableID:[%6lu]     pDb:[%p]"),
+                        tiu->tableName, tiu->tableID, wx_static_cast(void*, tiu->pDb));
+                s2.Printf(wxT("Orphaned table found using pDb:[%p]"), wx_static_cast(void*, this));
+                wxLogDebug(s.c_str(),s2.c_str());
+            }
+            pNode = pNode->GetNext();
         }
         }
-        pNode = pNode->GetNext();
     }
 #endif
 
     }
 #endif
 
@@ -1793,7 +1838,8 @@ bool wxDb::DispAllErrors(HENV aHenv, HDBC aHdbc, HSTMT aHstmt)
 
    while (SQLError(aHenv, aHdbc, aHstmt, (SQLTCHAR FAR *) sqlState, &nativeError, (SQLTCHAR FAR *) errorMsg, SQL_MAX_MESSAGE_LENGTH - 1, &cbErrorMsg) == SQL_SUCCESS)
      {
 
    while (SQLError(aHenv, aHdbc, aHstmt, (SQLTCHAR FAR *) sqlState, &nativeError, (SQLTCHAR FAR *) errorMsg, SQL_MAX_MESSAGE_LENGTH - 1, &cbErrorMsg) == SQL_SUCCESS)
      {
-        odbcErrMsg.Printf(wxT("SQL State = %s\nNative Error Code = %li\nError Message = %s\n"), sqlState, nativeError, errorMsg);
+        odbcErrMsg.Printf(wxT("SQL State = %s\nNative Error Code = %li\nError Message = %s\n"),
+                          sqlState, (long)nativeError, errorMsg);
         logError(odbcErrMsg, sqlState);
         if (!silent)
         {
         logError(odbcErrMsg, sqlState);
         if (!silent)
         {
@@ -1831,7 +1877,8 @@ void wxDb::DispNextError(void)
 {
     wxString odbcErrMsg;
 
 {
     wxString odbcErrMsg;
 
-    odbcErrMsg.Printf(wxT("SQL State = %s\nNative Error Code = %li\nError Message = %s\n"), sqlState, nativeError, errorMsg);
+    odbcErrMsg.Printf(wxT("SQL State = %s\nNative Error Code = %li\nError Message = %s\n"),
+                      sqlState, (long)nativeError, errorMsg);
     logError(odbcErrMsg, sqlState);
 
     if (silent)
     logError(odbcErrMsg, sqlState);
 
     if (silent)
@@ -1854,7 +1901,7 @@ void wxDb::DispNextError(void)
 /********** wxDb::logError() **********/
 void wxDb::logError(const wxString &errMsg, const wxString &SQLState)
 {
 /********** wxDb::logError() **********/
 void wxDb::logError(const wxString &errMsg, const wxString &SQLState)
 {
-    wxASSERT(errMsg.Length());
+    wxASSERT(errMsg.length());
 
     static int pLast = -1;
     int dbStatus;
 
     static int pLast = -1;
     int dbStatus;
@@ -1870,7 +1917,7 @@ void wxDb::logError(const wxString &errMsg, const wxString &SQLState)
     wxStrncpy(errorList[pLast], errMsg, DB_MAX_ERROR_MSG_LEN);
     errorList[pLast][DB_MAX_ERROR_MSG_LEN] = 0;
 
     wxStrncpy(errorList[pLast], errMsg, DB_MAX_ERROR_MSG_LEN);
     errorList[pLast][DB_MAX_ERROR_MSG_LEN] = 0;
 
-    if (SQLState.Length())
+    if (SQLState.length())
         if ((dbStatus = TranslateSqlState(SQLState)) != DB_ERR_FUNCTION_SEQUENCE_ERROR)
             DB_STATUS = dbStatus;
 
         if ((dbStatus = TranslateSqlState(SQLState)) != DB_ERR_FUNCTION_SEQUENCE_ERROR)
             DB_STATUS = dbStatus;
 
@@ -2135,7 +2182,7 @@ bool wxDb::CreateView(const wxString &viewName, const wxString &colList,
     sqlStmt  = wxT("CREATE VIEW ");
     sqlStmt += viewName;
 
     sqlStmt  = wxT("CREATE VIEW ");
     sqlStmt += viewName;
 
-    if (colList.Length())
+    if (colList.length())
     {
         sqlStmt += wxT(" (");
         sqlStmt += colList;
     {
         sqlStmt += wxT(" (");
         sqlStmt += colList;
@@ -2175,7 +2222,7 @@ bool wxDb::DropView(const wxString &viewName)
     cout << endl << sqlStmt.c_str() << endl;
 #endif
 
     cout << endl << sqlStmt.c_str() << endl;
 #endif
 
-    if (SQLExecDirect(hstmt, (SQLTCHAR FAR *) sqlStmt.c_str(), SQL_NTS) != SQL_SUCCESS)
+    if (SQLExecDirect(hstmt, WXSQLCAST(sqlStmt), SQL_NTS) != SQL_SUCCESS)
     {
         // Check for "Base table not found" error and ignore
         GetNextError(henv, hdbc, hstmt);
     {
         // Check for "Base table not found" error and ignore
         GetNextError(henv, hdbc, hstmt);
@@ -2208,7 +2255,7 @@ bool wxDb::ExecSql(const wxString &pSqlStmt)
 
     SQLFreeStmt(hstmt, SQL_CLOSE);
 
 
     SQLFreeStmt(hstmt, SQL_CLOSE);
 
-    retcode = SQLExecDirect(hstmt, (SQLTCHAR FAR *) pSqlStmt.c_str(), SQL_NTS);
+    retcode = SQLExecDirect(hstmt, WXSQLCAST(pSqlStmt), SQL_NTS);
     if (retcode == SQL_SUCCESS ||
         (Dbms() == dbmsDB2 && (retcode == SQL_SUCCESS_WITH_INFO || retcode == SQL_NO_DATA_FOUND)))
     {
     if (retcode == SQL_SUCCESS ||
         (Dbms() == dbmsDB2 && (retcode == SQL_SUCCESS_WITH_INFO || retcode == SQL_NO_DATA_FOUND)))
     {
@@ -2286,6 +2333,9 @@ bool wxDb::ExecSql(const wxString &pSqlStmt, wxDbColInf** columns, short& numcol
             case SQL_CHAR:
                 pColInf[colNum].dbDataType = DB_DATA_TYPE_VARCHAR;
                 break;
             case SQL_CHAR:
                 pColInf[colNum].dbDataType = DB_DATA_TYPE_VARCHAR;
                 break;
+            case SQL_LONGVARCHAR:
+                pColInf[colNum].dbDataType = DB_DATA_TYPE_MEMO;
+                break;
             case SQL_TINYINT:
             case SQL_SMALLINT:
             case SQL_INTEGER:
             case SQL_TINYINT:
             case SQL_SMALLINT:
             case SQL_INTEGER:
@@ -2386,7 +2436,7 @@ int wxDb::GetKeyFields(const wxString &tableName, wxDbColInf* colInf, UWORD noCo
     retcode = SQLPrimaryKeys(hstmt,
                              NULL, 0,                               /* Catalog name  */
                              NULL, 0,                               /* Schema name   */
     retcode = SQLPrimaryKeys(hstmt,
                              NULL, 0,                               /* Catalog name  */
                              NULL, 0,                               /* Schema name   */
-                             (SQLTCHAR FAR *) tableName.c_str(), SQL_NTS); /* Table name    */
+                             WXSQLCAST(tableName), SQL_NTS); /* Table name    */
 
     /*---------------------------------------------------------------------*/
     /* Fetch and display the result set. This will be a list of the        */
 
     /*---------------------------------------------------------------------*/
     /* Fetch and display the result set. This will be a list of the        */
@@ -2413,7 +2463,7 @@ int wxDb::GetKeyFields(const wxString &tableName, wxDbColInf* colInf, UWORD noCo
     retcode = SQLForeignKeys(hstmt,
                              NULL, 0,                            /* Primary catalog */
                              NULL, 0,                            /* Primary schema  */
     retcode = SQLForeignKeys(hstmt,
                              NULL, 0,                            /* Primary catalog */
                              NULL, 0,                            /* Primary schema  */
-                             (SQLTCHAR FAR *)tableName.c_str(), SQL_NTS,/* Primary table   */
+                             WXSQLCAST(tableName), SQL_NTS,/* Primary table   */
                              NULL, 0,                            /* Foreign catalog */
                              NULL, 0,                            /* Foreign schema  */
                              NULL, 0);                           /* Foreign table   */
                              NULL, 0,                            /* Foreign catalog */
                              NULL, 0,                            /* Foreign schema  */
                              NULL, 0);                           /* Foreign table   */
@@ -2462,7 +2512,7 @@ int wxDb::GetKeyFields(const wxString &tableName, wxDbColInf* colInf, UWORD noCo
                              NULL, 0,                             /* Primary table     */
                              NULL, 0,                             /* Foreign catalog   */
                              NULL, 0,                             /* Foreign schema    */
                              NULL, 0,                             /* Primary table     */
                              NULL, 0,                             /* Foreign catalog   */
                              NULL, 0,                             /* Foreign schema    */
-                             (SQLTCHAR *)tableName.c_str(), SQL_NTS);/* Foreign table     */
+                             WXSQLCAST(tableName), SQL_NTS);/* Foreign table     */
 
     /*---------------------------------------------------------------------*/
     /*  Fetch and display the result set. This will be all of the          */
 
     /*---------------------------------------------------------------------*/
     /*  Fetch and display the result set. This will be all of the          */
@@ -2580,8 +2630,8 @@ wxDbColInf *wxDb::GetColumns(wxChar *tableName[], const wxChar *userID)
             {
                 retcode = SQLColumns(hstmt,
                                      NULL, 0,                                // All qualifiers
             {
                 retcode = SQLColumns(hstmt,
                                      NULL, 0,                                // All qualifiers
-                                     (SQLTCHAR *) UserID.c_str(), SQL_NTS,      // Owner
-                                     (SQLTCHAR *) TableName.c_str(), SQL_NTS,
+                                     WXSQLCAST(UserID), SQL_NTS,      // Owner
+                                     WXSQLCAST(TableName), SQL_NTS,
                                      NULL, 0);                               // All columns
             }
             else
                                      NULL, 0);                               // All columns
             }
             else
@@ -2589,7 +2639,7 @@ wxDbColInf *wxDb::GetColumns(wxChar *tableName[], const wxChar *userID)
                 retcode = SQLColumns(hstmt,
                                      NULL, 0,                                // All qualifiers
                                      NULL, 0,                                // Owner
                 retcode = SQLColumns(hstmt,
                                      NULL, 0,                                // All qualifiers
                                      NULL, 0,                                // Owner
-                                     (SQLTCHAR *) TableName.c_str(), SQL_NTS,
+                                     WXSQLCAST(TableName), SQL_NTS,
                                      NULL, 0);                               // All columns
             }
             if (retcode != SQL_SUCCESS)
                                      NULL, 0);                               // All columns
             }
             if (retcode != SQL_SUCCESS)
@@ -2736,8 +2786,8 @@ wxDbColInf *wxDb::GetColumns(const wxString &tableName, UWORD *numCols, const wx
         {
             retcode = SQLColumns(hstmt,
                                  NULL, 0,                                // All qualifiers
         {
             retcode = SQLColumns(hstmt,
                                  NULL, 0,                                // All qualifiers
-                                 (SQLTCHAR *) UserID.c_str(), SQL_NTS,    // Owner
-                                 (SQLTCHAR *) TableName.c_str(), SQL_NTS,
+                                 WXSQLCAST(UserID), SQL_NTS,    // Owner
+                                 WXSQLCAST(TableName), SQL_NTS,
                                  NULL, 0);                               // All columns
         }
         else
                                  NULL, 0);                               // All columns
         }
         else
@@ -2745,7 +2795,7 @@ wxDbColInf *wxDb::GetColumns(const wxString &tableName, UWORD *numCols, const wx
             retcode = SQLColumns(hstmt,
                                  NULL, 0,                                 // All qualifiers
                                  NULL, 0,                                 // Owner
             retcode = SQLColumns(hstmt,
                                  NULL, 0,                                 // All qualifiers
                                  NULL, 0,                                 // Owner
-                                 (SQLTCHAR *) TableName.c_str(), SQL_NTS,
+                                 WXSQLCAST(TableName), SQL_NTS,
                                  NULL, 0);                                // All columns
         }
         if (retcode != SQL_SUCCESS)
                                  NULL, 0);                                // All columns
         }
         if (retcode != SQL_SUCCESS)
@@ -3069,6 +3119,9 @@ wxDbColInf *wxDb::GetColumns(const wxString &tableName, int *numCols, const wxCh
                         case SQL_CHAR:
                             colInf[colNo].dbDataType = DB_DATA_TYPE_VARCHAR;
                         break;
                         case SQL_CHAR:
                             colInf[colNo].dbDataType = DB_DATA_TYPE_VARCHAR;
                         break;
+                        case SQL_LONGVARCHAR:
+                            colInf[colNo].dbDataType = DB_DATA_TYPE_MEMO;
+                            break;
                         case SQL_TINYINT:
                         case SQL_SMALLINT:
                         case SQL_INTEGER:
                         case SQL_TINYINT:
                         case SQL_SMALLINT:
                         case SQL_INTEGER:
@@ -3240,8 +3293,8 @@ int wxDb::GetColumnCount(const wxString &tableName, const wxChar *userID)
     {
         retcode = SQLColumns(hstmt,
                              NULL, 0,                                // All qualifiers
     {
         retcode = SQLColumns(hstmt,
                              NULL, 0,                                // All qualifiers
-                             (SQLTCHAR *) UserID.c_str(), SQL_NTS,      // Owner
-                             (SQLTCHAR *) TableName.c_str(), SQL_NTS,
+                             WXSQLCAST(UserID), SQL_NTS,      // Owner
+                             WXSQLCAST(TableName), SQL_NTS,
                              NULL, 0);                               // All columns
     }
     else
                              NULL, 0);                               // All columns
     }
     else
@@ -3249,7 +3302,7 @@ int wxDb::GetColumnCount(const wxString &tableName, const wxChar *userID)
         retcode = SQLColumns(hstmt,
                              NULL, 0,                                // All qualifiers
                              NULL, 0,                                // Owner
         retcode = SQLColumns(hstmt,
                              NULL, 0,                                // All qualifiers
                              NULL, 0,                                // Owner
-                             (SQLTCHAR *) TableName.c_str(), SQL_NTS,
+                             WXSQLCAST(TableName), SQL_NTS,
                              NULL, 0);                               // All columns
     }
     if (retcode != SQL_SUCCESS)
                              NULL, 0);                               // All columns
     }
     if (retcode != SQL_SUCCESS)
@@ -3333,7 +3386,7 @@ wxDbInf *wxDb::GetCatalog(const wxChar *userID)
         {
             retcode = SQLTables(hstmt,
                                 NULL, 0,                             // All qualifiers
         {
             retcode = SQLTables(hstmt,
                                 NULL, 0,                             // All qualifiers
-                                (SQLTCHAR *) UserID.c_str(), SQL_NTS,   // User specified
+                                WXSQLCAST(UserID), SQL_NTS,   // User specified
                                 NULL, 0,                             // All tables
                                 NULL, 0);                            // All columns
         }
                                 NULL, 0,                             // All tables
                                 NULL, 0);                            // All columns
         }
@@ -3411,7 +3464,7 @@ bool wxDb::Catalog(const wxChar *userID, const wxString &fileName)
  *       to avoid undesired unbinding of columns.
  */
 {
  *       to avoid undesired unbinding of columns.
  */
 {
-    wxASSERT(fileName.Length());
+    wxASSERT(fileName.length());
 
     RETCODE   retcode;
     SQLLEN    cb;
 
     RETCODE   retcode;
     SQLLEN    cb;
@@ -3440,7 +3493,7 @@ bool wxDb::Catalog(const wxChar *userID, const wxString &fileName)
     {
         retcode = SQLColumns(hstmt,
                              NULL, 0,                                // All qualifiers
     {
         retcode = SQLColumns(hstmt,
                              NULL, 0,                                // All qualifiers
-                             (SQLTCHAR *) UserID.c_str(), SQL_NTS,      // User specified
+                             WXSQLCAST(UserID), SQL_NTS,      // User specified
                              NULL, 0,                                // All tables
                              NULL, 0);                               // All columns
     }
                              NULL, 0,                                // All tables
                              NULL, 0);                               // All columns
     }
@@ -3531,14 +3584,14 @@ bool wxDb::TableExists(const wxString &tableName, const wxChar *userID, const wx
  *        userID != ""    ... UserID set equal to 'userID'
  */
 {
  *        userID != ""    ... UserID set equal to 'userID'
  */
 {
-    wxASSERT(tableName.Length());
+    wxASSERT(tableName.length());
 
     wxString TableName;
 
     if (Dbms() == dbmsDBASE)
     {
         wxString dbName;
 
     wxString TableName;
 
     if (Dbms() == dbmsDBASE)
     {
         wxString dbName;
-        if (tablePath.Length())
+        if (tablePath.length())
             dbName.Printf(wxT("%s/%s.dbf"), tablePath.c_str(), tableName.c_str());
         else
             dbName.Printf(wxT("%s.dbf"), tableName.c_str());
             dbName.Printf(wxT("%s/%s.dbf"), tablePath.c_str(), tableName.c_str());
         else
             dbName.Printf(wxT("%s.dbf"), tableName.c_str());
@@ -3575,8 +3628,8 @@ bool wxDb::TableExists(const wxString &tableName, const wxChar *userID, const wx
     {
         retcode = SQLTables(hstmt,
                             NULL, 0,                                  // All qualifiers
     {
         retcode = SQLTables(hstmt,
                             NULL, 0,                                  // All qualifiers
-                            (SQLTCHAR *) UserID.c_str(), SQL_NTS,        // Only tables owned by this user
-                            (SQLTCHAR FAR *)TableName.c_str(), SQL_NTS,
+                            WXSQLCAST(UserID), SQL_NTS,        // Only tables owned by this user
+                            WXSQLCAST(TableName), SQL_NTS,
                             NULL, 0);                                 // All table types
     }
     else
                             NULL, 0);                                 // All table types
     }
     else
@@ -3584,7 +3637,7 @@ bool wxDb::TableExists(const wxString &tableName, const wxChar *userID, const wx
         retcode = SQLTables(hstmt,
                             NULL, 0,                                  // All qualifiers
                             NULL, 0,                                  // All owners
         retcode = SQLTables(hstmt,
                             NULL, 0,                                  // All qualifiers
                             NULL, 0,                                  // All owners
-                            (SQLTCHAR FAR *)TableName.c_str(), SQL_NTS,
+                            WXSQLCAST(TableName), SQL_NTS,
                             NULL, 0);                                 // All table types
     }
     if (retcode != SQL_SUCCESS)
                             NULL, 0);                                 // All table types
     }
     if (retcode != SQL_SUCCESS)
@@ -3608,7 +3661,7 @@ bool wxDb::TableExists(const wxString &tableName, const wxChar *userID, const wx
 bool wxDb::TablePrivileges(const wxString &tableName, const wxString &priv, const wxChar *userID,
                             const wxChar *schema, const wxString &WXUNUSED(tablePath))
 {
 bool wxDb::TablePrivileges(const wxString &tableName, const wxString &priv, const wxChar *userID,
                             const wxChar *schema, const wxString &WXUNUSED(tablePath))
 {
-    wxASSERT(tableName.Length());
+    wxASSERT(tableName.length());
 
     wxDbTablePrivilegeInfo  result;
     SQLLEN  cbRetVal;
 
     wxDbTablePrivilegeInfo  result;
     SQLLEN  cbRetVal;
@@ -3643,15 +3696,15 @@ bool wxDb::TablePrivileges(const wxString &tableName, const wxString &priv, cons
     {
         retcode = SQLTablePrivileges(hstmt,
                                      NULL, 0,                                    // Catalog
     {
         retcode = SQLTablePrivileges(hstmt,
                                      NULL, 0,                                    // Catalog
-                                     (SQLTCHAR FAR *)Schema.c_str(), SQL_NTS,               // Schema
-                                     (SQLTCHAR FAR *)TableName.c_str(), SQL_NTS);
+                                     WXSQLCAST(Schema), SQL_NTS,               // Schema
+                                     WXSQLCAST(TableName), SQL_NTS);
     }
     else
     {
         retcode = SQLTablePrivileges(hstmt,
                                      NULL, 0,                                    // Catalog
                                      NULL, 0,                                    // Schema
     }
     else
     {
         retcode = SQLTablePrivileges(hstmt,
                                      NULL, 0,                                    // Catalog
                                      NULL, 0,                                    // Schema
-                                     (SQLTCHAR FAR *)TableName.c_str(), SQL_NTS);
+                                     WXSQLCAST(TableName), SQL_NTS);
     }
 
 #ifdef DBDEBUG_CONSOLE
     }
 
 #ifdef DBDEBUG_CONSOLE
@@ -3757,7 +3810,7 @@ const wxString wxDb::SQLColumnName(const wxChar *colName)
 bool wxDb::SetSqlLogging(wxDbSqlLogState state, const wxString &filename, bool append)
 {
     wxASSERT(state == sqlLogON  || state == sqlLogOFF);
 bool wxDb::SetSqlLogging(wxDbSqlLogState state, const wxString &filename, bool append)
 {
     wxASSERT(state == sqlLogON  || state == sqlLogOFF);
-    wxASSERT(state == sqlLogOFF || filename.Length());
+    wxASSERT(state == sqlLogOFF || filename.length());
 
     if (state == sqlLogON)
     {
 
     if (state == sqlLogON)
     {
@@ -3787,7 +3840,7 @@ bool wxDb::SetSqlLogging(wxDbSqlLogState state, const wxString &filename, bool a
 /********** wxDb::WriteSqlLog() **********/
 bool wxDb::WriteSqlLog(const wxString &logMsg)
 {
 /********** wxDb::WriteSqlLog() **********/
 bool wxDb::WriteSqlLog(const wxString &logMsg)
 {
-    wxASSERT(logMsg.Length());
+    wxASSERT(logMsg.length());
 
     if (fpSqlLog == 0 || sqlLogState == sqlLogOFF)
         return false;
 
     if (fpSqlLog == 0 || sqlLogState == sqlLogOFF)
         return false;
@@ -3948,7 +4001,7 @@ wxDBMS wxDb::Dbms(void)
 
     baseName[3] = 0;
     if (!wxStricmp(baseName,wxT("DB2")))
 
     baseName[3] = 0;
     if (!wxStricmp(baseName,wxT("DB2")))
-        return((wxDBMS)(dbmsType = dbmsDBASE));
+        return((wxDBMS)(dbmsType = dbmsDB2));
 
     return((wxDBMS)(dbmsType = dbmsUNIDENTIFIED));
 
 
     return((wxDBMS)(dbmsType = dbmsUNIDENTIFIED));
 
@@ -3959,8 +4012,8 @@ bool wxDb::ModifyColumn(const wxString &tableName, const wxString &columnName,
                         int dataType, ULONG columnLength,
                         const wxString &optionalParam)
 {
                         int dataType, ULONG columnLength,
                         const wxString &optionalParam)
 {
-    wxASSERT(tableName.Length());
-    wxASSERT(columnName.Length());
+    wxASSERT(tableName.length());
+    wxASSERT(columnName.length());
     wxASSERT((dataType == DB_DATA_TYPE_VARCHAR && columnLength > 0) ||
              dataType != DB_DATA_TYPE_VARCHAR);
 
     wxASSERT((dataType == DB_DATA_TYPE_VARCHAR && columnLength > 0) ||
              dataType != DB_DATA_TYPE_VARCHAR);
 
@@ -4038,7 +4091,7 @@ bool wxDb::ModifyColumn(const wxString &tableName, const wxString &columnName,
     }
 
     // for passing things like "NOT NULL"
     }
 
     // for passing things like "NOT NULL"
-    if (optionalParam.Length())
+    if (optionalParam.length())
     {
         sqlStmt += wxT(" ");
         sqlStmt += optionalParam;
     {
         sqlStmt += wxT(" ");
         sqlStmt += optionalParam;
@@ -4048,6 +4101,28 @@ bool wxDb::ModifyColumn(const wxString &tableName, const wxString &columnName,
 
 } // wxDb::ModifyColumn()
 
 
 } // wxDb::ModifyColumn()
 
+/********** wxDb::EscapeSqlChars() **********/
+wxString wxDb::EscapeSqlChars(const wxString& valueOrig)
+{
+    wxString value(valueOrig);
+    switch (Dbms())
+    {
+        case dbmsACCESS:
+            // Access doesn't seem to care about backslashes, so only escape single quotes.
+            value.Replace(wxT("'"), wxT("''"));
+            break;
+
+        default:
+            // All the others are supposed to be the same for now, add special
+            // handling for them if necessary
+            value.Replace(wxT("\\"), wxT("\\\\"));
+            value.Replace(wxT("'"), wxT("\\'"));
+            break;
+    }
+
+    return value;
+} // wxDb::EscapeSqlChars()
+
 
 /********** wxDbGetConnection() **********/
 wxDb WXDLLIMPEXP_ODBC *wxDbGetConnection(wxDbConnectInf *pDbConfig, bool FwdOnlyCursors)
 
 /********** wxDbGetConnection() **********/
 wxDb WXDLLIMPEXP_ODBC *wxDbGetConnection(wxDbConnectInf *pDbConfig, bool FwdOnlyCursors)