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