From ed5640d8b587fbcfed7dd7967f3de04b37a76f26 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 11:06:44 +0200 Subject: Adding upstream version 4:7.4.7. Signed-off-by: Daniel Baumann --- .../source/commontools/AutoRetrievingBase.cxx | 52 + connectivity/source/commontools/BlobHelper.cxx | 71 + connectivity/source/commontools/CommonTools.cxx | 235 ++ .../source/commontools/ConnectionWrapper.cxx | 238 ++ connectivity/source/commontools/DateConversion.cxx | 526 +++++ connectivity/source/commontools/DriversConfig.cxx | 248 ++ .../commontools/FDatabaseMetaDataResultSet.cxx | 851 +++++++ .../FDatabaseMetaDataResultSetMetaData.cxx | 357 +++ connectivity/source/commontools/FValue.cxx | 2473 ++++++++++++++++++++ .../source/commontools/ParameterSubstitution.cxx | 105 + .../source/commontools/RowFunctionParser.cxx | 441 ++++ connectivity/source/commontools/TColumnsHelper.cxx | 208 ++ connectivity/source/commontools/TConnection.cxx | 85 + .../source/commontools/TDatabaseMetaDataBase.cxx | 325 +++ connectivity/source/commontools/TIndex.cxx | 100 + connectivity/source/commontools/TIndexColumns.cxx | 114 + connectivity/source/commontools/TIndexes.cxx | 247 ++ connectivity/source/commontools/TKey.cxx | 107 + connectivity/source/commontools/TKeyColumns.cxx | 132 ++ connectivity/source/commontools/TKeys.cxx | 309 +++ .../source/commontools/TPrivilegesResultSet.cxx | 140 ++ .../source/commontools/TSkipDeletedSet.cxx | 255 ++ connectivity/source/commontools/TSortIndex.cxx | 152 ++ connectivity/source/commontools/TTableHelper.cxx | 610 +++++ connectivity/source/commontools/conncleanup.cxx | 230 ++ connectivity/source/commontools/dbcharset.cxx | 190 ++ connectivity/source/commontools/dbconversion.cxx | 463 ++++ connectivity/source/commontools/dbexception.cxx | 495 ++++ connectivity/source/commontools/dbmetadata.cxx | 443 ++++ connectivity/source/commontools/dbtools.cxx | 2073 ++++++++++++++++ connectivity/source/commontools/dbtools2.cxx | 1018 ++++++++ connectivity/source/commontools/filtermanager.cxx | 254 ++ .../source/commontools/formattedcolumnvalue.cxx | 289 +++ connectivity/source/commontools/parameters.cxx | 1216 ++++++++++ connectivity/source/commontools/paramwrapper.cxx | 354 +++ connectivity/source/commontools/predicateinput.cxx | 421 ++++ connectivity/source/commontools/propertyids.cxx | 103 + connectivity/source/commontools/sqlerror.cxx | 295 +++ .../source/commontools/statementcomposer.cxx | 301 +++ .../source/commontools/warningscontainer.cxx | 110 + 40 files changed, 16636 insertions(+) create mode 100644 connectivity/source/commontools/AutoRetrievingBase.cxx create mode 100644 connectivity/source/commontools/BlobHelper.cxx create mode 100644 connectivity/source/commontools/CommonTools.cxx create mode 100644 connectivity/source/commontools/ConnectionWrapper.cxx create mode 100644 connectivity/source/commontools/DateConversion.cxx create mode 100644 connectivity/source/commontools/DriversConfig.cxx create mode 100644 connectivity/source/commontools/FDatabaseMetaDataResultSet.cxx create mode 100644 connectivity/source/commontools/FDatabaseMetaDataResultSetMetaData.cxx create mode 100644 connectivity/source/commontools/FValue.cxx create mode 100644 connectivity/source/commontools/ParameterSubstitution.cxx create mode 100644 connectivity/source/commontools/RowFunctionParser.cxx create mode 100644 connectivity/source/commontools/TColumnsHelper.cxx create mode 100644 connectivity/source/commontools/TConnection.cxx create mode 100644 connectivity/source/commontools/TDatabaseMetaDataBase.cxx create mode 100644 connectivity/source/commontools/TIndex.cxx create mode 100644 connectivity/source/commontools/TIndexColumns.cxx create mode 100644 connectivity/source/commontools/TIndexes.cxx create mode 100644 connectivity/source/commontools/TKey.cxx create mode 100644 connectivity/source/commontools/TKeyColumns.cxx create mode 100644 connectivity/source/commontools/TKeys.cxx create mode 100644 connectivity/source/commontools/TPrivilegesResultSet.cxx create mode 100644 connectivity/source/commontools/TSkipDeletedSet.cxx create mode 100644 connectivity/source/commontools/TSortIndex.cxx create mode 100644 connectivity/source/commontools/TTableHelper.cxx create mode 100644 connectivity/source/commontools/conncleanup.cxx create mode 100644 connectivity/source/commontools/dbcharset.cxx create mode 100644 connectivity/source/commontools/dbconversion.cxx create mode 100644 connectivity/source/commontools/dbexception.cxx create mode 100644 connectivity/source/commontools/dbmetadata.cxx create mode 100644 connectivity/source/commontools/dbtools.cxx create mode 100644 connectivity/source/commontools/dbtools2.cxx create mode 100644 connectivity/source/commontools/filtermanager.cxx create mode 100644 connectivity/source/commontools/formattedcolumnvalue.cxx create mode 100644 connectivity/source/commontools/parameters.cxx create mode 100644 connectivity/source/commontools/paramwrapper.cxx create mode 100644 connectivity/source/commontools/predicateinput.cxx create mode 100644 connectivity/source/commontools/propertyids.cxx create mode 100644 connectivity/source/commontools/sqlerror.cxx create mode 100644 connectivity/source/commontools/statementcomposer.cxx create mode 100644 connectivity/source/commontools/warningscontainer.cxx (limited to 'connectivity/source/commontools') diff --git a/connectivity/source/commontools/AutoRetrievingBase.cxx b/connectivity/source/commontools/AutoRetrievingBase.cxx new file mode 100644 index 000000000..99327f27e --- /dev/null +++ b/connectivity/source/commontools/AutoRetrievingBase.cxx @@ -0,0 +1,52 @@ +/* -*- 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 + +#include +#include + +namespace connectivity +{ + OUString OAutoRetrievingBase::getTransformedGeneratedStatement(const OUString& _sInsertStatement) const + { + OSL_ENSURE( m_bAutoRetrievingEnabled,"Illegal call here. isAutoRetrievingEnabled is false!"); + OUString sStmt = _sInsertStatement.toAsciiUpperCase(); + if ( sStmt.startsWith("INSERT") ) + { + static const char sTable[] = "$table"; + const sal_Int32 nColumnIndex {m_sGeneratedValueStatement.indexOf("$column")}; + if ( nColumnIndex>=0 ) + { // we need a column + } + const sal_Int32 nTableIndex {m_sGeneratedValueStatement.indexOf(sTable)}; + if ( nTableIndex>=0 ) + { // we need a table name + sal_Int32 nIntoIndex = sStmt.indexOf("INTO ") + 5; + while (nIntoIndex +#include +#include +#include + +using namespace connectivity; +using namespace dbtools; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::uno; + +BlobHelper::BlobHelper(const css::uno::Sequence< sal_Int8 >& _val) : m_aValue(_val) +{ +} + +::sal_Int64 SAL_CALL BlobHelper::length( ) +{ + return m_aValue.getLength(); +} + +css::uno::Sequence< ::sal_Int8 > SAL_CALL BlobHelper::getBytes( ::sal_Int64 pos, ::sal_Int32 _length ) +{ + if ( sal_Int32(pos + _length) > m_aValue.getLength() ) + throw css::sdbc::SQLException(); + return css::uno::Sequence< ::sal_Int8 >(m_aValue.getConstArray() + sal_Int32(pos),_length); +} + +css::uno::Reference< css::io::XInputStream > SAL_CALL BlobHelper::getBinaryStream( ) +{ + return new ::comphelper::SequenceInputStream(m_aValue); +} + + +// The "return" after a call to throwFeatureNotImplementedSQLException() +// (which always throws) will be detected as unreachable when doing +// global inlining. + +SAL_WNOUNREACHABLE_CODE_PUSH + +::sal_Int64 SAL_CALL BlobHelper::position( const css::uno::Sequence< ::sal_Int8 >& /*pattern*/, ::sal_Int64 /*start*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XBlob::position", *this ); + return 0; +} + +::sal_Int64 SAL_CALL BlobHelper::positionOfBlob( const css::uno::Reference< css::sdbc::XBlob >& /*pattern*/, ::sal_Int64 /*start*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XBlob::positionOfBlob", *this ); + return 0; +} + +SAL_WNOUNREACHABLE_CODE_POP + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/commontools/CommonTools.cxx b/connectivity/source/commontools/CommonTools.cxx new file mode 100644 index 000000000..739fe6e66 --- /dev/null +++ b/connectivity/source/commontools/CommonTools.cxx @@ -0,0 +1,235 @@ +/* -*- 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 + +#include +#include +#include +#include +#if HAVE_FEATURE_JAVA +#include +#endif +#include +#include +#include +#include + +using namespace ::comphelper; +static sal_Unicode rtl_ascii_toUpperCase( sal_Unicode ch ) +{ + return ch >= 0x0061 && ch <= 0x007a ? ch + 0x20 : ch; +} + +namespace connectivity +{ + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::java; + using namespace dbtools; + + const sal_Unicode CHAR_PLACE = '_'; + const sal_Unicode CHAR_WILD = '%'; + + bool match(const sal_Unicode* pWild, const sal_Unicode* pStr, const sal_Unicode cEscape) + { + int pos=0; + int flag=0; + + while ( *pWild || flag ) + { + switch (*pWild) + { + case CHAR_PLACE: + if ( *pStr == 0 ) + return false; + break; + default: + if (*pWild && (*pWild == cEscape) && ((*(pWild+1)== CHAR_PLACE) || (*(pWild+1) == CHAR_WILD)) ) + pWild++; + if ( rtl_ascii_toUpperCase(*pWild) != rtl_ascii_toUpperCase(*pStr) ) + if ( !pos ) + return false; + else + pWild += pos; + else + break; + // WARNING/TODO: in certain circumstances it will run into + // the next 'case'! + [[fallthrough]]; + case CHAR_WILD: + while ( *pWild == CHAR_WILD ) + pWild++; + if ( *pWild == 0 ) + return true; + flag = 1; + pos = 0; + if ( *pStr == 0 ) + return ( *pWild == 0 ); + while ( *pStr && *pStr != *pWild ) + { + if ( *pWild == CHAR_PLACE ) { + pWild++; + while ( *pWild == CHAR_WILD ) + pWild++; + } + pStr++; + if ( *pStr == 0 ) + return ( *pWild == 0 ); + } + break; + } + if ( *pWild != 0 ) + pWild++; + if ( *pStr != 0 ) + pStr++; + else + flag = 0; + if ( flag ) + pos--; + } + return ( *pStr == 0 ) && ( *pWild == 0 ); + } + +#if HAVE_FEATURE_JAVA + ::rtl::Reference< jvmaccess::VirtualMachine > getJavaVM(const Reference& _rxContext) + { + ::rtl::Reference< jvmaccess::VirtualMachine > aRet; + OSL_ENSURE(_rxContext.is(),"No XMultiServiceFactory a.v.!"); + if(!_rxContext.is()) + return aRet; + + try + { + Reference< XJavaVM > xVM = JavaVirtualMachine::create(_rxContext); + + Sequence processID(17); // 16 + 1 + auto pprocessID = processID.getArray(); + rtl_getGlobalProcessId( reinterpret_cast(pprocessID) ); + pprocessID[16] = 0; // RETURN_VIRTUALMACHINE + + Any uaJVM = xVM->getJavaVM( processID ); + sal_Int64 nTemp; + if (!(uaJVM >>= nTemp)) { + throw Exception("cannot get result for getJavaVM", nullptr); // -5 + } + aRet = reinterpret_cast( + static_cast(nTemp)); + } + catch (Exception&) + { + TOOLS_WARN_EXCEPTION("connectivity.commontools", "getJavaVM failed:"); + } + + return aRet; + } + + bool existsJavaClassByName( const ::rtl::Reference< jvmaccess::VirtualMachine >& _pJVM,std::u16string_view _sClassName ) + { + bool bRet = false; + if ( _pJVM.is() ) + { + jvmaccess::VirtualMachine::AttachGuard aGuard(_pJVM); + JNIEnv* pEnv = aGuard.getEnvironment(); + if( pEnv ) + { + OString sClassName = OUStringToOString(_sClassName, RTL_TEXTENCODING_ASCII_US); + sClassName = sClassName.replace('.','/'); + jobject out = pEnv->FindClass(sClassName.getStr()); + bRet = out != nullptr; + pEnv->DeleteLocalRef( out ); + } + } + return bRet; + } +#endif +} + +namespace dbtools +{ + +static bool isCharOk(sal_Unicode c, std::u16string_view _rSpecials) +{ + + return ( ((c >= 97) && (c <= 122)) || ((c >= 65) && (c <= 90)) || ((c >= 48) && (c <= 57)) || + c == '_' || _rSpecials.find(c) != std::u16string_view::npos); +} + + +bool isValidSQLName(const OUString& rName, std::u16string_view _rSpecials) +{ + // Test for correct naming (in SQL sense) + // This is important for table names for example + const sal_Unicode* pStr = rName.getStr(); + if (*pStr > 127 || rtl::isAsciiDigit(*pStr)) + return false; + + for (; *pStr; ++pStr ) + if(!isCharOk(*pStr,_rSpecials)) + return false; + + if ( !rName.isEmpty() + && ( (rName.toChar() == '_') + || ( (rName.toChar() >= '0') + && (rName.toChar() <= '9') + ) + ) + ) + return false; + // the SQL-Standard requires the first character to be an alphabetic character, which + // isn't easy to decide in UniCode... + // So we just prohibit the characters which already lead to problems... + // 11.04.00 - 74902 - FS + + return true; +} + +// Creates a new name if necessary +OUString convertName2SQLName(const OUString& rName, std::u16string_view _rSpecials) +{ + if(isValidSQLName(rName,_rSpecials)) + return rName; + + const sal_Unicode* pStr = rName.getStr(); + // if not valid + if (*pStr >= 128 || rtl::isAsciiDigit(*pStr)) + return OUString(); + + OUStringBuffer aNewName(rName); + sal_Int32 nLength = rName.getLength(); + for (sal_Int32 i=0; i < nLength; ++i) + if(!isCharOk(aNewName[i],_rSpecials)) + aNewName[i] = '_'; + + return aNewName.makeStringAndClear(); +} + +OUString quoteName(const OUString& _rQuote, const OUString& _rName) +{ + OUString sName = _rName; + if( !_rQuote.isEmpty() && _rQuote.toChar() != ' ') + sName = _rQuote + _rName + _rQuote; + return sName; +} + + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/commontools/ConnectionWrapper.cxx b/connectivity/source/commontools/ConnectionWrapper.cxx new file mode 100644 index 000000000..df5ef04ee --- /dev/null +++ b/connectivity/source/commontools/ConnectionWrapper.cxx @@ -0,0 +1,238 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace connectivity; + +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::beans; +using namespace com::sun::star::sdbc; +using namespace ::com::sun::star::reflection; + +OConnectionWrapper::OConnectionWrapper() +{ + +} + +void OConnectionWrapper::setDelegation(Reference< XAggregation >& _rxProxyConnection,oslInterlockedCount& _rRefCount) +{ + OSL_ENSURE(_rxProxyConnection.is(),"OConnectionWrapper: Connection must be valid!"); + osl_atomic_increment( &_rRefCount ); + if (_rxProxyConnection.is()) + { + // transfer the (one and only) real ref to the aggregate to our member + m_xProxyConnection = _rxProxyConnection; + _rxProxyConnection = nullptr; + ::comphelper::query_aggregation(m_xProxyConnection,m_xConnection); + m_xTypeProvider.set(m_xConnection,UNO_QUERY); + m_xUnoTunnel.set(m_xConnection,UNO_QUERY); + m_xServiceInfo.set(m_xConnection,UNO_QUERY); + + // set ourself as delegator + Reference xIf = static_cast< XUnoTunnel* >( this ); + m_xProxyConnection->setDelegator( xIf ); + + } + osl_atomic_decrement( &_rRefCount ); +} + +void OConnectionWrapper::setDelegation(const Reference< XConnection >& _xConnection + ,const Reference< XComponentContext>& _rxContext + ,oslInterlockedCount& _rRefCount) +{ + OSL_ENSURE(_xConnection.is(),"OConnectionWrapper: Connection must be valid!"); + osl_atomic_increment( &_rRefCount ); + + m_xConnection = _xConnection; + m_xTypeProvider.set(m_xConnection,UNO_QUERY); + m_xUnoTunnel.set(m_xConnection,UNO_QUERY); + m_xServiceInfo.set(m_xConnection,UNO_QUERY); + + Reference< XProxyFactory > xProxyFactory = ProxyFactory::create( _rxContext ); + Reference< XAggregation > xConProxy = xProxyFactory->createProxy(_xConnection); + if (xConProxy.is()) + { + // transfer the (one and only) real ref to the aggregate to our member + m_xProxyConnection = xConProxy; + + // set ourself as delegator + Reference xIf = static_cast< XUnoTunnel* >( this ); + m_xProxyConnection->setDelegator( xIf ); + + } + osl_atomic_decrement( &_rRefCount ); +} + +void OConnectionWrapper::disposing() +{ +m_xConnection.clear(); +} + +OConnectionWrapper::~OConnectionWrapper() +{ + if (m_xProxyConnection.is()) + m_xProxyConnection->setDelegator(nullptr); +} + +// XServiceInfo + +OUString SAL_CALL OConnectionWrapper::getImplementationName( ) +{ + return "com.sun.star.sdbc.drivers.OConnectionWrapper"; +} + + +css::uno::Sequence< OUString > SAL_CALL OConnectionWrapper::getSupportedServiceNames( ) +{ + // first collect the services which are supported by our aggregate + Sequence< OUString > aSupported; + if ( m_xServiceInfo.is() ) + aSupported = m_xServiceInfo->getSupportedServiceNames(); + + // append our own service, if necessary + OUString sConnectionService( "com.sun.star.sdbc.Connection" ); + if ( ::comphelper::findValue( aSupported, sConnectionService ) == -1 ) + { + sal_Int32 nLen = aSupported.getLength(); + aSupported.realloc( nLen + 1 ); + aSupported.getArray()[ nLen ] = sConnectionService; + } + + // outta here + return aSupported; +} + + +sal_Bool SAL_CALL OConnectionWrapper::supportsService( const OUString& _rServiceName ) +{ + return cppu::supportsService(this, _rServiceName); +} + + +Any SAL_CALL OConnectionWrapper::queryInterface( const Type& _rType ) +{ + Any aReturn = OConnection_BASE::queryInterface(_rType); + return aReturn.hasValue() ? aReturn : (m_xProxyConnection.is() ? m_xProxyConnection->queryAggregation(_rType) : aReturn); +} + +Sequence< Type > SAL_CALL OConnectionWrapper::getTypes( ) +{ + return ::comphelper::concatSequences( + OConnection_BASE::getTypes(), + m_xTypeProvider->getTypes() + ); +} + +// css::lang::XUnoTunnel +sal_Int64 SAL_CALL OConnectionWrapper::getSomething( const Sequence< sal_Int8 >& rId ) +{ + if (comphelper::isUnoTunnelId(rId)) + return comphelper::getSomething_cast(this); + + if(m_xUnoTunnel.is()) + return m_xUnoTunnel->getSomething(rId); + return 0; +} + + +const Sequence< sal_Int8 > & OConnectionWrapper::getUnoTunnelId() +{ + static const comphelper::UnoIdInit implId; + return implId.getSeq(); +} + +namespace +{ + class TPropertyValueLessFunctor + { + public: + TPropertyValueLessFunctor() + {} + bool operator() (const css::beans::PropertyValue& lhs, const css::beans::PropertyValue& rhs) const + { + return lhs.Name.compareToIgnoreAsciiCase(rhs.Name) < 0; + } + }; + +} + + +// creates a unique id out of the url and sequence of properties +void OConnectionWrapper::createUniqueId( const OUString& _rURL + ,Sequence< PropertyValue >& _rInfo + ,sal_uInt8* _pBuffer + ,const OUString& _rUserName + ,const OUString& _rPassword) +{ + // first we create the digest we want to have + ::comphelper::Hash sha1(::comphelper::HashType::SHA1); + sha1.update(reinterpret_cast(_rURL.getStr()), _rURL.getLength() * sizeof(sal_Unicode)); + if ( !_rUserName.isEmpty() ) + sha1.update(reinterpret_cast(_rUserName.getStr()), _rUserName.getLength() * sizeof(sal_Unicode)); + if ( !_rPassword.isEmpty() ) + sha1.update(reinterpret_cast(_rPassword.getStr()), _rPassword.getLength() * sizeof(sal_Unicode)); + // now we need to sort the properties + auto [begin, end] = asNonConstRange(_rInfo); + std::sort(begin,end,TPropertyValueLessFunctor()); + + for (PropertyValue const & prop : std::as_const(_rInfo)) + { + // we only include strings an integer values + OUString sValue; + if ( prop.Value >>= sValue ) + ; + else + { + sal_Int32 nValue = 0; + if ( prop.Value >>= nValue ) + sValue = OUString::number(nValue); + else + { + Sequence< OUString> aSeq; + if ( prop.Value >>= aSeq ) + { + for(OUString const & s : std::as_const(aSeq)) + sha1.update(reinterpret_cast(s.getStr()), s.getLength() * sizeof(sal_Unicode)); + } + } + } + if ( !sValue.isEmpty() ) + { + // we don't have to convert this into UTF8 because we don't store on a file system + sha1.update(reinterpret_cast(sValue.getStr()), sValue.getLength() * sizeof(sal_Unicode)); + } + } + + std::vector result(sha1.finalize()); + std::copy(result.begin(), result.end(), _pBuffer); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/commontools/DateConversion.cxx b/connectivity/source/commontools/DateConversion.cxx new file mode 100644 index 000000000..38f20af09 --- /dev/null +++ b/connectivity/source/commontools/DateConversion.cxx @@ -0,0 +1,526 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +using namespace ::connectivity; +using namespace ::comphelper; +using namespace ::com::sun::star::script; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::sdbc; +using namespace ::dbtools; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::uno; + +OUString DBTypeConversion::toSQLString(sal_Int32 eType, const Any& _rVal, + const Reference< XTypeConverter >& _rxTypeConverter) +{ + OUStringBuffer aRet; + if (_rVal.hasValue()) + { + try + { + switch (eType) + { + case DataType::INTEGER: + case DataType::BIT: + case DataType::BOOLEAN: + case DataType::TINYINT: + case DataType::SMALLINT: + if (_rVal.getValueType().getTypeClass() == css::uno::TypeClass_BOOLEAN) + { + if (::cppu::any2bool(_rVal)) + aRet.append("1"); + else + aRet.append("0"); + } + else + { + OUString sTemp; + _rxTypeConverter->convertToSimpleType(_rVal, TypeClass_STRING) >>= sTemp; + aRet.append(sTemp); + } + break; + case DataType::CHAR: + case DataType::VARCHAR: + case DataType::LONGVARCHAR: + aRet.append("'"); + { + OUString aTemp; + _rxTypeConverter->convertToSimpleType(_rVal, TypeClass_STRING) >>= aTemp; + sal_Int32 nIndex = sal_Int32(-2); + static const OUStringLiteral sQuot(u"\'"); + do + { + nIndex += 2; + nIndex = aTemp.indexOf(sQuot,nIndex); + if(nIndex != -1) + aTemp = aTemp.replaceAt(nIndex,sQuot.getLength(), u"\'\'"); + } while (nIndex != -1); + + aRet.append(aTemp); + } + aRet.append("'"); + break; + case DataType::REAL: + case DataType::DOUBLE: + case DataType::DECIMAL: + case DataType::NUMERIC: + case DataType::BIGINT: + default: + { + OUString sTemp; + _rxTypeConverter->convertToSimpleType(_rVal, TypeClass_STRING) >>= sTemp; + aRet.append(sTemp); + } + break; + case DataType::TIMESTAMP: + { + DateTime aDateTime; + bool bOk = false; + if (_rVal.getValueType().getTypeClass() == css::uno::TypeClass_DOUBLE) + { + double nValue = 0.0; + _rVal >>= nValue; + aDateTime = DBTypeConversion::toDateTime(nValue); + bOk = true; + } + else if (_rVal.getValueType().getTypeClass() == css::uno::TypeClass_STRING) + { + OUString sValue; + _rVal >>= sValue; + aDateTime = DBTypeConversion::toDateTime(sValue); + bOk = true; + } + else + bOk = _rVal >>= aDateTime; + + OSL_ENSURE( bOk, "DBTypeConversion::toSQLString: _rVal is not datetime!"); + // check if this is really a timestamp or only a date + if ( bOk ) + { + aRet.append("{ts '"); + aRet.append(DBTypeConversion::toDateTimeString(aDateTime)); + aRet.append("'}"); + break; + } + break; + } + case DataType::DATE: + { + Date aDate; + bool bOk = false; + if (_rVal.getValueType().getTypeClass() == css::uno::TypeClass_DOUBLE) + { + double nValue = 0.0; + _rVal >>= nValue; + aDate = DBTypeConversion::toDate(nValue); + bOk = true; + } + else if (_rVal.getValueType().getTypeClass() == css::uno::TypeClass_STRING) + { + OUString sValue; + _rVal >>= sValue; + aDate = DBTypeConversion::toDate(sValue); + bOk = true; + } + else + bOk = _rVal >>= aDate; + OSL_ENSURE( bOk, "DBTypeConversion::toSQLString: _rVal is not date!"); + aRet.append("{d '"); + aRet.append(DBTypeConversion::toDateString(aDate)); + aRet.append("'}"); + } break; + case DataType::TIME: + { + css::util::Time aTime; + bool bOk = false; + if (_rVal.getValueType().getTypeClass() == css::uno::TypeClass_DOUBLE) + { + double nValue = 0.0; + _rVal >>= nValue; + aTime = DBTypeConversion::toTime(nValue); + bOk = true; + } + else if (_rVal.getValueType().getTypeClass() == css::uno::TypeClass_STRING) + { + OUString sValue; + _rVal >>= sValue; + aTime = DBTypeConversion::toTime(sValue); + bOk = true; + } + else + bOk = _rVal >>= aTime; + OSL_ENSURE( bOk,"DBTypeConversion::toSQLString: _rVal is not time!"); + aRet.append("{t '"); + aRet.append(DBTypeConversion::toTimeString(aTime)); + aRet.append("'}"); + } break; + } + } + catch ( const Exception& ) + { + OSL_FAIL("TypeConversion Error"); + } + } + else + aRet.append(" NULL "); + return aRet.makeStringAndClear(); +} + +Date DBTypeConversion::getNULLDate(const Reference< XNumberFormatsSupplier > &xSupplier) +{ + OSL_ENSURE(xSupplier.is(), "getNULLDate : the formatter doesn't implement a supplier !"); + if (xSupplier.is()) + { + try + { + // get the null date + Date aDate; + xSupplier->getNumberFormatSettings()->getPropertyValue("NullDate") >>= aDate; + return aDate; + } + catch ( const Exception& ) + { + } + } + + return getStandardDate(); +} + +void DBTypeConversion::setValue(const Reference& xVariant, + const Reference& xFormatter, + const Date& rNullDate, + const OUString& rString, + sal_Int32 nKey, + sal_Int16 nFieldType, + sal_Int16 nKeyType) +{ + if (!rString.isEmpty()) + { + // Does the String need to be formatted? + sal_Int16 nTypeClass = nKeyType & ~NumberFormat::DEFINED; + bool bTextFormat = nTypeClass == NumberFormat::TEXT; + sal_Int32 nKeyToUse = bTextFormat ? 0 : nKey; + sal_Int16 nRealUsedTypeClass = nTypeClass; + // for a Text-Format the formatter needs some more freedom, otherwise + // convertStringToNumber will throw a NotNumericException + try + { + double fValue = xFormatter->convertStringToNumber(nKeyToUse, rString); + Reference< XNumberFormats > xFormats(xFormatter->getNumberFormatsSupplier()->getNumberFormats()); + Reference< XNumberFormatTypes > xFormatTypes(xFormats, UNO_QUERY); + sal_Int32 nStandardKey(0); + if(xFormatTypes.is()) + { + const Reference< XPropertySet > xFormatProps(xFormats->getByKey(nKeyToUse)); + if (xFormatProps.is()) + { + css::lang::Locale loc; + if (xFormatProps->getPropertyValue("Locale") >>= loc) + nStandardKey = xFormatTypes->getStandardIndex(loc); + else + { + assert(false); + } + } + else + { + SAL_WARN("connectivity.commontools", "no format by key " << nKeyToUse); + } + } + else + { + assert(false); + } + // Why use nStandardKey rather than nKeyToUse here? I'm not sure, but "it was always like that". + // Previously had hardcoded 0 instead of nStandardKey, which led to problems with dates + // because of differences M/D/Y vs D/M/Y. This at least fixes those problems, but possibly + // nKeyToUse is an even better choice than nStandardKey. + // OTOH, using nKeyToUse nullifies the special treatment for percent formats, + // leading to "5" (in a percent format) to be understood as "500%" instead of "5%". + sal_Int32 nRealUsedKey = xFormatter->detectNumberFormat(nStandardKey, rString); + if (nRealUsedKey != nKeyToUse) + nRealUsedTypeClass = getNumberFormatType(xFormatter, nRealUsedKey) & ~NumberFormat::DEFINED; + + // and again a special treatment, this time for percent formats + if ((NumberFormat::NUMBER == nRealUsedTypeClass) && (NumberFormat::PERCENT == nTypeClass)) + { // formatting should be "percent", but the String provides just a simple number -> adjust + OUString sExpanded = rString + "%"; + fValue = xFormatter->convertStringToNumber(nKeyToUse, sExpanded); + } + + switch (nRealUsedTypeClass) + { + case NumberFormat::DATE: + case NumberFormat::DATETIME: + case NumberFormat::TIME: + DBTypeConversion::setValue(xVariant,rNullDate,fValue,nRealUsedTypeClass); + break; + case NumberFormat::CURRENCY: + case NumberFormat::NUMBER: + case NumberFormat::SCIENTIFIC: + case NumberFormat::FRACTION: + case NumberFormat::PERCENT: + xVariant->updateDouble(fValue); + break; + default: + xVariant->updateString(rString); + } + } + catch(const Exception& ) + { + xVariant->updateString(rString); + } + } + else + { + switch (nFieldType) + { + case css::sdbc::DataType::CHAR: + case css::sdbc::DataType::VARCHAR: + case css::sdbc::DataType::LONGVARCHAR: + xVariant->updateString(rString); + break; + default: + xVariant->updateNull(); + } + } +} + + +void DBTypeConversion::setValue(const Reference& xVariant, + const Date& rNullDate, + const double& rValue, + sal_Int16 nKeyType) +{ + switch (nKeyType & ~NumberFormat::DEFINED) + { + case NumberFormat::DATE: + xVariant->updateDate(toDate( rValue, rNullDate)); + break; + case NumberFormat::DATETIME: + xVariant->updateTimestamp(toDateTime(rValue,rNullDate)); + break; + case NumberFormat::TIME: + xVariant->updateTime(toTime(rValue)); + break; + default: + { + double nValue = rValue; +// Reference xProp(xVariant,UNO_QUERY); +// if ( xProp.is() +// && xProp->getPropertySetInfo()->hasPropertyByName(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISSIGNED)) +// && !::comphelper::getBOOL(xProp->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISSIGNED))) ) +// { +// switch (::comphelper::getINT32(xProp->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)))) +// { +// case DataType::TINYINT: +// nValue = static_cast(rValue); +// break; +// case DataType::SMALLINT: +// nValue = static_cast(rValue); +// break; +// case DataType::INTEGER: +// nValue = static_cast(rValue); +// break; +// case DataType::BIGINT: +// nValue = static_cast(rValue); +// break; +// } +// } + xVariant->updateDouble(nValue); + } + } +} + + +double DBTypeConversion::getValue( const Reference< XColumn >& i_column, const Date& i_relativeToNullDate ) +{ + try + { + const Reference< XPropertySet > xProp( i_column, UNO_QUERY_THROW ); + + const sal_Int32 nColumnType = ::comphelper::getINT32( xProp->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_TYPE ) ) ); + switch ( nColumnType ) + { + case DataType::DATE: + return toDouble( i_column->getDate(), i_relativeToNullDate ); + + case DataType::TIME: + return toDouble( i_column->getTime() ); + + case DataType::TIMESTAMP: + return toDouble( i_column->getTimestamp(), i_relativeToNullDate ); + + default: + { + bool bIsSigned = true; + OSL_VERIFY( xProp->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_ISSIGNED ) ) >>= bIsSigned ); + if ( !bIsSigned ) + { + switch ( nColumnType) + { + case DataType::TINYINT: + return static_cast(static_cast(i_column->getByte())); + case DataType::SMALLINT: + return static_cast(static_cast(i_column->getShort())); + case DataType::INTEGER: + return static_cast(static_cast(i_column->getInt())); + case DataType::BIGINT: + return static_cast(static_cast(i_column->getLong())); + } + } + } + return i_column->getDouble(); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("connectivity.commontools"); + return 0.0; + } +} + +OUString DBTypeConversion::getFormattedValue(const Reference< XPropertySet>& _xColumn, + const Reference& _xFormatter, + const css::lang::Locale& _rLocale, + const Date& _rNullDate) +{ + OSL_ENSURE(_xColumn.is() && _xFormatter.is(), "DBTypeConversion::getFormattedValue: invalid arg !"); + if (!_xColumn.is() || !_xFormatter.is()) + return OUString(); + + sal_Int32 nKey(0); + try + { + _xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FORMATKEY)) >>= nKey; + } + catch (const Exception& ) + { + TOOLS_WARN_EXCEPTION( "connectivity.commontools", "DBTypeConversion::getValue: caught an exception while asking for the format key!"); + } + + if (!nKey) + { + Reference xFormats( _xFormatter->getNumberFormatsSupplier()->getNumberFormats() ); + + nKey = ::dbtools::getDefaultNumberFormat(_xColumn, + Reference< XNumberFormatTypes > (xFormats, UNO_QUERY), + _rLocale); + + } + + sal_Int16 nKeyType = getNumberFormatType(_xFormatter, nKey) & ~NumberFormat::DEFINED; + + return DBTypeConversion::getFormattedValue(Reference< XColumn > (_xColumn, UNO_QUERY), _xFormatter, _rNullDate, nKey, nKeyType); +} + + +OUString DBTypeConversion::getFormattedValue(const Reference& xVariant, + const Reference& xFormatter, + const Date& rNullDate, + sal_Int32 nKey, + sal_Int16 nKeyType) +{ + OUString aString; + if (xVariant.is()) + { + try + { + switch (nKeyType & ~NumberFormat::DEFINED) + { + case NumberFormat::DATE: + case NumberFormat::DATETIME: + { + // get a value which represents the given date, relative to the given null date + double fValue = getValue( xVariant, rNullDate ); + if ( !xVariant->wasNull() ) + { + // get the null date of the formatter + Date aFormatterNullDate( rNullDate ); + try + { + Reference< XNumberFormatsSupplier > xSupplier( xFormatter->getNumberFormatsSupplier(), UNO_SET_THROW ); + Reference< XPropertySet > xFormatterSettings( xSupplier->getNumberFormatSettings(), UNO_SET_THROW ); + OSL_VERIFY( xFormatterSettings->getPropertyValue("NullDate") >>= aFormatterNullDate ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("connectivity.commontools"); + } + // get a value which represents the given date, relative to the null date of the formatter + fValue -= toDays( rNullDate, aFormatterNullDate ); + // format this value + aString = xFormatter->convertNumberToString( nKey, fValue ); + } + } + break; + case NumberFormat::TIME: + case NumberFormat::NUMBER: + case NumberFormat::SCIENTIFIC: + case NumberFormat::FRACTION: + case NumberFormat::PERCENT: + { + double fValue = xVariant->getDouble(); + if (!xVariant->wasNull()) + aString = xFormatter->convertNumberToString(nKey, fValue); + } break; + case NumberFormat::CURRENCY: + { + double fValue = xVariant->getDouble(); + if (!xVariant->wasNull()) + aString = xFormatter->getInputString(nKey, fValue); + } break; + case NumberFormat::TEXT: + aString = xFormatter->formatString(nKey, xVariant->getString()); + break; + default: + aString = xVariant->getString(); + } + } + catch(const Exception& ) + { + aString = xVariant->getString(); + } + } + return aString; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/commontools/DriversConfig.cxx b/connectivity/source/commontools/DriversConfig.cxx new file mode 100644 index 000000000..e1d492f9f --- /dev/null +++ b/connectivity/source/commontools/DriversConfig.cxx @@ -0,0 +1,248 @@ +/* -*- 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 + +#include +#include +#include +#include + +using namespace connectivity; +using namespace utl; +using namespace ::com::sun::star; + +namespace +{ + void lcl_convert(const uno::Sequence< OUString >& _aSource,uno::Any& _rDest) + { + uno::Sequence aRet(_aSource.getLength()); + uno::Any* pAny = aRet.getArray(); + const OUString* pIter = _aSource.getConstArray(); + const OUString* pEnd = pIter + _aSource.getLength(); + for (;pIter != pEnd ; ++pIter,++pAny) + { + *pAny <<= *pIter; + } + _rDest <<= aRet; + } + void lcl_fillValues(const ::utl::OConfigurationNode& _aURLPatternNode,const OUString& _sNode,::comphelper::NamedValueCollection& _rValues) + { + const ::utl::OConfigurationNode aPropertiesNode = _aURLPatternNode.openNode(_sNode); + if ( !aPropertiesNode.isValid() ) + return; + + uno::Sequence< OUString > aStringSeq; + const uno::Sequence< OUString > aProperties = aPropertiesNode.getNodeNames(); + const OUString* pPropertiesIter = aProperties.getConstArray(); + const OUString* pPropertiesEnd = pPropertiesIter + aProperties.getLength(); + for (;pPropertiesIter != pPropertiesEnd ; ++pPropertiesIter) + { + uno::Any aValue = aPropertiesNode.getNodeValue(*pPropertiesIter + "/Value"); + if ( aValue >>= aStringSeq ) + { + lcl_convert(aStringSeq,aValue); + } + _rValues.put(*pPropertiesIter,aValue); + } // for (;pPropertiesIter != pPropertiesEnd ; ++pPropertiesIter,++pNamedIter) + } + void lcl_readURLPatternNode(const ::utl::OConfigurationTreeRoot& _aInstalled,const OUString& _sEntry,TInstalledDriver& _rInstalledDriver) + { + const ::utl::OConfigurationNode aURLPatternNode = _aInstalled.openNode(_sEntry); + if ( !aURLPatternNode.isValid() ) + return; + + OUString sParentURLPattern; + aURLPatternNode.getNodeValue("ParentURLPattern") >>= sParentURLPattern; + if ( !sParentURLPattern.isEmpty() ) + lcl_readURLPatternNode(_aInstalled,sParentURLPattern,_rInstalledDriver); + + OUString sDriverFactory; + aURLPatternNode.getNodeValue("Driver") >>= sDriverFactory; + if ( !sDriverFactory.isEmpty() ) + _rInstalledDriver.sDriverFactory = sDriverFactory; + + OUString sDriverTypeDisplayName; + aURLPatternNode.getNodeValue("DriverTypeDisplayName") >>= sDriverTypeDisplayName; + OSL_ENSURE(!sDriverTypeDisplayName.isEmpty(),"No valid DriverTypeDisplayName property!"); + if ( !sDriverTypeDisplayName.isEmpty() ) + _rInstalledDriver.sDriverTypeDisplayName = sDriverTypeDisplayName; + + lcl_fillValues(aURLPatternNode,"Properties",_rInstalledDriver.aProperties); + lcl_fillValues(aURLPatternNode,"Features",_rInstalledDriver.aFeatures); + lcl_fillValues(aURLPatternNode,"MetaData",_rInstalledDriver.aMetaData); + } +} + +DriversConfigImpl::DriversConfigImpl() +{ +} + +const TInstalledDrivers& DriversConfigImpl::getInstalledDrivers(const uno::Reference< uno::XComponentContext >& _rxORB) const +{ + if ( m_aDrivers.empty() ) + { + if ( !m_aInstalled.isValid() ) + { + m_aInstalled = ::utl::OConfigurationTreeRoot::createWithComponentContext(_rxORB, + "org.openoffice.Office.DataAccess.Drivers/Installed", -1, ::utl::OConfigurationTreeRoot::CM_READONLY); + } + + if ( m_aInstalled.isValid() ) + { + const uno::Sequence< OUString > aURLPatterns = m_aInstalled.getNodeNames(); + const OUString* pPatternIter = aURLPatterns.getConstArray(); + const OUString* pPatternEnd = pPatternIter + aURLPatterns.getLength(); + for (;pPatternIter != pPatternEnd ; ++pPatternIter) + { + TInstalledDriver aInstalledDriver; + lcl_readURLPatternNode(m_aInstalled,*pPatternIter,aInstalledDriver); + if ( !aInstalledDriver.sDriverFactory.isEmpty() ) + m_aDrivers.emplace(*pPatternIter,aInstalledDriver); + } + } // if ( m_aInstalled.isValid() ) + } + return m_aDrivers; +} + +DriversConfig::DriversConfig(const uno::Reference< uno::XComponentContext >& _rxORB) +:m_xORB(_rxORB) +{ +} + + +DriversConfig::~DriversConfig() +{ +} + + +DriversConfig::DriversConfig( const DriversConfig& _rhs ) +{ + *this = _rhs; +} + + +DriversConfig& DriversConfig::operator=( const DriversConfig& _rhs ) +{ + if ( this != &_rhs ) + { + m_aNode = _rhs.m_aNode; + } + return *this; +} + + +OUString DriversConfig::getDriverFactoryName(std::u16string_view _sURL) const +{ +#if ENABLE_FUZZERS + if (o3tl::starts_with(_sURL, u"sdbc:dbase:")) + return "com.sun.star.comp.sdbc.dbase.ODriver"; +#endif + + const TInstalledDrivers& rDrivers = m_aNode->getInstalledDrivers(m_xORB); + OUString sRet; + OUString sOldPattern; + for(const auto& [rPattern, rDriver] : rDrivers) + { + WildCard aWildCard(rPattern); + if ( sOldPattern.getLength() < rPattern.getLength() && aWildCard.Matches(_sURL) ) + { + sRet = rDriver.sDriverFactory; + sOldPattern = rPattern; + } + } + + return sRet; +} + +OUString DriversConfig::getDriverTypeDisplayName(std::u16string_view _sURL) const +{ + const TInstalledDrivers& rDrivers = m_aNode->getInstalledDrivers(m_xORB); + OUString sRet; + OUString sOldPattern; + for(const auto& [rPattern, rDriver] : rDrivers) + { + WildCard aWildCard(rPattern); + if ( sOldPattern.getLength() < rPattern.getLength() && aWildCard.Matches(_sURL) ) + { + sRet = rDriver.sDriverTypeDisplayName; + sOldPattern = rPattern; + } + } + + return sRet; +} + +const ::comphelper::NamedValueCollection& DriversConfig::getProperties(std::u16string_view _sURL) + const +{ + return impl_get(_sURL,1); +} + +const ::comphelper::NamedValueCollection& DriversConfig::getFeatures(std::u16string_view _sURL) + const +{ + return impl_get(_sURL,0); +} + +const ::comphelper::NamedValueCollection& DriversConfig::getMetaData(std::u16string_view _sURL) + const +{ + return impl_get(_sURL,2); +} + +const ::comphelper::NamedValueCollection& DriversConfig::impl_get(std::u16string_view _sURL,sal_Int32 _nProps) const +{ + const TInstalledDrivers& rDrivers = m_aNode->getInstalledDrivers(m_xORB); + const ::comphelper::NamedValueCollection* pRet = nullptr; + OUString sOldPattern; + for(const auto& [rPattern, rDriver] : rDrivers) + { + WildCard aWildCard(rPattern); + if ( sOldPattern.getLength() < rPattern.getLength() && aWildCard.Matches(_sURL) ) + { + switch(_nProps) + { + case 0: + pRet = &rDriver.aFeatures; + break; + case 1: + pRet = &rDriver.aProperties; + break; + case 2: + pRet = &rDriver.aMetaData; + break; + } + sOldPattern = rPattern; + } + } // for(;aIter != aEnd;++aIter) + if ( pRet == nullptr ) + { + static const ::comphelper::NamedValueCollection s_sEmpty; + pRet = &s_sEmpty; + } + return *pRet; +} + +uno::Sequence< OUString > DriversConfig::getURLs() const +{ + const TInstalledDrivers& rDrivers = m_aNode->getInstalledDrivers(m_xORB); + return comphelper::mapKeysToSequence(rDrivers); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/commontools/FDatabaseMetaDataResultSet.cxx b/connectivity/source/commontools/FDatabaseMetaDataResultSet.cxx new file mode 100644 index 000000000..3c755f206 --- /dev/null +++ b/connectivity/source/commontools/FDatabaseMetaDataResultSet.cxx @@ -0,0 +1,851 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace connectivity; +using namespace dbtools; +using namespace cppu; + +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; + +ODatabaseMetaDataResultSet::ODatabaseMetaDataResultSet() + :ODatabaseMetaDataResultSet_BASE(m_aMutex) + ,::comphelper::OPropertyContainer(ODatabaseMetaDataResultSet_BASE::rBHelper) + ,m_nColPos(0) + ,m_bBOF(true) + ,m_bEOF(true) +{ + construct(); +} + + +ODatabaseMetaDataResultSet::ODatabaseMetaDataResultSet( MetaDataResultSetType _eType ) + :ODatabaseMetaDataResultSet_BASE(m_aMutex) + ,::comphelper::OPropertyContainer(ODatabaseMetaDataResultSet_BASE::rBHelper) + ,m_nColPos(0) + ,m_bBOF(true) + ,m_bEOF(true) +{ + construct(); + + setType(_eType); +} + + +ODatabaseMetaDataResultSet::~ODatabaseMetaDataResultSet() +{ +} + +void ODatabaseMetaDataResultSet::construct() +{ + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE), PROPERTY_ID_FETCHSIZE, 0,&m_nFetchSize, ::cppu::UnoType::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE), PROPERTY_ID_RESULTSETTYPE, PropertyAttribute::READONLY,&m_nResultSetType, ::cppu::UnoType::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION), PROPERTY_ID_FETCHDIRECTION, 0, &m_nFetchDirection, ::cppu::UnoType::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY), PROPERTY_ID_RESULTSETCONCURRENCY, PropertyAttribute::READONLY,&m_nResultSetConcurrency, ::cppu::UnoType::get()); +} + +void ODatabaseMetaDataResultSet::setType(MetaDataResultSetType _eType) +{ + switch( _eType ) + { + case eCatalogs: setCatalogsMap(); break; + case eSchemas: setSchemasMap(); break; + case eColumnPrivileges: setColumnPrivilegesMap(); break; + case eColumns: setColumnsMap(); break; + case eTables: setTablesMap(); break; + case eTableTypes: setTableTypes(); break; + case eProcedureColumns: setProcedureColumnsMap(); break; + case eProcedures: setProceduresMap(); break; + case eExportedKeys: setExportedKeysMap(); break; + case eImportedKeys: setImportedKeysMap(); break; + case ePrimaryKeys: setPrimaryKeysMap(); break; + case eIndexInfo: setIndexInfoMap(); break; + case eTablePrivileges: setTablePrivilegesMap(); break; + case eCrossReference: setCrossReferenceMap(); break; + case eTypeInfo: setTypeInfoMap(); break; + case eBestRowIdentifier: setBestRowIdentifierMap(); break; + case eVersionColumns: setVersionColumnsMap(); break; + case eUDTs: setUDTsMap(); break; + default: + OSL_FAIL("Wrong type!"); + } +} + +void ODatabaseMetaDataResultSet::disposing() +{ + OPropertySetHelper::disposing(); + + ::osl::MutexGuard aGuard(m_aMutex); + m_aStatement.clear(); + m_xMetaData.clear(); + m_aRowsIter = m_aRows.end(); + m_aRows.clear(); + m_aRowsIter = m_aRows.end(); +} + +void SAL_CALL ODatabaseMetaDataResultSet::acquire() noexcept +{ + ODatabaseMetaDataResultSet_BASE::acquire(); +} + +void SAL_CALL ODatabaseMetaDataResultSet::release() noexcept +{ + ODatabaseMetaDataResultSet_BASE::release(); +} + +Any SAL_CALL ODatabaseMetaDataResultSet::queryInterface( const Type & rType ) +{ + Any aRet = OPropertySetHelper::queryInterface(rType); + return aRet.hasValue() ? aRet : ODatabaseMetaDataResultSet_BASE::queryInterface(rType); +} + +Sequence< Type > SAL_CALL ODatabaseMetaDataResultSet::getTypes( ) +{ + ::cppu::OTypeCollection aTypes( cppu::UnoType::get(), + cppu::UnoType::get(), + cppu::UnoType::get()); + + return ::comphelper::concatSequences(aTypes.getTypes(),ODatabaseMetaDataResultSet_BASE::getTypes()); +} + +void ODatabaseMetaDataResultSet::setRows(ORows&& _rRows) +{ + m_aRows = std::move(_rRows); + m_bBOF = true; + m_bEOF = m_aRows.empty(); +} + +sal_Int32 SAL_CALL ODatabaseMetaDataResultSet::findColumn( const OUString& columnName ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed ); + + + Reference< XResultSetMetaData > xMeta = getMetaData(); + sal_Int32 nLen = xMeta->getColumnCount(); + sal_Int32 i = 1; + for(;i<=nLen;++i) + { + if(xMeta->isCaseSensitive(i) ? columnName == xMeta->getColumnName(i) : + columnName.equalsIgnoreAsciiCase(xMeta->getColumnName(i)) + ) + return i; + } + + ::dbtools::throwInvalidColumnException( columnName, *this ); + O3TL_UNREACHABLE; +} + +void ODatabaseMetaDataResultSet::checkIndex(sal_Int32 columnIndex ) +{ + if(columnIndex < 1 || o3tl::make_unsigned(columnIndex) >= (*m_aRowsIter).size()) + ::dbtools::throwInvalidIndexException(*this); +} + +Reference< css::io::XInputStream > SAL_CALL ODatabaseMetaDataResultSet::getBinaryStream( sal_Int32 /*columnIndex*/ ) +{ + return nullptr; +} + +Reference< css::io::XInputStream > SAL_CALL ODatabaseMetaDataResultSet::getCharacterStream( sal_Int32 /*columnIndex*/ ) +{ + return nullptr; +} + + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::getBoolean( sal_Int32 columnIndex ) +{ + return getValue(columnIndex).getBool(); +} + + +sal_Int8 SAL_CALL ODatabaseMetaDataResultSet::getByte( sal_Int32 columnIndex ) +{ + return getValue(columnIndex).getInt8(); +} + + +Sequence< sal_Int8 > SAL_CALL ODatabaseMetaDataResultSet::getBytes( sal_Int32 columnIndex ) +{ + return getValue(columnIndex).getSequence(); +} + + +css::util::Date SAL_CALL ODatabaseMetaDataResultSet::getDate( sal_Int32 columnIndex ) +{ + return getValue(columnIndex).getDate(); +} + + +double SAL_CALL ODatabaseMetaDataResultSet::getDouble( sal_Int32 columnIndex ) +{ + return getValue(columnIndex).getDouble(); +} + + +float SAL_CALL ODatabaseMetaDataResultSet::getFloat( sal_Int32 columnIndex ) +{ + return getValue(columnIndex).getFloat(); +} + + +sal_Int32 SAL_CALL ODatabaseMetaDataResultSet::getInt( sal_Int32 columnIndex ) +{ + return getValue(columnIndex).getInt32(); +} + + +sal_Int32 SAL_CALL ODatabaseMetaDataResultSet::getRow( ) +{ + return 0; +} + + +sal_Int64 SAL_CALL ODatabaseMetaDataResultSet::getLong( sal_Int32 columnIndex ) +{ + return getValue(columnIndex).getLong(); +} + + +Reference< XResultSetMetaData > SAL_CALL ODatabaseMetaDataResultSet::getMetaData( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed ); + + + if(!m_xMetaData.is()) + m_xMetaData = new ODatabaseMetaDataResultSetMetaData(); + + return m_xMetaData; +} + +Reference< XArray > SAL_CALL ODatabaseMetaDataResultSet::getArray( sal_Int32 /*columnIndex*/ ) +{ + return nullptr; +} + + +Reference< XClob > SAL_CALL ODatabaseMetaDataResultSet::getClob( sal_Int32 /*columnIndex*/ ) +{ + return nullptr; +} + +Reference< XBlob > SAL_CALL ODatabaseMetaDataResultSet::getBlob( sal_Int32 /*columnIndex*/ ) +{ + return nullptr; +} + + +Reference< XRef > SAL_CALL ODatabaseMetaDataResultSet::getRef( sal_Int32 /*columnIndex*/ ) +{ + return nullptr; +} + + +Any SAL_CALL ODatabaseMetaDataResultSet::getObject( sal_Int32 columnIndex, const Reference< css::container::XNameAccess >& /*typeMap*/ ) +{ + return getValue(columnIndex).makeAny(); +} + + +sal_Int16 SAL_CALL ODatabaseMetaDataResultSet::getShort( sal_Int32 columnIndex ) +{ + return getValue(columnIndex).getInt16(); +} + + +OUString SAL_CALL ODatabaseMetaDataResultSet::getString( sal_Int32 columnIndex ) +{ + return getValue(columnIndex).getString(); +} + + +css::util::Time SAL_CALL ODatabaseMetaDataResultSet::getTime( sal_Int32 columnIndex ) +{ + return getValue(columnIndex).getTime(); +} + + +css::util::DateTime SAL_CALL ODatabaseMetaDataResultSet::getTimestamp( sal_Int32 columnIndex ) +{ + return getValue(columnIndex).getDateTime(); +} + + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::isAfterLast( ) +{ + return m_bEOF; +} + + +SAL_WNOUNREACHABLE_CODE_PUSH + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::isFirst( ) +{ + ::dbtools::throwFunctionSequenceException(*this); + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::isLast( ) +{ + ::dbtools::throwFunctionSequenceException(*this); + return false; +} + +SAL_WNOUNREACHABLE_CODE_POP + + +void SAL_CALL ODatabaseMetaDataResultSet::beforeFirst( ) +{ + ::dbtools::throwFunctionSequenceException(*this); +} + +void SAL_CALL ODatabaseMetaDataResultSet::afterLast( ) +{ + ::dbtools::throwFunctionSequenceException(*this); +} + + +void SAL_CALL ODatabaseMetaDataResultSet::close( ) +{ + { + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed ); + + } + dispose(); +} + + +SAL_WNOUNREACHABLE_CODE_PUSH + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::first( ) +{ + ::dbtools::throwFunctionSequenceException(*this); + return false; +} + + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::last( ) +{ + ::dbtools::throwFunctionSequenceException(*this); + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::absolute( sal_Int32 /*row*/ ) +{ + ::dbtools::throwFunctionSequenceException(*this); + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::relative( sal_Int32 /*row*/ ) +{ + ::dbtools::throwFunctionSequenceException(*this); + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::previous( ) +{ + ::dbtools::throwFunctionSequenceException(*this); + return false; +} + +SAL_WNOUNREACHABLE_CODE_POP + + +Reference< XInterface > SAL_CALL ODatabaseMetaDataResultSet::getStatement( ) +{ + return m_aStatement.get(); +} + + +SAL_WNOUNREACHABLE_CODE_PUSH + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::rowDeleted( ) +{ + ::dbtools::throwFunctionSequenceException(*this); + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::rowInserted( ) +{ + ::dbtools::throwFunctionSequenceException(*this); + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::rowUpdated( ) +{ + ::dbtools::throwFunctionSequenceException(*this); + return false; +} + +SAL_WNOUNREACHABLE_CODE_POP + + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::isBeforeFirst( ) +{ + return m_bBOF; +} + + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::next( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed ); + + if ( m_bBOF ) + { + m_aRowsIter = m_aRows.begin(); + m_bBOF = false; + } + else + { + if ( m_bEOF ) + throwFunctionSequenceException( *this ); + else + if ( m_aRowsIter != m_aRows.end() ) + ++m_aRowsIter; + } + + bool bSuccess = m_aRowsIter != m_aRows.end(); + if ( !bSuccess ) + { + m_bEOF = true; + m_bBOF = m_aRows.empty(); + } + return bSuccess; +} + + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::wasNull( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed ); + + + if(m_aRowsIter == m_aRows.end() || !(*m_aRowsIter)[m_nColPos].is()) + return true; + + return (*m_aRowsIter)[m_nColPos]->getValue().isNull(); +} + +void SAL_CALL ODatabaseMetaDataResultSet::refreshRow( ) +{ +} + + +void SAL_CALL ODatabaseMetaDataResultSet::cancel( ) +{ +} + +void SAL_CALL ODatabaseMetaDataResultSet::clearWarnings( ) +{ +} + +Any SAL_CALL ODatabaseMetaDataResultSet::getWarnings( ) +{ + return Any(); +} + +::cppu::IPropertyArrayHelper* ODatabaseMetaDataResultSet::createArrayHelper( ) const +{ + Sequence< Property > aProps; + describeProperties(aProps); + return new ::cppu::OPropertyArrayHelper(aProps); +} + +::cppu::IPropertyArrayHelper & ODatabaseMetaDataResultSet::getInfoHelper() +{ + return *getArrayHelper(); +} + +void ODatabaseMetaDataResultSet::setProceduresMap() +{ + rtl::Reference pMetaData = new ODatabaseMetaDataResultSetMetaData(); + pMetaData->setProceduresMap(); + m_xMetaData = pMetaData; +} + +void ODatabaseMetaDataResultSet::setCatalogsMap() +{ + rtl::Reference pMetaData = new ODatabaseMetaDataResultSetMetaData(); + pMetaData->setCatalogsMap(); + m_xMetaData = pMetaData; +} + +void ODatabaseMetaDataResultSet::setSchemasMap() +{ + rtl::Reference pMetaData = new ODatabaseMetaDataResultSetMetaData(); + pMetaData->setSchemasMap(); + m_xMetaData = pMetaData; +} + +void ODatabaseMetaDataResultSet::setColumnPrivilegesMap() +{ + rtl::Reference pMetaData = new ODatabaseMetaDataResultSetMetaData(); + pMetaData->setColumnPrivilegesMap(); + m_xMetaData = pMetaData; +} + +void ODatabaseMetaDataResultSet::setColumnsMap() +{ + rtl::Reference pMetaData = new ODatabaseMetaDataResultSetMetaData(); + pMetaData->setColumnsMap(); + m_xMetaData = pMetaData; +} + +void ODatabaseMetaDataResultSet::setTablesMap() +{ + rtl::Reference pMetaData = new ODatabaseMetaDataResultSetMetaData(); + pMetaData->setTablesMap(); + m_xMetaData = pMetaData; +} + +void ODatabaseMetaDataResultSet::setProcedureColumnsMap() +{ + rtl::Reference pMetaData = new ODatabaseMetaDataResultSetMetaData(); + pMetaData->setProcedureColumnsMap(); + m_xMetaData = pMetaData; +} + +void ODatabaseMetaDataResultSet::setPrimaryKeysMap() +{ + rtl::Reference pMetaData = new ODatabaseMetaDataResultSetMetaData(); + pMetaData->setPrimaryKeysMap(); + m_xMetaData = pMetaData; +} + +void ODatabaseMetaDataResultSet::setIndexInfoMap() +{ + rtl::Reference pMetaData = new ODatabaseMetaDataResultSetMetaData(); + pMetaData->setIndexInfoMap(); + m_xMetaData = pMetaData; +} + +void ODatabaseMetaDataResultSet::setTablePrivilegesMap() +{ + rtl::Reference pMetaData = new ODatabaseMetaDataResultSetMetaData(); + pMetaData->setTablePrivilegesMap(); + m_xMetaData = pMetaData; +} + +void ODatabaseMetaDataResultSet::setCrossReferenceMap() +{ + rtl::Reference pMetaData = new ODatabaseMetaDataResultSetMetaData(); + pMetaData->setCrossReferenceMap(); + m_xMetaData = pMetaData; +} + +void ODatabaseMetaDataResultSet::setVersionColumnsMap() +{ + rtl::Reference pMetaData = new ODatabaseMetaDataResultSetMetaData(); + pMetaData->setVersionColumnsMap(); + m_xMetaData = pMetaData; +} + +void ODatabaseMetaDataResultSet::setBestRowIdentifierMap() +{ + rtl::Reference pMetaData = new ODatabaseMetaDataResultSetMetaData(); + pMetaData->setBestRowIdentifierMap(); + m_xMetaData = pMetaData; +} + +void ODatabaseMetaDataResultSet::setTypeInfoMap() +{ + rtl::Reference pMetaData = new ODatabaseMetaDataResultSetMetaData(); + pMetaData->setTypeInfoMap(); + m_xMetaData = pMetaData; +} + +void ODatabaseMetaDataResultSet::setUDTsMap() +{ + rtl::Reference pMetaData = new ODatabaseMetaDataResultSetMetaData(); + pMetaData->setUDTsMap(); + m_xMetaData = pMetaData; +} + +void ODatabaseMetaDataResultSet::setTableTypes() +{ + rtl::Reference pMetaData = new ODatabaseMetaDataResultSetMetaData(); + pMetaData->setTableTypes(); + m_xMetaData = pMetaData; +} + +void ODatabaseMetaDataResultSet::setExportedKeysMap() +{ + rtl::Reference pMetaData = new ODatabaseMetaDataResultSetMetaData(); + pMetaData->setExportedKeysMap(); + m_xMetaData = pMetaData; +} + +void ODatabaseMetaDataResultSet::setImportedKeysMap() +{ + rtl::Reference pMetaData = new ODatabaseMetaDataResultSetMetaData(); + pMetaData->setImportedKeysMap(); + m_xMetaData = pMetaData; +} + +Reference< css::beans::XPropertySetInfo > SAL_CALL ODatabaseMetaDataResultSet::getPropertySetInfo( ) +{ + return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper()); +} + +ORowSetValueDecorator& ORowSetValueDecorator::operator=(const ORowSetValue& _aValue) +{ + m_aValue = _aValue; + return *this; +} + +const ORowSetValue& ODatabaseMetaDataResultSet::getValue(sal_Int32 columnIndex) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed ); + + if ( isBeforeFirst() || isAfterLast() ) + ::dbtools::throwFunctionSequenceException( *this ); + + checkIndex(columnIndex ); + m_nColPos = columnIndex; + + if(m_aRowsIter != m_aRows.end() && (*m_aRowsIter)[columnIndex].is()) + return *(*m_aRowsIter)[columnIndex]; + return m_aEmptyValue; +} + +/// return an empty ORowSetValueDecorator +ORowSetValueDecoratorRef const & ODatabaseMetaDataResultSet::getEmptyValue() +{ + static ORowSetValueDecoratorRef aEmptyValueRef = new ORowSetValueDecorator(); + return aEmptyValueRef; +} + +/// return an ORowSetValueDecorator with 0 as value +ORowSetValueDecoratorRef const & ODatabaseMetaDataResultSet::get0Value() +{ + static ORowSetValueDecoratorRef a0ValueRef = new ORowSetValueDecorator(sal_Int32(0)); + return a0ValueRef; +} + +/// return an ORowSetValueDecorator with 1 as value +ORowSetValueDecoratorRef const & ODatabaseMetaDataResultSet::get1Value() +{ + static ORowSetValueDecoratorRef a1ValueRef = new ORowSetValueDecorator(sal_Int32(1)); + return a1ValueRef; +} + +/// return an ORowSetValueDecorator with ColumnSearch::BASIC as value +ORowSetValueDecoratorRef const & ODatabaseMetaDataResultSet::getBasicValue() +{ + static ORowSetValueDecoratorRef aValueRef = new ORowSetValueDecorator(ColumnSearch::BASIC); + return aValueRef; +} + +ORowSetValueDecoratorRef const & ODatabaseMetaDataResultSet::getSelectValue() +{ + static ORowSetValueDecoratorRef aValueRef = new ORowSetValueDecorator(OUString("SELECT")); + return aValueRef; +} + +ORowSetValueDecoratorRef const & ODatabaseMetaDataResultSet::getInsertValue() +{ + static ORowSetValueDecoratorRef aValueRef = new ORowSetValueDecorator(OUString("INSERT")); + return aValueRef; +} + +ORowSetValueDecoratorRef const & ODatabaseMetaDataResultSet::getDeleteValue() +{ + static ORowSetValueDecoratorRef aValueRef = new ORowSetValueDecorator(OUString("DELETE")); + return aValueRef; +} + +ORowSetValueDecoratorRef const & ODatabaseMetaDataResultSet::getUpdateValue() +{ + static ORowSetValueDecoratorRef aValueRef = new ORowSetValueDecorator(OUString("UPDATE")); + return aValueRef; +} + +ORowSetValueDecoratorRef const & ODatabaseMetaDataResultSet::getCreateValue() +{ + static ORowSetValueDecoratorRef aValueRef = new ORowSetValueDecorator(OUString("CREATE")); + return aValueRef; +} + +ORowSetValueDecoratorRef const & ODatabaseMetaDataResultSet::getReadValue() +{ + static ORowSetValueDecoratorRef aValueRef = new ORowSetValueDecorator(OUString("READ")); + return aValueRef; +} + +ORowSetValueDecoratorRef const & ODatabaseMetaDataResultSet::getAlterValue() +{ + static ORowSetValueDecoratorRef aValueRef = new ORowSetValueDecorator(OUString("ALTER")); + return aValueRef; +} + +ORowSetValueDecoratorRef const & ODatabaseMetaDataResultSet::getDropValue() +{ + static ORowSetValueDecoratorRef aValueRef = new ORowSetValueDecorator(OUString("DROP")); + return aValueRef; +} + +ORowSetValueDecoratorRef const & ODatabaseMetaDataResultSet::getQuoteValue() +{ + static ORowSetValueDecoratorRef aValueRef = new ORowSetValueDecorator(OUString("'")); + return aValueRef; +} + +void SAL_CALL ODatabaseMetaDataResultSet::initialize( const Sequence< Any >& _aArguments ) +{ + if ( _aArguments.getLength() != 2 ) + return; + + sal_Int32 nResultSetType = 0; + if ( !(_aArguments[0] >>= nResultSetType)) + return; + + setType(static_cast(nResultSetType)); + Sequence< Sequence > aRows; + if ( !(_aArguments[1] >>= aRows) ) + return; + + ORows aRowsToSet; + const Sequence* pRowsIter = aRows.getConstArray(); + const Sequence* pRowsEnd = pRowsIter + aRows.getLength(); + for (; pRowsIter != pRowsEnd;++pRowsIter) + { + ORow aRowToSet; + const Any* pRowIter = pRowsIter->getConstArray(); + const Any* pRowEnd = pRowIter + pRowsIter->getLength(); + for (; pRowIter != pRowEnd;++pRowIter) + { + ORowSetValueDecoratorRef aValue; + switch( pRowIter->getValueTypeClass() ) + { + case TypeClass_BOOLEAN: + { + bool bValue = false; + *pRowIter >>= bValue; + aValue = new ORowSetValueDecorator(ORowSetValue(bValue)); + } + break; + case TypeClass_BYTE: + { + sal_Int8 nValue(0); + *pRowIter >>= nValue; + aValue = new ORowSetValueDecorator(ORowSetValue(nValue)); + } + break; + case TypeClass_SHORT: + case TypeClass_UNSIGNED_SHORT: + { + sal_Int16 nValue(0); + *pRowIter >>= nValue; + aValue = new ORowSetValueDecorator(ORowSetValue(nValue)); + } + break; + case TypeClass_LONG: + case TypeClass_UNSIGNED_LONG: + { + sal_Int32 nValue(0); + *pRowIter >>= nValue; + aValue = new ORowSetValueDecorator(ORowSetValue(nValue)); + } + break; + case TypeClass_HYPER: + case TypeClass_UNSIGNED_HYPER: + { + sal_Int64 nValue(0); + *pRowIter >>= nValue; + aValue = new ORowSetValueDecorator(ORowSetValue(nValue)); + } + break; + case TypeClass_FLOAT: + { + float nValue(0.0); + *pRowIter >>= nValue; + aValue = new ORowSetValueDecorator(ORowSetValue(nValue)); + } + break; + case TypeClass_DOUBLE: + { + double nValue(0.0); + *pRowIter >>= nValue; + aValue = new ORowSetValueDecorator(ORowSetValue(nValue)); + } + break; + case TypeClass_STRING: + { + OUString sValue; + *pRowIter >>= sValue; + aValue = new ORowSetValueDecorator(ORowSetValue(sValue)); + } + break; + default: + break; + } + aRowToSet.push_back(aValue); + } + aRowsToSet.push_back(aRowToSet); + } // for (; pRowsIter != pRowsEnd;++pRowsIter + setRows(std::move(aRowsToSet)); +} +// XServiceInfo + + + OUString SAL_CALL ODatabaseMetaDataResultSet::getImplementationName( ) + { + return "org.openoffice.comp.helper.DatabaseMetaDataResultSet"; + } + + sal_Bool SAL_CALL ODatabaseMetaDataResultSet::supportsService( const OUString& _rServiceName ) + { + return cppu::supportsService(this, _rServiceName); + } + + Sequence< OUString > SAL_CALL ODatabaseMetaDataResultSet::getSupportedServiceNames( ) + { + return Sequence{ "com.sun.star.sdbc.ResultSet" }; + } + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +connectivity_dbtools_ODatabaseMetaDataResultSet_get_implementation( + css::uno::XComponentContext* , css::uno::Sequence const&) +{ + return cppu::acquire(new ODatabaseMetaDataResultSet()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/commontools/FDatabaseMetaDataResultSetMetaData.cxx b/connectivity/source/commontools/FDatabaseMetaDataResultSetMetaData.cxx new file mode 100644 index 000000000..561953a07 --- /dev/null +++ b/connectivity/source/commontools/FDatabaseMetaDataResultSetMetaData.cxx @@ -0,0 +1,357 @@ +/* -*- 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 +#include +#include + +using namespace connectivity; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::lang; + +ODatabaseMetaDataResultSetMetaData::~ODatabaseMetaDataResultSetMetaData() +{ +} + +sal_Int32 SAL_CALL ODatabaseMetaDataResultSetMetaData::getColumnDisplaySize( sal_Int32 column ) +{ + if((m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end()) + return (*m_mColumnsIter).second.getColumnDisplaySize(); + + return 0; +} + +sal_Int32 SAL_CALL ODatabaseMetaDataResultSetMetaData::getColumnType( sal_Int32 column ) +{ + if((m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end()) + return (*m_mColumnsIter).second.getColumnType(); + return 1; +} + +sal_Int32 SAL_CALL ODatabaseMetaDataResultSetMetaData::getColumnCount( ) +{ + return m_mColumns.size(); +} + +sal_Bool SAL_CALL ODatabaseMetaDataResultSetMetaData::isCaseSensitive( sal_Int32 column ) +{ + if((m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end()) + return (*m_mColumnsIter).second.isCaseSensitive(); + return true; +} + +OUString SAL_CALL ODatabaseMetaDataResultSetMetaData::getSchemaName( sal_Int32 /*column*/ ) +{ + return OUString(); +} + +OUString SAL_CALL ODatabaseMetaDataResultSetMetaData::getColumnName( sal_Int32 column ) +{ + if((m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end()) + return (*m_mColumnsIter).second.getColumnName(); + return OUString(); +} + +OUString SAL_CALL ODatabaseMetaDataResultSetMetaData::getTableName( sal_Int32 column ) +{ + if((m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end()) + return (*m_mColumnsIter).second.getTableName(); + return OUString(); +} + +OUString SAL_CALL ODatabaseMetaDataResultSetMetaData::getCatalogName( sal_Int32 /*column*/ ) +{ + return OUString(); +} + +OUString SAL_CALL ODatabaseMetaDataResultSetMetaData::getColumnTypeName( sal_Int32 /*column*/ ) +{ + return OUString(); +} + +OUString SAL_CALL ODatabaseMetaDataResultSetMetaData::getColumnLabel( sal_Int32 column ) +{ + if((m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end()) + return (*m_mColumnsIter).second.getColumnLabel(); + return getColumnName(column); +} + +OUString SAL_CALL ODatabaseMetaDataResultSetMetaData::getColumnServiceName( sal_Int32 /*column*/ ) +{ + return OUString(); +} + +sal_Bool SAL_CALL ODatabaseMetaDataResultSetMetaData::isCurrency( sal_Int32 column ) +{ + if((m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end()) + return (*m_mColumnsIter).second.isCurrency(); + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaDataResultSetMetaData::isAutoIncrement( sal_Int32 column ) +{ + if((m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end()) + return (*m_mColumnsIter).second.isAutoIncrement(); + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaDataResultSetMetaData::isSigned( sal_Int32 column ) +{ + if((m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end()) + return (*m_mColumnsIter).second.isSigned(); + return false; +} + +sal_Int32 SAL_CALL ODatabaseMetaDataResultSetMetaData::getPrecision( sal_Int32 column ) +{ + if((m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end()) + return (*m_mColumnsIter).second.getPrecision(); + return 0; +} + +sal_Int32 SAL_CALL ODatabaseMetaDataResultSetMetaData::getScale( sal_Int32 column ) +{ + if((m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end()) + return (*m_mColumnsIter).second.getScale(); + + return 0; +} + +sal_Int32 SAL_CALL ODatabaseMetaDataResultSetMetaData::isNullable( sal_Int32 column ) +{ + if((m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end()) + return (*m_mColumnsIter).second.isNullable(); + + return sal_Int32(false); +} + +sal_Bool SAL_CALL ODatabaseMetaDataResultSetMetaData::isSearchable( sal_Int32 column ) +{ + if((m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end()) + return (*m_mColumnsIter).second.isSearchable(); + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaDataResultSetMetaData::isReadOnly( sal_Int32 /*column*/ ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaDataResultSetMetaData::isDefinitelyWritable( sal_Int32 /*column*/ ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaDataResultSetMetaData::isWritable( sal_Int32 column ) +{ + return isDefinitelyWritable(column); +} + +void ODatabaseMetaDataResultSetMetaData::setColumnPrivilegesMap() +{ + setColumnMap(); + m_mColumns[5] = OColumn(OUString(),"GRANTOR", ColumnValue::NULLABLE, 3,3,0, DataType::VARCHAR); + m_mColumns[6] = OColumn(OUString(),"GRANTEE", ColumnValue::NULLABLE, 3,3,0, DataType::VARCHAR); + m_mColumns[7] = OColumn(OUString(),"PRIVILEGE", ColumnValue::NULLABLE, 3,3,0, DataType::VARCHAR); + m_mColumns[8] = OColumn(OUString(),"IS_GRANTABLE", ColumnValue::NULLABLE, 3,3,0, DataType::VARCHAR); +} + +void ODatabaseMetaDataResultSetMetaData::setTableNameMap() +{ + m_mColumns[1] = OColumn(OUString(),"TABLE_CAT", ColumnValue::NULLABLE, 3,3,0, DataType::VARCHAR); + m_mColumns[2] = OColumn(OUString(),"TABLE_SCHEM", ColumnValue::NULLABLE, 3,3,0, DataType::VARCHAR); + m_mColumns[3] = OColumn(OUString(),"TABLE_NAME", ColumnValue::NO_NULLS, 3,3,0, DataType::VARCHAR); +} + +void ODatabaseMetaDataResultSetMetaData::setColumnMap() +{ + setTableNameMap(); + m_mColumns[4] = OColumn(OUString(),"COLUMN_NAME", ColumnValue::NO_NULLS, 3,3,0, DataType::VARCHAR); +} + +void ODatabaseMetaDataResultSetMetaData::setColumnsMap() +{ + setColumnMap(); + + m_mColumns[5] = OColumn(OUString(),"DATA_TYPE", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER); + m_mColumns[6] = OColumn(OUString(),"TYPE_NAME", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR); + m_mColumns[7] = OColumn(OUString(),"COLUMN_SIZE", ColumnValue::NO_NULLS, 3,3,0, DataType::INTEGER); + m_mColumns[8] = OColumn(OUString(),"BUFFER_LENGTH", ColumnValue::NULLABLE, 3,3,0, DataType::INTEGER); + m_mColumns[9] = OColumn(OUString(),"DECIMAL_DIGITS", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER); + m_mColumns[10] = OColumn(OUString(),"NUM_PREC_RADIX", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER); + m_mColumns[11] = OColumn(OUString(),"NULLABLE", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER); + m_mColumns[12] = OColumn(OUString(),"REMARKS", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR); + m_mColumns[13] = OColumn(OUString(),"COLUMN_DEF", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR); + m_mColumns[14] = OColumn(OUString(),"SQL_DATA_TYPE", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER); + m_mColumns[15] = OColumn(OUString(),"SQL_DATETIME_SUB", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER); + m_mColumns[16] = OColumn(OUString(),"CHAR_OCTET_LENGTH", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER); + m_mColumns[17] = OColumn(OUString(),"ORDINAL_POSITION", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER); + m_mColumns[18] = OColumn(OUString(),"IS_NULLABLE", ColumnValue::NO_NULLS, 1,1,0, DataType::VARCHAR); +} + +void ODatabaseMetaDataResultSetMetaData::setTablesMap() +{ + setTableNameMap(); + m_mColumns[4] = OColumn(OUString(),"TABLE_TYPE", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR); + m_mColumns[5] = OColumn(OUString(),"REMARKS", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR); +} + +void ODatabaseMetaDataResultSetMetaData::setProcedureNameMap() +{ + m_mColumns[1] = OColumn(OUString(),"PROCEDURE_CAT", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR); + m_mColumns[2] = OColumn(OUString(),"PROCEDURE_SCHEM", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR); + m_mColumns[3] = OColumn(OUString(),"PROCEDURE_NAME", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR); +} + +void ODatabaseMetaDataResultSetMetaData::setProcedureColumnsMap() +{ + setProcedureNameMap(); + m_mColumns[4] = OColumn(OUString(),"COLUMN_NAME", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR); + m_mColumns[5] = OColumn(OUString(),"COLUMN_TYPE", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER); + m_mColumns[6] = OColumn(OUString(),"DATA_TYPE", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER); + m_mColumns[7] = OColumn(OUString(),"TYPE_NAME", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR); + m_mColumns[8] = OColumn(OUString(),"PRECISION", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER); + m_mColumns[9] = OColumn(OUString(),"LENGTH", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER); + m_mColumns[10] = OColumn(OUString(),"SCALE", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER); + m_mColumns[11] = OColumn(OUString(),"RADIX", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER); + m_mColumns[12] = OColumn(OUString(),"NULLABLE", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER); + m_mColumns[13] = OColumn(OUString(),"REMARKS", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR); +} + +void ODatabaseMetaDataResultSetMetaData::setPrimaryKeysMap() +{ + setColumnMap(); + m_mColumns[5] = OColumn(OUString(),"KEY_SEQ", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER); + m_mColumns[6] = OColumn(OUString(),"PK_NAME", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR); +} + +void ODatabaseMetaDataResultSetMetaData::setIndexInfoMap() +{ + setTableNameMap(); + m_mColumns[4] = OColumn(OUString(),"NON_UNIQUE", ColumnValue::NO_NULLS, 1,1,0, DataType::BIT); + m_mColumns[5] = OColumn(OUString(),"INDEX_QUALIFIER", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR); + m_mColumns[6] = OColumn(OUString(),"INDEX_NAME", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR); + m_mColumns[7] = OColumn(OUString(),"TYPE", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER); + m_mColumns[8] = OColumn(OUString(),"ORDINAL_POSITION", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER); + m_mColumns[9] = OColumn(OUString(),"COLUMN_NAME", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR); + m_mColumns[10] = OColumn(OUString(),"ASC_OR_DESC", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR); + m_mColumns[11] = OColumn(OUString(),"CARDINALITY", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER); + m_mColumns[12] = OColumn(OUString(),"PAGES", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER); + m_mColumns[13] = OColumn(OUString(),"FILTER_CONDITION", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR); +} + +void ODatabaseMetaDataResultSetMetaData::setTablePrivilegesMap() +{ + setTableNameMap(); + m_mColumns[4] = OColumn(OUString(),"GRANTOR", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR); + m_mColumns[5] = OColumn(OUString(),"GRANTEE", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR); + m_mColumns[6] = OColumn(OUString(),"PRIVILEGE", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR); + m_mColumns[7] = OColumn(OUString(),"IS_GRANTABLE", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR); +} + +void ODatabaseMetaDataResultSetMetaData::setCrossReferenceMap() +{ + m_mColumns[1] = OColumn(OUString(),"PKTABLE_CAT", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR); + m_mColumns[2] = OColumn(OUString(),"PKTABLE_SCHEM", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR); + m_mColumns[3] = OColumn(OUString(),"PKTABLE_NAME", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR); + m_mColumns[4] = OColumn(OUString(),"PKCOLUMN_NAME", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR); + m_mColumns[5] = OColumn(OUString(),"FKTABLE_CAT", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR); + m_mColumns[6] = OColumn(OUString(),"FKTABLE_SCHEM", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR); + m_mColumns[7] = OColumn(OUString(),"FKTABLE_NAME", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR); + m_mColumns[8] = OColumn(OUString(),"FKCOLUMN_NAME", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR); + + m_mColumns[9] = OColumn(OUString(),"KEY_SEQ", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER); + m_mColumns[10] = OColumn(OUString(),"UPDATE_RULE", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER); + m_mColumns[11] = OColumn(OUString(),"DELETE_RULE", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER); + m_mColumns[12] = OColumn(OUString(),"FK_NAME", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR); + m_mColumns[13] = OColumn(OUString(),"PK_NAME", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR); + m_mColumns[14] = OColumn(OUString(),"DEFERRABILITY", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER); +} + +void ODatabaseMetaDataResultSetMetaData::setTypeInfoMap() +{ + m_mColumns[1] = OColumn(OUString(),"TYPE_NAME", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR); + m_mColumns[2] = OColumn(OUString(),"DATA_TYPE", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER); + m_mColumns[3] = OColumn(OUString(),"PRECISION", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER); + m_mColumns[4] = OColumn(OUString(),"LITERAL_PREFIX", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR); + m_mColumns[5] = OColumn(OUString(),"LITERAL_SUFFIX", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR); + m_mColumns[6] = OColumn(OUString(),"CREATE_PARAMS", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR); + m_mColumns[7] = OColumn(OUString(),"NULLABLE", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER); + m_mColumns[8] = OColumn(OUString(),"CASE_SENSITIVE", ColumnValue::NO_NULLS, 1,1,0, DataType::BIT); + m_mColumns[9] = OColumn(OUString(),"SEARCHABLE", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER); + m_mColumns[10] = OColumn(OUString(),"UNSIGNED_ATTRIBUTE", ColumnValue::NO_NULLS, 1,1,0, DataType::BIT); + m_mColumns[11] = OColumn(OUString(),"FIXED_PREC_SCALE", ColumnValue::NO_NULLS, 1,1,0, DataType::BIT); + m_mColumns[12] = OColumn(OUString(),"AUTO_INCREMENT", ColumnValue::NO_NULLS, 1,1,0, DataType::BIT); + m_mColumns[13] = OColumn(OUString(),"LOCAL_TYPE_NAME", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR); + m_mColumns[14] = OColumn(OUString(),"MINIMUM_SCALE", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER); + m_mColumns[15] = OColumn(OUString(),"MAXIMUM_SCALE", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER); + m_mColumns[16] = OColumn(OUString(),"SQL_DATA_TYPE", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER); + m_mColumns[17] = OColumn(OUString(),"SQL_DATETIME_SUB", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER); + m_mColumns[18] = OColumn(OUString(),"NUM_PREC_RADIX", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER); +} + +void ODatabaseMetaDataResultSetMetaData::setProceduresMap() +{ + setProcedureNameMap(); + m_mColumns[4] = OColumn(OUString(),"RESERVED1", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR); + m_mColumns[5] = OColumn(OUString(),"RESERVED2", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR); + m_mColumns[6] = OColumn(OUString(),"RESERVED3", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR); + m_mColumns[7] = OColumn(OUString(),"REMARKS", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR); + m_mColumns[8] = OColumn(OUString(),"PROCEDURE_TYPE", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER); +} + +void ODatabaseMetaDataResultSetMetaData::setTableTypes() +{ + m_mColumns[1] = OColumn(OUString(),"TABLE_TYPE", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR); +} + +void ODatabaseMetaDataResultSetMetaData::setCatalogsMap() +{ + m_mColumns[1] = OColumn(OUString(),"TABLE_CAT", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR); +} + +void ODatabaseMetaDataResultSetMetaData::setSchemasMap() +{ + m_mColumns[1] = OColumn(OUString(),"TABLE_SCHEM", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR); +} + +void ODatabaseMetaDataResultSetMetaData::setVersionColumnsMap() +{ + m_mColumns[1] = OColumn(OUString(),"SCOPE", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER); + m_mColumns[2] = OColumn(OUString(),"COLUMN_NAME", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR); + m_mColumns[3] = OColumn(OUString(),"DATA_TYPE", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER); + m_mColumns[4] = OColumn(OUString(),"TYPE_NAME", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR); + m_mColumns[5] = OColumn(OUString(),"COLUMN_SIZE", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER); + m_mColumns[6] = OColumn(OUString(),"BUFFER_LENGTH", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER); + m_mColumns[7] = OColumn(OUString(),"DECIMAL_DIGITS", ColumnValue::NULLABLE, 0,0,0, DataType::INTEGER); + m_mColumns[8] = OColumn(OUString(),"PSEUDO_COLUMN", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER); +} + +void ODatabaseMetaDataResultSetMetaData::setUDTsMap() +{ + m_mColumns[1] = OColumn(OUString(),"TYPE_CAT", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR); + m_mColumns[2] = OColumn(OUString(),"TYPE_SCHEM", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR); + m_mColumns[3] = OColumn(OUString(),"TYPE_NAME", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR); + m_mColumns[4] = OColumn(OUString(),"CLASS_NAME", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR); + m_mColumns[5] = OColumn(OUString(),"DATA_TYPE", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR); + m_mColumns[6] = OColumn(OUString(),"REMARKS", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/commontools/FValue.cxx b/connectivity/source/commontools/FValue.cxx new file mode 100644 index 000000000..4ac0235ac --- /dev/null +++ b/connectivity/source/commontools/FValue.cxx @@ -0,0 +1,2473 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::dbtools; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::io; + +namespace connectivity +{ + +namespace { + bool isStorageCompatible(sal_Int32 _eType1, sal_Int32 _eType2) + { + bool bIsCompatible = true; + + if (_eType1 != _eType2) + { + SAL_INFO( "connectivity.commontools", "ORowSetValue::isStorageCompatible _eType1 != _eType2" ); + switch (_eType1) + { + case DataType::CHAR: + case DataType::VARCHAR: + case DataType::DECIMAL: + case DataType::NUMERIC: + case DataType::LONGVARCHAR: + bIsCompatible = (DataType::CHAR == _eType2) + || (DataType::VARCHAR == _eType2) + || (DataType::DECIMAL == _eType2) + || (DataType::NUMERIC == _eType2) + || (DataType::LONGVARCHAR == _eType2); + break; + + case DataType::DOUBLE: + case DataType::REAL: + bIsCompatible = (DataType::DOUBLE == _eType2) + || (DataType::REAL == _eType2); + break; + + case DataType::BINARY: + case DataType::VARBINARY: + case DataType::LONGVARBINARY: + bIsCompatible = (DataType::BINARY == _eType2) + || (DataType::VARBINARY == _eType2) + || (DataType::LONGVARBINARY == _eType2); + break; + + case DataType::INTEGER: + bIsCompatible = (DataType::SMALLINT == _eType2) + || (DataType::TINYINT == _eType2) + || (DataType::BIT == _eType2) + || (DataType::BOOLEAN == _eType2); + break; + case DataType::SMALLINT: + bIsCompatible = (DataType::TINYINT == _eType2) + || (DataType::BIT == _eType2) + || (DataType::BOOLEAN == _eType2); + break; + case DataType::TINYINT: + bIsCompatible = (DataType::BIT == _eType2) + || (DataType::BOOLEAN == _eType2); + break; + + case DataType::BLOB: + case DataType::CLOB: + case DataType::OBJECT: + bIsCompatible = (DataType::BLOB == _eType2) + || (DataType::CLOB == _eType2) + || (DataType::OBJECT == _eType2); + break; + + default: + bIsCompatible = false; + } + } + return bIsCompatible; + } + + bool isStorageComparable(sal_Int32 _eType1, sal_Int32 _eType2) + { + bool bIsComparable = true; + + if (_eType1 != _eType2) + { + SAL_INFO( "connectivity.commontools", "ORowSetValue::isStorageCompatible _eType1 != _eType2" ); + switch (_eType1) + { + case DataType::CHAR: + case DataType::VARCHAR: + case DataType::LONGVARCHAR: + bIsComparable = (DataType::CHAR == _eType2) + || (DataType::VARCHAR == _eType2) + || (DataType::LONGVARCHAR == _eType2); + break; + + case DataType::DECIMAL: + case DataType::NUMERIC: + bIsComparable = (DataType::DECIMAL == _eType2) + || (DataType::NUMERIC == _eType2); + break; + + case DataType::DOUBLE: + case DataType::REAL: + bIsComparable = (DataType::DOUBLE == _eType2) + || (DataType::REAL == _eType2); + break; + + case DataType::BINARY: + case DataType::VARBINARY: + case DataType::LONGVARBINARY: + bIsComparable = (DataType::BINARY == _eType2) + || (DataType::VARBINARY == _eType2) + || (DataType::LONGVARBINARY == _eType2); + break; + + case DataType::INTEGER: + bIsComparable = (DataType::SMALLINT == _eType2) + || (DataType::TINYINT == _eType2) + || (DataType::BIT == _eType2) + || (DataType::BOOLEAN == _eType2); + break; + case DataType::SMALLINT: + bIsComparable = (DataType::TINYINT == _eType2) + || (DataType::BIT == _eType2) + || (DataType::BOOLEAN == _eType2); + break; + case DataType::TINYINT: + bIsComparable = (DataType::BIT == _eType2) + || (DataType::BOOLEAN == _eType2); + break; + + case DataType::BLOB: + case DataType::CLOB: + case DataType::OBJECT: + bIsComparable = (DataType::BLOB == _eType2) + || (DataType::CLOB == _eType2) + || (DataType::OBJECT == _eType2); + break; + + default: + bIsComparable = false; + } + } + return bIsComparable; + } +} + +void ORowSetValue::setTypeKind(sal_Int32 _eType) +{ + if ( !m_bNull && !isStorageCompatible(_eType, m_eTypeKind) ) + { + switch(_eType) + { + case DataType::VARCHAR: + case DataType::CHAR: + case DataType::DECIMAL: + case DataType::NUMERIC: + case DataType::LONGVARCHAR: + (*this) = getString(); + break; + case DataType::BIGINT: + { + sal_Int64 nVal(getLong()); + sal_uInt64 nuVal(getULong()); + if (nVal == 0 && nuVal != 0) + (*this) = nuVal; + else + (*this) = nVal; + break; + } + + case DataType::FLOAT: + (*this) = getFloat(); + break; + case DataType::DOUBLE: + case DataType::REAL: + (*this) = getDouble(); + break; + case DataType::TINYINT: + (*this) = getInt8(); + break; + case DataType::SMALLINT: + (*this) = getInt16(); + break; + case DataType::INTEGER: + { + sal_Int32 nVal(getInt32()); + sal_uInt32 nuVal(getUInt32()); + if (nVal == 0 && nuVal != 0) + (*this) = nuVal; + else + (*this) = nVal; + break; + } + case DataType::BIT: + case DataType::BOOLEAN: + (*this) = getBool(); + break; + case DataType::DATE: + (*this) = getDate(); + break; + case DataType::TIME: + (*this) = getTime(); + break; + case DataType::TIMESTAMP: + (*this) = getDateTime(); + break; + case DataType::BINARY: + case DataType::VARBINARY: + case DataType::LONGVARBINARY: + (*this) = getSequence(); + break; + case DataType::BLOB: + case DataType::CLOB: + case DataType::OBJECT: + case DataType::OTHER: + (*this) = makeAny(); + break; + default: + (*this) = makeAny(); + SAL_WARN( "connectivity.commontools","ORowSetValue::setTypeKind(): UNSUPPORTED TYPE!"); + } + } + + m_eTypeKind = _eType; +} + + +void ORowSetValue::free() noexcept +{ + if(m_bNull) + return; + + switch(m_eTypeKind) + { + case DataType::CHAR: + case DataType::VARCHAR: + case DataType::DECIMAL: + case DataType::NUMERIC: + case DataType::LONGVARCHAR: + OSL_ENSURE(m_aValue.m_pString,"String pointer is null!"); + rtl_uString_release(m_aValue.m_pString); + m_aValue.m_pString = nullptr; + break; + case DataType::DATE: + delete static_cast(m_aValue.m_pValue); + m_aValue.m_pValue = nullptr; + break; + case DataType::TIME: + delete static_cast(m_aValue.m_pValue); + m_aValue.m_pValue = nullptr; + break; + case DataType::TIMESTAMP: + delete static_cast(m_aValue.m_pValue); + m_aValue.m_pValue = nullptr; + break; + case DataType::BINARY: + case DataType::VARBINARY: + case DataType::LONGVARBINARY: + delete static_cast*>(m_aValue.m_pValue); + m_aValue.m_pValue = nullptr; + break; + case DataType::BLOB: + case DataType::CLOB: + case DataType::OBJECT: + delete static_cast(m_aValue.m_pValue); + m_aValue.m_pValue = nullptr; + break; + case DataType::BIT: + case DataType::TINYINT: + case DataType::SMALLINT: + case DataType::INTEGER: + case DataType::BIGINT: + case DataType::BOOLEAN: + case DataType::FLOAT: + case DataType::DOUBLE: + case DataType::REAL: + break; + default: + if ( m_aValue.m_pValue ) + { + delete static_cast(m_aValue.m_pValue); + m_aValue.m_pValue = nullptr; + } + break; + + } + m_bNull = true; +} + +ORowSetValue& ORowSetValue::operator=(const ORowSetValue& _rRH) +{ + if(&_rRH == this) + return *this; + + if ( m_eTypeKind != _rRH.m_eTypeKind || (_rRH.m_bNull && !m_bNull) || m_bSigned != _rRH.m_bSigned) + free(); + + m_bBound = _rRH.m_bBound; + m_eTypeKind = _rRH.m_eTypeKind; + m_bSigned = _rRH.m_bSigned; + + if(m_bNull && !_rRH.m_bNull) + { + switch(_rRH.m_eTypeKind) + { + case DataType::CHAR: + case DataType::VARCHAR: + case DataType::DECIMAL: + case DataType::NUMERIC: + case DataType::LONGVARCHAR: + rtl_uString_acquire(_rRH.m_aValue.m_pString); + m_aValue.m_pString = _rRH.m_aValue.m_pString; + break; + case DataType::DATE: + m_aValue.m_pValue = new Date(*static_cast(_rRH.m_aValue.m_pValue)); + break; + case DataType::TIME: + m_aValue.m_pValue = new Time(*static_cast(_rRH.m_aValue.m_pValue)); + break; + case DataType::TIMESTAMP: + m_aValue.m_pValue = new DateTime(*static_cast(_rRH.m_aValue.m_pValue)); + break; + case DataType::BINARY: + case DataType::VARBINARY: + case DataType::LONGVARBINARY: + m_aValue.m_pValue = new Sequence(*static_cast*>(_rRH.m_aValue.m_pValue)); + break; + case DataType::BIT: + case DataType::BOOLEAN: + m_aValue.m_bBool = _rRH.m_aValue.m_bBool; + break; + case DataType::TINYINT: + if ( _rRH.m_bSigned ) + m_aValue.m_nInt8 = _rRH.m_aValue.m_nInt8; + else + m_aValue.m_uInt8 = _rRH.m_aValue.m_uInt8; + break; + case DataType::SMALLINT: + if ( _rRH.m_bSigned ) + m_aValue.m_nInt16 = _rRH.m_aValue.m_nInt16; + else + m_aValue.m_uInt16 = _rRH.m_aValue.m_uInt16; + break; + case DataType::INTEGER: + if ( _rRH.m_bSigned ) + m_aValue.m_nInt32 = _rRH.m_aValue.m_nInt32; + else + m_aValue.m_uInt32 = _rRH.m_aValue.m_uInt32; + break; + case DataType::BIGINT: + if ( _rRH.m_bSigned ) + m_aValue.m_nInt64 = _rRH.m_aValue.m_nInt64; + else + m_aValue.m_uInt64 = _rRH.m_aValue.m_uInt64; + break; + case DataType::FLOAT: + m_aValue.m_nFloat = _rRH.m_aValue.m_nFloat; + break; + case DataType::DOUBLE: + case DataType::REAL: + m_aValue.m_nDouble = _rRH.m_aValue.m_nDouble; + break; + default: + m_aValue.m_pValue = new Any(*static_cast(_rRH.m_aValue.m_pValue)); + } + } + else if(!_rRH.m_bNull) + { + switch(_rRH.m_eTypeKind) + { + case DataType::CHAR: + case DataType::VARCHAR: + case DataType::DECIMAL: + case DataType::NUMERIC: + case DataType::LONGVARCHAR: + (*this) = OUString(_rRH.m_aValue.m_pString); + break; + case DataType::DATE: + (*this) = *static_cast(_rRH.m_aValue.m_pValue); + break; + case DataType::TIME: + (*this) = *static_cast(_rRH.m_aValue.m_pValue); + break; + case DataType::TIMESTAMP: + (*this) = *static_cast(_rRH.m_aValue.m_pValue); + break; + case DataType::BINARY: + case DataType::VARBINARY: + case DataType::LONGVARBINARY: + (*this) = *static_cast*>(_rRH.m_aValue.m_pValue); + break; + case DataType::BIT: + case DataType::BOOLEAN: + m_aValue.m_bBool = _rRH.m_aValue.m_bBool; + break; + case DataType::TINYINT: + if ( _rRH.m_bSigned ) + m_aValue.m_nInt8 = _rRH.m_aValue.m_nInt8; + else + m_aValue.m_uInt8 = _rRH.m_aValue.m_uInt8; + break; + case DataType::SMALLINT: + if ( _rRH.m_bSigned ) + m_aValue.m_nInt16 = _rRH.m_aValue.m_nInt16; + else + m_aValue.m_uInt16 = _rRH.m_aValue.m_uInt16; + break; + case DataType::INTEGER: + if ( _rRH.m_bSigned ) + m_aValue.m_nInt32 = _rRH.m_aValue.m_nInt32; + else + m_aValue.m_uInt32 = _rRH.m_aValue.m_uInt32; + break; + case DataType::BIGINT: + if ( _rRH.m_bSigned ) + m_aValue.m_nInt64 = _rRH.m_aValue.m_nInt64; + else + m_aValue.m_uInt64 = _rRH.m_aValue.m_uInt64; + break; + case DataType::FLOAT: + m_aValue.m_nFloat = _rRH.m_aValue.m_nFloat; + break; + case DataType::DOUBLE: + case DataType::REAL: + m_aValue.m_nDouble = _rRH.m_aValue.m_nDouble; + break; + default: + *static_cast(m_aValue.m_pValue) = *static_cast(_rRH.m_aValue.m_pValue); + } + } + + m_bNull = _rRH.m_bNull; + // OJ: BUGID: 96277 + m_eTypeKind = _rRH.m_eTypeKind; + + return *this; +} + +ORowSetValue& ORowSetValue::operator=(ORowSetValue&& _rRH) noexcept +{ + if ( m_eTypeKind != _rRH.m_eTypeKind || !m_bNull) + free(); + if(!_rRH.m_bNull) + { + m_aValue = _rRH.m_aValue; + memset(&_rRH.m_aValue, 0, sizeof(_rRH.m_aValue)); + } + m_bBound = _rRH.m_bBound; + m_eTypeKind = _rRH.m_eTypeKind; + m_bSigned = _rRH.m_bSigned; + m_bNull = _rRH.m_bNull; + _rRH.m_bNull = true; + return *this; +} + + +ORowSetValue& ORowSetValue::operator=(const Date& _rRH) +{ + if(m_eTypeKind != DataType::DATE) + free(); + + if(m_bNull) + { + m_aValue.m_pValue = new Date(_rRH); + m_eTypeKind = DataType::DATE; + m_bNull = false; + } + else + *static_cast(m_aValue.m_pValue) = _rRH; + + return *this; +} + +ORowSetValue& ORowSetValue::operator=(const css::util::Time& _rRH) +{ + if(m_eTypeKind != DataType::TIME) + free(); + + if(m_bNull) + { + m_aValue.m_pValue = new Time(_rRH); + m_eTypeKind = DataType::TIME; + m_bNull = false; + } + else + *static_cast(m_aValue.m_pValue) = _rRH; + + return *this; +} + +ORowSetValue& ORowSetValue::operator=(const DateTime& _rRH) +{ + if(m_eTypeKind != DataType::TIMESTAMP) + free(); + if(m_bNull) + { + m_aValue.m_pValue = new DateTime(_rRH); + m_eTypeKind = DataType::TIMESTAMP; + m_bNull = false; + } + else + *static_cast(m_aValue.m_pValue) = _rRH; + + return *this; +} + + +ORowSetValue& ORowSetValue::operator=(const OUString& _rRH) +{ + if(m_eTypeKind != DataType::VARCHAR || m_aValue.m_pString != _rRH.pData) + { + free(); + m_bNull = false; + + m_aValue.m_pString = _rRH.pData; + rtl_uString_acquire(m_aValue.m_pString); + m_eTypeKind = DataType::VARCHAR; + } + + return *this; +} + + +ORowSetValue& ORowSetValue::operator=(double _rRH) +{ + if(m_eTypeKind != DataType::DOUBLE) + free(); + + m_aValue.m_nDouble = _rRH; + m_eTypeKind = DataType::DOUBLE; + m_bNull = false; + + return *this; +} + +ORowSetValue& ORowSetValue::operator=(float _rRH) +{ + if(m_eTypeKind != DataType::FLOAT) + free(); + + m_aValue.m_nFloat = _rRH; + m_eTypeKind = DataType::FLOAT; + m_bNull = false; + + return *this; +} + + +ORowSetValue& ORowSetValue::operator=(sal_Int8 _rRH) +{ + if(m_eTypeKind != DataType::TINYINT ) + free(); + + m_aValue.m_nInt8 = _rRH; + m_eTypeKind = DataType::TINYINT; + m_bNull = false; + m_bSigned = true; + return *this; +} + +ORowSetValue& ORowSetValue::operator=(sal_Int16 _rRH) +{ + if(m_eTypeKind != DataType::SMALLINT ) + free(); + + m_aValue.m_nInt16 = _rRH; + m_eTypeKind = DataType::SMALLINT; + m_bNull = false; + m_bSigned = true; + + return *this; +} + + +ORowSetValue& ORowSetValue::operator=(sal_uInt16 _rRH) +{ + if(m_eTypeKind != DataType::SMALLINT ) + free(); + + m_aValue.m_uInt16 = _rRH; + m_eTypeKind = DataType::SMALLINT; + m_bNull = false; + m_bSigned = false; + + return *this; +} + + +ORowSetValue& ORowSetValue::operator=(sal_Int32 _rRH) +{ + if(m_eTypeKind != DataType::INTEGER ) + free(); + + m_aValue.m_nInt32 = _rRH; + + m_eTypeKind = DataType::INTEGER; + m_bNull = false; + m_bSigned = true; + + return *this; +} + + +ORowSetValue& ORowSetValue::operator=(sal_uInt32 _rRH) +{ + if(m_eTypeKind != DataType::INTEGER ) + free(); + + m_aValue.m_uInt32 = _rRH; + + m_eTypeKind = DataType::INTEGER; + m_bNull = false; + m_bSigned = false; + + return *this; +} + + +ORowSetValue& ORowSetValue::operator=(const bool _rRH) +{ + if(m_eTypeKind != DataType::BIT && DataType::BOOLEAN != m_eTypeKind ) + free(); + + m_aValue.m_bBool = _rRH; + m_eTypeKind = DataType::BOOLEAN; + m_bNull = false; + + return *this; +} + +ORowSetValue& ORowSetValue::operator=(sal_Int64 _rRH) +{ + if ( DataType::BIGINT != m_eTypeKind) + free(); + + m_aValue.m_nInt64 = _rRH; + m_eTypeKind = DataType::BIGINT; + m_bNull = false; + m_bSigned = true; + + return *this; +} + +ORowSetValue& ORowSetValue::operator=(sal_uInt64 _rRH) +{ + if ( DataType::BIGINT != m_eTypeKind) + free(); + + m_aValue.m_uInt64 = _rRH; + m_eTypeKind = DataType::BIGINT; + m_bNull = false; + m_bSigned = false; + + return *this; +} + +ORowSetValue& ORowSetValue::operator=(const Sequence& _rRH) +{ + if (!isStorageCompatible(DataType::LONGVARBINARY,m_eTypeKind)) + free(); + + if (m_bNull) + { + m_aValue.m_pValue = new Sequence(_rRH); + } + else + *static_cast< Sequence< sal_Int8 >* >(m_aValue.m_pValue) = _rRH; + + m_eTypeKind = DataType::LONGVARBINARY; + m_bNull = false; + + return *this; +} + +ORowSetValue& ORowSetValue::operator=(const Any& _rAny) +{ + if (!isStorageCompatible(DataType::OBJECT,m_eTypeKind)) + free(); + + if ( m_bNull ) + { + m_aValue.m_pValue = new Any(_rAny); + } + else + *static_cast(m_aValue.m_pValue) = _rAny; + + m_eTypeKind = DataType::OBJECT; + m_bNull = false; + + return *this; +} + + +bool ORowSetValue::operator==(const ORowSetValue& _rRH) const +{ + if ( m_bNull != _rRH.isNull() ) + return false; + + if(m_bNull && _rRH.isNull()) + return true; + + if ( !isStorageComparable(m_eTypeKind, _rRH.m_eTypeKind )) + { + switch(m_eTypeKind) + { + case DataType::FLOAT: + case DataType::DOUBLE: + case DataType::REAL: + return getDouble() == _rRH.getDouble(); + default: + switch(_rRH.m_eTypeKind) + { + case DataType::FLOAT: + case DataType::DOUBLE: + case DataType::REAL: + return getDouble() == _rRH.getDouble(); + default: + break; + } + break; + } + return false; + } + + bool bRet = false; + OSL_ENSURE(!m_bNull,"Should not be null!"); + switch(m_eTypeKind) + { + case DataType::VARCHAR: + case DataType::CHAR: + case DataType::LONGVARCHAR: + { + OUString aVal1(m_aValue.m_pString); + OUString aVal2(_rRH.m_aValue.m_pString); + return aVal1 == aVal2; + } + default: + if ( m_bSigned != _rRH.m_bSigned ) + return false; + break; + } + + switch(m_eTypeKind) + { + case DataType::DECIMAL: + case DataType::NUMERIC: + { + OUString aVal1(m_aValue.m_pString); + OUString aVal2(_rRH.m_aValue.m_pString); + bRet = aVal1 == aVal2; + } + break; + case DataType::FLOAT: + bRet = m_aValue.m_nFloat == _rRH.m_aValue.m_nFloat; + break; + case DataType::DOUBLE: + case DataType::REAL: + bRet = m_aValue.m_nDouble == _rRH.m_aValue.m_nDouble; + break; + case DataType::TINYINT: + bRet = m_bSigned ? ( m_aValue.m_nInt8 == _rRH.m_aValue.m_nInt8 ) : (m_aValue.m_uInt8 == _rRH.m_aValue.m_uInt8); + break; + case DataType::SMALLINT: + bRet = m_bSigned ? ( m_aValue.m_nInt16 == _rRH.m_aValue.m_nInt16 ) : (m_aValue.m_uInt16 == _rRH.m_aValue.m_uInt16); + break; + case DataType::INTEGER: + bRet = m_bSigned ? ( m_aValue.m_nInt32 == _rRH.m_aValue.m_nInt32 ) : (m_aValue.m_uInt32 == _rRH.m_aValue.m_uInt32); + break; + case DataType::BIGINT: + bRet = m_bSigned ? ( m_aValue.m_nInt64 == _rRH.m_aValue.m_nInt64 ) : (m_aValue.m_uInt64 == _rRH.m_aValue.m_uInt64); + break; + case DataType::BIT: + case DataType::BOOLEAN: + bRet = m_aValue.m_bBool == _rRH.m_aValue.m_bBool; + break; + case DataType::DATE: + bRet = *static_cast(m_aValue.m_pValue) == *static_cast(_rRH.m_aValue.m_pValue); + break; + case DataType::TIME: + bRet = *static_cast(m_aValue.m_pValue) == *static_cast(_rRH.m_aValue.m_pValue); + break; + case DataType::TIMESTAMP: + bRet = *static_cast(m_aValue.m_pValue) == *static_cast(_rRH.m_aValue.m_pValue); + break; + case DataType::BINARY: + case DataType::VARBINARY: + case DataType::LONGVARBINARY: + bRet = false; + break; + case DataType::BLOB: + case DataType::CLOB: + case DataType::OBJECT: + case DataType::OTHER: + bRet = false; + break; + default: + bRet = false; + SAL_WARN( "connectivity.commontools","ORowSetValue::operator==(): UNSUPPORTED TYPE!"); + break; + } + return bRet; +} + +Any ORowSetValue::makeAny() const +{ + Any rValue; + if(isBound() && !isNull()) + { + switch(getTypeKind()) + { + case DataType::SQLNULL: + assert(rValue == Any()); + break; + case DataType::CHAR: + case DataType::VARCHAR: + case DataType::DECIMAL: + case DataType::NUMERIC: + case DataType::LONGVARCHAR: + OSL_ENSURE(m_aValue.m_pString,"Value is null!"); + rValue <<= OUString(m_aValue.m_pString); + break; + case DataType::FLOAT: + rValue <<= m_aValue.m_nFloat; + break; + case DataType::DOUBLE: + case DataType::REAL: + rValue <<= m_aValue.m_nDouble; + break; + case DataType::DATE: + OSL_ENSURE(m_aValue.m_pValue,"Value is null!"); + rValue <<= *static_cast(m_aValue.m_pValue); + break; + case DataType::TIME: + OSL_ENSURE(m_aValue.m_pValue,"Value is null!"); + rValue <<= *static_cast(m_aValue.m_pValue); + break; + case DataType::TIMESTAMP: + OSL_ENSURE(m_aValue.m_pValue,"Value is null!"); + rValue <<= *static_cast(m_aValue.m_pValue); + break; + case DataType::BINARY: + case DataType::VARBINARY: + case DataType::LONGVARBINARY: + OSL_ENSURE(m_aValue.m_pValue,"Value is null!"); + rValue <<= *static_cast*>(m_aValue.m_pValue); + break; + case DataType::BLOB: + case DataType::CLOB: + case DataType::OBJECT: + case DataType::OTHER: + rValue = getAny(); + break; + case DataType::BIT: + case DataType::BOOLEAN: + rValue <<= m_aValue.m_bBool; + break; + case DataType::TINYINT: + if ( m_bSigned ) + // TypeClass_BYTE + rValue <<= m_aValue.m_nInt8; + else + // There is no TypeClass_UNSIGNED_BYTE, + // so silently promote it to a 16-bit integer, + // that is TypeClass_UNSIGNED_SHORT + rValue <<= static_cast(m_aValue.m_uInt8); + break; + case DataType::SMALLINT: + if ( m_bSigned ) + // TypeClass_SHORT + rValue <<= m_aValue.m_nInt16; + else + // TypeClass_UNSIGNED_SHORT + rValue <<= m_aValue.m_uInt16; + break; + case DataType::INTEGER: + if ( m_bSigned ) + // TypeClass_LONG + rValue <<= m_aValue.m_nInt32; + else + // TypeClass_UNSIGNED_LONG + rValue <<= m_aValue.m_uInt32; + break; + case DataType::BIGINT: + if ( m_bSigned ) + // TypeClass_HYPER + rValue <<= m_aValue.m_nInt64; + else + // TypeClass_UNSIGNED_HYPER + rValue <<= m_aValue.m_uInt64; + break; + default: + SAL_WARN( "connectivity.commontools","ORowSetValue::makeAny(): UNSUPPORTED TYPE!"); + rValue = getAny(); + break; + } + } + return rValue; +} + +OUString ORowSetValue::getString( ) const +{ + OUString aRet; + if(!m_bNull) + { + switch(getTypeKind()) + { + case DataType::CHAR: + case DataType::VARCHAR: + case DataType::DECIMAL: + case DataType::NUMERIC: + case DataType::LONGVARCHAR: + aRet = m_aValue.m_pString; + break; + case DataType::FLOAT: + aRet = OUString::number(getFloat()); + break; + case DataType::DOUBLE: + case DataType::REAL: + aRet = OUString::number(getDouble()); + break; + case DataType::DATE: + aRet = DBTypeConversion::toDateString(getDate()); + break; + case DataType::TIME: + aRet = DBTypeConversion::toTimeString(getTime()); + break; + case DataType::TIMESTAMP: + aRet = DBTypeConversion::toDateTimeString(getDateTime()); + break; + case DataType::BINARY: + case DataType::VARBINARY: + case DataType::LONGVARBINARY: + { + OUStringBuffer sVal("0x"); + Sequence aSeq(getSequence()); + const sal_Int8* pBegin = aSeq.getConstArray(); + const sal_Int8* pEnd = pBegin + aSeq.getLength(); + for(;pBegin != pEnd;++pBegin) + sVal.append(static_cast(*pBegin),16); + aRet = sVal.makeStringAndClear(); + } + break; + case DataType::BIT: + aRet = OUString::number(int(getBool())); + break; + case DataType::BOOLEAN: + aRet = OUString::boolean(getBool()); + break; + case DataType::TINYINT: + case DataType::SMALLINT: + case DataType::INTEGER: + if ( m_bSigned ) + aRet = OUString::number(getInt32()); + else + aRet = OUString::number(getUInt32()); + break; + case DataType::BIGINT: + if ( m_bSigned ) + aRet = OUString::number(getLong()); + else + aRet = OUString::number(getULong()); + break; + case DataType::CLOB: + { + Any aValue( getAny() ); + Reference< XClob > xClob; + if ( (aValue >>= xClob) && xClob.is() ) + { + aRet = xClob->getSubString(1,static_cast(xClob->length()) ); + } + } + break; + default: + { + Any aValue = makeAny(); + aValue >>= aRet; + break; + } + } + } + return aRet; +} + +bool ORowSetValue::getBool() const +{ + bool bRet = false; + if(!m_bNull) + { + switch(getTypeKind()) + { + case DataType::CHAR: + case DataType::VARCHAR: + case DataType::LONGVARCHAR: + { + const OUString sValue(m_aValue.m_pString); + if ( sValue.equalsIgnoreAsciiCase("true") || (sValue == "1") ) + { + bRet = true; + break; + } + else if ( sValue.equalsIgnoreAsciiCase("false") || (sValue == "0") ) + { + bRet = false; + break; + } + } + [[fallthrough]]; + case DataType::DECIMAL: + case DataType::NUMERIC: + + bRet = OUString::unacquired(&m_aValue.m_pString).toInt32() != 0; + break; + case DataType::FLOAT: + bRet = m_aValue.m_nFloat != 0.0; + break; + case DataType::DOUBLE: + case DataType::REAL: + bRet = m_aValue.m_nDouble != 0.0; + break; + case DataType::DATE: + case DataType::TIME: + case DataType::TIMESTAMP: + case DataType::BINARY: + case DataType::VARBINARY: + case DataType::LONGVARBINARY: + OSL_FAIL("getBool() for this type is not allowed!"); + break; + case DataType::BIT: + case DataType::BOOLEAN: + bRet = m_aValue.m_bBool; + break; + case DataType::TINYINT: + bRet = m_bSigned ? (m_aValue.m_nInt8 != 0) : (m_aValue.m_uInt8 != 0); + break; + case DataType::SMALLINT: + bRet = m_bSigned ? (m_aValue.m_nInt16 != 0) : (m_aValue.m_uInt16 != 0); + break; + case DataType::INTEGER: + bRet = m_bSigned ? (m_aValue.m_nInt32 != 0) : (m_aValue.m_uInt32 != 0); + break; + case DataType::BIGINT: + bRet = m_bSigned ? (m_aValue.m_nInt64 != 0) : (m_aValue.m_uInt64 != 0); + break; + default: + { + Any aValue = makeAny(); + aValue >>= bRet; + break; + } + } + } + return bRet; +} + + +sal_Int8 ORowSetValue::getInt8() const +{ + sal_Int8 nRet = 0; + if(!m_bNull) + { + switch(getTypeKind()) + { + case DataType::CHAR: + case DataType::VARCHAR: + case DataType::DECIMAL: + case DataType::NUMERIC: + case DataType::LONGVARCHAR: + nRet = sal_Int8(OUString::unacquired(&m_aValue.m_pString).toInt32()); + break; + case DataType::FLOAT: + nRet = sal_Int8(m_aValue.m_nFloat); + break; + case DataType::DOUBLE: + case DataType::REAL: + nRet = sal_Int8(m_aValue.m_nDouble); + break; + case DataType::DATE: + case DataType::TIME: + case DataType::TIMESTAMP: + case DataType::BINARY: + case DataType::VARBINARY: + case DataType::LONGVARBINARY: + case DataType::BLOB: + case DataType::CLOB: + OSL_FAIL("getInt8() for this type is not allowed!"); + break; + case DataType::BIT: + case DataType::BOOLEAN: + nRet = sal_Int8(m_aValue.m_bBool); + break; + case DataType::TINYINT: + if ( m_bSigned ) + nRet = m_aValue.m_nInt8; + else + nRet = static_cast(m_aValue.m_uInt8); + break; + case DataType::SMALLINT: + if ( m_bSigned ) + nRet = static_cast(m_aValue.m_nInt16); + else + nRet = static_cast(m_aValue.m_uInt16); + break; + case DataType::INTEGER: + if ( m_bSigned ) + nRet = static_cast(m_aValue.m_nInt32); + else + nRet = static_cast(m_aValue.m_uInt32); + break; + case DataType::BIGINT: + if ( m_bSigned ) + nRet = static_cast(m_aValue.m_nInt64); + else + nRet = static_cast(m_aValue.m_uInt64); + break; + default: + { + Any aValue = makeAny(); + aValue >>= nRet; + break; + } + } + } + return nRet; +} + + +sal_uInt8 ORowSetValue::getUInt8() const +{ + sal_uInt8 nRet = 0; + if(!m_bNull) + { + switch(getTypeKind()) + { + case DataType::CHAR: + case DataType::VARCHAR: + case DataType::DECIMAL: + case DataType::NUMERIC: + case DataType::LONGVARCHAR: + nRet = sal_uInt8(OUString::unacquired(&m_aValue.m_pString).toInt32()); + break; + case DataType::FLOAT: + nRet = sal_uInt8(m_aValue.m_nFloat); + break; + case DataType::DOUBLE: + case DataType::REAL: + nRet = sal_uInt8(m_aValue.m_nDouble); + break; + case DataType::DATE: + case DataType::TIME: + case DataType::TIMESTAMP: + case DataType::BINARY: + case DataType::VARBINARY: + case DataType::LONGVARBINARY: + case DataType::BLOB: + case DataType::CLOB: + OSL_FAIL("getuInt8() for this type is not allowed!"); + break; + case DataType::BIT: + case DataType::BOOLEAN: + nRet = int(m_aValue.m_bBool); + break; + case DataType::TINYINT: + if ( m_bSigned ) + nRet = m_aValue.m_nInt8; + else + nRet = m_aValue.m_uInt8; + break; + case DataType::SMALLINT: + if ( m_bSigned ) + nRet = static_cast(m_aValue.m_nInt16); + else + nRet = static_cast(m_aValue.m_uInt16); + break; + case DataType::INTEGER: + if ( m_bSigned ) + nRet = static_cast(m_aValue.m_nInt32); + else + nRet = static_cast(m_aValue.m_uInt32); + break; + case DataType::BIGINT: + if ( m_bSigned ) + nRet = static_cast(m_aValue.m_nInt64); + else + nRet = static_cast(m_aValue.m_uInt64); + break; + default: + { + Any aValue = makeAny(); + // Cf. "There is no TypeClass_UNSIGNED_BYTE" in makeAny: + sal_uInt16 n; + if (aValue >>= n) { + nRet = static_cast(n); + } + break; + } + } + } + return nRet; +} + + +sal_Int16 ORowSetValue::getInt16() const +{ + sal_Int16 nRet = 0; + if(!m_bNull) + { + switch(getTypeKind()) + { + case DataType::CHAR: + case DataType::VARCHAR: + case DataType::DECIMAL: + case DataType::NUMERIC: + case DataType::LONGVARCHAR: + nRet = sal_Int16(OUString::unacquired(&m_aValue.m_pString).toInt32()); + break; + case DataType::FLOAT: + nRet = sal_Int16(m_aValue.m_nFloat); + break; + case DataType::DOUBLE: + case DataType::REAL: + nRet = sal_Int16(m_aValue.m_nDouble); + break; + case DataType::DATE: + case DataType::TIME: + case DataType::TIMESTAMP: + case DataType::BINARY: + case DataType::VARBINARY: + case DataType::LONGVARBINARY: + case DataType::BLOB: + case DataType::CLOB: + OSL_FAIL("getInt16() for this type is not allowed!"); + break; + case DataType::BIT: + case DataType::BOOLEAN: + nRet = sal_Int16(m_aValue.m_bBool); + break; + case DataType::TINYINT: + if ( m_bSigned ) + nRet = m_aValue.m_nInt8; + else + nRet = m_aValue.m_uInt8; + break; + case DataType::SMALLINT: + if ( m_bSigned ) + nRet = m_aValue.m_nInt16; + else + nRet = static_cast(m_aValue.m_uInt16); + break; + case DataType::INTEGER: + if ( m_bSigned ) + nRet = static_cast(m_aValue.m_nInt32); + else + nRet = static_cast(m_aValue.m_uInt32); + break; + case DataType::BIGINT: + if ( m_bSigned ) + nRet = static_cast(m_aValue.m_nInt64); + else + nRet = static_cast(m_aValue.m_uInt64); + break; + default: + { + Any aValue = makeAny(); + aValue >>= nRet; + break; + } + } + } + return nRet; +} + + +sal_uInt16 ORowSetValue::getUInt16() const +{ + sal_uInt16 nRet = 0; + if(!m_bNull) + { + switch(getTypeKind()) + { + case DataType::CHAR: + case DataType::VARCHAR: + case DataType::DECIMAL: + case DataType::NUMERIC: + case DataType::LONGVARCHAR: + nRet = sal_uInt16(OUString::unacquired(&m_aValue.m_pString).toInt32()); + break; + case DataType::FLOAT: + nRet = sal_uInt16(m_aValue.m_nFloat); + break; + case DataType::DOUBLE: + case DataType::REAL: + nRet = sal_uInt16(m_aValue.m_nDouble); + break; + case DataType::DATE: + case DataType::TIME: + case DataType::TIMESTAMP: + case DataType::BINARY: + case DataType::VARBINARY: + case DataType::LONGVARBINARY: + case DataType::BLOB: + case DataType::CLOB: + OSL_FAIL("getuInt16() for this type is not allowed!"); + break; + case DataType::BIT: + case DataType::BOOLEAN: + nRet = sal_uInt16(m_aValue.m_bBool); + break; + case DataType::TINYINT: + if ( m_bSigned ) + nRet = m_aValue.m_nInt8; + else + nRet = m_aValue.m_uInt8; + break; + case DataType::SMALLINT: + if ( m_bSigned ) + nRet = m_aValue.m_nInt16; + else + nRet = m_aValue.m_uInt16; + break; + case DataType::INTEGER: + if ( m_bSigned ) + nRet = static_cast(m_aValue.m_nInt32); + else + nRet = static_cast(m_aValue.m_uInt32); + break; + case DataType::BIGINT: + if ( m_bSigned ) + nRet = static_cast(m_aValue.m_nInt64); + else + nRet = static_cast(m_aValue.m_uInt64); + break; + default: + { + Any aValue = makeAny(); + aValue >>= nRet; + break; + } + } + } + return nRet; +} + + +sal_Int32 ORowSetValue::getInt32() const +{ + sal_Int32 nRet = 0; + if(!m_bNull) + { + switch(getTypeKind()) + { + case DataType::CHAR: + case DataType::VARCHAR: + case DataType::DECIMAL: + case DataType::NUMERIC: + case DataType::LONGVARCHAR: + nRet = OUString::unacquired(&m_aValue.m_pString).toInt32(); + break; + case DataType::FLOAT: + nRet = sal_Int32(m_aValue.m_nFloat); + break; + case DataType::DOUBLE: + case DataType::REAL: + nRet = sal_Int32(m_aValue.m_nDouble); + break; + case DataType::DATE: + nRet = dbtools::DBTypeConversion::toDays(*static_cast(m_aValue.m_pValue)); + break; + case DataType::TIME: + case DataType::TIMESTAMP: + case DataType::BINARY: + case DataType::VARBINARY: + case DataType::LONGVARBINARY: + case DataType::BLOB: + case DataType::CLOB: + OSL_FAIL("getInt32() for this type is not allowed!"); + break; + case DataType::BIT: + case DataType::BOOLEAN: + nRet = sal_Int32(m_aValue.m_bBool); + break; + case DataType::TINYINT: + if ( m_bSigned ) + nRet = m_aValue.m_nInt8; + else + nRet = m_aValue.m_uInt8; + break; + case DataType::SMALLINT: + if ( m_bSigned ) + nRet = m_aValue.m_nInt16; + else + nRet = m_aValue.m_uInt16; + break; + case DataType::INTEGER: + if ( m_bSigned ) + nRet = m_aValue.m_nInt32; + else + nRet = static_cast(m_aValue.m_uInt32); + break; + case DataType::BIGINT: + if ( m_bSigned ) + nRet = static_cast(m_aValue.m_nInt64); + else + nRet = static_cast(m_aValue.m_uInt64); + break; + default: + { + Any aValue = makeAny(); + aValue >>= nRet; + break; + } + } + } + return nRet; +} + + +sal_uInt32 ORowSetValue::getUInt32() const +{ + sal_uInt32 nRet = 0; + if(!m_bNull) + { + switch(getTypeKind()) + { + case DataType::CHAR: + case DataType::VARCHAR: + case DataType::DECIMAL: + case DataType::NUMERIC: + case DataType::LONGVARCHAR: + nRet = OUString::unacquired(&m_aValue.m_pString).toUInt32(); + break; + case DataType::FLOAT: + nRet = sal_uInt32(m_aValue.m_nFloat); + break; + case DataType::DOUBLE: + case DataType::REAL: + nRet = sal_uInt32(m_aValue.m_nDouble); + break; + case DataType::DATE: + nRet = dbtools::DBTypeConversion::toDays(*static_cast(m_aValue.m_pValue)); + break; + case DataType::TIME: + case DataType::TIMESTAMP: + case DataType::BINARY: + case DataType::VARBINARY: + case DataType::LONGVARBINARY: + case DataType::BLOB: + case DataType::CLOB: + OSL_FAIL("getuInt32() for this type is not allowed!"); + break; + case DataType::BIT: + case DataType::BOOLEAN: + nRet = sal_uInt32(m_aValue.m_bBool); + break; + case DataType::TINYINT: + if ( m_bSigned ) + nRet = m_aValue.m_nInt8; + else + nRet = m_aValue.m_uInt8; + break; + case DataType::SMALLINT: + if ( m_bSigned ) + nRet = m_aValue.m_nInt16; + else + nRet = m_aValue.m_uInt16; + break; + case DataType::INTEGER: + if ( m_bSigned ) + nRet = m_aValue.m_nInt32; + else + nRet = m_aValue.m_uInt32; + break; + case DataType::BIGINT: + if ( m_bSigned ) + nRet = static_cast(m_aValue.m_nInt64); + else + nRet = static_cast(m_aValue.m_uInt64); + break; + default: + { + Any aValue = makeAny(); + aValue >>= nRet; + break; + } + } + } + return nRet; +} + + +sal_Int64 ORowSetValue::getLong() const +{ + sal_Int64 nRet = 0; + if(!m_bNull) + { + switch(getTypeKind()) + { + case DataType::CHAR: + case DataType::VARCHAR: + case DataType::DECIMAL: + case DataType::NUMERIC: + case DataType::LONGVARCHAR: + nRet = OUString::unacquired(&m_aValue.m_pString).toInt64(); + break; + case DataType::FLOAT: + nRet = sal_Int64(m_aValue.m_nFloat); + break; + case DataType::DOUBLE: + case DataType::REAL: + nRet = sal_Int64(m_aValue.m_nDouble); + break; + case DataType::DATE: + nRet = dbtools::DBTypeConversion::toDays(*static_cast(m_aValue.m_pValue)); + break; + case DataType::TIME: + case DataType::TIMESTAMP: + case DataType::BINARY: + case DataType::VARBINARY: + case DataType::LONGVARBINARY: + case DataType::BLOB: + case DataType::CLOB: + OSL_FAIL("getLong() for this type is not allowed!"); + break; + case DataType::BIT: + case DataType::BOOLEAN: + nRet = sal_Int64(m_aValue.m_bBool); + break; + case DataType::TINYINT: + if ( m_bSigned ) + nRet = m_aValue.m_nInt8; + else + nRet = m_aValue.m_uInt8; + break; + case DataType::SMALLINT: + if ( m_bSigned ) + nRet = m_aValue.m_nInt16; + else + nRet = m_aValue.m_uInt16; + break; + case DataType::INTEGER: + if ( m_bSigned ) + nRet = m_aValue.m_nInt32; + else + nRet = m_aValue.m_uInt32; + break; + case DataType::BIGINT: + if ( m_bSigned ) + nRet = m_aValue.m_nInt64; + else + nRet = static_cast(m_aValue.m_uInt64); + break; + default: + { + Any aValue = makeAny(); + aValue >>= nRet; + break; + } + } + } + return nRet; +} + + +sal_uInt64 ORowSetValue::getULong() const +{ + sal_uInt64 nRet = 0; + if(!m_bNull) + { + switch(getTypeKind()) + { + case DataType::CHAR: + case DataType::VARCHAR: + case DataType::DECIMAL: + case DataType::NUMERIC: + case DataType::LONGVARCHAR: + nRet = OUString::unacquired(&m_aValue.m_pString).toUInt64(); + break; + case DataType::FLOAT: + nRet = sal_uInt64(m_aValue.m_nFloat); + break; + case DataType::DOUBLE: + case DataType::REAL: + nRet = sal_uInt64(m_aValue.m_nDouble); + break; + case DataType::DATE: + nRet = dbtools::DBTypeConversion::toDays(*static_cast(m_aValue.m_pValue)); + break; + case DataType::TIME: + case DataType::TIMESTAMP: + case DataType::BINARY: + case DataType::VARBINARY: + case DataType::LONGVARBINARY: + case DataType::BLOB: + case DataType::CLOB: + OSL_FAIL("getULong() for this type is not allowed!"); + break; + case DataType::BIT: + case DataType::BOOLEAN: + nRet = sal_uInt64(m_aValue.m_bBool); + break; + case DataType::TINYINT: + if ( m_bSigned ) + nRet = m_aValue.m_nInt8; + else + nRet = m_aValue.m_uInt8; + break; + case DataType::SMALLINT: + if ( m_bSigned ) + nRet = m_aValue.m_nInt16; + else + nRet = m_aValue.m_uInt16; + break; + case DataType::INTEGER: + if ( m_bSigned ) + nRet = m_aValue.m_nInt32; + else + nRet = m_aValue.m_uInt32; + break; + case DataType::BIGINT: + if ( m_bSigned ) + nRet = m_aValue.m_nInt64; + else + nRet = m_aValue.m_uInt64; + break; + default: + { + Any aValue = makeAny(); + aValue >>= nRet; + break; + } + } + } + return nRet; +} + + +float ORowSetValue::getFloat() const +{ + float nRet = 0; + if(!m_bNull) + { + switch(getTypeKind()) + { + case DataType::CHAR: + case DataType::VARCHAR: + case DataType::DECIMAL: + case DataType::NUMERIC: + case DataType::LONGVARCHAR: + nRet = OUString::unacquired(&m_aValue.m_pString).toFloat(); + break; + case DataType::FLOAT: + nRet = m_aValue.m_nFloat; + break; + case DataType::DOUBLE: + case DataType::REAL: + nRet = static_cast(m_aValue.m_nDouble); + break; + case DataType::DATE: + nRet = static_cast(dbtools::DBTypeConversion::toDouble(*static_cast(m_aValue.m_pValue))); + break; + case DataType::TIME: + nRet = static_cast(dbtools::DBTypeConversion::toDouble(*static_cast(m_aValue.m_pValue))); + break; + case DataType::TIMESTAMP: + nRet = static_cast(dbtools::DBTypeConversion::toDouble(*static_cast(m_aValue.m_pValue))); + break; + case DataType::BINARY: + case DataType::VARBINARY: + case DataType::LONGVARBINARY: + case DataType::BLOB: + case DataType::CLOB: + OSL_FAIL("getDouble() for this type is not allowed!"); + break; + case DataType::BIT: + case DataType::BOOLEAN: + nRet = float(m_aValue.m_bBool); + break; + case DataType::TINYINT: + if ( m_bSigned ) + nRet = m_aValue.m_nInt8; + else + nRet = m_aValue.m_uInt8; + break; + case DataType::SMALLINT: + if ( m_bSigned ) + nRet = m_aValue.m_nInt16; + else + nRet = static_cast(m_aValue.m_uInt16); + break; + case DataType::INTEGER: + if ( m_bSigned ) + nRet = static_cast(m_aValue.m_nInt32); + else + nRet = static_cast(m_aValue.m_uInt32); + break; + case DataType::BIGINT: + if ( m_bSigned ) + nRet = static_cast(m_aValue.m_nInt64); + else + nRet = static_cast(m_aValue.m_uInt64); + break; + default: + { + Any aValue = makeAny(); + aValue >>= nRet; + break; + } + } + } + return nRet; +} + +double ORowSetValue::getDouble() const +{ + double nRet = 0; + if(!m_bNull) + { + switch(getTypeKind()) + { + case DataType::CHAR: + case DataType::VARCHAR: + case DataType::DECIMAL: + case DataType::NUMERIC: + case DataType::LONGVARCHAR: + nRet = OUString::unacquired(&m_aValue.m_pString).toDouble(); + break; + case DataType::FLOAT: + nRet = m_aValue.m_nFloat; + break; + case DataType::DOUBLE: + case DataType::REAL: + nRet = m_aValue.m_nDouble; + break; + case DataType::DATE: + nRet = dbtools::DBTypeConversion::toDouble(*static_cast(m_aValue.m_pValue)); + break; + case DataType::TIME: + nRet = dbtools::DBTypeConversion::toDouble(*static_cast(m_aValue.m_pValue)); + break; + case DataType::TIMESTAMP: + nRet = dbtools::DBTypeConversion::toDouble(*static_cast(m_aValue.m_pValue)); + break; + case DataType::BINARY: + case DataType::VARBINARY: + case DataType::LONGVARBINARY: + case DataType::BLOB: + case DataType::CLOB: + OSL_FAIL("getDouble() for this type is not allowed!"); + break; + case DataType::BIT: + case DataType::BOOLEAN: + nRet = double(m_aValue.m_bBool); + break; + case DataType::TINYINT: + if ( m_bSigned ) + nRet = m_aValue.m_nInt8; + else + nRet = m_aValue.m_uInt8; + break; + case DataType::SMALLINT: + if ( m_bSigned ) + nRet = m_aValue.m_nInt16; + else + nRet = m_aValue.m_uInt16; + break; + case DataType::INTEGER: + if ( m_bSigned ) + nRet = m_aValue.m_nInt32; + else + nRet = m_aValue.m_uInt32; + break; + case DataType::BIGINT: + if ( m_bSigned ) + nRet = m_aValue.m_nInt64; + else + nRet = m_aValue.m_uInt64; + break; + default: + { + Any aValue = makeAny(); + aValue >>= nRet; + break; + } + } + } + return nRet; +} + +Sequence ORowSetValue::getSequence() const +{ + Sequence aSeq; + if (!m_bNull) + { + switch(m_eTypeKind) + { + case DataType::OBJECT: + case DataType::CLOB: + case DataType::BLOB: + { + Reference xStream; + const Any aValue = makeAny(); + if(aValue.hasValue()) + { + Reference xBlob(aValue,UNO_QUERY); + if ( xBlob.is() ) + xStream = xBlob->getBinaryStream(); + else + { + Reference xClob(aValue,UNO_QUERY); + if ( xClob.is() ) + xStream = xClob->getCharacterStream(); + } + if(xStream.is()) + { + const sal_uInt32 nBytesToRead = 65535; + sal_uInt32 nRead; + + do + { + css::uno::Sequence< sal_Int8 > aReadSeq; + + nRead = xStream->readSomeBytes( aReadSeq, nBytesToRead ); + + if( nRead ) + { + const sal_uInt32 nOldLength = aSeq.getLength(); + aSeq.realloc( nOldLength + nRead ); + memcpy( aSeq.getArray() + nOldLength, aReadSeq.getConstArray(), aReadSeq.getLength() ); + } + } + while( nBytesToRead == nRead ); + xStream->closeInput(); + } + } + } + break; + case DataType::VARCHAR: + case DataType::LONGVARCHAR: + { + aSeq = Sequence(reinterpret_cast(m_aValue.m_pString->buffer), + sizeof(sal_Unicode) * m_aValue.m_pString->length); + } + break; + case DataType::BINARY: + case DataType::VARBINARY: + case DataType::LONGVARBINARY: + aSeq = *static_cast< Sequence*>(m_aValue.m_pValue); + break; + default: + { + Any aValue = makeAny(); + aValue >>= aSeq; + break; + } + } + } + return aSeq; + +} + +css::util::Date ORowSetValue::getDate() const +{ + css::util::Date aValue; + if(!m_bNull) + { + switch(m_eTypeKind) + { + case DataType::CHAR: + case DataType::VARCHAR: + case DataType::LONGVARCHAR: + aValue = DBTypeConversion::toDate(getString()); + break; + case DataType::DECIMAL: + case DataType::NUMERIC: + case DataType::FLOAT: + case DataType::DOUBLE: + case DataType::REAL: + aValue = DBTypeConversion::toDate(getDouble()); + break; + + case DataType::DATE: + aValue = *static_cast< css::util::Date*>(m_aValue.m_pValue); + break; + case DataType::TIMESTAMP: + { + css::util::DateTime* pDateTime = static_cast< css::util::DateTime*>(m_aValue.m_pValue); + aValue.Day = pDateTime->Day; + aValue.Month = pDateTime->Month; + aValue.Year = pDateTime->Year; + } + break; + case DataType::BIT: + case DataType::BOOLEAN: + case DataType::TINYINT: + case DataType::SMALLINT: + case DataType::INTEGER: + case DataType::BIGINT: + aValue = DBTypeConversion::toDate( double( getLong() ) ); + break; + + case DataType::BLOB: + case DataType::CLOB: + case DataType::OBJECT: + default: + OSL_ENSURE( false, "ORowSetValue::getDate: cannot retrieve the data!" ); + [[fallthrough]]; + + case DataType::BINARY: + case DataType::VARBINARY: + case DataType::LONGVARBINARY: + case DataType::TIME: + aValue = DBTypeConversion::toDate( double(0) ); + break; + } + } + return aValue; +} + +css::util::Time ORowSetValue::getTime() const +{ + css::util::Time aValue; + if(!m_bNull) + { + switch(m_eTypeKind) + { + case DataType::CHAR: + case DataType::VARCHAR: + case DataType::LONGVARCHAR: + aValue = DBTypeConversion::toTime(getString()); + break; + case DataType::DECIMAL: + case DataType::NUMERIC: + aValue = DBTypeConversion::toTime(getDouble()); + break; + case DataType::FLOAT: + case DataType::DOUBLE: + case DataType::REAL: + aValue = DBTypeConversion::toTime(getDouble()); + break; + case DataType::TIMESTAMP: + { + css::util::DateTime* pDateTime = static_cast< css::util::DateTime*>(m_aValue.m_pValue); + aValue.NanoSeconds = pDateTime->NanoSeconds; + aValue.Seconds = pDateTime->Seconds; + aValue.Minutes = pDateTime->Minutes; + aValue.Hours = pDateTime->Hours; + } + break; + case DataType::TIME: + aValue = *static_cast< css::util::Time*>(m_aValue.m_pValue); + break; + default: + { + Any aAnyValue = makeAny(); + aAnyValue >>= aValue; + break; + } + } + } + return aValue; +} + +css::util::DateTime ORowSetValue::getDateTime() const +{ + css::util::DateTime aValue; + if(!m_bNull) + { + switch(m_eTypeKind) + { + case DataType::CHAR: + case DataType::VARCHAR: + case DataType::LONGVARCHAR: + aValue = DBTypeConversion::toDateTime(getString()); + break; + case DataType::DECIMAL: + case DataType::NUMERIC: + aValue = DBTypeConversion::toDateTime(getDouble()); + break; + case DataType::FLOAT: + case DataType::DOUBLE: + case DataType::REAL: + aValue = DBTypeConversion::toDateTime(getDouble()); + break; + case DataType::DATE: + { + css::util::Date* pDate = static_cast< css::util::Date*>(m_aValue.m_pValue); + aValue.Day = pDate->Day; + aValue.Month = pDate->Month; + aValue.Year = pDate->Year; + } + break; + case DataType::TIME: + { + css::util::Time* pTime = static_cast< css::util::Time*>(m_aValue.m_pValue); + aValue.NanoSeconds = pTime->NanoSeconds; + aValue.Seconds = pTime->Seconds; + aValue.Minutes = pTime->Minutes; + aValue.Hours = pTime->Hours; + } + break; + case DataType::TIMESTAMP: + aValue = *static_cast< css::util::DateTime*>(m_aValue.m_pValue); + break; + default: + { + Any aAnyValue = makeAny(); + aAnyValue >>= aValue; + break; + } + } + } + return aValue; +} + +void ORowSetValue::setSigned(bool _bMod) +{ + if ( m_bSigned == _bMod ) + return; + + m_bSigned = _bMod; + if ( m_bNull ) + return; + + sal_Int32 nType = m_eTypeKind; + switch(m_eTypeKind) + { + case DataType::TINYINT: + if ( m_bSigned ) + (*this) = getInt8(); + else + { + m_bSigned = !m_bSigned; + (*this) = getInt16(); + m_bSigned = !m_bSigned; + } + break; + case DataType::SMALLINT: + if ( m_bSigned ) + (*this) = getInt16(); + else + { + m_bSigned = !m_bSigned; + (*this) = getInt32(); + m_bSigned = !m_bSigned; + } + break; + case DataType::INTEGER: + if ( m_bSigned ) + (*this) = getInt32(); + else + { + m_bSigned = !m_bSigned; + (*this) = getLong(); + m_bSigned = !m_bSigned; + } + break; + case DataType::BIGINT: + { + if ( m_bSigned ) + { + auto nTmp = static_cast(m_aValue.m_uInt64); + m_aValue.m_nInt64 = nTmp; + } + else + { + auto nTmp = static_cast(m_aValue.m_nInt64); + m_aValue.m_uInt64 = nTmp; + } + break; + } + } + m_eTypeKind = nType; +} + + +namespace detail +{ + class SAL_NO_VTABLE IValueSource + { + public: + virtual OUString getString() const = 0; + virtual bool getBoolean() const = 0; + virtual sal_Int8 getByte() const = 0; + virtual sal_Int16 getShort() const = 0; + virtual sal_Int32 getInt() const = 0; + virtual sal_Int64 getLong() const = 0; + virtual float getFloat() const = 0; + virtual double getDouble() const = 0; + virtual Date getDate() const = 0; + virtual css::util::Time getTime() const = 0; + virtual DateTime getTimestamp() const = 0; + virtual Sequence< sal_Int8 > getBytes() const = 0; + virtual Reference< XBlob > getBlob() const = 0; + virtual Reference< XClob > getClob() const = 0; + virtual Any getObject() const = 0; + virtual bool wasNull() const = 0; + + virtual ~IValueSource() { } + }; + + namespace { + + class RowValue : public IValueSource + { + public: + RowValue( const Reference< XRow >& _xRow, const sal_Int32 _nPos ) + :m_xRow( _xRow ) + ,m_nPos( _nPos ) + { + } + + // IValueSource + virtual OUString getString() const override { return m_xRow->getString( m_nPos ); }; + virtual bool getBoolean() const override { return m_xRow->getBoolean( m_nPos ); }; + virtual sal_Int8 getByte() const override { return m_xRow->getByte( m_nPos ); }; + virtual sal_Int16 getShort() const override { return m_xRow->getShort( m_nPos ); } + virtual sal_Int32 getInt() const override { return m_xRow->getInt( m_nPos ); } + virtual sal_Int64 getLong() const override { return m_xRow->getLong( m_nPos ); } + virtual float getFloat() const override { return m_xRow->getFloat( m_nPos ); }; + virtual double getDouble() const override { return m_xRow->getDouble( m_nPos ); }; + virtual Date getDate() const override { return m_xRow->getDate( m_nPos ); }; + virtual css::util::Time getTime() const override { return m_xRow->getTime( m_nPos ); }; + virtual DateTime getTimestamp() const override { return m_xRow->getTimestamp( m_nPos ); }; + virtual Sequence< sal_Int8 > getBytes() const override { return m_xRow->getBytes( m_nPos ); }; + virtual Reference< XBlob > getBlob() const override { return m_xRow->getBlob( m_nPos ); }; + virtual Reference< XClob > getClob() const override { return m_xRow->getClob( m_nPos ); }; + virtual Any getObject() const override { return m_xRow->getObject( m_nPos ,nullptr); }; + virtual bool wasNull() const override { return m_xRow->wasNull( ); }; + + private: + const Reference< XRow > m_xRow; + const sal_Int32 m_nPos; + }; + + class ColumnValue : public IValueSource + { + public: + explicit ColumnValue( const Reference< XColumn >& _rxColumn ) + :m_xColumn( _rxColumn ) + { + } + + // IValueSource + virtual OUString getString() const override { return m_xColumn->getString(); }; + virtual bool getBoolean() const override { return m_xColumn->getBoolean(); }; + virtual sal_Int8 getByte() const override { return m_xColumn->getByte(); }; + virtual sal_Int16 getShort() const override { return m_xColumn->getShort(); } + virtual sal_Int32 getInt() const override { return m_xColumn->getInt(); } + virtual sal_Int64 getLong() const override { return m_xColumn->getLong(); } + virtual float getFloat() const override { return m_xColumn->getFloat(); }; + virtual double getDouble() const override { return m_xColumn->getDouble(); }; + virtual Date getDate() const override { return m_xColumn->getDate(); }; + virtual css::util::Time getTime() const override { return m_xColumn->getTime(); }; + virtual DateTime getTimestamp() const override { return m_xColumn->getTimestamp(); }; + virtual Sequence< sal_Int8 > getBytes() const override { return m_xColumn->getBytes(); }; + virtual Reference< XBlob > getBlob() const override { return m_xColumn->getBlob(); }; + virtual Reference< XClob > getClob() const override { return m_xColumn->getClob(); }; + virtual Any getObject() const override { return m_xColumn->getObject( nullptr ); }; + virtual bool wasNull() const override { return m_xColumn->wasNull( ); }; + + private: + const Reference< XColumn > m_xColumn; + }; + + } +} + + +void ORowSetValue::fill( const sal_Int32 _nType, const Reference< XColumn >& _rxColumn ) +{ + detail::ColumnValue aColumnValue( _rxColumn ); + impl_fill( _nType, true, aColumnValue ); +} + + +void ORowSetValue::fill( sal_Int32 _nPos, sal_Int32 _nType, bool _bNullable, const Reference< XRow>& _xRow ) +{ + detail::RowValue aRowValue( _xRow, _nPos ); + impl_fill( _nType, _bNullable, aRowValue ); +} + + +void ORowSetValue::fill(sal_Int32 _nPos, + sal_Int32 _nType, + const css::uno::Reference< css::sdbc::XRow>& _xRow) +{ + fill(_nPos,_nType,true,_xRow); +} + + +void ORowSetValue::impl_fill( const sal_Int32 _nType, bool _bNullable, const detail::IValueSource& _rValueSource ) +{ + switch(_nType) + { + case DataType::CHAR: + case DataType::VARCHAR: + case DataType::DECIMAL: + case DataType::NUMERIC: + case DataType::LONGVARCHAR: + (*this) = _rValueSource.getString(); + break; + case DataType::BIGINT: + if ( isSigned() ) + (*this) = _rValueSource.getLong(); + else + // TODO: this is rather horrible performance-wise + // but fixing it needs extending the css::sdbc::XRow API + // to have a getULong(), and needs updating all drivers :-| + // When doing that, add getUByte, getUShort, getUInt for symmetry/completeness + (*this) = _rValueSource.getString().toUInt64(); + break; + case DataType::FLOAT: + (*this) = _rValueSource.getFloat(); + break; + case DataType::DOUBLE: + case DataType::REAL: + (*this) = _rValueSource.getDouble(); + break; + case DataType::DATE: + (*this) = _rValueSource.getDate(); + break; + case DataType::TIME: + (*this) = _rValueSource.getTime(); + break; + case DataType::TIMESTAMP: + (*this) = _rValueSource.getTimestamp(); + break; + case DataType::BINARY: + case DataType::VARBINARY: + case DataType::LONGVARBINARY: + (*this) = _rValueSource.getBytes(); + break; + case DataType::BIT: + case DataType::BOOLEAN: + (*this) = _rValueSource.getBoolean(); + break; + case DataType::TINYINT: + if ( isSigned() ) + (*this) = _rValueSource.getByte(); + else + (*this) = _rValueSource.getShort(); + break; + case DataType::SMALLINT: + if ( isSigned() ) + (*this) = _rValueSource.getShort(); + else + (*this) = _rValueSource.getInt(); + break; + case DataType::INTEGER: + if ( isSigned() ) + (*this) = _rValueSource.getInt(); + else + (*this) = _rValueSource.getLong(); + break; + case DataType::CLOB: + (*this) = css::uno::Any(_rValueSource.getClob()); + setTypeKind(DataType::CLOB); + break; + case DataType::BLOB: + (*this) = css::uno::Any(_rValueSource.getBlob()); + setTypeKind(DataType::BLOB); + break; + case DataType::OTHER: + (*this) = _rValueSource.getObject(); + setTypeKind(DataType::OTHER); + break; + default: + SAL_WARN( "connectivity.commontools", "ORowSetValue::fill: unsupported type!" ); + (*this) = _rValueSource.getObject(); + break; + } + if ( _bNullable && _rValueSource.wasNull() ) + setNull(); + setTypeKind(_nType); +} + +void ORowSetValue::fill(const Any& _rValue) +{ + switch (_rValue.getValueType().getTypeClass()) + { + case TypeClass_VOID: + setNull(); break; + case TypeClass_BOOLEAN: + { + bool bValue( false ); + _rValue >>= bValue; + (*this) = bValue; + break; + } + case TypeClass_CHAR: + { + sal_Unicode aDummy(0); + _rValue >>= aDummy; + (*this) = OUString(aDummy); + break; + } + case TypeClass_STRING: + { + OUString sDummy; + _rValue >>= sDummy; + (*this) = sDummy; + break; + } + case TypeClass_FLOAT: + { + float aDummy(0.0); + _rValue >>= aDummy; + (*this) = aDummy; + break; + } + case TypeClass_DOUBLE: + { + double aDummy(0.0); + _rValue >>= aDummy; + (*this) = aDummy; + break; + } + case TypeClass_BYTE: + { + sal_Int8 aDummy(0); + _rValue >>= aDummy; + (*this) = aDummy; + break; + } + case TypeClass_SHORT: + { + sal_Int16 aDummy(0); + _rValue >>= aDummy; + (*this) = aDummy; + break; + } + case TypeClass_UNSIGNED_SHORT: + { + sal_uInt16 nValue(0); + _rValue >>= nValue; + (*this) = nValue; + break; + } + case TypeClass_LONG: + { + sal_Int32 aDummy(0); + _rValue >>= aDummy; + (*this) = aDummy; + break; + } + case TypeClass_UNSIGNED_LONG: + { + sal_uInt32 nValue(0); + _rValue >>= nValue; + (*this) = static_cast(nValue); + setSigned(false); + break; + } + case TypeClass_HYPER: + { + sal_Int64 nValue(0); + _rValue >>= nValue; + (*this) = nValue; + break; + } + case TypeClass_UNSIGNED_HYPER: + { + sal_uInt64 nValue(0); + _rValue >>= nValue; + (*this) = nValue; + setSigned(false); + break; + } + case TypeClass_ENUM: + { + sal_Int32 enumValue( 0 ); + ::cppu::enum2int( enumValue, _rValue ); + (*this) = enumValue; + } + break; + + case TypeClass_SEQUENCE: + { + Sequence aDummy; + if ( _rValue >>= aDummy ) + (*this) = aDummy; + else + SAL_WARN( "connectivity.commontools", "ORowSetValue::fill: unsupported sequence type!" ); + break; + } + + case TypeClass_STRUCT: + { + css::util::Date aDate; + css::util::Time aTime; + css::util::DateTime aDateTime; + if ( _rValue >>= aDate ) + { + (*this) = aDate; + } + else if ( _rValue >>= aTime ) + { + (*this) = aTime; + } + else if ( _rValue >>= aDateTime ) + { + (*this) = aDateTime; + } + else + SAL_WARN( "connectivity.commontools", "ORowSetValue::fill: unsupported structure!" ); + + break; + } + case TypeClass_INTERFACE: + { + Reference< XClob > xClob; + if ( _rValue >>= xClob ) + { + (*this) = _rValue; + setTypeKind(DataType::CLOB); + } + else + { + Reference< XBlob > xBlob; + if ( _rValue >>= xBlob ) + { + (*this) = _rValue; + setTypeKind(DataType::BLOB); + } + else + { + (*this) = _rValue; + } + } + } + break; + + default: + SAL_WARN( "connectivity.commontools","Unknown type"); + break; + } +} + +} // namespace connectivity + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/commontools/ParameterSubstitution.cxx b/connectivity/source/commontools/ParameterSubstitution.cxx new file mode 100644 index 000000000..ca96cf331 --- /dev/null +++ b/connectivity/source/commontools/ParameterSubstitution.cxx @@ -0,0 +1,105 @@ +/* -*- 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 +#include +#include +#include + +namespace connectivity +{ + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::sdbc; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star; + + ParameterSubstitution::ParameterSubstitution(const css::uno::Reference< css::uno::XComponentContext >& _rxContext ) : m_xContext(_rxContext) + { + } + void SAL_CALL ParameterSubstitution::initialize( const uno::Sequence< uno::Any >& _aArguments ) + { + ::osl::MutexGuard aGuard(m_aMutex); + comphelper::SequenceAsHashMap aArgs(_aArguments); + uno::Reference< sdbc::XConnection > xConnection; + xConnection = aArgs.getUnpackedValueOrDefault("ActiveConnection",xConnection); + m_xConnection = xConnection; + } + + OUString SAL_CALL ParameterSubstitution::getImplementationName( ) + { + return "org.openoffice.comp.helper.ParameterSubstitution"; + } + + sal_Bool SAL_CALL ParameterSubstitution::supportsService( const OUString& _rServiceName ) + { + return cppu::supportsService(this, _rServiceName); + } + + Sequence< OUString > SAL_CALL ParameterSubstitution::getSupportedServiceNames( ) + { + return { "com.sun.star.sdb.ParameterSubstitution" }; + } + + + OUString SAL_CALL ParameterSubstitution::substituteVariables( const OUString& _sText, sal_Bool /*bSubstRequired*/ ) + { + OUString sRet = _sText; + uno::Reference< sdbc::XConnection > xConnection = m_xConnection; + if ( xConnection.is() ) + { + try + { + OSQLParser aParser( m_xContext ); + OUString sErrorMessage; + std::unique_ptr pNode = aParser.parseTree(sErrorMessage,_sText); + if(pNode) + { // special handling for parameters + OSQLParseNode::substituteParameterNames(pNode.get()); + OUString sNewSql; + pNode->parseNodeToStr( sNewSql, xConnection ); + sRet = sNewSql; + } + } + catch(const Exception&) + { + } + } + return sRet; + } + + OUString SAL_CALL ParameterSubstitution::reSubstituteVariables( const OUString& _sText ) + { + return _sText; + } + + OUString SAL_CALL ParameterSubstitution::getSubstituteVariableValue( const OUString& /*variable*/ ) + { + throw container::NoSuchElementException(); + } + + +} // connectivity + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +connectivity_dbtools_ParameterSubstitution_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence const&) +{ + return cppu::acquire(new connectivity::ParameterSubstitution(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/commontools/RowFunctionParser.cxx b/connectivity/source/commontools/RowFunctionParser.cxx new file mode 100644 index 000000000..21f5e638a --- /dev/null +++ b/connectivity/source/commontools/RowFunctionParser.cxx @@ -0,0 +1,441 @@ +/* -*- 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 . + */ + + +// Makes parser a static resource, +// we're synchronized externally. +// But watch out, the parser might have +// state not visible to this code! +#define BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE + +#if OSL_DEBUG_LEVEL >= 2 && defined(DBG_UTIL) +#include +#define BOOST_SPIRIT_DEBUG +#endif +#include +#include +#include + + +#if (OSL_DEBUG_LEVEL > 0) +#include +#endif +#include +#include + +namespace connectivity +{ +using namespace com::sun::star; + +namespace +{ + + +// EXPRESSION NODES + + +class ConstantValueExpression : public ExpressionNode +{ + ORowSetValueDecoratorRef maValue; + +public: + + explicit ConstantValueExpression( ORowSetValueDecoratorRef const & rValue ) : + maValue( rValue ) + { + } + virtual ORowSetValueDecoratorRef evaluate(const ODatabaseMetaDataResultSet::ORow& /*_aRow*/ ) const override + { + return maValue; + } + virtual void fill(const ODatabaseMetaDataResultSet::ORow& /*_aRow*/ ) const override + { + } +}; + + +/** ExpressionNode implementation for unary + function over two ExpressionNodes + */ +class BinaryFunctionExpression : public ExpressionNode +{ + const ExpressionFunct meFunct; + std::shared_ptr mpFirstArg; + std::shared_ptr mpSecondArg; + +public: + + BinaryFunctionExpression( const ExpressionFunct eFunct, const std::shared_ptr& rFirstArg, const std::shared_ptr& rSecondArg ) : + meFunct( eFunct ), + mpFirstArg( rFirstArg ), + mpSecondArg( rSecondArg ) + { + } + virtual ORowSetValueDecoratorRef evaluate(const ODatabaseMetaDataResultSet::ORow& _aRow ) const override + { + ORowSetValueDecoratorRef aRet; + switch(meFunct) + { + case ExpressionFunct::Equation: + aRet = new ORowSetValueDecorator( mpFirstArg->evaluate(_aRow )->getValue() == mpSecondArg->evaluate(_aRow )->getValue() ); + break; + case ExpressionFunct::And: + aRet = new ORowSetValueDecorator( mpFirstArg->evaluate(_aRow )->getValue().getBool() && mpSecondArg->evaluate(_aRow )->getValue().getBool() ); + break; + case ExpressionFunct::Or: + aRet = new ORowSetValueDecorator( mpFirstArg->evaluate(_aRow )->getValue().getBool() || mpSecondArg->evaluate(_aRow )->getValue().getBool() ); + break; + default: + break; + } + return aRet; + } + virtual void fill(const ODatabaseMetaDataResultSet::ORow& _aRow ) const override + { + switch(meFunct) + { + case ExpressionFunct::Equation: + (*mpFirstArg->evaluate(_aRow )) = mpSecondArg->evaluate(_aRow )->getValue(); + break; + default: + break; + } + } +}; + + +// FUNCTION PARSER + + +typedef const char* StringIteratorT; + +struct ParserContext +{ + typedef std::stack< std::shared_ptr > OperandStack; + + // stores a stack of not-yet-evaluated operands. This is used + // by the operators (i.e. '+', '*', 'sin' etc.) to pop their + // arguments from. If all arguments to an operator are constant, + // the operator pushes a precalculated result on the stack, and + // a composite ExpressionNode otherwise. + OperandStack maOperandStack; +}; + +typedef std::shared_ptr< ParserContext > ParserContextSharedPtr; + +/** Generate apriori constant value + */ + +class ConstantFunctor +{ + ParserContextSharedPtr mpContext; + +public: + + explicit ConstantFunctor( const ParserContextSharedPtr& rContext ) : + mpContext( rContext ) + { + } + void operator()( StringIteratorT rFirst,StringIteratorT rSecond) const + { + OUString sVal( rFirst, rSecond - rFirst, RTL_TEXTENCODING_UTF8 ); + mpContext->maOperandStack.push( std::make_shared( new ORowSetValueDecorator( sVal ) ) ); + } +}; + +/** Generate parse-dependent-but-then-constant value + */ +class IntConstantFunctor +{ + ParserContextSharedPtr mpContext; + +public: + explicit IntConstantFunctor( const ParserContextSharedPtr& rContext ) : + mpContext( rContext ) + { + } + void operator()( sal_Int32 n ) const + { + mpContext->maOperandStack.push( std::make_shared( new ORowSetValueDecorator( n ) ) ); + } +}; + +/** Implements a binary function over two ExpressionNodes + + @tpl Generator + Generator functor, to generate an ExpressionNode of + appropriate type + + */ +class BinaryFunctionFunctor +{ + const ExpressionFunct meFunct; + ParserContextSharedPtr mpContext; + +public: + + BinaryFunctionFunctor( const ExpressionFunct eFunct, const ParserContextSharedPtr& rContext ) : + meFunct( eFunct ), + mpContext( rContext ) + { + } + + void operator()( StringIteratorT, StringIteratorT ) const + { + ParserContext::OperandStack& rNodeStack( mpContext->maOperandStack ); + + if( rNodeStack.size() < 2 ) + throw ParseError( "Not enough arguments for binary operator" ); + + // retrieve arguments + std::shared_ptr pSecondArg( std::move(rNodeStack.top()) ); + rNodeStack.pop(); + std::shared_ptr pFirstArg( std::move(rNodeStack.top()) ); + rNodeStack.pop(); + + // create combined ExpressionNode + auto pNode = std::make_shared( meFunct, pFirstArg, pSecondArg ); + // check for constness + rNodeStack.push( pNode ); + } +}; +/** ExpressionNode implementation for unary + function over one ExpressionNode + */ +class UnaryFunctionExpression : public ExpressionNode +{ + std::shared_ptr mpArg; + +public: + explicit UnaryFunctionExpression( const std::shared_ptr& rArg ) : + mpArg( rArg ) + { + } + virtual ORowSetValueDecoratorRef evaluate(const ODatabaseMetaDataResultSet::ORow& _aRow ) const override + { + return _aRow[mpArg->evaluate(_aRow )->getValue().getUInt32()]; + } + virtual void fill(const ODatabaseMetaDataResultSet::ORow& /*_aRow*/ ) const override + { + } +}; + +class UnaryFunctionFunctor +{ + ParserContextSharedPtr mpContext; + +public: + + explicit UnaryFunctionFunctor(const ParserContextSharedPtr& rContext) + : mpContext(rContext) + { + } + void operator()( StringIteratorT, StringIteratorT ) const + { + + ParserContext::OperandStack& rNodeStack( mpContext->maOperandStack ); + + if( rNodeStack.empty() ) + throw ParseError( "Not enough arguments for unary operator" ); + + // retrieve arguments + std::shared_ptr pArg( std::move(rNodeStack.top()) ); + rNodeStack.pop(); + + rNodeStack.push( std::make_shared( pArg ) ); + } +}; + +/* This class implements the following grammar (more or + less literally written down below, only slightly + obfuscated by the parser actions): + + basic_expression = + number | + '(' additive_expression ')' + + unary_expression = + basic_expression + + multiplicative_expression = + unary_expression ( ( '*' unary_expression )* | + ( '/' unary_expression )* ) + + additive_expression = + multiplicative_expression ( ( '+' multiplicative_expression )* | + ( '-' multiplicative_expression )* ) + + */ +class ExpressionGrammar : public ::boost::spirit::classic::grammar< ExpressionGrammar > +{ +public: + /** Create an arithmetic expression grammar + + @param rParserContext + Contains context info for the parser + */ + explicit ExpressionGrammar( const ParserContextSharedPtr& rParserContext ) : + mpParserContext( rParserContext ) + { + } + + template< typename ScannerT > class definition + { + public: + // grammar definition + explicit definition( const ExpressionGrammar& self ) + { + using ::boost::spirit::classic::space_p; + using ::boost::spirit::classic::range_p; + using ::boost::spirit::classic::lexeme_d; + using ::boost::spirit::classic::ch_p; + using ::boost::spirit::classic::int_p; + using ::boost::spirit::classic::as_lower_d; + using ::boost::spirit::classic::strlit; + using ::boost::spirit::classic::inhibit_case; + + + typedef inhibit_case > token_t; + token_t COLUMN = as_lower_d[ "column" ]; + token_t OR_ = as_lower_d[ "or" ]; + token_t AND_ = as_lower_d[ "and" ]; + + integer = + int_p + [IntConstantFunctor(self.getContext())]; + + argument = + integer + | lexeme_d[ +( range_p('a','z') | range_p('A','Z') | range_p('0','9') ) ] + [ ConstantFunctor(self.getContext()) ] + ; + + unaryFunction = + (COLUMN >> '(' >> integer >> ')' ) + [ UnaryFunctionFunctor( self.getContext()) ] + ; + + assignment = + unaryFunction >> ch_p('=') >> argument + [ BinaryFunctionFunctor( ExpressionFunct::Equation, self.getContext()) ] + ; + + andExpression = + assignment + | ( '(' >> orExpression >> ')' ) + | ( assignment >> AND_ >> assignment ) [ BinaryFunctionFunctor( ExpressionFunct::And, self.getContext()) ] + ; + + orExpression = + andExpression + | ( orExpression >> OR_ >> andExpression ) [ BinaryFunctionFunctor( ExpressionFunct::Or, self.getContext()) ] + ; + + basicExpression = + orExpression + ; + + BOOST_SPIRIT_DEBUG_RULE(basicExpression); + BOOST_SPIRIT_DEBUG_RULE(unaryFunction); + BOOST_SPIRIT_DEBUG_RULE(assignment); + BOOST_SPIRIT_DEBUG_RULE(argument); + BOOST_SPIRIT_DEBUG_RULE(integer); + BOOST_SPIRIT_DEBUG_RULE(orExpression); + BOOST_SPIRIT_DEBUG_RULE(andExpression); + } + + const ::boost::spirit::classic::rule< ScannerT >& start() const + { + return basicExpression; + } + + private: + // the constituents of the Spirit arithmetic expression grammar. + // For the sake of readability, without 'ma' prefix. + ::boost::spirit::classic::rule< ScannerT > basicExpression; + ::boost::spirit::classic::rule< ScannerT > unaryFunction; + ::boost::spirit::classic::rule< ScannerT > assignment; + ::boost::spirit::classic::rule< ScannerT > integer,argument; + ::boost::spirit::classic::rule< ScannerT > orExpression,andExpression; + }; + + const ParserContextSharedPtr& getContext() const + { + return mpParserContext; + } + +private: + ParserContextSharedPtr mpParserContext; // might get modified during parsing +}; + +const ParserContextSharedPtr& getParserContext() +{ + static ParserContextSharedPtr lcl_parserContext = std::make_shared(); + + // clear node stack (since we reuse the static object, that's + // the whole point here) + while( !lcl_parserContext->maOperandStack.empty() ) + lcl_parserContext->maOperandStack.pop(); + + return lcl_parserContext; +} + +} + +std::shared_ptr const & FunctionParser::parseFunction( const OUString& _sFunction) +{ + // TODO(Q1): Check if a combination of the RTL_UNICODETOTEXT_FLAGS_* + // gives better conversion robustness here (we might want to map space + // etc. to ASCII space here) + const OString& rAsciiFunction( + OUStringToOString( _sFunction, RTL_TEXTENCODING_ASCII_US ) ); + + StringIteratorT aStart( rAsciiFunction.getStr() ); + StringIteratorT aEnd( rAsciiFunction.getStr()+rAsciiFunction.getLength() ); + + // static parser context, because the actual + // Spirit parser is also a static object + ParserContextSharedPtr pContext = getParserContext(); + + ExpressionGrammar aExpressionGrammer( pContext ); + + const ::boost::spirit::classic::parse_info aParseInfo( + ::boost::spirit::classic::parse( aStart, + aEnd, + aExpressionGrammer, + ::boost::spirit::classic::space_p ) ); + +#if (OSL_DEBUG_LEVEL > 0) + std::cout.flush(); // needed to keep stdout and cout in sync +#endif + + // input fully congested by the parser? + if( !aParseInfo.full ) + throw ParseError( "RowFunctionParser::parseFunction(): string not fully parseable" ); + + // parser's state stack now must contain exactly _one_ ExpressionNode, + // which represents our formula. + if( pContext->maOperandStack.size() != 1 ) + throw ParseError( "RowFunctionParser::parseFunction(): incomplete or empty expression" ); + + return pContext->maOperandStack.top(); +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/commontools/TColumnsHelper.cxx b/connectivity/source/commontools/TColumnsHelper.cxx new file mode 100644 index 000000000..f81eca9f0 --- /dev/null +++ b/connectivity/source/commontools/TColumnsHelper.cxx @@ -0,0 +1,208 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include + +using namespace ::comphelper; + + +using namespace connectivity::sdbcx; +using namespace connectivity; +using namespace dbtools; +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; + +namespace connectivity +{ + class OColumnsHelperImpl + { + public: + explicit OColumnsHelperImpl(bool _bCase) + : m_aColumnInfo(_bCase) + { + } + ColumnInformationMap m_aColumnInfo; + }; +} + +OColumnsHelper::OColumnsHelper( ::cppu::OWeakObject& _rParent + ,bool _bCase + ,::osl::Mutex& _rMutex + ,const ::std::vector< OUString> &_rVector + ,bool _bUseHardRef + ) : OCollection(_rParent,_bCase,_rMutex,_rVector,false,_bUseHardRef) + ,m_pTable(nullptr) +{ +} + +OColumnsHelper::~OColumnsHelper() +{ +} + + +sdbcx::ObjectType OColumnsHelper::createObject(const OUString& _rName) +{ + OSL_ENSURE(m_pTable,"NO Table set. Error!"); + Reference xConnection = m_pTable->getConnection(); + + if ( !m_pImpl ) + m_pImpl.reset(new OColumnsHelperImpl(isCaseSensitive())); + + bool bQueryInfo = true; + bool bAutoIncrement = false; + bool bIsCurrency = false; + sal_Int32 nDataType = DataType::OTHER; + + ColumnInformationMap::const_iterator aFind = m_pImpl->m_aColumnInfo.find(_rName); + if ( aFind == m_pImpl->m_aColumnInfo.end() ) // we have to fill it + { + OUString sComposedName = ::dbtools::composeTableNameForSelect( xConnection, m_pTable ); + collectColumnInformation(xConnection,sComposedName,u"*" ,m_pImpl->m_aColumnInfo); + aFind = m_pImpl->m_aColumnInfo.find(_rName); + } + if ( aFind != m_pImpl->m_aColumnInfo.end() ) + { + bQueryInfo = false; + bAutoIncrement = aFind->second.first.first; + bIsCurrency = aFind->second.first.second; + nDataType = aFind->second.second; + } // if ( aFind != m_pImpl->m_aColumnInfo.end() ) + + sdbcx::ObjectType xRet; + const ColumnDesc* pColDesc = m_pTable->getColumnDescription(_rName); + if ( pColDesc ) + { + Reference xPr = m_pTable; + const Reference xPrimaryKeyColumns = getPrimaryKeyColumns_throw(xPr); + sal_Int32 nField11 = pColDesc->nField11; + if ( nField11 != ColumnValue::NO_NULLS && xPrimaryKeyColumns.is() && xPrimaryKeyColumns->hasByName(_rName) ) + { + nField11 = ColumnValue::NO_NULLS; + } // if ( xKeys.is() ) + ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap(); + OUString aCatalog, aSchema, aTable; + m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME)) >>= aCatalog; + m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_SCHEMANAME)) >>= aSchema; + m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)) >>= aTable; + rtl::Reference pRet = new connectivity::sdbcx::OColumn(_rName, + pColDesc->aField6, + pColDesc->sField13, + pColDesc->sField12, + nField11, + pColDesc->nField7, + pColDesc->nField9, + pColDesc->nField5, + bAutoIncrement, + false, + bIsCurrency, + isCaseSensitive(), + aCatalog, + aSchema, + aTable); + + xRet = pRet; + } + else + { + + xRet = ::dbtools::createSDBCXColumn( m_pTable, + xConnection, + _rName, + isCaseSensitive(), + bQueryInfo, + bAutoIncrement, + bIsCurrency, + nDataType); + } + return xRet; +} + + +void OColumnsHelper::impl_refresh() +{ + if ( m_pTable ) + { + m_pImpl->m_aColumnInfo.clear(); + m_pTable->refreshColumns(); + } +} + +Reference< XPropertySet > OColumnsHelper::createDescriptor() +{ + return new OColumn(true); +} + +// XAppend +sdbcx::ObjectType OColumnsHelper::appendObject( const OUString& _rForName, const Reference< XPropertySet >& descriptor ) +{ + ::osl::MutexGuard aGuard(m_rMutex); + OSL_ENSURE(m_pTable,"OColumnsHelper::appendByDescriptor: Table is null!"); + if ( !m_pTable || m_pTable->isNew() ) + return cloneDescriptor( descriptor ); + + Reference xMetaData = m_pTable->getConnection()->getMetaData(); + OUString aSql = "ALTER TABLE " + + ::dbtools::composeTableName( xMetaData, m_pTable, ::dbtools::EComposeRule::InTableDefinitions, true ) + + " ADD " + + ::dbtools::createStandardColumnPart(descriptor,m_pTable->getConnection(),nullptr,m_pTable->getTypeCreatePattern()); + + Reference< XStatement > xStmt = m_pTable->getConnection()->createStatement( ); + if ( xStmt.is() ) + { + xStmt->execute(aSql); + ::comphelper::disposeComponent(xStmt); + } + return createObject( _rForName ); +} + +// XDrop +void OColumnsHelper::dropObject(sal_Int32 /*_nPos*/, const OUString& _sElementName) +{ + OSL_ENSURE(m_pTable,"OColumnsHelper::dropByName: Table is null!"); + if ( !m_pTable || m_pTable->isNew() ) + return; + + Reference xMetaData = m_pTable->getConnection()->getMetaData(); + OUString aQuote = xMetaData->getIdentifierQuoteString( ); + OUString aSql = "ALTER TABLE " + + ::dbtools::composeTableName( xMetaData, m_pTable, ::dbtools::EComposeRule::InTableDefinitions, true ) + + " DROP " + + ::dbtools::quoteName( aQuote,_sElementName); + + Reference< XStatement > xStmt = m_pTable->getConnection()->createStatement( ); + if ( xStmt.is() ) + { + xStmt->execute(aSql); + ::comphelper::disposeComponent(xStmt); + } +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/commontools/TConnection.cxx b/connectivity/source/commontools/TConnection.cxx new file mode 100644 index 000000000..f35e8ca19 --- /dev/null +++ b/connectivity/source/commontools/TConnection.cxx @@ -0,0 +1,85 @@ +/* -*- 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 +#include +#include +#include + +using namespace connectivity; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::sdbc; +using namespace com::sun::star::beans; +using namespace ::osl; + + +OMetaConnection::OMetaConnection() + : OMetaConnection_BASE(m_aMutex) + , m_nTextEncoding(RTL_TEXTENCODING_MS_1252) +{ +} + +void OMetaConnection::disposing() +{ + ::osl::MutexGuard aGuard(m_aMutex); + m_xMetaData = WeakReference< XDatabaseMetaData>(); + for (auto const& statement : m_aStatements) + { + try + { + Reference< XInterface > xStatement( statement.get() ); + ::comphelper::disposeComponent( xStatement ); + } + catch (const DisposedException&) + { + } + } + m_aStatements.clear(); +} +//XUnoTunnel +sal_Int64 SAL_CALL OMetaConnection::getSomething( const css::uno::Sequence< sal_Int8 >& rId ) +{ + return comphelper::getSomethingImpl(rId, this); +} + +const Sequence< sal_Int8 > & OMetaConnection::getUnoTunnelId() +{ + static const comphelper::UnoIdInit implId; + return implId.getSeq(); +} + +::dbtools::OPropertyMap& OMetaConnection::getPropMap() +{ + static ::dbtools::OPropertyMap s_aPropertyNameMap; + return s_aPropertyNameMap; +} + +void OMetaConnection::throwGenericSQLException(TranslateId pErrorResourceId, const Reference< XInterface>& _xContext ) +{ + OUString sErrorMessage; + if (pErrorResourceId) + sErrorMessage = m_aResources.getResourceString(pErrorResourceId); + Reference< XInterface> xContext = _xContext; + if ( !xContext.is() ) + xContext = *this; + ::dbtools::throwGenericSQLException( sErrorMessage, xContext); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/commontools/TDatabaseMetaDataBase.cxx b/connectivity/source/commontools/TDatabaseMetaDataBase.cxx new file mode 100644 index 000000000..0e81e71cf --- /dev/null +++ b/connectivity/source/commontools/TDatabaseMetaDataBase.cxx @@ -0,0 +1,325 @@ +/* -*- 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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::sdbc; +using namespace com::sun::star::beans; +using namespace comphelper; +using namespace connectivity; + + +ODatabaseMetaDataBase::ODatabaseMetaDataBase(const Reference< XConnection >& _rxConnection,const Sequence< PropertyValue >& _rInfo) + : m_aConnectionInfo(_rInfo) + ,m_isCatalogAtStart(false,false) + ,m_sCatalogSeparator(false,OUString()) + ,m_sIdentifierQuoteString(false,OUString()) + ,m_supportsCatalogsInTableDefinitions(false,false) + ,m_supportsSchemasInTableDefinitions(false,false) + ,m_supportsCatalogsInDataManipulation(false,false) + ,m_supportsSchemasInDataManipulation(false,false) + ,m_supportsMixedCaseQuotedIdentifiers(false,false) + ,m_supportsAlterTableWithAddColumn(false,false) + ,m_supportsAlterTableWithDropColumn(false,false) + ,m_MaxStatements(false,0) + ,m_MaxTablesInSelect(false,0) + ,m_storesMixedCaseQuotedIdentifiers(false,false) + , m_xConnection(_rxConnection) +{ + osl_atomic_increment( &m_refCount ); + { + m_xListenerHelper = new OEventListenerHelper(this); + Reference xCom(m_xConnection,UNO_QUERY); + if(xCom.is()) + xCom->addEventListener(m_xListenerHelper); + } + osl_atomic_decrement( &m_refCount ); +} + +ODatabaseMetaDataBase::~ODatabaseMetaDataBase() +{ +} + + +Sequence< PropertyValue > SAL_CALL ODatabaseMetaDataBase::getConnectionInfo( ) +{ + return m_aConnectionInfo; +} + + +void SAL_CALL ODatabaseMetaDataBase::disposing( const EventObject& /*Source*/ ) +{ + // cut off all references to the connection +m_xConnection.clear(); +m_xListenerHelper.clear(); +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaDataBase::getTypeInfo( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + if ( m_aTypeInfoRows.empty() ) + { + Reference< XResultSet > xRet = impl_getTypeInfo_throw(); + Reference< XRow > xRow(xRet,UNO_QUERY); + ::comphelper::SequenceAsHashMap aMap(m_aConnectionInfo); + Sequence< Any > aTypeInfoSettings; + aTypeInfoSettings = aMap.getUnpackedValueOrDefault("TypeInfoSettings",aTypeInfoSettings); + + if ( xRow.is() ) + { + static const sal_Int32 pTypes[] = { + DataType::VARCHAR + ,DataType::INTEGER + ,DataType::INTEGER + ,DataType::VARCHAR + ,DataType::VARCHAR + ,DataType::VARCHAR + ,DataType::INTEGER + ,DataType::BOOLEAN + ,DataType::INTEGER + ,DataType::BOOLEAN + ,DataType::BOOLEAN + ,DataType::BOOLEAN + ,DataType::VARCHAR + ,DataType::INTEGER + ,DataType::INTEGER + ,DataType::INTEGER + ,DataType::INTEGER + ,DataType::INTEGER + }; + std::vector> aConditions; + if ( aTypeInfoSettings.getLength() > 1 && ((aTypeInfoSettings.getLength() % 2) == 0) ) + { + const Any* pIter = aTypeInfoSettings.getConstArray(); + const Any* pEnd = pIter + aTypeInfoSettings.getLength(); + try + { + for(;pIter != pEnd;++pIter) + aConditions.push_back(FunctionParser::parseFunction(::comphelper::getString(*pIter))); + } + catch(ParseError&) + { + ::connectivity::SharedResources aResources; + const OUString sError( aResources.getResourceString(STR_FORMULA_WRONG)); + ::dbtools::throwGenericSQLException(sError,*this); + } + } + + ::connectivity::ODatabaseMetaDataResultSet::ORows aTypeInfoRows; + while( xRet->next() ) + { + ::connectivity::ODatabaseMetaDataResultSet::ORow aRow; + aRow.push_back(ODatabaseMetaDataResultSet::getEmptyValue()); + const sal_Int32* pType = pTypes; + for (sal_Int32 i = 1; i <= sal_Int32(std::size(pTypes)); ++i,++pType) + { + ORowSetValue aValue; + aValue.fill(i,*pType,xRow); + aRow.push_back(new ORowSetValueDecorator(aValue)); + } + + std::vector>::iterator aIter = aConditions.begin(); + std::vector>::const_iterator aEnd = aConditions.end(); + for (; aIter != aEnd; ++aIter) + { + if ( (*aIter)->evaluate(aRow)->getValue().getBool() ) + { + ++aIter; + (*aIter)->fill(aRow); + } + else + ++aIter; + } + aTypeInfoRows.push_back(aRow); + } + m_aTypeInfoRows = aTypeInfoRows; + } + } + rtl::Reference<::connectivity::ODatabaseMetaDataResultSet> pResult = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eTypeInfo); + pResult->setRows(std::vector(m_aTypeInfoRows)); + return pResult; +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaDataBase::getExportedKeys( + const Any& /*catalog*/, const OUString& /*schema*/, const OUString& /*table*/ ) +{ + return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eExportedKeys ); +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaDataBase::getImportedKeys( + const Any& /*catalog*/, const OUString& /*schema*/, const OUString& /*table*/ ) +{ + return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eImportedKeys ); +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaDataBase::getPrimaryKeys( + const Any& /*catalog*/, const OUString& /*schema*/, const OUString& /*table*/ ) +{ + return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::ePrimaryKeys ); +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaDataBase::getIndexInfo( + const Any& /*catalog*/, const OUString& /*schema*/, const OUString& /*table*/, + sal_Bool /*unique*/, sal_Bool /*approximate*/ ) +{ + return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eIndexInfo ); +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaDataBase::getBestRowIdentifier( + const Any& /*catalog*/, const OUString& /*schema*/, const OUString& /*table*/, sal_Int32 /*scope*/, + sal_Bool /*nullable*/ ) +{ + return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eBestRowIdentifier ); +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaDataBase::getCrossReference( + const Any& /*primaryCatalog*/, const OUString& /*primarySchema*/, + const OUString& /*primaryTable*/, const Any& /*foreignCatalog*/, + const OUString& /*foreignSchema*/, const OUString& /*foreignTable*/ ) +{ + return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eCrossReference ); +} + +Reference< XConnection > SAL_CALL ODatabaseMetaDataBase::getConnection( ) +{ + return m_xConnection; +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaDataBase::getProcedureColumns( + const Any& /*catalog*/, const OUString& /*schemaPattern*/, + const OUString& /*procedureNamePattern*/, const OUString& /*columnNamePattern*/ ) +{ + return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eProcedureColumns ); +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaDataBase::getProcedures( + const Any& /*catalog*/, const OUString& /*schemaPattern*/, + const OUString& /*procedureNamePattern*/ ) +{ + return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eProcedures ); +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaDataBase::getVersionColumns( + const Any& /*catalog*/, const OUString& /*schema*/, const OUString& /*table*/ ) +{ + return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eVersionColumns ); +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaDataBase::getSchemas( ) +{ + return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eSchemas ); +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaDataBase::getColumnPrivileges( + const Any& /*catalog*/, const OUString& /*schema*/, const OUString& /*table*/, + const OUString& /*columnNamePattern*/ ) +{ + return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eColumnPrivileges ); +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaDataBase::getTablePrivileges( + const Any& /*catalog*/, const OUString& /*schema*/, const OUString& /*table*/) +{ + return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eTablePrivileges ); +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaDataBase::getCatalogs( ) +{ + return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eCatalogs ); +} + +OUString SAL_CALL ODatabaseMetaDataBase::getIdentifierQuoteString( ) +{ + return callImplMethod(m_sIdentifierQuoteString,std::function(&ODatabaseMetaDataBase::impl_getIdentifierQuoteString_throw)); +} + +sal_Bool SAL_CALL ODatabaseMetaDataBase::isCatalogAtStart( ) +{ + return callImplMethod(m_isCatalogAtStart,std::function(&ODatabaseMetaDataBase::impl_isCatalogAtStart_throw)); +} + +OUString SAL_CALL ODatabaseMetaDataBase::getCatalogSeparator( ) +{ + return callImplMethod(m_sCatalogSeparator,std::function(&ODatabaseMetaDataBase::impl_getCatalogSeparator_throw)); +} + +sal_Bool SAL_CALL ODatabaseMetaDataBase::supportsCatalogsInTableDefinitions( ) +{ + return callImplMethod(m_supportsCatalogsInTableDefinitions,std::function(&ODatabaseMetaDataBase::impl_supportsCatalogsInTableDefinitions_throw)); +} + +sal_Bool SAL_CALL ODatabaseMetaDataBase::supportsSchemasInTableDefinitions( ) +{ + return callImplMethod(m_supportsSchemasInTableDefinitions,std::function(&ODatabaseMetaDataBase::impl_supportsSchemasInTableDefinitions_throw)); +} + +sal_Bool SAL_CALL ODatabaseMetaDataBase::supportsCatalogsInDataManipulation( ) +{ + return callImplMethod(m_supportsCatalogsInDataManipulation,std::function(&ODatabaseMetaDataBase::impl_supportsCatalogsInDataManipulation_throw)); +} + +sal_Bool SAL_CALL ODatabaseMetaDataBase::supportsSchemasInDataManipulation( ) +{ + return callImplMethod(m_supportsSchemasInDataManipulation,std::function(&ODatabaseMetaDataBase::impl_supportsSchemasInDataManipulation_throw)); +} + +sal_Bool SAL_CALL ODatabaseMetaDataBase::supportsMixedCaseQuotedIdentifiers( ) +{ + return callImplMethod(m_supportsMixedCaseQuotedIdentifiers,std::function(&ODatabaseMetaDataBase::impl_supportsMixedCaseQuotedIdentifiers_throw)); +} + +sal_Bool SAL_CALL ODatabaseMetaDataBase::supportsAlterTableWithAddColumn( ) +{ + return callImplMethod(m_supportsAlterTableWithAddColumn,std::function(&ODatabaseMetaDataBase::impl_supportsAlterTableWithAddColumn_throw)); +} + +sal_Bool SAL_CALL ODatabaseMetaDataBase::supportsAlterTableWithDropColumn( ) +{ + return callImplMethod(m_supportsAlterTableWithDropColumn,std::function(&ODatabaseMetaDataBase::impl_supportsAlterTableWithDropColumn_throw)); +} + +sal_Int32 SAL_CALL ODatabaseMetaDataBase::getMaxStatements( ) +{ + return callImplMethod(m_MaxStatements,std::function(&ODatabaseMetaDataBase::impl_getMaxStatements_throw)); +} + +sal_Int32 SAL_CALL ODatabaseMetaDataBase::getMaxTablesInSelect( ) +{ + return callImplMethod(m_MaxTablesInSelect,std::function(&ODatabaseMetaDataBase::impl_getMaxTablesInSelect_throw)); +} + +sal_Bool SAL_CALL ODatabaseMetaDataBase::storesMixedCaseQuotedIdentifiers( ) +{ + return callImplMethod(m_storesMixedCaseQuotedIdentifiers,std::function(&ODatabaseMetaDataBase::impl_storesMixedCaseQuotedIdentifiers_throw)); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/commontools/TIndex.cxx b/connectivity/source/commontools/TIndex.cxx new file mode 100644 index 000000000..f7f891308 --- /dev/null +++ b/connectivity/source/commontools/TIndex.cxx @@ -0,0 +1,100 @@ +/* -*- 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 +#include +#include +#include +#include +#include + +using namespace connectivity; +using namespace connectivity::sdbcx; +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; + +OIndexHelper::OIndexHelper( OTableHelper* _pTable) : connectivity::sdbcx::OIndex(true) + , m_pTable(_pTable) +{ + construct(); + std::vector< OUString> aVector; + m_pColumns.reset(new OIndexColumns(this,m_aMutex,aVector)); +} + +OIndexHelper::OIndexHelper( OTableHelper* _pTable, + const OUString& Name, + const OUString& Catalog, + bool _isUnique, + bool _isPrimaryKeyIndex, + bool _isClustered + ) : connectivity::sdbcx::OIndex(Name, + Catalog, + _isUnique, + _isPrimaryKeyIndex, + _isClustered,true) + ,m_pTable(_pTable) +{ + construct(); + refreshColumns(); +} + + +void OIndexHelper::refreshColumns() +{ + if ( !m_pTable ) + return; + + std::vector< OUString> aVector; + if ( !isNew() ) + { + ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap(); + OUString aSchema,aTable; + m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_SCHEMANAME)) >>= aSchema; + m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)) >>= aTable; + + Reference< XResultSet > xResult = m_pTable->getMetaData()->getIndexInfo( + m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME)), + aSchema,aTable,false,false); + + if ( xResult.is() ) + { + Reference< XRow > xRow(xResult,UNO_QUERY); + OUString aColName; + while( xResult->next() ) + { + if ( xRow->getString(6) == m_Name ) + { + aColName = xRow->getString(9); + if ( !xRow->wasNull() ) + aVector.push_back(aColName); + } + } + } + } + if(m_pColumns) + m_pColumns->reFill(aVector); + else + m_pColumns.reset(new OIndexColumns(this,m_aMutex,aVector)); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/commontools/TIndexColumns.cxx b/connectivity/source/commontools/TIndexColumns.cxx new file mode 100644 index 000000000..1db4426c1 --- /dev/null +++ b/connectivity/source/commontools/TIndexColumns.cxx @@ -0,0 +1,114 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include + +using namespace connectivity; +using namespace connectivity::sdbcx; +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; + +OIndexColumns::OIndexColumns( OIndexHelper* _pIndex, + ::osl::Mutex& _rMutex, + const std::vector< OUString> &_rVector) + : connectivity::sdbcx::OCollection(*_pIndex,true,_rMutex,_rVector) + ,m_pIndex(_pIndex) +{ +} + +sdbcx::ObjectType OIndexColumns::createObject(const OUString& _rName) +{ + ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap(); + OUString aCatalog, aSchema, aTable; + css::uno::Any Catalog(m_pIndex->getTable()->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME))); + Catalog >>= aCatalog; + m_pIndex->getTable()->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_SCHEMANAME)) >>= aSchema; + m_pIndex->getTable()->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)) >>= aTable; + + Reference< XResultSet > xResult = m_pIndex->getTable()->getConnection()->getMetaData()->getIndexInfo( + Catalog, aSchema, aTable, false, false); + + bool bAsc = true; + if ( xResult.is() ) + { + Reference< XRow > xRow(xResult,UNO_QUERY); + while( xResult->next() ) + { + if(xRow->getString(9) == _rName) + bAsc = xRow->getString(10) != "D"; + } + } + + xResult = m_pIndex->getTable()->getConnection()->getMetaData()->getColumns( + Catalog, aSchema, aTable, _rName); + + sdbcx::ObjectType xRet; + if ( xResult.is() ) + { + Reference< XRow > xRow(xResult,UNO_QUERY); + while( xResult->next() ) + { + if ( xRow->getString(4) == _rName ) + { + sal_Int32 nDataType = xRow->getInt(5); + OUString aTypeName(xRow->getString(6)); + sal_Int32 nSize = xRow->getInt(7); + sal_Int32 nDec = xRow->getInt(9); + sal_Int32 nNull = xRow->getInt(11); + OUString aColumnDef(xRow->getString(13)); + + xRet = new OIndexColumn(bAsc, + _rName, + aTypeName, + aColumnDef, + nNull, + nSize, + nDec, + nDataType, + true, + aCatalog, aSchema, aTable); + break; + } + } + } + + return xRet; +} + +Reference< XPropertySet > OIndexColumns::createDescriptor() +{ + return new OIndexColumn(true); +} + +void OIndexColumns::impl_refresh() +{ + m_pIndex->refreshColumns(); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/commontools/TIndexes.cxx b/connectivity/source/commontools/TIndexes.cxx new file mode 100644 index 000000000..b0998b5b3 --- /dev/null +++ b/connectivity/source/commontools/TIndexes.cxx @@ -0,0 +1,247 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +using namespace connectivity; +using namespace connectivity::sdbcx; +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 cppu; + + +OIndexesHelper::OIndexesHelper(OTableHelper* _pTable, + ::osl::Mutex& _rMutex, + const std::vector< OUString> &_rVector + ) + : OCollection(*_pTable,true,_rMutex,_rVector) + ,m_pTable(_pTable) +{ +} + + +sdbcx::ObjectType OIndexesHelper::createObject(const OUString& _rName) +{ + Reference< XConnection> xConnection = m_pTable->getConnection(); + if ( !xConnection.is() ) + return nullptr; + + sdbcx::ObjectType xRet; + OUString aName,aQualifier; + sal_Int32 nLen = _rName.indexOf('.'); + if ( nLen != -1 ) + { + aQualifier = _rName.copy(0,nLen); + aName = _rName.copy(nLen+1); + } + else + aName = _rName; + + ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap(); + OUString aSchema,aTable; + m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_SCHEMANAME)) >>= aSchema; + m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)) >>= aTable; + + Any aCatalog = m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME)); + Reference< XResultSet > xResult = m_pTable->getMetaData()->getIndexInfo(aCatalog,aSchema,aTable,false,false); + + if ( xResult.is() ) + { + Reference< XRow > xRow(xResult,UNO_QUERY); + while( xResult->next() ) + { + bool bUnique = !xRow->getBoolean(4); + if((aQualifier.isEmpty() || xRow->getString(5) == aQualifier ) && xRow->getString(6) == aName) + { + sal_Int32 nClustered = xRow->getShort(7); + bool bPrimarKeyIndex = false; + xRow.clear(); + xResult.clear(); + try + { + xResult = m_pTable->getMetaData()->getPrimaryKeys(aCatalog,aSchema,aTable); + xRow.set(xResult,UNO_QUERY); + + if ( xRow.is() && xResult->next() ) // there can be only one primary key + { + bPrimarKeyIndex = xRow->getString(6) == aName; + } + } + catch(const Exception&) + { + } + xRet = new OIndexHelper(m_pTable,aName,aQualifier,bUnique, + bPrimarKeyIndex, + nClustered == IndexType::CLUSTERED); + break; + } + } + } + + return xRet; +} + +void OIndexesHelper::impl_refresh() +{ + m_pTable->refreshIndexes(); +} + +Reference< XPropertySet > OIndexesHelper::createDescriptor() +{ + return new OIndexHelper(m_pTable); +} + +// XAppend +sdbcx::ObjectType OIndexesHelper::appendObject( const OUString& _rForName, const Reference< XPropertySet >& descriptor ) +{ + Reference< XConnection> xConnection = m_pTable->getConnection(); + if ( !xConnection.is() ) + return nullptr; + if ( m_pTable->isNew() ) + return cloneDescriptor( descriptor ); + + if ( m_pTable->getIndexService().is() ) + { + m_pTable->getIndexService()->addIndex(m_pTable,descriptor); + } + else + { + ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap(); + OUStringBuffer aSql( "CREATE " ); + OUString aQuote = m_pTable->getMetaData()->getIdentifierQuoteString( ); + + if(comphelper::getBOOL(descriptor->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_ISUNIQUE)))) + aSql.append("UNIQUE "); + aSql.append("INDEX "); + + + OUString aCatalog,aSchema,aTable; + dbtools::qualifiedNameComponents(m_pTable->getMetaData(),m_pTable->getName(),aCatalog,aSchema,aTable,::dbtools::EComposeRule::InDataManipulation); + + OUString aComposedName = dbtools::composeTableName(m_pTable->getMetaData(),aCatalog,aSchema,aTable, true, ::dbtools::EComposeRule::InIndexDefinitions); + if (!_rForName.isEmpty() ) + { + aSql.append( ::dbtools::quoteName( aQuote, _rForName ) ); + aSql.append(" ON "); + aSql.append(aComposedName); + aSql.append(" ( "); + + Reference xColumnSup(descriptor,UNO_QUERY); + Reference xColumns(xColumnSup->getColumns(),UNO_QUERY); + Reference< XPropertySet > xColProp; + bool bAddIndexAppendix = ::dbtools::getBooleanDataSourceSetting( m_pTable->getConnection(), "AddIndexAppendix" ); + sal_Int32 nCount = xColumns->getCount(); + for(sal_Int32 i = 0 ; i < nCount; ++i) + { + xColProp.set(xColumns->getByIndex(i),UNO_QUERY); + aSql.append(::dbtools::quoteName( aQuote,comphelper::getString(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME))))); + + if ( bAddIndexAppendix ) + { + + aSql.appendAscii(any2bool(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_ISASCENDING))) + ? + " ASC" + : + " DESC"); + } + aSql.append(","); + } + aSql[aSql.getLength() - 1] = ')'; + } + else + { + aSql.append(aComposedName); + + Reference xColumnSup(descriptor,UNO_QUERY); + Reference xColumns(xColumnSup->getColumns(),UNO_QUERY); + Reference< XPropertySet > xColProp; + if(xColumns->getCount() != 1) + throw SQLException(); + + xColumns->getByIndex(0) >>= xColProp; + + aSql.append("."); + aSql.append(::dbtools::quoteName( aQuote,comphelper::getString(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME))))); + } + + Reference< XStatement > xStmt = m_pTable->getConnection()->createStatement( ); + if ( xStmt.is() ) + { + OUString sSql = aSql.makeStringAndClear(); + xStmt->execute(sSql); + ::comphelper::disposeComponent(xStmt); + } + } + + return createObject( _rForName ); +} + +// XDrop +void OIndexesHelper::dropObject(sal_Int32 /*_nPos*/,const OUString& _sElementName) +{ + Reference< XConnection> xConnection = m_pTable->getConnection(); + if( !xConnection.is() || m_pTable->isNew() ) + return; + + if ( m_pTable->getIndexService().is() ) + { + m_pTable->getIndexService()->dropIndex(m_pTable,_sElementName); + } + else + { + OUString aName,aSchema; + sal_Int32 nLen = _sElementName.indexOf('.'); + if(nLen != -1) + aSchema = _sElementName.copy(0,nLen); + aName = _sElementName.copy(nLen+1); + + OUString aSql( "DROP INDEX " ); + + OUString aComposedName = dbtools::composeTableName( m_pTable->getMetaData(), m_pTable, ::dbtools::EComposeRule::InIndexDefinitions, true ); + OUString sIndexName = dbtools::composeTableName( m_pTable->getMetaData(), OUString(), aSchema, aName, true, ::dbtools::EComposeRule::InIndexDefinitions ); + + aSql += sIndexName + " ON " + aComposedName; + + Reference< XStatement > xStmt = m_pTable->getConnection()->createStatement( ); + if ( xStmt.is() ) + { + xStmt->execute(aSql); + ::comphelper::disposeComponent(xStmt); + } + } +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/commontools/TKey.cxx b/connectivity/source/commontools/TKey.cxx new file mode 100644 index 000000000..1341291ab --- /dev/null +++ b/connectivity/source/commontools/TKey.cxx @@ -0,0 +1,107 @@ +/* -*- 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 +#include +#include +#include +#include +#include + +using namespace connectivity; +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; + +OTableKeyHelper::OTableKeyHelper(OTableHelper* _pTable) : connectivity::sdbcx::OKey(true) + ,m_pTable(_pTable) +{ + construct(); +} + +OTableKeyHelper::OTableKeyHelper( OTableHelper* _pTable + ,const OUString& Name + ,const std::shared_ptr& _rProps + ) : connectivity::sdbcx::OKey(Name,_rProps,true) + ,m_pTable(_pTable) +{ + construct(); + refreshColumns(); +} + +void OTableKeyHelper::refreshColumns() +{ + if ( !m_pTable ) + return; + + std::vector< OUString> aVector; + if ( !isNew() ) + { + aVector = m_aProps->m_aKeyColumnNames; + if ( aVector.empty() ) + { + ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap(); + OUString aSchema,aTable; + m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_SCHEMANAME)) >>= aSchema; + m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)) >>= aTable; + + if ( !m_Name.isEmpty() ) // foreign key + { + + Reference< XResultSet > xResult = m_pTable->getMetaData()->getImportedKeys(m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME)), + aSchema,aTable); + + if ( xResult.is() ) + { + Reference< XRow > xRow(xResult,UNO_QUERY); + while( xResult->next() ) + { + OUString aForeignKeyColumn = xRow->getString(8); + if(xRow->getString(12) == m_Name) + aVector.push_back(aForeignKeyColumn); + } + } + } + + if ( aVector.empty() ) + { + const Reference< XResultSet > xResult = m_pTable->getMetaData()->getPrimaryKeys(m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME)), + aSchema,aTable); + + if ( xResult.is() ) + { + const Reference< XRow > xRow(xResult,UNO_QUERY); + while( xResult->next() ) + aVector.push_back(xRow->getString(4)); + } // if ( xResult.is() ) + } + } + } + + + if ( m_pColumns ) + m_pColumns->reFill(aVector); + else + m_pColumns.reset(new OKeyColumnsHelper(this,m_aMutex,aVector)); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/commontools/TKeyColumns.cxx b/connectivity/source/commontools/TKeyColumns.cxx new file mode 100644 index 000000000..0a2c02bb2 --- /dev/null +++ b/connectivity/source/commontools/TKeyColumns.cxx @@ -0,0 +1,132 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include + +using namespace connectivity; +using namespace connectivity::sdbcx; +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; + + +OKeyColumnsHelper::OKeyColumnsHelper( OTableKeyHelper* _pKey, + ::osl::Mutex& _rMutex, + const std::vector< OUString> &_rVector) + : connectivity::sdbcx::OCollection(*_pKey,true,_rMutex,_rVector) + ,m_pKey(_pKey) +{ +} + +sdbcx::ObjectType OKeyColumnsHelper::createObject(const OUString& _rName) +{ + ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap(); + OUString aCatalog, aSchema, aTable; + css::uno::Any Catalog(m_pKey->getTable()->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME))); + Catalog >>= aCatalog; + m_pKey->getTable()->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_SCHEMANAME)) >>= aSchema; + m_pKey->getTable()->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)) >>= aTable; + + // first get the related column to _rName + Reference< XResultSet > xResult = m_pKey->getTable()->getMetaData()->getImportedKeys( + Catalog, aSchema, aTable); + + OUString aRefColumnName; + if ( xResult.is() ) + { + Reference< XRow > xRow(xResult,UNO_QUERY); + OUString aTemp; + while(xResult->next()) + { + aTemp = xRow->getString(4); + if(xRow->getString(8) == _rName && m_pKey->getName() == xRow->getString(12)) + { + aRefColumnName = aTemp; + break; + } + } + } + + sdbcx::ObjectType xRet; + + // now describe the column _rName and set his related column + xResult = m_pKey->getTable()->getMetaData()->getColumns(Catalog, aSchema, aTable, _rName); + + if ( xResult.is() ) + { + Reference< XRow > xRow(xResult,UNO_QUERY); + if ( xResult->next() ) + { + if ( xRow->getString(4) == _rName ) + { + sal_Int32 nDataType = xRow->getInt(5); + OUString aTypeName(xRow->getString(6)); + sal_Int32 nSize = xRow->getInt(7); + sal_Int32 nDec = xRow->getInt(9); + sal_Int32 nNull = xRow->getInt(11); + OUString sColumnDef; + try + { + sColumnDef = xRow->getString(13); + } + catch(const SQLException&) + { + // sometimes we get an error when asking for this param + } + + xRet = new OKeyColumn(aRefColumnName, + _rName, + aTypeName, + sColumnDef, + nNull, + nSize, + nDec, + nDataType, + isCaseSensitive(), + aCatalog, + aSchema, + aTable); + } + } + } + + return xRet; +} + +Reference< XPropertySet > OKeyColumnsHelper::createDescriptor() +{ + return new OKeyColumn(isCaseSensitive()); +} + +void OKeyColumnsHelper::impl_refresh() +{ + m_pKey->refreshColumns(); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/commontools/TKeys.cxx b/connectivity/source/commontools/TKeys.cxx new file mode 100644 index 000000000..1a73a349b --- /dev/null +++ b/connectivity/source/commontools/TKeys.cxx @@ -0,0 +1,309 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace connectivity +{ +using namespace comphelper; +using namespace connectivity::sdbcx; +using namespace dbtools; +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; + + +OKeysHelper::OKeysHelper( OTableHelper* _pTable, + ::osl::Mutex& _rMutex, + const ::std::vector< OUString>& _rVector + ) : OKeys_BASE(*_pTable,true,_rMutex,_rVector,true) + ,m_pTable(_pTable) +{ +} + +sdbcx::ObjectType OKeysHelper::createObject(const OUString& _rName) +{ + sdbcx::ObjectType xRet; + + if(!_rName.isEmpty()) + { + xRet = new OTableKeyHelper(m_pTable,_rName,m_pTable->getKeyProperties(_rName)); + } + + if(!xRet.is()) // we have a primary key with a system name + { + xRet = new OTableKeyHelper(m_pTable,_rName,m_pTable->getKeyProperties(_rName)); + } + + return xRet; +} + +void OKeysHelper::impl_refresh() +{ + m_pTable->refreshKeys(); +} + +Reference< XPropertySet > OKeysHelper::createDescriptor() +{ + return new OTableKeyHelper(m_pTable); +} + +/** returns the keyrule string for the primary key +*/ +static OUString getKeyRuleString(bool _bUpdate,sal_Int32 _nKeyRule) +{ + const char* pKeyRule = nullptr; + switch ( _nKeyRule ) + { + case KeyRule::CASCADE: + pKeyRule = _bUpdate ? " ON UPDATE CASCADE " : " ON DELETE CASCADE "; + break; + case KeyRule::RESTRICT: + pKeyRule = _bUpdate ? " ON UPDATE RESTRICT " : " ON DELETE RESTRICT "; + break; + case KeyRule::SET_NULL: + pKeyRule = _bUpdate ? " ON UPDATE SET NULL " : " ON DELETE SET NULL "; + break; + case KeyRule::SET_DEFAULT: + pKeyRule = _bUpdate ? " ON UPDATE SET DEFAULT " : " ON DELETE SET DEFAULT "; + break; + default: + ; + } + OUString sRet; + if ( pKeyRule ) + sRet = OUString::createFromAscii(pKeyRule); + return sRet; +} + +void OKeysHelper::cloneDescriptorColumns( const sdbcx::ObjectType& _rSourceDescriptor, const sdbcx::ObjectType& _rDestDescriptor ) +{ + Reference< XColumnsSupplier > xColSupp( _rSourceDescriptor, UNO_QUERY_THROW ); + Reference< XIndexAccess > xSourceCols( xColSupp->getColumns(), UNO_QUERY_THROW ); + + xColSupp.set( _rDestDescriptor, UNO_QUERY_THROW ); + Reference< XAppend > xDestAppend( xColSupp->getColumns(), UNO_QUERY_THROW ); + + sal_Int32 nCount = xSourceCols->getCount(); + for ( sal_Int32 i=0; i< nCount; ++i ) + { + Reference< XPropertySet > xColProp( xSourceCols->getByIndex(i), UNO_QUERY ); + xDestAppend->appendByDescriptor( xColProp ); + } +} + +// XAppend +sdbcx::ObjectType OKeysHelper::appendObject( const OUString& _rForName, const Reference< XPropertySet >& descriptor ) +{ + Reference< XConnection> xConnection = m_pTable->getConnection(); + if ( !xConnection.is() ) + return nullptr; + if ( m_pTable->isNew() ) + { + Reference< XPropertySet > xNewDescriptor( cloneDescriptor( descriptor ) ); + cloneDescriptorColumns( descriptor, xNewDescriptor ); + return xNewDescriptor; + } + + const ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap(); + sal_Int32 nKeyType = getINT32(descriptor->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_TYPE))); + sal_Int32 nUpdateRule = 0, nDeleteRule = 0; + OUString sReferencedName; + + if ( nKeyType == KeyType::FOREIGN ) + { + descriptor->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_REFERENCEDTABLE)) >>= sReferencedName; + descriptor->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_UPDATERULE)) >>= nUpdateRule; + descriptor->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_DELETERULE)) >>= nDeleteRule; + } + + if ( m_pTable->getKeyService().is() ) + { + m_pTable->getKeyService()->addKey(m_pTable,descriptor); + } + else + { + // if we're here, we belong to a table which is not new, i.e. already exists in the database. + // In this case, really append the new index. + OUStringBuffer aSql; + aSql.append("ALTER TABLE "); + OUString aQuote = m_pTable->getConnection()->getMetaData()->getIdentifierQuoteString( ); + + aSql.append(composeTableName( m_pTable->getConnection()->getMetaData(), m_pTable, ::dbtools::EComposeRule::InTableDefinitions, true )); + aSql.append(" ADD "); + + if ( nKeyType == KeyType::PRIMARY ) + { + aSql.append(" PRIMARY KEY ("); + } + else if ( nKeyType == KeyType::FOREIGN ) + { + aSql.append(" FOREIGN KEY ("); + } + else + throw SQLException(); + + Reference xColumnSup(descriptor,UNO_QUERY); + Reference xColumns(xColumnSup->getColumns(),UNO_QUERY); + Reference< XPropertySet > xColProp; + for(sal_Int32 i = 0 ; i < xColumns->getCount() ; ++i) + { + if ( i > 0 ) + aSql.append(","); + xColProp.set(xColumns->getByIndex(i), css::uno::UNO_QUERY); + aSql.append( ::dbtools::quoteName( aQuote,getString(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)))) ); + + } + aSql.append(")"); + + if ( nKeyType == KeyType::FOREIGN ) + { + aSql.append(" REFERENCES "); + aSql.append(::dbtools::quoteTableName(m_pTable->getConnection()->getMetaData(),sReferencedName,::dbtools::EComposeRule::InTableDefinitions)); + aSql.append(" ("); + + for(sal_Int32 i=0;igetCount();++i) + { + if ( i > 0 ) + aSql.append(","); + xColumns->getByIndex(i) >>= xColProp; + aSql.append(::dbtools::quoteName( aQuote,getString(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_RELATEDCOLUMN))))); + + } + aSql.append(")"); + aSql.append(getKeyRuleString(true ,nUpdateRule)); + aSql.append(getKeyRuleString(false ,nDeleteRule)); + } + + Reference< XStatement > xStmt = m_pTable->getConnection()->createStatement( ); + xStmt->execute(aSql.makeStringAndClear()); + } + // find the name which the database gave the new key + OUString sNewName( _rForName ); + try + { + OUString aSchema,aTable; + m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_SCHEMANAME)) >>= aSchema; + m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)) >>= aTable; + Reference< XResultSet > xResult; + sal_Int32 nColumn = 12; + if ( nKeyType == KeyType::FOREIGN ) + xResult = m_pTable->getMetaData()->getImportedKeys( m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME)) + ,aSchema + ,aTable); + else + { + xResult = m_pTable->getMetaData()->getPrimaryKeys( m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME)) + ,aSchema + ,aTable); + nColumn = 6; + } + if ( xResult.is() ) + { + Reference< XRow > xRow(xResult,UNO_QUERY); + while( xResult->next() ) + { + OUString sName = xRow->getString(nColumn); + if ( !m_pElements->exists(sName) ) // this name wasn't inserted yet so it must be the new one + { + descriptor->setPropertyValue( rPropMap.getNameByIndex( PROPERTY_ID_NAME ), Any( sName ) ); + sNewName = sName; + break; + } + } + ::comphelper::disposeComponent(xResult); + } + } + catch(const SQLException&) + { + } + + m_pTable->addKey(sNewName,std::make_shared(sReferencedName,nKeyType,nUpdateRule,nDeleteRule)); + + return createObject( sNewName ); +} + +OUString OKeysHelper::getDropForeignKey() const +{ + return " DROP CONSTRAINT "; +} + +// XDrop +void OKeysHelper::dropObject(sal_Int32 _nPos, const OUString& _sElementName) +{ + Reference< XConnection> xConnection = m_pTable->getConnection(); + if ( !xConnection.is() || m_pTable->isNew() ) + return; + + Reference xKey(getObject(_nPos),UNO_QUERY); + if ( m_pTable->getKeyService().is() ) + { + m_pTable->getKeyService()->dropKey(m_pTable,xKey); + } + else + { + OUStringBuffer aSql; + aSql.append("ALTER TABLE "); + + aSql.append( composeTableName( m_pTable->getConnection()->getMetaData(), m_pTable,::dbtools::EComposeRule::InTableDefinitions, true )); + + sal_Int32 nKeyType = KeyType::PRIMARY; + if ( xKey.is() ) + { + ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap(); + xKey->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_TYPE)) >>= nKeyType; + } + if ( KeyType::PRIMARY == nKeyType ) + { + aSql.append(" DROP PRIMARY KEY"); + } + else + { + aSql.append(getDropForeignKey()); + const OUString aQuote = m_pTable->getConnection()->getMetaData()->getIdentifierQuoteString(); + aSql.append( ::dbtools::quoteName( aQuote,_sElementName) ); + } + + Reference< XStatement > xStmt = m_pTable->getConnection()->createStatement( ); + if ( xStmt.is() ) + { + xStmt->execute(aSql.makeStringAndClear()); + ::comphelper::disposeComponent(xStmt); + } + } +} + +} // namespace connectivity + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/commontools/TPrivilegesResultSet.cxx b/connectivity/source/commontools/TPrivilegesResultSet.cxx new file mode 100644 index 000000000..928e9c016 --- /dev/null +++ b/connectivity/source/commontools/TPrivilegesResultSet.cxx @@ -0,0 +1,140 @@ +/* -*- 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 + +using namespace connectivity; + +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; + +OResultSetPrivileges::OResultSetPrivileges( const Reference< XDatabaseMetaData>& _rxMeta + , const Any& catalog + , const OUString& schemaPattern + , const OUString& tableNamePattern) + : ODatabaseMetaDataResultSet(eTablePrivileges) + , m_bResetValues(true) +{ + osl_atomic_increment( &m_refCount ); + { + OUString sUserWorkingFor; + // we want all catalogues, all schemas, all tables + Sequence< OUString > sTableTypes {"VIEW", "TABLE", "%"}; // this last one is just to be sure to include anything else... + try + { + m_xTables = _rxMeta->getTables(catalog,schemaPattern,tableNamePattern,sTableTypes); + m_xRow.set(m_xTables,UNO_QUERY); + + sUserWorkingFor = _rxMeta->getUserName(); + } + catch(Exception&) + { + } + + ODatabaseMetaDataResultSet::ORows aRows; + ODatabaseMetaDataResultSet::ORow aRow(8); + aRow[5] = new ORowSetValueDecorator(sUserWorkingFor); + aRow[6] = ODatabaseMetaDataResultSet::getSelectValue(); + aRow[7] = new ORowSetValueDecorator(OUString("YES")); + aRows.push_back(aRow); + aRow[6] = ODatabaseMetaDataResultSet::getInsertValue(); + aRows.push_back(aRow); + aRow[6] = ODatabaseMetaDataResultSet::getDeleteValue(); + aRows.push_back(aRow); + aRow[6] = ODatabaseMetaDataResultSet::getUpdateValue(); + aRows.push_back(aRow); + aRow[6] = ODatabaseMetaDataResultSet::getCreateValue(); + aRows.push_back(aRow); + aRow[6] = ODatabaseMetaDataResultSet::getReadValue(); + aRows.push_back(aRow); + aRow[6] = ODatabaseMetaDataResultSet::getAlterValue(); + aRows.push_back(aRow); + aRow[6] = ODatabaseMetaDataResultSet::getDropValue(); + aRows.push_back(aRow); + aRow[6] = new ORowSetValueDecorator(OUString("REFERENCE")); + aRows.push_back(aRow); + + setRows(std::move(aRows)); + } + osl_atomic_decrement( &m_refCount ); +} + +const ORowSetValue& OResultSetPrivileges::getValue(sal_Int32 columnIndex) +{ + switch(columnIndex) + { + case 1: + case 2: + case 3: + if ( m_xRow.is() && m_bResetValues ) + { + (*m_aRowsIter)[1] = new ORowSetValueDecorator(m_xRow->getString(1)); + if ( m_xRow->wasNull() ) + (*m_aRowsIter)[1]->setNull(); + (*m_aRowsIter)[2] = new ORowSetValueDecorator(m_xRow->getString(2)); + if ( m_xRow->wasNull() ) + (*m_aRowsIter)[2]->setNull(); + (*m_aRowsIter)[3] = new ORowSetValueDecorator(m_xRow->getString(3)); + if ( m_xRow->wasNull() ) + (*m_aRowsIter)[3]->setNull(); + + m_bResetValues = false; + } + } + return ODatabaseMetaDataResultSet::getValue(columnIndex); +} + +void SAL_CALL OResultSetPrivileges::disposing() +{ + ODatabaseMetaDataResultSet::disposing(); + m_xTables.clear(); + m_xRow.clear(); +} + +sal_Bool SAL_CALL OResultSetPrivileges::next( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed ); + + bool bReturn = false; + if ( m_xTables.is() ) + { + if ( m_bBOF ) + { + m_bResetValues = true; + if ( !m_xTables->next() ) + return false; + } + + bReturn = ODatabaseMetaDataResultSet::next(); + if ( !bReturn ) + { + m_bBOF = false; + m_bResetValues = bReturn = m_xTables->next(); + } + } + return bReturn; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/commontools/TSkipDeletedSet.cxx b/connectivity/source/commontools/TSkipDeletedSet.cxx new file mode 100644 index 000000000..701bd743f --- /dev/null +++ b/connectivity/source/commontools/TSkipDeletedSet.cxx @@ -0,0 +1,255 @@ +/* -*- 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 +#include +#include +#include + +using namespace connectivity; + +OSkipDeletedSet::OSkipDeletedSet(IResultSetHelper* _pHelper) + : m_pHelper(_pHelper) + ,m_bDeletedVisible(false) +{ + m_aBookmarksPositions.reserve(256); +} + +OSkipDeletedSet::~OSkipDeletedSet() +{ + m_aBookmarksPositions.clear(); + //m_aBookmarks.clear(); +} + +bool OSkipDeletedSet::skipDeleted(IResultSetHelper::Movement _eCursorPosition, sal_Int32 _nOffset, bool _bRetrieveData) +{ + OSL_ENSURE(_eCursorPosition != IResultSetHelper::BOOKMARK,"OSkipDeletedSet::SkipDeleted can't be called for BOOKMARK"); + + IResultSetHelper::Movement eDelPosition = _eCursorPosition; + sal_Int32 nDelOffset = abs(_nOffset); + + switch (_eCursorPosition) + { + case IResultSetHelper::ABSOLUTE1: + return moveAbsolute(_nOffset,_bRetrieveData); + case IResultSetHelper::FIRST: // set the movement when positioning failed + eDelPosition = IResultSetHelper::NEXT; + nDelOffset = 1; + break; + case IResultSetHelper::LAST: + eDelPosition = IResultSetHelper::PRIOR; // last row is invalid so position before + nDelOffset = 1; + break; + case IResultSetHelper::RELATIVE1: + eDelPosition = (_nOffset >= 0) ? IResultSetHelper::NEXT : IResultSetHelper::PRIOR; + break; + default: + break; + } + + bool bDone = true; + bool bDataFound = false; + + if (_eCursorPosition == IResultSetHelper::LAST) + { + SAL_INFO( "connectivity.commontools", "OSkipDeletedSet::skipDeleted: last" ); + sal_Int32 nBookmark = 0; + // first position on the last known row + if ( m_aBookmarksPositions.empty() ) + { + bDataFound = m_pHelper->move(IResultSetHelper::FIRST, 0, _bRetrieveData); + if(bDataFound && (m_bDeletedVisible || !m_pHelper->isRowDeleted())) + //m_aBookmarksPositions.push_back(m_aBookmarks.emplace( m_pHelper->getDriverPos(),m_aBookmarksPositions.size()+1)).first); + m_aBookmarksPositions.push_back(m_pHelper->getDriverPos()); + } + else + { + // I already have a bookmark so we can positioned on that and look if it is the last one + nBookmark = (*m_aBookmarksPositions.rbegin())/*->first*/; + + bDataFound = m_pHelper->move(IResultSetHelper::BOOKMARK, nBookmark, _bRetrieveData); + OSL_ENSURE((m_bDeletedVisible || !m_pHelper->isRowDeleted()),"A bookmark should not be deleted!"); + } + + + // and then move forward until we are after the last row + while(bDataFound) + { + bDataFound = m_pHelper->move(IResultSetHelper::NEXT, 1, false); // we don't need the data here + if( bDataFound && ( m_bDeletedVisible || !m_pHelper->isRowDeleted()) ) + { // we weren't on the last row we remember it and move on + m_aBookmarksPositions.push_back(m_pHelper->getDriverPos()); + //m_aBookmarksPositions.push_back(m_aBookmarks.emplace( m_pHelper->getDriverPos(),m_aBookmarksPositions.size()+1)).first); + } + else if(!bDataFound && !m_aBookmarksPositions.empty() ) + { + // i already know the last bookmark :-) + // now we only have to repositioning us to the last row + nBookmark = (*m_aBookmarksPositions.rbegin())/*->first*/; + bDataFound = m_pHelper->move(IResultSetHelper::BOOKMARK, nBookmark, _bRetrieveData); + break; + } + } + return bDataFound; + } + else if (_eCursorPosition != IResultSetHelper::RELATIVE1) + { + bDataFound = m_pHelper->move(_eCursorPosition, _nOffset, _bRetrieveData); + bDone = bDataFound && (m_bDeletedVisible || !m_pHelper->isRowDeleted()); + } + else + { + bDataFound = m_pHelper->move(eDelPosition, 1, _bRetrieveData); + if (bDataFound && (m_bDeletedVisible || !m_pHelper->isRowDeleted())) + { + bDone = (--nDelOffset) == 0; + if ( !bDone ) + m_aBookmarksPositions.push_back(m_pHelper->getDriverPos()); + //m_aBookmarksPositions.push_back(m_aBookmarks.emplace( m_pHelper->getDriverPos(),m_aBookmarksPositions.size()+1)).first); + } + else + bDone = false; + } + + while (bDataFound && !bDone) // Iterate until we are at the valid set + { + bDataFound = m_pHelper->move(eDelPosition, 1, _bRetrieveData); + if (_eCursorPosition != IResultSetHelper::RELATIVE1) + bDone = bDataFound && (m_bDeletedVisible || !m_pHelper->isRowDeleted()); + else if (bDataFound && (m_bDeletedVisible || !m_pHelper->isRowDeleted())) + { + bDone = (--nDelOffset) == 0; + if ( !bDone ) + m_aBookmarksPositions.push_back(m_pHelper->getDriverPos()); + //m_aBookmarksPositions.push_back(m_aBookmarks.emplace( m_pHelper->getDriverPos(),m_aBookmarksPositions.size()+1)).first); + } + else + bDone = false; + } + + if(bDataFound && bDone) + { + const sal_Int32 nDriverPos = m_pHelper->getDriverPos(); + if ( m_bDeletedVisible ) + { + if ( nDriverPos > static_cast(m_aBookmarksPositions.size()) ) + m_aBookmarksPositions.push_back(nDriverPos); + } + else if ( std::find(m_aBookmarksPositions.begin(),m_aBookmarksPositions.end(),nDriverPos) == m_aBookmarksPositions.end() ) + m_aBookmarksPositions.push_back(nDriverPos); + /*sal_Int32 nDriverPos = m_pHelper->getDriverPos(); + if(m_aBookmarks.find(nDriverPos) == m_aBookmarks.end()) + m_aBookmarksPositions.push_back(m_aBookmarks.emplace( nDriverPos,m_aBookmarksPositions.size()+1)).first);*/ + } + + return bDataFound; +} + +bool OSkipDeletedSet::moveAbsolute(sal_Int32 _nPos,bool _bRetrieveData) +{ + bool bDataFound = false; + sal_Int32 nNewPos = _nPos; + if(nNewPos > 0) + { + if(static_cast(m_aBookmarksPositions.size()) < nNewPos) + { + // bookmark isn't known yet + // start at the last known position + sal_Int32 nCurPos = 0; + if ( m_aBookmarksPositions.empty() ) + { + bDataFound = m_pHelper->move(IResultSetHelper::FIRST, 0, _bRetrieveData ); + if(bDataFound && (m_bDeletedVisible || !m_pHelper->isRowDeleted())) + { + ++nCurPos; + m_aBookmarksPositions.push_back(m_pHelper->getDriverPos()); + //m_aBookmarksPositions.push_back(m_aBookmarks.emplace( m_pHelper->getDriverPos(),m_aBookmarksPositions.size()+1)).first); + --nNewPos; + } + } // if ( m_aBookmarksPositions.empty() ) + else + { + sal_Int32 nLastBookmark = *m_aBookmarksPositions.rbegin()/*->first*/; + nCurPos = /*(**/m_aBookmarksPositions.size()/*->second*/; + nNewPos = nNewPos - nCurPos; + bDataFound = m_pHelper->move(IResultSetHelper::BOOKMARK, nLastBookmark, _bRetrieveData); + } + + // now move to that row we need and don't count deleted rows + while (bDataFound && nNewPos) + { + bDataFound = m_pHelper->move(IResultSetHelper::NEXT, 1, _bRetrieveData); + if(bDataFound && (m_bDeletedVisible || !m_pHelper->isRowDeleted())) + { + ++nCurPos; + m_aBookmarksPositions.push_back(m_pHelper->getDriverPos()); + //m_aBookmarksPositions.push_back(m_aBookmarks.emplace( m_pHelper->getDriverPos(),m_aBookmarksPositions.size()+1)).first); + --nNewPos; + } + } + } + else + { + const sal_Int32 nBookmark = m_aBookmarksPositions[nNewPos-1]/*->first*/; + bDataFound = m_pHelper->move(IResultSetHelper::BOOKMARK,nBookmark, _bRetrieveData); + OSL_ENSURE((m_bDeletedVisible || !m_pHelper->isRowDeleted()),"moveAbsolute: row can't be deleted!"); + } + } + else + { + ++nNewPos; + bDataFound = skipDeleted(IResultSetHelper::LAST,0,nNewPos == 0); + + for(sal_Int32 i=nNewPos+1;bDataFound && i <= 0;++i) + bDataFound = skipDeleted(IResultSetHelper::PRIOR,1,i == 0); + + } + return bDataFound; +} + +void OSkipDeletedSet::clear() +{ + std::vector().swap(m_aBookmarksPositions); +} + +sal_Int32 OSkipDeletedSet::getMappedPosition(sal_Int32 _nPos) const +{ + std::vector::const_iterator aFind = std::find(m_aBookmarksPositions.begin(),m_aBookmarksPositions.end(),_nPos); + if ( aFind != m_aBookmarksPositions.end() ) + return (aFind - m_aBookmarksPositions.begin()) + 1; + OSL_FAIL("Why!"); + return -1; +} + +void OSkipDeletedSet::insertNewPosition(sal_Int32 _nPos) +{ + m_aBookmarksPositions.push_back(_nPos); +} + +void OSkipDeletedSet::deletePosition(sal_Int32 _nBookmark) +{ + std::vector::iterator aFind = std::find(m_aBookmarksPositions.begin(),m_aBookmarksPositions.end(),_nBookmark); + if ( aFind != m_aBookmarksPositions.end() ) + { + m_aBookmarksPositions.erase(aFind); + } +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/commontools/TSortIndex.cxx b/connectivity/source/commontools/TSortIndex.cxx new file mode 100644 index 000000000..44a883dc8 --- /dev/null +++ b/connectivity/source/commontools/TSortIndex.cxx @@ -0,0 +1,152 @@ +/* -*- 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 +#include +#include +#include + +using namespace connectivity; + +namespace { + +/// Functor object for class OSortIndex::TIntValuePairVector::value_type returntype is bool +struct TKeyValueFunc +{ + OSortIndex* pIndex; + + explicit TKeyValueFunc(OSortIndex* _pIndex) : pIndex(_pIndex) + { + } + // return false if compared values are equal otherwise true + bool operator()(const OSortIndex::TIntValuePairVector::value_type& lhs,const OSortIndex::TIntValuePairVector::value_type& rhs) const + { + const std::vector& aKeyType = pIndex->getKeyType(); + size_t i = 0; + for (auto const& elem : aKeyType) + { + const bool bGreater = pIndex->getAscending(i) != TAscendingOrder::ASC; + const bool bLess = !bGreater; + + // compare depending for type + switch (elem) + { + case OKeyType::String: + { + sal_Int32 nRes = lhs.second->getKeyString(i).compareTo(rhs.second->getKeyString(i)); + if (nRes < 0) + return bLess; + else if (nRes > 0) + return bGreater; + } + break; + case OKeyType::Double: + { + double d1 = lhs.second->getKeyDouble(i); + double d2 = rhs.second->getKeyDouble(i); + + if (d1 < d2) + return bLess; + else if (d1 > d2) + return bGreater; + } + break; + case OKeyType::NONE: + break; + } + ++i; + } + + // know we know that the values are equal + return false; + } +}; + +} + +::rtl::Reference OSortIndex::CreateKeySet() +{ + Freeze(); + + ::rtl::Reference pKeySet = new OKeySet(); + pKeySet->reserve(m_aKeyValues.size()); + std::transform(m_aKeyValues.begin() + ,m_aKeyValues.end() + ,std::back_inserter(*pKeySet) + ,::o3tl::select1st()); + pKeySet->setFrozen(); + return pKeySet; +} + +OSortIndex::OSortIndex( std::vector&& _aKeyType, + std::vector&& _aAscending) + :m_aKeyType(std::move(_aKeyType)) + ,m_aAscending(std::move(_aAscending)) + ,m_bFrozen(false) +{ +} + +OSortIndex::~OSortIndex() +{ +} + +void OSortIndex::AddKeyValue(std::unique_ptr pKeyValue) +{ + assert(pKeyValue && "Can not be null here!"); + if(m_bFrozen) + { + m_aKeyValues.push_back({pKeyValue->getValue(),nullptr}); + } + else + m_aKeyValues.push_back({pKeyValue->getValue(),std::move(pKeyValue)}); +} + +void OSortIndex::Freeze() +{ + OSL_ENSURE(! m_bFrozen,"OSortIndex::Freeze: already frozen!"); + // sorting: + if (m_aKeyType[0] != OKeyType::NONE) + // we will sort ourself when the first keyType say so + std::sort(m_aKeyValues.begin(),m_aKeyValues.end(),TKeyValueFunc(this)); + + for (auto & keyValue : m_aKeyValues) + { + keyValue.second.reset(); + } + + m_bFrozen = true; +} + + +OKeyValue::OKeyValue(sal_Int32 nVal) +: m_nValue(nVal) +{ +} + +OKeyValue::~OKeyValue() +{ +} + +std::unique_ptr OKeyValue::createKeyValue(sal_Int32 _nVal) +{ + return std::unique_ptr(new OKeyValue(_nVal)); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/commontools/TTableHelper.cxx b/connectivity/source/commontools/TTableHelper.cxx new file mode 100644 index 000000000..31e240469 --- /dev/null +++ b/connectivity/source/commontools/TTableHelper.cxx @@ -0,0 +1,610 @@ +/* -*- 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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +using namespace ::comphelper; +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; + +namespace +{ + /// helper class for column property change events which holds the OComponentDefinition weak +class OTableContainerListener: + public ::cppu::WeakImplHelper< XContainerListener > +{ + OTableHelper* m_pComponent; + std::map< OUString,bool> m_aRefNames; + +protected: + virtual ~OTableContainerListener() override {} +public: + explicit OTableContainerListener(OTableHelper* _pComponent) : m_pComponent(_pComponent){} + // noncopyable + OTableContainerListener(const OTableContainerListener&) = delete; + const OTableContainerListener& operator=(const OTableContainerListener&) = delete; + virtual void SAL_CALL elementInserted( const css::container::ContainerEvent& /*Event*/ ) override + { + } + virtual void SAL_CALL elementRemoved( const css::container::ContainerEvent& Event ) override + { + // tdf#137745, perhaps connectivity::OTableHelper::disposing() has been called + // which called OTableContainerListener::clear(), so m_pComponent may be null + if (m_pComponent == nullptr) + return; + + OUString sName; + Event.Accessor >>= sName; + if ( m_aRefNames.find(sName) != m_aRefNames.end() ) + m_pComponent->refreshKeys(); + } + virtual void SAL_CALL elementReplaced( const css::container::ContainerEvent& Event ) override + { + OUString sOldComposedName,sNewComposedName; + Event.ReplacedElement >>= sOldComposedName; + Event.Accessor >>= sNewComposedName; + if ( sOldComposedName != sNewComposedName && m_aRefNames.find(sOldComposedName) != m_aRefNames.end() ) + m_pComponent->refreshKeys(); + } + // XEventListener + virtual void SAL_CALL disposing( const EventObject& /*_rSource*/ ) override + { + } + void clear() { m_pComponent = nullptr; } + void add(const OUString& _sRefName) { m_aRefNames.emplace(_sRefName,true); } +}; +} +namespace connectivity +{ + static OUString lcl_getServiceNameForSetting(const Reference< css::sdbc::XConnection >& _xConnection,const OUString& i_sSetting) + { + OUString sSupportService; + Any aValue; + if ( ::dbtools::getDataSourceSetting(_xConnection,i_sSetting,aValue) ) + { + aValue >>= sSupportService; + } + return sSupportService; + } + struct OTableHelperImpl + { + TKeyMap m_aKeys; + // helper services which can be provided by extensions + Reference< css::sdb::tools::XTableRename> m_xRename; + Reference< css::sdb::tools::XTableAlteration> m_xAlter; + Reference< css::sdb::tools::XKeyAlteration> m_xKeyAlter; + Reference< css::sdb::tools::XIndexAlteration> m_xIndexAlter; + + Reference< css::sdbc::XDatabaseMetaData > m_xMetaData; + Reference< css::sdbc::XConnection > m_xConnection; + rtl::Reference m_xTablePropertyListener; + std::vector< ColumnDesc > m_aColumnDesc; + explicit OTableHelperImpl(const Reference< css::sdbc::XConnection >& _xConnection) + : m_xConnection(_xConnection) + { + try + { + m_xMetaData = m_xConnection->getMetaData(); + Reference xFac(_xConnection,UNO_QUERY); + if ( xFac.is() ) + { + m_xRename.set(xFac->createInstance(lcl_getServiceNameForSetting(m_xConnection,"TableRenameServiceName")),UNO_QUERY); + m_xAlter.set(xFac->createInstance(lcl_getServiceNameForSetting(m_xConnection,"TableAlterationServiceName")),UNO_QUERY); + m_xKeyAlter.set(xFac->createInstance(lcl_getServiceNameForSetting(m_xConnection,"KeyAlterationServiceName")),UNO_QUERY); + m_xIndexAlter.set(xFac->createInstance(lcl_getServiceNameForSetting(m_xConnection,"IndexAlterationServiceName")),UNO_QUERY); + } + } + catch(const Exception&) + { + } + } + }; +} + +OTableHelper::OTableHelper( sdbcx::OCollection* _pTables, + const Reference< XConnection >& _xConnection, + bool _bCase) + :OTable_TYPEDEF(_pTables,_bCase) + ,m_pImpl(new OTableHelperImpl(_xConnection)) +{ +} + +OTableHelper::OTableHelper( sdbcx::OCollection* _pTables, + const Reference< XConnection >& _xConnection, + bool _bCase, + const OUString& Name, + const OUString& Type, + const OUString& Description , + const OUString& SchemaName, + const OUString& CatalogName + ) : OTable_TYPEDEF(_pTables, + _bCase, + Name, + Type, + Description, + SchemaName, + CatalogName) + ,m_pImpl(new OTableHelperImpl(_xConnection)) +{ +} + +OTableHelper::~OTableHelper() +{ +} + +void SAL_CALL OTableHelper::disposing() +{ + ::osl::MutexGuard aGuard(m_aMutex); + if ( m_pImpl->m_xTablePropertyListener.is() ) + { + m_pTables->removeContainerListener(m_pImpl->m_xTablePropertyListener); + m_pImpl->m_xTablePropertyListener->clear(); + m_pImpl->m_xTablePropertyListener.clear(); + } + OTable_TYPEDEF::disposing(); + + m_pImpl->m_xConnection = nullptr; + m_pImpl->m_xMetaData = nullptr; + +} + + +namespace +{ + /** collects ColumnDesc's from a resultset produced by XDatabaseMetaData::getColumns + */ + void lcl_collectColumnDescs_throw( const Reference< XResultSet >& _rxResult, std::vector< ColumnDesc >& _out_rColumns ) + { + Reference< XRow > xRow( _rxResult, UNO_QUERY_THROW ); + OUString sName; + OrdinalPosition nOrdinalPosition( 0 ); + while ( _rxResult->next() ) + { + sName = xRow->getString( 4 ); // COLUMN_NAME + sal_Int32 nField5 = xRow->getInt(5); + OUString aField6 = xRow->getString(6); + sal_Int32 nField7 = xRow->getInt(7) + , nField9 = xRow->getInt(9) + , nField11= xRow->getInt(11); + OUString sField12 = xRow->getString(12) + ,sField13 = xRow->getString(13); + nOrdinalPosition = xRow->getInt( 17 ); // ORDINAL_POSITION + _out_rColumns.push_back( ColumnDesc( sName,nField5,aField6,nField7,nField9,nField11,sField12,sField13, nOrdinalPosition ) ); + } + } + + /** checks a given array of ColumnDesc's whether it has reasonable ordinal positions. If not, + they will be normalized to be the array index. + */ + void lcl_sanitizeColumnDescs( std::vector< ColumnDesc >& _rColumns ) + { + if ( _rColumns.empty() ) + return; + + // collect all used ordinals + std::set< OrdinalPosition > aUsedOrdinals; + for ( const auto& collect : _rColumns ) + aUsedOrdinals.insert( collect.nOrdinalPosition ); + + // we need to have as much different ordinals as we have different columns + bool bDuplicates = aUsedOrdinals.size() != _rColumns.size(); + // and it needs to be a continuous range + size_t nOrdinalsRange = *aUsedOrdinals.rbegin() - *aUsedOrdinals.begin() + 1; + bool bGaps = nOrdinalsRange != _rColumns.size(); + + // if that's not the case, normalize it + if ( bGaps || bDuplicates ) + { + OSL_FAIL( "lcl_sanitizeColumnDescs: database did provide invalid ORDINAL_POSITION values!" ); + + OrdinalPosition nNormalizedPosition = 1; + for ( auto& normalize : _rColumns ) + normalize.nOrdinalPosition = nNormalizedPosition++; + return; + } + + // what's left is that the range might not be from 1 to , but for instance + // 0 to -1. + size_t nOffset = *aUsedOrdinals.begin() - 1; + for ( auto& offset : _rColumns ) + offset.nOrdinalPosition -= nOffset; + } +} + + +void OTableHelper::refreshColumns() +{ + ::std::vector< OUString> aVector; + if(!isNew()) + { + Any aCatalog; + if ( !m_CatalogName.isEmpty() ) + aCatalog <<= m_CatalogName; + + ::utl::SharedUNOComponent< XResultSet > xResult( getMetaData()->getColumns( + aCatalog, + m_SchemaName, + m_Name, + "%" + ) ); + + // collect the column names, together with their ordinal position + m_pImpl->m_aColumnDesc.clear(); + lcl_collectColumnDescs_throw( xResult, m_pImpl->m_aColumnDesc ); + + // ensure that the ordinal positions as obtained from the meta data do make sense + lcl_sanitizeColumnDescs( m_pImpl->m_aColumnDesc ); + + // sort by ordinal position + std::map< OrdinalPosition, OUString > aSortedColumns; + for (const auto& copy : m_pImpl->m_aColumnDesc) + aSortedColumns[ copy.nOrdinalPosition ] = copy.sName; + + // copy them to aVector, now that we have the proper ordering + std::transform( + aSortedColumns.begin(), + aSortedColumns.end(), + std::insert_iterator< ::std::vector< OUString> >( aVector, aVector.begin() ), + ::o3tl::select2nd< std::map< OrdinalPosition, OUString >::value_type >() + ); + } + + if(m_xColumns) + m_xColumns->reFill(aVector); + else + m_xColumns.reset(createColumns(aVector)); +} + +const ColumnDesc* OTableHelper::getColumnDescription(const OUString& _sName) const +{ + const ColumnDesc* pRet = nullptr; + auto aIter = std::find_if(m_pImpl->m_aColumnDesc.begin(), m_pImpl->m_aColumnDesc.end(), + [&_sName](const ColumnDesc& rColumnDesc) { return rColumnDesc.sName == _sName; }); + if (aIter != m_pImpl->m_aColumnDesc.end()) + pRet = &*aIter; + return pRet; +} + +void OTableHelper::refreshPrimaryKeys(::std::vector< OUString>& _rNames) +{ + Any aCatalog; + if ( !m_CatalogName.isEmpty() ) + aCatalog <<= m_CatalogName; + Reference< XResultSet > xResult = getMetaData()->getPrimaryKeys(aCatalog,m_SchemaName,m_Name); + + if ( xResult.is() ) + { + auto pKeyProps = std::make_shared(OUString(),KeyType::PRIMARY,0,0); + OUString aPkName; + bool bAlreadyFetched = false; + const Reference< XRow > xRow(xResult,UNO_QUERY); + while ( xResult->next() ) + { + pKeyProps->m_aKeyColumnNames.push_back(xRow->getString(4)); + if ( !bAlreadyFetched ) + { + aPkName = xRow->getString(6); + SAL_WARN_IF(xRow->wasNull(),"connectivity.commontools", "NULL Primary Key name"); + SAL_WARN_IF(aPkName.isEmpty(),"connectivity.commontools", "empty Primary Key name"); + bAlreadyFetched = true; + } + } + + if(bAlreadyFetched) + { + SAL_WARN_IF(aPkName.isEmpty(),"connectivity.commontools", "empty Primary Key name"); + SAL_WARN_IF(pKeyProps->m_aKeyColumnNames.empty(),"connectivity.commontools", "Primary Key has no columns"); + m_pImpl->m_aKeys.emplace(aPkName,pKeyProps); + _rNames.push_back(aPkName); + } + } // if ( xResult.is() && xResult->next() ) + ::comphelper::disposeComponent(xResult); +} + +void OTableHelper::refreshForeignKeys(::std::vector< OUString>& _rNames) +{ + Any aCatalog; + if ( !m_CatalogName.isEmpty() ) + aCatalog <<= m_CatalogName; + Reference< XResultSet > xResult = getMetaData()->getImportedKeys(aCatalog,m_SchemaName,m_Name); + Reference< XRow > xRow(xResult,UNO_QUERY); + + if ( !xRow.is() ) + return; + + std::shared_ptr pKeyProps; + OUString aName,sCatalog,aSchema,sOldFKName; + while( xResult->next() ) + { + // this must be outside the "if" because we have to call in a right order + sCatalog = xRow->getString(1); + if ( xRow->wasNull() ) + sCatalog.clear(); + aSchema = xRow->getString(2); + aName = xRow->getString(3); + + const OUString sForeignKeyColumn = xRow->getString(8); + const sal_Int32 nUpdateRule = xRow->getInt(10); + const sal_Int32 nDeleteRule = xRow->getInt(11); + const OUString sFkName = xRow->getString(12); + + if ( !sFkName.isEmpty() && !xRow->wasNull() ) + { + if ( sOldFKName != sFkName ) + { + if ( pKeyProps ) + m_pImpl->m_aKeys.emplace(sOldFKName,pKeyProps); + + const OUString sReferencedName = ::dbtools::composeTableName(getMetaData(),sCatalog,aSchema,aName,false,::dbtools::EComposeRule::InDataManipulation); + pKeyProps = std::make_shared(sReferencedName,KeyType::FOREIGN,nUpdateRule,nDeleteRule); + pKeyProps->m_aKeyColumnNames.push_back(sForeignKeyColumn); + _rNames.push_back(sFkName); + if ( m_pTables->hasByName(sReferencedName) ) + { + if ( !m_pImpl->m_xTablePropertyListener.is() ) + m_pImpl->m_xTablePropertyListener = new OTableContainerListener(this); + m_pTables->addContainerListener(m_pImpl->m_xTablePropertyListener); + m_pImpl->m_xTablePropertyListener->add(sReferencedName); + } // if ( m_pTables->hasByName(sReferencedName) ) + sOldFKName = sFkName; + } // if ( sOldFKName != sFkName ) + else if ( pKeyProps ) + { + pKeyProps->m_aKeyColumnNames.push_back(sForeignKeyColumn); + } + } + } // while( xResult->next() ) + if ( pKeyProps ) + m_pImpl->m_aKeys.emplace(sOldFKName,pKeyProps); + ::comphelper::disposeComponent(xResult); +} + +void OTableHelper::refreshKeys() +{ + m_pImpl->m_aKeys.clear(); + + ::std::vector< OUString> aNames; + + if(!isNew()) + { + refreshPrimaryKeys(aNames); + refreshForeignKeys(aNames); + m_xKeys.reset(createKeys(aNames)); + } // if(!isNew()) + else if (!m_xKeys ) + m_xKeys.reset(createKeys(aNames)); + /*if(m_pKeys) + m_pKeys->reFill(aVector); + else*/ + +} + +void OTableHelper::refreshIndexes() +{ + ::std::vector< OUString> aVector; + if(!isNew()) + { + // fill indexes + Any aCatalog; + if ( !m_CatalogName.isEmpty() ) + aCatalog <<= m_CatalogName; + Reference< XResultSet > xResult = getMetaData()->getIndexInfo(aCatalog,m_SchemaName,m_Name,false,false); + + if(xResult.is()) + { + Reference< XRow > xRow(xResult,UNO_QUERY); + OUString sCatalogSep = getMetaData()->getCatalogSeparator(); + OUString sPreviousRoundName; + while( xResult->next() ) + { + OUString aName = xRow->getString(5); + if(!aName.isEmpty()) + aName += sCatalogSep; + aName += xRow->getString(6); + if ( !aName.isEmpty() ) + { + // don't insert the name if the last one we inserted was the same + if (sPreviousRoundName != aName) + aVector.push_back(aName); + } + sPreviousRoundName = aName; + } + ::comphelper::disposeComponent(xResult); + } + } + + if(m_xIndexes) + m_xIndexes->reFill(aVector); + else + m_xIndexes.reset(createIndexes(aVector)); +} + +OUString OTableHelper::getRenameStart() const +{ + OUString sSql("RENAME "); + if ( m_Type == "VIEW" ) + sSql += " VIEW "; + else + sSql += " TABLE "; + + return sSql; +} + +// XRename +void SAL_CALL OTableHelper::rename( const OUString& newName ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed( +#ifdef __GNUC__ + ::connectivity::sdbcx::OTableDescriptor_BASE::rBHelper.bDisposed +#else + rBHelper.bDisposed +#endif + ); + + if(!isNew()) + { + if ( m_pImpl->m_xRename.is() ) + { + m_pImpl->m_xRename->rename(this,newName); + } + else + { + OUString sSql = getRenameStart(); + + OUString sCatalog,sSchema,sTable; + ::dbtools::qualifiedNameComponents(getMetaData(),newName,sCatalog,sSchema,sTable,::dbtools::EComposeRule::InDataManipulation); + + OUString sComposedName; + sComposedName = ::dbtools::composeTableName(getMetaData(),m_CatalogName,m_SchemaName,m_Name,true,::dbtools::EComposeRule::InDataManipulation); + sSql += sComposedName + + " TO "; + sComposedName = ::dbtools::composeTableName(getMetaData(),sCatalog,sSchema,sTable,true,::dbtools::EComposeRule::InDataManipulation); + sSql += sComposedName; + + Reference< XStatement > xStmt = m_pImpl->m_xConnection->createStatement( ); + if ( xStmt.is() ) + { + xStmt->execute(sSql); + ::comphelper::disposeComponent(xStmt); + } + } + + OTable_TYPEDEF::rename(newName); + } + else + ::dbtools::qualifiedNameComponents(getMetaData(),newName,m_CatalogName,m_SchemaName,m_Name,::dbtools::EComposeRule::InTableDefinitions); +} + +Reference< XDatabaseMetaData> OTableHelper::getMetaData() const +{ + return m_pImpl->m_xMetaData; +} + +void SAL_CALL OTableHelper::alterColumnByIndex( sal_Int32 index, const Reference< XPropertySet >& descriptor ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed( +#ifdef __GNUC__ + ::connectivity::sdbcx::OTableDescriptor_BASE::rBHelper.bDisposed +#else + rBHelper.bDisposed +#endif + ); + + Reference< XPropertySet > xOld( + m_xColumns->getByIndex(index), css::uno::UNO_QUERY); + if(xOld.is()) + alterColumnByName(getString(xOld->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME))),descriptor); +} + + +OUString SAL_CALL OTableHelper::getName() +{ + OUString sComposedName = ::dbtools::composeTableName(getMetaData(),m_CatalogName,m_SchemaName,m_Name,false,::dbtools::EComposeRule::InDataManipulation); + return sComposedName; +} + +const OUString & OTableHelper::getTableName() +{ + return m_Name; +} + +std::shared_ptr OTableHelper::getKeyProperties(const OUString& _sName) const +{ + std::shared_ptr pKeyProps; + TKeyMap::const_iterator aFind = m_pImpl->m_aKeys.find(_sName); + if ( aFind != m_pImpl->m_aKeys.end() ) + { + pKeyProps = aFind->second; + } + else // only a fall back + { + OSL_FAIL("No key with the given name found"); + pKeyProps = std::make_shared(); + } + + return pKeyProps; +} + +void OTableHelper::addKey(const OUString& _sName,const std::shared_ptr& _aKeyProperties) +{ + m_pImpl->m_aKeys.emplace(_sName,_aKeyProperties); +} + +OUString OTableHelper::getTypeCreatePattern() const +{ + return OUString(); +} + +Reference< XConnection> const & OTableHelper::getConnection() const +{ + return m_pImpl->m_xConnection; +} + +Reference< css::sdb::tools::XTableRename> const & OTableHelper::getRenameService() const +{ + return m_pImpl->m_xRename; +} + +Reference< css::sdb::tools::XTableAlteration> const & OTableHelper::getAlterService() const +{ + return m_pImpl->m_xAlter; +} + +Reference< css::sdb::tools::XKeyAlteration> const & OTableHelper::getKeyService() const +{ + return m_pImpl->m_xKeyAlter; +} + +Reference< css::sdb::tools::XIndexAlteration> const & OTableHelper::getIndexService() const +{ + return m_pImpl->m_xIndexAlter; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/commontools/conncleanup.cxx b/connectivity/source/commontools/conncleanup.cxx new file mode 100644 index 000000000..52bbf2104 --- /dev/null +++ b/connectivity/source/commontools/conncleanup.cxx @@ -0,0 +1,230 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include + + +namespace dbtools +{ + + + using namespace css::uno; + using namespace css::beans; + using namespace css::sdbc; + using namespace css::lang; + + constexpr OUStringLiteral ACTIVE_CONNECTION_PROPERTY_NAME = u"ActiveConnection"; + + OAutoConnectionDisposer::OAutoConnectionDisposer(const Reference< XRowSet >& _rxRowSet, const Reference< XConnection >& _rxConnection) + :m_xRowSet( _rxRowSet ) + ,m_bRSListening( false ) + ,m_bPropertyListening( false ) + { + Reference< XPropertySet > xProps(_rxRowSet, UNO_QUERY); + OSL_ENSURE(xProps.is(), "OAutoConnectionDisposer::OAutoConnectionDisposer: invalid rowset (no XPropertySet)!"); + + if (!xProps.is()) + return; + + try + { + xProps->setPropertyValue( ACTIVE_CONNECTION_PROPERTY_NAME, Any( _rxConnection ) ); + m_xOriginalConnection = _rxConnection; + startPropertyListening( xProps ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "connectivity.commontools", "OAutoConnectionDisposer::OAutoConnectionDisposer" ); + } + } + + + void OAutoConnectionDisposer::startPropertyListening( const Reference< XPropertySet >& _rxRowSet ) + { + try + { + _rxRowSet->addPropertyChangeListener( ACTIVE_CONNECTION_PROPERTY_NAME, this ); + m_bPropertyListening = true; + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "connectivity.commontools", "OAutoConnectionDisposer::startPropertyListening" ); + } + } + + + void OAutoConnectionDisposer::stopPropertyListening( const Reference< XPropertySet >& _rxEventSource ) + { + // prevent deletion of ourself while we're herein + Reference< XInterface > xKeepAlive(static_cast< XWeak* >(this)); + + try + { // remove ourself as property change listener + OSL_ENSURE( _rxEventSource.is(), "OAutoConnectionDisposer::stopPropertyListening: invalid event source (no XPropertySet)!" ); + if ( _rxEventSource.is() ) + { + _rxEventSource->removePropertyChangeListener( ACTIVE_CONNECTION_PROPERTY_NAME, this ); + m_bPropertyListening = false; + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "connectivity.commontools", "OAutoConnectionDisposer::stopPropertyListening" ); + } + } + + + void OAutoConnectionDisposer::startRowSetListening() + { + OSL_ENSURE( !m_bRSListening, "OAutoConnectionDisposer::startRowSetListening: already listening!" ); + try + { + if ( !m_bRSListening ) + m_xRowSet->addRowSetListener( this ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "connectivity.commontools", "OAutoConnectionDisposer::startRowSetListening" ); + } + m_bRSListening = true; + } + + + void OAutoConnectionDisposer::stopRowSetListening() + { + OSL_ENSURE( m_bRSListening, "OAutoConnectionDisposer::stopRowSetListening: not listening!" ); + try + { + m_xRowSet->removeRowSetListener( this ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "connectivity.commontools", "OAutoConnectionDisposer::stopRowSetListening" ); + } + m_bRSListening = false; + } + + + void SAL_CALL OAutoConnectionDisposer::propertyChange( const PropertyChangeEvent& _rEvent ) + { + if ( _rEvent.PropertyName != ACTIVE_CONNECTION_PROPERTY_NAME ) + return; + +// somebody set a new ActiveConnection + + Reference< XConnection > xNewConnection; + _rEvent.NewValue >>= xNewConnection; + + if ( isRowSetListening() ) + { + // we're listening at the row set, this means that the row set does not have our + // m_xOriginalConnection as active connection anymore + // So there are two possibilities + // a. somebody sets a new connection which is not our original one + // b. somebody sets a new connection, which is exactly the original one + // a. we're not interested in a, but in b: In this case, we simply need to move to the state + // we had originally: listen for property changes, do not listen for row set changes, and + // do not dispose the connection until the row set does not need it anymore + if ( xNewConnection.get() == m_xOriginalConnection.get() ) + { + stopRowSetListening(); + } + } + else + { + // start listening at the row set. We're allowed to dispose the old connection as soon + // as the RowSet changed + + // Unfortunately, the our database form implementations sometimes fire the change of their + // ActiveConnection twice. This is an error in forms/source/component/DatabaseForm.cxx, but + // changing this would require incompatible changes we can't do for a while. + // So for the moment, we have to live with it here. + // + // The only scenario where this doubled notification causes problems is when the connection + // of the form is reset to the one we're responsible for (m_xOriginalConnection), so we + // check this here. + // + // Yes, this is a HACK :( + if ( xNewConnection.get() != m_xOriginalConnection.get() ) + { +#if OSL_DEBUG_LEVEL > 0 + Reference< XConnection > xOldConnection; + _rEvent.OldValue >>= xOldConnection; + OSL_ENSURE( xOldConnection.get() == m_xOriginalConnection.get(), "OAutoConnectionDisposer::propertyChange: unexpected (original) property value!" ); +#endif + startRowSetListening(); + } + } + } + + + void SAL_CALL OAutoConnectionDisposer::disposing( const EventObject& _rSource ) + { + // the rowset is being disposed, and nobody has set a new ActiveConnection in the meantime + if ( isRowSetListening() ) + stopRowSetListening(); + + clearConnection(); + + if ( m_bPropertyListening ) + stopPropertyListening( Reference< XPropertySet >( _rSource.Source, UNO_QUERY ) ); + } + + void OAutoConnectionDisposer::clearConnection() + { + try + { + // dispose the old connection + Reference< XComponent > xComp(m_xOriginalConnection, UNO_QUERY); + if (xComp.is()) + xComp->dispose(); + m_xOriginalConnection.clear(); + } + catch(Exception&) + { + TOOLS_WARN_EXCEPTION("connectivity.commontools", "OAutoConnectionDisposer::clearConnection"); + } + } + + void SAL_CALL OAutoConnectionDisposer::cursorMoved( const css::lang::EventObject& /*event*/ ) + { + } + + void SAL_CALL OAutoConnectionDisposer::rowChanged( const css::lang::EventObject& /*event*/ ) + { + } + + void SAL_CALL OAutoConnectionDisposer::rowSetChanged( const css::lang::EventObject& /*event*/ ) + { + stopRowSetListening(); + clearConnection(); + + } + + +} // namespace dbtools + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/commontools/dbcharset.cxx b/connectivity/source/commontools/dbcharset.cxx new file mode 100644 index 000000000..ebe45c028 --- /dev/null +++ b/connectivity/source/commontools/dbcharset.cxx @@ -0,0 +1,190 @@ +/* -*- 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 +#include +#include + + +namespace dbtools +{ + + OCharsetMap::OCharsetMap() + { + } + + + void OCharsetMap::lateConstruct() + { + const rtl_TextEncoding eFirstEncoding = RTL_TEXTENCODING_DONTKNOW; + const rtl_TextEncoding eLastEncoding = 100; // TODO: a define in rtl/textenc.h would be fine here ... + OSL_ENSURE( 0 == eFirstEncoding, "OCharsetMap::OCharsetMap: somebody changed the numbers!" ); + + rtl_TextEncodingInfo aInfo; aInfo.StructSize = sizeof( rtl_TextEncodingInfo ); + for ( rtl_TextEncoding eEncoding = eFirstEncoding; eEncoding < eLastEncoding; ++eEncoding ) + { + if ( ( RTL_TEXTENCODING_DONTKNOW == eEncoding ) // this is always allowed - it has the special meaning "system encoding" + || ( rtl_getTextEncodingInfo( eEncoding, &aInfo ) + && approveEncoding( eEncoding, aInfo ) + ) + ) + { + m_aEncodings.insert( eEncoding ); + } + } + + OSL_ENSURE( find( RTL_TEXTENCODING_MS_1252 ) != end(), "OCharsetMap::lateConstruct: missing compatibility encoding ANSI!" ); + OSL_ENSURE( find( RTL_TEXTENCODING_APPLE_ROMAN ) != end(), "OCharsetMap::lateConstruct: missing compatibility encoding macintosh!" ); + OSL_ENSURE( find( RTL_TEXTENCODING_IBM_437 ) != end(), "OCharsetMap::lateConstruct: missing compatibility encoding IBM437!" ); + OSL_ENSURE( find( RTL_TEXTENCODING_IBM_850) != end(), "OCharsetMap::lateConstruct: missing compatibility encoding IBM850!" ); + OSL_ENSURE( find( RTL_TEXTENCODING_IBM_860 ) != end(), "OCharsetMap::lateConstruct: missing compatibility encoding IBM860!" ); + OSL_ENSURE( find( RTL_TEXTENCODING_IBM_861 ) != end(), "OCharsetMap::lateConstruct: missing compatibility encoding IBM861!" ); + OSL_ENSURE( find( RTL_TEXTENCODING_IBM_863 ) != end(), "OCharsetMap::lateConstruct: missing compatibility encoding IBM863!" ); + OSL_ENSURE( find( RTL_TEXTENCODING_IBM_865 ) != end(), "OCharsetMap::lateConstruct: missing compatibility encoding IBM865!" ); + OSL_ENSURE( find( RTL_TEXTENCODING_IBM_866 ) != end(), "OCharsetMap::lateConstruct: missing compatibility encoding IBM866!" ); + OSL_ENSURE( find( RTL_TEXTENCODING_DONTKNOW ) != end(), "OCharsetMap::lateConstruct: missing compatibility encoding SYSTEM!" ); + OSL_ENSURE( find( RTL_TEXTENCODING_UTF8 ) != end(), "OCharsetMap::lateConstruct: missing compatibility encoding UTF-8!" ); + OSL_ENSURE( find( RTL_TEXTENCODING_BIG5_HKSCS ) != end(), "OCharsetMap::lateConstruct: missing compatibility encoding Big5-HKSCS!" ); + } + + + bool OCharsetMap::approveEncoding( const rtl_TextEncoding _eEncoding, const rtl_TextEncodingInfo& _rInfo ) const + { + bool bIsMimeEncoding = 0 != ( _rInfo.Flags & RTL_TEXTENCODING_INFO_MIME ); + OSL_ENSURE( !bIsMimeEncoding || rtl_getMimeCharsetFromTextEncoding( _eEncoding ), + "OCharsetMap::OCharsetMap: inconsistence in rtl!" ); + return bIsMimeEncoding; + } + + + OCharsetMap::~OCharsetMap() + { + } + + + OCharsetMap::CharsetIterator OCharsetMap::begin() const + { + ensureConstructed( ); + return CharsetIterator(this, m_aEncodings.begin() ); + } + + + OCharsetMap::CharsetIterator OCharsetMap::find(const rtl_TextEncoding _eEncoding) const + { + ensureConstructed( ); + return CharsetIterator( this, m_aEncodings.find( _eEncoding ) ); + } + + + OCharsetMap::CharsetIterator OCharsetMap::findIanaName(const OUString& _rIanaName) const + { + ensureConstructed( ); + + rtl_TextEncoding eEncoding = RTL_TEXTENCODING_DONTKNOW; + if ( !_rIanaName.isEmpty() ) + { + // byte string conversion + OString sMimeByteString( _rIanaName.getStr(), _rIanaName.getLength(), RTL_TEXTENCODING_ASCII_US ); + // look up + eEncoding = rtl_getTextEncodingFromMimeCharset( sMimeByteString.getStr() ); + + if ( RTL_TEXTENCODING_DONTKNOW == eEncoding ) + { // if we're here, the name is not empty, but unknown -> this is an invalid name + return end(); + } + } + + return find( eEncoding ); + } + + + OCharsetMap::CharsetIterator OCharsetMap::end() const + { + ensureConstructed( ); + + return CharsetIterator( this, m_aEncodings.end() ); + } + + + CharsetIteratorDerefHelper::CharsetIteratorDerefHelper( const CharsetIteratorDerefHelper& _rSource ) + :m_eEncoding( _rSource.m_eEncoding ) + ,m_aIanaName( _rSource.m_aIanaName ) + { + } + + + CharsetIteratorDerefHelper:: CharsetIteratorDerefHelper(const rtl_TextEncoding _eEncoding, const OUString& _rIanaName ) + :m_eEncoding( _eEncoding ) + ,m_aIanaName( _rIanaName ) + { + } + + OCharsetMap::CharsetIterator::CharsetIterator(const OCharsetMap* _pContainer, OCharsetMap::TextEncBag::const_iterator const & _aPos ) + :m_pContainer( _pContainer ) + ,m_aPos( _aPos ) + { + OSL_ENSURE( m_pContainer, "OCharsetMap::CharsetIterator::CharsetIterator : invalid container!" ); + } + + CharsetIteratorDerefHelper OCharsetMap::CharsetIterator::operator*() const + { + OSL_ENSURE( m_aPos != m_pContainer->m_aEncodings.end(), "OCharsetMap::CharsetIterator::operator*: invalid position!"); + + rtl_TextEncoding eEncoding = *m_aPos; + OUString sIanaName; + + if ( RTL_TEXTENCODING_DONTKNOW != eEncoding ) + { // it's not the virtual "system charset" + const char* pIanaName = rtl_getMimeCharsetFromTextEncoding( eEncoding ); + OSL_ENSURE( pIanaName, "OCharsetMap::CharsetIterator: invalid mime name!" ); + if ( pIanaName ) + sIanaName = OUString::createFromAscii( pIanaName ); + } + return CharsetIteratorDerefHelper( eEncoding, sIanaName ); + } + + + const OCharsetMap::CharsetIterator& OCharsetMap::CharsetIterator::operator++() + { + OSL_ENSURE( m_aPos != m_pContainer->m_aEncodings.end(), "OCharsetMap::CharsetIterator::operator++ : invalid position!" ); + if ( m_aPos != m_pContainer->m_aEncodings.end()) + ++m_aPos; + return *this; + } + + + const OCharsetMap::CharsetIterator& OCharsetMap::CharsetIterator::operator--() + { + OSL_ENSURE( m_aPos != m_pContainer->m_aEncodings.begin(), "OCharsetMap::CharsetIterator::operator-- : invalid position!" ); + if ( m_aPos != m_pContainer->m_aEncodings.begin() ) + --m_aPos; + return *this; + } + + + bool operator==(const OCharsetMap::CharsetIterator& lhs, const OCharsetMap::CharsetIterator& rhs) + { + return ( lhs.m_pContainer == rhs.m_pContainer ) && ( lhs.m_aPos == rhs.m_aPos ); + } + + +} // namespace dbtools + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/commontools/dbconversion.cxx b/connectivity/source/commontools/dbconversion.cxx new file mode 100644 index 000000000..af80efb60 --- /dev/null +++ b/connectivity/source/commontools/dbconversion.cxx @@ -0,0 +1,463 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace +{ + const sal_Int64 nanoSecInSec = 1000000000; + const sal_Int16 secInMin = 60; + const sal_Int16 minInHour = 60; + + const sal_Int64 secMask = 1000000000; + const sal_Int64 minMask = 100000000000LL; + const sal_Int64 hourMask = 10000000000000LL; + + const double fNanoSecondsPerDay = nanoSecInSec * secInMin * minInHour * 24.0; + + // 32767-12-31 in "(days since 0001-01-01) + 1" format + const sal_Int32 maxDays = 11967896; + // -32768-01-01 in "(days since 0001-01-01) + 1" format + // Yes, I know it is currently unused. Will have to be used + // when we implement negative years. Writing down the correct + // value for future reference. + // *** Please don't remove just because it is unused *** + // Lionel Élie Mamane 2017-08-02 + // const sal_Int32 minDays = -11968270; +} + + +namespace dbtools +{ + + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::util; + using namespace ::com::sun::star::sdb; + using namespace ::com::sun::star::sdbc; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + + + css::util::Date const & DBTypeConversion::getStandardDate() + { + static css::util::Date STANDARD_DB_DATE(1,1,1900); + return STANDARD_DB_DATE; + } + + OUString DBTypeConversion::toDateString(const css::util::Date& rDate) + { + std::ostringstream ostr; + using std::setw; + ostr.fill('0'); + ostr << setw(4) << rDate.Year << "-" + << setw(2) << rDate.Month << "-" + << setw(2) << rDate.Day; + return OUString::createFromAscii(ostr.str().c_str()); + } + + OUString DBTypeConversion::toTimeStringS(const css::util::Time& rTime) + { + std::ostringstream ostr; + using std::setw; + ostr.fill('0'); + ostr << setw(2) << rTime.Hours << ":" + << setw(2) << rTime.Minutes << ":" + << setw(2) << rTime.Seconds; + return OUString::createFromAscii(ostr.str().c_str()); + } + + OUString DBTypeConversion::toTimeString(const css::util::Time& rTime) + { + std::ostringstream ostr; + using std::setw; + ostr.fill('0'); + ostr << setw(2) << rTime.Hours << ":" + << setw(2) << rTime.Minutes << ":" + << setw(2) << rTime.Seconds << "." + << setw(9) << rTime.NanoSeconds; + return OUString::createFromAscii(ostr.str().c_str()); + } + + OUString DBTypeConversion::toDateTimeString(const css::util::DateTime& _rDateTime) + { + css::util::Date aDate(_rDateTime.Day,_rDateTime.Month,_rDateTime.Year); + css::util::Time const aTime(_rDateTime.NanoSeconds, _rDateTime.Seconds, + _rDateTime.Minutes, _rDateTime.Hours, _rDateTime.IsUTC); + return toDateString(aDate) + " " + toTimeString(aTime); + } + + css::util::Date DBTypeConversion::toDate(const sal_Int32 _nVal) + { + css::util::Date aReturn; + aReturn.Day = static_cast(_nVal % 100); + aReturn.Month = static_cast((_nVal / 100) % 100); + aReturn.Year = static_cast(_nVal / 10000); + return aReturn; + } + + + css::util::Time DBTypeConversion::toTime(const sal_Int64 _nVal) + { + css::util::Time aReturn; + sal_uInt64 unVal = static_cast(_nVal >= 0 ? _nVal : -_nVal); + aReturn.Hours = unVal / hourMask; + aReturn.Minutes = (unVal / minMask) % 100; + aReturn.Seconds = (unVal / secMask) % 100; + aReturn.NanoSeconds = unVal % secMask; + return aReturn; + } + + sal_Int64 DBTypeConversion::getNsFromTime(const css::util::Time& rVal) + { + sal_Int32 nHour = rVal.Hours; + sal_Int32 nMin = rVal.Minutes; + sal_Int32 nSec = rVal.Seconds; + sal_Int32 nNanoSec = rVal.NanoSeconds; + + return nNanoSec + + nSec * nanoSecInSec + + nMin * (secInMin * nanoSecInSec) + + nHour * (minInHour * secInMin * nanoSecInSec); + } + + + const sal_Int32 aDaysInMonth[12] = { 31, 28, 31, 30, 31, 30, + 31, 31, 30, 31, 30, 31 }; + + + static bool implIsLeapYear(sal_Int32 _nYear) + { + return ( ((_nYear % 4) == 0) + && ((_nYear % 100) != 0) + ) + + || ((_nYear % 400) == 0) + ; + } + + static sal_Int32 implDaysInMonth(sal_Int32 _nMonth, sal_Int32 _nYear) + { + SAL_WARN_IF(_nMonth < 1 || _nMonth > 12, "connectivity.commontools", "Month has invalid value: " << _nMonth); + if (_nMonth < 1) + _nMonth = 1; + else if (_nMonth > 12) + _nMonth = 12; + if (_nMonth != 2) + return aDaysInMonth[_nMonth-1]; + else + { + if (implIsLeapYear(_nYear)) + return aDaysInMonth[_nMonth-1] + 1; + else + return aDaysInMonth[_nMonth-1]; + } + } + + static sal_Int32 implRelativeToAbsoluteNull(const css::util::Date& _rDate) + { + sal_Int32 nDays = 0; + + // ripped this code from the implementation of tools::Date + sal_Int32 nNormalizedYear = _rDate.Year - 1; + nDays = nNormalizedYear * 365; + // leap years + nDays += (nNormalizedYear / 4) - (nNormalizedYear / 100) + (nNormalizedYear / 400); + + for (sal_Int32 i = 1; i < _rDate.Month; ++i) + nDays += implDaysInMonth(i, _rDate.Year); + + nDays += _rDate.Day; + return nDays; + } + + static void implBuildFromRelative( const sal_Int32 nDays, sal_uInt16& rDay, sal_uInt16& rMonth, sal_Int16& rYear) + { + sal_Int32 nTempDays; + sal_Int32 i = 0; + bool bCalc; + + do + { + nTempDays = nDays; + rYear = static_cast((nTempDays / 365) - i); + nTempDays -= (rYear-1) * 365; + nTempDays -= ((rYear-1) / 4) - ((rYear-1) / 100) + ((rYear-1) / 400); + bCalc = false; + if ( nTempDays < 1 ) + { + i++; + bCalc = true; + } + else + { + if ( nTempDays > 365 ) + { + if ( (nTempDays != 366) || !implIsLeapYear( rYear ) ) + { + i--; + bCalc = true; + } + } + } + } + while ( bCalc ); + + rMonth = 1; + while ( nTempDays > implDaysInMonth( rMonth, rYear ) ) + { + nTempDays -= implDaysInMonth( rMonth, rYear ); + rMonth++; + } + rDay = static_cast(nTempDays); + } + + sal_Int32 DBTypeConversion::toDays(const css::util::Date& _rVal, const css::util::Date& _rNullDate) + { + return implRelativeToAbsoluteNull(_rVal) - implRelativeToAbsoluteNull(_rNullDate); + } + + + double DBTypeConversion::toDouble(const css::util::Date& rVal, const css::util::Date& _rNullDate) + { + return static_cast(toDays(rVal, _rNullDate)); + } + + + double DBTypeConversion::toDouble(const css::util::Time& rVal) + { + return static_cast(getNsFromTime(rVal)) / fNanoSecondsPerDay; + } + + + double DBTypeConversion::toDouble(const css::util::DateTime& _rVal, const css::util::Date& _rNullDate) + { + sal_Int64 nTime = toDays(css::util::Date(_rVal.Day, _rVal.Month, _rVal.Year), _rNullDate); + css::util::Time aTimePart; + + aTimePart.Hours = _rVal.Hours; + aTimePart.Minutes = _rVal.Minutes; + aTimePart.Seconds = _rVal.Seconds; + aTimePart.NanoSeconds = _rVal.NanoSeconds; + + return static_cast(nTime) + toDouble(aTimePart); + } + + static void addDays(const sal_Int32 nDays, css::util::Date& _rDate) + { + sal_Int64 nTempDays = implRelativeToAbsoluteNull(_rDate); + + nTempDays += nDays; + if ( nTempDays > maxDays ) + { + _rDate.Day = 31; + _rDate.Month = 12; + _rDate.Year = 9999; + } + // TODO: can we replace that check by minDays? Would allow dates BCE + // implBuildFromRelative probably needs to be updated for the "no year 0" question + else if ( nTempDays <= 0 ) + { + _rDate.Day = 1; + _rDate.Month = 1; + _rDate.Year = 1; + } + else + implBuildFromRelative( nTempDays, _rDate.Day, _rDate.Month, _rDate.Year ); + } + + static void subDays(const sal_Int32 nDays, css::util::Date& _rDate ) + { + sal_Int64 nTempDays = implRelativeToAbsoluteNull(_rDate); + + nTempDays -= nDays; + if ( nTempDays > maxDays ) + { + _rDate.Day = 31; + _rDate.Month = 12; + _rDate.Year = 9999; + } + // TODO: can we replace that check by minDays? Would allow dates BCE + // implBuildFromRelative probably needs to be updated for the "no year 0" question + else if ( nTempDays <= 0 ) + { + _rDate.Day = 1; + _rDate.Month = 1; + _rDate.Year = 1; + } + else + implBuildFromRelative( nTempDays, _rDate.Day, _rDate.Month, _rDate.Year ); + } + + css::util::Date DBTypeConversion::toDate(const double dVal, const css::util::Date& _rNullDate) + { + css::util::Date aRet = _rNullDate; + + if (dVal >= 0) + addDays(static_cast(dVal),aRet); + else + subDays(static_cast(-dVal),aRet); + // x -= (sal_uInt32)(-nDays); + + return aRet; + } + + css::util::Time DBTypeConversion::toTime(const double dVal, short nDigits) + { + const double nDays = std::trunc(dVal); + double fSeconds((dVal - nDays) * (fNanoSecondsPerDay / nanoSecInSec)); + fSeconds = ::rtl::math::round(fSeconds, nDigits); + sal_Int64 nNS = fSeconds * nanoSecInSec; + + sal_Int16 nSign; + if ( nNS < 0 ) + { + nNS *= -1; + nSign = -1; + } + else + nSign = 1; + + css::util::Time aRet; + // normalize time + // we have to sal_Int32 here because otherwise we get an overflow + sal_Int64 nNanoSeconds = nNS; + sal_Int32 nSeconds = nNanoSeconds / nanoSecInSec; + sal_Int32 nMinutes = nSeconds / secInMin; + + aRet.NanoSeconds = nNanoSeconds % nanoSecInSec; + aRet.Seconds = nSeconds % secInMin; + aRet.Hours = nMinutes / minInHour; + aRet.Minutes = nMinutes % minInHour; + + // assemble time + sal_Int64 nTime = nSign * + (aRet.NanoSeconds + + aRet.Seconds * secMask + + aRet.Minutes * minMask + + aRet.Hours * hourMask); + + if(nTime < 0) + { + aRet.NanoSeconds = nanoSecInSec-1; + aRet.Seconds = secInMin-1; + aRet.Minutes = minInHour-1; + aRet.Hours = 23; + } + return aRet; + } + + css::util::DateTime DBTypeConversion::toDateTime(const double dVal, const css::util::Date& _rNullDate) + { + css::util::DateTime aRet; + + if (!std::isfinite(dVal)) + { + SAL_WARN("connectivity.commontools", "DateTime has invalid value: " << dVal); + return aRet; + } + + css::util::Date aDate = toDate(dVal, _rNullDate); + // there is not enough precision in a double to have both a date + // and a time up to nanoseconds -> limit to microseconds to have + // correct rounding, that is e.g. 13:00:00.000000000 instead of + // 12:59:59.999999790 + css::util::Time aTime = toTime(dVal, 6); + + aRet.Day = aDate.Day; + aRet.Month = aDate.Month; + aRet.Year = aDate.Year; + + aRet.NanoSeconds = aTime.NanoSeconds; + aRet.Minutes = aTime.Minutes; + aRet.Seconds = aTime.Seconds; + aRet.Hours = aTime.Hours; + + + return aRet; + } + + css::util::Date DBTypeConversion::toDate(std::u16string_view _sSQLString) + { + // get the token out of a string + static const sal_Unicode sDateSep = '-'; + + sal_Int32 nIndex = 0; + sal_uInt16 nYear = 0, + nMonth = 0, + nDay = 0; + nYear = static_cast(o3tl::toInt32(o3tl::getToken(_sSQLString, 0,sDateSep,nIndex))); + if(nIndex != -1) + { + nMonth = static_cast(o3tl::toInt32(o3tl::getToken(_sSQLString, 0,sDateSep,nIndex))); + if(nIndex != -1) + nDay = static_cast(o3tl::toInt32(o3tl::getToken(_sSQLString, 0,sDateSep,nIndex))); + } + + return css::util::Date(nDay,nMonth,nYear); + } + + + css::util::DateTime DBTypeConversion::toDateTime(const OUString& _sSQLString) + { + //@see http://java.sun.com/j2se/1.4.2/docs/api/java/sql/Timestamp.html#valueOf(java.lang.String) + //@see http://java.sun.com/j2se/1.4.2/docs/api/java/sql/Date.html#valueOf(java.lang.String) + //@see http://java.sun.com/j2se/1.4.2/docs/api/java/sql/Time.html#valueOf(java.lang.String) + + // the date part + css::util::Date aDate = toDate(_sSQLString); + css::util::Time aTime; + sal_Int32 nSeparation = _sSQLString.indexOf( ' ' ); + if ( -1 != nSeparation ) + { + const sal_Unicode *p = _sSQLString.getStr() + nSeparation; + const sal_Unicode *const begin = p; + while (rtl::isAsciiWhiteSpace(*p)) { ++p; } + nSeparation += p - begin; + aTime = toTime( _sSQLString.subView( nSeparation ) ); + } + + return css::util::DateTime(aTime.NanoSeconds, aTime.Seconds, aTime.Minutes, aTime.Hours, + aDate.Day, aDate.Month, aDate.Year, false); + } + + + css::util::Time DBTypeConversion::toTime(std::u16string_view _sSQLString) + { + css::util::Time aTime; + ::utl::ISO8601parseTime(_sSQLString, aTime); + return aTime; + } + + +} // namespace dbtools + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/commontools/dbexception.cxx b/connectivity/source/commontools/dbexception.cxx new file mode 100644 index 000000000..e6663f7d1 --- /dev/null +++ b/connectivity/source/commontools/dbexception.cxx @@ -0,0 +1,495 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace dbtools +{ + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::sdb; + using namespace ::com::sun::star::sdbc; + using namespace ::comphelper; + using namespace ::connectivity; + +SQLExceptionInfo::SQLExceptionInfo() + :m_eType(TYPE::Undefined) +{ +} + + +SQLExceptionInfo::SQLExceptionInfo(const css::sdbc::SQLException& _rError) +{ + m_aContent <<= _rError; + implDetermineType(); +} + + +SQLExceptionInfo::SQLExceptionInfo(const css::sdbc::SQLWarning& _rError) +{ + m_aContent <<= _rError; + implDetermineType(); +} + + +SQLExceptionInfo::SQLExceptionInfo(const css::sdb::SQLContext& _rError) +{ + m_aContent <<= _rError; + implDetermineType(); +} + + +SQLExceptionInfo::SQLExceptionInfo( const OUString& _rSimpleErrorMessage ) +{ + SQLException aError; + aError.Message = _rSimpleErrorMessage; + m_aContent <<= aError; + implDetermineType(); +} + +SQLExceptionInfo& SQLExceptionInfo::operator=(const css::sdbc::SQLException& _rError) +{ + m_aContent <<= _rError; + implDetermineType(); + return *this; +} + + +SQLExceptionInfo& SQLExceptionInfo::operator=(const css::sdbc::SQLWarning& _rError) +{ + m_aContent <<= _rError; + implDetermineType(); + return *this; +} + + +SQLExceptionInfo& SQLExceptionInfo::operator=(const css::sdb::SQLContext& _rError) +{ + m_aContent <<= _rError; + implDetermineType(); + return *this; +} + + +SQLExceptionInfo& SQLExceptionInfo::operator=(const css::sdb::SQLErrorEvent& _rErrorEvent) +{ + m_aContent = _rErrorEvent.Reason; + implDetermineType(); + return *this; +} + + +SQLExceptionInfo& SQLExceptionInfo::operator=(const css::uno::Any& _rCaughtSQLException) +{ + m_aContent = _rCaughtSQLException; + implDetermineType(); + return *this; +} + + +SQLExceptionInfo::SQLExceptionInfo(const css::uno::Any& _rError) +{ + const css::uno::Type& aSQLExceptionType = cppu::UnoType::get(); + bool bValid = isAssignableFrom(aSQLExceptionType, _rError.getValueType()); + if (bValid) + m_aContent = _rError; + // no assertion here : if used with the NextException member of an SQLException bValid==sal_False is allowed. + + implDetermineType(); +} + + +void SQLExceptionInfo::implDetermineType() +{ + const Type& aSQLExceptionType = ::cppu::UnoType::get(); + const Type& aSQLWarningType = ::cppu::UnoType::get(); + const Type& aSQLContextType = ::cppu::UnoType::get(); + + if ( isAssignableFrom( aSQLContextType, m_aContent.getValueType() ) ) + m_eType = TYPE::SQLContext; + else if ( isAssignableFrom( aSQLWarningType, m_aContent.getValueType() ) ) + m_eType = TYPE::SQLWarning; + else if ( isAssignableFrom( aSQLExceptionType, m_aContent.getValueType() ) ) + m_eType = TYPE::SQLException; + else + { + m_eType = TYPE::Undefined; + m_aContent.clear(); + } +} + + +bool SQLExceptionInfo::isKindOf(TYPE _eType) const +{ + switch (_eType) + { + case TYPE::SQLContext: + return (m_eType == TYPE::SQLContext); + case TYPE::SQLWarning: + return (m_eType == TYPE::SQLContext) || (m_eType == TYPE::SQLWarning); + case TYPE::SQLException: + return (m_eType == TYPE::SQLContext) || (m_eType == TYPE::SQLWarning) || (m_eType == TYPE::SQLException); + case TYPE::Undefined: + return (m_eType == TYPE::Undefined); + } + return false; +} + + +SQLExceptionInfo::operator const css::sdbc::SQLException*() const +{ + OSL_ENSURE(isKindOf(TYPE::SQLException), "SQLExceptionInfo::operator SQLException* : invalid call !"); + return o3tl::doAccess(m_aContent); +} + + +SQLExceptionInfo::operator const css::sdb::SQLContext*() const +{ + OSL_ENSURE(isKindOf(TYPE::SQLContext), "SQLExceptionInfo::operator SQLException* : invalid call !"); + return o3tl::doAccess(m_aContent); +} + + +void SQLExceptionInfo::prepend( const OUString& _rErrorMessage ) +{ + SQLException aException; + aException.Message = _rErrorMessage; + aException.ErrorCode = 0; + aException.SQLState = "S1000"; + aException.NextException = m_aContent; + m_aContent <<= aException; + + m_eType = TYPE::SQLException; +} + +// create the to-be-appended exception +Any SQLExceptionInfo::createException(TYPE eType, const OUString& rErrorMessage, const OUString& rSQLState, const sal_Int32 nErrorCode) +{ + Any aAppend; + switch (eType) + { + case TYPE::SQLException: + aAppend <<= SQLException(); + break; + case TYPE::SQLWarning: + aAppend <<= SQLWarning(); + break; + case TYPE::SQLContext: + aAppend <<= SQLContext(); + break; + default: + TOOLS_WARN_EXCEPTION("connectivity.commontools", "SQLExceptionInfo::createException: invalid exception type: this will crash!"); + break; + } + + SQLException& pAppendException = const_cast(*o3tl::forceAccess(aAppend)); + pAppendException.Message = rErrorMessage; + pAppendException.SQLState = rSQLState; + pAppendException.ErrorCode = nErrorCode; + + return aAppend; +} + +// find the end of the exception chain +SQLException* SQLExceptionInfo::getLastException(SQLException* pLastException) +{ + SQLException* pException = pLastException; + while (pException) + { + pException = const_cast(o3tl::tryAccess(pException->NextException)); + if (!pException) + break; + pLastException = pException; + } + return pLastException; +} + +void SQLExceptionInfo::append( TYPE _eType, const OUString& _rErrorMessage, const OUString& _rSQLState, const sal_Int32 _nErrorCode ) +{ + // create the to-be-appended exception + Any aAppend = createException(_eType, _rErrorMessage, _rSQLState, _nErrorCode); + + // find the end of the current chain + SQLException* pLastException = getLastException(const_cast(o3tl::tryAccess(m_aContent))); + + // append + if (pLastException) + pLastException->NextException = aAppend; + else + { + m_aContent = aAppend; + m_eType = _eType; + } +} + +void SQLExceptionInfo::doThrow() +{ + if ( m_aContent.getValueTypeClass() == TypeClass_EXCEPTION ) + ::cppu::throwException( m_aContent ); + throw RuntimeException(); +} + +SQLExceptionIteratorHelper::SQLExceptionIteratorHelper( const SQLExceptionInfo& _rChainStart ) + :m_pCurrent( nullptr ) + ,m_eCurrentType( SQLExceptionInfo::TYPE::Undefined ) +{ + if ( _rChainStart.isValid() ) + { + m_pCurrent = _rChainStart; + m_eCurrentType = _rChainStart.getType(); + } +} + + +SQLExceptionIteratorHelper::SQLExceptionIteratorHelper( const css::sdbc::SQLException& _rChainStart ) + :m_pCurrent( &_rChainStart ) + ,m_eCurrentType( SQLExceptionInfo::TYPE::SQLException ) +{ +} + + +void SQLExceptionIteratorHelper::current( SQLExceptionInfo& _out_rInfo ) const +{ + switch ( m_eCurrentType ) + { + case SQLExceptionInfo::TYPE::SQLException: + _out_rInfo = *m_pCurrent; + break; + + case SQLExceptionInfo::TYPE::SQLWarning: + _out_rInfo = *static_cast< const SQLWarning* >( m_pCurrent ); + break; + + case SQLExceptionInfo::TYPE::SQLContext: + _out_rInfo = *static_cast< const SQLContext* >( m_pCurrent ); + break; + + default: + _out_rInfo = Any(); + break; + } +} + + +const css::sdbc::SQLException* SQLExceptionIteratorHelper::next() +{ + OSL_ENSURE( hasMoreElements(), "SQLExceptionIteratorHelper::next : invalid call (please use hasMoreElements)!" ); + + const css::sdbc::SQLException* pReturn = m_pCurrent; + if ( !m_pCurrent ) + return pReturn; + + // check for the next element within the chain + const Type aTypeException( ::cppu::UnoType< SQLException >::get() ); + + Type aNextElementType = m_pCurrent->NextException.getValueType(); + if ( !isAssignableFrom( aTypeException, aNextElementType ) ) + { + // no SQLException at all in the next chain element + m_pCurrent = nullptr; + m_eCurrentType = SQLExceptionInfo::TYPE::Undefined; + return pReturn; + } + + m_pCurrent = o3tl::doAccess< SQLException >( m_pCurrent->NextException ); + + // no finally determine the proper type of the exception + const Type aTypeContext( ::cppu::UnoType< SQLContext >::get() ); + if ( isAssignableFrom( aTypeContext, aNextElementType ) ) + { + m_eCurrentType = SQLExceptionInfo::TYPE::SQLContext; + return pReturn; + } + + const Type aTypeWarning( ::cppu::UnoType< SQLWarning >::get() ); + if ( isAssignableFrom( aTypeWarning, aNextElementType ) ) + { + m_eCurrentType = SQLExceptionInfo::TYPE::SQLWarning; + return pReturn; + } + + // a simple SQLException + m_eCurrentType = SQLExceptionInfo::TYPE::SQLException; + return pReturn; +} + + +void SQLExceptionIteratorHelper::next( SQLExceptionInfo& _out_rInfo ) +{ + current( _out_rInfo ); + next(); +} + + +void throwFunctionSequenceException(const Reference< XInterface >& Context, const Any& Next) +{ + ::connectivity::SharedResources aResources; + throw SQLException( + aResources.getResourceString(STR_ERRORMSG_SEQUENCE), + Context, + getStandardSQLState( StandardSQLState::FUNCTION_SEQUENCE_ERROR ), + 0, + Next + ); +} + +void throwInvalidIndexException(const css::uno::Reference< css::uno::XInterface >& Context, + const css::uno::Any& Next) +{ + ::connectivity::SharedResources aResources; + throw SQLException( + aResources.getResourceString(STR_INVALID_INDEX), + Context, + getStandardSQLState( StandardSQLState::INVALID_DESCRIPTOR_INDEX ), + 0, + Next + ); +} + +void throwFunctionNotSupportedSQLException(const OUString& _rFunctionName, + const css::uno::Reference& _rxContext) +{ + ::connectivity::SharedResources aResources; + const OUString sError( aResources.getResourceStringWithSubstitution( + STR_UNSUPPORTED_FUNCTION, + "$functionname$", _rFunctionName + ) ); + throw SQLException( + sError, + _rxContext, + getStandardSQLState( StandardSQLState::FUNCTION_NOT_SUPPORTED ), + 0, + css::uno::Any() + ); +} + +void throwFunctionNotSupportedRuntimeException(const OUString& _rFunctionName, + const css::uno::Reference& _rxContext) +{ + ::connectivity::SharedResources aResources; + const OUString sError( aResources.getResourceStringWithSubstitution( + STR_UNSUPPORTED_FUNCTION, + "$functionname$", _rFunctionName + ) ); + throw RuntimeException( + sError, + _rxContext + ); +} + +void throwGenericSQLException(const OUString& _rMsg, const css::uno::Reference< css::uno::XInterface >& _rxSource) +{ + throwGenericSQLException(_rMsg, _rxSource, Any()); +} + + +void throwGenericSQLException(const OUString& _rMsg, const Reference< XInterface >& _rxSource, const Any& _rNextException) +{ + throw SQLException( _rMsg, _rxSource, getStandardSQLState( StandardSQLState::GENERAL_ERROR ), 0, _rNextException); +} + +void throwFeatureNotImplementedSQLException( const OUString& _rFeatureName, const Reference< XInterface >& _rxContext, const Any& _rNextException ) +{ + ::connectivity::SharedResources aResources; + const OUString sError( aResources.getResourceStringWithSubstitution( + STR_UNSUPPORTED_FEATURE, + "$featurename$", _rFeatureName + ) ); + + throw SQLException( + sError, + _rxContext, + getStandardSQLState( StandardSQLState::FEATURE_NOT_IMPLEMENTED ), + 0, + _rNextException + ); +} + +void throwFeatureNotImplementedRuntimeException(const OUString& _rFeatureName, const Reference< XInterface >& _rxContext) +{ + ::connectivity::SharedResources aResources; + const OUString sError( aResources.getResourceStringWithSubstitution( + STR_UNSUPPORTED_FEATURE, + "$featurename$", _rFeatureName + ) ); + + throw RuntimeException(sError, _rxContext); +} + +void throwInvalidColumnException( const OUString& _rColumnName, const Reference< XInterface >& _rxContext) +{ + ::connectivity::SharedResources aResources; + OUString sErrorMessage( aResources.getResourceStringWithSubstitution( + STR_INVALID_COLUMNNAME, + "$columnname$",_rColumnName) ); + throwSQLException( sErrorMessage, StandardSQLState::COLUMN_NOT_FOUND, _rxContext ); +} + +void throwSQLException( const OUString& _rMessage, const OUString& _rSQLState, + const Reference< XInterface >& _rxContext, const sal_Int32 _nErrorCode ) +{ + throw SQLException( + _rMessage, + _rxContext, + _rSQLState, + _nErrorCode, + Any() + ); +} + + +void throwSQLException( const OUString& _rMessage, StandardSQLState _eSQLState, + const Reference< XInterface >& _rxContext, const sal_Int32 _nErrorCode ) +{ + throwSQLException( _rMessage, getStandardSQLState( _eSQLState ), _rxContext, _nErrorCode ); +} + + +OUString getStandardSQLState( StandardSQLState _eState ) +{ + switch ( _eState ) + { + case StandardSQLState::INVALID_DESCRIPTOR_INDEX: return "07009"; + case StandardSQLState::INVALID_CURSOR_STATE: return "24000"; + case StandardSQLState::COLUMN_NOT_FOUND: return "42S22"; + case StandardSQLState::GENERAL_ERROR: return "HY000"; + case StandardSQLState::INVALID_SQL_DATA_TYPE: return "HY004"; + case StandardSQLState::FUNCTION_SEQUENCE_ERROR: return "HY010"; + case StandardSQLState::INVALID_CURSOR_POSITION: return "HY109"; + case StandardSQLState::FEATURE_NOT_IMPLEMENTED: return "HYC00"; + case StandardSQLState::FUNCTION_NOT_SUPPORTED: return "IM001"; + case StandardSQLState::CONNECTION_DOES_NOT_EXIST: return "08003"; + default: return "HY001"; // General Error + } +} + + +} // namespace dbtools + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/commontools/dbmetadata.cxx b/connectivity/source/commontools/dbmetadata.cxx new file mode 100644 index 000000000..7eb148735 --- /dev/null +++ b/connectivity/source/commontools/dbmetadata.cxx @@ -0,0 +1,443 @@ +/* -*- 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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + + +namespace dbtools +{ + + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::sdbc::XConnection; + using ::com::sun::star::sdbc::XDatabaseMetaData; + using ::com::sun::star::sdbc::XDatabaseMetaData2; + using ::com::sun::star::lang::IllegalArgumentException; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::uno::Any; + using ::com::sun::star::uno::XComponentContext; + using ::com::sun::star::container::XChild; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::beans::XPropertySet; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::sdbcx::XUsersSupplier; + using ::com::sun::star::sdbcx::XDataDefinitionSupplier; + using ::com::sun::star::sdbc::DriverManager; + using ::com::sun::star::sdbc::XDriverManager2; + using ::com::sun::star::uno::UNO_SET_THROW; + + namespace BooleanComparisonMode = ::com::sun::star::sdb::BooleanComparisonMode; + + struct DatabaseMetaData_Impl + { + Reference< XConnection > xConnection; + Reference< XDatabaseMetaData > xConnectionMetaData; + ::connectivity::DriversConfig aDriverConfig; + + ::std::optional< OUString > sCachedIdentifierQuoteString; + ::std::optional< OUString > sCachedCatalogSeparator; + + DatabaseMetaData_Impl() + : aDriverConfig( ::comphelper::getProcessComponentContext() ) + { + } + }; + + + namespace + { + + void lcl_construct( DatabaseMetaData_Impl& _metaDataImpl, const Reference< XConnection >& _connection ) + { + _metaDataImpl.xConnection = _connection; + if ( !_metaDataImpl.xConnection.is() ) + return; + + _metaDataImpl.xConnectionMetaData = _connection->getMetaData(); + if ( !_metaDataImpl.xConnectionMetaData.is() ) + throw IllegalArgumentException(); + } + + + void lcl_checkConnected( const DatabaseMetaData_Impl& _metaDataImpl ) + { + if ( !_metaDataImpl.xConnection.is() || !_metaDataImpl.xConnectionMetaData.is() ) + { + ::connectivity::SharedResources aResources; + const OUString sError( aResources.getResourceString(STR_NO_CONNECTION_GIVEN)); + throwSQLException( sError, StandardSQLState::CONNECTION_DOES_NOT_EXIST, nullptr ); + } + } + + + bool lcl_getDriverSetting( const OUString& _asciiName, const DatabaseMetaData_Impl& _metaData, Any& _out_setting ) + { + lcl_checkConnected( _metaData ); + const ::comphelper::NamedValueCollection& rDriverMetaData = _metaData.aDriverConfig.getMetaData( _metaData.xConnectionMetaData->getURL() ); + if ( !rDriverMetaData.has( _asciiName ) ) + return false; + _out_setting = rDriverMetaData.get( _asciiName ); + return true; + } + + + bool lcl_getConnectionSetting(const OUString& _asciiName, const DatabaseMetaData_Impl& _metaData, Any& _out_setting ) + { + try + { + Reference< XChild > xConnectionAsChild( _metaData.xConnection, UNO_QUERY ); + if ( xConnectionAsChild.is() ) + { + Reference< XPropertySet > xDataSource( xConnectionAsChild->getParent(), UNO_QUERY_THROW ); + Reference< XPropertySet > xDataSourceSettings( + xDataSource->getPropertyValue("Settings"), + UNO_QUERY_THROW ); + + _out_setting = xDataSourceSettings->getPropertyValue( _asciiName ); + } + else + { + Reference< XDatabaseMetaData2 > xExtendedMetaData( _metaData.xConnectionMetaData, UNO_QUERY_THROW ); + _out_setting = ::comphelper::NamedValueCollection::get( xExtendedMetaData->getConnectionInfo(), _asciiName ); + return _out_setting.hasValue(); + } + return true; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("connectivity.commontools"); + } + return false; + } + + + const OUString& lcl_getConnectionStringSetting( + const DatabaseMetaData_Impl& _metaData, ::std::optional< OUString >& _cachedSetting, + OUString (SAL_CALL XDatabaseMetaData::*_getter)() ) + { + if ( !_cachedSetting ) + { + lcl_checkConnected( _metaData ); + try + { + _cachedSetting = (_metaData.xConnectionMetaData.get()->*_getter)(); + } + catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION("connectivity.commontools"); } + } + return *_cachedSetting; + } + } + + DatabaseMetaData::DatabaseMetaData() + :m_pImpl( new DatabaseMetaData_Impl ) + { + } + + DatabaseMetaData::DatabaseMetaData( const Reference< XConnection >& _connection ) + :m_pImpl( new DatabaseMetaData_Impl ) + { + lcl_construct( *m_pImpl, _connection ); + } + + + DatabaseMetaData::DatabaseMetaData( const DatabaseMetaData& _copyFrom ) + :m_pImpl( new DatabaseMetaData_Impl( *_copyFrom.m_pImpl ) ) + { + } + + DatabaseMetaData::DatabaseMetaData(DatabaseMetaData&& _copyFrom) noexcept + :m_pImpl(std::move(_copyFrom.m_pImpl)) + { + } + + DatabaseMetaData& DatabaseMetaData::operator=( const DatabaseMetaData& _copyFrom ) + { + if ( this == &_copyFrom ) + return *this; + + m_pImpl.reset( new DatabaseMetaData_Impl( *_copyFrom.m_pImpl ) ); + return *this; + } + + DatabaseMetaData& DatabaseMetaData::operator=(DatabaseMetaData&& _copyFrom) noexcept + { + m_pImpl = std::move(_copyFrom.m_pImpl); + return *this; + } + + DatabaseMetaData::~DatabaseMetaData() + { + } + + bool DatabaseMetaData::isConnected() const + { + return m_pImpl->xConnection.is(); + } + + + bool DatabaseMetaData::supportsSubqueriesInFrom() const + { + lcl_checkConnected( *m_pImpl ); + + bool bSupportsSubQueries = false; + try + { + sal_Int32 maxTablesInselect = m_pImpl->xConnectionMetaData->getMaxTablesInSelect(); + bSupportsSubQueries = ( maxTablesInselect > 1 ) || ( maxTablesInselect == 0 ); + // TODO: is there a better way to determine this? The above is not really true. More precise, + // it's a *very* generous heuristics ... + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("connectivity.commontools"); + } + return bSupportsSubQueries; + } + + + bool DatabaseMetaData::supportsPrimaryKeys() const + { + lcl_checkConnected( *m_pImpl ); + + bool bDoesSupportPrimaryKeys = false; + try + { + Any setting; + if ( !( lcl_getConnectionSetting( "PrimaryKeySupport", *m_pImpl, setting ) ) + || !( setting >>= bDoesSupportPrimaryKeys ) + ) + bDoesSupportPrimaryKeys = m_pImpl->xConnectionMetaData->supportsCoreSQLGrammar() + || m_pImpl->xConnectionMetaData->supportsANSI92EntryLevelSQL(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("connectivity.commontools"); + } + return bDoesSupportPrimaryKeys; + } + + + const OUString& DatabaseMetaData::getIdentifierQuoteString() const + { + return lcl_getConnectionStringSetting( *m_pImpl, m_pImpl->sCachedIdentifierQuoteString, &XDatabaseMetaData::getIdentifierQuoteString ); + } + + + const OUString& DatabaseMetaData::getCatalogSeparator() const + { + return lcl_getConnectionStringSetting( *m_pImpl, m_pImpl->sCachedCatalogSeparator, &XDatabaseMetaData::getCatalogSeparator ); + } + + + bool DatabaseMetaData::restrictIdentifiersToSQL92() const + { + lcl_checkConnected( *m_pImpl ); + + bool restrict( false ); + Any setting; + if ( lcl_getConnectionSetting( "EnableSQL92Check", *m_pImpl, setting ) ) + if( ! (setting >>= restrict) ) + SAL_WARN("connectivity.commontools", "restrictIdentifiersToSQL92: unable to assign EnableSQL92Check"); + return restrict; + } + + + bool DatabaseMetaData::generateASBeforeCorrelationName() const + { + bool doGenerate( false ); + Any setting; + if ( lcl_getConnectionSetting( "GenerateASBeforeCorrelationName", *m_pImpl, setting ) ) + if( ! (setting >>= doGenerate) ) + SAL_WARN("connectivity.commontools", "generateASBeforeCorrelationName: unable to assign GenerateASBeforeCorrelationName"); + return doGenerate; + } + + bool DatabaseMetaData::shouldEscapeDateTime() const + { + bool doGenerate( true ); + Any setting; + if ( lcl_getConnectionSetting( "EscapeDateTime", *m_pImpl, setting ) ) + if( ! (setting >>= doGenerate) ) + SAL_WARN("connectivity.commontools", "shouldEscapeDateTime: unable to assign EscapeDateTime"); + return doGenerate; + } + + bool DatabaseMetaData::shouldSubstituteParameterNames() const + { + bool doSubstitute( true ); + Any setting; + if ( lcl_getConnectionSetting( "ParameterNameSubstitution", *m_pImpl, setting ) ) + if( ! (setting >>= doSubstitute) ) + SAL_WARN("connectivity.commontools", "shouldSubstituteParameterNames: unable to assign ParameterNameSubstitution"); + return doSubstitute; + } + + bool DatabaseMetaData::isAutoIncrementPrimaryKey() const + { + bool is( true ); + Any setting; + if ( lcl_getDriverSetting( "AutoIncrementIsPrimaryKey", *m_pImpl, setting ) ) + if( ! (setting >>= is) ) + SAL_WARN("connectivity.commontools", "isAutoIncrementPrimaryKey: unable to assign AutoIncrementIsPrimaryKey"); + return is; + } + + sal_Int32 DatabaseMetaData::getBooleanComparisonMode() const + { + sal_Int32 mode( BooleanComparisonMode::EQUAL_INTEGER ); + Any setting; + if ( lcl_getConnectionSetting( "BooleanComparisonMode", *m_pImpl, setting ) ) + if( ! (setting >>= mode) ) + SAL_WARN("connectivity.commontools", "getBooleanComparisonMode: unable to assign BooleanComparisonMode"); + return mode; + } + + bool DatabaseMetaData::supportsRelations() const + { + lcl_checkConnected( *m_pImpl ); + bool bSupport = false; + try + { + bSupport = m_pImpl->xConnectionMetaData->supportsIntegrityEnhancementFacility(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("connectivity.commontools"); + } + try + { + if ( !bSupport ) + { + const OUString url = m_pImpl->xConnectionMetaData->getURL(); + bSupport = url.startsWith("sdbc:mysql"); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("connectivity.commontools"); + } + return bSupport; + } + + + bool DatabaseMetaData::supportsColumnAliasInOrderBy() const + { + bool doGenerate( true ); + Any setting; + if ( lcl_getConnectionSetting( "ColumnAliasInOrderBy", *m_pImpl, setting ) ) + if( ! (setting >>= doGenerate) ) + SAL_WARN("connectivity.commontools", "supportsColumnAliasInOrderBy: unable to assign ColumnAliasInOrderBy"); + return doGenerate; + } + + + bool DatabaseMetaData::supportsUserAdministration( const Reference& _rContext ) const + { + lcl_checkConnected( *m_pImpl ); + + bool isSupported( false ); + try + { + // find the XUsersSupplier interface + // - either directly at the connection + Reference< XUsersSupplier > xUsersSupp( m_pImpl->xConnection, UNO_QUERY ); + if ( !xUsersSupp.is() ) + { + // - or at the driver manager + Reference< XDriverManager2 > xDriverManager = DriverManager::create( _rContext ); + Reference< XDataDefinitionSupplier > xDriver( xDriverManager->getDriverByURL( m_pImpl->xConnectionMetaData->getURL() ), UNO_QUERY ); + if ( xDriver.is() ) + xUsersSupp.set( xDriver->getDataDefinitionByConnection( m_pImpl->xConnection ), UNO_QUERY ); + } + + isSupported = ( xUsersSupp.is() && xUsersSupp->getUsers().is() ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("connectivity.commontools"); + } + return isSupported; + } + + + bool DatabaseMetaData::displayEmptyTableFolders() const + { + bool doDisplay( true ); +#ifdef IMPLEMENTED_LATER + Any setting; + if ( lcl_getConnectionSetting( "DisplayEmptyTableFolders", *m_pImpl, setting ) ) + if( ! (setting >>= doDisplay) ) + SAL_WARN("connectivity.commontools", "displayEmptyTableFolders: unable to assign DisplayEmptyTableFolders"); +#else + try + { + Reference< XDatabaseMetaData > xMeta( m_pImpl->xConnectionMetaData, UNO_SET_THROW ); + OUString sConnectionURL( xMeta->getURL() ); + doDisplay = sConnectionURL.startsWith( "sdbc:mysql:mysqlc" ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("connectivity.commontools"); + } +#endif + return doDisplay; + } + + bool DatabaseMetaData::supportsThreads() const + { + bool bSupported( true ); + try + { + Reference< XDatabaseMetaData > xMeta( m_pImpl->xConnectionMetaData, UNO_SET_THROW ); + OUString sConnectionURL( xMeta->getURL() ); + bSupported = !sConnectionURL.startsWith( "sdbc:mysql:mysqlc" ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("connectivity.commontools"); + } + return bSupported; + } + + +} // namespace dbtools + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/commontools/dbtools.cxx b/connectivity/source/commontools/dbtools.cxx new file mode 100644 index 000000000..7f6f5fb17 --- /dev/null +++ b/connectivity/source/commontools/dbtools.cxx @@ -0,0 +1,2073 @@ +/* -*- 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 +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +using namespace ::comphelper; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::awt; +using namespace ::com::sun::star::ui::dialogs; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::task; +using namespace ::com::sun::star::form; +using namespace connectivity; + +namespace dbtools +{ + +namespace +{ + typedef sal_Bool (SAL_CALL XDatabaseMetaData::*FMetaDataSupport)(); +} + +sal_Int32 getDefaultNumberFormat(const Reference< XPropertySet >& _xColumn, + const Reference< XNumberFormatTypes >& _xTypes, + const Locale& _rLocale) +{ + OSL_ENSURE(_xTypes.is() && _xColumn.is(), "dbtools::getDefaultNumberFormat: invalid arg !"); + if (!_xTypes.is() || !_xColumn.is()) + return NumberFormat::UNDEFINED; + + sal_Int32 nDataType = 0; + sal_Int32 nScale = 0; + try + { + // determine the datatype of the column + _xColumn->getPropertyValue("Type") >>= nDataType; + + if (DataType::NUMERIC == nDataType || DataType::DECIMAL == nDataType) + _xColumn->getPropertyValue("Scale") >>= nScale; + } + catch (Exception&) + { + return NumberFormat::UNDEFINED; + } + return getDefaultNumberFormat(nDataType, + nScale, + ::cppu::any2bool(_xColumn->getPropertyValue("IsCurrency")), + _xTypes, + _rLocale); +} + +sal_Int32 getDefaultNumberFormat(sal_Int32 _nDataType, + sal_Int32 _nScale, + bool _bIsCurrency, + const Reference< XNumberFormatTypes >& _xTypes, + const Locale& _rLocale) +{ + OSL_ENSURE(_xTypes.is() , "dbtools::getDefaultNumberFormat: invalid arg !"); + if (!_xTypes.is()) + return NumberFormat::UNDEFINED; + + sal_Int32 nFormat = 0; + sal_Int32 nNumberType = _bIsCurrency ? NumberFormat::CURRENCY : NumberFormat::NUMBER; + switch (_nDataType) + { + case DataType::BIT: + case DataType::BOOLEAN: + nFormat = _xTypes->getStandardFormat(NumberFormat::LOGICAL, _rLocale); + break; + case DataType::TINYINT: + case DataType::SMALLINT: + case DataType::INTEGER: + case DataType::BIGINT: + case DataType::FLOAT: + case DataType::REAL: + case DataType::DOUBLE: + case DataType::NUMERIC: + case DataType::DECIMAL: + { + try + { + nFormat = _xTypes->getStandardFormat(static_cast(nNumberType), _rLocale); + if(_nScale > 0) + { + // generate a new format if necessary + Reference< XNumberFormats > xFormats(_xTypes, UNO_QUERY); + OUString sNewFormat = xFormats->generateFormat( 0, _rLocale, false, false, static_cast(_nScale), 1); + + // and add it to the formatter if necessary + nFormat = xFormats->queryKey(sNewFormat, _rLocale, false); + if (nFormat == sal_Int32(-1)) + nFormat = xFormats->addNew(sNewFormat, _rLocale); + } + } + catch (Exception&) + { + nFormat = _xTypes->getStandardFormat(static_cast(nNumberType), _rLocale); + } + } break; + case DataType::CHAR: + case DataType::VARCHAR: + case DataType::LONGVARCHAR: + case DataType::CLOB: + nFormat = _xTypes->getStandardFormat(NumberFormat::TEXT, _rLocale); + break; + case DataType::DATE: + nFormat = _xTypes->getStandardFormat(NumberFormat::DATE, _rLocale); + break; + case DataType::TIME: + nFormat = _xTypes->getStandardFormat(NumberFormat::TIME, _rLocale); + break; + case DataType::TIMESTAMP: + nFormat = _xTypes->getStandardFormat(NumberFormat::DATETIME, _rLocale); + break; + case DataType::BINARY: + case DataType::VARBINARY: + case DataType::LONGVARBINARY: + case DataType::SQLNULL: + case DataType::OTHER: + case DataType::OBJECT: + case DataType::DISTINCT: + case DataType::STRUCT: + case DataType::ARRAY: + case DataType::BLOB: + case DataType::REF: + default: + nFormat = _xTypes->getStandardFormat(NumberFormat::UNDEFINED, _rLocale); + } + return nFormat; +} + +static Reference< XConnection> findConnection(const Reference< XInterface >& xParent) +{ + Reference< XConnection> xConnection(xParent, UNO_QUERY); + if (!xConnection.is()) + { + Reference< XChild> xChild(xParent, UNO_QUERY); + if (xChild.is()) + xConnection = findConnection(xChild->getParent()); + } + return xConnection; +} + +static Reference< XDataSource> getDataSource_allowException( + const OUString& _rsTitleOrPath, + const Reference< XComponentContext >& _rxContext ) +{ + ENSURE_OR_RETURN( !_rsTitleOrPath.isEmpty(), "getDataSource_allowException: invalid arg !", nullptr ); + + Reference< XDatabaseContext> xDatabaseContext = DatabaseContext::create(_rxContext); + + return Reference< XDataSource >( xDatabaseContext->getByName( _rsTitleOrPath ), UNO_QUERY ); +} + +Reference< XDataSource > getDataSource( + const OUString& _rsTitleOrPath, + const Reference< XComponentContext >& _rxContext ) +{ + Reference< XDataSource > xDS; + try + { + xDS = getDataSource_allowException( _rsTitleOrPath, _rxContext ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("connectivity.commontools"); + } + + return xDS; +} + +static Reference< XConnection > getConnection_allowException( + const OUString& _rsTitleOrPath, + const OUString& _rsUser, + const OUString& _rsPwd, + const Reference< XComponentContext>& _rxContext, + const Reference< XWindow >& _rxParent) +{ + Reference< XDataSource> xDataSource( getDataSource_allowException(_rsTitleOrPath, _rxContext) ); + Reference xConnection; + if (xDataSource.is()) + { + + //set ParentWindow for dialog, but just for the duration of this + //call, undo at end of scope + Reference xIni(xDataSource, UNO_QUERY); + if (xIni.is()) + { + Sequence< Any > aArgs{ Any(NamedValue( "ParentWindow", Any(_rxParent) )) }; + xIni->initialize(aArgs); + } + + // do it with interaction handler + if(_rsUser.isEmpty() || _rsPwd.isEmpty()) + { + Reference xProp(xDataSource,UNO_QUERY); + OUString sPwd, sUser; + bool bPwdReq = false; + try + { + xProp->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PASSWORD)) >>= sPwd; + bPwdReq = ::cppu::any2bool(xProp->getPropertyValue("IsPasswordRequired")); + xProp->getPropertyValue("User") >>= sUser; + } + catch(Exception&) + { + OSL_FAIL("dbtools::getConnection: error while retrieving data source properties!"); + } + if(bPwdReq && sPwd.isEmpty()) + { // password required, but empty -> connect using an interaction handler + Reference xConnectionCompletion(xProp, UNO_QUERY); + if (xConnectionCompletion.is()) + { // instantiate the default SDB interaction handler + Reference< XInteractionHandler > xHandler = + InteractionHandler::createWithParent(_rxContext, _rxParent); + xConnection = xConnectionCompletion->connectWithCompletion(xHandler); + } + } + else + xConnection = xDataSource->getConnection(sUser, sPwd); + } + if(!xConnection.is()) // try to get one if not already have one, just to make sure + xConnection = xDataSource->getConnection(_rsUser, _rsPwd); + + if (xIni.is()) + { + Sequence< Any > aArgs{ Any(NamedValue( "ParentWindow", Any(Reference()) )) }; + xIni->initialize(aArgs); + } + + } + return xConnection; +} + +Reference< XConnection> getConnection_withFeedback(const OUString& _rDataSourceName, + const OUString& _rUser, const OUString& _rPwd, const Reference< XComponentContext>& _rxContext, + const Reference< XWindow >& _rxParent) +{ + Reference< XConnection > xReturn; + try + { + xReturn = getConnection_allowException(_rDataSourceName, _rUser, _rPwd, _rxContext, _rxParent); + } + catch(SQLException&) + { + // allowed to pass + throw; + } + catch(Exception&) + { + TOOLS_WARN_EXCEPTION( "connectivity.commontools", "::dbtools::getConnection_withFeedback: unexpected (non-SQL) exception caught!"); + } + return xReturn; +} + +Reference< XConnection> getConnection(const Reference< XRowSet>& _rxRowSet) +{ + Reference< XConnection> xReturn; + Reference< XPropertySet> xRowSetProps(_rxRowSet, UNO_QUERY); + if (xRowSetProps.is()) + xRowSetProps->getPropertyValue("ActiveConnection") >>= xReturn; + return xReturn; +} + +// helper function which allows to implement both the connectRowset and the ensureRowSetConnection semantics +// if connectRowset (which is deprecated) is removed, this function and one of its parameters are +// not needed anymore, the whole implementation can be moved into ensureRowSetConnection then) +static SharedConnection lcl_connectRowSet(const Reference< XRowSet>& _rxRowSet, const Reference< XComponentContext >& _rxContext, + bool _bAttachAutoDisposer, const Reference< XWindow >& _rxParent) +{ + SharedConnection xConnection; + + do + { + Reference< XPropertySet> xRowSetProps(_rxRowSet, UNO_QUERY); + if ( !xRowSetProps.is() ) + break; + + // 1. already connected? + Reference< XConnection > xExistingConn( + xRowSetProps->getPropertyValue("ActiveConnection"), + UNO_QUERY ); + + if ( xExistingConn.is() + // 2. embedded in a database? + || isEmbeddedInDatabase( _rxRowSet, xExistingConn ) + // 3. is there a connection in the parent hierarchy? + || ( xExistingConn = findConnection( _rxRowSet ) ).is() + ) + { + xRowSetProps->setPropertyValue("ActiveConnection", Any( xExistingConn ) ); + // no auto disposer needed, since we did not create the connection + + xConnection.reset( xExistingConn, SharedConnection::NoTakeOwnership ); + break; + } + + // build a connection with its current settings (4. data source name, or 5. URL) + + static const OUStringLiteral sUserProp( u"User" ); + OUString sDataSourceName; + xRowSetProps->getPropertyValue("DataSourceName") >>= sDataSourceName; + OUString sURL; + xRowSetProps->getPropertyValue("URL") >>= sURL; + + Reference< XConnection > xPureConnection; + if (!sDataSourceName.isEmpty()) + { // the row set's data source property is set + // -> try to connect, get user and pwd setting for that + OUString sUser, sPwd; + + if (hasProperty(sUserProp, xRowSetProps)) + xRowSetProps->getPropertyValue(sUserProp) >>= sUser; + if (hasProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PASSWORD), xRowSetProps)) + xRowSetProps->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PASSWORD)) >>= sPwd; + + xPureConnection = getConnection_allowException( sDataSourceName, sUser, sPwd, _rxContext, _rxParent ); + } + else if (!sURL.isEmpty()) + { // the row set has no data source, but a connection url set + // -> try to connection with that url + Reference< XConnectionPool > xDriverManager; + try { + xDriverManager = ConnectionPool::create( _rxContext ); + } catch( const Exception& ) { } + if (xDriverManager.is()) + { + OUString sUser, sPwd; + if (hasProperty(sUserProp, xRowSetProps)) + xRowSetProps->getPropertyValue(sUserProp) >>= sUser; + if (hasProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PASSWORD), xRowSetProps)) + xRowSetProps->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PASSWORD)) >>= sPwd; + if (!sUser.isEmpty()) + { // use user and pwd together with the url + auto aInfo(::comphelper::InitPropertySequence({ + { "user", Any(sUser) }, + { "password", Any(sPwd) } + })); + xPureConnection = xDriverManager->getConnectionWithInfo( sURL, aInfo ); + } + else + // just use the url + xPureConnection = xDriverManager->getConnection( sURL ); + } + } + xConnection.reset( + xPureConnection, + _bAttachAutoDisposer ? SharedConnection::NoTakeOwnership : SharedConnection::TakeOwnership + /* take ownership if and only if we're *not* going to auto-dispose the connection */ + ); + + // now if we created a connection, forward it to the row set + if ( xConnection.is() ) + { + try + { + if ( _bAttachAutoDisposer ) + { + new OAutoConnectionDisposer( _rxRowSet, xConnection ); + } + else + xRowSetProps->setPropertyValue( + "ActiveConnection", + Any( xConnection.getTyped() ) + ); + } + catch(Exception&) + { + TOOLS_WARN_EXCEPTION( "connectivity.commontools", "EXception when we set the new active connection!"); + } + } + } + while ( false ); + + return xConnection; +} + +Reference< XConnection> connectRowset(const Reference< XRowSet>& _rxRowSet, const Reference< XComponentContext >& _rxContext, const Reference< XWindow >& _rxParent) +{ + SharedConnection xConnection = lcl_connectRowSet( _rxRowSet, _rxContext, true, _rxParent ); + return xConnection.getTyped(); +} + +SharedConnection ensureRowSetConnection(const Reference< XRowSet>& _rxRowSet, const Reference< XComponentContext>& _rxContext, const Reference< XWindow >& _rxParent) +{ + return lcl_connectRowSet( _rxRowSet, _rxContext, false/*bUseAutoConnectionDisposer*/, _rxParent ); +} + +Reference< XNameAccess> getTableFields(const Reference< XConnection>& _rxConn,const OUString& _rName) +{ + Reference< XComponent > xDummy; + return getFieldsByCommandDescriptor( _rxConn, CommandType::TABLE, _rName, xDummy ); +} + +Reference< XNameAccess> getPrimaryKeyColumns_throw(const Any& i_aTable) +{ + const Reference< XPropertySet > xTable(i_aTable,UNO_QUERY_THROW); + return getPrimaryKeyColumns_throw(xTable); +} + +Reference< XNameAccess> getPrimaryKeyColumns_throw(const Reference< XPropertySet >& i_xTable) +{ + Reference xKeyColumns; + const Reference xKeySup(i_xTable,UNO_QUERY); + if ( xKeySup.is() ) + { + const Reference xKeys = xKeySup->getKeys(); + if ( xKeys.is() ) + { + ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap(); + const OUString& sPropName = rPropMap.getNameByIndex(PROPERTY_ID_TYPE); + Reference xProp; + const sal_Int32 nCount = xKeys->getCount(); + for(sal_Int32 i = 0;i< nCount;++i) + { + xProp.set(xKeys->getByIndex(i),UNO_QUERY_THROW); + sal_Int32 nKeyType = 0; + xProp->getPropertyValue(sPropName) >>= nKeyType; + if(KeyType::PRIMARY == nKeyType) + { + const Reference xKeyColsSup(xProp,UNO_QUERY_THROW); + xKeyColumns = xKeyColsSup->getColumns(); + break; + } + } + } + } + + return xKeyColumns; +} + +namespace +{ + enum FieldLookupState + { + HANDLE_TABLE, HANDLE_QUERY, HANDLE_SQL, RETRIEVE_OBJECT, RETRIEVE_COLUMNS, DONE, FAILED + }; +} + +Reference< XNameAccess > getFieldsByCommandDescriptor( const Reference< XConnection >& _rxConnection, + const sal_Int32 _nCommandType, const OUString& _rCommand, + Reference< XComponent >& _rxKeepFieldsAlive, SQLExceptionInfo* _pErrorInfo ) +{ + OSL_PRECOND( _rxConnection.is(), "::dbtools::getFieldsByCommandDescriptor: invalid connection!" ); + OSL_PRECOND( ( CommandType::TABLE == _nCommandType ) || ( CommandType::QUERY == _nCommandType ) || ( CommandType::COMMAND == _nCommandType ), + "::dbtools::getFieldsByCommandDescriptor: invalid command type!" ); + OSL_PRECOND( !_rCommand.isEmpty(), "::dbtools::getFieldsByCommandDescriptor: invalid command (empty)!" ); + + Reference< XNameAccess > xFields; + + // reset the error + if ( _pErrorInfo ) + *_pErrorInfo = SQLExceptionInfo(); + // reset the ownership holder + _rxKeepFieldsAlive.clear(); + + // go for the fields + try + { + // some kind of state machine to ease the sharing of code + FieldLookupState eState = FAILED; + switch ( _nCommandType ) + { + case CommandType::TABLE: + eState = HANDLE_TABLE; + break; + case CommandType::QUERY: + eState = HANDLE_QUERY; + break; + case CommandType::COMMAND: + eState = HANDLE_SQL; + break; + } + + // needed in various states: + Reference< XNameAccess > xObjectCollection; + Reference< XColumnsSupplier > xSupplyColumns; + + // go! + while ( ( DONE != eState ) && ( FAILED != eState ) ) + { + switch ( eState ) + { + case HANDLE_TABLE: + { + // initial state for handling the tables + + // get the table objects + Reference< XTablesSupplier > xSupplyTables( _rxConnection, UNO_QUERY ); + if ( xSupplyTables.is() ) + xObjectCollection = xSupplyTables->getTables(); + // if something went wrong 'til here, then this will be handled in the next state + + // next state: get the object + eState = RETRIEVE_OBJECT; + } + break; + + case HANDLE_QUERY: + { + // initial state for handling the tables + + // get the table objects + Reference< XQueriesSupplier > xSupplyQueries( _rxConnection, UNO_QUERY ); + if ( xSupplyQueries.is() ) + xObjectCollection = xSupplyQueries->getQueries(); + // if something went wrong 'til here, then this will be handled in the next state + + // next state: get the object + eState = RETRIEVE_OBJECT; + } + break; + + case RETRIEVE_OBJECT: + // here we should have an object (aka query or table) collection, and are going + // to retrieve the desired object + + // next state: default to FAILED + eState = FAILED; + + OSL_ENSURE( xObjectCollection.is(), "::dbtools::getFieldsByCommandDescriptor: invalid connection (no sdb.Connection, or no Tables-/QueriesSupplier)!"); + if ( xObjectCollection.is() && xObjectCollection->hasByName( _rCommand ) ) + { + xObjectCollection->getByName( _rCommand ) >>= xSupplyColumns; + // (xSupplyColumns being NULL will be handled in the next state) + + // next: go for the columns + eState = RETRIEVE_COLUMNS; + } + break; + + case RETRIEVE_COLUMNS: + OSL_ENSURE( xSupplyColumns.is(), "::dbtools::getFieldsByCommandDescriptor: could not retrieve the columns supplier!" ); + + // next state: default to FAILED + eState = FAILED; + + if ( xSupplyColumns.is() ) + { + xFields = xSupplyColumns->getColumns(); + // that's it + eState = DONE; + } + break; + + case HANDLE_SQL: + { + OUString sStatementToExecute( _rCommand ); + + // well, the main problem here is to handle statements which contain a parameter + // If we would simply execute a parametrized statement, then this will fail because + // we cannot supply any parameter values. + // Thus, we try to analyze the statement, and to append a WHERE 0=1 filter criterion + // This should cause every driver to not really execute the statement, but to return + // an empty result set with the proper structure. We then can use this result set + // to retrieve the columns. + + try + { + Reference< XMultiServiceFactory > xComposerFac( _rxConnection, UNO_QUERY ); + + if ( xComposerFac.is() ) + { + Reference< XSingleSelectQueryComposer > xComposer(xComposerFac->createInstance("com.sun.star.sdb.SingleSelectQueryComposer"),UNO_QUERY); + if ( xComposer.is() ) + { + xComposer->setQuery( sStatementToExecute ); + + // Now set the filter to a dummy restriction which will result in an empty + // result set. + xComposer->setFilter( "0=1" ); + sStatementToExecute = xComposer->getQuery( ); + } + } + } + catch( const Exception& ) + { + // silent this error, this was just a try. If we're here, we did not change sStatementToExecute, + // so it will still be _rCommand, which then will be executed without being touched + } + + // now execute + Reference< XPreparedStatement > xStatement = _rxConnection->prepareStatement( sStatementToExecute ); + // transfer ownership of this temporary object to the caller + _rxKeepFieldsAlive.set(xStatement, css::uno::UNO_QUERY); + + // set the "MaxRows" to 0. This is just in case our attempt to append a 0=1 filter + // failed - in this case, the MaxRows restriction should at least ensure that there + // is no data returned (which would be potentially expensive) + Reference< XPropertySet > xStatementProps( xStatement,UNO_QUERY ); + try + { + if ( xStatementProps.is() ) + xStatementProps->setPropertyValue( "MaxRows", Any( sal_Int32( 0 ) ) ); + } + catch( const Exception& ) + { + OSL_FAIL( "::dbtools::getFieldsByCommandDescriptor: could not set the MaxRows!" ); + // oh damn. Not much of a chance to recover, we will no retrieve the complete + // full blown result set + } + + xSupplyColumns.set(xStatement->executeQuery(), css::uno::UNO_QUERY); + // this should have given us a result set which does not contain any data, but + // the structural information we need + + // so the next state is to get the columns + eState = RETRIEVE_COLUMNS; + } + break; + + default: + OSL_FAIL( "::dbtools::getFieldsByCommandDescriptor: oops! unhandled state here!" ); + eState = FAILED; + } + } + } + catch( const SQLContext& e ) { if ( _pErrorInfo ) *_pErrorInfo = SQLExceptionInfo( e ); } + catch( const SQLWarning& e ) { if ( _pErrorInfo ) *_pErrorInfo = SQLExceptionInfo( e ); } + catch( const SQLException& e ) { if ( _pErrorInfo ) *_pErrorInfo = SQLExceptionInfo( e ); } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "connectivity.commontools", "::dbtools::getFieldsByCommandDescriptor: caught an exception while retrieving the fields!" ); + } + + return xFields; +} + +Sequence< OUString > getFieldNamesByCommandDescriptor( const Reference< XConnection >& _rxConnection, + const sal_Int32 _nCommandType, const OUString& _rCommand, + SQLExceptionInfo* _pErrorInfo ) +{ + // get the container for the fields + Reference< XComponent > xKeepFieldsAlive; + Reference< XNameAccess > xFieldContainer = getFieldsByCommandDescriptor( _rxConnection, _nCommandType, _rCommand, xKeepFieldsAlive, _pErrorInfo ); + + // get the names of the fields + Sequence< OUString > aNames; + if ( xFieldContainer.is() ) + aNames = xFieldContainer->getElementNames(); + + // clean up any temporary objects which have been created + disposeComponent( xKeepFieldsAlive ); + + // outta here + return aNames; +} + +SQLException prependErrorInfo( const SQLException& _rChainedException, const Reference< XInterface >& _rxContext, + const OUString& _rAdditionalError, const StandardSQLState _eSQLState ) +{ + return SQLException( _rAdditionalError, _rxContext, + _eSQLState == StandardSQLState::ERROR_UNSPECIFIED ? OUString() : getStandardSQLState( _eSQLState ), + 0, Any( _rChainedException ) ); +} + +namespace +{ + struct NameComponentSupport + { + const bool bCatalogs; + const bool bSchemas; + + NameComponentSupport( const bool _bCatalogs, const bool _bSchemas ) + :bCatalogs( _bCatalogs ) + ,bSchemas( _bSchemas ) + { + } + }; + + NameComponentSupport lcl_getNameComponentSupport( const Reference< XDatabaseMetaData >& _rxMetaData, EComposeRule _eComposeRule ) + { + OSL_PRECOND( _rxMetaData.is(), "lcl_getNameComponentSupport: invalid meta data!" ); + + FMetaDataSupport pCatalogCall = &XDatabaseMetaData::supportsCatalogsInDataManipulation; + FMetaDataSupport pSchemaCall = &XDatabaseMetaData::supportsSchemasInDataManipulation; + bool bIgnoreMetaData = false; + + switch ( _eComposeRule ) + { + case EComposeRule::InTableDefinitions: + pCatalogCall = &XDatabaseMetaData::supportsCatalogsInTableDefinitions; + pSchemaCall = &XDatabaseMetaData::supportsSchemasInTableDefinitions; + break; + case EComposeRule::InIndexDefinitions: + pCatalogCall = &XDatabaseMetaData::supportsCatalogsInIndexDefinitions; + pSchemaCall = &XDatabaseMetaData::supportsSchemasInIndexDefinitions; + break; + case EComposeRule::InProcedureCalls: + pCatalogCall = &XDatabaseMetaData::supportsCatalogsInProcedureCalls; + pSchemaCall = &XDatabaseMetaData::supportsSchemasInProcedureCalls; + break; + case EComposeRule::InPrivilegeDefinitions: + pCatalogCall = &XDatabaseMetaData::supportsCatalogsInPrivilegeDefinitions; + pSchemaCall = &XDatabaseMetaData::supportsSchemasInPrivilegeDefinitions; + break; + case EComposeRule::Complete: + bIgnoreMetaData = true; + break; + case EComposeRule::InDataManipulation: + // already properly set above + break; + } + return NameComponentSupport( + bIgnoreMetaData || (_rxMetaData.get()->*pCatalogCall)(), + bIgnoreMetaData || (_rxMetaData.get()->*pSchemaCall)() + ); + } +} + +static OUString impl_doComposeTableName( const Reference< XDatabaseMetaData >& _rxMetaData, + const OUString& _rCatalog, const OUString& _rSchema, const OUString& _rName, + bool _bQuote, EComposeRule _eComposeRule ) +{ + OSL_ENSURE(_rxMetaData.is(), "impl_doComposeTableName : invalid meta data !"); + if ( !_rxMetaData.is() ) + return OUString(); + OSL_ENSURE(!_rName.isEmpty(), "impl_doComposeTableName : at least the name should be non-empty !"); + + const OUString sQuoteString = _rxMetaData->getIdentifierQuoteString(); + const NameComponentSupport aNameComps( lcl_getNameComponentSupport( _rxMetaData, _eComposeRule ) ); + + OUStringBuffer aComposedName; + + OUString sCatalogSep; + bool bCatlogAtStart = true; + if ( !_rCatalog.isEmpty() && aNameComps.bCatalogs ) + { + sCatalogSep = _rxMetaData->getCatalogSeparator(); + bCatlogAtStart = _rxMetaData->isCatalogAtStart(); + + if ( bCatlogAtStart && !sCatalogSep.isEmpty()) + { + aComposedName.append( _bQuote ? quoteName( sQuoteString, _rCatalog ) : _rCatalog ); + aComposedName.append( sCatalogSep ); + } + } + + if ( !_rSchema.isEmpty() && aNameComps.bSchemas ) + { + aComposedName.append( _bQuote ? quoteName( sQuoteString, _rSchema ) : _rSchema ); + aComposedName.append( "." ); + } + + aComposedName.append( _bQuote ? quoteName( sQuoteString, _rName ) : _rName ); + + if ( !_rCatalog.isEmpty() + && !bCatlogAtStart + && !sCatalogSep.isEmpty() + && aNameComps.bCatalogs + ) + { + aComposedName.append( sCatalogSep ); + aComposedName.append( _bQuote ? quoteName( sQuoteString, _rCatalog ) : _rCatalog ); + } + + return aComposedName.makeStringAndClear(); +} + +OUString quoteTableName(const Reference< XDatabaseMetaData>& _rxMeta + , const OUString& _rName + , EComposeRule _eComposeRule) +{ + OUString sCatalog, sSchema, sTable; + qualifiedNameComponents(_rxMeta,_rName,sCatalog,sSchema,sTable,_eComposeRule); + return impl_doComposeTableName( _rxMeta, sCatalog, sSchema, sTable, true, _eComposeRule ); +} + +void qualifiedNameComponents(const Reference< XDatabaseMetaData >& _rxConnMetaData, const OUString& _rQualifiedName, OUString& _rCatalog, OUString& _rSchema, OUString& _rName,EComposeRule _eComposeRule) +{ + OSL_ENSURE(_rxConnMetaData.is(), "QualifiedNameComponents : invalid meta data!"); + + NameComponentSupport aNameComps( lcl_getNameComponentSupport( _rxConnMetaData, _eComposeRule ) ); + + OUString sSeparator = _rxConnMetaData->getCatalogSeparator(); + + OUString sName(_rQualifiedName); + // do we have catalogs? + if ( aNameComps.bCatalogs ) + { + if (_rxConnMetaData->isCatalogAtStart()) + { + // search for the catalog name at the beginning + sal_Int32 nIndex = sName.indexOf(sSeparator); + if (-1 != nIndex) + { + _rCatalog = sName.copy(0, nIndex); + sName = sName.copy(nIndex + 1); + } + } + else + { + // Catalog name at the end + sal_Int32 nIndex = sName.lastIndexOf(sSeparator); + if (-1 != nIndex) + { + _rCatalog = sName.copy(nIndex + 1); + sName = sName.copy(0, nIndex); + } + } + } + + if ( aNameComps.bSchemas ) + { + sal_Int32 nIndex = sName.indexOf('.'); + // OSL_ENSURE(-1 != nIndex, "QualifiedNameComponents: no schema separator!"); + if ( nIndex != -1 ) + _rSchema = sName.copy(0, nIndex); + sName = sName.copy(nIndex + 1); + } + + _rName = sName; +} + +Reference< XNumberFormatsSupplier> getNumberFormats( + const Reference< XConnection>& _rxConn, + bool _bAlloweDefault, + const Reference< XComponentContext>& _rxContext) +{ + // ask the parent of the connection (should be a DatabaseAccess) + Reference< XNumberFormatsSupplier> xReturn; + Reference< XChild> xConnAsChild(_rxConn, UNO_QUERY); + static constexpr OUStringLiteral sPropFormatsSupplier( u"NumberFormatsSupplier" ); + if (xConnAsChild.is()) + { + Reference< XPropertySet> xConnParentProps(xConnAsChild->getParent(), UNO_QUERY); + if (xConnParentProps.is() && hasProperty(sPropFormatsSupplier, xConnParentProps)) + xConnParentProps->getPropertyValue(sPropFormatsSupplier) >>= xReturn; + } + else if(_bAlloweDefault && _rxContext.is()) + { + xReturn = NumberFormatsSupplier::createWithDefaultLocale( _rxContext ); + } + return xReturn; +} + +void TransferFormComponentProperties( + const Reference< XPropertySet>& xOldProps, + const Reference< XPropertySet>& xNewProps, + const Locale& _rLocale) +{ +try +{ + OSL_ENSURE( xOldProps.is() && xNewProps.is(), "TransferFormComponentProperties: invalid source/dest!" ); + if ( !xOldProps.is() || !xNewProps.is() ) + return; + + // First we copy all the Props, that are available in source and target and have the same description + Reference< XPropertySetInfo> xOldInfo( xOldProps->getPropertySetInfo()); + Reference< XPropertySetInfo> xNewInfo( xNewProps->getPropertySetInfo()); + + const Sequence< Property> aOldProperties = xOldInfo->getProperties(); + const Sequence< Property> aNewProperties = xNewInfo->getProperties(); + + static constexpr OUStringLiteral sPropFormatsSupplier(u"FormatsSupplier"); + static constexpr OUStringLiteral sPropCurrencySymbol(u"CurrencySymbol"); + static constexpr OUStringLiteral sPropDecimals(u"Decimals"); + static constexpr OUStringLiteral sPropEffectiveMin(u"EffectiveMin"); + static constexpr OUStringLiteral sPropEffectiveMax(u"EffectiveMax"); + static constexpr OUStringLiteral sPropEffectiveDefault(u"EffectiveDefault"); + static constexpr OUStringLiteral sPropDefaultText(u"DefaultText"); + static constexpr OUStringLiteral sPropDefaultDate(u"DefaultDate"); + static constexpr OUStringLiteral sPropDefaultTime(u"DefaultTime"); + static constexpr OUStringLiteral sPropValueMin(u"ValueMin"); + static constexpr OUStringLiteral sPropValueMax(u"ValueMax"); + static constexpr OUStringLiteral sPropDecimalAccuracy(u"DecimalAccuracy"); + static constexpr OUStringLiteral sPropClassId(u"ClassId"); + static constexpr OUStringLiteral sFormattedServiceName( u"com.sun.star.form.component.FormattedField" ); + + for (const Property& rOldProp : aOldProperties) + { + if ( rOldProp.Name != "DefaultControl" && rOldProp.Name != "LabelControl" ) + { + // binary search + const Property* pResult = std::lower_bound( + aNewProperties.begin(), aNewProperties.end(), rOldProp, ::comphelper::PropertyCompareByName()); + + if ( ( pResult != aNewProperties.end() ) + && ( pResult->Name == rOldProp.Name ) + && ( (pResult->Attributes & PropertyAttribute::READONLY) == 0 ) + && ( pResult->Type.equals(rOldProp.Type)) ) + { // Attributes match and the property is not read-only + try + { + xNewProps->setPropertyValue(pResult->Name, xOldProps->getPropertyValue(pResult->Name)); + } + catch(IllegalArgumentException const &) + { + TOOLS_WARN_EXCEPTION( "connectivity.commontools", "TransferFormComponentProperties : could not transfer the value for property \"" + << pResult->Name << "\""); + } + } + } + } + + // for formatted fields (either old or new) we have some special treatments + Reference< XServiceInfo > xSI( xOldProps, UNO_QUERY ); + bool bOldIsFormatted = xSI.is() && xSI->supportsService( sFormattedServiceName ); + xSI.set( xNewProps, UNO_QUERY ); + bool bNewIsFormatted = xSI.is() && xSI->supportsService( sFormattedServiceName ); + + if (!bOldIsFormatted && !bNewIsFormatted) + return; // nothing to do + + if (bOldIsFormatted && bNewIsFormatted) + // if both fields are formatted we do no conversions + return; + + if (bOldIsFormatted) + { + // get some properties from the selected format and put them in the new Set + Any aFormatKey( xOldProps->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FORMATKEY)) ); + if (aFormatKey.hasValue()) + { + Reference< XNumberFormatsSupplier> xSupplier; + xOldProps->getPropertyValue(sPropFormatsSupplier) >>= xSupplier; + if (xSupplier.is()) + { + Reference< XNumberFormats> xFormats(xSupplier->getNumberFormats()); + Reference< XPropertySet> xFormat(xFormats->getByKey(getINT32(aFormatKey))); + if (hasProperty(sPropCurrencySymbol, xFormat)) + { + Any aVal( xFormat->getPropertyValue(sPropCurrencySymbol) ); + if (aVal.hasValue() && hasProperty(sPropCurrencySymbol, xNewProps)) + // If the source value hasn't been set then don't copy it + // so we don't overwrite the default value + xNewProps->setPropertyValue(sPropCurrencySymbol, aVal); + } + if (hasProperty(sPropDecimals, xFormat) && hasProperty(sPropDecimals, xNewProps)) + xNewProps->setPropertyValue(sPropDecimals, xFormat->getPropertyValue(sPropDecimals)); + } + } + + // a potential Min-Max-Conversion + Any aEffectiveMin( xOldProps->getPropertyValue(sPropEffectiveMin) ); + if (aEffectiveMin.hasValue()) + { // Unlike the ValueMin the EffectiveMin can be void + if (hasProperty(sPropValueMin, xNewProps)) + { + OSL_ENSURE(aEffectiveMin.getValueType().getTypeClass() == TypeClass_DOUBLE, + "TransferFormComponentProperties : invalid property type !"); + xNewProps->setPropertyValue(sPropValueMin, aEffectiveMin); + } + } + Any aEffectiveMax( xOldProps->getPropertyValue(sPropEffectiveMax) ); + if (aEffectiveMax.hasValue()) + { // analog + if (hasProperty(sPropValueMax, xNewProps)) + { + OSL_ENSURE(aEffectiveMax.getValueType().getTypeClass() == TypeClass_DOUBLE, + "TransferFormComponentProperties : invalid property type !"); + xNewProps->setPropertyValue(sPropValueMax, aEffectiveMax); + } + } + + // then we can still convert and copy the default values + Any aEffectiveDefault( xOldProps->getPropertyValue(sPropEffectiveDefault) ); + if (aEffectiveDefault.hasValue()) + { + bool bIsString = aEffectiveDefault.getValueType().getTypeClass() == TypeClass_STRING; + OSL_ENSURE(bIsString || aEffectiveDefault.getValueType().getTypeClass() == TypeClass_DOUBLE, + "TransferFormComponentProperties : invalid property type !"); + // The Effective-Properties should always be void or string or double... + + if (hasProperty(sPropDefaultDate, xNewProps) && !bIsString) + { // (to convert an OUString into a date will not always succeed, because it might be bound to a text-column, + // but we can work with a double) + Date aDate = DBTypeConversion::toDate(getDouble(aEffectiveDefault)); + xNewProps->setPropertyValue(sPropDefaultDate, Any(aDate)); + } + + if (hasProperty(sPropDefaultTime, xNewProps) && !bIsString) + { // Completely analogous to time + css::util::Time aTime = DBTypeConversion::toTime(getDouble(aEffectiveDefault)); + xNewProps->setPropertyValue(sPropDefaultTime, Any(aTime)); + } + + if (hasProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE), xNewProps) && !bIsString) + { // Here we can simply pass the double + xNewProps->setPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE), aEffectiveDefault); + } + + if (hasProperty(sPropDefaultText, xNewProps) && bIsString) + { // and here the OUString + xNewProps->setPropertyValue(sPropDefaultText, aEffectiveDefault); + } + + // nyi: The translation between doubles and OUString would offer more alternatives + } + } + + // The other direction: the new Control shall be formatted + if (bNewIsFormatted) + { + // first the formatting + // we can't set a Supplier, so the new Set must bring one in + Reference< XNumberFormatsSupplier> xSupplier; + xNewProps->getPropertyValue(sPropFormatsSupplier) >>= xSupplier; + if (xSupplier.is()) + { + Reference< XNumberFormats> xFormats(xSupplier->getNumberFormats()); + + // Set number of decimals + sal_Int16 nDecimals = 2; + if (hasProperty(sPropDecimalAccuracy, xOldProps)) + xOldProps->getPropertyValue(sPropDecimalAccuracy) >>= nDecimals; + + // base format (depending on the ClassId of the old Set) + sal_Int32 nBaseKey = 0; + if (hasProperty(sPropClassId, xOldProps)) + { + Reference< XNumberFormatTypes> xTypeList(xFormats, UNO_QUERY); + if (xTypeList.is()) + { + sal_Int16 nClassId = 0; + xOldProps->getPropertyValue(sPropClassId) >>= nClassId; + switch (nClassId) + { + case FormComponentType::DATEFIELD : + nBaseKey = xTypeList->getStandardFormat(NumberFormat::DATE, _rLocale); + break; + + case FormComponentType::TIMEFIELD : + nBaseKey = xTypeList->getStandardFormat(NumberFormat::TIME, _rLocale); + break; + + case FormComponentType::CURRENCYFIELD : + nBaseKey = xTypeList->getStandardFormat(NumberFormat::CURRENCY, _rLocale); + break; + } + } + } + + // With this we can generate a new format ... + OUString sNewFormat = xFormats->generateFormat(nBaseKey, _rLocale, false, false, nDecimals, 0); + // No thousands separator, negative numbers are not in red, no leading zeros + + // ... and add at FormatsSupplier (if needed) + sal_Int32 nKey = xFormats->queryKey(sNewFormat, _rLocale, false); + if (nKey == sal_Int32(-1)) + { // not added yet in my formatter ... + nKey = xFormats->addNew(sNewFormat, _rLocale); + } + + xNewProps->setPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FORMATKEY), Any(nKey)); + } + + // min-/max-Value + Any aNewMin, aNewMax; + if (hasProperty(sPropValueMin, xOldProps)) + aNewMin = xOldProps->getPropertyValue(sPropValueMin); + if (hasProperty(sPropValueMax, xOldProps)) + aNewMax = xOldProps->getPropertyValue(sPropValueMax); + xNewProps->setPropertyValue(sPropEffectiveMin, aNewMin); + xNewProps->setPropertyValue(sPropEffectiveMax, aNewMax); + + // Default-Value + Any aNewDefault; + if (hasProperty(sPropDefaultDate, xOldProps)) + { + Any aDate( xOldProps->getPropertyValue(sPropDefaultDate) ); + if (aDate.hasValue()) + aNewDefault <<= DBTypeConversion::toDouble(*o3tl::doAccess(aDate)); + } + + if (hasProperty(sPropDefaultTime, xOldProps)) + { + Any aTime( xOldProps->getPropertyValue(sPropDefaultTime) ); + if (aTime.hasValue()) + aNewDefault <<= DBTypeConversion::toDouble(*o3tl::doAccess