LibreOffice Module connectivity (master) 1
HDriver.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <hsqldb/HDriver.hxx>
22#include <osl/diagnose.h>
23#include <sal/log.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>
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>
39#include <hsqldb/HCatalog.hxx>
40#include <rtl/ustrbuf.hxx>
41#include <osl/file.h>
42#include <osl/process.h>
47#include <comphelper/types.hxx>
50#include <strings.hrc>
54#include <o3tl/string_view.hxx>
55
56#include <memory>
57
58
59namespace connectivity
60{
61
62 using namespace hsqldb;
63 using namespace css::uno;
64 using namespace css::sdbc;
65 using namespace css::sdbcx;
66 using namespace css::beans;
67 using namespace css::frame;
68 using namespace css::lang;
69 using namespace css::embed;
70 using namespace css::io;
71 using namespace css::util;
72 using namespace css::reflection;
73
74 constexpr OUStringLiteral IMPL_NAME = u"com.sun.star.sdbcx.comp.hsqldb.Driver";
75
76
77
78 ODriverDelegator::ODriverDelegator(const Reference< XComponentContext >& _rxContext)
80 ,m_xContext(_rxContext)
81 ,m_bInShutDownConnections(false)
82 {
83 }
84
85
86 ODriverDelegator::~ODriverDelegator()
87 {
88 try
89 {
90 ::comphelper::disposeComponent(m_xDriver);
91 }
92 catch(const Exception&)
93 {
94 }
95 }
96
97
98 void SAL_CALL ODriverDelegator::disposing()
99 {
100 ::osl::MutexGuard aGuard(m_aMutex);
101
102 try
103 {
104 for (const auto& rConnection : m_aConnections)
105 {
106 Reference<XInterface > xTemp = rConnection.first.get();
107 ::comphelper::disposeComponent(xTemp);
108 }
109 }
110 catch(Exception&)
111 {
112 // not interested in
113 }
114 m_aConnections.clear();
115 TWeakPairVector().swap(m_aConnections);
116
117 cppu::WeakComponentImplHelperBase::disposing();
118 }
119
120 Reference< XDriver > const & ODriverDelegator::loadDriver( )
121 {
122 if ( !m_xDriver.is() )
123 {
124 Reference<XDriverManager2> xDriverAccess = DriverManager::create( m_xContext );
125 m_xDriver = xDriverAccess->getDriverByURL("jdbc:hsqldb:db");
126 }
127
128 return m_xDriver;
129 }
130
131
132 namespace
133 {
134 OUString lcl_getPermittedJavaMethods_nothrow( const Reference< XComponentContext >& _rxContext )
135 {
136 OUString aConfigPath =
137 "/org.openoffice.Office.DataAccess/DriverSettings/" +
138 IMPL_NAME +
139 "/PermittedJavaMethods";
141 _rxContext, aConfigPath ) );
142
143 OUStringBuffer aPermittedMethods;
144 const Sequence< OUString > aNodeNames( aConfig.getNodeNames() );
145 for ( auto const & nodeName : aNodeNames )
146 {
147 OUString sPermittedMethod;
148 OSL_VERIFY( aConfig.getNodeValue( nodeName ) >>= sPermittedMethod );
149
150 if ( !aPermittedMethods.isEmpty() )
151 aPermittedMethods.append( ';' );
152 aPermittedMethods.append( sPermittedMethod );
153 }
154
155 return aPermittedMethods.makeStringAndClear();
156 }
157 }
158
159
160 Reference< XConnection > SAL_CALL ODriverDelegator::connect( const OUString& url, const Sequence< PropertyValue >& info )
161 {
162 Reference< XConnection > xConnection;
163 if ( acceptsURL(url) )
164 {
165 Reference< XDriver > xDriver = loadDriver();
166 if ( xDriver.is() )
167 {
168 OUString sURL;
169 Reference<XStorage> xStorage;
170 const PropertyValue* pIter = info.getConstArray();
171 const PropertyValue* pEnd = pIter + info.getLength();
172
173 for (;pIter != pEnd; ++pIter)
174 {
175 if ( pIter->Name == "Storage" )
176 {
177 xStorage.set(pIter->Value,UNO_QUERY);
178 }
179 else if ( pIter->Name == "URL" )
180 {
181 pIter->Value >>= sURL;
182 }
183 }
184
185 if ( !xStorage.is() || sURL.isEmpty() )
186 {
188 const OUString sMessage = aResources.getResourceString(STR_NO_STORAGE);
190 }
191
192 OUString sSystemPath;
193 osl_getSystemPathFromFileURL( sURL.pData, &sSystemPath.pData );
194 if ( sURL.isEmpty() || sSystemPath.isEmpty() )
195 {
197 const OUString sMessage = aResources.getResourceString(STR_INVALID_FILE_URL);
199 }
200
201 bool bIsNewDatabase = !xStorage->hasElements();
202
204
205 // properties for accessing the embedded storage
206 OUString sKey = StorageContainer::registerStorage( xStorage, sSystemPath );
207 aProperties.put( "storage_key", sKey );
208 aProperties.put( "storage_class_name",
209 OUString( "com.sun.star.sdbcx.comp.hsqldb.StorageAccess" ) );
210 aProperties.put( "fileaccess_class_name",
211 OUString( "com.sun.star.sdbcx.comp.hsqldb.StorageFileAccess" ) );
212
213 // JDBC driver and driver's classpath
214 aProperties.put( "JavaDriverClass",
215 OUString( "org.hsqldb.jdbcDriver" ) );
216 aProperties.put( "JavaDriverClassPath",
217 OUString(
218#ifdef SYSTEM_HSQLDB
219 HSQLDB_JAR
220#else
221 "vnd.sun.star.expand:$LO_JAVA_DIR/hsqldb.jar"
222#endif
223 " vnd.sun.star.expand:$LO_JAVA_DIR/sdbc_hsqldb.jar"
224 ) );
225
226 // auto increment handling
227 aProperties.put( "IsAutoRetrievingEnabled", true );
228 aProperties.put( "AutoRetrievingStatement",
229 OUString( "CALL IDENTITY()" ) );
230 aProperties.put( "IgnoreDriverPrivileges", true );
231
232 // don't want to expose HSQLDB's schema capabilities which exist since 1.8.0RC10
233 aProperties.put( "default_schema",
234 OUString( "true" ) );
235
236 // security: permitted Java classes
237 NamedValue aPermittedClasses(
238 "hsqldb.method_class_names",
239 Any( lcl_getPermittedJavaMethods_nothrow( m_xContext ) )
240 );
241 aProperties.put( "SystemProperties", Sequence< NamedValue >( &aPermittedClasses, 1 ) );
242
243 OUString sMessage;
244 try
245 {
246 static constexpr OUStringLiteral sProperties( u"properties" );
247 if ( !bIsNewDatabase && xStorage->isStreamElement(sProperties) )
248 {
249 Reference<XStream > xStream = xStorage->openStreamElement(sProperties,ElementModes::READ);
250 if ( xStream.is() )
251 {
252 std::unique_ptr<SvStream> pStream( ::utl::UcbStreamHelper::CreateStream(xStream) );
253 if (pStream)
254 {
255 OStringBuffer sLine;
256 OString sVersionString;
257 while ( pStream->ReadLine(sLine) )
258 {
259 if ( sLine.isEmpty() )
260 continue;
261 sal_Int32 nIdx {0};
262 const std::string_view sIniKey = o3tl::getToken(sLine, 0, '=', nIdx);
263 const OString sValue(o3tl::getToken(sLine, 0, '=', nIdx));
264 if( sIniKey == "hsqldb.compatible_version" )
265 {
266 sVersionString = sValue;
267 }
268 else
269 {
270 if (sIniKey == "version" && sVersionString.isEmpty())
271 {
272 sVersionString = sValue;
273 }
274 }
275 }
276 if (!sVersionString.isEmpty())
277 {
278 sal_Int32 nIdx {0};
279 const sal_Int32 nMajor = o3tl::toInt32(o3tl::getToken(sVersionString, 0, '.', nIdx));
280 const sal_Int32 nMinor = o3tl::toInt32(o3tl::getToken(sVersionString, 0, '.', nIdx));
281 const sal_Int32 nMicro = o3tl::toInt32(o3tl::getToken(sVersionString, 0, '.', nIdx));
282 if ( nMajor > 1
283 || ( nMajor == 1 && nMinor > 8 )
284 || ( nMajor == 1 && nMinor == 8 && nMicro > 0 ) )
285 {
287 sMessage = aResources.getResourceString(STR_ERROR_NEW_VERSION);
288 }
289 }
290 }
291 } // if ( xStream.is() )
292 ::comphelper::disposeComponent(xStream);
293 }
294
295 // disallow any database/script files that contain a "SCRIPT[.*]" entry (this is belt and braces
296 // in that bundled hsqldb 1.8.0 is patched to also reject them)
297 //
298 // hsqldb 2.6.0 release notes have: added system role SCRIPT_OPS for export / import of database structure and data
299 // which seems to provide a builtin way to do this with contemporary hsqldb
300 static constexpr OUStringLiteral sScript(u"script");
301 if (!bIsNewDatabase && xStorage->isStreamElement(sScript))
302 {
303 Reference<XStream > xStream = xStorage->openStreamElement(sScript, ElementModes::READ);
304 if (xStream.is())
305 {
306 std::unique_ptr<SvStream> pStream(::utl::UcbStreamHelper::CreateStream(xStream));
307 if (pStream)
308 {
309 OStringBuffer sLine;
310 while (pStream->ReadLine(sLine))
311 {
312 OString sText = sLine.makeStringAndClear().trim();
313 if (sText.startsWithIgnoreAsciiCase("SCRIPT"))
314 {
316 sMessage = aResources.getResourceString(STR_COULD_NOT_LOAD_FILE).replaceFirst("$filename$", sSystemPath);
317 break;
318 }
319 }
320 }
321 } // if ( xStream.is() )
322 ::comphelper::disposeComponent(xStream);
323 }
324
325 }
326 catch(Exception&)
327 {
328 }
329 if ( !sMessage.isEmpty() )
330 {
332 }
333
334 // readonly?
335 Reference<XPropertySet> xProp(xStorage,UNO_QUERY);
336 if ( xProp.is() )
337 {
338 sal_Int32 nMode = 0;
339 xProp->getPropertyValue("OpenMode") >>= nMode;
340 if ( (nMode & ElementModes::WRITE) != ElementModes::WRITE )
341 {
342 aProperties.put( "readonly", OUString( "true" ) );
343 }
344 }
345
346 Sequence< PropertyValue > aConnectionArgs;
347 aProperties >>= aConnectionArgs;
348 OUString sConnectURL = "jdbc:hsqldb:" + sSystemPath;
349 Reference<XConnection> xOrig;
350 try
351 {
352 xOrig = xDriver->connect( sConnectURL, aConnectionArgs );
353 }
354 catch(const Exception&)
355 {
356 StorageContainer::revokeStorage(sKey,nullptr);
357 throw;
358 }
359
360 // if the storage is completely empty, then we just created a new HSQLDB
361 // In this case, do some initializations.
362 if ( bIsNewDatabase && xOrig.is() )
363 onConnectedNewDatabase( xOrig );
364
365 if ( xOrig.is() )
366 {
367 // now we have to set the URL to get the correct answer for metadata()->getURL()
368 auto pMetaConnection = comphelper::getFromUnoTunnel<OMetaConnection>(xOrig);
369 if ( pMetaConnection )
370 pMetaConnection->setURL(url);
371
372 Reference<XComponent> xComp(xOrig,UNO_QUERY);
373 if ( xComp.is() )
374 xComp->addEventListener(this);
375
376 // we want to close all connections when the office shuts down
377 static Reference< XTerminateListener> s_xTerminateListener = [&]()
378 {
379 Reference< XDesktop2 > xDesktop = Desktop::create( m_xContext );
380
381 rtl::Reference<OConnectionController> tmp = new OConnectionController(this);
382 xDesktop->addTerminateListener(tmp);
383 return tmp;
384 }();
385 Reference< XComponent> xIfc = new OHsqlConnection( this, xOrig, m_xContext );
386 xConnection.set(xIfc,UNO_QUERY);
387 m_aConnections.push_back(TWeakPair(WeakReferenceHelper(xOrig),TWeakConnectionPair(sKey,TWeakRefPair(WeakReferenceHelper(xConnection),WeakReferenceHelper()))));
388
389 Reference<XTransactionBroadcaster> xBroad(xStorage,UNO_QUERY);
390 if ( xBroad.is() )
391 {
392 xBroad->addTransactionListener(Reference<XTransactionListener>(this));
393 }
394 }
395 }
396 }
397 return xConnection;
398 }
399
400
401 sal_Bool SAL_CALL ODriverDelegator::acceptsURL( const OUString& url )
402 {
403 bool bEnabled = false;
404 javaFrameworkError e = jfw_getEnabled(&bEnabled);
405 switch (e) {
406 case JFW_E_NONE:
407 break;
409 SAL_INFO(
410 "connectivity.hsqldb",
411 "jfw_getEnabled: JFW_E_DIRECT_MODE, assuming true");
412 bEnabled = true;
413 break;
414 default:
415 SAL_WARN(
416 "connectivity.hsqldb", "jfw_getEnabled: error code " << +e);
417 break;
418 }
419 return bEnabled && url == "sdbc:embedded:hsqldb";
420 }
421
422
423 Sequence< DriverPropertyInfo > SAL_CALL ODriverDelegator::getPropertyInfo( const OUString& url, const Sequence< PropertyValue >& /*info*/ )
424 {
425 if ( !acceptsURL(url) )
426 return Sequence< DriverPropertyInfo >();
427 return
428 {
429 {
430 "Storage",
431 "Defines the storage where the database will be stored.",
432 true,
433 {},
434 {}
435 },
436 {
437 "URL",
438 "Defines the url of the data source.",
439 true,
440 {},
441 {}
442 },
443 {
444 "AutoRetrievingStatement",
445 "Defines the statement which will be executed to retrieve auto increment values.",
446 false,
447 "CALL IDENTITY()",
448 {}
449 }
450 };
451 }
452
453
454 sal_Int32 SAL_CALL ODriverDelegator::getMajorVersion( )
455 {
456 return 1;
457 }
458
459
460 sal_Int32 SAL_CALL ODriverDelegator::getMinorVersion( )
461 {
462 return 0;
463 }
464
465
466 Reference< XTablesSupplier > SAL_CALL ODriverDelegator::getDataDefinitionByConnection( const Reference< XConnection >& connection )
467 {
468 ::osl::MutexGuard aGuard( m_aMutex );
469 checkDisposed(ODriverDelegator_BASE::rBHelper.bDisposed);
470
471 Reference< XTablesSupplier > xTab;
472
473 TWeakPairVector::iterator i = std::find_if(m_aConnections.begin(), m_aConnections.end(),
474 [&connection](const TWeakPairVector::value_type& rConnection) {
475 return rConnection.second.second.first.get() == connection.get(); });
476 if (i != m_aConnections.end())
477 {
478 xTab.set(i->second.second.second,UNO_QUERY);
479 if ( !xTab.is() )
480 {
481 xTab = new OHCatalog(connection);
482 i->second.second.second = WeakReferenceHelper(xTab);
483 }
484 }
485
486 return xTab;
487 }
488
489
490 Reference< XTablesSupplier > SAL_CALL ODriverDelegator::getDataDefinitionByURL( const OUString& url, const Sequence< PropertyValue >& info )
491 {
492 if ( ! acceptsURL(url) )
493 {
495 const OUString sMessage = aResources.getResourceString(STR_URI_SYNTAX_ERROR);
497 }
498
499 return getDataDefinitionByConnection(connect(url,info));
500 }
501
502 // XServiceInfo
503
504 OUString SAL_CALL ODriverDelegator::getImplementationName( )
505 {
506 return IMPL_NAME;
507 }
508
509 sal_Bool SAL_CALL ODriverDelegator::supportsService( const OUString& _rServiceName )
510 {
511 return cppu::supportsService(this, _rServiceName);
512 }
513
514 Sequence< OUString > SAL_CALL ODriverDelegator::getSupportedServiceNames( )
515 {
516 return { "com.sun.star.sdbc.Driver", "com.sun.star.sdbcx.Driver" };
517 }
518
519 void SAL_CALL ODriverDelegator::createCatalog( const Sequence< PropertyValue >& /*info*/ )
520 {
521 ::dbtools::throwFeatureNotImplementedSQLException( "XCreateCatalog::createCatalog", *this );
522 }
523
524 void ODriverDelegator::shutdownConnection(const TWeakPairVector::iterator& _aIter )
525 {
526 OSL_ENSURE(m_aConnections.end() != _aIter,"Iterator equals .end()");
527 bool bLastOne = true;
528 try
529 {
530 Reference<XConnection> _xConnection(_aIter->first.get(),UNO_QUERY);
531
532 if ( _xConnection.is() )
533 {
534 Reference<XStatement> xStmt = _xConnection->createStatement();
535 if ( xStmt.is() )
536 {
537 Reference<XResultSet> xRes = xStmt->executeQuery("SELECT COUNT(*) FROM INFORMATION_SCHEMA.SYSTEM_SESSIONS WHERE USER_NAME ='SA'");
538 Reference<XRow> xRow(xRes,UNO_QUERY);
539 if ( xRow.is() && xRes->next() )
540 bLastOne = xRow->getInt(1) == 1;
541 if ( bLastOne )
542 xStmt->execute("SHUTDOWN");
543 }
544 }
545 }
546 catch(Exception&)
547 {
548 }
549 if ( bLastOne )
550 {
551 // Reference<XTransactionListener> xListener(*this,UNO_QUERY);
552 // a shutdown should commit all changes to the db files
553 StorageContainer::revokeStorage(_aIter->second.first,nullptr);
554 }
555 if ( !m_bInShutDownConnections )
556 m_aConnections.erase(_aIter);
557 }
558
559 void SAL_CALL ODriverDelegator::disposing( const css::lang::EventObject& Source )
560 {
561 ::osl::MutexGuard aGuard(m_aMutex);
562 Reference<XConnection> xCon(Source.Source,UNO_QUERY);
563 if ( xCon.is() )
564 {
565 TWeakPairVector::iterator i = std::find_if(m_aConnections.begin(), m_aConnections.end(),
566 [&xCon](const TWeakPairVector::value_type& rConnection) { return rConnection.first.get() == xCon.get(); });
567
568 if (i != m_aConnections.end())
569 shutdownConnection(i);
570 }
571 else
572 {
573 Reference< XStorage> xStorage(Source.Source,UNO_QUERY);
574 if ( xStorage.is() )
575 {
576 OUString sKey = StorageContainer::getRegisteredKey(xStorage);
577 TWeakPairVector::iterator i = std::find_if(m_aConnections.begin(),m_aConnections.end(),
578 [&sKey] (const TWeakPairVector::value_type& conn) {
579 return conn.second.first == sKey;
580 });
581
582 if ( i != m_aConnections.end() )
583 shutdownConnection(i);
584 }
585 }
586 }
587
588 void ODriverDelegator::shutdownConnections()
589 {
590 m_bInShutDownConnections = true;
591 for (const auto& rConnection : m_aConnections)
592 {
593 try
594 {
595 Reference<XConnection> xCon(rConnection.first,UNO_QUERY);
596 ::comphelper::disposeComponent(xCon);
597 }
598 catch(Exception&)
599 {
600 }
601 }
602 m_aConnections.clear();
603 m_bInShutDownConnections = true;
604 }
605
606 void ODriverDelegator::flushConnections()
607 {
608 for (const auto& rConnection : m_aConnections)
609 {
610 try
611 {
612 Reference<XFlushable> xCon(rConnection.second.second.first.get(),UNO_QUERY);
613 if (xCon.is())
614 xCon->flush();
615 }
616 catch(Exception&)
617 {
618 DBG_UNHANDLED_EXCEPTION("connectivity.hsqldb");
619 }
620 }
621 }
622
623 void SAL_CALL ODriverDelegator::preCommit( const css::lang::EventObject& aEvent )
624 {
625 ::osl::MutexGuard aGuard(m_aMutex);
626
627 Reference< XStorage> xStorage(aEvent.Source,UNO_QUERY);
628 OUString sKey = StorageContainer::getRegisteredKey(xStorage);
629 if ( sKey.isEmpty() )
630 return;
631
632 TWeakPairVector::const_iterator i = std::find_if(m_aConnections.begin(), m_aConnections.end(),
633 [&sKey] (const TWeakPairVector::value_type& conn) {
634 return conn.second.first == sKey;
635 });
636
637 OSL_ENSURE( i != m_aConnections.end(), "ODriverDelegator::preCommit: they're committing a storage which I do not know!" );
638 if ( i == m_aConnections.end() )
639 return;
640
641 try
642 {
643 Reference<XConnection> xConnection(i->first,UNO_QUERY);
644 if ( xConnection.is() )
645 {
646 Reference< XStatement> xStmt = xConnection->createStatement();
647 OSL_ENSURE( xStmt.is(), "ODriverDelegator::preCommit: no statement!" );
648 if ( xStmt.is() )
649 xStmt->execute( "SET WRITE_DELAY 0" );
650
651 bool bPreviousAutoCommit = xConnection->getAutoCommit();
652 xConnection->setAutoCommit( false );
653 xConnection->commit();
654 xConnection->setAutoCommit( bPreviousAutoCommit );
655
656 if ( xStmt.is() )
657 xStmt->execute( "SET WRITE_DELAY 60" );
658 }
659 }
660 catch(Exception&)
661 {
662 TOOLS_WARN_EXCEPTION( "connectivity.hsqldb", "ODriverDelegator::preCommit" );
663 }
664 }
665
666 void SAL_CALL ODriverDelegator::commited( const css::lang::EventObject& /*aEvent*/ )
667 {
668 }
669
670 void SAL_CALL ODriverDelegator::preRevert( const css::lang::EventObject& /*aEvent*/ )
671 {
672 }
673
674 void SAL_CALL ODriverDelegator::reverted( const css::lang::EventObject& /*aEvent*/ )
675 {
676 }
677
678 namespace
679 {
680
681 const char* lcl_getCollationForLocale( const OUString& _rLocaleString, bool _bAcceptCountryMismatch = false )
682 {
683 static const char* pTranslations[] =
684 {
685 "af-ZA", "Afrikaans",
686 "am-ET", "Amharic",
687 "ar", "Arabic",
688 "as-IN", "Assamese",
689 "az-AZ", "Azerbaijani_Latin",
690 "az-cyrillic", "Azerbaijani_Cyrillic",
691 "be-BY", "Belarusian",
692 "bg-BG", "Bulgarian",
693 "bn-IN", "Bengali",
694 "bo-CN", "Tibetan",
695 "bs-BA", "Bosnian",
696 "ca-ES", "Catalan",
697 "cs-CZ", "Czech",
698 "cy-GB", "Welsh",
699 "da-DK", "Danish",
700 "de-DE", "German",
701 "el-GR", "Greek",
702 "en-US", "Latin1_General",
703 "es-ES", "Spanish",
704 "et-EE", "Estonian",
705 "eu", "Basque",
706 "fi-FI", "Finnish",
707 "fr-FR", "French",
708 "gn-PY", "Guarani",
709 "gu-IN", "Gujarati",
710 "ha-NG", "Hausa",
711 "he-IL", "Hebrew",
712 "hi-IN", "Hindi",
713 "hr-HR", "Croatian",
714 "hu-HU", "Hungarian",
715 "hy-AM", "Armenian",
716 "id-ID", "Indonesian",
717 "ig-NG", "Igbo",
718 "is-IS", "Icelandic",
719 "it-IT", "Italian",
720 "iu-CA", "Inuktitut",
721 "ja-JP", "Japanese",
722 "ka-GE", "Georgian",
723 "kk-KZ", "Kazakh",
724 "km-KH", "Khmer",
725 "kn-IN", "Kannada",
726 "ko-KR", "Korean",
727 "kok-IN", "Konkani",
728 "ks", "Kashmiri",
729 "ky-KG", "Kirghiz",
730 "lo-LA", "Lao",
731 "lt-LT", "Lithuanian",
732 "lv-LV", "Latvian",
733 "mi-NZ", "Maori",
734 "mk-MK", "Macedonian",
735 "ml-IN", "Malayalam",
736 "mn-MN", "Mongolian",
737 "mni-IN", "Manipuri",
738 "mr-IN", "Marathi",
739 "ms-MY", "Malay",
740 "mt-MT", "Maltese",
741 "my-MM", "Burmese",
742 "nb-NO", "Danish_Norwegian",
743 "ne-NP", "Nepali",
744 "nl-NL", "Dutch",
745 "nn-NO", "Norwegian",
746 "or-IN", "Odia",
747 "pa-IN", "Punjabi",
748 "pl-PL", "Polish",
749 "ps-AF", "Pashto",
750 "pt-PT", "Portuguese",
751 "ro-RO", "Romanian",
752 "ru-RU", "Russian",
753 "sa-IN", "Sanskrit",
754 "sd-IN", "Sindhi",
755 "sk-SK", "Slovak",
756 "sl-SI", "Slovenian",
757 "so-SO", "Somali",
758 "sq-AL", "Albanian",
759 "sr-YU", "Serbian_Cyrillic",
760 "sv-SE", "Swedish",
761 "sw-KE", "Swahili",
762 "ta-IN", "Tamil",
763 "te-IN", "Telugu",
764 "tg-TJ", "Tajik",
765 "th-TH", "Thai",
766 "tk-TM", "Turkmen",
767 "tn-BW", "Tswana",
768 "tr-TR", "Turkish",
769 "tt-RU", "Tatar",
770 "uk-UA", "Ukrainian",
771 "ur-PK", "Urdu",
772 "uz-UZ", "Uzbek_Latin",
773 "ven-ZA", "Venda",
774 "vi-VN", "Vietnamese",
775 "yo-NG", "Yoruba",
776 "zh-CN", "Chinese",
777 "zu-ZA", "Zulu",
778 nullptr, nullptr
779 };
780
781 OUString sLocaleString( _rLocaleString );
782 char nCompareTermination = 0;
783
784 if ( _bAcceptCountryMismatch )
785 {
786 // strip the country part from the compare string
787 sal_Int32 nCountrySep = sLocaleString.indexOf( '-' );
788 if ( nCountrySep > -1 )
789 sLocaleString = sLocaleString.copy( 0, nCountrySep );
790
791 // the entries in the translation table are compared until the
792 // - character only, not until the terminating 0
793 nCompareTermination = '-';
794 }
795
796 const char** pLookup = pTranslations;
797 for ( ; *pLookup; pLookup +=2 )
798 {
799 sal_Int32 nCompareUntil = 0;
800 while ( (*pLookup)[ nCompareUntil ] != nCompareTermination && (*pLookup)[ nCompareUntil ] != 0 )
801 ++nCompareUntil;
802
803 if ( sLocaleString.equalsAsciiL( *pLookup, nCompareUntil ) )
804 return *( pLookup + 1 );
805 }
806
807 if ( !_bAcceptCountryMismatch )
808 // second round, this time without matching the country
809 return lcl_getCollationForLocale( _rLocaleString, true );
810
811 OSL_FAIL( "lcl_getCollationForLocale: unknown locale string, falling back to Latin1_General!" );
812 return "Latin1_General";
813 }
814
815
816 OUString lcl_getSystemLocale( const Reference< XComponentContext >& _rxContext )
817 {
818 OUString sLocaleString = "en-US";
819 try
820 {
821
822 Reference< XMultiServiceFactory > xConfigProvider(
823 css::configuration::theDefaultProvider::get( _rxContext ) );
824
825
826 // arguments for creating the config access
828 {
829 {"nodepath", Any(OUString("/org.openoffice.Setup/L10N" ))}, // the path to the node to open
830 {"depth", Any(sal_Int32(-1))}, // the depth: -1 means unlimited
831 }));
832 // create the access
833 Reference< XPropertySet > xNode(
834 xConfigProvider->createInstanceWithArguments(
835 "com.sun.star.configuration.ConfigurationAccess",
836 aArguments ),
837 UNO_QUERY );
838 OSL_ENSURE( xNode.is(), "lcl_getSystemLocale: invalid access returned (should throw an exception instead)!" );
839
840
841 // ask for the system locale setting
842 if ( xNode.is() )
843 xNode->getPropertyValue("ooSetupSystemLocale") >>= sLocaleString;
844 }
845 catch( const Exception& )
846 {
847 TOOLS_WARN_EXCEPTION( "connectivity.hsqldb", "lcl_getSystemLocale" );
848 }
849 if ( sLocaleString.isEmpty() )
850 {
851 rtl_Locale* pProcessLocale = nullptr;
852 osl_getProcessLocale( &pProcessLocale );
853 sLocaleString = LanguageTag( *pProcessLocale).getBcp47();
854 }
855 return sLocaleString;
856 }
857 }
858
859 void ODriverDelegator::onConnectedNewDatabase( const Reference< XConnection >& _rxConnection )
860 {
861 try
862 {
863 Reference< XStatement > xStatement = _rxConnection->createStatement();
864 OSL_ENSURE( xStatement.is(), "ODriverDelegator::onConnectedNewDatabase: could not create a statement!" );
865 if ( xStatement.is() )
866 {
867 OUStringBuffer aStatement( "SET DATABASE COLLATION \"" );
868 aStatement.appendAscii( lcl_getCollationForLocale( lcl_getSystemLocale( m_xContext ) ) );
869 aStatement.append( "\"" );
870
871 xStatement->execute( aStatement.makeStringAndClear() );
872 }
873 }
874 catch( const Exception& )
875 {
876 TOOLS_WARN_EXCEPTION( "connectivity.hsqldb", "ODriverDelegator::onConnectedNewDatabase" );
877 }
878 }
879
880
881} // namespace connectivity
882
883
884extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
886 css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
887{
888 return cppu::acquire(new connectivity::ODriverDelegator(context));
889}
890
891
892/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
SAL_DLLPUBLIC_EXPORT css::uno::XInterface * connectivity_hsqldb_ODriverDelegator_implementation(css::uno::XComponentContext *context, css::uno::Sequence< css::uno::Any > const &)
Definition: HDriver.cxx:885
Reference< XComponentContext > m_xContext
PropertiesInfo aProperties
Reference< XInputStream > xStream
AnyEventRef aEvent
const OUString & getBcp47(bool bResolveSystem=true) const
helper class for accessing resources shared by different libraries in the connectivity module
OUString getResourceString(TranslateId pResId) const
loads a string from the shared resource file
delegates all calls to the original driver and extend the existing one with the SDBCX layer.
Definition: HDriver.hxx:53
ODriverDelegator(const css::uno::Reference< css::uno::XComponentContext > &_rxContext)
creates a new delegator for a HSQLDB driver
static OConfigurationTreeRoot createWithComponentContext(const css::uno::Reference< css::uno::XComponentContext > &_rxContext, const OUString &_rPath, sal_Int32 _nDepth=-1, CREATION_MODE _eMode=CM_UPDATABLE)
static std::unique_ptr< SvStream > CreateStream(const OUString &rFileName, StreamMode eOpenMode, css::uno::Reference< css::awt::XWindow > xParentWin=nullptr)
#define TOOLS_WARN_EXCEPTION(area, stream)
#define DBG_UNHANDLED_EXCEPTION(...)
float u
javaFrameworkError jfw_getEnabled(bool *pbEnabled)
std::mutex m_aMutex
javaFrameworkError
JFW_E_DIRECT_MODE
JFW_E_NONE
Sequence< PropertyValue > aArguments
#define SAL_WARN(area, stream)
#define SAL_INFO(area, stream)
@ Exception
css::uno::Sequence< css::uno::Any > InitAnyPropertySequence(::std::initializer_list< ::std::pair< OUString, css::uno::Any > > vInit)
std::pair< css::uno::WeakReferenceHelper, css::uno::WeakReferenceHelper > TWeakRefPair
Definition: HDriver.hxx:41
std::pair< css::uno::WeakReferenceHelper, TWeakConnectionPair > TWeakPair
Definition: HDriver.hxx:44
std::pair< OUString,TWeakRefPair > TWeakConnectionPair
Definition: HDriver.hxx:42
::cppu::WeakComponentImplHelper< css::sdbc::XDriver, css::sdbcx::XDataDefinitionSupplier, css::lang::XServiceInfo, css::sdbcx::XCreateCatalog, css::embed::XTransactionListener > ODriverDelegator_BASE
Definition: HDriver.hxx:39
std::vector< TWeakPair > TWeakPairVector
Definition: HDriver.hxx:45
constexpr OUStringLiteral IMPL_NAME
Definition: HDriver.cxx:74
void checkDisposed(bool _bThrow)
Definition: dbtools.cxx:1951
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
void throwFeatureNotImplementedSQLException(const OUString &_rFeatureName, const Reference< XInterface > &_rxContext, const Any &_rNextException)
void throwGenericSQLException(const OUString &_rMsg, const css::uno::Reference< css::uno::XInterface > &_rxSource)
throw a generic SQLException, i.e.
int i
sal_Int32 toInt32(std::u16string_view str, sal_Int16 radix=10)
std::basic_string_view< charT, traits > getToken(std::basic_string_view< charT, traits > sv, charT delimiter, std::size_t &position)
OUString sMessage
unsigned char sal_Bool
constexpr OUStringLiteral sScript