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 <ado/AConnection.hxx>
21 #include <ado/ADatabaseMetaData.hxx>
22 #include <ado/ADriver.hxx>
23 #include <ado/AStatement.hxx>
24 #include <ado/ACallableStatement.hxx>
25 #include <ado/APreparedStatement.hxx>
26 #include <ado/ACatalog.hxx>
27 #include <com/sun/star/sdbc/ColumnValue.hpp>
28 #include <com/sun/star/sdbc/TransactionIsolation.hpp>
29 #include <com/sun/star/sdbc/XRow.hpp>
30 #include <com/sun/star/lang/DisposedException.hpp>
31 #include <cppuhelper/typeprovider.hxx>
32 #include <connectivity/dbexception.hxx>
33 #include <osl/file.hxx>
34 #include <strings.hrc>
36 using namespace dbtools
;
37 using namespace connectivity::ado
;
38 using namespace com::sun::star::uno
;
39 using namespace com::sun::star::lang
;
40 using namespace com::sun::star::beans
;
41 using namespace com::sun::star::sdbc
;
42 using namespace com::sun::star::sdbcx
;
45 IMPLEMENT_SERVICE_INFO(OConnection
,"com.sun.star.sdbcx.AConnection","com.sun.star.sdbc.Connection");
47 OConnection::OConnection(ODriver
* _pDriver
)
48 : m_xCatalog(nullptr),
50 m_pAdoConnection(nullptr),
56 osl_atomic_increment( &m_refCount
);
58 IClassFactory2
* pIUnknown
= nullptr;
60 hr
= CoGetClassObject( ADOS::CLSID_ADOCONNECTION_21
,
64 reinterpret_cast<void**>(&pIUnknown
) );
68 ADOConnection
*pCon
= nullptr;
69 IUnknown
*pOuter
= nullptr;
70 hr
= pIUnknown
->CreateInstanceLic( pOuter
,
72 ADOS::IID_ADOCONNECTION_21
,
73 ADOS::GetKeyStr().asBSTR(),
74 reinterpret_cast<void**>(&pCon
));
78 OSL_ENSURE( pCon
, "OConnection::OConnection: invalid ADO object!" );
80 m_pAdoConnection
= new WpADOConnection( pCon
);
81 // CreateInstanceLic returned an object which was already acquired
86 // Class Factory is no longer needed
90 osl_atomic_decrement( &m_refCount
);
93 OConnection::~OConnection()
97 void OConnection::construct(const OUString
& url
,const Sequence
< PropertyValue
>& info
)
99 osl_atomic_increment( &m_refCount
);
101 setConnectionInfo(info
);
103 sal_Int32 nLen
= url
.indexOf(':');
104 nLen
= url
.indexOf(':',nLen
+1);
105 OUString
aDSN(url
.copy(nLen
+1)),aUID
,aPWD
;
106 if ( aDSN
.startsWith("access:") )
109 sal_Int32 nTimeout
= 20;
110 const PropertyValue
*pIter
= info
.getConstArray();
111 const PropertyValue
*pEnd
= pIter
+ info
.getLength();
112 for(;pIter
!= pEnd
;++pIter
)
114 if(pIter
->Name
== "Timeout")
115 pIter
->Value
>>= nTimeout
;
116 else if(pIter
->Name
== "user")
117 pIter
->Value
>>= aUID
;
118 else if(pIter
->Name
== "password")
119 pIter
->Value
>>= aPWD
;
125 if(m_pAdoConnection
->Open(aDSN
,aUID
,aPWD
,adConnectUnspecified
))
126 m_pAdoConnection
->PutCommandTimeout(nTimeout
);
128 ADOS::ThrowException(*m_pAdoConnection
,*this);
129 if(m_pAdoConnection
->get_State() != adStateOpen
)
130 throwGenericSQLException( STR_NO_CONNECTION
,*this );
132 WpADOProperties aProps
= m_pAdoConnection
->get_Properties();
135 OTools::putValue(aProps
,OUString("Jet OLEDB:ODBC Parsing"),true);
136 OLEVariant
aVar(OTools::getValue(aProps
,OUString("Jet OLEDB:Engine Type")));
137 if(!aVar
.isNull() && !aVar
.isEmpty())
138 m_nEngineType
= aVar
.getInt32();
144 ::dbtools::throwFunctionSequenceException(*this);
147 catch(const Exception
& )
149 osl_atomic_decrement( &m_refCount
);
152 osl_atomic_decrement( &m_refCount
);
155 Reference
< XStatement
> SAL_CALL
OConnection::createStatement( )
157 ::osl::MutexGuard
aGuard( m_aMutex
);
158 checkDisposed(OConnection_BASE::rBHelper
.bDisposed
);
160 OStatement
* pStmt
= new OStatement(this);
161 Reference
< XStatement
> xStmt
= pStmt
;
162 m_aStatements
.push_back(WeakReferenceHelper(*pStmt
));
166 Reference
< XPreparedStatement
> SAL_CALL
OConnection::prepareStatement( const OUString
& sql
)
168 ::osl::MutexGuard
aGuard( m_aMutex
);
169 checkDisposed(OConnection_BASE::rBHelper
.bDisposed
);
172 OPreparedStatement
* pStmt
= new OPreparedStatement(this, sql
);
173 Reference
< XPreparedStatement
> xPStmt
= pStmt
;
174 m_aStatements
.push_back(WeakReferenceHelper(*pStmt
));
178 Reference
< XPreparedStatement
> SAL_CALL
OConnection::prepareCall( const OUString
& sql
)
180 ::osl::MutexGuard
aGuard( m_aMutex
);
181 checkDisposed(OConnection_BASE::rBHelper
.bDisposed
);
184 OCallableStatement
* pStmt
= new OCallableStatement(this, sql
);
185 Reference
< XPreparedStatement
> xPStmt
= pStmt
;
186 m_aStatements
.push_back(WeakReferenceHelper(*pStmt
));
190 OUString SAL_CALL
OConnection::nativeSQL( const OUString
& _sql
)
192 ::osl::MutexGuard
aGuard( m_aMutex
);
193 checkDisposed(OConnection_BASE::rBHelper
.bDisposed
);
197 WpADOProperties aProps
= m_pAdoConnection
->get_Properties();
200 OTools::putValue(aProps
,OUString("Jet OLEDB:ODBC Parsing"),true);
201 WpADOCommand aCommand
;
203 aCommand
.put_ActiveConnection(static_cast<IDispatch
*>(*m_pAdoConnection
));
204 aCommand
.put_CommandText(sql
);
205 sql
= aCommand
.get_CommandText();
211 void SAL_CALL
OConnection::setAutoCommit( sal_Bool autoCommit
)
213 ::osl::MutexGuard
aGuard( m_aMutex
);
214 checkDisposed(OConnection_BASE::rBHelper
.bDisposed
);
217 m_bAutocommit
= autoCommit
;
219 m_pAdoConnection
->BeginTrans();
221 m_pAdoConnection
->RollbackTrans();
224 sal_Bool SAL_CALL
OConnection::getAutoCommit( )
226 ::osl::MutexGuard
aGuard( m_aMutex
);
227 checkDisposed(OConnection_BASE::rBHelper
.bDisposed
);
230 return m_bAutocommit
;
233 void SAL_CALL
OConnection::commit( )
235 ::osl::MutexGuard
aGuard( m_aMutex
);
236 checkDisposed(OConnection_BASE::rBHelper
.bDisposed
);
239 m_pAdoConnection
->CommitTrans();
242 void SAL_CALL
OConnection::rollback( )
244 ::osl::MutexGuard
aGuard( m_aMutex
);
245 checkDisposed(OConnection_BASE::rBHelper
.bDisposed
);
248 m_pAdoConnection
->RollbackTrans();
251 sal_Bool SAL_CALL
OConnection::isClosed( )
253 ::osl::MutexGuard
aGuard( m_aMutex
);
255 return OConnection_BASE::rBHelper
.bDisposed
&& !m_pAdoConnection
->get_State();
258 Reference
< XDatabaseMetaData
> SAL_CALL
OConnection::getMetaData( )
260 ::osl::MutexGuard
aGuard( m_aMutex
);
261 checkDisposed(OConnection_BASE::rBHelper
.bDisposed
);
264 Reference
< XDatabaseMetaData
> xMetaData
= m_xMetaData
;
267 xMetaData
= new ODatabaseMetaData(this);
268 m_xMetaData
= xMetaData
;
274 void SAL_CALL
OConnection::setReadOnly( sal_Bool readOnly
)
276 ::osl::MutexGuard
aGuard( m_aMutex
);
277 checkDisposed(OConnection_BASE::rBHelper
.bDisposed
);
280 m_pAdoConnection
->put_Mode(readOnly
? adModeRead
: adModeReadWrite
);
281 ADOS::ThrowException(*m_pAdoConnection
,*this);
284 sal_Bool SAL_CALL
OConnection::isReadOnly( )
286 ::osl::MutexGuard
aGuard( m_aMutex
);
287 checkDisposed(OConnection_BASE::rBHelper
.bDisposed
);
290 return m_pAdoConnection
->get_Mode() == adModeRead
;
293 void SAL_CALL
OConnection::setCatalog( const OUString
& catalog
)
295 ::osl::MutexGuard
aGuard( m_aMutex
);
296 checkDisposed(OConnection_BASE::rBHelper
.bDisposed
);
298 m_pAdoConnection
->PutDefaultDatabase(catalog
);
299 ADOS::ThrowException(*m_pAdoConnection
,*this);
302 OUString SAL_CALL
OConnection::getCatalog( )
304 ::osl::MutexGuard
aGuard( m_aMutex
);
305 checkDisposed(OConnection_BASE::rBHelper
.bDisposed
);
307 return m_pAdoConnection
->GetDefaultDatabase();
310 void SAL_CALL
OConnection::setTransactionIsolation( sal_Int32 level
)
312 ::osl::MutexGuard
aGuard( m_aMutex
);
313 checkDisposed(OConnection_BASE::rBHelper
.bDisposed
);
316 IsolationLevelEnum eIso
;
319 case TransactionIsolation::NONE
:
320 eIso
= adXactUnspecified
;
322 case TransactionIsolation::READ_UNCOMMITTED
:
323 eIso
= adXactReadUncommitted
;
325 case TransactionIsolation::READ_COMMITTED
:
326 eIso
= adXactReadCommitted
;
328 case TransactionIsolation::REPEATABLE_READ
:
329 eIso
= adXactRepeatableRead
;
331 case TransactionIsolation::SERIALIZABLE
:
332 eIso
= adXactSerializable
;
335 OSL_FAIL("OConnection::setTransactionIsolation invalid level");
338 m_pAdoConnection
->put_IsolationLevel(eIso
);
339 ADOS::ThrowException(*m_pAdoConnection
,*this);
342 sal_Int32 SAL_CALL
OConnection::getTransactionIsolation( )
344 ::osl::MutexGuard
aGuard( m_aMutex
);
345 checkDisposed(OConnection_BASE::rBHelper
.bDisposed
);
349 switch(m_pAdoConnection
->get_IsolationLevel())
351 case adXactUnspecified
:
352 nRet
= TransactionIsolation::NONE
;
354 case adXactReadUncommitted
:
355 nRet
= TransactionIsolation::READ_UNCOMMITTED
;
357 case adXactReadCommitted
:
358 nRet
= TransactionIsolation::READ_COMMITTED
;
360 case adXactRepeatableRead
:
361 nRet
= TransactionIsolation::REPEATABLE_READ
;
363 case adXactSerializable
:
364 nRet
= TransactionIsolation::SERIALIZABLE
;
367 OSL_FAIL("OConnection::setTransactionIsolation invalid level");
369 ADOS::ThrowException(*m_pAdoConnection
,*this);
373 Reference
< css::container::XNameAccess
> SAL_CALL
OConnection::getTypeMap( )
375 ::osl::MutexGuard
aGuard( m_aMutex
);
376 checkDisposed(OConnection_BASE::rBHelper
.bDisposed
);
382 void SAL_CALL
OConnection::setTypeMap( const Reference
< css::container::XNameAccess
>& /*typeMap*/ )
384 ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::setTypeMap", *this );
388 void SAL_CALL
OConnection::close( )
391 ::osl::MutexGuard
aGuard( m_aMutex
);
392 checkDisposed(OConnection_BASE::rBHelper
.bDisposed
);
399 Any SAL_CALL
OConnection::getWarnings( )
404 void SAL_CALL
OConnection::clearWarnings( )
408 void OConnection::buildTypeInfo()
410 ::osl::MutexGuard
aGuard( m_aMutex
);
412 ADORecordset
*pRecordset
= m_pAdoConnection
->getTypeInfo();
415 pRecordset
->AddRef();
416 VARIANT_BOOL bIsAtBOF
;
417 pRecordset
->get_BOF(&bIsAtBOF
);
420 if ( bIsAtBOF
== VARIANT_TRUE
)
421 bOk
= SUCCEEDED(pRecordset
->MoveNext());
426 static const char s_sVarChar
[] = "VarChar";
430 OExtendedTypeInfo
* aInfo
= new OExtendedTypeInfo
;
431 aInfo
->aSimpleType
.aTypeName
= ADOS::getField(pRecordset
,nPos
++).get_Value().getString();
432 aInfo
->eType
= static_cast<DataTypeEnum
>(ADOS::getField(pRecordset
,nPos
++).get_Value().getInt32());
433 if ( aInfo
->eType
== adWChar
&& aInfo
->aSimpleType
.aTypeName
== s_sVarChar
)
434 aInfo
->eType
= adVarWChar
;
435 aInfo
->aSimpleType
.nType
= static_cast<sal_Int16
>(ADOS::MapADOType2Jdbc(aInfo
->eType
));
436 aInfo
->aSimpleType
.nPrecision
= ADOS::getField(pRecordset
,nPos
++).get_Value().getInt32();
437 nPos
++; // aLiteralPrefix
438 nPos
++; // aLiteralSuffix
439 nPos
++; // aCreateParams
441 nPos
++; // bCaseSensitive
442 nPos
++; // nSearchType
445 nPos
++; // bAutoIncrement
446 aInfo
->aSimpleType
.aLocalTypeName
= ADOS::getField(pRecordset
,nPos
++).get_Value().getString();
447 nPos
++; // nMinimumScale
448 aInfo
->aSimpleType
.nMaximumScale
= ADOS::getField(pRecordset
,nPos
++).get_Value().getInt16();
449 if ( adCurrency
== aInfo
->eType
&& !aInfo
->aSimpleType
.nMaximumScale
)
451 aInfo
->aSimpleType
.nMaximumScale
= 4;
453 nPos
++; // nNumPrecRadix
454 // Now that we have the type info, save it
455 // in the Hashtable if we don't already have an
456 // entry for this SQL type.
458 m_aTypeInfo
.emplace(aInfo
->eType
,aInfo
);
460 while ( SUCCEEDED(pRecordset
->MoveNext()) );
462 pRecordset
->Release();
466 void OConnection::disposing()
468 ::osl::MutexGuard
aGuard(m_aMutex
);
470 OConnection_BASE::disposing();
473 m_xMetaData
= css::uno::WeakReference
< css::sdbc::XDatabaseMetaData
>();
474 m_xCatalog
= css::uno::WeakReference
< css::sdbcx::XTablesSupplier
>();
477 m_pAdoConnection
->Close();
479 for (auto& rEntry
: m_aTypeInfo
)
480 delete rEntry
.second
;
484 delete m_pAdoConnection
;
485 m_pAdoConnection
= nullptr;
488 sal_Int64 SAL_CALL
OConnection::getSomething( const css::uno::Sequence
< sal_Int8
>& rId
)
490 return (rId
.getLength() == 16 && 0 == memcmp(getUnoTunnelImplementationId().getConstArray(), rId
.getConstArray(), 16 ) )
492 reinterpret_cast< sal_Int64
>( this )
494 OConnection_BASE::getSomething(rId
);
497 Sequence
< sal_Int8
> OConnection::getUnoTunnelImplementationId()
499 static ::cppu::OImplementationId implId
;
501 return implId
.getImplementationId();
504 const OExtendedTypeInfo
* OConnection::getTypeInfoFromType(const OTypeInfoMap
& _rTypeInfo
,
506 const OUString
& _sTypeName
,
507 sal_Int32 _nPrecision
,
509 bool& _brForceToType
)
511 const OExtendedTypeInfo
* pTypeInfo
= nullptr;
512 _brForceToType
= false;
514 std::pair
<OTypeInfoMap::const_iterator
, OTypeInfoMap::const_iterator
> aPair
= _rTypeInfo
.equal_range(_nType
);
515 OTypeInfoMap::const_iterator aIter
= aPair
.first
;
516 if(aIter
!= _rTypeInfo
.end()) // compare with end is correct here
518 for(;aIter
!= aPair
.second
;++aIter
)
520 // search the best matching type
521 OExtendedTypeInfo
* pInfo
= aIter
->second
;
522 if ( ( !_sTypeName
.getLength()
523 || (pInfo
->aSimpleType
.aTypeName
.equalsIgnoreAsciiCase(_sTypeName
))
525 && (pInfo
->aSimpleType
.nPrecision
>= _nPrecision
)
526 && (pInfo
->aSimpleType
.nMaximumScale
>= _nScale
)
532 if (aIter
== aPair
.second
)
534 for(aIter
= aPair
.first
; aIter
!= aPair
.second
; ++aIter
)
536 // search the best matching type (now comparing the local names)
537 if ( (aIter
->second
->aSimpleType
.aLocalTypeName
.equalsIgnoreAsciiCase(_sTypeName
))
538 && (aIter
->second
->aSimpleType
.nPrecision
>= _nPrecision
)
539 && (aIter
->second
->aSimpleType
.nMaximumScale
>= _nScale
)
542 // we can not assert here because we could be in d&d
544 OSL_FAIL(( OString("getTypeInfoFromType: assuming column type ")
545 += OString(aIter->second->aTypeName.getStr(), aIter->second->aTypeName.getLength(), osl_getThreadTextEncoding())
546 += OString("\" (expected type name ")
547 += OString(_sTypeName.getStr(), _sTypeName.getLength(), osl_getThreadTextEncoding())
548 += OString(" matches the type's local name).")).getStr());
555 if (aIter
== aPair
.second
)
556 { // no match for the names, no match for the local names
557 // -> drop the precision and the scale restriction, accept any type with the property
560 // we can not assert here because we could be in d&d
561 pTypeInfo
= aPair
.first
->second
;
562 _brForceToType
= true;
565 pTypeInfo
= aIter
->second
;
567 else if ( _sTypeName
.getLength() )
569 ::comphelper::UStringMixEqual
aCase(false);
570 // search for typeinfo where the typename is equal _sTypeName
571 OTypeInfoMap::const_iterator aFind
= std::find_if(_rTypeInfo
.begin(), _rTypeInfo
.end(),
572 [&aCase
, &_sTypeName
] (const OTypeInfoMap::value_type
& typeInfo
) {
573 return aCase(typeInfo
.second
->getDBName(), _sTypeName
);
576 if(aFind
!= _rTypeInfo
.end())
577 pTypeInfo
= aFind
->second
;
580 // we can not assert here because we could be in d&d
581 // OSL_ENSURE(pTypeInfo, "getTypeInfoFromType: no type info found for this type!");
586 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */