bump product version to 7.2.5.1
[LibreOffice.git] / connectivity / source / drivers / odbc / OConnection.cxx
blob7ae8c46802e225306a0cf380f8bfd4b75937aa4b
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 <odbc/OTools.hxx>
21 #include <odbc/OConnection.hxx>
22 #include <odbc/ODatabaseMetaData.hxx>
23 #include <odbc/OFunctions.hxx>
24 #include <odbc/ODriver.hxx>
25 #include <odbc/OStatement.hxx>
26 #include <odbc/OPreparedStatement.hxx>
27 #include <connectivity/dbcharset.hxx>
28 #include <connectivity/dbexception.hxx>
30 #include <sal/log.hxx>
32 #include <string.h>
34 using namespace connectivity::odbc;
35 using namespace connectivity;
36 using namespace dbtools;
39 using namespace com::sun::star::uno;
40 using namespace com::sun::star::lang;
41 using namespace com::sun::star::beans;
42 using namespace com::sun::star::sdbc;
44 OConnection::OConnection(const SQLHANDLE _pDriverHandle,ODBCDriver* _pDriver)
45 :m_xDriver(_pDriver)
46 ,m_aConnectionHandle(nullptr)
47 ,m_pDriverHandleCopy(_pDriverHandle)
48 ,m_nStatementCount(0)
49 ,m_bClosed(false)
50 ,m_bUseCatalog(false)
51 ,m_bUseOldDateFormat(false)
52 ,m_bIgnoreDriverPrivileges(false)
53 ,m_bPreventGetVersionColumns(false)
54 ,m_bReadOnly(true)
58 OConnection::~OConnection()
60 if(!isClosed( ))
61 close();
63 if ( SQL_NULL_HANDLE == m_aConnectionHandle )
64 return;
66 SQLRETURN rc;
68 if (!m_bClosed)
70 rc = N3SQLDisconnect( m_aConnectionHandle );
71 OSL_ENSURE( rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO, "Failure from SQLDisconnect" );
74 rc = N3SQLFreeHandle( SQL_HANDLE_DBC, m_aConnectionHandle );
75 OSL_ENSURE( rc == SQL_SUCCESS , "Failure from SQLFreeHandle for connection");
77 m_aConnectionHandle = SQL_NULL_HANDLE;
80 oslGenericFunction OConnection::getOdbcFunction(ODBC3SQLFunctionId _nIndex) const
82 OSL_ENSURE(m_xDriver, "OConnection::getOdbcFunction: m_xDriver is null!");
83 return m_xDriver->getOdbcFunction(_nIndex);
86 SQLRETURN OConnection::OpenConnection(const OUString& aConnectStr, sal_Int32 nTimeOut, bool bSilent)
88 ::osl::MutexGuard aGuard( m_aMutex );
90 if (m_aConnectionHandle == SQL_NULL_HANDLE)
91 return -1;
93 SQLRETURN nSQLRETURN = 0;
94 SDB_ODBC_CHAR szConnStrOut[4096] = {};
95 SDB_ODBC_CHAR szConnStrIn[2048] = {};
96 SQLSMALLINT cbConnStrOut;
97 OString aConStr(OUStringToOString(aConnectStr,getTextEncoding()));
98 memcpy(szConnStrIn, aConStr.getStr(), std::min<sal_Int32>(sal_Int32(2048),aConStr.getLength()));
100 #ifndef MACOSX
101 N3SQLSetConnectAttr(m_aConnectionHandle,SQL_ATTR_LOGIN_TIMEOUT,reinterpret_cast<SQLPOINTER>(nTimeOut),SQL_IS_UINTEGER);
102 #else
103 (void)nTimeOut; /* WaE */
104 #endif
106 #ifdef LINUX
107 (void) bSilent;
108 nSQLRETURN = N3SQLDriverConnect(m_aConnectionHandle,
109 nullptr,
110 szConnStrIn,
111 static_cast<SQLSMALLINT>(std::min(sal_Int32(2048),aConStr.getLength())),
112 szConnStrOut,
113 SQLSMALLINT(sizeof(szConnStrOut)/sizeof(SDB_ODBC_CHAR)) -1,
114 &cbConnStrOut,
115 SQL_DRIVER_NOPROMPT);
116 if (nSQLRETURN == SQL_ERROR || nSQLRETURN == SQL_NO_DATA || SQL_SUCCESS_WITH_INFO == nSQLRETURN)
117 return nSQLRETURN;
118 #else
120 SQLUSMALLINT nSilent = bSilent ? SQL_DRIVER_NOPROMPT : SQL_DRIVER_COMPLETE;
121 nSQLRETURN = N3SQLDriverConnect(m_aConnectionHandle,
122 nullptr,
123 szConnStrIn,
124 static_cast<SQLSMALLINT>(std::min<sal_Int32>(sal_Int32(2048),aConStr.getLength())),
125 szConnStrOut,
126 SQLSMALLINT(sizeof szConnStrOut),
127 &cbConnStrOut,
128 nSilent);
129 if (nSQLRETURN == SQL_ERROR || nSQLRETURN == SQL_NO_DATA)
130 return nSQLRETURN;
132 m_bClosed = false;
134 #endif //LINUX
138 OUString aVal;
139 OTools::GetInfo(this,m_aConnectionHandle,SQL_DATA_SOURCE_READ_ONLY,aVal,*this,getTextEncoding());
140 m_bReadOnly = aVal == "Y";
142 catch(Exception&)
144 m_bReadOnly = true;
148 OUString sVersion;
149 OTools::GetInfo(this,m_aConnectionHandle,SQL_DRIVER_ODBC_VER,sVersion,*this,getTextEncoding());
150 m_bUseOldDateFormat = sVersion == "02.50" || sVersion == "02.00";
152 catch(Exception&)
157 // autocommit is always default
159 if (!m_bReadOnly)
160 N3SQLSetConnectAttr(m_aConnectionHandle,SQL_ATTR_AUTOCOMMIT, reinterpret_cast<SQLPOINTER>(SQL_AUTOCOMMIT_ON),SQL_IS_INTEGER);
162 return nSQLRETURN;
165 SQLRETURN OConnection::Construct(const OUString& url,const Sequence< PropertyValue >& info)
167 m_aConnectionHandle = SQL_NULL_HANDLE;
168 m_sURL = url;
169 setConnectionInfo(info);
171 N3SQLAllocHandle(SQL_HANDLE_DBC,m_pDriverHandleCopy,&m_aConnectionHandle);
172 if(m_aConnectionHandle == SQL_NULL_HANDLE)
173 throw SQLException();
175 sal_Int32 nLen = url.indexOf(':');
176 nLen = url.indexOf(':',nLen+2);
177 OUString aDSN("DSN="), aUID, aPWD, aSysDrvSettings;
178 aDSN += url.subView(nLen+1);
180 sal_Int32 nTimeout = 20;
181 bool bSilent = true;
182 const PropertyValue *pBegin = info.getConstArray();
183 const PropertyValue *pEnd = pBegin + info.getLength();
184 for(;pBegin != pEnd;++pBegin)
186 if( pBegin->Name == "Timeout")
188 if( ! (pBegin->Value >>= nTimeout) )
189 SAL_WARN("connectivity.odbc", "Construct: unable to get property Timeout");
191 else if( pBegin->Name == "Silent")
193 if( ! (pBegin->Value >>= bSilent) )
194 SAL_WARN("connectivity.odbc", "Construct: unable to get property Silent");
196 else if( pBegin->Name == "IgnoreDriverPrivileges")
198 if( ! (pBegin->Value >>= m_bIgnoreDriverPrivileges) )
199 SAL_WARN("connectivity.odbc", "Construct: unable to get property IgnoreDriverPrivileges");
201 else if( pBegin->Name == "PreventGetVersionColumns")
203 if( ! (pBegin->Value >>= m_bPreventGetVersionColumns) )
204 SAL_WARN("connectivity.odbc", "Construct: unable to get property PreventGetVersionColumns");
206 else if( pBegin->Name == "IsAutoRetrievingEnabled")
208 bool bAutoRetrievingEnabled = false;
209 if( ! (pBegin->Value >>= bAutoRetrievingEnabled) )
210 SAL_WARN("connectivity.odbc", "Construct: unable to get property IsAutoRetrievingEnabled");
211 enableAutoRetrievingEnabled(bAutoRetrievingEnabled);
213 else if( pBegin->Name == "AutoRetrievingStatement")
215 OUString sGeneratedValueStatement;
216 if( ! (pBegin->Value >>= sGeneratedValueStatement) )
217 SAL_WARN("connectivity.odbc", "Construct: unable to get property AutoRetrievingStatement");
218 setAutoRetrievingStatement(sGeneratedValueStatement);
220 else if( pBegin->Name == "user")
222 if( ! (pBegin->Value >>= aUID) )
223 SAL_WARN("connectivity.odbc", "Construct: unable to get property user");
224 aDSN += ";UID=" + aUID;
226 else if( pBegin->Name == "password")
228 if( ! (pBegin->Value >>= aPWD) )
229 SAL_WARN("connectivity.odbc", "Construct: unable to get property password");
230 aDSN += ";PWD=" + aPWD;
232 else if( pBegin->Name == "UseCatalog")
234 if( !( pBegin->Value >>= m_bUseCatalog) )
235 SAL_WARN("connectivity.odbc", "Construct: unable to get property UseCatalog");
237 else if( pBegin->Name == "SystemDriverSettings")
239 if( ! (pBegin->Value >>= aSysDrvSettings) )
240 SAL_WARN("connectivity.odbc", "Construct: unable to get property SystemDriverSettings");
241 aDSN += ";" + aSysDrvSettings;
243 else if( pBegin->Name == "CharSet")
245 OUString sIanaName;
246 if( ! (pBegin->Value >>= sIanaName) )
247 SAL_WARN("connectivity.odbc", "Construct: unable to get property CharSet");
249 ::dbtools::OCharsetMap aLookupIanaName;
250 ::dbtools::OCharsetMap::const_iterator aLookup = aLookupIanaName.findIanaName(sIanaName);
251 if (aLookup != aLookupIanaName.end())
252 m_nTextEncoding = (*aLookup).getEncoding();
253 else
254 m_nTextEncoding = RTL_TEXTENCODING_DONTKNOW;
255 if(m_nTextEncoding == RTL_TEXTENCODING_DONTKNOW)
256 m_nTextEncoding = osl_getThreadTextEncoding();
259 m_sUser = aUID;
261 SQLRETURN nSQLRETURN = OpenConnection(aDSN,nTimeout, bSilent);
262 if (nSQLRETURN == SQL_ERROR || nSQLRETURN == SQL_NO_DATA)
264 OTools::ThrowException(this,nSQLRETURN,m_aConnectionHandle,SQL_HANDLE_DBC,*this,false);
266 return nSQLRETURN;
268 // XServiceInfo
270 IMPLEMENT_SERVICE_INFO(OConnection, "com.sun.star.sdbc.drivers.odbc.OConnection", "com.sun.star.sdbc.Connection")
273 Reference< XStatement > SAL_CALL OConnection::createStatement( )
275 ::osl::MutexGuard aGuard( m_aMutex );
276 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
278 Reference< XStatement > xReturn = new OStatement(this);
279 m_aStatements.push_back(WeakReferenceHelper(xReturn));
280 return xReturn;
283 Reference< XPreparedStatement > SAL_CALL OConnection::prepareStatement( const OUString& sql )
285 ::osl::MutexGuard aGuard( m_aMutex );
286 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
288 Reference< XPreparedStatement > xReturn = new OPreparedStatement(this,sql);
289 m_aStatements.push_back(WeakReferenceHelper(xReturn));
290 return xReturn;
293 Reference< XPreparedStatement > SAL_CALL OConnection::prepareCall( const OUString& /*sql*/ )
295 ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::prepareCall", *this );
296 return nullptr;
299 OUString SAL_CALL OConnection::nativeSQL( const OUString& sql )
301 ::osl::MutexGuard aGuard( m_aMutex );
303 OString aSql(OUStringToOString(sql,getTextEncoding()));
304 char pOut[2048];
305 SQLINTEGER nOutLen;
306 OTools::ThrowException(this,N3SQLNativeSql(m_aConnectionHandle,reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(aSql.getStr())),aSql.getLength(),reinterpret_cast<SDB_ODBC_CHAR*>(pOut),sizeof pOut - 1,&nOutLen),m_aConnectionHandle,SQL_HANDLE_DBC,*this);
307 return OUString(pOut,nOutLen,getTextEncoding());
310 void SAL_CALL OConnection::setAutoCommit( sal_Bool autoCommit )
312 ::osl::MutexGuard aGuard( m_aMutex );
313 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
316 OTools::ThrowException(this,N3SQLSetConnectAttr(m_aConnectionHandle,
317 SQL_ATTR_AUTOCOMMIT,
318 reinterpret_cast<SQLPOINTER>((autoCommit) ? SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF) ,SQL_IS_INTEGER),
319 m_aConnectionHandle,SQL_HANDLE_DBC,*this);
322 sal_Bool SAL_CALL OConnection::getAutoCommit( )
324 ::osl::MutexGuard aGuard( m_aMutex );
325 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
328 sal_uInt32 nOption = 0;
329 OTools::ThrowException(this,N3SQLGetConnectAttr(m_aConnectionHandle,
330 SQL_ATTR_AUTOCOMMIT, &nOption,0,nullptr),m_aConnectionHandle,SQL_HANDLE_DBC,*this);
331 return nOption == SQL_AUTOCOMMIT_ON ;
334 void SAL_CALL OConnection::commit( )
336 ::osl::MutexGuard aGuard( m_aMutex );
337 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
340 OTools::ThrowException(this,N3SQLEndTran(SQL_HANDLE_DBC,m_aConnectionHandle,SQL_COMMIT),m_aConnectionHandle,SQL_HANDLE_DBC,*this);
343 void SAL_CALL OConnection::rollback( )
345 ::osl::MutexGuard aGuard( m_aMutex );
346 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
349 OTools::ThrowException(this,N3SQLEndTran(SQL_HANDLE_DBC,m_aConnectionHandle,SQL_ROLLBACK),m_aConnectionHandle,SQL_HANDLE_DBC,*this);
352 sal_Bool SAL_CALL OConnection::isClosed( )
354 ::osl::MutexGuard aGuard( m_aMutex );
356 return OConnection_BASE::rBHelper.bDisposed;
359 Reference< XDatabaseMetaData > SAL_CALL OConnection::getMetaData( )
361 ::osl::MutexGuard aGuard( m_aMutex );
362 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
364 Reference< XDatabaseMetaData > xMetaData = m_xMetaData;
365 if(!xMetaData.is())
367 xMetaData = new ODatabaseMetaData(m_aConnectionHandle,this);
368 m_xMetaData = xMetaData;
371 return xMetaData;
374 void SAL_CALL OConnection::setReadOnly( sal_Bool readOnly )
376 ::osl::MutexGuard aGuard( m_aMutex );
377 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
380 OTools::ThrowException(this,
381 N3SQLSetConnectAttr(m_aConnectionHandle,SQL_ATTR_ACCESS_MODE,reinterpret_cast< SQLPOINTER >( readOnly ),SQL_IS_INTEGER),
382 m_aConnectionHandle,SQL_HANDLE_DBC,*this);
385 sal_Bool SAL_CALL OConnection::isReadOnly()
387 // const member which will initialized only once
388 return m_bReadOnly;
391 void SAL_CALL OConnection::setCatalog( const OUString& catalog )
393 ::osl::MutexGuard aGuard( m_aMutex );
394 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
397 OString aCat(OUStringToOString(catalog,getTextEncoding()));
398 OTools::ThrowException(this,
399 N3SQLSetConnectAttr(m_aConnectionHandle,SQL_ATTR_CURRENT_CATALOG,const_cast<char *>(aCat.getStr()),SQL_NTS),
400 m_aConnectionHandle,SQL_HANDLE_DBC,*this);
403 OUString SAL_CALL OConnection::getCatalog( )
405 ::osl::MutexGuard aGuard( m_aMutex );
406 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
409 SQLINTEGER nValueLen;
410 char pCat[1024];
411 OTools::ThrowException(this,
412 N3SQLGetConnectAttr(m_aConnectionHandle,SQL_ATTR_CURRENT_CATALOG,pCat,(sizeof pCat)-1,&nValueLen),
413 m_aConnectionHandle,SQL_HANDLE_DBC,*this);
415 return OUString(pCat,nValueLen,getTextEncoding());
418 void SAL_CALL OConnection::setTransactionIsolation( sal_Int32 level )
420 ::osl::MutexGuard aGuard( m_aMutex );
421 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
424 OTools::ThrowException(this,N3SQLSetConnectAttr(m_aConnectionHandle,
425 SQL_ATTR_TXN_ISOLATION,
426 reinterpret_cast<SQLPOINTER>(level),SQL_IS_INTEGER),
427 m_aConnectionHandle,SQL_HANDLE_DBC,*this);
430 sal_Int32 SAL_CALL OConnection::getTransactionIsolation( )
432 ::osl::MutexGuard aGuard( m_aMutex );
433 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
436 sal_Int32 nTxn = 0;
437 SQLINTEGER nValueLen;
438 OTools::ThrowException(this,
439 N3SQLGetConnectAttr(m_aConnectionHandle,SQL_ATTR_TXN_ISOLATION,&nTxn,sizeof nTxn,&nValueLen),
440 m_aConnectionHandle,SQL_HANDLE_DBC,*this);
441 return nTxn;
444 Reference< css::container::XNameAccess > SAL_CALL OConnection::getTypeMap( )
446 ::osl::MutexGuard aGuard( m_aMutex );
447 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
450 return nullptr;
453 void SAL_CALL OConnection::setTypeMap( const Reference< css::container::XNameAccess >& /*typeMap*/ )
455 ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::setTypeMap", *this );
458 // XCloseable
459 void SAL_CALL OConnection::close( )
462 ::osl::MutexGuard aGuard( m_aMutex );
463 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
466 dispose();
469 // XWarningsSupplier
470 Any SAL_CALL OConnection::getWarnings( )
472 return Any();
475 void SAL_CALL OConnection::clearWarnings( )
479 void OConnection::disposing()
481 ::osl::MutexGuard aGuard(m_aMutex);
483 OConnection_BASE::disposing();
485 for (auto const& connection : m_aConnections)
486 connection.second->dispose();
488 m_aConnections.clear();
490 if(!m_bClosed)
491 N3SQLDisconnect(m_aConnectionHandle);
492 m_bClosed = true;
495 SQLHANDLE OConnection::createStatementHandle()
497 rtl::Reference<OConnection> xConnectionTemp = this;
498 bool bNew = false;
501 sal_Int32 nMaxStatements = getMetaData()->getMaxStatements();
502 if(nMaxStatements && nMaxStatements <= m_nStatementCount)
504 rtl::Reference xConnection(new OConnection(m_pDriverHandleCopy,m_xDriver.get()));
505 xConnection->Construct(m_sURL,getConnectionInfo());
506 xConnectionTemp = xConnection;
507 bNew = true;
510 catch(SQLException&)
514 SQLHANDLE aStatementHandle = SQL_NULL_HANDLE;
515 N3SQLAllocHandle(SQL_HANDLE_STMT,xConnectionTemp->getConnection(),&aStatementHandle);
516 ++m_nStatementCount;
517 if(bNew)
518 m_aConnections.emplace(aStatementHandle,xConnectionTemp);
520 return aStatementHandle;
524 void OConnection::freeStatementHandle(SQLHANDLE& _pHandle)
526 if( SQL_NULL_HANDLE == _pHandle )
527 return;
529 auto aFind = m_aConnections.find(_pHandle);
531 N3SQLFreeStmt(_pHandle,SQL_RESET_PARAMS);
532 N3SQLFreeStmt(_pHandle,SQL_UNBIND);
533 N3SQLFreeStmt(_pHandle,SQL_CLOSE);
534 N3SQLFreeHandle(SQL_HANDLE_STMT,_pHandle);
536 _pHandle = SQL_NULL_HANDLE;
538 if(aFind != m_aConnections.end())
540 aFind->second->dispose();
541 m_aConnections.erase(aFind);
543 --m_nStatementCount;
547 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */