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 .
21 #include "diagnose_ex.h"
22 #include "MConnection.hxx"
23 #include "MDatabaseMetaData.hxx"
24 #include "MDriver.hxx"
25 #include "MColumnAlias.hxx"
26 #include "MStatement.hxx"
27 #include "MPreparedStatement.hxx"
29 #include <connectivity/dbcharset.hxx>
30 #include <connectivity/dbexception.hxx>
31 #include <connectivity/sqlerror.hxx>
33 #include "resource/mozab_res.hrc"
34 #include "resource/common_res.hrc"
36 #include <com/sun/star/sdbc/ColumnValue.hpp>
37 #include <com/sun/star/sdbc/XRow.hpp>
38 #include <com/sun/star/sdbc/TransactionIsolation.hpp>
40 #include <comphelper/officeresourcebundle.hxx>
41 #include <comphelper/processfactory.hxx>
43 #if OSL_DEBUG_LEVEL > 0
44 # define OUtoCStr( x ) ( OUStringToOString ( (x), RTL_TEXTENCODING_ASCII_US).getStr())
45 #else /* OSL_DEBUG_LEVEL */
46 # define OUtoCStr( x ) ("dummy")
47 #endif /* OSL_DEBUG_LEVEL */
49 extern "C" SAL_DLLPUBLIC_EXPORT
void* SAL_CALL
OMozabConnection_CreateInstance(
52 return (new connectivity::mozab::OConnection( reinterpret_cast<connectivity::mozab::MozabDriver
*>(_pDriver
) ));
55 using namespace dbtools
;
58 using namespace com::sun::star::uno
;
59 using namespace com::sun::star::lang
;
60 using namespace com::sun::star::beans
;
61 using namespace com::sun::star::sdbc
;
62 using namespace com::sun::star::sdbcx
;
65 namespace connectivity
{ namespace mozab
{
68 // = ConnectionImplData
70 struct ConnectionImplData
72 ::boost::shared_ptr
< ::comphelper::OfficeResourceBundle
> pResourceBundle
;
79 const sal_Char
* getSdbcScheme( SdbcScheme _eScheme
)
83 case SDBC_MOZILLA
: return "mozilla";
84 case SDBC_THUNDERBIRD
: return "thunderbird";
85 case SDBC_LDAP
: return "ldap";
86 case SDBC_OUTLOOK_MAPI
: return "outlook";
87 case SDBC_OUTLOOK_EXPRESS
: return "outlookexp";
92 OUString
OConnection::getDriverImplementationName()
94 return OUString(MOZAB_DRIVER_IMPL_NAME
);
98 const sal_Char
* getSchemeURI( MozillaScheme _eScheme
)
102 case SCHEME_MOZILLA
: return "moz-abdirectory://";
103 case SCHEME_MOZILLA_MDB
: return "moz-abmdbdirectory://";
104 case SCHEME_LDAP
: return "moz-abldapdirectory://";
105 case SCHEME_OUTLOOK_MAPI
: return "moz-aboutlookdirectory://op/";
106 case SCHEME_OUTLOOK_EXPRESS
: return "moz-aboutlookdirectory://oe/";
113 OConnection::OConnection(MozabDriver
* _pDriver
)
114 :OSubComponent
<OConnection
, OConnection_BASE
>((::cppu::OWeakObject
*)_pDriver
, this)
116 ,m_pImplData( new ConnectionImplData
)
117 ,m_aColumnAlias( _pDriver
->getMSFactory() )
118 ,m_nMaxResultRecords( -1 )
120 ,m_eSDBCAddressType(SDBCAddress::Unknown
)
121 ,m_bForceLoadTable(false)
123 m_pDriver
->acquire();
127 OConnection::~OConnection()
132 m_pDriver
->release();
136 void SAL_CALL
OConnection::release() throw()
142 void OConnection::construct(const OUString
& url
,const Sequence
< PropertyValue
>& info
) throw(SQLException
)
144 OSL_TRACE("IN OConnection::construct()" );
148 // Skip 'sdbc:mozab: part of URL
150 sal_Int32 nLen
= url
.indexOf(':');
151 nLen
= url
.indexOf(':',nLen
+1);
152 OSL_ENSURE( url
.copy( 0, nLen
) == "sdbc:address", "OConnection::construct: invalid start of the URI - should never have survived XDriver::acceptsURL!" );
154 OUString
aAddrbookURI(url
.copy(nLen
+1));
156 nLen
= aAddrbookURI
.indexOf(':');
157 OUString aAddrbookScheme
;
158 OUString sAdditionalInfo
;
161 // There isn't any subschema: - but could be just subschema
162 if ( !aAddrbookURI
.isEmpty() )
164 aAddrbookScheme
= aAddrbookURI
;
168 OSL_TRACE( "No subschema given!!!");
169 throwSQLException( STR_URI_SYNTAX_ERROR
, *this );
174 aAddrbookScheme
= aAddrbookURI
.copy(0, nLen
);
175 sAdditionalInfo
= aAddrbookURI
.copy( nLen
+ 1 );
178 OSL_TRACE("URI = %s", ((OUtoCStr(aAddrbookURI
)) ? (OUtoCStr(aAddrbookURI
)):("NULL")) );
179 OSL_TRACE("Scheme = %s\n", ((OUtoCStr(aAddrbookScheme
)) ? (OUtoCStr(aAddrbookScheme
)):("NULL")) );
182 // Now we have a URI convert it to a MozillaURI
184 // The Mapping being used is:
187 // "sdbc:address:mozilla:" -> abdirectory://
189 // "sdbc:address:ldap:" -> abldapdirectory://
190 // * for Outlook (using MAPI API)
191 // "sdbc:address:outlook:" -> aboutlookdirectory://op/
192 // * for windows system address book
193 // "sdbc:address:outlookexp:" -> aboutlookdirectory://oe/
197 m_bUseSSL
= sal_False
;
199 if ( aAddrbookScheme
.equalsAscii( getSdbcScheme( SDBC_MOZILLA
) ) ) {
200 m_sMozillaURI
= OUString::createFromAscii( getSchemeURI( SCHEME_MOZILLA
) );
201 m_eSDBCAddressType
= SDBCAddress::Mozilla
;
202 if(!sAdditionalInfo
.isEmpty())
203 m_sMozillaProfile
= sAdditionalInfo
;
206 if ( aAddrbookScheme
.equalsAscii( getSdbcScheme( SDBC_THUNDERBIRD
) ) ) {
207 //Yes. I am sure it is SCHEME_MOZILLA
208 m_sMozillaURI
= OUString::createFromAscii( getSchemeURI( SCHEME_MOZILLA
) );
209 m_eSDBCAddressType
= SDBCAddress::ThunderBird
;
210 if(!sAdditionalInfo
.isEmpty())
211 m_sMozillaProfile
= sAdditionalInfo
;
213 else if ( aAddrbookScheme
.equalsAscii( getSdbcScheme( SDBC_LDAP
) ) ) {
215 sal_Int32 nPortNumber
= -1;
217 m_sMozillaURI
= OUString::createFromAscii( getSchemeURI( SCHEME_LDAP
) );
218 m_eSDBCAddressType
= SDBCAddress::LDAP
;
220 if ( m_sHostName
.isEmpty() )
222 // see whether the URI contains a hostname/port
223 if ( !sAdditionalInfo
.isEmpty() )
225 sal_Int32 nPortSeparator
= sAdditionalInfo
.indexOf( ':' );
226 if ( nPortSeparator
== -1 )
227 m_sHostName
= sAdditionalInfo
;
230 m_sHostName
= sAdditionalInfo
.copy( 0, nPortSeparator
);
231 nPortNumber
= sAdditionalInfo
.copy( nPortSeparator
+ 1 ).toInt32();
232 OSL_ENSURE( nPortNumber
!= 0, "OConnection::construct: invalid LDAP port number in the URL!" );
233 if ( nPortNumber
== 0 )
239 const PropertyValue
* pInfo
= info
.getConstArray();
240 const PropertyValue
* pInfoEnd
= pInfo
+ info
.getLength();
242 for (; pInfo
!= pInfoEnd
; ++pInfo
)
244 OSL_TRACE( "info[%d].Name = %s", pInfo
- info
.getConstArray(), OUtoCStr( pInfo
->Name
) );
246 if ( pInfo
->Name
.equalsAscii("HostName") )
248 pInfo
->Value
>>= m_sHostName
;
250 else if ( pInfo
->Name
.equalsAscii("BaseDN") )
252 pInfo
->Value
>>= sBaseDN
;
254 else if ( pInfo
->Name
.equalsAscii("user") )
256 pInfo
->Value
>>= m_sBindDN
;
258 else if ( pInfo
->Name
.equalsAscii("password") )
260 pInfo
->Value
>>= m_sPassword
;
262 else if ( pInfo
->Name
.equalsAscii("UseSSL") )
264 pInfo
->Value
>>= m_bUseSSL
;
266 else if ( pInfo
->Name
.equalsAscii("PortNumber") )
268 OSL_VERIFY( pInfo
->Value
>>= nPortNumber
);
270 else if ( pInfo
->Name
.equalsAscii("MaxRowCount") )
272 pInfo
->Value
>>= m_nMaxResultRecords
;
276 if ( !m_sHostName
.isEmpty() ) {
277 m_sMozillaURI
+= m_sHostName
;
280 throwSQLException( STR_NO_HOSTNAME
, *this );
282 if ( nPortNumber
> 0 ) {
283 m_sMozillaURI
+= ":";
284 m_sMozillaURI
+= OUString::number( nPortNumber
);
287 if ( !sBaseDN
.isEmpty() ) {
288 m_sMozillaURI
+= "/";
289 m_sMozillaURI
+= sBaseDN
;
292 throwSQLException( STR_NO_BASEDN
, *this );
294 // Addition of a fake query to enable the Mozilla LDAP directory to work correctly.
295 m_sMozillaURI
+= "?(or(DisplayName,=,DontDoThisAtHome)))";
298 else if ( aAddrbookScheme
.equalsAscii( getSdbcScheme( SDBC_OUTLOOK_MAPI
) ) ) {
299 m_sMozillaURI
= OUString::createFromAscii( getSchemeURI( SCHEME_OUTLOOK_MAPI
) );
300 m_eSDBCAddressType
= SDBCAddress::Outlook
;
302 else if ( aAddrbookScheme
.equalsAscii( getSdbcScheme( SDBC_OUTLOOK_EXPRESS
) ) ) {
303 m_sMozillaURI
= OUString::createFromAscii( getSchemeURI( SCHEME_OUTLOOK_EXPRESS
) );
304 m_eSDBCAddressType
= SDBCAddress::OutlookExp
;
308 OSL_TRACE("Invalid subschema given!!!");
309 throwSQLException( STR_URI_SYNTAX_ERROR
, *this );
312 OSL_TRACE("Moz URI = %s, %s", ((OUtoCStr(m_sMozillaURI
)) ? (OUtoCStr(m_sMozillaURI
)):("NULL")), usesFactory() ? "uses factory" : "no factory");
313 OSL_TRACE( "\tOUT OConnection::construct()\n" );
315 MDatabaseMetaDataHelper _aDbHelper
;
317 // The creation of the nsIAbDirectory i/f for LDAP doesn't actually test
318 // the validity of the connection, it's normally delayed until the query
319 // is executed, but it's a bit late then to fail...
322 if ( !_aDbHelper
.testLDAPConnection( this ) )
324 OSL_TRACE("testLDAPConnection : FAILED" );
325 throwSQLException( _aDbHelper
.getError(), *this );
329 OSL_TRACE("testLDAPConnection : SUCCESS" );
333 // Test connection by getting to get the Table Names
334 ::std::vector
< OUString
> tables
;
335 ::std::vector
< OUString
> types
;
336 if ( !_aDbHelper
.getTableStrings( this, tables
, types
) )
338 throwSQLException( _aDbHelper
.getError(), *this );
344 IMPLEMENT_SERVICE_INFO(OConnection
, "com.sun.star.sdbc.drivers.mozab.OConnection", "com.sun.star.sdbc.Connection")
347 Reference
< XStatement
> SAL_CALL
OConnection::createStatement( ) throw(SQLException
, RuntimeException
)
349 ::osl::MutexGuard
aGuard( m_aMutex
);
350 checkDisposed(OConnection_BASE::rBHelper
.bDisposed
);
352 // create a statement
353 // the statement can only be executed once
354 Reference
< XStatement
> xReturn
= new OStatement(this);
355 m_aStatements
.push_back(WeakReferenceHelper(xReturn
));
359 Reference
< XPreparedStatement
> SAL_CALL
OConnection::prepareStatement( const OUString
& _sSql
) throw(SQLException
, RuntimeException
)
361 ::osl::MutexGuard
aGuard( m_aMutex
);
362 checkDisposed(OConnection_BASE::rBHelper
.bDisposed
);
364 OSL_TRACE("OConnection::prepareStatement( %s )", OUtoCStr( _sSql
) );
366 // create a statement
367 // the statement can only be executed more than once
368 OPreparedStatement
* pPrepared
= new OPreparedStatement(this,_sSql
);
369 Reference
< XPreparedStatement
> xReturn
= pPrepared
;
370 pPrepared
->lateInit();
372 m_aStatements
.push_back(WeakReferenceHelper(xReturn
));
376 Reference
< XPreparedStatement
> SAL_CALL
OConnection::prepareCall( const OUString
& _sSql
) throw(SQLException
, RuntimeException
)
379 ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::prepareCall", *this );
380 OSL_TRACE("OConnection::prepareCall( %s )", OUtoCStr( _sSql
) );
384 OUString SAL_CALL
OConnection::nativeSQL( const OUString
& _sSql
) throw(SQLException
, RuntimeException
)
386 ::osl::MutexGuard
aGuard( m_aMutex
);
387 // when you need to transform SQL92 to you driver specific you can do it here
388 OSL_TRACE("OConnection::nativeSQL( %s )", OUtoCStr( _sSql
) );
393 void SAL_CALL
OConnection::setAutoCommit( sal_Bool
/*autoCommit*/ ) throw(SQLException
, RuntimeException
)
395 ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::setAutoCommit", *this );
398 sal_Bool SAL_CALL
OConnection::getAutoCommit( ) throw(SQLException
, RuntimeException
)
400 // you have to distinguish which if you are in autocommit mode or not
401 // at normal case true should be fine here
406 void SAL_CALL
OConnection::commit( ) throw(SQLException
, RuntimeException
)
408 // when you database does support transactions you should commit here
411 void SAL_CALL
OConnection::rollback( ) throw(SQLException
, RuntimeException
)
413 // same as commit but for the other case
416 sal_Bool SAL_CALL
OConnection::isClosed( ) throw(SQLException
, RuntimeException
)
418 ::osl::MutexGuard
aGuard( m_aMutex
);
420 // just simple -> we are close when we are disposed that means someone called dispose(); (XComponent)
421 return OConnection_BASE::rBHelper
.bDisposed
;
424 Reference
< XDatabaseMetaData
> SAL_CALL
OConnection::getMetaData( ) throw(SQLException
, RuntimeException
)
426 ::osl::MutexGuard
aGuard( m_aMutex
);
427 checkDisposed(OConnection_BASE::rBHelper
.bDisposed
);
429 // here we have to create the class with biggest interface
430 // The answer is 42 :-)
431 Reference
< XDatabaseMetaData
> xMetaData
= m_xMetaData
;
434 xMetaData
= new ODatabaseMetaData(this); // need the connection because it can return it
435 m_xMetaData
= xMetaData
;
441 void SAL_CALL
OConnection::setReadOnly( sal_Bool
/*readOnly*/ ) throw(SQLException
, RuntimeException
)
443 ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::setReadOnly", *this );
446 sal_Bool SAL_CALL
OConnection::isReadOnly( ) throw(SQLException
, RuntimeException
)
448 // return if your connection to readonly
452 void SAL_CALL
OConnection::setCatalog( const OUString
& /*catalog*/ ) throw(SQLException
, RuntimeException
)
454 ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::setCatalog", *this );
457 OUString SAL_CALL
OConnection::getCatalog( ) throw(SQLException
, RuntimeException
)
459 // return your current catalog
463 void SAL_CALL
OConnection::setTransactionIsolation( sal_Int32
/*level*/ ) throw(SQLException
, RuntimeException
)
465 ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::setTransactionIsolation", *this );
468 sal_Int32 SAL_CALL
OConnection::getTransactionIsolation( ) throw(SQLException
, RuntimeException
)
470 // please have a look at @see com.sun.star.sdbc.TransactionIsolation
471 return TransactionIsolation::NONE
;
474 Reference
< ::com::sun::star::container::XNameAccess
> SAL_CALL
OConnection::getTypeMap( ) throw(SQLException
, RuntimeException
)
476 // if your driver has special database types you can return it here
480 void SAL_CALL
OConnection::setTypeMap( const Reference
< ::com::sun::star::container::XNameAccess
>& /*typeMap*/ ) throw(SQLException
, RuntimeException
)
482 ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::setTypeMap", *this );
486 void SAL_CALL
OConnection::close( ) throw(SQLException
, RuntimeException
)
488 // we just dispose us
490 ::osl::MutexGuard
aGuard( m_aMutex
);
491 checkDisposed(OConnection_BASE::rBHelper
.bDisposed
);
498 Any SAL_CALL
OConnection::getWarnings( ) throw(SQLException
, RuntimeException
)
500 // when you collected some warnings -> return it
504 void SAL_CALL
OConnection::clearWarnings( ) throw(SQLException
, RuntimeException
)
506 // you should clear your collected warnings here
509 void OConnection::disposing()
511 // we noticed that we should be destroied in near future so we have to dispose our statements
512 ::osl::MutexGuard
aGuard(m_aMutex
);
514 m_pImplData
->pResourceBundle
.reset();
516 OConnection_BASE::disposing();
517 if ( m_aNameMapper
) {
518 MQuery::FreeNameMapper( m_aNameMapper
);
519 m_aNameMapper
= NULL
;
526 Reference
< XTablesSupplier
> SAL_CALL
OConnection::createCatalog()
528 OSL_TRACE("IN OConnection::createCatalog()" );
529 ::osl::MutexGuard
aGuard( m_aMutex
);
530 Reference
< XTablesSupplier
> xTab
= m_xCatalog
;
533 OCatalog
*pCat
= new OCatalog(this);
537 OSL_TRACE( "\tOUT OConnection::createCatalog()" );
542 MNameMapper
* OConnection::getNameMapper ()
544 if (m_aNameMapper
==NULL
)
545 m_aNameMapper
= MQuery::CreateNameMapper();
547 return m_aNameMapper
;
551 void OConnection::throwSQLException( const ErrorDescriptor
& _rError
, const Reference
< XInterface
>& _rxContext
)
553 if ( _rError
.getResId() != 0 )
555 OSL_ENSURE( ( _rError
.getErrorCondition() == 0 ),
556 "OConnection::throwSQLException: unsupported error code combination!" );
558 OUString
sParameter( _rError
.getParameter() );
559 if ( !sParameter
.isEmpty() )
561 const OUString
sError( getResources().getResourceStringWithSubstitution(
565 ::dbtools::throwGenericSQLException( sError
, _rxContext
);
566 OSL_FAIL( "OConnection::throwSQLException: unreachable (1)!" );
569 throwGenericSQLException( _rError
.getResId(), _rxContext
);
570 OSL_FAIL( "OConnection::throwSQLException: unreachable (2)!" );
573 if ( _rError
.getErrorCondition() != 0 )
575 SQLError
aErrorHelper( comphelper::getComponentContext(getDriver()->getMSFactory()) );
576 OUString
sParameter( _rError
.getParameter() );
577 if ( !sParameter
.isEmpty() )
578 aErrorHelper
.raiseException( _rError
.getErrorCondition(), _rxContext
, sParameter
);
580 aErrorHelper
.raiseException( _rError
.getErrorCondition(), _rxContext
);
581 OSL_FAIL( "OConnection::throwSQLException: unreachable (3)!" );
584 throwGenericSQLException( STR_UNSPECIFIED_ERROR
, _rxContext
);
588 void OConnection::throwSQLException( const sal_uInt16 _nErrorResourceId
, const Reference
< XInterface
>& _rxContext
)
590 ErrorDescriptor aError
;
591 aError
.setResId( _nErrorResourceId
);
592 throwSQLException( aError
, _rxContext
);
595 } } // namespace connectivity::mozab
597 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */