X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/5f72522e58e75bbd2c6e04544b6dd6a8260ea836..69659fd770f615210efac4b4fa741b3ad6223616:/src/common/db.cpp diff --git a/src/common/db.cpp b/src/common/db.cpp index caccd58f8a..cf4f9a28b9 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,35 +21,29 @@ // 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 -#include "wx/filefn.h" -#include "wx/wxchar.h" -#if wxUSE_ODBC +#ifdef DBDEBUG_CONSOLE + #include "wx/ioswrap.h" +#endif + +#include "wx/filefn.h" +#include "wx/crt.h" #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 @@ -85,7 +88,7 @@ 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 -wxChar 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 @@ -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,33 +207,37 @@ void wxDbConnectInf::FreeHenv() void wxDbConnectInf::SetDsn(const wxString &dsn) { - wxASSERT(dsn.Length() < sizeof(Dsn)); + wxASSERT(dsn.length() < WXSIZEOF(Dsn)); - wxStrcpy(Dsn,dsn); + 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)); - wxStrcpy(Uid, uid); + 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)); - wxStrcpy(AuthStr, password); + 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; - wxStrcpy(ConnectionStr, connectStr); + wxStrncpy(ConnectionStr, connectStr, WXSIZEOF(ConnectionStr)-1); + ConnectionStr[WXSIZEOF(ConnectionStr)-1] = 0; // Prevent buffer overrun } // wxDbConnectInf::SetConnectionStr() @@ -283,14 +290,23 @@ int wxDbColFor::Format(int Nation, int dbDataType, SWORD sqlDataType, 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; 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_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_C_BINARY) @@ -313,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: @@ -523,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; @@ -546,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) { @@ -563,24 +584,23 @@ 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() bool wxDb::determineDataTypes(bool failOnDataTypeUnsupported) { - int iIndex; + size_t iIndex; // 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 + // 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) @@ -597,7 +617,7 @@ bool wxDb::determineDataTypes(bool failOnDataTypeUnsupported) // 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 + // 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 @@ -607,7 +627,7 @@ bool wxDb::determineDataTypes(bool failOnDataTypeUnsupported) // 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 + // 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, @@ -620,7 +640,7 @@ bool wxDb::determineDataTypes(bool failOnDataTypeUnsupported) // 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 + // 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, @@ -633,13 +653,23 @@ bool wxDb::determineDataTypes(bool failOnDataTypeUnsupported) // 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 + // 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 }; + // 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 @@ -686,8 +716,8 @@ bool wxDb::determineDataTypes(bool failOnDataTypeUnsupported) if (!getDbInfo(failOnDataTypeUnsupported)) return false; - // --------------- Varchar - (Variable length character string) --------------- - for (iIndex = 0; iIndex < WXSIZEOF(PossibleSqlCharTypes) && + // --------------- Varchar - (Variable length character string) --------------- + for (iIndex = 0; iIndex < WXSIZEOF(PossibleSqlCharTypes) && !getDataTypeInfo(PossibleSqlCharTypes[iIndex], typeInfVarchar); ++iIndex) {} @@ -696,8 +726,8 @@ bool wxDb::determineDataTypes(bool failOnDataTypeUnsupported) else if (failOnDataTypeUnsupported) return false; - // --------------- Float --------------- - for (iIndex = 0; iIndex < WXSIZEOF(PossibleSqlFloatTypes) && + // --------------- Float --------------- + for (iIndex = 0; iIndex < WXSIZEOF(PossibleSqlFloatTypes) && !getDataTypeInfo(PossibleSqlFloatTypes[iIndex], typeInfFloat); ++iIndex) {} @@ -707,7 +737,7 @@ bool wxDb::determineDataTypes(bool failOnDataTypeUnsupported) return false; // --------------- Integer ------------- - for (iIndex = 0; iIndex < WXSIZEOF(PossibleSqlIntegerTypes) && + for (iIndex = 0; iIndex < WXSIZEOF(PossibleSqlIntegerTypes) && !getDataTypeInfo(PossibleSqlIntegerTypes[iIndex], typeInfInteger); ++iIndex) {} @@ -726,8 +756,8 @@ bool wxDb::determineDataTypes(bool failOnDataTypeUnsupported) typeInfInteger.FsqlType = typeInfFloat.FsqlType; } - // --------------- Date/Time --------------- - for (iIndex = 0; iIndex < WXSIZEOF(PossibleSqlDateTypes) && + // --------------- Date/Time --------------- + for (iIndex = 0; iIndex < WXSIZEOF(PossibleSqlDateTypes) && !getDataTypeInfo(PossibleSqlDateTypes[iIndex], typeInfDate); ++iIndex) {} @@ -736,8 +766,8 @@ bool wxDb::determineDataTypes(bool failOnDataTypeUnsupported) else if (failOnDataTypeUnsupported) return false; - // --------------- BLOB --------------- - for (iIndex = 0; iIndex < WXSIZEOF(PossibleSqlBlobTypes) && + // --------------- BLOB --------------- + for (iIndex = 0; iIndex < WXSIZEOF(PossibleSqlBlobTypes) && !getDataTypeInfo(PossibleSqlBlobTypes[iIndex], typeInfBlob); ++iIndex) {} @@ -746,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 @@ -780,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 @@ -789,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; @@ -818,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)) @@ -836,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; @@ -863,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)) @@ -882,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); @@ -923,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)) @@ -938,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) && @@ -1035,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 @@ -1593,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) @@ -1700,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 @@ -1762,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) { @@ -1807,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; @@ -1824,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) @@ -1847,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; @@ -1855,14 +1909,15 @@ void wxDb::logError(const wxString &errMsg, const wxString &SQLState) 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[pLast], errMsg); + 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; @@ -2127,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; @@ -2167,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); @@ -2200,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))) { @@ -2238,15 +2293,15 @@ 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) + // 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, &Sdword) != SQL_SUCCESS) + &Sword, &Sqllen) != SQL_SUCCESS) { DispAllErrors(henv, hdbc, hstmt); delete[] pColInf; @@ -2254,21 +2309,33 @@ bool wxDb::ExecSql(const wxString &pSqlStmt, wxDbColInf** columns, short& numcol } 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, &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) + 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_LONGVARCHAR: + pColInf[colNum].dbDataType = DB_DATA_TYPE_MEMO; + break; case SQL_TINYINT: case SQL_SMALLINT: case SQL_INTEGER: @@ -2292,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 } @@ -2317,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); @@ -2347,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; /* @@ -2369,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 */ @@ -2396,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 */ @@ -2417,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 @@ -2427,7 +2494,10 @@ int wxDb::GetKeyFields(const wxString &tableName, wxDbColInf* colInf, UWORD noCo for (i=0; i 0) || dataType != DB_DATA_TYPE_VARCHAR); @@ -4007,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; @@ -4017,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) @@ -4234,11 +4340,11 @@ const wxChar WXDLLIMPEXP_ODBC *wxDbLogExtendedErrorMsg(const wxChar *userText, if (pDb->errorList[i]) { msg.Append(pDb->errorList[i]); - if (wxStrcmp(pDb->errorList[i],wxT("")) != 0) + 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],wxT("")); + wxStrcpy(pDb->errorList[i], wxEmptyString); } } msg += wxT("\n"); @@ -4298,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 @@ -4380,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 * ******************************************************************** ********************************************************************/