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