bump product version to 7.2.5.1
[LibreOffice.git] / connectivity / source / drivers / hsqldb / HDriver.cxx
blobe4d4e399ba2a6c6137b6d5d3417f0a78f973be31
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <hsqldb/HDriver.hxx>
21 #include <hsqldb/HConnection.hxx>
22 #include <osl/diagnose.h>
23 #include <sal/log.hxx>
24 #include <connectivity/dbexception.hxx>
25 #include <com/sun/star/configuration/theDefaultProvider.hpp>
26 #include <com/sun/star/sdbc/DriverManager.hpp>
27 #include <com/sun/star/sdbc/XResultSet.hpp>
28 #include <com/sun/star/sdbc/XRow.hpp>
29 #include <com/sun/star/embed/XTransactionBroadcaster.hpp>
30 #include <com/sun/star/embed/ElementModes.hpp>
31 #include <TConnection.hxx>
32 #include <hsqldb/HStorageMap.hxx>
33 #include <jvmfwk/framework.hxx>
34 #include <com/sun/star/reflection/XProxyFactory.hpp>
35 #include <com/sun/star/embed/XStorage.hpp>
36 #include <com/sun/star/frame/Desktop.hpp>
37 #include <com/sun/star/util/XFlushable.hpp>
38 #include "HTerminateListener.hxx"
39 #include <hsqldb/HCatalog.hxx>
40 #include <rtl/ustrbuf.hxx>
41 #include <osl/file.h>
42 #include <osl/process.h>
43 #include <comphelper/namedvaluecollection.hxx>
44 #include <comphelper/propertysequence.hxx>
45 #include <comphelper/servicehelper.hxx>
46 #include <cppuhelper/supportsservice.hxx>
47 #include <comphelper/types.hxx>
48 #include <unotools/confignode.hxx>
49 #include <unotools/ucbstreamhelper.hxx>
50 #include <strings.hrc>
51 #include <resource/sharedresources.hxx>
52 #include <i18nlangtag/languagetag.hxx>
53 #include <tools/diagnose_ex.h>
55 #include <memory>
58 namespace connectivity
61 using namespace hsqldb;
62 using namespace css::uno;
63 using namespace css::sdbc;
64 using namespace css::sdbcx;
65 using namespace css::beans;
66 using namespace css::frame;
67 using namespace css::lang;
68 using namespace css::embed;
69 using namespace css::io;
70 using namespace css::util;
71 using namespace css::reflection;
73 constexpr OUStringLiteral IMPL_NAME = u"com.sun.star.sdbcx.comp.hsqldb.Driver";
77 ODriverDelegator::ODriverDelegator(const Reference< XComponentContext >& _rxContext)
78 : ODriverDelegator_BASE(m_aMutex)
79 ,m_xContext(_rxContext)
80 ,m_bInShutDownConnections(false)
85 ODriverDelegator::~ODriverDelegator()
87 try
89 ::comphelper::disposeComponent(m_xDriver);
91 catch(const Exception&)
97 void SAL_CALL ODriverDelegator::disposing()
99 ::osl::MutexGuard aGuard(m_aMutex);
103 for (const auto& rConnection : m_aConnections)
105 Reference<XInterface > xTemp = rConnection.first.get();
106 ::comphelper::disposeComponent(xTemp);
109 catch(Exception&)
111 // not interested in
113 m_aConnections.clear();
114 TWeakPairVector().swap(m_aConnections);
116 cppu::WeakComponentImplHelperBase::disposing();
119 Reference< XDriver > const & ODriverDelegator::loadDriver( )
121 if ( !m_xDriver.is() )
123 Reference<XDriverManager2> xDriverAccess = DriverManager::create( m_xContext );
124 m_xDriver = xDriverAccess->getDriverByURL("jdbc:hsqldb:db");
127 return m_xDriver;
131 namespace
133 OUString lcl_getPermittedJavaMethods_nothrow( const Reference< XComponentContext >& _rxContext )
135 OUString aConfigPath =
136 "/org.openoffice.Office.DataAccess/DriverSettings/" +
137 IMPL_NAME +
138 "/PermittedJavaMethods";
139 ::utl::OConfigurationTreeRoot aConfig( ::utl::OConfigurationTreeRoot::createWithComponentContext(
140 _rxContext, aConfigPath ) );
142 OUStringBuffer aPermittedMethods;
143 const Sequence< OUString > aNodeNames( aConfig.getNodeNames() );
144 for ( auto const & nodeName : aNodeNames )
146 OUString sPermittedMethod;
147 OSL_VERIFY( aConfig.getNodeValue( nodeName ) >>= sPermittedMethod );
149 if ( !aPermittedMethods.isEmpty() )
150 aPermittedMethods.append( ';' );
151 aPermittedMethods.append( sPermittedMethod );
154 return aPermittedMethods.makeStringAndClear();
159 Reference< XConnection > SAL_CALL ODriverDelegator::connect( const OUString& url, const Sequence< PropertyValue >& info )
161 Reference< XConnection > xConnection;
162 if ( acceptsURL(url) )
164 Reference< XDriver > xDriver = loadDriver();
165 if ( xDriver.is() )
167 OUString sURL;
168 Reference<XStorage> xStorage;
169 const PropertyValue* pIter = info.getConstArray();
170 const PropertyValue* pEnd = pIter + info.getLength();
172 for (;pIter != pEnd; ++pIter)
174 if ( pIter->Name == "Storage" )
176 xStorage.set(pIter->Value,UNO_QUERY);
178 else if ( pIter->Name == "URL" )
180 pIter->Value >>= sURL;
184 if ( !xStorage.is() || sURL.isEmpty() )
186 ::connectivity::SharedResources aResources;
187 const OUString sMessage = aResources.getResourceString(STR_NO_STORAGE);
188 ::dbtools::throwGenericSQLException(sMessage ,*this);
191 OUString sSystemPath;
192 osl_getSystemPathFromFileURL( sURL.pData, &sSystemPath.pData );
193 if ( sURL.isEmpty() || sSystemPath.isEmpty() )
195 ::connectivity::SharedResources aResources;
196 const OUString sMessage = aResources.getResourceString(STR_INVALID_FILE_URL);
197 ::dbtools::throwGenericSQLException(sMessage ,*this);
200 bool bIsNewDatabase = !xStorage->hasElements();
202 ::comphelper::NamedValueCollection aProperties;
204 // properties for accessing the embedded storage
205 OUString sKey = StorageContainer::registerStorage( xStorage, sSystemPath );
206 aProperties.put( "storage_key", sKey );
207 aProperties.put( "storage_class_name",
208 OUString( "com.sun.star.sdbcx.comp.hsqldb.StorageAccess" ) );
209 aProperties.put( "fileaccess_class_name",
210 OUString( "com.sun.star.sdbcx.comp.hsqldb.StorageFileAccess" ) );
212 // JDBC driver and driver's classpath
213 aProperties.put( "JavaDriverClass",
214 OUString( "org.hsqldb.jdbcDriver" ) );
215 aProperties.put( "JavaDriverClassPath",
216 OUString(
217 #ifdef SYSTEM_HSQLDB
218 HSQLDB_JAR
219 #else
220 "vnd.sun.star.expand:$LO_JAVA_DIR/hsqldb.jar"
221 #endif
222 " vnd.sun.star.expand:$LO_JAVA_DIR/sdbc_hsqldb.jar"
223 ) );
225 // auto increment handling
226 aProperties.put( "IsAutoRetrievingEnabled", true );
227 aProperties.put( "AutoRetrievingStatement",
228 OUString( "CALL IDENTITY()" ) );
229 aProperties.put( "IgnoreDriverPrivileges", true );
231 // don't want to expose HSQLDB's schema capabilities which exist since 1.8.0RC10
232 aProperties.put( "default_schema",
233 OUString( "true" ) );
235 // security: permitted Java classes
236 NamedValue aPermittedClasses(
237 "hsqldb.method_class_names",
238 makeAny( lcl_getPermittedJavaMethods_nothrow( m_xContext ) )
240 aProperties.put( "SystemProperties", Sequence< NamedValue >( &aPermittedClasses, 1 ) );
242 OUString sMessage;
245 static const OUStringLiteral sProperties( u"properties" );
246 if ( !bIsNewDatabase && xStorage->isStreamElement(sProperties) )
248 Reference<XStream > xStream = xStorage->openStreamElement(sProperties,ElementModes::READ);
249 if ( xStream.is() )
251 std::unique_ptr<SvStream> pStream( ::utl::UcbStreamHelper::CreateStream(xStream) );
252 if (pStream)
254 OString sLine;
255 OString sVersionString;
256 while ( pStream->ReadLine(sLine) )
258 if ( sLine.isEmpty() )
259 continue;
260 sal_Int32 nIdx {0};
261 const OString sIniKey = sLine.getToken(0, '=', nIdx);
262 const OString sValue = sLine.getToken(0, '=', nIdx);
263 if( sIniKey == "hsqldb.compatible_version" )
265 sVersionString = sValue;
267 else
269 if (sIniKey == "version" && sVersionString.isEmpty())
271 sVersionString = sValue;
275 if (!sVersionString.isEmpty())
277 sal_Int32 nIdx {0};
278 const sal_Int32 nMajor = sVersionString.getToken(0, '.', nIdx).toInt32();
279 const sal_Int32 nMinor = sVersionString.getToken(0, '.', nIdx).toInt32();
280 const sal_Int32 nMicro = sVersionString.getToken(0, '.', nIdx).toInt32();
281 if ( nMajor > 1
282 || ( nMajor == 1 && nMinor > 8 )
283 || ( nMajor == 1 && nMinor == 8 && nMicro > 0 ) )
285 ::connectivity::SharedResources aResources;
286 sMessage = aResources.getResourceString(STR_ERROR_NEW_VERSION);
290 } // if ( xStream.is() )
291 ::comphelper::disposeComponent(xStream);
294 catch(Exception&)
297 if ( !sMessage.isEmpty() )
299 ::dbtools::throwGenericSQLException(sMessage ,*this);
302 // readonly?
303 Reference<XPropertySet> xProp(xStorage,UNO_QUERY);
304 if ( xProp.is() )
306 sal_Int32 nMode = 0;
307 xProp->getPropertyValue("OpenMode") >>= nMode;
308 if ( (nMode & ElementModes::WRITE) != ElementModes::WRITE )
310 aProperties.put( "readonly", OUString( "true" ) );
314 Sequence< PropertyValue > aConnectionArgs;
315 aProperties >>= aConnectionArgs;
316 OUString sConnectURL = "jdbc:hsqldb:" + sSystemPath;
317 Reference<XConnection> xOrig;
320 xOrig = xDriver->connect( sConnectURL, aConnectionArgs );
322 catch(const Exception&)
324 StorageContainer::revokeStorage(sKey,nullptr);
325 throw;
328 // if the storage is completely empty, then we just created a new HSQLDB
329 // In this case, do some initializations.
330 if ( bIsNewDatabase && xOrig.is() )
331 onConnectedNewDatabase( xOrig );
333 if ( xOrig.is() )
335 // now we have to set the URL to get the correct answer for metadata()->getURL()
336 auto pMetaConnection = comphelper::getUnoTunnelImplementation<OMetaConnection>(xOrig);
337 if ( pMetaConnection )
338 pMetaConnection->setURL(url);
340 Reference<XComponent> xComp(xOrig,UNO_QUERY);
341 if ( xComp.is() )
342 xComp->addEventListener(this);
344 // we want to close all connections when the office shuts down
345 static Reference< XTerminateListener> s_xTerminateListener = [&]()
347 Reference< XDesktop2 > xDesktop = Desktop::create( m_xContext );
349 rtl::Reference<OConnectionController> tmp = new OConnectionController(this);
350 xDesktop->addTerminateListener(tmp);
351 return tmp;
352 }();
353 Reference< XComponent> xIfc = new OHsqlConnection( this, xOrig, m_xContext );
354 xConnection.set(xIfc,UNO_QUERY);
355 m_aConnections.push_back(TWeakPair(WeakReferenceHelper(xOrig),TWeakConnectionPair(sKey,TWeakRefPair(WeakReferenceHelper(xConnection),WeakReferenceHelper()))));
357 Reference<XTransactionBroadcaster> xBroad(xStorage,UNO_QUERY);
358 if ( xBroad.is() )
360 Reference<XTransactionListener> xListener(*this,UNO_QUERY);
361 xBroad->addTransactionListener(xListener);
366 return xConnection;
370 sal_Bool SAL_CALL ODriverDelegator::acceptsURL( const OUString& url )
372 bool bEnabled = false;
373 javaFrameworkError e = jfw_getEnabled(&bEnabled);
374 switch (e) {
375 case JFW_E_NONE:
376 break;
377 case JFW_E_DIRECT_MODE:
378 SAL_INFO(
379 "connectivity.hsqldb",
380 "jfw_getEnabled: JFW_E_DIRECT_MODE, assuming true");
381 bEnabled = true;
382 break;
383 default:
384 SAL_WARN(
385 "connectivity.hsqldb", "jfw_getEnabled: error code " << +e);
386 break;
388 return bEnabled && url == "sdbc:embedded:hsqldb";
392 Sequence< DriverPropertyInfo > SAL_CALL ODriverDelegator::getPropertyInfo( const OUString& url, const Sequence< PropertyValue >& /*info*/ )
394 if ( !acceptsURL(url) )
395 return Sequence< DriverPropertyInfo >();
396 return
399 "Storage",
400 "Defines the storage where the database will be stored.",
401 true,
406 "URL",
407 "Defines the url of the data source.",
408 true,
413 "AutoRetrievingStatement",
414 "Defines the statement which will be executed to retrieve auto increment values.",
415 false,
416 "CALL IDENTITY()",
423 sal_Int32 SAL_CALL ODriverDelegator::getMajorVersion( )
425 return 1;
429 sal_Int32 SAL_CALL ODriverDelegator::getMinorVersion( )
431 return 0;
435 Reference< XTablesSupplier > SAL_CALL ODriverDelegator::getDataDefinitionByConnection( const Reference< XConnection >& connection )
437 ::osl::MutexGuard aGuard( m_aMutex );
438 checkDisposed(ODriverDelegator_BASE::rBHelper.bDisposed);
440 Reference< XTablesSupplier > xTab;
442 TWeakPairVector::iterator i = std::find_if(m_aConnections.begin(), m_aConnections.end(),
443 [&connection](const TWeakPairVector::value_type& rConnection) {
444 return rConnection.second.second.first.get() == connection.get(); });
445 if (i != m_aConnections.end())
447 xTab.set(i->second.second.second,UNO_QUERY);
448 if ( !xTab.is() )
450 xTab = new OHCatalog(connection);
451 i->second.second.second = WeakReferenceHelper(xTab);
455 return xTab;
459 Reference< XTablesSupplier > SAL_CALL ODriverDelegator::getDataDefinitionByURL( const OUString& url, const Sequence< PropertyValue >& info )
461 if ( ! acceptsURL(url) )
463 ::connectivity::SharedResources aResources;
464 const OUString sMessage = aResources.getResourceString(STR_URI_SYNTAX_ERROR);
465 ::dbtools::throwGenericSQLException(sMessage ,*this);
468 return getDataDefinitionByConnection(connect(url,info));
471 // XServiceInfo
473 OUString SAL_CALL ODriverDelegator::getImplementationName( )
475 return IMPL_NAME;
478 sal_Bool SAL_CALL ODriverDelegator::supportsService( const OUString& _rServiceName )
480 return cppu::supportsService(this, _rServiceName);
483 Sequence< OUString > SAL_CALL ODriverDelegator::getSupportedServiceNames( )
485 return { "com.sun.star.sdbc.Driver", "com.sun.star.sdbcx.Driver" };
488 void SAL_CALL ODriverDelegator::createCatalog( const Sequence< PropertyValue >& /*info*/ )
490 ::dbtools::throwFeatureNotImplementedSQLException( "XCreateCatalog::createCatalog", *this );
493 void ODriverDelegator::shutdownConnection(const TWeakPairVector::iterator& _aIter )
495 OSL_ENSURE(m_aConnections.end() != _aIter,"Iterator equals .end()");
496 bool bLastOne = true;
499 Reference<XConnection> _xConnection(_aIter->first.get(),UNO_QUERY);
501 if ( _xConnection.is() )
503 Reference<XStatement> xStmt = _xConnection->createStatement();
504 if ( xStmt.is() )
506 Reference<XResultSet> xRes = xStmt->executeQuery("SELECT COUNT(*) FROM INFORMATION_SCHEMA.SYSTEM_SESSIONS WHERE USER_NAME ='SA'");
507 Reference<XRow> xRow(xRes,UNO_QUERY);
508 if ( xRow.is() && xRes->next() )
509 bLastOne = xRow->getInt(1) == 1;
510 if ( bLastOne )
511 xStmt->execute("SHUTDOWN");
515 catch(Exception&)
518 if ( bLastOne )
520 // Reference<XTransactionListener> xListener(*this,UNO_QUERY);
521 // a shutdown should commit all changes to the db files
522 StorageContainer::revokeStorage(_aIter->second.first,nullptr);
524 if ( !m_bInShutDownConnections )
525 m_aConnections.erase(_aIter);
528 void SAL_CALL ODriverDelegator::disposing( const css::lang::EventObject& Source )
530 ::osl::MutexGuard aGuard(m_aMutex);
531 Reference<XConnection> xCon(Source.Source,UNO_QUERY);
532 if ( xCon.is() )
534 TWeakPairVector::iterator i = std::find_if(m_aConnections.begin(), m_aConnections.end(),
535 [&xCon](const TWeakPairVector::value_type& rConnection) { return rConnection.first.get() == xCon.get(); });
537 if (i != m_aConnections.end())
538 shutdownConnection(i);
540 else
542 Reference< XStorage> xStorage(Source.Source,UNO_QUERY);
543 if ( xStorage.is() )
545 OUString sKey = StorageContainer::getRegisteredKey(xStorage);
546 TWeakPairVector::iterator i = std::find_if(m_aConnections.begin(),m_aConnections.end(),
547 [&sKey] (const TWeakPairVector::value_type& conn) {
548 return conn.second.first == sKey;
551 if ( i != m_aConnections.end() )
552 shutdownConnection(i);
557 void ODriverDelegator::shutdownConnections()
559 m_bInShutDownConnections = true;
560 for (const auto& rConnection : m_aConnections)
564 Reference<XConnection> xCon(rConnection.first,UNO_QUERY);
565 ::comphelper::disposeComponent(xCon);
567 catch(Exception&)
571 m_aConnections.clear();
572 m_bInShutDownConnections = true;
575 void ODriverDelegator::flushConnections()
577 for (const auto& rConnection : m_aConnections)
581 Reference<XFlushable> xCon(rConnection.second.second.first.get(),UNO_QUERY);
582 if (xCon.is())
583 xCon->flush();
585 catch(Exception&)
587 DBG_UNHANDLED_EXCEPTION("connectivity.hsqldb");
592 void SAL_CALL ODriverDelegator::preCommit( const css::lang::EventObject& aEvent )
594 ::osl::MutexGuard aGuard(m_aMutex);
596 Reference< XStorage> xStorage(aEvent.Source,UNO_QUERY);
597 OUString sKey = StorageContainer::getRegisteredKey(xStorage);
598 if ( sKey.isEmpty() )
599 return;
601 TWeakPairVector::const_iterator i = std::find_if(m_aConnections.begin(), m_aConnections.end(),
602 [&sKey] (const TWeakPairVector::value_type& conn) {
603 return conn.second.first == sKey;
606 OSL_ENSURE( i != m_aConnections.end(), "ODriverDelegator::preCommit: they're committing a storage which I do not know!" );
607 if ( i == m_aConnections.end() )
608 return;
612 Reference<XConnection> xConnection(i->first,UNO_QUERY);
613 if ( xConnection.is() )
615 Reference< XStatement> xStmt = xConnection->createStatement();
616 OSL_ENSURE( xStmt.is(), "ODriverDelegator::preCommit: no statement!" );
617 if ( xStmt.is() )
618 xStmt->execute( "SET WRITE_DELAY 0" );
620 bool bPreviousAutoCommit = xConnection->getAutoCommit();
621 xConnection->setAutoCommit( false );
622 xConnection->commit();
623 xConnection->setAutoCommit( bPreviousAutoCommit );
625 if ( xStmt.is() )
626 xStmt->execute( "SET WRITE_DELAY 60" );
629 catch(Exception&)
631 TOOLS_WARN_EXCEPTION( "connectivity.hsqldb", "ODriverDelegator::preCommit" );
635 void SAL_CALL ODriverDelegator::commited( const css::lang::EventObject& /*aEvent*/ )
639 void SAL_CALL ODriverDelegator::preRevert( const css::lang::EventObject& /*aEvent*/ )
643 void SAL_CALL ODriverDelegator::reverted( const css::lang::EventObject& /*aEvent*/ )
647 namespace
650 const char* lcl_getCollationForLocale( const OUString& _rLocaleString, bool _bAcceptCountryMismatch = false )
652 static const char* pTranslations[] =
654 "af-ZA", "Afrikaans",
655 "am-ET", "Amharic",
656 "ar", "Arabic",
657 "as-IN", "Assamese",
658 "az-AZ", "Azerbaijani_Latin",
659 "az-cyrillic", "Azerbaijani_Cyrillic",
660 "be-BY", "Belarusian",
661 "bg-BG", "Bulgarian",
662 "bn-IN", "Bengali",
663 "bo-CN", "Tibetan",
664 "bs-BA", "Bosnian",
665 "ca-ES", "Catalan",
666 "cs-CZ", "Czech",
667 "cy-GB", "Welsh",
668 "da-DK", "Danish",
669 "de-DE", "German",
670 "el-GR", "Greek",
671 "en-US", "Latin1_General",
672 "es-ES", "Spanish",
673 "et-EE", "Estonian",
674 "eu", "Basque",
675 "fi-FI", "Finnish",
676 "fr-FR", "French",
677 "gn-PY", "Guarani",
678 "gu-IN", "Gujarati",
679 "ha-NG", "Hausa",
680 "he-IL", "Hebrew",
681 "hi-IN", "Hindi",
682 "hr-HR", "Croatian",
683 "hu-HU", "Hungarian",
684 "hy-AM", "Armenian",
685 "id-ID", "Indonesian",
686 "ig-NG", "Igbo",
687 "is-IS", "Icelandic",
688 "it-IT", "Italian",
689 "iu-CA", "Inuktitut",
690 "ja-JP", "Japanese",
691 "ka-GE", "Georgian",
692 "kk-KZ", "Kazakh",
693 "km-KH", "Khmer",
694 "kn-IN", "Kannada",
695 "ko-KR", "Korean",
696 "kok-IN", "Konkani",
697 "ks", "Kashmiri",
698 "ky-KG", "Kirghiz",
699 "lo-LA", "Lao",
700 "lt-LT", "Lithuanian",
701 "lv-LV", "Latvian",
702 "mi-NZ", "Maori",
703 "mk-MK", "Macedonian",
704 "ml-IN", "Malayalam",
705 "mn-MN", "Mongolian",
706 "mni-IN", "Manipuri",
707 "mr-IN", "Marathi",
708 "ms-MY", "Malay",
709 "mt-MT", "Maltese",
710 "my-MM", "Burmese",
711 "nb-NO", "Danish_Norwegian",
712 "ne-NP", "Nepali",
713 "nl-NL", "Dutch",
714 "nn-NO", "Norwegian",
715 "or-IN", "Odia",
716 "pa-IN", "Punjabi",
717 "pl-PL", "Polish",
718 "ps-AF", "Pashto",
719 "pt-PT", "Portuguese",
720 "ro-RO", "Romanian",
721 "ru-RU", "Russian",
722 "sa-IN", "Sanskrit",
723 "sd-IN", "Sindhi",
724 "sk-SK", "Slovak",
725 "sl-SI", "Slovenian",
726 "so-SO", "Somali",
727 "sq-AL", "Albanian",
728 "sr-YU", "Serbian_Cyrillic",
729 "sv-SE", "Swedish",
730 "sw-KE", "Swahili",
731 "ta-IN", "Tamil",
732 "te-IN", "Telugu",
733 "tg-TJ", "Tajik",
734 "th-TH", "Thai",
735 "tk-TM", "Turkmen",
736 "tn-BW", "Tswana",
737 "tr-TR", "Turkish",
738 "tt-RU", "Tatar",
739 "uk-UA", "Ukrainian",
740 "ur-PK", "Urdu",
741 "uz-UZ", "Uzbek_Latin",
742 "ven-ZA", "Venda",
743 "vi-VN", "Vietnamese",
744 "yo-NG", "Yoruba",
745 "zh-CN", "Chinese",
746 "zu-ZA", "Zulu",
747 nullptr, nullptr
750 OUString sLocaleString( _rLocaleString );
751 char nCompareTermination = 0;
753 if ( _bAcceptCountryMismatch )
755 // strip the country part from the compare string
756 sal_Int32 nCountrySep = sLocaleString.indexOf( '-' );
757 if ( nCountrySep > -1 )
758 sLocaleString = sLocaleString.copy( 0, nCountrySep );
760 // the entries in the translation table are compared until the
761 // - character only, not until the terminating 0
762 nCompareTermination = '-';
765 const char** pLookup = pTranslations;
766 for ( ; *pLookup; pLookup +=2 )
768 sal_Int32 nCompareUntil = 0;
769 while ( (*pLookup)[ nCompareUntil ] != nCompareTermination && (*pLookup)[ nCompareUntil ] != 0 )
770 ++nCompareUntil;
772 if ( sLocaleString.equalsAsciiL( *pLookup, nCompareUntil ) )
773 return *( pLookup + 1 );
776 if ( !_bAcceptCountryMismatch )
777 // second round, this time without matching the country
778 return lcl_getCollationForLocale( _rLocaleString, true );
780 OSL_FAIL( "lcl_getCollationForLocale: unknown locale string, falling back to Latin1_General!" );
781 return "Latin1_General";
785 OUString lcl_getSystemLocale( const Reference< XComponentContext >& _rxContext )
787 OUString sLocaleString = "en-US";
791 Reference< XMultiServiceFactory > xConfigProvider(
792 css::configuration::theDefaultProvider::get( _rxContext ) );
795 // arguments for creating the config access
796 Sequence<Any> aArguments(comphelper::InitAnyPropertySequence(
798 {"nodepath", Any(OUString("/org.openoffice.Setup/L10N" ))}, // the path to the node to open
799 {"depth", Any(sal_Int32(-1))}, // the depth: -1 means unlimited
800 }));
801 // create the access
802 Reference< XPropertySet > xNode(
803 xConfigProvider->createInstanceWithArguments(
804 "com.sun.star.configuration.ConfigurationAccess",
805 aArguments ),
806 UNO_QUERY );
807 OSL_ENSURE( xNode.is(), "lcl_getSystemLocale: invalid access returned (should throw an exception instead)!" );
810 // ask for the system locale setting
811 if ( xNode.is() )
812 xNode->getPropertyValue("ooSetupSystemLocale") >>= sLocaleString;
814 catch( const Exception& )
816 TOOLS_WARN_EXCEPTION( "connectivity.hsqldb", "lcl_getSystemLocale" );
818 if ( sLocaleString.isEmpty() )
820 rtl_Locale* pProcessLocale = nullptr;
821 osl_getProcessLocale( &pProcessLocale );
822 sLocaleString = LanguageTag( *pProcessLocale).getBcp47();
824 return sLocaleString;
828 void ODriverDelegator::onConnectedNewDatabase( const Reference< XConnection >& _rxConnection )
832 Reference< XStatement > xStatement = _rxConnection->createStatement();
833 OSL_ENSURE( xStatement.is(), "ODriverDelegator::onConnectedNewDatabase: could not create a statement!" );
834 if ( xStatement.is() )
836 OUStringBuffer aStatement;
837 aStatement.append( "SET DATABASE COLLATION \"" );
838 aStatement.appendAscii( lcl_getCollationForLocale( lcl_getSystemLocale( m_xContext ) ) );
839 aStatement.append( "\"" );
841 xStatement->execute( aStatement.makeStringAndClear() );
844 catch( const Exception& )
846 TOOLS_WARN_EXCEPTION( "connectivity.hsqldb", "ODriverDelegator::onConnectedNewDatabase" );
851 } // namespace connectivity
854 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
855 connectivity_hsqldb_ODriverDelegator_implementation(
856 css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
858 return cppu::acquire(new connectivity::ODriverDelegator(context));
862 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */