summaryrefslogtreecommitdiffstats
path: root/connectivity/source/commontools
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--connectivity/source/commontools/AutoRetrievingBase.cxx52
-rw-r--r--connectivity/source/commontools/BlobHelper.cxx63
-rw-r--r--connectivity/source/commontools/CommonTools.cxx235
-rw-r--r--connectivity/source/commontools/ConnectionWrapper.cxx238
-rw-r--r--connectivity/source/commontools/DateConversion.cxx517
-rw-r--r--connectivity/source/commontools/DriversConfig.cxx249
-rw-r--r--connectivity/source/commontools/FDatabaseMetaDataResultSet.cxx839
-rw-r--r--connectivity/source/commontools/FDatabaseMetaDataResultSetMetaData.cxx357
-rw-r--r--connectivity/source/commontools/FValue.cxx2473
-rw-r--r--connectivity/source/commontools/ParameterSubstitution.cxx106
-rw-r--r--connectivity/source/commontools/RowFunctionParser.cxx442
-rw-r--r--connectivity/source/commontools/TColumnsHelper.cxx208
-rw-r--r--connectivity/source/commontools/TConnection.cxx85
-rw-r--r--connectivity/source/commontools/TDatabaseMetaDataBase.cxx329
-rw-r--r--connectivity/source/commontools/TIndex.cxx100
-rw-r--r--connectivity/source/commontools/TIndexColumns.cxx114
-rw-r--r--connectivity/source/commontools/TIndexes.cxx247
-rw-r--r--connectivity/source/commontools/TKey.cxx107
-rw-r--r--connectivity/source/commontools/TKeyColumns.cxx132
-rw-r--r--connectivity/source/commontools/TKeys.cxx307
-rw-r--r--connectivity/source/commontools/TPrivilegesResultSet.cxx140
-rw-r--r--connectivity/source/commontools/TSkipDeletedSet.cxx255
-rw-r--r--connectivity/source/commontools/TSortIndex.cxx152
-rw-r--r--connectivity/source/commontools/TTableHelper.cxx610
-rw-r--r--connectivity/source/commontools/conncleanup.cxx230
-rw-r--r--connectivity/source/commontools/dbcharset.cxx191
-rw-r--r--connectivity/source/commontools/dbconversion.cxx392
-rw-r--r--connectivity/source/commontools/dbexception.cxx485
-rw-r--r--connectivity/source/commontools/dbmetadata.cxx443
-rw-r--r--connectivity/source/commontools/dbtools.cxx2074
-rw-r--r--connectivity/source/commontools/dbtools2.cxx1018
-rw-r--r--connectivity/source/commontools/filtermanager.cxx254
-rw-r--r--connectivity/source/commontools/formattedcolumnvalue.cxx291
-rw-r--r--connectivity/source/commontools/parameters.cxx1212
-rw-r--r--connectivity/source/commontools/paramwrapper.cxx345
-rw-r--r--connectivity/source/commontools/predicateinput.cxx411
-rw-r--r--connectivity/source/commontools/propertyids.cxx104
-rw-r--r--connectivity/source/commontools/sqlerror.cxx295
-rw-r--r--connectivity/source/commontools/statementcomposer.cxx301
-rw-r--r--connectivity/source/commontools/warningscontainer.cxx110
40 files changed, 16513 insertions, 0 deletions
diff --git a/connectivity/source/commontools/AutoRetrievingBase.cxx b/connectivity/source/commontools/AutoRetrievingBase.cxx
new file mode 100644
index 0000000000..99327f27ee
--- /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 <AutoRetrievingBase.hxx>
+
+#include <osl/diagnose.h>
+#include <o3tl/string_view.hxx>
+
+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<sStmt.getLength() && sStmt[nIntoIndex]==' ') ++nIntoIndex;
+ const std::u16string_view sTableName = o3tl::getToken(sStmt, 0, ' ', nIntoIndex);
+ return m_sGeneratedValueStatement.replaceAt(nTableIndex, strlen(sTable), sTableName);
+ }
+ return m_sGeneratedValueStatement;
+ }
+ return OUString();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/BlobHelper.cxx b/connectivity/source/commontools/BlobHelper.cxx
new file mode 100644
index 0000000000..f1f048a731
--- /dev/null
+++ b/connectivity/source/commontools/BlobHelper.cxx
@@ -0,0 +1,63 @@
+/* -*- 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 <connectivity/BlobHelper.hxx>
+#include <comphelper/seqstream.hxx>
+#include <connectivity/dbexception.hxx>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <o3tl/unreachable.hxx>
+
+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);
+}
+
+::sal_Int64 SAL_CALL BlobHelper::position( const css::uno::Sequence< ::sal_Int8 >& /*pattern*/, ::sal_Int64 /*start*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XBlob::position", *this );
+ O3TL_UNREACHABLE;
+}
+
+::sal_Int64 SAL_CALL BlobHelper::positionOfBlob( const css::uno::Reference< css::sdbc::XBlob >& /*pattern*/, ::sal_Int64 /*start*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XBlob::positionOfBlob", *this );
+ O3TL_UNREACHABLE;
+}
+
+/* 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 0000000000..596be7097d
--- /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 <config_java.h>
+
+#include <connectivity/CommonTools.hxx>
+#include <connectivity/dbtools.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/java/JavaVirtualMachine.hpp>
+#if HAVE_FEATURE_JAVA
+#include <jvmaccess/virtualmachine.hxx>
+#endif
+#include <osl/diagnose.h>
+#include <rtl/character.hxx>
+#include <rtl/process.h>
+#include <comphelper/diagnose_ex.hxx>
+
+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<XComponentContext >& _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<sal_Int8> processID(17); // 16 + 1
+ auto pprocessID = processID.getArray();
+ rtl_getGlobalProcessId( reinterpret_cast<sal_uInt8*>(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<jvmaccess::VirtualMachine *>(
+ static_cast<sal_IntPtr>(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(std::u16string_view _rQuote, const OUString& _rName)
+{
+ OUString sName = _rName;
+ if( !_rQuote.empty() && _rQuote[0] != ' ')
+ 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 0000000000..df5ef04ee5
--- /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 <connectivity/ConnectionWrapper.hxx>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <comphelper/uno3.hxx>
+#include <comphelper/sequence.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/hash.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <com/sun/star/reflection/ProxyFactory.hpp>
+#include <algorithm>
+
+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<XInterface> 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<XInterface> 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<OConnectionWrapper>(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<unsigned char const*>(_rURL.getStr()), _rURL.getLength() * sizeof(sal_Unicode));
+ if ( !_rUserName.isEmpty() )
+ sha1.update(reinterpret_cast<unsigned char const*>(_rUserName.getStr()), _rUserName.getLength() * sizeof(sal_Unicode));
+ if ( !_rPassword.isEmpty() )
+ sha1.update(reinterpret_cast<unsigned char const*>(_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<unsigned char const*>(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<unsigned char const*>(sValue.getStr()), sValue.getLength() * sizeof(sal_Unicode));
+ }
+ }
+
+ std::vector<unsigned char> 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 0000000000..0895881d7e
--- /dev/null
+++ b/connectivity/source/commontools/DateConversion.cxx
@@ -0,0 +1,517 @@
+/* -*- 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 <connectivity/dbconversion.hxx>
+#include <connectivity/dbtools.hxx>
+#include <com/sun/star/script/XTypeConverter.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/util/NumberFormat.hpp>
+#include <com/sun/star/util/XNumberFormatter.hpp>
+#include <com/sun/star/util/XNumberFormatTypes.hpp>
+#include <com/sun/star/sdb/XColumnUpdate.hpp>
+#include <com/sun/star/sdb/XColumn.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <comphelper/extract.hxx>
+#include <TConnection.hxx>
+#include <comphelper/numbers.hxx>
+#include <comphelper/types.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <comphelper/diagnose_ex.hxx>
+
+
+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;
+ aTemp = aTemp.replaceAll(u"\'", u"\'\'");
+ 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 '"
+ + DBTypeConversion::toDateTimeString(aDateTime)
+ + "'}");
+ 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 '"
+ + DBTypeConversion::toDateString(aDate)
+ + "'}");
+ } 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 '"
+ + DBTypeConversion::toTimeString(aTime)
+ + "'}");
+ } 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<XColumnUpdate>& xVariant,
+ const Reference<XNumberFormatter>& 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<XColumnUpdate>& 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<XPropertySet> 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<sal_uInt8>(rValue);
+// break;
+// case DataType::SMALLINT:
+// nValue = static_cast<sal_uInt16>(rValue);
+// break;
+// case DataType::INTEGER:
+// nValue = static_cast<sal_uInt32>(rValue);
+// break;
+// case DataType::BIGINT:
+// nValue = static_cast<sal_uInt64>(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<double>(static_cast<sal_uInt8>(i_column->getByte()));
+ case DataType::SMALLINT:
+ return static_cast<double>(static_cast<sal_uInt16>(i_column->getShort()));
+ case DataType::INTEGER:
+ return static_cast<double>(static_cast<sal_uInt32>(i_column->getInt()));
+ case DataType::BIGINT:
+ return static_cast<double>(static_cast<sal_uInt64>(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<XNumberFormatter>& _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<XNumberFormats> 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<XColumn>& xVariant,
+ const Reference<XNumberFormatter>& 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 0000000000..26a241e3f8
--- /dev/null
+++ b/connectivity/source/commontools/DriversConfig.cxx
@@ -0,0 +1,249 @@
+/* -*- 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 <config_fuzzers.h>
+
+#include <connectivity/DriversConfig.hxx>
+#include <o3tl/string_view.hxx>
+#include <tools/wldcrd.hxx>
+#include <comphelper/sequence.hxx>
+#include <utility>
+
+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<uno::Any> 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(uno::Reference< uno::XComponentContext > _xORB)
+:m_xORB(std::move(_xORB))
+{
+}
+
+
+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 0000000000..d4ae8760f2
--- /dev/null
+++ b/connectivity/source/commontools/FDatabaseMetaDataResultSet.cxx
@@ -0,0 +1,839 @@
+/* -*- 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 <ParameterSubstitution.hxx>
+#include <FDatabaseMetaDataResultSet.hxx>
+#include <FDatabaseMetaDataResultSetMetaData.hxx>
+#include <com/sun/star/sdbc/ColumnSearch.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <cppuhelper/typeprovider.hxx>
+#include <comphelper/sequence.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <connectivity/dbexception.hxx>
+#include <o3tl/safeint.hxx>
+#include <o3tl/unreachable.hxx>
+#include <TConnection.hxx>
+
+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<sal_Int32>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE), PROPERTY_ID_RESULTSETTYPE, PropertyAttribute::READONLY,&m_nResultSetType, ::cppu::UnoType<sal_Int32>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION), PROPERTY_ID_FETCHDIRECTION, 0, &m_nFetchDirection, ::cppu::UnoType<sal_Int32>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY), PROPERTY_ID_RESULTSETCONCURRENCY, PropertyAttribute::READONLY,&m_nResultSetConcurrency, ::cppu::UnoType<sal_Int32>::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<css::beans::XMultiPropertySet>::get(),
+ cppu::UnoType<css::beans::XFastPropertySet>::get(),
+ cppu::UnoType<css::beans::XPropertySet>::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_Bool SAL_CALL ODatabaseMetaDataResultSet::isFirst( )
+{
+ ::dbtools::throwFunctionSequenceException(*this);
+ O3TL_UNREACHABLE;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::isLast( )
+{
+ ::dbtools::throwFunctionSequenceException(*this);
+ O3TL_UNREACHABLE;
+}
+
+
+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_Bool SAL_CALL ODatabaseMetaDataResultSet::first( )
+{
+ ::dbtools::throwFunctionSequenceException(*this);
+ O3TL_UNREACHABLE;
+}
+
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::last( )
+{
+ ::dbtools::throwFunctionSequenceException(*this);
+ O3TL_UNREACHABLE;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::absolute( sal_Int32 /*row*/ )
+{
+ ::dbtools::throwFunctionSequenceException(*this);
+ O3TL_UNREACHABLE;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::relative( sal_Int32 /*row*/ )
+{
+ ::dbtools::throwFunctionSequenceException(*this);
+ O3TL_UNREACHABLE;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::previous( )
+{
+ ::dbtools::throwFunctionSequenceException(*this);
+ O3TL_UNREACHABLE;
+}
+
+
+Reference< XInterface > SAL_CALL ODatabaseMetaDataResultSet::getStatement( )
+{
+ return m_aStatement.get();
+}
+
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::rowDeleted( )
+{
+ ::dbtools::throwFunctionSequenceException(*this);
+ O3TL_UNREACHABLE;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::rowInserted( )
+{
+ ::dbtools::throwFunctionSequenceException(*this);
+ O3TL_UNREACHABLE;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::rowUpdated( )
+{
+ ::dbtools::throwFunctionSequenceException(*this);
+ O3TL_UNREACHABLE;
+}
+
+
+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<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setProceduresMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setCatalogsMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setCatalogsMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setSchemasMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setSchemasMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setColumnPrivilegesMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setColumnPrivilegesMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setColumnsMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setColumnsMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setTablesMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setTablesMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setProcedureColumnsMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setProcedureColumnsMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setPrimaryKeysMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setPrimaryKeysMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setIndexInfoMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setIndexInfoMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setTablePrivilegesMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setTablePrivilegesMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setCrossReferenceMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setCrossReferenceMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setVersionColumnsMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setVersionColumnsMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setBestRowIdentifierMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setBestRowIdentifierMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setTypeInfoMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setTypeInfoMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setUDTsMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setUDTsMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setTableTypes()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setTableTypes();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setExportedKeysMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setExportedKeysMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setImportedKeysMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> 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<MetaDataResultSetType>(nResultSetType));
+ Sequence< Sequence<Any> > aRows;
+ if ( !(_aArguments[1] >>= aRows) )
+ return;
+
+ ORows aRowsToSet;
+ const Sequence<Any>* pRowsIter = aRows.getConstArray();
+ const Sequence<Any>* 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<OUString>{ "com.sun.star.sdbc.ResultSet" };
+ }
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+connectivity_dbtools_ODatabaseMetaDataResultSet_get_implementation(
+ css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> 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 0000000000..561953a079
--- /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 <FDatabaseMetaDataResultSetMetaData.hxx>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+
+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 0000000000..4ac0235ac4
--- /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 <string.h>
+#include <connectivity/FValue.hxx>
+#include <connectivity/dbconversion.hxx>
+#include <comphelper/extract.hxx>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/sdbc/XClob.hpp>
+#include <com/sun/star/sdbc/XBlob.hpp>
+#include <com/sun/star/sdb/XColumn.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <osl/diagnose.h>
+
+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<css::util::Date*>(m_aValue.m_pValue);
+ m_aValue.m_pValue = nullptr;
+ break;
+ case DataType::TIME:
+ delete static_cast<css::util::Time*>(m_aValue.m_pValue);
+ m_aValue.m_pValue = nullptr;
+ break;
+ case DataType::TIMESTAMP:
+ delete static_cast<css::util::DateTime*>(m_aValue.m_pValue);
+ m_aValue.m_pValue = nullptr;
+ break;
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ delete static_cast<Sequence<sal_Int8>*>(m_aValue.m_pValue);
+ m_aValue.m_pValue = nullptr;
+ break;
+ case DataType::BLOB:
+ case DataType::CLOB:
+ case DataType::OBJECT:
+ delete static_cast<Any*>(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<Any*>(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<Date*>(_rRH.m_aValue.m_pValue));
+ break;
+ case DataType::TIME:
+ m_aValue.m_pValue = new Time(*static_cast<Time*>(_rRH.m_aValue.m_pValue));
+ break;
+ case DataType::TIMESTAMP:
+ m_aValue.m_pValue = new DateTime(*static_cast<DateTime*>(_rRH.m_aValue.m_pValue));
+ break;
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ m_aValue.m_pValue = new Sequence<sal_Int8>(*static_cast<Sequence<sal_Int8>*>(_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<Any*>(_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<Date*>(_rRH.m_aValue.m_pValue);
+ break;
+ case DataType::TIME:
+ (*this) = *static_cast<Time*>(_rRH.m_aValue.m_pValue);
+ break;
+ case DataType::TIMESTAMP:
+ (*this) = *static_cast<DateTime*>(_rRH.m_aValue.m_pValue);
+ break;
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ (*this) = *static_cast<Sequence<sal_Int8>*>(_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<Any*>(m_aValue.m_pValue) = *static_cast<Any*>(_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<Date*>(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<Time*>(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<DateTime*>(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<sal_Int8>& _rRH)
+{
+ if (!isStorageCompatible(DataType::LONGVARBINARY,m_eTypeKind))
+ free();
+
+ if (m_bNull)
+ {
+ m_aValue.m_pValue = new Sequence<sal_Int8>(_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<Any*>(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<Date*>(m_aValue.m_pValue) == *static_cast<Date*>(_rRH.m_aValue.m_pValue);
+ break;
+ case DataType::TIME:
+ bRet = *static_cast<Time*>(m_aValue.m_pValue) == *static_cast<Time*>(_rRH.m_aValue.m_pValue);
+ break;
+ case DataType::TIMESTAMP:
+ bRet = *static_cast<DateTime*>(m_aValue.m_pValue) == *static_cast<DateTime*>(_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<Date*>(m_aValue.m_pValue);
+ break;
+ case DataType::TIME:
+ OSL_ENSURE(m_aValue.m_pValue,"Value is null!");
+ rValue <<= *static_cast<Time*>(m_aValue.m_pValue);
+ break;
+ case DataType::TIMESTAMP:
+ OSL_ENSURE(m_aValue.m_pValue,"Value is null!");
+ rValue <<= *static_cast<DateTime*>(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<Sequence<sal_Int8>*>(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<sal_uInt16>(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<sal_Int8> aSeq(getSequence());
+ const sal_Int8* pBegin = aSeq.getConstArray();
+ const sal_Int8* pEnd = pBegin + aSeq.getLength();
+ for(;pBegin != pEnd;++pBegin)
+ sVal.append(static_cast<sal_Int32>(*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<sal_Int32>(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<sal_Int8>(m_aValue.m_uInt8);
+ break;
+ case DataType::SMALLINT:
+ if ( m_bSigned )
+ nRet = static_cast<sal_Int8>(m_aValue.m_nInt16);
+ else
+ nRet = static_cast<sal_Int8>(m_aValue.m_uInt16);
+ break;
+ case DataType::INTEGER:
+ if ( m_bSigned )
+ nRet = static_cast<sal_Int8>(m_aValue.m_nInt32);
+ else
+ nRet = static_cast<sal_Int8>(m_aValue.m_uInt32);
+ break;
+ case DataType::BIGINT:
+ if ( m_bSigned )
+ nRet = static_cast<sal_Int8>(m_aValue.m_nInt64);
+ else
+ nRet = static_cast<sal_Int8>(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<sal_uInt8>(m_aValue.m_nInt16);
+ else
+ nRet = static_cast<sal_uInt8>(m_aValue.m_uInt16);
+ break;
+ case DataType::INTEGER:
+ if ( m_bSigned )
+ nRet = static_cast<sal_uInt8>(m_aValue.m_nInt32);
+ else
+ nRet = static_cast<sal_uInt8>(m_aValue.m_uInt32);
+ break;
+ case DataType::BIGINT:
+ if ( m_bSigned )
+ nRet = static_cast<sal_uInt8>(m_aValue.m_nInt64);
+ else
+ nRet = static_cast<sal_uInt8>(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<sal_uInt8>(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<sal_Int16>(m_aValue.m_uInt16);
+ break;
+ case DataType::INTEGER:
+ if ( m_bSigned )
+ nRet = static_cast<sal_Int16>(m_aValue.m_nInt32);
+ else
+ nRet = static_cast<sal_Int16>(m_aValue.m_uInt32);
+ break;
+ case DataType::BIGINT:
+ if ( m_bSigned )
+ nRet = static_cast<sal_Int16>(m_aValue.m_nInt64);
+ else
+ nRet = static_cast<sal_Int16>(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<sal_uInt16>(m_aValue.m_nInt32);
+ else
+ nRet = static_cast<sal_uInt16>(m_aValue.m_uInt32);
+ break;
+ case DataType::BIGINT:
+ if ( m_bSigned )
+ nRet = static_cast<sal_uInt16>(m_aValue.m_nInt64);
+ else
+ nRet = static_cast<sal_uInt16>(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<css::util::Date*>(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<sal_Int32>(m_aValue.m_uInt32);
+ break;
+ case DataType::BIGINT:
+ if ( m_bSigned )
+ nRet = static_cast<sal_Int32>(m_aValue.m_nInt64);
+ else
+ nRet = static_cast<sal_Int32>(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<css::util::Date*>(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<sal_uInt32>(m_aValue.m_nInt64);
+ else
+ nRet = static_cast<sal_uInt32>(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<css::util::Date*>(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<sal_Int64>(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<css::util::Date*>(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<float>(m_aValue.m_nDouble);
+ break;
+ case DataType::DATE:
+ nRet = static_cast<float>(dbtools::DBTypeConversion::toDouble(*static_cast<css::util::Date*>(m_aValue.m_pValue)));
+ break;
+ case DataType::TIME:
+ nRet = static_cast<float>(dbtools::DBTypeConversion::toDouble(*static_cast<css::util::Time*>(m_aValue.m_pValue)));
+ break;
+ case DataType::TIMESTAMP:
+ nRet = static_cast<float>(dbtools::DBTypeConversion::toDouble(*static_cast<css::util::DateTime*>(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<float>(m_aValue.m_uInt16);
+ break;
+ case DataType::INTEGER:
+ if ( m_bSigned )
+ nRet = static_cast<float>(m_aValue.m_nInt32);
+ else
+ nRet = static_cast<float>(m_aValue.m_uInt32);
+ break;
+ case DataType::BIGINT:
+ if ( m_bSigned )
+ nRet = static_cast<float>(m_aValue.m_nInt64);
+ else
+ nRet = static_cast<float>(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<css::util::Date*>(m_aValue.m_pValue));
+ break;
+ case DataType::TIME:
+ nRet = dbtools::DBTypeConversion::toDouble(*static_cast<css::util::Time*>(m_aValue.m_pValue));
+ break;
+ case DataType::TIMESTAMP:
+ nRet = dbtools::DBTypeConversion::toDouble(*static_cast<css::util::DateTime*>(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<sal_Int8> ORowSetValue::getSequence() const
+{
+ Sequence<sal_Int8> aSeq;
+ if (!m_bNull)
+ {
+ switch(m_eTypeKind)
+ {
+ case DataType::OBJECT:
+ case DataType::CLOB:
+ case DataType::BLOB:
+ {
+ Reference<XInputStream> xStream;
+ const Any aValue = makeAny();
+ if(aValue.hasValue())
+ {
+ Reference<XBlob> xBlob(aValue,UNO_QUERY);
+ if ( xBlob.is() )
+ xStream = xBlob->getBinaryStream();
+ else
+ {
+ Reference<XClob> 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<sal_Int8>(reinterpret_cast<const sal_Int8*>(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<sal_Int8>*>(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<sal_Int64>(m_aValue.m_uInt64);
+ m_aValue.m_nInt64 = nTmp;
+ }
+ else
+ {
+ auto nTmp = static_cast<sal_uInt64>(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<sal_Int64>(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<sal_Int8> 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 0000000000..6fa5578080
--- /dev/null
+++ b/connectivity/source/commontools/ParameterSubstitution.cxx
@@ -0,0 +1,106 @@
+/* -*- 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 <ParameterSubstitution.hxx>
+#include <connectivity/sqlparse.hxx>
+#include <comphelper/sequenceashashmap.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <utility>
+
+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(css::uno::Reference< css::uno::XComponentContext > _xContext ) : m_xContext(std::move(_xContext))
+ {
+ }
+ 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<OSQLParseNode> 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<css::uno::Any> 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 0000000000..da4935dc61
--- /dev/null
+++ b/connectivity/source/commontools/RowFunctionParser.cxx
@@ -0,0 +1,442 @@
+/* -*- 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 <typeinfo>
+#define BOOST_SPIRIT_DEBUG
+#endif
+#include <boost/spirit/include/classic_core.hpp>
+#include <RowFunctionParser.hxx>
+#include <rtl/ustring.hxx>
+
+
+#if (OSL_DEBUG_LEVEL > 0)
+#include <iostream>
+#endif
+#include <algorithm>
+#include <stack>
+#include <utility>
+
+namespace connectivity
+{
+using namespace com::sun::star;
+
+namespace
+{
+
+
+// EXPRESSION NODES
+
+
+class ConstantValueExpression : public ExpressionNode
+{
+ ORowSetValueDecoratorRef maValue;
+
+public:
+
+ explicit ConstantValueExpression( ORowSetValueDecoratorRef aValue ) :
+ maValue(std::move( aValue ))
+ {
+ }
+ 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<ExpressionNode> mpFirstArg;
+ std::shared_ptr<ExpressionNode> mpSecondArg;
+
+public:
+
+ BinaryFunctionExpression( const ExpressionFunct eFunct, std::shared_ptr<ExpressionNode> xFirstArg, std::shared_ptr<ExpressionNode> xSecondArg ) :
+ meFunct( eFunct ),
+ mpFirstArg(std::move( xFirstArg )),
+ mpSecondArg(std::move( xSecondArg ))
+ {
+ }
+ virtual ORowSetValueDecoratorRef evaluate(const ODatabaseMetaDataResultSet::ORow& _aRow ) const override
+ {
+ ORowSetValueDecoratorRef aRet;
+ switch(meFunct)
+ {
+ case ExpressionFunct::Equation:
+ aRet = new ORowSetValueDecorator( ORowSetValue(mpFirstArg->evaluate(_aRow )->getValue() == mpSecondArg->evaluate(_aRow )->getValue()) );
+ break;
+ case ExpressionFunct::And:
+ aRet = new ORowSetValueDecorator( ORowSetValue(mpFirstArg->evaluate(_aRow )->getValue().getBool() && mpSecondArg->evaluate(_aRow )->getValue().getBool()) );
+ break;
+ case ExpressionFunct::Or:
+ aRet = new ORowSetValueDecorator( ORowSetValue(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<ExpressionNode> > 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( ParserContextSharedPtr xContext ) :
+ mpContext(std::move( xContext ))
+ {
+ }
+ void operator()( StringIteratorT rFirst,StringIteratorT rSecond) const
+ {
+ OUString sVal( rFirst, rSecond - rFirst, RTL_TEXTENCODING_UTF8 );
+ mpContext->maOperandStack.push( std::make_shared<ConstantValueExpression>( new ORowSetValueDecorator( sVal ) ) );
+ }
+};
+
+/** Generate parse-dependent-but-then-constant value
+ */
+class IntConstantFunctor
+{
+ ParserContextSharedPtr mpContext;
+
+public:
+ explicit IntConstantFunctor( ParserContextSharedPtr xContext ) :
+ mpContext(std::move( xContext ))
+ {
+ }
+ void operator()( sal_Int32 n ) const
+ {
+ mpContext->maOperandStack.push( std::make_shared<ConstantValueExpression>( 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, ParserContextSharedPtr xContext ) :
+ meFunct( eFunct ),
+ mpContext(std::move( xContext ))
+ {
+ }
+
+ 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<ExpressionNode> pSecondArg( std::move(rNodeStack.top()) );
+ rNodeStack.pop();
+ std::shared_ptr<ExpressionNode> pFirstArg( std::move(rNodeStack.top()) );
+ rNodeStack.pop();
+
+ // create combined ExpressionNode
+ auto pNode = std::make_shared<BinaryFunctionExpression>( meFunct, pFirstArg, pSecondArg );
+ // check for constness
+ rNodeStack.push( pNode );
+ }
+};
+/** ExpressionNode implementation for unary
+ function over one ExpressionNode
+ */
+class UnaryFunctionExpression : public ExpressionNode
+{
+ std::shared_ptr<ExpressionNode> mpArg;
+
+public:
+ explicit UnaryFunctionExpression( std::shared_ptr<ExpressionNode> xArg ) :
+ mpArg(std::move( xArg ))
+ {
+ }
+ 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(ParserContextSharedPtr xContext)
+ : mpContext(std::move(xContext))
+ {
+ }
+ 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<ExpressionNode> pArg( std::move(rNodeStack.top()) );
+ rNodeStack.pop();
+
+ rNodeStack.push( std::make_shared<UnaryFunctionExpression>( 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( ParserContextSharedPtr xParserContext ) :
+ mpParserContext(std::move( xParserContext ))
+ {
+ }
+
+ 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<strlit<> > 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<ParserContext>();
+
+ // 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<ExpressionNode> 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<StringIteratorT> 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 0000000000..f81eca9f0a
--- /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 <connectivity/TColumnsHelper.hxx>
+#include <connectivity/sdbcx/VColumn.hxx>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <comphelper/types.hxx>
+#include <connectivity/dbtools.hxx>
+#include <TConnection.hxx>
+#include <connectivity/TTableHelper.hxx>
+
+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> 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<XPropertySet> xPr = m_pTable;
+ const Reference<XNameAccess> 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<connectivity::sdbcx::OColumn> 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<XDatabaseMetaData> 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<XDatabaseMetaData> 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 0000000000..f35e8ca194
--- /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 <TConnection.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/dbexception.hxx>
+
+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 0000000000..bd2b7a4671
--- /dev/null
+++ b/connectivity/source/commontools/TDatabaseMetaDataBase.cxx
@@ -0,0 +1,329 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cstddef>
+
+#include <TDatabaseMetaDataBase.hxx>
+#include <RowFunctionParser.hxx>
+
+#include <comphelper/sequenceashashmap.hxx>
+#include <comphelper/evtlistenerhlp.hxx>
+#include <comphelper/types.hxx>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <resource/sharedresources.hxx>
+#include <strings.hrc>
+#include <connectivity/dbexception.hxx>
+#include <sal/macros.h>
+
+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<XComponent> 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<std::shared_ptr<ExpressionNode>> 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 (std::size_t i = 1; i <= std::size(pTypes); ++i,++pType)
+ {
+ ORowSetValue aValue;
+ aValue.fill(i,*pType,xRow);
+ aRow.push_back(new ORowSetValueDecorator(std::move(aValue)));
+ }
+
+ std::vector<std::shared_ptr<ExpressionNode>>::iterator aIter = aConditions.begin();
+ std::vector<std::shared_ptr<ExpressionNode>>::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<OUString(ODatabaseMetaDataBase *)>(&ODatabaseMetaDataBase::impl_getIdentifierQuoteString_throw));
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataBase::isCatalogAtStart( )
+{
+ return callImplMethod(m_isCatalogAtStart,std::function<bool(ODatabaseMetaDataBase *)>(&ODatabaseMetaDataBase::impl_isCatalogAtStart_throw));
+}
+
+OUString SAL_CALL ODatabaseMetaDataBase::getCatalogSeparator( )
+{
+ return callImplMethod(m_sCatalogSeparator,std::function<OUString(ODatabaseMetaDataBase *)>(&ODatabaseMetaDataBase::impl_getCatalogSeparator_throw));
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataBase::supportsCatalogsInTableDefinitions( )
+{
+ return callImplMethod(m_supportsCatalogsInTableDefinitions,std::function<bool(ODatabaseMetaDataBase *)>(&ODatabaseMetaDataBase::impl_supportsCatalogsInTableDefinitions_throw));
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataBase::supportsSchemasInTableDefinitions( )
+{
+ return callImplMethod(m_supportsSchemasInTableDefinitions,std::function<bool(ODatabaseMetaDataBase *)>(&ODatabaseMetaDataBase::impl_supportsSchemasInTableDefinitions_throw));
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataBase::supportsCatalogsInDataManipulation( )
+{
+ return callImplMethod(m_supportsCatalogsInDataManipulation,std::function<bool(ODatabaseMetaDataBase *)>(&ODatabaseMetaDataBase::impl_supportsCatalogsInDataManipulation_throw));
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataBase::supportsSchemasInDataManipulation( )
+{
+ return callImplMethod(m_supportsSchemasInDataManipulation,std::function<bool(ODatabaseMetaDataBase *)>(&ODatabaseMetaDataBase::impl_supportsSchemasInDataManipulation_throw));
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataBase::supportsMixedCaseQuotedIdentifiers( )
+{
+ return callImplMethod(m_supportsMixedCaseQuotedIdentifiers,std::function<bool(ODatabaseMetaDataBase *)>(&ODatabaseMetaDataBase::impl_supportsMixedCaseQuotedIdentifiers_throw));
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataBase::supportsAlterTableWithAddColumn( )
+{
+ return callImplMethod(m_supportsAlterTableWithAddColumn,std::function<bool(ODatabaseMetaDataBase *)>(&ODatabaseMetaDataBase::impl_supportsAlterTableWithAddColumn_throw));
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataBase::supportsAlterTableWithDropColumn( )
+{
+ return callImplMethod(m_supportsAlterTableWithDropColumn,std::function<bool(ODatabaseMetaDataBase *)>(&ODatabaseMetaDataBase::impl_supportsAlterTableWithDropColumn_throw));
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaDataBase::getMaxStatements( )
+{
+ return callImplMethod(m_MaxStatements,std::function<sal_Int32(ODatabaseMetaDataBase *)>(&ODatabaseMetaDataBase::impl_getMaxStatements_throw));
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaDataBase::getMaxTablesInSelect( )
+{
+ return callImplMethod(m_MaxTablesInSelect,std::function<sal_Int32(ODatabaseMetaDataBase *)>(&ODatabaseMetaDataBase::impl_getMaxTablesInSelect_throw));
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataBase::storesMixedCaseQuotedIdentifiers( )
+{
+ return callImplMethod(m_storesMixedCaseQuotedIdentifiers,std::function<bool(ODatabaseMetaDataBase *)>(&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 0000000000..f7f891308e
--- /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 <TIndex.hxx>
+#include <TIndexColumns.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <connectivity/TTableHelper.hxx>
+#include <TConnection.hxx>
+
+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 0000000000..1db4426c18
--- /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 <TIndexColumns.hxx>
+#include <sdbcx/VIndexColumn.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <TIndex.hxx>
+#include <connectivity/TTableHelper.hxx>
+#include <TConnection.hxx>
+
+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 0000000000..2ba9124a51
--- /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 <connectivity/TIndexes.hxx>
+#include <TIndex.hxx>
+#include <connectivity/TTableHelper.hxx>
+#include <com/sun/star/sdb/tools/XIndexAlteration.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/IndexType.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <connectivity/dbtools.hxx>
+#include <TConnection.hxx>
+#include <comphelper/extract.hxx>
+#include <comphelper/types.hxx>
+#include <rtl/ustrbuf.hxx>
+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 )
+ + " ON "
+ + aComposedName
+ + " ( ");
+
+ Reference<XColumnsSupplier> xColumnSup(descriptor,UNO_QUERY);
+ Reference<XIndexAccess> 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<XColumnsSupplier> xColumnSup(descriptor,UNO_QUERY);
+ Reference<XIndexAccess> xColumns(xColumnSup->getColumns(),UNO_QUERY);
+ Reference< XPropertySet > xColProp;
+ if(xColumns->getCount() != 1)
+ throw SQLException();
+
+ xColumns->getByIndex(0) >>= xColProp;
+
+ 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 0000000000..1341291abc
--- /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 <TKey.hxx>
+#include <TKeyColumns.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <TConnection.hxx>
+#include <connectivity/TTableHelper.hxx>
+
+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<sdbcx::KeyProperties>& _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 0000000000..0a2c02bb22
--- /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 <TKeyColumns.hxx>
+#include <TKey.hxx>
+#include <sdbcx/VKeyColumn.hxx>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <TConnection.hxx>
+#include <connectivity/TTableHelper.hxx>
+
+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 0000000000..e6e50f20a4
--- /dev/null
+++ b/connectivity/source/commontools/TKeys.cxx
@@ -0,0 +1,307 @@
+/* -*- 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 <connectivity/TKeys.hxx>
+#include <TKey.hxx>
+#include <connectivity/TTableHelper.hxx>
+#include <com/sun/star/sdb/tools/XKeyAlteration.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbcx/KeyType.hpp>
+#include <com/sun/star/sdbc/KeyRule.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <connectivity/dbtools.hxx>
+#include <comphelper/types.hxx>
+#include <TConnection.hxx>
+
+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("ALTER TABLE ");
+ OUString aQuote = m_pTable->getConnection()->getMetaData()->getIdentifierQuoteString( );
+
+ aSql.append(composeTableName( m_pTable->getConnection()->getMetaData(), m_pTable, ::dbtools::EComposeRule::InTableDefinitions, true )
+ + " ADD ");
+
+ if ( nKeyType == KeyType::PRIMARY )
+ {
+ aSql.append(" PRIMARY KEY (");
+ }
+ else if ( nKeyType == KeyType::FOREIGN )
+ {
+ aSql.append(" FOREIGN KEY (");
+ }
+ else
+ throw SQLException();
+
+ Reference<XColumnsSupplier> xColumnSup(descriptor,UNO_QUERY);
+ Reference<XIndexAccess> 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 "
+ + ::dbtools::quoteTableName(m_pTable->getConnection()->getMetaData(),sReferencedName,::dbtools::EComposeRule::InTableDefinitions)
+ + " (");
+
+ for(sal_Int32 i=0;i<xColumns->getCount();++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(")"
+ + getKeyRuleString(true ,nUpdateRule)
+ + 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<sdbcx::KeyProperties>(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<XPropertySet> xKey(getObject(_nPos),UNO_QUERY);
+ if ( m_pTable->getKeyService().is() )
+ {
+ m_pTable->getKeyService()->dropKey(m_pTable,xKey);
+ }
+ else
+ {
+ OUStringBuffer aSql(
+ "ALTER TABLE "
+ + 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 0000000000..928e9c016a
--- /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 <TPrivilegesResultSet.hxx>
+
+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 0000000000..701bd743f6
--- /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 <TSkipDeletedSet.hxx>
+#include <osl/diagnose.h>
+#include <sal/log.hxx>
+#include <algorithm>
+
+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<sal_Int32>(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<sal_Int32>(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<sal_Int32>().swap(m_aBookmarksPositions);
+}
+
+sal_Int32 OSkipDeletedSet::getMappedPosition(sal_Int32 _nPos) const
+{
+ std::vector<sal_Int32>::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<sal_Int32>::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 0000000000..44a883dc86
--- /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 <TSortIndex.hxx>
+#include <algorithm>
+#include <iterator>
+#include <o3tl/functional.hxx>
+
+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<OKeyType>& 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<OKeySet> OSortIndex::CreateKeySet()
+{
+ Freeze();
+
+ ::rtl::Reference<OKeySet> pKeySet = new OKeySet();
+ pKeySet->reserve(m_aKeyValues.size());
+ std::transform(m_aKeyValues.begin()
+ ,m_aKeyValues.end()
+ ,std::back_inserter(*pKeySet)
+ ,::o3tl::select1st<TIntValuePairVector::value_type>());
+ pKeySet->setFrozen();
+ return pKeySet;
+}
+
+OSortIndex::OSortIndex( std::vector<OKeyType>&& _aKeyType,
+ std::vector<TAscendingOrder>&& _aAscending)
+ :m_aKeyType(std::move(_aKeyType))
+ ,m_aAscending(std::move(_aAscending))
+ ,m_bFrozen(false)
+{
+}
+
+OSortIndex::~OSortIndex()
+{
+}
+
+void OSortIndex::AddKeyValue(std::unique_ptr<OKeyValue> 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> OKeyValue::createKeyValue(sal_Int32 _nVal)
+{
+ return std::unique_ptr<OKeyValue>(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 0000000000..31e2404694
--- /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 <sal/config.h>
+#include <sal/log.hxx>
+
+#include <connectivity/TTableHelper.hxx>
+#include <com/sun/star/sdb/tools/XTableRename.hpp>
+#include <com/sun/star/sdb/tools/XTableAlteration.hpp>
+#include <com/sun/star/sdb/tools/XKeyAlteration.hpp>
+#include <com/sun/star/sdb/tools/XIndexAlteration.hpp>
+#include <sdbcx/VKey.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbcx/KeyType.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <comphelper/types.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <unotools/sharedunocomponent.hxx>
+#include <TConnection.hxx>
+
+#include <o3tl/functional.hxx>
+
+#include <iterator>
+#include <set>
+
+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<OTableContainerListener> 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<XMultiServiceFactory> 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 <column count>, but for instance
+ // 0 to <column count>-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<sdbcx::KeyProperties>(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<sdbcx::KeyProperties> 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<sdbcx::KeyProperties>(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<sdbcx::KeyProperties> OTableHelper::getKeyProperties(const OUString& _sName) const
+{
+ std::shared_ptr<sdbcx::KeyProperties> 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<sdbcx::KeyProperties>();
+ }
+
+ return pKeyProps;
+}
+
+void OTableHelper::addKey(const OUString& _sName,const std::shared_ptr<sdbcx::KeyProperties>& _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 0000000000..7b703f093c
--- /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 <connectivity/conncleanup.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/sdbc/XRowSet.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <osl/diagnose.h>
+#include <comphelper/diagnose_ex.hxx>
+
+
+namespace dbtools
+{
+
+
+ using namespace css::uno;
+ using namespace css::beans;
+ using namespace css::sdbc;
+ using namespace css::lang;
+
+ constexpr OUString ACTIVE_CONNECTION_PROPERTY_NAME = u"ActiveConnection"_ustr;
+
+ 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(getXWeak());
+
+ 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 0000000000..381afa606e
--- /dev/null
+++ b/connectivity/source/commontools/dbcharset.cxx
@@ -0,0 +1,191 @@
+/* -*- 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 <connectivity/dbcharset.hxx>
+#include <utility>
+#include <osl/diagnose.h>
+#include <rtl/tencinfo.h>
+
+
+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(std::u16string_view _rIanaName) const
+ {
+ ensureConstructed( );
+
+ rtl_TextEncoding eEncoding = RTL_TEXTENCODING_DONTKNOW;
+ if ( !_rIanaName.empty() )
+ {
+ // byte string conversion
+ OString sMimeByteString = OUStringToOString( _rIanaName, 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, OUString _aIanaName )
+ :m_eEncoding( _eEncoding )
+ ,m_aIanaName(std::move( _aIanaName ))
+ {
+ }
+
+ OCharsetMap::CharsetIterator::CharsetIterator(const OCharsetMap* _pContainer, OCharsetMap::TextEncBag::const_iterator _aPos )
+ :m_pContainer( _pContainer )
+ ,m_aPos(std::move( _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 0000000000..704e168ad7
--- /dev/null
+++ b/connectivity/source/commontools/dbconversion.cxx
@@ -0,0 +1,392 @@
+/* -*- 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 <connectivity/dbconversion.hxx>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/util/Date.hpp>
+#include <com/sun/star/util/Time.hpp>
+#include <com/sun/star/util/DateTime.hpp>
+#include <rtl/character.hxx>
+#include <rtl/math.hxx>
+#include <sal/log.hxx>
+#include <unotools/datetime.hxx>
+#include <comphelper/date.hxx>
+#include <o3tl/string_view.hxx>
+#include <sstream>
+#include <iomanip>
+
+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());
+ }
+
+ 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());
+ }
+
+ 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());
+ }
+
+ 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<sal_uInt16>(_nVal % 100);
+ aReturn.Month = static_cast<sal_uInt16>((_nVal / 100) % 100);
+ aReturn.Year = static_cast<sal_uInt16>(_nVal / 10000);
+ return aReturn;
+ }
+
+
+ css::util::Time DBTypeConversion::toTime(const sal_Int64 _nVal)
+ {
+ css::util::Time aReturn;
+ sal_uInt64 unVal = static_cast<sal_uInt64>(_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);
+ }
+
+ static sal_Int32 implRelativeToAbsoluteNull(const css::util::Date& _rDate)
+ {
+ if (_rDate.Day == 0 && _rDate.Month == 0 && _rDate.Year == 0)
+ {
+ // 0000-00-00 is *NOT* a valid date and passing it to the date
+ // conversion even when normalizing rightly asserts. Whatever we
+ // return here, it will be wrong. The old before commit
+ // 52ff16771ac160d27fd7beb78a4cfba22ad84f06 wrong implementation
+ // calculated -365 for that, effectively that would be a date of
+ // -0001-01-01 now but it was likely assumed that would be
+ // 0000-00-01 or even 0000-00-00 instead. Try if we get away with 0
+ // for -0001-12-31, the same that
+ // comphelper::date::convertDateToDaysNormalizing()
+ // would return if comphelper::date::normalize() wouldn't ignore
+ // such "empty" date.
+
+ return 0;
+ }
+ return comphelper::date::convertDateToDaysNormalizing( _rDate.Day, _rDate.Month, _rDate.Year);
+ }
+
+ 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<double>(toDays(rVal, _rNullDate));
+ }
+
+
+ double DBTypeConversion::toDouble(const css::util::Time& rVal)
+ {
+ return static_cast<double>(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<double>(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
+ else if ( nTempDays <= 0 )
+ {
+ _rDate.Day = 1;
+ _rDate.Month = 1;
+ _rDate.Year = 1;
+ }
+ else
+ comphelper::date::convertDaysToDate( 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
+ else if ( nTempDays <= 0 )
+ {
+ _rDate.Day = 1;
+ _rDate.Month = 1;
+ _rDate.Year = 1;
+ }
+ else
+ comphelper::date::convertDaysToDate( 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<sal_Int32>(dVal),aRet);
+ else
+ subDays(static_cast<sal_uInt32>(-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<sal_uInt16>(o3tl::toInt32(o3tl::getToken(_sSQLString, 0,sDateSep,nIndex)));
+ if(nIndex != -1)
+ {
+ nMonth = static_cast<sal_uInt16>(o3tl::toInt32(o3tl::getToken(_sSQLString, 0,sDateSep,nIndex)));
+ if(nIndex != -1)
+ nDay = static_cast<sal_uInt16>(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 0000000000..bc5a9be808
--- /dev/null
+++ b/connectivity/source/commontools/dbexception.cxx
@@ -0,0 +1,485 @@
+/* -*- 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 <connectivity/dbexception.hxx>
+#include <comphelper/types.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <o3tl/any.hxx>
+#include <osl/diagnose.h>
+#include <com/sun/star/sdb/SQLContext.hpp>
+#include <com/sun/star/sdbc/SQLWarning.hpp>
+#include <com/sun/star/sdb/SQLErrorEvent.hpp>
+#include <strings.hrc>
+#include <resource/sharedresources.hxx>
+#include <comphelper/diagnose_ex.hxx>
+
+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(_rSimpleErrorMessage, {}, {}, 0, {});
+ 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<css::sdbc::SQLException>::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<SQLException>::get();
+ const Type& aSQLWarningType = ::cppu::UnoType<SQLWarning>::get();
+ const Type& aSQLContextType = ::cppu::UnoType<SQLContext>::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<css::sdbc::SQLException>(m_aContent);
+}
+
+
+SQLExceptionInfo::operator const css::sdb::SQLContext*() const
+{
+ OSL_ENSURE(isKindOf(TYPE::SQLContext), "SQLExceptionInfo::operator SQLException* : invalid call !");
+ return o3tl::doAccess<css::sdb::SQLContext>(m_aContent);
+}
+
+
+void SQLExceptionInfo::prepend( const OUString& _rErrorMessage )
+{
+ SQLException aException(_rErrorMessage, {}, "S1000", 0, 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(rErrorMessage, {}, rSQLState, nErrorCode, {});
+ break;
+ case TYPE::SQLWarning:
+ aAppend <<= SQLWarning(rErrorMessage, {}, rSQLState, nErrorCode, {});
+ break;
+ case TYPE::SQLContext:
+ aAppend <<= SQLContext(rErrorMessage, {}, rSQLState, nErrorCode, {}, {});
+ break;
+ default:
+ TOOLS_WARN_EXCEPTION("connectivity.commontools", "SQLExceptionInfo::createException: invalid exception type: this will crash!");
+ break;
+ }
+
+ return aAppend;
+}
+
+// find the end of the exception chain
+SQLException* SQLExceptionInfo::getLastException(SQLException* pLastException)
+{
+ SQLException* pException = pLastException;
+ while (pException)
+ {
+ pException = const_cast<SQLException*>(o3tl::tryAccess<SQLException>(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<SQLException*>(o3tl::tryAccess<SQLException>(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<css::uno::XInterface>& _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<css::uno::XInterface>& _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 0000000000..8983ee25ba
--- /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 <connectivity/dbmetadata.hxx>
+#include <connectivity/dbexception.hxx>
+#include <connectivity/DriversConfig.hxx>
+#include <strings.hrc>
+#include <resource/sharedresources.hxx>
+
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/sdb/BooleanComparisonMode.hpp>
+#include <com/sun/star/sdbc/XDatabaseMetaData2.hpp>
+#include <com/sun/star/sdbcx/XUsersSupplier.hpp>
+#include <com/sun/star/sdbcx/XDataDefinitionSupplier.hpp>
+#include <com/sun/star/sdbc/DriverManager.hpp>
+
+#include <comphelper/diagnose_ex.hxx>
+#include <comphelper/namedvaluecollection.hxx>
+#include <comphelper/processfactory.hxx>
+#include <sal/log.hxx>
+
+#include <optional>
+
+
+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<XComponentContext>& _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 0000000000..885e28c751
--- /dev/null
+++ b/connectivity/source/commontools/dbtools.cxx
@@ -0,0 +1,2074 @@
+/* -*- 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 <connectivity/CommonTools.hxx>
+#include <TConnection.hxx>
+#include <ParameterCont.hxx>
+
+#include <com/sun/star/awt/XWindow.hpp>
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/form/FormComponentType.hpp>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/sdb/DatabaseContext.hpp>
+#include <com/sun/star/sdb/BooleanComparisonMode.hpp>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/sdb/ErrorMessageDialog.hpp>
+#include <com/sun/star/sdb/ParametersRequest.hpp>
+#include <com/sun/star/sdb/RowSetVetoException.hpp>
+#include <com/sun/star/sdb/SQLContext.hpp>
+#include <com/sun/star/sdb/XCompletedConnection.hpp>
+#include <com/sun/star/sdb/XInteractionSupplyParameters.hpp>
+#include <com/sun/star/sdb/XOfficeDatabaseDocument.hpp>
+#include <com/sun/star/sdb/XParametersSupplier.hpp>
+#include <com/sun/star/sdb/XQueriesSupplier.hpp>
+#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
+#include <com/sun/star/sdbc/ConnectionPool.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdbc/XDataSource.hpp>
+#include <com/sun/star/sdbc/XParameters.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XRowSet.hpp>
+#include <com/sun/star/sdbc/XRowUpdate.hpp>
+#include <com/sun/star/sdbcx/KeyType.hpp>
+#include <com/sun/star/sdbcx/Privilege.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdbcx/XKeysSupplier.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/task/InteractionHandler.hpp>
+#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
+#include <com/sun/star/util/NumberFormat.hpp>
+#include <com/sun/star/util/NumberFormatsSupplier.hpp>
+#include <com/sun/star/util/XNumberFormatTypes.hpp>
+
+#include <comphelper/extract.hxx>
+#include <comphelper/interaction.hxx>
+#include <comphelper/property.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/conncleanup.hxx>
+#include <connectivity/dbconversion.hxx>
+#include <connectivity/dbexception.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/statementcomposer.hxx>
+#include <o3tl/any.hxx>
+#include <o3tl/safeint.hxx>
+#include <osl/diagnose.h>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <tools/stream.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <strings.hrc>
+#include <resource/sharedresources.hxx>
+
+#include <algorithm>
+#include <iterator>
+#include <set>
+
+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<sal_Int16>(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<sal_Int16>(_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<sal_Int16>(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> xConnection;
+ if (xDataSource.is())
+ {
+
+ //set ParentWindow for dialog, but just for the duration of this
+ //call, undo at end of scope
+ Reference<XInitialization> 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<XPropertySet> 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<XCompletedConnection> 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<XWindow>()) )) };
+ 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 constexpr OUString sUserProp( u"User"_ustr );
+ 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<XNameAccess> xKeyColumns;
+ const Reference<XKeysSupplier> xKeySup(i_xTable,UNO_QUERY);
+ if ( xKeySup.is() )
+ {
+ const Reference<XIndexAccess> xKeys = xKeySup->getKeys();
+ if ( xKeys.is() )
+ {
+ ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
+ const OUString& sPropName = rPropMap.getNameByIndex(PROPERTY_ID_TYPE);
+ Reference<XPropertySet> 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<XColumnsSupplier> 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 bCatalogAtStart = true;
+ if ( !_rCatalog.isEmpty() && aNameComps.bCatalogs )
+ {
+ sCatalogSep = _rxMetaData->getCatalogSeparator();
+ bCatalogAtStart = _rxMetaData->isCatalogAtStart();
+
+ if ( bCatalogAtStart && !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( _bQuote ? quoteName( sQuoteString, _rName ) : _rName );
+
+ if ( !_rCatalog.isEmpty()
+ && !bCatalogAtStart
+ && !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 OUString sPropFormatsSupplier( u"NumberFormatsSupplier"_ustr );
+ 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 OUString sPropFormatsSupplier(u"FormatsSupplier"_ustr);
+ static constexpr OUString sPropCurrencySymbol(u"CurrencySymbol"_ustr);
+ static constexpr OUString sPropDecimals(u"Decimals"_ustr);
+ static constexpr OUString sPropEffectiveMin(u"EffectiveMin"_ustr);
+ static constexpr OUString sPropEffectiveMax(u"EffectiveMax"_ustr);
+ static constexpr OUString sPropEffectiveDefault(u"EffectiveDefault"_ustr);
+ static constexpr OUString sPropDefaultText(u"DefaultText"_ustr);
+ static constexpr OUString sPropDefaultDate(u"DefaultDate"_ustr);
+ static constexpr OUString sPropDefaultTime(u"DefaultTime"_ustr);
+ static constexpr OUString sPropValueMin(u"ValueMin"_ustr);
+ static constexpr OUString sPropValueMax(u"ValueMax"_ustr);
+ static constexpr OUString sPropDecimalAccuracy(u"DecimalAccuracy"_ustr);
+ static constexpr OUString sPropClassId(u"ClassId"_ustr);
+ static constexpr OUString sFormattedServiceName( u"com.sun.star.form.component.FormattedField"_ustr );
+
+ 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<Date>(aDate));
+ }
+
+ if (hasProperty(sPropDefaultTime, xOldProps))
+ {
+ Any aTime( xOldProps->getPropertyValue(sPropDefaultTime) );
+ if (aTime.hasValue())
+ aNewDefault <<= DBTypeConversion::toDouble(*o3tl::doAccess<Time>(aTime));
+ }
+
+ // double or OUString will be copied directly
+ if (hasProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE), xOldProps))
+ aNewDefault = xOldProps->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE));
+ if (hasProperty(sPropDefaultText, xOldProps))
+ aNewDefault = xOldProps->getPropertyValue(sPropDefaultText);
+
+ if (aNewDefault.hasValue())
+ xNewProps->setPropertyValue(sPropEffectiveDefault, aNewDefault);
+ }
+}
+catch(const Exception&)
+{
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "TransferFormComponentProperties" );
+}
+}
+
+bool canInsert(const Reference< XPropertySet>& _rxCursorSet)
+{
+ return (_rxCursorSet.is() && (getINT32(_rxCursorSet->getPropertyValue("Privileges")) & Privilege::INSERT) != 0);
+}
+
+bool canUpdate(const Reference< XPropertySet>& _rxCursorSet)
+{
+ return (_rxCursorSet.is() && (getINT32(_rxCursorSet->getPropertyValue("Privileges")) & Privilege::UPDATE) != 0);
+}
+
+bool canDelete(const Reference< XPropertySet>& _rxCursorSet)
+{
+ return (_rxCursorSet.is() && (getINT32(_rxCursorSet->getPropertyValue("Privileges")) & Privilege::DELETE) != 0);
+}
+
+Reference< XDataSource> findDataSource(const Reference< XInterface >& _xParent)
+{
+ Reference< XOfficeDatabaseDocument> xDatabaseDocument(_xParent, UNO_QUERY);
+ Reference< XDataSource> xDataSource;
+ if ( xDatabaseDocument.is() )
+ xDataSource = xDatabaseDocument->getDataSource();
+ if ( !xDataSource.is() )
+ xDataSource.set(_xParent, UNO_QUERY);
+ if (!xDataSource.is())
+ {
+ Reference< XChild> xChild(_xParent, UNO_QUERY);
+ if ( xChild.is() )
+ xDataSource = findDataSource(xChild->getParent());
+ }
+ return xDataSource;
+}
+
+static Reference< XSingleSelectQueryComposer > getComposedRowSetStatement( const Reference< XPropertySet >& _rxRowSet, const Reference< XComponentContext >& _rxContext, const Reference< XWindow >& _rxParent )
+{
+ Reference< XSingleSelectQueryComposer > xComposer;
+ try
+ {
+ Reference< XConnection> xConn = connectRowset( Reference< XRowSet >( _rxRowSet, UNO_QUERY ), _rxContext, _rxParent );
+ if ( xConn.is() ) // implies _rxRowSet.is()
+ {
+ // build the statement the row set is based on (can't use the ActiveCommand property of the set
+ // as this reflects the status after the last execute, not the currently set properties)
+
+ sal_Int32 nCommandType = CommandType::COMMAND;
+ OUString sCommand;
+ bool bEscapeProcessing = false;
+
+ OSL_VERIFY( _rxRowSet->getPropertyValue("CommandType") >>= nCommandType );
+ OSL_VERIFY( _rxRowSet->getPropertyValue("Command") >>= sCommand );
+ OSL_VERIFY( _rxRowSet->getPropertyValue("EscapeProcessing") >>= bEscapeProcessing );
+
+ StatementComposer aComposer( xConn, sCommand, nCommandType, bEscapeProcessing );
+ // append sort
+ aComposer.setOrder( getString( _rxRowSet->getPropertyValue("Order") ) );
+
+ // append filter
+ bool bApplyFilter = true;
+ _rxRowSet->getPropertyValue("ApplyFilter") >>= bApplyFilter;
+ if ( bApplyFilter )
+ {
+ aComposer.setFilter( getString( _rxRowSet->getPropertyValue("Filter") ) );
+ aComposer.setHavingClause( getString( _rxRowSet->getPropertyValue("HavingClause") ) );
+ }
+
+ aComposer.getQuery();
+
+ xComposer = aComposer.getComposer();
+ aComposer.setDisposeComposer( false );
+ }
+ }
+ catch( const SQLException& )
+ {
+ throw;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+
+ return xComposer;
+}
+
+Reference< XSingleSelectQueryComposer > getCurrentSettingsComposer(
+ const Reference< XPropertySet>& _rxRowSetProps,
+ const Reference< XComponentContext>& _rxContext,
+ const Reference< XWindow >& _rxParent)
+{
+ Reference< XSingleSelectQueryComposer > xReturn;
+ try
+ {
+ xReturn = getComposedRowSetStatement( _rxRowSetProps, _rxContext, _rxParent );
+ }
+ catch( const SQLException& )
+ {
+ throw;
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "::getCurrentSettingsComposer : caught an exception !" );
+ }
+
+ return xReturn;
+}
+
+OUString composeTableName( const Reference< XDatabaseMetaData >& _rxMetaData,
+ const OUString& _rCatalog,
+ const OUString& _rSchema,
+ const OUString& _rName,
+ bool _bQuote,
+ EComposeRule _eComposeRule)
+{
+ return impl_doComposeTableName( _rxMetaData, _rCatalog, _rSchema, _rName, _bQuote, _eComposeRule );
+}
+
+OUString composeTableNameForSelect( const Reference< XConnection >& _rxConnection,
+ const OUString& _rCatalog, const OUString& _rSchema, const OUString& _rName )
+{
+ bool bUseCatalogInSelect = isDataSourcePropertyEnabled( _rxConnection, "UseCatalogInSelect", true );
+ bool bUseSchemaInSelect = isDataSourcePropertyEnabled( _rxConnection, "UseSchemaInSelect", true );
+
+ return impl_doComposeTableName(
+ _rxConnection->getMetaData(),
+ bUseCatalogInSelect ? _rCatalog : OUString(),
+ bUseSchemaInSelect ? _rSchema : OUString(),
+ _rName,
+ true,
+ EComposeRule::InDataManipulation
+ );
+}
+
+namespace
+{
+ void lcl_getTableNameComponents( const Reference<XPropertySet>& _xTable,
+ OUString& _out_rCatalog, OUString& _out_rSchema, OUString& _out_rName )
+ {
+ ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
+ Reference< XPropertySetInfo > xInfo;
+ if (_xTable.is())
+ xInfo = _xTable->getPropertySetInfo();
+ if ( xInfo.is()
+ && xInfo->hasPropertyByName(rPropMap.getNameByIndex(PROPERTY_ID_NAME)) )
+ {
+ if ( xInfo->hasPropertyByName(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME))
+ && xInfo->hasPropertyByName(rPropMap.getNameByIndex(PROPERTY_ID_SCHEMANAME)) )
+ {
+ _xTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME)) >>= _out_rCatalog;
+ _xTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_SCHEMANAME)) >>= _out_rSchema;
+ }
+ _xTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)) >>= _out_rName;
+ }
+ else
+ OSL_FAIL( "::dbtools::lcl_getTableNameComponents: this is no table object!" );
+ }
+}
+
+OUString composeTableNameForSelect( const Reference< XConnection >& _rxConnection, const Reference<XPropertySet>& _xTable )
+{
+ OUString sCatalog, sSchema, sName;
+ lcl_getTableNameComponents( _xTable, sCatalog, sSchema, sName );
+
+ return composeTableNameForSelect( _rxConnection, sCatalog, sSchema, sName );
+}
+
+OUString composeTableName(const Reference<XDatabaseMetaData>& _xMetaData,
+ const Reference<XPropertySet>& _xTable,
+ EComposeRule _eComposeRule,
+ bool _bQuote )
+{
+ OUString sCatalog, sSchema, sName;
+ lcl_getTableNameComponents( _xTable, sCatalog, sSchema, sName );
+
+ return impl_doComposeTableName(
+ _xMetaData,
+ sCatalog,
+ sSchema,
+ sName,
+ _bQuote,
+ _eComposeRule
+ );
+}
+
+sal_Int32 getSearchColumnFlag( const Reference< XConnection>& _rxConn,sal_Int32 _nDataType)
+{
+ sal_Int32 nSearchFlag = 0;
+ Reference<XResultSet> xSet = _rxConn->getMetaData()->getTypeInfo();
+ if(xSet.is())
+ {
+ Reference<XRow> xRow(xSet,UNO_QUERY);
+ while(xSet->next())
+ {
+ if(xRow->getInt(2) == _nDataType)
+ {
+ nSearchFlag = xRow->getInt(9);
+ break;
+ }
+ }
+ }
+ return nSearchFlag;
+}
+
+OUString createUniqueName( const Sequence< OUString >& _rNames, const OUString& _rBaseName, bool _bStartWithNumber )
+{
+ std::set< OUString > aUsedNames(_rNames.begin(), _rNames.end());
+
+ OUString sName( _rBaseName );
+ sal_Int32 nPos = 1;
+ if ( _bStartWithNumber )
+ sName += OUString::number( nPos );
+
+ while ( aUsedNames.find( sName ) != aUsedNames.end() )
+ {
+ sName = _rBaseName + OUString::number( ++nPos );
+ }
+ return sName;
+}
+
+OUString createUniqueName(const Reference<XNameAccess>& _rxContainer,const OUString& _rBaseName, bool _bStartWithNumber)
+{
+ Sequence< OUString > aElementNames;
+
+ OSL_ENSURE( _rxContainer.is(), "createUniqueName: invalid container!" );
+ if ( _rxContainer.is() )
+ aElementNames = _rxContainer->getElementNames();
+
+ return createUniqueName( aElementNames, _rBaseName, _bStartWithNumber );
+}
+
+void showError(const SQLExceptionInfo& _rInfo,
+ const Reference< XWindow>& _xParent,
+ const Reference< XComponentContext >& _rxContext)
+{
+ if (_rInfo.isValid())
+ {
+ try
+ {
+ Reference< XExecutableDialog > xErrorDialog = ErrorMessageDialog::create( _rxContext, "", _xParent, _rInfo.get() );
+ xErrorDialog->execute();
+ }
+ catch(const Exception&)
+ {
+ OSL_FAIL("showError: could not display the error message!");
+ }
+ }
+}
+
+bool implUpdateObject(const Reference< XRowUpdate >& _rxUpdatedObject,
+ const sal_Int32 _nColumnIndex, const Any& _rValue)
+{
+ bool bSuccessfullyReRouted = true;
+ switch (_rValue.getValueTypeClass())
+ {
+ case TypeClass_ANY:
+ {
+ bSuccessfullyReRouted = implUpdateObject(_rxUpdatedObject, _nColumnIndex, _rValue);
+ }
+ break;
+
+ case TypeClass_VOID:
+ _rxUpdatedObject->updateNull(_nColumnIndex);
+ break;
+
+ case TypeClass_STRING:
+ _rxUpdatedObject->updateString(_nColumnIndex, *o3tl::forceAccess<OUString>(_rValue));
+ break;
+
+ case TypeClass_BOOLEAN:
+ _rxUpdatedObject->updateBoolean(_nColumnIndex, *o3tl::forceAccess<bool>(_rValue));
+ break;
+
+ case TypeClass_BYTE:
+ _rxUpdatedObject->updateByte(_nColumnIndex, *o3tl::forceAccess<sal_Int8>(_rValue));
+ break;
+
+ case TypeClass_UNSIGNED_SHORT:
+ case TypeClass_SHORT:
+ _rxUpdatedObject->updateShort(_nColumnIndex, *o3tl::forceAccess<sal_Int16>(_rValue));
+ break;
+
+ case TypeClass_CHAR:
+ _rxUpdatedObject->updateString(_nColumnIndex,OUString(*o3tl::forceAccess<sal_Unicode>(_rValue)));
+ break;
+
+ case TypeClass_UNSIGNED_LONG:
+ case TypeClass_LONG:
+ _rxUpdatedObject->updateInt(_nColumnIndex, *o3tl::forceAccess<sal_Int32>(_rValue));
+ break;
+
+ case TypeClass_HYPER:
+ {
+ sal_Int64 nValue = 0;
+ OSL_VERIFY( _rValue >>= nValue );
+ _rxUpdatedObject->updateLong( _nColumnIndex, nValue );
+ }
+ break;
+
+ case TypeClass_FLOAT:
+ _rxUpdatedObject->updateFloat(_nColumnIndex, *o3tl::forceAccess<float>(_rValue));
+ break;
+
+ case TypeClass_DOUBLE:
+ _rxUpdatedObject->updateDouble(_nColumnIndex, *o3tl::forceAccess<double>(_rValue));
+ break;
+
+ case TypeClass_SEQUENCE:
+ if (auto s = o3tl::tryAccess<Sequence< sal_Int8 >>(_rValue))
+ _rxUpdatedObject->updateBytes(_nColumnIndex, *s);
+ else
+ bSuccessfullyReRouted = false;
+ break;
+ case TypeClass_STRUCT:
+ if (auto s1 = o3tl::tryAccess<DateTime>(_rValue))
+ _rxUpdatedObject->updateTimestamp(_nColumnIndex, *s1);
+ else if (auto s2 = o3tl::tryAccess<Date>(_rValue))
+ _rxUpdatedObject->updateDate(_nColumnIndex, *s2);
+ else if (auto s3 = o3tl::tryAccess<Time>(_rValue))
+ _rxUpdatedObject->updateTime(_nColumnIndex, *s3);
+ else
+ bSuccessfullyReRouted = false;
+ break;
+
+ case TypeClass_INTERFACE:
+ if (auto xStream = o3tl::tryAccess<Reference<XInputStream>>(_rValue))
+ {
+ _rxUpdatedObject->updateBinaryStream(_nColumnIndex, *xStream, (*xStream)->available());
+ break;
+ }
+ [[fallthrough]];
+ default:
+ bSuccessfullyReRouted = false;
+ }
+
+ return bSuccessfullyReRouted;
+}
+
+bool implSetObject( const Reference< XParameters >& _rxParameters,
+ const sal_Int32 _nColumnIndex, const Any& _rValue)
+{
+ bool bSuccessfullyReRouted = true;
+ switch (_rValue.getValueTypeClass())
+ {
+ case TypeClass_UNSIGNED_HYPER:
+ {
+ sal_uInt64 nValue = 0;
+ OSL_VERIFY( _rValue >>= nValue );
+ _rxParameters->setString(_nColumnIndex, OUString::number(nValue));
+ }
+ break;
+
+ case TypeClass_UNSIGNED_LONG:
+ case TypeClass_HYPER:
+ {
+ sal_Int64 nValue = 0;
+ OSL_VERIFY( _rValue >>= nValue );
+ _rxParameters->setLong( _nColumnIndex, nValue );
+ }
+ break;
+
+ case TypeClass_ANY:
+ {
+ bSuccessfullyReRouted = implSetObject(_rxParameters, _nColumnIndex, _rValue);
+ }
+ break;
+
+ case TypeClass_VOID:
+ _rxParameters->setNull(_nColumnIndex,DataType::VARCHAR);
+ break;
+
+ case TypeClass_STRING:
+ _rxParameters->setString(_nColumnIndex, *o3tl::forceAccess<OUString>(_rValue));
+ break;
+
+ case TypeClass_BOOLEAN:
+ _rxParameters->setBoolean(_nColumnIndex, *o3tl::forceAccess<bool>(_rValue));
+ break;
+
+ case TypeClass_BYTE:
+ _rxParameters->setByte(_nColumnIndex, *o3tl::forceAccess<sal_Int8>(_rValue));
+ break;
+
+ case TypeClass_SHORT:
+ _rxParameters->setShort(_nColumnIndex, *o3tl::forceAccess<sal_Int16>(_rValue));
+ break;
+
+ case TypeClass_CHAR:
+ _rxParameters->setString(_nColumnIndex, OUString(*o3tl::forceAccess<sal_Unicode>(_rValue)));
+ break;
+
+ case TypeClass_UNSIGNED_SHORT:
+ case TypeClass_LONG:
+ {
+ sal_Int32 nValue = 0;
+ OSL_VERIFY( _rValue >>= nValue );
+ _rxParameters->setInt(_nColumnIndex, nValue);
+ break;
+ }
+
+ case TypeClass_FLOAT:
+ _rxParameters->setFloat(_nColumnIndex, *o3tl::forceAccess<float>(_rValue));
+ break;
+
+ case TypeClass_DOUBLE:
+ _rxParameters->setDouble(_nColumnIndex, *o3tl::forceAccess<double>(_rValue));
+ break;
+
+ case TypeClass_SEQUENCE:
+ if (auto s = o3tl::tryAccess<Sequence< sal_Int8 >>(_rValue))
+ {
+ _rxParameters->setBytes(_nColumnIndex, *s);
+ }
+ else
+ bSuccessfullyReRouted = false;
+ break;
+ case TypeClass_STRUCT:
+ if (auto s1 = o3tl::tryAccess<DateTime>(_rValue))
+ _rxParameters->setTimestamp(_nColumnIndex, *s1);
+ else if (auto s2 = o3tl::tryAccess<Date>(_rValue))
+ _rxParameters->setDate(_nColumnIndex, *s2);
+ else if (auto s3 = o3tl::tryAccess<Time>(_rValue))
+ _rxParameters->setTime(_nColumnIndex, *s3);
+ else
+ bSuccessfullyReRouted = false;
+ break;
+
+ case TypeClass_INTERFACE:
+ if (_rValue.getValueType() == cppu::UnoType<XInputStream>::get())
+ {
+ Reference< XInputStream > xStream;
+ _rValue >>= xStream;
+ _rxParameters->setBinaryStream(_nColumnIndex, xStream, xStream->available());
+ break;
+ }
+ [[fallthrough]];
+ default:
+ bSuccessfullyReRouted = false;
+
+ }
+
+ return bSuccessfullyReRouted;
+}
+
+namespace
+{
+ class OParameterWrapper : public ::cppu::WeakImplHelper< XIndexAccess >
+ {
+ std::vector<bool, std::allocator<bool> > m_aSet;
+ Reference<XIndexAccess> m_xSource;
+ public:
+ OParameterWrapper(std::vector<bool, std::allocator<bool> >&& _aSet,const Reference<XIndexAccess>& _xSource)
+ : m_aSet(std::move(_aSet)), m_xSource(_xSource) {}
+ private:
+ // css::container::XElementAccess
+ virtual Type SAL_CALL getElementType() override
+ {
+ return m_xSource->getElementType();
+ }
+ virtual sal_Bool SAL_CALL hasElements( ) override
+ {
+ if ( m_aSet.empty() )
+ return m_xSource->hasElements();
+ return std::count(m_aSet.begin(),m_aSet.end(),false) != 0;
+ }
+ // css::container::XIndexAccess
+ virtual sal_Int32 SAL_CALL getCount( ) override
+ {
+ if ( m_aSet.empty() )
+ return m_xSource->getCount();
+ return std::count(m_aSet.begin(),m_aSet.end(),false);
+ }
+ virtual Any SAL_CALL getByIndex( sal_Int32 Index ) override
+ {
+ if ( m_aSet.empty() )
+ return m_xSource->getByIndex(Index);
+ if ( Index < 0 || m_aSet.size() < o3tl::make_unsigned(Index) )
+ throw IndexOutOfBoundsException();
+
+ std::vector<bool, std::allocator<bool> >::const_iterator aIter = m_aSet.begin();
+ std::vector<bool, std::allocator<bool> >::const_iterator aEnd = m_aSet.end();
+ sal_Int32 i = 0;
+ for(; aIter != aEnd && i <= Index; ++aIter)
+ {
+ if ( !*aIter )
+ {
+ ++i;
+ }
+ }
+ auto nParamPos = static_cast<sal_Int32>(std::distance(m_aSet.cbegin(), aIter)) - 1;
+ return m_xSource->getByIndex(nParamPos);
+ }
+ };
+}
+
+void askForParameters(const Reference< XSingleSelectQueryComposer >& _xComposer,
+ const Reference<XParameters>& _xParameters,
+ const Reference< XConnection>& _xConnection,
+ const Reference< XInteractionHandler >& _rxHandler,
+ const std::vector<bool, std::allocator<bool> >& _aParametersSet)
+{
+ OSL_ENSURE(_xComposer.is(),"dbtools::askForParameters XSQLQueryComposer is null!");
+ OSL_ENSURE(_xParameters.is(),"dbtools::askForParameters XParameters is null!");
+ OSL_ENSURE(_xConnection.is(),"dbtools::askForParameters XConnection is null!");
+ OSL_ENSURE(_rxHandler.is(),"dbtools::askForParameters XInteractionHandler is null!");
+
+ // we have to set this here again because getCurrentSettingsComposer can force a setpropertyvalue
+ Reference<XParametersSupplier> xParameters(_xComposer, UNO_QUERY);
+
+ Reference<XIndexAccess> xParamsAsIndicies = xParameters.is() ? xParameters->getParameters() : Reference<XIndexAccess>();
+ sal_Int32 nParamCount = xParamsAsIndicies.is() ? xParamsAsIndicies->getCount() : 0;
+ std::vector<bool, std::allocator<bool> > aNewParameterSet( _aParametersSet );
+ if ( !(nParamCount && std::count(aNewParameterSet.begin(),aNewParameterSet.end(),true) != nParamCount) )
+ return;
+
+ static const OUString PROPERTY_NAME(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME));
+ aNewParameterSet.resize(nParamCount ,false);
+ typedef std::map< OUString, std::vector<sal_Int32> > TParameterPositions;
+ TParameterPositions aParameterNames;
+ for(sal_Int32 i = 0; i < nParamCount; ++i)
+ {
+ Reference<XPropertySet> xParam(xParamsAsIndicies->getByIndex(i),UNO_QUERY);
+ OUString sName;
+ xParam->getPropertyValue(PROPERTY_NAME) >>= sName;
+
+ TParameterPositions::const_iterator aFind = aParameterNames.find(sName);
+ if ( aFind != aParameterNames.end() )
+ aNewParameterSet[i] = true;
+ aParameterNames[sName].push_back(i+1);
+ }
+ // build an interaction request
+ // two continuations (Ok and Cancel)
+ rtl::Reference<OInteractionAbort> pAbort = new OInteractionAbort;
+ rtl::Reference<OParameterContinuation> pParams = new OParameterContinuation;
+ // the request
+ ParametersRequest aRequest;
+ Reference<XIndexAccess> xWrappedParameters = new OParameterWrapper(std::move(aNewParameterSet),xParamsAsIndicies);
+ aRequest.Parameters = xWrappedParameters;
+ aRequest.Connection = _xConnection;
+ rtl::Reference<OInteractionRequest> pRequest = new OInteractionRequest(Any(aRequest));
+ // some knittings
+ pRequest->addContinuation(pAbort);
+ pRequest->addContinuation(pParams);
+
+ // execute the request
+ _rxHandler->handle(pRequest);
+
+ if (!pParams->wasSelected())
+ {
+ // canceled by the user (i.e. (s)he canceled the dialog)
+ RowSetVetoException e;
+ e.ErrorCode = ParameterInteractionCancelled;
+ throw e;
+ }
+
+ // now transfer the values from the continuation object to the parameter columns
+ Sequence< PropertyValue > aFinalValues = pParams->getValues();
+ const PropertyValue* pFinalValues = aFinalValues.getConstArray();
+ for (sal_Int32 i=0; i<aFinalValues.getLength(); ++i, ++pFinalValues)
+ {
+ Reference< XPropertySet > xParamColumn(xWrappedParameters->getByIndex(i),UNO_QUERY);
+ if (xParamColumn.is())
+ {
+ OUString sName;
+ xParamColumn->getPropertyValue(PROPERTY_NAME) >>= sName;
+ OSL_ENSURE(sName == pFinalValues->Name, "::dbaui::askForParameters: inconsistent parameter names!");
+
+ // determine the field type and ...
+ sal_Int32 nParamType = 0;
+ xParamColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)) >>= nParamType;
+ // ... the scale of the parameter column
+ sal_Int32 nScale = 0;
+ if (hasProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE), xParamColumn))
+ xParamColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE)) >>= nScale;
+ // (the index of the parameters is one-based)
+ TParameterPositions::const_iterator aFind = aParameterNames.find(pFinalValues->Name);
+ for(const auto& rItem : aFind->second)
+ {
+ if ( _aParametersSet.empty() || !_aParametersSet[rItem-1] )
+ {
+ _xParameters->setObjectWithInfo(rItem, pFinalValues->Value, nParamType, nScale);
+ }
+ }
+ }
+ }
+}
+
+void setObjectWithInfo(const Reference<XParameters>& _xParams,
+ sal_Int32 parameterIndex,
+ const Any& x,
+ sal_Int32 sqlType,
+ sal_Int32 scale)
+{
+ ORowSetValue aVal;
+ aVal.fill(x);
+ setObjectWithInfo(_xParams,parameterIndex,aVal,sqlType,scale);
+}
+
+void setObjectWithInfo(const Reference<XParameters>& _xParams,
+ sal_Int32 parameterIndex,
+ const ::connectivity::ORowSetValue& _rValue,
+ sal_Int32 sqlType,
+ sal_Int32 scale)
+{
+ if ( _rValue.isNull() )
+ _xParams->setNull(parameterIndex,sqlType);
+ else
+ {
+ switch(sqlType)
+ {
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ _xParams->setObjectWithInfo(parameterIndex,_rValue.makeAny(),sqlType,scale);
+ break;
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::LONGVARCHAR:
+ _xParams->setString(parameterIndex,_rValue.getString());
+ break;
+ case DataType::CLOB:
+ {
+ Any x(_rValue.makeAny());
+ OUString sValue;
+ if ( x >>= sValue )
+ _xParams->setString(parameterIndex,sValue);
+ else
+ {
+ Reference< XClob > xClob;
+ if(x >>= xClob)
+ _xParams->setClob(parameterIndex,xClob);
+ else
+ {
+ Reference< css::io::XInputStream > xStream;
+ if(x >>= xStream)
+ _xParams->setCharacterStream(parameterIndex,xStream,xStream->available());
+ }
+ }
+ }
+ break;
+ case DataType::BIGINT:
+ if ( _rValue.isSigned() )
+ _xParams->setLong(parameterIndex,_rValue.getLong());
+ else
+ _xParams->setString(parameterIndex,_rValue.getString());
+ break;
+
+ case DataType::FLOAT:
+ _xParams->setFloat(parameterIndex,_rValue.getFloat());
+ break;
+ case DataType::REAL:
+ case DataType::DOUBLE:
+ _xParams->setDouble(parameterIndex,_rValue.getDouble());
+ break;
+ case DataType::DATE:
+ _xParams->setDate(parameterIndex,_rValue.getDate());
+ break;
+ case DataType::TIME:
+ _xParams->setTime(parameterIndex,_rValue.getTime());
+ break;
+ case DataType::TIMESTAMP:
+ _xParams->setTimestamp(parameterIndex,_rValue.getDateTime());
+ break;
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ case DataType::BLOB:
+ {
+ Any x(_rValue.makeAny());
+ Sequence< sal_Int8> aBytes;
+ if(x >>= aBytes)
+ _xParams->setBytes(parameterIndex,aBytes);
+ else
+ {
+ Reference< XBlob > xBlob;
+ if(x >>= xBlob)
+ _xParams->setBlob(parameterIndex,xBlob);
+ else
+ {
+ Reference< XClob > xClob;
+ if(x >>= xClob)
+ _xParams->setClob(parameterIndex,xClob);
+ else
+ {
+ Reference< css::io::XInputStream > xBinStream;
+ if(x >>= xBinStream)
+ _xParams->setBinaryStream(parameterIndex,xBinStream,xBinStream->available());
+ }
+ }
+ }
+ }
+ break;
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ _xParams->setBoolean(parameterIndex,_rValue.getBool());
+ break;
+ case DataType::TINYINT:
+ if ( _rValue.isSigned() )
+ _xParams->setByte(parameterIndex,_rValue.getInt8());
+ else
+ _xParams->setShort(parameterIndex,_rValue.getInt16());
+ break;
+ case DataType::SMALLINT:
+ if ( _rValue.isSigned() )
+ _xParams->setShort(parameterIndex,_rValue.getInt16());
+ else
+ _xParams->setInt(parameterIndex,_rValue.getInt32());
+ break;
+ case DataType::INTEGER:
+ if ( _rValue.isSigned() )
+ _xParams->setInt(parameterIndex,_rValue.getULong());
+ else
+ _xParams->setLong(parameterIndex,_rValue.getLong());
+ break;
+ default:
+ {
+ ::connectivity::SharedResources aResources;
+ const OUString sError( aResources.getResourceStringWithSubstitution(
+ STR_UNKNOWN_PARA_TYPE,
+ "$position$", OUString::number(parameterIndex)
+ ) );
+ ::dbtools::throwGenericSQLException(sError,nullptr);
+ }
+ }
+ }
+}
+
+void getBooleanComparisonPredicate( std::u16string_view _rExpression, const bool _bValue, const sal_Int32 _nBooleanComparisonMode,
+ OUStringBuffer& _out_rSQLPredicate )
+{
+ switch ( _nBooleanComparisonMode )
+ {
+ case BooleanComparisonMode::IS_LITERAL:
+ _out_rSQLPredicate.append( _rExpression );
+ if ( _bValue )
+ _out_rSQLPredicate.append( " IS TRUE" );
+ else
+ _out_rSQLPredicate.append( " IS FALSE" );
+ break;
+
+ case BooleanComparisonMode::EQUAL_LITERAL:
+ _out_rSQLPredicate.append( _rExpression );
+ _out_rSQLPredicate.appendAscii( _bValue ? " = TRUE" : " = FALSE" );
+ break;
+
+ case BooleanComparisonMode::ACCESS_COMPAT:
+ if ( _bValue )
+ {
+ _out_rSQLPredicate.append( " NOT ( ( " );
+ _out_rSQLPredicate.append( _rExpression );
+ _out_rSQLPredicate.append( " = 0 ) OR ( " );
+ _out_rSQLPredicate.append( _rExpression );
+ _out_rSQLPredicate.append( " IS NULL ) )" );
+ }
+ else
+ {
+ _out_rSQLPredicate.append( _rExpression );
+ _out_rSQLPredicate.append( " = 0" );
+ }
+ break;
+
+ case BooleanComparisonMode::EQUAL_INTEGER:
+ // fall through
+ default:
+ _out_rSQLPredicate.append( _rExpression );
+ _out_rSQLPredicate.appendAscii( _bValue ? " = 1" : " = 0" );
+ break;
+ }
+}
+
+} // namespace dbtools
+
+namespace connectivity
+{
+void checkDisposed(bool _bThrow)
+{
+ if (_bThrow)
+ throw DisposedException();
+
+}
+
+OSQLColumns::const_iterator find(const OSQLColumns::const_iterator& first,
+ const OSQLColumns::const_iterator& last,
+ std::u16string_view _rVal,
+ const ::comphelper::UStringMixEqual& _rCase)
+{
+ OUString sName = OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME);
+ return find(first,last,sName,_rVal,_rCase);
+}
+
+OSQLColumns::const_iterator findRealName(const OSQLColumns::const_iterator& first,
+ const OSQLColumns::const_iterator& last,
+ std::u16string_view _rVal,
+ const ::comphelper::UStringMixEqual& _rCase)
+{
+ OUString sRealName = OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_REALNAME);
+ return find(first,last,sRealName,_rVal,_rCase);
+}
+
+OSQLColumns::const_iterator find(OSQLColumns::const_iterator first,
+ const OSQLColumns::const_iterator& last,
+ const OUString& _rProp,
+ std::u16string_view _rVal,
+ const ::comphelper::UStringMixEqual& _rCase)
+{
+ while (first != last && !_rCase(getString((*first)->getPropertyValue(_rProp)),_rVal))
+ ++first;
+ return first;
+}
+
+namespace dbase
+{
+ bool dbfDecodeCharset(rtl_TextEncoding &_out_encoding, sal_uInt8 nType, sal_uInt8 nCodepage)
+ {
+ switch (nType)
+ {
+ // dBaseIII header doesn't contain language driver ID
+ // See http://dbase.free.fr/tlcharge/structure%20tables.pdf
+ case dBaseIII:
+ case dBaseIIIMemo:
+ break;
+ case dBaseIV:
+ case dBaseV:
+ case VisualFoxPro:
+ case VisualFoxProAuto:
+ case dBaseFS:
+ case dBaseFSMemo:
+ case dBaseIVMemoSQL:
+ case FoxProMemo:
+ {
+ if (nCodepage != 0x00)
+ {
+ auto eEncoding(RTL_TEXTENCODING_DONTKNOW);
+ switch(nCodepage)
+ {
+ case 0x01: eEncoding = RTL_TEXTENCODING_IBM_437; break; // DOS USA code page 437
+ case 0x02: eEncoding = RTL_TEXTENCODING_IBM_850; break; // DOS Multilingual code page 850
+ case 0x03: eEncoding = RTL_TEXTENCODING_MS_1252; break; // Windows ANSI code page 1252
+ case 0x04: eEncoding = RTL_TEXTENCODING_APPLE_ROMAN; break; // Standard Macintosh
+ case 0x64: eEncoding = RTL_TEXTENCODING_IBM_852; break; // EE MS-DOS code page 852
+ case 0x65: eEncoding = RTL_TEXTENCODING_IBM_866; break; // Russian MS-DOS code page 866
+ case 0x66: eEncoding = RTL_TEXTENCODING_IBM_865; break; // Nordic MS-DOS code page 865
+ case 0x67: eEncoding = RTL_TEXTENCODING_IBM_861; break; // Icelandic MS-DOS
+ case 0x68: eEncoding = RTL_TEXTENCODING_KAMENICKY; break; // Kamenicky (Czech) MS-DOS
+ case 0x69: eEncoding = RTL_TEXTENCODING_MAZOVIA; break; // Mazovia (Polish) MS-DOS
+ case 0x6A: eEncoding = RTL_TEXTENCODING_IBM_737; break; // Greek MS-DOS (437G)
+ case 0x6B: eEncoding = RTL_TEXTENCODING_IBM_857; break; // Turkish MS-DOS
+ case 0x6C: eEncoding = RTL_TEXTENCODING_IBM_863; break; // MS-DOS, Canada
+ case 0x78: eEncoding = RTL_TEXTENCODING_MS_950; break; // Windows, Traditional Chinese
+ case 0x79: eEncoding = RTL_TEXTENCODING_MS_949; break; // Windows, Korean (Hangul)
+ case 0x7A: eEncoding = RTL_TEXTENCODING_MS_936; break; // Windows, Simplified Chinese
+ case 0x7B: eEncoding = RTL_TEXTENCODING_MS_932; break; // Windows, Japanese (Shift-jis)
+ case 0x7C: eEncoding = RTL_TEXTENCODING_MS_874; break; // Windows, Thai
+ case 0x7D: eEncoding = RTL_TEXTENCODING_MS_1255; break; // Windows, Hebrew
+ case 0x7E: eEncoding = RTL_TEXTENCODING_MS_1256; break; // Windows, Arabic
+ case 0x96: eEncoding = RTL_TEXTENCODING_APPLE_CYRILLIC; break; // Russian Macintosh
+ case 0x97: eEncoding = RTL_TEXTENCODING_APPLE_CENTEURO; break; // Eastern European Macintosh
+ case 0x98: eEncoding = RTL_TEXTENCODING_APPLE_GREEK; break; // Greek Macintosh
+ case 0xC8: eEncoding = RTL_TEXTENCODING_MS_1250; break; // Windows EE code page 1250
+ case 0xC9: eEncoding = RTL_TEXTENCODING_MS_1251; break; // Russian Windows
+ case 0xCA: eEncoding = RTL_TEXTENCODING_MS_1254; break; // Turkish Windows
+ case 0xCB: eEncoding = RTL_TEXTENCODING_MS_1253; break; // Greek Windows
+ case 0xCC: eEncoding = RTL_TEXTENCODING_MS_1257; break; // Windows, Baltic
+ }
+ if(eEncoding != RTL_TEXTENCODING_DONTKNOW)
+ {
+ _out_encoding = eEncoding;
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ bool dbfReadCharset(rtl_TextEncoding &nCharSet, SvStream* dbf_Stream)
+ {
+ sal_uInt8 nType=0;
+ dbf_Stream->ReadUChar( nType );
+
+ dbf_Stream->Seek(STREAM_SEEK_TO_BEGIN + 29);
+ if (dbf_Stream->eof())
+ {
+ return false;
+ }
+ else
+ {
+ sal_uInt8 nEncoding=0;
+ dbf_Stream->ReadUChar( nEncoding );
+ return dbfDecodeCharset(nCharSet, nType, nEncoding);
+ }
+ }
+
+}
+
+} //namespace connectivity
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/dbtools2.cxx b/connectivity/source/commontools/dbtools2.cxx
new file mode 100644
index 0000000000..8148b25ddc
--- /dev/null
+++ b/connectivity/source/commontools/dbtools2.cxx
@@ -0,0 +1,1018 @@
+/* -*- 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 <connectivity/dbtools.hxx>
+#include <connectivity/dbconversion.hxx>
+#include <connectivity/dbcharset.hxx>
+#include <SQLStatementHelper.hxx>
+#include <unotools/confignode.hxx>
+#include <resource/sharedresources.hxx>
+#include <strings.hrc>
+#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdbc/XDataSource.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/DriverManager.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbcx/XKeysSupplier.hpp>
+#include <com/sun/star/sdbcx/XDataDefinitionSupplier.hpp>
+#include <com/sun/star/sdbcx/Privilege.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/sdbc/KeyRule.hpp>
+#include <com/sun/star/sdbcx/KeyType.hpp>
+#include <TConnection.hxx>
+#include <connectivity/sdbcx/VColumn.hxx>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/container/XChild.hpp>
+
+#include <comphelper/types.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <unotools/sharedunocomponent.hxx>
+#include <algorithm>
+#include <string_view>
+
+namespace dbtools
+{
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::sdb;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::com::sun::star::sdbcx;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::container;
+ using namespace ::com::sun::star::frame;
+ using namespace connectivity;
+ using namespace comphelper;
+
+OUString createStandardTypePart(const Reference< XPropertySet >& xColProp,const Reference< XConnection>& _xConnection,std::u16string_view _sCreatePattern)
+{
+
+ Reference<XDatabaseMetaData> xMetaData = _xConnection->getMetaData();
+
+ ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
+
+ OUString sTypeName;
+ sal_Int32 nDataType = 0;
+ sal_Int32 nPrecision = 0;
+ sal_Int32 nScale = 0;
+
+ nDataType = nPrecision = nScale = 0;
+
+ xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_TYPENAME)) >>= sTypeName;
+ xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_TYPE)) >>= nDataType;
+ xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_PRECISION)) >>= nPrecision;
+ xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_SCALE)) >>= nScale;
+
+ OUStringBuffer aSql;
+
+ // check if the user enter a specific string to create autoincrement values
+ OUString sAutoIncrementValue;
+ Reference<XPropertySetInfo> xPropInfo = xColProp->getPropertySetInfo();
+ if ( xPropInfo.is() && xPropInfo->hasPropertyByName(rPropMap.getNameByIndex(PROPERTY_ID_AUTOINCREMENTCREATION)) )
+ xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_AUTOINCREMENTCREATION)) >>= sAutoIncrementValue;
+ // look if we have to use precisions
+ bool bUseLiteral = false;
+ OUString sPrefix,sPostfix,sCreateParams;
+ {
+ Reference<XResultSet> xRes = xMetaData->getTypeInfo();
+ if(xRes.is())
+ {
+ Reference<XRow> xRow(xRes,UNO_QUERY);
+ while(xRes->next())
+ {
+ OUString sTypeName2Cmp = xRow->getString(1);
+ sal_Int32 nType = xRow->getShort(2);
+ sPrefix = xRow->getString (4);
+ sPostfix = xRow->getString (5);
+ sCreateParams = xRow->getString(6);
+ // first identical type will be used if typename is empty
+ if ( sTypeName.isEmpty() && nType == nDataType )
+ sTypeName = sTypeName2Cmp;
+
+ if( sTypeName.equalsIgnoreAsciiCase(sTypeName2Cmp) && nType == nDataType && !sCreateParams.isEmpty() && !xRow->wasNull())
+ {
+ bUseLiteral = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if ( !sAutoIncrementValue.isEmpty() )
+ {
+ sal_Int32 nIndex = sTypeName.indexOf(sAutoIncrementValue);
+ if (nIndex != -1)
+ sTypeName = sTypeName.replaceAt(nIndex,sTypeName.getLength() - nIndex, u"");
+ }
+
+ if ( (nPrecision > 0 || nScale > 0) && bUseLiteral )
+ {
+ bool bTimed = (nDataType == DataType::TIME ||
+ nDataType == DataType::TIME_WITH_TIMEZONE ||
+ nDataType == DataType::TIMESTAMP ||
+ nDataType == DataType::TIMESTAMP_WITH_TIMEZONE);
+
+ sal_Int32 nParenPos = (nDataType == DataType::TIME_WITH_TIMEZONE ||
+ nDataType == DataType::TIMESTAMP_WITH_TIMEZONE) ?
+ sTypeName.indexOf(' ') :
+ sTypeName.indexOf('(');
+
+ if ( nParenPos == -1 )
+ aSql.append(sTypeName);
+ else
+ aSql.append(sTypeName.subView(0, nParenPos));
+ aSql.append("(");
+
+ if ( nPrecision > 0 && !bTimed )
+ {
+ aSql.append(nPrecision);
+ if ( (nScale > 0) || (!_sCreatePattern.empty() && sCreateParams.indexOf(_sCreatePattern) != -1) )
+ aSql.append(",");
+ }
+ if ( (nScale > 0) || ( !_sCreatePattern.empty() && sCreateParams.indexOf(_sCreatePattern) != -1 ) || bTimed )
+ aSql.append(nScale);
+
+ if ( nParenPos == -1 )
+ aSql.append(")");
+ else
+ {
+ if ( bTimed )
+ aSql.append(")");
+ else
+ nParenPos = sTypeName.indexOf(')',nParenPos);
+ aSql.append(sTypeName.subView(nParenPos));
+ }
+ }
+ else
+ aSql.append(sTypeName); // simply add the type name
+
+ OUString aDefault = ::comphelper::getString(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_DEFAULTVALUE)));
+ if ( !aDefault.isEmpty() )
+ {
+ aSql.append(" DEFAULT " + sPrefix + aDefault + sPostfix);
+ } // if ( aDefault.getLength() )
+
+ return aSql.makeStringAndClear();
+}
+
+OUString createStandardColumnPart(const Reference< XPropertySet >& xColProp,const Reference< XConnection>& _xConnection,ISQLStatementHelper* _pHelper,std::u16string_view _sCreatePattern)
+{
+ Reference<XDatabaseMetaData> xMetaData = _xConnection->getMetaData();
+
+ ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
+
+ bool bIsAutoIncrement = false;
+ xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT)) >>= bIsAutoIncrement;
+
+ const OUString sQuoteString = xMetaData->getIdentifierQuoteString();
+ OUStringBuffer aSql(::dbtools::quoteName(sQuoteString,::comphelper::getString(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)))));
+
+ // check if the user enter a specific string to create autoincrement values
+ OUString sAutoIncrementValue;
+ Reference<XPropertySetInfo> xPropInfo = xColProp->getPropertySetInfo();
+ if ( xPropInfo.is() && xPropInfo->hasPropertyByName(rPropMap.getNameByIndex(PROPERTY_ID_AUTOINCREMENTCREATION)) )
+ xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_AUTOINCREMENTCREATION)) >>= sAutoIncrementValue;
+
+ aSql.append(" " + createStandardTypePart(xColProp, _xConnection, _sCreatePattern));
+
+ if(::comphelper::getINT32(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_ISNULLABLE))) == ColumnValue::NO_NULLS)
+ aSql.append(" NOT NULL");
+
+ if ( bIsAutoIncrement && !sAutoIncrementValue.isEmpty())
+ {
+ aSql.append(" " + sAutoIncrementValue);
+ }
+
+ if ( _pHelper )
+ _pHelper->addComment(xColProp,aSql);
+
+ return aSql.makeStringAndClear();
+}
+
+
+OUString createStandardCreateStatement(const Reference< XPropertySet >& descriptor,const Reference< XConnection>& _xConnection,ISQLStatementHelper* _pHelper,std::u16string_view _sCreatePattern)
+{
+ OUStringBuffer aSql("CREATE TABLE ");
+ OUString sCatalog,sSchema,sTable,sComposedName;
+
+ Reference<XDatabaseMetaData> xMetaData = _xConnection->getMetaData();
+ ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
+
+ descriptor->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME)) >>= sCatalog;
+ descriptor->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_SCHEMANAME)) >>= sSchema;
+ descriptor->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)) >>= sTable;
+
+ sComposedName = ::dbtools::composeTableName( xMetaData, sCatalog, sSchema, sTable, true, ::dbtools::EComposeRule::InTableDefinitions );
+ if ( sComposedName.isEmpty() )
+ ::dbtools::throwFunctionSequenceException(_xConnection);
+
+ aSql.append(sComposedName + " (");
+
+ // columns
+ Reference<XColumnsSupplier> xColumnSup(descriptor,UNO_QUERY);
+ Reference<XIndexAccess> xColumns(xColumnSup->getColumns(),UNO_QUERY);
+ // check if there are columns
+ if(!xColumns.is() || !xColumns->getCount())
+ ::dbtools::throwFunctionSequenceException(_xConnection);
+
+ Reference< XPropertySet > xColProp;
+
+ sal_Int32 nCount = xColumns->getCount();
+ for(sal_Int32 i=0;i<nCount;++i)
+ {
+ if ( (xColumns->getByIndex(i) >>= xColProp) && xColProp.is() )
+ {
+ aSql.append(
+ createStandardColumnPart(xColProp,_xConnection,_pHelper,_sCreatePattern)
+ + ",");
+ }
+ }
+ return aSql.makeStringAndClear();
+}
+namespace
+{
+ OUString generateColumnNames(const Reference<XIndexAccess>& _xColumns,const Reference<XDatabaseMetaData>& _xMetaData)
+ {
+ ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
+
+ const OUString sQuote(_xMetaData->getIdentifierQuoteString());
+ OUStringBuffer sSql( " (" );
+ Reference< XPropertySet > xColProp;
+
+ sal_Int32 nColCount = _xColumns->getCount();
+ for(sal_Int32 i=0;i<nColCount;++i)
+ {
+ if ( (_xColumns->getByIndex(i) >>= xColProp) && xColProp.is() )
+ sSql.append( ::dbtools::quoteName(sQuote,::comphelper::getString(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)))) +
+ ",");
+ }
+
+ if ( nColCount )
+ sSql[sSql.getLength()-1] = ')';
+ return sSql.makeStringAndClear();
+ }
+}
+
+OUString createStandardKeyStatement(const Reference< XPropertySet >& descriptor,const Reference< XConnection>& _xConnection)
+{
+ Reference<XDatabaseMetaData> xMetaData = _xConnection->getMetaData();
+ ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
+
+ OUStringBuffer aSql;
+ // keys
+ Reference<XKeysSupplier> xKeySup(descriptor,UNO_QUERY);
+ Reference<XIndexAccess> xKeys = xKeySup->getKeys();
+ if ( xKeys.is() )
+ {
+ Reference< XPropertySet > xColProp;
+ Reference<XIndexAccess> xColumns;
+ Reference<XColumnsSupplier> xColumnSup;
+ OUString sCatalog,sSchema,sTable,sComposedName;
+ bool bPKey = false;
+ for(sal_Int32 i=0;i<xKeys->getCount();++i)
+ {
+ if ( (xKeys->getByIndex(i) >>= xColProp) && xColProp.is() )
+ {
+
+ sal_Int32 nKeyType = ::comphelper::getINT32(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_TYPE)));
+
+ if ( nKeyType == KeyType::PRIMARY )
+ {
+ if(bPKey)
+ ::dbtools::throwFunctionSequenceException(_xConnection);
+
+ bPKey = true;
+ xColumnSup.set(xColProp,UNO_QUERY);
+ xColumns.set(xColumnSup->getColumns(),UNO_QUERY);
+ if(!xColumns.is() || !xColumns->getCount())
+ ::dbtools::throwFunctionSequenceException(_xConnection);
+
+ aSql.append(" PRIMARY KEY " + generateColumnNames(xColumns,xMetaData));
+ }
+ else if(nKeyType == KeyType::UNIQUE)
+ {
+ xColumnSup.set(xColProp,UNO_QUERY);
+ xColumns.set(xColumnSup->getColumns(),UNO_QUERY);
+ if(!xColumns.is() || !xColumns->getCount())
+ ::dbtools::throwFunctionSequenceException(_xConnection);
+
+ aSql.append(" UNIQUE " + generateColumnNames(xColumns,xMetaData));
+ }
+ else if(nKeyType == KeyType::FOREIGN)
+ {
+ sal_Int32 nDeleteRule = getINT32(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_DELETERULE)));
+
+ xColumnSup.set(xColProp,UNO_QUERY);
+ xColumns.set(xColumnSup->getColumns(),UNO_QUERY);
+ if(!xColumns.is() || !xColumns->getCount())
+ ::dbtools::throwFunctionSequenceException(_xConnection);
+
+ aSql.append(" FOREIGN KEY ");
+ OUString sRefTable = getString(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_REFERENCEDTABLE)));
+ ::dbtools::qualifiedNameComponents(xMetaData,
+ sRefTable,
+ sCatalog,
+ sSchema,
+ sTable,
+ ::dbtools::EComposeRule::InDataManipulation);
+ sComposedName = ::dbtools::composeTableName( xMetaData, sCatalog, sSchema, sTable, true, ::dbtools::EComposeRule::InTableDefinitions );
+
+
+ if ( sComposedName.isEmpty() )
+ ::dbtools::throwFunctionSequenceException(_xConnection);
+
+ aSql.append(generateColumnNames(xColumns,xMetaData));
+
+ switch(nDeleteRule)
+ {
+ case KeyRule::CASCADE:
+ aSql.append(" ON DELETE CASCADE ");
+ break;
+ case KeyRule::RESTRICT:
+ aSql.append(" ON DELETE RESTRICT ");
+ break;
+ case KeyRule::SET_NULL:
+ aSql.append(" ON DELETE SET NULL ");
+ break;
+ case KeyRule::SET_DEFAULT:
+ aSql.append(" ON DELETE SET DEFAULT ");
+ break;
+ default:
+ ;
+ }
+ }
+ }
+ }
+ }
+
+ if ( !aSql.isEmpty() )
+ {
+ if ( aSql[aSql.getLength() - 1] == ',' )
+ aSql[aSql.getLength() - 1] = ')';
+ else
+ aSql.append(")");
+ }
+
+ return aSql.makeStringAndClear();
+
+}
+
+OUString createSqlCreateTableStatement( const Reference< XPropertySet >& descriptor,
+ const Reference< XConnection>& _xConnection)
+{
+ OUString aSql = ::dbtools::createStandardCreateStatement(descriptor,_xConnection,nullptr,{});
+ const OUString sKeyStmt = ::dbtools::createStandardKeyStatement(descriptor,_xConnection);
+ if ( !sKeyStmt.isEmpty() )
+ aSql += sKeyStmt;
+ else
+ {
+ if ( aSql.endsWith(",") )
+ aSql = aSql.replaceAt(aSql.getLength()-1, 1, u")");
+ else
+ aSql += ")";
+ }
+ return aSql;
+}
+namespace
+{
+ Reference<XPropertySet> lcl_createSDBCXColumn(const Reference<XNameAccess>& _xPrimaryKeyColumns,
+ const Reference<XConnection>& _xConnection,
+ const Any& _aCatalog,
+ const OUString& _aSchema,
+ const OUString& _aTable,
+ const OUString& _rQueryName,
+ const OUString& _rName,
+ bool _bCase,
+ bool _bQueryForInfo,
+ bool _bIsAutoIncrement,
+ bool _bIsCurrency,
+ sal_Int32 _nDataType)
+ {
+ Reference<XPropertySet> xProp;
+ Reference<XDatabaseMetaData> xMetaData = _xConnection->getMetaData();
+ Reference< XResultSet > xResult = xMetaData->getColumns(_aCatalog, _aSchema, _aTable, _rQueryName);
+ OUString sCatalog;
+ _aCatalog >>= sCatalog;
+
+ if ( xResult.is() )
+ {
+ UStringMixEqual aMixCompare(_bCase);
+ Reference< XRow > xRow(xResult,UNO_QUERY);
+ while( xResult->next() )
+ {
+ if ( aMixCompare(xRow->getString(4),_rName) )
+ {
+ 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);
+ ::comphelper::disposeComponent(xRow);
+
+ bool bAutoIncrement = _bIsAutoIncrement
+ ,bIsCurrency = _bIsCurrency;
+ if ( _bQueryForInfo )
+ {
+ const OUString sQuote = xMetaData->getIdentifierQuoteString();
+ OUString sQuotedName = ::dbtools::quoteName(sQuote,_rName);
+ OUString sComposedName = composeTableNameForSelect(_xConnection, getString( _aCatalog ), _aSchema, _aTable );
+
+ ColumnInformationMap aInfo(_bCase);
+ collectColumnInformation(_xConnection,sComposedName,sQuotedName,aInfo);
+ ColumnInformationMap::const_iterator aIter = aInfo.begin();
+ if ( aIter != aInfo.end() )
+ {
+ bAutoIncrement = aIter->second.first.first;
+ bIsCurrency = aIter->second.first.second;
+ if ( DataType::OTHER == nField5 )
+ nField5 = aIter->second.second;
+ }
+ }
+ else if ( DataType::OTHER == nField5 )
+ nField5 = _nDataType;
+
+ if ( nField11 != ColumnValue::NO_NULLS )
+ {
+ try
+ {
+ if ( _xPrimaryKeyColumns.is() )
+ {
+ if ( _xPrimaryKeyColumns->hasByName(_rName) )
+ nField11 = ColumnValue::NO_NULLS;
+
+ }
+ else
+ {
+ Reference< XResultSet > xPKeys = xMetaData->getPrimaryKeys( _aCatalog, _aSchema, _aTable );
+ Reference< XRow > xPKeyRow( xPKeys, UNO_QUERY_THROW );
+ while( xPKeys->next() ) // there can be only one primary key
+ {
+ OUString sKeyColumn = xPKeyRow->getString(4);
+ if ( aMixCompare(_rName,sKeyColumn) )
+ {
+ nField11 = ColumnValue::NO_NULLS;
+ break;
+ }
+ }
+ }
+ }
+ catch(SQLException&)
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "lcl_createSDBCXColumn" );
+ }
+ }
+
+ xProp = new connectivity::sdbcx::OColumn(_rName,
+ aField6,
+ sField13,
+ sField12,
+ nField11,
+ nField7,
+ nField9,
+ nField5,
+ bAutoIncrement,
+ false,
+ bIsCurrency,
+ _bCase,
+ sCatalog,
+ _aSchema,
+ _aTable);
+
+ break;
+ }
+ }
+ }
+
+ return xProp;
+ }
+
+ Reference< XModel> lcl_getXModel(const Reference< XInterface>& _xIface)
+ {
+ Reference< XInterface > xParent = _xIface;
+ Reference< XModel > xModel(xParent,UNO_QUERY);
+ while( xParent.is() && !xModel.is() )
+ {
+ Reference<XChild> xChild(xParent,UNO_QUERY);
+ xParent.set(xChild.is() ? xChild->getParent() : Reference< XInterface >(),UNO_QUERY);
+ xModel.set(xParent,UNO_QUERY);
+ }
+ return xModel;
+ }
+}
+
+Reference<XPropertySet> createSDBCXColumn(const Reference<XPropertySet>& _xTable,
+ const Reference<XConnection>& _xConnection,
+ const OUString& _rName,
+ bool _bCase,
+ bool _bQueryForInfo,
+ bool _bIsAutoIncrement,
+ bool _bIsCurrency,
+ sal_Int32 _nDataType)
+{
+ Reference<XPropertySet> xProp;
+ OSL_ENSURE(_xTable.is(),"Table is NULL!");
+ if ( !_xTable.is() )
+ return xProp;
+
+ ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
+ Any aCatalog = _xTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME));
+ OUString sCatalog;
+ aCatalog >>= sCatalog;
+
+ OUString aSchema, aTable;
+ _xTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_SCHEMANAME)) >>= aSchema;
+ _xTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)) >>= aTable;
+
+ Reference<XNameAccess> xPrimaryKeyColumns = getPrimaryKeyColumns_throw(_xTable);
+
+ xProp = lcl_createSDBCXColumn(xPrimaryKeyColumns,_xConnection,aCatalog, aSchema, aTable, _rName,_rName,_bCase,_bQueryForInfo,_bIsAutoIncrement,_bIsCurrency,_nDataType);
+ if ( !xProp.is() )
+ {
+ xProp = lcl_createSDBCXColumn(xPrimaryKeyColumns,_xConnection,aCatalog, aSchema, aTable, "%",_rName,_bCase,_bQueryForInfo,_bIsAutoIncrement,_bIsCurrency,_nDataType);
+ if ( !xProp.is() )
+ xProp = new connectivity::sdbcx::OColumn(_rName,
+ OUString(),OUString(),OUString(),
+ ColumnValue::NULLABLE_UNKNOWN,
+ 0,
+ 0,
+ DataType::VARCHAR,
+ _bIsAutoIncrement,
+ false,
+ _bIsCurrency,
+ _bCase,
+ sCatalog,
+ aSchema,
+ aTable);
+
+ }
+
+ return xProp;
+}
+
+
+bool getBooleanDataSourceSetting( const Reference< XConnection >& _rxConnection, const char* _pAsciiSettingName )
+{
+ return getBooleanDataSourceSetting(_rxConnection, OUString::createFromAscii( _pAsciiSettingName ));
+}
+
+bool getBooleanDataSourceSetting( const Reference< XConnection >& _rxConnection, const OUString & rSettingName )
+{
+ bool bValue( false );
+ try
+ {
+ Reference< XPropertySet> xDataSourceProperties( findDataSource( _rxConnection ), UNO_QUERY );
+ OSL_ENSURE( xDataSourceProperties.is(), "::dbtools::getBooleanDataSourceSetting: somebody is using this with a non-SDB-level connection!" );
+ if ( xDataSourceProperties.is() )
+ {
+ Reference< XPropertySet > xSettings(
+ xDataSourceProperties->getPropertyValue("Settings"),
+ UNO_QUERY_THROW
+ );
+ OSL_VERIFY( xSettings->getPropertyValue( rSettingName ) >>= bValue );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+ return bValue;
+}
+
+bool getDataSourceSetting( const Reference< XInterface >& _xChild, const OUString& _sAsciiSettingsName,
+ Any& /* [out] */ _rSettingsValue )
+{
+ bool bIsPresent = false;
+ try
+ {
+ const Reference< XPropertySet> xDataSourceProperties( findDataSource( _xChild ), UNO_QUERY );
+ if ( !xDataSourceProperties.is() )
+ return false;
+
+ const Reference< XPropertySet > xSettings(
+ xDataSourceProperties->getPropertyValue("Settings"),
+ UNO_QUERY_THROW
+ );
+
+ _rSettingsValue = xSettings->getPropertyValue( _sAsciiSettingsName );
+ bIsPresent = true;
+ }
+ catch( const Exception& )
+ {
+ bIsPresent = false;
+ }
+ return bIsPresent;
+}
+
+bool getDataSourceSetting( const Reference< XInterface >& _rxDataSource, const char* _pAsciiSettingsName,
+ Any& /* [out] */ _rSettingsValue )
+{
+ OUString sAsciiSettingsName = OUString::createFromAscii(_pAsciiSettingsName);
+ return getDataSourceSetting( _rxDataSource, sAsciiSettingsName,_rSettingsValue );
+}
+
+bool isDataSourcePropertyEnabled(const Reference<XInterface>& _xProp, const OUString& _sProperty, bool _bDefault)
+{
+ bool bEnabled = _bDefault;
+ try
+ {
+ Reference< XPropertySet> xProp(findDataSource(_xProp),UNO_QUERY);
+ if ( xProp.is() )
+ {
+ Sequence< PropertyValue > aInfo;
+ xProp->getPropertyValue("Info") >>= aInfo;
+ const PropertyValue* pValue =std::find_if(std::cbegin(aInfo),
+ std::cend(aInfo),
+ [&_sProperty](const PropertyValue& lhs)
+ { return lhs.Name == _sProperty; });
+ if ( pValue != std::cend(aInfo) )
+ pValue->Value >>= bEnabled;
+ }
+ }
+ catch(SQLException&)
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+ return bEnabled;
+}
+
+Reference< XTablesSupplier> getDataDefinitionByURLAndConnection(
+ const OUString& _rsUrl,
+ const Reference< XConnection>& _xConnection,
+ const Reference< XComponentContext >& _rxContext)
+{
+ Reference< XTablesSupplier> xTablesSup;
+ try
+ {
+ Reference< XDriverManager2 > xManager = DriverManager::create( _rxContext );
+ Reference< XDataDefinitionSupplier > xSupp( xManager->getDriverByURL( _rsUrl ), UNO_QUERY );
+
+ if ( xSupp.is() )
+ {
+ xTablesSup = xSupp->getDataDefinitionByConnection( _xConnection );
+ OSL_ENSURE(xTablesSup.is(),"No table supplier!");
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+ return xTablesSup;
+}
+
+
+sal_Int32 getTablePrivileges(const Reference< XDatabaseMetaData>& _xMetaData,
+ const OUString& _sCatalog,
+ const OUString& _sSchema,
+ const OUString& _sTable)
+{
+ OSL_ENSURE(_xMetaData.is(),"Invalid metadata!");
+ sal_Int32 nPrivileges = 0;
+ try
+ {
+ Any aVal;
+ if(!_sCatalog.isEmpty())
+ aVal <<= _sCatalog;
+ Reference< XResultSet > xPrivileges = _xMetaData->getTablePrivileges(aVal, _sSchema, _sTable);
+ Reference< XRow > xCurrentRow(xPrivileges, UNO_QUERY);
+
+ const OUString sUserWorkingFor = _xMetaData->getUserName();
+ static const char sSELECT[] = "SELECT";
+ static const char sINSERT[] = "INSERT";
+ static const char sUPDATE[] = "UPDATE";
+ static const char sDELETE[] = "DELETE";
+ static const char sREAD[] = "READ";
+ static const char sCREATE[] = "CREATE";
+ static const char sALTER[] = "ALTER";
+ static const char sREFERENCE[] = "REFERENCE";
+ static const char sDROP[] = "DROP";
+
+ if ( xCurrentRow.is() )
+ {
+ // after creation the set is positioned before the first record, per definition
+ OUString sPrivilege, sGrantee;
+ while ( xPrivileges->next() )
+ {
+ sGrantee = xCurrentRow->getString(5);
+ sPrivilege = xCurrentRow->getString(6);
+
+ if (!sUserWorkingFor.equalsIgnoreAsciiCase(sGrantee))
+ continue;
+
+ if (sPrivilege.equalsIgnoreAsciiCase(sSELECT))
+ nPrivileges |= Privilege::SELECT;
+ else if (sPrivilege.equalsIgnoreAsciiCase(sINSERT))
+ nPrivileges |= Privilege::INSERT;
+ else if (sPrivilege.equalsIgnoreAsciiCase(sUPDATE))
+ nPrivileges |= Privilege::UPDATE;
+ else if (sPrivilege.equalsIgnoreAsciiCase(sDELETE))
+ nPrivileges |= Privilege::DELETE;
+ else if (sPrivilege.equalsIgnoreAsciiCase(sREAD))
+ nPrivileges |= Privilege::READ;
+ else if (sPrivilege.equalsIgnoreAsciiCase(sCREATE))
+ nPrivileges |= Privilege::CREATE;
+ else if (sPrivilege.equalsIgnoreAsciiCase(sALTER))
+ nPrivileges |= Privilege::ALTER;
+ else if (sPrivilege.equalsIgnoreAsciiCase(sREFERENCE))
+ nPrivileges |= Privilege::REFERENCE;
+ else if (sPrivilege.equalsIgnoreAsciiCase(sDROP))
+ nPrivileges |= Privilege::DROP;
+ }
+ }
+ disposeComponent(xPrivileges);
+
+ // Some drivers put a table privilege as soon as any column has the privilege,
+ // some drivers only if all columns have the privilege.
+ // To unify the situation, collect column privileges here, too.
+ Reference< XResultSet > xColumnPrivileges = _xMetaData->getColumnPrivileges(aVal, _sSchema, _sTable, "%");
+ Reference< XRow > xColumnCurrentRow(xColumnPrivileges, UNO_QUERY);
+ if ( xColumnCurrentRow.is() )
+ {
+ // after creation the set is positioned before the first record, per definition
+ OUString sPrivilege, sGrantee;
+ while ( xColumnPrivileges->next() )
+ {
+ sGrantee = xColumnCurrentRow->getString(6);
+ sPrivilege = xColumnCurrentRow->getString(7);
+
+ if (!sUserWorkingFor.equalsIgnoreAsciiCase(sGrantee))
+ continue;
+
+ if (sPrivilege.equalsIgnoreAsciiCase(sSELECT))
+ nPrivileges |= Privilege::SELECT;
+ else if (sPrivilege.equalsIgnoreAsciiCase(sINSERT))
+ nPrivileges |= Privilege::INSERT;
+ else if (sPrivilege.equalsIgnoreAsciiCase(sUPDATE))
+ nPrivileges |= Privilege::UPDATE;
+ else if (sPrivilege.equalsIgnoreAsciiCase(sDELETE))
+ nPrivileges |= Privilege::DELETE;
+ else if (sPrivilege.equalsIgnoreAsciiCase(sREAD))
+ nPrivileges |= Privilege::READ;
+ else if (sPrivilege.equalsIgnoreAsciiCase(sCREATE))
+ nPrivileges |= Privilege::CREATE;
+ else if (sPrivilege.equalsIgnoreAsciiCase(sALTER))
+ nPrivileges |= Privilege::ALTER;
+ else if (sPrivilege.equalsIgnoreAsciiCase(sREFERENCE))
+ nPrivileges |= Privilege::REFERENCE;
+ else if (sPrivilege.equalsIgnoreAsciiCase(sDROP))
+ nPrivileges |= Privilege::DROP;
+ }
+ }
+ disposeComponent(xColumnPrivileges);
+ }
+ catch(const SQLException& e)
+ {
+ // some drivers don't support any privileges so we assume that we are allowed to do all we want :-)
+ if(e.SQLState == "IM001")
+ nPrivileges |= Privilege::DROP |
+ Privilege::REFERENCE |
+ Privilege::ALTER |
+ Privilege::CREATE |
+ Privilege::READ |
+ Privilege::DELETE |
+ Privilege::UPDATE |
+ Privilege::INSERT |
+ Privilege::SELECT;
+ else
+ OSL_FAIL("Could not collect the privileges !");
+ }
+ return nPrivileges;
+}
+
+// we need some more information about the column
+void collectColumnInformation(const Reference< XConnection>& _xConnection,
+ std::u16string_view _sComposedName,
+ std::u16string_view _rName,
+ ColumnInformationMap& _rInfo)
+{
+ OUString sSelect = OUString::Concat("SELECT ") + _rName +
+ " FROM " + _sComposedName +
+ " WHERE 0 = 1";
+
+ try
+ {
+ ::utl::SharedUNOComponent< XStatement > xStmt( _xConnection->createStatement() );
+ Reference< XPropertySet > xStatementProps( xStmt, UNO_QUERY_THROW );
+ xStatementProps->setPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_ESCAPEPROCESSING ), Any( false ) );
+ Reference< XResultSet > xResult( xStmt->executeQuery( sSelect ), UNO_SET_THROW );
+ Reference< XResultSetMetaDataSupplier > xSuppMeta( xResult, UNO_QUERY_THROW );
+ Reference< XResultSetMetaData > xMeta( xSuppMeta->getMetaData(), UNO_SET_THROW );
+
+ sal_Int32 nCount = xMeta->getColumnCount();
+ OSL_ENSURE( nCount != 0, "::dbtools::collectColumnInformation: result set has empty (column-less) meta data!" );
+ for (sal_Int32 i=1; i <= nCount ; ++i)
+ {
+ _rInfo.emplace( xMeta->getColumnName(i),
+ ColumnInformation(TBoolPair(xMeta->isAutoIncrement(i),xMeta->isCurrency(i)),xMeta->getColumnType(i)));
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+}
+
+
+bool isEmbeddedInDatabase( const Reference< XInterface >& _rxComponent, Reference< XConnection >& _rxActualConnection )
+{
+ bool bIsEmbedded = false;
+ try
+ {
+ Reference< XModel > xModel = lcl_getXModel( _rxComponent );
+
+ if ( xModel.is() )
+ {
+ Sequence< PropertyValue > aArgs = xModel->getArgs();
+ const PropertyValue* pIter = aArgs.getConstArray();
+ const PropertyValue* pEnd = pIter + aArgs.getLength();
+ for(;pIter != pEnd;++pIter)
+ {
+ if ( pIter->Name == "ComponentData" )
+ {
+ Sequence<PropertyValue> aDocumentContext;
+ pIter->Value >>= aDocumentContext;
+ const PropertyValue* pContextIter = aDocumentContext.getConstArray();
+ const PropertyValue* pContextEnd = pContextIter + aDocumentContext.getLength();
+ for(;pContextIter != pContextEnd;++pContextIter)
+ {
+ if ( pContextIter->Name == "ActiveConnection"
+ && ( pContextIter->Value >>= _rxActualConnection )
+ )
+ {
+ bIsEmbedded = true;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+ catch(Exception&)
+ {
+ // not interested in
+ }
+ return bIsEmbedded;
+}
+
+namespace
+{
+ OUString lcl_getEncodingName( rtl_TextEncoding _eEncoding )
+ {
+ OUString sEncodingName;
+
+ OCharsetMap aCharsets;
+ OCharsetMap::CharsetIterator aEncodingPos = aCharsets.find( _eEncoding );
+ OSL_ENSURE( aEncodingPos != aCharsets.end(), "lcl_getEncodingName: *which* encoding?" );
+ if ( aEncodingPos != aCharsets.end() )
+ sEncodingName = (*aEncodingPos).getIanaName();
+
+ return sEncodingName;
+ }
+}
+
+
+sal_Int32 DBTypeConversion::convertUnicodeString( const OUString& _rSource, OString& _rDest, rtl_TextEncoding _eEncoding )
+{
+ if ( !rtl_convertUStringToString( &_rDest.pData, _rSource.getStr(), _rSource.getLength(),
+ _eEncoding,
+ RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR |
+ RTL_UNICODETOTEXT_FLAGS_UNDEFINED_REPLACE |
+ RTL_UNICODETOTEXT_FLAGS_PRIVATE_MAPTO0 )
+ )
+ {
+ SharedResources aResources;
+ OUString sMessage = aResources.getResourceStringWithSubstitution( STR_CANNOT_CONVERT_STRING,
+ "$string$", _rSource,
+ "$charset$", lcl_getEncodingName( _eEncoding )
+ );
+
+ throw SQLException(
+ sMessage,
+ nullptr,
+ "22018",
+ 22018,
+ Any()
+ );
+ }
+
+ return _rDest.getLength();
+}
+
+
+sal_Int32 DBTypeConversion::convertUnicodeStringToLength( const OUString& _rSource, OString& _rDest,
+ sal_Int32 _nMaxLen, rtl_TextEncoding _eEncoding )
+{
+ sal_Int32 nLen = convertUnicodeString( _rSource, _rDest, _eEncoding );
+ if ( nLen > _nMaxLen )
+ {
+ SharedResources aResources;
+ OUString sMessage = aResources.getResourceStringWithSubstitution( STR_STRING_LENGTH_EXCEEDED,
+ "$string$", _rSource,
+ "$maxlen$", OUString::number( _nMaxLen ),
+ "$charset$", lcl_getEncodingName( _eEncoding )
+ );
+
+ throw SQLException(
+ sMessage,
+ nullptr,
+ "22001",
+ 22001,
+ Any()
+ );
+ }
+
+ return nLen;
+}
+
+OUString getDefaultReportEngineServiceName(const Reference< XComponentContext >& _rxORB)
+{
+ ::utl::OConfigurationTreeRoot aReportEngines = ::utl::OConfigurationTreeRoot::createWithComponentContext(
+ _rxORB, "org.openoffice.Office.DataAccess/ReportEngines", -1, ::utl::OConfigurationTreeRoot::CM_READONLY);
+
+ if ( aReportEngines.isValid() )
+ {
+ OUString sDefaultReportEngineName;
+ aReportEngines.getNodeValue("DefaultReportEngine") >>= sDefaultReportEngineName;
+ if ( !sDefaultReportEngineName.isEmpty() )
+ {
+ ::utl::OConfigurationNode aReportEngineNames = aReportEngines.openNode("ReportEngineNames");
+ if ( aReportEngineNames.isValid() )
+ {
+ ::utl::OConfigurationNode aReportEngine = aReportEngineNames.openNode(sDefaultReportEngineName);
+ if ( aReportEngine.isValid() )
+ {
+ OUString sRet;
+ aReportEngine.getNodeValue("ServiceName") >>= sRet;
+ return sRet;
+ }
+ }
+ }
+ else
+ return "org.libreoffice.report.pentaho.SOReportJobFactory";
+ }
+ else
+ return "org.libreoffice.report.pentaho.SOReportJobFactory";
+ return OUString();
+}
+
+bool isAggregateColumn(const Reference< XSingleSelectQueryComposer > &_xParser, const Reference< XPropertySet > &_xField)
+{
+ OUString sName;
+ _xField->getPropertyValue("Name") >>= sName;
+ Reference< XColumnsSupplier > xColumnsSupplier(_xParser, UNO_QUERY);
+ Reference< css::container::XNameAccess > xCols;
+ if (xColumnsSupplier.is())
+ xCols = xColumnsSupplier->getColumns();
+
+ return isAggregateColumn(xCols, sName);
+}
+
+bool isAggregateColumn(const Reference< XNameAccess > &_xColumns, const OUString &_sName)
+{
+ if ( _xColumns.is() && _xColumns->hasByName(_sName) )
+ {
+ Reference<XPropertySet> xProp(_xColumns->getByName(_sName),UNO_QUERY);
+ assert(xProp.is());
+ return isAggregateColumn( xProp );
+ }
+ return false;
+}
+
+bool isAggregateColumn( const Reference< XPropertySet > &_xColumn )
+{
+ bool bAgg(false);
+
+ static constexpr OUString sAgg = u"AggregateFunction"_ustr;
+ if ( _xColumn->getPropertySetInfo()->hasPropertyByName(sAgg) )
+ _xColumn->getPropertyValue(sAgg) >>= bAgg;
+
+ return bAgg;
+}
+
+
+} // namespace dbtools
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/filtermanager.cxx b/connectivity/source/commontools/filtermanager.cxx
new file mode 100644
index 0000000000..0a6ac9018f
--- /dev/null
+++ b/connectivity/source/commontools/filtermanager.cxx
@@ -0,0 +1,254 @@
+/* -*- 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 <connectivity/filtermanager.hxx>
+
+#include <com/sun/star/sdb/XSQLQueryComposerFactory.hpp>
+#include <TConnection.hxx>
+#include <osl/diagnose.h>
+#include <comphelper/diagnose_ex.hxx>
+#include <rtl/ustrbuf.hxx>
+
+
+namespace dbtools
+{
+
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::com::sun::star::sdb;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::beans;
+ using namespace connectivity;
+
+ FilterManager::FilterManager( )
+ :m_bApplyPublicFilter( true )
+ {
+ }
+
+
+ void FilterManager::initialize( const Reference< XPropertySet >& _rxComponentAggregate )
+ {
+ m_xComponentAggregate = _rxComponentAggregate;
+ OSL_ENSURE( m_xComponentAggregate.is(), "FilterManager::initialize: invalid arguments!" );
+
+ if ( m_xComponentAggregate.is() )
+ m_xComponentAggregate->setPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_APPLYFILTER), Any( true ) );
+ }
+
+
+ void FilterManager::dispose( )
+ {
+ m_xComponentAggregate.clear();
+ }
+
+
+ const OUString& FilterManager::getFilterComponent( FilterComponent _eWhich ) const
+ {
+ switch (_eWhich)
+ {
+ case FilterComponent::PublicFilter:
+ return m_aPublicFilterComponent;
+ case FilterComponent::PublicHaving:
+ return m_aPublicHavingComponent;
+ case FilterComponent::LinkFilter:
+ return m_aLinkFilterComponent;
+ case FilterComponent::LinkHaving:
+ return m_aLinkHavingComponent;
+ }
+ assert(false);
+
+ static constexpr OUString sErr(u"#FilterManager::getFilterComponent unknown component#"_ustr);
+ return sErr;
+ }
+
+
+ void FilterManager::setFilterComponent( FilterComponent _eWhich, const OUString& _rComponent )
+ {
+ switch (_eWhich)
+ {
+ case FilterComponent::PublicFilter:
+ m_aPublicFilterComponent = _rComponent;
+ break;
+ case FilterComponent::PublicHaving:
+ m_aPublicHavingComponent = _rComponent;
+ break;
+ case FilterComponent::LinkFilter:
+ m_aLinkFilterComponent = _rComponent;
+ break;
+ case FilterComponent::LinkHaving:
+ m_aLinkHavingComponent = _rComponent;
+ break;
+ }
+ try
+ {
+ if ( m_xComponentAggregate.is() )
+ {
+ bool propagate(true);
+ switch (_eWhich)
+ {
+ case FilterComponent::PublicFilter:
+ propagate = propagate && m_bApplyPublicFilter;
+ [[fallthrough]];
+ case FilterComponent::LinkFilter:
+ if (propagate)
+ m_xComponentAggregate->setPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FILTER), Any( getComposedFilter() ) );
+ break;
+ case FilterComponent::PublicHaving:
+ propagate = propagate && m_bApplyPublicFilter;
+ [[fallthrough]];
+ case FilterComponent::LinkHaving:
+ if (propagate)
+ m_xComponentAggregate->setPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_HAVINGCLAUSE), Any( getComposedHaving() ) );
+ break;
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+ }
+
+
+ void FilterManager::setApplyPublicFilter( bool _bApply )
+ {
+ if ( m_bApplyPublicFilter == _bApply )
+ return;
+
+ m_bApplyPublicFilter = _bApply;
+
+ try
+ {
+ if ( m_xComponentAggregate.is())
+ {
+ // only where/if something changed
+ if (!getFilterComponent( FilterComponent::PublicFilter ).isEmpty())
+ m_xComponentAggregate->setPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FILTER), Any( getComposedFilter() ) );
+ if (!getFilterComponent( FilterComponent::PublicHaving ).isEmpty())
+ m_xComponentAggregate->setPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_HAVINGCLAUSE), Any( getComposedHaving() ) );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+ }
+
+
+ void FilterManager::appendFilterComponent( OUStringBuffer& io_appendTo, std::u16string_view i_component )
+ {
+ if ( !io_appendTo.isEmpty() )
+ {
+ io_appendTo.insert( 0, '(' );
+ io_appendTo.insert( 1, ' ' );
+ io_appendTo.append( " ) AND " );
+ }
+
+ io_appendTo.append( "( " );
+ io_appendTo.append( i_component );
+ io_appendTo.append( " )" );
+ }
+
+
+ bool FilterManager::isThereAtMostOneFilterComponent( OUString& o_singleComponent ) const
+ {
+ if (m_bApplyPublicFilter) {
+ if (!m_aPublicFilterComponent.isEmpty() && !m_aLinkFilterComponent.isEmpty())
+ return false;
+ if (!m_aPublicFilterComponent.isEmpty())
+ o_singleComponent = m_aPublicFilterComponent;
+ else if (!m_aLinkFilterComponent.isEmpty())
+ o_singleComponent = m_aLinkFilterComponent;
+ else
+ o_singleComponent.clear();
+ return true;
+ }
+ else
+ {
+ if (m_aLinkFilterComponent.isEmpty())
+ o_singleComponent.clear();
+ else
+ o_singleComponent = m_aLinkFilterComponent;
+ return true;
+ }
+ }
+
+ bool FilterManager::isThereAtMostOneHavingComponent( OUString& o_singleComponent ) const
+ {
+ if (m_bApplyPublicFilter) {
+ if (!m_aPublicHavingComponent.isEmpty() && !m_aLinkHavingComponent.isEmpty())
+ return false;
+ if (!m_aPublicHavingComponent.isEmpty())
+ o_singleComponent = m_aPublicHavingComponent;
+ else if (!m_aLinkHavingComponent.isEmpty())
+ o_singleComponent = m_aLinkHavingComponent;
+ else
+ o_singleComponent.clear();
+ return true;
+ }
+ else
+ {
+ if (m_aLinkHavingComponent.isEmpty())
+ o_singleComponent.clear();
+ else
+ o_singleComponent = m_aLinkHavingComponent;
+ return true;
+ }
+ }
+
+
+ OUString FilterManager::getComposedFilter( ) const
+ {
+ // if we have only one non-empty component, then there's no need to compose anything
+ OUString singleComponent;
+ if ( isThereAtMostOneFilterComponent( singleComponent ) )
+ {
+ return singleComponent;
+ }
+ // append the single components
+ OUStringBuffer aComposedFilter(singleComponent);
+ if (m_bApplyPublicFilter)
+ appendFilterComponent( aComposedFilter, m_aPublicFilterComponent );
+ appendFilterComponent( aComposedFilter, m_aLinkFilterComponent );
+ return aComposedFilter.makeStringAndClear();
+ }
+
+
+ OUString FilterManager::getComposedHaving( ) const
+ {
+ // if we have only one non-empty component, then there's no need to compose anything
+ OUString singleComponent;
+ if ( isThereAtMostOneHavingComponent( singleComponent ) )
+ {
+ return singleComponent;
+ }
+ // append the single components
+ OUStringBuffer aComposedFilter(singleComponent);
+ if (m_bApplyPublicFilter)
+ appendFilterComponent( aComposedFilter, m_aPublicHavingComponent );
+ appendFilterComponent( aComposedFilter, m_aLinkHavingComponent );
+ return aComposedFilter.makeStringAndClear();
+ }
+
+
+} // namespace dbtools
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/formattedcolumnvalue.cxx b/connectivity/source/commontools/formattedcolumnvalue.cxx
new file mode 100644
index 0000000000..32db3d7177
--- /dev/null
+++ b/connectivity/source/commontools/formattedcolumnvalue.cxx
@@ -0,0 +1,291 @@
+/* -*- 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 <connectivity/formattedcolumnvalue.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/dbconversion.hxx>
+
+#include <com/sun/star/util/NumberFormatter.hpp>
+#include <com/sun/star/util/Date.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/util/XNumberFormatTypes.hpp>
+#include <com/sun/star/util/NumberFormat.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdb/XColumn.hpp>
+#include <com/sun/star/sdb/XColumnUpdate.hpp>
+
+#include <comphelper/diagnose_ex.hxx>
+#include <i18nlangtag/mslangid.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <comphelper/numbers.hxx>
+
+
+namespace dbtools
+{
+
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::UNO_QUERY;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::uno::UNO_SET_THROW;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::uno::XComponentContext;
+ using ::com::sun::star::sdbc::XRowSet;
+ using ::com::sun::star::beans::XPropertySet;
+ using ::com::sun::star::util::NumberFormatter;
+ using ::com::sun::star::util::XNumberFormatter;
+ using ::com::sun::star::util::Date;
+ using ::com::sun::star::sdbc::XConnection;
+ using ::com::sun::star::util::XNumberFormatsSupplier;
+ using ::com::sun::star::beans::XPropertySetInfo;
+ using ::com::sun::star::lang::Locale;
+ using ::com::sun::star::util::XNumberFormatTypes;
+ using ::com::sun::star::sdb::XColumn;
+ using ::com::sun::star::sdb::XColumnUpdate;
+
+ namespace DataType = ::com::sun::star::sdbc::DataType;
+ namespace NumberFormat = ::com::sun::star::util::NumberFormat;
+
+ struct FormattedColumnValue_Data
+ {
+ Reference< XNumberFormatter > m_xFormatter;
+ Date m_aNullDate;
+ sal_Int32 m_nFormatKey;
+ sal_Int32 m_nFieldType;
+ sal_Int16 m_nKeyType;
+ bool m_bNumericField;
+
+ Reference< XColumn > m_xColumn;
+ Reference< XColumnUpdate > m_xColumnUpdate;
+
+ FormattedColumnValue_Data()
+ :m_aNullDate( DBTypeConversion::getStandardDate() )
+ ,m_nFormatKey( 0 )
+ ,m_nFieldType( DataType::OTHER )
+ ,m_nKeyType( NumberFormat::UNDEFINED )
+ ,m_bNumericField( false )
+ {
+ }
+ };
+
+
+ namespace
+ {
+
+ void lcl_clear_nothrow( FormattedColumnValue_Data& _rData )
+ {
+ _rData.m_xFormatter.clear();
+ _rData.m_nFormatKey = 0;
+ _rData.m_nFieldType = DataType::OTHER;
+ _rData.m_nKeyType = NumberFormat::UNDEFINED;
+ _rData.m_bNumericField = false;
+
+ _rData.m_xColumn.clear();
+ _rData.m_xColumnUpdate.clear();
+ }
+
+
+ void lcl_initColumnDataValue_nothrow( FormattedColumnValue_Data& _rData,
+ const Reference< XNumberFormatter >& i_rNumberFormatter, const Reference< XPropertySet >& _rxColumn )
+ {
+ lcl_clear_nothrow( _rData );
+
+ OSL_PRECOND( i_rNumberFormatter.is(), "lcl_initColumnDataValue_nothrow: no number formats -> no formatted values!" );
+ if ( !i_rNumberFormatter.is() )
+ return;
+
+ try
+ {
+ Reference< XNumberFormatsSupplier > xNumberFormatsSupp( i_rNumberFormatter->getNumberFormatsSupplier(), UNO_SET_THROW );
+
+ // remember the column
+ _rData.m_xColumn.set( _rxColumn, UNO_QUERY_THROW );
+ _rData.m_xColumnUpdate.set( _rxColumn, UNO_QUERY );
+
+ // determine the field type, and whether it's a numeric field
+ OSL_VERIFY( _rxColumn->getPropertyValue("Type") >>= _rData.m_nFieldType );
+
+ switch ( _rData.m_nFieldType )
+ {
+ case DataType::DATE:
+ case DataType::TIME:
+ case DataType::TIME_WITH_TIMEZONE:
+ case DataType::TIMESTAMP:
+ case DataType::TIMESTAMP_WITH_TIMEZONE:
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ case DataType::TINYINT:
+ case DataType::SMALLINT:
+ case DataType::INTEGER:
+ case DataType::REAL:
+ case DataType::BIGINT:
+ case DataType::DOUBLE:
+ case DataType::NUMERIC:
+ case DataType::DECIMAL:
+ _rData.m_bNumericField = true;
+ break;
+ default:
+ _rData.m_bNumericField = false;
+ break;
+ }
+
+ // get the format key of our bound field
+ Reference< XPropertySetInfo > xPSI( _rxColumn->getPropertySetInfo(), UNO_SET_THROW );
+ bool bHaveFieldFormat = false;
+ static constexpr OUString sFormatKeyProperty( u"FormatKey"_ustr );
+ if ( xPSI->hasPropertyByName( sFormatKeyProperty ) )
+ {
+ bHaveFieldFormat = ( _rxColumn->getPropertyValue( sFormatKeyProperty ) >>= _rData.m_nFormatKey );
+ }
+ if ( !bHaveFieldFormat )
+ {
+ // fall back to a format key as indicated by the field type
+ Locale aSystemLocale( LanguageTag( MsLangId::getConfiguredSystemLanguage() ).getLocale() );
+ Reference< XNumberFormatTypes > xNumTypes( xNumberFormatsSupp->getNumberFormats(), UNO_QUERY_THROW );
+ _rData.m_nFormatKey = getDefaultNumberFormat( _rxColumn, xNumTypes, aSystemLocale );
+ }
+
+ // some more formatter settings
+ _rData.m_nKeyType = ::comphelper::getNumberFormatType( xNumberFormatsSupp->getNumberFormats(), _rData.m_nFormatKey );
+ Reference< XPropertySet > xFormatSettings( xNumberFormatsSupp->getNumberFormatSettings(), UNO_SET_THROW );
+ OSL_VERIFY( xFormatSettings->getPropertyValue("NullDate") >>= _rData.m_aNullDate );
+
+ // remember the formatter
+ _rData.m_xFormatter = i_rNumberFormatter;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+ }
+
+
+ void lcl_initColumnDataValue_nothrow( const Reference<XComponentContext>& i_rContext, FormattedColumnValue_Data& i_rData,
+ const Reference< XRowSet >& i_rRowSet, const Reference< XPropertySet >& i_rColumn )
+ {
+ OSL_PRECOND( i_rRowSet.is(), "lcl_initColumnDataValue_nothrow: no row set!" );
+ if ( !i_rRowSet.is() )
+ return;
+
+ Reference< XNumberFormatter > xNumberFormatter;
+ try
+ {
+ // get the number formats supplier of the connection of the form
+ Reference< XConnection > xConnection( getConnection( i_rRowSet ), UNO_SET_THROW );
+ Reference< XNumberFormatsSupplier > xSupplier( getNumberFormats( xConnection, true, i_rContext ), UNO_SET_THROW );
+
+ // create a number formatter for it
+ xNumberFormatter.set( NumberFormatter::create( i_rContext ), UNO_QUERY_THROW );
+ xNumberFormatter->attachNumberFormatsSupplier( xSupplier );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+
+ lcl_initColumnDataValue_nothrow( i_rData, xNumberFormatter, i_rColumn );
+ }
+ }
+
+ FormattedColumnValue::FormattedColumnValue( const Reference< XComponentContext >& _rxContext,
+ const Reference< XRowSet >& _rxRowSet, const Reference< XPropertySet >& i_rColumn )
+ :m_pData( new FormattedColumnValue_Data )
+ {
+ lcl_initColumnDataValue_nothrow( _rxContext, *m_pData, _rxRowSet, i_rColumn );
+ }
+
+
+ FormattedColumnValue::FormattedColumnValue( const Reference< XNumberFormatter >& i_rNumberFormatter,
+ const Reference< XPropertySet >& _rxColumn )
+ :m_pData( new FormattedColumnValue_Data )
+ {
+ lcl_initColumnDataValue_nothrow( *m_pData, i_rNumberFormatter, _rxColumn );
+ }
+
+
+ FormattedColumnValue::~FormattedColumnValue()
+ {
+ lcl_clear_nothrow( *m_pData );
+ }
+
+ sal_Int16 FormattedColumnValue::getKeyType() const
+ {
+ return m_pData->m_nKeyType;
+ }
+
+
+ const Reference< XColumn >& FormattedColumnValue::getColumn() const
+ {
+ return m_pData->m_xColumn;
+ }
+
+ bool FormattedColumnValue::setFormattedValue( const OUString& _rFormattedStringValue ) const
+ {
+ OSL_PRECOND( m_pData->m_xColumnUpdate.is(), "FormattedColumnValue::setFormattedValue: no column!" );
+ if ( !m_pData->m_xColumnUpdate.is() )
+ return false;
+
+ try
+ {
+ if ( m_pData->m_bNumericField )
+ {
+ ::dbtools::DBTypeConversion::setValue( m_pData->m_xColumnUpdate, m_pData->m_xFormatter, m_pData->m_aNullDate,
+ _rFormattedStringValue, m_pData->m_nFormatKey, ::sal::static_int_cast< sal_Int16 >( m_pData->m_nFieldType ),
+ m_pData->m_nKeyType );
+ }
+ else
+ {
+ m_pData->m_xColumnUpdate->updateString( _rFormattedStringValue );
+ }
+ }
+ catch( const Exception& )
+ {
+ return false;
+ }
+ return true;
+ }
+
+
+ OUString FormattedColumnValue::getFormattedValue() const
+ {
+ OSL_PRECOND( m_pData->m_xColumn.is(), "FormattedColumnValue::setFormattedValue: no column!" );
+
+ OUString sStringValue;
+ if ( m_pData->m_xColumn.is() )
+ {
+ if ( m_pData->m_bNumericField )
+ {
+ sStringValue = DBTypeConversion::getFormattedValue(
+ m_pData->m_xColumn, m_pData->m_xFormatter, m_pData->m_aNullDate, m_pData->m_nFormatKey, m_pData->m_nKeyType
+ );
+ }
+ else
+ {
+ sStringValue = m_pData->m_xColumn->getString();
+ }
+ }
+ return sStringValue;
+ }
+
+
+} // namespace dbtools
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/parameters.cxx b/connectivity/source/commontools/parameters.cxx
new file mode 100644
index 0000000000..990085c87f
--- /dev/null
+++ b/connectivity/source/commontools/parameters.cxx
@@ -0,0 +1,1212 @@
+/* -*- 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 <connectivity/parameters.hxx>
+
+#include <com/sun/star/form/DatabaseParameterEvent.hpp>
+#include <com/sun/star/form/XDatabaseParameterListener.hpp>
+#include <com/sun/star/sdbc/XParameters.hpp>
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdb/XParametersSupplier.hpp>
+#include <com/sun/star/sdb/ParametersRequest.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/task/XInteractionHandler.hpp>
+
+#include <connectivity/dbtools.hxx>
+#include <connectivity/filtermanager.hxx>
+#include <TConnection.hxx>
+
+#include <comphelper/diagnose_ex.hxx>
+
+#include <ParameterCont.hxx>
+#include <o3tl/safeint.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+
+namespace dbtools
+{
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::sdb;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::com::sun::star::sdbcx;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::task;
+ using namespace ::com::sun::star::form;
+ using namespace ::com::sun::star::container;
+
+ using namespace ::comphelper;
+ using namespace ::connectivity;
+
+ ParameterManager::ParameterManager( ::osl::Mutex& _rMutex, const Reference< XComponentContext >& _rxContext )
+ :m_rMutex ( _rMutex )
+ ,m_aParameterListeners( _rMutex )
+ ,m_xContext ( _rxContext )
+ ,m_nInnerCount ( 0 )
+ ,m_bUpToDate ( false )
+ {
+ OSL_ENSURE( m_xContext.is(), "ParameterManager::ParameterManager: no service factory!" );
+ }
+
+
+ void ParameterManager::initialize( const Reference< XPropertySet >& _rxComponent, const Reference< XAggregation >& _rxComponentAggregate )
+ {
+ OSL_ENSURE( !m_xComponent.get().is(), "ParameterManager::initialize: already initialized!" );
+
+ m_xComponent = _rxComponent;
+ m_xAggregatedRowSet = _rxComponentAggregate;
+ if ( m_xAggregatedRowSet.is() )
+ m_xAggregatedRowSet->queryAggregation( cppu::UnoType<decltype(m_xInnerParamUpdate)>::get() ) >>= m_xInnerParamUpdate;
+ OSL_ENSURE( m_xComponent.get().is() && m_xInnerParamUpdate.is(), "ParameterManager::initialize: invalid arguments!" );
+ if ( !m_xComponent.get().is() || !m_xInnerParamUpdate.is() )
+ return;
+ }
+
+
+ void ParameterManager::dispose( )
+ {
+ clearAllParameterInformation();
+
+ m_xComposer.clear();
+ m_xParentComposer.clear();
+ //m_xComponent.clear();
+ m_xInnerParamUpdate.clear();
+ m_xAggregatedRowSet.clear();
+ }
+
+
+ void ParameterManager::clearAllParameterInformation()
+ {
+ m_xInnerParamColumns.clear();
+ if ( m_pOuterParameters.is() )
+ m_pOuterParameters->dispose();
+ m_pOuterParameters = nullptr;
+ m_nInnerCount = 0;
+ ParameterInformation().swap(m_aParameterInformation);
+ m_aMasterFields.clear();
+ m_aDetailFields.clear();
+ m_sIdentifierQuoteString.clear();
+ m_sSpecialCharacters.clear();
+ m_xConnectionMetadata.clear();
+ std::vector< bool >().swap(m_aParametersVisited);
+ m_bUpToDate = false;
+ }
+
+
+ void ParameterManager::setAllParametersNull()
+ {
+ OSL_PRECOND( isAlive(), "ParameterManager::setAllParametersNull: not initialized, or already disposed!" );
+ if ( !isAlive() )
+ return;
+
+ for ( sal_Int32 i = 1; i <= m_nInnerCount; ++i )
+ m_xInnerParamUpdate->setNull( i, DataType::VARCHAR );
+ }
+
+
+ bool ParameterManager::initializeComposerByComponent( const Reference< XPropertySet >& _rxComponent )
+ {
+ OSL_PRECOND( _rxComponent.is(), "ParameterManager::initializeComposerByComponent: invalid !" );
+
+ m_xComposer.clear();
+ m_xInnerParamColumns.clear();
+ m_nInnerCount = 0;
+
+ // create and fill a composer
+ try
+ {
+ // get a query composer for the 's settings
+ m_xComposer.reset( getCurrentSettingsComposer( _rxComponent, m_xContext, nullptr ), SharedQueryComposer::TakeOwnership );
+
+ // see if the composer found parameters
+ Reference< XParametersSupplier > xParamSupp( m_xComposer, UNO_QUERY );
+ if ( xParamSupp.is() )
+ m_xInnerParamColumns = xParamSupp->getParameters();
+
+ if ( m_xInnerParamColumns.is() )
+ m_nInnerCount = m_xInnerParamColumns->getCount();
+ }
+ catch( const SQLException& )
+ {
+ }
+
+ return m_xInnerParamColumns.is();
+ }
+
+
+ void ParameterManager::collectInnerParameters( bool _bSecondRun )
+ {
+ OSL_PRECOND( m_xInnerParamColumns.is(), "ParameterManager::collectInnerParameters: missing some internal data!" );
+ if ( !m_xInnerParamColumns.is() )
+ return;
+
+ // strip previous index information
+ if ( _bSecondRun )
+ {
+ for (auto & paramInfo : m_aParameterInformation)
+ {
+ paramInfo.second.aInnerIndexes.clear();
+ }
+ }
+
+ // we need to map the parameter names (which is all we get from the 's
+ // MasterFields property) to indices, which are needed by the XParameters
+ // interface of the row set)
+ Reference<XPropertySet> xParam;
+ for ( sal_Int32 i = 0; i < m_nInnerCount; ++i )
+ {
+ try
+ {
+ xParam.clear();
+ m_xInnerParamColumns->getByIndex( i ) >>= xParam;
+
+ OUString sName;
+ xParam->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME) ) >>= sName;
+
+ // only append additional parameters when they are not already in the list
+ ParameterInformation::iterator aExistentPos = m_aParameterInformation.find( sName );
+ OSL_ENSURE( !_bSecondRun || ( aExistentPos != m_aParameterInformation.end() ),
+ "ParameterManager::collectInnerParameters: the parameter information should already exist in the second run!" );
+
+ if ( aExistentPos == m_aParameterInformation.end() )
+ {
+ aExistentPos = m_aParameterInformation.emplace(
+ sName, xParam ).first;
+ }
+ else
+ aExistentPos->second.xComposerColumn = xParam;
+
+ aExistentPos->second.aInnerIndexes.push_back( i );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "ParameterManager::collectInnerParameters" );
+ }
+ }
+ }
+
+
+ OUString ParameterManager::createFilterConditionFromColumnLink(
+ const OUString &_rMasterColumn, const Reference < XPropertySet > &xDetailField, OUString &o_rNewParamName )
+ {
+ OUString sFilter;
+ // format is:
+ // <detail_column> = :<new_param_name>
+ {
+ OUString tblName;
+ xDetailField->getPropertyValue("TableName") >>= tblName;
+ if (!tblName.isEmpty())
+ sFilter = ::dbtools::quoteTableName( m_xConnectionMetadata, tblName, ::dbtools::EComposeRule::InDataManipulation ) + ".";
+ }
+ {
+ OUString colName;
+ xDetailField->getPropertyValue("RealName") >>= colName;
+ bool isFunction(false);
+ xDetailField->getPropertyValue("Function") >>= isFunction;
+ if (isFunction)
+ sFilter += colName;
+ else
+ sFilter += quoteName( m_sIdentifierQuoteString, colName );
+ }
+
+ // generate a parameter name which is not already used
+ o_rNewParamName = "link_from_";
+ o_rNewParamName += convertName2SQLName( _rMasterColumn, m_sSpecialCharacters );
+ while ( m_aParameterInformation.find( o_rNewParamName ) != m_aParameterInformation.end() )
+ {
+ o_rNewParamName += "_";
+ }
+
+ return sFilter + " =:" + o_rNewParamName;
+ }
+
+
+ void ParameterManager::classifyLinks( const Reference< XNameAccess >& _rxParentColumns,
+ const Reference< XNameAccess >& _rxColumns,
+ std::vector< OUString >& _out_rAdditionalFilterComponents,
+ std::vector< OUString >& _out_rAdditionalHavingComponents )
+ {
+ OSL_PRECOND( m_aMasterFields.size() == m_aDetailFields.size(),
+ "ParameterManager::classifyLinks: master and detail fields should have the same length!" );
+ OSL_ENSURE( _rxColumns.is(), "ParameterManager::classifyLinks: invalid columns!" );
+
+ if ( !_rxColumns.is() )
+ return;
+
+ // we may need to strip any links which are invalid, so here go the containers
+ // for temporarily holding the new pairs
+ std::vector< OUString > aStrippedMasterFields;
+ std::vector< OUString > aStrippedDetailFields;
+
+ bool bNeedExchangeLinks = false;
+
+ // classify the links
+ auto pMasterFields = m_aMasterFields.begin();
+ auto pDetailFields = m_aDetailFields.begin();
+ auto pDetailFieldsEnd = m_aDetailFields.end();
+ for ( ; pDetailFields != pDetailFieldsEnd; ++pDetailFields, ++pMasterFields )
+ {
+ if ( pMasterFields->isEmpty() || pDetailFields->isEmpty() )
+ continue;
+
+ // if not even the master part of the relationship exists in the parent, the
+ // link is invalid as a whole #i63674#
+ if ( !_rxParentColumns->hasByName( *pMasterFields ) )
+ {
+ bNeedExchangeLinks = true;
+ continue;
+ }
+
+ bool bValidLink = true;
+
+ // is there an inner parameter with this name? That is, a parameter which is already part of
+ // the very original statement (not the one we create ourselves, with the additional parameters)
+ ParameterInformation::iterator aPos = m_aParameterInformation.find( *pDetailFields );
+ if ( aPos != m_aParameterInformation.end() )
+ { // there is an inner parameter with this name
+ aPos->second.eType = ParameterClassification::LinkedByParamName;
+ aStrippedDetailFields.push_back( *pDetailFields );
+ }
+ else
+ {
+ // does the detail name denote a column?
+ if ( _rxColumns->hasByName( *pDetailFields ) )
+ {
+ Reference< XPropertySet > xDetailField(_rxColumns->getByName( *pDetailFields ), UNO_QUERY);
+ assert(xDetailField.is());
+
+ OUString sNewParamName;
+ const OUString sFilterCondition = createFilterConditionFromColumnLink( *pMasterFields, xDetailField, sNewParamName );
+ OSL_PRECOND( !sNewParamName.isEmpty(), "ParameterManager::classifyLinks: createFilterConditionFromColumnLink returned nonsense!" );
+
+ // remember meta information about this new parameter
+ std::pair< ParameterInformation::iterator, bool > aInsertionPos =
+ m_aParameterInformation.emplace(
+ sNewParamName, ParameterMetaData( nullptr )
+ );
+ OSL_ENSURE( aInsertionPos.second, "ParameterManager::classifyLinks: there already was a parameter with this name!" );
+ aInsertionPos.first->second.eType = ParameterClassification::LinkedByColumnName;
+
+ // remember the filter component
+ if (isAggregateColumn(xDetailField))
+ _out_rAdditionalHavingComponents.push_back( sFilterCondition );
+ else
+ _out_rAdditionalFilterComponents.push_back( sFilterCondition );
+
+ // remember the new "detail field" for this link
+ aStrippedDetailFields.push_back( sNewParamName );
+ bNeedExchangeLinks = true;
+ }
+ else
+ {
+ // the detail field neither denotes a column name, nor a parameter name
+ bValidLink = false;
+ bNeedExchangeLinks = true;
+ }
+ }
+
+ if ( bValidLink )
+ aStrippedMasterFields.push_back( *pMasterFields );
+ }
+ SAL_WARN_IF( aStrippedMasterFields.size() != aStrippedDetailFields.size(),
+ "connectivity.commontools",
+ "ParameterManager::classifyLinks: inconsistency in new link pairs!" );
+
+ if ( bNeedExchangeLinks )
+ {
+ m_aMasterFields.swap(aStrippedMasterFields);
+ m_aDetailFields.swap(aStrippedDetailFields);
+ }
+ }
+
+
+ void ParameterManager::analyzeFieldLinks( FilterManager& _rFilterManager, bool& /* [out] */ _rColumnsInLinkDetails )
+ {
+ OSL_PRECOND( isAlive(), "ParameterManager::analyzeFieldLinks: not initialized, or already disposed!" );
+ if ( !isAlive() )
+ return;
+
+ _rColumnsInLinkDetails = false;
+ try
+ {
+ // the links as determined by the properties
+ Reference< XPropertySet > xProp = m_xComponent;
+ OSL_ENSURE(xProp.is(),"Someone already released my component!");
+ if ( xProp.is() )
+ {
+ Sequence<OUString> aTmp;
+ if (xProp->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MASTERFIELDS) ) >>= aTmp)
+ comphelper::sequenceToContainer(m_aMasterFields, aTmp);
+ if (xProp->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DETAILFIELDS) ) >>= aTmp)
+ comphelper::sequenceToContainer(m_aDetailFields, aTmp);
+ }
+
+ {
+ // normalize to equal length
+ sal_Int32 nMasterLength = m_aMasterFields.size();
+ sal_Int32 nDetailLength = m_aDetailFields.size();
+
+ if ( nMasterLength > nDetailLength )
+ m_aMasterFields.resize( nDetailLength );
+ else if ( nDetailLength > nMasterLength )
+ m_aDetailFields.resize( nMasterLength );
+ }
+
+ Reference< XNameAccess > xColumns;
+ if ( !getColumns( xColumns, true ) )
+ // already asserted in getColumns
+ return;
+
+ Reference< XNameAccess > xParentColumns;
+ if ( !getParentColumns( xParentColumns, true ) )
+ return;
+
+ // classify the links - depending on what the detail fields in each link pair denotes
+ std::vector< OUString > aAdditionalFilterComponents;
+ std::vector< OUString > aAdditionalHavingComponents;
+ classifyLinks( xParentColumns, xColumns, aAdditionalFilterComponents, aAdditionalHavingComponents );
+
+ // did we find links where the detail field refers to a detail column (instead of a parameter name)?
+ if ( !aAdditionalFilterComponents.empty() )
+ {
+ // build a conjunction of all the filter components
+ OUStringBuffer sAdditionalFilter;
+ for (auto const& elem : aAdditionalFilterComponents)
+ {
+ if ( !sAdditionalFilter.isEmpty() )
+ sAdditionalFilter.append(" AND ");
+
+ sAdditionalFilter.append("( " + elem + " )");
+ }
+
+ // now set this filter at the filter manager
+ _rFilterManager.setFilterComponent( FilterManager::FilterComponent::LinkFilter, sAdditionalFilter.makeStringAndClear() );
+
+ _rColumnsInLinkDetails = true;
+ }
+
+ if ( !aAdditionalHavingComponents.empty() )
+ {
+ // build a conjunction of all the filter components
+ OUStringBuffer sAdditionalHaving;
+ for (auto const& elem : aAdditionalHavingComponents)
+ {
+ if ( !sAdditionalHaving.isEmpty() )
+ sAdditionalHaving.append(" AND ");
+
+ sAdditionalHaving.append("( " + elem + " )");
+ }
+
+ // now set this having clause at the filter manager
+ _rFilterManager.setFilterComponent( FilterManager::FilterComponent::LinkHaving, sAdditionalHaving.makeStringAndClear() );
+
+ _rColumnsInLinkDetails = true;
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "ParameterManager::analyzeFieldLinks" );
+ }
+ }
+
+
+ void ParameterManager::createOuterParameters()
+ {
+ OSL_PRECOND( !m_pOuterParameters.is(), "ParameterManager::createOuterParameters: outer parameters not initialized!" );
+ OSL_PRECOND( m_xInnerParamUpdate.is(), "ParameterManager::createOuterParameters: no write access to the inner parameters!" );
+ if ( !m_xInnerParamUpdate.is() )
+ return;
+
+ m_pOuterParameters = new param::ParameterWrapperContainer;
+
+#if OSL_DEBUG_LEVEL > 0
+ sal_Int32 nSmallestIndexLinkedByColumnName = -1;
+ sal_Int32 nLargestIndexNotLinkedByColumnName = -1;
+#endif
+ for (auto & aParam : m_aParameterInformation)
+ {
+#if OSL_DEBUG_LEVEL > 0
+ if ( aParam.second.aInnerIndexes.size() )
+ {
+ if ( aParam.second.eType == ParameterClassification::LinkedByColumnName )
+ {
+ if ( nSmallestIndexLinkedByColumnName == -1 )
+ nSmallestIndexLinkedByColumnName = aParam.second.aInnerIndexes[ 0 ];
+ }
+ else
+ {
+ nLargestIndexNotLinkedByColumnName = aParam.second.aInnerIndexes[ aParam.second.aInnerIndexes.size() - 1 ];
+ }
+ }
+#endif
+ if ( aParam.second.eType != ParameterClassification::FilledExternally )
+ continue;
+
+ // check which of the parameters have already been visited (e.g. filled via XParameters)
+ size_t nAlreadyVisited = 0;
+ for (auto & aIndex : aParam.second.aInnerIndexes)
+ {
+ if ( ( m_aParametersVisited.size() > o3tl::make_unsigned(aIndex) ) && m_aParametersVisited[ aIndex ] )
+ { // exclude this index
+ aIndex = -1;
+ ++nAlreadyVisited;
+ }
+ }
+ if ( nAlreadyVisited == aParam.second.aInnerIndexes.size() )
+ continue;
+
+ // need a wrapper for this... the "inner parameters" as supplied by a result set don't have a "Value"
+ // property, but the parameter listeners expect such a property. So we need an object "aggregating"
+ // xParam and supplying an additional property ("Value")
+ // (it's no real aggregation of course...)
+ m_pOuterParameters->push_back( new param::ParameterWrapper( aParam.second.xComposerColumn, m_xInnerParamUpdate, std::vector(aParam.second.aInnerIndexes) ) );
+ }
+
+#if OSL_DEBUG_LEVEL > 0
+ OSL_ENSURE( ( nSmallestIndexLinkedByColumnName == -1 ) || ( nLargestIndexNotLinkedByColumnName == -1 ) ||
+ ( nSmallestIndexLinkedByColumnName > nLargestIndexNotLinkedByColumnName ),
+ "ParameterManager::createOuterParameters: inconsistency!" );
+
+ // for the master-detail links, where the detail field denoted a column name, we created an additional ("artificial")
+ // filter, and *appended* it to all other (potentially) existing filters of the row set. This means that the indexes
+ // for the parameters resulting from the artificial filter should be larger than any other parameter index, and this
+ // is what the assertion checks.
+ // If the assertion fails, then we would need another handling for the "parameters visited" flags, since they're based
+ // on parameter indexes *without* the artificial filter (because this filter is not visible from the outside).
+#endif
+ }
+
+
+ void ParameterManager::updateParameterInfo( FilterManager& _rFilterManager )
+ {
+ OSL_PRECOND( isAlive(), "ParameterManager::updateParameterInfo: not initialized, or already disposed!" );
+ if ( !isAlive() )
+ return;
+
+ clearAllParameterInformation();
+ cacheConnectionInfo();
+
+ // check whether the is based on a statement/query which requires parameters
+ Reference< XPropertySet > xProp = m_xComponent;
+ OSL_ENSURE(xProp.is(),"Some already released my component!");
+ if ( xProp.is() )
+ {
+ if ( !initializeComposerByComponent( xProp ) )
+ { // okay, nothing to do
+ m_bUpToDate = true;
+ return;
+ } // if ( !initializeComposerByComponent( m_xComponent ) )
+ }
+ SAL_WARN_IF( !m_xInnerParamColumns.is(),
+ "connectivity.commontools",
+ "ParameterManager::updateParameterInfo: initializeComposerByComponent did nonsense (1)!" );
+
+ // collect all parameters which are defined by the "inner parameters"
+ collectInnerParameters( false );
+
+ // analyze the master-detail relationships
+ bool bColumnsInLinkDetails = false;
+ analyzeFieldLinks( _rFilterManager, bColumnsInLinkDetails );
+
+ if ( bColumnsInLinkDetails )
+ {
+ // okay, in this case, analyzeFieldLinks modified the "real" filter at the RowSet, to contain
+ // an additional restriction (which we created ourself)
+ // So we need to update all information about our inner parameter columns
+ Reference< XPropertySet > xDirectRowSetProps;
+ m_xAggregatedRowSet->queryAggregation( cppu::UnoType<decltype(xDirectRowSetProps)>::get() ) >>= xDirectRowSetProps;
+ OSL_VERIFY( initializeComposerByComponent( xDirectRowSetProps ) );
+ collectInnerParameters( true );
+ }
+
+ if ( !m_nInnerCount )
+ { // no parameters at all
+ m_bUpToDate = true;
+ return;
+ }
+
+ // for what now remains as outer parameters, create the wrappers for the single
+ // parameter columns
+ createOuterParameters();
+
+ m_bUpToDate = true;
+ }
+
+
+ void ParameterManager::fillLinkedParameters( const Reference< XNameAccess >& _rxParentColumns )
+ {
+ OSL_PRECOND( isAlive(), "ParameterManager::fillLinkedParameters: not initialized, or already disposed!" );
+ if ( !isAlive() )
+ return;
+ OSL_PRECOND( m_xInnerParamColumns.is(), "ParameterManager::fillLinkedParameters: no inner parameters found!" );
+ OSL_ENSURE ( _rxParentColumns.is(), "ParameterManager::fillLinkedParameters: invalid parent columns!" );
+
+ try
+ {
+ // the master and detail field( name)s of the
+ auto pMasterFields = m_aMasterFields.begin();
+ auto pDetailFields = m_aDetailFields.begin();
+
+ sal_Int32 nMasterLen = m_aMasterFields.size();
+
+ // loop through all master fields. For each of them, get the respective column from the
+ // parent , and forward its current value as parameter value to the (inner) row set
+ for ( sal_Int32 i = 0; i < nMasterLen; ++i, ++pMasterFields, ++pDetailFields )
+ {
+ // does the name denote a valid column in the parent?
+ if ( !_rxParentColumns->hasByName( *pMasterFields ) )
+ {
+ SAL_WARN( "connectivity.commontools", "ParameterManager::fillLinkedParameters: invalid master names should have been stripped long before!" );
+ continue;
+ }
+
+ // do we, for this name, know where to place the values?
+ ParameterInformation::const_iterator aParamInfo = m_aParameterInformation.find( *pDetailFields );
+ if ( ( aParamInfo == m_aParameterInformation.end() )
+ || ( aParamInfo->second.aInnerIndexes.empty() )
+ )
+ {
+ SAL_WARN( "connectivity.commontools", "ParameterManager::fillLinkedParameters: nothing known about this detail field!" );
+ continue;
+ }
+
+ // the concrete master field
+ Reference< XPropertySet > xMasterField(_rxParentColumns->getByName( *pMasterFields ),UNO_QUERY);
+
+ // the positions where we have to fill in values for the current parameter name
+ for (auto const& aPosition : aParamInfo->second.aInnerIndexes)
+ {
+ // the concrete detail field
+ Reference< XPropertySet > xDetailField(m_xInnerParamColumns->getByIndex(aPosition),UNO_QUERY);
+ OSL_ENSURE( xDetailField.is(), "ParameterManager::fillLinkedParameters: invalid detail field!" );
+ if ( !xDetailField.is() )
+ continue;
+
+ // type and scale of the parameter field
+ sal_Int32 nParamType = DataType::VARCHAR;
+ OSL_VERIFY( xDetailField->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE) ) >>= nParamType );
+
+ sal_Int32 nScale = 0;
+ if ( xDetailField->getPropertySetInfo()->hasPropertyByName( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE) ) )
+ OSL_VERIFY( xDetailField->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE) ) >>= nScale );
+
+ // transfer the param value
+ try
+ {
+ m_xInnerParamUpdate->setObjectWithInfo(
+ aPosition + 1, // parameters are based at 1
+ xMasterField->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_VALUE) ),
+ nParamType,
+ nScale
+ );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ SAL_WARN( "connectivity.commontools", "ParameterManager::fillLinkedParameters: master-detail parameter number " <<
+ sal_Int32( aPosition + 1 ) << " could not be filled!" );
+ }
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+ }
+
+
+ bool ParameterManager::completeParameters( const Reference< XInteractionHandler >& _rxCompletionHandler, const Reference< XConnection >& _rxConnection )
+ {
+ OSL_PRECOND( isAlive(), "ParameterManager::completeParameters: not initialized, or already disposed!" );
+ OSL_ENSURE ( _rxCompletionHandler.is(), "ParameterManager::completeParameters: invalid interaction handler!" );
+
+ // two continuations (Ok and Cancel)
+ rtl::Reference<OInteractionAbort> pAbort = new OInteractionAbort;
+ rtl::Reference<OParameterContinuation> pParams = new OParameterContinuation;
+
+ // the request
+ ParametersRequest aRequest;
+ aRequest.Parameters = m_pOuterParameters.get();
+ aRequest.Connection = _rxConnection;
+ rtl::Reference<OInteractionRequest> pRequest = new OInteractionRequest( Any( aRequest ) );
+
+ // some knittings
+ pRequest->addContinuation( pAbort );
+ pRequest->addContinuation( pParams );
+
+ // execute the request
+ try
+ {
+ _rxCompletionHandler->handle( pRequest );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "ParameterManager::completeParameters: caught an exception while calling the handler" );
+ }
+
+ if ( !pParams->wasSelected() )
+ // canceled by the user (i.e. (s)he canceled the dialog)
+ return false;
+
+ try
+ {
+ // transfer the values from the continuation object to the parameter columns
+ const Sequence< PropertyValue >& aFinalValues = pParams->getValues();
+ const PropertyValue* pFinalValues = aFinalValues.getConstArray();
+ for ( sal_Int32 i = 0; i < aFinalValues.getLength(); ++i, ++pFinalValues )
+ {
+ Reference< XPropertySet > xParamColumn(aRequest.Parameters->getByIndex( i ),UNO_QUERY);
+ if ( xParamColumn.is() )
+ {
+ #ifdef DBG_UTIL
+ OUString sName;
+ xParamColumn->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME) ) >>= sName;
+ OSL_ENSURE( sName == pFinalValues->Name, "ParameterManager::completeParameters: inconsistent parameter names!" );
+ #endif
+ xParamColumn->setPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_VALUE), pFinalValues->Value );
+ // the property sets are wrapper classes, translating the Value property into a call to
+ // the appropriate XParameters interface
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "ParameterManager::completeParameters: caught an exception while propagating the values" );
+ }
+ return true;
+ }
+
+
+ bool ParameterManager::consultParameterListeners( ::osl::ResettableMutexGuard& _rClearForNotifies )
+ {
+ bool bCanceled = false;
+
+ sal_Int32 nParamsLeft = m_pOuterParameters->getParameters().size();
+ // TODO: shouldn't we subtract all the parameters which were already visited?
+ if ( nParamsLeft )
+ {
+ ::comphelper::OInterfaceIteratorHelper3 aIter( m_aParameterListeners );
+ Reference< XPropertySet > xProp = m_xComponent;
+ OSL_ENSURE(xProp.is(),"Some already released my component!");
+ DatabaseParameterEvent aEvent( xProp, m_pOuterParameters );
+
+ _rClearForNotifies.clear();
+ while ( aIter.hasMoreElements() && !bCanceled )
+ bCanceled = !aIter.next()->approveParameter( aEvent );
+ _rClearForNotifies.reset();
+ }
+
+ return !bCanceled;
+ }
+
+
+ bool ParameterManager::fillParameterValues( const Reference< XInteractionHandler >& _rxCompletionHandler, ::osl::ResettableMutexGuard& _rClearForNotifies )
+ {
+ OSL_PRECOND( isAlive(), "ParameterManager::fillParameterValues: not initialized, or already disposed!" );
+ if ( !isAlive() )
+ return true;
+
+ if ( m_nInnerCount == 0 )
+ // no parameters at all
+ return true;
+
+ // fill the parameters from the master-detail relationship
+ Reference< XNameAccess > xParentColumns;
+ if ( getParentColumns( xParentColumns, false ) && xParentColumns->hasElements() && !m_aMasterFields.empty() )
+ fillLinkedParameters( xParentColumns );
+
+ // let the user (via the interaction handler) fill all remaining parameters
+ Reference< XConnection > xConnection;
+ getConnection( xConnection );
+
+ if ( _rxCompletionHandler.is() )
+ return completeParameters( _rxCompletionHandler, xConnection );
+
+ return consultParameterListeners( _rClearForNotifies );
+ }
+
+
+ void ParameterManager::getConnection( Reference< XConnection >& /* [out] */ _rxConnection )
+ {
+ OSL_PRECOND( isAlive(), "ParameterManager::getConnection: not initialized, or already disposed!" );
+ if ( !isAlive() )
+ return;
+
+ _rxConnection.clear();
+ try
+ {
+ Reference< XPropertySet > xProp = m_xComponent;
+ OSL_ENSURE(xProp.is(),"Some already released my component!");
+ if ( xProp.is() )
+ xProp->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ACTIVE_CONNECTION) ) >>= _rxConnection;
+ }
+ catch( const Exception& )
+ {
+ SAL_WARN( "connectivity.commontools", "ParameterManager::getConnection: could not retrieve the connection of the !" );
+ }
+ }
+
+
+ void ParameterManager::cacheConnectionInfo()
+ {
+ try
+ {
+ Reference< XConnection > xConnection;
+ getConnection( xConnection );
+ Reference< XDatabaseMetaData > xMeta;
+ if ( xConnection.is() )
+ xMeta = xConnection->getMetaData();
+ if ( xMeta.is() )
+ {
+ m_xConnectionMetadata = xMeta;
+ m_sIdentifierQuoteString = xMeta->getIdentifierQuoteString();
+ m_sSpecialCharacters = xMeta->getExtraNameCharacters();
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "ParameterManager::cacheConnectionInfo: caught an exception" );
+ }
+ }
+
+
+ bool ParameterManager::getColumns( Reference< XNameAccess >& /* [out] */ _rxColumns, bool _bFromComposer )
+ {
+ _rxColumns.clear();
+
+ Reference< XColumnsSupplier > xColumnSupp;
+ if ( _bFromComposer )
+ xColumnSupp.set(m_xComposer, css::uno::UNO_QUERY);
+ else
+ xColumnSupp.set( m_xComponent.get(),UNO_QUERY);
+ if ( xColumnSupp.is() )
+ _rxColumns = xColumnSupp->getColumns();
+ OSL_ENSURE( _rxColumns.is(), "ParameterManager::getColumns: could not retrieve the columns for the detail !" );
+
+ return _rxColumns.is();
+ }
+
+
+ bool ParameterManager::getParentColumns( Reference< XNameAccess >& /* [out] */ _out_rxParentColumns, bool _bFromComposer )
+ {
+ OSL_PRECOND( isAlive(), "ParameterManager::getParentColumns: not initialized, or already disposed!" );
+
+ _out_rxParentColumns.clear();
+ try
+ {
+ // get the parent of the component we're working for
+ Reference< XChild > xAsChild( m_xComponent.get(), UNO_QUERY_THROW );
+ Reference< XPropertySet > xParent( xAsChild->getParent(), UNO_QUERY );
+ if ( !xParent.is() )
+ return false;
+
+ // the columns supplier: either from a composer, or directly from the
+ Reference< XColumnsSupplier > xParentColSupp;
+ if ( _bFromComposer )
+ {
+ // re-create the parent composer all the time. Else, we'd have to bother with
+ // being a listener at its properties, its loaded state, and event the parent-relationship.
+ m_xParentComposer.reset(
+ getCurrentSettingsComposer( xParent, m_xContext, nullptr ),
+ SharedQueryComposer::TakeOwnership
+ );
+ xParentColSupp.set(m_xParentComposer, css::uno::UNO_QUERY);
+ }
+ else
+ xParentColSupp.set(xParent, css::uno::UNO_QUERY);
+
+ // get the columns of the parent
+ if ( xParentColSupp.is() )
+ _out_rxParentColumns = xParentColSupp->getColumns();
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "ParameterManager::getParentColumns" );
+ }
+ return _out_rxParentColumns.is();
+ }
+
+
+ void ParameterManager::addParameterListener( const Reference< XDatabaseParameterListener >& _rxListener )
+ {
+ if ( _rxListener.is() )
+ m_aParameterListeners.addInterface( _rxListener );
+ }
+
+
+ void ParameterManager::removeParameterListener( const Reference< XDatabaseParameterListener >& _rxListener )
+ {
+ m_aParameterListeners.removeInterface( _rxListener );
+ }
+
+
+ void ParameterManager::resetParameterValues( )
+ {
+ OSL_PRECOND( isAlive(), "ParameterManager::resetParameterValues: not initialized, or already disposed!" );
+ if ( !isAlive() )
+ return;
+
+ if ( !m_nInnerCount )
+ // no parameters at all
+ return;
+
+ try
+ {
+ Reference< XNameAccess > xColumns;
+ if ( !getColumns( xColumns, false ) )
+ // already asserted in getColumns
+ return;
+
+ Reference< XNameAccess > xParentColumns;
+ if ( !getParentColumns( xParentColumns, false ) )
+ return;
+
+ // loop through all links pairs
+ auto pMasterFields = m_aMasterFields.begin();
+ auto pDetailFields = m_aDetailFields.begin();
+
+ Reference< XPropertySet > xMasterField;
+ Reference< XPropertySet > xDetailField;
+
+ // now really ....
+ auto pDetailFieldsEnd = m_aDetailFields.end();
+ for ( ; pDetailFields != pDetailFieldsEnd; ++pDetailFields, ++pMasterFields )
+ {
+ if ( !xParentColumns->hasByName( *pMasterFields ) )
+ {
+ // if this name is unknown in the parent columns, then we don't have a source
+ // for copying the value to the detail columns
+ SAL_WARN( "connectivity.commontools", "ParameterManager::resetParameterValues: this should have been stripped long before!" );
+ continue;
+ }
+
+ // for all inner parameters which are bound to the name as specified by the
+ // slave element of the link, propagate the value from the master column to this
+ // parameter column
+ ParameterInformation::const_iterator aParamInfo = m_aParameterInformation.find( *pDetailFields );
+ if ( ( aParamInfo == m_aParameterInformation.end() )
+ || ( aParamInfo->second.aInnerIndexes.empty() )
+ )
+ {
+ SAL_WARN( "connectivity.commontools", "ParameterManager::resetParameterValues: nothing known about this detail field!" );
+ continue;
+ }
+
+ xParentColumns->getByName( *pMasterFields ) >>= xMasterField;
+ if ( !xMasterField.is() )
+ continue;
+
+ for (auto const& aPosition : aParamInfo->second.aInnerIndexes)
+ {
+ Reference< XPropertySet > xInnerParameter;
+ m_xInnerParamColumns->getByIndex(aPosition) >>= xInnerParameter;
+ if ( !xInnerParameter.is() )
+ continue;
+
+ OUString sParamColumnRealName;
+ xInnerParameter->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_REALNAME) ) >>= sParamColumnRealName;
+ if ( xColumns->hasByName( sParamColumnRealName ) )
+ { // our own columns have a column which's name equals the real name of the param column
+ // -> transfer the value property
+ xColumns->getByName( sParamColumnRealName ) >>= xDetailField;
+ if ( xDetailField.is() )
+ xDetailField->setPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_VALUE), xMasterField->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_VALUE) ) );
+ }
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "ParameterManager::resetParameterValues" );
+ }
+
+ }
+
+
+ void ParameterManager::externalParameterVisited( sal_Int32 _nIndex )
+ {
+ if ( m_aParametersVisited.size() < o3tl::make_unsigned(_nIndex) )
+ {
+ m_aParametersVisited.reserve( _nIndex );
+ for ( sal_Int32 i = m_aParametersVisited.size(); i < _nIndex; ++i )
+ m_aParametersVisited.push_back( false );
+ }
+ m_aParametersVisited[ _nIndex - 1 ] = true;
+ }
+
+ void ParameterManager::setNull( sal_Int32 _nIndex, sal_Int32 sqlType )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setNull(_nIndex, sqlType);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setObjectNull( sal_Int32 _nIndex, sal_Int32 sqlType, const OUString& typeName )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setObjectNull(_nIndex, sqlType, typeName);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setBoolean( sal_Int32 _nIndex, bool x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setBoolean(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setByte( sal_Int32 _nIndex, sal_Int8 x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setByte(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setShort( sal_Int32 _nIndex, sal_Int16 x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setShort(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setInt( sal_Int32 _nIndex, sal_Int32 x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setInt(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setLong( sal_Int32 _nIndex, sal_Int64 x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setLong(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setFloat( sal_Int32 _nIndex, float x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setFloat(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setDouble( sal_Int32 _nIndex, double x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setDouble(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setString( sal_Int32 _nIndex, const OUString& x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setString(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setBytes( sal_Int32 _nIndex, const css::uno::Sequence< sal_Int8 >& x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setBytes(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setDate( sal_Int32 _nIndex, const css::util::Date& x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setDate(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setTime( sal_Int32 _nIndex, const css::util::Time& x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setTime(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setTimestamp( sal_Int32 _nIndex, const css::util::DateTime& x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setTimestamp(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setBinaryStream( sal_Int32 _nIndex, const css::uno::Reference< css::io::XInputStream>& x, sal_Int32 length )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setBinaryStream(_nIndex, x, length);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setCharacterStream( sal_Int32 _nIndex, const css::uno::Reference< css::io::XInputStream>& x, sal_Int32 length )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setCharacterStream(_nIndex, x, length);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setObject( sal_Int32 _nIndex, const css::uno::Any& x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setObject(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setObjectWithInfo( sal_Int32 _nIndex, const css::uno::Any& x, sal_Int32 targetSqlType, sal_Int32 scale )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setObjectWithInfo(_nIndex, x, targetSqlType, scale);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setRef( sal_Int32 _nIndex, const css::uno::Reference< css::sdbc::XRef>& x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setRef(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setBlob( sal_Int32 _nIndex, const css::uno::Reference< css::sdbc::XBlob>& x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setBlob(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setClob( sal_Int32 _nIndex, const css::uno::Reference< css::sdbc::XClob>& x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setClob(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setArray( sal_Int32 _nIndex, const css::uno::Reference< css::sdbc::XArray>& x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setArray(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::clearParameters( )
+ {
+ if ( m_xInnerParamUpdate.is() )
+ m_xInnerParamUpdate->clearParameters( );
+ }
+
+ void SAL_CALL OParameterContinuation::setParameters( const Sequence< PropertyValue >& _rValues )
+ {
+ m_aValues = _rValues;
+ }
+
+
+} // namespace frm
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/paramwrapper.cxx b/connectivity/source/commontools/paramwrapper.cxx
new file mode 100644
index 0000000000..e25a3e7b49
--- /dev/null
+++ b/connectivity/source/commontools/paramwrapper.cxx
@@ -0,0 +1,345 @@
+/* -*- 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 <connectivity/paramwrapper.hxx>
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/XParameters.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/lang/WrappedTargetException.hpp>
+#include <com/sun/star/sdb/XParametersSupplier.hpp>
+#include <com/sun/star/sdb/XSingleSelectQueryAnalyzer.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+
+#include <o3tl/safeint.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <comphelper/enumhelper.hxx>
+
+#define PROPERTY_ID_VALUE 1000
+
+
+namespace dbtools::param
+{
+
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::sdbc::XParameters;
+ using ::com::sun::star::uno::Sequence;
+ using ::com::sun::star::uno::Type;
+ using ::com::sun::star::uno::RuntimeException;
+ using ::com::sun::star::uno::XWeak;
+ using ::com::sun::star::beans::XPropertySet;
+ using ::com::sun::star::beans::XFastPropertySet;
+ using ::com::sun::star::beans::XMultiPropertySet;
+ using ::com::sun::star::beans::XPropertySetInfo;
+ using ::com::sun::star::beans::Property;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::sdbc::SQLException;
+ using ::com::sun::star::lang::WrappedTargetException;
+ using ::com::sun::star::lang::IndexOutOfBoundsException;
+ using ::com::sun::star::container::XEnumeration;
+ using ::com::sun::star::sdb::XSingleSelectQueryAnalyzer;
+ using ::com::sun::star::sdb::XParametersSupplier;
+ using ::com::sun::star::lang::DisposedException;
+
+ namespace PropertyAttribute = ::com::sun::star::beans::PropertyAttribute;
+ namespace DataType = ::com::sun::star::sdbc::DataType;
+
+ ParameterWrapper::ParameterWrapper( const Reference< XPropertySet >& _rxColumn )
+ :PropertyBase( m_aBHelper )
+ ,m_xDelegator( _rxColumn )
+ {
+ if ( m_xDelegator.is() )
+ m_xDelegatorPSI = m_xDelegator->getPropertySetInfo();
+ if ( !m_xDelegatorPSI.is() )
+ throw RuntimeException();
+ }
+
+
+ ParameterWrapper::ParameterWrapper( const Reference< XPropertySet >& _rxColumn,
+ const Reference< XParameters >& _rxAllParameters, std::vector< sal_Int32 >&& _rIndexes )
+ :PropertyBase( m_aBHelper )
+ ,m_aIndexes( std::move(_rIndexes) )
+ ,m_xDelegator( _rxColumn )
+ ,m_xValueDestination( _rxAllParameters )
+ {
+ if ( m_xDelegator.is() )
+ m_xDelegatorPSI = m_xDelegator->getPropertySetInfo();
+ if ( !m_xDelegatorPSI.is() )
+ throw RuntimeException();
+
+ OSL_ENSURE( !m_aIndexes.empty(), "ParameterWrapper::ParameterWrapper: sure about the indexes?" );
+ }
+
+
+ ParameterWrapper::~ParameterWrapper()
+ {
+ }
+
+
+ IMPLEMENT_FORWARD_REFCOUNT( ParameterWrapper, UnoBase )
+
+ css::uno::Any ParameterWrapper::queryInterface(css::uno::Type const & aType)
+ {
+ css::uno::Any a(UnoBase::queryInterface(aType));
+ if (!a.hasValue()) {
+ a = PropertyBase::queryInterface(aType);
+ if (!a.hasValue()
+ && aType == cppu::UnoType<css::lang::XTypeProvider>::get())
+ {
+ a <<= css::uno::Reference<css::lang::XTypeProvider>(this);
+ }
+ }
+ return a;
+ }
+
+
+ Sequence< Type > SAL_CALL ParameterWrapper::getTypes( )
+ {
+ return Sequence< Type > {
+ cppu::UnoType<XWeak>::get(),
+ cppu::UnoType<XTypeProvider>::get(),
+ cppu::UnoType<XPropertySet>::get(),
+ cppu::UnoType<XFastPropertySet>::get(),
+ cppu::UnoType<XMultiPropertySet>::get()
+ };
+ }
+
+
+ IMPLEMENT_GET_IMPLEMENTATION_ID( ParameterWrapper )
+
+
+ OUString ParameterWrapper::impl_getPseudoAggregatePropertyName( sal_Int32 _nHandle ) const
+ {
+ Reference< XPropertySetInfo > xInfo = const_cast<ParameterWrapper*>( this )->getPropertySetInfo();
+ const css::uno::Sequence<Property> aProperties = xInfo->getProperties();
+ for ( const Property& rProperty : aProperties )
+ {
+ if ( rProperty.Handle == _nHandle )
+ return rProperty.Name;
+ }
+
+ OSL_FAIL( "ParameterWrapper::impl_getPseudoAggregatePropertyName: invalid argument!" );
+ return OUString();
+ }
+
+
+ Reference< XPropertySetInfo > ParameterWrapper::getPropertySetInfo()
+ {
+ return createPropertySetInfo( getInfoHelper() );
+ }
+
+
+ ::cppu::IPropertyArrayHelper& ParameterWrapper::getInfoHelper()
+ {
+ if (!m_pInfoHelper)
+ {
+ Sequence< Property > aProperties;
+ try
+ {
+ aProperties = m_xDelegatorPSI->getProperties();
+ sal_Int32 nProperties( aProperties.getLength() );
+ aProperties.realloc( nProperties + 1 );
+ aProperties.getArray()[ nProperties ] = Property(
+ "Value",
+ PROPERTY_ID_VALUE,
+ ::cppu::UnoType< Any >::get(),
+ PropertyAttribute::TRANSIENT | PropertyAttribute::MAYBEVOID
+ );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+
+ m_pInfoHelper.reset( new ::cppu::OPropertyArrayHelper( aProperties, false ) );
+ }
+ return *m_pInfoHelper;
+ }
+
+
+ sal_Bool ParameterWrapper::convertFastPropertyValue(Any& rConvertedValue, Any& rOldValue, sal_Int32 nHandle, const Any& rValue)
+ {
+ OSL_ENSURE( PROPERTY_ID_VALUE == nHandle, "ParameterWrapper::convertFastPropertyValue: the only non-readonly prop should be our PROPERTY_VALUE!" );
+
+ // we're lazy here ...
+ rOldValue = m_aValue.makeAny();
+ rConvertedValue = rValue;
+ return true; // assume "modified" ...
+ }
+
+
+ void ParameterWrapper::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue )
+ {
+ if ( nHandle == PROPERTY_ID_VALUE )
+ {
+ try
+ {
+ // TODO : aParamType & nScale can be obtained within the constructor...
+ sal_Int32 nParamType = DataType::VARCHAR;
+ OSL_VERIFY( m_xDelegator->getPropertyValue("Type") >>= nParamType );
+
+ sal_Int32 nScale = 0;
+ if ( m_xDelegatorPSI->hasPropertyByName("Scale") )
+ OSL_VERIFY( m_xDelegator->getPropertyValue("Scale") >>= nScale );
+
+ if ( m_xValueDestination.is() )
+ {
+ for ( const auto& rIndex : m_aIndexes )
+ {
+ m_xValueDestination->setObjectWithInfo( rIndex + 1, rValue, nParamType, nScale );
+ // (the index of the parameters is one-based)
+ }
+ }
+
+ m_aValue = rValue;
+ }
+ catch( SQLException& e )
+ {
+ throw WrappedTargetException(e.Message, e.Context, css::uno::Any(e));
+ }
+ }
+ else
+ {
+ OUString aName = impl_getPseudoAggregatePropertyName( nHandle );
+ m_xDelegator->setPropertyValue( aName, rValue );
+ }
+ }
+
+
+ void ParameterWrapper::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
+ {
+ if ( nHandle == PROPERTY_ID_VALUE )
+ {
+ rValue = m_aValue.makeAny();
+ }
+ else
+ {
+ OUString aName = impl_getPseudoAggregatePropertyName( nHandle );
+ rValue = m_xDelegator->getPropertyValue( aName );
+ }
+ }
+
+
+ void ParameterWrapper::dispose()
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ m_aValue.setNull();
+ m_aIndexes.resize(0);
+ m_xDelegator.clear();
+ m_xDelegatorPSI.clear();
+ m_xValueDestination.clear();
+
+ m_aBHelper.bDisposed = true;
+ }
+
+ ParameterWrapperContainer::ParameterWrapperContainer()
+ {
+ }
+
+
+ ParameterWrapperContainer::ParameterWrapperContainer( const Reference< XSingleSelectQueryAnalyzer >& _rxComposer )
+ {
+ Reference< XParametersSupplier > xSuppParams( _rxComposer, UNO_QUERY_THROW );
+ Reference< XIndexAccess > xParameters( xSuppParams->getParameters(), css::uno::UNO_SET_THROW );
+ sal_Int32 nParamCount( xParameters->getCount() );
+ m_aParameters.reserve( nParamCount );
+ for ( sal_Int32 i=0; i<nParamCount; ++i )
+ {
+ m_aParameters.push_back( new ParameterWrapper( Reference< XPropertySet >( xParameters->getByIndex( i ), UNO_QUERY_THROW ) ) );
+ }
+ }
+
+
+ ParameterWrapperContainer::~ParameterWrapperContainer()
+ {
+ }
+
+
+ Type SAL_CALL ParameterWrapperContainer::getElementType()
+ {
+ std::unique_lock aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+ return cppu::UnoType<XPropertySet>::get();
+ }
+
+
+ sal_Bool SAL_CALL ParameterWrapperContainer::hasElements()
+ {
+ std::unique_lock aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+ return !m_aParameters.empty();
+ }
+
+
+ sal_Int32 SAL_CALL ParameterWrapperContainer::getCount()
+ {
+ std::unique_lock aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+ return m_aParameters.size();
+ }
+
+
+ Any SAL_CALL ParameterWrapperContainer::getByIndex( sal_Int32 _nIndex )
+ {
+ std::unique_lock aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ if ( ( _nIndex < 0 ) || ( o3tl::make_unsigned(_nIndex) >= m_aParameters.size() ) )
+ throw IndexOutOfBoundsException();
+
+ return Any( Reference< XPropertySet >( m_aParameters[ _nIndex ] ) );
+ }
+
+
+ Reference< XEnumeration > ParameterWrapperContainer::createEnumeration()
+ {
+ std::unique_lock aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ return new ::comphelper::OEnumerationByIndex( static_cast< XIndexAccess* >( this ) );
+ }
+
+
+ void ParameterWrapperContainer::impl_checkDisposed_throw()
+ {
+ if ( m_bDisposed )
+ throw DisposedException( OUString(), *this );
+ }
+
+
+ void ParameterWrapperContainer::disposing(std::unique_lock<std::mutex>& /*rGuard*/)
+ {
+ for (const auto& rxParam : m_aParameters)
+ {
+ rxParam->dispose();
+ }
+
+ Parameters().swap(m_aParameters);
+ }
+
+
+} // namespace
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/predicateinput.cxx b/connectivity/source/commontools/predicateinput.cxx
new file mode 100644
index 0000000000..cbeaf511a9
--- /dev/null
+++ b/connectivity/source/commontools/predicateinput.cxx
@@ -0,0 +1,411 @@
+/* -*- 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 <connectivity/predicateinput.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/dbtools.hxx>
+#include <com/sun/star/i18n/LocaleData.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/util/NumberFormatter.hpp>
+#include <osl/diagnose.h>
+#include <connectivity/sqlnode.hxx>
+#include <connectivity/PColumn.hxx>
+#include <comphelper/numbers.hxx>
+#include <comphelper/diagnose_ex.hxx>
+
+#include <memory>
+#include <string_view>
+
+namespace dbtools
+{
+
+
+ using ::com::sun::star::sdbc::XConnection;
+ using ::com::sun::star::util::XNumberFormatsSupplier;
+ using ::com::sun::star::util::NumberFormatter;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::uno::XComponentContext;
+ using ::com::sun::star::beans::XPropertySet;
+ using ::com::sun::star::beans::XPropertySetInfo;
+ using ::com::sun::star::lang::Locale;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::i18n::LocaleData;
+ using ::com::sun::star::i18n::LocaleDataItem;
+ using ::com::sun::star::uno::Any;
+
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::connectivity;
+
+ using ::connectivity::OSQLParseNode;
+
+
+ static sal_Unicode lcl_getSeparatorChar(
+ std::u16string_view _rSeparator, sal_Unicode _nFallback )
+ {
+ OSL_ENSURE( !_rSeparator.empty(), "::lcl_getSeparatorChar: invalid separator string!" );
+
+ sal_Unicode nReturn( _nFallback );
+ if ( !_rSeparator.empty() )
+ nReturn = _rSeparator[0];
+ return nReturn;
+ }
+
+ bool OPredicateInputController::getSeparatorChars( const Locale& _rLocale, sal_Unicode& _rDecSep, sal_Unicode& _rThdSep ) const
+ {
+ _rDecSep = '.';
+ _rThdSep = ',';
+ try
+ {
+ LocaleDataItem aLocaleData;
+ if ( m_xLocaleData.is() )
+ {
+ aLocaleData = m_xLocaleData->getLocaleItem( _rLocale );
+ _rDecSep = lcl_getSeparatorChar( aLocaleData.decimalSeparator, _rDecSep );
+ _rThdSep = lcl_getSeparatorChar( aLocaleData.thousandSeparator, _rThdSep );
+ return true;
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "OPredicateInputController::getSeparatorChars" );
+ }
+ return false;
+ }
+
+
+ OPredicateInputController::OPredicateInputController(
+ const Reference< XComponentContext >& rxContext, const Reference< XConnection >& _rxConnection, const IParseContext* _pParseContext )
+ : m_xConnection( _rxConnection )
+ ,m_aParser( rxContext, _pParseContext )
+ {
+ try
+ {
+ // create a number formatter / number formats supplier pair
+ OSL_ENSURE( rxContext.is(), "OPredicateInputController::OPredicateInputController: need a service factory!" );
+ if ( rxContext.is() )
+ {
+ m_xFormatter.set( NumberFormatter::create(rxContext), UNO_QUERY_THROW );
+ }
+
+ Reference< XNumberFormatsSupplier > xNumberFormats = ::dbtools::getNumberFormats( m_xConnection, true );
+ if ( !xNumberFormats.is() )
+ ::comphelper::disposeComponent( m_xFormatter );
+ else
+ m_xFormatter->attachNumberFormatsSupplier( xNumberFormats );
+
+ // create the locale data
+ if ( rxContext.is() )
+ {
+ m_xLocaleData = LocaleData::create( rxContext );
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "OPredicateInputController::OPredicateInputController" );
+ }
+ }
+
+
+ std::unique_ptr<OSQLParseNode> OPredicateInputController::implPredicateTree(OUString& _rErrorMessage, const OUString& _rStatement, const Reference< XPropertySet > & _rxField) const
+ {
+ std::unique_ptr<OSQLParseNode> pReturn = const_cast< OSQLParser& >( m_aParser ).predicateTree( _rErrorMessage, _rStatement, m_xFormatter, _rxField );
+ if ( !pReturn )
+ { // is it a text field ?
+ sal_Int32 nType = DataType::OTHER;
+ _rxField->getPropertyValue("Type") >>= nType;
+
+ if ( ( DataType::CHAR == nType )
+ || ( DataType::VARCHAR == nType )
+ || ( DataType::LONGVARCHAR == nType )
+ || ( DataType::CLOB == nType )
+ )
+ { // yes -> force a quoted text and try again
+ OUString sQuoted( _rStatement );
+ if ( !sQuoted.isEmpty()
+ && ( !sQuoted.startsWith("'")
+ || !sQuoted.endsWith("'")
+ )
+ )
+ {
+ sQuoted = u"'" + sQuoted.replaceAll(u"'", u"''") + u"'";
+ }
+ pReturn = const_cast< OSQLParser& >( m_aParser ).predicateTree( _rErrorMessage, sQuoted, m_xFormatter, _rxField );
+ }
+
+ // one more fallback: for numeric fields, and value strings containing a decimal/thousands separator
+ // problem which is to be solved with this:
+ // * a system locale "german"
+ // * a column formatted with an english number format
+ // => the output is german (as we use the system locale for this), i.e. "3,4"
+ // => the input does not recognize the german text, as predicateTree uses the number format
+ // of the column to determine the main locale - the locale on the context is only a fallback
+ if ( ( DataType::FLOAT == nType )
+ || ( DataType::REAL == nType )
+ || ( DataType::DOUBLE == nType )
+ || ( DataType::NUMERIC == nType )
+ || ( DataType::DECIMAL == nType )
+ )
+ {
+ const IParseContext& rParseContext = m_aParser.getContext();
+ // get the separators for the locale of our parse context
+ sal_Unicode nCtxDecSep;
+ sal_Unicode nCtxThdSep;
+ getSeparatorChars( rParseContext.getPreferredLocale(), nCtxDecSep, nCtxThdSep );
+
+ // determine the locale of the column we're building a predicate string for
+ sal_Unicode nFmtDecSep( nCtxDecSep );
+ sal_Unicode nFmtThdSep( nCtxThdSep );
+ try
+ {
+ Reference< XPropertySetInfo > xPSI( _rxField->getPropertySetInfo() );
+ if ( xPSI.is() && xPSI->hasPropertyByName("FormatKey") )
+ {
+ sal_Int32 nFormatKey = 0;
+ _rxField->getPropertyValue("FormatKey") >>= nFormatKey;
+ if ( nFormatKey && m_xFormatter.is() )
+ {
+ Locale aFormatLocale;
+ ::comphelper::getNumberFormatProperty(
+ m_xFormatter,
+ nFormatKey,
+ "Locale"
+ ) >>= aFormatLocale;
+
+ // valid locale
+ if ( !aFormatLocale.Language.isEmpty() )
+ {
+ getSeparatorChars( aFormatLocale, nFmtDecSep, nCtxThdSep );
+ }
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "OPredicateInputController::implPredicateTree: caught an exception while dealing with the formats!" );
+ }
+
+ bool bDecDiffers = ( nCtxDecSep != nFmtDecSep );
+ bool bFmtDiffers = ( nCtxThdSep != nFmtThdSep );
+ if ( bDecDiffers || bFmtDiffers )
+ { // okay, at least one differs
+ // "translate" the value into the "format locale"
+ OUString sTranslated( _rStatement );
+ const sal_Unicode nIntermediate( '_' );
+ sTranslated = sTranslated.replace( nCtxDecSep, nIntermediate );
+ sTranslated = sTranslated.replace( nCtxThdSep, nFmtThdSep );
+ sTranslated = sTranslated.replace( nIntermediate, nFmtDecSep );
+
+ pReturn = const_cast< OSQLParser& >( m_aParser ).predicateTree( _rErrorMessage, sTranslated, m_xFormatter, _rxField );
+ }
+ }
+ }
+ return pReturn;
+ }
+
+
+ bool OPredicateInputController::normalizePredicateString(
+ OUString& _rPredicateValue, const Reference< XPropertySet > & _rxField, OUString* _pErrorMessage ) const
+ {
+ OSL_ENSURE( m_xConnection.is() && m_xFormatter.is() && _rxField.is(),
+ "OPredicateInputController::normalizePredicateString: invalid state or params!" );
+
+ bool bSuccess = false;
+ if ( m_xConnection.is() && m_xFormatter.is() && _rxField.is() )
+ {
+ // parse the string
+ OUString sError;
+ OUString sTransformedText( _rPredicateValue );
+ std::unique_ptr<OSQLParseNode> pParseNode = implPredicateTree( sError, sTransformedText, _rxField );
+ if ( _pErrorMessage ) *_pErrorMessage = sError;
+
+ if ( pParseNode )
+ {
+ const IParseContext& rParseContext = m_aParser.getContext();
+ sal_Unicode nDecSeparator, nThousandSeparator;
+ getSeparatorChars( rParseContext.getPreferredLocale(), nDecSeparator, nThousandSeparator );
+
+ // translate it back into a string
+ sTransformedText.clear();
+ pParseNode->parseNodeToPredicateStr(
+ sTransformedText, m_xConnection, m_xFormatter, _rxField, OUString(),
+ rParseContext.getPreferredLocale(), OUString(nDecSeparator), &rParseContext
+ );
+ _rPredicateValue = sTransformedText;
+
+ bSuccess = true;
+ }
+ }
+
+ return bSuccess;
+ }
+
+
+ OUString OPredicateInputController::getPredicateValueStr(
+ const OUString& _rPredicateValue, const Reference< XPropertySet > & _rxField ) const
+ {
+ OSL_ENSURE( _rxField.is(), "OPredicateInputController::getPredicateValue: invalid params!" );
+ OUString sReturn;
+ if ( _rxField.is() )
+ {
+ // The following is mostly stolen from the former implementation in the parameter dialog
+ // (dbaccess/source/ui/dlg/paramdialog.cxx). I do not fully understand this...
+
+ OUString sError;
+ std::unique_ptr<OSQLParseNode> pParseNode = implPredicateTree( sError, _rPredicateValue, _rxField );
+
+ implParseNode(std::move(pParseNode), true) >>= sReturn;
+ }
+
+ return sReturn;
+ }
+
+ OUString OPredicateInputController::getPredicateValueStr(
+ const OUString& _sField, const OUString& _rPredicateValue ) const
+ {
+ OUString sReturn = _rPredicateValue;
+ OUString sError;
+ sal_Int32 nIndex = 0;
+ OUString sField = _sField.getToken(0, '(', nIndex);
+ if(nIndex == -1)
+ sField = _sField;
+ sal_Int32 nType = ::connectivity::OSQLParser::getFunctionReturnType(sField,&m_aParser.getContext());
+ if ( nType == DataType::OTHER || sField.isEmpty() )
+ {
+ // first try the international version
+ OUString sSql = "SELECT * FROM x WHERE " + sField + _rPredicateValue;
+ const_cast< OSQLParser& >( m_aParser ).parseTree( sError, sSql, true );
+ nType = DataType::DOUBLE;
+ }
+
+ Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData();
+ rtl::Reference<parse::OParseColumn> pColumn = new parse::OParseColumn( sField,
+ OUString(),
+ OUString(),
+ OUString(),
+ ColumnValue::NULLABLE_UNKNOWN,
+ 0,
+ 0,
+ nType,
+ false,
+ false,
+ xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers(),
+ OUString(),
+ OUString(),
+ OUString());
+ Reference<XPropertySet> xColumn = pColumn;
+ pColumn->setFunction(true);
+ pColumn->setRealName(sField);
+
+ std::unique_ptr<OSQLParseNode> pParseNode = implPredicateTree( sError, _rPredicateValue, xColumn );
+ if(pParseNode)
+ {
+ implParseNode(std::move(pParseNode), true) >>= sReturn;
+ }
+ return sReturn;
+ }
+
+ Any OPredicateInputController::getPredicateValue(
+ const OUString& _rPredicateValue, const Reference< XPropertySet > & _rxField ) const
+ {
+ OSL_ENSURE( _rxField.is(), "OPredicateInputController::getPredicateValue: invalid params!" );
+
+ if ( _rxField.is() )
+ {
+ // The following is mostly stolen from the former implementation in the parameter dialog
+ // (dbaccess/source/ui/dlg/paramdialog.cxx). I do not fully understand this...
+
+ OUString sError;
+ std::unique_ptr<OSQLParseNode> pParseNode = implPredicateTree( sError, _rPredicateValue, _rxField );
+
+ return implParseNode(std::move(pParseNode), false);
+ }
+
+ return Any();
+ }
+
+ Any OPredicateInputController::implParseNode(std::unique_ptr<OSQLParseNode> pParseNode, bool _bForStatementUse) const
+ {
+ if ( ! pParseNode )
+ return Any();
+ else
+ {
+ OUString sReturn;
+ OSQLParseNode* pOdbcSpec = pParseNode->getByRule( OSQLParseNode::odbc_fct_spec );
+ if ( pOdbcSpec )
+ {
+ if ( _bForStatementUse )
+ {
+ OSQLParseNode* pFuncSpecParent = pOdbcSpec->getParent();
+ OSL_ENSURE( pFuncSpecParent, "OPredicateInputController::getPredicateValue: an ODBC func spec node without parent?" );
+ if ( pFuncSpecParent )
+ pFuncSpecParent->parseNodeToStr(sReturn, m_xConnection, &m_aParser.getContext());
+ }
+ else
+ {
+ OSQLParseNode* pValueNode = pOdbcSpec->getChild(1);
+ if ( SQLNodeType::String == pValueNode->getNodeType() )
+ sReturn = pValueNode->getTokenValue();
+ else
+ pValueNode->parseNodeToStr(sReturn, m_xConnection, &m_aParser.getContext());
+ }
+ }
+ else
+ {
+ if (pParseNode->getKnownRuleID() == OSQLParseNode::test_for_null )
+ {
+ assert(pParseNode->count() == 2);
+ return Any();
+ }
+ // LEM this seems overly permissive as test...
+ else if (pParseNode->count() >= 3)
+ {
+ OSQLParseNode* pValueNode = pParseNode->getChild(2);
+ assert(pValueNode && "OPredicateInputController::getPredicateValue: invalid node child!");
+ if ( !_bForStatementUse )
+ {
+ if ( SQLNodeType::String == pValueNode->getNodeType() )
+ sReturn = pValueNode->getTokenValue();
+ else
+ pValueNode->parseNodeToStr(
+ sReturn, m_xConnection, &m_aParser.getContext()
+ );
+ }
+ else
+ pValueNode->parseNodeToStr(
+ sReturn, m_xConnection, &m_aParser.getContext()
+ );
+ }
+ else
+ {
+ OSL_FAIL( "OPredicateInputController::getPredicateValue: unknown/invalid structure (noodbc)!" );
+ return Any();
+ }
+ }
+ return Any(sReturn);
+ }
+ }
+
+} // namespace dbtools
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/propertyids.cxx b/connectivity/source/commontools/propertyids.cxx
new file mode 100644
index 0000000000..cedd0f5f06
--- /dev/null
+++ b/connectivity/source/commontools/propertyids.cxx
@@ -0,0 +1,104 @@
+/* -*- 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 <propertyids.hxx>
+
+namespace dbtools
+{
+ OPropertyMap::OPropertyMap()
+ {
+ // MSVC complains about ambiguous operator=
+ m_aPropertyMap.insert({
+ {PROPERTY_ID_QUERYTIMEOUT, "QueryTimeOut"},
+ {PROPERTY_ID_MAXFIELDSIZE, "MaxFieldSize"},
+ {PROPERTY_ID_MAXROWS, "MaxRows"},
+ {PROPERTY_ID_CURSORNAME, "CursorName"},
+ {PROPERTY_ID_RESULTSETCONCURRENCY, "ResultSetConcurrency"},
+
+ {PROPERTY_ID_RESULTSETTYPE, "ResultSetType"},
+ {PROPERTY_ID_FETCHDIRECTION, "FetchDirection"},
+ {PROPERTY_ID_FETCHSIZE, "FetchSize"},
+ {PROPERTY_ID_ESCAPEPROCESSING, "EscapeProcessing"},
+ {PROPERTY_ID_USEBOOKMARKS, "UseBookmarks"},
+ // Column
+ {PROPERTY_ID_NAME, "Name"},
+ {PROPERTY_ID_TYPE, "Type"},
+ {PROPERTY_ID_TYPENAME, "TypeName"},
+ {PROPERTY_ID_PRECISION, "Precision"},
+ {PROPERTY_ID_SCALE, "Scale"},
+ {PROPERTY_ID_ISNULLABLE, "IsNullable"},
+ {PROPERTY_ID_ISAUTOINCREMENT, "IsAutoIncrement"},
+ {PROPERTY_ID_ISROWVERSION, "IsRowVersion"},
+ {PROPERTY_ID_DESCRIPTION, "Description"},
+ {PROPERTY_ID_DEFAULTVALUE, "DefaultValue"},
+
+ {PROPERTY_ID_REFERENCEDTABLE, "ReferencedTable"},
+ {PROPERTY_ID_UPDATERULE, "UpdateRule"},
+ {PROPERTY_ID_DELETERULE, "DeleteRule"},
+ {PROPERTY_ID_CATALOG, "Catalog"},
+ {PROPERTY_ID_ISUNIQUE, "IsUnique"},
+ {PROPERTY_ID_ISPRIMARYKEYINDEX, "IsPrimaryKeyIndex"},
+ {PROPERTY_ID_ISCLUSTERED, "IsClustered"},
+ {PROPERTY_ID_ISASCENDING, "IsAscending"},
+ {PROPERTY_ID_SCHEMANAME, "SchemaName"},
+ {PROPERTY_ID_CATALOGNAME, "CatalogName"},
+
+ {PROPERTY_ID_COMMAND, "Command"},
+ {PROPERTY_ID_CHECKOPTION, "CheckOption"},
+ {PROPERTY_ID_PASSWORD, "Password"},
+ {PROPERTY_ID_RELATEDCOLUMN, "RelatedColumn"},
+
+ {PROPERTY_ID_FUNCTION, "Function"},
+ {PROPERTY_ID_AGGREGATEFUNCTION, "AggregateFunction"},
+ {PROPERTY_ID_TABLENAME, "TableName"},
+ {PROPERTY_ID_REALNAME, "RealName"},
+ {PROPERTY_ID_DBASEPRECISIONCHANGED,"DbasePrecisionChanged"},
+ {PROPERTY_ID_ISCURRENCY, "IsCurrency"},
+ {PROPERTY_ID_ISBOOKMARKABLE, "IsBookmarkable"},
+ {PROPERTY_ID_HY010, "HY010"}, // error messages
+ {PROPERTY_ID_DELIMITER, "/"},
+ {PROPERTY_ID_FORMATKEY, "FormatKey"},
+ {PROPERTY_ID_LOCALE, "Locale"},
+ {PROPERTY_ID_AUTOINCREMENTCREATION, "AutoIncrementCreation"},
+ {PROPERTY_ID_PRIVILEGES, "Privileges"},
+ {PROPERTY_ID_HAVINGCLAUSE, "HavingClause"},
+ {PROPERTY_ID_ISSIGNED, "IsSigned"},
+ {PROPERTY_ID_ISSEARCHABLE, "IsSearchable"},
+ {PROPERTY_ID_LABEL, "Label"},
+ {PROPERTY_ID_APPLYFILTER, "ApplyFilter"},
+ {PROPERTY_ID_FILTER, "Filter"},
+ {PROPERTY_ID_MASTERFIELDS, "MasterFields"},
+ {PROPERTY_ID_DETAILFIELDS, "DetailFields"},
+ {PROPERTY_ID_FIELDTYPE, "FieldType"},
+ {PROPERTY_ID_VALUE, "Value"},
+ {PROPERTY_ID_ACTIVE_CONNECTION, "ActiveConnection"},
+ } );
+ }
+
+ const OUString& OPropertyMap::getNameByIndex(sal_Int32 _nIndex) const
+ {
+ std::map<sal_Int32, OUString>::const_iterator aIter = m_aPropertyMap.find(_nIndex);
+ assert(aIter != m_aPropertyMap.end());
+ return aIter->second;
+ }
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/sqlerror.cxx b/connectivity/source/commontools/sqlerror.cxx
new file mode 100644
index 0000000000..50c5968cd7
--- /dev/null
+++ b/connectivity/source/commontools/sqlerror.cxx
@@ -0,0 +1,295 @@
+/* -*- 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 <memory>
+#include <connectivity/sqlerror.hxx>
+
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdb/ErrorCondition.hpp>
+
+#include <cppuhelper/exc_hlp.hxx>
+#include <unotools/resmgr.hxx>
+#include <osl/diagnose.h>
+
+#include <strings.hrc>
+#include <strings.hxx>
+#include <string.h>
+
+namespace connectivity
+{
+
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::uno::XInterface;
+ using ::com::sun::star::sdbc::SQLException;
+ using ::com::sun::star::uno::Type;
+
+ class SQLError_Impl
+ {
+ public:
+ explicit SQLError_Impl();
+
+ // versions of the public SQLError methods which are just delegated to this impl-class
+ static const OUString& getMessagePrefix();
+ OUString getErrorMessage( const ErrorCondition _eCondition, const std::optional<OUString>& _rParamValue1, const std::optional<OUString>& _rParamValue2, const std::optional<OUString>& _rParamValue3 ) const;
+ static ErrorCode getErrorCode( const ErrorCondition _eCondition );
+ void raiseException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext, const std::optional<OUString>& _rParamValue1, const std::optional<OUString>& _rParamValue2, const std::optional<OUString>& _rParamValue3 );
+ void raiseException( const ErrorCondition _eCondition, const std::optional<OUString>& _rParamValue1, const std::optional<OUString>& _rParamValue2, const std::optional<OUString>& _rParamValue3 );
+ void raiseTypedException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext, const Type& _rExceptionType, const std::optional<OUString>& _rParamValue1, const std::optional<OUString>& _rParamValue2, const std::optional<OUString>& _rParamValue3 );
+ SQLException getSQLException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext, const std::optional<OUString>& _rParamValue1, const std::optional<OUString>& _rParamValue2, const std::optional<OUString>& _rParamValue3 );
+
+ private:
+ /// returns the basic error message associated with the given error condition, without any parameter replacements
+ OUString impl_getErrorMessage( ErrorCondition _eCondition ) const;
+
+ /// returns the SQLState associated with the given error condition
+ static OUString
+ impl_getSQLState( ErrorCondition _eCondition );
+
+ /// returns an SQLException describing the given error condition
+ SQLException
+ impl_buildSQLException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext,
+ const std::optional<OUString>& _rParamValue1, const std::optional<OUString>& _rParamValue2, const std::optional<OUString>& _rParamValue3 );
+ private:
+ std::locale m_aResources;
+ };
+
+ SQLError_Impl::SQLError_Impl()
+ : m_aResources(Translate::Create("cnr"))
+ {
+ }
+
+ const OUString& SQLError_Impl::getMessagePrefix()
+ {
+ static constexpr OUString s_sMessagePrefix( u"[OOoBase]"_ustr );
+ return s_sMessagePrefix;
+ }
+
+ namespace
+ {
+
+ /** substitutes a given placeholder in the given message with the given value
+ */
+ void lcl_substitutePlaceholder(OUString& _rMessage, const char* _pPlaceholder, const std::optional<OUString>& rParamValue)
+ {
+ size_t nPlaceholderLen( strlen( _pPlaceholder ) );
+ sal_Int32 nIndex = _rMessage.indexOfAsciiL( _pPlaceholder, nPlaceholderLen );
+
+ bool bHasPlaceholder = ( nIndex != -1 );
+ bool bWantsPlaceholder = rParamValue.has_value();
+ OSL_ENSURE( bHasPlaceholder == bWantsPlaceholder, "lcl_substitutePlaceholder: placeholder where none is expected, or no placeholder where one is needed!" );
+
+ if ( bHasPlaceholder && bWantsPlaceholder )
+ _rMessage = _rMessage.replaceAt( nIndex, nPlaceholderLen, *rParamValue );
+ }
+
+ TranslateId lcl_getResourceErrorID(const ErrorCondition _eCondition)
+ {
+ switch (_eCondition)
+ {
+ case css::sdb::ErrorCondition::ROW_SET_OPERATION_VETOED:
+ return STR_ROW_SET_OPERATION_VETOED;
+ case css::sdb::ErrorCondition::PARSER_CYCLIC_SUB_QUERIES:
+ return STR_PARSER_CYCLIC_SUB_QUERIES;
+ case css::sdb::ErrorCondition::DB_OBJECT_NAME_WITH_SLASHES:
+ return STR_DB_OBJECT_NAME_WITH_SLASHES;
+ case css::sdb::ErrorCondition::DB_INVALID_SQL_NAME:
+ return STR_DB_INVALID_SQL_NAME;
+ case css::sdb::ErrorCondition::DB_QUERY_NAME_WITH_QUOTES:
+ return STR_DB_QUERY_NAME_WITH_QUOTES;
+ case css::sdb::ErrorCondition::DB_OBJECT_NAME_IS_USED:
+ return STR_DB_OBJECT_NAME_IS_USED;
+ case css::sdb::ErrorCondition::DB_NOT_CONNECTED:
+ return STR_DB_NOT_CONNECTED;
+ case css::sdb::ErrorCondition::AB_ADDRESSBOOK_NOT_FOUND:
+ return STR_AB_ADDRESSBOOK_NOT_FOUND;
+ case css::sdb::ErrorCondition::DATA_CANNOT_SELECT_UNFILTERED:
+ return STR_DATA_CANNOT_SELECT_UNFILTERED;
+ }
+ return {};
+ }
+
+ OUString lcl_getResourceState(const ErrorCondition _eCondition)
+ {
+ switch (_eCondition)
+ {
+ case css::sdb::ErrorCondition::DB_NOT_CONNECTED:
+ return STR_DB_NOT_CONNECTED_STATE;
+ case css::sdb::ErrorCondition::DATA_CANNOT_SELECT_UNFILTERED:
+ return STR_DATA_CANNOT_SELECT_UNFILTERED_STATE;
+ }
+ return OUString();
+ }
+ }
+
+ OUString SQLError_Impl::getErrorMessage( const ErrorCondition _eCondition, const std::optional<OUString>& _rParamValue1, const std::optional<OUString>& _rParamValue2, const std::optional<OUString>& _rParamValue3 ) const
+ {
+ OUString sErrorMessage( impl_getErrorMessage( _eCondition ) );
+
+ lcl_substitutePlaceholder( sErrorMessage, "$1$", _rParamValue1 );
+ lcl_substitutePlaceholder( sErrorMessage, "$2$", _rParamValue2 );
+ lcl_substitutePlaceholder( sErrorMessage, "$3$", _rParamValue3 );
+
+ return sErrorMessage;
+ }
+
+
+ ErrorCode SQLError_Impl::getErrorCode( const ErrorCondition _eCondition )
+ {
+ return 0 - ::sal::static_int_cast< ErrorCode, ErrorCondition >( _eCondition );
+ }
+
+
+ void SQLError_Impl::raiseException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext, const std::optional<OUString>& _rParamValue1, const std::optional<OUString>& _rParamValue2, const std::optional<OUString>& _rParamValue3 )
+ {
+ raiseTypedException(
+ _eCondition,
+ _rxContext,
+ ::cppu::UnoType< SQLException >::get(),
+ _rParamValue1,
+ _rParamValue2,
+ _rParamValue3
+ );
+ }
+
+
+ void SQLError_Impl::raiseException( const ErrorCondition _eCondition, const std::optional<OUString>& _rParamValue1, const std::optional<OUString>& _rParamValue2, const std::optional<OUString>& _rParamValue3 )
+ {
+ raiseTypedException(
+ _eCondition,
+ nullptr,
+ ::cppu::UnoType< SQLException >::get(),
+ _rParamValue1,
+ _rParamValue2,
+ _rParamValue3
+ );
+ }
+
+ void SQLError_Impl::raiseTypedException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext,
+ const Type& _rExceptionType, const std::optional<OUString>& _rParamValue1, const std::optional<OUString>& _rParamValue2, const std::optional<OUString>& _rParamValue3 )
+ {
+ if ( !::cppu::UnoType< SQLException >::get().isAssignableFrom( _rExceptionType ) )
+ throw std::bad_cast();
+
+ // default-construct an exception of the desired type
+ Any aException( nullptr, _rExceptionType );
+
+ // fill it
+ SQLException* pException = static_cast< SQLException* >( aException.pData );
+ *pException = impl_buildSQLException( _eCondition, _rxContext, _rParamValue1, _rParamValue2, _rParamValue3 );
+
+ // throw it
+ ::cppu::throwException( aException );
+ }
+
+ SQLException SQLError_Impl::getSQLException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext,
+ const std::optional<OUString>& _rParamValue1, const std::optional<OUString>& _rParamValue2, const std::optional<OUString>& _rParamValue3 )
+ {
+ return impl_buildSQLException( _eCondition, _rxContext, _rParamValue1, _rParamValue2, _rParamValue3 );
+ }
+
+ SQLException SQLError_Impl::impl_buildSQLException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext,
+ const std::optional<OUString>& _rParamValue1, const std::optional<OUString>& _rParamValue2, const std::optional<OUString>& _rParamValue3 )
+ {
+ return SQLException(
+ getErrorMessage( _eCondition, _rParamValue1, _rParamValue2, _rParamValue3 ),
+ _rxContext,
+ impl_getSQLState( _eCondition ),
+ getErrorCode( _eCondition ),
+ Any()
+ );
+ }
+
+ OUString SQLError_Impl::impl_getErrorMessage( ErrorCondition _eCondition ) const
+ {
+ OUString sResMessage(Translate::get(lcl_getResourceErrorID(_eCondition), m_aResources));
+ OSL_ENSURE( !sResMessage.isEmpty(), "SQLError_Impl::impl_getErrorMessage: illegal error condition, or invalid resource!" );
+ return getMessagePrefix() + " " + sResMessage;
+ }
+
+ OUString SQLError_Impl::impl_getSQLState( ErrorCondition _eCondition )
+ {
+ static constexpr OUStringLiteral DEFAULT_STATE = u"S1000";
+ OUString sState = lcl_getResourceState(_eCondition);
+ if (sState.isEmpty())
+ sState = DEFAULT_STATE;
+ return sState;
+ }
+
+ SQLError::SQLError()
+ :m_pImpl( std::make_shared<SQLError_Impl>() )
+ {
+ }
+
+
+ SQLError::~SQLError()
+ {
+ }
+
+
+ const OUString& SQLError::getMessagePrefix()
+ {
+ return SQLError_Impl::getMessagePrefix();
+ }
+
+
+ OUString SQLError::getErrorMessage( const ErrorCondition _eCondition ) const
+ {
+ return m_pImpl->getErrorMessage( _eCondition, std::optional<OUString>(), std::optional<OUString>(), std::optional<OUString>() );
+ }
+
+
+ ErrorCode SQLError::getErrorCode( const ErrorCondition _eCondition )
+ {
+ return SQLError_Impl::getErrorCode( _eCondition );
+ }
+
+
+ void SQLError::raiseException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext, const std::optional<OUString>& _rParamValue1, const std::optional<OUString>& _rParamValue2, const std::optional<OUString>& _rParamValue3 ) const
+ {
+ m_pImpl->raiseException( _eCondition, _rxContext, _rParamValue1, _rParamValue2, _rParamValue3 );
+ }
+
+
+ void SQLError::raiseException( const ErrorCondition _eCondition ) const
+ {
+ m_pImpl->raiseException( _eCondition, std::optional<OUString>(), std::optional<OUString>(), std::optional<OUString>() );
+ }
+
+
+ void SQLError::raiseTypedException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext,
+ const Type& _rExceptionType ) const
+ {
+ m_pImpl->raiseTypedException( _eCondition, _rxContext, _rExceptionType, std::optional<OUString>(), std::optional<OUString>(), std::optional<OUString>() );
+ }
+
+
+ SQLException SQLError::getSQLException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext,
+ const std::optional<OUString>& _rParamValue1, const std::optional<OUString>& _rParamValue2, const std::optional<OUString>& _rParamValue3 ) const
+ {
+ return m_pImpl->getSQLException( _eCondition, _rxContext, _rParamValue1, _rParamValue2, _rParamValue3 );
+ }
+
+
+} // namespace connectivity
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/statementcomposer.cxx b/connectivity/source/commontools/statementcomposer.cxx
new file mode 100644
index 0000000000..8ebbd9ca86
--- /dev/null
+++ b/connectivity/source/commontools/statementcomposer.cxx
@@ -0,0 +1,301 @@
+/* -*- 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 <connectivity/statementcomposer.hxx>
+
+#include <connectivity/dbtools.hxx>
+
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/lang/NullPointerException.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/sdb/XQueriesSupplier.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+
+#include <unotools/sharedunocomponent.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <comphelper/property.hxx>
+
+
+namespace dbtools
+{
+
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::sdbc::XConnection;
+ using ::com::sun::star::sdb::XSingleSelectQueryComposer;
+ using ::com::sun::star::lang::NullPointerException;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::lang::XComponent;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::sdb::XQueriesSupplier;
+ using ::com::sun::star::container::XNameAccess;
+ using ::com::sun::star::beans::XPropertySet;
+ using ::com::sun::star::lang::XMultiServiceFactory;
+ using ::com::sun::star::sdbc::SQLException;
+
+ namespace CommandType = ::com::sun::star::sdb::CommandType;
+
+ struct StatementComposer_Data
+ {
+ const Reference< XConnection > xConnection;
+ Reference< XSingleSelectQueryComposer > xComposer;
+ OUString sCommand;
+ OUString sFilter;
+ OUString sHavingClause;
+ OUString sOrder;
+ sal_Int32 nCommandType;
+ bool bEscapeProcessing;
+ bool bComposerDirty;
+ bool bDisposeComposer;
+
+ explicit StatementComposer_Data( const Reference< XConnection >& _rxConnection )
+ :xConnection( _rxConnection )
+ ,nCommandType( CommandType::COMMAND )
+ ,bEscapeProcessing( true )
+ ,bComposerDirty( true )
+ ,bDisposeComposer( true )
+ {
+ if ( !_rxConnection.is() )
+ throw NullPointerException();
+ }
+ };
+
+
+ namespace
+ {
+
+ void lcl_resetComposer( StatementComposer_Data& _rData )
+ {
+ if ( _rData.bDisposeComposer && _rData.xComposer.is() )
+ {
+ try
+ {
+ Reference< XComponent > xComposerComponent( _rData.xComposer, UNO_QUERY_THROW );
+ xComposerComponent->dispose();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+ }
+ _rData.xComposer.clear();
+ }
+
+
+ bool lcl_ensureUpToDateComposer_nothrow( StatementComposer_Data& _rData )
+ {
+ if ( !_rData.bComposerDirty )
+ return _rData.xComposer.is();
+ lcl_resetComposer( _rData );
+
+ try
+ {
+ OUString sStatement;
+ switch ( _rData.nCommandType )
+ {
+ case CommandType::COMMAND:
+ if ( _rData.bEscapeProcessing )
+ sStatement = _rData.sCommand;
+ // (in case of no escape processing we assume a not parseable statement)
+ break;
+
+ case CommandType::TABLE:
+ {
+ if ( _rData.sCommand.isEmpty() )
+ break;
+
+ sStatement = "SELECT * FROM ";
+
+ OUString sCatalog, sSchema, sTable;
+ qualifiedNameComponents( _rData.xConnection->getMetaData(), _rData.sCommand, sCatalog, sSchema, sTable, EComposeRule::InDataManipulation );
+
+ sStatement += composeTableNameForSelect( _rData.xConnection, sCatalog, sSchema, sTable );
+ }
+ break;
+
+ case CommandType::QUERY:
+ {
+ // ask the connection for the query
+ Reference< XQueriesSupplier > xSupplyQueries( _rData.xConnection, UNO_QUERY_THROW );
+ Reference< XNameAccess > xQueries( xSupplyQueries->getQueries(), css::uno::UNO_SET_THROW );
+
+ if ( !xQueries->hasByName( _rData.sCommand ) )
+ break;
+
+ Reference< XPropertySet > xQuery( xQueries->getByName( _rData.sCommand ), UNO_QUERY_THROW );
+
+ // a native query ?
+ bool bQueryEscapeProcessing = false;
+ xQuery->getPropertyValue("EscapeProcessing") >>= bQueryEscapeProcessing;
+ if ( !bQueryEscapeProcessing )
+ break;
+
+ // the command used by the query
+ xQuery->getPropertyValue("Command") >>= sStatement;
+ if ( sStatement.isEmpty() )
+ break;
+
+ // use a composer to build a statement from the query filter/order props
+ Reference< XMultiServiceFactory > xFactory( _rData.xConnection, UNO_QUERY_THROW );
+ ::utl::SharedUNOComponent< XSingleSelectQueryComposer > xComposer;
+ xComposer.set(
+ xFactory->createInstance("com.sun.star.sdb.SingleSelectQueryComposer"),
+ UNO_QUERY_THROW
+ );
+
+ // the "basic" statement
+ xComposer->setElementaryQuery( sStatement );
+
+ // the sort order
+ static constexpr OUString sPropOrder( u"Order"_ustr );
+ if ( ::comphelper::hasProperty( sPropOrder, xQuery ) )
+ {
+ OUString sOrder;
+ OSL_VERIFY( xQuery->getPropertyValue( sPropOrder ) >>= sOrder );
+ xComposer->setOrder( sOrder );
+ }
+
+ // the filter
+ bool bApplyFilter = true;
+ static constexpr OUString sPropApply( u"ApplyFilter"_ustr );
+ if ( ::comphelper::hasProperty( sPropApply, xQuery ) )
+ {
+ OSL_VERIFY( xQuery->getPropertyValue( sPropApply ) >>= bApplyFilter );
+ }
+
+ if ( bApplyFilter )
+ {
+ OUString sFilter;
+ OSL_VERIFY( xQuery->getPropertyValue("Filter") >>= sFilter );
+ xComposer->setFilter( sFilter );
+ OSL_VERIFY( xQuery->getPropertyValue("HavingClause") >>= sFilter );
+ xComposer->setHavingClause( sFilter );
+ }
+
+ // the composed statement
+ sStatement = xComposer->getQuery();
+ }
+ break;
+
+ default:
+ OSL_FAIL("lcl_ensureUpToDateComposer_nothrow: no table, no query, no statement - what else ?!");
+ break;
+ }
+
+ if ( !sStatement.isEmpty() )
+ {
+ // create a composer
+ Reference< XMultiServiceFactory > xFactory( _rData.xConnection, UNO_QUERY_THROW );
+ Reference< XSingleSelectQueryComposer > xComposer( xFactory->createInstance("com.sun.star.sdb.SingleSelectQueryComposer"),
+ UNO_QUERY_THROW );
+ xComposer->setElementaryQuery( sStatement );
+
+ // append sort/filter
+ xComposer->setOrder( _rData.sOrder );
+ xComposer->setFilter( _rData.sFilter );
+ xComposer->setHavingClause( _rData.sHavingClause );
+
+ sStatement = xComposer->getQuery();
+
+ _rData.xComposer = xComposer;
+ _rData.bComposerDirty = false;
+ }
+ }
+ catch( const SQLException& )
+ {
+ // allowed to leave here
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+
+ return _rData.xComposer.is();
+ }
+ }
+
+ StatementComposer::StatementComposer( const Reference< XConnection >& _rxConnection,
+ const OUString& _rCommand, const sal_Int32 _nCommandType, const bool _bEscapeProcessing )
+ :m_pData( new StatementComposer_Data( _rxConnection ) )
+ {
+ OSL_PRECOND( _rxConnection.is(), "StatementComposer::StatementComposer: illegal connection!" );
+ m_pData->sCommand = _rCommand;
+ m_pData->nCommandType = _nCommandType;
+ m_pData->bEscapeProcessing = _bEscapeProcessing;
+ }
+
+
+ StatementComposer::~StatementComposer()
+ {
+ lcl_resetComposer( *m_pData );
+ }
+
+
+ void StatementComposer::setDisposeComposer( bool _bDoDispose )
+ {
+ m_pData->bDisposeComposer = _bDoDispose;
+ }
+
+
+ void StatementComposer::setFilter( const OUString& _rFilter )
+ {
+ m_pData->sFilter = _rFilter;
+ m_pData->bComposerDirty = true;
+ }
+
+
+ void StatementComposer::setHavingClause( const OUString& _rHavingClause )
+ {
+ m_pData->sHavingClause = _rHavingClause;
+ m_pData->bComposerDirty = true;
+ }
+
+
+ void StatementComposer::setOrder( const OUString& _rOrder )
+ {
+ m_pData->sOrder = _rOrder;
+ m_pData->bComposerDirty = true;
+ }
+
+
+ Reference< XSingleSelectQueryComposer > const & StatementComposer::getComposer()
+ {
+ lcl_ensureUpToDateComposer_nothrow( *m_pData );
+ return m_pData->xComposer;
+ }
+
+
+ OUString StatementComposer::getQuery()
+ {
+ if ( lcl_ensureUpToDateComposer_nothrow( *m_pData ) )
+ {
+ return m_pData->xComposer->getQuery();
+ }
+
+ return OUString();
+ }
+
+
+} // namespace dbtools
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/warningscontainer.cxx b/connectivity/source/commontools/warningscontainer.cxx
new file mode 100644
index 0000000000..ba78256125
--- /dev/null
+++ b/connectivity/source/commontools/warningscontainer.cxx
@@ -0,0 +1,110 @@
+/* -*- 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 <connectivity/warningscontainer.hxx>
+#include <connectivity/dbexception.hxx>
+
+#include <com/sun/star/sdb/SQLContext.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+
+#include <o3tl/any.hxx>
+#include <osl/diagnose.h>
+
+
+namespace dbtools
+{
+
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::com::sun::star::sdb;
+
+ static void lcl_concatWarnings( Any& _rChainLeft, const Any& _rChainRight )
+ {
+ if ( !_rChainLeft.hasValue() )
+ _rChainLeft = _rChainRight;
+ else
+ {
+ // to travel the chain by reference (and not by value), we need the getValue...
+ // looks like a hack, but the meaning of getValue is documented, and it's the only chance for reference-traveling...
+
+ OSL_ENSURE( SQLExceptionInfo( _rChainLeft ).isValid(),
+ "lcl_concatWarnings: invalid warnings chain (this will crash)!" );
+
+ const SQLException* pChainTravel = o3tl::doAccess<SQLException>( _rChainLeft );
+ SQLExceptionIteratorHelper aReferenceIterHelper( *pChainTravel );
+ while ( aReferenceIterHelper.hasMoreElements() )
+ pChainTravel = aReferenceIterHelper.next();
+
+ // reached the end of the chain, and pChainTravel points to the last element
+ const_cast< SQLException* >( pChainTravel )->NextException = _rChainRight;
+ }
+ }
+
+
+ void WarningsContainer::appendWarning(const SQLException& _rWarning)
+ {
+ lcl_concatWarnings( m_aOwnWarnings, Any( _rWarning ) );
+ }
+
+
+ void WarningsContainer::appendWarning( const SQLContext& _rContext )
+ {
+ lcl_concatWarnings( m_aOwnWarnings, Any( _rContext ));
+ }
+
+
+ void WarningsContainer::appendWarning(const SQLWarning& _rWarning)
+ {
+ lcl_concatWarnings( m_aOwnWarnings, Any( _rWarning ) );
+ }
+
+
+ Any WarningsContainer::getWarnings( ) const
+ {
+ Any aAllWarnings;
+ if ( m_xExternalWarnings.is() )
+ aAllWarnings = m_xExternalWarnings->getWarnings();
+
+ if ( m_aOwnWarnings.hasValue() )
+ lcl_concatWarnings( aAllWarnings, m_aOwnWarnings );
+
+ return aAllWarnings;
+ }
+
+
+ void WarningsContainer::clearWarnings( )
+ {
+ if ( m_xExternalWarnings.is() )
+ m_xExternalWarnings->clearWarnings();
+ m_aOwnWarnings.clear();
+ }
+
+
+ void WarningsContainer::appendWarning( const OUString& _rWarning, const char* _pAsciiSQLState, const Reference< XInterface >& _rxContext )
+ {
+ appendWarning( SQLWarning( _rWarning, _rxContext, OUString::createFromAscii( _pAsciiSQLState ), 0, Any() ) );
+ }
+
+
+} // namespace dbtools
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */