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 <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>
32 #ifdef HAVE_ODBC_SUPPORT
35 #define ODBC_LIBRARY "ODBC32.DLL"
39 #define ODBC_LIBRARY "libiodbc.dylib"
41 #define ODBC_LIBRARY_1 "libodbc.so.1"
42 #define ODBC_LIBRARY "libodbc.so"
46 #include <connectivity/odbc.hxx>
50 #define ODBC_LIBRARY ""
52 #endif // HAVE_ODBC_SUPPORT
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
);
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)
72 #ifdef HAVE_ODBC_SUPPORT
73 OOdbcLibWrapper::OOdbcLibWrapper()
81 bool OOdbcLibWrapper::load(const sal_Char
* _pLibPath
)
83 m_sLibPath
= OUString::createFromAscii(_pLibPath
);
84 #ifdef HAVE_ODBC_SUPPORT
86 m_pOdbcLib
= osl_loadModule(m_sLibPath
.pData
, SAL_LOADMODULE_NOW
);
87 return (NULL
!= m_pOdbcLib
);
93 void OOdbcLibWrapper::unload()
95 #ifdef HAVE_ODBC_SUPPORT
98 osl_unloadModule(m_pOdbcLib
);
104 oslGenericFunction
OOdbcLibWrapper::loadSymbol(const sal_Char
* _pFunctionName
)
106 return osl_getFunctionSymbol(m_pOdbcLib
, OUString::createFromAscii(_pFunctionName
).pData
);
109 OOdbcLibWrapper::~OOdbcLibWrapper()
118 #ifdef HAVE_ODBC_SUPPORT
119 SQLHANDLE hEnvironment
;
120 OdbcTypesImpl() : hEnvironment(0) { }
126 OOdbcEnumeration::OOdbcEnumeration()
127 #ifdef HAVE_ODBC_SUPPORT
128 :m_pAllocHandle(NULL
)
131 ,m_pDataSources(NULL
)
132 ,m_pImpl(new OdbcTypesImpl
)
135 bool bLoaded
= load(ODBC_LIBRARY
);
136 #ifdef ODBC_LIBRARY_1
138 bLoaded
= load(ODBC_LIBRARY_1
);
143 #ifdef HAVE_ODBC_SUPPORT
144 // load the generic functions
145 m_pAllocHandle
= loadSymbol("SQLAllocHandle");
146 m_pFreeHandle
= loadSymbol("SQLFreeHandle");
147 m_pSetEnvAttr
= loadSymbol("SQLSetEnvAttr");
148 m_pDataSources
= loadSymbol("SQLDataSources");
151 if (!m_pAllocHandle
|| !m_pSetEnvAttr
|| !m_pDataSources
|| !m_pFreeHandle
)
154 m_pAllocHandle
= m_pFreeHandle
= m_pSetEnvAttr
= m_pDataSources
= NULL
;
160 OOdbcEnumeration::~OOdbcEnumeration()
167 bool OOdbcEnumeration::allocEnv()
169 OSL_ENSURE(isLoaded(), "OOdbcEnumeration::allocEnv: not loaded!");
173 #ifdef HAVE_ODBC_SUPPORT
174 if (m_pImpl
->hEnvironment
)
177 SQLRETURN nResult
= NSQLAllocHandle(SQL_HANDLE_ENV
, SQL_NULL_HANDLE
, &m_pImpl
->hEnvironment
);
178 if (SQL_SUCCESS
!= nResult
)
179 // can't do anything without environment
182 NSQLSetEnvAttr(m_pImpl
->hEnvironment
, SQL_ATTR_ODBC_VERSION
, reinterpret_cast<SQLPOINTER
>(SQL_OV_ODBC3
), SQL_IS_INTEGER
);
189 void OOdbcEnumeration::freeEnv()
191 #ifdef HAVE_ODBC_SUPPORT
192 if (m_pImpl
->hEnvironment
)
193 NSQLFreeHandle(SQL_HANDLE_ENV
, m_pImpl
->hEnvironment
);
194 m_pImpl
->hEnvironment
= 0;
198 void OOdbcEnumeration::getDatasourceNames(StringBag
& _rNames
)
200 OSL_ENSURE(isLoaded(), "OOdbcEnumeration::getDatasourceNames: not loaded!");
206 OSL_FAIL("OOdbcEnumeration::getDatasourceNames: could not allocate an ODBC environment!");
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];
214 UCHAR szDescription
[1024+1];
215 SWORD pcbDescription
;
216 SQLRETURN nResult
= SQL_SUCCESS
;
217 rtl_TextEncoding nTextEncoding
= osl_getThreadTextEncoding();
219 for ( nResult
= NSQLDataSources(m_pImpl
->hEnvironment
, SQL_FETCH_FIRST
, szDSN
, sizeof(szDSN
), &pcbDSN
, szDescription
, sizeof(szDescription
)-1, &pcbDescription
);
221 nResult
= NSQLDataSources(m_pImpl
->hEnvironment
, SQL_FETCH_NEXT
, szDSN
, sizeof(szDSN
), &pcbDSN
, szDescription
, sizeof(szDescription
)-1, &pcbDescription
)
224 if (nResult
!= SQL_SUCCESS
)
225 // no further error handling
229 OUString
aCurrentDsn(reinterpret_cast<const char*>(szDSN
),pcbDSN
, nTextEncoding
);
230 _rNames
.insert(aCurrentDsn
);
238 #ifdef HAVE_ODBC_ADMINISTRATION
240 // ProcessTerminationWait
241 class ProcessTerminationWait
: public ::osl::Thread
243 oslProcess m_hProcessHandle
;
247 ProcessTerminationWait( oslProcess _hProcessHandle
, const Link
<>& _rFinishHdl
)
248 :m_hProcessHandle( _hProcessHandle
)
249 ,m_aFinishHdl( _rFinishHdl
)
254 virtual void SAL_CALL
run()
256 osl_setThreadName("dbaui::ProcessTerminationWait");
258 osl_joinProcess( m_hProcessHandle
);
259 osl_freeProcessHandle( m_hProcessHandle
);
260 Application::PostUserEvent( m_aFinishHdl
);
265 OOdbcManagement::OOdbcManagement(const Link
<>& rAsyncFinishCallback
)
266 : m_aAsyncFinishCallback(rAsyncFinishCallback
)
270 OOdbcManagement::~OOdbcManagement()
272 // wait for our thread to be finished
273 if ( m_pProcessWait
.get() )
274 m_pProcessWait
->join();
277 bool OOdbcManagement::manageDataSources_async()
279 OSL_PRECOND( !isRunning(), "OOdbcManagement::manageDataSources_async: still running from the previous call!" );
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
)
292 m_pProcessWait
.reset( new ProcessTerminationWait( hProcessHandle
, m_aAsyncFinishCallback
) );
293 m_pProcessWait
->create();
297 bool OOdbcManagement::isRunning() const
299 return ( m_pProcessWait
.get() && m_pProcessWait
->isRunning() );
302 #endif // HAVE_ODBC_ADMINISTRATION
306 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */