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 <com/sun/star/sdbc/ColumnValue.hpp>
28 #include <com/sun/star/sdbc/XRow.hpp>
29 #include <com/sun/star/lang/DisposedException.hpp>
30 #include <connectivity/dbcharset.hxx>
31 #include <connectivity/FValue.hxx>
32 #include <comphelper/extract.hxx>
33 #include "diagnose_ex.h"
34 #include <connectivity/dbexception.hxx>
38 using namespace connectivity::odbc
;
39 using namespace connectivity
;
40 using namespace dbtools
;
43 using namespace com::sun::star::uno
;
44 using namespace com::sun::star::lang
;
45 using namespace com::sun::star::beans
;
46 using namespace com::sun::star::sdbc
;
48 OConnection::OConnection(const SQLHANDLE _pDriverHandle
,ODBCDriver
* _pDriver
)
49 : OSubComponent
<OConnection
, OConnection_BASE
>((::cppu::OWeakObject
*)_pDriver
, this)
51 ,m_aConnectionHandle(NULL
)
52 ,m_pDriverHandleCopy(_pDriverHandle
)
56 ,m_bUseOldDateFormat(false)
57 ,m_bParameterSubstitution(false)
58 ,m_bIgnoreDriverPrivileges(false)
59 ,m_bPreventGetVersionColumns(false)
65 OConnection::~OConnection()
70 if ( SQL_NULL_HANDLE
!= m_aConnectionHandle
)
74 rc
= N3SQLDisconnect( m_aConnectionHandle
);
75 OSL_ENSURE( rc
== SQL_SUCCESS
|| rc
== SQL_SUCCESS_WITH_INFO
, "Failure from SQLDisconnect" );
77 rc
= N3SQLFreeHandle( SQL_HANDLE_DBC
, m_aConnectionHandle
);
78 OSL_ENSURE( rc
== SQL_SUCCESS
, "Failure from SQLFreeHandle for connection");
81 m_aConnectionHandle
= SQL_NULL_HANDLE
;
88 void SAL_CALL
OConnection::release() throw()
93 oslGenericFunction
OConnection::getOdbcFunction(sal_Int32 _nIndex
) const
95 OSL_ENSURE(m_pDriver
,"OConnection::getOdbcFunction: m_pDriver is null!");
96 return m_pDriver
->getOdbcFunction(_nIndex
);
99 SQLRETURN
OConnection::OpenConnection(const OUString
& aConnectStr
, sal_Int32 nTimeOut
, bool bSilent
)
101 ::osl::MutexGuard
aGuard( m_aMutex
);
103 if (m_aConnectionHandle
== SQL_NULL_HANDLE
)
106 SQLRETURN nSQLRETURN
= 0;
107 SDB_ODBC_CHAR szConnStrOut
[4096];
108 SDB_ODBC_CHAR szConnStrIn
[2048];
109 SQLSMALLINT cbConnStrOut
;
110 memset(szConnStrOut
,'\0',4096);
111 memset(szConnStrIn
,'\0',2048);
112 OString
aConStr(OUStringToOString(aConnectStr
,getTextEncoding()));
113 memcpy(szConnStrIn
, (SDB_ODBC_CHAR
*) aConStr
.getStr(), ::std::min
<sal_Int32
>((sal_Int32
)2048,aConStr
.getLength()));
116 N3SQLSetConnectAttr(m_aConnectionHandle
,SQL_ATTR_LOGIN_TIMEOUT
,(SQLPOINTER
)(sal_IntPtr
)nTimeOut
,SQL_IS_UINTEGER
);
118 (void)nTimeOut
; /* WaE */
122 OSL_UNUSED( bSilent
);
123 nSQLRETURN
= N3SQLDriverConnect(m_aConnectionHandle
,
126 (SQLSMALLINT
) ::std::min((sal_Int32
)2048,aConStr
.getLength()),
128 (SQLSMALLINT
) (sizeof(szConnStrOut
)/sizeof(SDB_ODBC_CHAR
)) -1,
130 SQL_DRIVER_NOPROMPT
);
131 if (nSQLRETURN
== SQL_ERROR
|| nSQLRETURN
== SQL_NO_DATA
|| SQL_SUCCESS_WITH_INFO
== nSQLRETURN
)
135 SQLUSMALLINT nSilent
= bSilent
? SQL_DRIVER_NOPROMPT
: SQL_DRIVER_COMPLETE
;
136 nSQLRETURN
= N3SQLDriverConnect(m_aConnectionHandle
,
139 (SQLSMALLINT
) ::std::min
<sal_Int32
>((sal_Int32
)2048,aConStr
.getLength()),
141 (SQLSMALLINT
) sizeof szConnStrOut
,
144 if (nSQLRETURN
== SQL_ERROR
|| nSQLRETURN
== SQL_NO_DATA
)
154 OTools::GetInfo(this,m_aConnectionHandle
,SQL_DATA_SOURCE_READ_ONLY
,aVal
,*this,getTextEncoding());
155 m_bReadOnly
= aVal
.equalsAscii("Y");
164 OTools::GetInfo(this,m_aConnectionHandle
,SQL_DRIVER_ODBC_VER
,sVersion
,*this,getTextEncoding());
165 m_bUseOldDateFormat
= sVersion
== "02.50" || sVersion
== "02.00";
172 // autocoomit is always default
175 N3SQLSetConnectAttr(m_aConnectionHandle
,SQL_ATTR_AUTOCOMMIT
,(SQLPOINTER
)SQL_AUTOCOMMIT_ON
,SQL_IS_INTEGER
);
180 SQLRETURN
OConnection::Construct(const OUString
& url
,const Sequence
< PropertyValue
>& info
) throw(SQLException
)
182 m_aConnectionHandle
= SQL_NULL_HANDLE
;
184 setConnectionInfo(info
);
186 N3SQLAllocHandle(SQL_HANDLE_DBC
,m_pDriverHandleCopy
,&m_aConnectionHandle
);
187 if(m_aConnectionHandle
== SQL_NULL_HANDLE
)
188 throw SQLException();
190 sal_Int32 nLen
= url
.indexOf(':');
191 nLen
= url
.indexOf(':',nLen
+1);
192 OUString
aDSN("DSN="), aUID
, aPWD
, aSysDrvSettings
;
193 aDSN
+= url
.copy(nLen
+1);
195 const char* pUser
= "user";
196 const char* pTimeout
= "Timeout";
197 const char* pSilent
= "Silent";
198 const char* pPwd
= "password";
199 const char* pUseCatalog
= "UseCatalog";
200 const char* pSysDrv
= "SystemDriverSettings";
201 const char* pCharSet
= "CharSet";
202 const char* pParaName
= "ParameterNameSubstitution";
203 const char* pPrivName
= "IgnoreDriverPrivileges";
204 const char* pVerColName
= "PreventGetVersionColumns"; // #i60273#
205 const char* pRetrieving
= "IsAutoRetrievingEnabled";
206 const char* pRetriStmt
= "AutoRetrievingStatement";
208 sal_Int32 nTimeout
= 20;
210 const PropertyValue
*pBegin
= info
.getConstArray();
211 const PropertyValue
*pEnd
= pBegin
+ info
.getLength();
212 for(;pBegin
!= pEnd
;++pBegin
)
214 if( pBegin
->Name
.equalsAscii(pTimeout
))
215 OSL_VERIFY( pBegin
->Value
>>= nTimeout
);
216 else if( pBegin
->Name
.equalsAscii(pSilent
))
217 OSL_VERIFY( pBegin
->Value
>>= bSilent
);
218 else if( pBegin
->Name
.equalsAscii(pPrivName
))
219 OSL_VERIFY( pBegin
->Value
>>= m_bIgnoreDriverPrivileges
);
220 else if( pBegin
->Name
.equalsAscii(pVerColName
))
221 OSL_VERIFY( pBegin
->Value
>>= m_bPreventGetVersionColumns
);
222 else if( pBegin
->Name
.equalsAscii(pParaName
))
223 OSL_VERIFY( pBegin
->Value
>>= m_bParameterSubstitution
);
224 else if( pBegin
->Name
.equalsAscii(pRetrieving
))
226 bool bAutoRetrievingEnabled
= false;
227 OSL_VERIFY( pBegin
->Value
>>= bAutoRetrievingEnabled
);
228 enableAutoRetrievingEnabled(bAutoRetrievingEnabled
);
230 else if( pBegin
->Name
.equalsAscii(pRetriStmt
))
232 OUString sGeneratedValueStatement
;
233 OSL_VERIFY( pBegin
->Value
>>= sGeneratedValueStatement
);
234 setAutoRetrievingStatement(sGeneratedValueStatement
);
236 else if( pBegin
->Name
.equalsAscii(pUser
))
238 OSL_VERIFY( pBegin
->Value
>>= aUID
);
239 aDSN
= aDSN
+ ";UID=" + aUID
;
241 else if( pBegin
->Name
.equalsAscii(pPwd
))
243 OSL_VERIFY( pBegin
->Value
>>= aPWD
);
244 aDSN
= aDSN
+ ";PWD=" + aPWD
;
246 else if( pBegin
->Name
.equalsAscii(pUseCatalog
))
248 OSL_VERIFY( pBegin
->Value
>>= m_bUseCatalog
);
250 else if( pBegin
->Name
.equalsAscii(pSysDrv
))
252 OSL_VERIFY( pBegin
->Value
>>= aSysDrvSettings
);
254 aDSN
+= aSysDrvSettings
;
256 else if( pBegin
->Name
.equalsAscii(pCharSet
))
259 OSL_VERIFY( pBegin
->Value
>>= sIanaName
);
261 ::dbtools::OCharsetMap aLookupIanaName
;
262 ::dbtools::OCharsetMap::const_iterator aLookup
= aLookupIanaName
.find(sIanaName
, ::dbtools::OCharsetMap::IANA());
263 if (aLookup
!= aLookupIanaName
.end())
264 m_nTextEncoding
= (*aLookup
).getEncoding();
266 m_nTextEncoding
= RTL_TEXTENCODING_DONTKNOW
;
267 if(m_nTextEncoding
== RTL_TEXTENCODING_DONTKNOW
)
268 m_nTextEncoding
= osl_getThreadTextEncoding();
273 SQLRETURN nSQLRETURN
= OpenConnection(aDSN
,nTimeout
, bSilent
);
274 if (nSQLRETURN
== SQL_ERROR
|| nSQLRETURN
== SQL_NO_DATA
)
276 OTools::ThrowException(this,nSQLRETURN
,m_aConnectionHandle
,SQL_HANDLE_DBC
,*this,false);
282 IMPLEMENT_SERVICE_INFO(OConnection
, "com.sun.star.sdbc.drivers.odbc.OConnection", "com.sun.star.sdbc.Connection")
285 Reference
< XStatement
> SAL_CALL
OConnection::createStatement( ) throw(SQLException
, RuntimeException
, std::exception
)
287 ::osl::MutexGuard
aGuard( m_aMutex
);
288 checkDisposed(OConnection_BASE::rBHelper
.bDisposed
);
290 Reference
< XStatement
> xReturn
= new OStatement(this);
291 m_aStatements
.push_back(WeakReferenceHelper(xReturn
));
295 Reference
< XPreparedStatement
> SAL_CALL
OConnection::prepareStatement( const OUString
& sql
) throw(SQLException
, RuntimeException
, std::exception
)
297 ::osl::MutexGuard
aGuard( m_aMutex
);
298 checkDisposed(OConnection_BASE::rBHelper
.bDisposed
);
300 Reference
< XPreparedStatement
> xReturn
= new OPreparedStatement(this,sql
);
301 m_aStatements
.push_back(WeakReferenceHelper(xReturn
));
305 Reference
< XPreparedStatement
> SAL_CALL
OConnection::prepareCall( const OUString
& /*sql*/ ) throw(SQLException
, RuntimeException
, std::exception
)
307 ::dbtools::throwFeatureNotImplementedException( "XConnection::prepareCall", *this );
311 OUString SAL_CALL
OConnection::nativeSQL( const OUString
& sql
) throw(SQLException
, RuntimeException
, std::exception
)
313 ::osl::MutexGuard
aGuard( m_aMutex
);
315 OString
aSql(OUStringToOString(sql
.getStr(),getTextEncoding()));
318 OTools::ThrowException(this,N3SQLNativeSql(m_aConnectionHandle
,(SDB_ODBC_CHAR
*)aSql
.getStr(),aSql
.getLength(),(SDB_ODBC_CHAR
*)pOut
,sizeof pOut
- 1,&nOutLen
),m_aConnectionHandle
,SQL_HANDLE_DBC
,*this);
319 return OUString(pOut
,nOutLen
,getTextEncoding());
322 void SAL_CALL
OConnection::setAutoCommit( sal_Bool autoCommit
) throw(SQLException
, RuntimeException
, std::exception
)
324 ::osl::MutexGuard
aGuard( m_aMutex
);
325 checkDisposed(OConnection_BASE::rBHelper
.bDisposed
);
328 OTools::ThrowException(this,N3SQLSetConnectAttr(m_aConnectionHandle
,
330 (SQLPOINTER
)((autoCommit
) ? SQL_AUTOCOMMIT_ON
: SQL_AUTOCOMMIT_OFF
) ,SQL_IS_INTEGER
),
331 m_aConnectionHandle
,SQL_HANDLE_DBC
,*this);
334 sal_Bool SAL_CALL
OConnection::getAutoCommit( ) throw(SQLException
, RuntimeException
, std::exception
)
336 ::osl::MutexGuard
aGuard( m_aMutex
);
337 checkDisposed(OConnection_BASE::rBHelper
.bDisposed
);
340 sal_uInt32 nOption
= 0;
341 OTools::ThrowException(this,N3SQLGetConnectAttr(m_aConnectionHandle
,
342 SQL_ATTR_AUTOCOMMIT
, &nOption
,0,0),m_aConnectionHandle
,SQL_HANDLE_DBC
,*this);
343 return nOption
== SQL_AUTOCOMMIT_ON
;
346 void SAL_CALL
OConnection::commit( ) throw(SQLException
, RuntimeException
, std::exception
)
348 ::osl::MutexGuard
aGuard( m_aMutex
);
349 checkDisposed(OConnection_BASE::rBHelper
.bDisposed
);
352 OTools::ThrowException(this,N3SQLEndTran(SQL_HANDLE_DBC
,m_aConnectionHandle
,SQL_COMMIT
),m_aConnectionHandle
,SQL_HANDLE_DBC
,*this);
355 void SAL_CALL
OConnection::rollback( ) throw(SQLException
, RuntimeException
, std::exception
)
357 ::osl::MutexGuard
aGuard( m_aMutex
);
358 checkDisposed(OConnection_BASE::rBHelper
.bDisposed
);
361 OTools::ThrowException(this,N3SQLEndTran(SQL_HANDLE_DBC
,m_aConnectionHandle
,SQL_ROLLBACK
),m_aConnectionHandle
,SQL_HANDLE_DBC
,*this);
364 sal_Bool SAL_CALL
OConnection::isClosed( ) throw(SQLException
, RuntimeException
, std::exception
)
366 ::osl::MutexGuard
aGuard( m_aMutex
);
368 return OConnection_BASE::rBHelper
.bDisposed
;
371 Reference
< XDatabaseMetaData
> SAL_CALL
OConnection::getMetaData( ) throw(SQLException
, RuntimeException
, std::exception
)
373 ::osl::MutexGuard
aGuard( m_aMutex
);
374 checkDisposed(OConnection_BASE::rBHelper
.bDisposed
);
376 Reference
< XDatabaseMetaData
> xMetaData
= m_xMetaData
;
379 xMetaData
= new ODatabaseMetaData(m_aConnectionHandle
,this);
380 m_xMetaData
= xMetaData
;
386 void SAL_CALL
OConnection::setReadOnly( sal_Bool readOnly
) throw(SQLException
, RuntimeException
, std::exception
)
388 ::osl::MutexGuard
aGuard( m_aMutex
);
389 checkDisposed(OConnection_BASE::rBHelper
.bDisposed
);
392 OTools::ThrowException(this,
393 N3SQLSetConnectAttr(m_aConnectionHandle
,SQL_ATTR_ACCESS_MODE
,reinterpret_cast< SQLPOINTER
>( readOnly
),SQL_IS_INTEGER
),
394 m_aConnectionHandle
,SQL_HANDLE_DBC
,*this);
397 sal_Bool SAL_CALL
OConnection::isReadOnly() throw(SQLException
, RuntimeException
, std::exception
)
399 // const member which will initialized only once
403 void SAL_CALL
OConnection::setCatalog( const OUString
& catalog
) throw(SQLException
, RuntimeException
, std::exception
)
405 ::osl::MutexGuard
aGuard( m_aMutex
);
406 checkDisposed(OConnection_BASE::rBHelper
.bDisposed
);
409 OString
aCat(OUStringToOString(catalog
.getStr(),getTextEncoding()));
410 OTools::ThrowException(this,
411 N3SQLSetConnectAttr(m_aConnectionHandle
,SQL_ATTR_CURRENT_CATALOG
,(SDB_ODBC_CHAR
*)aCat
.getStr(),SQL_NTS
),
412 m_aConnectionHandle
,SQL_HANDLE_DBC
,*this);
415 OUString SAL_CALL
OConnection::getCatalog( ) throw(SQLException
, RuntimeException
, std::exception
)
417 ::osl::MutexGuard
aGuard( m_aMutex
);
418 checkDisposed(OConnection_BASE::rBHelper
.bDisposed
);
421 SQLINTEGER nValueLen
;
423 OTools::ThrowException(this,
424 N3SQLGetConnectAttr(m_aConnectionHandle
,SQL_ATTR_CURRENT_CATALOG
,(SDB_ODBC_CHAR
*)pCat
,(sizeof pCat
)-1,&nValueLen
),
425 m_aConnectionHandle
,SQL_HANDLE_DBC
,*this);
427 return OUString(pCat
,nValueLen
,getTextEncoding());
430 void SAL_CALL
OConnection::setTransactionIsolation( sal_Int32 level
) throw(SQLException
, RuntimeException
, std::exception
)
432 ::osl::MutexGuard
aGuard( m_aMutex
);
433 checkDisposed(OConnection_BASE::rBHelper
.bDisposed
);
436 OTools::ThrowException(this,N3SQLSetConnectAttr(m_aConnectionHandle
,
437 SQL_ATTR_TXN_ISOLATION
,
438 (SQLPOINTER
)(sal_IntPtr
)level
,SQL_IS_INTEGER
),
439 m_aConnectionHandle
,SQL_HANDLE_DBC
,*this);
442 sal_Int32 SAL_CALL
OConnection::getTransactionIsolation( ) throw(SQLException
, RuntimeException
, std::exception
)
444 ::osl::MutexGuard
aGuard( m_aMutex
);
445 checkDisposed(OConnection_BASE::rBHelper
.bDisposed
);
449 SQLINTEGER nValueLen
;
450 OTools::ThrowException(this,
451 N3SQLGetConnectAttr(m_aConnectionHandle
,SQL_ATTR_TXN_ISOLATION
,&nTxn
,sizeof nTxn
,&nValueLen
),
452 m_aConnectionHandle
,SQL_HANDLE_DBC
,*this);
456 Reference
< ::com::sun::star::container::XNameAccess
> SAL_CALL
OConnection::getTypeMap( ) throw(SQLException
, RuntimeException
, std::exception
)
458 ::osl::MutexGuard
aGuard( m_aMutex
);
459 checkDisposed(OConnection_BASE::rBHelper
.bDisposed
);
465 void SAL_CALL
OConnection::setTypeMap( const Reference
< ::com::sun::star::container::XNameAccess
>& /*typeMap*/ ) throw(SQLException
, RuntimeException
, std::exception
)
467 ::dbtools::throwFeatureNotImplementedException( "XConnection::setTypeMap", *this );
471 void SAL_CALL
OConnection::close( ) throw(SQLException
, RuntimeException
, std::exception
)
474 ::osl::MutexGuard
aGuard( m_aMutex
);
475 checkDisposed(OConnection_BASE::rBHelper
.bDisposed
);
482 Any SAL_CALL
OConnection::getWarnings( ) throw(SQLException
, RuntimeException
, std::exception
)
487 void SAL_CALL
OConnection::clearWarnings( ) throw(SQLException
, RuntimeException
, std::exception
)
491 void OConnection::disposing()
493 ::osl::MutexGuard
aGuard(m_aMutex
);
495 OConnection_BASE::disposing();
497 for (::std::map
< SQLHANDLE
,OConnection
*>::iterator aConIter
= m_aConnections
.begin();aConIter
!= m_aConnections
.end();++aConIter
)
498 aConIter
->second
->dispose();
500 ::std::map
< SQLHANDLE
,OConnection
*>().swap(m_aConnections
);
503 N3SQLDisconnect(m_aConnectionHandle
);
509 OConnection
* OConnection::cloneConnection()
511 return new OConnection(m_pDriverHandleCopy
,m_pDriver
);
514 SQLHANDLE
OConnection::createStatementHandle()
516 OConnection
* pConnectionTemp
= this;
520 sal_Int32 nMaxStatements
= getMetaData()->getMaxStatements();
521 if(nMaxStatements
&& nMaxStatements
<= m_nStatementCount
)
523 OConnection
* pConnection
= cloneConnection();
524 pConnection
->acquire();
525 pConnection
->Construct(m_sURL
,getConnectionInfo());
526 pConnectionTemp
= pConnection
;
534 SQLHANDLE aStatementHandle
= SQL_NULL_HANDLE
;
535 SQLRETURN nRetcode
= N3SQLAllocHandle(SQL_HANDLE_STMT
,pConnectionTemp
->getConnection(),&aStatementHandle
);
536 OSL_UNUSED( nRetcode
);
539 m_aConnections
.insert(::std::map
< SQLHANDLE
,OConnection
*>::value_type(aStatementHandle
,pConnectionTemp
));
541 return aStatementHandle
;
545 void OConnection::freeStatementHandle(SQLHANDLE
& _pHandle
)
547 if( SQL_NULL_HANDLE
== _pHandle
)
550 ::std::map
< SQLHANDLE
,OConnection
*>::iterator aFind
= m_aConnections
.find(_pHandle
);
552 N3SQLFreeStmt(_pHandle
,SQL_RESET_PARAMS
);
553 N3SQLFreeStmt(_pHandle
,SQL_UNBIND
);
554 N3SQLFreeStmt(_pHandle
,SQL_CLOSE
);
555 N3SQLFreeHandle(SQL_HANDLE_STMT
,_pHandle
);
557 _pHandle
= SQL_NULL_HANDLE
;
559 if(aFind
!= m_aConnections
.end())
561 aFind
->second
->dispose();
562 m_aConnections
.erase(aFind
);
570 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */