]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/db.cpp
filename correction
[wxWidgets.git] / src / common / db.cpp
index 963f6e349763382a7fa4c18a3056f30684bc1db9..5d92d95366d15633aca8c5fbc0b31061fb20405b 100644 (file)
 // Created:     9.96
 // RCS-ID:      $Id$
 // Copyright:   (c) 1996 Remstar International, Inc.
 // Created:     9.96
 // RCS-ID:      $Id$
 // Copyright:   (c) 1996 Remstar International, Inc.
-// Licence:     wxWindows licence, plus:
-// Notice:      This class library and its intellectual design are free of charge for use,
-//              modification, enhancement, debugging under the following conditions:
-//              1) These classes may only be used as part of the implementation of a
-//                 wxWindows-based application
-//              2) All enhancements and bug fixes are to be submitted back to the wxWindows
-//                 user groups free of all charges for use with the wxWindows library.
-//              3) These classes may not be distributed as part of any other class library,
-//                 DLL, text (written or electronic), other than a complete distribution of
-//                 the wxWindows GUI development toolkit.
+// Licence:     wxWindows licence
 ///////////////////////////////////////////////////////////////////////////////
 
 /*
 ///////////////////////////////////////////////////////////////////////////////
 
 /*
 
 #include "wx/wxprec.h"
 
 
 #include "wx/wxprec.h"
 
-
-// Use this line for wxWindows v1.x
-//#include "wx_ver.h"
-// Use this line for wxWindows v2.x
-#include "wx/version.h"
-
-#if wxMAJOR_VERSION == 2
-    #ifdef __GNUG__
-        #pragma implementation "db.h"
-    #endif
+#ifdef __BORLANDC__
+    #pragma hdrstop
 #endif
 
 #ifdef DBDEBUG_CONSOLE
     #include "wx/ioswrap.h"
 #endif
 
 #endif
 
 #ifdef DBDEBUG_CONSOLE
     #include "wx/ioswrap.h"
 #endif
 
-#ifdef    __BORLANDC__
-    #pragma hdrstop
-#endif  //__BORLANDC__
-
-#if wxMAJOR_VERSION == 2
-    #ifndef WX_PRECOMP
-        #include "wx/string.h"
-        #include "wx/object.h"
-        #include "wx/list.h"
-        #include "wx/utils.h"
-        #include "wx/msgdlg.h"
-        #include "wx/log.h"
-    #endif
-    #include "wx/filefn.h"
-    #include "wx/wxchar.h"
-#endif
-
-
-#if wxMAJOR_VERSION == 1
-#    if defined(wx_msw) || defined(wx_x)
-#        ifdef WX_PRECOMP
-#            include "wx_prec.h"
-#        else
-#            include "wx.h"
-#        endif
-#    endif
-#    define wxUSE_ODBC 1
+#ifndef WX_PRECOMP
+    #include "wx/string.h"
+    #include "wx/object.h"
+    #include "wx/list.h"
+    #include "wx/utils.h"
+    #include "wx/log.h"
 #endif
 #endif
+#include "wx/filefn.h"
+#include "wx/wxchar.h"
 
 #if wxUSE_ODBC
 
 
 #if wxUSE_ODBC
 
 #include <stdlib.h>
 #include <ctype.h>
 
 #include <stdlib.h>
 #include <ctype.h>
 
-#if   wxMAJOR_VERSION == 1
-    #include "db.h"
-#elif wxMAJOR_VERSION == 2
-    #include "wx/db.h"
-#endif
+#include "wx/db.h"
 
 
-WXDLLEXPORT_DATA(wxDbList*) PtrBegDbList = 0;
+// DLL options compatibility check:
+#include "wx/app.h"
+WX_CHECK_BUILD_OPTIONS("wxODBC")
 
 
+WXDLLIMPEXP_DATA_ODBC(wxDbList*) PtrBegDbList = 0;
 
 
-char const *SQL_LOG_FILENAME         = "sqllog.txt";
-char const *SQL_CATALOG_FILENAME     = "catalog.txt";
+wxChar const *SQL_LOG_FILENAME         = wxT("sqllog.txt");
+wxChar const *SQL_CATALOG_FILENAME     = wxT("catalog.txt");
 
 #ifdef __WXDEBUG__
     extern wxList TablesInUse;
 
 #ifdef __WXDEBUG__
     extern wxList TablesInUse;
@@ -109,8 +72,6 @@ char const *SQL_CATALOG_FILENAME     = "catalog.txt";
 // SQL Log defaults to be used by GetDbConnection
 wxDbSqlLogState SQLLOGstate = sqlLogOFF;
 
 // SQL Log defaults to be used by GetDbConnection
 wxDbSqlLogState SQLLOGstate = sqlLogOFF;
 
-//char SQLLOGfn[wxDB_PATH_MAX+1] = SQL_LOG_FILENAME;
-//wxChar *SQLLOGfn         = (wxChar*) SQL_LOG_FILENAME;
 static wxString SQLLOGfn = SQL_LOG_FILENAME;
 
 // The wxDb::errorList is copied to this variable when the wxDb object
 static wxString SQLLOGfn = SQL_LOG_FILENAME;
 
 // The wxDb::errorList is copied to this variable when the wxDb object
@@ -121,7 +82,8 @@ static wxString SQLLOGfn = SQL_LOG_FILENAME;
 // will overwrite the errors of the previously destroyed wxDb object in
 // this variable.  NOTE: This occurs during a CLOSE, not a FREEing of the
 // connection
 // will overwrite the errors of the previously destroyed wxDb object in
 // this variable.  NOTE: This occurs during a CLOSE, not a FREEing of the
 // connection
-char DBerrorList[DB_MAX_ERROR_HISTORY][DB_MAX_ERROR_MSG_LEN];
+wxChar DBerrorList[DB_MAX_ERROR_HISTORY][DB_MAX_ERROR_MSG_LEN+1];
+
 
 // This type defines the return row-struct form
 // SQLTablePrivileges, and is used by wxDB::TablePrivileges.
 
 // This type defines the return row-struct form
 // SQLTablePrivileges, and is used by wxDB::TablePrivileges.
@@ -137,104 +99,170 @@ typedef struct
 } wxDbTablePrivilegeInfo;
 
 
 } wxDbTablePrivilegeInfo;
 
 
-/********** wxDbColFor Constructor **********/
-wxDbColFor::wxDbColFor()
+/********** wxDbConnectInf Constructor - form 1 **********/
+wxDbConnectInf::wxDbConnectInf()
 {
 {
-    s_Field = "";
-    int i;
-    for (i=0;i<7;i++)
+    Henv = 0;
+    freeHenvOnDestroy = false;
+
+    Initialize();
+}  // Constructor
+
+
+/********** wxDbConnectInf Constructor - form 2 **********/
+wxDbConnectInf::wxDbConnectInf(HENV henv, const wxString &dsn, const wxString &userID,
+                       const wxString &password, const wxString &defaultDir,
+                       const wxString &fileType, const wxString &description)
+{
+    Henv = 0;
+    freeHenvOnDestroy = false;
+
+    Initialize();
+
+    if (henv)
+        SetHenv(henv);
+    else
+        AllocHenv();
+
+    SetDsn(dsn);
+    SetUserID(userID);
+    SetPassword(password);
+    SetDescription(description);
+    SetFileType(fileType);
+    SetDefaultDir(defaultDir);
+}  // wxDbConnectInf Constructor
+
+
+wxDbConnectInf::~wxDbConnectInf()
+{
+    if (freeHenvOnDestroy)
     {
     {
-        s_Format[i] = "";
-        s_Amount[i] = "";
-        i_Amount[i] = 0;
+        FreeHenv();
     }
     }
-    i_Nation      = 0;                     // 0=EU, 1=UK, 2=International, 3=US
-    i_dbDataType  = 0;
-    i_sqlDataType = 0;
-    Format(1,DB_DATA_TYPE_VARCHAR,0,0,0);  // the Function that does the work
-}  // wxDbColFor::wxDbColFor()
+}  // wxDbConnectInf Destructor
+
 
 
 
 
-wxDbColFor::~wxDbColFor()
+/********** wxDbConnectInf::Initialize() **********/
+bool wxDbConnectInf::Initialize()
 {
 {
-}  // wxDbColFor::~wxDbColFor()
+    freeHenvOnDestroy = false;
 
 
+    if (freeHenvOnDestroy && Henv)
+        FreeHenv();
 
 
-/********** wxDbColInf Con / Destructor **********/
-wxDbColInf::wxDbColInf()
+    Henv = 0;
+    Dsn[0] = 0;
+    Uid[0] = 0;
+    AuthStr[0] = 0;
+    ConnectionStr[0] = 0;
+    Description.Empty();
+    FileType.Empty();
+    DefaultDir.Empty();
+
+    useConnectionStr = false;
+
+    return true;
+}  // wxDbConnectInf::Initialize()
+
+
+/********** wxDbConnectInf::AllocHenv() **********/
+bool wxDbConnectInf::AllocHenv()
 {
 {
-    catalog[0]      = 0;
-    schema[0]       = 0;
-    tableName[0]    = 0;
-    colName[0]      = 0;
-    sqlDataType     = 0;
-    typeName[0]     = 0;
-    columnSize      = 0;
-    bufferLength    = 0;
-    decimalDigits   = 0;
-    numPrecRadix    = 0;
-    nullable        = 0;
-    remarks[0]      = 0;
-    dbDataType      = 0;
-    PkCol           = 0;
-    PkTableName[0]  = 0;
-    FkCol           = 0;
-    FkTableName[0]  = 0;
-    pColFor         = NULL;
-}  // wxDbColInf::wxDbColFor()
+    // This is here to help trap if you are getting a new henv
+    // without releasing an existing henv
+    wxASSERT(!Henv);
 
 
+    // Initialize the ODBC Environment for Database Operations
+    if (SQLAllocEnv(&Henv) != SQL_SUCCESS)
+    {
+        wxLogDebug(wxT("A problem occurred while trying to get a connection to the data source"));
+        return false;
+    }
 
 
-wxDbColInf::~wxDbColInf()
+    freeHenvOnDestroy = true;
+
+    return true;
+}  // wxDbConnectInf::AllocHenv()
+
+
+void wxDbConnectInf::FreeHenv()
 {
 {
-    if (pColFor)
-        delete pColFor;
-    pColFor = NULL;
-}  // wxDbColInf::~wxDbColInf()
+    wxASSERT(Henv);
 
 
+    if (Henv)
+        SQLFreeEnv(Henv);
 
 
-/********** wxDbTableInf Constructor ********/
-wxDbTableInf::wxDbTableInf()
+    Henv = 0;
+    freeHenvOnDestroy = false;
+
+}  // wxDbConnectInf::FreeHenv()
+
+
+void wxDbConnectInf::SetDsn(const wxString &dsn)
 {
 {
-    tableName[0]    = 0;
-    tableType[0]    = 0;
-    tableRemarks[0] = 0;
-    numCols         = 0;
-    pColInf         = NULL;
-}  // wxDbTableInf::wxDbTableFor()
+    wxASSERT(dsn.Length() < sizeof(Dsn));
 
 
+    wxStrncpy(Dsn, dsn, sizeof(Dsn)-1);
+    Dsn[sizeof(Dsn)-1] = 0;  // Prevent buffer overrun
+}  // wxDbConnectInf::SetDsn()
 
 
-/********** wxDbTableInf Constructor ********/
-wxDbTableInf::~wxDbTableInf()
+
+void wxDbConnectInf::SetUserID(const wxString &uid)
 {
 {
-    if (pColInf)
-        delete [] pColInf;
-    pColInf = NULL;
-}  // wxDbTableInf::~wxDbTableInf()
+    wxASSERT(uid.Length() < sizeof(Uid));
+    wxStrncpy(Uid, uid, sizeof(Uid)-1);
+    Uid[sizeof(Uid)-1] = 0;  // Prevent buffer overrun
+}  // wxDbConnectInf::SetUserID()
 
 
 
 
-/********** wxDbInf Constructor *************/
-wxDbInf::wxDbInf()
+void wxDbConnectInf::SetPassword(const wxString &password)
 {
 {
-    catalog[0]      = 0;
-    schema[0]       = 0;
-    numTables       = 0;
-    pTableInf       = NULL;
-}  // wxDbInf::wxDbFor()
+    wxASSERT(password.Length() < sizeof(AuthStr));
 
 
+    wxStrncpy(AuthStr, password, sizeof(AuthStr)-1);
+    AuthStr[sizeof(AuthStr)-1] = 0;  // Prevent buffer overrun
+}  // wxDbConnectInf::SetPassword()
 
 
-/********** wxDbInf Destructor *************/
-wxDbInf::~wxDbInf()
+void wxDbConnectInf::SetConnectionStr(const wxString &connectStr)
 {
 {
-  if (pTableInf)
-    delete [] pTableInf;
-  pTableInf = NULL;
-}  // wxDbInf::~wxDbInf()
+    wxASSERT(connectStr.Length() < sizeof(ConnectionStr));
+
+    useConnectionStr = wxStrlen(connectStr) > 0;
 
 
+    wxStrncpy(ConnectionStr, connectStr, sizeof(ConnectionStr)-1);
+    ConnectionStr[sizeof(ConnectionStr)-1] = 0;  // Prevent buffer overrun
+}  // wxDbConnectInf::SetConnectionStr()
 
 
-/*************************************************/
+
+/********** wxDbColFor Constructor **********/
+wxDbColFor::wxDbColFor()
+{
+    Initialize();
+}  // wxDbColFor::wxDbColFor()
 
 
 
 
-int wxDbColFor::Format(int Nation,int dbDataType,SWORD sqlDataType,short columnSize,short decimalDigits)
+/********** wxDbColFor::Initialize() **********/
+void wxDbColFor::Initialize()
+{
+    s_Field.Empty();
+    int i;
+    for (i=0; i<7; i++)
+    {
+        s_Format[i].Empty();
+        s_Amount[i].Empty();
+        i_Amount[i] = 0;
+    }
+    i_Nation      = 0;                     // 0=EU, 1=UK, 2=International, 3=US
+    i_dbDataType  = 0;
+    i_sqlDataType = 0;
+    Format(1,DB_DATA_TYPE_VARCHAR,0,0,0);  // the Function that does the work
+}  // wxDbColFor::Initialize()
+
+
+/********** wxDbColFor::Format() **********/
+int wxDbColFor::Format(int Nation, int dbDataType, SWORD sqlDataType,
+                       short columnLength, short decimalDigits)
 {
     // ----------------------------------------------------------------------------------------
     // -- 19991224 : mj10777 : Create
 {
     // ----------------------------------------------------------------------------------------
     // -- 19991224 : mj10777 : Create
@@ -248,83 +276,212 @@ int wxDbColFor::Format(int Nation,int dbDataType,SWORD sqlDataType,short columnS
     // ----------------------------------------------------------------------------------------
     // There should also be a function to scan in a string to fill the variable
     // ----------------------------------------------------------------------------------------
     // ----------------------------------------------------------------------------------------
     // There should also be a function to scan in a string to fill the variable
     // ----------------------------------------------------------------------------------------
-    wxString Temp0;
+    wxString tempStr;
     i_Nation      = Nation;                                       // 0 = timestamp , 1=EU, 2=UK, 3=International, 4=US
     i_dbDataType  = dbDataType;
     i_sqlDataType = sqlDataType;
     s_Field.Printf(wxT("%s%d"),s_Amount[1].c_str(),i_Amount[1]);  // OK for VARCHAR, INTEGER and FLOAT
     i_Nation      = Nation;                                       // 0 = timestamp , 1=EU, 2=UK, 3=International, 4=US
     i_dbDataType  = dbDataType;
     i_sqlDataType = sqlDataType;
     s_Field.Printf(wxT("%s%d"),s_Amount[1].c_str(),i_Amount[1]);  // OK for VARCHAR, INTEGER and FLOAT
+
     if (i_dbDataType == 0)                                        // Filter unsupported dbDataTypes
     {
     if (i_dbDataType == 0)                                        // Filter unsupported dbDataTypes
     {
-        if ((i_sqlDataType == SQL_VARCHAR) || (i_sqlDataType == SQL_LONGVARCHAR))
+        if ((i_sqlDataType == SQL_VARCHAR)
+#if wxUSE_UNICODE
+    #if defined(SQL_WCHAR)
+            || (i_sqlDataType == SQL_WCHAR) 
+    #endif
+    #if defined(SQL_WVARCHAR)
+            || (i_sqlDataType == SQL_WVARCHAR)
+    #endif
+#endif
+            || (i_sqlDataType == SQL_LONGVARCHAR))
             i_dbDataType = DB_DATA_TYPE_VARCHAR;
             i_dbDataType = DB_DATA_TYPE_VARCHAR;
-        if (i_sqlDataType == SQL_C_DATE)
+        if ((i_sqlDataType == SQL_C_DATE) || (i_sqlDataType == SQL_C_TIMESTAMP))
             i_dbDataType = DB_DATA_TYPE_DATE;
         if (i_sqlDataType == SQL_C_BIT)
             i_dbDataType = DB_DATA_TYPE_INTEGER;
         if (i_sqlDataType == SQL_NUMERIC)
             i_dbDataType = DB_DATA_TYPE_DATE;
         if (i_sqlDataType == SQL_C_BIT)
             i_dbDataType = DB_DATA_TYPE_INTEGER;
         if (i_sqlDataType == SQL_NUMERIC)
-            i_dbDataType = DB_DATA_TYPE_VARCHAR;
+            i_dbDataType = DB_DATA_TYPE_VARCHAR;   // glt - ??? is this right?
         if (i_sqlDataType == SQL_REAL)
             i_dbDataType = DB_DATA_TYPE_FLOAT;
         if (i_sqlDataType == SQL_REAL)
             i_dbDataType = DB_DATA_TYPE_FLOAT;
+        if (i_sqlDataType == SQL_C_BINARY)
+            i_dbDataType = DB_DATA_TYPE_BLOB;
     }
     }
+
     if ((i_dbDataType == DB_DATA_TYPE_INTEGER) && (i_sqlDataType == SQL_C_DOUBLE))
     {   // DBASE Numeric
         i_dbDataType = DB_DATA_TYPE_FLOAT;
     }
     if ((i_dbDataType == DB_DATA_TYPE_INTEGER) && (i_sqlDataType == SQL_C_DOUBLE))
     {   // DBASE Numeric
         i_dbDataType = DB_DATA_TYPE_FLOAT;
     }
-    switch(i_dbDataType)     // -A-> Still a lot of proper formatting to do
+
+    switch(i_dbDataType)     // TBD: Still a lot of proper formatting to do
     {
         case DB_DATA_TYPE_VARCHAR:
     {
         case DB_DATA_TYPE_VARCHAR:
-            s_Field = "%s";
+            s_Field = wxT("%s");
             break;
         case DB_DATA_TYPE_INTEGER:
             break;
         case DB_DATA_TYPE_INTEGER:
-            s_Field = "%d";
+            s_Field = wxT("%d");
             break;
         case DB_DATA_TYPE_FLOAT:
             if (decimalDigits == 0)
                 decimalDigits = 2;
             break;
         case DB_DATA_TYPE_FLOAT:
             if (decimalDigits == 0)
                 decimalDigits = 2;
-            Temp0 = "%";
-            Temp0.Printf(wxT("%s%d.%d"),Temp0.c_str(),columnSize,decimalDigits);
-            s_Field.Printf(wxT("%sf"),Temp0.c_str());
+            tempStr.Printf(wxT("%%%d.%d"), columnLength, decimalDigits);
+            s_Field.Printf(wxT("%sf"), tempStr.c_str());
             break;
         case DB_DATA_TYPE_DATE:
             if (i_Nation == 0)      // timestamp       YYYY-MM-DD HH:MM:SS.SSS (tested for SYBASE)
             {
             break;
         case DB_DATA_TYPE_DATE:
             if (i_Nation == 0)      // timestamp       YYYY-MM-DD HH:MM:SS.SSS (tested for SYBASE)
             {
-                s_Field = "%04d-%02d-%02d %02d:%02d:%02d.%03d";
+                s_Field = wxT("%04d-%02d-%02d %02d:%02d:%02d.%03d");
             }
             if (i_Nation == 1)      // European        DD.MM.YYYY HH:MM:SS.SSS
             {
             }
             if (i_Nation == 1)      // European        DD.MM.YYYY HH:MM:SS.SSS
             {
-                s_Field = "%02d.%02d.%04d %02d:%02d:%02d.%03d";
+                s_Field = wxT("%02d.%02d.%04d %02d:%02d:%02d.%03d");
             }
             if (i_Nation == 2)      // UK              DD/MM/YYYY HH:MM:SS.SSS
             {
             }
             if (i_Nation == 2)      // UK              DD/MM/YYYY HH:MM:SS.SSS
             {
-                s_Field = "%02d/%02d/%04d %02d:%02d:%02d.%03d";
+                s_Field = wxT("%02d/%02d/%04d %02d:%02d:%02d.%03d");
             }
             if (i_Nation == 3)      // International   YYYY-MM-DD HH:MM:SS.SSS
             {
             }
             if (i_Nation == 3)      // International   YYYY-MM-DD HH:MM:SS.SSS
             {
-                s_Field = "%04d-%02d-%02d %02d:%02d:%02d.%03d";
+                s_Field = wxT("%04d-%02d-%02d %02d:%02d:%02d.%03d");
             }
             if (i_Nation == 4)      // US              MM/DD/YYYY HH:MM:SS.SSS
             {
             }
             if (i_Nation == 4)      // US              MM/DD/YYYY HH:MM:SS.SSS
             {
-                s_Field = "%02d/%02d/%04d %02d:%02d:%02d.%03d";
+                s_Field = wxT("%02d/%02d/%04d %02d:%02d:%02d.%03d");
             }
             break;
             }
             break;
+          case DB_DATA_TYPE_BLOB:
+            s_Field.Printf(wxT("Unable to format(%d)-SQL(%d)"), dbDataType,sqlDataType);        //
+                break;
         default:
         default:
-            s_Field.Printf(wxT("Unknown Format(%d)-SQL(%d)"),dbDataType,sqlDataType);        //
+            s_Field.Printf(wxT("Unknown Format(%d)-SQL(%d)"), dbDataType,sqlDataType);        //
             break;
     };
     return TRUE;
 }  // wxDbColFor::Format()
 
 
             break;
     };
     return TRUE;
 }  // wxDbColFor::Format()
 
 
-/********** wxDb Constructors **********/
-wxDb::wxDb(HENV &aHenv, bool FwdOnlyCursors)
+/********** wxDbColInf Constructor **********/
+wxDbColInf::wxDbColInf()
+{
+    Initialize();
+}  // wxDbColInf::wxDbColInf()
+
+
+/********** wxDbColInf Destructor ********/
+wxDbColInf::~wxDbColInf()
+{
+    if (pColFor)
+        delete pColFor;
+    pColFor = NULL;
+}  // wxDbColInf::~wxDbColInf()
+
+
+bool wxDbColInf::Initialize()
+{
+    catalog[0]      = 0;
+    schema[0]       = 0;
+    tableName[0]    = 0;
+    colName[0]      = 0;
+    sqlDataType     = 0;
+    typeName[0]     = 0;
+    columnLength    = 0;
+    bufferSize      = 0;
+    decimalDigits   = 0;
+    numPrecRadix    = 0;
+    nullable        = 0;
+    remarks[0]      = 0;
+    dbDataType      = 0;
+    PkCol           = 0;
+    PkTableName[0]  = 0;
+    FkCol           = 0;
+    FkTableName[0]  = 0;
+    pColFor         = NULL;
+
+    return true;
+}  // wxDbColInf::Initialize()
+
+
+/********** wxDbTableInf Constructor ********/
+wxDbTableInf::wxDbTableInf()
+{
+    Initialize();
+}  // wxDbTableInf::wxDbTableInf()
+
+
+/********** wxDbTableInf Constructor ********/
+wxDbTableInf::~wxDbTableInf()
+{
+    if (pColInf)
+        delete [] pColInf;
+    pColInf = NULL;
+}  // wxDbTableInf::~wxDbTableInf()
+
+
+bool wxDbTableInf::Initialize()
+{
+    tableName[0]    = 0;
+    tableType[0]    = 0;
+    tableRemarks[0] = 0;
+    numCols         = 0;
+    pColInf         = NULL;
+
+    return true;
+}  // wxDbTableInf::Initialize()
+
+
+/********** wxDbInf Constructor *************/
+wxDbInf::wxDbInf()
+{
+    Initialize();
+}  // wxDbInf::wxDbInf()
+
+
+/********** wxDbInf Destructor *************/
+wxDbInf::~wxDbInf()
+{
+  if (pTableInf)
+    delete [] pTableInf;
+  pTableInf = NULL;
+}  // wxDbInf::~wxDbInf()
+
+
+/********** wxDbInf::Initialize() *************/
+bool wxDbInf::Initialize()
+{
+    catalog[0]      = 0;
+    schema[0]       = 0;
+    numTables       = 0;
+    pTableInf       = NULL;
+
+    return true;
+}  // wxDbInf::Initialize()
+
+
+/********** wxDb Constructor **********/
+wxDb::wxDb(const HENV &aHenv, bool FwdOnlyCursors)
 {
     // Copy the HENV into the db class
     henv = aHenv;
     fwdOnlyCursors = FwdOnlyCursors;
 {
     // Copy the HENV into the db class
     henv = aHenv;
     fwdOnlyCursors = FwdOnlyCursors;
+
     initialize();
 } // wxDb::wxDb()
 
 
     initialize();
 } // wxDb::wxDb()
 
 
+/********** wxDb Destructor **********/
+wxDb::~wxDb()
+{
+    wxASSERT_MSG(!IsCached(),wxT("Cached connections must not be manually deleted, use\nwxDbFreeConnection() or wxDbCloseConnections()."));
+
+    if (IsOpen())
+    {
+        Close();
+    }
+}  // wxDb destructor
+
+
+
+/********** PRIVATE! wxDb::initialize PRIVATE! **********/
+/********** wxDb::initialize() **********/
 void wxDb::initialize()
 /*
  * Private member function that sets all wxDb member variables to
 void wxDb::initialize()
 /*
  * Private member function that sets all wxDb member variables to
@@ -338,39 +495,45 @@ void wxDb::initialize()
     nTables       = 0;
     dbmsType      = dbmsUNIDENTIFIED;
 
     nTables       = 0;
     dbmsType      = dbmsUNIDENTIFIED;
 
-    wxStrcpy(sqlState,wxT(""));
-    wxStrcpy(errorMsg,wxT(""));
+    wxStrcpy(sqlState,wxEmptyString);
+    wxStrcpy(errorMsg,wxEmptyString);
     nativeError = cbErrorMsg = 0;
     for (i = 0; i < DB_MAX_ERROR_HISTORY; i++)
     nativeError = cbErrorMsg = 0;
     for (i = 0; i < DB_MAX_ERROR_HISTORY; i++)
-        wxStrcpy(errorList[i], wxT(""));
+        wxStrcpy(errorList[i], wxEmptyString);
 
     // Init typeInf structures
 
     // Init typeInf structures
-    wxStrcpy(typeInfVarchar.TypeName,wxT(""));
+    typeInfVarchar.TypeName.Empty();
     typeInfVarchar.FsqlType      = 0;
     typeInfVarchar.Precision     = 0;
     typeInfVarchar.CaseSensitive = 0;
     typeInfVarchar.MaximumScale  = 0;
 
     typeInfVarchar.FsqlType      = 0;
     typeInfVarchar.Precision     = 0;
     typeInfVarchar.CaseSensitive = 0;
     typeInfVarchar.MaximumScale  = 0;
 
-    wxStrcpy(typeInfInteger.TypeName,wxT(""));
+    typeInfInteger.TypeName.Empty();
     typeInfInteger.FsqlType      = 0;
     typeInfInteger.Precision     = 0;
     typeInfInteger.CaseSensitive = 0;
     typeInfInteger.MaximumScale  = 0;
 
     typeInfInteger.FsqlType      = 0;
     typeInfInteger.Precision     = 0;
     typeInfInteger.CaseSensitive = 0;
     typeInfInteger.MaximumScale  = 0;
 
-    wxStrcpy(typeInfFloat.TypeName,wxT(""));
+    typeInfFloat.TypeName.Empty();
     typeInfFloat.FsqlType      = 0;
     typeInfFloat.Precision     = 0;
     typeInfFloat.CaseSensitive = 0;
     typeInfFloat.MaximumScale  = 0;
 
     typeInfFloat.FsqlType      = 0;
     typeInfFloat.Precision     = 0;
     typeInfFloat.CaseSensitive = 0;
     typeInfFloat.MaximumScale  = 0;
 
-    wxStrcpy(typeInfDate.TypeName,wxT(""));
+    typeInfDate.TypeName.Empty();
     typeInfDate.FsqlType      = 0;
     typeInfDate.Precision     = 0;
     typeInfDate.CaseSensitive = 0;
     typeInfDate.MaximumScale  = 0;
 
     typeInfDate.FsqlType      = 0;
     typeInfDate.Precision     = 0;
     typeInfDate.CaseSensitive = 0;
     typeInfDate.MaximumScale  = 0;
 
+    typeInfBlob.TypeName.Empty();
+    typeInfBlob.FsqlType      = 0;
+    typeInfBlob.Precision     = 0;
+    typeInfBlob.CaseSensitive = 0;
+    typeInfBlob.MaximumScale  = 0;
+
     // Error reporting is turned OFF by default
     // Error reporting is turned OFF by default
-    silent = TRUE;
+    silent = true;
 
     // Allocate a data source connection handle
     if (SQLAllocConnect(henv, &hdbc) != SQL_SUCCESS)
 
     // Allocate a data source connection handle
     if (SQLAllocConnect(henv, &hdbc) != SQL_SUCCESS)
@@ -380,83 +543,122 @@ void wxDb::initialize()
     DB_STATUS = 0;
 
     // Mark database as not open as of yet
     DB_STATUS = 0;
 
     // Mark database as not open as of yet
-    dbIsOpen = FALSE;
+    dbIsOpen = false;
+    dbIsCached = false;
+    dbOpenedWithConnectionString = false;
 }  // wxDb::initialize()
 
 
 }  // wxDb::initialize()
 
 
-/********** wxDb::Open() **********/
-bool wxDb::Open(char *Dsn, char *Uid, char *AuthStr)
+/********** PRIVATE! wxDb::convertUserID PRIVATE! **********/
+//
+// NOTE: Return value from this function MUST be copied
+//       immediately, as the value is not good after
+//       this function has left scope.
+//
+const wxChar *wxDb::convertUserID(const wxChar *userID, wxString &UserID)
 {
 {
-    assert(Dsn && wxStrlen(Dsn));
-    dsn        = Dsn;
-    uid        = Uid;
-    authStr    = AuthStr;
-
-    RETCODE retcode;
-
-    if (!FwdOnlyCursors())
+    if (userID)
     {
     {
-        // Specify that the ODBC cursor library be used, if needed.  This must be
-        // specified before the connection is made.
-        retcode = SQLSetConnectOption(hdbc, SQL_ODBC_CURSORS, SQL_CUR_USE_IF_NEEDED);
-
-#ifdef DBDEBUG_CONSOLE
-        if (retcode == SQL_SUCCESS)
-            cout << "SQLSetConnectOption(CURSOR_LIB) successful" << endl;
+        if (!wxStrlen(userID))
+            UserID = uid;
         else
         else
-            cout << "SQLSetConnectOption(CURSOR_LIB) failed" << endl;
-#endif
+            UserID = userID;
     }
     }
+    else
+        UserID.Empty();
 
 
-    // Connect to the data source
-    retcode = SQLConnect(hdbc, (UCHAR FAR *) dsn, SQL_NTS,
-                         (UCHAR FAR *) uid, SQL_NTS,
-                         (UCHAR FAR *) authStr,SQL_NTS);
+    // dBase does not use user names, and some drivers fail if you try to pass one
+    if ( Dbms() == dbmsDBASE
+         || Dbms() == dbmsXBASE_SEQUITER )
+        UserID.Empty();
 
 
-/*
-    if (retcode == SQL_SUCCESS_WITH_INFO)
-        DispAllErrors(henv, hdbc);
-    else if (retcode != SQL_SUCCESS)
-        return(DispAllErrors(henv, hdbc));
+    // Some databases require user names to be specified in uppercase,
+    // so force the name to uppercase
+    if ((Dbms() == dbmsORACLE) ||
+        (Dbms() == dbmsMAXDB))
+        UserID = UserID.Upper();
 
 
-       if (retcode == SQL_ERROR)
-               return(DispAllErrors(henv, hdbc));
-*/
-       if ((retcode != SQL_SUCCESS) &&
-        (retcode != SQL_SUCCESS_WITH_INFO))
-               return(DispAllErrors(henv, hdbc));
+    return UserID.c_str();
+}  // wxDb::convertUserID()
 
 
-/*
-    If using Intersolv branded ODBC drivers, this is the place where you would substitute
-    your branded driver license information
 
 
-    SQLSetConnectOption(hdbc, 1041, (UDWORD) "");
-    SQLSetConnectOption(hdbc, 1042, (UDWORD) "");
-*/
+bool wxDb::determineDataTypes(bool failOnDataTypeUnsupported)
+{
+    size_t iIndex;
 
 
-    // Mark database as open
-    dbIsOpen = TRUE;
+    // These are the possible SQL types we check for use against the datasource we are connected
+    // to for the purpose of determining which data type to use for the basic character strings
+    // column types
+    //
+    // 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 PossibleSqlCharTypes[] = {
+#if wxUSE_UNICODE && defined(SQL_WVARCHAR)
+        SQL_WVARCHAR,
+#endif
+        SQL_VARCHAR,
+#if wxUSE_UNICODE && defined(SQL_WVARCHAR)
+        SQL_WCHAR,
+#endif
+        SQL_CHAR
+    };
 
 
-    // Allocate a statement handle for the database connection
-    if (SQLAllocStmt(hdbc, &hstmt) != SQL_SUCCESS)
-        return(DispAllErrors(henv, hdbc));
+    // These are the possible SQL types we check for use against the datasource we are connected
+    // to for the purpose of determining which data type to use for the basic non-floating point
+    // column types
+    //
+    // 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 PossibleSqlIntegerTypes[] = {
+        SQL_INTEGER
+    };
 
 
-    // Set Connection Options
-    if (!setConnectionOptions())
-        return(FALSE);
+    // These are the possible SQL types we check for use against the datasource we are connected
+    // to for the purpose of determining which data type to use for the basic floating point number
+    // column types
+    //
+    // 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 PossibleSqlFloatTypes[] = {
+        SQL_DOUBLE,
+        SQL_REAL,
+        SQL_FLOAT,
+        SQL_DECIMAL,
+        SQL_NUMERIC
+    };
+
+    // 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 date/time column types
+    //
+    // 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 PossibleSqlDateTypes[] = {
+        SQL_TIMESTAMP,
+        SQL_DATE,
+#ifdef SQL_DATETIME
+        SQL_DATETIME
+#endif
+    };
+
+    // 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 BLOB column types.
+    //
+    // 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 PossibleSqlBlobTypes[] = {
+        SQL_LONGVARBINARY,
+        SQL_VARBINARY
+    };
 
 
-    // Query the data source for inf. about itself
-    if (!getDbInfo())
-        return(FALSE);
 
     // Query the data source regarding data type information
 
     //
 
     // Query the data source regarding data type information
 
     //
-    // The way I determined which SQL data types to use was by calling SQLGetInfo
+    // The way it was determined which SQL data types to use was by calling SQLGetInfo
     // for all of the possible SQL data types to see which ones were supported.  If
     // a type is not supported, the SQLFetch() that's called from getDataTypeInfo()
     // fails with SQL_NO_DATA_FOUND.  This is ugly because I'm sure the three SQL data
     // for all of the possible SQL data types to see which ones were supported.  If
     // a type is not supported, the SQLFetch() that's called from getDataTypeInfo()
     // fails with SQL_NO_DATA_FOUND.  This is ugly because I'm sure the three SQL data
-    // types I've selected below will not alway's be what we want.  These are just
+    // types I've selected below will not always be what we want.  These are just
     // what happened to work against an Oracle 7/Intersolv combination.  The following is
     // a complete list of the results I got back against the Oracle 7 database:
     //
     // what happened to work against an Oracle 7/Intersolv combination.  The following is
     // a complete list of the results I got back against the Oracle 7 database:
     //
@@ -490,82 +692,225 @@ bool wxDb::Open(char *Dsn, char *Uid, char *AuthStr)
     // SQL_DOUBLE             type name = 'DOUBLE', Precision = 15
     // SQL_INTEGER            type name = 'LONG', Precision = 10
 
     // SQL_DOUBLE             type name = 'DOUBLE', Precision = 15
     // SQL_INTEGER            type name = 'LONG', Precision = 10
 
-    // VARCHAR = Variable length character string
-    if (!getDataTypeInfo(SQL_VARCHAR, typeInfVarchar))
-        if (!getDataTypeInfo(SQL_CHAR, typeInfVarchar))
-            return(FALSE);
-        else
-            typeInfVarchar.FsqlType = SQL_CHAR;
-    else
-        typeInfVarchar.FsqlType = SQL_VARCHAR;
-
-    // Float
-    if (!getDataTypeInfo(SQL_DOUBLE,typeInfFloat))
-
-        if (!getDataTypeInfo(SQL_REAL,typeInfFloat))
-            if (!getDataTypeInfo(SQL_FLOAT,typeInfFloat))
-                if (!getDataTypeInfo(SQL_DECIMAL,typeInfFloat))
-                    if (!getDataTypeInfo(SQL_NUMERIC,typeInfFloat))
-                        return(FALSE);
-                    else
-                        typeInfFloat.FsqlType = SQL_NUMERIC;
-                else
-                    typeInfFloat.FsqlType = SQL_DECIMAL;
-            else
-                typeInfFloat.FsqlType = SQL_FLOAT;
-        else
-            typeInfFloat.FsqlType = SQL_REAL;
-    else
-        typeInfFloat.FsqlType = SQL_DOUBLE;
-
-    // Integer
-    if (!getDataTypeInfo(SQL_INTEGER, typeInfInteger))
+    // Query the data source for info about itself
+    if (!getDbInfo(failOnDataTypeUnsupported))
+        return false;
+
+    // --------------- Varchar - (Variable length character string) ---------------
+    for (iIndex = 0; iIndex < WXSIZEOF(PossibleSqlCharTypes) &&
+                     !getDataTypeInfo(PossibleSqlCharTypes[iIndex], typeInfVarchar); ++iIndex)
+    {}
+
+    if (iIndex < WXSIZEOF(PossibleSqlCharTypes))
+        typeInfVarchar.FsqlType = PossibleSqlCharTypes[iIndex];
+    else if (failOnDataTypeUnsupported)
+        return false;
+
+    // --------------- Float ---------------
+    for (iIndex = 0; iIndex < WXSIZEOF(PossibleSqlFloatTypes) &&
+                     !getDataTypeInfo(PossibleSqlFloatTypes[iIndex], typeInfFloat); ++iIndex)
+    {}
+
+    if (iIndex < WXSIZEOF(PossibleSqlFloatTypes))
+        typeInfFloat.FsqlType = PossibleSqlFloatTypes[iIndex];
+    else if (failOnDataTypeUnsupported)
+        return false;
+
+    // --------------- Integer -------------
+    for (iIndex = 0; iIndex < WXSIZEOF(PossibleSqlIntegerTypes) &&
+                     !getDataTypeInfo(PossibleSqlIntegerTypes[iIndex], typeInfInteger); ++iIndex)
+    {}
+
+    if (iIndex < WXSIZEOF(PossibleSqlIntegerTypes))
+        typeInfInteger.FsqlType = PossibleSqlIntegerTypes[iIndex];
+    else if (failOnDataTypeUnsupported)
     {
     {
-        // If SQL_INTEGER is not supported, use the floating point
-        // data type to store integers as well as floats
+        // If no non-floating point data types are supported, we'll
+        // use the type assigned for floats to store integers as well
         if (!getDataTypeInfo(typeInfFloat.FsqlType, typeInfInteger))
         if (!getDataTypeInfo(typeInfFloat.FsqlType, typeInfInteger))
-            return(FALSE);
+        {
+            if (failOnDataTypeUnsupported)
+                return false;
+        }
         else
             typeInfInteger.FsqlType = typeInfFloat.FsqlType;
     }
         else
             typeInfInteger.FsqlType = typeInfFloat.FsqlType;
     }
-    else
-        typeInfInteger.FsqlType = SQL_INTEGER;
 
 
-    // Date/Time
-    if (Dbms() != dbmsDBASE)
+    // --------------- Date/Time ---------------
+    for (iIndex = 0; iIndex < WXSIZEOF(PossibleSqlDateTypes) &&
+                     !getDataTypeInfo(PossibleSqlDateTypes[iIndex], typeInfDate); ++iIndex)
+    {}
+
+    if (iIndex < WXSIZEOF(PossibleSqlDateTypes))
+        typeInfDate.FsqlType = PossibleSqlDateTypes[iIndex];
+    else if (failOnDataTypeUnsupported)
+        return false;
+
+    // --------------- BLOB ---------------
+    for (iIndex = 0; iIndex < WXSIZEOF(PossibleSqlBlobTypes) &&
+                     !getDataTypeInfo(PossibleSqlBlobTypes[iIndex], typeInfBlob); ++iIndex)
+    {}
+
+    if (iIndex < WXSIZEOF(PossibleSqlBlobTypes))
+        typeInfBlob.FsqlType = PossibleSqlBlobTypes[iIndex];
+    else if (failOnDataTypeUnsupported)
+        return false;
+
+    return true;
+}  // wxDb::determineDataTypes
+
+
+bool wxDb::open(bool failOnDataTypeUnsupported)
+{
+/*
+    If using Intersolv branded ODBC drivers, this is the place where you would substitute
+    your branded driver license information
+
+    SQLSetConnectOption(hdbc, 1041, (UDWORD) wxEmptyString);
+    SQLSetConnectOption(hdbc, 1042, (UDWORD) wxEmptyString);
+*/
+
+    // Mark database as open
+    dbIsOpen = true;
+
+    // Allocate a statement handle for the database connection
+    if (SQLAllocStmt(hdbc, &hstmt) != SQL_SUCCESS)
+        return(DispAllErrors(henv, hdbc));
+
+    // Set Connection Options
+    if (!setConnectionOptions())
+        return false;
+
+    if (!determineDataTypes(failOnDataTypeUnsupported))
+        return false;
+
+#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 << endl;
+#endif
+
+    // Completed Successfully
+    return true;
+}
+
+bool wxDb::Open(const wxString& inConnectStr, bool failOnDataTypeUnsupported)
+{
+    wxASSERT(inConnectStr.Length());
+    return Open(inConnectStr, NULL, failOnDataTypeUnsupported);
+}
+
+bool wxDb::Open(const wxString& inConnectStr, SQLHWND parentWnd, bool failOnDataTypeUnsupported)
+{
+    dsn        = wxT("");
+    uid        = wxT("");
+    authStr    = wxT("");
+
+    RETCODE retcode;
+
+    if (!FwdOnlyCursors())
     {
     {
-        if (! getDataTypeInfo(SQL_TIMESTAMP,typeInfDate))
-            return(FALSE);
+        // Specify that the ODBC cursor library be used, if needed.  This must be
+        // specified before the connection is made.
+        retcode = SQLSetConnectOption(hdbc, SQL_ODBC_CURSORS, SQL_CUR_USE_IF_NEEDED);
+
+#ifdef DBDEBUG_CONSOLE
+        if (retcode == SQL_SUCCESS)
+            cout << wxT("SQLSetConnectOption(CURSOR_LIB) successful") << endl;
         else
         else
-            typeInfDate.FsqlType = SQL_TIMESTAMP;
+            cout << wxT("SQLSetConnectOption(CURSOR_LIB) failed") << endl;
+#else
+        wxUnusedVar(retcode);
+#endif
     }
     }
-    else
+
+    // Connect to the data source
+    SQLTCHAR outConnectBuffer[SQL_MAX_CONNECTSTR_LEN+1];  // MS recommends at least 1k buffer
+    short outConnectBufferLen;
+
+    inConnectionStr = inConnectStr;
+
+    retcode = SQLDriverConnect(hdbc, parentWnd, (SQLTCHAR FAR *)inConnectionStr.c_str(),
+                        (SWORD)inConnectionStr.Length(), (SQLTCHAR FAR *)outConnectBuffer,
+                        sizeof(outConnectBuffer), &outConnectBufferLen, SQL_DRIVER_COMPLETE );
+
+    if ((retcode != SQL_SUCCESS) &&
+        (retcode != SQL_SUCCESS_WITH_INFO))
+        return(DispAllErrors(henv, hdbc));
+
+    outConnectBuffer[outConnectBufferLen] = 0;
+    outConnectionStr = outConnectBuffer;
+    dbOpenedWithConnectionString = true;
+
+    return open(failOnDataTypeUnsupported);
+}
+
+/********** wxDb::Open() **********/
+bool wxDb::Open(const wxString &Dsn, const wxString &Uid, const wxString &AuthStr, bool failOnDataTypeUnsupported)
+{
+    wxASSERT(Dsn.Length());
+    dsn        = Dsn;
+    uid        = Uid;
+    authStr    = AuthStr;
+
+    inConnectionStr = wxT("");
+    outConnectionStr = wxT("");
+
+    RETCODE retcode;
+
+    if (!FwdOnlyCursors())
     {
     {
-        if (!getDataTypeInfo(SQL_DATE,typeInfDate))
-            return(FALSE);
-        else
-            typeInfDate.FsqlType = SQL_DATE;
-    }
+        // Specify that the ODBC cursor library be used, if needed.  This must be
+        // specified before the connection is made.
+        retcode = SQLSetConnectOption(hdbc, SQL_ODBC_CURSORS, SQL_CUR_USE_IF_NEEDED);
 
 #ifdef DBDEBUG_CONSOLE
 
 #ifdef DBDEBUG_CONSOLE
-    cout << "VARCHAR DATA TYPE: " << typeInfVarchar.TypeName << endl;
-    cout << "INTEGER DATA TYPE: " << typeInfInteger.TypeName << endl;
-    cout << "FLOAT   DATA TYPE: " << typeInfFloat.TypeName << endl;
-    cout << "DATE    DATA TYPE: " << typeInfDate.TypeName << endl;
-    cout << endl;
+        if (retcode == SQL_SUCCESS)
+            cout << wxT("SQLSetConnectOption(CURSOR_LIB) successful") << endl;
+        else
+            cout << wxT("SQLSetConnectOption(CURSOR_LIB) failed") << endl;
+#else
+        wxUnusedVar( retcode );
 #endif
 #endif
+    }
 
 
-    // Completed Successfully
-    return(TRUE);
+    // 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);
+
+    if ((retcode != SQL_SUCCESS) &&
+        (retcode != SQL_SUCCESS_WITH_INFO))
+        return(DispAllErrors(henv, hdbc));
+
+    return open(failOnDataTypeUnsupported);
 
 } // wxDb::Open()
 
 
 
 } // wxDb::Open()
 
 
+bool wxDb::Open(wxDbConnectInf *dbConnectInf, bool failOnDataTypeUnsupported)
+{
+    wxASSERT(dbConnectInf);
+
+    // Use the connection string if one is present
+    if (dbConnectInf->UseConnectionStr())
+        return Open(GetConnectionInStr(), failOnDataTypeUnsupported);
+    else
+        return Open(dbConnectInf->GetDsn(), dbConnectInf->GetUserID(),
+                    dbConnectInf->GetPassword(), failOnDataTypeUnsupported);
+}  // wxDb::Open()
+
+
 bool wxDb::Open(wxDb *copyDb)
 {
 bool wxDb::Open(wxDb *copyDb)
 {
-    dsn        = (char *)copyDb->GetDatasourceName();
-    uid        = (char *)copyDb->GetUsername();
-    authStr    = (char *)copyDb->GetPassword();
+    dsn              = copyDb->GetDatasourceName();
+    uid              = copyDb->GetUsername();
+    authStr          = copyDb->GetPassword();
+    inConnectionStr  = copyDb->GetConnectionInStr();
+    outConnectionStr = copyDb->GetConnectionOutStr();
 
     RETCODE retcode;
 
 
     RETCODE retcode;
 
@@ -577,30 +922,56 @@ bool wxDb::Open(wxDb *copyDb)
 
 #ifdef DBDEBUG_CONSOLE
         if (retcode == SQL_SUCCESS)
 
 #ifdef DBDEBUG_CONSOLE
         if (retcode == SQL_SUCCESS)
-            cout << "SQLSetConnectOption(CURSOR_LIB) successful" << endl;
+            cout << wxT("SQLSetConnectOption(CURSOR_LIB) successful") << endl;
         else
         else
-            cout << "SQLSetConnectOption(CURSOR_LIB) failed" << endl;
+            cout << wxT("SQLSetConnectOption(CURSOR_LIB) failed") << endl;
+#else
+        wxUnusedVar( retcode );
 #endif
     }
 
 #endif
     }
 
-    // Connect to the data source
-    retcode = SQLConnect(hdbc, (UCHAR FAR *) dsn, SQL_NTS,
-                         (UCHAR FAR *) uid, SQL_NTS,
-                         (UCHAR FAR *) authStr, SQL_NTS);
+    if (copyDb->OpenedWithConnectionString())
+    {
+        // Connect to the data source
+        SQLTCHAR outConnectBuffer[SQL_MAX_CONNECTSTR_LEN+1];
+        short outConnectBufferLen;
+
+        inConnectionStr = copyDb->GetConnectionInStr();
+
+        retcode = SQLDriverConnect(hdbc, NULL, (SQLTCHAR FAR *)inConnectionStr.c_str(),
+                            (SWORD)inConnectionStr.Length(), (SQLTCHAR FAR *)outConnectBuffer,
+                            sizeof(outConnectBuffer), &outConnectBufferLen, SQL_DRIVER_COMPLETE);
+
+        if ((retcode != SQL_SUCCESS) &&
+            (retcode != SQL_SUCCESS_WITH_INFO))
+            return(DispAllErrors(henv, hdbc));
 
 
-       if (retcode == SQL_ERROR)
-               return(DispAllErrors(henv, hdbc));
+        outConnectBuffer[outConnectBufferLen] = 0;
+        outConnectionStr = outConnectBuffer;
+        dbOpenedWithConnectionString = true;
+    }
+    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);
+    }
+
+    if ((retcode != SQL_SUCCESS) &&
+        (retcode != SQL_SUCCESS_WITH_INFO))
+        return(DispAllErrors(henv, hdbc));
 
 /*
     If using Intersolv branded ODBC drivers, this is the place where you would substitute
     your branded driver license information
 
 
 /*
     If using Intersolv branded ODBC drivers, this is the place where you would substitute
     your branded driver license information
 
-    SQLSetConnectOption(hdbc, 1041, (UDWORD) "");
-    SQLSetConnectOption(hdbc, 1042, (UDWORD) "");
+    SQLSetConnectOption(hdbc, 1041, (UDWORD) wxEmptyString);
+    SQLSetConnectOption(hdbc, 1042, (UDWORD) wxEmptyString);
 */
 
     // Mark database as open
 */
 
     // Mark database as open
-    dbIsOpen = TRUE;
+    dbIsOpen = true;
 
     // Allocate a statement handle for the database connection
     if (SQLAllocStmt(hdbc, &hstmt) != SQL_SUCCESS)
 
     // Allocate a statement handle for the database connection
     if (SQLAllocStmt(hdbc, &hstmt) != SQL_SUCCESS)
@@ -608,7 +979,7 @@ bool wxDb::Open(wxDb *copyDb)
 
     // Set Connection Options
     if (!setConnectionOptions())
 
     // Set Connection Options
     if (!setConnectionOptions())
-        return(FALSE);
+        return false;
 
     // Instead of Querying the data source for info about itself, it can just be copied
     // from the wxDb instance that was passed in (copyDb).
 
     // Instead of Querying the data source for info about itself, it can just be copied
     // from the wxDb instance that was passed in (copyDb).
@@ -645,43 +1016,51 @@ bool wxDb::Open(wxDb *copyDb)
     dbInf.loginTimeout = copyDb->dbInf.loginTimeout;
 
     // VARCHAR = Variable length character string
     dbInf.loginTimeout = copyDb->dbInf.loginTimeout;
 
     // VARCHAR = Variable length character string
-    typeInfVarchar.FsqlType = copyDb->typeInfVarchar.FsqlType;
-    wxStrcpy(typeInfVarchar.TypeName, copyDb->typeInfVarchar.TypeName);
+    typeInfVarchar.FsqlType         = copyDb->typeInfVarchar.FsqlType;
+    typeInfVarchar.TypeName         = copyDb->typeInfVarchar.TypeName;
     typeInfVarchar.Precision        = copyDb->typeInfVarchar.Precision;
     typeInfVarchar.CaseSensitive    = copyDb->typeInfVarchar.CaseSensitive;
     typeInfVarchar.MaximumScale     = copyDb->typeInfVarchar.MaximumScale;
 
     // Float
     typeInfVarchar.Precision        = copyDb->typeInfVarchar.Precision;
     typeInfVarchar.CaseSensitive    = copyDb->typeInfVarchar.CaseSensitive;
     typeInfVarchar.MaximumScale     = copyDb->typeInfVarchar.MaximumScale;
 
     // Float
-    typeInfFloat.FsqlType = copyDb->typeInfFloat.FsqlType;
-    wxStrcpy(typeInfFloat.TypeName, copyDb->typeInfFloat.TypeName);
+    typeInfFloat.FsqlType         = copyDb->typeInfFloat.FsqlType;
+    typeInfFloat.TypeName         = copyDb->typeInfFloat.TypeName;
     typeInfFloat.Precision        = copyDb->typeInfFloat.Precision;
     typeInfFloat.CaseSensitive    = copyDb->typeInfFloat.CaseSensitive;
     typeInfFloat.MaximumScale     = copyDb->typeInfFloat.MaximumScale;
 
     // Integer
     typeInfFloat.Precision        = copyDb->typeInfFloat.Precision;
     typeInfFloat.CaseSensitive    = copyDb->typeInfFloat.CaseSensitive;
     typeInfFloat.MaximumScale     = copyDb->typeInfFloat.MaximumScale;
 
     // Integer
-    typeInfInteger.FsqlType = copyDb->typeInfInteger.FsqlType;
-    wxStrcpy(typeInfInteger.TypeName, copyDb->typeInfInteger.TypeName);
+    typeInfInteger.FsqlType         = copyDb->typeInfInteger.FsqlType;
+    typeInfInteger.TypeName         = copyDb->typeInfInteger.TypeName;
     typeInfInteger.Precision        = copyDb->typeInfInteger.Precision;
     typeInfInteger.CaseSensitive    = copyDb->typeInfInteger.CaseSensitive;
     typeInfInteger.MaximumScale     = copyDb->typeInfInteger.MaximumScale;
 
     // Date/Time
     typeInfInteger.Precision        = copyDb->typeInfInteger.Precision;
     typeInfInteger.CaseSensitive    = copyDb->typeInfInteger.CaseSensitive;
     typeInfInteger.MaximumScale     = copyDb->typeInfInteger.MaximumScale;
 
     // Date/Time
-    typeInfDate.FsqlType = copyDb->typeInfDate.FsqlType;
-    wxStrcpy(typeInfDate.TypeName, copyDb->typeInfDate.TypeName);
+    typeInfDate.FsqlType         = copyDb->typeInfDate.FsqlType;
+    typeInfDate.TypeName         = copyDb->typeInfDate.TypeName;
     typeInfDate.Precision        = copyDb->typeInfDate.Precision;
     typeInfDate.CaseSensitive    = copyDb->typeInfDate.CaseSensitive;
     typeInfDate.MaximumScale     = copyDb->typeInfDate.MaximumScale;
 
     typeInfDate.Precision        = copyDb->typeInfDate.Precision;
     typeInfDate.CaseSensitive    = copyDb->typeInfDate.CaseSensitive;
     typeInfDate.MaximumScale     = copyDb->typeInfDate.MaximumScale;
 
+    // Blob
+    typeInfBlob.FsqlType         = copyDb->typeInfBlob.FsqlType;
+    typeInfBlob.TypeName         = copyDb->typeInfBlob.TypeName;
+    typeInfBlob.Precision        = copyDb->typeInfBlob.Precision;
+    typeInfBlob.CaseSensitive    = copyDb->typeInfBlob.CaseSensitive;
+    typeInfBlob.MaximumScale     = copyDb->typeInfBlob.MaximumScale;
+
 #ifdef DBDEBUG_CONSOLE
 #ifdef DBDEBUG_CONSOLE
-    cout << "VARCHAR DATA TYPE: " << typeInfVarchar.TypeName << endl;
-    cout << "INTEGER DATA TYPE: " << typeInfInteger.TypeName << endl;
-    cout << "FLOAT   DATA TYPE: " << typeInfFloat.TypeName << endl;
-    cout << "DATE    DATA TYPE: " << typeInfDate.TypeName << endl;
+    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 << endl;
 #endif
 
     // Completed Successfully
     cout << endl;
 #endif
 
     // Completed Successfully
-    return(TRUE);
+    return true;
 } // wxDb::Open() 2
 
 
 } // wxDb::Open() 2
 
 
@@ -695,12 +1074,15 @@ bool wxDb::setConnectionOptions(void)
 
     // I need to get the DBMS name here, because some of the connection options
     // are database specific and need to call the Dbms() function.
 
     // I need to get the DBMS name here, because some of the connection options
     // are database specific and need to call the Dbms() function.
-    if (SQLGetInfo(hdbc, SQL_DBMS_NAME, (UCHAR*) dbInf.dbmsName, 40, &cb) != SQL_SUCCESS)
+    RETCODE retcode;
+
+    retcode = SQLGetInfo(hdbc, SQL_DBMS_NAME, (UCHAR *) dbInf.dbmsName, sizeof(dbInf.dbmsName), &cb);
+    if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
         return(DispAllErrors(henv, hdbc));
 
         return(DispAllErrors(henv, hdbc));
 
-    SQLSetConnectOption(hdbc, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF);
-    SQLSetConnectOption(hdbc, SQL_OPT_TRACE, SQL_OPT_TRACE_OFF);
-//     SQLSetConnectOption(hdbc, SQL_TXN_ISOLATION, SQL_TXN_READ_COMMITTED);  // No dirty reads
+    /* retcode = */ SQLSetConnectOption(hdbc, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF);
+    /* retcode = */ SQLSetConnectOption(hdbc, SQL_OPT_TRACE, SQL_OPT_TRACE_OFF);
+//  SQLSetConnectOption(hdbc, SQL_TXN_ISOLATION, SQL_TXN_READ_COMMITTED);  // No dirty reads
 
     // By default, MS Sql Server closes cursors on commit and rollback.  The following
     // call to SQLSetConnectOption() is needed to force SQL Server to preserve cursors
 
     // By default, MS Sql Server closes cursors on commit and rollback.  The following
     // call to SQLSetConnectOption() is needed to force SQL Server to preserve cursors
@@ -711,346 +1093,499 @@ bool wxDb::setConnectionOptions(void)
     {
         const long SQL_PRESERVE_CURSORS = 1204L;
         const long SQL_PC_ON = 1L;
     {
         const long SQL_PRESERVE_CURSORS = 1204L;
         const long SQL_PC_ON = 1L;
-        SQLSetConnectOption(hdbc, SQL_PRESERVE_CURSORS, SQL_PC_ON);
+        /* retcode = */ SQLSetConnectOption(hdbc, SQL_PRESERVE_CURSORS, SQL_PC_ON);
     }
 
     // Display the connection options to verify them
 #ifdef DBDEBUG_CONSOLE
     long l;
     }
 
     // Display the connection options to verify them
 #ifdef DBDEBUG_CONSOLE
     long l;
-    cout << "****** CONNECTION OPTIONS ******" << endl;
+    cout << wxT("****** CONNECTION OPTIONS ******") << endl;
 
 
-    if (SQLGetConnectOption(hdbc, SQL_AUTOCOMMIT, &l) != SQL_SUCCESS)
+    retcode = SQLGetConnectOption(hdbc, SQL_AUTOCOMMIT, &l);
+    if (retcode != SQL_SUCCESS)
         return(DispAllErrors(henv, hdbc));
         return(DispAllErrors(henv, hdbc));
-    cout << "AUTOCOMMIT: " << (l == SQL_AUTOCOMMIT_OFF ? "OFF" : "ON") << endl;
+    cout << wxT("AUTOCOMMIT: ") << (l == SQL_AUTOCOMMIT_OFF ? "OFF" : "ON") << endl;
 
 
-    if (SQLGetConnectOption(hdbc, SQL_ODBC_CURSORS, &l) != SQL_SUCCESS)
+    retcode = SQLGetConnectOption(hdbc, SQL_ODBC_CURSORS, &l);
+    if (retcode != SQL_SUCCESS)
         return(DispAllErrors(henv, hdbc));
         return(DispAllErrors(henv, hdbc));
-    cout << "ODBC CURSORS: ";
+    cout << wxT("ODBC CURSORS: ");
     switch(l)
     switch(l)
-        {
+    {
         case(SQL_CUR_USE_IF_NEEDED):
         case(SQL_CUR_USE_IF_NEEDED):
-            cout << "SQL_CUR_USE_IF_NEEDED";
+            cout << wxT("SQL_CUR_USE_IF_NEEDED");
             break;
         case(SQL_CUR_USE_ODBC):
             break;
         case(SQL_CUR_USE_ODBC):
-            cout << "SQL_CUR_USE_ODBC";
+            cout << wxT("SQL_CUR_USE_ODBC");
             break;
         case(SQL_CUR_USE_DRIVER):
             break;
         case(SQL_CUR_USE_DRIVER):
-            cout << "SQL_CUR_USE_DRIVER";
+            cout << wxT("SQL_CUR_USE_DRIVER");
             break;
             break;
-        }
-        cout << endl;
+    }
+    cout << endl;
 
 
-    if (SQLGetConnectOption(hdbc, SQL_OPT_TRACE, &l) != SQL_SUCCESS)
+    retcode = SQLGetConnectOption(hdbc, SQL_OPT_TRACE, &l)
+    if (retcode != SQL_SUCCESS)
         return(DispAllErrors(henv, hdbc));
         return(DispAllErrors(henv, hdbc));
-    cout << "TRACING: " << (l == SQL_OPT_TRACE_OFF ? "OFF" : "ON") << endl;
+    cout << wxT("TRACING: ") << (l == SQL_OPT_TRACE_OFF ? wxT("OFF") : wxT("ON")) << endl;
 
     cout << endl;
 #endif
 
     // Completed Successfully
 
     cout << endl;
 #endif
 
     // Completed Successfully
-    return(TRUE);
+    return true;
 
 } // wxDb::setConnectionOptions()
 
 
 /********** wxDb::getDbInfo() **********/
 
 } // wxDb::setConnectionOptions()
 
 
 /********** wxDb::getDbInfo() **********/
-bool wxDb::getDbInfo(void)
+bool wxDb::getDbInfo(bool failOnDataTypeUnsupported)
 {
     SWORD cb;
     RETCODE retcode;
 
 {
     SWORD cb;
     RETCODE retcode;
 
-    if (SQLGetInfo(hdbc, SQL_SERVER_NAME, (UCHAR*) dbInf.serverName, 80, &cb) != SQL_SUCCESS)
-        return(DispAllErrors(henv, hdbc));
+    retcode = SQLGetInfo(hdbc, SQL_SERVER_NAME, (UCHAR*) dbInf.serverName, sizeof(dbInf.serverName), &cb);
+    if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO )
+    {
+        DispAllErrors(henv, hdbc);
+        if (failOnDataTypeUnsupported)
+            return false;
+    }
 
 
-    if (SQLGetInfo(hdbc, SQL_DATABASE_NAME, (UCHAR*) dbInf.databaseName, 128, &cb) != SQL_SUCCESS)
-        return(DispAllErrors(henv, hdbc));
+    retcode = SQLGetInfo(hdbc, SQL_DATABASE_NAME, (UCHAR*) dbInf.databaseName, sizeof(dbInf.databaseName), &cb);
+    if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO )
+    {
+        DispAllErrors(henv, hdbc);
+        if (failOnDataTypeUnsupported)
+            return false;
+    }
 
 
-    if (SQLGetInfo(hdbc, SQL_DBMS_NAME, (UCHAR*) dbInf.dbmsName, 40, &cb) != SQL_SUCCESS)
-        return(DispAllErrors(henv, hdbc));
+    retcode = SQLGetInfo(hdbc, SQL_DBMS_NAME, (UCHAR*) dbInf.dbmsName, sizeof(dbInf.dbmsName), &cb);
+    if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO )
+    {
+        DispAllErrors(henv, hdbc);
+        if (failOnDataTypeUnsupported)
+            return false;
+    }
 
     // 16-Mar-1999
     // After upgrading to MSVC6, the original 20 char buffer below was insufficient,
     // causing database connectivity to fail in some cases.
 
     // 16-Mar-1999
     // After upgrading to MSVC6, the original 20 char buffer below was insufficient,
     // causing database connectivity to fail in some cases.
-    retcode = SQLGetInfo(hdbc, SQL_DBMS_VER, (UCHAR*) dbInf.dbmsVer, 64, &cb);
-
+    retcode = SQLGetInfo(hdbc, SQL_DBMS_VER, (UCHAR*) dbInf.dbmsVer, sizeof(dbInf.dbmsVer), &cb);
     if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO )
     if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO )
-        return(DispAllErrors(henv, hdbc));
+    {
+        DispAllErrors(henv, hdbc);
+        if (failOnDataTypeUnsupported)
+            return false;
+    }
 
 
-    if (SQLGetInfo(hdbc, SQL_ACTIVE_CONNECTIONS, (UCHAR*) &dbInf.maxConnections, sizeof(dbInf.maxConnections), &cb) != SQL_SUCCESS)
-        return(DispAllErrors(henv, hdbc));
+    retcode = SQLGetInfo(hdbc, SQL_ACTIVE_CONNECTIONS, (UCHAR*) &dbInf.maxConnections, sizeof(dbInf.maxConnections), &cb);
+    if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO )
+    {
+        DispAllErrors(henv, hdbc);
+        if (failOnDataTypeUnsupported)
+            return false;
+    }
 
 
-    if (SQLGetInfo(hdbc, SQL_ACTIVE_STATEMENTS, (UCHAR*) &dbInf.maxStmts, sizeof(dbInf.maxStmts), &cb) != SQL_SUCCESS)
-        return(DispAllErrors(henv, hdbc));
+    retcode = SQLGetInfo(hdbc, SQL_ACTIVE_STATEMENTS, (UCHAR*) &dbInf.maxStmts, sizeof(dbInf.maxStmts), &cb);
+    if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO )
+    {
+        DispAllErrors(henv, hdbc);
+        if (failOnDataTypeUnsupported)
+            return false;
+    }
 
 
-    if (SQLGetInfo(hdbc, SQL_DRIVER_NAME, (UCHAR*) dbInf.driverName, 40, &cb) != SQL_SUCCESS)
-        return(DispAllErrors(henv, hdbc));
+    retcode = SQLGetInfo(hdbc, SQL_DRIVER_NAME, (UCHAR*) dbInf.driverName, sizeof(dbInf.driverName), &cb);
+    if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO )
+    {
+        DispAllErrors(henv, hdbc);
+        if (failOnDataTypeUnsupported)
+            return false;
+    }
 
 
-    if (SQLGetInfo(hdbc, SQL_DRIVER_ODBC_VER, (UCHAR*) dbInf.odbcVer, 60, &cb) == SQL_ERROR)
-        return(DispAllErrors(henv, hdbc));
+    retcode = SQLGetInfo(hdbc, SQL_DRIVER_ODBC_VER, (UCHAR*) dbInf.odbcVer, sizeof(dbInf.odbcVer), &cb);
+    if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO )
+    {
+        DispAllErrors(henv, hdbc);
+        if (failOnDataTypeUnsupported)
+            return false;
+    }
 
 
-    retcode = SQLGetInfo(hdbc, SQL_ODBC_VER, (UCHAR*) dbInf.drvMgrOdbcVer, 60, &cb);
+    retcode = SQLGetInfo(hdbc, SQL_ODBC_VER, (UCHAR*) dbInf.drvMgrOdbcVer, sizeof(dbInf.drvMgrOdbcVer), &cb);
     if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
     if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
-        return(DispAllErrors(henv, hdbc));
+    {
+        DispAllErrors(henv, hdbc);
+        if (failOnDataTypeUnsupported)
+            return false;
+    }
 
 
-    if (SQLGetInfo(hdbc, SQL_DRIVER_VER, (UCHAR*) dbInf.driverVer, 60, &cb) == SQL_ERROR)
-        return(DispAllErrors(henv, hdbc));
+    retcode = SQLGetInfo(hdbc, SQL_DRIVER_VER, (UCHAR*) dbInf.driverVer, sizeof(dbInf.driverVer), &cb);
+    if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO )
+    {
+        DispAllErrors(henv, hdbc);
+        if (failOnDataTypeUnsupported)
+            return false;
+    }
 
 
-    if (SQLGetInfo(hdbc, SQL_ODBC_API_CONFORMANCE, (UCHAR*) &dbInf.apiConfLvl, sizeof(dbInf.apiConfLvl), &cb) != SQL_SUCCESS)
-        return(DispAllErrors(henv, hdbc));
+    retcode = SQLGetInfo(hdbc, SQL_ODBC_API_CONFORMANCE, (UCHAR*) &dbInf.apiConfLvl, sizeof(dbInf.apiConfLvl), &cb);
+    if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO )
+    {
+        DispAllErrors(henv, hdbc);
+        if (failOnDataTypeUnsupported)
+            return false;
+    }
 
 
-    if (SQLGetInfo(hdbc, SQL_ODBC_SAG_CLI_CONFORMANCE, (UCHAR*) &dbInf.cliConfLvl, sizeof(dbInf.cliConfLvl), &cb) != SQL_SUCCESS)
-//        return(DispAllErrors(henv, hdbc));
+    retcode = SQLGetInfo(hdbc, SQL_ODBC_SAG_CLI_CONFORMANCE, (UCHAR*) &dbInf.cliConfLvl, sizeof(dbInf.cliConfLvl), &cb);
+    if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO )
     {
         // Not all drivers support this call - Nick Gorham(unixODBC)
         dbInf.cliConfLvl = 0;
     {
         // Not all drivers support this call - Nick Gorham(unixODBC)
         dbInf.cliConfLvl = 0;
+        DispAllErrors(henv, hdbc);
+        if (failOnDataTypeUnsupported)
+            return false;
     }
 
     }
 
-    if (SQLGetInfo(hdbc, SQL_ODBC_SQL_CONFORMANCE, (UCHAR*) &dbInf.sqlConfLvl, sizeof(dbInf.sqlConfLvl), &cb) != SQL_SUCCESS)
-        return(DispAllErrors(henv, hdbc));
+    retcode = SQLGetInfo(hdbc, SQL_ODBC_SQL_CONFORMANCE, (UCHAR*) &dbInf.sqlConfLvl, sizeof(dbInf.sqlConfLvl), &cb);
+    if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO )
+    {
+        DispAllErrors(henv, hdbc);
+        if (failOnDataTypeUnsupported)
+            return false;
+    }
 
 
-    if (SQLGetInfo(hdbc, SQL_OUTER_JOINS, (UCHAR*) dbInf.outerJoins, 2, &cb) != SQL_SUCCESS)
-        return(DispAllErrors(henv, hdbc));
+    retcode = SQLGetInfo(hdbc, SQL_OUTER_JOINS, (UCHAR*) dbInf.outerJoins, sizeof(dbInf.outerJoins), &cb);
+    if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO )
+    {
+        DispAllErrors(henv, hdbc);
+        if (failOnDataTypeUnsupported)
+            return false;
+    }
 
 
-    if (SQLGetInfo(hdbc, SQL_PROCEDURES, (UCHAR*) dbInf.procedureSupport, 2, &cb) != SQL_SUCCESS)
-        return(DispAllErrors(henv, hdbc));
+    retcode = SQLGetInfo(hdbc, SQL_PROCEDURES, (UCHAR*) dbInf.procedureSupport, sizeof(dbInf.procedureSupport), &cb);
+    if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO )
+    {
+        DispAllErrors(henv, hdbc);
+        if (failOnDataTypeUnsupported)
+            return false;
+    }
 
 
-    if (SQLGetInfo(hdbc, SQL_ACCESSIBLE_TABLES, (UCHAR*) dbInf.accessibleTables, 2, &cb) != SQL_SUCCESS)
-        return(DispAllErrors(henv, hdbc));
+    retcode = SQLGetInfo(hdbc, SQL_ACCESSIBLE_TABLES, (UCHAR*) dbInf.accessibleTables, sizeof(dbInf.accessibleTables), &cb);
+    if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO )
+    {
+        DispAllErrors(henv, hdbc);
+        if (failOnDataTypeUnsupported)
+            return false;
+    }
 
 
-    if (SQLGetInfo(hdbc, SQL_CURSOR_COMMIT_BEHAVIOR, (UCHAR*) &dbInf.cursorCommitBehavior, sizeof(dbInf.cursorCommitBehavior), &cb) != SQL_SUCCESS)
-        return(DispAllErrors(henv, hdbc));
+    retcode = SQLGetInfo(hdbc, SQL_CURSOR_COMMIT_BEHAVIOR, (UCHAR*) &dbInf.cursorCommitBehavior, sizeof(dbInf.cursorCommitBehavior), &cb);
+    if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO )
+    {
+        DispAllErrors(henv, hdbc);
+        if (failOnDataTypeUnsupported)
+            return false;
+    }
 
 
-    if (SQLGetInfo(hdbc, SQL_CURSOR_ROLLBACK_BEHAVIOR, (UCHAR*) &dbInf.cursorRollbackBehavior, sizeof(dbInf.cursorRollbackBehavior), &cb) != SQL_SUCCESS)
-        return(DispAllErrors(henv, hdbc));
+    retcode = SQLGetInfo(hdbc, SQL_CURSOR_ROLLBACK_BEHAVIOR, (UCHAR*) &dbInf.cursorRollbackBehavior, sizeof(dbInf.cursorRollbackBehavior), &cb);
+    if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO )
+    {
+        DispAllErrors(henv, hdbc);
+        if (failOnDataTypeUnsupported)
+            return false;
+    }
 
 
-    if (SQLGetInfo(hdbc, SQL_NON_NULLABLE_COLUMNS, (UCHAR*) &dbInf.supportNotNullClause, sizeof(dbInf.supportNotNullClause), &cb) != SQL_SUCCESS)
-        return(DispAllErrors(henv, hdbc));
+    retcode = SQLGetInfo(hdbc, SQL_NON_NULLABLE_COLUMNS, (UCHAR*) &dbInf.supportNotNullClause, sizeof(dbInf.supportNotNullClause), &cb);
+    if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO )
+    {
+        DispAllErrors(henv, hdbc);
+        if (failOnDataTypeUnsupported)
+            return false;
+    }
 
 
-    if (SQLGetInfo(hdbc, SQL_ODBC_SQL_OPT_IEF, (UCHAR*) dbInf.supportIEF, 2, &cb) != SQL_SUCCESS)
-        return(DispAllErrors(henv, hdbc));
+    retcode = SQLGetInfo(hdbc, SQL_ODBC_SQL_OPT_IEF, (UCHAR*) dbInf.supportIEF, sizeof(dbInf.supportIEF), &cb);
+    if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO )
+    {
+        DispAllErrors(henv, hdbc);
+        if (failOnDataTypeUnsupported)
+            return false;
+    }
 
 
-    if (SQLGetInfo(hdbc, SQL_DEFAULT_TXN_ISOLATION, (UCHAR*) &dbInf.txnIsolation, sizeof(dbInf.txnIsolation), &cb) != SQL_SUCCESS)
-        return(DispAllErrors(henv, hdbc));
+    retcode = SQLGetInfo(hdbc, SQL_DEFAULT_TXN_ISOLATION, (UCHAR*) &dbInf.txnIsolation, sizeof(dbInf.txnIsolation), &cb);
+    if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO )
+    {
+        DispAllErrors(henv, hdbc);
+        if (failOnDataTypeUnsupported)
+            return false;
+    }
 
 
-    if (SQLGetInfo(hdbc, SQL_TXN_ISOLATION_OPTION, (UCHAR*) &dbInf.txnIsolationOptions, sizeof(dbInf.txnIsolationOptions), &cb) != SQL_SUCCESS)
-        return(DispAllErrors(henv, hdbc));
+    retcode = SQLGetInfo(hdbc, SQL_TXN_ISOLATION_OPTION, (UCHAR*) &dbInf.txnIsolationOptions, sizeof(dbInf.txnIsolationOptions), &cb);
+    if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO )
+    {
+        DispAllErrors(henv, hdbc);
+        if (failOnDataTypeUnsupported)
+            return false;
+    }
 
 
-    if (SQLGetInfo(hdbc, SQL_FETCH_DIRECTION, (UCHAR*) &dbInf.fetchDirections, sizeof(dbInf.fetchDirections), &cb) != SQL_SUCCESS)
-        return(DispAllErrors(henv, hdbc));
+    retcode = SQLGetInfo(hdbc, SQL_FETCH_DIRECTION, (UCHAR*) &dbInf.fetchDirections, sizeof(dbInf.fetchDirections), &cb);
+    if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO )
+    {
+        DispAllErrors(henv, hdbc);
+        if (failOnDataTypeUnsupported)
+            return false;
+    }
 
 
-    if (SQLGetInfo(hdbc, SQL_LOCK_TYPES, (UCHAR*) &dbInf.lockTypes, sizeof(dbInf.lockTypes), &cb) != SQL_SUCCESS)
-        return(DispAllErrors(henv, hdbc));
+    retcode = SQLGetInfo(hdbc, SQL_LOCK_TYPES, (UCHAR*) &dbInf.lockTypes, sizeof(dbInf.lockTypes), &cb);
+    if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO )
+    {
+        DispAllErrors(henv, hdbc);
+        if (failOnDataTypeUnsupported)
+            return false;
+    }
 
 
-    if (SQLGetInfo(hdbc, SQL_POS_OPERATIONS, (UCHAR*) &dbInf.posOperations, sizeof(dbInf.posOperations), &cb) != SQL_SUCCESS)
-        return(DispAllErrors(henv, hdbc));
+    retcode = SQLGetInfo(hdbc, SQL_POS_OPERATIONS, (UCHAR*) &dbInf.posOperations, sizeof(dbInf.posOperations), &cb);
+    if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO )
+    {
+        DispAllErrors(henv, hdbc);
+        if (failOnDataTypeUnsupported)
+            return false;
+    }
 
 
-    if (SQLGetInfo(hdbc, SQL_POSITIONED_STATEMENTS, (UCHAR*) &dbInf.posStmts, sizeof(dbInf.posStmts), &cb) != SQL_SUCCESS)
-        return(DispAllErrors(henv, hdbc));
+    retcode = SQLGetInfo(hdbc, SQL_POSITIONED_STATEMENTS, (UCHAR*) &dbInf.posStmts, sizeof(dbInf.posStmts), &cb);
+    if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO )
+    {
+        DispAllErrors(henv, hdbc);
+        if (failOnDataTypeUnsupported)
+            return false;
+    }
 
 
-    if (SQLGetInfo(hdbc, SQL_SCROLL_CONCURRENCY, (UCHAR*) &dbInf.scrollConcurrency, sizeof(dbInf.scrollConcurrency), &cb) != SQL_SUCCESS)
-        return(DispAllErrors(henv, hdbc));
+    retcode = SQLGetInfo(hdbc, SQL_SCROLL_CONCURRENCY, (UCHAR*) &dbInf.scrollConcurrency, sizeof(dbInf.scrollConcurrency), &cb);
+    if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO )
+    {
+        DispAllErrors(henv, hdbc);
+        if (failOnDataTypeUnsupported)
+            return false;
+    }
 
 
-    if (SQLGetInfo(hdbc, SQL_SCROLL_OPTIONS, (UCHAR*) &dbInf.scrollOptions, sizeof(dbInf.scrollOptions), &cb) != SQL_SUCCESS)
-        return(DispAllErrors(henv, hdbc));
+    retcode = SQLGetInfo(hdbc, SQL_SCROLL_OPTIONS, (UCHAR*) &dbInf.scrollOptions, sizeof(dbInf.scrollOptions), &cb);
+    if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO )
+    {
+        DispAllErrors(henv, hdbc);
+        if (failOnDataTypeUnsupported)
+            return false;
+    }
 
 
-    if (SQLGetInfo(hdbc, SQL_STATIC_SENSITIVITY, (UCHAR*) &dbInf.staticSensitivity, sizeof(dbInf.staticSensitivity), &cb) != SQL_SUCCESS)
-        return(DispAllErrors(henv, hdbc));
+    retcode = SQLGetInfo(hdbc, SQL_STATIC_SENSITIVITY, (UCHAR*) &dbInf.staticSensitivity, sizeof(dbInf.staticSensitivity), &cb);
+    if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO )
+    {
+        DispAllErrors(henv, hdbc);
+        if (failOnDataTypeUnsupported)
+            return false;
+    }
 
 
-    if (SQLGetInfo(hdbc, SQL_TXN_CAPABLE, (UCHAR*) &dbInf.txnCapable, sizeof(dbInf.txnCapable), &cb) != SQL_SUCCESS)
-        return(DispAllErrors(henv, hdbc));
+    retcode = SQLGetInfo(hdbc, SQL_TXN_CAPABLE, (UCHAR*) &dbInf.txnCapable, sizeof(dbInf.txnCapable), &cb);
+    if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO )
+    {
+        DispAllErrors(henv, hdbc);
+        if (failOnDataTypeUnsupported)
+            return false;
+    }
 
 
-    if (SQLGetInfo(hdbc, SQL_LOGIN_TIMEOUT, (UCHAR*) &dbInf.loginTimeout, sizeof(dbInf.loginTimeout), &cb) != SQL_SUCCESS)
-        return(DispAllErrors(henv, hdbc));
+    retcode = SQLGetInfo(hdbc, SQL_LOGIN_TIMEOUT, (UCHAR*) &dbInf.loginTimeout, sizeof(dbInf.loginTimeout), &cb);
+    if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO )
+    {
+        DispAllErrors(henv, hdbc);
+        if (failOnDataTypeUnsupported)
+            return false;
+    }
 
 #ifdef DBDEBUG_CONSOLE
 
 #ifdef DBDEBUG_CONSOLE
-    cout << "***** DATA SOURCE INFORMATION *****" << endl;
-    cout << "SERVER Name: " << dbInf.serverName << endl;
-    cout << "DBMS Name: " << dbInf.dbmsName << "; DBMS Version: " << dbInf.dbmsVer << endl;
-    cout << "ODBC Version: " << dbInf.odbcVer << "; Driver Version: " << dbInf.driverVer << endl;
+    cout << wxT("***** DATA SOURCE INFORMATION *****") << endl;
+    cout << wxT(wxT("SERVER Name: ") << dbInf.serverName << endl;
+    cout << wxT("DBMS Name: ") << dbInf.dbmsName << wxT("; DBMS Version: ") << dbInf.dbmsVer << endl;
+    cout << wxT("ODBC Version: ") << dbInf.odbcVer << wxT("; Driver Version: ") << dbInf.driverVer << endl;
 
 
-    cout << "API Conf. Level: ";
+    cout << wxT("API Conf. Level: ");
     switch(dbInf.apiConfLvl)
     {
     switch(dbInf.apiConfLvl)
     {
-        case SQL_OAC_NONE:      cout << "None";       break;
-        case SQL_OAC_LEVEL1:    cout << "Level 1";    break;
-        case SQL_OAC_LEVEL2:    cout << "Level 2";    break;
+        case SQL_OAC_NONE:      cout << wxT("None");       break;
+        case SQL_OAC_LEVEL1:    cout << wxT("Level 1");    break;
+        case SQL_OAC_LEVEL2:    cout << wxT("Level 2");    break;
     }
     cout << endl;
 
     }
     cout << endl;
 
-    cout << "SAG CLI Conf. Level: ";
+    cout << wxT("SAG CLI Conf. Level: ");
     switch(dbInf.cliConfLvl)
     {
     switch(dbInf.cliConfLvl)
     {
-        case SQL_OSCC_NOT_COMPLIANT:    cout << "Not Compliant";    break;
-        case SQL_OSCC_COMPLIANT:        cout << "Compliant";        break;
+        case SQL_OSCC_NOT_COMPLIANT:    cout << wxT("Not Compliant");    break;
+        case SQL_OSCC_COMPLIANT:        cout << wxT("Compliant");        break;
     }
     cout << endl;
 
     }
     cout << endl;
 
-    cout << "SQL Conf. Level: ";
+    cout << wxT("SQL Conf. Level: ");
     switch(dbInf.sqlConfLvl)
     {
     switch(dbInf.sqlConfLvl)
     {
-        case SQL_OSC_MINIMUM:     cout << "Minimum Grammar";     break;
-        case SQL_OSC_CORE:        cout << "Core Grammar";        break;
-        case SQL_OSC_EXTENDED:    cout << "Extended Grammar";    break;
+        case SQL_OSC_MINIMUM:     cout << wxT("Minimum Grammar");     break;
+        case SQL_OSC_CORE:        cout << wxT("Core Grammar");        break;
+        case SQL_OSC_EXTENDED:    cout << wxT("Extended Grammar");    break;
     }
     cout << endl;
 
     }
     cout << endl;
 
-    cout << "Max. Connections: "       << dbInf.maxConnections   << endl;
-    cout << "Outer Joins: "            << dbInf.outerJoins       << endl;
-    cout << "Support for Procedures: " << dbInf.procedureSupport << endl;
-    cout << "All tables accessible : " << dbInf.accessibleTables << endl;
-    cout << "Cursor COMMIT Behavior: ";
+    cout << wxT("Max. Connections: ")       << dbInf.maxConnections   << endl;
+    cout << wxT("Outer Joins: ")            << dbInf.outerJoins       << endl;
+    cout << wxT("Support for Procedures: ") << dbInf.procedureSupport << endl;
+    cout << wxT("All tables accessible : ") << dbInf.accessibleTables << endl;
+    cout << wxT("Cursor COMMIT Behavior: ");
     switch(dbInf.cursorCommitBehavior)
     {
     switch(dbInf.cursorCommitBehavior)
     {
-        case SQL_CB_DELETE:        cout << "Delete cursors";      break;
-        case SQL_CB_CLOSE:         cout << "Close cursors";       break;
-        case SQL_CB_PRESERVE:      cout << "Preserve cursors";    break;
+        case SQL_CB_DELETE:        cout << wxT("Delete cursors");      break;
+        case SQL_CB_CLOSE:         cout << wxT("Close cursors");       break;
+        case SQL_CB_PRESERVE:      cout << wxT("Preserve cursors");    break;
     }
     cout << endl;
 
     }
     cout << endl;
 
-    cout << "Cursor ROLLBACK Behavior: ";
+    cout << wxT("Cursor ROLLBACK Behavior: ");
     switch(dbInf.cursorRollbackBehavior)
     {
     switch(dbInf.cursorRollbackBehavior)
     {
-        case SQL_CB_DELETE:      cout << "Delete cursors";      break;
-        case SQL_CB_CLOSE:       cout << "Close cursors";       break;
-        case SQL_CB_PRESERVE:    cout << "Preserve cursors";    break;
+        case SQL_CB_DELETE:      cout << wxT("Delete cursors");      break;
+        case SQL_CB_CLOSE:       cout << wxT("Close cursors");       break;
+        case SQL_CB_PRESERVE:    cout << wxT("Preserve cursors");    break;
     }
     cout << endl;
 
     }
     cout << endl;
 
-    cout << "Support NOT NULL clause: ";
+    cout << wxT("Support NOT NULL clause: ");
     switch(dbInf.supportNotNullClause)
     {
     switch(dbInf.supportNotNullClause)
     {
-        case SQL_NNC_NULL:        cout << "No";        break;
-        case SQL_NNC_NON_NULL:    cout << "Yes";       break;
+        case SQL_NNC_NULL:        cout << wxT("No");        break;
+        case SQL_NNC_NON_NULL:    cout << wxT("Yes");       break;
     }
     cout << endl;
 
     }
     cout << endl;
 
-    cout << "Support IEF (Ref. Integrity): " << dbInf.supportIEF   << endl;
-    cout << "Login Timeout: "                << dbInf.loginTimeout << endl;
+    cout << wxT("Support IEF (Ref. Integrity): ") << dbInf.supportIEF   << endl;
+    cout << wxT("Login Timeout: ")                << dbInf.loginTimeout << endl;
 
 
-    cout << endl << endl << "more ..." << endl;
+    cout << endl << endl << wxT("more ...") << endl;
     getchar();
 
     getchar();
 
-    cout << "Default Transaction Isolation: ";
+    cout << wxT("Default Transaction Isolation: ";
     switch(dbInf.txnIsolation)
     {
     switch(dbInf.txnIsolation)
     {
-        case SQL_TXN_READ_UNCOMMITTED:  cout << "Read Uncommitted";    break;
-        case SQL_TXN_READ_COMMITTED:    cout << "Read Committed";      break;
-        case SQL_TXN_REPEATABLE_READ:   cout << "Repeatable Read";     break;
-        case SQL_TXN_SERIALIZABLE:      cout << "Serializable";        break;
+        case SQL_TXN_READ_UNCOMMITTED:  cout << wxT("Read Uncommitted");    break;
+        case SQL_TXN_READ_COMMITTED:    cout << wxT("Read Committed");      break;
+        case SQL_TXN_REPEATABLE_READ:   cout << wxT("Repeatable Read");     break;
+        case SQL_TXN_SERIALIZABLE:      cout << wxT("Serializable");        break;
 #ifdef ODBC_V20
 #ifdef ODBC_V20
-        case SQL_TXN_VERSIONING:        cout << "Versioning";          break;
+        case SQL_TXN_VERSIONING:        cout << wxT("Versioning");          break;
 #endif
     }
     cout << endl;
 
 #endif
     }
     cout << endl;
 
-    cout << "Transaction Isolation Options: ";
+    cout << wxT("Transaction Isolation Options: ");
     if (dbInf.txnIsolationOptions & SQL_TXN_READ_UNCOMMITTED)
     if (dbInf.txnIsolationOptions & SQL_TXN_READ_UNCOMMITTED)
-        cout << "Read Uncommitted, ";
+        cout << wxT("Read Uncommitted, ");
     if (dbInf.txnIsolationOptions & SQL_TXN_READ_COMMITTED)
     if (dbInf.txnIsolationOptions & SQL_TXN_READ_COMMITTED)
-        cout << "Read Committed, ";
+        cout << wxT("Read Committed, ");
     if (dbInf.txnIsolationOptions & SQL_TXN_REPEATABLE_READ)
     if (dbInf.txnIsolationOptions & SQL_TXN_REPEATABLE_READ)
-        cout << "Repeatable Read, ";
+        cout << wxT("Repeatable Read, ");
     if (dbInf.txnIsolationOptions & SQL_TXN_SERIALIZABLE)
     if (dbInf.txnIsolationOptions & SQL_TXN_SERIALIZABLE)
-        cout << "Serializable, ";
+        cout << wxT("Serializable, ");
 #ifdef ODBC_V20
     if (dbInf.txnIsolationOptions & SQL_TXN_VERSIONING)
 #ifdef ODBC_V20
     if (dbInf.txnIsolationOptions & SQL_TXN_VERSIONING)
-        cout << "Versioning";
+        cout << wxT("Versioning");
 #endif
     cout << endl;
 
 #endif
     cout << endl;
 
-    cout << "Fetch Directions Supported:" << endl << "   ";
+    cout << wxT("Fetch Directions Supported:") << endl << wxT("   ");
     if (dbInf.fetchDirections & SQL_FD_FETCH_NEXT)
     if (dbInf.fetchDirections & SQL_FD_FETCH_NEXT)
-        cout << "Next, ";
+        cout << wxT("Next, ");
     if (dbInf.fetchDirections & SQL_FD_FETCH_PRIOR)
     if (dbInf.fetchDirections & SQL_FD_FETCH_PRIOR)
-        cout << "Prev, ";
+        cout << wxT("Prev, ");
     if (dbInf.fetchDirections & SQL_FD_FETCH_FIRST)
     if (dbInf.fetchDirections & SQL_FD_FETCH_FIRST)
-        cout << "First, ";
+        cout << wxT("First, ");
     if (dbInf.fetchDirections & SQL_FD_FETCH_LAST)
     if (dbInf.fetchDirections & SQL_FD_FETCH_LAST)
-        cout << "Last, ";
+        cout << wxT("Last, ");
     if (dbInf.fetchDirections & SQL_FD_FETCH_ABSOLUTE)
     if (dbInf.fetchDirections & SQL_FD_FETCH_ABSOLUTE)
-        cout << "Absolute, ";
+        cout << wxT("Absolute, ");
     if (dbInf.fetchDirections & SQL_FD_FETCH_RELATIVE)
     if (dbInf.fetchDirections & SQL_FD_FETCH_RELATIVE)
-        cout << "Relative, ";
+        cout << wxT("Relative, ");
 #ifdef ODBC_V20
     if (dbInf.fetchDirections & SQL_FD_FETCH_RESUME)
 #ifdef ODBC_V20
     if (dbInf.fetchDirections & SQL_FD_FETCH_RESUME)
-        cout << "Resume, ";
+        cout << wxT("Resume, ");
 #endif
     if (dbInf.fetchDirections & SQL_FD_FETCH_BOOKMARK)
 #endif
     if (dbInf.fetchDirections & SQL_FD_FETCH_BOOKMARK)
-        cout << "Bookmark";
+        cout << wxT("Bookmark");
     cout << endl;
 
     cout << endl;
 
-    cout << "Lock Types Supported (SQLSetPos): ";
+    cout << wxT("Lock Types Supported (SQLSetPos): ");
     if (dbInf.lockTypes & SQL_LCK_NO_CHANGE)
     if (dbInf.lockTypes & SQL_LCK_NO_CHANGE)
-        cout << "No Change, ";
+        cout << wxT("No Change, ");
     if (dbInf.lockTypes & SQL_LCK_EXCLUSIVE)
     if (dbInf.lockTypes & SQL_LCK_EXCLUSIVE)
-        cout << "Exclusive, ";
+        cout << wxT("Exclusive, ");
     if (dbInf.lockTypes & SQL_LCK_UNLOCK)
     if (dbInf.lockTypes & SQL_LCK_UNLOCK)
-        cout << "UnLock";
+        cout << wxT("UnLock");
     cout << endl;
 
     cout << endl;
 
-    cout << "Position Operations Supported (SQLSetPos): ";
+    cout << wxT("Position Operations Supported (SQLSetPos): ");
     if (dbInf.posOperations & SQL_POS_POSITION)
     if (dbInf.posOperations & SQL_POS_POSITION)
-        cout << "Position, ";
+        cout << wxT("Position, ");
     if (dbInf.posOperations & SQL_POS_REFRESH)
     if (dbInf.posOperations & SQL_POS_REFRESH)
-        cout << "Refresh, ";
+        cout << wxT("Refresh, ");
     if (dbInf.posOperations & SQL_POS_UPDATE)
     if (dbInf.posOperations & SQL_POS_UPDATE)
-        cout << "Upd, ";
+        cout << wxT("Upd, "));
     if (dbInf.posOperations & SQL_POS_DELETE)
     if (dbInf.posOperations & SQL_POS_DELETE)
-        cout << "Del, ";
+        cout << wxT("Del, ");
     if (dbInf.posOperations & SQL_POS_ADD)
     if (dbInf.posOperations & SQL_POS_ADD)
-        cout << "Add";
+        cout << wxT("Add");
     cout << endl;
 
     cout << endl;
 
-    cout << "Positioned Statements Supported: ";
+    cout << wxT("Positioned Statements Supported: ");
     if (dbInf.posStmts & SQL_PS_POSITIONED_DELETE)
     if (dbInf.posStmts & SQL_PS_POSITIONED_DELETE)
-        cout << "Pos delete, ";
+        cout << wxT("Pos delete, ");
     if (dbInf.posStmts & SQL_PS_POSITIONED_UPDATE)
     if (dbInf.posStmts & SQL_PS_POSITIONED_UPDATE)
-        cout << "Pos update, ";
+        cout << wxT("Pos update, ");
     if (dbInf.posStmts & SQL_PS_SELECT_FOR_UPDATE)
     if (dbInf.posStmts & SQL_PS_SELECT_FOR_UPDATE)
-        cout << "Select for update";
+        cout << wxT("Select for update");
     cout << endl;
 
     cout << endl;
 
-    cout << "Scroll Concurrency: ";
+    cout << wxT("Scroll Concurrency: ");
     if (dbInf.scrollConcurrency & SQL_SCCO_READ_ONLY)
     if (dbInf.scrollConcurrency & SQL_SCCO_READ_ONLY)
-        cout << "Read Only, ";
+        cout << wxT("Read Only, ");
     if (dbInf.scrollConcurrency & SQL_SCCO_LOCK)
     if (dbInf.scrollConcurrency & SQL_SCCO_LOCK)
-        cout << "Lock, ";
+        cout << wxT("Lock, ");
     if (dbInf.scrollConcurrency & SQL_SCCO_OPT_ROWVER)
     if (dbInf.scrollConcurrency & SQL_SCCO_OPT_ROWVER)
-        cout << "Opt. Rowver, ";
+        cout << wxT("Opt. Rowver, ");
     if (dbInf.scrollConcurrency & SQL_SCCO_OPT_VALUES)
     if (dbInf.scrollConcurrency & SQL_SCCO_OPT_VALUES)
-        cout << "Opt. Values";
+        cout << wxT("Opt. Values");
     cout << endl;
 
     cout << endl;
 
-    cout << "Scroll Options: ";
+    cout << wxT("Scroll Options: ");
     if (dbInf.scrollOptions & SQL_SO_FORWARD_ONLY)
     if (dbInf.scrollOptions & SQL_SO_FORWARD_ONLY)
-        cout << "Fwd Only, ";
+        cout << wxT("Fwd Only, ");
     if (dbInf.scrollOptions & SQL_SO_STATIC)
     if (dbInf.scrollOptions & SQL_SO_STATIC)
-        cout << "Static, ";
+        cout << wxT("Static, ");
     if (dbInf.scrollOptions & SQL_SO_KEYSET_DRIVEN)
     if (dbInf.scrollOptions & SQL_SO_KEYSET_DRIVEN)
-        cout << "Keyset Driven, ";
+        cout << wxT("Keyset Driven, ");
     if (dbInf.scrollOptions & SQL_SO_DYNAMIC)
     if (dbInf.scrollOptions & SQL_SO_DYNAMIC)
-        cout << "Dynamic, ";
+        cout << wxT("Dynamic, ");
     if (dbInf.scrollOptions & SQL_SO_MIXED)
     if (dbInf.scrollOptions & SQL_SO_MIXED)
-        cout << "Mixed";
+        cout << wxT("Mixed");
     cout << endl;
 
     cout << endl;
 
-    cout << "Static Sensitivity: ";
+    cout << wxT("Static Sensitivity: ");
     if (dbInf.staticSensitivity & SQL_SS_ADDITIONS)
     if (dbInf.staticSensitivity & SQL_SS_ADDITIONS)
-        cout << "Additions, ";
+        cout << wxT("Additions, ");
     if (dbInf.staticSensitivity & SQL_SS_DELETIONS)
     if (dbInf.staticSensitivity & SQL_SS_DELETIONS)
-        cout << "Deletions, ";
+        cout << wxT("Deletions, ");
     if (dbInf.staticSensitivity & SQL_SS_UPDATES)
     if (dbInf.staticSensitivity & SQL_SS_UPDATES)
-        cout << "Updates";
+        cout << wxT("Updates");
     cout << endl;
 
     cout << endl;
 
-    cout << "Transaction Capable?: ";
+    cout << wxT("Transaction Capable?: ");
     switch(dbInf.txnCapable)
     {
     switch(dbInf.txnCapable)
     {
-        case SQL_TC_NONE:          cout << "No";            break;
-        case SQL_TC_DML:           cout << "DML Only";      break;
-        case SQL_TC_DDL_COMMIT:    cout << "DDL Commit";    break;
-        case SQL_TC_DDL_IGNORE:    cout << "DDL Ignore";    break;
-        case SQL_TC_ALL:           cout << "DDL & DML";     break;
+        case SQL_TC_NONE:          cout << wxT("No");            break;
+        case SQL_TC_DML:           cout << wxT("DML Only");      break;
+        case SQL_TC_DDL_COMMIT:    cout << wxT("DDL Commit");    break;
+        case SQL_TC_DDL_IGNORE:    cout << wxT("DDL Ignore");    break;
+        case SQL_TC_ALL:           cout << wxT("DDL & DML");     break;
     }
     cout << endl;
 
     }
     cout << endl;
 
@@ -1058,7 +1593,7 @@ bool wxDb::getDbInfo(void)
 #endif
 
     // Completed Successfully
 #endif
 
     // Completed Successfully
-    return(TRUE);
+    return true;
 
 } // wxDb::getDbInfo()
 
 
 } // wxDb::getDbInfo()
 
@@ -1073,45 +1608,58 @@ bool wxDb::getDataTypeInfo(SWORD fSqlType, wxDbSqlTypeInfo &structSQLTypeInfo)
  * wxDbSqlTypeInfo is a structure that is filled in with data type information,
  */
     RETCODE retcode;
  * wxDbSqlTypeInfo is a structure that is filled in with data type information,
  */
     RETCODE retcode;
-    SDWORD  cbRet;
+    SQLLEN  cbRet;
 
     // Get information about the data type specified
     if (SQLGetTypeInfo(hstmt, fSqlType) != SQL_SUCCESS)
         return(DispAllErrors(henv, hdbc, hstmt));
 
     // Get information about the data type specified
     if (SQLGetTypeInfo(hstmt, fSqlType) != SQL_SUCCESS)
         return(DispAllErrors(henv, hdbc, hstmt));
+
     // Fetch the record
     // Fetch the record
-    if ((retcode = SQLFetch(hstmt)) != SQL_SUCCESS)
+    retcode = SQLFetch(hstmt);
+    if (retcode != SQL_SUCCESS)
     {
 #ifdef DBDEBUG_CONSOLE
         if (retcode == SQL_NO_DATA_FOUND)
     {
 #ifdef DBDEBUG_CONSOLE
         if (retcode == SQL_NO_DATA_FOUND)
-            cout << "SQL_NO_DATA_FOUND fetching inf. about data type." << endl;
+            cout << wxT("SQL_NO_DATA_FOUND fetching information about data type.") << endl;
 #endif
         DispAllErrors(henv, hdbc, hstmt);
         SQLFreeStmt(hstmt, SQL_CLOSE);
 #endif
         DispAllErrors(henv, hdbc, hstmt);
         SQLFreeStmt(hstmt, SQL_CLOSE);
-        return(FALSE);
+        return false;
     }
     }
+
+    wxChar typeName[DB_TYPE_NAME_LEN+1];
+
     // Obtain columns from the record
     // Obtain columns from the record
-    if (SQLGetData(hstmt, 1, SQL_C_CHAR, (UCHAR*) structSQLTypeInfo.TypeName, DB_TYPE_NAME_LEN, &cbRet) != SQL_SUCCESS)
+    if (SQLGetData(hstmt, 1, SQL_C_WXCHAR, typeName, sizeof(typeName), &cbRet) != SQL_SUCCESS)
         return(DispAllErrors(henv, hdbc, hstmt));
 
         return(DispAllErrors(henv, hdbc, hstmt));
 
+    structSQLTypeInfo.TypeName = typeName;
+
     // BJO 20000503: no more needed with new GetColumns...
 #if  OLD_GETCOLUMNS
     // BJO 991209
     if (Dbms() == dbmsMY_SQL)
     {
     // BJO 20000503: no more needed with new GetColumns...
 #if  OLD_GETCOLUMNS
     // BJO 991209
     if (Dbms() == dbmsMY_SQL)
     {
-        if (!wxStrcmp(structSQLTypeInfo.TypeName, "middleint")) wxStrcpy(structSQLTypeInfo.TypeName, "mediumint");
-        if (!wxStrcmp(structSQLTypeInfo.TypeName, "middleint unsigned")) wxStrcpy(structSQLTypeInfo.TypeName, "mediumint unsigned");
-        if (!wxStrcmp(structSQLTypeInfo.TypeName, "integer")) wxStrcpy(structSQLTypeInfo.TypeName, "int");
-        if (!wxStrcmp(structSQLTypeInfo.TypeName, "integer unsigned")) wxStrcpy(structSQLTypeInfo.TypeName, "int unsigned");
-        if (!wxStrcmp(structSQLTypeInfo.TypeName, "middleint")) wxStrcpy(structSQLTypeInfo.TypeName, "mediumint");
-        if (!wxStrcmp(structSQLTypeInfo.TypeName, "varchar")) wxStrcpy(structSQLTypeInfo.TypeName, "char");
+        if (structSQLTypeInfo.TypeName == wxT("middleint"))
+            structSQLTypeInfo.TypeName = wxT("mediumint");
+        else if (structSQLTypeInfo.TypeName == wxT("middleint unsigned"))
+            structSQLTypeInfo.TypeName = wxT("mediumint unsigned");
+        else if (structSQLTypeInfo.TypeName == wxT("integer"))
+            structSQLTypeInfo.TypeName = wxT("int");
+        else if (structSQLTypeInfo.TypeName == wxT("integer unsigned"))
+            structSQLTypeInfo.TypeName = wxT("int unsigned");
+        else if (structSQLTypeInfo.TypeName == wxT("middleint"))
+            structSQLTypeInfo.TypeName = wxT("mediumint");
+        else if (structSQLTypeInfo.TypeName == wxT("varchar"))
+            structSQLTypeInfo.TypeName = wxT("char");
     }
 
     // BJO 20000427 : OpenLink driver
     }
 
     // BJO 20000427 : OpenLink driver
-    if (!wxStrncmp(dbInf.driverName, "oplodbc", 7) ||
-        !wxStrncmp(dbInf.driverName, "OLOD", 4))
+    if (!wxStrncmp(dbInf.driverName, wxT("oplodbc"), 7) ||
+        !wxStrncmp(dbInf.driverName, wxT("OLOD"), 4))
     {
     {
-        if (!wxStrcmp(structSQLTypeInfo.TypeName, "double precision"))
-            wxStrcpy(structSQLTypeInfo.TypeName, "real");
+        if (structSQLTypeInfo.TypeName == wxT("double precision"))
+            structSQLTypeInfo.TypeName = wxT("real");
     }
 #endif
 
     }
 #endif
 
@@ -1133,7 +1681,7 @@ bool wxDb::getDataTypeInfo(SWORD fSqlType, wxDbSqlTypeInfo &structSQLTypeInfo)
         return(DispAllErrors(henv, hdbc, hstmt));
 
     // Completed Successfully
         return(DispAllErrors(henv, hdbc, hstmt));
 
     // Completed Successfully
-    return(TRUE);
+    return true;
 
 } // wxDb::getDataTypeInfo()
 
 
 } // wxDb::getDataTypeInfo()
 
@@ -1164,33 +1712,33 @@ void wxDb::Close(void)
         DispAllErrors(henv, hdbc);
 
     // There should be zero Ctable objects still connected to this db object
         DispAllErrors(henv, hdbc);
 
     // There should be zero Ctable objects still connected to this db object
-    assert(nTables == 0);
+    wxASSERT(nTables == 0);
 
 #ifdef __WXDEBUG__
     wxTablesInUse *tiu;
 
 #ifdef __WXDEBUG__
     wxTablesInUse *tiu;
-    wxNode *pNode;
-    pNode = TablesInUse.First();
+    wxList::compatibility_iterator pNode;
+    pNode = TablesInUse.GetFirst();
     wxString s,s2;
     while (pNode)
     {
     wxString s,s2;
     while (pNode)
     {
-        tiu = (wxTablesInUse *)pNode->Data();
+        tiu = (wxTablesInUse *)pNode->GetData();
         if (tiu->pDb == this)
         {
         if (tiu->pDb == this)
         {
-            s.sprintf(wxT("(%-20s)     tableID:[%6lu]     pDb:[%p]"), tiu->tableName,tiu->tableID,tiu->pDb);
-            s2.sprintf(wxT("Orphaned found using pDb:[%p]"),this);
-            wxLogDebug (s.c_str(),s2.c_str());
+            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());
         }
         }
-        pNode = pNode->Next();
+        pNode = pNode->GetNext();
     }
 #endif
 
     // Copy the error messages to a global variable
     int i;
     for (i = 0; i < DB_MAX_ERROR_HISTORY; i++)
     }
 #endif
 
     // Copy the error messages to a global variable
     int i;
     for (i = 0; i < DB_MAX_ERROR_HISTORY; i++)
-        wxStrcpy(DBerrorList[i],errorList[i]);
+        wxStrcpy(DBerrorList[i], errorList[i]);
 
 
-    dbmsType   = dbmsUNIDENTIFIED;
-    dbIsOpen = FALSE;
+    dbmsType = dbmsUNIDENTIFIED;
+    dbIsOpen = false;
 
 } // wxDb::Close()
 
 
 } // wxDb::Close()
 
@@ -1206,7 +1754,7 @@ bool wxDb::CommitTrans(void)
     }
 
     // Completed successfully
     }
 
     // Completed successfully
-    return(TRUE);
+    return true;
 
 } // wxDb::CommitTrans()
 
 
 } // wxDb::CommitTrans()
 
@@ -1219,7 +1767,7 @@ bool wxDb::RollbackTrans(void)
         return(DispAllErrors(henv, hdbc));
 
     // Completed successfully
         return(DispAllErrors(henv, hdbc));
 
     // Completed successfully
-    return(TRUE);
+    return true;
 
 } // wxDb::RollbackTrans()
 
 
 } // wxDb::RollbackTrans()
 
@@ -1229,40 +1777,40 @@ bool wxDb::DispAllErrors(HENV aHenv, HDBC aHdbc, HSTMT aHstmt)
 /*
  * This function is called internally whenever an error condition prevents the user's
  * request from being executed.  This function will query the datasource as to the
 /*
  * This function is called internally whenever an error condition prevents the user's
  * request from being executed.  This function will query the datasource as to the
- * actual error(s) that just occured on the previous request of the datasource.
+ * actual error(s) that just occurred on the previous request of the datasource.
  *
  * The function will retrieve each error condition from the datasource and
  *
  * The function will retrieve each error condition from the datasource and
- * sprintf the codes/text values into a string which it then logs via logError().
+ * Printf the codes/text values into a string which it then logs via logError().
  * If in DBDEBUG_CONSOLE mode, the constructed string will be displayed in the console
  * window and program execution will be paused until the user presses a key.
  *
  * If in DBDEBUG_CONSOLE mode, the constructed string will be displayed in the console
  * window and program execution will be paused until the user presses a key.
  *
- * This function always returns a FALSE, so that functions which call this function
+ * This function always returns false, so that functions which call this function
  * can have a line like "return (DispAllErrors(henv, hdbc));" to indicate the failure
  * can have a line like "return (DispAllErrors(henv, hdbc));" to indicate the failure
- * of the users request, so that the calling code can then process the error msg log
+ * of the user's request, so that the calling code can then process the error message log.
  */
 {
     wxString odbcErrMsg;
 
  */
 {
     wxString odbcErrMsg;
 
-    while (SQLError(aHenv, aHdbc, aHstmt, (UCHAR FAR *) sqlState, &nativeError, (UCHAR FAR *) errorMsg, SQL_MAX_MESSAGE_LENGTH - 1, &cbErrorMsg) == SQL_SUCCESS)
-    {
-        odbcErrMsg.sprintf("SQL State = %s\nNative Error Code = %li\nError Message = %s\n", sqlState, nativeError, errorMsg);
-        logError(odbcErrMsg.c_str(), sqlState);
+   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);
+        logError(odbcErrMsg, sqlState);
         if (!silent)
         {
 #ifdef DBDEBUG_CONSOLE
             // When run in console mode, use standard out to display errors.
             cout << odbcErrMsg.c_str() << endl;
         if (!silent)
         {
 #ifdef DBDEBUG_CONSOLE
             // When run in console mode, use standard out to display errors.
             cout << odbcErrMsg.c_str() << endl;
-            cout << "Press any key to continue..." << endl;
+            cout << wxT("Press any key to continue...") << endl;
             getchar();
 #endif
 
 #ifdef __WXDEBUG__
             getchar();
 #endif
 
 #ifdef __WXDEBUG__
-            wxLogDebug(odbcErrMsg.c_str(),wxT("ODBC DEBUG MESSAGE from DispAllErrors()"));
+            wxLogDebug(odbcErrMsg,wxT("ODBC DEBUG MESSAGE from DispAllErrors()"));
 #endif
         }
     }
 
 #endif
         }
     }
 
-    return(FALSE);  // This function always returns false.
+    return false;  // This function always returns false.
 
 } // wxDb::DispAllErrors()
 
 
 } // wxDb::DispAllErrors()
 
@@ -1270,10 +1818,10 @@ bool wxDb::DispAllErrors(HENV aHenv, HDBC aHdbc, HSTMT aHstmt)
 /********** wxDb::GetNextError() **********/
 bool wxDb::GetNextError(HENV aHenv, HDBC aHdbc, HSTMT aHstmt)
 {
 /********** wxDb::GetNextError() **********/
 bool wxDb::GetNextError(HENV aHenv, HDBC aHdbc, HSTMT aHstmt)
 {
-    if (SQLError(aHenv, aHdbc, aHstmt, (UCHAR FAR *) sqlState, &nativeError, (UCHAR FAR *) errorMsg, SQL_MAX_MESSAGE_LENGTH - 1, &cbErrorMsg) == SQL_SUCCESS)
-        return(TRUE);
+   if (SQLError(aHenv, aHdbc, aHstmt, (SQLTCHAR FAR *) sqlState, &nativeError, (SQLTCHAR FAR *) errorMsg, SQL_MAX_MESSAGE_LENGTH - 1, &cbErrorMsg) == SQL_SUCCESS)
+     return true;
     else
     else
-        return(FALSE);
+        return false;
 
 } // wxDb::GetNextError()
 
 
 } // wxDb::GetNextError()
 
@@ -1283,8 +1831,8 @@ void wxDb::DispNextError(void)
 {
     wxString odbcErrMsg;
 
 {
     wxString odbcErrMsg;
 
-    odbcErrMsg.sprintf("SQL State = %s\nNative Error Code = %li\nError Message = %s\n", sqlState, nativeError, errorMsg);
-    logError(odbcErrMsg.c_str(), sqlState);
+    odbcErrMsg.Printf(wxT("SQL State = %s\nNative Error Code = %li\nError Message = %s\n"), sqlState, nativeError, errorMsg);
+    logError(odbcErrMsg, sqlState);
 
     if (silent)
         return;
 
     if (silent)
         return;
@@ -1292,7 +1840,7 @@ void wxDb::DispNextError(void)
 #ifdef DBDEBUG_CONSOLE
     // When run in console mode, use standard out to display errors.
     cout << odbcErrMsg.c_str() << endl;
 #ifdef DBDEBUG_CONSOLE
     // When run in console mode, use standard out to display errors.
     cout << odbcErrMsg.c_str() << endl;
-    cout << "Press any key to continue..."  << endl;
+    cout << wxT("Press any key to continue...")  << endl;
     getchar();
 #endif
 
     getchar();
 #endif
 
@@ -1304,9 +1852,9 @@ void wxDb::DispNextError(void)
 
 
 /********** wxDb::logError() **********/
 
 
 /********** wxDb::logError() **********/
-void wxDb::logError(const char *errMsg, const char *SQLState)
+void wxDb::logError(const wxString &errMsg, const wxString &SQLState)
 {
 {
-    assert(errMsg && wxStrlen(errMsg));
+    wxASSERT(errMsg.Length());
 
     static int pLast = -1;
     int dbStatus;
 
     static int pLast = -1;
     int dbStatus;
@@ -1314,14 +1862,15 @@ void wxDb::logError(const char *errMsg, const char *SQLState)
     if (++pLast == DB_MAX_ERROR_HISTORY)
     {
         int i;
     if (++pLast == DB_MAX_ERROR_HISTORY)
     {
         int i;
-        for (i = 0; i < DB_MAX_ERROR_HISTORY; i++)
+        for (i = 0; i < DB_MAX_ERROR_HISTORY-1; i++)
             wxStrcpy(errorList[i], errorList[i+1]);
         pLast--;
     }
 
             wxStrcpy(errorList[i], errorList[i+1]);
         pLast--;
     }
 
-    wxStrcpy(errorList[pLast], errMsg);
+    wxStrncpy(errorList[pLast], errMsg, DB_MAX_ERROR_MSG_LEN);
+    errorList[pLast][DB_MAX_ERROR_MSG_LEN] = 0;
 
 
-    if (SQLState && wxStrlen(SQLState))
+    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;
 
@@ -1332,7 +1881,7 @@ void wxDb::logError(const char *errMsg, const char *SQLState)
 
 
 /**********wxDb::TranslateSqlState()  **********/
 
 
 /**********wxDb::TranslateSqlState()  **********/
-int wxDb::TranslateSqlState(const wxChar *SQLState)
+int wxDb::TranslateSqlState(const wxString &SQLState)
 {
     if (!wxStrcmp(SQLState, wxT("01000")))
         return(DB_ERR_GENERAL_WARNING);
 {
     if (!wxStrcmp(SQLState, wxT("01000")))
         return(DB_ERR_GENERAL_WARNING);
@@ -1520,113 +2069,113 @@ int wxDb::TranslateSqlState(const wxChar *SQLState)
 
 
 /**********  wxDb::Grant() **********/
 
 
 /**********  wxDb::Grant() **********/
-bool wxDb::Grant(int privileges, const char *tableName, const char *userList)
+bool wxDb::Grant(int privileges, const wxString &tableName, const wxString &userList)
 {
     wxString sqlStmt;
 
     // Build the grant statement
 {
     wxString sqlStmt;
 
     // Build the grant statement
-    sqlStmt  = "GRANT ";
+    sqlStmt  = wxT("GRANT ");
     if (privileges == DB_GRANT_ALL)
     if (privileges == DB_GRANT_ALL)
-        sqlStmt += "ALL";
+        sqlStmt += wxT("ALL");
     else
     {
         int c = 0;
         if (privileges & DB_GRANT_SELECT)
         {
     else
     {
         int c = 0;
         if (privileges & DB_GRANT_SELECT)
         {
-            sqlStmt += "SELECT";
+            sqlStmt += wxT("SELECT");
             c++;
         }
         if (privileges & DB_GRANT_INSERT)
         {
             if (c++)
             c++;
         }
         if (privileges & DB_GRANT_INSERT)
         {
             if (c++)
-                sqlStmt += ", ";
-            sqlStmt += "INSERT";
+                sqlStmt += wxT(", ");
+            sqlStmt += wxT("INSERT");
         }
         if (privileges & DB_GRANT_UPDATE)
         {
             if (c++)
         }
         if (privileges & DB_GRANT_UPDATE)
         {
             if (c++)
-                sqlStmt += ", ";
-            sqlStmt += "UPDATE";
+                sqlStmt += wxT(", ");
+            sqlStmt += wxT("UPDATE");
         }
         if (privileges & DB_GRANT_DELETE)
         {
             if (c++)
         }
         if (privileges & DB_GRANT_DELETE)
         {
             if (c++)
-                sqlStmt += ", ";
-            sqlStmt += "DELETE";
+                sqlStmt += wxT(", ");
+            sqlStmt += wxT("DELETE");
         }
     }
 
         }
     }
 
-    sqlStmt += " ON ";
-    sqlStmt += tableName;
-    sqlStmt += " TO ";
+    sqlStmt += wxT(" ON ");
+    sqlStmt += SQLTableName(tableName);
+    sqlStmt += wxT(" TO ");
     sqlStmt += userList;
 
 #ifdef DBDEBUG_CONSOLE
     cout << endl << sqlStmt.c_str() << endl;
 #endif
 
     sqlStmt += userList;
 
 #ifdef DBDEBUG_CONSOLE
     cout << endl << sqlStmt.c_str() << endl;
 #endif
 
-    WriteSqlLog(sqlStmt.c_str());
+    WriteSqlLog(sqlStmt);
 
 
-    return(ExecSql(sqlStmt.c_str()));
+    return(ExecSql(sqlStmt));
 
 }  // wxDb::Grant()
 
 
 /********** wxDb::CreateView() **********/
 
 }  // wxDb::Grant()
 
 
 /********** wxDb::CreateView() **********/
-bool wxDb::CreateView(const char *viewName, const char *colList, const char *pSqlStmt, bool attemptDrop)
+bool wxDb::CreateView(const wxString &viewName, const wxString &colList,
+                      const wxString &pSqlStmt, bool attemptDrop)
 {
     wxString sqlStmt;
 
     // Drop the view first
     if (attemptDrop && !DropView(viewName))
 {
     wxString sqlStmt;
 
     // Drop the view first
     if (attemptDrop && !DropView(viewName))
-        return FALSE;
+        return false;
 
     // Build the create view statement
 
     // Build the create view statement
-    sqlStmt  = "CREATE VIEW ";
+    sqlStmt  = wxT("CREATE VIEW ");
     sqlStmt += viewName;
 
     sqlStmt += viewName;
 
-    if (wxStrlen(colList))
+    if (colList.Length())
     {
     {
-        sqlStmt += " (";
+        sqlStmt += wxT(" (");
         sqlStmt += colList;
         sqlStmt += colList;
-        sqlStmt += ")";
+        sqlStmt += wxT(")");
     }
 
     }
 
-    sqlStmt += " AS ";
+    sqlStmt += wxT(" AS ");
     sqlStmt += pSqlStmt;
 
     sqlStmt += pSqlStmt;
 
-    WriteSqlLog(sqlStmt.c_str());
+    WriteSqlLog(sqlStmt);
 
 #ifdef DBDEBUG_CONSOLE
     cout << sqlStmt.c_str() << endl;
 #endif
 
 
 #ifdef DBDEBUG_CONSOLE
     cout << sqlStmt.c_str() << endl;
 #endif
 
-    return(ExecSql(sqlStmt.c_str()));
+    return(ExecSql(sqlStmt));
 
 }  // wxDb::CreateView()
 
 
 /********** wxDb::DropView()  **********/
 
 }  // wxDb::CreateView()
 
 
 /********** wxDb::DropView()  **********/
-bool wxDb::DropView(const char *viewName)
+bool wxDb::DropView(const wxString &viewName)
 {
 /*
 {
 /*
- * NOTE: This function returns TRUE if the View does not exist, but
+ * NOTE: This function returns true if the View does not exist, but
  *       only for identified databases.  Code will need to be added
  *            below for any other databases when those databases are defined
  *       to handle this situation consistently
  */
  *       only for identified databases.  Code will need to be added
  *            below for any other databases when those databases are defined
  *       to handle this situation consistently
  */
-//    char sqlStmt[DB_MAX_STATEMENT_LEN];
     wxString sqlStmt;
 
     wxString sqlStmt;
 
-    sqlStmt.sprintf("DROP VIEW %s", viewName);
+    sqlStmt.Printf(wxT("DROP VIEW %s"), viewName.c_str());
 
 
-    WriteSqlLog(sqlStmt.c_str());
+    WriteSqlLog(sqlStmt);
 
 #ifdef DBDEBUG_CONSOLE
     cout << endl << sqlStmt.c_str() << endl;
 #endif
 
 
 #ifdef DBDEBUG_CONSOLE
     cout << endl << sqlStmt.c_str() << endl;
 #endif
 
-    if (SQLExecDirect(hstmt, (UCHAR FAR *) sqlStmt.c_str(), SQL_NTS) != SQL_SUCCESS)
+    if (SQLExecDirect(hstmt, (SQLTCHAR FAR *) sqlStmt.c_str(), 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);
@@ -1638,99 +2187,206 @@ bool wxDb::DropView(const char *viewName)
                 DispNextError();
                 DispAllErrors(henv, hdbc, hstmt);
                 RollbackTrans();
                 DispNextError();
                 DispAllErrors(henv, hdbc, hstmt);
                 RollbackTrans();
-                return(FALSE);
+                return false;
             }
         }
     }
 
     // Commit the transaction
             }
         }
     }
 
     // Commit the transaction
-    if (! CommitTrans())
-        return(FALSE);
+    if (!CommitTrans())
+        return false;
 
 
-    return TRUE;
+    return true;
 
 }  // wxDb::DropView()
 
 
 /********** wxDb::ExecSql()  **********/
 
 }  // wxDb::DropView()
 
 
 /********** wxDb::ExecSql()  **********/
-bool wxDb::ExecSql(const char *pSqlStmt)
+bool wxDb::ExecSql(const wxString &pSqlStmt)
 {
 {
+    RETCODE retcode;
+
     SQLFreeStmt(hstmt, SQL_CLOSE);
     SQLFreeStmt(hstmt, SQL_CLOSE);
-    if (SQLExecDirect(hstmt, (UCHAR FAR *) pSqlStmt, SQL_NTS) == SQL_SUCCESS)
-        return(TRUE);
+
+    retcode = SQLExecDirect(hstmt, (SQLTCHAR FAR *) pSqlStmt.c_str(), SQL_NTS);
+    if (retcode == SQL_SUCCESS ||
+        (Dbms() == dbmsDB2 && (retcode == SQL_SUCCESS_WITH_INFO || retcode == SQL_NO_DATA_FOUND)))
+    {
+        return true;
+    }
     else
     {
         DispAllErrors(henv, hdbc, hstmt);
     else
     {
         DispAllErrors(henv, hdbc, hstmt);
-        return(FALSE);
+        return false;
     }
 
 }  // wxDb::ExecSql()
 
 
     }
 
 }  // wxDb::ExecSql()
 
 
+/********** wxDb::ExecSql() with column info **********/
+bool wxDb::ExecSql(const wxString &pSqlStmt, wxDbColInf** columns, short& numcols)
+{
+    //execute the statement first
+    if (!ExecSql(pSqlStmt))
+        return false;
+
+    SWORD noCols;
+    if (SQLNumResultCols(hstmt, &noCols) != SQL_SUCCESS)
+    {
+        DispAllErrors(henv, hdbc, hstmt);
+        return false;
+    }
+
+    if (noCols == 0)
+        return false;
+    else
+        numcols = noCols;
+
+    //  Get column information
+    short colNum;
+    wxChar name[DB_MAX_COLUMN_NAME_LEN+1];
+    SWORD Sword;
+    SQLLEN Sqllen;
+    wxDbColInf* pColInf = new wxDbColInf[noCols];
+
+    // Fill in column information (name, datatype)
+    for (colNum = 0; colNum < noCols; colNum++)
+    {
+        if (SQLColAttributes(hstmt, (UWORD)(colNum+1), SQL_COLUMN_NAME,
+            name, sizeof(name),
+            &Sword, &Sqllen) != SQL_SUCCESS)
+        {
+            DispAllErrors(henv, hdbc, hstmt);
+            delete[] pColInf;
+            return false;
+        }
+
+        wxStrncpy(pColInf[colNum].colName, name, DB_MAX_COLUMN_NAME_LEN);
+        pColInf[colNum].colName[DB_MAX_COLUMN_NAME_LEN] = 0;  // Prevent buffer overrun
+
+        if (SQLColAttributes(hstmt, (UWORD)(colNum+1), SQL_COLUMN_TYPE,
+            NULL, 0, &Sword, &Sqllen) != SQL_SUCCESS)
+        {
+            DispAllErrors(henv, hdbc, hstmt);
+            delete[] pColInf;
+            return false;
+        }
+
+        switch (Sqllen)
+        {
+#if wxUSE_UNICODE
+    #if defined(SQL_WCHAR)
+            case SQL_WCHAR:
+    #endif
+    #if defined(SQL_WVARCHAR)
+            case SQL_WVARCHAR:
+    #endif
+#endif
+            case SQL_VARCHAR:
+            case SQL_CHAR:
+                pColInf[colNum].dbDataType = DB_DATA_TYPE_VARCHAR;
+                break;
+            case SQL_TINYINT:
+            case SQL_SMALLINT:
+            case SQL_INTEGER:
+            case SQL_BIT:
+                pColInf[colNum].dbDataType = DB_DATA_TYPE_INTEGER;
+                break;
+            case SQL_DOUBLE:
+            case SQL_DECIMAL:
+            case SQL_NUMERIC:
+            case SQL_FLOAT:
+            case SQL_REAL:
+                pColInf[colNum].dbDataType = DB_DATA_TYPE_FLOAT;
+                break;
+            case SQL_DATE:
+            case SQL_TIMESTAMP:
+                pColInf[colNum].dbDataType = DB_DATA_TYPE_DATE;
+                break;
+            case SQL_BINARY:
+                pColInf[colNum].dbDataType = DB_DATA_TYPE_BLOB;
+                break;
+#ifdef __WXDEBUG__
+            default:
+                wxString errMsg;
+                errMsg.Printf(wxT("SQL Data type %ld currently not supported by wxWidgets"), (long)Sqllen);
+                wxLogDebug(errMsg,wxT("ODBC DEBUG MESSAGE"));
+#endif
+        }
+    }
+
+    *columns = pColInf;
+    return true;
+}  // wxDb::ExecSql()
+
 /********** wxDb::GetNext()  **********/
 bool wxDb::GetNext(void)
 {
     if (SQLFetch(hstmt) == SQL_SUCCESS)
 /********** wxDb::GetNext()  **********/
 bool wxDb::GetNext(void)
 {
     if (SQLFetch(hstmt) == SQL_SUCCESS)
-        return(TRUE);
+        return true;
     else
     {
         DispAllErrors(henv, hdbc, hstmt);
     else
     {
         DispAllErrors(henv, hdbc, hstmt);
-        return(FALSE);
+        return false;
     }
 
 }  // wxDb::GetNext()
 
 
 /********** wxDb::GetData()  **********/
     }
 
 }  // wxDb::GetNext()
 
 
 /********** wxDb::GetData()  **********/
-bool wxDb::GetData(UWORD colNo, SWORD cType, PTR pData, SDWORD maxLen, SDWORD FAR *cbReturned)
+bool wxDb::GetData(UWORD colNo, SWORD cType, PTR pData, SDWORD maxLen, SQLLEN FAR *cbReturned)
 {
 {
-    assert(pData);
-    assert(cbReturned);
+    wxASSERT(pData);
+    wxASSERT(cbReturned);
+
+    long bufferSize = maxLen;
+
+    if (cType == SQL_C_WXCHAR)
+        bufferSize = maxLen * sizeof(wxChar);
 
 
-    if (SQLGetData(hstmt, colNo, cType, pData, maxLen, cbReturned) == SQL_SUCCESS)
-        return(TRUE);
+    if (SQLGetData(hstmt, colNo, cType, pData, bufferSize, cbReturned) == SQL_SUCCESS)
+        return true;
     else
     {
         DispAllErrors(henv, hdbc, hstmt);
     else
     {
         DispAllErrors(henv, hdbc, hstmt);
-        return(FALSE);
+        return false;
     }
 
 }  // wxDb::GetData()
 
 
 /********** wxDb::GetKeyFields() **********/
     }
 
 }  // wxDb::GetData()
 
 
 /********** wxDb::GetKeyFields() **********/
-int wxDb::GetKeyFields(char *tableName, wxDbColInf* colInf, int noCols)
-{
-    char         szPkTable[DB_MAX_TABLE_NAME_LEN+1];  /* Primary key table name */
-    char         szFkTable[DB_MAX_TABLE_NAME_LEN+1];  /* Foreign key table name */
-    short        iKeySeq;
-//    SQLSMALLINT  iKeySeq;
-    char         szPkCol[DB_MAX_COLUMN_NAME_LEN+1];   /* Primary key column     */
-    char         szFkCol[DB_MAX_COLUMN_NAME_LEN+1];   /* Foreign key column     */
+int wxDb::GetKeyFields(const wxString &tableName, wxDbColInf* colInf, UWORD noCols)
+{
+    wxChar       szPkTable[DB_MAX_TABLE_NAME_LEN+1];  /* Primary key table name */
+    wxChar       szFkTable[DB_MAX_TABLE_NAME_LEN+1];  /* Foreign key table name */
+    SWORD        iKeySeq;
+    wxChar       szPkCol[DB_MAX_COLUMN_NAME_LEN+1];   /* Primary key column     */
+    wxChar       szFkCol[DB_MAX_COLUMN_NAME_LEN+1];   /* Foreign key column     */
     SQLRETURN    retcode;
     SQLRETURN    retcode;
-    SDWORD       cb;
-    int          i;
-    wxString     Temp0;
+    SQLLEN       cb;
+    SWORD        i;
+    wxString     tempStr;
     /*
     /*
-     * ---------------------------------------------------------------------
-     * -- 19991224 : mj10777 : Create                         ------
-     * --          : Three things are done and stored here :          ------
-     * --          : 1) which Column(s) is/are Primary Key(s)         ------
-     * --          : 2) which tables use this Key as a Foreign Key    ------
-     * --          : 3) which columns are Foreign Key and the name    ------
-     * --          :     of the Table where the Key is the Primary Key -----
-     * --          : Called from GetColumns(char *tableName,          ------
-     * --                           int *numCols,const char *userID ) ------
-     * ---------------------------------------------------------------------
+     * -----------------------------------------------------------------------
+     * -- 19991224 : mj10777 : Create                                   ------
+     * --          : Three things are done and stored here :            ------
+     * --          : 1) which Column(s) is/are Primary Key(s)           ------
+     * --          : 2) which tables use this Key as a Foreign Key      ------
+     * --          : 3) which columns are Foreign Key and the name      ------
+     * --          :     of the Table where the Key is the Primary Key  -----
+     * --          : Called from GetColumns(const wxString &tableName,  ------
+     * --                           int *numCols,const wxChar *userID ) ------
+     * -----------------------------------------------------------------------
      */
 
     /*---------------------------------------------------------------------*/
     /* Get the names of the columns in the primary key.                    */
     /*---------------------------------------------------------------------*/
     retcode = SQLPrimaryKeys(hstmt,
      */
 
     /*---------------------------------------------------------------------*/
     /* Get the names of the columns in the primary key.                    */
     /*---------------------------------------------------------------------*/
     retcode = SQLPrimaryKeys(hstmt,
-                             NULL, 0,                       /* Catalog name  */
-                             NULL, 0,                       /* Schema name   */
-                             (UCHAR *) tableName, SQL_NTS); /* Table name    */
+                             NULL, 0,                               /* Catalog name  */
+                             NULL, 0,                               /* Schema name   */
+                             (SQLTCHAR FAR *) tableName.c_str(), 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        */
@@ -1741,7 +2397,7 @@ int wxDb::GetKeyFields(char *tableName, wxDbColInf* colInf, int noCols)
         retcode = SQLFetch(hstmt);
         if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
         {
         retcode = SQLFetch(hstmt);
         if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
         {
-            GetData( 4, SQL_C_CHAR,   szPkCol,     DB_MAX_COLUMN_NAME_LEN+1, &cb);
+            GetData( 4, SQL_C_WXCHAR,  szPkCol,    DB_MAX_COLUMN_NAME_LEN+1, &cb);
             GetData( 5, SQL_C_SSHORT, &iKeySeq,    0,                        &cb);
             //-------
             for (i=0;i<noCols;i++)                          // Find the Column name
             GetData( 5, SQL_C_SSHORT, &iKeySeq,    0,                        &cb);
             //-------
             for (i=0;i<noCols;i++)                          // Find the Column name
@@ -1755,75 +2411,80 @@ int wxDb::GetKeyFields(char *tableName, wxDbColInf* colInf, int noCols)
     /* Get all the foreign keys that refer to tableName primary key.       */
     /*---------------------------------------------------------------------*/
     retcode = SQLForeignKeys(hstmt,
     /* Get all the foreign keys that refer to tableName primary key.       */
     /*---------------------------------------------------------------------*/
     retcode = SQLForeignKeys(hstmt,
-                             NULL, 0,                       /* Primary catalog */
-                             NULL, 0,                       /* Primary schema  */
-                             (UCHAR *)tableName, SQL_NTS,   /* Primary table   */
-                             NULL, 0,                       /* Foreign catalog */
-                             NULL, 0,                       /* Foreign schema  */
-                             NULL, 0);                      /* Foreign table   */
+                             NULL, 0,                            /* Primary catalog */
+                             NULL, 0,                            /* Primary schema  */
+                             (SQLTCHAR FAR *)tableName.c_str(), SQL_NTS,/* Primary table   */
+                             NULL, 0,                            /* Foreign catalog */
+                             NULL, 0,                            /* Foreign schema  */
+                             NULL, 0);                           /* Foreign table   */
 
     /*---------------------------------------------------------------------*/
     /* Fetch and display the result set. This will be all of the foreign   */
     /* keys in other tables that refer to the tableName  primary key.      */
     /*---------------------------------------------------------------------*/
 
     /*---------------------------------------------------------------------*/
     /* Fetch and display the result set. This will be all of the foreign   */
     /* keys in other tables that refer to the tableName  primary key.      */
     /*---------------------------------------------------------------------*/
-    Temp0.Empty();
+    tempStr.Empty();
     szPkCol[0] = 0;
     while ((retcode == SQL_SUCCESS) || (retcode == SQL_SUCCESS_WITH_INFO))
     {
         retcode = SQLFetch(hstmt);
         if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
         {
     szPkCol[0] = 0;
     while ((retcode == SQL_SUCCESS) || (retcode == SQL_SUCCESS_WITH_INFO))
     {
         retcode = SQLFetch(hstmt);
         if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
         {
-            GetData( 3, SQL_C_CHAR,   szPkTable,   DB_MAX_TABLE_NAME_LEN+1,  &cb);
-            GetData( 4, SQL_C_CHAR,   szPkCol,     DB_MAX_COLUMN_NAME_LEN+1, &cb);
-            GetData( 5, SQL_C_SSHORT, &iKeySeq,    0,                        &cb);
-            GetData( 7, SQL_C_CHAR,   szFkTable,   DB_MAX_TABLE_NAME_LEN+1,  &cb);
-            GetData( 8, SQL_C_CHAR,   szFkCol,     DB_MAX_COLUMN_NAME_LEN+1, &cb);
-            Temp0.Printf(wxT("%s[%s] "),Temp0.c_str(),szFkTable);  // [ ] in case there is a blank in the Table name
+            GetData( 3, SQL_C_WXCHAR,  szPkTable,   DB_MAX_TABLE_NAME_LEN+1,   &cb);
+            GetData( 4, SQL_C_WXCHAR,  szPkCol,     DB_MAX_COLUMN_NAME_LEN+1,  &cb);
+            GetData( 5, SQL_C_SSHORT, &iKeySeq,     0,                         &cb);
+            GetData( 7, SQL_C_WXCHAR,  szFkTable,   DB_MAX_TABLE_NAME_LEN+1,   &cb);
+            GetData( 8, SQL_C_WXCHAR,  szFkCol,     DB_MAX_COLUMN_NAME_LEN+1,  &cb);
+            tempStr << _T('[') << szFkTable << _T(']');  // [ ] in case there is a blank in the Table name
         }  // if
     }  // while
         }  // if
     }  // while
-    Temp0.Trim();     // Get rid of any unneeded blanks
-    if (Temp0 != wxT(""))
+
+    tempStr.Trim();     // Get rid of any unneeded blanks
+    if (!tempStr.empty())
     {
     {
-        for (i=0;i<noCols;i++)
+        for (i=0; i<noCols; i++)
         {   // Find the Column name
         {   // Find the Column name
-            if (!wxStrcmp(colInf[i].colName,szPkCol))           // We have found the Column, store the Information
-                wxStrcpy(colInf[i].PkTableName,Temp0.c_str());  // Name of the Tables where this Primary Key is used as a Foreign Key
+            if (!wxStrcmp(colInf[i].colName, szPkCol))           // We have found the Column, store the Information
+            {
+                wxStrncpy(colInf[i].PkTableName, tempStr.c_str(), DB_MAX_TABLE_NAME_LEN);  // Name of the Tables where this Primary Key is used as a Foreign Key
+                colInf[i].PkTableName[DB_MAX_TABLE_NAME_LEN] = 0;  // Prevent buffer overrun
+            }
         }
     }  // if
         }
     }  // if
+
     SQLFreeStmt(hstmt, SQL_CLOSE);  /* Close the cursor (the hstmt is still allocated). */
 
     /*---------------------------------------------------------------------*/
     /* Get all the foreign keys in the tablename table.                    */
     /*---------------------------------------------------------------------*/
     retcode = SQLForeignKeys(hstmt,
     SQLFreeStmt(hstmt, SQL_CLOSE);  /* Close the cursor (the hstmt is still allocated). */
 
     /*---------------------------------------------------------------------*/
     /* Get all the foreign keys in the tablename table.                    */
     /*---------------------------------------------------------------------*/
     retcode = SQLForeignKeys(hstmt,
-                             NULL, 0,                        /* Primary catalog   */
-                             NULL, 0,                        /* Primary schema    */
-                             NULL, 0,                        /* Primary table     */
-                             NULL, 0,                        /* Foreign catalog   */
-                             NULL, 0,                        /* Foreign schema    */
-                             (UCHAR *)tableName, SQL_NTS);   /* Foreign table     */
+                             NULL, 0,                             /* Primary catalog   */
+                             NULL, 0,                             /* Primary schema    */
+                             NULL, 0,                             /* Primary table     */
+                             NULL, 0,                             /* Foreign catalog   */
+                             NULL, 0,                             /* Foreign schema    */
+                             (SQLTCHAR *)tableName.c_str(), SQL_NTS);/* Foreign table     */
 
     /*---------------------------------------------------------------------*/
     /*  Fetch and display the result set. This will be all of the          */
     /*  primary keys in other tables that are referred to by foreign       */
     /*  keys in the tableName table.                                       */
     /*---------------------------------------------------------------------*/
 
     /*---------------------------------------------------------------------*/
     /*  Fetch and display the result set. This will be all of the          */
     /*  primary keys in other tables that are referred to by foreign       */
     /*  keys in the tableName table.                                       */
     /*---------------------------------------------------------------------*/
-    i = 0;
     while ((retcode == SQL_SUCCESS) || (retcode == SQL_SUCCESS_WITH_INFO))
     {
         retcode = SQLFetch(hstmt);
         if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
         {
     while ((retcode == SQL_SUCCESS) || (retcode == SQL_SUCCESS_WITH_INFO))
     {
         retcode = SQLFetch(hstmt);
         if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
         {
-            GetData( 3, SQL_C_CHAR,   szPkTable,   DB_MAX_TABLE_NAME_LEN+1,  &cb);
-            GetData( 5, SQL_C_SSHORT, &iKeySeq,    0,                        &cb);
-            GetData( 8, SQL_C_CHAR,   szFkCol,     DB_MAX_COLUMN_NAME_LEN+1, &cb);
+            GetData( 3, SQL_C_WXCHAR,  szPkTable,   DB_MAX_TABLE_NAME_LEN+1,  &cb);
+            GetData( 5, SQL_C_SSHORT, &iKeySeq,     0,                        &cb);
+            GetData( 8, SQL_C_WXCHAR,  szFkCol,     DB_MAX_COLUMN_NAME_LEN+1, &cb);
             //-------
             //-------
-            for (i=0;i<noCols;i++)                              // Find the Column name
+            for (i=0; i<noCols; i++)                            // Find the Column name
             {
                 if (!wxStrcmp(colInf[i].colName,szFkCol))       // We have found the (Foreign Key) Column
                 {
                     colInf[i].FkCol = iKeySeq;                  // Which Foreign Key is this (first, second usw.) ?
             {
                 if (!wxStrcmp(colInf[i].colName,szFkCol))       // We have found the (Foreign Key) Column
                 {
                     colInf[i].FkCol = iKeySeq;                  // Which Foreign Key is this (first, second usw.) ?
-                    wxStrcpy(colInf[i].FkTableName,szPkTable);  // Name of the Table where this Foriegn is the Primary Key
+                    wxStrncpy(colInf[i].FkTableName, szFkTable, DB_MAX_TABLE_NAME_LEN);  // Name of the Table where this Foriegn is the Primary Key
+                    colInf[i].FkTableName[DB_MAX_TABLE_NAME_LEN] = 0;  // Prevent buffer overrun
                 } // if
             }  // for
         }  // if
                 } // if
             }  // for
         }  // if
@@ -1837,12 +2498,12 @@ int wxDb::GetKeyFields(char *tableName, wxDbColInf* colInf, int noCols)
 
 #if OLD_GETCOLUMNS
 /********** wxDb::GetColumns() **********/
 
 #if OLD_GETCOLUMNS
 /********** wxDb::GetColumns() **********/
-wxDbColInf *wxDb::GetColumns(char *tableName[], const char *userID)
+wxDbColInf *wxDb::GetColumns(wxChar *tableName[], const wxChar *userID)
 /*
  *        1) The last array element of the tableName[] argument must be zero (null).
  *            This is how the end of the array is detected.
  *        2) This function returns an array of wxDbColInf structures.  If no columns
 /*
  *        1) The last array element of the tableName[] argument must be zero (null).
  *            This is how the end of the array is detected.
  *        2) This function returns an array of wxDbColInf structures.  If no columns
- *            were found, or an error occured, this pointer will be zero (null).  THE
+ *            were found, or an error occurred, this pointer will be zero (null).  THE
  *            CALLING FUNCTION IS RESPONSIBLE FOR DELETING THE MEMORY RETURNED WHEN IT
  *            IS FINISHED WITH IT.  i.e.
  *
  *            CALLING FUNCTION IS RESPONSIBLE FOR DELETING THE MEMORY RETURNED WHEN IT
  *            IS FINISHED WITH IT.  i.e.
  *
@@ -1865,34 +2526,17 @@ wxDbColInf *wxDb::GetColumns(char *tableName[], const char *userID)
  *       to avoid undesired unbinding of columns.
  */
 {
  *       to avoid undesired unbinding of columns.
  */
 {
-    int      noCols = 0;
-    int      colNo  = 0;
+    UWORD       noCols = 0;
+    UWORD       colNo  = 0;
     wxDbColInf *colInf = 0;
 
     RETCODE  retcode;
     wxDbColInf *colInf = 0;
 
     RETCODE  retcode;
-    SDWORD   cb;
+    SQLLEN   cb;
 
 
-    wxString UserID;
     wxString TableName;
 
     wxString TableName;
 
-    if (userID)
-    {
-        if (!wxStrlen(userID))
-            UserID = uid;
-        else
-            UserID = userID;
-    }
-    else
-        UserID = "";
-
-    // dBase does not use user names, and some drivers fail if you try to pass one
-    if (Dbms() == dbmsDBASE)
-        UserID = "";
-
-    // Oracle and Interbase user names may only be in uppercase, so force
-    // the name to uppercase
-    if (Dbms() == dbmsORACLE)
-        UserID = UserID.Upper();
+    wxString UserID;
+    convertUserID(userID,UserID);
 
     // Pass 1 - Determine how many columns there are.
     // Pass 2 - Allocate the wxDbColInf array and fill in
 
     // Pass 1 - Determine how many columns there are.
     // Pass 2 - Allocate the wxDbColInf array and fill in
@@ -1909,8 +2553,8 @@ wxDbColInf *wxDb::GetColumns(char *tableName[], const char *userID)
             if (!colInf)
                 break;
             // Mark the end of the array
             if (!colInf)
                 break;
             // Mark the end of the array
-            wxStrcpy(colInf[noCols].tableName, wxT(""));
-            wxStrcpy(colInf[noCols].colName, wxT(""));
+            wxStrcpy(colInf[noCols].tableName, wxEmptyString);
+            wxStrcpy(colInf[noCols].colName, wxEmptyString);
             colInf[noCols].sqlDataType = 0;
         }
         // Loop through each table name
             colInf[noCols].sqlDataType = 0;
         }
         // Loop through each table name
@@ -1921,6 +2565,7 @@ wxDbColInf *wxDb::GetColumns(char *tableName[], const char *userID)
             // Oracle and Interbase table names are uppercase only, so force
             // the name to uppercase just in case programmer forgot to do this
             if ((Dbms() == dbmsORACLE) ||
             // Oracle and Interbase table names are uppercase only, so force
             // the name to uppercase just in case programmer forgot to do this
             if ((Dbms() == dbmsORACLE) ||
+                (Dbms() == dbmsFIREBIRD) ||
                 (Dbms() == dbmsINTERBASE))
                 TableName = TableName.Upper();
 
                 (Dbms() == dbmsINTERBASE))
                 TableName = TableName.Upper();
 
@@ -1928,15 +2573,15 @@ wxDbColInf *wxDb::GetColumns(char *tableName[], const char *userID)
 
             // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we
             // use the call below that leaves out the user name
 
             // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we
             // use the call below that leaves out the user name
-            if (wxStrcmp(UserID.c_str(),wxT("")) &&
-                 Dbms() != dbmsMY_SQL &&
-                 Dbms() != dbmsACCESS &&
-                 Dbms() != dbmsMS_SQL_SERVER)
+            if (!UserID.empty() &&
+                Dbms() != dbmsMY_SQL &&
+                Dbms() != dbmsACCESS &&
+                Dbms() != dbmsMS_SQL_SERVER)
             {
                 retcode = SQLColumns(hstmt,
                                      NULL, 0,                                // All qualifiers
             {
                 retcode = SQLColumns(hstmt,
                                      NULL, 0,                                // All qualifiers
-                                     (UCHAR *) UserID.c_str(), SQL_NTS,    // Owner
-                                     (UCHAR *) TableName.c_str(), SQL_NTS,
+                                     (SQLTCHAR *) UserID.c_str(), SQL_NTS,      // Owner
+                                     (SQLTCHAR *) TableName.c_str(), SQL_NTS,
                                      NULL, 0);                               // All columns
             }
             else
                                      NULL, 0);                               // All columns
             }
             else
@@ -1944,11 +2589,11 @@ wxDbColInf *wxDb::GetColumns(char *tableName[], const char *userID)
                 retcode = SQLColumns(hstmt,
                                      NULL, 0,                                // All qualifiers
                                      NULL, 0,                                // Owner
                 retcode = SQLColumns(hstmt,
                                      NULL, 0,                                // All qualifiers
                                      NULL, 0,                                // Owner
-                                     (UCHAR *) TableName.c_str(), SQL_NTS,
+                                     (SQLTCHAR *) TableName.c_str(), SQL_NTS,
                                      NULL, 0);                               // All columns
             }
             if (retcode != SQL_SUCCESS)
                                      NULL, 0);                               // All columns
             }
             if (retcode != SQL_SUCCESS)
-            {  // Error occured, abort
+            {  // Error occurred, abort
                 DispAllErrors(henv, hdbc, hstmt);
                 if (colInf)
                     delete [] colInf;
                 DispAllErrors(henv, hdbc, hstmt);
                 if (colInf)
                     delete [] colInf;
@@ -1965,47 +2610,48 @@ wxDbColInf *wxDb::GetColumns(char *tableName[], const char *userID)
                     if (colNo < noCols)  // Some extra error checking to prevent memory overwrites
                     {
                         // NOTE: Only the ODBC 1.x fields are retrieved
                     if (colNo < noCols)  // Some extra error checking to prevent memory overwrites
                     {
                         // NOTE: Only the ODBC 1.x fields are retrieved
-                        GetData( 1, SQL_C_CHAR,   (UCHAR*)  colInf[colNo].catalog,      128+1,                    &cb);
-                        GetData( 2, SQL_C_CHAR,   (UCHAR*)  colInf[colNo].schema,       128+1,                    &cb);
-                        GetData( 3, SQL_C_CHAR,   (UCHAR*)  colInf[colNo].tableName,    DB_MAX_TABLE_NAME_LEN+1,  &cb);
-                        GetData( 4, SQL_C_CHAR,   (UCHAR*)  colInf[colNo].colName,      DB_MAX_COLUMN_NAME_LEN+1, &cb);
+                        GetData( 1, SQL_C_WXCHAR, (UCHAR*)  colInf[colNo].catalog,      128+1,                    &cb);
+                        GetData( 2, SQL_C_WXCHAR, (UCHAR*)  colInf[colNo].schema,       128+1,                    &cb);
+                        GetData( 3, SQL_C_WXCHAR, (UCHAR*)  colInf[colNo].tableName,    DB_MAX_TABLE_NAME_LEN+1,  &cb);
+                        GetData( 4, SQL_C_WXCHAR, (UCHAR*)  colInf[colNo].colName,      DB_MAX_COLUMN_NAME_LEN+1, &cb);
                         GetData( 5, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].sqlDataType,  0,                        &cb);
                         GetData( 5, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].sqlDataType,  0,                        &cb);
-                        GetData( 6, SQL_C_CHAR,   (UCHAR*)  colInf[colNo].typeName,     128+1,                    &cb);
-                        GetData( 7, SQL_C_SLONG,  (UCHAR*) &colInf[colNo].columnSize,   0,                        &cb);
-                        GetData( 8, SQL_C_SLONG,  (UCHAR*) &colInf[colNo].bufferLength, 0,                        &cb);
+                        GetData( 6, SQL_C_WXCHAR, (UCHAR*)  colInf[colNo].typeName,     128+1,                    &cb);
+                        GetData( 7, SQL_C_SLONG,  (UCHAR*) &colInf[colNo].columnLength, 0,                        &cb);
+                        GetData( 8, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].bufferSize,   0,                        &cb);
                         GetData( 9, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].decimalDigits,0,                        &cb);
                         GetData(10, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].numPrecRadix, 0,                        &cb);
                         GetData(11, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].nullable,     0,                        &cb);
                         GetData( 9, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].decimalDigits,0,                        &cb);
                         GetData(10, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].numPrecRadix, 0,                        &cb);
                         GetData(11, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].nullable,     0,                        &cb);
-                        GetData(12, SQL_C_CHAR,   (UCHAR*)  colInf[colNo].remarks,      254+1,                    &cb);
+                        GetData(12, SQL_C_WXCHAR, (UCHAR*)  colInf[colNo].remarks,      254+1,                    &cb);
 
                         // Determine the wxDb data type that is used to represent the native data type of this data source
                         colInf[colNo].dbDataType = 0;
                         if (!wxStricmp(typeInfVarchar.TypeName,colInf[colNo].typeName))
                         {
 #ifdef _IODBC_
 
                         // Determine the wxDb data type that is used to represent the native data type of this data source
                         colInf[colNo].dbDataType = 0;
                         if (!wxStricmp(typeInfVarchar.TypeName,colInf[colNo].typeName))
                         {
 #ifdef _IODBC_
-                            // IODBC does not return a correct columnSize, so we set
-                            // columnSize = bufferLength if no column size was returned
-                            // IODBC returns the columnSize in bufferLength.. (bug)
-                            if (colInf[colNo].columnSize < 1)
+                            // IODBC does not return a correct columnLength, so we set
+                            // columnLength = bufferSize if no column length was returned
+                            // IODBC returns the columnLength in bufferSize. (bug)
+                            if (colInf[colNo].columnLength < 1)
                             {
                             {
-                               colInf[colNo].columnSize = colInf[colNo].bufferLength;
+                               colInf[colNo].columnLength = colInf[colNo].bufferSize;
                             }
 #endif
                             colInf[colNo].dbDataType = DB_DATA_TYPE_VARCHAR;
                         }
                             }
 #endif
                             colInf[colNo].dbDataType = DB_DATA_TYPE_VARCHAR;
                         }
-                        else if (!wxStricmp(typeInfInteger.TypeName,colInf[colNo].typeName))
+                        else if (!wxStricmp(typeInfInteger.TypeName, colInf[colNo].typeName))
                             colInf[colNo].dbDataType = DB_DATA_TYPE_INTEGER;
                             colInf[colNo].dbDataType = DB_DATA_TYPE_INTEGER;
-                        else if (!wxStricmp(typeInfFloat.TypeName,colInf[colNo].typeName))
+                        else if (!wxStricmp(typeInfFloat.TypeName, colInf[colNo].typeName))
                             colInf[colNo].dbDataType = DB_DATA_TYPE_FLOAT;
                             colInf[colNo].dbDataType = DB_DATA_TYPE_FLOAT;
-                        else if (!wxStricmp(typeInfDate.TypeName,colInf[colNo].typeName))
+                        else if (!wxStricmp(typeInfDate.TypeName, colInf[colNo].typeName))
                             colInf[colNo].dbDataType = DB_DATA_TYPE_DATE;
                             colInf[colNo].dbDataType = DB_DATA_TYPE_DATE;
-
+                        else if (!wxStricmp(typeInfBlob.TypeName, colInf[colNo].typeName))
+                            colInf[colNo].dbDataType = DB_DATA_TYPE_BLOB;
                         colNo++;
                     }
                 }
             }
             if (retcode != SQL_NO_DATA_FOUND)
                         colNo++;
                     }
                 }
             }
             if (retcode != SQL_NO_DATA_FOUND)
-            {  // Error occured, abort
+            {  // Error occurred, abort
                 DispAllErrors(henv, hdbc, hstmt);
                 if (colInf)
                     delete [] colInf;
                 DispAllErrors(henv, hdbc, hstmt);
                 if (colInf)
                     delete [] colInf;
@@ -2023,7 +2669,7 @@ wxDbColInf *wxDb::GetColumns(char *tableName[], const char *userID)
 
 /********** wxDb::GetColumns() **********/
 
 
 /********** wxDb::GetColumns() **********/
 
-wxDbColInf *wxDb::GetColumns(char *tableName, int *numCols, const char *userID)
+wxDbColInf *wxDb::GetColumns(const wxString &tableName, UWORD *numCols, const wxChar *userID)
 //
 // Same as the above GetColumns() function except this one gets columns
 // only for a single table, and if 'numCols' is not NULL, the number of
 //
 // Same as the above GetColumns() function except this one gets columns
 // only for a single table, and if 'numCols' is not NULL, the number of
@@ -2039,34 +2685,17 @@ wxDbColInf *wxDb::GetColumns(char *tableName, int *numCols, const char *userID)
 //       to avoid undesired unbinding of columns.
 
 {
 //       to avoid undesired unbinding of columns.
 
 {
-    int       noCols = 0;
-    int       colNo  = 0;
+    UWORD       noCols = 0;
+    UWORD       colNo  = 0;
     wxDbColInf *colInf = 0;
 
     RETCODE  retcode;
     wxDbColInf *colInf = 0;
 
     RETCODE  retcode;
-    SDWORD   cb;
+    SQLLEN   cb;
 
 
-    wxString UserID;
     wxString TableName;
 
     wxString TableName;
 
-    if (userID)
-    {
-        if (!wxStrlen(userID))
-            UserID = uid;
-        else
-            UserID = userID;
-    }
-    else
-        UserID = "";
-
-    // dBase does not use user names, and some drivers fail if you try to pass one
-    if (Dbms() == dbmsDBASE)
-        UserID = "";
-
-    // Oracle user names may only be in uppercase, so force
-    // the name to uppercase
-    if (Dbms() == dbmsORACLE)
-        UserID = UserID.Upper();
+    wxString UserID;
+    convertUserID(userID,UserID);
 
     // Pass 1 - Determine how many columns there are.
     // Pass 2 - Allocate the wxDbColInf array and fill in
 
     // Pass 1 - Determine how many columns there are.
     // Pass 2 - Allocate the wxDbColInf array and fill in
@@ -2083,8 +2712,8 @@ wxDbColInf *wxDb::GetColumns(char *tableName, int *numCols, const char *userID)
             if (!colInf)
                 break;
             // Mark the end of the array
             if (!colInf)
                 break;
             // Mark the end of the array
-            wxStrcpy(colInf[noCols].tableName, wxT(""));
-            wxStrcpy(colInf[noCols].colName, wxT(""));
+            wxStrcpy(colInf[noCols].tableName, wxEmptyString);
+            wxStrcpy(colInf[noCols].colName, wxEmptyString);
             colInf[noCols].sqlDataType = 0;
         }
 
             colInf[noCols].sqlDataType = 0;
         }
 
@@ -2092,6 +2721,7 @@ wxDbColInf *wxDb::GetColumns(char *tableName, int *numCols, const char *userID)
         // Oracle and Interbase table names are uppercase only, so force
         // the name to uppercase just in case programmer forgot to do this
         if ((Dbms() == dbmsORACLE) ||
         // Oracle and Interbase table names are uppercase only, so force
         // the name to uppercase just in case programmer forgot to do this
         if ((Dbms() == dbmsORACLE) ||
+            (Dbms() == dbmsFIREBIRD) ||
             (Dbms() == dbmsINTERBASE))
             TableName = TableName.Upper();
 
             (Dbms() == dbmsINTERBASE))
             TableName = TableName.Upper();
 
@@ -2099,15 +2729,15 @@ wxDbColInf *wxDb::GetColumns(char *tableName, int *numCols, const char *userID)
 
         // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we
         // use the call below that leaves out the user name
 
         // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we
         // use the call below that leaves out the user name
-        if (wxStrcmp(UserID.c_str(),wxT("")) &&
-             Dbms() != dbmsMY_SQL &&
-             Dbms() != dbmsACCESS &&
-             Dbms() != dbmsMS_SQL_SERVER)
+        if (!UserID.empty() &&
+            Dbms() != dbmsMY_SQL &&
+            Dbms() != dbmsACCESS &&
+            Dbms() != dbmsMS_SQL_SERVER)
         {
             retcode = SQLColumns(hstmt,
                                  NULL, 0,                                // All qualifiers
         {
             retcode = SQLColumns(hstmt,
                                  NULL, 0,                                // All qualifiers
-                                 (UCHAR *) UserID.c_str(), SQL_NTS,    // Owner
-                                 (UCHAR *) TableName.c_str(), SQL_NTS,
+                                 (SQLTCHAR *) UserID.c_str(), SQL_NTS,    // Owner
+                                 (SQLTCHAR *) TableName.c_str(), SQL_NTS,
                                  NULL, 0);                               // All columns
         }
         else
                                  NULL, 0);                               // All columns
         }
         else
@@ -2115,11 +2745,11 @@ wxDbColInf *wxDb::GetColumns(char *tableName, int *numCols, const char *userID)
             retcode = SQLColumns(hstmt,
                                  NULL, 0,                                 // All qualifiers
                                  NULL, 0,                                 // Owner
             retcode = SQLColumns(hstmt,
                                  NULL, 0,                                 // All qualifiers
                                  NULL, 0,                                 // Owner
-                                 (UCHAR *) TableName.c_str(), SQL_NTS,
+                                 (SQLTCHAR *) TableName.c_str(), SQL_NTS,
                                  NULL, 0);                                // All columns
         }
         if (retcode != SQL_SUCCESS)
                                  NULL, 0);                                // All columns
         }
         if (retcode != SQL_SUCCESS)
-        {  // Error occured, abort
+        {  // Error occurred, abort
             DispAllErrors(henv, hdbc, hstmt);
             if (colInf)
                 delete [] colInf;
             DispAllErrors(henv, hdbc, hstmt);
             if (colInf)
                 delete [] colInf;
@@ -2138,19 +2768,19 @@ wxDbColInf *wxDb::GetColumns(char *tableName, int *numCols, const char *userID)
                 if (colNo < noCols)  // Some extra error checking to prevent memory overwrites
                 {
                     // NOTE: Only the ODBC 1.x fields are retrieved
                 if (colNo < noCols)  // Some extra error checking to prevent memory overwrites
                 {
                     // NOTE: Only the ODBC 1.x fields are retrieved
-                    GetData( 1, SQL_C_CHAR,   (UCHAR*)  colInf[colNo].catalog,      128+1,                    &cb);
-                    GetData( 2, SQL_C_CHAR,   (UCHAR*)  colInf[colNo].schema,       128+1,                    &cb);
-                    GetData( 3, SQL_C_CHAR,   (UCHAR*)  colInf[colNo].tableName,    DB_MAX_TABLE_NAME_LEN+1,  &cb);
-                    GetData( 4, SQL_C_CHAR,   (UCHAR*)  colInf[colNo].colName,      DB_MAX_COLUMN_NAME_LEN+1, &cb);
-                    GetData( 5, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].sqlDataType,  0,                        &cb);
-                    GetData( 6, SQL_C_CHAR,   (UCHAR*)  colInf[colNo].typeName,     128+1,                    &cb);
-                    GetData( 7, SQL_C_SLONG,  (UCHAR*) &colInf[colNo].columnSize,   0,                        &cb);
+                    GetData( 1, SQL_C_WXCHAR, (UCHAR*)  colInf[colNo].catalog,      128+1,                     &cb);
+                    GetData( 2, SQL_C_WXCHAR, (UCHAR*)  colInf[colNo].schema,       128+1,                     &cb);
+                    GetData( 3, SQL_C_WXCHAR, (UCHAR*)  colInf[colNo].tableName,    DB_MAX_TABLE_NAME_LEN+1,   &cb);
+                    GetData( 4, SQL_C_WXCHAR, (UCHAR*)  colInf[colNo].colName,      DB_MAX_COLUMN_NAME_LEN+1,  &cb);
+                    GetData( 5, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].sqlDataType,  0,                         &cb);
+                    GetData( 6, SQL_C_WXCHAR, (UCHAR*)  colInf[colNo].typeName,     128+1,                     &cb);
+                    GetData( 7, SQL_C_SLONG,  (UCHAR*) &colInf[colNo].columnLength, 0,                         &cb);
                     // BJO 991214 : SQL_C_SSHORT instead of SQL_C_SLONG, otherwise fails on Sparc (probably all 64 bit architectures)
                     // BJO 991214 : SQL_C_SSHORT instead of SQL_C_SLONG, otherwise fails on Sparc (probably all 64 bit architectures)
-                    GetData( 8, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].bufferLength, 0,                        &cb);
-                    GetData( 9, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].decimalDigits,0,                        &cb);
-                    GetData(10, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].numPrecRadix, 0,                        &cb);
-                    GetData(11, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].nullable,     0,                        &cb);
-                    GetData(12, SQL_C_CHAR,   (UCHAR*)  colInf[colNo].remarks,      254+1,                    &cb);
+                    GetData( 8, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].bufferSize,   0,                         &cb);
+                    GetData( 9, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].decimalDigits,0,                         &cb);
+                    GetData(10, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].numPrecRadix, 0,                         &cb);
+                    GetData(11, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].nullable,     0,                         &cb);
+                    GetData(12, SQL_C_WXCHAR, (UCHAR*)  colInf[colNo].remarks,      254+1,                     &cb);
                     // Start Values for Primary/Foriegn Key (=No)
                     colInf[colNo].PkCol = 0;           // Primary key column   0=No; 1= First Key, 2 = Second Key etc.
                     colInf[colNo].PkTableName[0] = 0;  // Tablenames where Primary Key is used as a Foreign Key
                     // Start Values for Primary/Foriegn Key (=No)
                     colInf[colNo].PkCol = 0;           // Primary key column   0=No; 1= First Key, 2 = Second Key etc.
                     colInf[colNo].PkTableName[0] = 0;  // Tablenames where Primary Key is used as a Foreign Key
@@ -2160,40 +2790,42 @@ wxDbColInf *wxDb::GetColumns(char *tableName, int *numCols, const char *userID)
                     // BJO 20000428 : Virtuoso returns type names with upper cases!
                     if (Dbms() == dbmsVIRTUOSO)
                     {
                     // BJO 20000428 : Virtuoso returns type names with upper cases!
                     if (Dbms() == dbmsVIRTUOSO)
                     {
-                        wxString s =  colInf[colNo].typeName;
+                        wxString s = colInf[colNo].typeName;
                         s = s.MakeLower();
                         wxStrcmp(colInf[colNo].typeName, s.c_str());
                     }
 
                     // Determine the wxDb data type that is used to represent the native data type of this data source
                     colInf[colNo].dbDataType = 0;
                         s = s.MakeLower();
                         wxStrcmp(colInf[colNo].typeName, s.c_str());
                     }
 
                     // Determine the wxDb data type that is used to represent the native data type of this data source
                     colInf[colNo].dbDataType = 0;
-                    if (!wxStricmp(typeInfVarchar.TypeName,colInf[colNo].typeName))
+                    if (!wxStricmp(typeInfVarchar.TypeName, colInf[colNo].typeName))
                     {
 #ifdef _IODBC_
                     {
 #ifdef _IODBC_
-                        // IODBC does not return a correct columnSize, so we set
-                        // columnSize = bufferLength if no column size was returned
-                        // IODBC returns the columnSize in bufferLength.. (bug)
-                        if (colInf[colNo].columnSize < 1)
+                        // IODBC does not return a correct columnLength, so we set
+                        // columnLength = bufferSize if no column length was returned
+                        // IODBC returns the columnLength in bufferSize. (bug)
+                        if (colInf[colNo].columnLength < 1)
                         {
                         {
-                           colInf[colNo].columnSize = colInf[colNo].bufferLength;
+                           colInf[colNo].columnLength = colInf[colNo].bufferSize;
                         }
 #endif
 
                         colInf[colNo].dbDataType = DB_DATA_TYPE_VARCHAR;
                     }
                         }
 #endif
 
                         colInf[colNo].dbDataType = DB_DATA_TYPE_VARCHAR;
                     }
-                    else if (!wxStricmp(typeInfInteger.TypeName,colInf[colNo].typeName))
+                    else if (!wxStricmp(typeInfInteger.TypeName, colInf[colNo].typeName))
                         colInf[colNo].dbDataType = DB_DATA_TYPE_INTEGER;
                         colInf[colNo].dbDataType = DB_DATA_TYPE_INTEGER;
-                    else if (!wxStricmp(typeInfFloat.TypeName,colInf[colNo].typeName))
+                    else if (!wxStricmp(typeInfFloat.TypeName, colInf[colNo].typeName))
                         colInf[colNo].dbDataType = DB_DATA_TYPE_FLOAT;
                         colInf[colNo].dbDataType = DB_DATA_TYPE_FLOAT;
-                    else if (!wxStricmp(typeInfDate.TypeName,colInf[colNo].typeName))
+                    else if (!wxStricmp(typeInfDate.TypeName, colInf[colNo].typeName))
                         colInf[colNo].dbDataType = DB_DATA_TYPE_DATE;
                         colInf[colNo].dbDataType = DB_DATA_TYPE_DATE;
+                    else if (!wxStricmp(typeInfBlob.TypeName, colInf[colNo].typeName))
+                        colInf[colNo].dbDataType = DB_DATA_TYPE_BLOB;
 
                     colNo++;
                 }
             }
         }
         if (retcode != SQL_NO_DATA_FOUND)
 
                     colNo++;
                 }
             }
         }
         if (retcode != SQL_NO_DATA_FOUND)
-        {  // Error occured, abort
+        {  // Error occurred, abort
             DispAllErrors(henv, hdbc, hstmt);
             if (colInf)
                 delete [] colInf;
             DispAllErrors(henv, hdbc, hstmt);
             if (colInf)
                 delete [] colInf;
@@ -2222,15 +2854,15 @@ wxDbColInf *wxDb::GetColumns(char *tableName, int *numCols, const char *userID)
 /*
     BJO 20000503
     These are tentative new GetColumns members which should be more database
 /*
     BJO 20000503
     These are tentative new GetColumns members which should be more database
-    independant and which always returns the columns in the order they were
+    independent and which always returns the columns in the order they were
     created.
 
     created.
 
-    - The first one (wxDbColInf *wxDb::GetColumns(char *tableName[], const
-      char* userID)) calls the second implementation for each separate table
+    - The first one (wxDbColInf *wxDb::GetColumns(wxChar *tableName[], const
+      wxChar* userID)) calls the second implementation for each separate table
       before merging the results. This makes the code easier to maintain as
       only one member (the second) makes the real work
       before merging the results. This makes the code easier to maintain as
       only one member (the second) makes the real work
-    - wxDbColInf *wxDb::GetColumns(char *tableName, int *numCols, const
-      char *userID) is a little bit improved
+    - wxDbColInf *wxDb::GetColumns(const wxString &tableName, int *numCols, const
+      wxChar *userID) is a little bit improved
     - It doesn't anymore rely on the type-name to find out which database-type
       each column has
     - It ends by sorting the columns, so that they are returned in the same
     - It doesn't anymore rely on the type-name to find out which database-type
       each column has
     - It ends by sorting the columns, so that they are returned in the same
@@ -2239,18 +2871,18 @@ wxDbColInf *wxDb::GetColumns(char *tableName, int *numCols, const char *userID)
 
 typedef struct
 {
 
 typedef struct
 {
-    int noCols;
+    UWORD noCols;
     wxDbColInf *colInf;
 } _TableColumns;
 
 
     wxDbColInf *colInf;
 } _TableColumns;
 
 
-wxDbColInf *wxDb::GetColumns(char *tableName[], const char* userID)
+wxDbColInf *wxDb::GetColumns(wxChar *tableName[], const wxChar *userID)
 {
     int i, j;
     // The last array element of the tableName[] argument must be zero (null).
     // This is how the end of the array is detected.
 
 {
     int i, j;
     // The last array element of the tableName[] argument must be zero (null).
     // This is how the end of the array is detected.
 
-    int noCols = 0;
+    UWORD noCols = 0;
 
     // How many tables ?
     int tbl;
 
     // How many tables ?
     int tbl;
@@ -2273,8 +2905,8 @@ wxDbColInf *wxDb::GetColumns(char *tableName[], const char* userID)
     wxDbColInf *colInf = new wxDbColInf[noCols+1];
 
     // Mark the end of the array
     wxDbColInf *colInf = new wxDbColInf[noCols+1];
 
     // Mark the end of the array
-    wxStrcpy(colInf[noCols].tableName, wxT(""));
-    wxStrcpy(colInf[noCols].colName, wxT(""));
+    wxStrcpy(colInf[noCols].tableName, wxEmptyString);
+    wxStrcpy(colInf[noCols].colName, wxEmptyString);
     colInf[noCols].sqlDataType = 0;
 
     // Merge ...
     colInf[noCols].sqlDataType = 0;
 
     // Merge ...
@@ -2294,7 +2926,7 @@ wxDbColInf *wxDb::GetColumns(char *tableName[], const char* userID)
 }  // wxDb::GetColumns()  -- NEW
 
 
 }  // wxDb::GetColumns()  -- NEW
 
 
-wxDbColInf *wxDb::GetColumns(char *tableName, int *numCols, const char *userID)
+wxDbColInf *wxDb::GetColumns(const wxString &tableName, int *numCols, const wxChar *userID)
 //
 // Same as the above GetColumns() function except this one gets columns
 // only for a single table, and if 'numCols' is not NULL, the number of
 //
 // Same as the above GetColumns() function except this one gets columns
 // only for a single table, and if 'numCols' is not NULL, the number of
@@ -2309,34 +2941,17 @@ wxDbColInf *wxDb::GetColumns(char *tableName, int *numCols, const char *userID)
 //       by this function.  This function should use its own wxDb instance
 //       to avoid undesired unbinding of columns.
 {
 //       by this function.  This function should use its own wxDb instance
 //       to avoid undesired unbinding of columns.
 {
-    SWORD       noCols = 0;
-    int         colNo  = 0;
+    UWORD       noCols = 0;
+    UWORD       colNo  = 0;
     wxDbColInf *colInf = 0;
 
     RETCODE  retcode;
     SDWORD   cb;
 
     wxDbColInf *colInf = 0;
 
     RETCODE  retcode;
     SDWORD   cb;
 
-    wxString UserID;
     wxString TableName;
 
     wxString TableName;
 
-    if (userID)
-    {
-        if (!wxStrlen(userID))
-            UserID = uid;
-        else
-            UserID = userID;
-    }
-    else
-        UserID = "";
-
-    // dBase does not use user names, and some drivers fail if you try to pass one
-    if (Dbms() == dbmsDBASE)
-        UserID = "";
-
-    // Oracle user names may only be in uppercase, so force
-    // the name to uppercase
-    if (Dbms() == dbmsORACLE)
-        UserID = UserID.Upper();
+    wxString UserID;
+    convertUserID(userID,UserID);
 
     // Pass 1 - Determine how many columns there are.
     // Pass 2 - Allocate the wxDbColInf array and fill in
 
     // Pass 1 - Determine how many columns there are.
     // Pass 2 - Allocate the wxDbColInf array and fill in
@@ -2353,8 +2968,8 @@ wxDbColInf *wxDb::GetColumns(char *tableName, int *numCols, const char *userID)
             if (!colInf)
                 break;
             // Mark the end of the array
             if (!colInf)
                 break;
             // Mark the end of the array
-            wxStrcpy(colInf[noCols].tableName, wxT(""));
-            wxStrcpy(colInf[noCols].colName, wxT(""));
+            wxStrcpy(colInf[noCols].tableName, wxEmptyString);
+            wxStrcpy(colInf[noCols].colName, wxEmptyString);
             colInf[noCols].sqlDataType = 0;
         }
 
             colInf[noCols].sqlDataType = 0;
         }
 
@@ -2362,6 +2977,7 @@ wxDbColInf *wxDb::GetColumns(char *tableName, int *numCols, const char *userID)
         // Oracle and Interbase table names are uppercase only, so force
         // the name to uppercase just in case programmer forgot to do this
         if ((Dbms() == dbmsORACLE) ||
         // Oracle and Interbase table names are uppercase only, so force
         // the name to uppercase just in case programmer forgot to do this
         if ((Dbms() == dbmsORACLE) ||
+            (Dbms() == dbmsFIREBIRD) ||
             (Dbms() == dbmsINTERBASE))
             TableName = TableName.Upper();
 
             (Dbms() == dbmsINTERBASE))
             TableName = TableName.Upper();
 
@@ -2369,7 +2985,7 @@ wxDbColInf *wxDb::GetColumns(char *tableName, int *numCols, const char *userID)
 
         // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we
         // use the call below that leaves out the user name
 
         // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we
         // use the call below that leaves out the user name
-        if (wxStrcmp(UserID.c_str(),wxT("")) &&
+        if (!UserID.empty() &&
             Dbms() != dbmsMY_SQL &&
             Dbms() != dbmsACCESS &&
             Dbms() != dbmsMS_SQL_SERVER)
             Dbms() != dbmsMY_SQL &&
             Dbms() != dbmsACCESS &&
             Dbms() != dbmsMS_SQL_SERVER)
@@ -2389,7 +3005,7 @@ wxDbColInf *wxDb::GetColumns(char *tableName, int *numCols, const char *userID)
                                  NULL, 0);                             // All columns
         }
         if (retcode != SQL_SUCCESS)
                                  NULL, 0);                             // All columns
         }
         if (retcode != SQL_SUCCESS)
-        {  // Error occured, abort
+        {  // Error occurred, abort
             DispAllErrors(henv, hdbc, hstmt);
             if (colInf)
                 delete [] colInf;
             DispAllErrors(henv, hdbc, hstmt);
             if (colInf)
                 delete [] colInf;
@@ -2408,18 +3024,18 @@ wxDbColInf *wxDb::GetColumns(char *tableName, int *numCols, const char *userID)
                 if (colNo < noCols)  // Some extra error checking to prevent memory overwrites
                 {
                     // NOTE: Only the ODBC 1.x fields are retrieved
                 if (colNo < noCols)  // Some extra error checking to prevent memory overwrites
                 {
                     // NOTE: Only the ODBC 1.x fields are retrieved
-                    GetData( 1, SQL_C_CHAR,   (UCHAR*)  colInf[colNo].catalog,      128+1,                    &cb);
-                    GetData( 2, SQL_C_CHAR,   (UCHAR*)  colInf[colNo].schema,       128+1,                    &cb);
-                    GetData( 3, SQL_C_CHAR,   (UCHAR*)  colInf[colNo].tableName,    DB_MAX_TABLE_NAME_LEN+1,  &cb);
-                    GetData( 4, SQL_C_CHAR,   (UCHAR*)  colInf[colNo].colName,      DB_MAX_COLUMN_NAME_LEN+1, &cb);
-                    GetData( 5, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].sqlDataType,  0,                        &cb);
-                    GetData( 6, SQL_C_CHAR,   (UCHAR*)  colInf[colNo].typeName,     128+1,                    &cb);
-                    GetData( 7, SQL_C_SLONG,  (UCHAR*) &colInf[colNo].columnSize,   0,                        &cb);
-                    GetData( 8, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].bufferLength, 0,                        &cb);
-                    GetData( 9, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].decimalDigits,0,                        &cb);
-                    GetData(10, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].numPrecRadix, 0,                        &cb);
-                    GetData(11, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].nullable,     0,                        &cb);
-                    GetData(12, SQL_C_CHAR,   (UCHAR*)  colInf[colNo].remarks,      254+1,                    &cb);
+                    GetData( 1, SQL_C_WXCHAR, (UCHAR*)  colInf[colNo].catalog,      128+1,                     &cb);
+                    GetData( 2, SQL_C_WXCHAR, (UCHAR*)  colInf[colNo].schema,       128+1,                     &cb);
+                    GetData( 3, SQL_C_WXCHAR, (UCHAR*)  colInf[colNo].tableName,    DB_MAX_TABLE_NAME_LEN+1,   &cb);
+                    GetData( 4, SQL_C_WXCHAR, (UCHAR*)  colInf[colNo].colName,      DB_MAX_COLUMN_NAME_LEN+1,  &cb);
+                    GetData( 5, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].sqlDataType,  0,                         &cb);
+                    GetData( 6, SQL_C_WXCHAR, (UCHAR*)  colInf[colNo].typeName,     128+1,                     &cb);
+                    GetData( 7, SQL_C_SLONG,  (UCHAR*) &colInf[colNo].columnLength, 0,                         &cb);
+                    GetData( 8, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].bufferSize,   0,                         &cb);
+                    GetData( 9, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].decimalDigits,0,                         &cb);
+                    GetData(10, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].numPrecRadix, 0,                         &cb);
+                    GetData(11, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].nullable,     0,                         &cb);
+                    GetData(12, SQL_C_WXCHAR, (UCHAR*)  colInf[colNo].remarks,      254+1,                     &cb);
                     // Start Values for Primary/Foriegn Key (=No)
                     colInf[colNo].PkCol = 0;           // Primary key column   0=No; 1= First Key, 2 = Second Key etc.
                     colInf[colNo].PkTableName[0] = 0;  // Tablenames where Primary Key is used as a Foreign Key
                     // Start Values for Primary/Foriegn Key (=No)
                     colInf[colNo].PkCol = 0;           // Primary key column   0=No; 1= First Key, 2 = Second Key etc.
                     colInf[colNo].PkTableName[0] = 0;  // Tablenames where Primary Key is used as a Foreign Key
@@ -2427,12 +3043,12 @@ wxDbColInf *wxDb::GetColumns(char *tableName, int *numCols, const char *userID)
                     colInf[colNo].FkTableName[0] = 0;  // Foreign key table name
 
 #ifdef _IODBC_
                     colInf[colNo].FkTableName[0] = 0;  // Foreign key table name
 
 #ifdef _IODBC_
-                    // IODBC does not return a correct columnSize, so we set
-                    // columnSize = bufferLength if no column size was returned
-                    // IODBC returns the columnSize in bufferLength.. (bug)
-                    if (colInf[colNo].columnSize < 1)
+                    // IODBC does not return a correct columnLength, so we set
+                    // columnLength = bufferSize if no column length was returned
+                    // IODBC returns the columnLength in bufferSize. (bug)
+                    if (colInf[colNo].columnLength < 1)
                     {
                     {
-                       colInf[colNo].columnSize = colInf[colNo].bufferLength;
+                       colInf[colNo].columnLength = colInf[colNo].bufferSize;
                     }
 #endif
 
                     }
 #endif
 
@@ -2441,14 +3057,22 @@ wxDbColInf *wxDb::GetColumns(char *tableName, int *numCols, const char *userID)
                     // Get the intern datatype
                     switch (colInf[colNo].sqlDataType)
                     {
                     // Get the intern datatype
                     switch (colInf[colNo].sqlDataType)
                     {
+#if wxUSE_UNICODE
+    #if defined(SQL_WCHAR)
+                        case SQL_WCHAR:
+    #endif
+    #if defined(SQL_WVARCHAR)
+                        case SQL_WVARCHAR:
+    #endif
+#endif
                         case SQL_VARCHAR:
                         case SQL_CHAR:
                             colInf[colNo].dbDataType = DB_DATA_TYPE_VARCHAR;
                         break;
                         case SQL_VARCHAR:
                         case SQL_CHAR:
                             colInf[colNo].dbDataType = DB_DATA_TYPE_VARCHAR;
                         break;
-
                         case SQL_TINYINT:
                         case SQL_SMALLINT:
                         case SQL_INTEGER:
                         case SQL_TINYINT:
                         case SQL_SMALLINT:
                         case SQL_INTEGER:
+                        case SQL_BIT:
                             colInf[colNo].dbDataType = DB_DATA_TYPE_INTEGER;
                             break;
                         case SQL_DOUBLE:
                             colInf[colNo].dbDataType = DB_DATA_TYPE_INTEGER;
                             break;
                         case SQL_DOUBLE:
@@ -2459,12 +3083,16 @@ wxDbColInf *wxDb::GetColumns(char *tableName, int *numCols, const char *userID)
                             colInf[colNo].dbDataType = DB_DATA_TYPE_FLOAT;
                             break;
                         case SQL_DATE:
                             colInf[colNo].dbDataType = DB_DATA_TYPE_FLOAT;
                             break;
                         case SQL_DATE:
+                        case SQL_TIMESTAMP:
                             colInf[colNo].dbDataType = DB_DATA_TYPE_DATE;
                             break;
                             colInf[colNo].dbDataType = DB_DATA_TYPE_DATE;
                             break;
+                        case SQL_BINARY:
+                            colInf[colNo].dbDataType = DB_DATA_TYPE_BLOB;
+                            break;
 #ifdef __WXDEBUG__
                         default:
                             wxString errMsg;
 #ifdef __WXDEBUG__
                         default:
                             wxString errMsg;
-                            errMsg.sprintf("SQL Data type %d currently not supported by wxWindows", colInf[colNo].sqlDataType);
+                            errMsg.Printf(wxT("SQL Data type %d currently not supported by wxWidgets"), colInf[colNo].sqlDataType);
                             wxLogDebug(errMsg,wxT("ODBC DEBUG MESSAGE"));
 #endif
                     }
                             wxLogDebug(errMsg,wxT("ODBC DEBUG MESSAGE"));
 #endif
                     }
@@ -2473,7 +3101,7 @@ wxDbColInf *wxDb::GetColumns(char *tableName, int *numCols, const char *userID)
             }
         }
         if (retcode != SQL_NO_DATA_FOUND)
             }
         }
         if (retcode != SQL_NO_DATA_FOUND)
-        {  // Error occured, abort
+        {  // Error occurred, abort
             DispAllErrors(henv, hdbc, hstmt);
             if (colInf)
                 delete [] colInf;
             DispAllErrors(henv, hdbc, hstmt);
             if (colInf)
                 delete [] colInf;
@@ -2496,7 +3124,7 @@ wxDbColInf *wxDb::GetColumns(char *tableName, int *numCols, const char *userID)
     // Build a generic SELECT statement which returns 0 rows
     wxString Stmt;
 
     // Build a generic SELECT statement which returns 0 rows
     wxString Stmt;
 
-    Stmt.sprintf("select * from %s where 0=1", tableName);
+    Stmt.Printf(wxT("select * from \"%s\" where 0=1"), tableName);
 
     // Execute query
     if (SQLExecDirect(hstmt, (UCHAR FAR *) Stmt.c_str(), SQL_NTS) != SQL_SUCCESS)
 
     // Execute query
     if (SQLExecDirect(hstmt, (UCHAR FAR *) Stmt.c_str(), SQL_NTS) != SQL_SUCCESS)
@@ -2568,7 +3196,7 @@ wxDbColInf *wxDb::GetColumns(char *tableName, int *numCols, const char *userID)
 
 
 /********** wxDb::GetColumnCount() **********/
 
 
 /********** wxDb::GetColumnCount() **********/
-int wxDb::GetColumnCount(char *tableName, const char *userID)
+int wxDb::GetColumnCount(const wxString &tableName, const wxChar *userID)
 /*
  * Returns a count of how many columns are in a table.
  * If an error occurs in computing the number of columns
 /*
  * Returns a count of how many columns are in a table.
  * If an error occurs in computing the number of columns
@@ -2584,83 +3212,62 @@ int wxDb::GetColumnCount(char *tableName, const char *userID)
  *       to avoid undesired unbinding of columns.
  */
 {
  *       to avoid undesired unbinding of columns.
  */
 {
-    int      noCols = 0;
+    UWORD    noCols = 0;
 
     RETCODE  retcode;
 
 
     RETCODE  retcode;
 
-    wxString UserID;
-    wxString TableName;
+    wxString TableName;
+
+    wxString UserID;
+    convertUserID(userID,UserID);
+
+    TableName = tableName;
+    // Oracle and Interbase table names are uppercase only, so force
+    // the name to uppercase just in case programmer forgot to do this
+    if ((Dbms() == dbmsORACLE) ||
+        (Dbms() == dbmsFIREBIRD) ||
+        (Dbms() == dbmsINTERBASE))
+        TableName = TableName.Upper();
+
+    SQLFreeStmt(hstmt, SQL_CLOSE);
 
 
-    if (userID)
+    // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we
+    // use the call below that leaves out the user name
+    if (!UserID.empty() &&
+        Dbms() != dbmsMY_SQL &&
+        Dbms() != dbmsACCESS &&
+        Dbms() != dbmsMS_SQL_SERVER)
     {
     {
-        if (!wxStrlen(userID))
-            UserID = uid;
-        else
-            UserID = userID;
+        retcode = SQLColumns(hstmt,
+                             NULL, 0,                                // All qualifiers
+                             (SQLTCHAR *) UserID.c_str(), SQL_NTS,      // Owner
+                             (SQLTCHAR *) TableName.c_str(), SQL_NTS,
+                             NULL, 0);                               // All columns
     }
     else
     }
     else
-        UserID = wxT("");
-
-    // dBase does not use user names, and some drivers fail if you try to pass one
-    if (Dbms() == dbmsDBASE)
-        UserID = wxT("");
-
-    // Oracle user names may only be in uppercase, so force
-    // the name to uppercase
-    if (Dbms() == dbmsORACLE)
-        UserID = UserID.Upper();
-
     {
     {
-        // Loop through each table name
-        {
-            TableName = tableName;
-            // Oracle and Interbase table names are uppercase only, so force
-            // the name to uppercase just in case programmer forgot to do this
-            if ((Dbms() == dbmsORACLE) ||
-                (Dbms() == dbmsINTERBASE))
-                TableName = TableName.Upper();
-
-            SQLFreeStmt(hstmt, SQL_CLOSE);
-
-            // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we
-            // use the call below that leaves out the user name
-            if (wxStrcmp(UserID.c_str(),wxT("")) &&
-                 Dbms() != dbmsMY_SQL &&
-                 Dbms() != dbmsACCESS &&
-                 Dbms() != dbmsMS_SQL_SERVER)
-            {
-                retcode = SQLColumns(hstmt,
-                                     NULL, 0,                                // All qualifiers
-                                     (UCHAR *) UserID.c_str(), SQL_NTS,      // Owner
-                                     (UCHAR *) TableName.c_str(), SQL_NTS,
-                                     NULL, 0);                               // All columns
-            }
-            else
-            {
-                retcode = SQLColumns(hstmt,
-                                     NULL, 0,                                // All qualifiers
-                                     NULL, 0,                                // Owner
-                                     (UCHAR *) TableName.c_str(), SQL_NTS,
-                                     NULL, 0);                               // All columns
-            }
-            if (retcode != SQL_SUCCESS)
-            {  // Error occured, abort
-                DispAllErrors(henv, hdbc, hstmt);
-                SQLFreeStmt(hstmt, SQL_CLOSE);
-                return(-1);
-            }
+        retcode = SQLColumns(hstmt,
+                             NULL, 0,                                // All qualifiers
+                             NULL, 0,                                // Owner
+                             (SQLTCHAR *) TableName.c_str(), SQL_NTS,
+                             NULL, 0);                               // All columns
+    }
+    if (retcode != SQL_SUCCESS)
+    {  // Error occurred, abort
+        DispAllErrors(henv, hdbc, hstmt);
+        SQLFreeStmt(hstmt, SQL_CLOSE);
+        return(-1);
+    }
 
 
-            // Count the columns
-            while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS)
-                noCols++;
+    // Count the columns
+    while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS)
+        noCols++;
 
 
-            if (retcode != SQL_NO_DATA_FOUND)
-            {  // Error occured, abort
-                DispAllErrors(henv, hdbc, hstmt);
-                SQLFreeStmt(hstmt, SQL_CLOSE);
-                return(-1);
-            }
-        }
+    if (retcode != SQL_NO_DATA_FOUND)
+    {  // Error occurred, abort
+        DispAllErrors(henv, hdbc, hstmt);
+        SQLFreeStmt(hstmt, SQL_CLOSE);
+        return(-1);
     }
 
     SQLFreeStmt(hstmt, SQL_CLOSE);
     }
 
     SQLFreeStmt(hstmt, SQL_CLOSE);
@@ -2670,7 +3277,7 @@ int wxDb::GetColumnCount(char *tableName, const char *userID)
 
 
 /********** wxDb::GetCatalog() *******/
 
 
 /********** wxDb::GetCatalog() *******/
-wxDbInf *wxDb::GetCatalog(char *userID)
+wxDbInf *wxDb::GetCatalog(const wxChar *userID)
 /*
  * ---------------------------------------------------------------------
  * -- 19991203 : mj10777 : Create                                 ------
 /*
  * ---------------------------------------------------------------------
  * -- 19991203 : mj10777 : Create                                 ------
@@ -2678,7 +3285,7 @@ wxDbInf *wxDb::GetCatalog(char *userID)
  * --          : uses SQLTables and fills pTableInf;              ------
  * --          : pColInf is set to NULL and numCols to 0;         ------
  * --          : returns pDbInf (wxDbInf)                         ------
  * --          : uses SQLTables and fills pTableInf;              ------
  * --          : pColInf is set to NULL and numCols to 0;         ------
  * --          : returns pDbInf (wxDbInf)                         ------
- * --            - if unsuccesfull (pDbInf == NULL)               ------
+ * --            - if unsuccessful (pDbInf == NULL)               ------
  * --          : pColInf can be filled with GetColumns(..);       ------
  * --          : numCols   can be filled with GetColumnCount(..); ------
  * ---------------------------------------------------------------------
  * --          : pColInf can be filled with GetColumns(..);       ------
  * --          : numCols   can be filled with GetColumnCount(..); ------
  * ---------------------------------------------------------------------
@@ -2693,36 +3300,20 @@ wxDbInf *wxDb::GetCatalog(char *userID)
  *       to avoid undesired unbinding of columns.
  */
 {
  *       to avoid undesired unbinding of columns.
  */
 {
-    wxDbInf *pDbInf = NULL; // Array of catalog entries
     int      noTab = 0;     // Counter while filling table entries
     int      pass;
     RETCODE  retcode;
     int      noTab = 0;     // Counter while filling table entries
     int      pass;
     RETCODE  retcode;
-    SDWORD   cb;
+    SQLLEN   cb;
     wxString tblNameSave;
 
     wxString UserID;
     wxString tblNameSave;
 
     wxString UserID;
+    convertUserID(userID,UserID);
 
 
-    if (userID)
-    {
-        if (!wxStrlen(userID))
-            UserID = uid;
-        else
-            UserID = userID;
-    }
-    else
-        UserID = wxT("");
-
-    // dBase does not use user names, and some drivers fail if you try to pass one
-    if (Dbms() == dbmsDBASE)
-        UserID = wxT("");
+    //-------------------------------------------------------------
+    // Create the Database Array of catalog entries
 
 
-    // Oracle user names may only be in uppercase, so force
-    // the name to uppercase
-    if (Dbms() == dbmsORACLE)
-        UserID = UserID.Upper();
+    wxDbInf *pDbInf = new wxDbInf;
 
 
-    //-------------------------------------------------------------
-    pDbInf = new wxDbInf;          // Create the Database Arrray
     //-------------------------------------------------------------
     // Table Information
     // Pass 1 - Determine how many Tables there are.
     //-------------------------------------------------------------
     // Table Information
     // Pass 1 - Determine how many Tables there are.
@@ -2733,15 +3324,16 @@ wxDbInf *wxDb::GetCatalog(char *userID)
     for (pass = 1; pass <= 2; pass++)
     {
         SQLFreeStmt(hstmt, SQL_CLOSE);   // Close if Open
     for (pass = 1; pass <= 2; pass++)
     {
         SQLFreeStmt(hstmt, SQL_CLOSE);   // Close if Open
-        tblNameSave = wxT("");
+        tblNameSave.Empty();
 
 
-        if (wxStrcmp(UserID.c_str(),wxT("")) &&
+        if (!UserID.empty() &&
             Dbms() != dbmsMY_SQL &&
             Dbms() != dbmsMY_SQL &&
-            Dbms() != dbmsACCESS)
+            Dbms() != dbmsACCESS &&
+            Dbms() != dbmsMS_SQL_SERVER)
         {
             retcode = SQLTables(hstmt,
                                 NULL, 0,                             // All qualifiers
         {
             retcode = SQLTables(hstmt,
                                 NULL, 0,                             // All qualifiers
-                                (UCHAR *) UserID.c_str(), SQL_NTS,   // User specified
+                                (SQLTCHAR *) UserID.c_str(), SQL_NTS,   // User specified
                                 NULL, 0,                             // All tables
                                 NULL, 0);                            // All columns
         }
                                 NULL, 0,                             // All tables
                                 NULL, 0);                            // All columns
         }
@@ -2768,8 +3360,8 @@ wxDbInf *wxDb::GetCatalog(char *userID)
             {
                 if (pDbInf->numTables == 0)
                 {
             {
                 if (pDbInf->numTables == 0)
                 {
-                    GetData( 1, SQL_C_CHAR,   (UCHAR*)  pDbInf->catalog,  128+1, &cb);
-                    GetData( 2, SQL_C_CHAR,   (UCHAR*)  pDbInf->schema,   128+1, &cb);
+                    GetData( 1, SQL_C_WXCHAR,   (UCHAR*)  pDbInf->catalog,  128+1, &cb);
+                    GetData( 2, SQL_C_WXCHAR,   (UCHAR*)  pDbInf->schema,   128+1, &cb);
                  }
                  pDbInf->numTables++;      // Counter for Tables
             }  // if (pass == 1)
                  }
                  pDbInf->numTables++;      // Counter for Tables
             }  // if (pass == 1)
@@ -2781,9 +3373,9 @@ wxDbInf *wxDb::GetCatalog(char *userID)
                     noTab = 0;
                 } // if (pDbInf->pTableInf == NULL)   // Has the Table Array been created
 
                     noTab = 0;
                 } // if (pDbInf->pTableInf == NULL)   // Has the Table Array been created
 
-                GetData( 3, SQL_C_CHAR,   (UCHAR*)  (pDbInf->pTableInf+noTab)->tableName,    DB_MAX_TABLE_NAME_LEN+1, &cb);
-                GetData( 4, SQL_C_CHAR,   (UCHAR*)  (pDbInf->pTableInf+noTab)->tableType,    30+1,                    &cb);
-                GetData( 5, SQL_C_CHAR,   (UCHAR*)  (pDbInf->pTableInf+noTab)->tableRemarks, 254+1,                   &cb);
+                GetData( 3, SQL_C_WXCHAR,   (UCHAR*)  (pDbInf->pTableInf+noTab)->tableName,    DB_MAX_TABLE_NAME_LEN+1, &cb);
+                GetData( 4, SQL_C_WXCHAR,   (UCHAR*)  (pDbInf->pTableInf+noTab)->tableType,    30+1,                    &cb);
+                GetData( 5, SQL_C_WXCHAR,   (UCHAR*)  (pDbInf->pTableInf+noTab)->tableRemarks, 254+1,                   &cb);
 
                 noTab++;
             }  // if
 
                 noTab++;
             }  // if
@@ -2794,7 +3386,7 @@ wxDbInf *wxDb::GetCatalog(char *userID)
     // Query how many columns are in each table
     for (noTab=0;noTab<pDbInf->numTables;noTab++)
     {
     // Query how many columns are in each table
     for (noTab=0;noTab<pDbInf->numTables;noTab++)
     {
-        (pDbInf->pTableInf+noTab)->numCols = GetColumnCount((pDbInf->pTableInf+noTab)->tableName,UserID);
+        (pDbInf->pTableInf+noTab)->numCols = (UWORD)GetColumnCount((pDbInf->pTableInf+noTab)->tableName,UserID);
     }
 
     return pDbInf;
     }
 
     return pDbInf;
@@ -2803,7 +3395,7 @@ wxDbInf *wxDb::GetCatalog(char *userID)
 
 
 /********** wxDb::Catalog() **********/
 
 
 /********** wxDb::Catalog() **********/
-bool wxDb::Catalog(const char *userID, const char *fileName)
+bool wxDb::Catalog(const wxChar *userID, const wxString &fileName)
 /*
  * Creates the text file specified in 'filename' which will contain
  * a minimal data dictionary of all tables accessible by the user specified
 /*
  * Creates the text file specified in 'filename' which will contain
  * a minimal data dictionary of all tables accessible by the user specified
@@ -2819,51 +3411,36 @@ bool wxDb::Catalog(const char *userID, const char *fileName)
  *       to avoid undesired unbinding of columns.
  */
 {
  *       to avoid undesired unbinding of columns.
  */
 {
-    assert(fileName && wxStrlen(fileName));
+    wxASSERT(fileName.Length());
 
     RETCODE   retcode;
 
     RETCODE   retcode;
-    SDWORD    cb;
-    char      tblName[DB_MAX_TABLE_NAME_LEN+1];
+    SQLLEN    cb;
+    wxChar    tblName[DB_MAX_TABLE_NAME_LEN+1];
     wxString  tblNameSave;
     wxString  tblNameSave;
-    char      colName[DB_MAX_COLUMN_NAME_LEN+1];
+    wxChar    colName[DB_MAX_COLUMN_NAME_LEN+1];
     SWORD     sqlDataType;
     SWORD     sqlDataType;
-    char      typeName[30+1];
-    SWORD     precision, length;
-
-    wxString UserID;
+    wxChar    typeName[30+1];
+    SDWORD    precision, length;
 
 
-    FILE *fp = fopen(fileName,"wt");
+    FILE *fp = wxFopen(fileName.c_str(),wxT("wt"));
     if (fp == NULL)
     if (fp == NULL)
-        return(FALSE);
+        return false;
 
     SQLFreeStmt(hstmt, SQL_CLOSE);
 
 
     SQLFreeStmt(hstmt, SQL_CLOSE);
 
-    if (userID)
-    {
-        if (!wxStrlen(userID))
-            UserID = uid;
-        else
-            UserID = userID;
-    }
-    else
-        UserID = wxT("");
-
-    // dBase does not use user names, and some drivers fail if you try to pass one
-    if (Dbms() == dbmsDBASE)
-        UserID = wxT("");
-
-    // Oracle user names may only be in uppercase, so force
-    // the name to uppercase
-    if (Dbms() == dbmsORACLE)
-        UserID = UserID.Upper();
+    wxString UserID;
+    convertUserID(userID,UserID);
 
 
-    if (wxStrcmp(UserID.c_str(),wxT("")) &&
-         Dbms() != dbmsMY_SQL &&
-         Dbms() != dbmsACCESS)
+    if (!UserID.empty() &&
+        Dbms() != dbmsMY_SQL &&
+        Dbms() != dbmsACCESS &&
+        Dbms() != dbmsFIREBIRD &&
+        Dbms() != dbmsINTERBASE &&
+        Dbms() != dbmsMS_SQL_SERVER)
     {
         retcode = SQLColumns(hstmt,
                              NULL, 0,                                // All qualifiers
     {
         retcode = SQLColumns(hstmt,
                              NULL, 0,                                // All qualifiers
-                             (UCHAR *) UserID.c_str(), SQL_NTS,      // User specified
+                             (SQLTCHAR *) UserID.c_str(), SQL_NTS,      // User specified
                              NULL, 0,                                // All tables
                              NULL, 0);                               // All columns
     }
                              NULL, 0,                                // All tables
                              NULL, 0);                               // All columns
     }
@@ -2879,49 +3456,53 @@ bool wxDb::Catalog(const char *userID, const char *fileName)
     {
         DispAllErrors(henv, hdbc, hstmt);
         fclose(fp);
     {
         DispAllErrors(henv, hdbc, hstmt);
         fclose(fp);
-        return(FALSE);
+        return false;
     }
 
     wxString outStr;
     }
 
     wxString outStr;
-    tblNameSave = wxT("");
+    tblNameSave.Empty();
     int cnt = 0;
 
     int cnt = 0;
 
-    while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS)
+    while (true)
     {
     {
-        if (wxStrcmp(tblName,tblNameSave.c_str()))
+        retcode = SQLFetch(hstmt);
+        if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
+            break;
+
+        GetData(3,SQL_C_WXCHAR,  (UCHAR *) tblName,     DB_MAX_TABLE_NAME_LEN+1, &cb);
+        GetData(4,SQL_C_WXCHAR,  (UCHAR *) colName,     DB_MAX_COLUMN_NAME_LEN+1,&cb);
+        GetData(5,SQL_C_SSHORT,  (UCHAR *)&sqlDataType, 0,                       &cb);
+        GetData(6,SQL_C_WXCHAR,  (UCHAR *) typeName,    sizeof(typeName),        &cb);
+        GetData(7,SQL_C_SLONG,   (UCHAR *)&precision,   0,                       &cb);
+        GetData(8,SQL_C_SLONG,   (UCHAR *)&length,      0,                       &cb);
+
+        if (wxStrcmp(tblName, tblNameSave.c_str()))
         {
             if (cnt)
         {
             if (cnt)
-                fputs("\n", fp);
-            fputs("================================ ", fp);
-            fputs("================================ ", fp);
-            fputs("===================== ", fp);
-            fputs("========= ", fp);
-            fputs("=========\n", fp);
-            outStr.sprintf(wxT("%-32s %-32s %-21s %9s %9s\n"),
+                wxFputs(wxT("\n"), fp);
+            wxFputs(wxT("================================ "), fp);
+            wxFputs(wxT("================================ "), fp);
+            wxFputs(wxT("===================== "), fp);
+            wxFputs(wxT("========= "), fp);
+            wxFputs(wxT("=========\n"), fp);
+            outStr.Printf(wxT("%-32s %-32s %-21s %9s %9s\n"),
                 wxT("TABLE NAME"), wxT("COLUMN NAME"), wxT("DATA TYPE"), wxT("PRECISION"), wxT("LENGTH"));
                 wxT("TABLE NAME"), wxT("COLUMN NAME"), wxT("DATA TYPE"), wxT("PRECISION"), wxT("LENGTH"));
-            fputs(outStr.c_str(), fp);
-            fputs("================================ ", fp);
-            fputs("================================ ", fp);
-            fputs("===================== ", fp);
-            fputs("========= ", fp);
-            fputs("=========\n", fp);
+            wxFputs(outStr.c_str(), fp);
+            wxFputs(wxT("================================ "), fp);
+            wxFputs(wxT("================================ "), fp);
+            wxFputs(wxT("===================== "), fp);
+            wxFputs(wxT("========= "), fp);
+            wxFputs(wxT("=========\n"), fp);
             tblNameSave = tblName;
         }
 
             tblNameSave = tblName;
         }
 
-      GetData(3,SQL_C_CHAR,  (UCHAR *)tblName,     DB_MAX_TABLE_NAME_LEN+1, &cb);
-      GetData(4,SQL_C_CHAR,  (UCHAR *)colName,     DB_MAX_COLUMN_NAME_LEN+1,&cb);
-      GetData(5,SQL_C_SSHORT,(UCHAR *)&sqlDataType,0,                       &cb);
-      GetData(6,SQL_C_CHAR,  (UCHAR *)typeName,    sizeof(typeName),        &cb);
-      GetData(7,SQL_C_SSHORT,(UCHAR *)&precision,  0,                       &cb);
-      GetData(8,SQL_C_SSHORT,(UCHAR *)&length,     0,                       &cb);
-
-        outStr.sprintf("%-32s %-32s (%04d)%-15s %9d %9d\n",
+        outStr.Printf(wxT("%-32s %-32s (%04d)%-15s %9ld %9ld\n"),
             tblName, colName, sqlDataType, typeName, precision, length);
             tblName, colName, sqlDataType, typeName, precision, length);
-        if (fputs(outStr.c_str(), fp) == EOF)
+        if (wxFputs(outStr.c_str(), fp) == EOF)
         {
             SQLFreeStmt(hstmt, SQL_CLOSE);
             fclose(fp);
         {
             SQLFreeStmt(hstmt, SQL_CLOSE);
             fclose(fp);
-            return(FALSE);
+            return false;
         }
         cnt++;
     }
         }
         cnt++;
     }
@@ -2937,7 +3518,7 @@ bool wxDb::Catalog(const char *userID, const char *fileName)
 }  // wxDb::Catalog()
 
 
 }  // wxDb::Catalog()
 
 
-bool wxDb::TableExists(const char *tableName, const char *userID, const char *tablePath)
+bool wxDb::TableExists(const wxString &tableName, const wxChar *userID, const wxString &tablePath)
 /*
  * Table name can refer to a table, view, alias or synonym.  Returns true
  * if the object exists in the database.  This function does not indicate
 /*
  * Table name can refer to a table, view, alias or synonym.  Returns true
  * if the object exists in the database.  This function does not indicate
@@ -2950,43 +3531,31 @@ bool wxDb::TableExists(const char *tableName, const char *userID, const char *ta
  *        userID != ""    ... UserID set equal to 'userID'
  */
 {
  *        userID != ""    ... UserID set equal to 'userID'
  */
 {
-    wxString UserID;
-    wxString TableName;
+    wxASSERT(tableName.Length());
 
 
-    assert(tableName && wxStrlen(tableName));
+    wxString TableName;
 
     if (Dbms() == dbmsDBASE)
     {
         wxString dbName;
 
     if (Dbms() == dbmsDBASE)
     {
         wxString dbName;
-        if (tablePath && wxStrlen(tablePath))
-            dbName.sprintf("%s\\%s.dbf",tablePath,tableName);
+        if (tablePath.Length())
+            dbName.Printf(wxT("%s/%s.dbf"), tablePath.c_str(), tableName.c_str());
         else
         else
-            dbName.sprintf("%s.dbf",tableName);
+            dbName.Printf(wxT("%s.dbf"), tableName.c_str());
 
         bool exists;
 
         bool exists;
-        exists = wxFileExists(dbName.c_str());
+        exists = wxFileExists(dbName);
         return exists;
     }
 
         return exists;
     }
 
-    if (userID)
-    {
-        if (!wxStrlen(userID))
-            UserID = uid;
-        else
-            UserID = userID;
-    }
-    else
-        UserID = "";
-
-    // Oracle user names may only be in uppercase, so force
-    // the name to uppercase
-    if (Dbms() == dbmsORACLE)
-        UserID = UserID.Upper();
+    wxString UserID;
+    convertUserID(userID,UserID);
 
     TableName = tableName;
     // Oracle and Interbase table names are uppercase only, so force
     // the name to uppercase just in case programmer forgot to do this
     if ((Dbms() == dbmsORACLE) ||
 
     TableName = tableName;
     // Oracle and Interbase table names are uppercase only, so force
     // the name to uppercase just in case programmer forgot to do this
     if ((Dbms() == dbmsORACLE) ||
+        (Dbms() == dbmsFIREBIRD) ||
         (Dbms() == dbmsINTERBASE))
         TableName = TableName.Upper();
 
         (Dbms() == dbmsINTERBASE))
         TableName = TableName.Upper();
 
@@ -2995,15 +3564,19 @@ bool wxDb::TableExists(const char *tableName, const char *userID, const char *ta
 
     // Some databases cannot accept a user name when looking up table names,
     // so we use the call below that leaves out the user name
 
     // Some databases cannot accept a user name when looking up table names,
     // so we use the call below that leaves out the user name
-    if (wxStrcmp(UserID,"") &&
+    if (!UserID.empty() &&
         Dbms() != dbmsMY_SQL &&
         Dbms() != dbmsACCESS &&
         Dbms() != dbmsMY_SQL &&
         Dbms() != dbmsACCESS &&
-        Dbms() != dbmsMS_SQL_SERVER)
+        Dbms() != dbmsMS_SQL_SERVER &&
+        Dbms() != dbmsDB2 &&
+        Dbms() != dbmsFIREBIRD &&
+        Dbms() != dbmsINTERBASE &&
+        Dbms() != dbmsPERVASIVE_SQL)
     {
         retcode = SQLTables(hstmt,
                             NULL, 0,                                  // All qualifiers
     {
         retcode = SQLTables(hstmt,
                             NULL, 0,                                  // All qualifiers
-                            (UCHAR *) UserID.c_str(), SQL_NTS,        // Only tables owned by this user
-                            (UCHAR FAR *)TableName.c_str(), SQL_NTS,
+                            (SQLTCHAR *) UserID.c_str(), SQL_NTS,        // Only tables owned by this user
+                            (SQLTCHAR FAR *)TableName.c_str(), SQL_NTS,
                             NULL, 0);                                 // All table types
     }
     else
                             NULL, 0);                                 // All table types
     }
     else
@@ -3011,7 +3584,7 @@ bool wxDb::TableExists(const char *tableName, const char *userID, const char *ta
         retcode = SQLTables(hstmt,
                             NULL, 0,                                  // All qualifiers
                             NULL, 0,                                  // All owners
         retcode = SQLTables(hstmt,
                             NULL, 0,                                  // All qualifiers
                             NULL, 0,                                  // All owners
-                            (UCHAR FAR *)TableName.c_str(), SQL_NTS,
+                            (SQLTCHAR FAR *)TableName.c_str(), SQL_NTS,
                             NULL, 0);                                 // All table types
     }
     if (retcode != SQL_SUCCESS)
                             NULL, 0);                                 // All table types
     }
     if (retcode != SQL_SUCCESS)
@@ -3026,148 +3599,173 @@ bool wxDb::TableExists(const char *tableName, const char *userID, const char *ta
 
     SQLFreeStmt(hstmt, SQL_CLOSE);
 
 
     SQLFreeStmt(hstmt, SQL_CLOSE);
 
-    return(TRUE);
+    return true;
 
 }  // wxDb::TableExists()
 
 
 /********** wxDb::TablePrivileges() **********/
 
 }  // wxDb::TableExists()
 
 
 /********** wxDb::TablePrivileges() **********/
-bool wxDb::TablePrivileges(const char *tableName, const char* priv, const char *userID,
-                            const char *schema, const char *tablePath)
+bool wxDb::TablePrivileges(const wxString &tableName, const wxString &priv, const wxChar *userID,
+                            const wxChar *schema, const wxString &WXUNUSED(tablePath))
 {
 {
+    wxASSERT(tableName.Length());
+
     wxDbTablePrivilegeInfo  result;
     wxDbTablePrivilegeInfo  result;
-    SDWORD  cbRetVal;
+    SQLLEN  cbRetVal;
     RETCODE retcode;
 
     RETCODE retcode;
 
-    //We probably need to be able to dynamically set this based on
-    //the driver type, and state.
-    char curRole[]="public";
+    // We probably need to be able to dynamically set this based on
+    // the driver type, and state.
+    wxChar curRole[]=wxT("public");
 
 
-    //Prologue here similar to db::TableExists()
-    wxString UserID;
     wxString TableName;
 
     wxString TableName;
 
-    assert(userID);
-    assert(tableName && wxStrlen(tableName));
-
-    if (userID)
-    {
-        if (!wxStrlen(userID))
-            UserID = uid;
-        else
-            UserID = userID;
-    }
-    else
-        UserID = "";
-
-    // Oracle user names may only be in uppercase, so force
-    // the name to uppercase
-    if (Dbms() == dbmsORACLE)
-        UserID = UserID.Upper();
+    wxString UserID,Schema;
+    convertUserID(userID,UserID);
+    convertUserID(schema,Schema);
 
     TableName = tableName;
     // Oracle and Interbase table names are uppercase only, so force
     // the name to uppercase just in case programmer forgot to do this
     if ((Dbms() == dbmsORACLE) ||
 
     TableName = tableName;
     // Oracle and Interbase table names are uppercase only, so force
     // the name to uppercase just in case programmer forgot to do this
     if ((Dbms() == dbmsORACLE) ||
+        (Dbms() == dbmsFIREBIRD) ||
         (Dbms() == dbmsINTERBASE))
         TableName = TableName.Upper();
 
     SQLFreeStmt(hstmt, SQL_CLOSE);
 
         (Dbms() == dbmsINTERBASE))
         TableName = TableName.Upper();
 
     SQLFreeStmt(hstmt, SQL_CLOSE);
 
-    if (!schema)
+    // Some databases cannot accept a user name when looking up table names,
+    // so we use the call below that leaves out the user name
+    if (!Schema.empty() &&
+        Dbms() != dbmsMY_SQL &&
+        Dbms() != dbmsACCESS &&
+        Dbms() != dbmsMS_SQL_SERVER)
     {
         retcode = SQLTablePrivileges(hstmt,
                                      NULL, 0,                                    // Catalog
     {
         retcode = SQLTablePrivileges(hstmt,
                                      NULL, 0,                                    // Catalog
-                                     NULL, 0,                                    // Schema
-                                     (UCHAR FAR *)TableName.c_str(), SQL_NTS);
+                                     (SQLTCHAR FAR *)Schema.c_str(), SQL_NTS,               // Schema
+                                     (SQLTCHAR FAR *)TableName.c_str(), SQL_NTS);
     }
     else
     {
         retcode = SQLTablePrivileges(hstmt,
                                      NULL, 0,                                    // Catalog
     }
     else
     {
         retcode = SQLTablePrivileges(hstmt,
                                      NULL, 0,                                    // Catalog
-                                     (UCHAR FAR *)schema, SQL_NTS,               // Schema
-                                     (UCHAR FAR *)TableName.c_str(), SQL_NTS);
+                                     NULL, 0,                                    // Schema
+                                     (SQLTCHAR FAR *)TableName.c_str(), SQL_NTS);
     }
 
 #ifdef DBDEBUG_CONSOLE
     }
 
 #ifdef DBDEBUG_CONSOLE
-    fprintf(stderr ,"SQLTablePrivileges() returned %i \n",retcode);
+    wxFprintf(stderr ,wxT("SQLTablePrivileges() returned %i \n"),retcode);
 #endif
 
     if ((retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO))
 #endif
 
     if ((retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO))
-        return(DispAllErrors(henv, hdbc, hstmt));
+        return (DispAllErrors(henv, hdbc, hstmt));
 
 
+    bool failed = false;
     retcode = SQLFetch(hstmt);
     while (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
     {
     retcode = SQLFetch(hstmt);
     while (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
     {
-        if (SQLGetData(hstmt, 1, SQL_C_CHAR, (UCHAR*) result.tableQual, sizeof(result.tableQual), &cbRetVal) != SQL_SUCCESS)
-            return(DispAllErrors(henv, hdbc, hstmt));
+        if (SQLGetData(hstmt, 1, SQL_C_WXCHAR, (UCHAR*) result.tableQual, sizeof(result.tableQual), &cbRetVal) != SQL_SUCCESS)
+            failed = true;
 
 
-        if (SQLGetData(hstmt, 2, SQL_C_CHAR, (UCHAR*) result.tableOwner, sizeof(result.tableOwner), &cbRetVal) != SQL_SUCCESS)
-            return(DispAllErrors(henv, hdbc, hstmt));
+        if (!failed && SQLGetData(hstmt, 2, SQL_C_WXCHAR, (UCHAR*) result.tableOwner, sizeof(result.tableOwner), &cbRetVal) != SQL_SUCCESS)
+            failed = true;
 
 
-        if (SQLGetData(hstmt, 3, SQL_C_CHAR, (UCHAR*) result.tableName, sizeof(result.tableName), &cbRetVal) != SQL_SUCCESS)
-            return(DispAllErrors(henv, hdbc, hstmt));
+        if (!failed && SQLGetData(hstmt, 3, SQL_C_WXCHAR, (UCHAR*) result.tableName, sizeof(result.tableName), &cbRetVal) != SQL_SUCCESS)
+            failed = true;
 
 
-        if (SQLGetData(hstmt, 4, SQL_C_CHAR, (UCHAR*) result.grantor, sizeof(result.grantor), &cbRetVal) != SQL_SUCCESS)
-            return(DispAllErrors(henv, hdbc, hstmt));
+        if (!failed && SQLGetData(hstmt, 4, SQL_C_WXCHAR, (UCHAR*) result.grantor, sizeof(result.grantor), &cbRetVal) != SQL_SUCCESS)
+            failed = true;
 
 
-        if (SQLGetData(hstmt, 5, SQL_C_CHAR, (UCHAR*) result.grantee, sizeof(result.grantee), &cbRetVal) != SQL_SUCCESS)
-            return(DispAllErrors(henv, hdbc, hstmt));
+        if (!failed && SQLGetData(hstmt, 5, SQL_C_WXCHAR, (UCHAR*) result.grantee, sizeof(result.grantee), &cbRetVal) != SQL_SUCCESS)
+            failed = true;
 
 
-        if (SQLGetData(hstmt, 6, SQL_C_CHAR, (UCHAR*) result.privilege, sizeof(result.privilege), &cbRetVal) != SQL_SUCCESS)
-            return(DispAllErrors(henv, hdbc, hstmt));
+        if (!failed && SQLGetData(hstmt, 6, SQL_C_WXCHAR, (UCHAR*) result.privilege, sizeof(result.privilege), &cbRetVal) != SQL_SUCCESS)
+            failed = true;
 
 
-        if (SQLGetData(hstmt, 7, SQL_C_CHAR, (UCHAR*) result.grantable, sizeof(result.grantable), &cbRetVal) != SQL_SUCCESS)
-            return(DispAllErrors(henv, hdbc, hstmt));
+        if (!failed && SQLGetData(hstmt, 7, SQL_C_WXCHAR, (UCHAR*) result.grantable, sizeof(result.grantable), &cbRetVal) != SQL_SUCCESS)
+            failed = true;
 
 
+        if (failed)
+        {
+            return(DispAllErrors(henv, hdbc, hstmt));
+        }
 #ifdef DBDEBUG_CONSOLE
 #ifdef DBDEBUG_CONSOLE
-        fprintf(stderr,"Scanning %s privilege on table %s.%s granted by %s to %s\n",
+        wxFprintf(stderr,wxT("Scanning %s privilege on table %s.%s granted by %s to %s\n"),
                 result.privilege,result.tableOwner,result.tableName,
                 result.grantor, result.grantee);
 #endif
 
                 result.privilege,result.tableOwner,result.tableName,
                 result.grantor, result.grantee);
 #endif
 
-        if (UserID.IsSameAs(result.tableOwner,FALSE))
+        if (UserID.IsSameAs(result.tableOwner,false))
         {
             SQLFreeStmt(hstmt, SQL_CLOSE);
         {
             SQLFreeStmt(hstmt, SQL_CLOSE);
-            return TRUE;
+            return true;
         }
 
         }
 
-        if (UserID.IsSameAs(result.grantee,FALSE) &&
+        if (UserID.IsSameAs(result.grantee,false) &&
             !wxStrcmp(result.privilege,priv))
         {
             SQLFreeStmt(hstmt, SQL_CLOSE);
             !wxStrcmp(result.privilege,priv))
         {
             SQLFreeStmt(hstmt, SQL_CLOSE);
-            return TRUE;
+            return true;
         }
 
         if (!wxStrcmp(result.grantee,curRole) &&
             !wxStrcmp(result.privilege,priv))
         {
             SQLFreeStmt(hstmt, SQL_CLOSE);
         }
 
         if (!wxStrcmp(result.grantee,curRole) &&
             !wxStrcmp(result.privilege,priv))
         {
             SQLFreeStmt(hstmt, SQL_CLOSE);
-            return TRUE;
+            return true;
         }
 
         retcode = SQLFetch(hstmt);
     }
 
     SQLFreeStmt(hstmt, SQL_CLOSE);
         }
 
         retcode = SQLFetch(hstmt);
     }
 
     SQLFreeStmt(hstmt, SQL_CLOSE);
-    return FALSE;
+    return false;
 
 }  // wxDb::TablePrivileges
 
 
 
 }  // wxDb::TablePrivileges
 
 
+const wxString wxDb::SQLTableName(const wxChar *tableName)
+{
+    wxString TableName;
+
+    if (Dbms() == dbmsACCESS)
+        TableName = _T("\"");
+    TableName += tableName;
+    if (Dbms() == dbmsACCESS)
+        TableName += _T("\"");
+
+    return TableName;
+}  // wxDb::SQLTableName()
+
+
+const wxString wxDb::SQLColumnName(const wxChar *colName)
+{
+    wxString ColName;
+
+    if (Dbms() == dbmsACCESS)
+        ColName = _T("\"");
+    ColName += colName;
+    if (Dbms() == dbmsACCESS)
+        ColName += _T("\"");
+
+    return ColName;
+}  // wxDb::SQLColumnName()
+
+
 /********** wxDb::SetSqlLogging() **********/
 /********** wxDb::SetSqlLogging() **********/
-bool wxDb::SetSqlLogging(wxDbSqlLogState state, const char *filename, bool append)
+bool wxDb::SetSqlLogging(wxDbSqlLogState state, const wxString &filename, bool append)
 {
 {
-    assert(state == sqlLogON  || state == sqlLogOFF);
-    assert(state == sqlLogOFF || filename);
+    wxASSERT(state == sqlLogON  || state == sqlLogOFF);
+    wxASSERT(state == sqlLogOFF || filename.Length());
 
     if (state == sqlLogON)
     {
         if (fpSqlLog == 0)
         {
 
     if (state == sqlLogON)
     {
         if (fpSqlLog == 0)
         {
-            fpSqlLog = fopen(filename, (append ? "at" : "wt"));
+            fpSqlLog = wxFopen(filename.c_str(), (append ? wxT("at") : wxT("wt")));
             if (fpSqlLog == NULL)
             if (fpSqlLog == NULL)
-                return(FALSE);
+                return false;
         }
     }
     else  // sqlLogOFF
         }
     }
     else  // sqlLogOFF
@@ -3175,30 +3773,33 @@ bool wxDb::SetSqlLogging(wxDbSqlLogState state, const char *filename, bool appen
         if (fpSqlLog)
         {
             if (fclose(fpSqlLog))
         if (fpSqlLog)
         {
             if (fclose(fpSqlLog))
-                return(FALSE);
+                return false;
             fpSqlLog = 0;
         }
     }
 
     sqlLogState = state;
             fpSqlLog = 0;
         }
     }
 
     sqlLogState = state;
-    return(TRUE);
+    return true;
 
 }  // wxDb::SetSqlLogging()
 
 
 /********** wxDb::WriteSqlLog() **********/
 
 }  // wxDb::SetSqlLogging()
 
 
 /********** wxDb::WriteSqlLog() **********/
-bool wxDb::WriteSqlLog(const wxChar *logMsg)
+bool wxDb::WriteSqlLog(const wxString &logMsg)
 {
 {
-    assert(logMsg);
+    wxASSERT(logMsg.Length());
 
     if (fpSqlLog == 0 || sqlLogState == sqlLogOFF)
 
     if (fpSqlLog == 0 || sqlLogState == sqlLogOFF)
-        return(FALSE);
+        return false;
 
 
-    if (fputs("\n",   fpSqlLog) == EOF) return(FALSE);
-    if (fputs(logMsg, fpSqlLog) == EOF) return(FALSE);
-    if (fputs("\n",   fpSqlLog) == EOF) return(FALSE);
+    if (wxFputs(wxT("\n"),   fpSqlLog) == EOF)
+        return false;
+    if (wxFputs(logMsg, fpSqlLog) == EOF)
+        return false;
+    if (wxFputs(wxT("\n"),   fpSqlLog) == EOF)
+        return false;
 
 
-    return(TRUE);
+    return true;
 
 }  // wxDb::WriteSqlLog()
 
 
 }  // wxDb::WriteSqlLog()
 
@@ -3226,7 +3827,7 @@ wxDBMS wxDb::Dbms(void)
  *        - Does not support the SQL_TIMESTAMP structure
  *        - Supports only one cursor and one connect (apparently? with Microsoft driver only?)
  *        - Does not automatically create the primary index if the 'keyField' param of SetColDef
  *        - Does not support the SQL_TIMESTAMP structure
  *        - Supports only one cursor and one connect (apparently? with Microsoft driver only?)
  *        - Does not automatically create the primary index if the 'keyField' param of SetColDef
- *            is TRUE.  The user must create ALL indexes from their program.
+ *            is true.  The user must create ALL indexes from their program.
  *        - Table names can only be 8 characters long
  *        - Column names can only be 10 characters long
  *
  *        - Table names can only be 8 characters long
  *        - Column names can only be 10 characters long
  *
@@ -3254,7 +3855,16 @@ wxDBMS wxDb::Dbms(void)
  *
  * DB2
  *        - Primary keys must be declared as NOT NULL
  *
  * DB2
  *        - Primary keys must be declared as NOT NULL
+ *        - Table and index names must not be longer than 13 characters in length (technically
+ *          table names can be up to 18 characters, but the primary index is created using the
+ *          base table name plus "_PIDX", so the limit if the table has a primary index is 13.
+ *
+ * PERVASIVE SQL
  *
  *
+ * INTERBASE
+ *        - Columns that are part of primary keys must be defined as being NOT NULL
+ *          when they are created.  Some code is added in ::CreateIndex to try to adjust the
+ *          column definition if it is not defined correctly, but it is experimental
  */
 {
     // Should only need to do this once for each new database connection
  */
 {
     // Should only need to do this once for each new database connection
@@ -3263,62 +3873,81 @@ wxDBMS wxDb::Dbms(void)
     if (dbmsType != dbmsUNIDENTIFIED)
         return(dbmsType);
 
     if (dbmsType != dbmsUNIDENTIFIED)
         return(dbmsType);
 
+#ifdef DBDEBUG_CONSOLE
+               // When run in console mode, use standard out to display errors.
+               cout << "Database connecting to: " << dbInf.dbmsName << endl;
+#endif  // DBDEBUG_CONSOLE
+
+    wxLogDebug(wxT("Database connecting to: "));
+    wxLogDebug(dbInf.dbmsName);
+
     wxChar baseName[25+1];
     wxChar baseName[25+1];
-    wxStrncpy(baseName,dbInf.dbmsName,25);
+    wxStrncpy(baseName, dbInf.dbmsName, 25);
     baseName[25] = 0;
 
     // RGG 20001025 : add support for Interbase
     // GT : Integrated to base classes on 20001121
     baseName[25] = 0;
 
     // RGG 20001025 : add support for Interbase
     // GT : Integrated to base classes on 20001121
-    if (!wxStricmp(dbInf.dbmsName,"Interbase"))
+    if (!wxStricmp(dbInf.dbmsName,wxT("Interbase")))
         return((wxDBMS)(dbmsType = dbmsINTERBASE));
 
     // BJO 20000428 : add support for Virtuoso
         return((wxDBMS)(dbmsType = dbmsINTERBASE));
 
     // BJO 20000428 : add support for Virtuoso
-    if (!wxStricmp(dbInf.dbmsName,"OpenLink Virtuoso VDBMS"))
+    if (!wxStricmp(dbInf.dbmsName,wxT("OpenLink Virtuoso VDBMS")))
       return((wxDBMS)(dbmsType = dbmsVIRTUOSO));
 
       return((wxDBMS)(dbmsType = dbmsVIRTUOSO));
 
-    if (!wxStricmp(dbInf.dbmsName,"Adaptive Server Anywhere"))
+    if (!wxStricmp(dbInf.dbmsName,wxT("Adaptive Server Anywhere")))
         return((wxDBMS)(dbmsType = dbmsSYBASE_ASA));
 
     // BJO 20000427 : The "SQL Server" string is also returned by SQLServer when
     // connected through an OpenLink driver.
     // Is it also returned by Sybase Adapatitve server?
     // OpenLink driver name is OLOD3032.DLL for msw and oplodbc.so for unix
         return((wxDBMS)(dbmsType = dbmsSYBASE_ASA));
 
     // BJO 20000427 : The "SQL Server" string is also returned by SQLServer when
     // connected through an OpenLink driver.
     // Is it also returned by Sybase Adapatitve server?
     // OpenLink driver name is OLOD3032.DLL for msw and oplodbc.so for unix
-    if (!wxStricmp(dbInf.dbmsName,"SQL Server"))
+    if (!wxStricmp(dbInf.dbmsName,wxT("SQL Server")))
     {
     {
-      if (!wxStrncmp(dbInf.driverName, "oplodbc", 7) ||
-          !wxStrncmp(dbInf.driverName, "OLOD", 4))
-                       return ((wxDBMS)(dbmsMS_SQL_SERVER));
-               else
-                       return ((wxDBMS)(dbmsType = dbmsSYBASE_ASE));
+      if (!wxStrncmp(dbInf.driverName, wxT("oplodbc"), 7) ||
+          !wxStrncmp(dbInf.driverName, wxT("OLOD"), 4))
+            return ((wxDBMS)(dbmsMS_SQL_SERVER));
+        else
+            return ((wxDBMS)(dbmsType = dbmsSYBASE_ASE));
     }
 
     }
 
-    if (!wxStricmp(dbInf.dbmsName,"Microsoft SQL Server"))
+    if (!wxStricmp(dbInf.dbmsName,wxT("Microsoft SQL Server")))
         return((wxDBMS)(dbmsType = dbmsMS_SQL_SERVER));
         return((wxDBMS)(dbmsType = dbmsMS_SQL_SERVER));
-    if (!wxStricmp(dbInf.dbmsName,"MySQL"))
-        return((wxDBMS)(dbmsType = dbmsMY_SQL));
-    if (!wxStricmp(dbInf.dbmsName,"PostgreSQL"))  // v6.5.0
+
+    baseName[10] = 0;
+    if (!wxStricmp(baseName,wxT("PostgreSQL")))  // v6.5.0
         return((wxDBMS)(dbmsType = dbmsPOSTGRES));
 
         return((wxDBMS)(dbmsType = dbmsPOSTGRES));
 
+    baseName[9] = 0;
+    if (!wxStricmp(baseName,wxT("Pervasive")))
+        return((wxDBMS)(dbmsType = dbmsPERVASIVE_SQL));
+
     baseName[8] = 0;
     baseName[8] = 0;
-    if (!wxStricmp(baseName,"Informix"))
+    if (!wxStricmp(baseName,wxT("Informix")))
         return((wxDBMS)(dbmsType = dbmsINFORMIX));
 
         return((wxDBMS)(dbmsType = dbmsINFORMIX));
 
+    if (!wxStricmp(baseName,wxT("Firebird")))
+        return((wxDBMS)(dbmsType = dbmsFIREBIRD));
+
     baseName[6] = 0;
     baseName[6] = 0;
-    if (!wxStricmp(baseName,"Oracle"))
+    if (!wxStricmp(baseName,wxT("Oracle")))
         return((wxDBMS)(dbmsType = dbmsORACLE));
         return((wxDBMS)(dbmsType = dbmsORACLE));
-    if (!wxStricmp(dbInf.dbmsName,"ACCESS"))
+    if (!wxStricmp(baseName,wxT("ACCESS")))
         return((wxDBMS)(dbmsType = dbmsACCESS));
         return((wxDBMS)(dbmsType = dbmsACCESS));
-    if (!wxStricmp(dbInf.dbmsName,"MySQL"))
-        return((wxDBMS)(dbmsType = dbmsMY_SQL));
-    if (!wxStricmp(baseName,"Sybase"))
+    if (!wxStricmp(baseName,wxT("Sybase")))
       return((wxDBMS)(dbmsType = dbmsSYBASE_ASE));
 
     baseName[5] = 0;
       return((wxDBMS)(dbmsType = dbmsSYBASE_ASE));
 
     baseName[5] = 0;
-    if (!wxStricmp(baseName,"DBASE"))
+    if (!wxStricmp(baseName,wxT("DBASE")))
         return((wxDBMS)(dbmsType = dbmsDBASE));
         return((wxDBMS)(dbmsType = dbmsDBASE));
+    if (!wxStricmp(baseName,wxT("xBase")))
+        return((wxDBMS)(dbmsType = dbmsXBASE_SEQUITER));
+    if (!wxStricmp(baseName,wxT("MySQL")))
+        return((wxDBMS)(dbmsType = dbmsMY_SQL));
+    if (!wxStricmp(baseName,wxT("MaxDB")))
+        return((wxDBMS)(dbmsType = dbmsMAXDB));
 
     baseName[3] = 0;
 
     baseName[3] = 0;
-    if (!wxStricmp(baseName,"DB2"))
+    if (!wxStricmp(baseName,wxT("DB2")))
         return((wxDBMS)(dbmsType = dbmsDBASE));
 
     return((wxDBMS)(dbmsType = dbmsUNIDENTIFIED));
         return((wxDBMS)(dbmsType = dbmsDBASE));
 
     return((wxDBMS)(dbmsType = dbmsUNIDENTIFIED));
@@ -3326,8 +3955,102 @@ wxDBMS wxDb::Dbms(void)
 }  // wxDb::Dbms()
 
 
 }  // wxDb::Dbms()
 
 
+bool wxDb::ModifyColumn(const wxString &tableName, const wxString &columnName,
+                        int dataType, ULONG columnLength,
+                        const wxString &optionalParam)
+{
+    wxASSERT(tableName.Length());
+    wxASSERT(columnName.Length());
+    wxASSERT((dataType == DB_DATA_TYPE_VARCHAR && columnLength > 0) ||
+             dataType != DB_DATA_TYPE_VARCHAR);
+
+    // Must specify a columnLength if modifying a VARCHAR type column
+    if (dataType == DB_DATA_TYPE_VARCHAR && !columnLength)
+        return false;
+
+    wxString dataTypeName;
+    wxString sqlStmt;
+    wxString alterSlashModify;
+
+    switch(dataType)
+    {
+        case DB_DATA_TYPE_VARCHAR :
+            dataTypeName = typeInfVarchar.TypeName;
+            break;
+        case DB_DATA_TYPE_INTEGER :
+            dataTypeName = typeInfInteger.TypeName;
+            break;
+        case DB_DATA_TYPE_FLOAT :
+            dataTypeName = typeInfFloat.TypeName;
+            break;
+        case DB_DATA_TYPE_DATE :
+            dataTypeName = typeInfDate.TypeName;
+            break;
+        case DB_DATA_TYPE_BLOB :
+            dataTypeName = typeInfBlob.TypeName;
+            break;
+        default:
+            return false;
+    }
+
+    // Set the modify or alter syntax depending on the type of database connected to
+    switch (Dbms())
+    {
+        case dbmsORACLE :
+            alterSlashModify = _T("MODIFY");
+            break;
+        case dbmsMS_SQL_SERVER :
+            alterSlashModify = _T("ALTER COLUMN");
+            break;
+        case dbmsUNIDENTIFIED :
+            return false;
+        case dbmsSYBASE_ASA :
+        case dbmsSYBASE_ASE :
+        case dbmsMY_SQL :
+        case dbmsPOSTGRES :
+        case dbmsACCESS :
+        case dbmsDBASE :
+        case dbmsXBASE_SEQUITER :
+        default :
+            alterSlashModify = _T("MODIFY");
+            break;
+    }
+
+    // create the SQL statement
+    if ( Dbms() == dbmsMY_SQL )
+    {
+        sqlStmt.Printf(wxT("ALTER TABLE %s %s %s %s"), tableName.c_str(), alterSlashModify.c_str(),
+              columnName.c_str(), dataTypeName.c_str());
+    }
+    else
+    {
+        sqlStmt.Printf(wxT("ALTER TABLE \"%s\" \"%s\" \"%s\" %s"), tableName.c_str(), alterSlashModify.c_str(),
+              columnName.c_str(), dataTypeName.c_str());
+    }
+
+    // For varchars only, append the size of the column
+    if (dataType == DB_DATA_TYPE_VARCHAR &&
+        (Dbms() != dbmsMY_SQL || dataTypeName != _T("text")))
+    {
+        wxString s;
+        s.Printf(wxT("(%lu)"), columnLength);
+        sqlStmt += s;
+    }
+
+    // for passing things like "NOT NULL"
+    if (optionalParam.Length())
+    {
+        sqlStmt += wxT(" ");
+        sqlStmt += optionalParam;
+    }
+
+    return ExecSql(sqlStmt);
+
+} // wxDb::ModifyColumn()
+
+
 /********** wxDbGetConnection() **********/
 /********** wxDbGetConnection() **********/
-wxDb WXDLLEXPORT *wxDbGetConnection(wxDbConnectInf *pDbConfig, bool FwdOnlyCursors)
+wxDb WXDLLIMPEXP_ODBC *wxDbGetConnection(wxDbConnectInf *pDbConfig, bool FwdOnlyCursors)
 {
     wxDbList *pList;
 
 {
     wxDbList *pList;
 
@@ -3345,17 +4068,42 @@ wxDb WXDLLEXPORT *wxDbGetConnection(wxDbConnectInf *pDbConfig, bool FwdOnlyCurso
         // The database connection must be for the same datasource
         // name and must currently not be in use.
         if (pList->Free &&
         // The database connection must be for the same datasource
         // name and must currently not be in use.
         if (pList->Free &&
-            (pList->PtrDb->FwdOnlyCursors() == FwdOnlyCursors) &&
-            (!wxStrcmp(pDbConfig->Dsn, pList->Dsn)))  // Found a free connection
+            (pList->PtrDb->FwdOnlyCursors() == FwdOnlyCursors))
         {
         {
-            pList->Free = FALSE;
-            return(pList->PtrDb);
+            if (pDbConfig->UseConnectionStr())
+            {
+                if (pList->PtrDb->OpenedWithConnectionString() &&
+                     (!wxStrcmp(pDbConfig->GetConnectionStr(), pList->ConnectionStr)))
+                {
+                    // Found a free connection
+                    pList->Free = false;
+                    return(pList->PtrDb);
+                }
+            }
+            else
+            {
+                if (!pList->PtrDb->OpenedWithConnectionString() &&
+                     (!wxStrcmp(pDbConfig->GetDsn(), pList->Dsn)))
+                {
+                    // Found a free connection
+                    pList->Free = false;
+                    return(pList->PtrDb);
+                }
+            }
         }
 
         }
 
-        if (!wxStrcmp(pDbConfig->Dsn, pList->Dsn) &&
-            !wxStrcmp(pDbConfig->Uid, pList->Uid) &&
-            !wxStrcmp(pDbConfig->AuthStr, pList->AuthStr))
-            matchingDbConnection = pList->PtrDb;
+        if (pDbConfig->UseConnectionStr())
+        {
+            if (!wxStrcmp(pDbConfig->GetConnectionStr(), pList->ConnectionStr))
+                matchingDbConnection = pList->PtrDb;
+        }
+        else
+        {
+            if (!wxStrcmp(pDbConfig->GetDsn(), pList->Dsn) &&
+                !wxStrcmp(pDbConfig->GetUserID(), pList->Uid) &&
+                !wxStrcmp(pDbConfig->GetPassword(), pList->AuthStr))
+                matchingDbConnection = pList->PtrDb;
+        }
     }
 
     // No available connections.  A new connection must be made and
     }
 
     // No available connections.  A new connection must be made and
@@ -3377,25 +4125,36 @@ wxDb WXDLLEXPORT *wxDbGetConnection(wxDbConnectInf *pDbConfig, bool FwdOnlyCurso
     }
 
     // Initialize new node in the linked list
     }
 
     // Initialize new node in the linked list
-    pList->PtrNext = 0;
-    pList->Free = FALSE;
-    wxStrcpy(pList->Dsn, pDbConfig->Dsn);
-    wxStrcpy(pList->Uid, pDbConfig->Uid);
-    wxStrcpy(pList->AuthStr, pDbConfig->AuthStr);
+    pList->PtrNext          = 0;
+    pList->Free             = false;
+    pList->Dsn              = pDbConfig->GetDsn();
+    pList->Uid              = pDbConfig->GetUserID();
+    pList->AuthStr          = pDbConfig->GetPassword();
+    pList->ConnectionStr    = pDbConfig->GetConnectionStr();
 
 
-    pList->PtrDb = new wxDb(pDbConfig->Henv,FwdOnlyCursors);
+    pList->PtrDb = new wxDb(pDbConfig->GetHenv(), FwdOnlyCursors);
 
 
-    bool opened = FALSE;
+    bool opened;
 
     if (!matchingDbConnection)
 
     if (!matchingDbConnection)
-        opened = pList->PtrDb->Open(pDbConfig->Dsn, pDbConfig->Uid, pDbConfig->AuthStr);
+    {
+        if (pDbConfig->UseConnectionStr())
+        {
+            opened = pList->PtrDb->Open(pDbConfig->GetConnectionStr());
+        }
+        else
+        {
+            opened = pList->PtrDb->Open(pDbConfig->GetDsn(), pDbConfig->GetUserID(), pDbConfig->GetPassword());
+        }
+    }
     else
         opened = pList->PtrDb->Open(matchingDbConnection);
 
     // Connect to the datasource
     if (opened)
     {
     else
         opened = pList->PtrDb->Open(matchingDbConnection);
 
     // Connect to the datasource
     if (opened)
     {
-        pList->PtrDb->SetSqlLogging(SQLLOGstate,SQLLOGfn,TRUE);
+        pList->PtrDb->setCached(true);  // Prevent a user from deleting a cached connection
+        pList->PtrDb->SetSqlLogging(SQLLOGstate, SQLLOGfn, true);
         return(pList->PtrDb);
     }
     else  // Unable to connect, destroy list item
         return(pList->PtrDb);
     }
     else  // Unable to connect, destroy list item
@@ -3403,11 +4162,12 @@ wxDb WXDLLEXPORT *wxDbGetConnection(wxDbConnectInf *pDbConfig, bool FwdOnlyCurso
         if (pList->PtrPrev)
             pList->PtrPrev->PtrNext = 0;
         else
         if (pList->PtrPrev)
             pList->PtrPrev->PtrNext = 0;
         else
-            PtrBegDbList = 0;                // Empty list again
-        pList->PtrDb->CommitTrans();    // Commit any open transactions on wxDb object
-        pList->PtrDb->Close();            // Close the wxDb object
-        delete pList->PtrDb;                // Deletes the wxDb object
-        delete pList;                        // Deletes the linked list object
+            PtrBegDbList = 0;        // Empty list again
+
+        pList->PtrDb->CommitTrans(); // Commit any open transactions on wxDb object
+        pList->PtrDb->Close();       // Close the wxDb object
+        delete pList->PtrDb;         // Deletes the wxDb object
+        delete pList;                // Deletes the linked list object
         return(0);
     }
 
         return(0);
     }
 
@@ -3415,7 +4175,7 @@ wxDb WXDLLEXPORT *wxDbGetConnection(wxDbConnectInf *pDbConfig, bool FwdOnlyCurso
 
 
 /********** wxDbFreeConnection() **********/
 
 
 /********** wxDbFreeConnection() **********/
-bool WXDLLEXPORT wxDbFreeConnection(wxDb *pDb)
+bool WXDLLIMPEXP_ODBC wxDbFreeConnection(wxDb *pDb)
 {
     wxDbList *pList;
 
 {
     wxDbList *pList;
 
@@ -3423,17 +4183,17 @@ bool WXDLLEXPORT wxDbFreeConnection(wxDb *pDb)
     for (pList = PtrBegDbList; pList; pList = pList->PtrNext)
     {
         if (pList->PtrDb == pDb)  // Found it, now free it!!!
     for (pList = PtrBegDbList; pList; pList = pList->PtrNext)
     {
         if (pList->PtrDb == pDb)  // Found it, now free it!!!
-            return (pList->Free = TRUE);
+            return (pList->Free = true);
     }
 
     // Never found the database object, return failure
     }
 
     // Never found the database object, return failure
-    return(FALSE);
+    return false;
 
 }  // wxDbFreeConnection()
 
 
 /********** wxDbCloseConnections() **********/
 
 }  // wxDbFreeConnection()
 
 
 /********** wxDbCloseConnections() **********/
-void WXDLLEXPORT wxDbCloseConnections(void)
+void WXDLLIMPEXP_ODBC wxDbCloseConnections(void)
 {
     wxDbList *pList, *pNext;
 
 {
     wxDbList *pList, *pNext;
 
@@ -3443,6 +4203,7 @@ void WXDLLEXPORT wxDbCloseConnections(void)
         pNext = pList->PtrNext;       // Save the pointer to next
         pList->PtrDb->CommitTrans();  // Commit any open transactions on wxDb object
         pList->PtrDb->Close();        // Close the wxDb object
         pNext = pList->PtrNext;       // Save the pointer to next
         pList->PtrDb->CommitTrans();  // Commit any open transactions on wxDb object
         pList->PtrDb->Close();        // Close the wxDb object
+        pList->PtrDb->setCached(false);  // Allows deletion of the wxDb instance
         delete pList->PtrDb;          // Deletes the wxDb object
         delete pList;                 // Deletes the linked list object
     }
         delete pList->PtrDb;          // Deletes the wxDb object
         delete pList;                 // Deletes the linked list object
     }
@@ -3454,7 +4215,7 @@ void WXDLLEXPORT wxDbCloseConnections(void)
 
 
 /********** wxDbConnectionsInUse() **********/
 
 
 /********** wxDbConnectionsInUse() **********/
-int WXDLLEXPORT wxDbConnectionsInUse(void)
+int WXDLLIMPEXP_ODBC wxDbConnectionsInUse(void)
 {
     wxDbList *pList;
     int cnt = 0;
 {
     wxDbList *pList;
     int cnt = 0;
@@ -3462,7 +4223,7 @@ int WXDLLEXPORT wxDbConnectionsInUse(void)
     // Scan the linked list counting db connections that are currently in use
     for (pList = PtrBegDbList; pList; pList = pList->PtrNext)
     {
     // Scan the linked list counting db connections that are currently in use
     for (pList = PtrBegDbList; pList; pList = pList->PtrNext)
     {
-        if (pList->Free == FALSE)
+        if (pList->Free == false)
             cnt++;
     }
 
             cnt++;
     }
 
@@ -3471,31 +4232,79 @@ int WXDLLEXPORT wxDbConnectionsInUse(void)
 }  // wxDbConnectionsInUse()
 
 
 }  // wxDbConnectionsInUse()
 
 
+
+/********** wxDbLogExtendedErrorMsg() **********/
+// DEBUG ONLY function
+const wxChar WXDLLIMPEXP_ODBC *wxDbLogExtendedErrorMsg(const wxChar *userText,
+                                                  wxDb *pDb,
+                                                  const wxChar *ErrFile,
+                                                  int ErrLine)
+{
+    static wxString msg;
+    msg = userText;
+
+    wxString tStr;
+
+    if (ErrFile || ErrLine)
+    {
+        msg += wxT("File: ");
+        msg += ErrFile;
+        msg += wxT("   Line: ");
+        tStr.Printf(wxT("%d"),ErrLine);
+        msg += tStr.c_str();
+        msg += wxT("\n");
+    }
+
+    msg.Append (wxT("\nODBC errors:\n"));
+    msg += wxT("\n");
+
+    // Display errors for this connection
+    int i;
+    for (i = 0; i < DB_MAX_ERROR_HISTORY; i++)
+    {
+        if (pDb->errorList[i])
+        {
+            msg.Append(pDb->errorList[i]);
+            if (wxStrcmp(pDb->errorList[i], wxEmptyString) != 0)
+                msg.Append(wxT("\n"));
+            // Clear the errmsg buffer so the next error will not
+            // end up showing the previous error that have occurred
+            wxStrcpy(pDb->errorList[i], wxEmptyString);
+        }
+    }
+    msg += wxT("\n");
+
+    wxLogDebug(msg.c_str());
+
+    return msg.c_str();
+}  // wxDbLogExtendedErrorMsg()
+
+
 /********** wxDbSqlLog() **********/
 bool wxDbSqlLog(wxDbSqlLogState state, const wxChar *filename)
 {
 /********** wxDbSqlLog() **********/
 bool wxDbSqlLog(wxDbSqlLogState state, const wxChar *filename)
 {
-    bool append = FALSE;
+    bool append = false;
     wxDbList *pList;
 
     for (pList = PtrBegDbList; pList; pList = pList->PtrNext)
     {
         if (!pList->PtrDb->SetSqlLogging(state,filename,append))
     wxDbList *pList;
 
     for (pList = PtrBegDbList; pList; pList = pList->PtrNext)
     {
         if (!pList->PtrDb->SetSqlLogging(state,filename,append))
-            return(FALSE);
-        append = TRUE;
+            return false;
+        append = true;
     }
 
     SQLLOGstate = state;
     SQLLOGfn = filename;
 
     }
 
     SQLLOGstate = state;
     SQLLOGfn = filename;
 
-    return(TRUE);
+    return true;
 
 }  // wxDbSqlLog()
 
 
 #if 0
 /********** wxDbCreateDataSource() **********/
 
 }  // wxDbSqlLog()
 
 
 #if 0
 /********** wxDbCreateDataSource() **********/
-int wxDbCreateDataSource(const char *driverName, const char *dsn, const char *description,
-                         bool sysDSN, const char *defDir, wxWindow *parent)
+int wxDbCreateDataSource(const wxString &driverName, const wxString &dsn, const wxString &description,
+                         bool sysDSN, const wxString &defDir, wxWindow *parent)
 /*
  * !!!! ONLY FUNCTIONAL UNDER MSW with VC6 !!!!
  * Very rudimentary creation of an ODBC data source.
 /*
  * !!!! ONLY FUNCTIONAL UNDER MSW with VC6 !!!!
  * Very rudimentary creation of an ODBC data source.
@@ -3518,16 +4327,16 @@ int wxDbCreateDataSource(const char *driverName, const char *dsn, const char *de
     // NOTE: The decimal 2 is an invalid character in all keyword pairs
     // so that is why I used it, as wxString does not deal well with
     // embedded nulls in strings
     // NOTE: The decimal 2 is an invalid character in all keyword pairs
     // so that is why I used it, as wxString does not deal well with
     // embedded nulls in strings
-    setupStr.sprintf("DSN=%s%cDescription=%s%cDefaultDir=%s%c",dsn,2,description,2,defDir,2);
+    setupStr.Printf(wxT("DSN=%s%cDescription=%s%cDefaultDir=%s%c"),dsn,2,description,2,defDir,2);
 
 
-    // Replace the separator from above with the '\0' seperator needed
+    // Replace the separator from above with the '\0' separator needed
     // by the SQLConfigDataSource() function
     int k;
     do
     {
     // by the SQLConfigDataSource() function
     int k;
     do
     {
-        k = setupStr.Find((wxChar)2,TRUE);
+        k = setupStr.Find((wxChar)2,true);
         if (k != wxNOT_FOUND)
         if (k != wxNOT_FOUND)
-            setupStr[(UINT)k] = '\0';
+            setupStr[(UINT)k] = wxT('\0');
     }
     while (k != wxNOT_FOUND);
 
     }
     while (k != wxNOT_FOUND);
 
@@ -3540,7 +4349,7 @@ int wxDbCreateDataSource(const char *driverName, const char *dsn, const char *de
         DWORD retcode = 0;
         WORD cb;
         wxChar errMsg[SQL_MAX_MESSAGE_LENGTH];
         DWORD retcode = 0;
         WORD cb;
         wxChar errMsg[SQL_MAX_MESSAGE_LENGTH];
-        errMsg[0] = '\0';
+        errMsg[0] = wxT('\0');
 
         // This function is only supported in ODBC drivers v3.0 compliant and above
         SQLInstallerError(1,&retcode,errMsg,SQL_MAX_MESSAGE_LENGTH-1,&cb);
 
         // This function is only supported in ODBC drivers v3.0 compliant and above
         SQLInstallerError(1,&retcode,errMsg,SQL_MAX_MESSAGE_LENGTH-1,&cb);
@@ -3564,7 +4373,7 @@ int wxDbCreateDataSource(const char *driverName, const char *dsn, const char *de
     // Using iODBC/unixODBC or some other compiler which does not support the APIs
     // necessary to use this function, so this function is not supported
 #ifdef __WXDEBUG__
     // Using iODBC/unixODBC or some other compiler which does not support the APIs
     // necessary to use this function, so this function is not supported
 #ifdef __WXDEBUG__
-    wxLogDebug("wxDbCreateDataSource() not available except under VC++/MSW",wxT("ODBC DEBUG MESSAGE"));
+    wxLogDebug(wxT("wxDbCreateDataSource() not available except under VC++/MSW"),wxT("ODBC DEBUG MESSAGE"));
 #endif
     result = FALSE;
 #endif  // __VISUALC__
 #endif
     result = FALSE;
 #endif  // __VISUALC__
@@ -3576,20 +4385,22 @@ int wxDbCreateDataSource(const char *driverName, const char *dsn, const char *de
 
 
 /********** wxDbGetDataSource() **********/
 
 
 /********** wxDbGetDataSource() **********/
-bool wxDbGetDataSource(HENV henv, char *Dsn, SWORD DsnMax, char *DsDesc, SWORD DsDescMax,
-                         UWORD direction)
+bool wxDbGetDataSource(HENV henv, wxChar *Dsn, SWORD DsnMaxLength, wxChar *DsDesc,
+                       SWORD DsDescMaxLength, UWORD direction)
 /*
  * Dsn and DsDesc will contain the data source name and data source
  * description upon return
  */
 {
     SWORD cb1,cb2;
 /*
  * Dsn and DsDesc will contain the data source name and data source
  * description upon return
  */
 {
     SWORD cb1,cb2;
+    SWORD lengthDsn = (SWORD)(DsnMaxLength*sizeof(wxChar));
+    SWORD lengthDsDesc = (SWORD)(DsDescMaxLength*sizeof(wxChar));
 
 
-    if (SQLDataSources(henv, direction, (UCHAR FAR *) Dsn, DsnMax, &cb1,
-                             (UCHAR FAR *) DsDesc, DsDescMax, &cb2) == SQL_SUCCESS)
-        return(TRUE);
+    if (SQLDataSources(henv, direction, (SQLTCHAR FAR *) Dsn, lengthDsn, &cb1,
+                       (SQLTCHAR FAR *) DsDesc, lengthDsDesc, &cb2) == SQL_SUCCESS)
+        return true;
     else
     else
-        return(FALSE);
+        return false;
 
 }  // wxDbGetDataSource()
 
 
 }  // wxDbGetDataSource()
 
@@ -3600,7 +4411,7 @@ bool wxDbGetDataSource(HENV henv, char *Dsn, SWORD DsnMax, char *DsDesc, SWORD D
  ********************************************************************
  *
  * The following functions are all DEPRECATED and are included for
  ********************************************************************
  *
  * The following functions are all DEPRECATED and are included for
- * backward compatability reasons only
+ * backward compatibility reasons only
  *
  ********************************************************************
  ********************************************************************/
  *
  ********************************************************************
  ********************************************************************/
@@ -3615,22 +4426,22 @@ bool GetDataSource(HENV henv, char *Dsn, SWORD DsnMax, char *DsDesc, SWORD DsDes
     return wxDbGetDataSource(henv, Dsn, DsnMax, DsDesc, DsDescMax, direction);
 }
 /***** DEPRECATED: use wxDbGetConnection() *****/
     return wxDbGetDataSource(henv, Dsn, DsnMax, DsDesc, DsDescMax, direction);
 }
 /***** DEPRECATED: use wxDbGetConnection() *****/
-wxDb WXDLLEXPORT *GetDbConnection(DbStuff *pDbStuff, bool FwdOnlyCursors)
+wxDb WXDLLIMPEXP_ODBC *GetDbConnection(DbStuff *pDbStuff, bool FwdOnlyCursors)
 {
     return wxDbGetConnection((wxDbConnectInf *)pDbStuff, FwdOnlyCursors);
 }
 /***** DEPRECATED: use wxDbFreeConnection() *****/
 {
     return wxDbGetConnection((wxDbConnectInf *)pDbStuff, FwdOnlyCursors);
 }
 /***** DEPRECATED: use wxDbFreeConnection() *****/
-bool WXDLLEXPORT FreeDbConnection(wxDb *pDb)
+bool WXDLLIMPEXP_ODBC FreeDbConnection(wxDb *pDb)
 {
     return wxDbFreeConnection(pDb);
 }
 /***** DEPRECATED: use wxDbCloseConnections() *****/
 {
     return wxDbFreeConnection(pDb);
 }
 /***** DEPRECATED: use wxDbCloseConnections() *****/
-void WXDLLEXPORT CloseDbConnections(void)
+void WXDLLIMPEXP_ODBC CloseDbConnections(void)
 {
     wxDbCloseConnections();
 }
 /***** DEPRECATED: use wxDbConnectionsInUse() *****/
 {
     wxDbCloseConnections();
 }
 /***** DEPRECATED: use wxDbConnectionsInUse() *****/
-int WXDLLEXPORT NumberDbConnectionsInUse(void)
+int WXDLLIMPEXP_ODBC NumberDbConnectionsInUse(void)
 {
     return wxDbConnectionsInUse();
 }
 {
     return wxDbConnectionsInUse();
 }