xref: /AOO41X/main/connectivity/source/drivers/hsqldb/HDriver.cxx (revision 9b5730f6ddef7eb82608ca4d31dc0d7678e652cf)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_connectivity.hxx"
26 #include "hsqldb/HDriver.hxx"
27 #include "hsqldb/HConnection.hxx"
28 #include <osl/diagnose.h>
29 #include "connectivity/dbexception.hxx"
30 #include <com/sun/star/sdbc/XDriverAccess.hpp>
31 #include <com/sun/star/sdbc/XResultSet.hpp>
32 #include <com/sun/star/sdbc/XRow.hpp>
33 #include <com/sun/star/embed/XTransactionBroadcaster.hpp>
34 #include <com/sun/star/embed/ElementModes.hpp>
35 #include "TConnection.hxx"
36 #include "hsqldb/HStorageMap.hxx"
37 #include <jvmfwk/framework.h>
38 #include <com/sun/star/reflection/XProxyFactory.hpp>
39 #include <com/sun/star/embed/XStorage.hpp>
40 #include <com/sun/star/frame/XDesktop.hpp>
41 #include <com/sun/star/lang/Locale.hpp>
42 #include <com/sun/star/util/XFlushable.hpp>
43 #include "HTerminateListener.hxx"
44 #include "hsqldb/HCatalog.hxx"
45 #include "diagnose_ex.h"
46 #include <rtl/ustrbuf.hxx>
47 #include <osl/file.h>
48 #include <osl/process.h>
49 #include <connectivity/dbexception.hxx>
50 #include <comphelper/namedvaluecollection.hxx>
51 #include <unotools/confignode.hxx>
52 #include <unotools/ucbstreamhelper.hxx>
53 #include "resource/hsqldb_res.hrc"
54 #include "resource/sharedresources.hxx"
55 
56 //........................................................................
57 namespace connectivity
58 {
59 //........................................................................
60     using namespace hsqldb;
61     using namespace ::com::sun::star::uno;
62     using namespace ::com::sun::star::sdbc;
63     using namespace ::com::sun::star::sdbcx;
64     using namespace ::com::sun::star::beans;
65     using namespace ::com::sun::star::frame;
66     using namespace ::com::sun::star::lang;
67     using namespace ::com::sun::star::embed;
68     using namespace ::com::sun::star::io;
69     using namespace ::com::sun::star::task;
70     using namespace ::com::sun::star::util;
71     using namespace ::com::sun::star::reflection;
72 
73     namespace hsqldb
74     {
ODriverDelegator_CreateInstance(const Reference<::com::sun::star::lang::XMultiServiceFactory> & _rxFac)75         Reference< XInterface >  SAL_CALL ODriverDelegator_CreateInstance(const Reference< ::com::sun::star::lang::XMultiServiceFactory >& _rxFac) throw( Exception )
76         {
77             return *(new ODriverDelegator(_rxFac));
78         }
79     }
80 
81 
82 
83     //====================================================================
84     //= ODriverDelegator
85     //====================================================================
86     //--------------------------------------------------------------------
ODriverDelegator(const Reference<XMultiServiceFactory> & _rxFactory)87     ODriverDelegator::ODriverDelegator(const Reference< XMultiServiceFactory >& _rxFactory)
88         : ODriverDelegator_BASE(m_aMutex)
89         ,m_xFactory(_rxFactory)
90         ,m_bInShutDownConnections(sal_False)
91     {
92     }
93 
94     //--------------------------------------------------------------------
~ODriverDelegator()95     ODriverDelegator::~ODriverDelegator()
96     {
97         try
98         {
99             ::comphelper::disposeComponent(m_xDriver);
100         }
101         catch(const Exception&)
102         {
103         }
104     }
105 
106     // --------------------------------------------------------------------------------
disposing()107     void SAL_CALL ODriverDelegator::disposing()
108     {
109         ::osl::MutexGuard aGuard(m_aMutex);
110 
111         try
112         {
113             for (TWeakPairVector::iterator i = m_aConnections.begin(); m_aConnections.end() != i; ++i)
114             {
115                 Reference<XInterface > xTemp = i->first.get();
116                 ::comphelper::disposeComponent(xTemp);
117             }
118         }
119         catch(Exception&)
120         {
121             // not interested in
122         }
123         m_aConnections.clear();
124         TWeakPairVector().swap(m_aConnections);
125 
126         cppu::WeakComponentImplHelperBase::disposing();
127     }
128     //--------------------------------------------------------------------
loadDriver()129     Reference< XDriver > ODriverDelegator::loadDriver( )
130     {
131         if ( !m_xDriver.is() )
132         {
133             ::rtl::OUString sURL(RTL_CONSTASCII_USTRINGPARAM("jdbc:hsqldb:db"));
134             Reference<XDriverAccess> xDriverAccess(m_xFactory->createInstance(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.sdbc.DriverManager")) ),UNO_QUERY);
135             OSL_ENSURE(xDriverAccess.is(),"Could not load driver manager!");
136             if ( xDriverAccess.is() )
137                 m_xDriver = xDriverAccess->getDriverByURL(sURL);
138         }
139 
140         return m_xDriver;
141     }
142 
143     //--------------------------------------------------------------------
144     namespace
145     {
lcl_getPermittedJavaMethods_nothrow(const Reference<XMultiServiceFactory> & _rxORB)146         ::rtl::OUString lcl_getPermittedJavaMethods_nothrow( const Reference< XMultiServiceFactory >& _rxORB )
147         {
148             ::rtl::OUStringBuffer aConfigPath;
149             aConfigPath.appendAscii( "/org.openoffice.Office.DataAccess/DriverSettings/" );
150             aConfigPath.append     ( ODriverDelegator::getImplementationName_Static() );
151             aConfigPath.appendAscii( "/PermittedJavaMethods" );
152             ::utl::OConfigurationTreeRoot aConfig( ::utl::OConfigurationTreeRoot::createWithServiceFactory(
153                 _rxORB, aConfigPath.makeStringAndClear() ) );
154 
155             ::rtl::OUStringBuffer aPermittedMethods;
156             Sequence< ::rtl::OUString > aNodeNames( aConfig.getNodeNames() );
157             for (   const ::rtl::OUString* pNodeNames = aNodeNames.getConstArray();
158                     pNodeNames != aNodeNames.getConstArray() + aNodeNames.getLength();
159                     ++pNodeNames
160                 )
161             {
162                 ::rtl::OUString sPermittedMethod;
163                 OSL_VERIFY( aConfig.getNodeValue( *pNodeNames ) >>= sPermittedMethod );
164 
165                 if ( aPermittedMethods.getLength() )
166                     aPermittedMethods.append( (sal_Unicode)';' );
167                 aPermittedMethods.append( sPermittedMethod );
168             }
169 
170             return aPermittedMethods.makeStringAndClear();;
171         }
172     }
173 
174     //--------------------------------------------------------------------
connect(const::rtl::OUString & url,const Sequence<PropertyValue> & info)175     Reference< XConnection > SAL_CALL ODriverDelegator::connect( const ::rtl::OUString& url, const Sequence< PropertyValue >& info ) throw (SQLException, RuntimeException)
176     {
177         Reference< XConnection > xConnection;
178         if ( acceptsURL(url) )
179         {
180             Reference< XDriver > xDriver = loadDriver();
181             if ( xDriver.is() )
182             {
183                 ::rtl::OUString sURL;
184                 Reference<XStorage> xStorage;
185                 const PropertyValue* pIter = info.getConstArray();
186                 const PropertyValue* pEnd = pIter + info.getLength();
187 
188                 for (;pIter != pEnd; ++pIter)
189                 {
190                     if ( pIter->Name.equalsAscii("Storage") )
191                     {
192                         xStorage.set(pIter->Value,UNO_QUERY);
193                     }
194                     else if ( pIter->Name.equalsAscii("URL") )
195                     {
196                         pIter->Value >>= sURL;
197                     }
198                 }
199 
200                 if ( !xStorage.is() || !sURL.getLength() )
201                 {
202                     ::connectivity::SharedResources aResources;
203                     const ::rtl::OUString sMessage = aResources.getResourceString(STR_NO_STROAGE);
204                     ::dbtools::throwGenericSQLException(sMessage ,*this);
205                 }
206 
207                 ::rtl::OUString sSystemPath;
208                 osl_getSystemPathFromFileURL( sURL.pData, &sSystemPath.pData );
209                 sal_Int32 nIndex = sSystemPath.lastIndexOf('.');
210                 if ( !sURL.getLength() || !sSystemPath.getLength() )
211                 {
212                     ::connectivity::SharedResources aResources;
213                     const ::rtl::OUString sMessage = aResources.getResourceString(STR_INVALID_FILE_URL);
214                     ::dbtools::throwGenericSQLException(sMessage ,*this);
215                 }
216 
217                 bool bIsNewDatabase = !xStorage->hasElements();
218 
219                 ::comphelper::NamedValueCollection aProperties;
220 
221                 // properties for accessing the embedded storage
222                 ::rtl::OUString sConnPartURL = sSystemPath.copy( 0, ::std::max< sal_Int32 >( nIndex, sSystemPath.getLength() ) );
223                 ::rtl::OUString sKey = StorageContainer::registerStorage( xStorage, sConnPartURL );
224                 aProperties.put( "storage_key", sKey );
225                 aProperties.put( "storage_class_name",
226                     ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.sdbcx.comp.hsqldb.StorageAccess" ) ) );
227                 aProperties.put( "fileaccess_class_name",
228                     ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.sdbcx.comp.hsqldb.StorageFileAccess" ) ) );
229 
230                 // JDBC driver and driver's classpath
231                 aProperties.put( "JavaDriverClass",
232                     ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "org.hsqldb.jdbcDriver" ) ) );
233                 aProperties.put( "JavaDriverClassPath",
234                     ::rtl::OUString(
235 #ifdef SYSTEM_HSQLDB
236                         RTL_CONSTASCII_USTRINGPARAM(HSQLDB_JAR
237                         " vnd.sun.star.expand:$OOO_BASE_DIR/program/classes/sdbc_hsqldb.jar" )
238 #else
239                         RTL_CONSTASCII_USTRINGPARAM("vnd.sun.star.expand:$OOO_BASE_DIR/program/classes/hsqldb.jar"
240                         " vnd.sun.star.expand:$OOO_BASE_DIR/program/classes/sdbc_hsqldb.jar" )
241 #endif
242                         ) );
243 
244                 // auto increment handling
245                 aProperties.put( "IsAutoRetrievingEnabled", true );
246                 aProperties.put( "AutoRetrievingStatement",
247                     ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CALL IDENTITY()" ) ) );
248                 aProperties.put( "IgnoreDriverPrivileges", true );
249 
250                 // don't want to expose HSQLDB's schema capabilities which exist since 1.8.0RC10
251                 aProperties.put( "default_schema",
252                     ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "true" ) ) );
253 
254                 // security: permitted Java classes
255                 NamedValue aPermittedClasses(
256                     ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "hsqldb.method_class_names" ) ),
257                     makeAny( lcl_getPermittedJavaMethods_nothrow( m_xFactory ) )
258                 );
259                 aProperties.put( "SystemProperties", Sequence< NamedValue >( &aPermittedClasses, 1 ) );
260 
261                 const ::rtl::OUString sProperties( RTL_CONSTASCII_USTRINGPARAM( "properties" ) );
262                 ::rtl::OUString sMessage;
263                 try
264                 {
265                     if ( !bIsNewDatabase && xStorage->isStreamElement(sProperties) )
266                     {
267                         Reference<XStream > xStream = xStorage->openStreamElement(sProperties,ElementModes::READ);
268                         if ( xStream.is() )
269                         {
270                             ::std::auto_ptr<SvStream> pStream( ::utl::UcbStreamHelper::CreateStream(xStream) );
271                             if ( pStream.get() )
272                             {
273                                 ByteString sLine;
274                                 ByteString sVersionString;
275                                 while ( pStream->ReadLine(sLine) )
276                                 {
277                                     if ( sLine.Len() == 0 )
278                                         continue;
279                                     const ByteString sIniKey = sLine.GetToken( 0, '=' );
280                                     const ByteString sValue = sLine.GetToken( 1, '=' );
281                                     if ( sIniKey.Equals( "hsqldb.compatible_version" ) )
282                                     {
283                                         sVersionString = sValue;
284                                     }
285                                     else
286                                     {
287                                         if  (   sIniKey.Equals( "version" )
288                                             &&  ( sVersionString.Len() == 0 )
289                                             )
290                                         {
291                                             sVersionString = sValue;
292                                         }
293                                     }
294                                 }
295                                 if ( sVersionString.Len() )
296                                 {
297                                     const sal_Int32 nMajor = sVersionString.GetToken(0,'.').ToInt32();
298                                     const sal_Int32 nMinor = sVersionString.GetToken(1,'.').ToInt32();
299                                     const sal_Int32 nMicro = sVersionString.GetToken(2,'.').ToInt32();
300                                     if (     nMajor > 1
301                                         || ( nMajor == 1 && nMinor > 8 )
302                                         || ( nMajor == 1 && nMinor == 8 && nMicro > 0 ) )
303                                     {
304                                         ::connectivity::SharedResources aResources;
305                                         sMessage = aResources.getResourceString(STR_ERROR_NEW_VERSION);
306                                     }
307                                 }
308                             }
309                         } // if ( xStream.is() )
310                         ::comphelper::disposeComponent(xStream);
311                     }
312                 }
313                 catch(Exception&)
314                 {
315                 }
316                 if ( sMessage.getLength() )
317                 {
318                     ::dbtools::throwGenericSQLException(sMessage ,*this);
319                 }
320 
321                 // readonly?
322                 Reference<XPropertySet> xProp(xStorage,UNO_QUERY);
323                 if ( xProp.is() )
324                 {
325                     sal_Int32 nMode = 0;
326                     xProp->getPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("OpenMode"))) >>= nMode;
327                     if ( (nMode & ElementModes::WRITE) != ElementModes::WRITE )
328                     {
329                         aProperties.put( "readonly", ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "true" ) ) );
330                     }
331                 }
332 
333                 Sequence< PropertyValue > aConnectionArgs;
334                 aProperties >>= aConnectionArgs;
335 
336                 ::rtl::OUString sConnectURL(RTL_CONSTASCII_USTRINGPARAM("jdbc:hsqldb:"));
337 
338                 sConnectURL += sConnPartURL;
339                 Reference<XConnection> xOrig;
340                 try
341                 {
342                     xOrig = xDriver->connect( sConnectURL, aConnectionArgs );
343                 }
344                 catch(const Exception& e)
345                 {
346                     StorageContainer::revokeStorage(sKey,NULL);
347                     (void)e;
348                     throw;
349                 }
350 
351                 // if the storage is completely empty, then we just created a new HSQLDB
352                 // In this case, do some initializations.
353                 if ( bIsNewDatabase && xOrig.is() )
354                     onConnectedNewDatabase( xOrig );
355 
356                 if ( xOrig.is() )
357                 {
358                     OMetaConnection* pMetaConnection = NULL;
359                     // now we have to set the URL to get the correct answer for metadata()->getURL()
360                     Reference< XUnoTunnel> xTunnel(xOrig,UNO_QUERY);
361                     if ( xTunnel.is() )
362                     {
363                         pMetaConnection = reinterpret_cast<OMetaConnection*>(xTunnel->getSomething( OMetaConnection::getUnoTunnelImplementationId() ));
364                         if ( pMetaConnection )
365                             pMetaConnection->setURL(url);
366                     }
367 
368                     Reference<XComponent> xComp(xOrig,UNO_QUERY);
369                     if ( xComp.is() )
370                         xComp->addEventListener(this);
371 
372                     // we want to close all connections when the office shuts down
373                     static Reference< XTerminateListener> s_xTerminateListener;
374                     if( !s_xTerminateListener.is() )
375                     {
376                         Reference< XDesktop > xDesktop( m_xFactory->createInstance( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.frame.Desktop")) ), UNO_QUERY );
377 
378                         if( xDesktop.is() )
379                         {
380                             s_xTerminateListener = new OConnectionController(this);
381                             xDesktop->addTerminateListener(s_xTerminateListener);
382                         }
383                     }
384                     Reference< XComponent> xIfc = new OHsqlConnection( this, xOrig, m_xFactory );
385                     xConnection.set(xIfc,UNO_QUERY);
386                     m_aConnections.push_back(TWeakPair(WeakReferenceHelper(xOrig),TWeakConnectionPair(sKey,TWeakRefPair(WeakReferenceHelper(xConnection),WeakReferenceHelper()))));
387 
388                     Reference<XTransactionBroadcaster> xBroad(xStorage,UNO_QUERY);
389                     if ( xBroad.is() )
390                     {
391                         Reference<XTransactionListener> xListener(*this,UNO_QUERY);
392                         xBroad->addTransactionListener(xListener);
393                     }
394                 }
395             }
396         }
397         return xConnection;
398     }
399 
400     //--------------------------------------------------------------------
acceptsURL(const::rtl::OUString & url)401     sal_Bool SAL_CALL ODriverDelegator::acceptsURL( const ::rtl::OUString& url ) throw (SQLException, RuntimeException)
402     {
403         sal_Bool bEnabled = sal_False;
404         OSL_VERIFY_EQUALS( jfw_getEnabled( &bEnabled ), JFW_E_NONE, "error in jfw_getEnabled" );
405         return bEnabled  && url.compareToAscii("sdbc:embedded:hsqldb",sizeof("sdbc:embedded:hsqldb")) == 0;
406     }
407 
408     //--------------------------------------------------------------------
getPropertyInfo(const::rtl::OUString & url,const Sequence<PropertyValue> &)409     Sequence< DriverPropertyInfo > SAL_CALL ODriverDelegator::getPropertyInfo( const ::rtl::OUString& url, const Sequence< PropertyValue >& /*info*/ ) throw (SQLException, RuntimeException)
410     {
411         if ( !acceptsURL(url) )
412             return Sequence< DriverPropertyInfo >();
413         ::std::vector< DriverPropertyInfo > aDriverInfo;
414         aDriverInfo.push_back(DriverPropertyInfo(
415                 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Storage"))
416                 ,::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Defines the storage where the database will be stored."))
417                 ,sal_True
418                 ,::rtl::OUString()
419                 ,Sequence< ::rtl::OUString >())
420                 );
421         aDriverInfo.push_back(DriverPropertyInfo(
422                 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("URL"))
423                 ,::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Defines the url of the data source."))
424                 ,sal_True
425                 ,::rtl::OUString()
426                 ,Sequence< ::rtl::OUString >())
427                 );
428         aDriverInfo.push_back(DriverPropertyInfo(
429                 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AutoRetrievingStatement"))
430                 ,::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Defines the statement which will be executed to retrieve auto increment values."))
431                 ,sal_False
432                 ,::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CALL IDENTITY()"))
433                 ,Sequence< ::rtl::OUString >())
434                 );
435         return Sequence< DriverPropertyInfo >(&aDriverInfo[0],aDriverInfo.size());
436     }
437 
438     //--------------------------------------------------------------------
getMajorVersion()439     sal_Int32 SAL_CALL ODriverDelegator::getMajorVersion(  ) throw (RuntimeException)
440     {
441         return 1;
442     }
443 
444     //--------------------------------------------------------------------
getMinorVersion()445     sal_Int32 SAL_CALL ODriverDelegator::getMinorVersion(  ) throw (RuntimeException)
446     {
447         return 0;
448     }
449 
450     //--------------------------------------------------------------------
getDataDefinitionByConnection(const Reference<XConnection> & connection)451     Reference< XTablesSupplier > SAL_CALL ODriverDelegator::getDataDefinitionByConnection( const Reference< XConnection >& connection ) throw (SQLException, RuntimeException)
452     {
453         ::osl::MutexGuard aGuard( m_aMutex );
454         checkDisposed(ODriverDelegator_BASE::rBHelper.bDisposed);
455 
456         Reference< XTablesSupplier > xTab;
457 
458         TWeakPairVector::iterator aEnd = m_aConnections.end();
459         for (TWeakPairVector::iterator i = m_aConnections.begin(); aEnd != i; ++i)
460         {
461             if ( i->second.second.first.get() == connection.get() )
462             {
463                 xTab = Reference< XTablesSupplier >(i->second.second.second.get().get(),UNO_QUERY);
464                 if ( !xTab.is() )
465                 {
466                     xTab = new OHCatalog(connection);
467                     i->second.second.second = WeakReferenceHelper(xTab);
468                 }
469                 break;
470             }
471         }
472 
473         return xTab;
474     }
475 
476     //--------------------------------------------------------------------
getDataDefinitionByURL(const::rtl::OUString & url,const Sequence<PropertyValue> & info)477     Reference< XTablesSupplier > SAL_CALL ODriverDelegator::getDataDefinitionByURL( const ::rtl::OUString& url, const Sequence< PropertyValue >& info ) throw (SQLException, RuntimeException)
478     {
479         if ( ! acceptsURL(url) )
480         {
481             ::connectivity::SharedResources aResources;
482             const ::rtl::OUString sMessage = aResources.getResourceString(STR_URI_SYNTAX_ERROR);
483             ::dbtools::throwGenericSQLException(sMessage ,*this);
484         }
485 
486         return getDataDefinitionByConnection(connect(url,info));
487     }
488 
489     // XServiceInfo
490     // --------------------------------------------------------------------------------
491     //------------------------------------------------------------------------------
getImplementationName_Static()492     rtl::OUString ODriverDelegator::getImplementationName_Static(  ) throw(RuntimeException)
493     {
494         return rtl::OUString::createFromAscii("com.sun.star.sdbcx.comp.hsqldb.Driver");
495     }
496     //------------------------------------------------------------------------------
getSupportedServiceNames_Static()497     Sequence< ::rtl::OUString > ODriverDelegator::getSupportedServiceNames_Static(  ) throw (RuntimeException)
498     {
499         Sequence< ::rtl::OUString > aSNS( 2 );
500         aSNS[0] = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.sdbc.Driver"));
501         aSNS[1] = ::rtl::OUString::createFromAscii("com.sun.star.sdbcx.Driver");
502         return aSNS;
503     }
504     //------------------------------------------------------------------
getImplementationName()505     ::rtl::OUString SAL_CALL ODriverDelegator::getImplementationName(  ) throw(RuntimeException)
506     {
507         return getImplementationName_Static();
508     }
509 
510     //------------------------------------------------------------------
supportsService(const::rtl::OUString & _rServiceName)511     sal_Bool SAL_CALL ODriverDelegator::supportsService( const ::rtl::OUString& _rServiceName ) throw(RuntimeException)
512     {
513         Sequence< ::rtl::OUString > aSupported(getSupportedServiceNames());
514         const ::rtl::OUString* pSupported = aSupported.getConstArray();
515         const ::rtl::OUString* pEnd = pSupported + aSupported.getLength();
516         for (;pSupported != pEnd && !pSupported->equals(_rServiceName); ++pSupported)
517             ;
518 
519         return pSupported != pEnd;
520     }
521     //------------------------------------------------------------------
getSupportedServiceNames()522     Sequence< ::rtl::OUString > SAL_CALL ODriverDelegator::getSupportedServiceNames(  ) throw(RuntimeException)
523     {
524         return getSupportedServiceNames_Static();
525     }
526     //------------------------------------------------------------------
createCatalog(const Sequence<PropertyValue> &)527     void SAL_CALL ODriverDelegator::createCatalog( const Sequence< PropertyValue >& /*info*/ ) throw (SQLException, ::com::sun::star::container::ElementExistException, RuntimeException)
528     {
529         ::dbtools::throwFeatureNotImplementedException( "XCreateCatalog::createCatalog", *this );
530     }
531     //------------------------------------------------------------------
shutdownConnection(const TWeakPairVector::iterator & _aIter)532     void ODriverDelegator::shutdownConnection(const TWeakPairVector::iterator& _aIter )
533     {
534         OSL_ENSURE(m_aConnections.end() != _aIter,"Iterator equals .end()");
535         sal_Bool bLastOne = sal_True;
536         try
537         {
538             Reference<XConnection> _xConnection(_aIter->first.get(),UNO_QUERY);
539 
540             if ( _xConnection.is() )
541             {
542                 Reference<XStatement> xStmt = _xConnection->createStatement();
543                 if ( xStmt.is() )
544                 {
545                     Reference<XResultSet> xRes(xStmt->executeQuery(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("SELECT COUNT(*) FROM INFORMATION_SCHEMA.SYSTEM_SESSIONS WHERE USER_NAME ='SA'"))),UNO_QUERY);
546                     Reference<XRow> xRow(xRes,UNO_QUERY);
547                     if ( xRow.is() && xRes->next() )
548                         bLastOne = xRow->getInt(1) == 1;
549                     if ( bLastOne )
550                         xStmt->execute(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("SHUTDOWN")));
551                 }
552             }
553         }
554         catch(Exception&)
555         {
556         }
557         if ( bLastOne )
558         {
559             // Reference<XTransactionListener> xListener(*this,UNO_QUERY);
560             // a shutdown should commit all changes to the db files
561             StorageContainer::revokeStorage(_aIter->second.first,NULL);
562         }
563         if ( !m_bInShutDownConnections )
564             m_aConnections.erase(_aIter);
565     }
566     //------------------------------------------------------------------
disposing(const::com::sun::star::lang::EventObject & Source)567     void SAL_CALL ODriverDelegator::disposing( const ::com::sun::star::lang::EventObject& Source ) throw(::com::sun::star::uno::RuntimeException)
568     {
569         ::osl::MutexGuard aGuard(m_aMutex);
570         Reference<XConnection> xCon(Source.Source,UNO_QUERY);
571         if ( xCon.is() )
572         {
573             TWeakPairVector::iterator i = m_aConnections.begin();
574             for (; m_aConnections.end() != i; ++i)
575             {
576                 if ( i->first.get() == xCon.get() )
577                 {
578                     shutdownConnection(i);
579                     break;
580                 }
581             }
582         }
583         else
584         {
585             Reference< XStorage> xStorage(Source.Source,UNO_QUERY);
586             if ( xStorage.is() )
587             {
588                 ::rtl::OUString sKey = StorageContainer::getRegisteredKey(xStorage);
589                 TWeakPairVector::iterator i = ::std::find_if(m_aConnections.begin(),m_aConnections.end(),::std::compose1(
590                                 ::std::bind2nd(::std::equal_to< ::rtl::OUString >(),sKey)
591                                 ,::std::compose1(::std::select1st<TWeakConnectionPair>(),::std::select2nd< TWeakPair >())));
592                 if ( i != m_aConnections.end() )
593                     shutdownConnection(i);
594             }
595         }
596     }
597     //------------------------------------------------------------------
shutdownConnections()598     void ODriverDelegator::shutdownConnections()
599     {
600         m_bInShutDownConnections = sal_True;
601         TWeakPairVector::iterator aEnd = m_aConnections.end();
602         for (TWeakPairVector::iterator i = m_aConnections.begin(); aEnd != i; ++i)
603         {
604             try
605             {
606                 Reference<XConnection> xCon(i->first,UNO_QUERY);
607                 ::comphelper::disposeComponent(xCon);
608             }
609             catch(Exception&)
610             {
611             }
612         }
613         m_aConnections.clear();
614         m_bInShutDownConnections = sal_True;
615     }
616     //------------------------------------------------------------------
flushConnections()617     void ODriverDelegator::flushConnections()
618     {
619         TWeakPairVector::iterator aEnd = m_aConnections.end();
620         for (TWeakPairVector::iterator i = m_aConnections.begin(); aEnd != i; ++i)
621         {
622             try
623             {
624                 Reference<XFlushable> xCon(i->second.second.first.get(),UNO_QUERY);
625                 xCon->flush();
626             }
627             catch(Exception&)
628             {
629             }
630         }
631     }
632     //------------------------------------------------------------------
preCommit(const::com::sun::star::lang::EventObject & aEvent)633     void SAL_CALL ODriverDelegator::preCommit( const ::com::sun::star::lang::EventObject& aEvent ) throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException)
634     {
635         ::osl::MutexGuard aGuard(m_aMutex);
636 
637         Reference< XStorage> xStorage(aEvent.Source,UNO_QUERY);
638         ::rtl::OUString sKey = StorageContainer::getRegisteredKey(xStorage);
639         if ( sKey.getLength() )
640         {
641             TWeakPairVector::iterator i = ::std::find_if(m_aConnections.begin(),m_aConnections.end(),::std::compose1(
642                             ::std::bind2nd(::std::equal_to< ::rtl::OUString >(),sKey)
643                             ,::std::compose1(::std::select1st<TWeakConnectionPair>(),::std::select2nd< TWeakPair >())));
644             OSL_ENSURE( i != m_aConnections.end(), "ODriverDelegator::preCommit: they're committing a storage which I do not know!" );
645             if ( i != m_aConnections.end() )
646             {
647                 try
648                 {
649                     Reference<XConnection> xConnection(i->first,UNO_QUERY);
650                     if ( xConnection.is() )
651                     {
652                         Reference< XStatement> xStmt = xConnection->createStatement();
653                         OSL_ENSURE( xStmt.is(), "ODriverDelegator::preCommit: no statement!" );
654                         if ( xStmt.is() )
655                             xStmt->execute( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "SET WRITE_DELAY 0" ) ) );
656 
657                         sal_Bool bPreviousAutoCommit = xConnection->getAutoCommit();
658                         xConnection->setAutoCommit( sal_False );
659                         xConnection->commit();
660                         xConnection->setAutoCommit( bPreviousAutoCommit );
661 
662                         if ( xStmt.is() )
663                             xStmt->execute( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "SET WRITE_DELAY 60" ) ) );
664                     }
665                 }
666                 catch(Exception&)
667                 {
668                     OSL_ENSURE( false, "ODriverDelegator::preCommit: caught an exception!" );
669                 }
670             }
671         }
672     }
673     //------------------------------------------------------------------
commited(const::com::sun::star::lang::EventObject &)674     void SAL_CALL ODriverDelegator::commited( const ::com::sun::star::lang::EventObject& /*aEvent*/ ) throw (::com::sun::star::uno::RuntimeException)
675     {
676     }
677     //------------------------------------------------------------------
preRevert(const::com::sun::star::lang::EventObject &)678     void SAL_CALL ODriverDelegator::preRevert( const ::com::sun::star::lang::EventObject& /*aEvent*/ ) throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException)
679     {
680     }
681     //------------------------------------------------------------------
reverted(const::com::sun::star::lang::EventObject &)682     void SAL_CALL ODriverDelegator::reverted( const ::com::sun::star::lang::EventObject& /*aEvent*/ ) throw (::com::sun::star::uno::RuntimeException)
683     {
684     }
685     //------------------------------------------------------------------
686     namespace
687     {
688         //..............................................................
lcl_getCollationForLocale(const::rtl::OUString & _rLocaleString,bool _bAcceptCountryMismatch=false)689         const sal_Char* lcl_getCollationForLocale( const ::rtl::OUString& _rLocaleString, bool _bAcceptCountryMismatch = false )
690         {
691             static const sal_Char* pTranslations[] =
692             {
693                 "af-ZA", "Afrikaans",
694                 "am-ET", "Amharic",
695                 "ar", "Arabic",
696                 "as-IN", "Assamese",
697                 "az-AZ", "Azerbaijani_Latin",
698                 "az-cyrillic", "Azerbaijani_Cyrillic",
699                 "be-BY", "Belarusian",
700                 "bg-BG", "Bulgarian",
701                 "bn-IN", "Bengali",
702                 "bo-CN", "Tibetan",
703                 "bs-BA", "Bosnian",
704                 "ca-ES", "Catalan",
705                 "cs-CZ", "Czech",
706                 "cy-GB", "Welsh",
707                 "da-DK", "Danish",
708                 "de-DE", "German",
709                 "el-GR", "Greek",
710                 "en-US", "Latin1_General",
711                 "es-ES", "Spanish",
712                 "et-EE", "Estonian",
713                 "eu", "Basque",
714                 "fi-FI", "Finnish",
715                 "fr-FR", "French",
716                 "gn-PY", "Guarani",
717                 "gu-IN", "Gujarati",
718                 "ha-NG", "Hausa",
719                 "he-IL", "Hebrew",
720                 "hi-IN", "Hindi",
721                 "hr-HR", "Croatian",
722                 "hu-HU", "Hungarian",
723                 "hy-AM", "Armenian",
724                 "id-ID", "Indonesian",
725                 "ig-NG", "Igbo",
726                 "is-IS", "Icelandic",
727                 "it-IT", "Italian",
728                 "iu-CA", "Inuktitut",
729                 "ja-JP", "Japanese",
730                 "ka-GE", "Georgian",
731                 "kk-KZ", "Kazakh",
732                 "km-KH", "Khmer",
733                 "kn-IN", "Kannada",
734                 "ko-KR", "Korean",
735                 "kok-IN", "Konkani",
736                 "ks", "Kashmiri",
737                 "ky-KG", "Kirghiz",
738                 "lo-LA", "Lao",
739                 "lt-LT", "Lithuanian",
740                 "lv-LV", "Latvian",
741                 "mi-NZ", "Maori",
742                 "mk-MK", "Macedonian",
743                 "ml-IN", "Malayalam",
744                 "mn-MN", "Mongolian",
745                 "mni-IN", "Manipuri",
746                 "mr-IN", "Marathi",
747                 "ms-MY", "Malay",
748                 "mt-MT", "Maltese",
749                 "my-MM", "Burmese",
750                 "nb-NO", "Danish_Norwegian",
751                 "ne-NP", "Nepali",
752                 "nl-NL", "Dutch",
753                 "nn-NO", "Norwegian",
754                 "or-IN", "Oriya",
755                 "pa-IN", "Punjabi",
756                 "pl-PL", "Polish",
757                 "ps-AF", "Pashto",
758                 "pt-PT", "Portuguese",
759                 "ro-RO", "Romanian",
760                 "ru-RU", "Russian",
761                 "sa-IN", "Sanskrit",
762                 "sd-IN", "Sindhi",
763                 "sk-SK", "Slovak",
764                 "sl-SI", "Slovenian",
765                 "so-SO", "Somali",
766                 "sq-AL", "Albanian",
767                 "sr-YU", "Serbian_Cyrillic",
768                 "sv-SE", "Swedish",
769                 "sw-KE", "Swahili",
770                 "ta-IN", "Tamil",
771                 "te-IN", "Telugu",
772                 "tg-TJ", "Tajik",
773                 "th-TH", "Thai",
774                 "tk-TM", "Turkmen",
775                 "tn-BW", "Tswana",
776                 "tr-TR", "Turkish",
777                 "tt-RU", "Tatar",
778                 "uk-UA", "Ukrainian",
779                 "ur-PK", "Urdu",
780                 "uz-UZ", "Uzbek_Latin",
781                 "ven-ZA", "Venda",
782                 "vi-VN", "Vietnamese",
783                 "yo-NG", "Yoruba",
784                 "zh-CN", "Chinese",
785                 "zu-ZA", "Zulu",
786                 NULL, NULL
787             };
788 
789             ::rtl::OUString sLocaleString( _rLocaleString );
790             sal_Char nCompareTermination = 0;
791 
792             if ( _bAcceptCountryMismatch )
793             {
794                 // strip the country part from the compare string
795                 sal_Int32 nCountrySep = sLocaleString.indexOf( '-' );
796                 if ( nCountrySep > -1 )
797                     sLocaleString = sLocaleString.copy( 0, nCountrySep );
798 
799                 // the entries in the translation table are compared until the
800                 // - character only, not until the terminating 0
801                 nCompareTermination = '-';
802             }
803 
804             const sal_Char** pLookup = pTranslations;
805             for ( ; *pLookup; pLookup +=2 )
806             {
807                 sal_Int32 nCompareUntil = 0;
808                 while ( (*pLookup)[ nCompareUntil ] != nCompareTermination && (*pLookup)[ nCompareUntil ] != 0 )
809                     ++nCompareUntil;
810 
811                 if ( sLocaleString.equalsAsciiL( *pLookup, nCompareUntil ) )
812                     return *( pLookup + 1 );
813             }
814 
815             if ( !_bAcceptCountryMismatch )
816                 // second round, this time without matching the country
817                 return lcl_getCollationForLocale( _rLocaleString, true );
818 
819             OSL_ENSURE( false, "lcl_getCollationForLocale: unknown locale string, falling back to Latin1_General!" );
820             return "Latin1_General";
821         }
822 
823         //..............................................................
lcl_getSystemLocale(const Reference<XMultiServiceFactory> & _rxORB)824         ::rtl::OUString lcl_getSystemLocale( const Reference< XMultiServiceFactory >& _rxORB )
825         {
826             ::rtl::OUString sLocaleString = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "en-US" ) );
827             try
828             {
829                 //.........................................................
830                 Reference< XMultiServiceFactory > xConfigProvider(
831                     _rxORB->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.configuration.ConfigurationProvider" ) ),
832                     UNO_QUERY
833                 );
834                 OSL_ENSURE( xConfigProvider.is(), "lcl_getSystemLocale: could not create the config provider!" );
835 
836                 if ( !xConfigProvider.is() )
837                     return sLocaleString;
838 
839                 //.........................................................
840                 // arguments for creating the config access
841                 Sequence< Any > aArguments(2);
842                 // the path to the node to open
843                 ::rtl::OUString sNodePath = ::rtl::OUString::createFromAscii ("/org.openoffice.Setup/L10N" );
844                 aArguments[0] <<= PropertyValue( ::rtl::OUString::createFromAscii( "nodepath"), 0,
845                     makeAny( sNodePath ), PropertyState_DIRECT_VALUE
846                 );
847                 // the depth: -1 means unlimited
848                 aArguments[1] <<= PropertyValue(
849                     ::rtl::OUString::createFromAscii( "depth"), 0,
850                     makeAny( (sal_Int32)-1 ), PropertyState_DIRECT_VALUE
851                 );
852 
853                 //.........................................................
854                 // create the access
855                 Reference< XPropertySet > xNode(
856                     xConfigProvider->createInstanceWithArguments(
857                         ::rtl::OUString::createFromAscii( "com.sun.star.configuration.ConfigurationAccess" ),
858                         aArguments ),
859                     UNO_QUERY );
860                 OSL_ENSURE( xNode.is(), "lcl_getSystemLocale: invalid access returned (should throw an exception instead)!" );
861 
862                 //.........................................................
863                 // ask for the system locale setting
864                 if ( xNode.is() )
865                     xNode->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ooSetupSystemLocale" ) ) ) >>= sLocaleString;
866             }
867             catch( const Exception& )
868             {
869                 OSL_ENSURE( sal_False, "lcl_getSystemLocale: caught an exception!" );
870             }
871             if ( !sLocaleString.getLength() )
872             {
873                 rtl_Locale* pProcessLocale = NULL;
874                 osl_getProcessLocale( &pProcessLocale );
875 
876                 ::rtl::OUStringBuffer aProcLocale;
877                 aProcLocale.append( pProcessLocale->Language->buffer, pProcessLocale->Language->length );
878                 if ( pProcessLocale->Country->length )
879                 {
880                     aProcLocale.appendAscii( "-" );
881                     aProcLocale.append( pProcessLocale->Country->buffer, pProcessLocale->Country->length );
882                 }
883                 sLocaleString = aProcLocale.makeStringAndClear();
884             }
885             return sLocaleString;
886         }
887     }
888     //------------------------------------------------------------------
onConnectedNewDatabase(const Reference<XConnection> & _rxConnection)889     void ODriverDelegator::onConnectedNewDatabase( const Reference< XConnection >& _rxConnection )
890     {
891         try
892         {
893             Reference< XStatement > xStatement = _rxConnection->createStatement();
894             OSL_ENSURE( xStatement.is(), "ODriverDelegator::onConnectedNewDatabase: could not create a statement!" );
895             if ( xStatement.is() )
896             {
897                 ::rtl::OUStringBuffer aStatement;
898                 aStatement.appendAscii( "SET DATABASE COLLATION \"" );
899                 aStatement.appendAscii( lcl_getCollationForLocale( lcl_getSystemLocale( m_xFactory ) ) );
900                 aStatement.appendAscii( "\"" );
901 
902                 xStatement->execute( aStatement.makeStringAndClear() );
903             }
904         }
905         catch( const Exception& )
906         {
907             OSL_ENSURE( sal_False, "ODriverDelegator::onConnectedNewDatabase: caught an exception!" );
908         }
909     }
910 
911     //------------------------------------------------------------------
912     //------------------------------------------------------------------
913 //........................................................................
914 }   // namespace connectivity
915 //........................................................................
916 
917