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 : #include <rtl/bootstrap.hxx>
24 : #include <rtl/ustring.hxx>
25 : #include <rtl/ustrbuf.hxx>
26 : #include <osl/diagnose.h>
27 : #include <osl/process.h>
28 : #include <osl/thread.hxx>
29 : #include <tools/debug.hxx>
30 : #include <vcl/svapp.hxx>
31 :
32 : #ifdef HAVE_ODBC_SUPPORT
33 :
34 : #if defined WNT
35 : #define ODBC_LIBRARY "ODBC32.DLL"
36 : #endif
37 : #ifdef UNX
38 : #ifdef MACOSX
39 : #define ODBC_LIBRARY "libiodbc.dylib"
40 : #else
41 : #define ODBC_LIBRARY_1 "libodbc.so.1"
42 : #define ODBC_LIBRARY "libodbc.so"
43 : #endif
44 : #endif
45 :
46 : #include <connectivity/odbc.hxx>
47 :
48 : #else
49 :
50 : #define ODBC_LIBRARY ""
51 :
52 : #endif // HAVE_ODBC_SUPPORT
53 :
54 : namespace dbaui
55 : {
56 :
57 : #ifdef HAVE_ODBC_SUPPORT
58 : typedef SQLRETURN (SQL_API* TSQLManageDataSource) (SQLHWND hwndParent);
59 : typedef SQLRETURN (SQL_API* TSQLAllocHandle) (SQLSMALLINT HandleType, SQLHANDLE InputHandle, SQLHANDLE* OutputHandlePtr);
60 : typedef SQLRETURN (SQL_API* TSQLFreeHandle) (SQLSMALLINT HandleType, SQLHANDLE Handle);
61 : typedef SQLRETURN (SQL_API* TSQLSetEnvAttr) (SQLHENV EnvironmentHandle, SQLINTEGER Attribute, SQLPOINTER ValuePtr, SQLINTEGER StringLength);
62 : typedef SQLRETURN (SQL_API* TSQLDataSources) (SQLHENV EnvironmentHandle, SQLUSMALLINT Direction, SQLCHAR* ServerName,
63 : SQLSMALLINT BufferLength1, SQLSMALLINT* NameLength1Ptr, SQLCHAR* Description, SQLSMALLINT BufferLength2, SQLSMALLINT* NameLength2Ptr);
64 :
65 : #define NSQLAllocHandle(a,b,c) (*reinterpret_cast<TSQLAllocHandle>(m_pAllocHandle))(a,b,c)
66 : #define NSQLFreeHandle(a,b) (*reinterpret_cast<TSQLFreeHandle>(m_pFreeHandle))(a,b)
67 : #define NSQLSetEnvAttr(a,b,c,d) (*reinterpret_cast<TSQLSetEnvAttr>(m_pSetEnvAttr))(a,b,c,d)
68 : #define NSQLDataSources(a,b,c,d,e,f,g,h) (*reinterpret_cast<TSQLDataSources>(m_pDataSources))(a,b,c,d,e,f,g,h)
69 : #endif
70 :
71 : // OOdbcLibWrapper
72 : #ifdef HAVE_ODBC_SUPPORT
73 0 : OOdbcLibWrapper::OOdbcLibWrapper()
74 0 : :m_pOdbcLib(NULL)
75 : {
76 :
77 0 : }
78 :
79 : #endif
80 :
81 0 : bool OOdbcLibWrapper::load(const sal_Char* _pLibPath)
82 : {
83 0 : m_sLibPath = OUString::createFromAscii(_pLibPath);
84 : #ifdef HAVE_ODBC_SUPPORT
85 : // load the module
86 0 : m_pOdbcLib = osl_loadModule(m_sLibPath.pData, SAL_LOADMODULE_NOW);
87 0 : return (NULL != m_pOdbcLib);
88 : #else
89 : return sal_False;
90 : #endif
91 : }
92 :
93 0 : void OOdbcLibWrapper::unload()
94 : {
95 : #ifdef HAVE_ODBC_SUPPORT
96 0 : if (isLoaded())
97 : {
98 0 : osl_unloadModule(m_pOdbcLib);
99 0 : m_pOdbcLib = NULL;
100 : }
101 : #endif
102 0 : }
103 :
104 0 : oslGenericFunction OOdbcLibWrapper::loadSymbol(const sal_Char* _pFunctionName)
105 : {
106 0 : return osl_getFunctionSymbol(m_pOdbcLib, OUString::createFromAscii(_pFunctionName).pData);
107 : }
108 :
109 0 : OOdbcLibWrapper::~OOdbcLibWrapper()
110 : {
111 0 : unload();
112 :
113 0 : }
114 :
115 : // OOdbcEnumeration
116 : struct OdbcTypesImpl
117 : {
118 : #ifdef HAVE_ODBC_SUPPORT
119 : SQLHANDLE hEnvironment;
120 0 : OdbcTypesImpl() : hEnvironment(0) { }
121 : #else
122 : void* pDummy;
123 : #endif
124 : };
125 :
126 0 : OOdbcEnumeration::OOdbcEnumeration()
127 : #ifdef HAVE_ODBC_SUPPORT
128 : :m_pAllocHandle(NULL)
129 : ,m_pFreeHandle(NULL)
130 : ,m_pSetEnvAttr(NULL)
131 : ,m_pDataSources(NULL)
132 0 : ,m_pImpl(new OdbcTypesImpl)
133 : #endif
134 : {
135 0 : bool bLoaded = load(ODBC_LIBRARY);
136 : #ifdef ODBC_LIBRARY_1
137 0 : if ( !bLoaded )
138 0 : bLoaded = load(ODBC_LIBRARY_1);
139 : #endif
140 :
141 0 : if ( bLoaded )
142 : {
143 : #ifdef HAVE_ODBC_SUPPORT
144 : // load the generic functions
145 0 : m_pAllocHandle = loadSymbol("SQLAllocHandle");
146 0 : m_pFreeHandle = loadSymbol("SQLFreeHandle");
147 0 : m_pSetEnvAttr = loadSymbol("SQLSetEnvAttr");
148 0 : m_pDataSources = loadSymbol("SQLDataSources");
149 :
150 : // all or nothing
151 0 : if (!m_pAllocHandle || !m_pSetEnvAttr || !m_pDataSources || !m_pFreeHandle)
152 : {
153 0 : unload();
154 0 : m_pAllocHandle = m_pFreeHandle = m_pSetEnvAttr = m_pDataSources = NULL;
155 : }
156 : #endif
157 : }
158 0 : }
159 :
160 0 : OOdbcEnumeration::~OOdbcEnumeration()
161 : {
162 0 : freeEnv();
163 0 : delete m_pImpl;
164 :
165 0 : }
166 :
167 0 : bool OOdbcEnumeration::allocEnv()
168 : {
169 : OSL_ENSURE(isLoaded(), "OOdbcEnumeration::allocEnv: not loaded!");
170 0 : if (!isLoaded())
171 0 : return false;
172 :
173 : #ifdef HAVE_ODBC_SUPPORT
174 0 : if (m_pImpl->hEnvironment)
175 : // nothing to do
176 0 : return true;
177 0 : SQLRETURN nResult = NSQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &m_pImpl->hEnvironment);
178 0 : if (SQL_SUCCESS != nResult)
179 : // can't do anything without environment
180 0 : return false;
181 :
182 0 : NSQLSetEnvAttr(m_pImpl->hEnvironment, SQL_ATTR_ODBC_VERSION, reinterpret_cast<SQLPOINTER>(SQL_OV_ODBC3), SQL_IS_INTEGER);
183 0 : return true;
184 : #else
185 : return sal_False;
186 : #endif
187 : }
188 :
189 0 : void OOdbcEnumeration::freeEnv()
190 : {
191 : #ifdef HAVE_ODBC_SUPPORT
192 0 : if (m_pImpl->hEnvironment)
193 0 : NSQLFreeHandle(SQL_HANDLE_ENV, m_pImpl->hEnvironment);
194 0 : m_pImpl->hEnvironment = 0;
195 : #endif
196 0 : }
197 :
198 0 : void OOdbcEnumeration::getDatasourceNames(StringBag& _rNames)
199 : {
200 : OSL_ENSURE(isLoaded(), "OOdbcEnumeration::getDatasourceNames: not loaded!");
201 0 : if (!isLoaded())
202 0 : return;
203 :
204 0 : if (!allocEnv())
205 : {
206 : OSL_FAIL("OOdbcEnumeration::getDatasourceNames: could not allocate an ODBC environment!");
207 0 : return;
208 : }
209 :
210 : #ifdef HAVE_ODBC_SUPPORT
211 : // now that we have an environment collect the data source names
212 : UCHAR szDSN[SQL_MAX_DSN_LENGTH+1];
213 : SWORD pcbDSN;
214 : UCHAR szDescription[1024+1];
215 : SWORD pcbDescription;
216 0 : SQLRETURN nResult = SQL_SUCCESS;
217 0 : rtl_TextEncoding nTextEncoding = osl_getThreadTextEncoding();
218 :
219 0 : for ( nResult = NSQLDataSources(m_pImpl->hEnvironment, SQL_FETCH_FIRST, szDSN, sizeof(szDSN), &pcbDSN, szDescription, sizeof(szDescription)-1, &pcbDescription);
220 : ;
221 0 : nResult = NSQLDataSources(m_pImpl->hEnvironment, SQL_FETCH_NEXT, szDSN, sizeof(szDSN), &pcbDSN, szDescription, sizeof(szDescription)-1, &pcbDescription)
222 : )
223 : {
224 0 : if (nResult != SQL_SUCCESS)
225 : // no further error handling
226 0 : break;
227 : else
228 : {
229 0 : OUString aCurrentDsn(reinterpret_cast<const char*>(szDSN),pcbDSN, nTextEncoding);
230 0 : _rNames.insert(aCurrentDsn);
231 : }
232 0 : }
233 : #else
234 : (void) _rNames;
235 : #endif
236 : }
237 :
238 : #ifdef HAVE_ODBC_ADMINISTRATION
239 :
240 : // ProcessTerminationWait
241 : class ProcessTerminationWait : public ::osl::Thread
242 : {
243 : oslProcess m_hProcessHandle;
244 : Link<> m_aFinishHdl;
245 :
246 : public:
247 : ProcessTerminationWait( oslProcess _hProcessHandle, const Link<>& _rFinishHdl )
248 : :m_hProcessHandle( _hProcessHandle )
249 : ,m_aFinishHdl( _rFinishHdl )
250 : {
251 : }
252 :
253 : protected:
254 : virtual void SAL_CALL run()
255 : {
256 : osl_setThreadName("dbaui::ProcessTerminationWait");
257 :
258 : osl_joinProcess( m_hProcessHandle );
259 : osl_freeProcessHandle( m_hProcessHandle );
260 : Application::PostUserEvent( m_aFinishHdl );
261 : }
262 : };
263 :
264 : // OOdbcManagement
265 : OOdbcManagement::OOdbcManagement(const Link<>& rAsyncFinishCallback)
266 : : m_aAsyncFinishCallback(rAsyncFinishCallback)
267 : {
268 : }
269 :
270 : OOdbcManagement::~OOdbcManagement()
271 : {
272 : // wait for our thread to be finished
273 : if ( m_pProcessWait.get() )
274 : m_pProcessWait->join();
275 : }
276 :
277 : bool OOdbcManagement::manageDataSources_async()
278 : {
279 : OSL_PRECOND( !isRunning(), "OOdbcManagement::manageDataSources_async: still running from the previous call!" );
280 : if ( isRunning() )
281 : return false;
282 :
283 : // this is done in an external process, due to #i78733#
284 : // (and note this whole functionality is supported on Windows only, ATM)
285 : OUString sExecutableName( "$BRAND_BASE_DIR/" LIBO_LIBEXEC_FOLDER "/odbcconfig.exe" );
286 : ::rtl::Bootstrap::expandMacros( sExecutableName ); //TODO: detect failure
287 : oslProcess hProcessHandle(0);
288 : oslProcessError eError = osl_executeProcess( sExecutableName.pData, NULL, 0, 0, NULL, NULL, NULL, 0, &hProcessHandle );
289 : if ( eError != osl_Process_E_None )
290 : return false;
291 :
292 : m_pProcessWait.reset( new ProcessTerminationWait( hProcessHandle, m_aAsyncFinishCallback ) );
293 : m_pProcessWait->create();
294 : return true;
295 : }
296 :
297 : bool OOdbcManagement::isRunning() const
298 : {
299 : return ( m_pProcessWait.get() && m_pProcessWait->isRunning() );
300 : }
301 :
302 : #endif // HAVE_ODBC_ADMINISTRATION
303 :
304 : } // namespace dbaui
305 :
306 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|