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