1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_dbaccess.hxx" 30 31 #ifndef _DBAUI_ODBC_CONFIG_HXX_ 32 #include "odbcconfig.hxx" 33 #endif 34 #include <rtl/bootstrap.hxx> 35 #ifndef _RTL_USTRING_HXX_ 36 #include <rtl/ustring.hxx> 37 #endif 38 #ifndef _RTL_USTRBUF_HXX_ 39 #include <rtl/ustrbuf.hxx> 40 #endif 41 #ifndef _OSL_DIAGNOSE_H_ 42 #include <osl/diagnose.h> 43 #endif 44 #ifndef _OSL_PROCESS_H_ 45 #include <osl/process.h> 46 #endif 47 #ifndef _THREAD_HXX_ 48 #include <osl/thread.hxx> 49 #endif 50 #ifndef _TOOLS_DEBUG_HXX 51 #include <tools/debug.hxx> 52 #endif 53 #ifndef _SV_SVAPP_HXX 54 #include <vcl/svapp.hxx> 55 #endif 56 57 #ifdef HAVE_ODBC_SUPPORT 58 59 #if defined(OS2) 60 #define ODBC_LIBRARY "ODBC.DLL" 61 #define ODBC_UI_LIBRARY "ODBCINST.DLL" 62 #endif 63 #if defined WNT 64 #define ODBC_LIBRARY "ODBC32.DLL" 65 #define ODBC_UI_LIBRARY "ODBCCP32.DLL" 66 #endif 67 #ifdef UNX 68 #ifdef MACOSX 69 #define ODBC_LIBRARY "libiodbc.dylib" 70 #define ODBC_UI_LIBRARY "libiodbcinst.dylib" 71 #else 72 #define ODBC_LIBRARY_1 "libodbc.so.1" 73 #define ODBC_UI_LIBRARY_1 "libodbcinst.so.1" 74 #define ODBC_LIBRARY "libodbc.so" 75 #define ODBC_UI_LIBRARY "libodbcinst.so" 76 #endif 77 #endif 78 79 // just to go with calling convention of windows 80 // so don't touch this 81 #if defined(WNT) 82 #define SQL_API __stdcall 83 // At least under some circumstances, the below #include <odbc/sqlext.h> re- 84 // defines SQL_API to an empty string, leading to a compiler warning on MSC; to 85 // not break the current behavior, this is worked around by locally disabling 86 // that warning: 87 #if defined _MSC_VER 88 #pragma warning(push) 89 #pragma warning(disable: 4005) 90 #endif 91 #endif // defined(WNT) 92 93 #if defined(OS2) 94 #define ALLREADY_HAVE_OS2_TYPES 95 #define DONT_TD_VOID 96 #endif 97 98 #ifdef SYSTEM_ODBC_HEADERS 99 #include <sqlext.h> 100 #else 101 #ifndef __SQLEXT_H 102 #include <odbc/sqlext.h> 103 #endif 104 #endif 105 106 #if defined(WNT) 107 #if defined _MSC_VER 108 #pragma warning(pop) 109 #endif 110 #undef SQL_API 111 #define SQL_API __stdcall 112 #endif // defined(WNT) 113 // from here on you can do what you want to 114 115 #if defined(OS2) 116 #define SQL_API _System 117 #endif // defined(OS2) 118 119 #else 120 121 #define ODBC_LIBRARY "" 122 #define ODBC_UI_LIBRARY "" 123 124 #endif // HAVE_ODBC_SUPPORT 125 126 //......................................................................... 127 namespace dbaui 128 { 129 //......................................................................... 130 131 132 #ifdef HAVE_ODBC_SUPPORT 133 typedef SQLRETURN (SQL_API* TSQLManageDataSource) (SQLHWND hwndParent); 134 typedef SQLRETURN (SQL_API* TSQLAllocHandle) (SQLSMALLINT HandleType, SQLHANDLE InputHandle, SQLHANDLE* OutputHandlePtr); 135 typedef SQLRETURN (SQL_API* TSQLFreeHandle) (SQLSMALLINT HandleType, SQLHANDLE Handle); 136 typedef SQLRETURN (SQL_API* TSQLSetEnvAttr) (SQLHENV EnvironmentHandle, SQLINTEGER Attribute, SQLPOINTER ValuePtr, SQLINTEGER StringLength); 137 typedef SQLRETURN (SQL_API* TSQLDataSources) (SQLHENV EnvironmentHandle, SQLUSMALLINT Direction, SQLCHAR* ServerName, 138 SQLSMALLINT BufferLength1, SQLSMALLINT* NameLength1Ptr, SQLCHAR* Description, SQLSMALLINT BufferLength2, SQLSMALLINT* NameLength2Ptr); 139 140 #define NSQLManageDataSource(a) (*(TSQLManageDataSource)(m_pSQLManageDataSource))(a) 141 #define NSQLAllocHandle(a,b,c) (*(TSQLAllocHandle)(m_pAllocHandle))(a,b,c) 142 #define NSQLFreeHandle(a,b) (*(TSQLFreeHandle)(m_pFreeHandle))(a,b) 143 #define NSQLSetEnvAttr(a,b,c,d) (*(TSQLSetEnvAttr)(m_pSetEnvAttr))(a,b,c,d) 144 #define NSQLDataSources(a,b,c,d,e,f,g,h) (*(TSQLDataSources)(m_pDataSources))(a,b,c,d,e,f,g,h) 145 #endif 146 147 //========================================================================= 148 //= OOdbcLibWrapper 149 //========================================================================= 150 DBG_NAME(OOdbcLibWrapper) 151 //------------------------------------------------------------------------- 152 #ifdef HAVE_ODBC_SUPPORT 153 OOdbcLibWrapper::OOdbcLibWrapper() 154 :m_pOdbcLib(NULL) 155 { 156 DBG_CTOR(OOdbcLibWrapper,NULL); 157 158 } 159 #endif 160 161 //------------------------------------------------------------------------- 162 sal_Bool OOdbcLibWrapper::load(const sal_Char* _pLibPath) 163 { 164 m_sLibPath = ::rtl::OUString::createFromAscii(_pLibPath); 165 #ifdef HAVE_ODBC_SUPPORT 166 // load the module 167 m_pOdbcLib = osl_loadModule(m_sLibPath.pData, SAL_LOADMODULE_NOW); 168 return (NULL != m_pOdbcLib); 169 #endif 170 } 171 172 //------------------------------------------------------------------------- 173 void OOdbcLibWrapper::unload() 174 { 175 #ifdef HAVE_ODBC_SUPPORT 176 if (isLoaded()) 177 { 178 osl_unloadModule(m_pOdbcLib); 179 m_pOdbcLib = NULL; 180 } 181 #endif 182 } 183 184 //------------------------------------------------------------------------- 185 oslGenericFunction OOdbcLibWrapper::loadSymbol(const sal_Char* _pFunctionName) 186 { 187 return osl_getFunctionSymbol(m_pOdbcLib, ::rtl::OUString::createFromAscii(_pFunctionName).pData); 188 } 189 190 //------------------------------------------------------------------------- 191 OOdbcLibWrapper::~OOdbcLibWrapper() 192 { 193 unload(); 194 195 DBG_DTOR(OOdbcLibWrapper,NULL); 196 } 197 198 //========================================================================= 199 //= OOdbcEnumeration 200 //========================================================================= 201 struct OdbcTypesImpl 202 { 203 #ifdef HAVE_ODBC_SUPPORT 204 SQLHANDLE hEnvironment; 205 OdbcTypesImpl() : hEnvironment(0) { } 206 #else 207 void* pDummy; 208 #endif 209 }; 210 DBG_NAME(OOdbcEnumeration) 211 //------------------------------------------------------------------------- 212 OOdbcEnumeration::OOdbcEnumeration() 213 #ifdef HAVE_ODBC_SUPPORT 214 :m_pAllocHandle(NULL) 215 ,m_pSetEnvAttr(NULL) 216 ,m_pDataSources(NULL) 217 ,m_pImpl(new OdbcTypesImpl) 218 #endif 219 { 220 DBG_CTOR(OOdbcEnumeration,NULL); 221 222 sal_Bool bLoaded = load(ODBC_LIBRARY); 223 #ifdef ODBC_LIBRARY_1 224 if ( !bLoaded ) 225 bLoaded = load(ODBC_LIBRARY_1); 226 #endif 227 228 if ( bLoaded ) 229 { 230 #ifdef HAVE_ODBC_SUPPORT 231 // load the generic functions 232 m_pAllocHandle = loadSymbol("SQLAllocHandle"); 233 m_pFreeHandle = loadSymbol("SQLFreeHandle"); 234 m_pSetEnvAttr = loadSymbol("SQLSetEnvAttr"); 235 m_pDataSources = loadSymbol("SQLDataSources"); 236 237 // all or nothing 238 if (!m_pAllocHandle || !m_pSetEnvAttr || !m_pDataSources || !m_pFreeHandle) 239 { 240 unload(); 241 m_pAllocHandle = m_pFreeHandle = m_pSetEnvAttr = m_pDataSources = NULL; 242 } 243 #endif 244 } 245 } 246 247 //------------------------------------------------------------------------- 248 OOdbcEnumeration::~OOdbcEnumeration() 249 { 250 freeEnv(); 251 delete m_pImpl; 252 253 DBG_DTOR(OOdbcEnumeration,NULL); 254 } 255 256 //------------------------------------------------------------------------- 257 sal_Bool OOdbcEnumeration::allocEnv() 258 { 259 OSL_ENSURE(isLoaded(), "OOdbcEnumeration::allocEnv: not loaded!"); 260 if (!isLoaded()) 261 return sal_False; 262 263 #ifdef HAVE_ODBC_SUPPORT 264 if (m_pImpl->hEnvironment) 265 // nothing to do 266 return sal_True; 267 SQLRETURN nResult = NSQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &m_pImpl->hEnvironment); 268 if (SQL_SUCCESS != nResult) 269 // can't do anything without environment 270 return sal_False; 271 272 NSQLSetEnvAttr(m_pImpl->hEnvironment, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, SQL_IS_INTEGER); 273 return sal_True; 274 #else 275 return sal_False; 276 #endif 277 } 278 279 //------------------------------------------------------------------------- 280 void OOdbcEnumeration::freeEnv() 281 { 282 #ifdef HAVE_ODBC_SUPPORT 283 if (m_pImpl->hEnvironment) 284 NSQLFreeHandle(SQL_HANDLE_ENV, m_pImpl->hEnvironment); 285 m_pImpl->hEnvironment = 0; 286 #endif 287 } 288 289 //------------------------------------------------------------------------- 290 void OOdbcEnumeration::getDatasourceNames(StringBag& _rNames) 291 { 292 OSL_ENSURE(isLoaded(), "OOdbcEnumeration::getDatasourceNames: not loaded!"); 293 if (!isLoaded()) 294 return; 295 296 if (!allocEnv()) 297 { 298 OSL_ENSURE(sal_False, "OOdbcEnumeration::getDatasourceNames: could not allocate an ODBC environment!"); 299 return; 300 } 301 302 #ifdef HAVE_ODBC_SUPPORT 303 // now that we have an environment collect the data source names 304 UCHAR szDSN[SQL_MAX_DSN_LENGTH+1]; 305 SWORD pcbDSN; 306 UCHAR szDescription[1024+1]; 307 SWORD pcbDescription; 308 SQLRETURN nResult = SQL_SUCCESS; 309 rtl_TextEncoding nTextEncoding = osl_getThreadTextEncoding(); 310 311 for ( nResult = NSQLDataSources(m_pImpl->hEnvironment, SQL_FETCH_FIRST, szDSN, sizeof(szDSN), &pcbDSN, szDescription, sizeof(szDescription)-1, &pcbDescription); 312 ; 313 nResult = NSQLDataSources(m_pImpl->hEnvironment, SQL_FETCH_NEXT, szDSN, sizeof(szDSN), &pcbDSN, szDescription, sizeof(szDescription)-1, &pcbDescription) 314 ) 315 { 316 if (nResult != SQL_SUCCESS) 317 // no further error handling 318 break; 319 else 320 { 321 ::rtl::OUString aCurrentDsn(reinterpret_cast<const char*>(szDSN),pcbDSN, nTextEncoding); 322 _rNames.insert(aCurrentDsn); 323 } 324 } 325 #endif 326 } 327 328 #ifdef HAVE_ODBC_ADMINISTRATION 329 330 //========================================================================= 331 //= ProcessTerminationWait 332 //========================================================================= 333 class ProcessTerminationWait : public ::osl::Thread 334 { 335 oslProcess m_hProcessHandle; 336 Link m_aFinishHdl; 337 338 public: 339 ProcessTerminationWait( oslProcess _hProcessHandle, const Link& _rFinishHdl ) 340 :m_hProcessHandle( _hProcessHandle ) 341 ,m_aFinishHdl( _rFinishHdl ) 342 { 343 } 344 345 protected: 346 virtual void SAL_CALL run() 347 { 348 osl_joinProcess( m_hProcessHandle ); 349 osl_freeProcessHandle( m_hProcessHandle ); 350 Application::PostUserEvent( m_aFinishHdl ); 351 } 352 }; 353 354 //========================================================================= 355 //= OOdbcManagement 356 //========================================================================= 357 //------------------------------------------------------------------------- 358 OOdbcManagement::OOdbcManagement( const Link& _rAsyncFinishCallback ) 359 :m_pProcessWait( NULL ) 360 ,m_aAsyncFinishCallback( _rAsyncFinishCallback ) 361 { 362 } 363 364 //------------------------------------------------------------------------- 365 OOdbcManagement::~OOdbcManagement() 366 { 367 // wait for our thread to be finished 368 if ( m_pProcessWait.get() ) 369 m_pProcessWait->join(); 370 } 371 372 //------------------------------------------------------------------------- 373 bool OOdbcManagement::manageDataSources_async() 374 { 375 OSL_PRECOND( !isRunning(), "OOdbcManagement::manageDataSources_async: still running from the previous call!" ); 376 if ( isRunning() ) 377 return false; 378 379 // this is done in an external process, due to #i78733# 380 // (and note this whole functionality is supported on Windows only, ATM) 381 ::rtl::OUString sExecutableName( RTL_CONSTASCII_USTRINGPARAM( "$OOO_BASE_DIR/program/odbcconfig.exe" ) ); 382 ::rtl::Bootstrap::expandMacros( sExecutableName ); //TODO: detect failure 383 oslProcess hProcessHandle(0); 384 oslProcessError eError = osl_executeProcess( sExecutableName.pData, NULL, 0, 0, NULL, NULL, NULL, 0, &hProcessHandle ); 385 if ( eError != osl_Process_E_None ) 386 return false; 387 388 m_pProcessWait.reset( new ProcessTerminationWait( hProcessHandle, m_aAsyncFinishCallback ) ); 389 m_pProcessWait->create(); 390 return true; 391 } 392 393 //------------------------------------------------------------------------- 394 bool OOdbcManagement::isRunning() const 395 { 396 return ( m_pProcessWait.get() && m_pProcessWait->isRunning() ); 397 } 398 399 #endif // HAVE_ODBC_ADMINISTRATION 400 401 //......................................................................... 402 } // namespace dbaui 403 //......................................................................... 404