X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/5054c9365a68862e9fc662f2ca1677404ddc14a7..db6634e0d53fce875c78a089f4237a88ae206335:/src/common/db.cpp diff --git a/src/common/db.cpp b/src/common/db.cpp index a73b422186..7ca9dc47ae 100644 --- a/src/common/db.cpp +++ b/src/common/db.cpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////// -// Name: db.cpp +// Name: src/common/db.cpp // Purpose: Implementation of the wxDb class. The wxDb class represents a connection // to an ODBC data source. The wxDb class allows operations on the data // source such as opening and closing the data source. @@ -21,36 +21,30 @@ // Licence: wxWindows licence /////////////////////////////////////////////////////////////////////////////// -/* -// SYNOPSIS START -// SYNOPSIS STOP -*/ -#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) - #pragma implementation "db.h" -#endif - #include "wx/wxprec.h" #ifdef __BORLANDC__ #pragma hdrstop #endif -#ifdef DBDEBUG_CONSOLE - #include "wx/ioswrap.h" -#endif +#if wxUSE_ODBC #ifndef WX_PRECOMP - #include "wx/string.h" #include "wx/object.h" #include "wx/list.h" + #include "wx/string.h" #include "wx/utils.h" #include "wx/log.h" + #include "wx/app.h" +#endif + +#ifdef DBDEBUG_CONSOLE + #include "wx/ioswrap.h" #endif + #include "wx/filefn.h" #include "wx/wxchar.h" -#if wxUSE_ODBC - #include #include #include @@ -59,8 +53,14 @@ #include "wx/db.h" +// FIXME-UTF8: get rid of this after switching to Unicode-only builds: +#if wxUSE_UNICODE + #define WXSQLCAST(s) ((SQLTCHAR FAR *)(wchar_t*)(s).wchar_str()) +#else + #define WXSQLCAST(s) ((SQLTCHAR FAR *)(char*)(s).char_str()) +#endif + // DLL options compatibility check: -#include "wx/app.h" WX_CHECK_BUILD_OPTIONS("wxODBC") WXDLLIMPEXP_DATA_ODBC(wxDbList*) PtrBegDbList = 0; @@ -69,7 +69,10 @@ wxChar const *SQL_LOG_FILENAME = wxT("sqllog.txt"); wxChar const *SQL_CATALOG_FILENAME = wxT("catalog.txt"); #ifdef __WXDEBUG__ + #include "wx/thread.h" + extern wxList TablesInUse; + extern wxCriticalSection csTablesInUse; #endif // SQL Log defaults to be used by GetDbConnection @@ -179,7 +182,7 @@ bool wxDbConnectInf::AllocHenv() // Initialize the ODBC Environment for Database Operations if (SQLAllocEnv(&Henv) != SQL_SUCCESS) { - wxLogDebug(wxT("A problem occured while trying to get a connection to the data source")); + wxLogDebug(wxT("A problem occurred while trying to get a connection to the data source")); return false; } @@ -204,37 +207,37 @@ void wxDbConnectInf::FreeHenv() void wxDbConnectInf::SetDsn(const wxString &dsn) { - wxASSERT(dsn.Length() < sizeof(Dsn)); + wxASSERT(dsn.length() < WXSIZEOF(Dsn)); - wxStrncpy(Dsn, dsn, sizeof(Dsn)-1); - Dsn[sizeof(Dsn)-1] = 0; // Prevent buffer overrun + wxStrncpy(Dsn, dsn, WXSIZEOF(Dsn)-1); + Dsn[WXSIZEOF(Dsn)-1] = 0; // Prevent buffer overrun } // wxDbConnectInf::SetDsn() void wxDbConnectInf::SetUserID(const wxString &uid) { - wxASSERT(uid.Length() < sizeof(Uid)); - wxStrncpy(Uid, uid, sizeof(Uid)-1); - Uid[sizeof(Uid)-1] = 0; // Prevent buffer overrun + wxASSERT(uid.length() < WXSIZEOF(Uid)); + wxStrncpy(Uid, uid, WXSIZEOF(Uid)-1); + Uid[WXSIZEOF(Uid)-1] = 0; // Prevent buffer overrun } // wxDbConnectInf::SetUserID() void wxDbConnectInf::SetPassword(const wxString &password) { - wxASSERT(password.Length() < sizeof(AuthStr)); + wxASSERT(password.length() < WXSIZEOF(AuthStr)); - wxStrncpy(AuthStr, password, sizeof(AuthStr)-1); - AuthStr[sizeof(AuthStr)-1] = 0; // Prevent buffer overrun + wxStrncpy(AuthStr, password, WXSIZEOF(AuthStr)-1); + AuthStr[WXSIZEOF(AuthStr)-1] = 0; // Prevent buffer overrun } // wxDbConnectInf::SetPassword() void wxDbConnectInf::SetConnectionStr(const wxString &connectStr) { - wxASSERT(connectStr.Length() < sizeof(ConnectionStr)); + wxASSERT(connectStr.length() < WXSIZEOF(ConnectionStr)); useConnectionStr = wxStrlen(connectStr) > 0; - wxStrncpy(ConnectionStr, connectStr, sizeof(ConnectionStr)-1); - ConnectionStr[sizeof(ConnectionStr)-1] = 0; // Prevent buffer overrun + wxStrncpy(ConnectionStr, connectStr, WXSIZEOF(ConnectionStr)-1); + ConnectionStr[WXSIZEOF(ConnectionStr)-1] = 0; // Prevent buffer overrun } // wxDbConnectInf::SetConnectionStr() @@ -290,7 +293,7 @@ int wxDbColFor::Format(int Nation, int dbDataType, SWORD sqlDataType, if ((i_sqlDataType == SQL_VARCHAR) #if wxUSE_UNICODE #if defined(SQL_WCHAR) - || (i_sqlDataType == SQL_WCHAR) + || (i_sqlDataType == SQL_WCHAR) #endif #if defined(SQL_WVARCHAR) || (i_sqlDataType == SQL_WVARCHAR) @@ -326,8 +329,7 @@ int wxDbColFor::Format(int Nation, int dbDataType, SWORD sqlDataType, case DB_DATA_TYPE_FLOAT: if (decimalDigits == 0) decimalDigits = 2; - tempStr = wxT("%"); - tempStr.Printf(wxT("%s%d.%d"), tempStr.c_str(),columnLength, decimalDigits); + tempStr.Printf(wxT("%%%d.%d"), columnLength, decimalDigits); s_Field.Printf(wxT("%sf"), tempStr.c_str()); break; case DB_DATA_TYPE_DATE: @@ -536,6 +538,12 @@ void wxDb::initialize() typeInfBlob.CaseSensitive = 0; typeInfBlob.MaximumScale = 0; + typeInfMemo.TypeName.Empty(); + typeInfMemo.FsqlType = 0; + typeInfMemo.Precision = 0; + typeInfMemo.CaseSensitive = 0; + typeInfMemo.MaximumScale = 0; + // Error reporting is turned OFF by default silent = true; @@ -559,7 +567,7 @@ void wxDb::initialize() // immediately, as the value is not good after // this function has left scope. // -const wxChar *wxDb::convertUserID(const wxChar *userID, wxString &UserID) +void wxDb::convertUserID(const wxChar *userID, wxString &UserID) { if (userID) { @@ -576,12 +584,11 @@ const wxChar *wxDb::convertUserID(const wxChar *userID, wxString &UserID) || Dbms() == dbmsXBASE_SEQUITER ) UserID.Empty(); - // Oracle user names may only be in uppercase, so force - // the name to uppercase - if (Dbms() == dbmsORACLE) + // Some databases require user names to be specified in uppercase, + // so force the name to uppercase + if ((Dbms() == dbmsORACLE) || + (Dbms() == dbmsMAXDB)) UserID = UserID.Upper(); - - return UserID.c_str(); } // wxDb::convertUserID() @@ -653,6 +660,16 @@ bool wxDb::determineDataTypes(bool failOnDataTypeUnsupported) SQL_VARBINARY }; + // These are the possible SQL types we check for use agains the datasource we are connected + // to for the purpose of determining which data type to use for the MEMO column types + // (a type which allow to store large strings; like VARCHAR just with a bigger precision) + // + // NOTE: The first type in this enumeration that is determined to be supported by the + // datasource/driver is the one that will be used. + SWORD PossibleSqlMemoTypes[] = { + SQL_LONGVARCHAR, + }; + // Query the data source regarding data type information @@ -759,6 +776,16 @@ bool wxDb::determineDataTypes(bool failOnDataTypeUnsupported) else if (failOnDataTypeUnsupported) return false; + // --------------- MEMO --------------- + for (iIndex = 0; iIndex < WXSIZEOF(PossibleSqlMemoTypes) && + !getDataTypeInfo(PossibleSqlMemoTypes[iIndex], typeInfMemo); ++iIndex) + {} + + if (iIndex < WXSIZEOF(PossibleSqlMemoTypes)) + typeInfMemo.FsqlType = PossibleSqlMemoTypes[iIndex]; + else if (failOnDataTypeUnsupported) + return false; + return true; } // wxDb::determineDataTypes @@ -793,6 +820,7 @@ bool wxDb::open(bool failOnDataTypeUnsupported) cout << wxT("FLOAT DATA TYPE: ") << typeInfFloat.TypeName << endl; cout << wxT("DATE DATA TYPE: ") << typeInfDate.TypeName << endl; cout << wxT("BLOB DATA TYPE: ") << typeInfBlob.TypeName << endl; + cout << wxT("MEMO DATA TYPE: ") << typeInfMemo.TypeName << endl; cout << endl; #endif @@ -802,10 +830,15 @@ bool wxDb::open(bool failOnDataTypeUnsupported) bool wxDb::Open(const wxString& inConnectStr, bool failOnDataTypeUnsupported) { - wxASSERT(inConnectStr.Length()); - dsn = wxT(""); - uid = wxT(""); - authStr = wxT(""); + wxASSERT(inConnectStr.length()); + return Open(inConnectStr, NULL, failOnDataTypeUnsupported); +} + +bool wxDb::Open(const wxString& inConnectStr, SQLHWND parentWnd, bool failOnDataTypeUnsupported) +{ + dsn = wxEmptyString; + uid = wxEmptyString; + authStr = wxEmptyString; RETCODE retcode; @@ -831,9 +864,9 @@ bool wxDb::Open(const wxString& inConnectStr, bool failOnDataTypeUnsupported) inConnectionStr = inConnectStr; - retcode = SQLDriverConnect(hdbc, NULL, (SQLTCHAR FAR *)inConnectionStr.c_str(), - (SWORD)inConnectionStr.Length(), (SQLTCHAR FAR *)outConnectBuffer, - sizeof(outConnectBuffer), &outConnectBufferLen, SQL_DRIVER_COMPLETE ); + retcode = SQLDriverConnect(hdbc, parentWnd, WXSQLCAST(inConnectionStr), + (SWORD)inConnectionStr.length(), (SQLTCHAR FAR *)outConnectBuffer, + WXSIZEOF(outConnectBuffer), &outConnectBufferLen, SQL_DRIVER_COMPLETE ); if ((retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO)) @@ -849,13 +882,13 @@ bool wxDb::Open(const wxString& inConnectStr, bool failOnDataTypeUnsupported) /********** wxDb::Open() **********/ bool wxDb::Open(const wxString &Dsn, const wxString &Uid, const wxString &AuthStr, bool failOnDataTypeUnsupported) { - wxASSERT(Dsn.Length()); + wxASSERT(!Dsn.empty()); dsn = Dsn; uid = Uid; authStr = AuthStr; - inConnectionStr = wxT(""); - outConnectionStr = wxT(""); + inConnectionStr = wxEmptyString; + outConnectionStr = wxEmptyString; RETCODE retcode; @@ -876,9 +909,10 @@ bool wxDb::Open(const wxString &Dsn, const wxString &Uid, const wxString &AuthSt } // Connect to the data source - retcode = SQLConnect(hdbc, (SQLTCHAR FAR *) dsn.c_str(), SQL_NTS, - (SQLTCHAR FAR *) uid.c_str(), SQL_NTS, - (SQLTCHAR FAR *) authStr.c_str(), SQL_NTS); + retcode = SQLConnect(hdbc, + WXSQLCAST(dsn), SQL_NTS, + WXSQLCAST(uid), SQL_NTS, + WXSQLCAST(authStr), SQL_NTS); if ((retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO)) @@ -895,7 +929,7 @@ bool wxDb::Open(wxDbConnectInf *dbConnectInf, bool failOnDataTypeUnsupported) // Use the connection string if one is present if (dbConnectInf->UseConnectionStr()) - return Open(GetConnectionInStr(), failOnDataTypeUnsupported); + return Open(dbConnectInf->GetConnectionStr(), failOnDataTypeUnsupported); else return Open(dbConnectInf->GetDsn(), dbConnectInf->GetUserID(), dbConnectInf->GetPassword(), failOnDataTypeUnsupported); @@ -936,9 +970,9 @@ bool wxDb::Open(wxDb *copyDb) inConnectionStr = copyDb->GetConnectionInStr(); - retcode = SQLDriverConnect(hdbc, NULL, (SQLTCHAR FAR *)inConnectionStr.c_str(), - (SWORD)inConnectionStr.Length(), (SQLTCHAR FAR *)outConnectBuffer, - sizeof(outConnectBuffer), &outConnectBufferLen, SQL_DRIVER_COMPLETE); + retcode = SQLDriverConnect(hdbc, NULL, WXSQLCAST(inConnectionStr), + (SWORD)inConnectionStr.length(), (SQLTCHAR FAR *)outConnectBuffer, + WXSIZEOF(outConnectBuffer), &outConnectBufferLen, SQL_DRIVER_COMPLETE); if ((retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO)) @@ -951,9 +985,10 @@ bool wxDb::Open(wxDb *copyDb) else { // Connect to the data source - retcode = SQLConnect(hdbc, (SQLTCHAR FAR *) dsn.c_str(), SQL_NTS, - (SQLTCHAR FAR *) uid.c_str(), SQL_NTS, - (SQLTCHAR FAR *) authStr.c_str(), SQL_NTS); + retcode = SQLConnect(hdbc, + WXSQLCAST(dsn), SQL_NTS, + WXSQLCAST(uid), SQL_NTS, + WXSQLCAST(authStr), SQL_NTS); } if ((retcode != SQL_SUCCESS) && @@ -1048,12 +1083,20 @@ bool wxDb::Open(wxDb *copyDb) typeInfBlob.CaseSensitive = copyDb->typeInfBlob.CaseSensitive; typeInfBlob.MaximumScale = copyDb->typeInfBlob.MaximumScale; + // Memo + typeInfMemo.FsqlType = copyDb->typeInfMemo.FsqlType; + typeInfMemo.TypeName = copyDb->typeInfMemo.TypeName; + typeInfMemo.Precision = copyDb->typeInfMemo.Precision; + typeInfMemo.CaseSensitive = copyDb->typeInfMemo.CaseSensitive; + typeInfMemo.MaximumScale = copyDb->typeInfMemo.MaximumScale; + #ifdef DBDEBUG_CONSOLE cout << wxT("VARCHAR DATA TYPE: ") << typeInfVarchar.TypeName << endl; cout << wxT("INTEGER DATA TYPE: ") << typeInfInteger.TypeName << endl; cout << wxT("FLOAT DATA TYPE: ") << typeInfFloat.TypeName << endl; cout << wxT("DATE DATA TYPE: ") << typeInfDate.TypeName << endl; cout << wxT("BLOB DATA TYPE: ") << typeInfBlob.TypeName << endl; + cout << wxT("MEMO DATA TYPE: ") << typeInfMemo.TypeName << endl; cout << endl; #endif @@ -1606,7 +1649,7 @@ bool wxDb::getDataTypeInfo(SWORD fSqlType, wxDbSqlTypeInfo &structSQLTypeInfo) * 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) @@ -1713,20 +1756,24 @@ void wxDb::Close(void) wxASSERT(nTables == 0); #ifdef __WXDEBUG__ - wxTablesInUse *tiu; - wxList::compatibility_iterator pNode; - pNode = TablesInUse.GetFirst(); - wxString s,s2; - while (pNode) { - tiu = (wxTablesInUse *)pNode->GetData(); - if (tiu->pDb == this) + wxCriticalSectionLocker lock(csTablesInUse); + wxTablesInUse *tiu; + wxList::compatibility_iterator pNode; + pNode = TablesInUse.GetFirst(); + wxString s,s2; + while (pNode) { - s.Printf(wxT("(%-20s) tableID:[%6lu] pDb:[%p]"), tiu->tableName,tiu->tableID,tiu->pDb); - s2.Printf(wxT("Orphaned table found using pDb:[%p]"),this); - wxLogDebug(s.c_str(),s2.c_str()); + tiu = (wxTablesInUse *)pNode->GetData(); + if (tiu->pDb == this) + { + s.Printf(wxT("(%-20s) tableID:[%6lu] pDb:[%p]"), + tiu->tableName, tiu->tableID, wx_static_cast(void*, tiu->pDb)); + s2.Printf(wxT("Orphaned table found using pDb:[%p]"), wx_static_cast(void*, this)); + wxLogDebug(s.c_str(),s2.c_str()); + } + pNode = pNode->GetNext(); } - pNode = pNode->GetNext(); } #endif @@ -1775,27 +1822,24 @@ 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 - * 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 * 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. * - * 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 - * 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; -#ifdef __VMS - while (SQLError(aHenv, aHdbc, aHstmt, (SQLTCHAR FAR *) sqlState, (SQLINTEGER *) &nativeError, (SQLTCHAR FAR *) errorMsg, SQL_MAX_MESSAGE_LENGTH - 1, &cbErrorMsg) == SQL_SUCCESS) -#else - while (SQLError(aHenv, aHdbc, aHstmt, (SQLTCHAR FAR *) sqlState, (long*) &nativeError, (SQLTCHAR FAR *) errorMsg, SQL_MAX_MESSAGE_LENGTH - 1, &cbErrorMsg) == SQL_SUCCESS) -#endif + while (SQLError(aHenv, aHdbc, aHstmt, (SQLTCHAR FAR *) sqlState, &nativeError, (SQLTCHAR FAR *) errorMsg, SQL_MAX_MESSAGE_LENGTH - 1, &cbErrorMsg) == SQL_SUCCESS) { - odbcErrMsg.Printf(wxT("SQL State = %s\nNative Error Code = %li\nError Message = %s\n"), sqlState, nativeError, errorMsg); + odbcErrMsg.Printf(wxT("SQL State = %s\nNative Error Code = %li\nError Message = %s\n"), + sqlState, (long)nativeError, errorMsg); logError(odbcErrMsg, sqlState); if (!silent) { @@ -1820,11 +1864,7 @@ bool wxDb::DispAllErrors(HENV aHenv, HDBC aHdbc, HSTMT aHstmt) /********** wxDb::GetNextError() **********/ bool wxDb::GetNextError(HENV aHenv, HDBC aHdbc, HSTMT aHstmt) { -#ifdef __VMS - if (SQLError(aHenv, aHdbc, aHstmt, (SQLTCHAR FAR *) sqlState, (SQLINTEGER *) &nativeError, (SQLTCHAR FAR *) errorMsg, SQL_MAX_MESSAGE_LENGTH - 1, &cbErrorMsg) == SQL_SUCCESS) -#else - if (SQLError(aHenv, aHdbc, aHstmt, (SQLTCHAR FAR *) sqlState, (long*) &nativeError, (SQLTCHAR FAR *) errorMsg, SQL_MAX_MESSAGE_LENGTH - 1, &cbErrorMsg) == SQL_SUCCESS) -#endif + if (SQLError(aHenv, aHdbc, aHstmt, (SQLTCHAR FAR *) sqlState, &nativeError, (SQLTCHAR FAR *) errorMsg, SQL_MAX_MESSAGE_LENGTH - 1, &cbErrorMsg) == SQL_SUCCESS) return true; else return false; @@ -1837,7 +1877,8 @@ void wxDb::DispNextError(void) { wxString odbcErrMsg; - odbcErrMsg.Printf(wxT("SQL State = %s\nNative Error Code = %li\nError Message = %s\n"), sqlState, nativeError, errorMsg); + odbcErrMsg.Printf(wxT("SQL State = %s\nNative Error Code = %li\nError Message = %s\n"), + sqlState, (long)nativeError, errorMsg); logError(odbcErrMsg, sqlState); if (silent) @@ -1860,7 +1901,7 @@ void wxDb::DispNextError(void) /********** wxDb::logError() **********/ void wxDb::logError(const wxString &errMsg, const wxString &SQLState) { - wxASSERT(errMsg.Length()); + wxASSERT(errMsg.length()); static int pLast = -1; int dbStatus; @@ -1876,7 +1917,7 @@ void wxDb::logError(const wxString &errMsg, const wxString &SQLState) wxStrncpy(errorList[pLast], errMsg, DB_MAX_ERROR_MSG_LEN); errorList[pLast][DB_MAX_ERROR_MSG_LEN] = 0; - if (SQLState.Length()) + if (SQLState.length()) if ((dbStatus = TranslateSqlState(SQLState)) != DB_ERR_FUNCTION_SEQUENCE_ERROR) DB_STATUS = dbStatus; @@ -2141,7 +2182,7 @@ bool wxDb::CreateView(const wxString &viewName, const wxString &colList, sqlStmt = wxT("CREATE VIEW "); sqlStmt += viewName; - if (colList.Length()) + if (colList.length()) { sqlStmt += wxT(" ("); sqlStmt += colList; @@ -2181,7 +2222,7 @@ bool wxDb::DropView(const wxString &viewName) cout << endl << sqlStmt.c_str() << endl; #endif - if (SQLExecDirect(hstmt, (SQLTCHAR FAR *) sqlStmt.c_str(), SQL_NTS) != SQL_SUCCESS) + if (SQLExecDirect(hstmt, WXSQLCAST(sqlStmt), SQL_NTS) != SQL_SUCCESS) { // Check for "Base table not found" error and ignore GetNextError(henv, hdbc, hstmt); @@ -2214,7 +2255,7 @@ bool wxDb::ExecSql(const wxString &pSqlStmt) SQLFreeStmt(hstmt, SQL_CLOSE); - retcode = SQLExecDirect(hstmt, (SQLTCHAR FAR *) pSqlStmt.c_str(), SQL_NTS); + retcode = SQLExecDirect(hstmt, WXSQLCAST(pSqlStmt), SQL_NTS); if (retcode == SQL_SUCCESS || (Dbms() == dbmsDB2 && (retcode == SQL_SUCCESS_WITH_INFO || retcode == SQL_NO_DATA_FOUND))) { @@ -2252,7 +2293,7 @@ bool wxDb::ExecSql(const wxString &pSqlStmt, wxDbColInf** columns, short& numcol short colNum; wxChar name[DB_MAX_COLUMN_NAME_LEN+1]; SWORD Sword; - SDWORD Sdword; + SQLLEN Sqllen; wxDbColInf* pColInf = new wxDbColInf[noCols]; // Fill in column information (name, datatype) @@ -2260,7 +2301,7 @@ bool wxDb::ExecSql(const wxString &pSqlStmt, wxDbColInf** columns, short& numcol { if (SQLColAttributes(hstmt, (UWORD)(colNum+1), SQL_COLUMN_NAME, name, sizeof(name), - &Sword, &Sdword) != SQL_SUCCESS) + &Sword, &Sqllen) != SQL_SUCCESS) { DispAllErrors(henv, hdbc, hstmt); delete[] pColInf; @@ -2271,14 +2312,14 @@ bool wxDb::ExecSql(const wxString &pSqlStmt, wxDbColInf** columns, short& numcol pColInf[colNum].colName[DB_MAX_COLUMN_NAME_LEN] = 0; // Prevent buffer overrun if (SQLColAttributes(hstmt, (UWORD)(colNum+1), SQL_COLUMN_TYPE, - NULL, 0, &Sword, &Sdword) != SQL_SUCCESS) + NULL, 0, &Sword, &Sqllen) != SQL_SUCCESS) { DispAllErrors(henv, hdbc, hstmt); delete[] pColInf; return false; } - switch (Sdword) + switch (Sqllen) { #if wxUSE_UNICODE #if defined(SQL_WCHAR) @@ -2292,6 +2333,9 @@ bool wxDb::ExecSql(const wxString &pSqlStmt, wxDbColInf** columns, short& numcol case SQL_CHAR: pColInf[colNum].dbDataType = DB_DATA_TYPE_VARCHAR; break; + case SQL_LONGVARCHAR: + pColInf[colNum].dbDataType = DB_DATA_TYPE_MEMO; + break; case SQL_TINYINT: case SQL_SMALLINT: case SQL_INTEGER: @@ -2315,7 +2359,7 @@ bool wxDb::ExecSql(const wxString &pSqlStmt, wxDbColInf** columns, short& numcol #ifdef __WXDEBUG__ default: wxString errMsg; - errMsg.Printf(wxT("SQL Data type %ld currently not supported by wxWidgets"), (long)Sdword); + errMsg.Printf(wxT("SQL Data type %ld currently not supported by wxWidgets"), (long)Sqllen); wxLogDebug(errMsg,wxT("ODBC DEBUG MESSAGE")); #endif } @@ -2340,7 +2384,7 @@ bool wxDb::GetNext(void) /********** 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) { wxASSERT(pData); wxASSERT(cbReturned); @@ -2370,7 +2414,7 @@ int wxDb::GetKeyFields(const wxString &tableName, wxDbColInf* colInf, UWORD noCo wxChar szPkCol[DB_MAX_COLUMN_NAME_LEN+1]; /* Primary key column */ wxChar szFkCol[DB_MAX_COLUMN_NAME_LEN+1]; /* Foreign key column */ SQLRETURN retcode; - SDWORD cb; + SQLLEN cb; SWORD i; wxString tempStr; /* @@ -2392,7 +2436,7 @@ int wxDb::GetKeyFields(const wxString &tableName, wxDbColInf* colInf, UWORD noCo retcode = SQLPrimaryKeys(hstmt, NULL, 0, /* Catalog name */ NULL, 0, /* Schema name */ - (SQLTCHAR FAR *) tableName.c_str(), SQL_NTS); /* Table name */ + WXSQLCAST(tableName), SQL_NTS); /* Table name */ /*---------------------------------------------------------------------*/ /* Fetch and display the result set. This will be a list of the */ @@ -2419,7 +2463,7 @@ int wxDb::GetKeyFields(const wxString &tableName, wxDbColInf* colInf, UWORD noCo retcode = SQLForeignKeys(hstmt, NULL, 0, /* Primary catalog */ NULL, 0, /* Primary schema */ - (SQLTCHAR FAR *)tableName.c_str(), SQL_NTS,/* Primary table */ + WXSQLCAST(tableName), SQL_NTS,/* Primary table */ NULL, 0, /* Foreign catalog */ NULL, 0, /* Foreign schema */ NULL, 0); /* Foreign table */ @@ -2440,7 +2484,7 @@ int wxDb::GetKeyFields(const wxString &tableName, wxDbColInf* colInf, UWORD noCo 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.Printf(wxT("%s[%s] "),tempStr.c_str(),szFkTable); // [ ] in case there is a blank in the Table name + tempStr << _T('[') << szFkTable << _T(']'); // [ ] in case there is a blank in the Table name } // if } // while @@ -2468,7 +2512,7 @@ int wxDb::GetKeyFields(const wxString &tableName, wxDbColInf* colInf, UWORD noCo NULL, 0, /* Primary table */ NULL, 0, /* Foreign catalog */ NULL, 0, /* Foreign schema */ - (SQLTCHAR *)tableName.c_str(), SQL_NTS);/* Foreign table */ + WXSQLCAST(tableName), SQL_NTS);/* Foreign table */ /*---------------------------------------------------------------------*/ /* Fetch and display the result set. This will be all of the */ @@ -2509,7 +2553,7 @@ 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 - * 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. * @@ -2537,7 +2581,7 @@ wxDbColInf *wxDb::GetColumns(wxChar *tableName[], const wxChar *userID) wxDbColInf *colInf = 0; RETCODE retcode; - SDWORD cb; + SQLLEN cb; wxString TableName; @@ -2586,8 +2630,8 @@ wxDbColInf *wxDb::GetColumns(wxChar *tableName[], const wxChar *userID) { retcode = SQLColumns(hstmt, NULL, 0, // All qualifiers - (SQLTCHAR *) UserID.c_str(), SQL_NTS, // Owner - (SQLTCHAR *) TableName.c_str(), SQL_NTS, + WXSQLCAST(UserID), SQL_NTS, // Owner + WXSQLCAST(TableName), SQL_NTS, NULL, 0); // All columns } else @@ -2595,11 +2639,11 @@ wxDbColInf *wxDb::GetColumns(wxChar *tableName[], const wxChar *userID) retcode = SQLColumns(hstmt, NULL, 0, // All qualifiers NULL, 0, // Owner - (SQLTCHAR *) TableName.c_str(), SQL_NTS, + WXSQLCAST(TableName), SQL_NTS, NULL, 0); // All columns } if (retcode != SQL_SUCCESS) - { // Error occured, abort + { // Error occurred, abort DispAllErrors(henv, hdbc, hstmt); if (colInf) delete [] colInf; @@ -2657,7 +2701,7 @@ wxDbColInf *wxDb::GetColumns(wxChar *tableName[], const wxChar *userID) } } if (retcode != SQL_NO_DATA_FOUND) - { // Error occured, abort + { // Error occurred, abort DispAllErrors(henv, hdbc, hstmt); if (colInf) delete [] colInf; @@ -2696,7 +2740,7 @@ wxDbColInf *wxDb::GetColumns(const wxString &tableName, UWORD *numCols, const wx wxDbColInf *colInf = 0; RETCODE retcode; - SDWORD cb; + SQLLEN cb; wxString TableName; @@ -2742,8 +2786,8 @@ wxDbColInf *wxDb::GetColumns(const wxString &tableName, UWORD *numCols, const wx { retcode = SQLColumns(hstmt, NULL, 0, // All qualifiers - (SQLTCHAR *) UserID.c_str(), SQL_NTS, // Owner - (SQLTCHAR *) TableName.c_str(), SQL_NTS, + WXSQLCAST(UserID), SQL_NTS, // Owner + WXSQLCAST(TableName), SQL_NTS, NULL, 0); // All columns } else @@ -2751,11 +2795,11 @@ wxDbColInf *wxDb::GetColumns(const wxString &tableName, UWORD *numCols, const wx retcode = SQLColumns(hstmt, NULL, 0, // All qualifiers NULL, 0, // Owner - (SQLTCHAR *) TableName.c_str(), SQL_NTS, + WXSQLCAST(TableName), SQL_NTS, NULL, 0); // All columns } if (retcode != SQL_SUCCESS) - { // Error occured, abort + { // Error occurred, abort DispAllErrors(henv, hdbc, hstmt); if (colInf) delete [] colInf; @@ -2831,7 +2875,7 @@ wxDbColInf *wxDb::GetColumns(const wxString &tableName, UWORD *numCols, const wx } } if (retcode != SQL_NO_DATA_FOUND) - { // Error occured, abort + { // Error occurred, abort DispAllErrors(henv, hdbc, hstmt); if (colInf) delete [] colInf; @@ -2860,7 +2904,7 @@ wxDbColInf *wxDb::GetColumns(const wxString &tableName, UWORD *numCols, const wx /* 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. - The first one (wxDbColInf *wxDb::GetColumns(wxChar *tableName[], const @@ -3011,7 +3055,7 @@ wxDbColInf *wxDb::GetColumns(const wxString &tableName, int *numCols, const wxCh NULL, 0); // All columns } if (retcode != SQL_SUCCESS) - { // Error occured, abort + { // Error occurred, abort DispAllErrors(henv, hdbc, hstmt); if (colInf) delete [] colInf; @@ -3075,6 +3119,9 @@ wxDbColInf *wxDb::GetColumns(const wxString &tableName, int *numCols, const wxCh case SQL_CHAR: colInf[colNo].dbDataType = DB_DATA_TYPE_VARCHAR; break; + case SQL_LONGVARCHAR: + colInf[colNo].dbDataType = DB_DATA_TYPE_MEMO; + break; case SQL_TINYINT: case SQL_SMALLINT: case SQL_INTEGER: @@ -3107,7 +3154,7 @@ wxDbColInf *wxDb::GetColumns(const wxString &tableName, int *numCols, const wxCh } } if (retcode != SQL_NO_DATA_FOUND) - { // Error occured, abort + { // Error occurred, abort DispAllErrors(henv, hdbc, hstmt); if (colInf) delete [] colInf; @@ -3246,8 +3293,8 @@ int wxDb::GetColumnCount(const wxString &tableName, const wxChar *userID) { retcode = SQLColumns(hstmt, NULL, 0, // All qualifiers - (SQLTCHAR *) UserID.c_str(), SQL_NTS, // Owner - (SQLTCHAR *) TableName.c_str(), SQL_NTS, + WXSQLCAST(UserID), SQL_NTS, // Owner + WXSQLCAST(TableName), SQL_NTS, NULL, 0); // All columns } else @@ -3255,11 +3302,11 @@ int wxDb::GetColumnCount(const wxString &tableName, const wxChar *userID) retcode = SQLColumns(hstmt, NULL, 0, // All qualifiers NULL, 0, // Owner - (SQLTCHAR *) TableName.c_str(), SQL_NTS, + WXSQLCAST(TableName), SQL_NTS, NULL, 0); // All columns } if (retcode != SQL_SUCCESS) - { // Error occured, abort + { // Error occurred, abort DispAllErrors(henv, hdbc, hstmt); SQLFreeStmt(hstmt, SQL_CLOSE); return(-1); @@ -3270,7 +3317,7 @@ int wxDb::GetColumnCount(const wxString &tableName, const wxChar *userID) noCols++; if (retcode != SQL_NO_DATA_FOUND) - { // Error occured, abort + { // Error occurred, abort DispAllErrors(henv, hdbc, hstmt); SQLFreeStmt(hstmt, SQL_CLOSE); return(-1); @@ -3291,7 +3338,7 @@ wxDbInf *wxDb::GetCatalog(const wxChar *userID) * -- : 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(..); ------ * --------------------------------------------------------------------- @@ -3309,7 +3356,7 @@ wxDbInf *wxDb::GetCatalog(const wxChar *userID) int noTab = 0; // Counter while filling table entries int pass; RETCODE retcode; - SDWORD cb; + SQLLEN cb; wxString tblNameSave; wxString UserID; @@ -3339,7 +3386,7 @@ wxDbInf *wxDb::GetCatalog(const wxChar *userID) { retcode = SQLTables(hstmt, NULL, 0, // All qualifiers - (SQLTCHAR *) UserID.c_str(), SQL_NTS, // User specified + WXSQLCAST(UserID), SQL_NTS, // User specified NULL, 0, // All tables NULL, 0); // All columns } @@ -3417,10 +3464,10 @@ bool wxDb::Catalog(const wxChar *userID, const wxString &fileName) * to avoid undesired unbinding of columns. */ { - wxASSERT(fileName.Length()); + wxASSERT(fileName.length()); RETCODE retcode; - SDWORD cb; + SQLLEN cb; wxChar tblName[DB_MAX_TABLE_NAME_LEN+1]; wxString tblNameSave; wxChar colName[DB_MAX_COLUMN_NAME_LEN+1]; @@ -3446,7 +3493,7 @@ bool wxDb::Catalog(const wxChar *userID, const wxString &fileName) { retcode = SQLColumns(hstmt, NULL, 0, // All qualifiers - (SQLTCHAR *) UserID.c_str(), SQL_NTS, // User specified + WXSQLCAST(UserID), SQL_NTS, // User specified NULL, 0, // All tables NULL, 0); // All columns } @@ -3537,14 +3584,14 @@ bool wxDb::TableExists(const wxString &tableName, const wxChar *userID, const wx * userID != "" ... UserID set equal to 'userID' */ { - wxASSERT(tableName.Length()); + wxASSERT(tableName.length()); wxString TableName; if (Dbms() == dbmsDBASE) { wxString dbName; - if (tablePath.Length()) + if (tablePath.length()) dbName.Printf(wxT("%s/%s.dbf"), tablePath.c_str(), tableName.c_str()); else dbName.Printf(wxT("%s.dbf"), tableName.c_str()); @@ -3581,8 +3628,8 @@ bool wxDb::TableExists(const wxString &tableName, const wxChar *userID, const wx { retcode = SQLTables(hstmt, NULL, 0, // All qualifiers - (SQLTCHAR *) UserID.c_str(), SQL_NTS, // Only tables owned by this user - (SQLTCHAR FAR *)TableName.c_str(), SQL_NTS, + WXSQLCAST(UserID), SQL_NTS, // Only tables owned by this user + WXSQLCAST(TableName), SQL_NTS, NULL, 0); // All table types } else @@ -3590,7 +3637,7 @@ bool wxDb::TableExists(const wxString &tableName, const wxChar *userID, const wx retcode = SQLTables(hstmt, NULL, 0, // All qualifiers NULL, 0, // All owners - (SQLTCHAR FAR *)TableName.c_str(), SQL_NTS, + WXSQLCAST(TableName), SQL_NTS, NULL, 0); // All table types } if (retcode != SQL_SUCCESS) @@ -3614,10 +3661,10 @@ bool wxDb::TableExists(const wxString &tableName, const wxChar *userID, const wx bool wxDb::TablePrivileges(const wxString &tableName, const wxString &priv, const wxChar *userID, const wxChar *schema, const wxString &WXUNUSED(tablePath)) { - wxASSERT(tableName.Length()); + wxASSERT(tableName.length()); wxDbTablePrivilegeInfo result; - SDWORD cbRetVal; + SQLLEN cbRetVal; RETCODE retcode; // We probably need to be able to dynamically set this based on @@ -3649,15 +3696,15 @@ bool wxDb::TablePrivileges(const wxString &tableName, const wxString &priv, cons { retcode = SQLTablePrivileges(hstmt, NULL, 0, // Catalog - (SQLTCHAR FAR *)Schema.c_str(), SQL_NTS, // Schema - (SQLTCHAR FAR *)TableName.c_str(), SQL_NTS); + WXSQLCAST(Schema), SQL_NTS, // Schema + WXSQLCAST(TableName), SQL_NTS); } else { retcode = SQLTablePrivileges(hstmt, NULL, 0, // Catalog NULL, 0, // Schema - (SQLTCHAR FAR *)TableName.c_str(), SQL_NTS); + WXSQLCAST(TableName), SQL_NTS); } #ifdef DBDEBUG_CONSOLE @@ -3763,7 +3810,7 @@ const wxString wxDb::SQLColumnName(const wxChar *colName) bool wxDb::SetSqlLogging(wxDbSqlLogState state, const wxString &filename, bool append) { wxASSERT(state == sqlLogON || state == sqlLogOFF); - wxASSERT(state == sqlLogOFF || filename.Length()); + wxASSERT(state == sqlLogOFF || filename.length()); if (state == sqlLogON) { @@ -3793,7 +3840,7 @@ bool wxDb::SetSqlLogging(wxDbSqlLogState state, const wxString &filename, bool a /********** wxDb::WriteSqlLog() **********/ bool wxDb::WriteSqlLog(const wxString &logMsg) { - wxASSERT(logMsg.Length()); + wxASSERT(logMsg.length()); if (fpSqlLog == 0 || sqlLogState == sqlLogOFF) return false; @@ -3949,10 +3996,12 @@ wxDBMS wxDb::Dbms(void) 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; if (!wxStricmp(baseName,wxT("DB2"))) - return((wxDBMS)(dbmsType = dbmsDBASE)); + return((wxDBMS)(dbmsType = dbmsDB2)); return((wxDBMS)(dbmsType = dbmsUNIDENTIFIED)); @@ -3963,8 +4012,8 @@ bool wxDb::ModifyColumn(const wxString &tableName, const wxString &columnName, int dataType, ULONG columnLength, const wxString &optionalParam) { - wxASSERT(tableName.Length()); - wxASSERT(columnName.Length()); + wxASSERT(tableName.length()); + wxASSERT(columnName.length()); wxASSERT((dataType == DB_DATA_TYPE_VARCHAR && columnLength > 0) || dataType != DB_DATA_TYPE_VARCHAR); @@ -4042,7 +4091,7 @@ bool wxDb::ModifyColumn(const wxString &tableName, const wxString &columnName, } // for passing things like "NOT NULL" - if (optionalParam.Length()) + if (optionalParam.length()) { sqlStmt += wxT(" "); sqlStmt += optionalParam; @@ -4052,6 +4101,28 @@ bool wxDb::ModifyColumn(const wxString &tableName, const wxString &columnName, } // wxDb::ModifyColumn() +/********** wxDb::EscapeSqlChars() **********/ +wxString wxDb::EscapeSqlChars(const wxString& valueOrig) +{ + wxString value(valueOrig); + switch (Dbms()) + { + case dbmsACCESS: + // Access doesn't seem to care about backslashes, so only escape single quotes. + value.Replace(wxT("'"), wxT("''")); + break; + + default: + // All the others are supposed to be the same for now, add special + // handling for them if necessary + value.Replace(wxT("\\"), wxT("\\\\")); + value.Replace(wxT("'"), wxT("\\'")); + break; + } + + return value; +} // wxDb::EscapeSqlChars() + /********** wxDbGetConnection() **********/ wxDb WXDLLIMPEXP_ODBC *wxDbGetConnection(wxDbConnectInf *pDbConfig, bool FwdOnlyCursors) @@ -4333,7 +4404,7 @@ int wxDbCreateDataSource(const wxString &driverName, const wxString &dsn, const // embedded nulls in strings 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 @@ -4415,7 +4486,7 @@ bool wxDbGetDataSource(HENV henv, wxChar *Dsn, SWORD DsnMaxLength, wxChar *DsDes ******************************************************************** * * The following functions are all DEPRECATED and are included for - * backward compatability reasons only + * backward compatibility reasons only * ******************************************************************** ********************************************************************/