From 0907ea9c5826258c7fda17f9db921539f5cde5ea Mon Sep 17 00:00:00 2001 From: George Tasker Date: Wed, 12 May 2004 19:41:03 +0000 Subject: [PATCH] [SF#789459] Add support for connection strings. The patch originally submitted was not comprehensive enough to use for the connection caching, so a significant number of additional changes were added to support opening a connection with a connection string git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@27241 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/db.h | 25 +++- include/wx/dbtable.h | 1 + src/common/db.cpp | 280 +++++++++++++++++++++++++++++------------ src/common/dbtable.cpp | 6 +- 4 files changed, 226 insertions(+), 86 deletions(-) diff --git a/include/wx/db.h b/include/wx/db.h index 3c53c5b423..771874678c 100644 --- a/include/wx/db.h +++ b/include/wx/db.h @@ -274,16 +274,25 @@ enum wxODBC_ERRORS #define SQL_MAX_AUTHSTR_LEN MAXNAME #endif +#ifndef SQL_MAX_CONNECTSTR_LEN + // There does not seem to be a standard for this, so I am + // defaulting to the value that MS recommends + #define SQL_MAX_CONNECTSTR_LEN 1024 +#endif + + class WXDLLIMPEXP_ODBC wxDbConnectInf { private: bool freeHenvOnDestroy; + bool useConnectionStr; public: HENV Henv; wxChar Dsn[SQL_MAX_DSN_LENGTH+1]; // Data Source Name wxChar Uid[SQL_MAX_USER_NAME_LEN+1]; // User ID wxChar AuthStr[SQL_MAX_AUTHSTR_LEN+1]; // Authorization string (password) + wxChar ConnectionStr[SQL_MAX_CONNECTSTR_LEN+1]; // Connection string (password) wxString Description; // Not sure what the max length is wxString FileType; // Not sure what the max length is @@ -316,6 +325,9 @@ class WXDLLIMPEXP_ODBC wxDbConnectInf const wxChar *GetAuthStr() { return AuthStr; }; const wxChar *GetPassword() { return AuthStr; }; + const wxChar *GetConnectionStr() { return ConnectionStr; }; + bool UseConnectionStr() { return useConnectionStr; }; + const wxChar *GetDescription() { return Description; }; const wxChar *GetFileType() { return FileType; }; const wxChar *GetDefaultDir() { return DefaultDir; }; @@ -330,6 +342,8 @@ class WXDLLIMPEXP_ODBC wxDbConnectInf void SetPassword(const wxString &password); void SetAuthStr(const wxString &authstr) { SetPassword(authstr); }; + void SetConnectionStr(const wxString &connectStr); + void SetDescription(const wxString &desc) { Description = desc; }; void SetFileType(const wxString &fileType) { FileType = fileType; }; void SetDefaultDir(const wxString &defDir) { DefaultDir = defDir; }; @@ -472,21 +486,25 @@ class WXDLLIMPEXP_ODBC wxDb private: bool dbIsOpen; bool dbIsCached; // Was connection created by caching functions + bool dbOpenedWithConnectionString; // Was the database connection opened with a connection string wxString dsn; // Data source name wxString uid; // User ID wxString authStr; // Authorization string (password) + wxString inConnectionStr; // Connection string used to connect to the database + wxString outConnectionStr;// Connection string returned by the database when a connection is successfully opened FILE *fpSqlLog; // Sql Log file pointer wxDbSqlLogState sqlLogState; // On or Off bool fwdOnlyCursors; wxDBMS dbmsType; // Type of datasource - i.e. Oracle, dBase, SQLServer, etc // Private member functions - bool getDbInfo(bool failOnDataTypeUnsupported = TRUE); + bool getDbInfo(bool failOnDataTypeUnsupported=TRUE); bool getDataTypeInfo(SWORD fSqlType, wxDbSqlTypeInfo &structSQLTypeInfo); bool setConnectionOptions(void); void logError(const wxString &errMsg, const wxString &SQLState); const wxChar *convertUserID(const wxChar *userID, wxString &UserID); void initialize(); + bool open(bool failOnDataTypeUnsupported=TRUE); #if !wxODBC_BACKWARD_COMPATABILITY // ODBC handles @@ -598,6 +616,7 @@ public: ~wxDb(); // Data Source Name, User ID, Password and whether open should fail on data type not supported + bool Open(const wxString& inConnectStr, bool failOnDataTypeUnsupported=TRUE); bool Open(const wxString &Dsn, const wxString &Uid, const wxString &AuthStr, bool failOnDataTypeUnsupported=TRUE); bool Open(wxDbConnectInf *dbConnectInf, bool failOnDataTypeUnsupported=TRUE); bool Open(wxDb *copyDb); // pointer to a wxDb whose connection info should be copied rather than re-queried @@ -627,7 +646,10 @@ public: const wxString &GetDatasourceName(void){return dsn;} const wxString &GetUsername(void) {return uid;} const wxString &GetPassword(void) {return authStr;} + const wxString &GetConnectionInStr(void) {return inConnectionStr;} + const wxString &GetConnectionOutStr(void) {return outConnectionStr;} bool IsOpen(void) {return dbIsOpen;} + bool OpenedWithConnectionString(void) {return dbOpenedWithConnectionString;} HENV GetHENV(void) {return henv;} HDBC GetHDBC(void) {return hdbc;} HSTMT GetHSTMT(void) {return hstmt;} @@ -685,6 +707,7 @@ struct wxDbList wxString Dsn; // Data Source Name wxString Uid; // User ID wxString AuthStr; // Authorization string (password) + wxString ConnectionStr; // Connection string used instead of DSN wxDb *PtrDb; // Pointer to the wxDb object bool Free; // Is item free or in use? wxDbList *PtrNext; // Pointer to next item in the list diff --git a/include/wx/dbtable.h b/include/wx/dbtable.h index 8843cba083..625270b5ff 100644 --- a/include/wx/dbtable.h +++ b/include/wx/dbtable.h @@ -109,6 +109,7 @@ private: const wxString &qryTblName, bool qryOnly, const wxString &tblPath); void cleanup(); + void setCbValueForColumn(int columnIndex); bool bindParams(bool forUpdate); // called by the other 'bind' functions bool bindInsertParams(void); bool bindUpdateParams(void); diff --git a/src/common/db.cpp b/src/common/db.cpp index eb9137aa42..6f07ddc635 100644 --- a/src/common/db.cpp +++ b/src/common/db.cpp @@ -167,10 +167,13 @@ bool wxDbConnectInf::Initialize() Dsn[0] = 0; Uid[0] = 0; AuthStr[0] = 0; + ConnectionStr[0] = 0; Description.Empty(); FileType.Empty(); DefaultDir.Empty(); + useConnectionStr = FALSE; + return TRUE; } // wxDbConnectInf::Initialize() @@ -219,7 +222,7 @@ void wxDbConnectInf::SetDsn(const wxString &dsn) void wxDbConnectInf::SetUserID(const wxString &uid) { wxASSERT(uid.Length() < sizeof(Uid)); - wxStrcpy(Uid,uid); + wxStrcpy(Uid, uid); } // wxDbConnectInf::SetUserID() @@ -227,9 +230,17 @@ void wxDbConnectInf::SetPassword(const wxString &password) { wxASSERT(password.Length() < sizeof(AuthStr)); - wxStrcpy(AuthStr,password); + wxStrcpy(AuthStr, password); } // wxDbConnectInf::SetPassword() +void wxDbConnectInf::SetConnectionStr(const wxString &connectStr) +{ + wxASSERT(connectStr.Length() < sizeof(ConnectionStr)); + + useConnectionStr = wxStrlen(connectStr) > 0; + + wxStrcpy(ConnectionStr, connectStr); +} // wxDbConnectInf::SetConnectionStr() /********** wxDbColFor Constructor **********/ @@ -540,6 +551,7 @@ void wxDb::initialize() // Mark database as not open as of yet dbIsOpen = FALSE; dbIsCached = FALSE; + dbOpenedWithConnectionString = FALSE; } // wxDb::initialize() @@ -575,41 +587,8 @@ const wxChar *wxDb::convertUserID(const wxChar *userID, wxString &UserID) } // wxDb::convertUserID() -/********** wxDb::Open() **********/ -bool wxDb::Open(const wxString &Dsn, const wxString &Uid, const wxString &AuthStr, bool failOnDataTypeUnsupported) +bool wxDb::open(bool failOnDataTypeUnsupported) { - wxASSERT(Dsn.Length()); - dsn = Dsn; - uid = Uid; - authStr = AuthStr; - - RETCODE retcode; - - if (!FwdOnlyCursors()) - { - // Specify that the ODBC cursor library be used, if needed. This must be - // specified before the connection is made. - retcode = SQLSetConnectOption(hdbc, SQL_ODBC_CURSORS, SQL_CUR_USE_IF_NEEDED); - -#ifdef DBDEBUG_CONSOLE - if (retcode == SQL_SUCCESS) - cout << wxT("SQLSetConnectOption(CURSOR_LIB) successful") << endl; - else - cout << wxT("SQLSetConnectOption(CURSOR_LIB) failed") << endl; -#else - wxUnusedVar( retcode ); -#endif - } - - // Connect to the data source - retcode = SQLConnect(hdbc, (SQLTCHAR FAR *) dsn.c_str(), SQL_NTS, - (SQLTCHAR FAR *) uid.c_str(), SQL_NTS, - (SQLTCHAR FAR *) authStr.c_str(), SQL_NTS); - - if ((retcode != SQL_SUCCESS) && - (retcode != SQL_SUCCESS_WITH_INFO)) - return(DispAllErrors(henv, hdbc)); - /* If using Intersolv branded ODBC drivers, this is the place where you would substitute your branded driver license information @@ -769,22 +748,115 @@ bool wxDb::Open(const wxString &Dsn, const wxString &Uid, const wxString &AuthSt // Completed Successfully return(TRUE); +} + +bool wxDb::Open(const wxString& inConnectStr, bool failOnDataTypeUnsupported) +{ + wxASSERT(inConnectStr.Length()); + dsn = ""; + uid = ""; + authStr = ""; + + RETCODE retcode; + + if (!FwdOnlyCursors()) + { + // Specify that the ODBC cursor library be used, if needed. This must be + // specified before the connection is made. + retcode = SQLSetConnectOption(hdbc, SQL_ODBC_CURSORS, SQL_CUR_USE_IF_NEEDED); + +#ifdef DBDEBUG_CONSOLE + if (retcode == SQL_SUCCESS) + cout << wxT("SQLSetConnectOption(CURSOR_LIB) successful") << endl; + else + cout << wxT("SQLSetConnectOption(CURSOR_LIB) failed") << endl; +#endif + } + + // Connect to the data source + UCHAR outConnectBuffer[SQL_MAX_CONNECTSTR_LEN+1]; // MS recommends at least 1k buffer + short outConnectBufferLen; + + inConnectionStr = inConnectStr; + + retcode = SQLDriverConnect(hdbc, NULL, (UCHAR FAR *)inConnectionStr.c_str(), + inConnectionStr.Length(), (UCHAR FAR *)outConnectBuffer, + sizeof(outConnectBuffer), &outConnectBufferLen, SQL_DRIVER_COMPLETE ); + + if ((retcode != SQL_SUCCESS) && + (retcode != SQL_SUCCESS_WITH_INFO)) + return(DispAllErrors(henv, hdbc)); + + outConnectBuffer[outConnectBufferLen] = 0; + outConnectionStr = outConnectBuffer; + dbOpenedWithConnectionString = TRUE; + + return open(failOnDataTypeUnsupported); +} + +/********** wxDb::Open() **********/ +bool wxDb::Open(const wxString &Dsn, const wxString &Uid, const wxString &AuthStr, bool failOnDataTypeUnsupported) +{ + wxASSERT(Dsn.Length()); + dsn = Dsn; + uid = Uid; + authStr = AuthStr; + + inConnectionStr = ""; + outConnectionStr = ""; + + RETCODE retcode; + + if (!FwdOnlyCursors()) + { + // Specify that the ODBC cursor library be used, if needed. This must be + // specified before the connection is made. + retcode = SQLSetConnectOption(hdbc, SQL_ODBC_CURSORS, SQL_CUR_USE_IF_NEEDED); + +#ifdef DBDEBUG_CONSOLE + if (retcode == SQL_SUCCESS) + cout << wxT("SQLSetConnectOption(CURSOR_LIB) successful") << endl; + else + cout << wxT("SQLSetConnectOption(CURSOR_LIB) failed") << endl; +#else + wxUnusedVar( retcode ); +#endif + } + + // Connect to the data source + retcode = SQLConnect(hdbc, (SQLTCHAR FAR *) dsn.c_str(), SQL_NTS, + (SQLTCHAR FAR *) uid.c_str(), SQL_NTS, + (SQLTCHAR FAR *) authStr.c_str(), SQL_NTS); + + if ((retcode != SQL_SUCCESS) && + (retcode != SQL_SUCCESS_WITH_INFO)) + return(DispAllErrors(henv, hdbc)); + + return open(failOnDataTypeUnsupported); } // wxDb::Open() bool wxDb::Open(wxDbConnectInf *dbConnectInf, bool failOnDataTypeUnsupported) { - return Open(dbConnectInf->GetDsn(), dbConnectInf->GetUserID(), - dbConnectInf->GetPassword(), failOnDataTypeUnsupported); + wxASSERT(dbConnectInf); + + // Use the connection string if one is present + if (dbConnectInf->UseConnectionStr()) + return Open(GetConnectionInStr(), failOnDataTypeUnsupported); + else + return Open(dbConnectInf->GetDsn(), dbConnectInf->GetUserID(), + dbConnectInf->GetPassword(), failOnDataTypeUnsupported); } // wxDb::Open() bool wxDb::Open(wxDb *copyDb) { - dsn = copyDb->GetDatasourceName(); - uid = copyDb->GetUsername(); - authStr = copyDb->GetPassword(); + dsn = copyDb->GetDatasourceName(); + uid = copyDb->GetUsername(); + authStr = copyDb->GetPassword(); + inConnectionStr = copyDb->GetConnectionInStr(); + outConnectionStr = copyDb->GetConnectionOutStr(); RETCODE retcode; @@ -804,12 +876,36 @@ bool wxDb::Open(wxDb *copyDb) #endif } - // Connect to the data source - retcode = SQLConnect(hdbc, (SQLTCHAR FAR *) dsn.c_str(), SQL_NTS, - (SQLTCHAR FAR *) uid.c_str(), SQL_NTS, - (SQLTCHAR FAR *) authStr.c_str(), SQL_NTS); + if (copyDb->OpenedWithConnectionString()) + { + // Connect to the data source + UCHAR outConnectBuffer[SQL_MAX_CONNECTSTR_LEN+1]; + short outConnectBufferLen; - if (retcode == SQL_ERROR) + inConnectionStr = copyDb->GetConnectionInStr(); + + retcode = SQLDriverConnect(hdbc, NULL, (UCHAR FAR *)inConnectionStr.c_str(), + inConnectionStr.Length(), (UCHAR FAR *)outConnectBuffer, + sizeof(outConnectBuffer), &outConnectBufferLen, SQL_DRIVER_COMPLETE); + + if ((retcode != SQL_SUCCESS) && + (retcode != SQL_SUCCESS_WITH_INFO)) + return(DispAllErrors(henv, hdbc)); + + outConnectBuffer[outConnectBufferLen] = 0; + outConnectionStr = outConnectBuffer; + dbOpenedWithConnectionString = TRUE; + } + else + { + // Connect to the data source + retcode = SQLConnect(hdbc, (SQLTCHAR FAR *) dsn.c_str(), SQL_NTS, + (SQLTCHAR FAR *) uid.c_str(), SQL_NTS, + (SQLTCHAR FAR *) authStr.c_str(), SQL_NTS); + } + + if ((retcode != SQL_SUCCESS) && + (retcode != SQL_SUCCESS_WITH_INFO)) return(DispAllErrors(henv, hdbc)); /* @@ -1100,10 +1196,6 @@ bool wxDb::getDbInfo(bool failOnDataTypeUnsupported) retcode = SQLGetInfo(hdbc, SQL_OUTER_JOINS, (UCHAR*) dbInf.outerJoins, 2, &cb); if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) { - // TODO: BugTracker# 785080 : fails with mysql 4 on linux - edr - // TODO: dbInf.outerJoins[0]='N'; - // TODO: dbInf.outerJoins[1]='\x0'; - DispAllErrors(henv, hdbc); if (failOnDataTypeUnsupported) return FALSE; @@ -1112,10 +1204,6 @@ bool wxDb::getDbInfo(bool failOnDataTypeUnsupported) retcode = SQLGetInfo(hdbc, SQL_PROCEDURES, (UCHAR*) dbInf.procedureSupport, 2, &cb); if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) { - // TODO: BugTracker# 785080 : fails with mysql 4 on linux - edr - // TODO: dbInf.procedureSupport[0]='N'; - // TODO: dbInf.procedureSupport[1]='\x0'; - DispAllErrors(henv, hdbc); if (failOnDataTypeUnsupported) return FALSE; @@ -1124,10 +1212,6 @@ bool wxDb::getDbInfo(bool failOnDataTypeUnsupported) retcode = SQLGetInfo(hdbc, SQL_ACCESSIBLE_TABLES, (UCHAR*) dbInf.accessibleTables, 2, &cb); if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) { - // TODO: BugTracker# 785080 : fails with mysql 4 on linux - edr - // TODO: dbInf.accessibleTables[0]='N'; - // TODO: dbInf.accessibleTables[1]='\x0'; - DispAllErrors(henv, hdbc); if (failOnDataTypeUnsupported) return FALSE; @@ -1160,10 +1244,6 @@ bool wxDb::getDbInfo(bool failOnDataTypeUnsupported) retcode = SQLGetInfo(hdbc, SQL_ODBC_SQL_OPT_IEF, (UCHAR*) dbInf.supportIEF, 2, &cb); if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) { - // TODO: BugTracker# 785080 : fails with mysql 4 on linux - edr - // TODO: dbInf.supportIEF[0]='N'; - // TODO: dbInf.supportIEF[1]='\x0'; - DispAllErrors(henv, hdbc); if (failOnDataTypeUnsupported) return FALSE; @@ -3793,17 +3873,42 @@ wxDb WXDLLIMPEXP_ODBC *wxDbGetConnection(wxDbConnectInf *pDbConfig, bool FwdOnly // The database connection must be for the same datasource // name and must currently not be in use. if (pList->Free && - (pList->PtrDb->FwdOnlyCursors() == FwdOnlyCursors) && - (!wxStrcmp(pDbConfig->GetDsn(), pList->Dsn))) // Found a free connection + (pList->PtrDb->FwdOnlyCursors() == FwdOnlyCursors)) { - pList->Free = FALSE; - return(pList->PtrDb); + if (pDbConfig->UseConnectionStr()) + { + if (pList->PtrDb->OpenedWithConnectionString() && + (!wxStrcmp(pDbConfig->GetConnectionStr(), pList->ConnectionStr))) + { + // Found a free connection + pList->Free = FALSE; + return(pList->PtrDb); + } + } + else + { + if (!pList->PtrDb->OpenedWithConnectionString() && + (!wxStrcmp(pDbConfig->GetDsn(), pList->Dsn))) + { + // Found a free connection + pList->Free = FALSE; + return(pList->PtrDb); + } + } } - if (!wxStrcmp(pDbConfig->GetDsn(), pList->Dsn) && - !wxStrcmp(pDbConfig->GetUserID(), pList->Uid) && - !wxStrcmp(pDbConfig->GetPassword(), pList->AuthStr)) - matchingDbConnection = pList->PtrDb; + if (pDbConfig->UseConnectionStr()) + { + if (!wxStrcmp(pDbConfig->GetConnectionStr(), pList->ConnectionStr)) + matchingDbConnection = pList->PtrDb; + } + else + { + if (!wxStrcmp(pDbConfig->GetDsn(), pList->Dsn) && + !wxStrcmp(pDbConfig->GetUserID(), pList->Uid) && + !wxStrcmp(pDbConfig->GetPassword(), pList->AuthStr)) + matchingDbConnection = pList->PtrDb; + } } // No available connections. A new connection must be made and @@ -3825,18 +3930,28 @@ wxDb WXDLLIMPEXP_ODBC *wxDbGetConnection(wxDbConnectInf *pDbConfig, bool FwdOnly } // Initialize new node in the linked list - pList->PtrNext = 0; - pList->Free = FALSE; - pList->Dsn = pDbConfig->GetDsn(); - pList->Uid = pDbConfig->GetUserID(); - pList->AuthStr = pDbConfig->GetPassword(); + pList->PtrNext = 0; + pList->Free = FALSE; + pList->Dsn = pDbConfig->GetDsn(); + pList->Uid = pDbConfig->GetUserID(); + pList->AuthStr = pDbConfig->GetPassword(); + pList->ConnectionStr = pDbConfig->GetConnectionStr(); pList->PtrDb = new wxDb(pDbConfig->GetHenv(), FwdOnlyCursors); bool opened; if (!matchingDbConnection) - opened = pList->PtrDb->Open(pDbConfig->GetDsn(), pDbConfig->GetUserID(), pDbConfig->GetPassword()); + { + if (pDbConfig->UseConnectionStr()) + { + opened = pList->PtrDb->Open(pDbConfig->GetConnectionStr()); + } + else + { + opened = pList->PtrDb->Open(pDbConfig->GetDsn(), pDbConfig->GetUserID(), pDbConfig->GetPassword()); + } + } else opened = pList->PtrDb->Open(matchingDbConnection); @@ -3844,7 +3959,7 @@ wxDb WXDLLIMPEXP_ODBC *wxDbGetConnection(wxDbConnectInf *pDbConfig, bool FwdOnly if (opened) { pList->PtrDb->setCached(TRUE); // Prevent a user from deleting a cached connection - pList->PtrDb->SetSqlLogging(SQLLOGstate,SQLLOGfn,TRUE); + pList->PtrDb->SetSqlLogging(SQLLOGstate, SQLLOGfn, TRUE); return(pList->PtrDb); } else // Unable to connect, destroy list item @@ -3852,11 +3967,12 @@ wxDb WXDLLIMPEXP_ODBC *wxDbGetConnection(wxDbConnectInf *pDbConfig, bool FwdOnly if (pList->PtrPrev) pList->PtrPrev->PtrNext = 0; else - PtrBegDbList = 0; // Empty list again - pList->PtrDb->CommitTrans(); // Commit any open transactions on wxDb object - pList->PtrDb->Close(); // Close the wxDb object - delete pList->PtrDb; // Deletes the wxDb object - delete pList; // Deletes the linked list object + PtrBegDbList = 0; // Empty list again + + pList->PtrDb->CommitTrans(); // Commit any open transactions on wxDb object + pList->PtrDb->Close(); // Close the wxDb object + delete pList->PtrDb; // Deletes the wxDb object + delete pList; // Deletes the linked list object return(0); } diff --git a/src/common/dbtable.cpp b/src/common/dbtable.cpp index a34a07fa41..9e71e79480 100644 --- a/src/common/dbtable.cpp +++ b/src/common/dbtable.cpp @@ -410,7 +410,7 @@ ODBC 3.0 says to use this form /***************************** PRIVATE FUNCTIONS *****************************/ -bool wxDbTable::setCbValueForColumn(int columnIndex) +void wxDbTable::setCbValueForColumn(int columnIndex) { switch(colDefs[columnIndex].DbDataType) { @@ -2535,7 +2535,7 @@ bool wxDbTable::SetColNull(UWORD colNo, bool set) if (set) // Blank out the values in the member variable ClearMemberVar(colNo, FALSE); // Must call with FALSE here, or infinite recursion will happen - setCbValueForColumn(i); + setCbValueForColumn(colNo); return(TRUE); } @@ -2561,7 +2561,7 @@ bool wxDbTable::SetColNull(const wxString &colName, bool set) if (set) // Blank out the values in the member variable ClearMemberVar(colNo,FALSE); // Must call with FALSE here, or infinite recursion will happen - setCbValueForColumn(i); + setCbValueForColumn(colNo); return(TRUE); } -- 2.45.2