1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <config_folders.h>
21 #include "odbcconfig.hxx"
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>
30 #ifdef HAVE_ODBC_SUPPORT
33 #define ODBC_LIBRARY "ODBC32.DLL"
37 #define ODBC_LIBRARY "libiodbc.dylib"
39 #define ODBC_LIBRARY_PLAIN "libodbc.so"
40 #define ODBC_LIBRARY_1 "libodbc.so.1"
41 #define ODBC_LIBRARY "libodbc.so.2"
45 #include <connectivity/odbc.hxx>
49 #define ODBC_LIBRARY ""
51 #endif // HAVE_ODBC_SUPPORT
56 #ifdef HAVE_ODBC_SUPPORT
57 typedef SQLRETURN (SQL_API
* TSQLManageDataSource
) (SQLHWND hwndParent
);
58 typedef SQLRETURN (SQL_API
* TSQLAllocHandle
) (SQLSMALLINT HandleType
, SQLHANDLE InputHandle
, SQLHANDLE
* OutputHandlePtr
);
59 typedef SQLRETURN (SQL_API
* TSQLFreeHandle
) (SQLSMALLINT HandleType
, SQLHANDLE Handle
);
60 typedef SQLRETURN (SQL_API
* TSQLSetEnvAttr
) (SQLHENV EnvironmentHandle
, SQLINTEGER Attribute
, SQLPOINTER ValuePtr
, SQLINTEGER StringLength
);
61 typedef SQLRETURN (SQL_API
* TSQLDataSources
) (SQLHENV EnvironmentHandle
, SQLUSMALLINT Direction
, SQLCHAR
* ServerName
,
62 SQLSMALLINT BufferLength1
, SQLSMALLINT
* NameLength1Ptr
, SQLCHAR
* Description
, SQLSMALLINT BufferLength2
, SQLSMALLINT
* NameLength2Ptr
);
68 bool OOdbcEnumeration::load(const char* _pLibPath
)
70 m_sLibPath
= OUString::createFromAscii(_pLibPath
);
71 #if defined(HAVE_ODBC_SUPPORT) && !defined(DISABLE_DYNLOADING)
73 m_pOdbcLib
= osl_loadModule(m_sLibPath
.pData
, SAL_LOADMODULE_NOW
);
74 return (nullptr != m_pOdbcLib
);
80 void OOdbcEnumeration::unload()
82 #if defined(HAVE_ODBC_SUPPORT) && !defined(DISABLE_DYNLOADING)
85 osl_unloadModule(m_pOdbcLib
);
91 oslGenericFunction
OOdbcEnumeration::loadSymbol(const char* _pFunctionName
)
93 return osl_getFunctionSymbol(m_pOdbcLib
, OUString::createFromAscii(_pFunctionName
).pData
);
99 #ifdef HAVE_ODBC_SUPPORT
100 SQLHANDLE hEnvironment
;
101 OdbcTypesImpl() : hEnvironment(nullptr) { }
107 OOdbcEnumeration::OOdbcEnumeration()
109 #ifdef HAVE_ODBC_SUPPORT
110 ,m_pAllocHandle(nullptr)
111 ,m_pFreeHandle(nullptr)
112 ,m_pSetEnvAttr(nullptr)
113 ,m_pDataSources(nullptr)
114 ,m_pImpl(new OdbcTypesImpl
)
117 bool bLoaded
= load(ODBC_LIBRARY
);
118 #ifdef ODBC_LIBRARY_1
120 bLoaded
= load(ODBC_LIBRARY_1
);
122 #ifdef ODBC_LIBRARY_PLAIN
124 bLoaded
= load(ODBC_LIBRARY_PLAIN
);
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");
138 if (!m_pAllocHandle
|| !m_pSetEnvAttr
|| !m_pDataSources
|| !m_pFreeHandle
)
141 m_pAllocHandle
= m_pFreeHandle
= m_pSetEnvAttr
= m_pDataSources
= nullptr;
146 OOdbcEnumeration::~OOdbcEnumeration()
153 bool OOdbcEnumeration::allocEnv()
155 OSL_ENSURE(isLoaded(), "OOdbcEnumeration::allocEnv: not loaded!");
159 #ifdef HAVE_ODBC_SUPPORT
160 if (m_pImpl
->hEnvironment
)
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
168 (*reinterpret_cast<TSQLSetEnvAttr
>(m_pSetEnvAttr
))(m_pImpl
->hEnvironment
, SQL_ATTR_ODBC_VERSION
, reinterpret_cast<SQLPOINTER
>(SQL_OV_ODBC3
),SQL_IS_INTEGER
);
175 void OOdbcEnumeration::freeEnv()
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;
184 void OOdbcEnumeration::getDatasourceNames(std::set
<OUString
>& _rNames
)
186 OSL_ENSURE(isLoaded(), "OOdbcEnumeration::getDatasourceNames: not loaded!");
192 OSL_FAIL("OOdbcEnumeration::getDatasourceNames: could not allocate an ODBC environment!");
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];
200 UCHAR szDescription
[1024+1];
201 SWORD pcbDescription
;
202 SQLRETURN nResult
= SQL_SUCCESS
;
203 rtl_TextEncoding nTextEncoding
= osl_getThreadTextEncoding();
205 for ( nResult
= (*reinterpret_cast<TSQLDataSources
>(m_pDataSources
))(m_pImpl
->hEnvironment
, SQL_FETCH_FIRST
, szDSN
,
206 sizeof(szDSN
), &pcbDSN
, szDescription
, sizeof(szDescription
)-1, &pcbDescription
);
208 nResult
= (*reinterpret_cast<TSQLDataSources
>(m_pDataSources
))(m_pImpl
->hEnvironment
, SQL_FETCH_NEXT
, szDSN
,
209 sizeof(szDSN
), &pcbDSN
, szDescription
, sizeof(szDescription
)-1, &pcbDescription
)
212 if (nResult
!= SQL_SUCCESS
)
213 // no further error handling
217 OUString
aCurrentDsn(reinterpret_cast<const char*>(szDSN
),pcbDSN
, nTextEncoding
);
218 _rNames
.insert(aCurrentDsn
);
226 #ifdef HAVE_ODBC_ADMINISTRATION
228 // ProcessTerminationWait
229 class ProcessTerminationWait
: public ::osl::Thread
231 oslProcess m_hProcessHandle
;
232 Link
<void*,void> m_aFinishHdl
;
233 ImplSVEvent
* m_nEventId
;
236 ProcessTerminationWait( oslProcess _hProcessHandle
, const Link
<void*,void>& _rFinishHdl
)
237 : m_hProcessHandle( _hProcessHandle
)
238 , m_aFinishHdl( _rFinishHdl
)
239 , m_nEventId(nullptr)
243 void disableCallback()
245 // if finished event not posted yet, disable by turning it to a no-op Link
246 m_aFinishHdl
= Link
<void*, void>();
249 // already posted, remove it
250 Application::RemoveUserEvent(m_nEventId
);
251 m_nEventId
= nullptr;
255 void receivedCallback()
257 m_nEventId
= nullptr;
261 virtual void SAL_CALL
run() override
263 osl_setThreadName("dbaui::ProcessTerminationWait");
265 osl_joinProcess( m_hProcessHandle
);
266 osl_freeProcessHandle( m_hProcessHandle
);
267 m_nEventId
= Application::PostUserEvent( m_aFinishHdl
);
272 OOdbcManagement::OOdbcManagement(const Link
<void*,void>& rAsyncFinishCallback
)
273 : m_aAsyncFinishCallback(rAsyncFinishCallback
)
277 OOdbcManagement::~OOdbcManagement()
279 // wait for our thread to be finished
280 if ( m_pProcessWait
)
281 m_pProcessWait
->join();
284 bool OOdbcManagement::manageDataSources_async()
286 OSL_PRECOND( !isRunning(), "OOdbcManagement::manageDataSources_async: still running from the previous call!" );
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
)
299 m_pProcessWait
.reset( new ProcessTerminationWait( hProcessHandle
, m_aAsyncFinishCallback
) );
300 m_pProcessWait
->create();
304 void OOdbcManagement::disableCallback()
307 m_pProcessWait
->disableCallback();
310 void OOdbcManagement::receivedCallback()
313 m_pProcessWait
->receivedCallback();
316 bool OOdbcManagement::isRunning() const
318 return ( m_pProcessWait
&& m_pProcessWait
->isRunning() );
321 #endif // HAVE_ODBC_ADMINISTRATION
325 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */