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