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