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 <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>
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
)
45 ,m_aConnectionHandle(nullptr)
46 ,m_pDriverHandleCopy(_pDriverHandle
)
50 ,m_bUseOldDateFormat(false)
51 ,m_bIgnoreDriverPrivileges(false)
52 ,m_bPreventGetVersionColumns(false)
57 OConnection::~OConnection()
62 if ( SQL_NULL_HANDLE
== m_aConnectionHandle
)
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
)
92 SQLRETURN nSQLRETURN
= 0;
95 functions().SetConnectAttr(m_aConnectionHandle
,SQL_ATTR_LOGIN_TIMEOUT
,reinterpret_cast<SQLPOINTER
>(static_cast<sal_IntPtr
>(nTimeOut
)),SQL_IS_UINTEGER
);
97 (void)nTimeOut
; /* WaE */
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
,
115 std::size(szConnStrOut
) - 1,
121 SQLChars
sqlConnectStr(aConnectStr
, getTextEncoding());
122 SQLCHAR szConnStrOut
[4096] = {};
123 SQLSMALLINT cbConnStrOut
;
124 nSQLRETURN
= functions().DriverConnect(m_aConnectionHandle
,
129 std::size(szConnStrOut
) - 1,
134 if (nSQLRETURN
== SQL_ERROR
|| nSQLRETURN
== SQL_NO_DATA
|| SQL_SUCCESS_WITH_INFO
== nSQLRETURN
)
136 if (nSQLRETURN
== SQL_ERROR
|| nSQLRETURN
== SQL_NO_DATA
)
145 OTools::GetInfo(this,m_aConnectionHandle
,SQL_DATA_SOURCE_READ_ONLY
,aVal
,*this,getTextEncoding());
146 m_bReadOnly
= aVal
== "Y";
155 OTools::GetInfo(this,m_aConnectionHandle
,SQL_DRIVER_ODBC_VER
,sVersion
,*this,getTextEncoding());
156 m_bUseOldDateFormat
= sVersion
== "02.50" || sVersion
== "02.00";
163 // autocommit is always default
166 functions().SetConnectAttr(m_aConnectionHandle
,SQL_ATTR_AUTOCOMMIT
, reinterpret_cast<SQLPOINTER
>(SQL_AUTOCOMMIT_ON
),SQL_IS_INTEGER
);
171 SQLRETURN
OConnection::Construct(const OUString
& url
,const Sequence
< PropertyValue
>& info
)
173 m_aConnectionHandle
= SQL_NULL_HANDLE
;
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;
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")
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();
260 m_nTextEncoding
= RTL_TEXTENCODING_DONTKNOW
;
261 if(m_nTextEncoding
== RTL_TEXTENCODING_DONTKNOW
)
262 m_nTextEncoding
= osl_getThreadTextEncoding();
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);
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
));
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
));
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
);
309 if (bUseWChar
&& functions().has(ODBC3SQLFunctionId::NativeSqlW
))
311 SQLWChars
nativeSQL(sql
);
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
);
321 SQLChars
nativeSQL(sql
, getTextEncoding());
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
,
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
;
388 xMetaData
= new ODatabaseMetaData(m_aConnectionHandle
,this);
389 m_xMetaData
= 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
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);
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
))
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
));
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
);
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);
485 Reference
< css::container::XNameAccess
> SAL_CALL
OConnection::getTypeMap( )
487 ::osl::MutexGuard
aGuard( m_aMutex
);
488 checkDisposed(OConnection_BASE::rBHelper
.bDisposed
);
494 void SAL_CALL
OConnection::setTypeMap( const Reference
< css::container::XNameAccess
>& /*typeMap*/ )
496 ::dbtools::throwFeatureNotImplementedSQLException( u
"XConnection::setTypeMap"_ustr
, *this );
500 void SAL_CALL
OConnection::close( )
503 ::osl::MutexGuard
aGuard( m_aMutex
);
504 checkDisposed(OConnection_BASE::rBHelper
.bDisposed
);
511 Any SAL_CALL
OConnection::getWarnings( )
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();
532 functions().Disconnect(m_aConnectionHandle
);
536 SQLHANDLE
OConnection::createStatementHandle()
538 rtl::Reference
<OConnection
> xConnectionTemp
= this;
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
);
555 SQLHANDLE aStatementHandle
= SQL_NULL_HANDLE
;
556 functions().AllocHandle(SQL_HANDLE_STMT
,xConnectionTemp
->getConnection(),&aStatementHandle
);
559 m_aConnections
.emplace(aStatementHandle
,xConnectionTemp
);
561 return aStatementHandle
;
565 void OConnection::freeStatementHandle(SQLHANDLE
& _pHandle
)
567 if( SQL_NULL_HANDLE
== _pHandle
)
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
);
588 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */