cid#1636677 Uninitialized scalar field
[LibreOffice.git] / connectivity / source / drivers / odbc / OConnection.cxx
blob57b3891958fa19828c2aa30f3194065de7a046d5
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::beans;
41 using namespace com::sun::star::sdbc;
43 OConnection::OConnection(const SQLHANDLE _pDriverHandle,ODBCDriver* _pDriver)
44 :m_xDriver(_pDriver)
45 ,m_aConnectionHandle(nullptr)
46 ,m_pDriverHandleCopy(_pDriverHandle)
47 ,m_nStatementCount(0)
48 ,m_bClosed(false)
49 ,m_bUseCatalog(false)
50 ,m_bUseOldDateFormat(false)
51 ,m_bIgnoreDriverPrivileges(false)
52 ,m_bPreventGetVersionColumns(false)
53 ,m_bReadOnly(true)
57 OConnection::~OConnection()
59 if(!isClosed( ))
60 close();
62 if ( SQL_NULL_HANDLE == m_aConnectionHandle )
63 return;
65 SQLRETURN rc;
67 if (!m_bClosed)
69 rc = functions().Disconnect(m_aConnectionHandle);
70 OSL_ENSURE( rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO, "Failure from SQLDisconnect" );
73 rc = functions().FreeHandle(SQL_HANDLE_DBC, m_aConnectionHandle);
74 OSL_ENSURE( rc == SQL_SUCCESS , "Failure from SQLFreeHandle for connection");
76 m_aConnectionHandle = SQL_NULL_HANDLE;
79 const Functions& OConnection::functions() const
81 OSL_ENSURE(m_xDriver, "OConnection::getOdbcFunction: m_xDriver is null!");
82 return m_xDriver->functions();
85 SQLRETURN OConnection::OpenConnection(const OUString& aConnectStr, sal_Int32 nTimeOut, bool bSilent)
87 ::osl::MutexGuard aGuard( m_aMutex );
89 if (m_aConnectionHandle == SQL_NULL_HANDLE)
90 return -1;
92 SQLRETURN nSQLRETURN = 0;
94 #ifndef MACOSX
95 functions().SetConnectAttr(m_aConnectionHandle,SQL_ATTR_LOGIN_TIMEOUT,reinterpret_cast<SQLPOINTER>(static_cast<sal_IntPtr>(nTimeOut)),SQL_IS_UINTEGER);
96 #else
97 (void)nTimeOut; /* WaE */
98 #endif
100 #ifdef LINUX
101 bSilent = true;
102 #endif //LINUX
103 SQLUSMALLINT nSilent = bSilent ? SQL_DRIVER_NOPROMPT : SQL_DRIVER_COMPLETE;
105 if (bUseWChar && functions().has(ODBC3SQLFunctionId::DriverConnectW))
107 SQLWChars sqlConnectStr(aConnectStr);
108 SQLWCHAR szConnStrOut[4096] = {};
109 SQLSMALLINT cchConnStrOut;
110 nSQLRETURN = functions().DriverConnectW(m_aConnectionHandle,
111 nullptr,
112 sqlConnectStr.get(),
113 sqlConnectStr.cch(),
114 szConnStrOut,
115 std::size(szConnStrOut) - 1,
116 &cchConnStrOut,
117 nSilent);
119 else
121 SQLChars sqlConnectStr(aConnectStr, getTextEncoding());
122 SQLCHAR szConnStrOut[4096] = {};
123 SQLSMALLINT cbConnStrOut;
124 nSQLRETURN = functions().DriverConnect(m_aConnectionHandle,
125 nullptr,
126 sqlConnectStr.get(),
127 sqlConnectStr.cch(),
128 szConnStrOut,
129 std::size(szConnStrOut) - 1,
130 &cbConnStrOut,
131 nSilent);
133 #ifdef LINUX
134 if (nSQLRETURN == SQL_ERROR || nSQLRETURN == SQL_NO_DATA || SQL_SUCCESS_WITH_INFO == nSQLRETURN)
135 #else
136 if (nSQLRETURN == SQL_ERROR || nSQLRETURN == SQL_NO_DATA)
137 #endif
138 return nSQLRETURN;
140 m_bClosed = false;
144 OUString aVal;
145 OTools::GetInfo(this,m_aConnectionHandle,SQL_DATA_SOURCE_READ_ONLY,aVal,*this,getTextEncoding());
146 m_bReadOnly = aVal == "Y";
148 catch(Exception&)
150 m_bReadOnly = true;
154 OUString sVersion;
155 OTools::GetInfo(this,m_aConnectionHandle,SQL_DRIVER_ODBC_VER,sVersion,*this,getTextEncoding());
156 m_bUseOldDateFormat = sVersion == "02.50" || sVersion == "02.00";
158 catch(Exception&)
163 // autocommit is always default
165 if (!m_bReadOnly)
166 functions().SetConnectAttr(m_aConnectionHandle,SQL_ATTR_AUTOCOMMIT, reinterpret_cast<SQLPOINTER>(SQL_AUTOCOMMIT_ON),SQL_IS_INTEGER);
168 return nSQLRETURN;
171 SQLRETURN OConnection::Construct(const OUString& url,const Sequence< PropertyValue >& info)
173 m_aConnectionHandle = SQL_NULL_HANDLE;
174 m_sURL = url;
175 setConnectionInfo(info);
177 functions().AllocHandle(SQL_HANDLE_DBC,m_pDriverHandleCopy,&m_aConnectionHandle);
178 if(m_aConnectionHandle == SQL_NULL_HANDLE)
179 throw SQLException();
181 sal_Int32 nLen = url.indexOf(':');
182 nLen = url.indexOf(':',nLen+2);
183 OUString aDSN(u"DSN="_ustr), aUID, aPWD, aSysDrvSettings;
184 aDSN += url.subView(nLen+1);
186 sal_Int32 nTimeout = 20;
187 bool bSilent = true;
188 const PropertyValue *pBegin = info.getConstArray();
189 const PropertyValue *pEnd = pBegin + info.getLength();
190 for(;pBegin != pEnd;++pBegin)
192 if( pBegin->Name == "Timeout")
194 if( ! (pBegin->Value >>= nTimeout) )
195 SAL_WARN("connectivity.odbc", "Construct: unable to get property Timeout");
197 else if( pBegin->Name == "Silent")
199 if( ! (pBegin->Value >>= bSilent) )
200 SAL_WARN("connectivity.odbc", "Construct: unable to get property Silent");
202 else if( pBegin->Name == "IgnoreDriverPrivileges")
204 if( ! (pBegin->Value >>= m_bIgnoreDriverPrivileges) )
205 SAL_WARN("connectivity.odbc", "Construct: unable to get property IgnoreDriverPrivileges");
207 else if( pBegin->Name == "PreventGetVersionColumns")
209 if( ! (pBegin->Value >>= m_bPreventGetVersionColumns) )
210 SAL_WARN("connectivity.odbc", "Construct: unable to get property PreventGetVersionColumns");
212 else if( pBegin->Name == "IsAutoRetrievingEnabled")
214 bool bAutoRetrievingEnabled = false;
215 if( ! (pBegin->Value >>= bAutoRetrievingEnabled) )
216 SAL_WARN("connectivity.odbc", "Construct: unable to get property IsAutoRetrievingEnabled");
217 enableAutoRetrievingEnabled(bAutoRetrievingEnabled);
219 else if( pBegin->Name == "AutoRetrievingStatement")
221 OUString sGeneratedValueStatement;
222 if( ! (pBegin->Value >>= sGeneratedValueStatement) )
223 SAL_WARN("connectivity.odbc", "Construct: unable to get property AutoRetrievingStatement");
224 setAutoRetrievingStatement(sGeneratedValueStatement);
226 else if( pBegin->Name == "user")
228 if( ! (pBegin->Value >>= aUID) )
229 SAL_WARN("connectivity.odbc", "Construct: unable to get property user");
230 aDSN += ";UID=" + aUID;
232 else if( pBegin->Name == "password")
234 if( ! (pBegin->Value >>= aPWD) )
235 SAL_WARN("connectivity.odbc", "Construct: unable to get property password");
236 aDSN += ";PWD=" + aPWD;
238 else if( pBegin->Name == "UseCatalog")
240 if( !( pBegin->Value >>= m_bUseCatalog) )
241 SAL_WARN("connectivity.odbc", "Construct: unable to get property UseCatalog");
243 else if( pBegin->Name == "SystemDriverSettings")
245 if( ! (pBegin->Value >>= aSysDrvSettings) )
246 SAL_WARN("connectivity.odbc", "Construct: unable to get property SystemDriverSettings");
247 aDSN += ";" + aSysDrvSettings;
249 else if( pBegin->Name == "CharSet")
251 OUString sIanaName;
252 if( ! (pBegin->Value >>= sIanaName) )
253 SAL_WARN("connectivity.odbc", "Construct: unable to get property CharSet");
255 ::dbtools::OCharsetMap aLookupIanaName;
256 ::dbtools::OCharsetMap::const_iterator aLookup = aLookupIanaName.findIanaName(sIanaName);
257 if (aLookup != aLookupIanaName.end())
258 m_nTextEncoding = (*aLookup).getEncoding();
259 else
260 m_nTextEncoding = RTL_TEXTENCODING_DONTKNOW;
261 if(m_nTextEncoding == RTL_TEXTENCODING_DONTKNOW)
262 m_nTextEncoding = osl_getThreadTextEncoding();
265 m_sUser = aUID;
267 SQLRETURN nSQLRETURN = OpenConnection(aDSN,nTimeout, bSilent);
268 if (nSQLRETURN == SQL_ERROR || nSQLRETURN == SQL_NO_DATA)
270 OTools::ThrowException(this,nSQLRETURN,m_aConnectionHandle,SQL_HANDLE_DBC,*this,false);
272 return nSQLRETURN;
274 // XServiceInfo
276 IMPLEMENT_SERVICE_INFO(OConnection, u"com.sun.star.sdbc.drivers.odbc.OConnection"_ustr, u"com.sun.star.sdbc.Connection"_ustr)
279 Reference< XStatement > SAL_CALL OConnection::createStatement( )
281 ::osl::MutexGuard aGuard( m_aMutex );
282 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
284 Reference< XStatement > xReturn = new OStatement(this);
285 m_aStatements.push_back(WeakReferenceHelper(xReturn));
286 return xReturn;
289 Reference< XPreparedStatement > SAL_CALL OConnection::prepareStatement( const OUString& sql )
291 ::osl::MutexGuard aGuard( m_aMutex );
292 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
294 Reference< XPreparedStatement > xReturn = new OPreparedStatement(this,sql);
295 m_aStatements.push_back(WeakReferenceHelper(xReturn));
296 return xReturn;
299 Reference< XPreparedStatement > SAL_CALL OConnection::prepareCall( const OUString& /*sql*/ )
301 ::dbtools::throwFeatureNotImplementedSQLException( u"XConnection::prepareCall"_ustr, *this );
304 OUString SAL_CALL OConnection::nativeSQL( const OUString& sql )
306 ::osl::MutexGuard aGuard( m_aMutex );
308 SQLINTEGER nOutLen;
309 if (bUseWChar && functions().has(ODBC3SQLFunctionId::NativeSqlW))
311 SQLWChars nativeSQL(sql);
312 SQLWCHAR pOut[2048];
313 SQLRETURN ret = functions().NativeSqlW(m_aConnectionHandle,
314 nativeSQL.get(), nativeSQL.cch(),
315 pOut, std::size(pOut) - 1, &nOutLen);
316 OTools::ThrowException(this, ret, m_aConnectionHandle, SQL_HANDLE_DBC, *this);
317 return toUString(pOut, nOutLen);
319 else
321 SQLChars nativeSQL(sql, getTextEncoding());
322 SQLCHAR pOut[2048];
323 SQLRETURN ret = functions().NativeSql(m_aConnectionHandle,
324 nativeSQL.get(), nativeSQL.cch(),
325 pOut, std::size(pOut) - 1, &nOutLen);
326 OTools::ThrowException(this, ret, m_aConnectionHandle, SQL_HANDLE_DBC, *this);
327 return toUString(pOut, nOutLen, getTextEncoding());
331 void SAL_CALL OConnection::setAutoCommit( sal_Bool autoCommit )
333 ::osl::MutexGuard aGuard( m_aMutex );
334 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
336 const sal_IntPtr nAutocommit = autoCommit ? SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF;
337 OTools::ThrowException(this,functions().SetConnectAttr(m_aConnectionHandle,
338 SQL_ATTR_AUTOCOMMIT,
339 reinterpret_cast<SQLPOINTER>(nAutocommit) ,SQL_IS_INTEGER),
340 m_aConnectionHandle,SQL_HANDLE_DBC,*this);
343 sal_Bool SAL_CALL OConnection::getAutoCommit( )
345 ::osl::MutexGuard aGuard( m_aMutex );
346 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
349 sal_uInt32 nOption = 0;
350 OTools::ThrowException(this,functions().GetConnectAttr(m_aConnectionHandle,
351 SQL_ATTR_AUTOCOMMIT, &nOption,0,nullptr),m_aConnectionHandle,SQL_HANDLE_DBC,*this);
352 return nOption == SQL_AUTOCOMMIT_ON ;
355 void SAL_CALL OConnection::commit( )
357 ::osl::MutexGuard aGuard( m_aMutex );
358 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
361 OTools::ThrowException(this,functions().EndTran(SQL_HANDLE_DBC,m_aConnectionHandle,SQL_COMMIT),m_aConnectionHandle,SQL_HANDLE_DBC,*this);
364 void SAL_CALL OConnection::rollback( )
366 ::osl::MutexGuard aGuard( m_aMutex );
367 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
370 OTools::ThrowException(this,functions().EndTran(SQL_HANDLE_DBC,m_aConnectionHandle,SQL_ROLLBACK),m_aConnectionHandle,SQL_HANDLE_DBC,*this);
373 sal_Bool SAL_CALL OConnection::isClosed( )
375 ::osl::MutexGuard aGuard( m_aMutex );
377 return OConnection_BASE::rBHelper.bDisposed;
380 Reference< XDatabaseMetaData > SAL_CALL OConnection::getMetaData( )
382 ::osl::MutexGuard aGuard( m_aMutex );
383 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
385 Reference< XDatabaseMetaData > xMetaData = m_xMetaData;
386 if(!xMetaData.is())
388 xMetaData = new ODatabaseMetaData(m_aConnectionHandle,this);
389 m_xMetaData = xMetaData;
392 return xMetaData;
395 void SAL_CALL OConnection::setReadOnly( sal_Bool readOnly )
397 ::osl::MutexGuard aGuard( m_aMutex );
398 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
401 OTools::ThrowException(this,
402 functions().SetConnectAttr(m_aConnectionHandle,SQL_ATTR_ACCESS_MODE,reinterpret_cast< SQLPOINTER >( readOnly ),SQL_IS_INTEGER),
403 m_aConnectionHandle,SQL_HANDLE_DBC,*this);
406 sal_Bool SAL_CALL OConnection::isReadOnly()
408 // const member which will initialized only once
409 return m_bReadOnly;
412 void SAL_CALL OConnection::setCatalog( const OUString& catalog )
414 ::osl::MutexGuard aGuard( m_aMutex );
415 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
417 if (bUseWChar && functions().has(ODBC3SQLFunctionId::SetConnectAttrW))
419 SQLWChars sqlCatalog(catalog);
420 OTools::ThrowException(this,
421 functions().SetConnectAttrW(m_aConnectionHandle, SQL_ATTR_CURRENT_CATALOG, sqlCatalog.get(), SQL_NTSL),
422 m_aConnectionHandle,SQL_HANDLE_DBC,*this);
424 else
426 SQLChars sqlCatalog(catalog, getTextEncoding());
427 OTools::ThrowException(this,
428 functions().SetConnectAttr(m_aConnectionHandle,SQL_ATTR_CURRENT_CATALOG,sqlCatalog.get(),SQL_NTS),
429 m_aConnectionHandle,SQL_HANDLE_DBC,*this);
433 OUString SAL_CALL OConnection::getCatalog( )
435 ::osl::MutexGuard aGuard( m_aMutex );
436 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
438 SQLINTEGER nValueLen;
439 if (bUseWChar && functions().has(ODBC3SQLFunctionId::GetConnectAttrW))
441 SQLWCHAR pCat[1024];
442 // SQLGetConnectAttrW gets/returns count of bytes, not characters
443 OTools::ThrowException(this,
444 functions().GetConnectAttrW(m_aConnectionHandle,SQL_ATTR_CURRENT_CATALOG,pCat,sizeof(pCat)-sizeof(SQLWCHAR),&nValueLen),
445 m_aConnectionHandle,SQL_HANDLE_DBC,*this);
446 return toUString(pCat, nValueLen / sizeof(SQLWCHAR));
448 else
450 SQLCHAR pCat[1024];
451 OTools::ThrowException(this,
452 functions().GetConnectAttr(m_aConnectionHandle,SQL_ATTR_CURRENT_CATALOG,pCat,sizeof(pCat)-1,&nValueLen),
453 m_aConnectionHandle,SQL_HANDLE_DBC,*this);
455 return toUString(pCat, nValueLen, getTextEncoding());
459 void SAL_CALL OConnection::setTransactionIsolation( sal_Int32 level )
461 ::osl::MutexGuard aGuard( m_aMutex );
462 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
465 OTools::ThrowException(this,functions().SetConnectAttr(m_aConnectionHandle,
466 SQL_ATTR_TXN_ISOLATION,
467 reinterpret_cast<SQLPOINTER>(static_cast<sal_IntPtr>(level)),SQL_IS_INTEGER),
468 m_aConnectionHandle,SQL_HANDLE_DBC,*this);
471 sal_Int32 SAL_CALL OConnection::getTransactionIsolation( )
473 ::osl::MutexGuard aGuard( m_aMutex );
474 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
477 sal_Int32 nTxn = 0;
478 SQLINTEGER nValueLen;
479 OTools::ThrowException(this,
480 functions().GetConnectAttr(m_aConnectionHandle,SQL_ATTR_TXN_ISOLATION,&nTxn,sizeof nTxn,&nValueLen),
481 m_aConnectionHandle,SQL_HANDLE_DBC,*this);
482 return nTxn;
485 Reference< css::container::XNameAccess > SAL_CALL OConnection::getTypeMap( )
487 ::osl::MutexGuard aGuard( m_aMutex );
488 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
491 return nullptr;
494 void SAL_CALL OConnection::setTypeMap( const Reference< css::container::XNameAccess >& /*typeMap*/ )
496 ::dbtools::throwFeatureNotImplementedSQLException( u"XConnection::setTypeMap"_ustr, *this );
499 // XCloseable
500 void SAL_CALL OConnection::close( )
503 ::osl::MutexGuard aGuard( m_aMutex );
504 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
507 dispose();
510 // XWarningsSupplier
511 Any SAL_CALL OConnection::getWarnings( )
513 return Any();
516 void SAL_CALL OConnection::clearWarnings( )
520 void OConnection::disposing()
522 ::osl::MutexGuard aGuard(m_aMutex);
524 OConnection_BASE::disposing();
526 for (auto const& connection : m_aConnections)
527 connection.second->dispose();
529 m_aConnections.clear();
531 if(!m_bClosed)
532 functions().Disconnect(m_aConnectionHandle);
533 m_bClosed = true;
536 SQLHANDLE OConnection::createStatementHandle()
538 rtl::Reference<OConnection> xConnectionTemp = this;
539 bool bNew = false;
542 sal_Int32 nMaxStatements = getMetaData()->getMaxStatements();
543 if(nMaxStatements && nMaxStatements <= m_nStatementCount)
545 rtl::Reference xConnection(new OConnection(m_pDriverHandleCopy,m_xDriver.get()));
546 xConnection->Construct(m_sURL,getConnectionInfo());
547 xConnectionTemp = std::move(xConnection);
548 bNew = true;
551 catch(SQLException&)
555 SQLHANDLE aStatementHandle = SQL_NULL_HANDLE;
556 functions().AllocHandle(SQL_HANDLE_STMT,xConnectionTemp->getConnection(),&aStatementHandle);
557 ++m_nStatementCount;
558 if(bNew)
559 m_aConnections.emplace(aStatementHandle,xConnectionTemp);
561 return aStatementHandle;
565 void OConnection::freeStatementHandle(SQLHANDLE& _pHandle)
567 if( SQL_NULL_HANDLE == _pHandle )
568 return;
570 auto aFind = m_aConnections.find(_pHandle);
572 functions().FreeStmt(_pHandle,SQL_RESET_PARAMS);
573 functions().FreeStmt(_pHandle,SQL_UNBIND);
574 functions().FreeStmt(_pHandle,SQL_CLOSE);
575 functions().FreeHandle(SQL_HANDLE_STMT,_pHandle);
577 _pHandle = SQL_NULL_HANDLE;
579 if(aFind != m_aConnections.end())
581 aFind->second->dispose();
582 m_aConnections.erase(aFind);
584 --m_nStatementCount;
588 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */