diff options
Diffstat (limited to '')
21 files changed, 4717 insertions, 0 deletions
diff --git a/connectivity/source/drivers/hsqldb/HCatalog.cxx b/connectivity/source/drivers/hsqldb/HCatalog.cxx new file mode 100644 index 000000000..1074be535 --- /dev/null +++ b/connectivity/source/drivers/hsqldb/HCatalog.cxx @@ -0,0 +1,148 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <hsqldb/HCatalog.hxx> +#include <hsqldb/HUsers.hxx> +#include <hsqldb/HTables.hxx> +#include <hsqldb/HViews.hxx> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <comphelper/types.hxx> + + +using namespace connectivity; +using namespace connectivity::hsqldb; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; + +OHCatalog::OHCatalog(const Reference< XConnection >& _xConnection) : sdbcx::OCatalog(_xConnection) + ,m_xConnection(_xConnection) +{ +} + +void OHCatalog::refreshObjects(const Sequence< OUString >& _sKindOfObject,::std::vector< OUString>& _rNames) +{ + Reference< XResultSet > xResult = m_xMetaData->getTables(Any(), + "%", + "%", + _sKindOfObject); + fillNames(xResult,_rNames); +} + +void OHCatalog::refreshTables() +{ + ::std::vector< OUString> aVector; + + Sequence< OUString > sTableTypes {"VIEW", "TABLE"}; + + refreshObjects(sTableTypes,aVector); + + if ( m_pTables ) + m_pTables->reFill(aVector); + else + m_pTables.reset( new OTables(m_xMetaData,*this,m_aMutex,aVector) ); +} + +void OHCatalog::refreshViews() +{ + Sequence< OUString > aTypes { "VIEW" }; + + bool bSupportsViews = false; + try + { + Reference<XResultSet> xRes = m_xMetaData->getTableTypes(); + Reference<XRow> xRow(xRes,UNO_QUERY); + while ( xRow.is() && xRes->next() ) + { + if ( (bSupportsViews = xRow->getString(1).equalsIgnoreAsciiCase(aTypes[0])) ) + { + break; + } + } + } + catch(const SQLException&) + { + } + + ::std::vector< OUString> aVector; + if ( bSupportsViews ) + refreshObjects(aTypes,aVector); + + if ( m_pViews ) + m_pViews->reFill(aVector); + else + m_pViews.reset( new HViews( m_xConnection, *this, m_aMutex, aVector ) ); +} + +void OHCatalog::refreshGroups() +{ +} + +void OHCatalog::refreshUsers() +{ + ::std::vector< OUString> aVector; + Reference< XStatement > xStmt = m_xConnection->createStatement( ); + Reference< XResultSet > xResult = xStmt->executeQuery("select User from hsqldb.user group by User"); + if ( xResult.is() ) + { + Reference< XRow > xRow(xResult,UNO_QUERY); + while( xResult->next() ) + aVector.push_back(xRow->getString(1)); + ::comphelper::disposeComponent(xResult); + } + ::comphelper::disposeComponent(xStmt); + + if(m_pUsers) + m_pUsers->reFill(aVector); + else + m_pUsers.reset( new OUsers(*this,m_aMutex,aVector,m_xConnection,this) ); +} + +Any SAL_CALL OHCatalog::queryInterface( const Type & rType ) +{ + if ( rType == cppu::UnoType<XGroupsSupplier>::get()) + return Any(); + + return OCatalog::queryInterface(rType); +} + +Sequence< Type > SAL_CALL OHCatalog::getTypes( ) +{ + Sequence< Type > aTypes = OCatalog::getTypes(); + std::vector<Type> aOwnTypes; + aOwnTypes.reserve(aTypes.getLength()); + const Type* pBegin = aTypes.getConstArray(); + const Type* pEnd = pBegin + aTypes.getLength(); + for(;pBegin != pEnd;++pBegin) + { + if ( *pBegin != cppu::UnoType<XGroupsSupplier>::get()) + { + aOwnTypes.push_back(*pBegin); + } + } + return Sequence< Type >(aOwnTypes.data(), aOwnTypes.size()); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/hsqldb/HColumns.cxx b/connectivity/source/drivers/hsqldb/HColumns.cxx new file mode 100644 index 000000000..3f03c3616 --- /dev/null +++ b/connectivity/source/drivers/hsqldb/HColumns.cxx @@ -0,0 +1,76 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <hsqldb/HColumns.hxx> +#include <TConnection.hxx> + + +using namespace ::comphelper; +using namespace connectivity::hsqldb; +using namespace connectivity::sdbcx; +using namespace connectivity; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; + +OHSQLColumns::OHSQLColumns( ::cppu::OWeakObject& _rParent + ,::osl::Mutex& _rMutex + ,const ::std::vector< OUString> &_rVector + ) : OColumnsHelper(_rParent,true/*_bCase*/,_rMutex,_rVector,true/*_bUseHardRef*/) +{ +} + +Reference< XPropertySet > OHSQLColumns::createDescriptor() +{ + return new OHSQLColumn; +} + + +OHSQLColumn::OHSQLColumn() + : connectivity::sdbcx::OColumn( true/*_bCase*/ ) +{ + construct(); +} + +void OHSQLColumn::construct() +{ + m_sAutoIncrement = "IDENTITY"; + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_AUTOINCREMENTCREATION),PROPERTY_ID_AUTOINCREMENTCREATION,0,&m_sAutoIncrement, cppu::UnoType<decltype(m_sAutoIncrement)>::get()); +} + +::cppu::IPropertyArrayHelper* OHSQLColumn::createArrayHelper( sal_Int32 /*_nId*/ ) const +{ + return doCreateArrayHelper(); +} + +::cppu::IPropertyArrayHelper & SAL_CALL OHSQLColumn::getInfoHelper() +{ + return *OHSQLColumn_PROP::getArrayHelper(isNew() ? 1 : 0); +} + +Sequence< OUString > SAL_CALL OHSQLColumn::getSupportedServiceNames( ) +{ + return { "com.sun.star.sdbcx.Column" }; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/hsqldb/HConnection.cxx b/connectivity/source/drivers/hsqldb/HConnection.cxx new file mode 100644 index 000000000..506bf5b07 --- /dev/null +++ b/connectivity/source/drivers/hsqldb/HConnection.cxx @@ -0,0 +1,337 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include <hsqldb/HConnection.hxx> +#include <hsqldb/HTools.hxx> +#include <bitmaps.hlst> + +#include <connectivity/dbtools.hxx> + +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/sdbcx/XDataDefinitionSupplier.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/graphic/GraphicProvider.hpp> +#include <com/sun/star/graphic/XGraphicProvider.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/sdbc/XDatabaseMetaData2.hpp> + +#include <comphelper/propertyvalue.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <rtl/ustrbuf.hxx> +#include <sal/log.hxx> +#include <tools/diagnose_ex.h> + +#include <resource/sharedresources.hxx> +#include <strings.hrc> + +using ::com::sun::star::util::XFlushListener; +using ::com::sun::star::lang::EventObject; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Exception; +using ::com::sun::star::uno::RuntimeException; +using ::com::sun::star::uno::UNO_QUERY; +using ::com::sun::star::uno::UNO_QUERY_THROW; +using ::com::sun::star::uno::XComponentContext; +using ::com::sun::star::sdbc::XStatement; +using ::com::sun::star::sdbc::XConnection; +using ::com::sun::star::sdbcx::XDataDefinitionSupplier; +using ::com::sun::star::sdbcx::XTablesSupplier; +using ::com::sun::star::container::XNameAccess; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::lang::WrappedTargetException; +using ::com::sun::star::sdbc::XDriver; +using ::com::sun::star::graphic::XGraphic; +using ::com::sun::star::graphic::GraphicProvider; +using ::com::sun::star::graphic::XGraphicProvider; +using ::com::sun::star::uno::XInterface; +using ::com::sun::star::lang::IllegalArgumentException; +using ::com::sun::star::sdbc::XResultSet; +using ::com::sun::star::sdbc::XDatabaseMetaData; +using ::com::sun::star::sdbc::XDatabaseMetaData2; +using ::com::sun::star::sdbc::XRow; +using ::com::sun::star::sdb::application::XDatabaseDocumentUI; +using ::com::sun::star::beans::PropertyValue; + + +namespace connectivity::hsqldb +{ + void SAL_CALL OHsqlConnection::disposing() + { + m_aFlushListeners.disposeAndClear( EventObject( *this ) ); + OHsqlConnection_BASE::disposing(); + OConnectionWrapper::disposing(); + } + + OHsqlConnection::OHsqlConnection( const Reference< XDriver >& _rxDriver, + const Reference< XConnection >& _xConnection ,const Reference< XComponentContext >& _rxContext ) + :OHsqlConnection_BASE( m_aMutex ) + ,m_aFlushListeners( m_aMutex ) + ,m_xDriver( _rxDriver ) + ,m_xContext( _rxContext ) + ,m_bIni(true) + ,m_bReadOnly(false) + { + setDelegation(_xConnection,_rxContext,m_refCount); + } + + OHsqlConnection::~OHsqlConnection() + { + if ( !OHsqlConnection_BASE::rBHelper.bDisposed ) + { + osl_atomic_increment( &m_refCount ); + dispose(); + } + } + + IMPLEMENT_FORWARD_XINTERFACE2(OHsqlConnection,OHsqlConnection_BASE,OConnectionWrapper) + IMPLEMENT_SERVICE_INFO(OHsqlConnection, "com.sun.star.sdbc.drivers.hsqldb.OHsqlConnection", "com.sun.star.sdbc.Connection") + IMPLEMENT_FORWARD_XTYPEPROVIDER2(OHsqlConnection,OHsqlConnection_BASE,OConnectionWrapper) + + + ::osl::Mutex& OHsqlConnection::getMutex() const + { + return m_aMutex; + } + + + void OHsqlConnection::checkDisposed() const + { + ::connectivity::checkDisposed( rBHelper.bDisposed ); + } + + // XFlushable + + void SAL_CALL OHsqlConnection::flush( ) + { + MethodGuard aGuard( *this ); + + try + { + if ( m_xConnection.is() ) + { + if ( m_bIni ) + { + m_bIni = false; + Reference< XDatabaseMetaData2 > xMeta2(m_xConnection->getMetaData(),UNO_QUERY_THROW); + const Sequence< PropertyValue > aInfo = xMeta2->getConnectionInfo(); + const PropertyValue* pIter = aInfo.getConstArray(); + const PropertyValue* pEnd = pIter + aInfo.getLength(); + for(;pIter != pEnd;++pIter) + { + if ( pIter->Name == "readonly" ) + m_bReadOnly = true; + } + } + try + { + if ( !m_bReadOnly ) + { + Reference< XStatement > xStmt( m_xConnection->createStatement(), css::uno::UNO_SET_THROW ); + xStmt->execute( "CHECKPOINT DEFRAG" ); + } + } + catch(const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("connectivity.hsqldb"); + } + } + + EventObject aFlushedEvent( *this ); + m_aFlushListeners.notifyEach( &XFlushListener::flushed, aFlushedEvent ); + } + catch(const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("connectivity.hsqldb"); + } + } + + + void SAL_CALL OHsqlConnection::addFlushListener( const Reference< XFlushListener >& l ) + { + MethodGuard aGuard( *this ); + m_aFlushListeners.addInterface( l ); + } + + + void SAL_CALL OHsqlConnection::removeFlushListener( const Reference< XFlushListener >& l ) + { + MethodGuard aGuard( *this ); + m_aFlushListeners.removeInterface( l ); + } + + + Reference< XGraphic > SAL_CALL OHsqlConnection::getTableIcon( const OUString& TableName, ::sal_Int32 /*_ColorMode*/ ) + { + MethodGuard aGuard( *this ); + + impl_checkExistingTable_throw( TableName ); + if ( !impl_isTextTable_nothrow( TableName ) ) + return nullptr; + + return impl_getTextTableIcon_nothrow(); + } + + + Reference< XInterface > SAL_CALL OHsqlConnection::getTableEditor( const Reference< XDatabaseDocumentUI >& DocumentUI, const OUString& TableName ) + { + MethodGuard aGuard( *this ); + + impl_checkExistingTable_throw( TableName ); + if ( !impl_isTextTable_nothrow( TableName ) ) + return nullptr; + + if ( !DocumentUI.is() ) + { + ::connectivity::SharedResources aResources; + const OUString sError( aResources.getResourceString(STR_NO_DOCUMENTUI)); + throw IllegalArgumentException( + sError, + *this, + 0 + ); + } // if ( !_DocumentUI.is() ) + + +// Reference< XExecutableDialog > xEditor = impl_createLinkedTableEditor_throw( _DocumentUI, _TableName ); +// return xEditor.get(); + return nullptr; + // editor not yet implemented in this CWS + } + + + Reference< XNameAccess > OHsqlConnection::impl_getTableContainer_throw() + { + Reference< XNameAccess > xTables; + try + { + Reference< XConnection > xMe( *this, UNO_QUERY ); + Reference< XDataDefinitionSupplier > xDefinitionsSupp( m_xDriver, UNO_QUERY_THROW ); + Reference< XTablesSupplier > xTablesSupp( xDefinitionsSupp->getDataDefinitionByConnection( xMe ), css::uno::UNO_SET_THROW ); + xTables.set( xTablesSupp->getTables(), css::uno::UNO_SET_THROW ); + } + catch( const RuntimeException& ) { throw; } + catch( const Exception& ) + { + css::uno::Any anyEx = cppu::getCaughtException(); + ::connectivity::SharedResources aResources; + const OUString sError( aResources.getResourceString(STR_NO_TABLE_CONTAINER)); + throw WrappedTargetException( sError ,*this, anyEx ); + } + + SAL_WARN_IF( !xTables.is(), "connectivity.hsqldb", "OHsqlConnection::impl_getTableContainer_throw: post condition not met!" ); + return xTables; + } + + //TODO: resource + + void OHsqlConnection::impl_checkExistingTable_throw( const OUString& _rTableName ) + { + bool bDoesExist = false; + try + { + Reference< XNameAccess > xTables( impl_getTableContainer_throw(), css::uno::UNO_SET_THROW ); + bDoesExist = xTables->hasByName( _rTableName ); + } + catch( const Exception& ) + { + // that's a serious error in impl_getTableContainer_throw, or hasByName, however, we're only + // allowed to throw an IllegalArgumentException ourself + DBG_UNHANDLED_EXCEPTION("connectivity.hsqldb"); + } + + if ( !bDoesExist ) + { + ::connectivity::SharedResources aResources; + const OUString sError( aResources.getResourceStringWithSubstitution( + STR_NO_TABLENAME, + "$tablename$", _rTableName + )); + throw IllegalArgumentException( sError,*this, 0 ); + } // if ( !bDoesExist ) + } + + + bool OHsqlConnection::impl_isTextTable_nothrow( const OUString& _rTableName ) + { + bool bIsTextTable = false; + try + { + Reference< XConnection > xMe( *this, UNO_QUERY_THROW ); + + // split the fully qualified name + Reference< XDatabaseMetaData > xMetaData( xMe->getMetaData(), css::uno::UNO_SET_THROW ); + OUString sCatalog, sSchema, sName; + ::dbtools::qualifiedNameComponents( xMetaData, _rTableName, sCatalog, sSchema, sName, ::dbtools::EComposeRule::Complete ); + + // get the table information + OUStringBuffer sSQL; + sSQL.append( "SELECT HSQLDB_TYPE FROM INFORMATION_SCHEMA.SYSTEM_TABLES" ); + HTools::appendTableFilterCrit( sSQL, sCatalog, sSchema, sName, true ); + sSQL.append( " AND TABLE_TYPE = 'TABLE'" ); + + Reference< XStatement > xStatement( xMe->createStatement(), css::uno::UNO_SET_THROW ); + Reference< XResultSet > xTableHsqlType( xStatement->executeQuery( sSQL.makeStringAndClear() ), css::uno::UNO_SET_THROW ); + + if ( xTableHsqlType->next() ) // might not succeed in case of VIEWs + { + Reference< XRow > xValueAccess( xTableHsqlType, UNO_QUERY_THROW ); + OUString sTableType = xValueAccess->getString( 1 ); + bIsTextTable = sTableType == "TEXT"; + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("connectivity.hsqldb"); + } + + return bIsTextTable; + } + + + Reference< XGraphic > OHsqlConnection::impl_getTextTableIcon_nothrow() + { + Reference< XGraphic > xGraphic; + try + { + // create a graphic provider + Reference< XGraphicProvider > xProvider; + if ( m_xContext.is() ) + xProvider.set( GraphicProvider::create(m_xContext) ); + + // ask the provider to obtain a graphic + Sequence< PropertyValue > aMediaProperties{ comphelper::makePropertyValue( + "URL", OUString( + // load the graphic from the global graphic repository + "private:graphicrepository/" + // the relative path within the images.zip + LINKED_TEXT_TABLE_IMAGE_RESOURCE)) }; + xGraphic = xProvider->queryGraphic( aMediaProperties ); + OSL_ENSURE( xGraphic.is(), "OHsqlConnection::impl_getTextTableIcon_nothrow: the provider did not give us a graphic object!" ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("connectivity.hsqldb"); + } + return xGraphic; + } + +} // namespace connectivity::hsqldb + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/hsqldb/HDriver.cxx b/connectivity/source/drivers/hsqldb/HDriver.cxx new file mode 100644 index 000000000..c18a46e84 --- /dev/null +++ b/connectivity/source/drivers/hsqldb/HDriver.cxx @@ -0,0 +1,894 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <hsqldb/HDriver.hxx> +#include <hsqldb/HConnection.hxx> +#include <osl/diagnose.h> +#include <sal/log.hxx> +#include <connectivity/dbexception.hxx> +#include <com/sun/star/configuration/theDefaultProvider.hpp> +#include <com/sun/star/sdbc/DriverManager.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/embed/XTransactionBroadcaster.hpp> +#include <com/sun/star/embed/ElementModes.hpp> +#include <TConnection.hxx> +#include <hsqldb/HStorageMap.hxx> +#include <jvmfwk/framework.hxx> +#include <com/sun/star/reflection/XProxyFactory.hpp> +#include <com/sun/star/embed/XStorage.hpp> +#include <com/sun/star/frame/Desktop.hpp> +#include <com/sun/star/util/XFlushable.hpp> +#include "HTerminateListener.hxx" +#include <hsqldb/HCatalog.hxx> +#include <rtl/ustrbuf.hxx> +#include <osl/file.h> +#include <osl/process.h> +#include <comphelper/namedvaluecollection.hxx> +#include <comphelper/propertysequence.hxx> +#include <comphelper/servicehelper.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <comphelper/types.hxx> +#include <unotools/confignode.hxx> +#include <unotools/ucbstreamhelper.hxx> +#include <strings.hrc> +#include <resource/sharedresources.hxx> +#include <i18nlangtag/languagetag.hxx> +#include <tools/diagnose_ex.h> +#include <o3tl/string_view.hxx> + +#include <memory> + + +namespace connectivity +{ + + using namespace hsqldb; + using namespace css::uno; + using namespace css::sdbc; + using namespace css::sdbcx; + using namespace css::beans; + using namespace css::frame; + using namespace css::lang; + using namespace css::embed; + using namespace css::io; + using namespace css::util; + using namespace css::reflection; + + constexpr OUStringLiteral IMPL_NAME = u"com.sun.star.sdbcx.comp.hsqldb.Driver"; + + + + ODriverDelegator::ODriverDelegator(const Reference< XComponentContext >& _rxContext) + : ODriverDelegator_BASE(m_aMutex) + ,m_xContext(_rxContext) + ,m_bInShutDownConnections(false) + { + } + + + ODriverDelegator::~ODriverDelegator() + { + try + { + ::comphelper::disposeComponent(m_xDriver); + } + catch(const Exception&) + { + } + } + + + void SAL_CALL ODriverDelegator::disposing() + { + ::osl::MutexGuard aGuard(m_aMutex); + + try + { + for (const auto& rConnection : m_aConnections) + { + Reference<XInterface > xTemp = rConnection.first.get(); + ::comphelper::disposeComponent(xTemp); + } + } + catch(Exception&) + { + // not interested in + } + m_aConnections.clear(); + TWeakPairVector().swap(m_aConnections); + + cppu::WeakComponentImplHelperBase::disposing(); + } + + Reference< XDriver > const & ODriverDelegator::loadDriver( ) + { + if ( !m_xDriver.is() ) + { + Reference<XDriverManager2> xDriverAccess = DriverManager::create( m_xContext ); + m_xDriver = xDriverAccess->getDriverByURL("jdbc:hsqldb:db"); + } + + return m_xDriver; + } + + + namespace + { + OUString lcl_getPermittedJavaMethods_nothrow( const Reference< XComponentContext >& _rxContext ) + { + OUString aConfigPath = + "/org.openoffice.Office.DataAccess/DriverSettings/" + + IMPL_NAME + + "/PermittedJavaMethods"; + ::utl::OConfigurationTreeRoot aConfig( ::utl::OConfigurationTreeRoot::createWithComponentContext( + _rxContext, aConfigPath ) ); + + OUStringBuffer aPermittedMethods; + const Sequence< OUString > aNodeNames( aConfig.getNodeNames() ); + for ( auto const & nodeName : aNodeNames ) + { + OUString sPermittedMethod; + OSL_VERIFY( aConfig.getNodeValue( nodeName ) >>= sPermittedMethod ); + + if ( !aPermittedMethods.isEmpty() ) + aPermittedMethods.append( ';' ); + aPermittedMethods.append( sPermittedMethod ); + } + + return aPermittedMethods.makeStringAndClear(); + } + } + + + Reference< XConnection > SAL_CALL ODriverDelegator::connect( const OUString& url, const Sequence< PropertyValue >& info ) + { + Reference< XConnection > xConnection; + if ( acceptsURL(url) ) + { + Reference< XDriver > xDriver = loadDriver(); + if ( xDriver.is() ) + { + OUString sURL; + Reference<XStorage> xStorage; + const PropertyValue* pIter = info.getConstArray(); + const PropertyValue* pEnd = pIter + info.getLength(); + + for (;pIter != pEnd; ++pIter) + { + if ( pIter->Name == "Storage" ) + { + xStorage.set(pIter->Value,UNO_QUERY); + } + else if ( pIter->Name == "URL" ) + { + pIter->Value >>= sURL; + } + } + + if ( !xStorage.is() || sURL.isEmpty() ) + { + ::connectivity::SharedResources aResources; + const OUString sMessage = aResources.getResourceString(STR_NO_STORAGE); + ::dbtools::throwGenericSQLException(sMessage ,*this); + } + + OUString sSystemPath; + osl_getSystemPathFromFileURL( sURL.pData, &sSystemPath.pData ); + if ( sURL.isEmpty() || sSystemPath.isEmpty() ) + { + ::connectivity::SharedResources aResources; + const OUString sMessage = aResources.getResourceString(STR_INVALID_FILE_URL); + ::dbtools::throwGenericSQLException(sMessage ,*this); + } + + bool bIsNewDatabase = !xStorage->hasElements(); + + ::comphelper::NamedValueCollection aProperties; + + // properties for accessing the embedded storage + OUString sKey = StorageContainer::registerStorage( xStorage, sSystemPath ); + aProperties.put( "storage_key", sKey ); + aProperties.put( "storage_class_name", + OUString( "com.sun.star.sdbcx.comp.hsqldb.StorageAccess" ) ); + aProperties.put( "fileaccess_class_name", + OUString( "com.sun.star.sdbcx.comp.hsqldb.StorageFileAccess" ) ); + + // JDBC driver and driver's classpath + aProperties.put( "JavaDriverClass", + OUString( "org.hsqldb.jdbcDriver" ) ); + aProperties.put( "JavaDriverClassPath", + OUString( +#ifdef SYSTEM_HSQLDB + HSQLDB_JAR +#else + "vnd.sun.star.expand:$LO_JAVA_DIR/hsqldb.jar" +#endif + " vnd.sun.star.expand:$LO_JAVA_DIR/sdbc_hsqldb.jar" + ) ); + + // auto increment handling + aProperties.put( "IsAutoRetrievingEnabled", true ); + aProperties.put( "AutoRetrievingStatement", + OUString( "CALL IDENTITY()" ) ); + aProperties.put( "IgnoreDriverPrivileges", true ); + + // don't want to expose HSQLDB's schema capabilities which exist since 1.8.0RC10 + aProperties.put( "default_schema", + OUString( "true" ) ); + + // security: permitted Java classes + NamedValue aPermittedClasses( + "hsqldb.method_class_names", + Any( lcl_getPermittedJavaMethods_nothrow( m_xContext ) ) + ); + aProperties.put( "SystemProperties", Sequence< NamedValue >( &aPermittedClasses, 1 ) ); + + OUString sMessage; + try + { + static const OUStringLiteral sProperties( u"properties" ); + if ( !bIsNewDatabase && xStorage->isStreamElement(sProperties) ) + { + Reference<XStream > xStream = xStorage->openStreamElement(sProperties,ElementModes::READ); + if ( xStream.is() ) + { + std::unique_ptr<SvStream> pStream( ::utl::UcbStreamHelper::CreateStream(xStream) ); + if (pStream) + { + OStringBuffer sLine; + OString sVersionString; + while ( pStream->ReadLine(sLine) ) + { + if ( sLine.isEmpty() ) + continue; + sal_Int32 nIdx {0}; + const std::string_view sIniKey = o3tl::getToken(sLine, 0, '=', nIdx); + const OString sValue(o3tl::getToken(sLine, 0, '=', nIdx)); + if( sIniKey == "hsqldb.compatible_version" ) + { + sVersionString = sValue; + } + else + { + if (sIniKey == "version" && sVersionString.isEmpty()) + { + sVersionString = sValue; + } + } + } + if (!sVersionString.isEmpty()) + { + sal_Int32 nIdx {0}; + const sal_Int32 nMajor = o3tl::toInt32(o3tl::getToken(sVersionString, 0, '.', nIdx)); + const sal_Int32 nMinor = o3tl::toInt32(o3tl::getToken(sVersionString, 0, '.', nIdx)); + const sal_Int32 nMicro = o3tl::toInt32(o3tl::getToken(sVersionString, 0, '.', nIdx)); + if ( nMajor > 1 + || ( nMajor == 1 && nMinor > 8 ) + || ( nMajor == 1 && nMinor == 8 && nMicro > 0 ) ) + { + ::connectivity::SharedResources aResources; + sMessage = aResources.getResourceString(STR_ERROR_NEW_VERSION); + } + } + } + } // if ( xStream.is() ) + ::comphelper::disposeComponent(xStream); + } + + // disallow any database/script files that contain a "SCRIPT[.*]" entry (this is belt and braces + // in that bundled hsqldb 1.8.0 is patched to also reject them) + // + // hsqldb 2.6.0 release notes have: added system role SCRIPT_OPS for export / import of database structure and data + // which seems to provide a builtin way to do this with contemporary hsqldb + static const OUStringLiteral sScript(u"script"); + if (!bIsNewDatabase && xStorage->isStreamElement(sScript)) + { + Reference<XStream > xStream = xStorage->openStreamElement(sScript, ElementModes::READ); + if (xStream.is()) + { + std::unique_ptr<SvStream> pStream(::utl::UcbStreamHelper::CreateStream(xStream)); + if (pStream) + { + OStringBuffer sLine; + while (pStream->ReadLine(sLine)) + { + OString sText = sLine.makeStringAndClear().trim(); + if (sText.startsWithIgnoreAsciiCase("SCRIPT")) + { + ::connectivity::SharedResources aResources; + sMessage = aResources.getResourceString(STR_COULD_NOT_LOAD_FILE).replaceFirst("$filename$", sSystemPath); + break; + } + } + } + } // if ( xStream.is() ) + ::comphelper::disposeComponent(xStream); + } + + } + catch(Exception&) + { + } + if ( !sMessage.isEmpty() ) + { + ::dbtools::throwGenericSQLException(sMessage ,*this); + } + + // readonly? + Reference<XPropertySet> xProp(xStorage,UNO_QUERY); + if ( xProp.is() ) + { + sal_Int32 nMode = 0; + xProp->getPropertyValue("OpenMode") >>= nMode; + if ( (nMode & ElementModes::WRITE) != ElementModes::WRITE ) + { + aProperties.put( "readonly", OUString( "true" ) ); + } + } + + Sequence< PropertyValue > aConnectionArgs; + aProperties >>= aConnectionArgs; + OUString sConnectURL = "jdbc:hsqldb:" + sSystemPath; + Reference<XConnection> xOrig; + try + { + xOrig = xDriver->connect( sConnectURL, aConnectionArgs ); + } + catch(const Exception&) + { + StorageContainer::revokeStorage(sKey,nullptr); + throw; + } + + // if the storage is completely empty, then we just created a new HSQLDB + // In this case, do some initializations. + if ( bIsNewDatabase && xOrig.is() ) + onConnectedNewDatabase( xOrig ); + + if ( xOrig.is() ) + { + // now we have to set the URL to get the correct answer for metadata()->getURL() + auto pMetaConnection = comphelper::getFromUnoTunnel<OMetaConnection>(xOrig); + if ( pMetaConnection ) + pMetaConnection->setURL(url); + + Reference<XComponent> xComp(xOrig,UNO_QUERY); + if ( xComp.is() ) + xComp->addEventListener(this); + + // we want to close all connections when the office shuts down + static Reference< XTerminateListener> s_xTerminateListener = [&]() + { + Reference< XDesktop2 > xDesktop = Desktop::create( m_xContext ); + + rtl::Reference<OConnectionController> tmp = new OConnectionController(this); + xDesktop->addTerminateListener(tmp); + return tmp; + }(); + Reference< XComponent> xIfc = new OHsqlConnection( this, xOrig, m_xContext ); + xConnection.set(xIfc,UNO_QUERY); + m_aConnections.push_back(TWeakPair(WeakReferenceHelper(xOrig),TWeakConnectionPair(sKey,TWeakRefPair(WeakReferenceHelper(xConnection),WeakReferenceHelper())))); + + Reference<XTransactionBroadcaster> xBroad(xStorage,UNO_QUERY); + if ( xBroad.is() ) + { + Reference<XTransactionListener> xListener(*this,UNO_QUERY); + xBroad->addTransactionListener(xListener); + } + } + } + } + return xConnection; + } + + + sal_Bool SAL_CALL ODriverDelegator::acceptsURL( const OUString& url ) + { + bool bEnabled = false; + javaFrameworkError e = jfw_getEnabled(&bEnabled); + switch (e) { + case JFW_E_NONE: + break; + case JFW_E_DIRECT_MODE: + SAL_INFO( + "connectivity.hsqldb", + "jfw_getEnabled: JFW_E_DIRECT_MODE, assuming true"); + bEnabled = true; + break; + default: + SAL_WARN( + "connectivity.hsqldb", "jfw_getEnabled: error code " << +e); + break; + } + return bEnabled && url == "sdbc:embedded:hsqldb"; + } + + + Sequence< DriverPropertyInfo > SAL_CALL ODriverDelegator::getPropertyInfo( const OUString& url, const Sequence< PropertyValue >& /*info*/ ) + { + if ( !acceptsURL(url) ) + return Sequence< DriverPropertyInfo >(); + return + { + { + "Storage", + "Defines the storage where the database will be stored.", + true, + {}, + {} + }, + { + "URL", + "Defines the url of the data source.", + true, + {}, + {} + }, + { + "AutoRetrievingStatement", + "Defines the statement which will be executed to retrieve auto increment values.", + false, + "CALL IDENTITY()", + {} + } + }; + } + + + sal_Int32 SAL_CALL ODriverDelegator::getMajorVersion( ) + { + return 1; + } + + + sal_Int32 SAL_CALL ODriverDelegator::getMinorVersion( ) + { + return 0; + } + + + Reference< XTablesSupplier > SAL_CALL ODriverDelegator::getDataDefinitionByConnection( const Reference< XConnection >& connection ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(ODriverDelegator_BASE::rBHelper.bDisposed); + + Reference< XTablesSupplier > xTab; + + TWeakPairVector::iterator i = std::find_if(m_aConnections.begin(), m_aConnections.end(), + [&connection](const TWeakPairVector::value_type& rConnection) { + return rConnection.second.second.first.get() == connection.get(); }); + if (i != m_aConnections.end()) + { + xTab.set(i->second.second.second,UNO_QUERY); + if ( !xTab.is() ) + { + xTab = new OHCatalog(connection); + i->second.second.second = WeakReferenceHelper(xTab); + } + } + + return xTab; + } + + + Reference< XTablesSupplier > SAL_CALL ODriverDelegator::getDataDefinitionByURL( const OUString& url, const Sequence< PropertyValue >& info ) + { + if ( ! acceptsURL(url) ) + { + ::connectivity::SharedResources aResources; + const OUString sMessage = aResources.getResourceString(STR_URI_SYNTAX_ERROR); + ::dbtools::throwGenericSQLException(sMessage ,*this); + } + + return getDataDefinitionByConnection(connect(url,info)); + } + + // XServiceInfo + + OUString SAL_CALL ODriverDelegator::getImplementationName( ) + { + return IMPL_NAME; + } + + sal_Bool SAL_CALL ODriverDelegator::supportsService( const OUString& _rServiceName ) + { + return cppu::supportsService(this, _rServiceName); + } + + Sequence< OUString > SAL_CALL ODriverDelegator::getSupportedServiceNames( ) + { + return { "com.sun.star.sdbc.Driver", "com.sun.star.sdbcx.Driver" }; + } + + void SAL_CALL ODriverDelegator::createCatalog( const Sequence< PropertyValue >& /*info*/ ) + { + ::dbtools::throwFeatureNotImplementedSQLException( "XCreateCatalog::createCatalog", *this ); + } + + void ODriverDelegator::shutdownConnection(const TWeakPairVector::iterator& _aIter ) + { + OSL_ENSURE(m_aConnections.end() != _aIter,"Iterator equals .end()"); + bool bLastOne = true; + try + { + Reference<XConnection> _xConnection(_aIter->first.get(),UNO_QUERY); + + if ( _xConnection.is() ) + { + Reference<XStatement> xStmt = _xConnection->createStatement(); + if ( xStmt.is() ) + { + Reference<XResultSet> xRes = xStmt->executeQuery("SELECT COUNT(*) FROM INFORMATION_SCHEMA.SYSTEM_SESSIONS WHERE USER_NAME ='SA'"); + Reference<XRow> xRow(xRes,UNO_QUERY); + if ( xRow.is() && xRes->next() ) + bLastOne = xRow->getInt(1) == 1; + if ( bLastOne ) + xStmt->execute("SHUTDOWN"); + } + } + } + catch(Exception&) + { + } + if ( bLastOne ) + { + // Reference<XTransactionListener> xListener(*this,UNO_QUERY); + // a shutdown should commit all changes to the db files + StorageContainer::revokeStorage(_aIter->second.first,nullptr); + } + if ( !m_bInShutDownConnections ) + m_aConnections.erase(_aIter); + } + + void SAL_CALL ODriverDelegator::disposing( const css::lang::EventObject& Source ) + { + ::osl::MutexGuard aGuard(m_aMutex); + Reference<XConnection> xCon(Source.Source,UNO_QUERY); + if ( xCon.is() ) + { + TWeakPairVector::iterator i = std::find_if(m_aConnections.begin(), m_aConnections.end(), + [&xCon](const TWeakPairVector::value_type& rConnection) { return rConnection.first.get() == xCon.get(); }); + + if (i != m_aConnections.end()) + shutdownConnection(i); + } + else + { + Reference< XStorage> xStorage(Source.Source,UNO_QUERY); + if ( xStorage.is() ) + { + OUString sKey = StorageContainer::getRegisteredKey(xStorage); + TWeakPairVector::iterator i = std::find_if(m_aConnections.begin(),m_aConnections.end(), + [&sKey] (const TWeakPairVector::value_type& conn) { + return conn.second.first == sKey; + }); + + if ( i != m_aConnections.end() ) + shutdownConnection(i); + } + } + } + + void ODriverDelegator::shutdownConnections() + { + m_bInShutDownConnections = true; + for (const auto& rConnection : m_aConnections) + { + try + { + Reference<XConnection> xCon(rConnection.first,UNO_QUERY); + ::comphelper::disposeComponent(xCon); + } + catch(Exception&) + { + } + } + m_aConnections.clear(); + m_bInShutDownConnections = true; + } + + void ODriverDelegator::flushConnections() + { + for (const auto& rConnection : m_aConnections) + { + try + { + Reference<XFlushable> xCon(rConnection.second.second.first.get(),UNO_QUERY); + if (xCon.is()) + xCon->flush(); + } + catch(Exception&) + { + DBG_UNHANDLED_EXCEPTION("connectivity.hsqldb"); + } + } + } + + void SAL_CALL ODriverDelegator::preCommit( const css::lang::EventObject& aEvent ) + { + ::osl::MutexGuard aGuard(m_aMutex); + + Reference< XStorage> xStorage(aEvent.Source,UNO_QUERY); + OUString sKey = StorageContainer::getRegisteredKey(xStorage); + if ( sKey.isEmpty() ) + return; + + TWeakPairVector::const_iterator i = std::find_if(m_aConnections.begin(), m_aConnections.end(), + [&sKey] (const TWeakPairVector::value_type& conn) { + return conn.second.first == sKey; + }); + + OSL_ENSURE( i != m_aConnections.end(), "ODriverDelegator::preCommit: they're committing a storage which I do not know!" ); + if ( i == m_aConnections.end() ) + return; + + try + { + Reference<XConnection> xConnection(i->first,UNO_QUERY); + if ( xConnection.is() ) + { + Reference< XStatement> xStmt = xConnection->createStatement(); + OSL_ENSURE( xStmt.is(), "ODriverDelegator::preCommit: no statement!" ); + if ( xStmt.is() ) + xStmt->execute( "SET WRITE_DELAY 0" ); + + bool bPreviousAutoCommit = xConnection->getAutoCommit(); + xConnection->setAutoCommit( false ); + xConnection->commit(); + xConnection->setAutoCommit( bPreviousAutoCommit ); + + if ( xStmt.is() ) + xStmt->execute( "SET WRITE_DELAY 60" ); + } + } + catch(Exception&) + { + TOOLS_WARN_EXCEPTION( "connectivity.hsqldb", "ODriverDelegator::preCommit" ); + } + } + + void SAL_CALL ODriverDelegator::commited( const css::lang::EventObject& /*aEvent*/ ) + { + } + + void SAL_CALL ODriverDelegator::preRevert( const css::lang::EventObject& /*aEvent*/ ) + { + } + + void SAL_CALL ODriverDelegator::reverted( const css::lang::EventObject& /*aEvent*/ ) + { + } + + namespace + { + + const char* lcl_getCollationForLocale( const OUString& _rLocaleString, bool _bAcceptCountryMismatch = false ) + { + static const char* pTranslations[] = + { + "af-ZA", "Afrikaans", + "am-ET", "Amharic", + "ar", "Arabic", + "as-IN", "Assamese", + "az-AZ", "Azerbaijani_Latin", + "az-cyrillic", "Azerbaijani_Cyrillic", + "be-BY", "Belarusian", + "bg-BG", "Bulgarian", + "bn-IN", "Bengali", + "bo-CN", "Tibetan", + "bs-BA", "Bosnian", + "ca-ES", "Catalan", + "cs-CZ", "Czech", + "cy-GB", "Welsh", + "da-DK", "Danish", + "de-DE", "German", + "el-GR", "Greek", + "en-US", "Latin1_General", + "es-ES", "Spanish", + "et-EE", "Estonian", + "eu", "Basque", + "fi-FI", "Finnish", + "fr-FR", "French", + "gn-PY", "Guarani", + "gu-IN", "Gujarati", + "ha-NG", "Hausa", + "he-IL", "Hebrew", + "hi-IN", "Hindi", + "hr-HR", "Croatian", + "hu-HU", "Hungarian", + "hy-AM", "Armenian", + "id-ID", "Indonesian", + "ig-NG", "Igbo", + "is-IS", "Icelandic", + "it-IT", "Italian", + "iu-CA", "Inuktitut", + "ja-JP", "Japanese", + "ka-GE", "Georgian", + "kk-KZ", "Kazakh", + "km-KH", "Khmer", + "kn-IN", "Kannada", + "ko-KR", "Korean", + "kok-IN", "Konkani", + "ks", "Kashmiri", + "ky-KG", "Kirghiz", + "lo-LA", "Lao", + "lt-LT", "Lithuanian", + "lv-LV", "Latvian", + "mi-NZ", "Maori", + "mk-MK", "Macedonian", + "ml-IN", "Malayalam", + "mn-MN", "Mongolian", + "mni-IN", "Manipuri", + "mr-IN", "Marathi", + "ms-MY", "Malay", + "mt-MT", "Maltese", + "my-MM", "Burmese", + "nb-NO", "Danish_Norwegian", + "ne-NP", "Nepali", + "nl-NL", "Dutch", + "nn-NO", "Norwegian", + "or-IN", "Odia", + "pa-IN", "Punjabi", + "pl-PL", "Polish", + "ps-AF", "Pashto", + "pt-PT", "Portuguese", + "ro-RO", "Romanian", + "ru-RU", "Russian", + "sa-IN", "Sanskrit", + "sd-IN", "Sindhi", + "sk-SK", "Slovak", + "sl-SI", "Slovenian", + "so-SO", "Somali", + "sq-AL", "Albanian", + "sr-YU", "Serbian_Cyrillic", + "sv-SE", "Swedish", + "sw-KE", "Swahili", + "ta-IN", "Tamil", + "te-IN", "Telugu", + "tg-TJ", "Tajik", + "th-TH", "Thai", + "tk-TM", "Turkmen", + "tn-BW", "Tswana", + "tr-TR", "Turkish", + "tt-RU", "Tatar", + "uk-UA", "Ukrainian", + "ur-PK", "Urdu", + "uz-UZ", "Uzbek_Latin", + "ven-ZA", "Venda", + "vi-VN", "Vietnamese", + "yo-NG", "Yoruba", + "zh-CN", "Chinese", + "zu-ZA", "Zulu", + nullptr, nullptr + }; + + OUString sLocaleString( _rLocaleString ); + char nCompareTermination = 0; + + if ( _bAcceptCountryMismatch ) + { + // strip the country part from the compare string + sal_Int32 nCountrySep = sLocaleString.indexOf( '-' ); + if ( nCountrySep > -1 ) + sLocaleString = sLocaleString.copy( 0, nCountrySep ); + + // the entries in the translation table are compared until the + // - character only, not until the terminating 0 + nCompareTermination = '-'; + } + + const char** pLookup = pTranslations; + for ( ; *pLookup; pLookup +=2 ) + { + sal_Int32 nCompareUntil = 0; + while ( (*pLookup)[ nCompareUntil ] != nCompareTermination && (*pLookup)[ nCompareUntil ] != 0 ) + ++nCompareUntil; + + if ( sLocaleString.equalsAsciiL( *pLookup, nCompareUntil ) ) + return *( pLookup + 1 ); + } + + if ( !_bAcceptCountryMismatch ) + // second round, this time without matching the country + return lcl_getCollationForLocale( _rLocaleString, true ); + + OSL_FAIL( "lcl_getCollationForLocale: unknown locale string, falling back to Latin1_General!" ); + return "Latin1_General"; + } + + + OUString lcl_getSystemLocale( const Reference< XComponentContext >& _rxContext ) + { + OUString sLocaleString = "en-US"; + try + { + + Reference< XMultiServiceFactory > xConfigProvider( + css::configuration::theDefaultProvider::get( _rxContext ) ); + + + // arguments for creating the config access + Sequence<Any> aArguments(comphelper::InitAnyPropertySequence( + { + {"nodepath", Any(OUString("/org.openoffice.Setup/L10N" ))}, // the path to the node to open + {"depth", Any(sal_Int32(-1))}, // the depth: -1 means unlimited + })); + // create the access + Reference< XPropertySet > xNode( + xConfigProvider->createInstanceWithArguments( + "com.sun.star.configuration.ConfigurationAccess", + aArguments ), + UNO_QUERY ); + OSL_ENSURE( xNode.is(), "lcl_getSystemLocale: invalid access returned (should throw an exception instead)!" ); + + + // ask for the system locale setting + if ( xNode.is() ) + xNode->getPropertyValue("ooSetupSystemLocale") >>= sLocaleString; + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "connectivity.hsqldb", "lcl_getSystemLocale" ); + } + if ( sLocaleString.isEmpty() ) + { + rtl_Locale* pProcessLocale = nullptr; + osl_getProcessLocale( &pProcessLocale ); + sLocaleString = LanguageTag( *pProcessLocale).getBcp47(); + } + return sLocaleString; + } + } + + void ODriverDelegator::onConnectedNewDatabase( const Reference< XConnection >& _rxConnection ) + { + try + { + Reference< XStatement > xStatement = _rxConnection->createStatement(); + OSL_ENSURE( xStatement.is(), "ODriverDelegator::onConnectedNewDatabase: could not create a statement!" ); + if ( xStatement.is() ) + { + OUStringBuffer aStatement; + aStatement.append( "SET DATABASE COLLATION \"" ); + aStatement.appendAscii( lcl_getCollationForLocale( lcl_getSystemLocale( m_xContext ) ) ); + aStatement.append( "\"" ); + + xStatement->execute( aStatement.makeStringAndClear() ); + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "connectivity.hsqldb", "ODriverDelegator::onConnectedNewDatabase" ); + } + } + + +} // namespace connectivity + + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +connectivity_hsqldb_ODriverDelegator_implementation( + css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&) +{ + return cppu::acquire(new connectivity::ODriverDelegator(context)); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/hsqldb/HStorageAccess.cxx b/connectivity/source/drivers/hsqldb/HStorageAccess.cxx new file mode 100644 index 000000000..36ef9f287 --- /dev/null +++ b/connectivity/source/drivers/hsqldb/HStorageAccess.cxx @@ -0,0 +1,511 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <hsqldb/HStorageAccess.hxx> +#include <com/sun/star/embed/XStorage.hpp> +#include <hsqldb/HStorageMap.hxx> +#include "accesslog.hxx" +#include <osl/diagnose.h> +#include <tools/diagnose_ex.h> + +#include <string.h> + +#include <algorithm> + +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::embed; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::lang; +using namespace ::connectivity::hsqldb; + +#define ThrowException(env, type, msg) { \ + env->ThrowNew(env->FindClass(type), msg); } + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess + * Method: openStream + * Signature: (Ljava/lang/String;Ljava/lang/String;I)V + */ +extern "C" SAL_JNI_EXPORT void JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess_openStream + (JNIEnv * env, jobject /*obj_this*/,jstring name, jstring key, jint mode) +{ +#ifdef HSQLDB_DBG + { + OperationLogFile( env, name, "data" ).logOperation( "openStream" ); + LogFile( env, name, "data" ).create(); + } +#endif + + StorageContainer::registerStream(env,name,key,mode); +} + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess + * Method: close + * Signature: (Ljava/lang/String;Ljava/lang/String;)V + */ +extern "C" SAL_JNI_EXPORT void JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess_close + (JNIEnv * env, jobject /*obj_this*/,jstring name, jstring key) +{ +#ifdef HSQLDB_DBG + { + OUString sKey = StorageContainer::jstring2ustring(env,key); + OUString sName = StorageContainer::jstring2ustring(env,name); + } +#endif + std::shared_ptr<StreamHelper> pHelper = StorageContainer::getRegisteredStream(env,name,key); + Reference< XOutputStream> xFlush = pHelper ? pHelper->getOutputStream() : Reference< XOutputStream>(); + if ( xFlush.is() ) + try + { + xFlush->flush(); + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION( "connectivity.hsqldb", "NativeStorageAccess::close: caught an exception while flushing!" ); + } +#ifdef HSQLDB_DBG + { + OperationLogFile aOpLog( env, name, "data" ); + aOpLog.logOperation( "close" ); + aOpLog.close(); + + LogFile aDataLog( env, name, "data" ); + aDataLog.close(); + } +#endif + + StorageContainer::revokeStream(env,name,key); +} + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess + * Method: getFilePointer + * Signature: (Ljava/lang/String;Ljava/lang/String;)J + */ +extern "C" SAL_JNI_EXPORT jlong JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess_getFilePointer + (JNIEnv * env, jobject /*obj_this*/,jstring name, jstring key) +{ +#ifdef HSQLDB_DBG + OperationLogFile aOpLog( env, name, "data" ); + aOpLog.logOperation( "getFilePointer" ); +#endif + + std::shared_ptr<StreamHelper> pHelper = StorageContainer::getRegisteredStream(env,name,key); + OSL_ENSURE(pHelper,"No stream helper!"); + + jlong nReturn = pHelper ? pHelper->getSeek()->getPosition() : jlong(0); +#ifdef HSQLDB_DBG + aOpLog.logReturn( nReturn ); +#endif + return nReturn; +} + + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess + * Method: length + * Signature: (Ljava/lang/String;Ljava/lang/String;)J + */ +extern "C" SAL_JNI_EXPORT jlong JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess_length + (JNIEnv * env, jobject /*obj_this*/,jstring name, jstring key) +{ +#ifdef HSQLDB_DBG + OperationLogFile aOpLog( env, name, "data" ); + aOpLog.logOperation( "length" ); +#endif + + std::shared_ptr<StreamHelper> pHelper = StorageContainer::getRegisteredStream(env,name,key); + OSL_ENSURE(pHelper,"No stream helper!"); + + jlong nReturn = pHelper ? pHelper->getSeek()->getLength() :jlong(0); +#ifdef HSQLDB_DBG + aOpLog.logReturn( nReturn ); +#endif + return nReturn; +} + + +jint read_from_storage_stream( JNIEnv * env, jstring name, jstring key ) +{ + std::shared_ptr<StreamHelper> pHelper = StorageContainer::getRegisteredStream(env,name,key); + Reference< XInputStream> xIn = pHelper ? pHelper->getInputStream() : Reference< XInputStream>(); + OSL_ENSURE(xIn.is(),"Input stream is NULL!"); + if ( !xIn.is() ) + return -1; + + Sequence< ::sal_Int8 > aData(1); + sal_Int32 nBytesRead = -1; + try + { + nBytesRead = xIn->readBytes(aData,1); + } + catch(const Exception& e) + { + StorageContainer::throwJavaException(e,env); + return -1; + + } + if (nBytesRead <= 0) + { + return -1; + } + else + { + return static_cast<unsigned char>(aData[0]); + } + return -1; +} + + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess + * Method: read + * Signature: (Ljava/lang/String;Ljava/lang/String;)I + */ +extern "C" SAL_JNI_EXPORT jint JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess_read__Ljava_lang_String_2Ljava_lang_String_2 + (JNIEnv* env, jobject /*obj_this*/, jstring name, jstring key) +{ +#ifdef HSQLDB_DBG + OperationLogFile aOpLog( env, name, "data" ); + aOpLog.logOperation( "read" ); + + DataLogFile aDataLog( env, name, "data" ); + return read_from_storage_stream( env, obj_this, name, key, &aDataLog ); +#else + return read_from_storage_stream( env, name, key ); +#endif +} + + +jint read_from_storage_stream_into_buffer( JNIEnv * env, jstring name, jstring key, jbyteArray buffer, jint off, jint len ) +{ +#ifdef HSQLDB_DBG + { + OUString sKey = StorageContainer::jstring2ustring(env,key); + OUString sName = StorageContainer::jstring2ustring(env,name); + } +#endif + std::shared_ptr<StreamHelper> pHelper = StorageContainer::getRegisteredStream(env,name,key); + Reference< XInputStream> xIn = pHelper ? pHelper->getInputStream() : Reference< XInputStream>(); + OSL_ENSURE(xIn.is(),"Input stream is NULL!"); + if ( xIn.is() ) + { + jsize nLen = env->GetArrayLength(buffer); + if ( nLen < len || len <= 0 ) + { + ThrowException( env, + "java/io/IOException", + "len is greater or equal to the buffer size"); + return -1; + } + sal_Int32 nBytesRead = -1; + + Sequence< ::sal_Int8 > aData(nLen); + try + { + nBytesRead = xIn->readBytes(aData, len); + } + catch(const Exception& e) + { + StorageContainer::throwJavaException(e,env); + return -1; + } + + if (nBytesRead <= 0) + return -1; + env->SetByteArrayRegion(buffer,off,nBytesRead,reinterpret_cast<const jbyte*>(&aData[0])); + + return nBytesRead; + } + ThrowException( env, + "java/io/IOException", + "Stream is not valid"); + return -1; +} + + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess + * Method: read + * Signature: (Ljava/lang/String;Ljava/lang/String;[BII)I + */ +extern "C" SAL_JNI_EXPORT jint JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess_read__Ljava_lang_String_2Ljava_lang_String_2_3BII + (JNIEnv * env, jobject obj_this,jstring name, jstring key, jbyteArray buffer, jint off, jint len) +{ +#ifdef HSQLDB_DBG + OperationLogFile aOpLog( env, name, "data" ); + aOpLog.logOperation( "read( byte[], int, int )" ); + + DataLogFile aDataLog( env, name, "data" ); + return read_from_storage_stream_into_buffer( env, obj_this, name, key, buffer, off, len, &aDataLog ); +#else + (void)obj_this; + return read_from_storage_stream_into_buffer( env, name, key, buffer, off, len ); +#endif +} + + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess + * Method: readInt + * Signature: (Ljava/lang/String;Ljava/lang/String;)I + */ +extern "C" SAL_JNI_EXPORT jint JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess_readInt + (JNIEnv * env, jobject /*obj_this*/,jstring name, jstring key) +{ +#ifdef HSQLDB_DBG + OperationLogFile aOpLog( env, name, "data" ); + aOpLog.logOperation( "readInt" ); +#endif + + std::shared_ptr<StreamHelper> pHelper = StorageContainer::getRegisteredStream(env,name,key); + Reference< XInputStream> xIn = pHelper ? pHelper->getInputStream() : Reference< XInputStream>(); + OSL_ENSURE(xIn.is(),"Input stream is NULL!"); + if ( xIn.is() ) + { + Sequence< ::sal_Int8 > aData(4); + sal_Int32 nBytesRead = -1; + try + { + nBytesRead = xIn->readBytes(aData, 4); + } + catch(const Exception& e) + { + StorageContainer::throwJavaException(e,env); + return -1; + } + + if ( nBytesRead != 4 ) { + ThrowException( env, + "java/io/IOException", + "Bytes read != 4"); + return -1; + } + + Sequence< sal_Int32 > ch(4); + std::transform(aData.begin(), aData.end(), ch.getArray(), + [](auto c) { return static_cast<unsigned char>(c); }); + + if ((ch[0] | ch[1] | ch[2] | ch[3]) < 0) + { + ThrowException( env, + "java/io/IOException", + "One byte is < 0"); + return -1; + } + jint nRet = (ch[0] << 24) + (ch[1] << 16) + (ch[2] << 8) + (ch[3] << 0); +#ifdef HSQLDB_DBG + DataLogFile aDataLog( env, name, "data" ); + aDataLog.write( nRet ); + + aOpLog.logReturn( nRet ); +#endif + return nRet; + } + ThrowException( env, + "java/io/IOException", + "No InputStream"); + return -1; +} + + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess + * Method: seek + * Signature: (Ljava/lang/String;Ljava/lang/String;J)V + */ +extern "C" SAL_JNI_EXPORT void JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess_seek + (JNIEnv * env, jobject /*obj_this*/,jstring name, jstring key, jlong position) +{ +#ifdef HSQLDB_DBG + OperationLogFile aOpLog( env, name, "data" ); + aOpLog.logOperation( "seek", position ); +#endif + + std::shared_ptr<StreamHelper> pHelper = StorageContainer::getRegisteredStream(env,name,key); + Reference< XSeekable> xSeek = pHelper ? pHelper->getSeek() : Reference< XSeekable>(); + + OSL_ENSURE(xSeek.is(),"No Seekable stream!"); + if (!xSeek) + return; + +#ifdef HSQLDB_DBG + DataLogFile aDataLog( env, name, "data" ); +#endif + + ::sal_Int64 nLen = xSeek->getLength(); + if ( nLen < position) + { + static const ::sal_Int64 BUFFER_SIZE = 9192; + #ifdef HSQLDB_DBG + aDataLog.seek( nLen ); + #endif + xSeek->seek(nLen); + Reference< XOutputStream> xOut = pHelper->getOutputStream(); + OSL_ENSURE(xOut.is(),"No output stream!"); + + ::sal_Int64 diff = position - nLen; + sal_Int32 n; + while( diff != 0 ) + { + if ( BUFFER_SIZE < diff ) + { + n = static_cast<sal_Int32>(BUFFER_SIZE); + diff = diff - BUFFER_SIZE; + } + else + { + n = static_cast<sal_Int32>(diff); + diff = 0; + } + Sequence< ::sal_Int8 > aData(n); + memset(aData.getArray(),0,n); + xOut->writeBytes(aData); + #ifdef HSQLDB_DBG + aDataLog.write( aData.getConstArray(), n ); + #endif + } + } + xSeek->seek(position); + OSL_ENSURE(xSeek->getPosition() == position,"Wrong position after seeking the stream"); + +#ifdef HSQLDB_DBG + aDataLog.seek( position ); + OSL_ENSURE( xSeek->getPosition() == aDataLog.tell(), "Wrong position after seeking the stream" ); +#endif +} + + +void write_to_storage_stream_from_buffer( JNIEnv* env, jstring name, jstring key, jbyteArray buffer, jint off, jint len ) +{ + std::shared_ptr<StreamHelper> pHelper = StorageContainer::getRegisteredStream(env,name,key); + Reference< XOutputStream> xOut = pHelper ? pHelper->getOutputStream() : Reference< XOutputStream>(); + OSL_ENSURE(xOut.is(),"Stream is NULL"); + + try + { + if ( xOut.is() ) + { + jbyte *buf = env->GetByteArrayElements(buffer,nullptr); + if (env->ExceptionCheck()) + { + env->ExceptionClear(); + OSL_FAIL("ExceptionClear"); + } + OSL_ENSURE(buf,"buf is NULL"); + if ( buf && len > 0 && len <= env->GetArrayLength(buffer)) + { + Sequence< ::sal_Int8 > aData(reinterpret_cast<sal_Int8 *>(buf + off),len); + env->ReleaseByteArrayElements(buffer, buf, JNI_ABORT); + xOut->writeBytes(aData); + } + } + else + { + ThrowException( env, + "java/io/IOException", + "No OutputStream"); + } + } + catch(const Exception& e) + { + TOOLS_WARN_EXCEPTION( "connectivity.hsqldb", "Exception caught! : write [BII)V"); + StorageContainer::throwJavaException(e,env); + } +} + + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess + * Method: write + * Signature: (Ljava/lang/String;Ljava/lang/String;[BII)V + */ +extern "C" SAL_JNI_EXPORT void JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess_write + (JNIEnv * env, jobject obj_this,jstring name, jstring key, jbyteArray buffer, jint off, jint len) +{ +#ifdef HSQLDB_DBG + OperationLogFile aOpLog( env, name, "data" ); + aOpLog.logOperation( "write( byte[], int, int )" ); + + DataLogFile aDataLog( env, name, "data" ); + write_to_storage_stream_from_buffer( env, obj_this, name, key, buffer, off, len, &aDataLog ); +#else + (void)obj_this; + write_to_storage_stream_from_buffer( env, name, key, buffer, off, len ); +#endif +} + + +void write_to_storage_stream( JNIEnv* env, jstring name, jstring key, jint v ) +{ + std::shared_ptr<StreamHelper> pHelper = StorageContainer::getRegisteredStream(env,name,key); + Reference< XOutputStream> xOut = pHelper ? pHelper->getOutputStream() : Reference< XOutputStream>(); + OSL_ENSURE(xOut.is(),"Stream is NULL"); + try + { + if ( xOut.is() ) + { + Sequence< ::sal_Int8 > oneByte + { + static_cast<sal_Int8>((v >> 24) & 0xFF), + static_cast<sal_Int8>((v >> 16) & 0xFF), + static_cast<sal_Int8>((v >> 8) & 0xFF), + static_cast<sal_Int8>((v >> 0) & 0xFF) + }; + + xOut->writeBytes(oneByte); + } + else + { + ThrowException( env, + "java/io/IOException", + "No OutputStream"); + } + } + catch(const Exception& e) + { + TOOLS_WARN_EXCEPTION( "connectivity.hsqldb", "writeBytes(aData);"); + StorageContainer::throwJavaException(e,env); + } +} + + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess + * Method: writeInt + * Signature: (Ljava/lang/String;Ljava/lang/String;I)V + */ +extern "C" SAL_JNI_EXPORT void JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess_writeInt + (JNIEnv * env, jobject obj_this,jstring name, jstring key, jint v) +{ +#ifdef HSQLDB_DBG + OperationLogFile aOpLog( env, name, "data" ); + aOpLog.logOperation( "writeInt" ); + + DataLogFile aDataLog( env, name, "data" ); + write_to_storage_stream( env, name, key, v, &aDataLog ); +#else + (void)obj_this; + write_to_storage_stream( env, name, key, v ); +#endif +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/hsqldb/HStorageMap.cxx b/connectivity/source/drivers/hsqldb/HStorageMap.cxx new file mode 100644 index 000000000..aba88f192 --- /dev/null +++ b/connectivity/source/drivers/hsqldb/HStorageMap.cxx @@ -0,0 +1,361 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <hsqldb/HStorageMap.hxx> +#include <comphelper/types.hxx> +#include <com/sun/star/embed/XTransactionBroadcaster.hpp> +#include <com/sun/star/embed/XTransactedObject.hpp> +#include <com/sun/star/embed/ElementModes.hpp> +#include <com/sun/star/lang/DisposedException.hpp> +#include <osl/diagnose.h> +#include <sal/log.hxx> +#include <uno/mapping.hxx> +#include <algorithm> +#include <tools/diagnose_ex.h> + +namespace connectivity::hsqldb +{ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::embed; + using namespace ::com::sun::star::io; + + StreamHelper::StreamHelper(const Reference< XStream>& _xStream) + : m_xStream(_xStream) + { + } + + StreamHelper::~StreamHelper() + { + try + { + m_xStream.clear(); + m_xSeek.clear(); + if ( m_xInputStream.is() ) + { + m_xInputStream->closeInput(); + m_xInputStream.clear(); + } + // this is done implicitly by the closing of the input stream + else if ( m_xOutputStream.is() ) + { + m_xOutputStream->closeOutput(); + try + { + ::comphelper::disposeComponent(m_xOutputStream); + } + catch(const DisposedException&) + { + } + catch(const Exception&) + { + OSL_FAIL("Could not dispose OutputStream"); + } + m_xOutputStream.clear(); + } + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION( "connectivity.hsqldb", ""); + } + } + + Reference< XInputStream> const & StreamHelper::getInputStream() + { + if ( !m_xInputStream.is() ) + m_xInputStream = m_xStream->getInputStream(); + return m_xInputStream; + } + + Reference< XOutputStream> const & StreamHelper::getOutputStream() + { + if ( !m_xOutputStream.is() ) + m_xOutputStream = m_xStream->getOutputStream(); + return m_xOutputStream; + } + + Reference< XSeekable> const & StreamHelper::getSeek() + { + if ( !m_xSeek.is() ) + m_xSeek.set(m_xStream,UNO_QUERY); + return m_xSeek; + } + + css::uno::Reference<css::embed::XStorage> StorageData::mapStorage() + const + { + css::uno::Environment env(css::uno::Environment::getCurrent()); + if (!(env.is() && storageEnvironment.is())) { + throw css::uno::RuntimeException("cannot get environments"); + } + if (env.get() == storageEnvironment.get()) { + return storage; + } else { + css::uno::Mapping map(storageEnvironment, env); + if (!map.is()) { + throw css::uno::RuntimeException("cannot get mapping"); + } + css::uno::Reference<css::embed::XStorage> mapped; + map.mapInterface( + reinterpret_cast<void **>(&mapped), storage.get(), + cppu::UnoType<css::embed::XStorage>::get()); + return mapped; + } + } + + static TStorages& lcl_getStorageMap() + { + static TStorages s_aMap; + return s_aMap; + } + + static OUString lcl_getNextCount() + { + static sal_Int32 s_nCount = 0; + return OUString::number(s_nCount++); + } + + OUString StorageContainer::removeURLPrefix(std::u16string_view _sURL,const OUString& _sFileURL) + { + return OUString(_sURL.substr(_sFileURL.getLength()+1)); + } + + OUString StorageContainer::removeOldURLPrefix(const OUString& _sURL) + { + OUString sRet = _sURL; +#if defined(_WIN32) + sal_Int32 nIndex = sRet.lastIndexOf('\\'); +#else + sal_Int32 nIndex = sRet.lastIndexOf('/'); +#endif + if ( nIndex != -1 ) + { + sRet = _sURL.copy(nIndex+1); + } + return sRet; + + } + /*****************************************************************************/ + /* convert jstring to rtl_uString */ + + OUString StorageContainer::jstring2ustring(JNIEnv * env, jstring jstr) + { + if (env->ExceptionCheck()) + { + env->ExceptionClear(); + OSL_FAIL("ExceptionClear"); + } + OUString aStr; + if ( jstr ) + { + jboolean bCopy(true); + const jchar* pChar = env->GetStringChars(jstr,&bCopy); + jsize len = env->GetStringLength(jstr); + aStr = OUString( + reinterpret_cast<sal_Unicode const *>(pChar), len); + + if(bCopy) + env->ReleaseStringChars(jstr,pChar); + } + + if (env->ExceptionCheck()) + { + env->ExceptionClear(); + OSL_FAIL("ExceptionClear"); + } + return aStr; + } + + + OUString StorageContainer::registerStorage(const Reference< XStorage>& _xStorage,const OUString& _sURL) + { + OSL_ENSURE(_xStorage.is(),"Storage is NULL!"); + TStorages& rMap = lcl_getStorageMap(); + // check if the storage is already in our map + TStorages::const_iterator aFind = std::find_if(rMap.begin(),rMap.end(), + [&_xStorage] (const TStorages::value_type& storage) { + return storage.second.mapStorage() == _xStorage; + }); + + if ( aFind == rMap.end() ) + { + aFind = rMap.insert(TStorages::value_type(lcl_getNextCount(), {_xStorage, css::uno::Environment::getCurrent(), _sURL, TStreamMap()})).first; + } + + return aFind->first; + } + + TStorages::mapped_type StorageContainer::getRegisteredStorage(const OUString& _sKey) + { + TStorages::mapped_type aRet; + TStorages& rMap = lcl_getStorageMap(); + TStorages::const_iterator aFind = rMap.find(_sKey); + OSL_ENSURE(aFind != rMap.end(),"Storage could not be found in list!"); + if ( aFind != rMap.end() ) + aRet = aFind->second; + + return aRet; + } + + OUString StorageContainer::getRegisteredKey(const Reference< XStorage>& _xStorage) + { + OUString sKey; + OSL_ENSURE(_xStorage.is(),"Storage is NULL!"); + TStorages& rMap = lcl_getStorageMap(); + // check if the storage is already in our map + TStorages::const_iterator aFind = std::find_if(rMap.begin(),rMap.end(), + [&_xStorage] (const TStorages::value_type& storage) { + return storage.second.mapStorage() == _xStorage; + }); + + if ( aFind != rMap.end() ) + sKey = aFind->first; + return sKey; + } + + void StorageContainer::revokeStorage(const OUString& _sKey,const Reference<XTransactionListener>& _xListener) + { + TStorages& rMap = lcl_getStorageMap(); + TStorages::iterator aFind = rMap.find(_sKey); + if ( aFind == rMap.end() ) + return; + + try + { + if ( _xListener.is() ) + { + Reference<XTransactionBroadcaster> xBroad(aFind->second.mapStorage(),UNO_QUERY); + if ( xBroad.is() ) + xBroad->removeTransactionListener(_xListener); + Reference<XTransactedObject> xTrans(aFind->second.mapStorage(),UNO_QUERY); + if ( xTrans.is() ) + xTrans->commit(); + } + } + catch(const Exception&) + { + } + rMap.erase(aFind); + } + + TStreamMap::mapped_type StorageContainer::registerStream(JNIEnv * env,jstring name, jstring key,sal_Int32 _nMode) + { + TStreamMap::mapped_type pHelper; + TStorages& rMap = lcl_getStorageMap(); + OUString sKey = jstring2ustring(env,key); + TStorages::iterator aFind = rMap.find(sKey); + OSL_ENSURE(aFind != rMap.end(),"Storage could not be found in list!"); + if ( aFind != rMap.end() ) + { + TStorages::mapped_type aStoragePair = StorageContainer::getRegisteredStorage(sKey); + auto storage = aStoragePair.mapStorage(); + OSL_ENSURE(storage.is(),"No Storage available!"); + if ( storage.is() ) + { + OUString sOrgName = StorageContainer::jstring2ustring(env,name); + OUString sName = removeURLPrefix(sOrgName,aStoragePair.url); + TStreamMap::iterator aStreamFind = aFind->second.streams.find(sName); + OSL_ENSURE( aStreamFind == aFind->second.streams.end(),"A Stream was already registered for this object!"); + if ( aStreamFind != aFind->second.streams.end() ) + { + pHelper = aStreamFind->second; + } + else + { + try + { + try + { + pHelper = std::make_shared<StreamHelper>(storage->openStreamElement(sName,_nMode)); + } + catch(const Exception&) + { + OUString sStrippedName = removeOldURLPrefix(sOrgName); + + if ( (_nMode & ElementModes::WRITE) != ElementModes::WRITE ) + { + bool bIsStream = true; + try + { + bIsStream = storage->isStreamElement(sStrippedName); + } + catch(const Exception&) + { + bIsStream = false; + } + if ( !bIsStream ) + return pHelper; // readonly file without data stream + } + pHelper = std::make_shared<StreamHelper>(storage->openStreamElement( sStrippedName, _nMode ) ); + } + aFind->second.streams.emplace(sName,pHelper); + } + catch(const Exception& e) + { + TOOLS_WARN_EXCEPTION( "connectivity.hsqldb", "[HSQLDB-SDBC] caught an exception while opening a stream\n" + "Name: " << sName + << "\nMode: 0x" << ( _nMode < 16 ? "0" : "") + << std::hex << _nMode ); + StorageContainer::throwJavaException(e,env); + } + } + } + } + return pHelper; + } + + void StorageContainer::revokeStream( JNIEnv * env,jstring name, jstring key) + { + TStorages& rMap = lcl_getStorageMap(); + TStorages::iterator aFind = rMap.find(jstring2ustring(env,key)); + OSL_ENSURE(aFind != rMap.end(),"Storage could not be found in list!"); + if ( aFind != rMap.end() ) + aFind->second.streams.erase(removeURLPrefix(jstring2ustring(env,name),aFind->second.url)); + } + + TStreamMap::mapped_type StorageContainer::getRegisteredStream( JNIEnv * env,jstring name, jstring key) + { + TStreamMap::mapped_type pRet; + TStorages& rMap = lcl_getStorageMap(); + TStorages::const_iterator aFind = rMap.find(jstring2ustring(env,key)); + OSL_ENSURE(aFind != rMap.end(),"Storage could not be found in list!"); + if ( aFind != rMap.end() ) + { + TStreamMap::const_iterator aStreamFind = aFind->second.streams.find(removeURLPrefix(jstring2ustring(env,name),aFind->second.url)); + if ( aStreamFind != aFind->second.streams.end() ) + pRet = aStreamFind->second; + } + + return pRet; + } + + void StorageContainer::throwJavaException(const Exception& _aException,JNIEnv * env) + { + if (env->ExceptionCheck()) + env->ExceptionClear(); + SAL_WARN("connectivity.hsqldb", "forwarding Exception: " << _aException ); + OString cstr( OUStringToOString(_aException.Message, RTL_TEXTENCODING_JAVA_UTF8 ) ); + env->ThrowNew(env->FindClass("java/io/IOException"), cstr.getStr()); + } + +} // namespace + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/hsqldb/HTable.cxx b/connectivity/source/drivers/hsqldb/HTable.cxx new file mode 100644 index 000000000..42ca7b527 --- /dev/null +++ b/connectivity/source/drivers/hsqldb/HTable.cxx @@ -0,0 +1,386 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <hsqldb/HTable.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/sdbcx/Privilege.hpp> +#include <comphelper/property.hxx> +#include <comphelper/servicehelper.hxx> +#include <comphelper/types.hxx> +#include <connectivity/dbtools.hxx> +#include <connectivity/TKeys.hxx> +#include <connectivity/TIndexes.hxx> +#include <hsqldb/HColumns.hxx> +#include <TConnection.hxx> + +#include <tools/diagnose_ex.h> + + +using namespace ::comphelper; +using namespace connectivity::hsqldb; +using namespace connectivity::sdbcx; +using namespace connectivity; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; + +OHSQLTable::OHSQLTable( sdbcx::OCollection* _pTables, + const Reference< XConnection >& _xConnection) + :OTableHelper(_pTables,_xConnection,true) +{ + // we create a new table here, so we should have all the rights or ;-) + m_nPrivileges = Privilege::DROP | + Privilege::REFERENCE | + Privilege::ALTER | + Privilege::CREATE | + Privilege::READ | + Privilege::DELETE | + Privilege::UPDATE | + Privilege::INSERT | + Privilege::SELECT; + construct(); +} + +OHSQLTable::OHSQLTable( sdbcx::OCollection* _pTables, + const Reference< XConnection >& _xConnection, + const OUString& Name, + const OUString& Type, + const OUString& Description , + const OUString& SchemaName, + const OUString& CatalogName, + sal_Int32 _nPrivileges + ) : OTableHelper( _pTables, + _xConnection, + true, + Name, + Type, + Description, + SchemaName, + CatalogName) + , m_nPrivileges(_nPrivileges) +{ + construct(); +} + +void OHSQLTable::construct() +{ + OTableHelper::construct(); + if ( !isNew() ) + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRIVILEGES), PROPERTY_ID_PRIVILEGES,PropertyAttribute::READONLY,&m_nPrivileges, cppu::UnoType<decltype(m_nPrivileges)>::get()); +} + +::cppu::IPropertyArrayHelper* OHSQLTable::createArrayHelper( sal_Int32 /*_nId*/ ) const +{ + return doCreateArrayHelper(); +} + +::cppu::IPropertyArrayHelper & OHSQLTable::getInfoHelper() +{ + return *static_cast<OHSQLTable_PROP*>(this)->getArrayHelper(isNew() ? 1 : 0); +} + +sdbcx::OCollection* OHSQLTable::createColumns(const ::std::vector< OUString>& _rNames) +{ + OHSQLColumns* pColumns = new OHSQLColumns(*this,m_aMutex,_rNames); + pColumns->setParent(this); + return pColumns; +} + +sdbcx::OCollection* OHSQLTable::createKeys(const ::std::vector< OUString>& _rNames) +{ + return new OKeysHelper(this,m_aMutex,_rNames); +} + +sdbcx::OCollection* OHSQLTable::createIndexes(const ::std::vector< OUString>& _rNames) +{ + return new OIndexesHelper(this,m_aMutex,_rNames); +} + +const Sequence< sal_Int8 > & OHSQLTable::getUnoTunnelId() +{ + static const comphelper::UnoIdInit implId; + return implId.getSeq(); +} + +// css::lang::XUnoTunnel + +sal_Int64 OHSQLTable::getSomething( const Sequence< sal_Int8 > & rId ) +{ + return comphelper::getSomethingImpl(rId, this, + comphelper::FallbackToGetSomethingOf<OTable_TYPEDEF>{}); +} + +// XAlterTable +void SAL_CALL OHSQLTable::alterColumnByName( const OUString& colName, const Reference< XPropertySet >& descriptor ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed( +#ifdef __GNUC__ + ::connectivity::sdbcx::OTableDescriptor_BASE::rBHelper.bDisposed +#else + rBHelper.bDisposed +#endif + ); + + if ( !m_xColumns || !m_xColumns->hasByName(colName) ) + throw NoSuchElementException(colName,*this); + + + if ( !isNew() ) + { + // first we have to check what should be altered + Reference<XPropertySet> xProp; + m_xColumns->getByName(colName) >>= xProp; + // first check the types + sal_Int32 nOldType = 0,nNewType = 0,nOldPrec = 0,nNewPrec = 0,nOldScale = 0,nNewScale = 0; + OUString sOldTypeName, sNewTypeName; + + ::dbtools::OPropertyMap& rProp = OMetaConnection::getPropMap(); + + // type/typename + xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_TYPE)) >>= nOldType; + descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_TYPE)) >>= nNewType; + xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_TYPENAME)) >>= sOldTypeName; + descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_TYPENAME))>>= sNewTypeName; + + // and precision and scale + xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_PRECISION)) >>= nOldPrec; + descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_PRECISION))>>= nNewPrec; + xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_SCALE)) >>= nOldScale; + descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_SCALE)) >>= nNewScale; + + // second: check the "is nullable" value + sal_Int32 nOldNullable = 0,nNewNullable = 0; + xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_ISNULLABLE)) >>= nOldNullable; + descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_ISNULLABLE)) >>= nNewNullable; + + // check also the auto_increment + bool bOldAutoIncrement = false,bAutoIncrement = false; + xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT)) >>= bOldAutoIncrement; + descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT)) >>= bAutoIncrement; + + // now we should look if the name of the column changed + OUString sNewColumnName; + descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_NAME)) >>= sNewColumnName; + if ( sNewColumnName != colName ) + { + const OUString sQuote = getMetaData()->getIdentifierQuoteString( ); + + OUString sSql = getAlterTableColumnPart() + + " ALTER COLUMN " + + ::dbtools::quoteName(sQuote,colName) + + " RENAME TO " + + ::dbtools::quoteName(sQuote,sNewColumnName); + + executeStatement(sSql); + } + + if ( nOldType != nNewType + || sOldTypeName != sNewTypeName + || nOldPrec != nNewPrec + || nOldScale != nNewScale + || nNewNullable != nOldNullable + || bOldAutoIncrement != bAutoIncrement ) + { + // special handling because they change the type names to distinguish + // if a column should be an auto_increment one + if ( bOldAutoIncrement != bAutoIncrement ) + { + /// TODO: insert special handling for auto increment "IDENTITY" and primary key + } + alterColumnType(nNewType,sNewColumnName,descriptor); + } + + // third: check the default values + OUString sNewDefault,sOldDefault; + xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_DEFAULTVALUE)) >>= sOldDefault; + descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_DEFAULTVALUE)) >>= sNewDefault; + + if(!sOldDefault.isEmpty()) + { + dropDefaultValue(colName); + if(!sNewDefault.isEmpty() && sOldDefault != sNewDefault) + alterDefaultValue(sNewDefault,sNewColumnName); + } + else if(sOldDefault.isEmpty() && !sNewDefault.isEmpty()) + alterDefaultValue(sNewDefault,sNewColumnName); + + m_xColumns->refresh(); + } + else + { + if(m_xColumns) + { + m_xColumns->dropByName(colName); + m_xColumns->appendByDescriptor(descriptor); + } + } + +} + +void OHSQLTable::alterColumnType(sal_Int32 nNewType,const OUString& _rColName, const Reference<XPropertySet>& _xDescriptor) +{ + OUString sSql = getAlterTableColumnPart() + " ALTER COLUMN "; +#if OSL_DEBUG_LEVEL > 0 + try + { + OUString sDescriptorName; + OSL_ENSURE( _xDescriptor.is() + && ( _xDescriptor->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_NAME ) ) >>= sDescriptorName ) + && ( sDescriptorName == _rColName ), + "OHSQLTable::alterColumnType: unexpected column name!" ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("connectivity.hsqldb"); + } +#else + (void)_rColName; +#endif + + rtl::Reference<OHSQLColumn> pColumn = new OHSQLColumn; + ::comphelper::copyProperties(_xDescriptor,pColumn); + pColumn->setPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE),Any(nNewType)); + + sSql += ::dbtools::createStandardColumnPart(pColumn,getConnection()); + executeStatement(sSql); +} + +void OHSQLTable::alterDefaultValue(std::u16string_view _sNewDefault,const OUString& _rColName) +{ + const OUString sQuote = getMetaData()->getIdentifierQuoteString( ); + OUString sSql = getAlterTableColumnPart() + + " ALTER COLUMN " + + ::dbtools::quoteName(sQuote,_rColName) + + " SET DEFAULT '" + _sNewDefault + "'"; + + executeStatement(sSql); +} + +void OHSQLTable::dropDefaultValue(const OUString& _rColName) +{ + const OUString sQuote = getMetaData()->getIdentifierQuoteString( ); + OUString sSql = getAlterTableColumnPart() + + " ALTER COLUMN " + + ::dbtools::quoteName(sQuote,_rColName) + + " DROP DEFAULT"; + + executeStatement(sSql); +} + +OUString OHSQLTable::getAlterTableColumnPart() const +{ + OUString sSql( "ALTER TABLE " ); + + OUString sComposedName( ::dbtools::composeTableName( getMetaData(), m_CatalogName, m_SchemaName, m_Name, true, ::dbtools::EComposeRule::InTableDefinitions ) ); + sSql += sComposedName; + + return sSql; +} + +void OHSQLTable::executeStatement(const OUString& _rStatement ) +{ + OUString sSQL = _rStatement; + if(sSQL.endsWith(",")) + sSQL = sSQL.replaceAt(sSQL.getLength()-1, 1, u")"); + + Reference< XStatement > xStmt = getConnection()->createStatement( ); + if ( xStmt.is() ) + { + try { xStmt->execute(sSQL); } + catch( const Exception& ) + { + ::comphelper::disposeComponent(xStmt); + throw; + } + ::comphelper::disposeComponent(xStmt); + } +} + +Sequence< Type > SAL_CALL OHSQLTable::getTypes( ) +{ + if ( m_Type == "VIEW" ) + { + Sequence< Type > aTypes = OTableHelper::getTypes(); + std::vector<Type> aOwnTypes; + aOwnTypes.reserve(aTypes.getLength()); + const Type* pIter = aTypes.getConstArray(); + const Type* pEnd = pIter + aTypes.getLength(); + for(;pIter != pEnd;++pIter) + { + if( *pIter != cppu::UnoType<XRename>::get()) + { + aOwnTypes.push_back(*pIter); + } + } + return Sequence< Type >(aOwnTypes.data(), aOwnTypes.size()); + } + return OTableHelper::getTypes(); +} + +// XRename +void SAL_CALL OHSQLTable::rename( const OUString& newName ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed( +#ifdef __GNUC__ + ::connectivity::sdbcx::OTableDescriptor_BASE::rBHelper.bDisposed +#else + rBHelper.bDisposed +#endif + ); + + if(!isNew()) + { + OUString sSql = "ALTER "; + if ( m_Type == "VIEW" ) + sSql += " VIEW "; + else + sSql += " TABLE "; + + OUString sCatalog,sSchema,sTable; + ::dbtools::qualifiedNameComponents(getMetaData(),newName,sCatalog,sSchema,sTable,::dbtools::EComposeRule::InDataManipulation); + + sSql += + ::dbtools::composeTableName( getMetaData(), m_CatalogName, m_SchemaName, m_Name, true, ::dbtools::EComposeRule::InDataManipulation ) + + " RENAME TO " + + ::dbtools::composeTableName( getMetaData(), sCatalog, sSchema, sTable, true, ::dbtools::EComposeRule::InDataManipulation ); + + executeStatement(sSql); + + ::connectivity::OTable_TYPEDEF::rename(newName); + } + else + ::dbtools::qualifiedNameComponents(getMetaData(),newName,m_CatalogName,m_SchemaName,m_Name,::dbtools::EComposeRule::InTableDefinitions); +} + + +Any SAL_CALL OHSQLTable::queryInterface( const Type & rType ) +{ + if( m_Type == "VIEW" && rType == cppu::UnoType<XRename>::get()) + return Any(); + + return OTableHelper::queryInterface(rType); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/hsqldb/HTables.cxx b/connectivity/source/drivers/hsqldb/HTables.cxx new file mode 100644 index 000000000..de99a3b04 --- /dev/null +++ b/connectivity/source/drivers/hsqldb/HTables.cxx @@ -0,0 +1,176 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <hsqldb/HTables.hxx> +#include <hsqldb/HViews.hxx> +#include <hsqldb/HTable.hxx> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <com/sun/star/sdbcx/Privilege.hpp> +#include <hsqldb/HCatalog.hxx> +#include <connectivity/dbtools.hxx> +#include <comphelper/types.hxx> +#include <TConnection.hxx> + +using namespace ::comphelper; +using namespace connectivity; +using namespace ::cppu; +using namespace connectivity::hsqldb; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; +using namespace dbtools; + +sdbcx::ObjectType OTables::createObject(const OUString& _rName) +{ + OUString sCatalog,sSchema,sTable; + ::dbtools::qualifiedNameComponents(m_xMetaData,_rName,sCatalog,sSchema,sTable,::dbtools::EComposeRule::InDataManipulation); + + Sequence< OUString > sTableTypes {"VIEW", "TABLE", "%"}; // this last one just to be sure to include anything else... + + Any aCatalog; + if ( !sCatalog.isEmpty() ) + aCatalog <<= sCatalog; + Reference< XResultSet > xResult = m_xMetaData->getTables(aCatalog,sSchema,sTable,sTableTypes); + + sdbcx::ObjectType xRet; + if ( xResult.is() ) + { + Reference< XRow > xRow(xResult,UNO_QUERY); + if ( xResult->next() ) // there can be only one table with this name + { + sal_Int32 nPrivileges = ::dbtools::getTablePrivileges( m_xMetaData, sCatalog, sSchema, sTable ); + if ( m_xMetaData->isReadOnly() ) + nPrivileges &= ~( Privilege::INSERT | Privilege::UPDATE | Privilege::DELETE | Privilege::CREATE | Privilege::ALTER | Privilege::DROP ); + + // obtain privileges + xRet = new OHSQLTable( this + ,static_cast<OHCatalog&>(m_rParent).getConnection() + ,sTable + ,xRow->getString(4) + ,xRow->getString(5) + ,sSchema + ,sCatalog + ,nPrivileges); + } + ::comphelper::disposeComponent(xResult); + } + + return xRet; +} + +void OTables::impl_refresh( ) +{ + static_cast<OHCatalog&>(m_rParent).refreshTables(); +} + +void OTables::disposing() +{ + m_xMetaData.clear(); + OCollection::disposing(); +} + +Reference< XPropertySet > OTables::createDescriptor() +{ + return new OHSQLTable(this,static_cast<OHCatalog&>(m_rParent).getConnection()); +} + +// XAppend +sdbcx::ObjectType OTables::appendObject( const OUString& _rForName, const Reference< XPropertySet >& descriptor ) +{ + createTable(descriptor); + return createObject( _rForName ); +} + +// XDrop +void OTables::dropObject(sal_Int32 _nPos,const OUString& _sElementName) +{ + Reference< XInterface > xObject( getObject( _nPos ) ); + bool bIsNew = connectivity::sdbcx::ODescriptor::isNew( xObject ); + if (bIsNew) + return; + + Reference< XConnection > xConnection = static_cast<OHCatalog&>(m_rParent).getConnection(); + + + OUString sCatalog,sSchema,sTable; + ::dbtools::qualifiedNameComponents(m_xMetaData,_sElementName,sCatalog,sSchema,sTable,::dbtools::EComposeRule::InDataManipulation); + + OUString aSql( "DROP " ); + + Reference<XPropertySet> xProp(xObject,UNO_QUERY); + bool bIsView; + if((bIsView = (xProp.is() && ::comphelper::getString(xProp->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE))) == "VIEW"))) // here we have a view + aSql += "VIEW "; + else + aSql += "TABLE "; + + OUString sComposedName( + ::dbtools::composeTableName( m_xMetaData, sCatalog, sSchema, sTable, true, ::dbtools::EComposeRule::InDataManipulation ) ); + aSql += sComposedName; + Reference< XStatement > xStmt = xConnection->createStatement( ); + if ( xStmt.is() ) + { + xStmt->execute(aSql); + ::comphelper::disposeComponent(xStmt); + } + // if no exception was thrown we must delete it from the views + if ( bIsView ) + { + HViews* pViews = static_cast<HViews*>(static_cast<OHCatalog&>(m_rParent).getPrivateViews()); + if ( pViews && pViews->hasByName(_sElementName) ) + pViews->dropByNameImpl(_sElementName); + } +} + +void OTables::createTable( const Reference< XPropertySet >& descriptor ) +{ + Reference< XConnection > xConnection = static_cast<OHCatalog&>(m_rParent).getConnection(); + OUString aSql = ::dbtools::createSqlCreateTableStatement(descriptor,xConnection); + + Reference< XStatement > xStmt = xConnection->createStatement( ); + if ( xStmt.is() ) + { + xStmt->execute(aSql); + ::comphelper::disposeComponent(xStmt); + } +} + +void OTables::appendNew(const OUString& _rsNewTable) +{ + insertElement(_rsNewTable,nullptr); + + // notify our container listeners + ContainerEvent aEvent(static_cast<XContainer*>(this), Any(_rsNewTable), Any(), Any()); + OInterfaceIteratorHelper3 aListenerLoop(m_aContainerListeners); + while (aListenerLoop.hasMoreElements()) + aListenerLoop.next()->elementInserted(aEvent); +} + +OUString OTables::getNameForObject(const sdbcx::ObjectType& _xObject) +{ + OSL_ENSURE(_xObject.is(),"OTables::getNameForObject: Object is NULL!"); + return ::dbtools::composeTableName( m_xMetaData, _xObject, ::dbtools::EComposeRule::InDataManipulation, false ); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/hsqldb/HTerminateListener.cxx b/connectivity/source/drivers/hsqldb/HTerminateListener.cxx new file mode 100644 index 000000000..a9df5ccc9 --- /dev/null +++ b/connectivity/source/drivers/hsqldb/HTerminateListener.cxx @@ -0,0 +1,45 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "HTerminateListener.hxx" +#include <hsqldb/HDriver.hxx> + +namespace connectivity +{ +using namespace hsqldb; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; + +// XEventListener +void SAL_CALL OConnectionController::disposing(const EventObject& /*Source*/) {} + +// XTerminateListener +void SAL_CALL OConnectionController::queryTermination(const EventObject& /*aEvent*/) +{ + m_pDriver->flushConnections(); +} + +void SAL_CALL OConnectionController::notifyTermination(const EventObject& /*aEvent*/) +{ + m_pDriver->shutdownConnections(); +} + +} // namespace connectivity + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/hsqldb/HTerminateListener.hxx b/connectivity/source/drivers/hsqldb/HTerminateListener.hxx new file mode 100644 index 000000000..baf66e90e --- /dev/null +++ b/connectivity/source/drivers/hsqldb/HTerminateListener.hxx @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include <cppuhelper/implbase.hxx> +#include <com/sun/star/frame/XTerminateListener.hpp> + + +namespace connectivity::hsqldb + { + class ODriverDelegator; + class OConnectionController : public ::cppu::WeakImplHelper< css::frame::XTerminateListener > + { + ODriverDelegator* m_pDriver; + protected: + virtual ~OConnectionController() override {m_pDriver = nullptr;} + public: + explicit OConnectionController(ODriverDelegator* _pDriver) : m_pDriver(_pDriver){} + + // XEventListener + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + + // XTerminateListener + virtual void SAL_CALL queryTermination( const css::lang::EventObject& aEvent ) override; + virtual void SAL_CALL notifyTermination( const css::lang::EventObject& aEvent ) override; + }; + +} // namespace connectivity::hsqldb + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/hsqldb/HTools.cxx b/connectivity/source/drivers/hsqldb/HTools.cxx new file mode 100644 index 000000000..3dd388ace --- /dev/null +++ b/connectivity/source/drivers/hsqldb/HTools.cxx @@ -0,0 +1,53 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <hsqldb/HTools.hxx> + + +namespace connectivity::hsqldb +{ + + void HTools::appendTableFilterCrit( OUStringBuffer& _inout_rBuffer, std::u16string_view _rCatalog, + std::u16string_view _rSchema, std::u16string_view _rName, bool _bShortForm ) + { + _inout_rBuffer.append( " WHERE " ); + if ( !_rCatalog.empty() ) + { + _inout_rBuffer.appendAscii( _bShortForm ? "TABLE_CAT" : "TABLE_CATALOG" ); + _inout_rBuffer.append( " = '" ); + _inout_rBuffer.append ( _rCatalog ); + _inout_rBuffer.append( "' AND " ); + } + if ( !_rSchema.empty() ) + { + _inout_rBuffer.appendAscii( _bShortForm ? "TABLE_SCHEM" : "TABLE_SCHEMA" ); + _inout_rBuffer.append( " = '" ); + _inout_rBuffer.append ( _rSchema ); + _inout_rBuffer.append( "' AND " ); + } + _inout_rBuffer.append( "TABLE_NAME = '" ); + _inout_rBuffer.append ( _rName ); + _inout_rBuffer.append( "'" ); + } + + +} // namespace connectivity::hsqldb + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/hsqldb/HUser.cxx b/connectivity/source/drivers/hsqldb/HUser.cxx new file mode 100644 index 000000000..2ed0c0626 --- /dev/null +++ b/connectivity/source/drivers/hsqldb/HUser.cxx @@ -0,0 +1,328 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <hsqldb/HUser.hxx> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <connectivity/dbtools.hxx> +#include <connectivity/dbexception.hxx> +#include <comphelper/types.hxx> +#include <com/sun/star/sdbcx/Privilege.hpp> +#include <com/sun/star/sdbcx/PrivilegeObject.hpp> +#include <TConnection.hxx> +#include <strings.hrc> + +using namespace connectivity; +using namespace connectivity::hsqldb; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; + +OHSQLUser::OHSQLUser( const css::uno::Reference< css::sdbc::XConnection >& _xConnection) : connectivity::sdbcx::OUser(true) + ,m_xConnection(_xConnection) +{ + construct(); +} + +OHSQLUser::OHSQLUser( const css::uno::Reference< css::sdbc::XConnection >& _xConnection, + const OUString& Name + ) : connectivity::sdbcx::OUser(Name,true) + ,m_xConnection(_xConnection) +{ + construct(); +} + +void OHSQLUser::refreshGroups() +{ +} + +OUserExtend::OUserExtend( const css::uno::Reference< css::sdbc::XConnection >& _xConnection) : OHSQLUser(_xConnection) +{ + construct(); +} + +void OUserExtend::construct() +{ + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PASSWORD), PROPERTY_ID_PASSWORD,0,&m_Password,::cppu::UnoType<OUString>::get()); +} + +cppu::IPropertyArrayHelper* OUserExtend::createArrayHelper() const +{ + Sequence< Property > aProps; + describeProperties(aProps); + return new cppu::OPropertyArrayHelper(aProps); +} + +cppu::IPropertyArrayHelper & OUserExtend::getInfoHelper() +{ + return *OUserExtend_PROP::getArrayHelper(); +} +typedef connectivity::sdbcx::OUser_BASE OUser_BASE_RBHELPER; + +sal_Int32 SAL_CALL OHSQLUser::getPrivileges( const OUString& objName, sal_Int32 objType ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OUser_BASE_RBHELPER::rBHelper.bDisposed); + + sal_Int32 nRights,nRightsWithGrant; + findPrivilegesAndGrantPrivileges(objName,objType,nRights,nRightsWithGrant); + return nRights; +} + +void OHSQLUser::findPrivilegesAndGrantPrivileges(const OUString& objName, sal_Int32 objType,sal_Int32& nRights,sal_Int32& nRightsWithGrant) +{ + nRightsWithGrant = nRights = 0; + // first we need to create the sql stmt to select the privs + Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData(); + OUString sCatalog,sSchema,sTable; + ::dbtools::qualifiedNameComponents(xMeta,objName,sCatalog,sSchema,sTable,::dbtools::EComposeRule::InDataManipulation); + Reference<XResultSet> xRes; + switch(objType) + { + case PrivilegeObject::TABLE: + case PrivilegeObject::VIEW: + { + Any aCatalog; + if ( !sCatalog.isEmpty() ) + aCatalog <<= sCatalog; + xRes = xMeta->getTablePrivileges(aCatalog,sSchema,sTable); + } + break; + + case PrivilegeObject::COLUMN: + { + Any aCatalog; + if ( !sCatalog.isEmpty() ) + aCatalog <<= sCatalog; + xRes = xMeta->getColumnPrivileges(aCatalog,sSchema,sTable,"%"); + } + break; + } + + if ( !xRes.is() ) + return; + + static const char sYes [] = "YES"; + + nRightsWithGrant = nRights = 0; + + Reference<XRow> xCurrentRow(xRes,UNO_QUERY); + while( xCurrentRow.is() && xRes->next() ) + { + OUString sGrantee = xCurrentRow->getString(5); + OUString sPrivilege = xCurrentRow->getString(6); + OUString sGrantable = xCurrentRow->getString(7); + + if (!m_Name.equalsIgnoreAsciiCase(sGrantee)) + continue; + + if (sPrivilege.equalsIgnoreAsciiCase("SELECT")) + { + nRights |= Privilege::SELECT; + if ( sGrantable.equalsIgnoreAsciiCase(sYes) ) + nRightsWithGrant |= Privilege::SELECT; + } + else if (sPrivilege.equalsIgnoreAsciiCase("INSERT")) + { + nRights |= Privilege::INSERT; + if ( sGrantable.equalsIgnoreAsciiCase(sYes) ) + nRightsWithGrant |= Privilege::INSERT; + } + else if (sPrivilege.equalsIgnoreAsciiCase("UPDATE")) + { + nRights |= Privilege::UPDATE; + if ( sGrantable.equalsIgnoreAsciiCase(sYes) ) + nRightsWithGrant |= Privilege::UPDATE; + } + else if (sPrivilege.equalsIgnoreAsciiCase("DELETE")) + { + nRights |= Privilege::DELETE; + if ( sGrantable.equalsIgnoreAsciiCase(sYes) ) + nRightsWithGrant |= Privilege::DELETE; + } + else if (sPrivilege.equalsIgnoreAsciiCase("READ")) + { + nRights |= Privilege::READ; + if ( sGrantable.equalsIgnoreAsciiCase(sYes) ) + nRightsWithGrant |= Privilege::READ; + } + else if (sPrivilege.equalsIgnoreAsciiCase("CREATE")) + { + nRights |= Privilege::CREATE; + if ( sGrantable.equalsIgnoreAsciiCase(sYes) ) + nRightsWithGrant |= Privilege::CREATE; + } + else if (sPrivilege.equalsIgnoreAsciiCase("ALTER")) + { + nRights |= Privilege::ALTER; + if ( sGrantable.equalsIgnoreAsciiCase(sYes) ) + nRightsWithGrant |= Privilege::ALTER; + } + else if (sPrivilege.equalsIgnoreAsciiCase("REFERENCE")) + { + nRights |= Privilege::REFERENCE; + if ( sGrantable.equalsIgnoreAsciiCase(sYes) ) + nRightsWithGrant |= Privilege::REFERENCE; + } + else if (sPrivilege.equalsIgnoreAsciiCase("DROP")) + { + nRights |= Privilege::DROP; + if ( sGrantable.equalsIgnoreAsciiCase(sYes) ) + nRightsWithGrant |= Privilege::DROP; + } + } + ::comphelper::disposeComponent(xRes); +} + +sal_Int32 SAL_CALL OHSQLUser::getGrantablePrivileges( const OUString& objName, sal_Int32 objType ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OUser_BASE_RBHELPER::rBHelper.bDisposed); + + sal_Int32 nRights,nRightsWithGrant; + findPrivilegesAndGrantPrivileges(objName,objType,nRights,nRightsWithGrant); + return nRightsWithGrant; +} + +void SAL_CALL OHSQLUser::grantPrivileges( const OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges ) +{ + if ( objType != PrivilegeObject::TABLE ) + { + ::connectivity::SharedResources aResources; + const OUString sError( aResources.getResourceString(STR_PRIVILEGE_NOT_GRANTED)); + ::dbtools::throwGenericSQLException(sError,*this); + } // if ( objType != PrivilegeObject::TABLE ) + + + ::osl::MutexGuard aGuard(m_aMutex); + + OUString sPrivs = getPrivilegeString(objPrivileges); + if(!sPrivs.isEmpty()) + { + Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData(); + OUString sGrant = "GRANT " + sPrivs + + " ON " + ::dbtools::quoteTableName(xMeta,objName,::dbtools::EComposeRule::InDataManipulation) + + " TO " + ::dbtools::quoteName(xMeta->getIdentifierQuoteString(), m_Name); + + Reference<XStatement> xStmt = m_xConnection->createStatement(); + if(xStmt.is()) + xStmt->execute(sGrant); + ::comphelper::disposeComponent(xStmt); + } +} + +void SAL_CALL OHSQLUser::revokePrivileges( const OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges ) +{ + if ( objType != PrivilegeObject::TABLE ) + { + ::connectivity::SharedResources aResources; + const OUString sError( aResources.getResourceString(STR_PRIVILEGE_NOT_REVOKED)); + ::dbtools::throwGenericSQLException(sError,*this); + } // if ( objType != PrivilegeObject::TABLE ) + + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OUser_BASE_RBHELPER::rBHelper.bDisposed); + OUString sPrivs = getPrivilegeString(objPrivileges); + if(!sPrivs.isEmpty()) + { + Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData(); + OUString sGrant = "REVOKE " + sPrivs + + " ON " + ::dbtools::quoteTableName(xMeta,objName,::dbtools::EComposeRule::InDataManipulation) + + " FROM " + ::dbtools::quoteName(xMeta->getIdentifierQuoteString(), m_Name); + + Reference<XStatement> xStmt = m_xConnection->createStatement(); + if(xStmt.is()) + xStmt->execute(sGrant); + ::comphelper::disposeComponent(xStmt); + } +} + +// XUser +void SAL_CALL OHSQLUser::changePassword( const OUString& /*oldPassword*/, const OUString& newPassword ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OUser_BASE_RBHELPER::rBHelper.bDisposed); + + Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData(); + + if( m_Name != xMeta->getUserName() ) + { + ::dbtools::throwGenericSQLException("HSQLDB can only change password of the current user.", *this); + } + + OUString sAlterPwd = "SET PASSWORD " + + ::dbtools::quoteName(xMeta->getIdentifierQuoteString(), newPassword); + + Reference<XStatement> xStmt = m_xConnection->createStatement(); + if ( xStmt.is() ) + { + xStmt->execute(sAlterPwd); + ::comphelper::disposeComponent(xStmt); + } +} + +OUString OHSQLUser::getPrivilegeString(sal_Int32 nRights) +{ + OUString sPrivs; + if((nRights & Privilege::INSERT) == Privilege::INSERT) + sPrivs += "INSERT"; + + if((nRights & Privilege::DELETE) == Privilege::DELETE) + { + if(!sPrivs.isEmpty()) + sPrivs += ","; + sPrivs += "DELETE"; + } + + if((nRights & Privilege::UPDATE) == Privilege::UPDATE) + { + if(!sPrivs.isEmpty()) + sPrivs += ","; + sPrivs += "UPDATE"; + } + + if((nRights & Privilege::ALTER) == Privilege::ALTER) + { + if(!sPrivs.isEmpty()) + sPrivs += ","; + sPrivs += "ALTER"; + } + + if((nRights & Privilege::SELECT) == Privilege::SELECT) + { + if(!sPrivs.isEmpty()) + sPrivs += ","; + sPrivs += "SELECT"; + } + + if((nRights & Privilege::REFERENCE) == Privilege::REFERENCE) + { + if(!sPrivs.isEmpty()) + sPrivs += ","; + sPrivs += "REFERENCES"; + } + + return sPrivs; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/hsqldb/HUsers.cxx b/connectivity/source/drivers/hsqldb/HUsers.cxx new file mode 100644 index 000000000..9fe31e58e --- /dev/null +++ b/connectivity/source/drivers/hsqldb/HUsers.cxx @@ -0,0 +1,98 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <hsqldb/HUsers.hxx> +#include <hsqldb/HUser.hxx> +#include <connectivity/sdbcx/IRefreshable.hxx> +#include <comphelper/types.hxx> +#include <connectivity/dbtools.hxx> +#include <TConnection.hxx> + +using namespace ::comphelper; +using namespace connectivity; +using namespace connectivity::hsqldb; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; + +OUsers::OUsers( ::cppu::OWeakObject& _rParent, + ::osl::Mutex& _rMutex, + const ::std::vector< OUString> &_rVector, + const css::uno::Reference< css::sdbc::XConnection >& _xConnection, + connectivity::sdbcx::IRefreshableUsers* _pParent) + : sdbcx::OCollection(_rParent, true, _rMutex, _rVector) + ,m_xConnection(_xConnection) + ,m_pParent(_pParent) +{ +} + + +sdbcx::ObjectType OUsers::createObject(const OUString& _rName) +{ + return new OHSQLUser(m_xConnection,_rName); +} + +void OUsers::impl_refresh() +{ + m_pParent->refreshUsers(); +} + +Reference< XPropertySet > OUsers::createDescriptor() +{ + return new OUserExtend(m_xConnection); +} + +// XAppend +sdbcx::ObjectType OUsers::appendObject( const OUString& _rForName, const Reference< XPropertySet >& descriptor ) +{ + OUString aQuote = m_xConnection->getMetaData()->getIdentifierQuoteString( ); + OUString sPassword; + descriptor->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PASSWORD)) >>= sPassword; + OUString aSql = "GRANT USAGE ON * TO " + + ::dbtools::quoteName(aQuote,_rForName) + " @\"%\" "; + if ( !sPassword.isEmpty() ) + { + aSql += " IDENTIFIED BY '" + sPassword + "'"; + } + + Reference< XStatement > xStmt = m_xConnection->createStatement( ); + if(xStmt.is()) + xStmt->execute(aSql); + ::comphelper::disposeComponent(xStmt); + + return createObject( _rForName ); +} + +// XDrop +void OUsers::dropObject(sal_Int32 /*nPos*/,const OUString& _sElementName) +{ + OUString aSql( "REVOKE ALL ON * FROM " ); + OUString aQuote = m_xConnection->getMetaData()->getIdentifierQuoteString( ); + aSql += ::dbtools::quoteName(aQuote,_sElementName); + + Reference< XStatement > xStmt = m_xConnection->createStatement( ); + if(xStmt.is()) + xStmt->execute(aSql); + ::comphelper::disposeComponent(xStmt); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/hsqldb/HView.cxx b/connectivity/source/drivers/hsqldb/HView.cxx new file mode 100644 index 000000000..29e5a4000 --- /dev/null +++ b/connectivity/source/drivers/hsqldb/HView.cxx @@ -0,0 +1,216 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include <hsqldb/HView.hxx> +#include <hsqldb/HTools.hxx> + +#include <propertyids.hxx> + +#include <connectivity/dbtools.hxx> + +#include <com/sun/star/lang/WrappedTargetException.hpp> +#include <com/sun/star/lang/DisposedException.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> + +#include <cppuhelper/exc_hlp.hxx> +#include <tools/diagnose_ex.h> +#include <unotools/sharedunocomponent.hxx> + + +namespace connectivity::hsqldb +{ + + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::uno::RuntimeException; + using ::com::sun::star::uno::Any; + using ::com::sun::star::sdbc::SQLException; + using ::com::sun::star::sdbc::XConnection; + using ::com::sun::star::lang::WrappedTargetException; + using ::com::sun::star::sdbc::XResultSet; + using ::com::sun::star::sdbc::XStatement; + using ::com::sun::star::lang::DisposedException; + using ::com::sun::star::sdbc::XRow; + + HView::HView( const Reference< XConnection >& _rxConnection, bool _bCaseSensitive, + const OUString& _rSchemaName, const OUString& _rName ) + :HView_Base( _bCaseSensitive, _rName, _rxConnection->getMetaData(), OUString(), _rSchemaName, OUString() ) + ,m_xConnection( _rxConnection ) + { + } + + + HView::~HView() + { + } + + + IMPLEMENT_FORWARD_XINTERFACE2( HView, HView_Base, HView_IBASE ) + IMPLEMENT_FORWARD_XTYPEPROVIDER2( HView, HView_Base, HView_IBASE ) + + + void SAL_CALL HView::alterCommand( const OUString& _rNewCommand ) + { + // not really atomic ... as long as we do not have something like + // ALTER VIEW <name> TO <command> + // in HSQL, we need to do it this way ... + // + // I can imagine scenarios where this fails, e.g. when dropping the view + // succeeds, re-creating it fails, some other thread alters a table which + // the view was based on, and then we try to restore the view with the + // original command, which then fails, too. + // + // However, there's not much chance to prevent this kind of errors without + // backend support. + + OUString sQualifiedName( ::dbtools::composeTableName( + m_xMetaData, m_CatalogName, m_SchemaName, m_Name, true, ::dbtools::EComposeRule::InDataManipulation ) ); + + ::utl::SharedUNOComponent< XStatement > xStatement; xStatement.set( m_xConnection->createStatement(), UNO_QUERY_THROW ); + + // create a statement which can be used to re-create the original view, in case + // dropping it succeeds, but creating it with a new statement fails + OUString sRestoreCommand = + "CREATE VIEW " + + sQualifiedName + + " AS " + + impl_getCommand_throwSQLException(); + + bool bDropSucceeded( false ); + try + { + // drop the existing view + OUString aCommand ="DROP VIEW " + sQualifiedName; + xStatement->execute( aCommand ); + bDropSucceeded = true; + + // create a new one with the same name + aCommand = "CREATE VIEW " + sQualifiedName + " AS " + _rNewCommand; + xStatement->execute( aCommand ); + } + catch( const SQLException& ) + { + if ( bDropSucceeded ) + // drop succeeded, but creation failed -> re-create the view with the original + // statement + xStatement->execute( sRestoreCommand ); + throw; + } + catch( const RuntimeException& ) + { + if ( bDropSucceeded ) + xStatement->execute( sRestoreCommand ); + throw; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("connectivity.hsqldb"); + if ( bDropSucceeded ) + xStatement->execute( sRestoreCommand ); + } + } + + + void SAL_CALL HView::getFastPropertyValue( Any& _rValue, sal_Int32 _nHandle ) const + { + if ( _nHandle == PROPERTY_ID_COMMAND ) + { + // retrieve the very current command, don't rely on the base classes cached value + // (which we initialized empty, anyway) + _rValue <<= impl_getCommand_wrapSQLException(); + return; + } + + HView_Base::getFastPropertyValue( _rValue, _nHandle ); + } + + OUString HView::impl_getCommand() const + { + OUStringBuffer aCommand; + aCommand.append( "SELECT VIEW_DEFINITION FROM INFORMATION_SCHEMA.SYSTEM_VIEWS " ); + HTools::appendTableFilterCrit( aCommand, m_CatalogName, m_SchemaName, m_Name, false ); + ::utl::SharedUNOComponent< XStatement > xStatement; xStatement.set( m_xConnection->createStatement(), UNO_QUERY_THROW ); + Reference< XResultSet > xResult( xStatement->executeQuery( aCommand.makeStringAndClear() ), css::uno::UNO_SET_THROW ); + if ( !xResult->next() ) + { + // hmm. There is no view the name as we know it. Can only mean some other instance + // dropped this view meanwhile... + throw DisposedException(); + } + + Reference< XRow > xRow( xResult, UNO_QUERY_THROW ); + return xRow->getString( 1 ); + } + + OUString HView::impl_getCommand_wrapSQLException() const + { + OUString sCommand; + + try + { + sCommand = impl_getCommand(); + } + catch( const RuntimeException& ) + { + throw; + } + catch( const SQLException& e ) + { + throw WrappedTargetException( e.Message, static_cast< XAlterView* >( const_cast< HView* >( this ) ), ::cppu::getCaughtException() ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("connectivity.hsqldb"); + } + + return sCommand; + } + + OUString HView::impl_getCommand_throwSQLException() const + { + OUString sCommand; + + try + { + sCommand = impl_getCommand(); + } + catch( const RuntimeException& ) + { + throw; + } + catch( const SQLException& ) + { + throw; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("connectivity.hsqldb"); + } + + return sCommand; + } + +} // namespace connectivity::hsqldb + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/hsqldb/HViews.cxx b/connectivity/source/drivers/hsqldb/HViews.cxx new file mode 100644 index 000000000..1f4b80748 --- /dev/null +++ b/connectivity/source/drivers/hsqldb/HViews.cxx @@ -0,0 +1,148 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include <hsqldb/HTables.hxx> +#include <hsqldb/HViews.hxx> +#include <hsqldb/HView.hxx> +#include <hsqldb/HCatalog.hxx> +#include <connectivity/dbtools.hxx> +#include <comphelper/types.hxx> +#include <TConnection.hxx> + +using namespace ::comphelper; + +using namespace ::cppu; +using namespace connectivity; +using namespace connectivity::hsqldb; +using namespace css::uno; +using namespace css::beans; +using namespace css::sdbcx; +using namespace css::sdbc; +using namespace css::container; +using namespace css::lang; +using namespace dbtools; +typedef connectivity::sdbcx::OCollection OCollection_TYPE; + + +HViews::HViews( const Reference< XConnection >& _rxConnection, ::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex, + const ::std::vector< OUString> &_rVector ) + :sdbcx::OCollection( _rParent, true, _rMutex, _rVector ) + ,m_xConnection( _rxConnection ) + ,m_xMetaData( _rxConnection->getMetaData() ) + ,m_bInDrop( false ) +{ +} + + +sdbcx::ObjectType HViews::createObject(const OUString& _rName) +{ + OUString sCatalog,sSchema,sTable; + ::dbtools::qualifiedNameComponents(m_xMetaData, + _rName, + sCatalog, + sSchema, + sTable, + ::dbtools::EComposeRule::InDataManipulation); + return new HView( m_xConnection, isCaseSensitive(), sSchema, sTable ); +} + + +void HViews::impl_refresh( ) +{ + static_cast<OHCatalog&>(m_rParent).refreshTables(); +} + +void HViews::disposing() +{ + m_xMetaData.clear(); + OCollection::disposing(); +} + +Reference< XPropertySet > HViews::createDescriptor() +{ + Reference<XConnection> xConnection = static_cast<OHCatalog&>(m_rParent).getConnection(); + return new connectivity::sdbcx::OView(true, xConnection->getMetaData()); +} + +// XAppend +sdbcx::ObjectType HViews::appendObject( const OUString& _rForName, const Reference< XPropertySet >& descriptor ) +{ + createView(descriptor); + return createObject( _rForName ); +} + +// XDrop +void HViews::dropObject(sal_Int32 _nPos,const OUString& /*_sElementName*/) +{ + if ( m_bInDrop ) + return; + + Reference< XInterface > xObject( getObject( _nPos ) ); + bool bIsNew = connectivity::sdbcx::ODescriptor::isNew( xObject ); + if (!bIsNew) + { + OUString aSql( "DROP VIEW" ); + + Reference<XPropertySet> xProp(xObject,UNO_QUERY); + aSql += ::dbtools::composeTableName( m_xMetaData, xProp, ::dbtools::EComposeRule::InTableDefinitions, true ); + + Reference<XConnection> xConnection = static_cast<OHCatalog&>(m_rParent).getConnection(); + Reference< XStatement > xStmt = xConnection->createStatement( ); + xStmt->execute(aSql); + ::comphelper::disposeComponent(xStmt); + } +} + +void HViews::dropByNameImpl(const OUString& elementName) +{ + m_bInDrop = true; + OCollection_TYPE::dropByName(elementName); + m_bInDrop = false; +} + +void HViews::createView( const Reference< XPropertySet >& descriptor ) +{ + Reference<XConnection> xConnection = static_cast<OHCatalog&>(m_rParent).getConnection(); + + OUString sCommand; + descriptor->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_COMMAND)) >>= sCommand; + + OUString aSql = "CREATE VIEW " + + ::dbtools::composeTableName( m_xMetaData, descriptor, ::dbtools::EComposeRule::InTableDefinitions, true ) + + " AS " + sCommand; + + Reference< XStatement > xStmt = xConnection->createStatement( ); + if ( xStmt.is() ) + { + xStmt->execute(aSql); + ::comphelper::disposeComponent(xStmt); + } + + // insert the new view also in the tables collection + OTables* pTables = static_cast<OTables*>(static_cast<OHCatalog&>(m_rParent).getPrivateTables()); + if ( pTables ) + { + OUString sName = ::dbtools::composeTableName( m_xMetaData, descriptor, ::dbtools::EComposeRule::InDataManipulation, false ); + pTables->appendNew(sName); + } +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/hsqldb/StorageFileAccess.cxx b/connectivity/source/drivers/hsqldb/StorageFileAccess.cxx new file mode 100644 index 000000000..e352f78fb --- /dev/null +++ b/connectivity/source/drivers/hsqldb/StorageFileAccess.cxx @@ -0,0 +1,167 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#if defined(HAVE_CONFIG_H) && HAVE_CONFIG_H +#include <config.h> +#endif +#include <com/sun/star/embed/XStorage.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <hsqldb/HStorageMap.hxx> +#include <tools/diagnose_ex.h> + +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::embed; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::lang; +using namespace ::connectivity::hsqldb; + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_StorageFileAccess + * Method: isStreamElement + * Signature: (Ljava/lang/String;Ljava/lang/String;)Z + */ +extern "C" SAL_JNI_EXPORT jboolean JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageFileAccess_isStreamElement + (JNIEnv * env, jobject /*obj_this*/,jstring key, jstring name) +{ + TStorages::mapped_type aStoragePair = StorageContainer::getRegisteredStorage(StorageContainer::jstring2ustring(env,key)); + auto storage = aStoragePair.mapStorage(); + if ( !storage ) + return JNI_FALSE; + + try + { + OUString sName = StorageContainer::jstring2ustring(env,name); + try + { + OUString sOldName = StorageContainer::removeOldURLPrefix(sName); + if ( storage->isStreamElement(sOldName) ) + { + try + { + storage->renameElement(sOldName,StorageContainer::removeURLPrefix(sName,aStoragePair.url)); + } + catch(const Exception&) + { + } + } + } + catch(const NoSuchElementException&) + { + } + catch(const IllegalArgumentException&) + { + } + return storage->isStreamElement(StorageContainer::removeURLPrefix(sName,aStoragePair.url)); + } + catch(const NoSuchElementException&) + { + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("connectivity.hsqldb", "forwarding"); + if (env->ExceptionCheck()) + env->ExceptionClear(); + } + return JNI_FALSE; +} + + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_StorageFileAccess + * Method: removeElement + * Signature: (Ljava/lang/String;Ljava/lang/String;)V + */ +extern "C" SAL_JNI_EXPORT void JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageFileAccess_removeElement + (JNIEnv * env, jobject /*obj_this*/,jstring key, jstring name) +{ +#ifdef HSQLDB_DBG + { + OUString sKey = StorageContainer::jstring2ustring(env,key); + OUString sName = StorageContainer::jstring2ustring(env,name); + } +#endif + TStorages::mapped_type aStoragePair = StorageContainer::getRegisteredStorage(StorageContainer::jstring2ustring(env,key)); + auto storage = aStoragePair.mapStorage(); + if ( !storage.is() ) + return; + + try + { + storage->removeElement(StorageContainer::removeURLPrefix(StorageContainer::jstring2ustring(env,name),aStoragePair.url)); + } + catch(const NoSuchElementException&) + { + if (env->ExceptionCheck()) + env->ExceptionClear(); + } + catch(const Exception& e) + { + TOOLS_WARN_EXCEPTION("connectivity.hsqldb", ""); + StorageContainer::throwJavaException(e,env); + } +} + + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_StorageFileAccess + * Method: renameElement + * Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + */ +extern "C" SAL_JNI_EXPORT void JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageFileAccess_renameElement + (JNIEnv * env, jobject /*obj_this*/,jstring key, jstring oldname, jstring newname) +{ +#ifdef HSQLDB_DBG + { + OUString sKey = StorageContainer::jstring2ustring(env,key); + OUString sNewName = StorageContainer::jstring2ustring(env,newname); + OUString sOldName = StorageContainer::jstring2ustring(env,oldname); + } +#endif + TStorages::mapped_type aStoragePair = StorageContainer::getRegisteredStorage(StorageContainer::jstring2ustring(env,key)); + auto storage = aStoragePair.mapStorage(); + if ( !storage.is() ) + return; + + try + { + storage->renameElement( + StorageContainer::removeURLPrefix(StorageContainer::jstring2ustring(env,oldname),aStoragePair.url), + StorageContainer::removeURLPrefix(StorageContainer::jstring2ustring(env,newname),aStoragePair.url) + ); +#ifdef HSQLDB_DBG + { + OUString sNewName = StorageContainer::removeURLPrefix(StorageContainer::jstring2ustring(env,newname),aStoragePair.first.second); + OSL_ENSURE(aStoragePair.first.first->isStreamElement(sNewName),"Stream could not be renamed"); + } +#endif + } + catch(const NoSuchElementException&) + { + } + catch(const Exception& e) + { + TOOLS_WARN_EXCEPTION( "connectivity.hsqldb", "Java_com_sun_star_sdbcx_comp_hsqldb_StorageFileAccess_renameElement"); + StorageContainer::throwJavaException(e,env); + } +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/hsqldb/StorageNativeInputStream.cxx b/connectivity/source/drivers/hsqldb/StorageNativeInputStream.cxx new file mode 100644 index 000000000..4fcbbc5aa --- /dev/null +++ b/connectivity/source/drivers/hsqldb/StorageNativeInputStream.cxx @@ -0,0 +1,292 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#if defined(HAVE_CONFIG_H) && HAVE_CONFIG_H +#include <config.h> +#endif +#include <com/sun/star/io/XStream.hpp> +#include <com/sun/star/document/XDocumentSubStorageSupplier.hpp> +#include <hsqldb/HStorageAccess.hxx> +#include <hsqldb/HStorageMap.hxx> + +#include <osl/diagnose.h> +#include <tools/diagnose_ex.h> +#include "accesslog.hxx" + +#include <limits> + + +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::document; +using namespace ::com::sun::star::embed; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::lang; +using namespace ::connectivity::hsqldb; + +/*****************************************************************************/ +/* exception macros */ + +#define ThrowException(env, type, msg) { \ + env->ThrowNew(env->FindClass(type), msg); } +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_StorageNativeInputStream + * Method: openStream + * Signature: (Ljava/lang/String;Ljava/lang/String;I)V + */ +extern "C" SAL_JNI_EXPORT void JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageNativeInputStream_openStream + (JNIEnv * env, jobject /*obj_this*/,jstring key, jstring name, jint mode) +{ +#ifdef HSQLDB_DBG + { + OperationLogFile( env, name, "input" ).logOperation( "openStream" ); + LogFile( env, name, "input" ).create(); + } +#endif + StorageContainer::registerStream(env,name,key,mode); +} + + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_StorageNativeInputStream + * Method: read + * Signature: (Ljava/lang/String;Ljava/lang/String;)I + */ +extern "C" SAL_JNI_EXPORT jint JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageNativeInputStream_read__Ljava_lang_String_2Ljava_lang_String_2 + (JNIEnv * env, jobject /*obj_this*/, jstring key, jstring name) +{ +#ifdef HSQLDB_DBG + OperationLogFile( env, name, "input" ).logOperation( "read()" ); + + DataLogFile aDataLog( env, name, "input" ); + return read_from_storage_stream( env, obj_this, name, key, &aDataLog ); +#else + return read_from_storage_stream( env, name, key ); +#endif +} + + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_StorageNativeInputStream + * Method: read + * Signature: (Ljava/lang/String;Ljava/lang/String;[BII)I + */ +extern "C" SAL_JNI_EXPORT jint JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageNativeInputStream_read__Ljava_lang_String_2Ljava_lang_String_2_3BII + (JNIEnv * env, jobject obj_this, jstring key, jstring name, jbyteArray buffer, jint off, jint len) +{ +#ifdef HSQLDB_DBG + OperationLogFile( env, name, "input" ).logOperation( "read( byte[], int, int )" ); + + DataLogFile aDataLog( env, name, "input" ); + return read_from_storage_stream_into_buffer( env, obj_this, name, key, buffer, off, len, &aDataLog ); +#else + (void)obj_this; + return read_from_storage_stream_into_buffer(env, name,key,buffer,off,len); +#endif +} + + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_StorageNativeInputStream + * Method: close + * Signature: (Ljava/lang/String;Ljava/lang/String;)V + */ +extern "C" SAL_JNI_EXPORT void JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageNativeInputStream_close + (JNIEnv * env, jobject /*obj_this*/,jstring key, jstring name) +{ +#ifdef HSQLDB_DBG + OperationLogFile aOpLog( env, name, "input" ); + aOpLog.logOperation( "close" ); + aOpLog.close(); + + LogFile aDataLog( env, name, "input" ); + aDataLog.close(); +#endif + StorageContainer::revokeStream(env,name,key); +} + + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_StorageNativeInputStream + * Method: skip + * Signature: (Ljava/lang/String;Ljava/lang/String;J)J + */ +extern "C" SAL_JNI_EXPORT jlong JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageNativeInputStream_skip + (JNIEnv * env, jobject /*obj_this*/,jstring key, jstring name, jlong n) +{ +#ifdef HSQLDB_DBG + OperationLogFile( env, name, "input" ).logOperation( "skip()" ); +#endif + + if ( n < 0 ) + ThrowException( env, + "java/io/IOException", + "n < 0"); + + std::shared_ptr<StreamHelper> pHelper = StorageContainer::getRegisteredStream(env,name,key); + OSL_ENSURE(pHelper,"No stream helper!"); + if ( pHelper ) + { + Reference<XInputStream> xIn = pHelper->getInputStream(); + if ( xIn.is() ) + { + try + { + sal_Int64 tmpLongVal = n; + sal_Int32 tmpIntVal; + + try + { + do { + if (tmpLongVal >= std::numeric_limits<sal_Int64>::max() ) + tmpIntVal = std::numeric_limits<sal_Int32>::max(); + else // Casting is safe here. + tmpIntVal = static_cast<sal_Int32>(tmpLongVal); + + tmpLongVal -= tmpIntVal; + + xIn->skipBytes(tmpIntVal); + + } while (tmpLongVal > 0); + } + catch(const Exception&) + { + } + + return n - tmpLongVal; + } + catch(const Exception& e) + { + TOOLS_WARN_EXCEPTION( "connectivity.hsqldb", "skip();"); + StorageContainer::throwJavaException(e,env); + } + } + } + else + { + ThrowException( env, + "java/io/IOException", + "Stream is not valid"); + } + return 0; +} + + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_StorageNativeInputStream + * Method: available + * Signature: (Ljava/lang/String;Ljava/lang/String;)I + */ +extern "C" SAL_JNI_EXPORT jint JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageNativeInputStream_available + (JNIEnv * env, jobject /*obj_this*/,jstring key, jstring name) +{ +#ifdef HSQLDB_DBG + OperationLogFile aOpLog( env, name, "input" ); + aOpLog.logOperation( "available" ); +#endif + + std::shared_ptr<StreamHelper> pHelper = StorageContainer::getRegisteredStream(env,name,key); + OSL_ENSURE(pHelper,"No stream helper!"); + Reference<XInputStream> xIn = pHelper ? pHelper->getInputStream() : Reference<XInputStream>(); + if ( xIn.is() ) + { + try + { + jint nAvailable = xIn->available(); +#ifdef HSQLDB_DBG + aOpLog.logReturn( nAvailable ); +#endif + return nAvailable; + } + catch(const Exception& e) + { + TOOLS_WARN_EXCEPTION( "connectivity.hsqldb", "available();"); + StorageContainer::throwJavaException(e,env); + } + } + else + { + ThrowException( env, + "java/io/IOException", + "Stream is not valid"); + } + return 0; +} + + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_StorageNativeInputStream + * Method: read + * Signature: (Ljava/lang/String;Ljava/lang/String;[B)I + */ +extern "C" SAL_JNI_EXPORT jint JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageNativeInputStream_read__Ljava_lang_String_2Ljava_lang_String_2_3B + (JNIEnv * env, jobject /*obj_this*/,jstring key, jstring name, jbyteArray buffer) +{ +#ifdef HSQLDB_DBG + OperationLogFile aOpLog( env, name, "input" ); + aOpLog.logOperation( "read( byte[] )" ); + + DataLogFile aDataLog( env, name, "input" ); +#endif + + std::shared_ptr<StreamHelper> pHelper = StorageContainer::getRegisteredStream(env,name,key); + Reference< XInputStream> xIn = pHelper ? pHelper->getInputStream() : Reference< XInputStream>(); + OSL_ENSURE(xIn.is(),"Input stream is NULL!"); + jint nBytesRead = 0; + if ( xIn.is() ) + { + jsize nLen = env->GetArrayLength(buffer); + Sequence< ::sal_Int8 > aData(nLen); + + try + { + nBytesRead = xIn->readBytes(aData,nLen); + } + catch(const Exception& e) + { + TOOLS_WARN_EXCEPTION( "connectivity.hsqldb", "skip();"); + StorageContainer::throwJavaException(e,env); + } + + // Casting bytesRead to an int is okay, since the user can + // only pass in an integer length to read, so the bytesRead + // must <= len. + + if (nBytesRead <= 0) { +#ifdef HSQLDB_DBG + aOpLog.logReturn( (jint)-1 ); +#endif + return -1; + } + OSL_ENSURE(nLen >= nBytesRead,"Buffer is too small!"); + OSL_ENSURE(aData.getLength() >= nBytesRead,"Buffer is too small!"); + env->SetByteArrayRegion(buffer, 0, nBytesRead, reinterpret_cast<const jbyte*>(&aData[0])); +#ifdef HSQLDB_DBG + aDataLog.write( &aData[0], nBytesRead ); +#endif + } +#ifdef HSQLDB_DBG + aOpLog.logReturn( nBytesRead ); +#endif + return nBytesRead; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/hsqldb/StorageNativeOutputStream.cxx b/connectivity/source/drivers/hsqldb/StorageNativeOutputStream.cxx new file mode 100644 index 000000000..f766696e0 --- /dev/null +++ b/connectivity/source/drivers/hsqldb/StorageNativeOutputStream.cxx @@ -0,0 +1,195 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#if defined(HAVE_CONFIG_H) && HAVE_CONFIG_H +#include <config.h> +#endif + +#include <cppuhelper/bootstrap.hxx> +#include <osl/diagnose.h> +#include "accesslog.hxx" +#include <com/sun/star/embed/XTransactedObject.hpp> +#include <com/sun/star/io/XStream.hpp> +#include <com/sun/star/document/XDocumentSubStorageSupplier.hpp> +#include <hsqldb/HStorageAccess.hxx> +#include <hsqldb/HStorageMap.hxx> + +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::document; +using namespace ::com::sun::star::embed; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::lang; +using namespace ::connectivity::hsqldb; + + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_StorageNativeOutputStream + * Method: openStream + * Signature: (Ljava/lang/String;Ljava/lang/String;I)V + */ +extern "C" SAL_JNI_EXPORT void JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageNativeOutputStream_openStream + (JNIEnv * env, jobject /*obj_this*/, jstring name, jstring key, jint mode) +{ +#ifdef HSQLDB_DBG + { + OperationLogFile( env, name, "output" ).logOperation( "openStream" ); + LogFile( env, name, "output" ).create(); + } +#endif + StorageContainer::registerStream(env,name,key,mode); +} +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_StorageNativeOutputStream + * Method: write + * Signature: (Ljava/lang/String;Ljava/lang/String;[BII)V + */ +extern "C" SAL_JNI_EXPORT void JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageNativeOutputStream_write__Ljava_lang_String_2Ljava_lang_String_2_3BII + (JNIEnv * env, jobject obj_this, jstring key, jstring name, jbyteArray buffer, jint off, jint len) +{ +#ifdef HSQLDB_DBG + OperationLogFile( env, name, "output" ).logOperation( "write( byte[], int, int )" ); + + DataLogFile aDataLog( env, name, "output" ); + write_to_storage_stream_from_buffer( env, obj_this, name, key, buffer, off, len, &aDataLog ); +#else + (void)obj_this; + write_to_storage_stream_from_buffer( env, name, key, buffer, off, len ); +#endif +} + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_StorageNativeOutputStream + * Method: write + * Signature: (Ljava/lang/String;Ljava/lang/String;[B)V + */ +extern "C" SAL_JNI_EXPORT void JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageNativeOutputStream_write__Ljava_lang_String_2Ljava_lang_String_2_3B + (JNIEnv * env, jobject obj_this, jstring key, jstring name, jbyteArray buffer) +{ +#ifdef HSQLDB_DBG + OperationLogFile( env, name, "output" ).logOperation( "write( byte[] )" ); + + DataLogFile aDataLog( env, name, "output" ); + write_to_storage_stream_from_buffer( env, obj_this, name, key, buffer, 0, env->GetArrayLength( buffer ), &aDataLog ); +#else + (void)obj_this; + write_to_storage_stream_from_buffer( env, name, key, buffer, 0, env->GetArrayLength( buffer ) ); +#endif +} + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_StorageNativeOutputStream + * Method: close + * Signature: (Ljava/lang/String;Ljava/lang/String;)V + */ +extern "C" SAL_JNI_EXPORT void JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageNativeOutputStream_close + (JNIEnv * env, jobject /*obj_this*/, jstring key, jstring name) +{ +#ifdef HSQLDB_DBG + OperationLogFile aOpLog( env, name, "output" ); + aOpLog.logOperation( "close" ); + + LogFile aDataLog( env, name, "output" ); +#endif + + std::shared_ptr<StreamHelper> pHelper = StorageContainer::getRegisteredStream(env,name,key); + Reference< XOutputStream> xFlush = pHelper ? pHelper->getOutputStream() : Reference< XOutputStream>(); + if ( xFlush.is() ) + try + { + xFlush->flush(); + } + catch(Exception&) + {} + +#ifdef HSQLDB_DBG + aDataLog.close(); + aOpLog.close(); +#endif + StorageContainer::revokeStream(env,name,key); +} + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_StorageNativeOutputStream + * Method: write + * Signature: (Ljava/lang/String;Ljava/lang/String;I)V + */ +extern "C" SAL_JNI_EXPORT void JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageNativeOutputStream_write__Ljava_lang_String_2Ljava_lang_String_2I + (JNIEnv * env, jobject obj_this, jstring key, jstring name,jint b) +{ +#ifdef HSQLDB_DBG + OperationLogFile( env, name, "output" ).logOperation( "write( int )" ); + + DataLogFile aDataLog( env, name, "output" ); + write_to_storage_stream( env, name, key, b, &aDataLog ); +#else + (void)obj_this; + write_to_storage_stream( env, name, key, b ); +#endif +} + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_StorageNativeOutputStream + * Method: flush + * Signature: (Ljava/lang/String;Ljava/lang/String;)V + */ +extern "C" SAL_JNI_EXPORT void JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageNativeOutputStream_flush + (JNIEnv * env, jobject /*obj_this*/, jstring key, jstring name) +{ +#ifdef HSQLDB_DBG + OperationLogFile( env, name, "output" ).logOperation( "flush" ); + + OUString sKey = StorageContainer::jstring2ustring(env,key); + OUString sName = StorageContainer::jstring2ustring(env,name); +#else + (void) env; + (void) key; + (void) name; +#endif +} + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_StorageNativeOutputStream + * Method: sync + * Signature: (Ljava/lang/String;Ljava/lang/String;)V + */ +extern "C" SAL_JNI_EXPORT void JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageNativeOutputStream_sync + (JNIEnv * env, jobject /*obj_this*/, jstring key, jstring name) +{ +#ifdef HSQLDB_DBG + OperationLogFile( env, name, "output" ).logOperation( "sync" ); +#endif + std::shared_ptr< StreamHelper > pStream = StorageContainer::getRegisteredStream( env, name, key ); + Reference< XOutputStream > xFlush = pStream ? pStream->getOutputStream() : Reference< XOutputStream>(); + OSL_ENSURE( xFlush.is(), "StorageNativeOutputStream::sync: could not retrieve an output stream!" ); + if ( xFlush.is() ) + { + try + { + xFlush->flush(); + } + catch(Exception&) + { + OSL_FAIL( "StorageNativeOutputStream::sync: could not flush output stream!" ); + } + } +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/hsqldb/accesslog.cxx b/connectivity/source/drivers/hsqldb/accesslog.cxx new file mode 100644 index 000000000..f7e0f10ee --- /dev/null +++ b/connectivity/source/drivers/hsqldb/accesslog.cxx @@ -0,0 +1,78 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#ifdef HSQLDB_DBG + +#include <map> + +#include "accesslog.hxx" +#include "hsqldb/HStorageMap.hxx" + +#include <osl/thread.h> + +namespace connectivity::hsqldb +{ + typedef std::map<OUString, FILE *> TDebugStreamMap; + TDebugStreamMap& getStreams() + { + static TDebugStreamMap streams; + return streams; + } + + + LogFile::LogFile( JNIEnv* env, jstring streamName, const char* _pAsciiSuffix ) + : m_sFileName(StorageContainer::jstring2ustring(env,streamName) + + "." + OUString::createFromAscii( _pAsciiSuffix ) ) + { + } + + + FILE*& LogFile::getLogFile() + { + FILE*& pLogFile = getStreams()[m_sFileName]; + if ( !pLogFile ) + { + OString sByteLogName = OUStringToOString(m_sFileName,osl_getThreadTextEncoding()); + pLogFile = fopen( sByteLogName.getStr(), "a+" ); + } + return pLogFile; + } + + + void LogFile::writeString( const char* _pString, bool _bEndLine ) + { + FILE* pLogFile = getLogFile(); + fwrite( _pString, sizeof( *_pString ), strlen( _pString ), pLogFile ); + if ( _bEndLine ) + fwrite( "\n", sizeof( *_pString ), strlen( "\n" ), pLogFile ); + fflush( pLogFile ); + } + + + void LogFile::close() + { + fclose( getLogFile() ); + getLogFile() = NULL; + } +} } +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/hsqldb/accesslog.hxx b/connectivity/source/drivers/hsqldb/accesslog.hxx new file mode 100644 index 000000000..81db98ae7 --- /dev/null +++ b/connectivity/source/drivers/hsqldb/accesslog.hxx @@ -0,0 +1,135 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#ifdef HSQLDB_DBG + +#include <jni.h> +#include <rtl/ustring.hxx> +#include <rtl/string.hxx> + +namespace connectivity::hsqldb +{ + class LogFile + { + private: + OUString m_sFileName; + + public: + LogFile( JNIEnv* env, jstring streamName, const char* _pAsciiSuffix ); + + public: + void writeString( const char* _pString, bool _bEndLine = true ); + void create() { getLogFile(); } + virtual void close(); + + protected: + FILE*& getLogFile(); + }; + + class OperationLogFile : public LogFile + { + public: + OperationLogFile( JNIEnv* env, jstring streamName, const char* _pAsciiSuffix ) + :LogFile( env, streamName, ( OString( _pAsciiSuffix ) += ".op" ).getStr() ) + { + } + + void logOperation( const char* _pOp ) + { + writeString( _pOp, true ); + } + + void logOperation( const char* _pOp, jlong _nLongArg ) + { + OString sLine( _pOp ); + sLine += "( "; + sLine += OString::number( _nLongArg ); + sLine += " )"; + writeString( sLine.getStr(), true ); + } + + void logReturn( jlong _nRetVal ) + { + OString sLine( " -> " ); + sLine += OString::number( _nRetVal ); + writeString( sLine.getStr(), true ); + } + + void logReturn( jint _nRetVal ) + { + OString sLine( " -> " ); + sLine += OString::number( _nRetVal ); + writeString( sLine.getStr(), true ); + } + + virtual void close() + { + writeString( "-------------------------------", true ); + writeString( "", true ); + LogFile::close(); + } + }; + + class DataLogFile : public LogFile + { + public: + DataLogFile( JNIEnv* env, jstring streamName, const char* _pAsciiSuffix ) + :LogFile( env, streamName, _pAsciiSuffix ) + { + } + + void write( jint value ) + { + fputc( value, getLogFile() ); + fflush( getLogFile() ); + } + + void write( const sal_Int8* buffer, sal_Int32 bytesRead ) + { + fwrite( buffer, sizeof(sal_Int8), bytesRead, getLogFile() ); + fflush( getLogFile() ); + } + + sal_Int64 seek( sal_Int64 pos ) + { + FILE* pFile = getLogFile(); + fseek( pFile, 0, SEEK_END ); + if ( ftell( pFile ) < pos ) + { + sal_Int8 filler( 0 ); + while ( ftell( pFile ) < pos ) + fwrite( &filler, sizeof( sal_Int8 ), 1, pFile ); + fflush( pFile ); + } + fseek( pFile, pos, SEEK_SET ); + return ftell( pFile ); + } + + sal_Int64 tell() + { + return ftell( getLogFile() ); + } + }; + +} } +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/hsqldb/hsqldb.component b/connectivity/source/drivers/hsqldb/hsqldb.component new file mode 100644 index 000000000..a541e02aa --- /dev/null +++ b/connectivity/source/drivers/hsqldb/hsqldb.component @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + --> + +<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@" + xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="com.sun.star.sdbcx.comp.hsqldb.Driver" + constructor="connectivity_hsqldb_ODriverDelegator_implementation"> + <service name="com.sun.star.sdbc.Driver"/> + <service name="com.sun.star.sdbcx.Driver"/> + </implementation> +</component> |