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