xref: /trunk/main/dbaccess/source/ui/dlg/odbcconfig.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
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