Version 4.3.0.0.beta1, tag libreoffice-4.3.0.0.beta1
[LibreOffice.git] / connectivity / source / drivers / odbc / OConnection.cxx
blob93c0b3ee83b109be71f1957f3020250050c4b14e
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 <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>
36 #include <string.h>
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)
50 ,m_pDriver(_pDriver)
51 ,m_aConnectionHandle(NULL)
52 ,m_pDriverHandleCopy(_pDriverHandle)
53 ,m_nStatementCount(0)
54 ,m_bClosed(true)
55 ,m_bUseCatalog(false)
56 ,m_bUseOldDateFormat(false)
57 ,m_bParameterSubstitution(false)
58 ,m_bIgnoreDriverPrivileges(false)
59 ,m_bPreventGetVersionColumns(false)
60 ,m_bReadOnly(true)
62 m_pDriver->acquire();
65 OConnection::~OConnection()
67 if(!isClosed( ))
68 close();
70 if ( SQL_NULL_HANDLE != m_aConnectionHandle )
72 SQLRETURN rc;
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");
79 (void) rc;
81 m_aConnectionHandle = SQL_NULL_HANDLE;
84 m_pDriver->release();
85 m_pDriver = NULL;
88 void SAL_CALL OConnection::release() throw()
90 relase_ChildImpl();
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)
104 return -1;
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()));
115 #ifndef MACOSX
116 N3SQLSetConnectAttr(m_aConnectionHandle,SQL_ATTR_LOGIN_TIMEOUT,(SQLPOINTER)(sal_IntPtr)nTimeOut,SQL_IS_UINTEGER);
117 #else
118 (void)nTimeOut; /* WaE */
119 #endif
121 #ifdef LINUX
122 OSL_UNUSED( bSilent );
123 nSQLRETURN = N3SQLDriverConnect(m_aConnectionHandle,
124 NULL,
125 szConnStrIn,
126 (SQLSMALLINT) ::std::min((sal_Int32)2048,aConStr.getLength()),
127 szConnStrOut,
128 (SQLSMALLINT) (sizeof(szConnStrOut)/sizeof(SDB_ODBC_CHAR)) -1,
129 &cbConnStrOut,
130 SQL_DRIVER_NOPROMPT);
131 if (nSQLRETURN == SQL_ERROR || nSQLRETURN == SQL_NO_DATA || SQL_SUCCESS_WITH_INFO == nSQLRETURN)
132 return nSQLRETURN;
133 #else
135 SQLUSMALLINT nSilent = bSilent ? SQL_DRIVER_NOPROMPT : SQL_DRIVER_COMPLETE;
136 nSQLRETURN = N3SQLDriverConnect(m_aConnectionHandle,
137 NULL,
138 szConnStrIn,
139 (SQLSMALLINT) ::std::min<sal_Int32>((sal_Int32)2048,aConStr.getLength()),
140 szConnStrOut,
141 (SQLSMALLINT) sizeof szConnStrOut,
142 &cbConnStrOut,
143 nSilent);
144 if (nSQLRETURN == SQL_ERROR || nSQLRETURN == SQL_NO_DATA)
145 return nSQLRETURN;
147 m_bClosed = false;
149 #endif //LINUX
153 OUString aVal;
154 OTools::GetInfo(this,m_aConnectionHandle,SQL_DATA_SOURCE_READ_ONLY,aVal,*this,getTextEncoding());
155 m_bReadOnly = aVal.equalsAscii("Y");
157 catch(Exception&)
159 m_bReadOnly = true;
163 OUString sVersion;
164 OTools::GetInfo(this,m_aConnectionHandle,SQL_DRIVER_ODBC_VER,sVersion,*this,getTextEncoding());
165 m_bUseOldDateFormat = sVersion == "02.50" || sVersion == "02.00";
167 catch(Exception&)
172 // autocoomit is always default
174 if (!m_bReadOnly)
175 N3SQLSetConnectAttr(m_aConnectionHandle,SQL_ATTR_AUTOCOMMIT,(SQLPOINTER)SQL_AUTOCOMMIT_ON,SQL_IS_INTEGER);
177 return nSQLRETURN;
180 SQLRETURN OConnection::Construct(const OUString& url,const Sequence< PropertyValue >& info) throw(SQLException)
182 m_aConnectionHandle = SQL_NULL_HANDLE;
183 m_sURL = url;
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;
209 bool bSilent = true;
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 );
253 aDSN += ";";
254 aDSN += aSysDrvSettings;
256 else if( pBegin->Name.equalsAscii(pCharSet))
258 OUString sIanaName;
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();
265 else
266 m_nTextEncoding = RTL_TEXTENCODING_DONTKNOW;
267 if(m_nTextEncoding == RTL_TEXTENCODING_DONTKNOW)
268 m_nTextEncoding = osl_getThreadTextEncoding();
271 m_sUser = aUID;
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);
278 return nSQLRETURN;
280 // XServiceInfo
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));
292 return 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));
302 return xReturn;
305 Reference< XPreparedStatement > SAL_CALL OConnection::prepareCall( const OUString& /*sql*/ ) throw(SQLException, RuntimeException, std::exception)
307 ::dbtools::throwFeatureNotImplementedException( "XConnection::prepareCall", *this );
308 return NULL;
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()));
316 char pOut[2048];
317 SQLINTEGER nOutLen;
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,
329 SQL_ATTR_AUTOCOMMIT,
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;
377 if(!xMetaData.is())
379 xMetaData = new ODatabaseMetaData(m_aConnectionHandle,this);
380 m_xMetaData = xMetaData;
383 return 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
400 return m_bReadOnly;
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;
422 char pCat[1024];
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);
448 sal_Int32 nTxn = 0;
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);
453 return nTxn;
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);
462 return NULL;
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 );
470 // XCloseable
471 void SAL_CALL OConnection::close( ) throw(SQLException, RuntimeException, std::exception)
474 ::osl::MutexGuard aGuard( m_aMutex );
475 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
478 dispose();
481 // XWarningsSupplier
482 Any SAL_CALL OConnection::getWarnings( ) throw(SQLException, RuntimeException, std::exception)
484 return Any();
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);
502 if(!m_bClosed)
503 N3SQLDisconnect(m_aConnectionHandle);
504 m_bClosed = true;
506 dispose_ChildImpl();
509 OConnection* OConnection::cloneConnection()
511 return new OConnection(m_pDriverHandleCopy,m_pDriver);
514 SQLHANDLE OConnection::createStatementHandle()
516 OConnection* pConnectionTemp = this;
517 bool bNew = false;
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;
527 bNew = true;
530 catch(SQLException&)
534 SQLHANDLE aStatementHandle = SQL_NULL_HANDLE;
535 SQLRETURN nRetcode = N3SQLAllocHandle(SQL_HANDLE_STMT,pConnectionTemp->getConnection(),&aStatementHandle);
536 OSL_UNUSED( nRetcode );
537 ++m_nStatementCount;
538 if(bNew)
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 )
548 return;
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);
564 --m_nStatementCount;
570 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */