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 #endif // defined(WNT) 90 91 #if defined(OS2) 92 #define ALLREADY_HAVE_OS2_TYPES 93 #define DONT_TD_VOID 94 #endif 95 96 #ifdef SYSTEM_ODBC_HEADERS 97 #include <sqlext.h> 98 #else 99 #ifndef __SQLEXT_H 100 #include <odbc/sqlext.h> 101 #endif 102 #endif 103 104 #if defined(WNT) 105 #if defined _MSC_VER 106 #pragma warning(pop) 107 #endif 108 #undef SQL_API 109 #define SQL_API __stdcall 110 #endif // defined(WNT) 111 // from here on you can do what you want to 112 113 #else 114 115 #define ODBC_LIBRARY "" 116 #define ODBC_UI_LIBRARY "" 117 118 #endif // HAVE_ODBC_SUPPORT 119 120 //......................................................................... 121 namespace dbaui 122 { 123 //......................................................................... 124 125 126 #ifdef HAVE_ODBC_SUPPORT 127 typedef SQLRETURN (SQL_API* TSQLManageDataSource) (SQLHWND hwndParent); 128 typedef SQLRETURN (SQL_API* TSQLAllocHandle) (SQLSMALLINT HandleType, SQLHANDLE InputHandle, SQLHANDLE* OutputHandlePtr); 129 typedef SQLRETURN (SQL_API* TSQLFreeHandle) (SQLSMALLINT HandleType, SQLHANDLE Handle); 130 typedef SQLRETURN (SQL_API* TSQLSetEnvAttr) (SQLHENV EnvironmentHandle, SQLINTEGER Attribute, SQLPOINTER ValuePtr, SQLINTEGER StringLength); 131 typedef SQLRETURN (SQL_API* TSQLDataSources) (SQLHENV EnvironmentHandle, SQLUSMALLINT Direction, SQLCHAR* ServerName, 132 SQLSMALLINT BufferLength1, SQLSMALLINT* NameLength1Ptr, SQLCHAR* Description, SQLSMALLINT BufferLength2, SQLSMALLINT* NameLength2Ptr); 133 134 #define NSQLManageDataSource(a) (*(TSQLManageDataSource)(m_pSQLManageDataSource))(a) 135 #define NSQLAllocHandle(a,b,c) (*(TSQLAllocHandle)(m_pAllocHandle))(a,b,c) 136 #define NSQLFreeHandle(a,b) (*(TSQLFreeHandle)(m_pFreeHandle))(a,b) 137 #define NSQLSetEnvAttr(a,b,c,d) (*(TSQLSetEnvAttr)(m_pSetEnvAttr))(a,b,c,d) 138 #define NSQLDataSources(a,b,c,d,e,f,g,h) (*(TSQLDataSources)(m_pDataSources))(a,b,c,d,e,f,g,h) 139 #endif 140 141 //========================================================================= 142 //= OOdbcLibWrapper 143 //========================================================================= 144 DBG_NAME(OOdbcLibWrapper) 145 //------------------------------------------------------------------------- 146 #ifdef HAVE_ODBC_SUPPORT 147 OOdbcLibWrapper::OOdbcLibWrapper() 148 :m_pOdbcLib(NULL) 149 { 150 DBG_CTOR(OOdbcLibWrapper,NULL); 151 152 } 153 #endif 154 155 //------------------------------------------------------------------------- 156 sal_Bool OOdbcLibWrapper::load(const sal_Char* _pLibPath) 157 { 158 m_sLibPath = ::rtl::OUString::createFromAscii(_pLibPath); 159 #ifdef HAVE_ODBC_SUPPORT 160 // load the module 161 m_pOdbcLib = osl_loadModule(m_sLibPath.pData, SAL_LOADMODULE_NOW); 162 return (NULL != m_pOdbcLib); 163 #endif 164 } 165 166 //------------------------------------------------------------------------- 167 void OOdbcLibWrapper::unload() 168 { 169 #ifdef HAVE_ODBC_SUPPORT 170 if (isLoaded()) 171 { 172 osl_unloadModule(m_pOdbcLib); 173 m_pOdbcLib = NULL; 174 } 175 #endif 176 } 177 178 //------------------------------------------------------------------------- 179 oslGenericFunction OOdbcLibWrapper::loadSymbol(const sal_Char* _pFunctionName) 180 { 181 return osl_getFunctionSymbol(m_pOdbcLib, ::rtl::OUString::createFromAscii(_pFunctionName).pData); 182 } 183 184 //------------------------------------------------------------------------- 185 OOdbcLibWrapper::~OOdbcLibWrapper() 186 { 187 unload(); 188 189 DBG_DTOR(OOdbcLibWrapper,NULL); 190 } 191 192 //========================================================================= 193 //= OOdbcEnumeration 194 //========================================================================= 195 struct OdbcTypesImpl 196 { 197 #ifdef HAVE_ODBC_SUPPORT 198 SQLHANDLE hEnvironment; 199 OdbcTypesImpl() : hEnvironment(0) { } 200 #else 201 void* pDummy; 202 #endif 203 }; 204 DBG_NAME(OOdbcEnumeration) 205 //------------------------------------------------------------------------- 206 OOdbcEnumeration::OOdbcEnumeration() 207 #ifdef HAVE_ODBC_SUPPORT 208 :m_pAllocHandle(NULL) 209 ,m_pSetEnvAttr(NULL) 210 ,m_pDataSources(NULL) 211 ,m_pImpl(new OdbcTypesImpl) 212 #endif 213 { 214 DBG_CTOR(OOdbcEnumeration,NULL); 215 216 sal_Bool bLoaded = load(ODBC_LIBRARY); 217 #ifdef ODBC_LIBRARY_1 218 if ( !bLoaded ) 219 bLoaded = load(ODBC_LIBRARY_1); 220 #endif 221 #ifdef ODBC_LIBRARY_2 222 if ( !bLoaded ) 223 bLoaded = load(ODBC_LIBRARY_2); 224 #endif 225 226 if ( bLoaded ) 227 { 228 #ifdef HAVE_ODBC_SUPPORT 229 // load the generic functions 230 m_pAllocHandle = loadSymbol("SQLAllocHandle"); 231 m_pFreeHandle = loadSymbol("SQLFreeHandle"); 232 m_pSetEnvAttr = loadSymbol("SQLSetEnvAttr"); 233 m_pDataSources = loadSymbol("SQLDataSources"); 234 235 // all or nothing 236 if (!m_pAllocHandle || !m_pSetEnvAttr || !m_pDataSources || !m_pFreeHandle) 237 { 238 unload(); 239 m_pAllocHandle = m_pFreeHandle = m_pSetEnvAttr = m_pDataSources = NULL; 240 } 241 #endif 242 } 243 } 244 245 //------------------------------------------------------------------------- 246 OOdbcEnumeration::~OOdbcEnumeration() 247 { 248 freeEnv(); 249 delete m_pImpl; 250 251 DBG_DTOR(OOdbcEnumeration,NULL); 252 } 253 254 //------------------------------------------------------------------------- 255 sal_Bool OOdbcEnumeration::allocEnv() 256 { 257 OSL_ENSURE(isLoaded(), "OOdbcEnumeration::allocEnv: not loaded!"); 258 if (!isLoaded()) 259 return sal_False; 260 261 #ifdef HAVE_ODBC_SUPPORT 262 if (m_pImpl->hEnvironment) 263 // nothing to do 264 return sal_True; 265 SQLRETURN nResult = NSQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &m_pImpl->hEnvironment); 266 if (SQL_SUCCESS != nResult) 267 // can't do anything without environment 268 return sal_False; 269 270 NSQLSetEnvAttr(m_pImpl->hEnvironment, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, SQL_IS_INTEGER); 271 return sal_True; 272 #else 273 return sal_False; 274 #endif 275 } 276 277 //------------------------------------------------------------------------- 278 void OOdbcEnumeration::freeEnv() 279 { 280 #ifdef HAVE_ODBC_SUPPORT 281 if (m_pImpl->hEnvironment) 282 NSQLFreeHandle(SQL_HANDLE_ENV, m_pImpl->hEnvironment); 283 m_pImpl->hEnvironment = 0; 284 #endif 285 } 286 287 //------------------------------------------------------------------------- 288 void OOdbcEnumeration::getDatasourceNames(StringBag& _rNames) 289 { 290 OSL_ENSURE(isLoaded(), "OOdbcEnumeration::getDatasourceNames: not loaded!"); 291 if (!isLoaded()) 292 return; 293 294 if (!allocEnv()) 295 { 296 OSL_ENSURE(sal_False, "OOdbcEnumeration::getDatasourceNames: could not allocate an ODBC environment!"); 297 return; 298 } 299 300 #ifdef HAVE_ODBC_SUPPORT 301 // now that we have an environment collect the data source names 302 UCHAR szDSN[SQL_MAX_DSN_LENGTH+1]; 303 SWORD pcbDSN; 304 UCHAR szDescription[1024+1]; 305 SWORD pcbDescription; 306 SQLRETURN nResult = SQL_SUCCESS; 307 rtl_TextEncoding nTextEncoding = osl_getThreadTextEncoding(); 308 309 for ( nResult = NSQLDataSources(m_pImpl->hEnvironment, SQL_FETCH_FIRST, szDSN, sizeof(szDSN), &pcbDSN, szDescription, sizeof(szDescription)-1, &pcbDescription); 310 ; 311 nResult = NSQLDataSources(m_pImpl->hEnvironment, SQL_FETCH_NEXT, szDSN, sizeof(szDSN), &pcbDSN, szDescription, sizeof(szDescription)-1, &pcbDescription) 312 ) 313 { 314 if (nResult != SQL_SUCCESS) 315 // no further error handling 316 break; 317 else 318 { 319 ::rtl::OUString aCurrentDsn(reinterpret_cast<const char*>(szDSN),pcbDSN, nTextEncoding); 320 _rNames.insert(aCurrentDsn); 321 } 322 } 323 #endif 324 } 325 326 #ifdef HAVE_ODBC_ADMINISTRATION 327 328 //========================================================================= 329 //= ProcessTerminationWait 330 //========================================================================= 331 class ProcessTerminationWait : public ::osl::Thread 332 { 333 oslProcess m_hProcessHandle; 334 Link m_aFinishHdl; 335 336 public: 337 ProcessTerminationWait( oslProcess _hProcessHandle, const Link& _rFinishHdl ) 338 :m_hProcessHandle( _hProcessHandle ) 339 ,m_aFinishHdl( _rFinishHdl ) 340 { 341 } 342 343 protected: 344 virtual void SAL_CALL run() 345 { 346 osl_joinProcess( m_hProcessHandle ); 347 osl_freeProcessHandle( m_hProcessHandle ); 348 Application::PostUserEvent( m_aFinishHdl ); 349 } 350 }; 351 352 //========================================================================= 353 //= OOdbcManagement 354 //========================================================================= 355 //------------------------------------------------------------------------- 356 OOdbcManagement::OOdbcManagement( const Link& _rAsyncFinishCallback ) 357 :m_pProcessWait( NULL ) 358 ,m_aAsyncFinishCallback( _rAsyncFinishCallback ) 359 { 360 } 361 362 //------------------------------------------------------------------------- 363 OOdbcManagement::~OOdbcManagement() 364 { 365 // wait for our thread to be finished 366 if ( m_pProcessWait.get() ) 367 m_pProcessWait->join(); 368 } 369 370 //------------------------------------------------------------------------- 371 bool OOdbcManagement::manageDataSources_async() 372 { 373 OSL_PRECOND( !isRunning(), "OOdbcManagement::manageDataSources_async: still running from the previous call!" ); 374 if ( isRunning() ) 375 return false; 376 377 // this is done in an external process, due to #i78733# 378 // (and note this whole functionality is supported on Windows only, ATM) 379 ::rtl::OUString sExecutableName( RTL_CONSTASCII_USTRINGPARAM( "$OOO_BASE_DIR/program/odbcconfig.exe" ) ); 380 ::rtl::Bootstrap::expandMacros( sExecutableName ); //TODO: detect failure 381 oslProcess hProcessHandle(0); 382 oslProcessError eError = osl_executeProcess( sExecutableName.pData, NULL, 0, 0, NULL, NULL, NULL, 0, &hProcessHandle ); 383 if ( eError != osl_Process_E_None ) 384 return false; 385 386 m_pProcessWait.reset( new ProcessTerminationWait( hProcessHandle, m_aAsyncFinishCallback ) ); 387 m_pProcessWait->create(); 388 return true; 389 } 390 391 //------------------------------------------------------------------------- 392 bool OOdbcManagement::isRunning() const 393 { 394 return ( m_pProcessWait.get() && m_pProcessWait->isRunning() ); 395 } 396 397 #endif // HAVE_ODBC_ADMINISTRATION 398 399 //......................................................................... 400 } // namespace dbaui 401 //......................................................................... 402