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