X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/08429a81cad38f84f52ce915fdfe90a5216a9f8c..9b5f1895643cf94b38ac19a4c1151e259310852e:/src/common/db.cpp diff --git a/src/common/db.cpp b/src/common/db.cpp index 8153f3ab79..486ce397dd 100644 --- a/src/common/db.cpp +++ b/src/common/db.cpp @@ -25,9 +25,6 @@ // SYNOPSIS START // SYNOPSIS STOP */ -#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) - #pragma implementation "db.h" -#endif #include "wx/wxprec.h" @@ -85,7 +82,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 +176,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 +201,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 +284,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 +323,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 +532,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; @@ -563,39 +578,94 @@ 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::open(bool failOnDataTypeUnsupported) +bool wxDb::determineDataTypes(bool failOnDataTypeUnsupported) { -/* - If using Intersolv branded ODBC drivers, this is the place where you would substitute - your branded driver license information + size_t iIndex; - SQLSetConnectOption(hdbc, 1041, (UDWORD) wxEmptyString); - SQLSetConnectOption(hdbc, 1042, (UDWORD) wxEmptyString); -*/ + // 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 + }; - // 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 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 + }; - // 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 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 + }; - // Set Connection Options - if (!setConnectionOptions()) - return false; + // 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 + }; + + // 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 for inf. about itself - if (!getDbInfo(failOnDataTypeUnsupported)) - return false; // Query the data source regarding data type information @@ -604,7 +674,7 @@ bool wxDb::open(bool failOnDataTypeUnsupported) // 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: // @@ -638,41 +708,41 @@ bool wxDb::open(bool failOnDataTypeUnsupported) // 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; + // Query the data source for info about itself + if (!getDbInfo(failOnDataTypeUnsupported)) + return false; - // 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)) - { - if (failOnDataTypeUnsupported) - 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; + // --------------- Varchar - (Variable length character string) --------------- + for (iIndex = 0; iIndex < WXSIZEOF(PossibleSqlCharTypes) && + !getDataTypeInfo(PossibleSqlCharTypes[iIndex], typeInfVarchar); ++iIndex) + {} - // Integer - if (!getDataTypeInfo(SQL_INTEGER, typeInfInteger)) + 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 (failOnDataTypeUnsupported) @@ -681,46 +751,64 @@ bool wxDb::open(bool failOnDataTypeUnsupported) else typeInfInteger.FsqlType = typeInfFloat.FsqlType; } - else - typeInfInteger.FsqlType = SQL_INTEGER; - // Date/Time - if (!getDataTypeInfo(SQL_TIMESTAMP,typeInfDate)) - { - if (!getDataTypeInfo(SQL_DATE,typeInfDate)) - { -#ifdef SQL_DATETIME - if (getDataTypeInfo(SQL_DATETIME,typeInfDate)) - { - typeInfDate.FsqlType = SQL_TIME; - } - else -#endif // SQL_DATETIME defined - { - if (failOnDataTypeUnsupported) - return false; - } - } - else - typeInfDate.FsqlType = SQL_DATE; - } - else - typeInfDate.FsqlType = SQL_TIMESTAMP; + // --------------- 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; - if (!getDataTypeInfo(SQL_LONGVARBINARY, typeInfBlob)) - { - if (!getDataTypeInfo(SQL_VARBINARY,typeInfBlob)) - { - if (failOnDataTypeUnsupported) - return false; - } - else - typeInfBlob.FsqlType = SQL_VARBINARY; - } - else - typeInfBlob.FsqlType = SQL_LONGVARBINARY; + // --------------- 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; + + // --------------- 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 + + +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; @@ -728,6 +816,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 @@ -738,6 +827,11 @@ bool wxDb::open(bool failOnDataTypeUnsupported) 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(""); @@ -766,7 +860,7 @@ bool wxDb::Open(const wxString& inConnectStr, bool failOnDataTypeUnsupported) inConnectionStr = inConnectStr; - retcode = SQLDriverConnect(hdbc, NULL, (SQLTCHAR FAR *)inConnectionStr.c_str(), + retcode = SQLDriverConnect(hdbc, parentWnd, (SQLTCHAR FAR *)inConnectionStr.c_str(), (SWORD)inConnectionStr.Length(), (SQLTCHAR FAR *)outConnectBuffer, sizeof(outConnectBuffer), &outConnectBufferLen, SQL_DRIVER_COMPLETE ); @@ -983,12 +1077,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 @@ -1013,8 +1115,8 @@ bool wxDb::setConnectionOptions(void) if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) return(DispAllErrors(henv, hdbc)); - retcode = SQLSetConnectOption(hdbc, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF); - retcode = SQLSetConnectOption(hdbc, SQL_OPT_TRACE, SQL_OPT_TRACE_OFF); + /* 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 @@ -1026,7 +1128,7 @@ bool wxDb::setConnectionOptions(void) { const long SQL_PRESERVE_CURSORS = 1204L; const long SQL_PC_ON = 1L; - retcode = SQLSetConnectOption(hdbc, SQL_PRESERVE_CURSORS, SQL_PC_ON); + /* retcode = */ SQLSetConnectOption(hdbc, SQL_PRESERVE_CURSORS, SQL_PC_ON); } // Display the connection options to verify them @@ -1541,7 +1643,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) @@ -1553,7 +1655,7 @@ bool wxDb::getDataTypeInfo(SWORD fSqlType, wxDbSqlTypeInfo &structSQLTypeInfo) { #ifdef DBDEBUG_CONSOLE if (retcode == SQL_NO_DATA_FOUND) - cout << wxT("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); @@ -1710,25 +1812,21 @@ 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); logError(odbcErrMsg, sqlState); @@ -1755,11 +1853,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; @@ -1803,12 +1897,13 @@ 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 ((dbStatus = TranslateSqlState(SQLState)) != DB_ERR_FUNCTION_SEQUENCE_ERROR) @@ -2163,90 +2258,104 @@ bool wxDb::ExecSql(const wxString &pSqlStmt) } // wxDb::ExecSql() -/********** wxDb::ExecSql() with column info **********/ +/********** wxDb::ExecSql() with column info **********/ bool wxDb::ExecSql(const wxString &pSqlStmt, wxDbColInf** columns, short& numcols) { //execute the statement first - if (! ExecSql(pSqlStmt)) return false; + if (!ExecSql(pSqlStmt)) + return false; SWORD noCols; - if (SQLNumResultCols (hstmt, &noCols) != SQL_SUCCESS) + if (SQLNumResultCols(hstmt, &noCols) != SQL_SUCCESS) { DispAllErrors(henv, hdbc, hstmt); return false; } - - if (noCols == 0) return false; - else numcols = noCols; - + + if (noCols == 0) + return false; + else + numcols = noCols; + // Get column information short colNum; - UCHAR name[DB_MAX_COLUMN_NAME_LEN+1]; + 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) - for (colNum = 0; colNum < noCols; colNum++) + + // Fill in column information (name, datatype) + for (colNum = 0; colNum < noCols; colNum++) { - if (SQLColAttributes(hstmt,colNum+1, SQL_COLUMN_NAME, + 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; return false; } - - wxStrncpy(pColInf[colNum].colName, (const char*) name, DB_MAX_COLUMN_NAME_LEN); - - if (SQLColAttributes(hstmt,colNum+1, SQL_COLUMN_TYPE, - NULL, 0, &Sword, &Sdword) != SQL_SUCCESS) + + 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 (Sdword) + + switch (Sqllen) { - 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; +#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: + 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 %d currently not supported by wxWindows"), Sdword); - wxLogDebug(errMsg,wxT("ODBC DEBUG MESSAGE")); + 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::ExecSqlGetInf() +} // wxDb::ExecSql() /********** wxDb::GetNext() **********/ bool wxDb::GetNext(void) @@ -2263,7 +2372,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); @@ -2290,11 +2399,10 @@ int wxDb::GetKeyFields(const wxString &tableName, wxDbColInf* colInf, UWORD noCo 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; -// SQLSMALLINT 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; - SDWORD cb; + SQLLEN cb; SWORD i; wxString tempStr; /* @@ -2364,17 +2472,20 @@ 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 tempStr.Trim(); // Get rid of any unneeded blanks - if (!tempStr.IsEmpty()) + if (!tempStr.empty()) { for (i=0; ierrorList[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"); @@ -4225,7 +4370,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 @@ -4289,9 +4434,11 @@ bool wxDbGetDataSource(HENV henv, wxChar *Dsn, SWORD DsnMaxLength, wxChar *DsDes */ { SWORD cb1,cb2; + SWORD lengthDsn = (SWORD)(DsnMaxLength*sizeof(wxChar)); + SWORD lengthDsDesc = (SWORD)(DsDescMaxLength*sizeof(wxChar)); - if (SQLDataSources(henv, direction, (SQLTCHAR FAR *) Dsn, DsnMaxLength*sizeof(wxChar), &cb1, - (SQLTCHAR FAR *) DsDesc, DsDescMaxLength*sizeof(wxChar), &cb2) == SQL_SUCCESS) + if (SQLDataSources(henv, direction, (SQLTCHAR FAR *) Dsn, lengthDsn, &cb1, + (SQLTCHAR FAR *) DsDesc, lengthDsDesc, &cb2) == SQL_SUCCESS) return true; else return false; @@ -4305,7 +4452,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 * ******************************************************************** ********************************************************************/