1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: MConnection.cxx,v $
10 * $Revision: 1.28.56.2 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_connectivity.hxx"
34 #include "diagnose_ex.h"
35 #include "MConnection.hxx"
36 #include "MDatabaseMetaData.hxx"
37 #include "MDriver.hxx"
38 #include "MColumnAlias.hxx"
39 #include "MStatement.hxx"
40 #include "MPreparedStatement.hxx"
42 #include <connectivity/dbcharset.hxx>
43 #include <connectivity/dbexception.hxx>
44 #include <connectivity/sqlerror.hxx>
46 #include "resource/mozab_res.hrc"
47 #include "resource/common_res.hrc"
49 #include <com/sun/star/sdbc/ColumnValue.hpp>
50 #include <com/sun/star/sdbc/XRow.hpp>
51 #include <com/sun/star/sdbc/TransactionIsolation.hpp>
53 #include <comphelper/officeresourcebundle.hxx>
55 #if OSL_DEBUG_LEVEL > 0
56 # define OUtoCStr( x ) ( ::rtl::OUStringToOString ( (x), RTL_TEXTENCODING_ASCII_US).getStr())
57 #else /* OSL_DEBUG_LEVEL */
58 # define OUtoCStr( x ) ("dummy")
59 #endif /* OSL_DEBUG_LEVEL */
61 extern "C" SAL_DLLPUBLIC_EXPORT
void* SAL_CALL
OMozabConnection_CreateInstance(
64 return (new connectivity::mozab::OConnection( reinterpret_cast<connectivity::mozab::MozabDriver
*>(_pDriver
) ));
67 using namespace dbtools
;
69 //------------------------------------------------------------------------------
70 using namespace com::sun::star::uno
;
71 using namespace com::sun::star::lang
;
72 using namespace com::sun::star::beans
;
73 using namespace com::sun::star::sdbc
;
74 using namespace com::sun::star::sdbcx
;
75 // --------------------------------------------------------------------------------
77 namespace connectivity
{ namespace mozab
{
79 // =====================================================================
80 // = ConnectionImplData
81 // =====================================================================
82 struct ConnectionImplData
84 ::boost::shared_ptr
< ::comphelper::OfficeResourceBundle
> pResourceBundle
;
87 // -----------------------------------------------------------------------------
91 const sal_Char
* getSdbcScheme( SdbcScheme _eScheme
)
95 case SDBC_MOZILLA
: return "mozilla";
96 case SDBC_THUNDERBIRD
: return "thunderbird";
97 case SDBC_LDAP
: return "ldap";
98 case SDBC_OUTLOOK_MAPI
: return "outlook";
99 case SDBC_OUTLOOK_EXPRESS
: return "outlookexp";
103 // -----------------------------------------------------------------------------
104 ::rtl::OUString
OConnection::getDriverImplementationName()
106 return rtl::OUString::createFromAscii(MOZAB_DRIVER_IMPL_NAME
);
109 // -----------------------------------------------------------------------------
110 const sal_Char
* getSchemeURI( MozillaScheme _eScheme
)
114 case SCHEME_MOZILLA
: return "moz-abdirectory://";
115 case SCHEME_MOZILLA_MDB
: return "moz-abmdbdirectory://";
116 case SCHEME_LDAP
: return "moz-abldapdirectory://";
117 case SCHEME_OUTLOOK_MAPI
: return "moz-aboutlookdirectory://op/";
118 case SCHEME_OUTLOOK_EXPRESS
: return "moz-aboutlookdirectory://oe/";
123 // -----------------------------------------------------------------------------
125 OConnection::OConnection(MozabDriver
* _pDriver
)
126 :OSubComponent
<OConnection
, OConnection_BASE
>((::cppu::OWeakObject
*)_pDriver
, this)
128 ,m_pImplData( new ConnectionImplData
)
129 ,m_aColumnAlias( _pDriver
->getMSFactory() )
130 ,m_nMaxResultRecords( -1 )
132 ,m_eSDBCAddressType(SDBCAddress::Unknown
)
134 m_pDriver
->acquire();
137 //-----------------------------------------------------------------------------
138 OConnection::~OConnection()
143 m_pDriver
->release();
146 //-----------------------------------------------------------------------------
147 void SAL_CALL
OConnection::release() throw()
151 // -----------------------------------------------------------------------------
152 //-----------------------------------------------------------------------------
153 void OConnection::construct(const ::rtl::OUString
& url
,const Sequence
< PropertyValue
>& info
) throw(SQLException
)
155 OSL_TRACE("IN OConnection::construct()\n" );
159 // Skip 'sdbc:mozab: part of URL
161 sal_Int32 nLen
= url
.indexOf(':');
162 nLen
= url
.indexOf(':',nLen
+1);
163 OSL_ENSURE( url
.copy( 0, nLen
).equalsAscii( "sdbc:address" ), "OConnection::construct: invalid start of the URI - should never have survived XDriver::acceptsURL!" );
165 ::rtl::OUString
aAddrbookURI(url
.copy(nLen
+1));
167 nLen
= aAddrbookURI
.indexOf(':');
168 ::rtl::OUString aAddrbookScheme
;
169 ::rtl::OUString sAdditionalInfo
;
172 // There isn't any subschema: - but could be just subschema
173 if ( aAddrbookURI
.getLength() > 0 )
175 aAddrbookScheme
= aAddrbookURI
;
179 OSL_TRACE( "No subschema given!!!\n");
180 throwSQLException( STR_URI_SYNTAX_ERROR
, *this );
185 aAddrbookScheme
= aAddrbookURI
.copy(0, nLen
);
186 sAdditionalInfo
= aAddrbookURI
.copy( nLen
+ 1 );
189 OSL_TRACE("URI = %s\n", ((OUtoCStr(aAddrbookURI
)) ? (OUtoCStr(aAddrbookURI
)):("NULL")) );
190 OSL_TRACE("Scheme = %s\n", ((OUtoCStr(aAddrbookScheme
)) ? (OUtoCStr(aAddrbookScheme
)):("NULL")) );
193 // Now we have a URI convert it to a MozillaURI
195 // The Mapping being used is:
198 // "sdbc:address:mozilla:" -> abdirectory://
200 // "sdbc:address:ldap:" -> abldapdirectory://
201 // * for Outlook (using MAPI API)
202 // "sdbc:address:outlook:" -> aboutlookdirectory://op/
203 // * for windows system address book
204 // "sdbc:address:outlookexp:" -> aboutlookdirectory://oe/
206 m_sBindDN
= rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(""));
207 m_sPassword
= rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(""));
208 m_bUseSSL
= sal_False
;
210 if ( aAddrbookScheme
.compareToAscii( getSdbcScheme( SDBC_MOZILLA
) ) == 0 ) {
211 m_sMozillaURI
= rtl::OUString::createFromAscii( getSchemeURI( SCHEME_MOZILLA
) );
212 m_eSDBCAddressType
= SDBCAddress::Mozilla
;
213 if(sAdditionalInfo
.getLength())
214 m_sMozillaProfile
= sAdditionalInfo
;
217 if ( aAddrbookScheme
.compareToAscii( getSdbcScheme( SDBC_THUNDERBIRD
) ) == 0 ) {
218 //Yes. I am sure it is SCHEME_MOZILLA
219 m_sMozillaURI
= rtl::OUString::createFromAscii( getSchemeURI( SCHEME_MOZILLA
) );
220 m_eSDBCAddressType
= SDBCAddress::ThunderBird
;
221 if(sAdditionalInfo
.getLength())
222 m_sMozillaProfile
= sAdditionalInfo
;
224 else if ( aAddrbookScheme
.compareToAscii( getSdbcScheme( SDBC_LDAP
) ) == 0 ) {
225 rtl::OUString sBaseDN
;
226 sal_Int32 nPortNumber
= -1;
228 m_sMozillaURI
= rtl::OUString::createFromAscii( getSchemeURI( SCHEME_LDAP
) );
229 m_eSDBCAddressType
= SDBCAddress::LDAP
;
231 if ( !m_sHostName
.getLength() )
233 // see whether the URI contains a hostname/port
234 if ( sAdditionalInfo
.getLength() )
236 sal_Int32 nPortSeparator
= sAdditionalInfo
.indexOf( ':' );
237 if ( nPortSeparator
== -1 )
238 m_sHostName
= sAdditionalInfo
;
241 m_sHostName
= sAdditionalInfo
.copy( 0, nPortSeparator
);
242 nPortNumber
= sAdditionalInfo
.copy( nPortSeparator
+ 1 ).toInt32();
243 OSL_ENSURE( nPortNumber
!= 0, "OConnection::construct: invalid LDAP port number in the URL!" );
244 if ( nPortNumber
== 0 )
250 const PropertyValue
* pInfo
= info
.getConstArray();
251 const PropertyValue
* pInfoEnd
= pInfo
+ info
.getLength();
253 for (; pInfo
!= pInfoEnd
; ++pInfo
)
255 OSL_TRACE( "info[%d].Name = %s\n", pInfo
- info
.getConstArray(), OUtoCStr( pInfo
->Name
) );
257 if ( 0 == pInfo
->Name
.compareToAscii("HostName") )
259 pInfo
->Value
>>= m_sHostName
;
261 else if ( 0 == pInfo
->Name
.compareToAscii("BaseDN") )
263 pInfo
->Value
>>= sBaseDN
;
265 else if ( 0 == pInfo
->Name
.compareToAscii("user") )
267 pInfo
->Value
>>= m_sBindDN
;
269 else if ( 0 == pInfo
->Name
.compareToAscii("password") )
271 pInfo
->Value
>>= m_sPassword
;
273 else if ( 0 == pInfo
->Name
.compareToAscii("UseSSL") )
275 pInfo
->Value
>>= m_bUseSSL
;
277 else if ( 0 == pInfo
->Name
.compareToAscii("PortNumber") )
279 OSL_VERIFY( pInfo
->Value
>>= nPortNumber
);
281 else if ( 0 == pInfo
->Name
.compareToAscii("MaxRowCount") )
283 pInfo
->Value
>>= m_nMaxResultRecords
;
287 if ( m_sHostName
.getLength() != 0 ) {
288 m_sMozillaURI
+= m_sHostName
;
291 throwSQLException( STR_NO_HOSTNAME
, *this );
293 if ( nPortNumber
> 0 ) {
294 m_sMozillaURI
+= rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(":") );
295 m_sMozillaURI
+= rtl::OUString::valueOf( nPortNumber
);
298 if ( sBaseDN
.getLength() != 0 ) {
299 m_sMozillaURI
+= rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("/") );
300 m_sMozillaURI
+= sBaseDN
;
303 throwSQLException( STR_NO_BASEDN
, *this );
305 // Addition of a fake query to enable the Mozilla LDAP directory to work correctly.
306 m_sMozillaURI
+= ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("?(or(DisplayName,=,DontDoThisAtHome)))"));
309 else if ( aAddrbookScheme
.compareToAscii( getSdbcScheme( SDBC_OUTLOOK_MAPI
) ) == 0 ) {
310 m_sMozillaURI
= ::rtl::OUString::createFromAscii( getSchemeURI( SCHEME_OUTLOOK_MAPI
) );
311 m_eSDBCAddressType
= SDBCAddress::Outlook
;
313 else if ( aAddrbookScheme
.compareToAscii( getSdbcScheme( SDBC_OUTLOOK_EXPRESS
) ) == 0 ) {
314 m_sMozillaURI
= rtl::OUString::createFromAscii( getSchemeURI( SCHEME_OUTLOOK_EXPRESS
) );
315 m_eSDBCAddressType
= SDBCAddress::OutlookExp
;
319 OSL_TRACE("Invalid subschema given!!!\n");
320 throwSQLException( STR_URI_SYNTAX_ERROR
, *this );
323 OSL_TRACE("Moz URI = %s, %s\n", ((OUtoCStr(m_sMozillaURI
)) ? (OUtoCStr(m_sMozillaURI
)):("NULL")), usesFactory() ? "uses factory" : "no factory");
324 OSL_TRACE( "\tOUT OConnection::construct()\n" );
326 MDatabaseMetaDataHelper _aDbHelper
;
328 // The creation of the nsIAbDirectory i/f for LDAP doesn't actually test
329 // the validity of the connection, it's normally delayed until the query
330 // is executed, but it's a bit late then to fail...
333 if ( !_aDbHelper
.testLDAPConnection( this ) )
335 OSL_TRACE("testLDAPConnection : FAILED\n" );
336 throwSQLException( _aDbHelper
.getError(), *this );
340 OSL_TRACE("testLDAPConnection : SUCCESS\n" );
344 // Test connection by getting to get the Table Names
345 ::std::vector
< ::rtl::OUString
> tables
;
346 ::std::vector
< ::rtl::OUString
> types
;
347 if ( !_aDbHelper
.getTableStrings( this, tables
, types
) )
349 throwSQLException( _aDbHelper
.getError(), *this );
354 // --------------------------------------------------------------------------------
355 IMPLEMENT_SERVICE_INFO(OConnection
, "com.sun.star.sdbc.drivers.mozab.OConnection", "com.sun.star.sdbc.Connection")
357 // --------------------------------------------------------------------------------
358 Reference
< XStatement
> SAL_CALL
OConnection::createStatement( ) throw(SQLException
, RuntimeException
)
360 ::osl::MutexGuard
aGuard( m_aMutex
);
361 checkDisposed(OConnection_BASE::rBHelper
.bDisposed
);
363 // create a statement
364 // the statement can only be executed once
365 Reference
< XStatement
> xReturn
= new OStatement(this);
366 m_aStatements
.push_back(WeakReferenceHelper(xReturn
));
369 // --------------------------------------------------------------------------------
370 Reference
< XPreparedStatement
> SAL_CALL
OConnection::prepareStatement( const ::rtl::OUString
& _sSql
) throw(SQLException
, RuntimeException
)
372 ::osl::MutexGuard
aGuard( m_aMutex
);
373 checkDisposed(OConnection_BASE::rBHelper
.bDisposed
);
375 OSL_TRACE("OConnection::prepareStatement( %s )", OUtoCStr( _sSql
) );
377 // create a statement
378 // the statement can only be executed more than once
379 OPreparedStatement
* pPrepared
= new OPreparedStatement(this,_sSql
);
380 Reference
< XPreparedStatement
> xReturn
= pPrepared
;
381 pPrepared
->lateInit();
383 m_aStatements
.push_back(WeakReferenceHelper(xReturn
));
386 // --------------------------------------------------------------------------------
387 Reference
< XPreparedStatement
> SAL_CALL
OConnection::prepareCall( const ::rtl::OUString
& _sSql
) throw(SQLException
, RuntimeException
)
390 ::dbtools::throwFeatureNotImplementedException( "XConnection::prepareCall", *this );
391 OSL_TRACE("OConnection::prepareCall( %s )", OUtoCStr( _sSql
) );
394 // --------------------------------------------------------------------------------
395 ::rtl::OUString SAL_CALL
OConnection::nativeSQL( const ::rtl::OUString
& _sSql
) throw(SQLException
, RuntimeException
)
397 ::osl::MutexGuard
aGuard( m_aMutex
);
398 // when you need to transform SQL92 to you driver specific you can do it here
399 OSL_TRACE("OConnection::nativeSQL( %s )", OUtoCStr( _sSql
) );
403 // --------------------------------------------------------------------------------
404 void SAL_CALL
OConnection::setAutoCommit( sal_Bool
/*autoCommit*/ ) throw(SQLException
, RuntimeException
)
406 ::dbtools::throwFeatureNotImplementedException( "XConnection::setAutoCommit", *this );
408 // --------------------------------------------------------------------------------
409 sal_Bool SAL_CALL
OConnection::getAutoCommit( ) throw(SQLException
, RuntimeException
)
411 // you have to distinguish which if you are in autocommit mode or not
412 // at normal case true should be fine here
416 // --------------------------------------------------------------------------------
417 void SAL_CALL
OConnection::commit( ) throw(SQLException
, RuntimeException
)
419 // when you database does support transactions you should commit here
421 // --------------------------------------------------------------------------------
422 void SAL_CALL
OConnection::rollback( ) throw(SQLException
, RuntimeException
)
424 // same as commit but for the other case
426 // --------------------------------------------------------------------------------
427 sal_Bool SAL_CALL
OConnection::isClosed( ) throw(SQLException
, RuntimeException
)
429 ::osl::MutexGuard
aGuard( m_aMutex
);
431 // just simple -> we are close when we are disposed taht means someone called dispose(); (XComponent)
432 return OConnection_BASE::rBHelper
.bDisposed
;
434 // --------------------------------------------------------------------------------
435 Reference
< XDatabaseMetaData
> SAL_CALL
OConnection::getMetaData( ) throw(SQLException
, RuntimeException
)
437 ::osl::MutexGuard
aGuard( m_aMutex
);
438 checkDisposed(OConnection_BASE::rBHelper
.bDisposed
);
440 // here we have to create the class with biggest interface
441 // The answer is 42 :-)
442 Reference
< XDatabaseMetaData
> xMetaData
= m_xMetaData
;
445 xMetaData
= new ODatabaseMetaData(this); // need the connection because it can return it
446 m_xMetaData
= xMetaData
;
451 // --------------------------------------------------------------------------------
452 void SAL_CALL
OConnection::setReadOnly( sal_Bool
/*readOnly*/ ) throw(SQLException
, RuntimeException
)
454 ::dbtools::throwFeatureNotImplementedException( "XConnection::setReadOnly", *this );
456 // --------------------------------------------------------------------------------
457 sal_Bool SAL_CALL
OConnection::isReadOnly( ) throw(SQLException
, RuntimeException
)
459 // return if your connection to readonly
462 // --------------------------------------------------------------------------------
463 void SAL_CALL
OConnection::setCatalog( const ::rtl::OUString
& /*catalog*/ ) throw(SQLException
, RuntimeException
)
465 ::dbtools::throwFeatureNotImplementedException( "XConnection::setCatalog", *this );
467 // --------------------------------------------------------------------------------
468 ::rtl::OUString SAL_CALL
OConnection::getCatalog( ) throw(SQLException
, RuntimeException
)
470 // return your current catalog
471 return ::rtl::OUString();
473 // --------------------------------------------------------------------------------
474 void SAL_CALL
OConnection::setTransactionIsolation( sal_Int32
/*level*/ ) throw(SQLException
, RuntimeException
)
476 ::dbtools::throwFeatureNotImplementedException( "XConnection::setTransactionIsolation", *this );
478 // --------------------------------------------------------------------------------
479 sal_Int32 SAL_CALL
OConnection::getTransactionIsolation( ) throw(SQLException
, RuntimeException
)
481 // please have a look at @see com.sun.star.sdbc.TransactionIsolation
482 return TransactionIsolation::NONE
;
484 // --------------------------------------------------------------------------------
485 Reference
< ::com::sun::star::container::XNameAccess
> SAL_CALL
OConnection::getTypeMap( ) throw(SQLException
, RuntimeException
)
487 // if your driver has special database types you can return it here
490 // --------------------------------------------------------------------------------
491 void SAL_CALL
OConnection::setTypeMap( const Reference
< ::com::sun::star::container::XNameAccess
>& /*typeMap*/ ) throw(SQLException
, RuntimeException
)
493 ::dbtools::throwFeatureNotImplementedException( "XConnection::setTypeMap", *this );
495 // --------------------------------------------------------------------------------
497 void SAL_CALL
OConnection::close( ) throw(SQLException
, RuntimeException
)
499 // we just dispose us
501 ::osl::MutexGuard
aGuard( m_aMutex
);
502 checkDisposed(OConnection_BASE::rBHelper
.bDisposed
);
507 // --------------------------------------------------------------------------------
509 Any SAL_CALL
OConnection::getWarnings( ) throw(SQLException
, RuntimeException
)
511 // when you collected some warnings -> return it
514 // --------------------------------------------------------------------------------
515 void SAL_CALL
OConnection::clearWarnings( ) throw(SQLException
, RuntimeException
)
517 // you should clear your collected warnings here
519 //------------------------------------------------------------------------------
520 void OConnection::disposing()
522 // we noticed that we should be destroied in near future so we have to dispose our statements
523 ::osl::MutexGuard
aGuard(m_aMutex
);
525 m_pImplData
->pResourceBundle
.reset();
527 OConnection_BASE::disposing();
528 if ( m_aNameMapper
) {
529 MQuery::FreeNameMapper( m_aNameMapper
);
530 m_aNameMapper
= NULL
;
535 // -----------------------------------------------------------------------------
537 Reference
< XTablesSupplier
> SAL_CALL
OConnection::createCatalog()
539 OSL_TRACE("IN OConnection::createCatalog()\n" );
540 ::osl::MutexGuard
aGuard( m_aMutex
);
541 Reference
< XTablesSupplier
> xTab
= m_xCatalog
;
544 OCatalog
*pCat
= new OCatalog(this);
548 OSL_TRACE( "\tOUT OConnection::createCatalog()\n" );
551 // -----------------------------------------------------------------------------
553 MNameMapper
* OConnection::getNameMapper ()
555 if (m_aNameMapper
==NULL
)
556 m_aNameMapper
= MQuery::CreateNameMapper();
558 return m_aNameMapper
;
561 // -----------------------------------------------------------------------------
562 void OConnection::throwSQLException( const ErrorDescriptor
& _rError
, const Reference
< XInterface
>& _rxContext
)
564 if ( _rError
.getResId() != 0 )
566 OSL_ENSURE( ( _rError
.getErrorCondition() == 0 ),
567 "OConnection::throwSQLException: unsupported error code combination!" );
569 ::rtl::OUString
sParameter( _rError
.getParameter() );
570 if ( sParameter
.getLength() )
572 const ::rtl::OUString
sError( getResources().getResourceStringWithSubstitution(
576 ::dbtools::throwGenericSQLException( sError
, _rxContext
);
577 OSL_ENSURE( false, "OConnection::throwSQLException: unreachable (1)!" );
580 throwGenericSQLException( _rError
.getResId(), _rxContext
);
581 OSL_ENSURE( false, "OConnection::throwSQLException: unreachable (2)!" );
584 if ( _rError
.getErrorCondition() != 0 )
586 SQLError
aErrorHelper( getDriver()->getMSFactory() );
587 ::rtl::OUString
sParameter( _rError
.getParameter() );
588 if ( sParameter
.getLength() )
589 aErrorHelper
.raiseException( _rError
.getErrorCondition(), _rxContext
, sParameter
);
591 aErrorHelper
.raiseException( _rError
.getErrorCondition(), _rxContext
);
592 OSL_ENSURE( false, "OConnection::throwSQLException: unreachable (3)!" );
595 throwGenericSQLException( STR_UNSPECIFIED_ERROR
, _rxContext
);
598 // -----------------------------------------------------------------------------
599 void OConnection::throwSQLException( const sal_uInt16 _nErrorResourceId
, const Reference
< XInterface
>& _rxContext
)
601 ErrorDescriptor aError
;
602 aError
.setResId( _nErrorResourceId
);
603 throwSQLException( aError
, _rxContext
);
606 } } // namespace connectivity::mozab