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::lang
;
41 using namespace com::sun::star::beans
;
42 using namespace com::sun::star::sdbc
;
44 OConnection::OConnection(const SQLHANDLE _pDriverHandle
,ODBCDriver
* _pDriver
)
46 ,m_aConnectionHandle(nullptr)
47 ,m_pDriverHandleCopy(_pDriverHandle
)
51 ,m_bUseOldDateFormat(false)
52 ,m_bIgnoreDriverPrivileges(false)
53 ,m_bPreventGetVersionColumns(false)
58 OConnection::~OConnection()
63 if ( SQL_NULL_HANDLE
== m_aConnectionHandle
)
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
)
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()));
101 N3SQLSetConnectAttr(m_aConnectionHandle
,SQL_ATTR_LOGIN_TIMEOUT
,reinterpret_cast<SQLPOINTER
>(nTimeOut
),SQL_IS_UINTEGER
);
103 (void)nTimeOut
; /* WaE */
108 nSQLRETURN
= N3SQLDriverConnect(m_aConnectionHandle
,
111 static_cast<SQLSMALLINT
>(std::min(sal_Int32(2048),aConStr
.getLength())),
113 SQLSMALLINT(sizeof(szConnStrOut
)/sizeof(SDB_ODBC_CHAR
)) -1,
115 SQL_DRIVER_NOPROMPT
);
116 if (nSQLRETURN
== SQL_ERROR
|| nSQLRETURN
== SQL_NO_DATA
|| SQL_SUCCESS_WITH_INFO
== nSQLRETURN
)
120 SQLUSMALLINT nSilent
= bSilent
? SQL_DRIVER_NOPROMPT
: SQL_DRIVER_COMPLETE
;
121 nSQLRETURN
= N3SQLDriverConnect(m_aConnectionHandle
,
124 static_cast<SQLSMALLINT
>(std::min
<sal_Int32
>(sal_Int32(2048),aConStr
.getLength())),
126 SQLSMALLINT(sizeof szConnStrOut
),
129 if (nSQLRETURN
== SQL_ERROR
|| nSQLRETURN
== SQL_NO_DATA
)
139 OTools::GetInfo(this,m_aConnectionHandle
,SQL_DATA_SOURCE_READ_ONLY
,aVal
,*this,getTextEncoding());
140 m_bReadOnly
= aVal
== "Y";
149 OTools::GetInfo(this,m_aConnectionHandle
,SQL_DRIVER_ODBC_VER
,sVersion
,*this,getTextEncoding());
150 m_bUseOldDateFormat
= sVersion
== "02.50" || sVersion
== "02.00";
157 // autocommit is always default
160 N3SQLSetConnectAttr(m_aConnectionHandle
,SQL_ATTR_AUTOCOMMIT
, reinterpret_cast<SQLPOINTER
>(SQL_AUTOCOMMIT_ON
),SQL_IS_INTEGER
);
165 SQLRETURN
OConnection::Construct(const OUString
& url
,const Sequence
< PropertyValue
>& info
)
167 m_aConnectionHandle
= SQL_NULL_HANDLE
;
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;
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")
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();
254 m_nTextEncoding
= RTL_TEXTENCODING_DONTKNOW
;
255 if(m_nTextEncoding
== RTL_TEXTENCODING_DONTKNOW
)
256 m_nTextEncoding
= osl_getThreadTextEncoding();
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);
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
));
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
));
293 Reference
< XPreparedStatement
> SAL_CALL
OConnection::prepareCall( const OUString
& /*sql*/ )
295 ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::prepareCall", *this );
299 OUString SAL_CALL
OConnection::nativeSQL( const OUString
& sql
)
301 ::osl::MutexGuard
aGuard( m_aMutex
);
303 OString
aSql(OUStringToOString(sql
,getTextEncoding()));
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
,
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
;
367 xMetaData
= new ODatabaseMetaData(m_aConnectionHandle
,this);
368 m_xMetaData
= 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
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
;
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
);
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);
444 Reference
< css::container::XNameAccess
> SAL_CALL
OConnection::getTypeMap( )
446 ::osl::MutexGuard
aGuard( m_aMutex
);
447 checkDisposed(OConnection_BASE::rBHelper
.bDisposed
);
453 void SAL_CALL
OConnection::setTypeMap( const Reference
< css::container::XNameAccess
>& /*typeMap*/ )
455 ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::setTypeMap", *this );
459 void SAL_CALL
OConnection::close( )
462 ::osl::MutexGuard
aGuard( m_aMutex
);
463 checkDisposed(OConnection_BASE::rBHelper
.bDisposed
);
470 Any SAL_CALL
OConnection::getWarnings( )
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();
491 N3SQLDisconnect(m_aConnectionHandle
);
495 SQLHANDLE
OConnection::createStatementHandle()
497 rtl::Reference
<OConnection
> xConnectionTemp
= this;
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
;
514 SQLHANDLE aStatementHandle
= SQL_NULL_HANDLE
;
515 N3SQLAllocHandle(SQL_HANDLE_STMT
,xConnectionTemp
->getConnection(),&aStatementHandle
);
518 m_aConnections
.emplace(aStatementHandle
,xConnectionTemp
);
520 return aStatementHandle
;
524 void OConnection::freeStatementHandle(SQLHANDLE
& _pHandle
)
526 if( SQL_NULL_HANDLE
== _pHandle
)
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
);
547 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */